diff --git a/README.md b/README.md
index 7ab49fa..1e35206 100755
--- a/README.md
+++ b/README.md
@@ -414,6 +414,31 @@ Output (only part shown):
```
+#### get_tx
+
+```bash
+curl -w "\n" -X POST http://127.0.0.1:1984/get_tx -d '{"tx_hash": "bfbfbb3bfa169731a092891795be1c3c923a018882ac0efc0ed3e79e2d2b2e54"}'
+```
+
+Output (only part shown):
+
+```json
+{
+ "coinbase": false,
+ "error": "",
+ "fee": 22893920000,
+ "mixin_no": 11,
+ "no_confirmations": 2898,
+ "pub_key": "b753c863c64565ae81630bfdbf497f06955b6ce041f656565809d04be6ef9343",
+ "size": 13461,
+ "status": "OK",
+ "tx_hash": "bfbfbb3bfa169731a092891795be1c3c923a018882ac0efc0ed3e79e2d2b2e54",
+ "tx_height": 960491,
+ "xmr_inputs": 0,
+ "xmr_outputs": 0
+}
+```
+
#### get_unspent_outs
```bash
diff --git a/html/index.html b/html/index.html
index 9faf3fa..7dece73 100755
--- a/html/index.html
+++ b/html/index.html
@@ -65,6 +65,7 @@
+
diff --git a/html/js/controllers/account_overview.js b/html/js/controllers/account_overview.js
index 0f2590f..0b13970 100755
--- a/html/js/controllers/account_overview.js
+++ b/html/js/controllers/account_overview.js
@@ -26,7 +26,9 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-thinwalletCtrls.controller('AccountOverviewCtrl', function ($scope, $rootScope, $http, $interval, AccountService, EVENT_CODES) {
+thinwalletCtrls.controller('AccountOverviewCtrl', function ($scope, $rootScope, $http,
+ $interval, AccountService,
+ EVENT_CODES) {
"use strict";
$rootScope.$watch('account', $scope.fetchTransactions);
diff --git a/html/js/controllers/transaction_details.js b/html/js/controllers/transaction_details.js
new file mode 100644
index 0000000..3a5ef66
--- /dev/null
+++ b/html/js/controllers/transaction_details.js
@@ -0,0 +1,14 @@
+/**
+ * Created by mwo on 02/08/17.
+ */
+
+
+thinwalletCtrls.controller('TransactionDetailsCtrl', function ($scope, $http,
+ AccountService,
+ ModalService,
+ ApiCalls) {
+ "use strict";
+
+ console.log("TransactionDetailsCtrl");
+
+});
diff --git a/html/modals/transaction-details.html b/html/modals/transaction-details.html
new file mode 100755
index 0000000..248ea6d
--- /dev/null
+++ b/html/modals/transaction-details.html
@@ -0,0 +1,57 @@
+
+
+
+
+ +
+
+
Transaction details
+
Transaction details
+
+
+
+
diff --git a/main.cpp b/main.cpp
index b25a417..fa473ba 100755
--- a/main.cpp
+++ b/main.cpp
@@ -162,6 +162,7 @@ MAKE_RESOURCE(get_random_outs);
MAKE_RESOURCE(submit_raw_tx);
MAKE_RESOURCE(import_wallet_request);
MAKE_RESOURCE(import_recent_wallet_request);
+MAKE_RESOURCE(get_tx);
MAKE_RESOURCE(get_version);
// restbed service
@@ -176,6 +177,7 @@ service.publish(get_random_outs);
service.publish(submit_raw_tx);
service.publish(import_wallet_request);
service.publish(import_recent_wallet_request);
+service.publish(get_tx);
service.publish(get_version);
auto settings = make_shared( );
diff --git a/src/CurrentBlockchainStatus.cpp b/src/CurrentBlockchainStatus.cpp
index 4be323f..a1557ac 100755
--- a/src/CurrentBlockchainStatus.cpp
+++ b/src/CurrentBlockchainStatus.cpp
@@ -247,7 +247,7 @@ CurrentBlockchainStatus::tx_exist(const string& tx_hash_str, uint64_t& tx_index)
return tx_exist(tx_hash, tx_index);
}
- throw runtime_error("hex_to_pod(tx_hash_str, tx_hash) failed!");
+ false;
}
bool
@@ -863,8 +863,38 @@ CurrentBlockchainStatus::find_txs_in_mempool(
return true;
};
+bool
+CurrentBlockchainStatus::get_tx(crypto::hash const& tx_hash, transaction& tx)
+{
+ return mcore->get_tx(tx_hash, tx);
+}
+
+
+bool
+CurrentBlockchainStatus::get_tx(string const& tx_hash_str, transaction& tx)
+{
+ crypto::hash tx_hash;
+
+ if (!hex_to_pod(tx_hash_str, tx_hash))
+ {
+ return false;
+ }
- bool
+ return mcore->get_tx(tx_hash, tx);
+}
+
+bool
+CurrentBlockchainStatus::get_tx_block_height(crypto::hash const& tx_hash, int64_t& tx_height)
+{
+ if (!tx_exist(tx_hash))
+ return false;
+
+ tx_height = core_storage->get_db().get_tx_block_height(tx_hash);
+
+ return true;
+}
+
+bool
CurrentBlockchainStatus::set_new_searched_blk_no(const string& address, uint64_t new_value)
{
std::lock_guard lck (searching_threads_map_mtx);
diff --git a/src/CurrentBlockchainStatus.h b/src/CurrentBlockchainStatus.h
index 644e6ac..5906f0f 100755
--- a/src/CurrentBlockchainStatus.h
+++ b/src/CurrentBlockchainStatus.h
@@ -188,6 +188,15 @@ struct CurrentBlockchainStatus
find_txs_in_mempool(const string& address_str,
json& transactions);
+ static bool
+ get_tx(crypto::hash const& tx_hash, transaction& tx);
+
+ static bool
+ get_tx(string const& tx_hash_str, transaction& tx);
+
+ static bool
+ get_tx_block_height(crypto::hash const& tx_hash, int64_t& tx_height);
+
static bool
set_new_searched_blk_no(const string& address,
uint64_t new_value);
diff --git a/src/YourMoneroRequests.cpp b/src/YourMoneroRequests.cpp
index 73623cc..472b123 100755
--- a/src/YourMoneroRequests.cpp
+++ b/src/YourMoneroRequests.cpp
@@ -133,7 +133,7 @@ YourMoneroRequests::get_address_txs(const shared_ptr< Session > session, const B
json j_response;
json j_request;
- vector requested_values{"address", "view_key"};
+ vector requested_values {"address", "view_key"};
if (!parse_request(body, requested_values, j_request, j_response))
{
@@ -993,6 +993,156 @@ YourMoneroRequests::import_recent_wallet_request(const shared_ptr< Session > ses
}
+
+void
+YourMoneroRequests::get_tx(const shared_ptr< Session > session, const Bytes & body)
+{
+
+ json j_request = body_to_json(body);
+
+ string tx_hash_str = j_request["tx_hash"];
+
+ json j_response;
+
+ j_response["status"] = "error";
+ j_response["error"] = "Some error occured";
+
+
+ crypto::hash tx_hash;
+
+ if (!hex_to_pod(tx_hash_str, tx_hash))
+ {
+ cerr << "Cant parse tx hash! : " << tx_hash_str << '\n';
+ j_response["status"] = "Cant parse tx hash! : " + tx_hash_str;
+ session_close(session, j_response.dump());
+ return;
+ }
+
+
+ transaction tx;
+
+ bool tx_found {false};
+
+ if (!CurrentBlockchainStatus::get_tx(tx_hash, tx))
+ {
+ // if tx not found in the blockchain, check if its in mempool
+
+ vector> mempool_txs =
+ CurrentBlockchainStatus::get_mempool_txs();
+
+
+ for (auto const& mtx: mempool_txs)
+ {
+
+ cout << (get_transaction_hash(mtx.second)) << endl;
+ if (get_transaction_hash(mtx.second) == tx_hash)
+ {
+ tx = mtx.second;
+ tx_found = true;
+ break;
+ }
+ }
+
+ tx_found = false;
+ }
+ else
+ {
+ tx_found = true;
+ }
+
+ if (tx_found)
+ {
+ crypto::hash tx_hash = get_transaction_hash(tx);
+
+ // return tx hash. can be used to check if we acctually
+ // delivered the tx that was requested
+ j_response["tx_hash"] = pod_to_hex(tx_hash);
+
+ j_response["pub_key"] = pod_to_hex(xmreg::get_tx_pub_key_from_received_outs(tx));
+
+
+ bool coinbase = is_coinbase(tx);
+
+ j_response["coinbase"] = coinbase;
+
+ // key images of inputs
+ vector input_key_imgs;
+
+ // public keys and xmr amount of outputs
+ vector> output_pub_keys;
+
+ uint64_t xmr_inputs;
+ uint64_t xmr_outputs;
+ uint64_t num_nonrct_inputs;
+ uint64_t fee;
+ uint64_t mixin_no;
+ uint64_t size;
+ uint64_t blk_height;
+
+ // sum xmr in inputs and ouputs in the given tx
+ array const& sum_data = xmreg::summary_of_in_out_rct(
+ tx, output_pub_keys, input_key_imgs);
+
+ xmr_outputs = sum_data[0];
+ xmr_inputs = sum_data[1];
+ mixin_no = sum_data[2];
+ num_nonrct_inputs = sum_data[3];
+
+ j_response["xmr_outputs"] = xmr_outputs;
+ j_response["xmr_inputs"] = xmr_inputs;
+ j_response["mixin_no"] = mixin_no;
+
+ fee = 0;
+
+ if (!coinbase && tx.vin.size() > 0)
+ {
+ // check if not miner tx
+ // i.e., for blocks without any user transactions
+ if (tx.vin.at(0).type() != typeid(txin_gen))
+ {
+ // get tx fee
+ fee = get_tx_fee(tx);
+ }
+ }
+
+ j_response["fee"] = fee;
+
+ // get tx size in bytes
+ size = get_object_blobsize(tx);
+
+ j_response["size"] = size;
+
+ int64_t tx_height {-1};
+
+ int64_t no_confirmations {-1};
+
+ if (CurrentBlockchainStatus::get_tx_block_height(tx_hash, tx_height))
+ {
+ // get the current blockchain height. Just to check
+ uint64_t bc_height = get_current_blockchain_height();
+
+ no_confirmations = bc_height - tx_height;
+ }
+
+ j_response["tx_height"] = tx_height;
+ j_response["no_confirmations"] = no_confirmations;
+ j_response["status"] = "OK";
+ j_response["error"] = "";
+ }
+ else
+ {
+ cerr << "Cant get tx details for tx hash! : " << tx_hash_str << '\n';
+ j_response["status"] = "Cant get tx details for tx hash! : " + tx_hash_str;
+ }
+
+ string response_body = j_response.dump();
+
+ auto response_headers = make_headers({{ "Content-Length", to_string(response_body.size())}});
+
+ session->close( OK, response_body, response_headers);
+}
+
+
void
YourMoneroRequests::get_version(const shared_ptr< Session > session, const Bytes & body)
{
diff --git a/src/YourMoneroRequests.h b/src/YourMoneroRequests.h
index dd35ff8..70dda20 100755
--- a/src/YourMoneroRequests.h
+++ b/src/YourMoneroRequests.h
@@ -105,6 +105,9 @@ public:
void
import_recent_wallet_request(const shared_ptr< Session > session, const Bytes & body);
+ void
+ get_tx(const shared_ptr< Session > session, const Bytes & body);
+
void
get_version(const shared_ptr< Session > session, const Bytes & body);
diff --git a/src/tools.cpp b/src/tools.cpp
index 5e5417f..7995c80 100755
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -290,7 +290,112 @@ get_blockchain_path(bf::path& blockchain_path,
}
-uint64_t
+
+
+array
+summary_of_in_out_rct(
+ const transaction& tx,
+ vector>& output_pub_keys,
+ vector& input_key_imgs)
+{
+
+ uint64_t xmr_outputs {0};
+ uint64_t xmr_inputs {0};
+ uint64_t mixin_no {0};
+ uint64_t num_nonrct_inputs {0};
+
+
+ for (const tx_out& txout: tx.vout)
+ {
+ if (txout.target.type() != typeid(txout_to_key))
+ {
+ // push empty pair.
+ output_pub_keys.push_back(pair{});
+ continue;
+ }
+
+ // get tx input key
+ const txout_to_key& txout_key
+ = boost::get(txout.target);
+
+ output_pub_keys.push_back(make_pair(txout_key, txout.amount));
+
+ xmr_outputs += txout.amount;
+ }
+
+ size_t input_no = tx.vin.size();
+
+ for (size_t i = 0; i < input_no; ++i)
+ {
+
+ if(tx.vin[i].type() != typeid(cryptonote::txin_to_key))
+ {
+ continue;
+ }
+
+ // get tx input key
+ const cryptonote::txin_to_key& tx_in_to_key
+ = boost::get(tx.vin[i]);
+
+ xmr_inputs += tx_in_to_key.amount;
+
+ if (tx_in_to_key.amount != 0)
+ {
+ ++num_nonrct_inputs;
+ }
+
+ if (mixin_no == 0)
+ {
+ mixin_no = tx_in_to_key.key_offsets.size();
+ }
+
+ input_key_imgs.push_back(tx_in_to_key);
+
+ } // for (size_t i = 0; i < input_no; ++i)
+
+
+ return {xmr_outputs, xmr_inputs, mixin_no, num_nonrct_inputs};
+};
+
+
+// this version for mempool txs from json
+array
+summary_of_in_out_rct(const json& _json)
+{
+ uint64_t xmr_outputs {0};
+ uint64_t xmr_inputs {0};
+ uint64_t no_outputs {0};
+ uint64_t no_inputs {0};
+ uint64_t mixin_no {0};
+ uint64_t num_nonrct_inputs {0};
+
+ for (const json& vout: _json["vout"])
+ {
+ xmr_outputs += vout["amount"].get();
+ }
+
+ no_outputs = _json["vout"].size();
+
+ for (const json& vin: _json["vin"])
+ {
+ uint64_t amount = vin["key"]["amount"].get();
+
+ xmr_inputs += amount;
+
+ if (amount != 0)
+ ++num_nonrct_inputs;
+ }
+
+ no_inputs = _json["vin"].size();
+
+ mixin_no = _json["vin"].at(0)["key"]["key_offsets"].size() - 1;
+
+ return {xmr_outputs, xmr_inputs, no_outputs, no_inputs, mixin_no, num_nonrct_inputs};
+};
+
+
+
+ uint64_t
sum_money_in_outputs(const transaction& tx)
{
uint64_t sum_xmr {0};
diff --git a/src/tools.h b/src/tools.h
index 99fd1b0..4cf46d1 100755
--- a/src/tools.h
+++ b/src/tools.h
@@ -105,6 +105,16 @@ bool
get_blockchain_path(bf::path& blockchain_path,
bool testnet = false);
+array
+summary_of_in_out_rct(
+ const transaction& tx,
+ vector>& output_pub_keys,
+ vector& input_key_imgs);
+
+// this version for mempool txs from json
+array
+summary_of_in_out_rct(const json& _json);
+
uint64_t
sum_money_in_outputs(const transaction& tx);