diff --git a/CMakeLists.txt b/CMakeLists.txt index 375842f..2833d93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,12 +19,16 @@ endif() message(STATUS MONERO_DIR ": ${MONERO_DIR}") -set(MONERO_SOURCE_DIR ${MONERO_DIR} - CACHE PATH "Path to the root directory for Monero") +if (NOT MONERO_SOURCE_DIR) + set(MONERO_SOURCE_DIR ${MONERO_DIR} + CACHE PATH "Path to the root directory for Monero") +endif() -# set location of monero build tree -set(MONERO_BUILD_DIR ${MONERO_SOURCE_DIR}/build/release/ - CACHE PATH "Path to the build directory for Monero") +if (NOT MONERO_BUILD_DIR) + # set location of monero build tree + set(MONERO_BUILD_DIR ${MONERO_SOURCE_DIR}/build/release/ + CACHE PATH "Path to the build directory for Monero") +endif() set(MY_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE PATH "The path to the cmake directory of the current project") @@ -65,9 +69,16 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR WIN32) set_property(TARGET unbound PROPERTY IMPORTED_LOCATION ${MONERO_BUILD_DIR}/external/unbound/libunbound.a) endif() + + # include boost headers include_directories(${Boost_INCLUDE_DIRS}) + +# include monero +include_directories(${MONERO_SOURCE_DIR}/build) + include_directories("ext/mstch/include") +include_directories("ext/mstch/include/src") include_directories("ext/crow") # add ext/ subfolder diff --git a/main.cpp b/main.cpp index 4729298..2a7e544 100644 --- a/main.cpp +++ b/main.cpp @@ -336,9 +336,14 @@ main(int ac, const char* av[]) return crow::response(xmrblocks.show_block_hex(block_height, true)); }); +// CROW_ROUTE(app, "/ringmemberstxhex/") +// ([&](string tx_hash) { +// return crow::response(xmrblocks.show_ringmemberstx_hex(remove_bad_chars(tx_hash))); +// }); + CROW_ROUTE(app, "/ringmemberstxhex/") ([&](string tx_hash) { - return crow::response(xmrblocks.show_ringmemberstx_hex(remove_bad_chars(tx_hash))); + return myxmr::jsonresponse {xmrblocks.show_ringmemberstx_jsonhex(remove_bad_chars(tx_hash))}; }); } diff --git a/src/page.h b/src/page.h index 3d27334..42115ca 100644 --- a/src/page.h +++ b/src/page.h @@ -22,15 +22,20 @@ #include "../ext/crow/crow.h" +#include "../ext/json.hpp" + #include "../ext/vpetrigocaches/cache.hpp" #include "../ext/vpetrigocaches/lru_cache_policy.hpp" #include "../ext/vpetrigocaches/fifo_cache_policy.hpp" +#include "../ext/mstch/src/visitor/render_node.hpp" + + #include #include #include #include -#include + #define TMPL_DIR "./templates" @@ -190,8 +195,6 @@ using namespace std; using epee::string_tools::pod_to_hex; using epee::string_tools::hex_to_pod; - - /** * @brief The tx_details struct * @@ -1842,7 +1845,248 @@ show_ringmemberstx_hex(string const& tx_hash_str) ::buff_to_hex_nodelimer(oss.str()); } +/** + * @brief Get ring member tx data + * + * Used for generating json file of txs used in unit testing. + * Thanks to json output from this function, we can mock + * a number of blockchain quries about key images + * + * @param tx_hash_str + * @return + */ +json +show_ringmemberstx_jsonhex(string const& tx_hash_str) +{ + transaction tx; + crypto::hash tx_hash; + if (!get_tx(tx_hash_str, tx, tx_hash)) + return string {"Cant get tx: "} + tx_hash_str; + + vector input_key_imgs = xmreg::get_key_images(tx); + + json tx_json; + + string tx_hex; + + try + { + tx_hex = tx_to_hex(tx); + } + catch (std::exception const& e) + { + cerr << e.what() << endl; + return json {"error", "Failed to obtain hex of tx"}; + } + + tx_json["hash"] = tx_hash_str; + tx_json["hex"] = tx_hex; + tx_json["nettype"] = static_cast(nettype); + tx_json["is_ringct"] = (tx.version > 1); + tx_json["rct_type"] = tx.rct_signatures.type; + + tx_json["_comment"] = "Just a placeholder for some comment if needed later"; + + // add placeholder for sender and recipient details + // this is most useful for unit testing on stagenet/testnet + // private monero networks, so we can easly put these + // networks accounts details here. + tx_json["sender"] = json { + {"seed", ""}, + {"address", ""}, + {"viewkey", ""}, + {"spendkey", ""}, + {"amount", 0ull}, + {"change", 0ull}, + {"outputs", json::array({json::array( + {"index placeholder", + "public_key placeholder", + "amount placeholder"} + )}) + }, + {"_comment", ""}}; + + tx_json["recipient"] = json::array(); + + + tx_json["recipient"].push_back( + json { {"seed", ""}, + {"address", ""}, + {"is_subaddress", false}, + {"viewkey", ""}, + {"spendkey", ""}, + {"amount", 0ull}, + {"outputs", json::array({json::array( + {"index placeholder", + "public_key placeholder", + "amount placeholder"} + )}) + }, + {"_comment", ""}}); + + + uint64_t tx_blk_height {0}; + + try + { + tx_blk_height = core_storage->get_db().get_tx_block_height(tx_hash); + } + catch (exception& e) + { + cerr << "Cant get block height: " << tx_hash + << e.what() << endl; + + return json {"error", "Cant get block height"}; + } + + // get block cointaining this tx + block blk; + + if ( !mcore->get_block_by_height(tx_blk_height, blk)) + { + cerr << "Cant get block: " << tx_blk_height << endl; + return json {"error", "Cant get block"}; + } + + block_complete_entry complete_block_data; + + if (!mcore->get_block_complete_entry(blk, complete_block_data)) + { + cerr << "Failed to obtain complete block data " << endl; + return json {"error", "Failed to obtain complete block data "}; + } + + std::string complete_block_data_str; + + if(!epee::serialization::store_t_to_binary( + complete_block_data, complete_block_data_str)) + { + cerr << "Failed to serialize complete_block_data\n"; + return json {"error", "Failed to obtain complete block data"}; + } + + tx_details txd = get_tx_details(tx); + + tx_json["payment_id"] = pod_to_hex(txd.payment_id); + tx_json["payment_id8"] = pod_to_hex(txd.payment_id8); + tx_json["payment_id8e"] = pod_to_hex(txd.payment_id8); + + tx_json["block"] = epee::string_tools + ::buff_to_hex_nodelimer(complete_block_data_str); + + tx_json["block_version"] = json {blk.major_version, blk.minor_version}; + + tx_json["inputs"] = json::array(); + + + // key: constracted from concatenation of in_key.amount and absolute_offsets, + // value: vector of string where string is transaction hash + output index + tx_hex + // will have to cut this string when de-seraializing this data + // later in the unit tests + // transaction hash and output index represent tx_out_index + std::map> all_mixin_txs; + + for (txin_to_key const& in_key: input_key_imgs) + { + // get absolute offsets of mixins + std::vector absolute_offsets + = cryptonote::relative_output_offsets_to_absolute( + in_key.key_offsets); + + //tx_out_index is pair:: + vector indices; + std::vector mixin_outputs; + + // get tx hashes and indices in the txs for the + // given outputs of mixins + // this cant THROW DB_EXCEPTION + try + { + // get tx of the real output + core_storage->get_db().get_output_tx_and_index( + in_key.amount, absolute_offsets, indices); + + // get mining ouput info + core_storage->get_db().get_output_key( + in_key.amount, + absolute_offsets, + mixin_outputs); + } + catch (exception const& e) + { + + string out_msg = fmt::format( + "Cant get ring member tx_out_index for tx {:s}", tx_hash_str + ); + + cerr << out_msg << endl; + + return json {"error", out_msg}; + } + + + tx_json["inputs"].push_back(json {{"key_image", pod_to_hex(in_key.k_image)}, + {"amount", in_key.amount}, + {"absolute_offsets", absolute_offsets}, + {"ring_members", json::array()}}); + + json& ring_members = tx_json["inputs"].back()["ring_members"]; + + + if (indices.size() != mixin_outputs.size()) + { + cerr << "indices.size() != mixin_outputs.size()\n"; + return json {"error", "indices.size() != mixin_outputs.size()"}; + } + + // serialize each mixin tx + //for (auto const& txi : indices) + for (size_t i = 0; i < indices.size(); ++i) + { + + tx_out_index const& txi = indices[i]; + output_data_t const& mo = mixin_outputs[i]; + + auto const& mixin_tx_hash = txi.first; + auto const& output_index_in_tx = txi.second; + + transaction mixin_tx; + + if (!mcore->get_tx(mixin_tx_hash, mixin_tx)) + { + throw std::runtime_error("Cant get tx: " + + pod_to_hex(mixin_tx_hash)); + } + + // serialize tx + string tx_hex = epee::string_tools::buff_to_hex_nodelimer( + t_serializable_object_to_blob(mixin_tx)); + + ring_members.push_back( + json { + {"ouput_pk", pod_to_hex(mo.pubkey)}, + {"tx_hash", pod_to_hex(mixin_tx_hash)}, + {"output_index_in_tx", txi.second}, + {"tx_hex", tx_hex}, + }); + + } + + } // for (txin_to_key const& in_key: input_key_imgs) + + + // archive all_mixin_outputs vector + std::ostringstream oss; + boost::archive::portable_binary_oarchive archive(oss); + archive << all_mixin_txs; + + // return as all_mixin_outputs vector hex + //return epee::string_tools + // ::buff_to_hex_nodelimer(oss.str()); + + return tx_json; +} string show_my_outputs(string tx_hash_str, @@ -2162,8 +2406,11 @@ show_my_outputs(string tx_hash_str, address_info.address.m_spend_public_key, tx_pubkey); - //cout << pod_to_hex(outp.first.key) << endl; - //cout << pod_to_hex(tx_pubkey) << endl; +// cout << pod_to_hex(derivation) << ", " << output_idx << ", " +// << pod_to_hex(address_info.address.m_spend_public_key) << ", " +// << pod_to_hex(outp.first.key) << " == " +// << pod_to_hex(tx_pubkey) << '\n' << '\n'; + // check if generated public key matches the current output's key bool mine_output = (outp.first.key == tx_pubkey); @@ -2178,6 +2425,7 @@ show_my_outputs(string tx_hash_str, address_info.address.m_spend_public_key, tx_pubkey); + mine_output = (outp.first.key == tx_pubkey); with_additional = true; @@ -4642,7 +4890,7 @@ json_block(string block_no_or_hash) {"data" , json {}} }; - json& j_data = j_response["data"]; + nlohmann::json& j_data = j_response["data"]; uint64_t current_blockchain_height = core_storage->get_current_blockchain_height();