From d7d2cc5a400f599742aba277f1079ae68bc783c6 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Sun, 20 May 2018 12:05:07 +0800 Subject: [PATCH] Check if key images already in mempool Partially solves issue: https://github.com/moneroexamples/openmonero/issues/48 It checks if a tx that you are submitting contains key images that are present in mempool, and print outs an appropiate error message. Ideally, differnt outputs should be used by the frontend in this case. But for now, we have to just wait till our past txs get confirmed and disappear from the mempool. --- src/CurrentBlockchainStatus.cpp | 50 +++++++++++++++++++++++++++++++++ src/CurrentBlockchainStatus.h | 6 ++++ src/YourMoneroRequests.cpp | 47 ++++++++++++++++++++++++++++--- 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/CurrentBlockchainStatus.cpp b/src/CurrentBlockchainStatus.cpp index 1ed5f22..60be5cd 100755 --- a/src/CurrentBlockchainStatus.cpp +++ b/src/CurrentBlockchainStatus.cpp @@ -895,6 +895,56 @@ CurrentBlockchainStatus::find_tx_in_mempool( return false; } +bool +CurrentBlockchainStatus::find_key_images_in_mempool(std::vector const& vin) +{ + mempool_txs_t mempool_tx_cpy; + + { + // make local copy of the mempool, so that we dont lock it for + // long, as this function can take longer to execute + std::lock_guard lck (searching_threads_map_mtx); + mempool_tx_cpy = mempool_txs; + } + + // perform exhostive search to check if any key image in vin vector + // is in the mempool. This is used to check if a tx generated by the frontend + // is using any key images that area already in the mempool. + for (auto const& kin: vin) + { + if(kin.type() != typeid(txin_to_key)) + continue; + + // get tx input key + const txin_to_key& tx_in_to_key + = boost::get(kin); + + for (auto const& mtx: mempool_tx_cpy) + { + const transaction &m_tx = mtx.second; + + vector input_key_imgs = xmreg::get_key_images(m_tx); + + for (auto const& mki: input_key_imgs) + { + // if a matching key image found in the mempool + if (mki.k_image == tx_in_to_key.k_image) + return true; + } + } + } + + return false; +} + + +bool +CurrentBlockchainStatus::find_key_images_in_mempool(transaction const& tx) +{ + return find_key_images_in_mempool(tx.vin); +} + + bool CurrentBlockchainStatus::get_tx(crypto::hash const& tx_hash, transaction& tx) { diff --git a/src/CurrentBlockchainStatus.h b/src/CurrentBlockchainStatus.h index a22b267..5cfe6d7 100755 --- a/src/CurrentBlockchainStatus.h +++ b/src/CurrentBlockchainStatus.h @@ -198,6 +198,12 @@ struct CurrentBlockchainStatus find_tx_in_mempool(crypto::hash const& tx_hash, transaction& tx); + static bool + find_key_images_in_mempool(std::vector const& vin); + + static bool + find_key_images_in_mempool(transaction const& tx); + static bool get_tx(crypto::hash const& tx_hash, transaction& tx); diff --git a/src/YourMoneroRequests.cpp b/src/YourMoneroRequests.cpp index edeb6af..d0a6f1c 100755 --- a/src/YourMoneroRequests.cpp +++ b/src/YourMoneroRequests.cpp @@ -821,17 +821,56 @@ YourMoneroRequests::submit_raw_tx(const shared_ptr< Session > session, const Byt 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"; + session_close(session, j_response.dump()); + 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"; + session_close(session, j_response.dump()); + return; + } + + if (CurrentBlockchainStatus::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"; + session_close(session, j_response.dump()); + return; + } + if (!CurrentBlockchainStatus::commit_tx( raw_tx_blob, error_msg, CurrentBlockchainStatus::do_not_relay)) { j_response["status"] = "error"; j_response["error"] = error_msg; + session_close(session, j_response.dump()); + return; } - else - { - j_response["status"] = "success"; - } + + j_response["status"] = "success"; + string response_body = j_response.dump();