From b8bbedba5edd576c845203a1f5ec31ac21ab7ef4 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Mon, 21 Jan 2019 14:20:20 +0800 Subject: [PATCH] Rename YourMoneroREquest files --- main.cpp | 4 +- src/CMakeLists.txt | 8 +- src/YourMoneroRequests.cpp | 2080 ------------------------------------ src/YourMoneroRequests.h | 173 --- tests/mysql_tests.cpp | 2 +- 5 files changed, 7 insertions(+), 2260 deletions(-) delete mode 100755 src/YourMoneroRequests.cpp delete mode 100755 src/YourMoneroRequests.h diff --git a/main.cpp b/main.cpp index 63b189c..afee0cf 100755 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,7 @@ #include "src/om_log.h" #include "src/CmdLineOptions.h" #include "src/MicroCore.h" -#include "src/YourMoneroRequests.h" +#include "src/OpenMoneroRequests.h" #include "src/ThreadRAII.h" #include "src/db/MysqlPing.h" @@ -218,7 +218,7 @@ std::thread mysql_ping_thread( OMINFO << "MySQL ping thread started"; // create REST JSON API services -xmreg::YourMoneroRequests open_monero(mysql_accounts, current_bc_status); +xmreg::OpenMoneroRequests open_monero(mysql_accounts, current_bc_status); // create Open Monero APIs MAKE_RESOURCE(login); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 79649de..c4a4c15 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,10 +7,10 @@ set(SOURCE_FILES tools.cpp CmdLineOptions.cpp CurrentBlockchainStatus.cpp - db/MySqlConnector.cpp - db/MySqlAccounts.cpp - db/ssqlses.cpp - YourMoneroRequests.cpp + db/MySqlConnector.cpp + db/MySqlAccounts.cpp + db/ssqlses.cpp + OpenMoneroRequests.cpp TxSearch.cpp RPCCalls.cpp OutputInputIdentification.cpp diff --git a/src/YourMoneroRequests.cpp b/src/YourMoneroRequests.cpp deleted file mode 100755 index 72874e1..0000000 --- a/src/YourMoneroRequests.cpp +++ /dev/null @@ -1,2080 +0,0 @@ -// -// Created by mwo on 8/01/17. -// - -#define MYSQLPP_SSQLS_NO_STATICS 1 - - -#include "YourMoneroRequests.h" - -#include "db/ssqlses.h" -#include "OutputInputIdentification.h" - -namespace xmreg -{ - - -handel_::handel_(const fetch_func_t& callback): - request_callback {callback} -{} - -void -handel_::operator()(const shared_ptr< Session > session) -{ - const auto request = session->get_request( ); - size_t content_length = request->get_header( "Content-Length", 0); - session->fetch(content_length, this->request_callback); -} - - - -YourMoneroRequests::YourMoneroRequests( - shared_ptr _acc, - shared_ptr _current_bc_status): - xmr_accounts {_acc}, current_bc_status {_current_bc_status} -{ - -} - - -void -YourMoneroRequests::login(const shared_ptr session, const Bytes & body) -{ - json j_response; - json j_request; - - vector required_values {"address", "view_key"}; - - if (!parse_request(body, required_values, j_request, j_response)) - { - session_close(session, j_response); - return; - } - - string xmr_address; - string view_key; - - try - { - xmr_address = j_request["address"]; - view_key = j_request["view_key"]; - } - catch (json::exception const& e) - { - cerr << "json exception: " << e.what() << '\n'; - session_close(session, j_response); - return; - } - - // a placeholder for exciting or new account data - XmrAccount acc; - - uint64_t acc_id {0}; - - // marks if this is new account creation or not - bool new_account_created {false}; - - // first check if new account - // select this account if its existing one - if (!xmr_accounts->select(xmr_address, acc)) - { - // account does not exist, so create new one - // for this address - - uint64_t current_blockchain_height = get_current_blockchain_height(); - - // initialize current blockchain timestamp with current time - // in a moment we will try to get last block timestamp - // to replace this value. But if it fails, we just use current - // timestamp - uint64_t current_blockchain_timestamp = std::time(nullptr); - - // get last block so we have its timestamp when - // createing the account - block last_blk; - - if (current_bc_status->get_block(current_blockchain_height, last_blk)) - { - current_blockchain_timestamp = last_blk.timestamp; - } - - DateTime blk_timestamp_mysql_format - = XmrTransaction::timestamp_to_DateTime( - current_blockchain_timestamp); - - - // create new account - XmrAccount new_account( - mysqlpp::null, - xmr_address, - make_hash(view_key), - current_blockchain_height, /* for scanned_block_height */ - blk_timestamp_mysql_format, - current_blockchain_height); - - // insert the new account into the mysql - if ((acc_id = xmr_accounts->insert(new_account)) == 0) - { - // if creating account failed - j_response = json {{"status", "error"}, - {"reason", "Account creation failed"}}; - - session_close(session, j_response); - return; - } - - // set this flag to indicate that we have just created a - // new account in mysql. this information is sent to front-end - // as it can disply some greeting window to new users upon - // their first install - new_account_created = true; - - } // if (!xmr_accounts->select(xmr_address, acc)) - - - // so by now new account has been created or it already exists - // so we just login into it. - - if (login_and_start_search_thread(xmr_address, view_key, acc, j_response)) - { - // if successfuly logged in and created search thread - j_response["status"] = "success"; - - // we overwrite what ever was sent in login_and_start_search_thread - // for the j_response["new_address"]. - j_response["new_address"] = new_account_created; - } - else - { - // some error with loggin in or search thread start - session_close(session, j_response); - return; - - } // else if (login_and_start_search_thread(xmr_address, - - - session_close(session, j_response); -} - -void -YourMoneroRequests::get_address_txs( - const shared_ptr< Session > session, const Bytes & body) -{ - json j_response; - json j_request; - - vector requested_values {"address", "view_key"}; - - if (!parse_request(body, requested_values, j_request, j_response)) - { - session_close(session, j_response); - return; - } - - string xmr_address; - string view_key; - - try - { - xmr_address = j_request["address"]; - view_key = j_request["view_key"]; - } - catch (json::exception const& e) - { - OMERROR << "json exception: " << e.what(); - session_close(session, j_response, UNPROCESSABLE_ENTITY); - return; - } - - // make hash of the submited viewkey. we only store - // hash of viewkey in database, not acctual viewkey. - string viewkey_hash = make_hash(view_key); - - // initialize json response - j_response = json { - {"total_received" , 0}, // calculated in this function - {"total_received_unlocked", 0}, // calculated in this function - {"scanned_height" , 0}, // not used. just to match mymonero - {"scanned_block_height" , 0}, // taken from Accounts table - {"scanned_block_timestamp", 0}, // taken from Accounts table - {"start_height" , 0}, // blockchain height whencreated - {"blockchain_height" , 0}, // current blockchain height - {"transactions" , json::array()} - }; - - // a placeholder for exciting or new account data - xmreg::XmrAccount acc; - - // for this to continue, search thread must have already been - // created and still exisits. -// if (current_bc_status->search_thread_exist(xmr_address)) -// { - if (login_and_start_search_thread(xmr_address, view_key, acc, j_response)) - { - // populate acc and check view_key -// if (!login_and_start_search_thread(xmr_address, view_key, acc, j_response)) -// { -// // some error with loggin in or search thread start -// session_close(session, j_response.dump()); -// return; -// } - - // before fetching txs, check if provided view key - // is correct. this is simply to ensure that - // we cant fetch an account's txs using only address. - // knowlage of the viewkey is also needed. - - - - uint64_t total_received {0}; - uint64_t total_received_unlocked {0}; - - j_response["total_received"] = total_received; - j_response["start_height"] = acc.start_height; - j_response["scanned_block_height"] = acc.scanned_block_height; - j_response["scanned_block_timestamp"] = static_cast( - acc.scanned_block_timestamp); - j_response["blockchain_height"] = get_current_blockchain_height(); - - vector txs; - - xmr_accounts->select(acc.id.data, txs); - - if (xmr_accounts->select_txs_for_account_spendability_check( - acc.id.data, txs)) - { - json j_txs = json::array(); - - for (XmrTransaction const& tx: txs) - { - json j_tx { - {"id" , tx.blockchain_tx_id}, - {"coinbase" , bool {tx.coinbase}}, - {"tx_pub_key" , tx.tx_pub_key}, - {"hash" , tx.hash}, - {"height" , tx.height}, - {"mixin" , tx.mixin}, - {"payment_id" , tx.payment_id}, - {"unlock_time" , tx.unlock_time}, - {"total_sent" , 0}, // to be field when checking for spent_outputs below - {"total_received" , std::to_string(tx.total_received)}, - {"timestamp" , static_cast(tx.timestamp)*1000}, - {"mempool" , false} // tx in database are never from mempool - }; - - vector inputs; - - if (xmr_accounts->select_for_tx(tx.id.data, inputs)) - { - json j_spent_outputs = json::array(); - - uint64_t total_spent {0}; - - for (XmrInput input: inputs) - { - XmrOutput out; - - if (xmr_accounts->select_by_primary_id( - input.output_id, out)) - { - total_spent += input.amount; - - j_spent_outputs.push_back({ - {"amount" , std::to_string(input.amount)}, - {"key_image" , input.key_image}, - {"tx_pub_key" , out.tx_pub_key}, - {"out_index" , out.out_index}, - {"mixin" , out.mixin}}); - } - } - - j_tx["total_sent"] = std::to_string(total_spent); - - j_tx["spent_outputs"] = j_spent_outputs; - - } // if (xmr_accounts->select_inputs_for_tx(tx.id, inputs)) - - total_received += tx.total_received; - - if (bool {tx.spendable}) - { - total_received_unlocked += tx.total_received; - } - - j_txs.push_back(j_tx); - - } // for (XmrTransaction tx: txs) - - j_response["total_received"] = std::to_string(total_received); - j_response["total_received_unlocked"] = std::to_string(total_received_unlocked); - - j_response["transactions"] = j_txs; - - } // if (xmr_accounts->select_txs_for_ac - - } // if (current_bc_status->search_thread_exist(xmr_address)) - else - { - j_response = json {{"status", "error"}, - {"reason", "Search thread does not exist."}}; - - // some error with loggin in or search thread start - session_close(session, j_response); - return; - } - - // append txs found in mempool to the json returned - - json j_mempool_tx; - - if (current_bc_status->find_txs_in_mempool( - xmr_address, j_mempool_tx)) - { - if(!j_mempool_tx.empty()) - { - uint64_t total_received_mempool {0}; - uint64_t total_sent_mempool {0}; - - // get last tx id (i.e., index) so that we can - // set some ids for the mempool txs. These ids are - // used for sorting in the frontend. Since we want mempool - // tx to be first, they need to be higher than last_tx_id_db - uint64_t last_tx_id_db {0}; - - if (!j_response["transactions"].empty()) - { - last_tx_id_db = j_response["transactions"].back()["id"]; - } - - - for (json& j_tx: j_mempool_tx) - { - //cout << "mempool j_tx[\"total_received\"]: " - // << j_tx["total_received"] << endl; - - j_tx["id"] = ++last_tx_id_db; - - total_received_mempool += boost::lexical_cast( - j_tx["total_received"].get()); - total_sent_mempool += boost::lexical_cast( - j_tx["total_sent"].get()); - - j_response["transactions"].push_back(j_tx); - } - - // we account for mempool txs when providing final - // unlocked and locked balances. - - j_response["total_received"] - = std::to_string( - boost::lexical_cast( - j_response["total_received"].get()) - + total_received_mempool - total_sent_mempool); - - j_response["total_received_unlocked"] - = std::to_string( - boost::lexical_cast( - j_response["total_received_unlocked"].get()) - + total_received_mempool - total_sent_mempool); - } - - } - - 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_address_info( - const shared_ptr< Session > session, const Bytes & body) -{ - json j_response; - json j_request; - - vector requested_values {"address" , "view_key"}; - - if (!parse_request(body, requested_values, j_request, j_response)) - { - session_close(session, j_response); - return; - } - - string xmr_address; - string view_key; - - try - { - xmr_address = j_request["address"]; - view_key = j_request["view_key"]; - } - catch (json::exception const& e) - { - cerr << "json exception: " << e.what() << '\n'; - session_close(session, j_response); - return; - } - - // make hash of the submited viewkey. we only store - // hash of viewkey in database, not acctual viewkey. - string viewkey_hash = make_hash(view_key); - - j_response = json { - {"locked_funds" , "0"}, // locked xmr (e.g., younger than 10 blocks) - {"total_received" , "0"}, // calculated in this function - {"total_sent" , "0"}, // calculated in this function - {"scanned_height" , 0}, // not used. it is here to match mymonero - {"scanned_block_height" , 0}, // taken from Accounts table - {"scanned_block_timestamp", 0}, // taken from Accounts table - {"start_height" , 0}, // not used, but available in Accounts table. - // it is here to match mymonero - {"blockchain_height" , 0}, // current blockchain height - {"spent_outputs" , nullptr} // list of spent outputs that we think - // user has spent. client side will - // filter out false positives since - // only client has spent key - }; - - // a placeholder for exciting or new account data - xmreg::XmrAccount acc; - - // for this to continue, search thread must have already been - // created and still exisits. - if (login_and_start_search_thread(xmr_address, view_key, acc, j_response)) - { - uint64_t total_received {0}; - - // ping the search thread that we still need it. - // otherwise it will finish after some time. - current_bc_status->ping_search_thread(xmr_address); - - uint64_t current_searched_blk_no {0}; - - if (current_bc_status->get_searched_blk_no( - xmr_address, current_searched_blk_no)) - { - // if current_searched_blk_no is higher than what is in mysql, update it - // in the search thread. This may occure when manually editing scanned_block_height - // in Accounts table to import txs or rescan txs. - // we use the minumum difference of 10 blocks, for this update to happen - - if (current_searched_blk_no > acc.scanned_block_height + 10) - { - current_bc_status->set_new_searched_blk_no( - xmr_address, acc.scanned_block_height); - } - } - - j_response["total_received"] = std::to_string(total_received); - j_response["start_height"] = acc.start_height; - j_response["scanned_block_height"] = acc.scanned_block_height; - j_response["scanned_block_timestamp"] - = static_cast(acc.scanned_block_timestamp); - j_response["blockchain_height"] = get_current_blockchain_height(); - - uint64_t total_sent {0}; - - vector txs; - - // get all txs of for the account - xmr_accounts->select(acc.id.data, txs); - - // now, filter out or updated transactions from txs vector that no - // longer exisit in the recent blocks. Update is done to check for their - // spendability status. - if (xmr_accounts->select_txs_for_account_spendability_check( - acc.id.data, txs)) - { - json j_spent_outputs = json::array(); - - for (XmrTransaction tx: txs) - { - vector outs; - - if (xmr_accounts->select_for_tx(tx.id.data, outs)) - { - for (XmrOutput &out: outs) - { - // check if the output, has been spend - vector ins; - - if (xmr_accounts->select_inputs_for_out( - out.id.data, ins)) - { - for (XmrInput& in: ins) - { - j_spent_outputs.push_back({ - {"amount" , std::to_string(in.amount)}, - {"key_image" , in.key_image}, - {"tx_pub_key" , out.tx_pub_key}, - {"out_index" , out.out_index}, - {"mixin" , out.mixin}, - }); - - total_sent += in.amount; - } - } - - total_received += out.amount; - - } // for (XmrOutput &out: outs) - - } // if (xmr_accounts->select_outputs_for_tx(tx.id, outs)) - - } // for (XmrTransaction tx: txs) - - - j_response["total_received"] = std::to_string(total_received); - j_response["total_sent"] = std::to_string(total_sent); - - j_response["spent_outputs"] = j_spent_outputs; - - } // if (xmr_accounts->select_txs_for_account_spendability_check(acc.id, txs)) - - } // if (current_bc_status->search_thread_exist(xmr_address)) - else - { - j_response = json {{"status", "error"}, - {"reason", "Search thread does not exist."}}; - - // some error with loggin in or search thread start - session_close(session, j_response); - return; - } - - 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_unspent_outs( - const shared_ptr< Session > session, - const Bytes & body) -{ - json j_response; - json j_request; - - vector requested_values {"address" , "view_key", "mixin", - "use_dust", "dust_threshold", "amount"}; - - if (!parse_request(body, requested_values, j_request, j_response)) - { - session_close(session, j_response); - return; - } - - string xmr_address; - string view_key; - uint64_t mixin {4}; - bool use_dust {false}; - uint64_t dust_threshold {1000000000}; - uint64_t amount {0}; - - try - { - xmr_address = j_request["address"]; - view_key = j_request["view_key"]; - - mixin = j_request["mixin"]; - use_dust = j_request["use_dust"]; - - dust_threshold = boost::lexical_cast( - j_request["dust_threshold"].get()); - amount = boost::lexical_cast( - j_request["amount"].get()); - } - catch (json::exception const& e) - { - cerr << "json exception: " << e.what() << '\n'; - session_close(session, j_response); - return; - } - catch (boost::bad_lexical_cast const& e) - { - cerr << "Bed lexical cast" << e.what() << '\n'; - session_close(session, j_response); - return; - } - - // make hash of the submited viewkey. we only store - // hash of viewkey in database, not acctual viewkey. - string viewkey_hash = make_hash(view_key); - - j_response = json { - {"amount" , "0"}, // total value of the outputs - {"outputs", json::array()} // list of outputs - // exclude those without require - // no of confirmation - }; - - // a placeholder for exciting or new account data - xmreg::XmrAccount acc; - - // select this account if its existing one - - // for this to continue, search thread must have already been - // created and still exisits. - if (current_bc_status->search_thread_exist(xmr_address)) - { - // populate acc and check view_key - if (!login_and_start_search_thread(xmr_address, view_key, acc, j_response)) - { - // some error with loggin in or search thread start - session_close(session, j_response); - return; - } - - uint64_t total_outputs_amount {0}; - -// uint64_t current_blockchain_height -// = current_bc_status->get_current_blockchain_height(); - - vector txs; - - // retrieve txs from mysql associated with the given address - if (xmr_accounts->select(acc.id.data, txs)) - { - // we found some txs. - - json& j_outputs = j_response["outputs"]; - - for (XmrTransaction& tx: txs) - { - // we skip over locked outputs - // as they cant be spent anyway. - // thus no reason to return them to the frontend - // for constructing a tx. - - if (!current_bc_status->is_tx_unlocked( - tx.unlock_time, tx.height)) - { - continue; - } - -// if (!bool {tx.coinbase}) -// { -// continue; -// } - - vector outs; - - if (xmr_accounts->select_for_tx(tx.id.data, outs)) - { - for (XmrOutput &out: outs) - { - // skip outputs considered as dust - if (out.amount < dust_threshold) - { - continue; - } - - // need to check for rct commintment - // coinbase ringct txs dont have - // rct filed in them. Thus - // we need to make them. - - uint64_t global_amount_index = out.global_index; - - string rct = out.get_rct(); - - // coinbase rct txs require speciall treatment - if (tx.coinbase && tx.is_rct) - { - uint64_t amount = (tx.is_rct ? 0 : out.amount); - - output_data_t od = - current_bc_status->get_output_key( - amount, global_amount_index); - - string rtc_outpk = pod_to_hex(od.commitment); - string rtc_mask = pod_to_hex(rct::identity()); - string rtc_amount(64, '0'); - - rct = rtc_outpk + rtc_mask + rtc_amount; - } - - json j_out{ - {"amount" , std::to_string(out.amount)}, - {"public_key" , out.out_pub_key}, - {"index" , out.out_index}, - {"global_index" , out.global_index}, - {"rct" , rct}, - {"tx_id" , out.tx_id}, - {"tx_hash" , tx.hash}, - {"tx_prefix_hash" , tx.prefix_hash}, - {"tx_pub_key" , tx.tx_pub_key}, - {"timestamp" , static_cast( - out.timestamp*1e3)}, - {"height" , tx.height}, - {"spend_key_images", json::array()} - }; - - vector ins; - - if (xmr_accounts->select_inputs_for_out( - out.id.data, ins)) - { - json& j_ins = j_out["spend_key_images"]; - - for (XmrInput& in: ins) - { - j_ins.push_back(in.key_image); - } - } - - j_outputs.push_back(j_out); - - total_outputs_amount += out.amount; - - } //for (XmrOutput &out: outs) - - } // if (xmr_accounts->select_outputs_for_tx(tx.id, outs)) - - } // for (XmrTransaction& tx: txs) - - } // if (xmr_accounts->select_txs(acc.id, txs)) - - j_response["amount"] = std::to_string(total_outputs_amount); - - - // need proper per_kb_fee estimate as - // it is already using dynanamic fees. frontend - // uses old fixed fees. - - j_response["per_byte_fee"] = current_bc_status - ->get_dynamic_base_fee_estimate(); - - - } // if (current_bc_status->search_thread_exist(xmr_address)) - else - { - j_response = json {{"status", "error"}, - {"reason", "Search thread does not exist."}}; - - // some error with loggin in or search thread start - session_close(session, j_response); - return; - - } - - 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_random_outs( - const shared_ptr< Session > session, const Bytes & body) -{ - json j_request; - json j_response; - - vector requested_values; - - if (!parse_request(body, requested_values, j_request, j_response)) - { - session_close(session, j_response); - return; - } - - uint64_t count; - - try - { - count = j_request["count"]; - } - catch (json::exception const& e) - { - cerr << "json exception: " << e.what() << '\n'; - session_close(session, j_response); - return; - }; - - if (count > 41) - { - cerr << "Request ring size too big" << '\n'; - j_response["status"] = "error"; - j_response["error"] = fmt::format("Request ring size {:d} too large", - count); - session_close(session, j_response); - } - - vector amounts; - - try - { - // populate amounts vector so that we can pass it directly to - // daeamon to get random outputs for these amounts - for (json amount: j_request["amounts"]) - { - amounts.push_back(boost::lexical_cast( - amount.get())); - - // amounts.push_back(0); - } - } - catch (boost::bad_lexical_cast& e) - { - cerr << "Bed lexical cast" << '\n'; - session_close(session, j_response); - return; - } - - vector found_outputs; - - if (current_bc_status->get_random_outputs(amounts, count, found_outputs)) - { - json& j_amount_outs = j_response["amount_outs"]; - - for (const auto& outs: found_outputs) - { - json j_outs {{"amount", std::to_string(outs.amount)}, - {"outputs", json::array()}}; - - - json& j_outputs = j_outs["outputs"]; - - for (auto const& out: outs.outs) - { - tuple - rct_field = current_bc_status - ->construct_output_rct_field( - out.global_amount_index, outs.amount); - - string rct = std::get<0>(rct_field) // rct_pk - + std::get<1>(rct_field) // rct_mask - + std::get<2>(rct_field); // rct_amount - - json out_details { - {"global_index", out.global_amount_index}, - {"public_key" , pod_to_hex(out.out_key)}, - {"rct" , rct} - }; - - j_outputs.push_back(out_details); - - } // for (const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AM - - j_amount_outs.push_back(j_outs); - - } // for (const COMMAND_RPC_GET_RANDOM_OUTPUTS_ - - } // if (current_bc_status->get_random_outputs(amounts, - else - { - j_response["status"] = "error"; - j_response["error"] = fmt::format("Error getting random " - "outputs from monero deamon"); - } - - 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::submit_raw_tx( - const shared_ptr< Session > session, const Bytes & body) -{ - json j_request = body_to_json(body); - - string raw_tx_blob = j_request["tx"]; - - json j_response; - - string error_msg; - - // before we submit the tx into the deamon, we are going to do a few checks. - // first, we parse the hexbuffer submmited by the frontend into - // binary buffer block - // second, we are going to check if we can construct - // valid transaction object - // fromt that binary buffer. - // third, we are going to check if any key image in this tx is - // in any of the txs - // in the mempool. This allows us to make a clear comment that the tx - // uses outputs just spend. This happens we a users submits few txs, - // one after another - // before previous txs get included in a block and are still - // present in the mempool. - - std::string tx_blob; - - if(!epee::string_tools::parse_hexstr_to_binbuff(raw_tx_blob, tx_blob)) - { - j_response["status"] = "error"; - j_response["Error"] = "Tx faild parse_hexstr_to_binbuff"; - - OMERROR << j_response["Error"]; - - session_close(session, j_response, - UNPROCESSABLE_ENTITY); - return; - } - - transaction tx_to_be_submitted; - - if (!parse_and_validate_tx_from_blob(tx_blob, tx_to_be_submitted)) - { - j_response["status"] = "error"; - j_response["Error"] = "Tx faild parse_and_validate_tx_from_blob"; - - OMERROR << j_response["Error"]; - - session_close(session, j_response, - UNPROCESSABLE_ENTITY); - return; - } - - if (current_bc_status->find_key_images_in_mempool(tx_to_be_submitted)) - { - j_response["status"] = "error"; - j_response["Error"] = "Tx uses your outputs that area already " - "in the mempool. " - "Please wait till your previous tx(s) " - "get mined"; - - OMERROR << j_response["Error"]; - - session_close(session, j_response, - UNPROCESSABLE_ENTITY); - return; - } - - if (!current_bc_status->commit_tx( - raw_tx_blob, error_msg, - current_bc_status->get_bc_setup().do_not_relay)) - { - j_response["status"] = "error"; - j_response["Error"] = error_msg; - - OMERROR << j_response["Error"]; - - session_close(session, j_response, - UNPROCESSABLE_ENTITY); - return; - } - - j_response["status"] = "success"; - - - 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::import_wallet_request( - const shared_ptr< Session > session, const Bytes & body) -{ - - json j_response; - json j_request; - - vector requested_values {"address" , "view_key"}; - - if (!parse_request(body, requested_values, - j_request, j_response)) - { - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "Cant parse json body!"); - return; - } - - string xmr_address; - string view_key; - - try - { - xmr_address = j_request["address"]; - view_key = j_request["view_key"]; - } - catch (json::exception const& e) - { - OMERROR << "json exception: " << e.what(); - session_close(session, j_response, UNPROCESSABLE_ENTITY, - e.what()); - return; - } - - - j_response["request_fulfilled"] = false; - j_response["import_fee"] = std::to_string( - current_bc_status->get_bc_setup() - .import_fee); - j_response["status"] = "error"; - j_response["error"] = "Some error occured"; - - // get account from mysql db if exists - auto xmr_account = select_account(xmr_address); - - if (!xmr_account) - { - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "The account does not exists!"); - return; - } - - // if import_fee is zero, we just import the wallet. - // we dont care about any databases or anything, as importing - // wallet is free. - // just reset the scanned block height in mysql and finish. - if (current_bc_status->get_bc_setup().import_fee == 0) - { - // change search blk number in the search thread - if (!current_bc_status->set_new_searched_blk_no(xmr_address, 0)) - { - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "Updating searched_blk_no failed!"); - return; - } - - j_response["request_fulfilled"] = true; - j_response["status"] = "Import will start shortly"; - j_response["new_request"] = true; - j_response["error"] = ""; - - session_close(session, j_response); - - return; - } - - // payment fee is not zero, so we need to - // ask for the payment. So we first get payment details - // associated with the given account. - - auto xmr_payment = select_payment(*xmr_account); - - // something went wrong. - if (!xmr_payment) - { - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "Selecting payment details failed!"); - return; - } - - // payment id is null - if (xmr_payment->id == mysqlpp::null) - { - // no current payment record exist, - // so we have to create new one. - - // payment request is new, so create its entry in - // Payments table - - uint64_t payment_table_id {0}; - - crypto::hash8 random_payment_id8 = crypto::rand(); - - string integrated_address = - current_bc_status->get_account_integrated_address_as_str( - random_payment_id8); - - xmr_payment->account_id = xmr_account->id.data; - xmr_payment->payment_id = pod_to_hex(random_payment_id8); - xmr_payment->import_fee = current_bc_status - ->get_bc_setup().import_fee; // xmr - xmr_payment->request_fulfilled = false; - xmr_payment->tx_hash = ""; // no tx_hash yet with the payment - xmr_payment->payment_address = integrated_address; - - if ((payment_table_id = xmr_accounts->insert(*xmr_payment)) == 0) - { - OMERROR << xmr_address.substr(0, 6) - + ": failed to create new payment record!"; - - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "Failed to create new payment record!"); - return; - } - - // payment entry created - - j_response["payment_id"] = payment_table_id; - j_response["import_fee"] = std::to_string( - xmr_payment->import_fee); - j_response["new_request"] = true; - j_response["request_fulfilled"] - = bool {xmr_payment->request_fulfilled}; - j_response["payment_address"] = xmr_payment->payment_address; - j_response["status"] = "Payment not yet received"; - j_response["error"] = ""; - - session_close(session, j_response); - return; - } // if (xmr_payment->id == mysqlpp::null) - - // payment id is not null, so it means that - // we have already payment record in our db for that - // account. - - bool request_fulfilled = bool {xmr_payment->request_fulfilled}; - - if (request_fulfilled) - { - // if payment has been made, and we get new request to import txs - // indicate that this is new requeest, but request was fulfiled. - // front end should give proper message in this case - - j_response["request_fulfilled"] = request_fulfilled; - j_response["status"] = "Wallet already imported or " - "in the progress."; - j_response["new_request"] = false; - j_response["error"] = ""; - - session_close(session, j_response); - return; - } - - // payment has not been yet done, so we are going - // to check if it has just been done and update - // db accordingly - - string integrated_address = - current_bc_status->get_account_integrated_address_as_str( - xmr_payment->payment_id); - - if (integrated_address.empty()) - { - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "get_account_integrated_address_as_str failed!"); - return; - } - - j_response["payment_id"] = xmr_payment->payment_id; - j_response["import_fee"] = std::to_string(xmr_payment->import_fee); - j_response["new_request"] = false; - j_response["request_fulfilled"] = request_fulfilled; - j_response["payment_address"] = integrated_address; - j_response["status"] = "Payment not yet received"; - - string tx_hash_with_payment; - - // if payment has not yet been done - // check if it has just been done now - // if yes, mark it in mysql - - if(current_bc_status->search_if_payment_made( - xmr_payment->payment_id, - xmr_payment->import_fee, - tx_hash_with_payment)) - { - XmrPayment updated_xmr_payment = *xmr_payment; - - // updated values - updated_xmr_payment.request_fulfilled = true; - updated_xmr_payment.tx_hash = tx_hash_with_payment; - - // save to mysql - if (!xmr_accounts->update(*xmr_payment, updated_xmr_payment)) - { - - OMERROR << xmr_address.substr(0,6) + - "Updating payment db failed!\n"; - - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "Updating payment db failed!"); - return; - } - - XmrAccount updated_acc = *xmr_account; - - updated_acc.scanned_block_height = 0; - - // set scanned_block_height to 0 to begin - // scanning entire blockchain - - if (!xmr_accounts->update(*xmr_account, updated_acc)) - { - OMERROR << xmr_address.substr(0,6) + - "Updating scanned_block_height failed!\n"; - - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "Updating scanned_block_height failed!"); - return; - } - - // if success, set acc to updated_acc; - request_fulfilled = true; - - // change search blk number in the search thread - if (!current_bc_status - ->set_new_searched_blk_no(xmr_address, 0)) - { - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "updating searched_blk_no failed!"); - return; - - } - - j_response["request_fulfilled"] - = request_fulfilled; - j_response["status"] - = "Payment received. Thank you."; - j_response["new_request"] = true; - j_response["error"] = ""; - - } // if(current_bc_status->search_if_payment_made( - - - session_close(session, j_response); -} - - - -void -YourMoneroRequests::import_recent_wallet_request( - const shared_ptr< Session > session, const Bytes & body) -{ - json j_response; - json j_request; - - bool request_fulfilled {false}; - - j_response["request_fulfilled"] = false; - - vector requested_values {"address" , "view_key", - "no_blocks_to_import"}; - - if (!parse_request(body, requested_values, - j_request, j_response)) - { - session_close(session, j_response, UNPROCESSABLE_ENTITY, - "Cant parse json body!"); - return; - } - - string xmr_address; - string view_key; - - try - { - xmr_address = j_request["address"]; - view_key = j_request["view_key"]; - } - catch (json::exception const& e) - { - OMERROR << "json exception: " << e.what(); - session_close(session, j_response, UNPROCESSABLE_ENTITY, - e.what()); - return; - } - - uint64_t no_blocks_to_import {1000}; - - try - { - no_blocks_to_import - = boost::lexical_cast( - j_request["no_blocks_to_import"].get()); - } - catch (boost::bad_lexical_cast& e) - { - string msg = "Cant parse " - + j_request["no_blocks_to_import"].get() - + " into number"; - - cerr << msg << '\n'; - - j_response["Error"] = msg; - session_close(session, j_response); - return; - } - - // make sure that we dont import more that the maximum alowed no of blocks - no_blocks_to_import = std::min(no_blocks_to_import, - current_bc_status->get_bc_setup() - .max_number_of_blocks_to_import); - - no_blocks_to_import - = std::min(no_blocks_to_import, - current_bc_status->get_current_blockchain_height()); - - XmrAccount acc; - - if (xmr_accounts->select(xmr_address, acc)) - { - XmrAccount updated_acc = acc; - - // make sure scanned_block_height is larger than - // no_blocks_to_import so we dont - // end up with overflowing uint64_t. - - if (updated_acc.scanned_block_height >= no_blocks_to_import) - { - // repetead calls to import_recent_wallet_request will be - // moving the scanning backward. - // not sure yet if any protection is needed to - // make sure that a user does not - // go back too much back by importing his/hers - // wallet multiple times in a row. - updated_acc.scanned_block_height - = updated_acc.scanned_block_height - no_blocks_to_import; - - if (xmr_accounts->update(acc, updated_acc)) - { - // change search blk number in the search thread - if (!current_bc_status - ->set_new_searched_blk_no(xmr_address, - updated_acc.scanned_block_height)) - { - cerr << "Updating searched_blk_no failed!" << endl; - j_response["Error"] = "Updating searched_blk_no failed!"; - } - else - { - // if success, makre that request was successful; - request_fulfilled = true; - } - } - - } // if (updated_acc.scanned_block_height > no_blocks_to_import) - } - else - { - cerr << "Updating account with new scanned_block_height failed!\n"; - j_response["status"] - = "Updating account with new scanned_block_height failed!"; - } - - if (request_fulfilled) - { - j_response["request_fulfilled"] = request_fulfilled; - j_response["status"] = "Updating account with for" - " importing recent txs successeful."; - } - - string response_body = j_response.dump(); - - auto response_headers = make_headers({{ "Content-Length", - std::to_string(response_body.size())}}); - - session->close( OK, response_body, response_headers); -} - - - -void -YourMoneroRequests::get_tx( - const shared_ptr< Session > session, const Bytes & body) -{ - json j_response; - json j_request; - - vector requested_values {"address" , "view_key", "tx_hash"}; - - if (!parse_request(body, requested_values, j_request, j_response)) - { - session_close(session, j_response); - return; - } - - string xmr_address; - string view_key; - string tx_hash_str; - - try - { - xmr_address = j_request["address"]; - view_key = j_request["view_key"]; - tx_hash_str = j_request["tx_hash"]; - } - catch (json::exception const& e) - { - cerr << "json exception: " << e.what() << '\n'; - session_close(session, j_response); - return; - } - - 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); - return; - } - - transaction tx; - - uint64_t default_timestamp {0}; - - bool tx_found {false}; - - bool tx_in_mempool {false}; - - if (!current_bc_status->get_tx(tx_hash, tx)) - { - // if tx not found in the blockchain, check if its in mempool - - // recieved_time, tx - vector> mempool_txs = - current_bc_status->get_mempool_txs(); - - //cout << "serach mempool" << endl; - - for (auto const& mtx: mempool_txs) - { - //cout << (get_transaction_hash(mtx.second)) << '\n'; - - if (get_transaction_hash(mtx.second) == tx_hash) - { - tx = mtx.second; - tx_found = true; - tx_in_mempool = true; - default_timestamp = mtx.first; - break; - } - } - } - 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 {0}; - uint64_t mixin_no; - uint64_t size; - - // 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; - j_response["num_of_outputs"] = output_pub_keys.size(); - j_response["num_of_inputs"] = input_key_imgs.size(); - - 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; - - // to be field later on using data from OutputInputIdentification - j_response["total_sent"] = "0"; - j_response["total_received"] = "0"; - - int64_t tx_height {-1}; - - int64_t no_confirmations {-1}; - - if (current_bc_status->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; - } - - // Class that is responsible for identification of our outputs - // and inputs in a given tx. - - j_response["payment_id"] = string {}; - j_response["timestamp"] = default_timestamp; - - address_parse_info address_info; - secret_key viewkey; - - // to get info about recived xmr in this tx, we calculate it from - // scrach, i.e., search for outputs. We could get this info - // directly from the database, but doing it again here, is a good way - // to double check tx data in the frontend, and also maybe try doing - // it differently than before. Its not great, since we reinvent - // the wheel - // but its worth double checking - // the mysql data, and also allows for new - // implementation in the frontend. - if (current_bc_status->get_xmr_address_viewkey( - xmr_address, address_info, viewkey)) - { - OutputInputIdentification oi_identification { - &address_info, &viewkey, &tx, tx_hash, - coinbase}; - - oi_identification.identify_outputs(); - - uint64_t total_received {0}; - - // we just get total amount recieved. we have viewkey, - // so this must be correct and front end does not - // need to do anything to check this. - for (auto& out_info: oi_identification.identified_outputs) - { - total_received += out_info.amount; - } - - j_response["total_received"] = std::to_string(total_received); - - json j_spent_outputs = json::array(); - - // to get spendings, we need to have our key_images. but - // the backend does not have spendkey, so it cant determine - // which key images are really ours or not. this is the task - // for the frontend. however, backend can only provide guesses and - // nessessery data to the frontend to filter out incorrect - // guesses. - // - // for input identification, we will use our mysql. its just much - // faster to use it here, than before. but first we need to - // get account id of the user asking for tx details. - - // a placeholder for exciting or new account data - XmrAccount acc; - - // select this account if its existing one - if (xmr_accounts->select(xmr_address, acc)) - { - // if user exist, get tx data from database - // this will work only for tx in the blockchain, - // not those in the mempool. - - if (!tx_in_mempool) - { - // if not in mempool, but in blockchain, just - // get data aout key images from the mysql - - XmrTransaction xmr_tx; - - if (xmr_accounts->tx_exists( - acc.id.data, tx_hash_str, xmr_tx)) - { - j_response["payment_id"] = xmr_tx.payment_id; - j_response["timestamp"] - = static_cast(xmr_tx.timestamp*1e3); - - vector inputs; - - if (xmr_accounts->select_for_tx( - xmr_tx.id.data, inputs)) - { - json j_spent_outputs = json::array(); - - uint64_t total_spent {0}; - - for (XmrInput input: inputs) - { - XmrOutput out; - - if (xmr_accounts - ->select_by_primary_id( - input.output_id, out)) - { - total_spent += input.amount; - - j_spent_outputs.push_back({ - {"amount" , std::to_string(input.amount)}, - {"key_image" , input.key_image}, - {"tx_pub_key" , out.tx_pub_key}, - {"out_index" , out.out_index}, - {"mixin" , out.mixin}}); - } - - } // for (XmrInput input: inputs) - - j_response["total_sent"] = std::to_string(total_spent); - - j_response["spent_outputs"] = j_spent_outputs; - - } // if (xmr_accounts->select_inputs_ - - } // if (xmr_accounts->tx_exists(acc.id - - } // if (!tx_in_mempool) - else - { - // if tx in mempool, mysql will not have this tx, so - // we cant pull info about key images from mysql for this tx. - - // we have to redo this info from basically from scrach. - - unordered_map known_outputs_keys; - - if (current_bc_status->get_known_outputs_keys( - xmr_address, known_outputs_keys)) - { - // we got known_outputs_keys from the search thread. - // so now we can use OutputInputIdentification to - // get info about inputs. - - // Class that is resposnible for idenficitaction - // of our outputs - // and inputs in a given tx. - OutputInputIdentification oi_identification - {&address_info, &viewkey, &tx, tx_hash, - coinbase}; - - // no need mutex here, as this will be exectued only - // after the above. there is no threads here. - oi_identification.identify_inputs(known_outputs_keys, - current_bc_status.get()); - - json j_spent_outputs = json::array(); - - uint64_t total_spent {0}; - - for (auto& in_info: oi_identification.identified_inputs) - { - - // need to get output info from mysql, as we need - // to know output's amount, its orginal - // tx public key and its index in that tx - XmrOutput out; - - string out_pub_key - = pod_to_hex(in_info.out_pub_key); - - if (xmr_accounts->output_exists(out_pub_key, out)) - { - total_spent += out.amount; - - j_spent_outputs.push_back({ - {"amount" , std::to_string(in_info.amount)}, - {"key_image" , in_info.key_img}, - {"tx_pub_key" , out.tx_pub_key}, - {"out_index" , out.out_index}, - {"mixin" , out.mixin}}); - } - - } // for (auto& in_info: oi_identification - - j_response["total_sent"] = std::to_string(total_spent); - - j_response["spent_outputs"] = j_spent_outputs; - - } //if (current_bc_status->get_known_outputs_keys( - // xmr_address, known_outputs_keys)) - - } // else - - } // if (xmr_accounts->select(xmr_address, acc)) - - } // if (current_bc_status->get_xmr_add - - 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) -{ - - (void) body; - - json j_response { - {"last_git_commit_hash", string {GIT_COMMIT_HASH}}, - {"last_git_commit_date", string {GIT_COMMIT_DATETIME}}, - {"git_branch_name" , string {GIT_BRANCH_NAME}}, - {"monero_version_full" , string {MONERO_VERSION_FULL}}, - {"api" , OPENMONERO_RPC_VERSION}, - {"testnet" , current_bc_status->get_bc_setup().net_type - == network_type::TESTNET}, - {"network_type" , current_bc_status->get_bc_setup().net_type}, - {"blockchain_height" , get_current_blockchain_height()} - }; - - 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); -} - - -shared_ptr -YourMoneroRequests::make_resource( - function< void (YourMoneroRequests&, const shared_ptr< Session >, - const Bytes& ) > handle_func, - const string& path) -{ - auto a_request = std::bind(handle_func, *this, - std::placeholders::_1, - std::placeholders::_2); - - shared_ptr resource_ptr = make_shared(); - - resource_ptr->set_path(path); - resource_ptr->set_method_handler( "OPTIONS", generic_options_handler); - resource_ptr->set_method_handler( "POST" , handel_(a_request) ); - - return resource_ptr; -} - - -void -YourMoneroRequests::generic_options_handler( - const shared_ptr< Session > session ) -{ - const auto request = session->get_request( ); - - size_t content_length = request->get_header( "Content-Length", 0); - - session->fetch(content_length, - [](const shared_ptr< Session > session, - const Bytes &) - { - session->close( OK, string{}, make_headers()); - }); -} - - -multimap -YourMoneroRequests::make_headers( - const multimap& extra_headers) -{ - multimap headers { - {"Access-Control-Allow-Origin" , "*"}, - {"Access-Control-Allow-Headers" , "Content-Type"}, - {"Content-Type" , "application/json"} - }; - - headers.insert(extra_headers.begin(), extra_headers.end()); - - return headers; -}; - -void -YourMoneroRequests::print_json_log(const string& text, const json& j) -{ - cout << text << '\n' << j.dump(4) << endl; -} - - -string -YourMoneroRequests::body_to_string(const Bytes & body) -{ - return string(reinterpret_cast(body.data()), body.size()); -} - -json -YourMoneroRequests::body_to_json(const Bytes & body) -{ - json j = json::parse(body_to_string(body)); - return j; -} - - -uint64_t -YourMoneroRequests::get_current_blockchain_height() -{ - return current_bc_status->get_current_blockchain_height(); -} - -bool -YourMoneroRequests::login_and_start_search_thread( - const string& xmr_address, - const string& view_key, - XmrAccount& acc, - json& j_response) -{ - - // select this account if its existing one - if (xmr_accounts->select(xmr_address, acc)) - { - // we got accunt from the database. we double check - // if hash of provided viewkey by the frontend, matches - // what we have in database. - - // make hash of the submited viewkey. we only store - // hash of viewkey in database, not acctual viewkey. - string viewkey_hash = make_hash(view_key); - - if (viewkey_hash == acc.viewkey_hash) - { - // if match, than save the viewkey in account object - // and proceed to checking if a search thread exisits - // for this account. if not, then create new thread - - acc.viewkey = view_key; - - // so we have an account now. Either existing or - // newly created. Thus, we can start a tread - // which will scan for transactions belonging to - // that account, using its address and view key. - // the thread will scan the blockchain for txs belonging - // to that account and updated mysql database whenever it - // will find something. - // - // The other client (i.e., a webbrowser) will query other - // functions to retrieve - // any belonging transactions in a loop. - // Thus the thread does not need - // to do anything except looking for tx and updating mysql - // with relative tx information - - if (!current_bc_status->search_thread_exist(acc.address)) - { - std::unique_ptr tx_search; - - try - { - tx_search - = std::make_unique(acc, - current_bc_status); - } - catch (std::exception const& e) - { - OMERROR << "TxSearch construction faild."; - j_response = json {{"status", "error"}, - {"reason", "Failed to construct " - "TxSearch object"}}; - return false; - } - - - if (current_bc_status->start_tx_search_thread( - acc, std::move(tx_search))) - { - j_response["status"] = "success"; - j_response["new_address"] = false; - - // thread has been started - // everything seems fine. - - return true; - } - } - else - { - j_response["status"] = "success"; - j_response["new_address"] = false; - - // thread already exists - // everything seems fine. - - return true; - } - - j_response = json {{"status", "error"}, - {"reason", "Failed created search " - "thread for this account"}}; - } - else - { - j_response = json {{"status", "error"}, - {"reason", "Viewkey provided is incorrect"}}; - } - } - - return false; -} - - -bool -YourMoneroRequests::parse_request( - const Bytes& body, - vector& values_map, - json& j_request, - json& j_response) -{ - - try - { - j_request = body_to_json(body); - - // parsing was successful - // now check if all required values are there. - - for (const auto& v: values_map) - { - - if (j_request.count(v) == 0) - { - cerr << v + " value not provided" << endl; - - j_response["status"] = "error"; - j_response["reason"] = v + " value not provided"; - - return false; - } - - } - - return true; - } - catch (std::exception& e) - { - cerr << "YourMoneroRequests::parse_request: " << e.what() << endl; - - j_response["status"] = "error"; - j_response["reason"] = "reqest json parsing failed"; - - return false; - } -} - -boost::optional -YourMoneroRequests::select_account( - string const& xmr_address) const -{ - boost::optional acc = XmrAccount{}; - - if (!xmr_accounts->select(xmr_address, *acc)) - { - OMERROR << xmr_address.substr(0,6) + - ": address does not exists!"; - - return acc; - } - - return acc; -} - -boost::optional -YourMoneroRequests::select_payment( - XmrAccount const& xmr_account) const -{ - vector xmr_payments; - - if (!xmr_accounts->select(xmr_account.id.data, - xmr_payments)) - { - OMINFO << xmr_account.address.substr(0,6) + - ": no payment record found!"; - - // so create empty record to be inserted into - // db after. - XmrPayment xmr_payment; - xmr_payment.id = mysqlpp::null; - - return xmr_payment; - } - - if (xmr_payments.size() > 1) - { - OMERROR << xmr_account.address.substr(0,6) + - ": more than one payment record found!"; - return {}; - } - - // if xmr_payments is empty it means - // that the given account has no import - // paymnet record created. so new - // paymnet will be created - if (xmr_payments.empty()) - { - OMINFO << xmr_account.address.substr(0,6) + - ": no payment record found!"; - - // so create empty record to be inserted into - // db after. - XmrPayment xmr_payment; - xmr_payment.id = mysqlpp::null; - - return xmr_payment; - } - - return xmr_payments.at(0); -} - -void -YourMoneroRequests::session_close( - const shared_ptr< Session > session, - json& j_response, - int return_code, - string error_msg) const -{ - if (return_code != OK) - { - j_response["Error"] = error_msg; - } - - string response_body = j_response.dump(); - - auto response_headers - = make_headers({{ "Content-Length", - std::to_string(response_body.size())}}); - - session->close( return_code, - response_body, response_headers); -} - -} - - - diff --git a/src/YourMoneroRequests.h b/src/YourMoneroRequests.h deleted file mode 100755 index 9a3db63..0000000 --- a/src/YourMoneroRequests.h +++ /dev/null @@ -1,173 +0,0 @@ -// -// Created by mwo on 8/12/16. -// - -#ifndef RESTBED_XMR_YOURMONEROREQUESTS_H -#define RESTBED_XMR_YOURMONEROREQUESTS_H - -#include -#include - - -#include "version.h" - -#include "CurrentBlockchainStatus.h" -#include "db/MySqlAccounts.h" -#include "../gen/version.h" - -#include "../ext/restbed/source/restbed" - -#ifndef MAKE_RESOURCE -#define MAKE_RESOURCE(name) auto name = open_monero.make_resource( \ - &xmreg::YourMoneroRequests::name, "/" + string(#name)); -#endif - - - -// When making *any* change here, bump minor -// If the change is incompatible, then bump major and set minor to 0 -// This ensures that RPC_VERSION always increases, that every change -// has its own version, and that clients can just test major to see -// whether they can talk to a given backend without having to know in -// advance which version they will stop working with -// Don't go over 32767 for any of these -#define OPENMONERO_RPC_VERSION_MAJOR 1 -#define OPENMONERO_RPC_VERSION_MINOR 3 -#define MAKE_OPENMONERO_RPC_VERSION(major,minor) (((major)<<16)|(minor)) -#define OPENMONERO_RPC_VERSION \ - MAKE_OPENMONERO_RPC_VERSION(OPENMONERO_RPC_VERSION_MAJOR, OPENMONERO_RPC_VERSION_MINOR) - - -namespace xmreg -{ - -using namespace std; -using namespace restbed; -using namespace nlohmann; - - -struct handel_ -{ - using fetch_func_t = function< void ( const shared_ptr< Session >, const Bytes& ) >; - - fetch_func_t request_callback; - - handel_(const fetch_func_t& callback); - - void operator()(const shared_ptr< Session > session); -}; - - -class YourMoneroRequests -{ - - // this manages all mysql queries - shared_ptr xmr_accounts; - shared_ptr current_bc_status; - -public: - - YourMoneroRequests(shared_ptr _acc, - shared_ptr _current_bc_status); - - /** - * A login request handler. - * - * It takes address and viewkey from the request - * and check mysql if address/account exist. If yes, - * it returns this account. If not, it creates new one. - * - * Once this complites, a thread is started that looks - * for txs belonging to that account. - * - * @param session a Restbed session - * @param body a POST body, i.e., json string - */ - void - login(const shared_ptr session, const Bytes & body); - - void - get_address_txs(const shared_ptr< Session > session, const Bytes & body); - - void - get_address_info(const shared_ptr< Session > session, const Bytes & body); - - void - get_unspent_outs(const shared_ptr< Session > session, const Bytes & body); - - void - get_random_outs(const shared_ptr< Session > session, const Bytes & body); - - void - submit_raw_tx(const shared_ptr< Session > session, const Bytes & body); - - void - import_wallet_request(const shared_ptr< Session > session, const Bytes & body); - - 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); - - shared_ptr - make_resource(function< void (YourMoneroRequests&, const shared_ptr< Session >, const Bytes& ) > handle_func, - const string& path); - - static void - generic_options_handler( const shared_ptr< Session > session ); - - static multimap - make_headers( - const multimap& extra_headers - = multimap()); - - static void - print_json_log(const string& text, const json& j); - - static inline string - body_to_string(const Bytes & body); - - static inline json - body_to_json(const Bytes & body); - - inline uint64_t - get_current_blockchain_height(); - -private: - - bool - login_and_start_search_thread( - const string& xmr_address, - const string& viewkey, - XmrAccount& acc, - json& j_response); - - - bool - parse_request(const Bytes& body, - vector& values_map, - json& j_request, - json& j_response); - - boost::optional - select_account(string const& xmr_address) const; - - boost::optional - select_payment(XmrAccount const& xmr_account) const; - - void - session_close( - const shared_ptr< Session > session, - json& j_response, - int return_code = OK, - string error_msg = "") const; -}; - - - -} -#endif //RESTBED_XMR_YOURMONEROREQUESTS_H diff --git a/tests/mysql_tests.cpp b/tests/mysql_tests.cpp index f1c4d33..34c7164 100755 --- a/tests/mysql_tests.cpp +++ b/tests/mysql_tests.cpp @@ -3,7 +3,7 @@ // #include "../src/MicroCore.h" -#include "../src/YourMoneroRequests.h" +#include "../src/OpenMoneroRequests.h" #include "../src/db/MysqlPing.h" //#include "chaingen.h"