From 3485483cf2db88f5e5ef6d0fbfd39fd64a47610d Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Thu, 15 Dec 2016 12:58:00 +0800 Subject: [PATCH] basic transactions search added --- src/MySqlConnector.h | 169 +++++++++++++++++++++++++++++---------- src/TxSearch.h | 108 +++++++++++++++++++++---- src/YourMoneroRequests.h | 50 ++++++++++-- src/ssqlses.h | 37 ++++++++- 4 files changed, 297 insertions(+), 67 deletions(-) diff --git a/src/MySqlConnector.h b/src/MySqlConnector.h index 2270f74..b8153bb 100644 --- a/src/MySqlConnector.h +++ b/src/MySqlConnector.h @@ -108,22 +108,25 @@ class MysqlTransactions public: bool - select(const string& address, vector& txs) + select(const uint64_t& address_id, vector& txs) { +// +// static shared_ptr query; +// +// if (!query) +// { +// Query q = MySqlConnector::getInstance().query( +// XmrTransaction::SELECT_STMT); +// q.parse(); +// query = shared_ptr(new Query(q)); +// } - static shared_ptr query; - - if (!query) - { - Query q = MySqlConnector::getInstance().query( - XmrTransaction::SELECT_STMT); - q.parse(); - query = shared_ptr(new Query(q)); - } + Query query = MySqlConnector::getInstance().query(XmrTransaction::SELECT_STMT); + query.parse(); try { - query->storein(txs, address); + query.storein(txs, address_id); if (!txs.empty()) { @@ -142,6 +145,53 @@ public: return false; } + + uint64_t + insert(const XmrTransaction& tx_data) + { + +// static shared_ptr query; +// +// if (!query) +// { +// Query q = MySqlConnector::getInstance().query(XmrTransaction::INSERT_STMT); +// q.parse(); +// query = shared_ptr(new Query(q)); +// } + + + Query query = MySqlConnector::getInstance().query(XmrTransaction::INSERT_STMT); + query.parse(); + + // cout << query << endl; + + try + { + SimpleResult sr = query.execute(tx_data.hash, + tx_data.account_id, + tx_data.total_received, + tx_data.total_sent, + tx_data.unlock_time, + tx_data.height, + tx_data.coinbase, + tx_data.payment_id, + tx_data.mixin, + tx_data.timestamp); + + if (sr.rows() == 1) + return sr.insert_id(); + + } + catch (mysqlpp::Exception& e) + { + MYSQL_EXCEPTION_MSG(e); + return 0; + } + + return 0; + } + + }; @@ -149,6 +199,8 @@ public: class MySqlAccounts { + MysqlTransactions mysql_tx; + public: @@ -156,22 +208,22 @@ public: select(const string& address, XmrAccount& account) { - static shared_ptr query; - - if (!query) - { - Query q = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT); - q.parse(); - query = shared_ptr(new Query(q)); - } +// static shared_ptr query; +// +// if (!query) +// { +// Query q = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT); +// q.parse(); +// query = shared_ptr(new Query(q)); +// } -// Query query = conn.query(XmrAccount::SELECT_STMT); -// query.parse(); + Query query = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT); + query.parse(); try { vector res; - query->storein(res, address); + query.storein(res, address); if (!res.empty()) { @@ -196,22 +248,22 @@ public: select(const int64_t& acc_id, XmrAccount& account) { - static shared_ptr query; + //static shared_ptr query; - if (!query) - { - Query q = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT2); - q.parse(); - query = shared_ptr(new Query(q)); - } +// if (!query) +// { +// Query q = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT2); +// q.parse(); +// query = shared_ptr(new Query(q)); +// } -// Query query = conn.query(XmrAccount::SELECT_STMT2); -// query.parse(); + Query query = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT2); + query.parse(); try { vector res; - query->storein(res, acc_id); + query.storein(res, acc_id); if (!res.empty()) { @@ -232,24 +284,24 @@ public: insert(const string& address, const uint64_t& scanned_block_height = 0) { - static shared_ptr query; + // static shared_ptr query; - if (!query) - { - Query q = MySqlConnector::getInstance().query(XmrAccount::INSERT_STMT); - q.parse(); - query = shared_ptr(new Query(q)); - } +// if (!query) +// { +// Query q = MySqlConnector::getInstance().query(XmrAccount::INSERT_STMT); +// q.parse(); +// query = shared_ptr(new Query(q)); +// } -// Query query = conn.query(XmrAccount::INSERT_STMT); -// query.parse(); + Query query = MySqlConnector::getInstance().query(XmrAccount::INSERT_STMT); + query.parse(); // cout << query << endl; try { - SimpleResult sr = query->execute(address, scanned_block_height); + SimpleResult sr = query.execute(address, scanned_block_height); if (sr.rows() == 1) return sr.insert_id(); @@ -264,6 +316,39 @@ public: return 0; } + uint64_t + insert_tx(const XmrTransaction& tx_data) + { + return mysql_tx.insert(tx_data); + } + + bool + select_txs(const string& xmr_address, vector& txs) + { + // having address first get its address_id + + + // a placeholder for exciting or new account data + xmreg::XmrAccount acc; + + // select this account if its existing one + if (!select(xmr_address, acc)) + { + cerr << "Address" << xmr_address << "does not exist in database" << endl; + return false; + } + + + return mysql_tx.select(acc.id, txs); + } + + bool + select_txs(const uint64_t& account_id, vector& txs) + { + return mysql_tx.select(account_id, txs); + } + + bool update(XmrAccount& acc_orginal, XmrAccount& acc_new) { diff --git a/src/TxSearch.h b/src/TxSearch.h index 33130f4..ce39864 100644 --- a/src/TxSearch.h +++ b/src/TxSearch.h @@ -89,11 +89,9 @@ public: throw TxSearchException("searched_blk_no > CurrentBlockchainStatus::current_height"); } - while(continue_search) - { + while(continue_search) { - if (searched_blk_no > CurrentBlockchainStatus::current_height) - { + if (searched_blk_no > CurrentBlockchainStatus::current_height) { fmt::print("searched_blk_no {:d} and current_height {:d}\n", searched_blk_no, CurrentBlockchainStatus::current_height); @@ -106,33 +104,34 @@ public: } // - cout << " - searching tx of: " << acc << endl; + //cout << " - searching tx of: " << acc << endl; // get block cointaining this tx block blk; - if (!CurrentBlockchainStatus::get_block(searched_blk_no, blk)) - { + if (!CurrentBlockchainStatus::get_block(searched_blk_no, blk)) { cerr << "Cant get block of height: " + to_string(searched_blk_no) << endl; - searched_blk_no =- 2; // just go back one block, and retry + searched_blk_no = -2; // just go back one block, and retry continue; } // for each tx in the given block look, get ouputs - list blk_txs; + list blk_txs; - if (!CurrentBlockchainStatus::get_block_txs(blk, blk_txs)) - { + if (!CurrentBlockchainStatus::get_block_txs(blk, blk_txs)) { throw TxSearchException("Cant get transactions in block: " + to_string(searched_blk_no)); } - - //std::lock_guard lck (mtx); - fmt::print(" - searching block {:d} of hash {:s} \n", - searched_blk_no, pod_to_hex(get_block_hash(blk))); +// if (searched_blk_no % 10 == 0) +// { +// // print status every 10th block +// +// fmt::print(" - searching block {:d} of hash {:s} \n", +// searched_blk_no, pod_to_hex(get_block_hash(blk))); +// } for (transaction& tx: blk_txs) { @@ -164,6 +163,10 @@ public: throw TxSearchException(""); } + uint64_t total_received {0}; + + bool found_mine_outputs {false}; + for (auto& out: outputs) { txout_to_key txout_k = std::get<0>(out); @@ -225,15 +228,88 @@ public: pod_to_hex(txout_k.key)); cout << msg << endl; + + + total_received += amount; + + found_mine_outputs = true; } } // for (const auto& out: outputs) + if (found_mine_outputs) + { + + crypto::hash payment_id = null_hash; + crypto::hash8 payment_id8 = null_hash8; + + get_payment_id(tx, payment_id, payment_id8); + + string payment_id_str {""}; + + if (payment_id != null_hash) + { + payment_id_str = pod_to_hex(payment_id); + } + else if (payment_id8 != null_hash8) + { + payment_id_str = pod_to_hex(payment_id8); + } + + XmrTransaction tx_data; + + tx_data.hash = pod_to_hex(tx_hash); + tx_data.account_id = acc.id; + tx_data.total_received = total_received; + tx_data.total_sent = 0; // at this stage we don't have any + // info about spendings + tx_data.unlock_time = 0; + tx_data.height = searched_blk_no; + tx_data.coinbase = is_coinbase(tx); + tx_data.payment_id = payment_id_str; + tx_data.mixin = get_mixin_no(tx) - 1; + tx_data.timestamp = XmrTransaction::timestamp_to_DateTime(blk.timestamp); + + // insert tx_data into mysql's Transactions table + uint64_t tx_mysql_id = xmr_accounts.insert_tx(tx_data); + + + // once tx was added, update Accounts table + + XmrAccount updated_acc = acc; + + updated_acc.total_received = acc.total_received + tx_data.total_received; + + if (xmr_accounts.update(acc, updated_acc)) + { + // iff success, set acc to updated_acc; + acc = updated_acc; + } + + } + + } // for (const transaction& tx: blk_txs) + + if (searched_blk_no % 10) + { + // every 10 blocks updated scanned_block_height + + XmrAccount updated_acc = acc; + + updated_acc.scanned_block_height = searched_blk_no; + + if (xmr_accounts.update(acc, updated_acc)) + { + // iff success, set acc to updated_acc; + acc = updated_acc; + } + } + ++searched_blk_no; - std::this_thread::sleep_for(std::chrono::seconds(1)); + //std::this_thread::sleep_for(std::chrono::seconds(1)); } } diff --git a/src/YourMoneroRequests.h b/src/YourMoneroRequests.h index 1e25e5a..3c7a9dd 100644 --- a/src/YourMoneroRequests.h +++ b/src/YourMoneroRequests.h @@ -183,18 +183,54 @@ public: { json j_request = body_to_json(body); -// if (show_logs) -// print_json_log("get_address_txs request: ", j_request); + if (show_logs) + print_json_log("get_address_txs request: ", j_request); + + string xmr_address = j_request["address"]; + // initializa json response json j_response { { "total_received", "0"}, - { "scanned_height", 2012455}, - { "scanned_block_height", 1195848}, - { "start_height", 2012455}, - { "transaction_height", 2012455}, - { "blockchain_height", 1195848} + { "scanned_height", 0}, + { "scanned_block_height", 0}, + { "start_height", 0}, + { "transaction_height", 0}, + { "blockchain_height", 0} }; + + // a placeholder for exciting or new account data + xmreg::XmrAccount acc; + + // select this account if its existing one + if (xmr_accounts->select(xmr_address, acc)) + { + j_response["total_received"] = acc.total_received; + j_response["scanned_block_height"] = acc.scanned_block_height; + j_response["blockchain_height"] = CurrentBlockchainStatus::get_current_blockchain_height(); + + vector txs; + + // retrive txs from mysql associated with the given address + if (xmr_accounts->select_txs(acc.id, txs)) + { + // we found some txs. + + if (!txs.empty()) + { + json j_txs = json::array(); + + for (XmrTransaction tx: txs) + { + j_txs.push_back(tx.to_json()); + } + + j_response["transactions"] = j_txs; + } + } + } + + string response_body = j_response.dump(); auto response_headers = make_headers({{ "Content-Length", to_string(response_body.size())}}); diff --git a/src/ssqlses.h b/src/ssqlses.h index 654f6aa..b45be19 100644 --- a/src/ssqlses.h +++ b/src/ssqlses.h @@ -54,6 +54,17 @@ struct XmrAccount : public Accounts using Accounts::Accounts; + XmrAccount():Accounts() + { + address = ""; + scanned_height = 0; + scanned_block_height = 0; + start_height = 0; + transaction_height = 0; + blockchain_height = 0; + total_sent = 0; + } + // viewkey is not stored in mysql db or anywhere // so need to be populated when user logs in. string viewkey; @@ -83,7 +94,7 @@ ostream& operator<< (std::ostream& os, const XmrAccount& acc) { }; -sql_create_10(Transactions, 1, 2, +sql_create_11(Transactions, 1, 2, sql_bigint_unsigned, id, sql_varchar , hash, sql_bigint_unsigned, account_id, @@ -92,6 +103,7 @@ sql_create_10(Transactions, 1, 2, sql_bigint_unsigned, unlock_time, sql_bigint_unsigned, height, sql_bool , coinbase, + sql_varchar , payment_id, sql_bigint_unsigned, mixin, sql_timestamp , timestamp); @@ -101,13 +113,26 @@ struct XmrTransaction : public Transactions { static constexpr const char* SELECT_STMT = R"( - SELECT * FROM `Transactions` WHERE `address_id` = (%0q) + SELECT * FROM `Transactions` WHERE `account_id` = (%0q) )"; static constexpr const char* SELECT_STMT2 = R"( SELECT * FROM `Transactions` WHERE `id` = (%0q) )"; + static constexpr const char* INSERT_STMT = R"( + INSERT IGNORE INTO `Transactions` (`hash`, `account_id`, `total_received`, + `total_sent`, `unlock_time`, `height`, + `coinbase`, `payment_id`, `mixin`, + `timestamp`) + VALUES (%0q, %1q, %2q, + %3q, %4q, %5q, + %6q, %7q, %8q, + %9q); + )"; + + + using Transactions::Transactions; json @@ -119,12 +144,20 @@ struct XmrTransaction : public Transactions {"total_received" , total_received}, {"total_sent" , total_sent}, {"height" , height}, + {"coinbase" , bool {coinbase}}, + {"mixin" , mixin}, {"timestamp" , timestamp} }; return j; } + static DateTime + timestamp_to_DateTime(time_t timestamp) + { + return DateTime(timestamp); + } + friend std::ostream& operator<< (std::ostream& stream, const XmrTransaction& acc); };