From fab2a28db0535903af8676e42adcaceffbd351e0 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Mon, 2 Oct 2017 11:31:04 +0800 Subject: [PATCH 01/27] compile with current dev version of monero --- CMakeLists.txt | 3 +++ cmake/FindMonero.cmake | 14 +++++++------- src/monero_headers.h | 3 +-- src/page.h | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5124560..2d39c93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,7 @@ set(LIBRARIES cryptonote_basic daemonizer cncrypto + blocks lmdb ringct @@ -108,6 +109,8 @@ set(LIBRARIES mnemonics epee easylogging + checkpoints + version ${Boost_LIBRARIES} pthread unbound diff --git a/cmake/FindMonero.cmake b/cmake/FindMonero.cmake index 89a2ee7..12d62ca 100644 --- a/cmake/FindMonero.cmake +++ b/cmake/FindMonero.cmake @@ -30,7 +30,7 @@ set(LIBS common;blocks;cryptonote_basic;cryptonote_core; cryptonote_protocol;daemonizer;mnemonics;epee;lmdb; - blockchain_db;ringct;wallet;cncrypto) + blockchain_db;ringct;wallet;cncrypto;easylogging;version;checkpoints) set(Xmr_INCLUDE_DIRS "${CPP_MONERO_DIR}") @@ -44,7 +44,7 @@ foreach (l ${LIBS}) find_library(Xmr_${L}_LIBRARY NAMES ${l} PATHS ${CMAKE_LIBRARY_PATH} - PATH_SUFFIXES "/src/${l}" "/external/db_drivers/lib${l}" "/lib" "/src/crypto" "/contrib/epee/src" + PATH_SUFFIXES "/src/${l}" "/src/" "/external/db_drivers/lib${l}" "/lib" "/src/crypto" "/contrib/epee/src" "/external/easylogging++/" NO_DEFAULT_PATH ) @@ -57,11 +57,11 @@ foreach (l ${LIBS}) endforeach() -if (EXISTS ${MONERO_BUILD_DIR}/external/easylogging++/libeasylogging.a) - add_library(easylogging STATIC IMPORTED) - set_property(TARGET easylogging - PROPERTY IMPORTED_LOCATION ${MONERO_BUILD_DIR}/external/easylogging++/libeasylogging.a) -endif() +#if (EXISTS ${MONERO_BUILD_DIR}/external/easylogging++/libeasylogging.a) +# add_library(easylogging STATIC IMPORTED) +# set_property(TARGET easylogging +# PROPERTY IMPORTED_LOCATION ${MONERO_BUILD_DIR}/external/easylogging++/libeasylogging.a) +#endif() message(STATUS ${MONERO_SOURCE_DIR}/build) diff --git a/src/monero_headers.h b/src/monero_headers.h index d43573e..6067f8d 100644 --- a/src/monero_headers.h +++ b/src/monero_headers.h @@ -16,12 +16,11 @@ #define FEE_ESTIMATE_GRACE_BLOCKS 10 // estimate fee valid for that many blocks -#include "release/version/version.h" +#include "version.h" #include "net/http_client.h" #include "storages/http_abstract_invoke.h" -//#include "cryptonote_core/cryptonote_basic.h" #include "cryptonote_core/tx_pool.h" #include "cryptonote_core/blockchain.h" #include "blockchain_db/lmdb/db_lmdb.h" diff --git a/src/page.h b/src/page.h index ab3bfa8..2f0f290 100644 --- a/src/page.h +++ b/src/page.h @@ -9,10 +9,10 @@ #include "mstch/mstch.hpp" -#include "version.h" - #include "monero_headers.h" +#include "../gen/version.h" + #include "MicroCore.h" #include "tools.h" #include "rpccalls.h" From 08a86df0bfc410a51af9257c1573915b9e8930ca Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Fri, 6 Oct 2017 09:37:23 +0800 Subject: [PATCH 02/27] Show payment id status in the index page https://github.com/moneroexamples/onion-monero-blockchain-explorer/issues/83#issuecomment-334315512 --- src/MempoolStatus.cpp | 12 ++++++++++++ src/MempoolStatus.h | 4 ++++ src/page.h | 12 ++++++++++++ src/templates/index2.html | 4 ++-- src/templates/mempool.html | 4 ++-- src/templates/partials/tx_details.html | 2 +- 6 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/MempoolStatus.cpp b/src/MempoolStatus.cpp index d562401..d2c543c 100644 --- a/src/MempoolStatus.cpp +++ b/src/MempoolStatus.cpp @@ -182,6 +182,18 @@ MempoolStatus::read_mempool() last_tx.txsize = fmt::format("{:0.2f}", static_cast(_tx_info.blob_size)/1024.0); + last_tx.pID = '-'; + + crypto::hash payment_id; + crypto::hash8 payment_id8; + + get_payment_id(tx, payment_id, payment_id8); + + if (payment_id != null_hash) + last_tx.pID = 'l'; // legacy payment id + else if (payment_id8 != null_hash8) + last_tx.pID = 'e'; // encrypted payment id + } // if (hex_to_pod(_tx_info.id_hash, mem_tx_hash)) } // for (size_t i = 0; i < mempool_tx_info.size(); ++i) diff --git a/src/MempoolStatus.h b/src/MempoolStatus.h index 44607ea..8a42ab5 100644 --- a/src/MempoolStatus.h +++ b/src/MempoolStatus.h @@ -42,6 +42,10 @@ struct MempoolStatus string xmr_outputs_str; string timestamp_str; string txsize; + + char pID; // '-' - no payment ID, + // 'l' - legacy, long 64 character payment id, + // 'e' - encrypted, short, from integrated addresses }; diff --git a/src/page.h b/src/page.h index 2f0f290..4915dd2 100644 --- a/src/page.h +++ b/src/page.h @@ -134,6 +134,9 @@ namespace xmreg uint64_t size; uint64_t blk_height; size_t version; + char pID; // '-' - no payment ID, + // 'l' - legacy, long 64 character payment id, + // 'e' - encrypted, short, from integrated addresses uint64_t unlock_time; uint64_t no_confirmations; vector extra; @@ -188,6 +191,7 @@ namespace xmreg {"version" , static_cast(version)}, {"has_payment_id" , payment_id != null_hash}, {"has_payment_id8" , payment_id8 != null_hash8}, + {"pID" , string {pID}}, {"payment_id" , pod_to_hex(payment_id)}, {"confirmations" , no_confirmations}, {"extra" , get_extra_str()}, @@ -885,6 +889,7 @@ namespace xmreg {"xmr_outputs" , mempool_tx.xmr_outputs_str}, {"no_inputs" , mempool_tx.no_inputs}, {"no_outputs" , mempool_tx.no_outputs}, + {"pID" , string {mempool_tx.pID}}, {"no_nonrct_inputs", mempool_tx.num_nonrct_inputs}, {"mixin" , mempool_tx.mixin_no}, {"txsize" , mempool_tx.txsize} @@ -5739,6 +5744,8 @@ namespace xmreg } } + txd.pID = '-'; // no payment ID + get_payment_id(tx, txd.payment_id, txd.payment_id8); // get tx size in bytes @@ -5749,6 +5756,11 @@ namespace xmreg if (txd.payment_id != null_hash) { txd.payment_id_as_ascii = std::string(txd.payment_id.data, crypto::HASH_SIZE); + txd.pID = 'l'; // legacy payment id + } + else if (txd.payment_id8 != null_hash8) + { + txd.pID = 'e'; // encrypted payment id } // get tx signatures for each input diff --git a/src/templates/index2.html b/src/templates/index2.html index 53da4f8..c83eb91 100644 --- a/src/templates/index2.html +++ b/src/templates/index2.html @@ -76,7 +76,7 @@ tx hash fees outputs - in(nonrct)/out + in/out/pID ring size tx size [kB] @@ -88,7 +88,7 @@ {{hash}} {{tx_fee_short}} {{sum_outputs_short}} - {{no_inputs}}({{no_nonrct_inputs}})/{{no_outputs}} + {{no_inputs}}/{{no_outputs}}/{{pID}} {{mixin}} {{tx_size_short}} diff --git a/src/templates/mempool.html b/src/templates/mempool.html index 361865e..f508b2a 100644 --- a/src/templates/mempool.html +++ b/src/templates/mempool.html @@ -10,7 +10,7 @@ transaction hash fee outputs - in(nonrct)/out + in/out/pID ring size tx size [kB] @@ -20,7 +20,7 @@ {{hash}} {{fee}} {{xmr_outputs}} - {{no_inputs}}({{no_nonrct_inputs}})/{{no_outputs}} + {{no_inputs}}/{{no_outputs}}/{{pID}} {{mixin}} {{txsize}} diff --git a/src/templates/partials/tx_details.html b/src/templates/partials/tx_details.html index d92da77..9fd52c3 100644 --- a/src/templates/partials/tx_details.html +++ b/src/templates/partials/tx_details.html @@ -9,7 +9,7 @@ {{#has_payment_id}}
Payment id: {{payment_id}}
-
Payment id as ascii ([a-zA-Z0-9 /!]): {{payment_id_as_ascii}}
+
Payment id as ascii: {{payment_id_as_ascii}}
{{/has_payment_id}} {{#has_payment_id8}} From 16835ec144d38c58c6c306fb67a4c3f16c2516b4 Mon Sep 17 00:00:00 2001 From: stoffu Date: Fri, 6 Oct 2017 14:18:16 +0900 Subject: [PATCH 03/27] tx-pusher: support hex string of raw tx --- src/page.h | 139 ++++++++++++++++++++++----------------- src/templates/rawtx.html | 5 +- 2 files changed, 82 insertions(+), 62 deletions(-) diff --git a/src/page.h b/src/page.h index 4915dd2..2d8fb36 100644 --- a/src/page.h +++ b/src/page.h @@ -817,7 +817,7 @@ namespace xmreg { // get only first no_of_mempool_tx txs mempool_txs = MempoolStatus::get_mempool_txs(no_of_mempool_tx); - no_of_mempool_tx = std::min(no_of_mempool_tx, mempool_txs.size()); + no_of_mempool_tx = std::min(no_of_mempool_tx, mempool_txs.size()); } // total size of mempool in bytes @@ -945,7 +945,7 @@ namespace xmreg cerr << "rpc.get_alt_blocks(atl_blks_hashes) failed" << endl; } - context.emplace("no_alt_blocks", atl_blks_hashes.size()); + context.emplace("no_alt_blocks", (uint64_t)atl_blks_hashes.size()); for (const string& alt_blk_hash: atl_blks_hashes) { @@ -2774,85 +2774,102 @@ namespace xmreg { clean_post_data(raw_tx_data); - string decoded_raw_tx_data = epee::string_encoding::base64_decode(raw_tx_data); - - const size_t magiclen = strlen(SIGNED_TX_PREFIX); - - string data_prefix = xmreg::make_printable(decoded_raw_tx_data.substr(0, magiclen)); - // initalize page template context map mstch::map context { {"testnet" , testnet}, {"have_raw_tx" , true}, {"has_error" , false}, {"error_msg" , string {}}, - {"data_prefix" , data_prefix}, }; - context.emplace("txs", mstch::array{}); // add header and footer string full_page = template_file["pushrawtx"]; add_css_style(context); - if (strncmp(decoded_raw_tx_data.c_str(), SIGNED_TX_PREFIX, magiclen) != 0) + std::vector ptx_vector; + + // first try reading raw_tx_data as a raw hex string + std::string tx_blob; + cryptonote::transaction parsed_tx; + crypto::hash parsed_tx_hash, parsed_tx_prefixt_hash; + if (epee::string_tools::parse_hexstr_to_binbuff(raw_tx_data, tx_blob) && parse_and_validate_tx_from_blob(tx_blob, parsed_tx, parsed_tx_hash, parsed_tx_prefixt_hash)) { - string error_msg = fmt::format("The data does not appear to be signed raw tx! Data prefix: {:s}", - data_prefix); + ptx_vector.push_back({}); + ptx_vector.back().tx = parsed_tx; + } + // if failed, treat raw_tx_data as base64 encoding of signed_monero_tx + else + { + string decoded_raw_tx_data = epee::string_encoding::base64_decode(raw_tx_data); - context["has_error"] = true; - context["error_msg"] = error_msg; + const size_t magiclen = strlen(SIGNED_TX_PREFIX); - return mstch::render(full_page, context); + string data_prefix = xmreg::make_printable(decoded_raw_tx_data.substr(0, magiclen)); + + context["data_prefix"] = data_prefix; + + if (strncmp(decoded_raw_tx_data.c_str(), SIGNED_TX_PREFIX, magiclen) != 0) + { + string error_msg = fmt::format("The data does not appear to be signed raw tx! Data prefix: {:s}", + data_prefix); + + context["has_error"] = true; + context["error_msg"] = error_msg; + + return mstch::render(full_page, context); + } + + if (this->enable_pusher == false) + { + string error_msg = fmt::format( + "Pushing disabled!\n " + "Run explorer with --enable-pusher flag to enable it."); + + context["has_error"] = true; + context["error_msg"] = error_msg; + + return mstch::render(full_page, context); + } + + bool r {false}; + + string s = decoded_raw_tx_data.substr(magiclen); + + ::tools::wallet2::signed_tx_set signed_txs; + + try + { + std::istringstream iss(s); + boost::archive::portable_binary_iarchive ar(iss); + ar >> signed_txs; + + r = true; + } + catch (...) + { + cerr << "Failed to parse signed tx data " << endl; + } + + + if (!r) + { + string error_msg = fmt::format("Deserialization of signed tx data NOT successful! " + "Maybe its not base64 encoded?"); + + context["has_error"] = true; + context["error_msg"] = error_msg; + + return mstch::render(full_page, context); + } + + ptx_vector = signed_txs.ptx; } - if (this->enable_pusher == false) - { - string error_msg = fmt::format( - "Pushing disabled!\n " - "Run explorer with --enable-pusher flag to enable it."); - - context["has_error"] = true; - context["error_msg"] = error_msg; - - return mstch::render(full_page, context); - } - - bool r {false}; - - string s = decoded_raw_tx_data.substr(magiclen); - - ::tools::wallet2::signed_tx_set signed_txs; - - try - { - std::istringstream iss(s); - boost::archive::portable_binary_iarchive ar(iss); - ar >> signed_txs; - - r = true; - } - catch (...) - { - cerr << "Failed to parse signed tx data " << endl; - } - - - if (!r) - { - string error_msg = fmt::format("Deserialization of signed tx data NOT successful! " - "Maybe its not base64 encoded?"); - - context["has_error"] = true; - context["error_msg"] = error_msg; - - return mstch::render(full_page, context); - } + context.emplace("txs", mstch::array{}); mstch::array& txs = boost::get(context["txs"]); - std::vector ptx_vector = signed_txs.ptx; - // actually commit the transactions while (!ptx_vector.empty()) { @@ -4724,7 +4741,7 @@ namespace xmreg } // maxium five last blocks - no_of_last_blocks = std::min(no_of_last_blocks, 5ul); + no_of_last_blocks = std::min(no_of_last_blocks, 5ul); if (address_str.empty()) { diff --git a/src/templates/rawtx.html b/src/templates/rawtx.html index b7f65ed..47b2a98 100644 --- a/src/templates/rawtx.html +++ b/src/templates/rawtx.html @@ -8,13 +8,16 @@
- Paste base64 encoded, unsigned or signed transaction data here
+ Paste here either a hex string of raw transaction (the tx_blob response in the wallet RPC, or the raw_monero_tx file saved by the wallet CLI with --do-not-relay option specified),
+ or base64 encoded, unsigned or signed transaction data
(In Linux, can get base64 signed raw tx data: base64 signed_monero_tx | xclip -selection clipboard)
(In Windows, can get base64 signed raw tx data: certutil.exe -encode -f signed_monero_tx encoded.txt & type "encoded.txt" | clip)

Note: data is sent to the server, as the calculations are done on the server side
+ Note: "check" does not work for the hex string of raw transaction +
                                        From 86d373462728546e5e438de7b60f7d5bcba40c78 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Sat, 21 Oct 2017 16:53:16 +0800 Subject: [PATCH 04/27] make it compile with subaddresses --- src/page.h | 133 ++++++++++++++++++++++++++++---------------------- src/tools.cpp | 14 +++--- src/tools.h | 6 +-- 3 files changed, 85 insertions(+), 68 deletions(-) diff --git a/src/page.h b/src/page.h index 2d8fb36..35b1a9a 100644 --- a/src/page.h +++ b/src/page.h @@ -1458,9 +1458,9 @@ namespace xmreg } // parse string representing given monero address - cryptonote::account_public_address address; + cryptonote::address_parse_info address_info; - if (!xmreg::parse_str_address(xmr_address_str, address, testnet)) + if (!xmreg::parse_str_address(xmr_address_str, address_info, testnet)) { cerr << "Cant parse string address: " << xmr_address_str << endl; return string("Cant parse xmr address: " + xmr_address_str); @@ -1649,7 +1649,7 @@ namespace xmreg // to create, so called, derived key. key_derivation derivation; - public_key pub_key = tx_prove ? address.m_view_public_key : txd.pk; + public_key pub_key = tx_prove ? address_info.address.m_view_public_key : txd.pk; //cout << "txd.pk: " << pod_to_hex(txd.pk) << endl; @@ -1693,7 +1693,7 @@ namespace xmreg derive_public_key(derivation, output_idx, - address.m_spend_public_key, + address_info.address.m_spend_public_key, tx_pubkey); //cout << pod_to_hex(outp.first.key) << endl; @@ -1948,7 +1948,7 @@ namespace xmreg derive_public_key(derivation, output_idx_in_tx, - address.m_spend_public_key, + address_info.address.m_spend_public_key, tx_pubkey_generated); // check if generated public key matches the current output's key @@ -2239,7 +2239,8 @@ namespace xmreg for (const tx_destination_entry& a_dest: tx_cd.splitted_dsts) { mstch::map dest_info { - {"dest_address" , get_account_address_as_str(testnet, a_dest.addr)}, + {"dest_address" , get_account_address_as_str( + testnet, a_dest.is_subaddress, a_dest.addr)}, {"dest_amount" , xmreg::xmr_amount_to_str(a_dest.amount)} }; @@ -2579,7 +2580,8 @@ namespace xmreg destination_addresses.push_back( mstch::map { - {"dest_address" , get_account_address_as_str(testnet, a_dest.addr)}, + {"dest_address" , get_account_address_as_str( + testnet, a_dest.is_subaddress, a_dest.addr)}, {"dest_amount" , xmreg::xmr_amount_to_str(a_dest.amount)}, {"is_this_change" , false} } @@ -2595,8 +2597,10 @@ namespace xmreg { destination_addresses.push_back( mstch::map { - {"dest_address" , get_account_address_as_str(testnet, ptx.construction_data.change_dts.addr)}, - {"dest_amount" , xmreg::xmr_amount_to_str(ptx.construction_data.change_dts.amount)}, + {"dest_address" , get_account_address_as_str( + testnet, ptx.construction_data.change_dts.is_subaddress, ptx.construction_data.change_dts.addr)}, + {"dest_amount" , + xmreg::xmr_amount_to_str(ptx.construction_data.change_dts.amount)}, {"is_this_change" , true} } ); @@ -3101,8 +3105,13 @@ namespace xmreg reinterpret_cast( decoded_raw_data.data()); - context.insert({"address" , REMOVE_HASH_BRAKETS(xmreg::print_address(*xmr_address, testnet))}); - context.insert({"viewkey" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", prv_view_key))}); + address_parse_info address_info {*xmr_address, false}; + + + context.insert({"address" , REMOVE_HASH_BRAKETS( + xmreg::print_address(address_info, testnet))}); + context.insert({"viewkey" , REMOVE_HASH_BRAKETS( + fmt::format("{:s}", prv_view_key))}); context.insert({"has_total_xmr" , false}); context.insert({"total_xmr" , string{}}); context.insert({"key_imgs" , mstch::array{}}); @@ -3128,7 +3137,8 @@ namespace xmreg {"key_no" , fmt::format("{:03d}", n)}, {"key_image" , pod_to_hex(key_image)}, {"signature" , fmt::format("{:s}", signature)}, - {"address" , xmreg::print_address(*xmr_address, testnet)}, + {"address" , xmreg::print_address( + address_info, testnet)}, {"is_spent" , core_storage->have_tx_keyimg_as_spent(key_image)}, {"tx_hash" , string{}} }; @@ -3229,8 +3239,12 @@ namespace xmreg reinterpret_cast( decoded_raw_data.data()); - context.insert({"address" , REMOVE_HASH_BRAKETS(xmreg::print_address(*xmr_address, testnet))}); - context.insert({"viewkey" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", prv_view_key))}); + address_parse_info address_info {*xmr_address, false}; + + context.insert({"address" , REMOVE_HASH_BRAKETS( + xmreg::print_address(address_info, testnet))}); + context.insert({"viewkey" , REMOVE_HASH_BRAKETS( + fmt::format("{:s}", prv_view_key))}); context.insert({"has_total_xmr" , false}); context.insert({"total_xmr" , string{}}); context.insert({"output_keys" , mstch::array{}}); @@ -3436,47 +3450,48 @@ namespace xmreg if (search_str_length == 95) { // parse string representing given monero address - cryptonote::account_public_address address; + address_parse_info address_info; bool testnet_addr {false}; if (search_text[0] == '9' || search_text[0] == 'A') testnet_addr = true; - if (!xmreg::parse_str_address(search_text, address, testnet_addr)) + if (!xmreg::parse_str_address(search_text, address_info, testnet_addr)) { cerr << "Cant parse string address: " << search_text << endl; return string("Cant parse address (probably incorrect format): ") + search_text; } - return show_address_details(address, testnet_addr); + return show_address_details(address_info, testnet_addr); } - // check if integrated monero address is given based on its length - // if yes, then show its public components search tx based on encrypted id - if (search_str_length == 106) - { - - cryptonote::account_public_address address; - - bool has_payment_id; - - crypto::hash8 encrypted_payment_id; - - if (!get_account_integrated_address_from_str(address, - has_payment_id, - encrypted_payment_id, - testnet, - search_text)) - { - cerr << "Cant parse string integerated address: " << search_text << endl; - return string("Cant parse address (probably incorrect format): ") - + search_text; - } - - return show_integrated_address_details(address, encrypted_payment_id, testnet); - } +// // check if integrated monero address is given based on its length +// // if yes, then show its public components search tx based on encrypted id +// @todo does not work with integrated address for now +// if (search_str_length == 106) +// { +// +// cryptonote::account_public_address address; +// +// bool has_payment_id; +// +// crypto::hash8 encrypted_payment_id; +// +// if (!get_account_integrated_address_from_str(address_info.address, +// has_payment_id, +// encrypted_payment_id, +// testnet, +// search_text)) +// { +// cerr << "Cant parse string integerated address: " << search_text << endl; +// return string("Cant parse address (probably incorrect format): ") +// + search_text; +// } +// +// return show_integrated_address_details(address_info.address, encrypted_payment_id, testnet); +// } // all_possible_tx_hashes was field using custom lmdb database // it was dropped, so all_possible_tx_hashes will be alwasy empty @@ -3489,12 +3504,12 @@ namespace xmreg } string - show_address_details(const account_public_address& address, bool testnet = false) + show_address_details(const address_parse_info& address_info, bool testnet = false) { - string address_str = xmreg::print_address(address, testnet); - string pub_viewkey_str = fmt::format("{:s}", address.m_view_public_key); - string pub_spendkey_str = fmt::format("{:s}", address.m_spend_public_key); + string address_str = xmreg::print_address(address_info, testnet); + string pub_viewkey_str = fmt::format("{:s}", address_info.address.m_view_public_key); + string pub_spendkey_str = fmt::format("{:s}", address_info.address.m_spend_public_key); mstch::map context { {"xmr_address" , REMOVE_HASH_BRAKETS(address_str)}, @@ -3512,14 +3527,14 @@ namespace xmreg // ; string - show_integrated_address_details(const account_public_address& address, + show_integrated_address_details(const address_parse_info& address_info, const crypto::hash8& encrypted_payment_id, bool testnet = false) { - string address_str = xmreg::print_address(address, testnet); - string pub_viewkey_str = fmt::format("{:s}", address.m_view_public_key); - string pub_spendkey_str = fmt::format("{:s}", address.m_spend_public_key); + string address_str = xmreg::print_address(address_info, testnet); + string pub_viewkey_str = fmt::format("{:s}", address_info.address.m_view_public_key); + string pub_spendkey_str = fmt::format("{:s}", address_info.address.m_spend_public_key); string enc_payment_id_str = fmt::format("{:s}", encrypted_payment_id); mstch::map context { @@ -4572,9 +4587,9 @@ namespace xmreg } // parse string representing given monero address - cryptonote::account_public_address address; + address_parse_info address_info; - if (!xmreg::parse_str_address(address_str, address, testnet)) + if (!xmreg::parse_str_address(address_str, address_info, testnet)) { j_response["status"] = "error"; j_response["message"] = "Cant parse monero address: " + address_str; @@ -4618,7 +4633,7 @@ namespace xmreg // to create, so called, derived key. key_derivation derivation; - public_key pub_key = tx_prove ? address.m_view_public_key : txd.pk; + public_key pub_key = tx_prove ? address_info.address.m_view_public_key : txd.pk; //cout << "txd.pk: " << pod_to_hex(txd.pk) << endl; @@ -4646,7 +4661,7 @@ namespace xmreg derive_public_key(derivation, output_idx, - address.m_spend_public_key, + address_info.address.m_spend_public_key, tx_pubkey); // check if generated public key matches the current output's key @@ -4699,7 +4714,7 @@ namespace xmreg // check if submited data in the request // matches to what was used to produce response. j_data["tx_hash"] = pod_to_hex(txd.hash); - j_data["address"] = pod_to_hex(address); + j_data["address"] = pod_to_hex(address_info.address); j_data["viewkey"] = pod_to_hex(prv_view_key); j_data["tx_prove"] = tx_prove; @@ -4758,9 +4773,9 @@ namespace xmreg } // parse string representing given monero address - cryptonote::account_public_address address; + address_parse_info address_info; - if (!xmreg::parse_str_address(address_str, address, testnet)) + if (!xmreg::parse_str_address(address_str, address_info, testnet)) { j_response["status"] = "error"; j_response["message"] = "Cant parse monero address: " + address_str; @@ -4806,7 +4821,7 @@ namespace xmreg } if (!find_our_outputs( - address, prv_view_key, + address_info.address, prv_view_key, 0 /* block_no */, true /*is mempool*/, tmp_vector.cbegin(), tmp_vector.cend(), j_outptus /* found outputs are pushed to this*/, @@ -4863,7 +4878,7 @@ namespace xmreg (void) missed_txs; if (!find_our_outputs( - address, prv_view_key, + address_info.address, prv_view_key, block_no, false /*is mempool*/, blk_txs.cbegin(), blk_txs.cend(), j_outptus /* found outputs are pushed to this*/, @@ -4881,7 +4896,7 @@ namespace xmreg // return parsed values. can be use to double // check if submited data in the request // matches to what was used to produce response. - j_data["address"] = pod_to_hex(address); + j_data["address"] = pod_to_hex(address_info.address); j_data["viewkey"] = pod_to_hex(prv_view_key); j_data["limit"] = _limit; j_data["height"] = height; diff --git a/src/tools.cpp b/src/tools.cpp index 17fbc84..1bb0501 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -77,11 +77,11 @@ namespace xmreg */ bool parse_str_address(const string& address_str, - account_public_address& address, + address_parse_info& address_info, bool testnet) { - if (!get_account_address_from_str(address, testnet, address_str)) + if (!get_account_address_from_str(address_info, testnet, address_str)) { cerr << "Error getting address: " << address_str << endl; return false; @@ -95,9 +95,11 @@ namespace xmreg * Return string representation of monero address */ string - print_address(const account_public_address& address, bool testnet) + print_address(const address_parse_info& address_info, bool testnet) { - return "<" + get_account_address_as_str(testnet, address) + ">"; + return "<" + get_account_address_as_str( + testnet, address_info.is_subaddress, address_info.address) + + ">"; } string @@ -176,9 +178,9 @@ namespace xmreg } ostream& - operator<< (ostream& os, const account_public_address& addr) + operator<< (ostream& os, const address_parse_info& addr_info) { - os << get_account_address_as_str(false, addr); + os << get_account_address_as_str(false, addr_info.is_subaddress, addr_info.address); return os; } diff --git a/src/tools.h b/src/tools.h index a395b75..a22d314 100644 --- a/src/tools.h +++ b/src/tools.h @@ -80,14 +80,14 @@ namespace xmreg bool parse_str_address(const string& address_str, - account_public_address& address, + address_parse_info& address_info, bool testnet = false); inline bool is_separator(char c); string - print_address(const account_public_address& address, + print_address(const address_parse_info& address, bool testnet = false); string @@ -103,7 +103,7 @@ namespace xmreg timestamp_to_str_gm(time_t timestamp, const char* format = "%F %T"); ostream& - operator<< (ostream& os, const account_public_address& addr); + operator<< (ostream& os, const address_parse_info& addr_info); string From d24e23a02f1d095d6ff623f26e1ef68e75711378 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Sat, 21 Oct 2017 17:41:06 +0800 Subject: [PATCH 05/27] tx pusher text updated --- src/templates/rawtx.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/templates/rawtx.html b/src/templates/rawtx.html index 47b2a98..5ffd147 100644 --- a/src/templates/rawtx.html +++ b/src/templates/rawtx.html @@ -8,10 +8,13 @@
- Paste here either a hex string of raw transaction (the tx_blob response in the wallet RPC, or the raw_monero_tx file saved by the wallet CLI with --do-not-relay option specified),
+ Paste here either a hex string of raw transaction
+ (the tx_blob response in the wallet RPC, or the raw_monero_tx + file saved by the wallet CLI with --do-not-relay option specified),
or base64 encoded, unsigned or signed transaction data
- (In Linux, can get base64 signed raw tx data: base64 signed_monero_tx | xclip -selection clipboard)
- (In Windows, can get base64 signed raw tx data: certutil.exe -encode -f signed_monero_tx encoded.txt & type "encoded.txt" | clip)
+
+ (In Linux, can get the raw tx data: cat raw_monero_tx | xclip -selection clipboard)
+ (In Windows, can get the raw tx data: certutil.exe -encode -f raw_monero_tx encoded.txt & type "encoded.txt" | clip)

Note: data is sent to the server, as the calculations are done on the server side From 98347be35b1aba9c07f72f8aa27e954d3548dd20 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Tue, 24 Oct 2017 17:35:36 +0800 Subject: [PATCH 06/27] Update tx_details.html "subaddress" added to tx html. --- src/templates/partials/tx_details.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/templates/partials/tx_details.html b/src/templates/partials/tx_details.html index 9fd52c3..eca5f79 100644 --- a/src/templates/partials/tx_details.html +++ b/src/templates/partials/tx_details.html @@ -81,15 +81,15 @@
-

Check which outputs belong to given Monero address and viewkey

+

Check which outputs belong to given Monero address/subaddress and viewkey

For RingCT transactions, outputs' amounts are also decoded
- Note: address and viewkey are sent to the server, as the calculations are done on the server side + Note: address/subaddress and viewkey are sent to the server, as the calculations are done on the server side

-
+

@@ -108,12 +108,12 @@ Tx private key can be obtained using get_tx_key command in monero-wallet-cli command line tool
- Note: address and tx private key are sent to the server, as the calculations are done on the server side + Note: address/subaddress and tx private key are sent to the server, as the calculations are done on the server side

-
+
From 6e6d47eeefda8476855bf0975d83a39edfd1f508 Mon Sep 17 00:00:00 2001 From: ajs Date: Tue, 31 Oct 2017 19:06:32 +0200 Subject: [PATCH 07/27] Added Atesti to Clearnet versions --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3058dcb..349a024 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Clearnet versions: - [https://moneroexplorer.pro/](https://moneroexplorer.pro/) - nice looking one, https enabled. - [https://explorer.monero-otc.com/](https://explorer.monero-otc.com/) - https enabled. - [http://monerochain.com/](http://monerochain.com/) - JSON API based, multiple nodes. + - [http://atesti.mooo.com:8081/](http://atesti.mooo.com:8081/) - Proof of Existence built with Monero and IPFS. Clearnet testnet Monero version: From 0b6123be6e1f6f963298d92d59e4ff0597144260 Mon Sep 17 00:00:00 2001 From: ajs Date: Tue, 31 Oct 2017 19:06:32 +0200 Subject: [PATCH 08/27] Added Atesti to Clearnet versions --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3058dcb..349a024 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Clearnet versions: - [https://moneroexplorer.pro/](https://moneroexplorer.pro/) - nice looking one, https enabled. - [https://explorer.monero-otc.com/](https://explorer.monero-otc.com/) - https enabled. - [http://monerochain.com/](http://monerochain.com/) - JSON API based, multiple nodes. + - [http://atesti.mooo.com:8081/](http://atesti.mooo.com:8081/) - Proof of Existence built with Monero and IPFS. Clearnet testnet Monero version: From 5ef7ca1412e968fc3b89bf7f90ef7a2203b5d7f3 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Wed, 8 Nov 2017 15:51:59 +0800 Subject: [PATCH 09/27] readme updated to Monero v0.11.1.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 349a024..2df5802 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ git clone https://github.com/monero-project/monero cd monero/ # checkout last monero version -git checkout -b last_release v0.11.0.0 +git checkout -b last_release v0.11.1.0 make ``` From 886d2a57494ccd573c0a133ff1f347f12065b5b9 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Wed, 8 Nov 2017 16:17:38 +0800 Subject: [PATCH 10/27] fix: show integrated address details --- src/page.h | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/src/page.h b/src/page.h index 35b1a9a..fe95a42 100644 --- a/src/page.h +++ b/src/page.h @@ -3454,7 +3454,7 @@ namespace xmreg bool testnet_addr {false}; - if (search_text[0] == '9' || search_text[0] == 'A') + if (search_text[0] == '9' || search_text[0] == 'A' || search_text[0] == 'B') testnet_addr = true; if (!xmreg::parse_str_address(search_text, address_info, testnet_addr)) @@ -3467,31 +3467,26 @@ namespace xmreg return show_address_details(address_info, testnet_addr); } -// // check if integrated monero address is given based on its length -// // if yes, then show its public components search tx based on encrypted id -// @todo does not work with integrated address for now -// if (search_str_length == 106) -// { -// -// cryptonote::account_public_address address; -// -// bool has_payment_id; -// -// crypto::hash8 encrypted_payment_id; -// -// if (!get_account_integrated_address_from_str(address_info.address, -// has_payment_id, -// encrypted_payment_id, -// testnet, -// search_text)) -// { -// cerr << "Cant parse string integerated address: " << search_text << endl; -// return string("Cant parse address (probably incorrect format): ") -// + search_text; -// } -// -// return show_integrated_address_details(address_info.address, encrypted_payment_id, testnet); -// } + // check if integrated monero address is given based on its length + // if yes, then show its public components search tx based on encrypted id + if (search_str_length == 106) + { + + cryptonote::account_public_address address; + + address_parse_info address_info; + + if (!get_account_address_from_str(address_info, testnet, search_text)) + { + cerr << "Cant parse string integerated address: " << search_text << endl; + return string("Cant parse address (probably incorrect format): ") + + search_text; + } + + return show_integrated_address_details(address_info, + address_info.payment_id, + testnet); + } // all_possible_tx_hashes was field using custom lmdb database // it was dropped, so all_possible_tx_hashes will be alwasy empty From ddc6ef740593ea0b3a0624e036fe40d5181c207e Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Thu, 9 Nov 2017 08:14:18 +0800 Subject: [PATCH 11/27] apply patch from @stoffu for sub-addresses https://github.com/moneroexamples/onion-monero-blockchain-explorer/pull/86#issuecomment-342997868 --- .gitignore | 1 + src/page.h | 128 ++++++++++++++++++++++++++++++++++++++++++++++---- src/tools.cpp | 30 ++++++++---- src/tools.h | 23 +++++++++ 4 files changed, 162 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 1d63d7d..832ca90 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ *.log *.orig tests/ +build/ cmake-build-debug/ diff --git a/src/page.h b/src/page.h index fe95a42..a7b349b 100644 --- a/src/page.h +++ b/src/page.h @@ -126,6 +126,7 @@ namespace xmreg crypto::hash hash; crypto::hash prefix_hash; crypto::public_key pk; + std::vector additional_pks; uint64_t xmr_inputs; uint64_t xmr_outputs; uint64_t num_nonrct_inputs; @@ -1469,11 +1470,22 @@ namespace xmreg // parse string representing given private key crypto::secret_key prv_view_key; - if (!xmreg::parse_str_secret_key(viewkey_str, prv_view_key)) + std::vector multiple_tx_secret_keys; + + if (!xmreg::parse_str_secret_key(viewkey_str, multiple_tx_secret_keys)) { cerr << "Cant parse the private key: " << viewkey_str << endl; return string("Cant parse private key: " + viewkey_str); } + if (multiple_tx_secret_keys.size() == 1) + { + prv_view_key = multiple_tx_secret_keys[0]; + } + else if (!tx_prove) + { + cerr << "Concatenated secret keys are only for tx proving!" << endl; + return string("Concatenated secret keys are only for tx proving!"); + } // just to see how would having spend keys could worked @@ -1648,12 +1660,20 @@ namespace xmreg // public transaction key is combined with our viewkey // to create, so called, derived key. key_derivation derivation; + std::vector additional_derivations(txd.additional_pks.size()); + + //cout << multiple_tx_secret_keys.size() << " " << txd.additional_pks.size() + 1 << '\n'; + + if (tx_prove && multiple_tx_secret_keys.size() != txd.additional_pks.size() + 1) + { + return string("This transaction includes additional tx pubkeys whose size doesn't match with the provided tx secret keys"); + } public_key pub_key = tx_prove ? address_info.address.m_view_public_key : txd.pk; //cout << "txd.pk: " << pod_to_hex(txd.pk) << endl; - if (!generate_key_derivation(pub_key, prv_view_key, derivation)) + if (!generate_key_derivation(pub_key, tx_prove ? multiple_tx_secret_keys[0] : prv_view_key, derivation)) { cerr << "Cant get derived key for: " << "\n" << "pub_tx_key: " << pub_key << " and " @@ -1661,6 +1681,17 @@ namespace xmreg return string("Cant get key_derivation"); } + for (size_t i = 0; i < txd.additional_pks.size(); ++i) + { + if (!generate_key_derivation(tx_prove ? pub_key : txd.additional_pks[i], tx_prove ? multiple_tx_secret_keys[i + 1] : prv_view_key, additional_derivations[i])) + { + cerr << "Cant get derived key for: " << "\n" + << "pub_tx_key: " << txd.additional_pks[i] << " and " + << "prv_view_key" << prv_view_key << endl; + + return string("Cant get key_derivation"); + } + } // decrypt encrypted payment id, as used in integreated addresses crypto::hash8 decrypted_payment_id8 = txd.payment_id8; @@ -1701,6 +1732,16 @@ namespace xmreg // check if generated public key matches the current output's key bool mine_output = (outp.first.key == tx_pubkey); + bool with_additional = false; + if (!mine_output && txd.additional_pks.size() == txd.output_pub_keys.size()) + { + derive_public_key(additional_derivations[output_idx], + output_idx, + address_info.address.m_spend_public_key, + tx_pubkey); + mine_output = (outp.first.key == tx_pubkey); + with_additional = true; + } // if mine output has RingCT, i.e., tx version is 2 if (mine_output && tx.version == 2) @@ -1716,8 +1757,7 @@ namespace xmreg bool r; r = decode_ringct(tx.rct_signatures, - pub_key, - prv_view_key, + with_additional ? additional_derivations[output_idx] : derivation, output_idx, tx.rct_signatures.ecdhInfo[output_idx].mask, rct_amount); @@ -1888,12 +1928,14 @@ namespace xmreg public_key mixin_tx_pub_key = xmreg::get_tx_pub_key_from_received_outs(mixin_tx); + std::vector mixin_additional_tx_pub_keys = cryptonote::get_additional_tx_pub_keys_from_extra(mixin_tx); string mixin_tx_pub_key_str = pod_to_hex(mixin_tx_pub_key); // public transaction key is combined with our viewkey // to create, so called, derived key. key_derivation derivation; + std::vector additional_derivations(mixin_additional_tx_pub_keys.size()); if (!generate_key_derivation(mixin_tx_pub_key, prv_view_key, derivation)) { @@ -1903,6 +1945,17 @@ namespace xmreg continue; } + for (size_t i = 0; i < mixin_additional_tx_pub_keys.size(); ++i) + { + if (!generate_key_derivation(mixin_additional_tx_pub_keys[i], prv_view_key, additional_derivations[i])) + { + cerr << "Cant get derived key for: " << "\n" + << "pub_tx_key: " << mixin_additional_tx_pub_keys[i] << " and " + << "prv_view_key" << prv_view_key << endl; + + continue; + } + } // vector> output_pub_keys; @@ -1953,6 +2006,16 @@ namespace xmreg // check if generated public key matches the current output's key bool mine_output = (txout_k.key == tx_pubkey_generated); + bool with_additional = false; + if (!mine_output && mixin_additional_tx_pub_keys.size() == output_pub_keys.size()) + { + derive_public_key(additional_derivations[output_idx_in_tx], + output_idx_in_tx, + address_info.address.m_spend_public_key, + tx_pubkey_generated); + mine_output = (txout_k.key == tx_pubkey_generated); + with_additional = true; + } if (mine_output && mixin_tx.version == 2) @@ -1967,8 +2030,7 @@ namespace xmreg bool r; r = decode_ringct(mixin_tx.rct_signatures, - mixin_tx_pub_key, - prv_view_key, + with_additional ? additional_derivations[output_idx_in_tx] : derivation, output_idx_in_tx, mixin_tx.rct_signatures.ecdhInfo[output_idx_in_tx].mask, rct_amount); @@ -3308,6 +3370,7 @@ namespace xmreg } public_key tx_pub_key = xmreg::get_tx_pub_key_from_received_outs(tx); + std::vector additional_tx_pub_keys = cryptonote::get_additional_tx_pub_keys_from_extra(tx); // cointbase txs have amounts in plain sight. // so use amount from ringct, only for non-coinbase txs @@ -3320,6 +3383,12 @@ namespace xmreg td.m_internal_output_index, tx.rct_signatures.ecdhInfo[td.m_internal_output_index].mask, xmr_amount); + r = r || decode_ringct(tx.rct_signatures, + additional_tx_pub_keys[td.m_internal_output_index], + prv_view_key, + td.m_internal_output_index, + tx.rct_signatures.ecdhInfo[td.m_internal_output_index].mask, + xmr_amount); if (!r) { @@ -4627,6 +4696,7 @@ namespace xmreg // public transaction key is combined with our viewkey // to create, so called, derived key. key_derivation derivation; + std::vector additional_derivations(txd.additional_pks.size()); public_key pub_key = tx_prove ? address_info.address.m_view_public_key : txd.pk; @@ -4638,6 +4708,15 @@ namespace xmreg j_response["message"] = "Cant calculate key_derivation"; return j_response; } + for (size_t i = 0; i < txd.additional_pks.size(); ++i) + { + if (!generate_key_derivation(txd.additional_pks[i], prv_view_key, additional_derivations[i])) + { + j_response["status"] = "error"; + j_response["message"] = "Cant calculate key_derivation"; + return j_response; + } + } uint64_t output_idx {0}; @@ -4661,6 +4740,16 @@ namespace xmreg // check if generated public key matches the current output's key bool mine_output = (outp.first.key == tx_pubkey); + bool with_additional = false; + if (!mine_output && txd.additional_pks.size() == txd.output_pub_keys.size()) + { + derive_public_key(additional_derivations[output_idx], + output_idx, + address_info.address.m_spend_public_key, + tx_pubkey); + mine_output = (outp.first.key == tx_pubkey); + with_additional = true; + } // if mine output has RingCT, i.e., tx version is 2 if (mine_output && tx.version == 2) @@ -4676,8 +4765,7 @@ namespace xmreg bool r; r = decode_ringct(tx.rct_signatures, - pub_key, - prv_view_key, + with_additional ? additional_derivations[output_idx] : derivation, output_idx, tx.rct_signatures.ecdhInfo[output_idx].mask, rct_amount); @@ -5081,6 +5169,16 @@ namespace xmreg return false; } + std::vector additional_derivations(txd.additional_pks.size()); + for (size_t i = 0; i < txd.additional_pks.size(); ++i) + { + if (!generate_key_derivation(txd.additional_pks[i], prv_view_key, additional_derivations[i])) + { + error_msg = "Cant calculate key_derivation"; + return false; + } + } + uint64_t output_idx{0}; std::vector money_transfered(tx.vout.size(), 0); @@ -5103,6 +5201,16 @@ namespace xmreg // check if generated public key matches the current output's key bool mine_output = (outp.first.key == tx_pubkey); + bool with_additional = false; + if (!mine_output && txd.additional_pks.size() == txd.output_pub_keys.size()) + { + derive_public_key(additional_derivations[output_idx], + output_idx, + address.m_spend_public_key, + tx_pubkey); + mine_output = (outp.first.key == tx_pubkey); + with_additional = true; + } // if mine output has RingCT, i.e., tx version is 2 if (mine_output && tx.version == 2) @@ -5120,8 +5228,7 @@ namespace xmreg rct::key mask = tx.rct_signatures.ecdhInfo[output_idx].mask; r = decode_ringct(tx.rct_signatures, - txd.pk, - prv_view_key, + with_additional ? additional_derivations[output_idx] : derivation, output_idx, mask, rct_amount); @@ -5747,6 +5854,7 @@ namespace xmreg // due to previous bug with sining txs: // https://github.com/monero-project/monero/pull/1358/commits/7abfc5474c0f86e16c405f154570310468b635c2 txd.pk = xmreg::get_tx_pub_key_from_received_outs(tx); + txd.additional_pks = cryptonote::get_additional_tx_pub_keys_from_extra(tx); // sum xmr in inputs and ouputs in the given tx diff --git a/src/tools.cpp b/src/tools.cpp index 1bb0501..8d7cda6 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -903,19 +903,29 @@ namespace xmreg unsigned int i, rct::key & mask, uint64_t & amount) + { + crypto::key_derivation derivation; + + bool r = crypto::generate_key_derivation(pub, sec, derivation); + + if (!r) + { + cerr <<"Failed to generate key derivation to decode rct output " << i << endl; + return false; + } + + return decode_ringct(rv, derivation, i, mask, amount); + } + + bool + decode_ringct(const rct::rctSig& rv, + const crypto::key_derivation &derivation, + unsigned int i, + rct::key & mask, + uint64_t & amount) { try { - crypto::key_derivation derivation; - - bool r = crypto::generate_key_derivation(pub, sec, derivation); - - if (!r) - { - cerr <<"Failed to generate key derivation to decode rct output " << i << endl; - return false; - } - crypto::secret_key scalar1; crypto::derivation_to_scalar(derivation, i, scalar1); diff --git a/src/tools.h b/src/tools.h index a22d314..1cc3431 100644 --- a/src/tools.h +++ b/src/tools.h @@ -72,6 +72,22 @@ namespace xmreg bool parse_str_secret_key(const string& key_str, T& secret_key); + template + bool + parse_str_secret_key(const string& key_str, std::vector& secret_keys) + { + const size_t num_keys = key_str.size() / 64; + if (num_keys * 64 != key_str.size()) + return false; + secret_keys.resize(num_keys); + for (size_t i = 0; i < num_keys; ++i) + { + if (!parse_str_secret_key(key_str.substr(64*i, 64), secret_keys[i])) + return false; + } + return true; + } + bool get_tx_pub_key_from_str_hash(Blockchain& core_storage, @@ -227,6 +243,13 @@ namespace xmreg rct::key & mask, uint64_t & amount); + bool + decode_ringct(const rct::rctSig & rv, + const crypto::key_derivation &derivation, + unsigned int i, + rct::key & mask, + uint64_t & amount); + bool url_decode(const std::string& in, std::string& out); From 4e68bcf8c6fb9e10c8a751d17a14e6634fbbe0f7 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Thu, 9 Nov 2017 10:31:19 +0800 Subject: [PATCH 12/27] small formating updates --- src/page.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/page.h b/src/page.h index 903c4d0..d6b60cf 100644 --- a/src/page.h +++ b/src/page.h @@ -1666,14 +1666,17 @@ namespace xmreg if (tx_prove && multiple_tx_secret_keys.size() != txd.additional_pks.size() + 1) { - return string("This transaction includes additional tx pubkeys whose size doesn't match with the provided tx secret keys"); + return string("This transaction includes additional tx pubkeys whose " + "size doesn't match with the provided tx secret keys"); } public_key pub_key = tx_prove ? address_info.address.m_view_public_key : txd.pk; //cout << "txd.pk: " << pod_to_hex(txd.pk) << endl; - if (!generate_key_derivation(pub_key, tx_prove ? multiple_tx_secret_keys[0] : prv_view_key, derivation)) + if (!generate_key_derivation(pub_key, + tx_prove ? multiple_tx_secret_keys[0] : prv_view_key, + derivation)) { cerr << "Cant get derived key for: " << "\n" << "pub_tx_key: " << pub_key << " and " @@ -1681,9 +1684,12 @@ namespace xmreg return string("Cant get key_derivation"); } + for (size_t i = 0; i < txd.additional_pks.size(); ++i) { - if (!generate_key_derivation(tx_prove ? pub_key : txd.additional_pks[i], tx_prove ? multiple_tx_secret_keys[i + 1] : prv_view_key, additional_derivations[i])) + if (!generate_key_derivation(tx_prove ? pub_key : txd.additional_pks[i], + tx_prove ? multiple_tx_secret_keys[i + 1] : prv_view_key, + additional_derivations[i])) { cerr << "Cant get derived key for: " << "\n" << "pub_tx_key: " << txd.additional_pks[i] << " and " @@ -1732,14 +1738,18 @@ namespace xmreg // check if generated public key matches the current output's key bool mine_output = (outp.first.key == tx_pubkey); + bool with_additional = false; + if (!mine_output && txd.additional_pks.size() == txd.output_pub_keys.size()) { derive_public_key(additional_derivations[output_idx], output_idx, address_info.address.m_spend_public_key, tx_pubkey); + mine_output = (outp.first.key == tx_pubkey); + with_additional = true; } From 432db7e6da4bd58d915457d5ad66160dae6ce7b9 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Mon, 20 Nov 2017 08:39:08 +0800 Subject: [PATCH 13/27] proving raw tx added --- main.cpp | 14 +++++++++----- src/page.h | 2 +- src/rpccalls.h | 3 ++- src/templates/partials/tx_details.html | 2 ++ 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/main.cpp b/main.cpp index e7ba34e..aa17fbf 100644 --- a/main.cpp +++ b/main.cpp @@ -342,14 +342,18 @@ main(int ac, const char* av[]) "tx hash not provided"); } - string tx_hash = post_body["txhash"];; - string tx_prv_key = post_body["txprvkey"];; - string xmr_address = post_body["xmraddress"];; + string tx_hash = post_body["txhash"]; + string tx_prv_key = post_body["txprvkey"]; + string xmr_address = post_body["xmraddress"]; + + // this will be only not empty when checking raw tx data + // using tx pusher + string raw_tx_data = post_body["raw_tx_data"]; string domain = get_domain(req); return xmrblocks.show_prove(tx_hash, xmr_address, - tx_prv_key, domain); + tx_prv_key, raw_tx_data, domain); }); @@ -360,7 +364,7 @@ main(int ac, const char* av[]) string domain = get_domain(req); return xmrblocks.show_prove(tx_hash, xmr_address, - tx_prv_key, domain); + tx_prv_key, string {}, domain); }); if (enable_pusher) diff --git a/src/page.h b/src/page.h index d6b60cf..474797c 100644 --- a/src/page.h +++ b/src/page.h @@ -2191,9 +2191,9 @@ namespace xmreg show_prove(string tx_hash_str, string xmr_address_str, string tx_prv_key_str, + string const& raw_tx_data, string domain) { - string raw_tx_data {""}; // not using it in prove tx. only for outputs return show_my_outputs(tx_hash_str, xmr_address_str, tx_prv_key_str, raw_tx_data, diff --git a/src/rpccalls.h b/src/rpccalls.h index cbe14ca..1e8ef83 100644 --- a/src/rpccalls.h +++ b/src/rpccalls.h @@ -9,6 +9,7 @@ #include "monero_headers.h" #include +#include @@ -23,7 +24,7 @@ struct has_destructor { // has destructor template - static std::true_type test(decltype(declval().~A()) *) + static std::true_type test(decltype(std::declval().~A()) *) { return std::true_type(); } diff --git a/src/templates/partials/tx_details.html b/src/templates/partials/tx_details.html index eca5f79..cf431d6 100644 --- a/src/templates/partials/tx_details.html +++ b/src/templates/partials/tx_details.html @@ -113,6 +113,8 @@


+ +
From b969375ea0ab8cae722804e16ecd49b6ac5e3185 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Mon, 20 Nov 2017 09:06:14 +0800 Subject: [PATCH 14/27] readme updated --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 2df5802..20fc56f 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ The key features of the Onion Monero Blockchain Explorer are: - estimate possible spendings based on address and viewkey, - can provide total amount of all miner fees. - decoding encrypted payment id. + - decoding outputs and proving txs sent to sub-address. ## Compilation on Ubuntu 16.04 @@ -99,9 +100,6 @@ git clone https://github.com/monero-project/monero cd monero/ -# checkout last monero version -git checkout -b last_release v0.11.1.0 - make ``` From 0186a579648cca70930f3d93b147c747395f35c3 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Mon, 20 Nov 2017 09:06:34 +0800 Subject: [PATCH 15/27] readme updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20fc56f..51006d0 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ The key features of the Onion Monero Blockchain Explorer are: ## Compilation on Ubuntu 16.04 -##### Compile latest Monero release v0.11 +##### Compile latest Monero development version Download and compile recent Monero into your home folder: From 8bbcfc938039adc54bd9d03cbd305706994d530c Mon Sep 17 00:00:00 2001 From: stoffu Date: Fri, 15 Dec 2017 14:50:16 +0900 Subject: [PATCH 16/27] misc fixes to eliminate compiler warnings --- main.cpp | 1 + src/MempoolStatus.cpp | 2 +- src/page.h | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/main.cpp b/main.cpp index aa17fbf..4d7640f 100644 --- a/main.cpp +++ b/main.cpp @@ -392,6 +392,7 @@ main(int ac, const char* av[]) return xmrblocks.show_checkrawtx(raw_tx_data, action); else if (action == "push") return xmrblocks.show_pushrawtx(raw_tx_data, action); + return string("Provided action is neither check nor push"); }); } diff --git a/src/MempoolStatus.cpp b/src/MempoolStatus.cpp index 92da790..551df53 100644 --- a/src/MempoolStatus.cpp +++ b/src/MempoolStatus.cpp @@ -58,7 +58,7 @@ MempoolStatus::start_mempool_status_thread() else { cout << "Current network info read, "; - loop_index == 0; + loop_index = 0; } } diff --git a/src/page.h b/src/page.h index 474797c..fee3651 100644 --- a/src/page.h +++ b/src/page.h @@ -3129,7 +3129,7 @@ namespace xmreg context["data_prefix"] = data_prefix; - if (!strncmp(decoded_raw_data.c_str(), KEY_IMAGE_EXPORT_FILE_MAGIC, magiclen) == 0) + if (strncmp(decoded_raw_data.c_str(), KEY_IMAGE_EXPORT_FILE_MAGIC, magiclen) != 0) { string error_msg = fmt::format("This does not seem to be key image export data."); @@ -3274,7 +3274,7 @@ namespace xmreg context["data_prefix"] = data_prefix; - if (!strncmp(decoded_raw_data.c_str(), OUTPUT_EXPORT_FILE_MAGIC, magiclen) == 0) + if (strncmp(decoded_raw_data.c_str(), OUTPUT_EXPORT_FILE_MAGIC, magiclen) != 0) { string error_msg = fmt::format("This does not seem to be output keys export data."); From e5f9a155c8155ea139b09df934fc5b12594ae414 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Sat, 16 Dec 2017 16:12:32 +0800 Subject: [PATCH 17/27] use _tx_info.tx_blob instead of manually parsing json https://github.com/moneroexamples/onion-monero-blockchain-explorer/issues/89 --- src/MempoolStatus.cpp | 91 +++++++++++++++++++------------------------ src/tools.cpp | 11 ++++-- 2 files changed, 48 insertions(+), 54 deletions(-) diff --git a/src/MempoolStatus.cpp b/src/MempoolStatus.cpp index 92da790..9258d8b 100644 --- a/src/MempoolStatus.cpp +++ b/src/MempoolStatus.cpp @@ -126,75 +126,64 @@ MempoolStatus::read_mempool() // get transaction info of the tx in the mempool const tx_info& _tx_info = mempool_tx_info.at(i); - crypto::hash mem_tx_hash = null_hash; + transaction tx; + crypto::hash tx_hash; + crypto::hash tx_prefix_hash; - if (epee::string_tools::hex_to_pod(_tx_info.id_hash, mem_tx_hash)) + if (!parse_and_validate_tx_from_blob( + _tx_info.tx_blob, tx, tx_hash, tx_prefix_hash)) { - transaction tx; + cerr << "Cant make tx from _tx_info.tx_blob" << endl; + return false; + } - if (!xmreg::make_tx_from_json(_tx_info.tx_json, tx)) - { - cerr << "Cant make tx from _tx_info.tx_json" << endl; - return false; - } - crypto::hash tx_hash_reconstructed = get_transaction_hash(tx); + mempool_size_kB += _tx_info.blob_size; - if (mem_tx_hash != tx_hash_reconstructed) - { - cerr << "Hash of reconstructed tx from json does not match " - "what we should get!" - << endl; + local_copy_of_mempool_txs.push_back(mempool_tx {tx_hash, tx}); - return false; - } + mempool_tx& last_tx = local_copy_of_mempool_txs.back(); - mempool_size_kB += _tx_info.blob_size; + // key images of inputs + vector input_key_imgs; - local_copy_of_mempool_txs.push_back(mempool_tx {tx_hash_reconstructed, tx}); + // public keys and xmr amount of outputs + vector> output_pub_keys; - mempool_tx& last_tx = local_copy_of_mempool_txs.back(); + // sum xmr in inputs and ouputs in the given tx + const array& sum_data = summary_of_in_out_rct( + tx, output_pub_keys, input_key_imgs); - // key images of inputs - vector input_key_imgs; + last_tx.receive_time = _tx_info.receive_time; - // public keys and xmr amount of outputs - vector> output_pub_keys; + last_tx.sum_outputs = sum_data[0]; + last_tx.sum_inputs = sum_data[1]; + last_tx.no_outputs = output_pub_keys.size(); + last_tx.no_inputs = input_key_imgs.size(); + last_tx.mixin_no = sum_data[2]; + last_tx.num_nonrct_inputs = sum_data[3]; - // sum xmr in inputs and ouputs in the given tx - const array& sum_data = summary_of_in_out_rct( - tx, output_pub_keys, input_key_imgs); + last_tx.fee_str = xmreg::xmr_amount_to_str(_tx_info.fee, "{:0.3f}", false); + last_tx.xmr_inputs_str = xmreg::xmr_amount_to_str(last_tx.sum_inputs , "{:0.3f}"); + last_tx.xmr_outputs_str = xmreg::xmr_amount_to_str(last_tx.sum_outputs, "{:0.3f}"); + last_tx.timestamp_str = xmreg::timestamp_to_str_gm(_tx_info.receive_time); - last_tx.receive_time = _tx_info.receive_time; + last_tx.txsize = fmt::format("{:0.2f}", + static_cast(_tx_info.blob_size)/1024.0); - last_tx.sum_outputs = sum_data[0]; - last_tx.sum_inputs = sum_data[1]; - last_tx.no_outputs = output_pub_keys.size(); - last_tx.no_inputs = input_key_imgs.size(); - last_tx.mixin_no = sum_data[2]; - last_tx.num_nonrct_inputs = sum_data[3]; + last_tx.pID = '-'; - last_tx.fee_str = xmreg::xmr_amount_to_str(_tx_info.fee, "{:0.3f}", false); - last_tx.xmr_inputs_str = xmreg::xmr_amount_to_str(last_tx.sum_inputs , "{:0.3f}"); - last_tx.xmr_outputs_str = xmreg::xmr_amount_to_str(last_tx.sum_outputs, "{:0.3f}"); - last_tx.timestamp_str = xmreg::timestamp_to_str_gm(_tx_info.receive_time); + crypto::hash payment_id; + crypto::hash8 payment_id8; - last_tx.txsize = fmt::format("{:0.2f}", - static_cast(_tx_info.blob_size)/1024.0); + get_payment_id(tx, payment_id, payment_id8); - last_tx.pID = '-'; + if (payment_id != null_hash) + last_tx.pID = 'l'; // legacy payment id + else if (payment_id8 != null_hash8) + last_tx.pID = 'e'; // encrypted payment id - crypto::hash payment_id; - crypto::hash8 payment_id8; - - get_payment_id(tx, payment_id, payment_id8); - - if (payment_id != null_hash) - last_tx.pID = 'l'; // legacy payment id - else if (payment_id8 != null_hash8) - last_tx.pID = 'e'; // encrypted payment id - - } // if (hex_to_pod(_tx_info.id_hash, mem_tx_hash)) + // } // if (hex_to_pod(_tx_info.id_hash, mem_tx_hash)) } // for (size_t i = 0; i < mempool_tx_info.size(); ++i) diff --git a/src/tools.cpp b/src/tools.cpp index 8d7cda6..c88f766 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -1203,7 +1203,7 @@ namespace xmreg } - // cout << "\n\n j.dump()" << j.dump(4) << endl; + cout << "\n\n j.dump()" << j.dump(4) << '\n'; // get version and unlock time from json tx.version = j["version"].get(); @@ -1401,7 +1401,8 @@ namespace xmreg last_range_sig.asig = asig; memcpy(&(last_range_sig.Ci), &(key64_contained.Ci), sizeof(rct::key64)); - } + + } // for (json& range_s: j["rctsig_prunable"]["rangeSigs"]) vector& mg_sigs = rctsig_prunable.MGs; @@ -1441,7 +1442,11 @@ namespace xmreg } mg_sigs.push_back(new_mg_sig); - } + } // for (json& a_mgs: j["rctsig_prunable"]["MGs"]) + + //std::vector& bulletproof = rctsig_prunable.bulletproofs; + + } // j.find("rctsig_prunable") != j.end() From ad31f1850a80530f815b9ab49877a1bfbe68d284 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Sat, 16 Dec 2017 16:24:27 +0800 Subject: [PATCH 18/27] correctly decode amounts of bulletproof txs --- src/tools.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tools.cpp b/src/tools.cpp index c88f766..446f41e 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -918,11 +918,11 @@ namespace xmreg } bool - decode_ringct(const rct::rctSig& rv, - const crypto::key_derivation &derivation, + decode_ringct(rct::rctSig const& rv, + crypto::key_derivation const& derivation, unsigned int i, - rct::key & mask, - uint64_t & amount) + rct::key& mask, + uint64_t& amount) { try { @@ -933,25 +933,27 @@ namespace xmreg switch (rv.type) { case rct::RCTTypeSimple: + case rct::RCTTypeSimpleBulletproof: amount = rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask); break; case rct::RCTTypeFull: + case rct::RCTTypeFullBulletproof: amount = rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask); break; default: - cerr << "Unsupported rct type: " << rv.type << endl; + cerr << "Unsupported rct type: " << rv.type << '\n'; return false; } } catch (...) { - cerr << "Failed to decode input " << i << endl; + cerr << "Failed to decode input " << i << '\n'; return false; } From 93c3013366aa0d9b48d18e2d4731a0ba40dd60d2 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Sun, 17 Dec 2017 11:12:52 +0800 Subject: [PATCH 19/27] remove make_tx_from_json --- src/MempoolStatus.cpp | 65 +- src/tools.cpp | 2529 ++++++++++++++++++----------------------- 2 files changed, 1160 insertions(+), 1434 deletions(-) diff --git a/src/MempoolStatus.cpp b/src/MempoolStatus.cpp index 2239b2f..380d087 100644 --- a/src/MempoolStatus.cpp +++ b/src/MempoolStatus.cpp @@ -35,48 +35,48 @@ MempoolStatus::start_mempool_status_thread() { uint64_t loop_index {0}; - // so that network status is checked every minute - uint64_t loop_index_divider = std::max(1, 60 / mempool_refresh_time); + // so that network status is checked every minute + uint64_t loop_index_divider = std::max(1, 60 / mempool_refresh_time); - while (true) + while (true) + { + + // we just query network status every minute. No sense + // to do it as frequently as getting mempool data. + if (loop_index % loop_index_divider == 0) { - - // we just query network status every minute. No sense - // to do it as frequently as getting mempool data. - if (loop_index % loop_index_divider == 0) + if (!MempoolStatus::read_network_info()) { - if (!MempoolStatus::read_network_info()) - { - network_info local_copy = current_network_info; + network_info local_copy = current_network_info; - cerr << " Cant read network info "<< endl; + cerr << " Cant read network info "<< endl; - local_copy.current = false; + local_copy.current = false; - current_network_info = local_copy; - } - else - { - cout << "Current network info read, "; - loop_index = 0; - } + current_network_info = local_copy; } - - if (MempoolStatus::read_mempool()) + else { - vector current_mempool_txs = get_mempool_txs(); - - cout << "mempool status txs: " - << current_mempool_txs.size() - << endl; + cout << "Current network info read, "; + loop_index = 0; } + } - // when we reach top of the blockchain, update - // the emission amount every minute. - boost::this_thread::sleep_for( - boost::chrono::seconds(mempool_refresh_time)); + if (MempoolStatus::read_mempool()) + { + vector current_mempool_txs = get_mempool_txs(); - ++loop_index; + cout << "mempool status txs: " + << current_mempool_txs.size() + << endl; + } + + // when we reach top of the blockchain, update + // the emission amount every minute. + boost::this_thread::sleep_for( + boost::chrono::seconds(mempool_refresh_time)); + + ++loop_index; } // while (true) } @@ -84,7 +84,7 @@ MempoolStatus::start_mempool_status_thread() { cout << "Mempool status thread interrupted." << endl; return; - } + } }}; // m_thread = boost::thread{[]() @@ -137,7 +137,6 @@ MempoolStatus::read_mempool() return false; } - mempool_size_kB += _tx_info.blob_size; local_copy_of_mempool_txs.push_back(mempool_tx {tx_hash, tx}); diff --git a/src/tools.cpp b/src/tools.cpp index 446f41e..ac90da5 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -15,141 +15,141 @@ namespace xmreg * into crypto::secret_key or crypto::public_key * depending on the template argument. */ - template - bool - parse_str_secret_key(const string& key_str, T& secret_key) +template +bool +parse_str_secret_key(const string& key_str, T& secret_key) +{ + + // hash and keys have same structure, so to parse string of + // a key, e.g., a view key, we can first parse it into the hash + // object using parse_hash256 function, and then copy the reslting + // hash data into secret key. + crypto::hash hash_; + + if(!parse_hash256(key_str, hash_)) { - - // hash and keys have same structure, so to parse string of - // a key, e.g., a view key, we can first parse it into the hash - // object using parse_hash256 function, and then copy the reslting - // hash data into secret key. - crypto::hash hash_; - - if(!parse_hash256(key_str, hash_)) - { - cerr << "Cant parse a key (e.g. viewkey): " << key_str << endl; - return false; - } - - // crypto::hash and crypto::secret_key have basicly same - // structure. They both keep they key/hash as c-style char array - // of fixed size. Thus we can just copy data from hash - // to key - copy(begin(hash_.data), end(hash_.data), secret_key.data); - - return true; + cerr << "Cant parse a key (e.g. viewkey): " << key_str << endl; + return false; } + // crypto::hash and crypto::secret_key have basicly same + // structure. They both keep they key/hash as c-style char array + // of fixed size. Thus we can just copy data from hash + // to key + copy(begin(hash_.data), end(hash_.data), secret_key.data); + + return true; +} + // explicit instantiations of get template function - template bool parse_str_secret_key(const string& key_str, crypto::secret_key& secret_key); - template bool parse_str_secret_key(const string& key_str, crypto::public_key& secret_key); - template bool parse_str_secret_key(const string& key_str, crypto::hash& secret_key); +template bool parse_str_secret_key(const string& key_str, crypto::secret_key& secret_key); +template bool parse_str_secret_key(const string& key_str, crypto::public_key& secret_key); +template bool parse_str_secret_key(const string& key_str, crypto::hash& secret_key); /** - * Get transaction tx using given tx hash. Hash is represent as string here, - * so before we can tap into the blockchain, we need to pare it into - * crypto::hash object. - */ - bool - get_tx_pub_key_from_str_hash(Blockchain& core_storage, const string& hash_str, transaction& tx) +* Get transaction tx using given tx hash. Hash is represent as string here, +* so before we can tap into the blockchain, we need to pare it into +* crypto::hash object. +*/ +bool +get_tx_pub_key_from_str_hash(Blockchain& core_storage, const string& hash_str, transaction& tx) +{ + crypto::hash tx_hash; + parse_hash256(hash_str, tx_hash); + + try { - crypto::hash tx_hash; - parse_hash256(hash_str, tx_hash); - - try - { - // get transaction with given hash - tx = core_storage.get_db().get_tx(tx_hash); - } - catch (const TX_DNE& e) - { - cerr << e.what() << endl; - return false; - } - - return true; + // get transaction with given hash + tx = core_storage.get_db().get_tx(tx_hash); } + catch (const TX_DNE& e) + { + cerr << e.what() << endl; + return false; + } + + return true; +} /** - * Parse monero address in a string form into - * cryptonote::account_public_address object - */ - bool - parse_str_address(const string& address_str, - address_parse_info& address_info, - bool testnet) +* Parse monero address in a string form into +* cryptonote::account_public_address object +*/ +bool +parse_str_address(const string& address_str, + address_parse_info& address_info, + bool testnet) +{ + + if (!get_account_address_from_str(address_info, testnet, address_str)) { - - if (!get_account_address_from_str(address_info, testnet, address_str)) - { - cerr << "Error getting address: " << address_str << endl; - return false; - } - - return true; + cerr << "Error getting address: " << address_str << endl; + return false; } + return true; +} + /** - * Return string representation of monero address - */ - string - print_address(const address_parse_info& address_info, bool testnet) - { - return "<" + get_account_address_as_str( - testnet, address_info.is_subaddress, address_info.address) - + ">"; - } +* Return string representation of monero address +*/ +string +print_address(const address_parse_info& address_info, bool testnet) +{ + return "<" + get_account_address_as_str( + testnet, address_info.is_subaddress, address_info.address) + + ">"; +} - string - print_sig (const signature& sig) - { - stringstream ss; +string +print_sig (const signature& sig) +{ + stringstream ss; - ss << "c: <" << epee::string_tools::pod_to_hex(sig.c) << "> " - << "r: <" << epee::string_tools::pod_to_hex(sig.r) << ">"; + ss << "c: <" << epee::string_tools::pod_to_hex(sig.c) << "> " + << "r: <" << epee::string_tools::pod_to_hex(sig.r) << ">"; - return ss.str(); - } + return ss.str(); +} /** - * Check if a character is a path seprator - */ - inline bool - is_separator(char c) - { - // default linux path separator - const char separator = PATH_SEPARARTOR; +* Check if a character is a path seprator +*/ +inline bool +is_separator(char c) +{ + // default linux path separator + const char separator = PATH_SEPARARTOR; - return c == separator; - } + return c == separator; +} /** - * Remove trailinig path separator. - */ - string - remove_trailing_path_separator(const string& in_path) - { - string new_string = in_path; - if (!new_string.empty() && is_separator(new_string[new_string.size() - 1])) - new_string.erase(new_string.size() - 1); - return new_string; - } +* Remove trailinig path separator. +*/ +string +remove_trailing_path_separator(const string& in_path) +{ + string new_string = in_path; + if (!new_string.empty() && is_separator(new_string[new_string.size() - 1])) + new_string.erase(new_string.size() - 1); + return new_string; +} - bf::path - remove_trailing_path_separator(const bf::path& in_path) - { +bf::path +remove_trailing_path_separator(const bf::path& in_path) +{ #ifdef WIN32 - std::wstring_convert, wchar_t> converter; - string path_str = converter.to_bytes(in_path.native()); + std::wstring_convert, wchar_t> converter; +string path_str = converter.to_bytes(in_path.native()); #else - string path_str = in_path.native(); + string path_str = in_path.native(); #endif - return bf::path(remove_trailing_path_separator(path_str)); - } + return bf::path(remove_trailing_path_separator(path_str)); +} //string //timestamp_to_str(time_t timestamp, const char* format) @@ -158,1381 +158,1108 @@ namespace xmreg //} - string - timestamp_to_str_gm(time_t timestamp, const char* format) - { - const time_t* t = ×tamp; +string +timestamp_to_str_gm(time_t timestamp, const char* format) +{ + const time_t* t = ×tamp; - const int TIME_LENGTH = 60; + const int TIME_LENGTH = 60; - char str_buff[TIME_LENGTH]; + char str_buff[TIME_LENGTH]; - std::tm tmp; - gmtime_r(t, &tmp); + std::tm tmp; + gmtime_r(t, &tmp); - size_t len; + size_t len; - len = std::strftime(str_buff, TIME_LENGTH, format, &tmp); + len = std::strftime(str_buff, TIME_LENGTH, format, &tmp); - return string(str_buff, len); - } + return string(str_buff, len); +} - ostream& - operator<< (ostream& os, const address_parse_info& addr_info) - { - os << get_account_address_as_str(false, addr_info.is_subaddress, addr_info.address); - return os; - } +ostream& +operator<< (ostream& os, const address_parse_info& addr_info) +{ + os << get_account_address_as_str(false, addr_info.is_subaddress, addr_info.address); + return os; +} /* - * Generate key_image of foran ith output - */ - bool - generate_key_image(const crypto::key_derivation& derivation, - const std::size_t i, - const crypto::secret_key& sec_key, - const crypto::public_key& pub_key, - crypto::key_image& key_img) +* Generate key_image of foran ith output +*/ +bool +generate_key_image(const crypto::key_derivation& derivation, + const std::size_t i, + const crypto::secret_key& sec_key, + const crypto::public_key& pub_key, + crypto::key_image& key_img) +{ + + cryptonote::keypair in_ephemeral; + + if (!crypto::derive_public_key(derivation, i, + pub_key, + in_ephemeral.pub)) { - - cryptonote::keypair in_ephemeral; - - if (!crypto::derive_public_key(derivation, i, - pub_key, - in_ephemeral.pub)) - { - cerr << "Error generating publick key " << pub_key << endl; - return false; - } - - try - { - - crypto::derive_secret_key(derivation, i, - sec_key, - in_ephemeral.sec); - } - catch(const std::exception& e) - { - cerr << "Error generate secret image: " << e.what() << endl; - return false; - } - - - try - { - crypto::generate_key_image(in_ephemeral.pub, - in_ephemeral.sec, - key_img); - } - catch(const std::exception& e) - { - cerr << "Error generate key image: " << e.what() << endl; - return false; - } - - return true; + cerr << "Error generating publick key " << pub_key << endl; + return false; } - - string - get_default_lmdb_folder(bool testnet) + try { - // default path to monero folder - // on linux this is /home//.bitmonero - string default_monero_dir = tools::get_default_data_dir(); - if (testnet) - default_monero_dir += "/testnet"; - - - // the default folder of the lmdb blockchain database - // is therefore as follows - return default_monero_dir + string("/lmdb"); + crypto::derive_secret_key(derivation, i, + sec_key, + in_ephemeral.sec); } - - -/* - * Ge blockchain exception from command line option - * - * If not given, provide default path - */ - bool - get_blockchain_path(const boost::optional& bc_path, - bf::path& blockchain_path, - bool testnet) + catch(const std::exception& e) { - // the default folder of the lmdb blockchain database - string default_lmdb_dir = xmreg::get_default_lmdb_folder(testnet); - - blockchain_path = bc_path - ? bf::path(*bc_path) - : bf::path(default_lmdb_dir); - - if (!bf::is_directory(blockchain_path)) - { - cerr << "Given path \"" << blockchain_path << "\" " - << "is not a folder or does not exist" << " " - << endl; - - return false; - } - - blockchain_path = xmreg::remove_trailing_path_separator(blockchain_path); - - return true; - } - - - uint64_t - sum_money_in_outputs(const transaction& tx) - { - uint64_t sum_xmr {0}; - - for (const tx_out& txout: tx.vout) - { - sum_xmr += txout.amount; - } - - return sum_xmr; - } - - pair - sum_money_in_outputs(const string& json_str) - { - pair sum_xmr {0, 0}; - - json j; - - try - { - j = json::parse( json_str); - } - catch (std::invalid_argument& e) - { - cerr << "sum_money_in_outputs: " << e.what() << endl; - return sum_xmr; - } - - for (json& vout: j["vout"]) - { - sum_xmr.first += vout["amount"].get(); - ++sum_xmr.second; - } - - - return sum_xmr; - }; - - pair - sum_money_in_outputs(const json& _json) - { - pair sum_xmr {0ULL, 0ULL}; - - for (const json& vout: _json["vout"]) - { - sum_xmr.first += vout["amount"].get(); - ++sum_xmr.second; - } - - return sum_xmr; - }; - - - 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_inputs(const transaction& tx) - { - uint64_t sum_xmr {0}; - - 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]); - - sum_xmr += tx_in_to_key.amount; - } - - return sum_xmr; - } - - pair - sum_money_in_inputs(const string& json_str) - { - pair sum_xmr {0, 0}; - - json j; - try - { - j = json::parse( json_str); - } - catch (std::invalid_argument& e) - { - cerr << "sum_money_in_outputs: " << e.what() << endl; - return sum_xmr; - } - - for (json& vin: j["vin"]) - { - sum_xmr.first += vin["key"]["amount"].get(); - ++sum_xmr.second; - } - - return sum_xmr; - }; - - - pair - sum_money_in_inputs(const json& _json) - { - pair sum_xmr {0, 0}; - - for (const json& vin: _json["vin"]) - { - sum_xmr.first += vin["key"]["amount"].get(); - ++sum_xmr.second; - } - - return sum_xmr; - }; - - uint64_t - count_nonrct_inputs(const transaction& tx) - { - uint64_t num {0}; - - 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]); - - if (tx_in_to_key.amount != 0) - ++num; - } - - return num; - } - - uint64_t - count_nonrct_inputs(const string& json_str) - { - uint64_t num {0}; - - json j; - try - { - j = json::parse( json_str); - } - catch (std::invalid_argument& e) - { - cerr << "count_nonrct_inputs: " << e.what() << endl; - return num; - } - - for (json& vin: j["vin"]) - { - uint64_t amount = vin["key"]["amount"].get(); - if (amount != 0) - ++num; - } - - return num; - }; - - - uint64_t - count_nonrct_inputs(const json& _json) - { - uint64_t num {0}; - - for (const json& vin: _json["vin"]) - { - uint64_t amount = vin["key"]["amount"].get(); - if (amount != 0) - ++num; - } - - return num; - }; - - array - sum_money_in_tx(const transaction& tx) - { - array sum_xmr; - - sum_xmr[0] = sum_money_in_inputs(tx); - sum_xmr[1] = sum_money_in_outputs(tx); - - return sum_xmr; - }; - - - array - sum_money_in_txs(const vector& txs) - { - array sum_xmr {0,0}; - - for (const transaction& tx: txs) - { - sum_xmr[0] += sum_money_in_inputs(tx); - sum_xmr[1] += sum_money_in_outputs(tx); - } - - return sum_xmr; - }; - - - uint64_t - sum_fees_in_txs(const vector& txs) - { - uint64_t fees_sum {0}; - - for (const transaction& tx: txs) - { - fees_sum += get_tx_fee(tx); - } - - return fees_sum; - } - - - - vector> - get_ouputs(const transaction& tx) - { - vector> outputs; - - for (const tx_out& txout: tx.vout) - { - if (txout.target.type() != typeid(txout_to_key)) - { - // push empty pair. - outputs.push_back(pair{}); - continue; - } - - // get tx input key - const txout_to_key& txout_key - = boost::get(txout.target); - - outputs.push_back(make_pair(txout_key, txout.amount)); - } - - return outputs; - - }; - - vector> - get_ouputs_tuple(const transaction& tx) - { - vector> outputs; - - for (uint64_t n = 0; n < tx.vout.size(); ++n) - { - - if (tx.vout[n].target.type() != typeid(txout_to_key)) - { - continue; - } - - // get tx input key - const txout_to_key& txout_key - = boost::get(tx.vout[n].target); - - outputs.push_back(make_tuple(txout_key, tx.vout[n].amount, n)); - } - - return outputs; - }; - - uint64_t - get_mixin_no(const transaction& tx) - { - uint64_t mixin_no {0}; - - 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 txin_to_key& tx_in_to_key - = boost::get(tx.vin[i]); - - mixin_no = tx_in_to_key.key_offsets.size(); - - // look for first mixin number. - // all inputs in a single transaction have same number - if (mixin_no > 0) - { - break; - } - } - - return mixin_no; - } - vector - get_mixin_no(const string& json_str) - { - vector mixin_no; - - json j; - - try - { - j = json::parse(json_str); - - mixin_no.push_back(j["vin"].at(0)["key"]["key_offsets"].size()); - } - catch (std::invalid_argument& e) - { - cerr << "get_mixin_no: " << e.what() << endl; - return mixin_no; - } - - return mixin_no; - } - - vector - get_mixin_no(const json& _json) - { - vector mixin_no; - - mixin_no.push_back(_json["vin"].at(0)["key"]["key_offsets"].size()); - - return mixin_no; - } - - - - vector - get_mixin_no_in_txs(const vector& txs) - { - vector mixin_no; - - for (const transaction& tx: txs) - { - mixin_no.push_back(get_mixin_no(tx)); - } - - return mixin_no; - } - - - vector - get_key_images(const transaction& tx) - { - vector key_images; - - size_t input_no = tx.vin.size(); - - for (size_t i = 0; i < input_no; ++i) - { - - if(tx.vin[i].type() != typeid(txin_to_key)) - { - continue; - } - - // get tx input key - const txin_to_key& tx_in_to_key - = boost::get(tx.vin[i]); - - key_images.push_back(tx_in_to_key); - } - - return key_images; - } - - - bool - get_payment_id(const vector& extra, - crypto::hash& payment_id, - crypto::hash8& payment_id8) - { - payment_id = null_hash; - payment_id8 = null_hash8; - - std::vector tx_extra_fields; - - if(!parse_tx_extra(extra, tx_extra_fields)) - { - return false; - } - - tx_extra_nonce extra_nonce; - - if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) - { - // first check for encrypted id and then for normal one - if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) - { - return true; - } - else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) - { - return true; - } - } - + cerr << "Error generate secret image: " << e.what() << endl; return false; } - bool - get_payment_id(const transaction& tx, - crypto::hash& payment_id, - crypto::hash8& payment_id8) + try { - return get_payment_id(tx.extra, payment_id, payment_id8); + crypto::generate_key_image(in_ephemeral.pub, + in_ephemeral.sec, + key_img); + } + catch(const std::exception& e) + { + cerr << "Error generate key image: " << e.what() << endl; + return false; + } + + return true; +} + + +string +get_default_lmdb_folder(bool testnet) +{ + // default path to monero folder + // on linux this is /home//.bitmonero + string default_monero_dir = tools::get_default_data_dir(); + + if (testnet) + default_monero_dir += "/testnet"; + + + // the default folder of the lmdb blockchain database + // is therefore as follows + return default_monero_dir + string("/lmdb"); +} + + +/* +* Ge blockchain exception from command line option +* +* If not given, provide default path +*/ +bool +get_blockchain_path(const boost::optional& bc_path, + bf::path& blockchain_path, + bool testnet) +{ + // the default folder of the lmdb blockchain database + string default_lmdb_dir = xmreg::get_default_lmdb_folder(testnet); + + blockchain_path = bc_path + ? bf::path(*bc_path) + : bf::path(default_lmdb_dir); + + if (!bf::is_directory(blockchain_path)) + { + cerr << "Given path \"" << blockchain_path << "\" " + << "is not a folder or does not exist" << " " + << endl; + + return false; + } + + blockchain_path = xmreg::remove_trailing_path_separator(blockchain_path); + + return true; +} + + +uint64_t +sum_money_in_outputs(const transaction& tx) +{ + uint64_t sum_xmr {0}; + + for (const tx_out& txout: tx.vout) + { + sum_xmr += txout.amount; + } + + return sum_xmr; +} + +pair +sum_money_in_outputs(const string& json_str) +{ + pair sum_xmr {0, 0}; + + json j; + + try + { + j = json::parse( json_str); + } + catch (std::invalid_argument& e) + { + cerr << "sum_money_in_outputs: " << e.what() << endl; + return sum_xmr; + } + + for (json& vout: j["vout"]) + { + sum_xmr.first += vout["amount"].get(); + ++sum_xmr.second; } - array - timestamp_difference(uint64_t t1, uint64_t t2) + return sum_xmr; +}; + +pair +sum_money_in_outputs(const json& _json) +{ + pair sum_xmr {0ULL, 0ULL}; + + for (const json& vout: _json["vout"]) { - - uint64_t timestamp_diff = t1 - t2; - - // calculate difference of timestamps from current block to the mixin one - if (t2 > t1) - { - timestamp_diff = t2 - t1; - } - - uint64_t time_diff_years = timestamp_diff / 31536000; - - timestamp_diff -= time_diff_years * 31536000; - - uint64_t time_diff_days = timestamp_diff / 86400; - - timestamp_diff -= time_diff_days * 86400; - - uint64_t time_diff_hours = timestamp_diff / 3600; - - timestamp_diff -= time_diff_hours * 3600; - - uint64_t time_diff_minutes = timestamp_diff / 60; - - timestamp_diff -= time_diff_minutes * 60; - - uint64_t time_diff_seconds = timestamp_diff ; - - return array {time_diff_years, time_diff_days, - time_diff_hours, time_diff_minutes, - time_diff_seconds}; - - }; - - - string - read(string filename) - { - if (!bf::exists(bf::path(filename))) - { - cerr << "File does not exist: " << filename << endl; - return string(); - } - - std::ifstream t(filename); - return string(std::istreambuf_iterator(t), - std::istreambuf_iterator()); + sum_xmr.first += vout["amount"].get(); + ++sum_xmr.second; } - pair - timestamps_time_scale(const vector& timestamps, - uint64_t timeN, - uint64_t resolution, - uint64_t time0) + return sum_xmr; +}; + + +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) { - string empty_time = string(resolution, '_'); - - size_t time_axis_length = empty_time.size(); - - uint64_t interval_length = timeN-time0; - - double scale = double(interval_length) / double(time_axis_length); - - for (const auto& timestamp: timestamps) + if (txout.target.type() != typeid(txout_to_key)) { + // push empty pair. + output_pub_keys.push_back(pair{}); + continue; + } - if (timestamp < time0 || timestamp > timeN) + // 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_inputs(const transaction& tx) +{ + uint64_t sum_xmr {0}; + + 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]); + + sum_xmr += tx_in_to_key.amount; + } + + return sum_xmr; +} + +pair +sum_money_in_inputs(const string& json_str) +{ + pair sum_xmr {0, 0}; + + json j; + try + { + j = json::parse( json_str); + } + catch (std::invalid_argument& e) + { + cerr << "sum_money_in_outputs: " << e.what() << endl; + return sum_xmr; + } + + for (json& vin: j["vin"]) + { + sum_xmr.first += vin["key"]["amount"].get(); + ++sum_xmr.second; + } + + return sum_xmr; +}; + + +pair +sum_money_in_inputs(const json& _json) +{ + pair sum_xmr {0, 0}; + + for (const json& vin: _json["vin"]) + { + sum_xmr.first += vin["key"]["amount"].get(); + ++sum_xmr.second; + } + + return sum_xmr; +}; + +uint64_t +count_nonrct_inputs(const transaction& tx) +{ + uint64_t num {0}; + + 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]); + + if (tx_in_to_key.amount != 0) + ++num; + } + + return num; +} + +uint64_t +count_nonrct_inputs(const string& json_str) +{ + uint64_t num {0}; + + json j; + try + { + j = json::parse( json_str); + } + catch (std::invalid_argument& e) + { + cerr << "count_nonrct_inputs: " << e.what() << endl; + return num; + } + + for (json& vin: j["vin"]) + { + uint64_t amount = vin["key"]["amount"].get(); + if (amount != 0) + ++num; + } + + return num; +}; + + +uint64_t +count_nonrct_inputs(const json& _json) +{ + uint64_t num {0}; + + for (const json& vin: _json["vin"]) + { + uint64_t amount = vin["key"]["amount"].get(); + if (amount != 0) + ++num; + } + + return num; +}; + +array +sum_money_in_tx(const transaction& tx) +{ + array sum_xmr; + + sum_xmr[0] = sum_money_in_inputs(tx); + sum_xmr[1] = sum_money_in_outputs(tx); + + return sum_xmr; +}; + + +array +sum_money_in_txs(const vector& txs) +{ + array sum_xmr {0,0}; + + for (const transaction& tx: txs) + { + sum_xmr[0] += sum_money_in_inputs(tx); + sum_xmr[1] += sum_money_in_outputs(tx); + } + + return sum_xmr; +}; + + +uint64_t +sum_fees_in_txs(const vector& txs) +{ + uint64_t fees_sum {0}; + + for (const transaction& tx: txs) + { + fees_sum += get_tx_fee(tx); + } + + return fees_sum; +} + + + +vector> +get_ouputs(const transaction& tx) +{ + vector> outputs; + + for (const tx_out& txout: tx.vout) + { + if (txout.target.type() != typeid(txout_to_key)) + { + // push empty pair. + outputs.push_back(pair{}); + continue; + } + + // get tx input key + const txout_to_key& txout_key + = boost::get(txout.target); + + outputs.push_back(make_pair(txout_key, txout.amount)); + } + + return outputs; + +}; + +vector> +get_ouputs_tuple(const transaction& tx) +{ + vector> outputs; + + for (uint64_t n = 0; n < tx.vout.size(); ++n) + { + + if (tx.vout[n].target.type() != typeid(txout_to_key)) + { + continue; + } + + // get tx input key + const txout_to_key& txout_key + = boost::get(tx.vout[n].target); + + outputs.push_back(make_tuple(txout_key, tx.vout[n].amount, n)); + } + + return outputs; +}; + +uint64_t +get_mixin_no(const transaction& tx) +{ + uint64_t mixin_no {0}; + + 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 txin_to_key& tx_in_to_key + = boost::get(tx.vin[i]); + + mixin_no = tx_in_to_key.key_offsets.size(); + + // look for first mixin number. + // all inputs in a single transaction have same number + if (mixin_no > 0) + { + break; + } + } + + return mixin_no; +} +vector +get_mixin_no(const string& json_str) +{ + vector mixin_no; + + json j; + + try + { + j = json::parse(json_str); + + mixin_no.push_back(j["vin"].at(0)["key"]["key_offsets"].size()); + } + catch (std::invalid_argument& e) + { + cerr << "get_mixin_no: " << e.what() << endl; + return mixin_no; + } + + return mixin_no; +} + +vector +get_mixin_no(const json& _json) +{ + vector mixin_no; + + mixin_no.push_back(_json["vin"].at(0)["key"]["key_offsets"].size()); + + return mixin_no; +} + + + +vector +get_mixin_no_in_txs(const vector& txs) +{ + vector mixin_no; + + for (const transaction& tx: txs) + { + mixin_no.push_back(get_mixin_no(tx)); + } + + return mixin_no; +} + + +vector +get_key_images(const transaction& tx) +{ + vector key_images; + + size_t input_no = tx.vin.size(); + + for (size_t i = 0; i < input_no; ++i) + { + + if(tx.vin[i].type() != typeid(txin_to_key)) + { + continue; + } + + // get tx input key + const txin_to_key& tx_in_to_key + = boost::get(tx.vin[i]); + + key_images.push_back(tx_in_to_key); + } + + return key_images; +} + + +bool +get_payment_id(const vector& extra, + crypto::hash& payment_id, + crypto::hash8& payment_id8) +{ + payment_id = null_hash; + payment_id8 = null_hash8; + + std::vector tx_extra_fields; + + if(!parse_tx_extra(extra, tx_extra_fields)) + { + return false; + } + + tx_extra_nonce extra_nonce; + + if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) + { + // first check for encrypted id and then for normal one + if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) + { + return true; + } + else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + { + return true; + } + } + + return false; +} + + +bool +get_payment_id(const transaction& tx, + crypto::hash& payment_id, + crypto::hash8& payment_id8) +{ + return get_payment_id(tx.extra, payment_id, payment_id8); +} + + +array +timestamp_difference(uint64_t t1, uint64_t t2) +{ + + uint64_t timestamp_diff = t1 - t2; + + // calculate difference of timestamps from current block to the mixin one + if (t2 > t1) + { + timestamp_diff = t2 - t1; + } + + uint64_t time_diff_years = timestamp_diff / 31536000; + + timestamp_diff -= time_diff_years * 31536000; + + uint64_t time_diff_days = timestamp_diff / 86400; + + timestamp_diff -= time_diff_days * 86400; + + uint64_t time_diff_hours = timestamp_diff / 3600; + + timestamp_diff -= time_diff_hours * 3600; + + uint64_t time_diff_minutes = timestamp_diff / 60; + + timestamp_diff -= time_diff_minutes * 60; + + uint64_t time_diff_seconds = timestamp_diff ; + + return array {time_diff_years, time_diff_days, + time_diff_hours, time_diff_minutes, + time_diff_seconds}; + +}; + + +string +read(string filename) +{ + if (!bf::exists(bf::path(filename))) + { + cerr << "File does not exist: " << filename << endl; + return string(); + } + + std::ifstream t(filename); + return string(std::istreambuf_iterator(t), + std::istreambuf_iterator()); +} + +pair +timestamps_time_scale(const vector& timestamps, + uint64_t timeN, + uint64_t resolution, + uint64_t time0) +{ + string empty_time = string(resolution, '_'); + + size_t time_axis_length = empty_time.size(); + + uint64_t interval_length = timeN-time0; + + double scale = double(interval_length) / double(time_axis_length); + + for (const auto& timestamp: timestamps) + { + + if (timestamp < time0 || timestamp > timeN) + { + cout << "Out of range" << endl; + continue; + } + + uint64_t timestamp_place = double(timestamp-time0) + / double(interval_length)*(time_axis_length - 1); + + empty_time[timestamp_place + 1] = '*'; + } + + return make_pair(empty_time, scale); +} + +bool +decode_ringct(const rct::rctSig& rv, + const crypto::public_key pub, + const crypto::secret_key &sec, + unsigned int i, + rct::key & mask, + uint64_t & amount) +{ + crypto::key_derivation derivation; + + bool r = crypto::generate_key_derivation(pub, sec, derivation); + + if (!r) + { + cerr <<"Failed to generate key derivation to decode rct output " << i << endl; + return false; + } + + return decode_ringct(rv, derivation, i, mask, amount); +} + +bool +decode_ringct(rct::rctSig const& rv, + crypto::key_derivation const& derivation, + unsigned int i, + rct::key& mask, + uint64_t& amount) +{ + try + { + crypto::secret_key scalar1; + + crypto::derivation_to_scalar(derivation, i, scalar1); + + switch (rv.type) + { + case rct::RCTTypeSimple: + case rct::RCTTypeSimpleBulletproof: + amount = rct::decodeRctSimple(rv, + rct::sk2rct(scalar1), + i, + mask); + break; + case rct::RCTTypeFull: + case rct::RCTTypeFullBulletproof: + amount = rct::decodeRct(rv, + rct::sk2rct(scalar1), + i, + mask); + break; + default: + cerr << "Unsupported rct type: " << rv.type << '\n'; + return false; + } + } + catch (...) + { + cerr << "Failed to decode input " << i << '\n'; + return false; + } + + return true; +} + +bool +url_decode(const std::string& in, std::string& out) +{ + out.clear(); + out.reserve(in.size()); + for (std::size_t i = 0; i < in.size(); ++i) + { + if (in[i] == '%') + { + if (i + 3 <= in.size()) { - cout << "Out of range" << endl; - continue; - } - - uint64_t timestamp_place = double(timestamp-time0) - / double(interval_length)*(time_axis_length - 1); - - empty_time[timestamp_place + 1] = '*'; - } - - return make_pair(empty_time, scale); - } - - bool - decode_ringct(const rct::rctSig& rv, - const crypto::public_key pub, - const crypto::secret_key &sec, - unsigned int i, - rct::key & mask, - uint64_t & amount) - { - crypto::key_derivation derivation; - - bool r = crypto::generate_key_derivation(pub, sec, derivation); - - if (!r) - { - cerr <<"Failed to generate key derivation to decode rct output " << i << endl; - return false; - } - - return decode_ringct(rv, derivation, i, mask, amount); - } - - bool - decode_ringct(rct::rctSig const& rv, - crypto::key_derivation const& derivation, - unsigned int i, - rct::key& mask, - uint64_t& amount) - { - try - { - crypto::secret_key scalar1; - - crypto::derivation_to_scalar(derivation, i, scalar1); - - switch (rv.type) - { - case rct::RCTTypeSimple: - case rct::RCTTypeSimpleBulletproof: - amount = rct::decodeRctSimple(rv, - rct::sk2rct(scalar1), - i, - mask); - break; - case rct::RCTTypeFull: - case rct::RCTTypeFullBulletproof: - amount = rct::decodeRct(rv, - rct::sk2rct(scalar1), - i, - mask); - break; - default: - cerr << "Unsupported rct type: " << rv.type << '\n'; - return false; - } - } - catch (...) - { - cerr << "Failed to decode input " << i << '\n'; - return false; - } - - return true; - } - - bool - url_decode(const std::string& in, std::string& out) - { - out.clear(); - out.reserve(in.size()); - for (std::size_t i = 0; i < in.size(); ++i) - { - if (in[i] == '%') - { - if (i + 3 <= in.size()) + int value = 0; + std::istringstream is(in.substr(i + 1, 2)); + if (is >> std::hex >> value) { - int value = 0; - std::istringstream is(in.substr(i + 1, 2)); - if (is >> std::hex >> value) - { - out += static_cast(value); - i += 2; - } - else - { - return false; - } + out += static_cast(value); + i += 2; } else { return false; } } - else if (in[i] == '+') - { - out += ' '; - } else { - out += in[i]; + return false; } } - return true; - } - - map - parse_crow_post_data(const string& req_body) - { - map body; - - vector vec; - string tmp; - bool result = url_decode(req_body, tmp); - if (result) + else if (in[i] == '+') { - boost::algorithm::split(vec, tmp, [](char x) {return x == '&'; }); - for(auto &it : vec) - { - auto pos = it.find("="); - if (pos != string::npos) - { - body[it.substr(0, pos)] = it.substr(pos + 1); - } - else - { - break; - } - } - } - return body; - } - - -// from wallet2::decrypt - string - decrypt(const std::string &ciphertext, - const crypto::secret_key &skey, - bool authenticated) - { - - const size_t prefix_size = sizeof(chacha8_iv) - + (authenticated ? sizeof(crypto::signature) : 0); - if (ciphertext.size() < prefix_size) - { - cerr << "Unexpected ciphertext size" << endl; - return {}; - } - - crypto::chacha8_key key; - crypto::generate_chacha8_key(&skey, sizeof(skey), key); - - const crypto::chacha8_iv &iv = *(const crypto::chacha8_iv*)&ciphertext[0]; - - std::string plaintext; - - plaintext.resize(ciphertext.size() - prefix_size); - - if (authenticated) - { - crypto::hash hash; - crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash); - crypto::public_key pkey; - crypto::secret_key_to_public_key(skey, pkey); - - const crypto::signature &signature = - *(const crypto::signature*)&ciphertext[ciphertext.size() - - sizeof(crypto::signature)]; - - if (!crypto::check_signature(hash, pkey, signature)) - { - cerr << "Failed to authenticate criphertext" << endl; - return {}; - } - - } - - crypto::chacha8(ciphertext.data() + sizeof(iv), - ciphertext.size() - prefix_size, - key, iv, &plaintext[0]); - - return plaintext; - } - -// based on -// crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const - public_key - get_tx_pub_key_from_received_outs(const transaction &tx) - { - std::vector tx_extra_fields; - - if(!parse_tx_extra(tx.extra, tx_extra_fields)) - { - // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key - } - - // Due to a previous bug, there might be more than one tx pubkey in extra, one being - // the result of a previously discarded signature. - // For speed, since scanning for outputs is a slow process, we check whether extra - // contains more than one pubkey. If not, the first one is returned. If yes, they're - // checked for whether they yield at least one output - tx_extra_pub_key pub_key_field; - - if (!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 0)) - { - return null_pkey; - } - - public_key tx_pub_key = pub_key_field.pub_key; - - bool two_found = find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 1); - - if (!two_found) - { - // easy case, just one found - return tx_pub_key; + out += ' '; } else { - // just return second one if there are two. - // this does not require private view key, as - // its not needed for my use case. - return pub_key_field.pub_key; + out += in[i]; + } + } + return true; +} + +map +parse_crow_post_data(const string& req_body) +{ + map body; + + vector vec; + string tmp; + bool result = url_decode(req_body, tmp); + if (result) + { + boost::algorithm::split(vec, tmp, [](char x) {return x == '&'; }); + for(auto &it : vec) + { + auto pos = it.find("="); + if (pos != string::npos) + { + body[it.substr(0, pos)] = it.substr(pos + 1); + } + else + { + break; + } + } + } + return body; +} + + +// from wallet2::decrypt +string +decrypt(const std::string &ciphertext, + const crypto::secret_key &skey, + bool authenticated) +{ + + const size_t prefix_size = sizeof(chacha8_iv) + + (authenticated ? sizeof(crypto::signature) : 0); + if (ciphertext.size() < prefix_size) + { + cerr << "Unexpected ciphertext size" << endl; + return {}; + } + + crypto::chacha8_key key; + crypto::generate_chacha8_key(&skey, sizeof(skey), key); + + const crypto::chacha8_iv &iv = *(const crypto::chacha8_iv*)&ciphertext[0]; + + std::string plaintext; + + plaintext.resize(ciphertext.size() - prefix_size); + + if (authenticated) + { + crypto::hash hash; + crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash); + crypto::public_key pkey; + crypto::secret_key_to_public_key(skey, pkey); + + const crypto::signature &signature = + *(const crypto::signature*)&ciphertext[ciphertext.size() + - sizeof(crypto::signature)]; + + if (!crypto::check_signature(hash, pkey, signature)) + { + cerr << "Failed to authenticate criphertext" << endl; + return {}; } + } + + crypto::chacha8(ciphertext.data() + sizeof(iv), + ciphertext.size() - prefix_size, + key, iv, &plaintext[0]); + + return plaintext; +} + +// based on +// crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const +public_key +get_tx_pub_key_from_received_outs(const transaction &tx) +{ + std::vector tx_extra_fields; + + if(!parse_tx_extra(tx.extra, tx_extra_fields)) + { + // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key + } + + // Due to a previous bug, there might be more than one tx pubkey in extra, one being + // the result of a previously discarded signature. + // For speed, since scanning for outputs is a slow process, we check whether extra + // contains more than one pubkey. If not, the first one is returned. If yes, they're + // checked for whether they yield at least one output + tx_extra_pub_key pub_key_field; + + if (!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 0)) + { return null_pkey; } + public_key tx_pub_key = pub_key_field.pub_key; + + bool two_found = find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 1); + + if (!two_found) + { + // easy case, just one found + return tx_pub_key; + } + else + { + // just return second one if there are two. + // this does not require private view key, as + // its not needed for my use case. + return pub_key_field.pub_key; + } + + return null_pkey; +} + /** * Check if given output (specified by output_index) * belongs is ours based * on our private view key and public spend key */ - bool - is_output_ours(const size_t& output_index, - const transaction& tx, - const public_key& pub_tx_key, - const secret_key& private_view_key, - const public_key& public_spend_key) +bool +is_output_ours(const size_t& output_index, + const transaction& tx, + const public_key& pub_tx_key, + const secret_key& private_view_key, + const public_key& public_spend_key) +{ + // public transaction key is combined with our viewkey + // to create, so called, derived key. + key_derivation derivation; + + if (!generate_key_derivation(pub_tx_key, private_view_key, derivation)) { - // public transaction key is combined with our viewkey - // to create, so called, derived key. - key_derivation derivation; - - if (!generate_key_derivation(pub_tx_key, private_view_key, derivation)) - { - cerr << "Cant get dervied key for: " << "\n" - << "pub_tx_key: " << pub_tx_key << " and " - << "prv_view_key" << private_view_key << endl; - - return false; - } - - - // get the tx output public key - // that normally would be generated for us, - // if someone had sent us some xmr. - public_key pubkey; - - derive_public_key(derivation, - output_index, - public_spend_key, - pubkey); - - //cout << "\n" << tx.vout.size() << " " << output_index << endl; - - // get tx output public key - const txout_to_key tx_out_to_key - = boost::get(tx.vout[output_index].target); - - - if (tx_out_to_key.key == pubkey) - { - return true; - } + cerr << "Cant get dervied key for: " << "\n" + << "pub_tx_key: " << pub_tx_key << " and " + << "prv_view_key" << private_view_key << endl; return false; } - bool - get_real_output_for_key_image(const key_image& ki, - const transaction& tx, - const secret_key& private_view_key, - const public_key& public_spend_key, - uint64_t output_idx, - public_key output_pub_key) + // get the tx output public key + // that normally would be generated for us, + // if someone had sent us some xmr. + public_key pubkey; + + derive_public_key(derivation, + output_index, + public_spend_key, + pubkey); + + //cout << "\n" << tx.vout.size() << " " << output_index << endl; + + // get tx output public key + const txout_to_key tx_out_to_key + = boost::get(tx.vout[output_index].target); + + + if (tx_out_to_key.key == pubkey) { - - - - return false; - } - - - bool - make_tx_from_json(const string& json_str, transaction& tx) - { - json j; - - try - { - j = json::parse(json_str); - } - catch (std::invalid_argument& e) - { - cerr << "make_tx_from_json: cant parse json string: " << e.what() << endl; - return false; - } - - - cout << "\n\n j.dump()" << j.dump(4) << '\n'; - - // get version and unlock time from json - tx.version = j["version"].get(); - tx.unlock_time = j["unlock_time"].get(); - - // next get extra data - for (json& extra_val: j["extra"]) - tx.extra.push_back(extra_val.get()); - - - // now populate output data from json - vector& tx_outputs = tx.vout; - - for (json& vo: j["vout"]) - { - uint64_t amount = vo["amount"].get(); - - public_key out_pub_key; - - if (!epee::string_tools::hex_to_pod(vo["target"]["key"], out_pub_key)) - { - cerr << "Faild to parse public_key of an output from json" << endl; - return false; - } - - txout_target_v target {txout_to_key {out_pub_key}}; - - tx_outputs.push_back(tx_out {amount, target}); - } - - // now populate input data from json - vector& tx_inputs = tx.vin; - - for (json& vi: j["vin"]) - { - uint64_t amount = vi["key"]["amount"].get(); - - key_image in_key_image; - - if (!epee::string_tools::hex_to_pod(vi["key"]["k_image"], in_key_image)) - { - cerr << "Faild to parse key_image of an input from json" << endl; - return false; - } - - vector key_offsets; - - for (json& ko: vi["key"]["key_offsets"]) - { - key_offsets.push_back(ko.get()); - } - - txin_v _txin_v {txin_to_key {amount, key_offsets, in_key_image}}; - - tx_inputs.push_back(_txin_v); - } - - // add ring signatures field - - if (j.find("signatures") != j.end()) - { - vector>& signatures = tx.signatures; - - for (json& sigs: j["signatures"]) - { - string concatanted_sig = sigs; - - vector sig_split; - - auto split_sig = [&](string::iterator &b, string::iterator &e) - { - signature a_sig; - - if (!epee::string_tools::hex_to_pod(string(b, e), a_sig)) - { - cerr << "Faild to parse signature from json" << endl; - return false; - } - - sig_split.push_back(a_sig); - - return true; - }; - - chunks(concatanted_sig.begin(), concatanted_sig.end(), 128, split_sig); - - signatures.push_back(sig_split); - } - - } - - // now add rct_signatures from json to tx if exist - - if (j.find("rct_signatures") != j.end()) - { - rct::rctSig& rct_signatures = tx.rct_signatures; - - if (j["rct_signatures"].find("pseudoOuts") != j["rct_signatures"].end()) - { - rct::keyV& pseudoOuts = rct_signatures.pseudoOuts; - - for (json& pOut: j["rct_signatures"]["pseudoOuts"]) - { - rct::key pOut_key; - - if (!epee::string_tools::hex_to_pod(pOut, pOut_key)) - { - cerr << "Faild to parse pOut_key of pseudoOuts from json" << endl; - return false; - } - - pseudoOuts.push_back(pOut_key); - } - } - - vector& ecdhInfo = rct_signatures.ecdhInfo; - - for (json& ecdhI: j["rct_signatures"]["ecdhInfo"]) - { - rct::ecdhTuple a_tuple; - - //cout << "ecdhI[\"amount\"]: " << ecdhI["amount"] << endl; - - if (!epee::string_tools::hex_to_pod(ecdhI["amount"], a_tuple.amount)) - { - cerr << "Faild to parse ecdhInfo of an amount from json" << endl; - return false; - } - - //cout << epee::string_tools::pod_to_hex(a_tuple.amount) << endl; - - if (!epee::string_tools::hex_to_pod(ecdhI["mask"], a_tuple.mask)) - { - cerr << "Faild to parse ecdhInfo of an mask from json" << endl; - return false; - } - - ecdhInfo.push_back(a_tuple); - } - - vector& outPk = rct_signatures.outPk; - - for (json& pk: j["rct_signatures"]["outPk"]) - { - outPk.push_back(rct::ctkey {rct::zero(), rct::zero()}); - - rct::key& mask = outPk.back().mask; - - if (!epee::string_tools::hex_to_pod(pk, mask)) - { - cerr << "Faild to parse rct::key of an outPk from json" << endl; - return false; - } - - // cout << "dest: " << epee::string_tools::pod_to_hex(outPk.back().mask) << endl; - } - - rct_signatures.txnFee = j["rct_signatures"]["txnFee"].get(); - rct_signatures.type = j["rct_signatures"]["type"].get(); - - } // if (j.find("rct_signatures") != j.end()) - - - if (j.find("rctsig_prunable") != j.end()) - { - rct::rctSigPrunable& rctsig_prunable = tx.rct_signatures.p; - - vector& range_sigs = rctsig_prunable.rangeSigs; - - for (json& range_s: j["rctsig_prunable"]["rangeSigs"]) - { - rct::boroSig asig; - - if (!epee::string_tools::hex_to_pod(range_s["asig"], asig)) - { - cerr << "Faild to parse asig of an asnlSig from json" << endl; - return false; - } - - - struct { - rct::key64 Ci; - } key64_contained; - - if (!epee::string_tools::hex_to_pod(range_s["Ci"], key64_contained)) - { - cerr << "Faild to parse Ci of an asnlSig from json" << endl; - return false; - } - - range_sigs.push_back(rct::rangeSig {}); - - rct::rangeSig& last_range_sig = range_sigs.back(); - - last_range_sig.asig = asig; - - memcpy(&(last_range_sig.Ci), &(key64_contained.Ci), sizeof(rct::key64)); - - } // for (json& range_s: j["rctsig_prunable"]["rangeSigs"]) - - vector& mg_sigs = rctsig_prunable.MGs; - - for (json& a_mgs: j["rctsig_prunable"]["MGs"]) - { - rct::mgSig new_mg_sig; - - vector& ss = new_mg_sig.ss; - - for (json& ss_j: a_mgs["ss"]) - { - rct::key a_key1; - - if (!epee::string_tools::hex_to_pod(ss_j[0], a_key1)) - { - cerr << "Faild to parse ss a_key1 of an MGs from json" << endl; - return false; - } - - rct::key a_key2; - - if (!epee::string_tools::hex_to_pod(ss_j[1], a_key2)) - { - cerr << "Faild to parse ss a_key2 of an MGs from json" << endl; - return false; - } - - ss.push_back(vector{a_key1, a_key2}); - } - - json& cc_j = a_mgs["cc"]; - - if (!epee::string_tools::hex_to_pod(cc_j, new_mg_sig.cc)) - { - cerr << "Faild to parse cc an MGs from json" << endl; - return false; - } - - mg_sigs.push_back(new_mg_sig); - } // for (json& a_mgs: j["rctsig_prunable"]["MGs"]) - - //std::vector& bulletproof = rctsig_prunable.bulletproofs; - - - - } // j.find("rctsig_prunable") != j.end() - - - - - //cout << "From reconstructed tx: " << obj_to_json_str(tx) << endl; - return true; } + return false; +} - string - make_printable(const string& in_s) + +bool +get_real_output_for_key_image(const key_image& ki, + const transaction& tx, + const secret_key& private_view_key, + const public_key& public_spend_key, + uint64_t output_idx, + public_key output_pub_key) +{ + + + + return false; +} + + +string +make_printable(const string& in_s) +{ + string output; + + for (char c: in_s) { - string output; - for (char c: in_s) + if (isprint(c)) { - - if (isprint(c)) - { - output += c; + output += c; + } + else + { + switch(c){ + case '\000': output += "\\000";break; + case '\001': output += "\\001";break; + case '\002': output += "\\002";break; + case '\003': output += "\\003";break; + case '\004': output += "\\004";break; + case '\005': output += "\\005";break; + case '\006': output += "\\006";break; + case '\007': output += "\\007";break; + // there are more case but for now its ok + default: + stringstream ss; + ss << std::hex << (int)c; + output += "0x" + ss.str(); + break; } - else - { - switch(c){ - case '\000': output += "\\000";break; - case '\001': output += "\\001";break; - case '\002': output += "\\002";break; - case '\003': output += "\\003";break; - case '\004': output += "\\004";break; - case '\005': output += "\\005";break; - case '\006': output += "\\006";break; - case '\007': output += "\\007";break; - // there are more case but for now its ok - default: - stringstream ss; - ss << std::hex << (int)c; - output += "0x" + ss.str(); - break; - } - } - } - return output; } + return output; +} - string - get_human_readable_timestamp(uint64_t ts) +string +get_human_readable_timestamp(uint64_t ts) +{ + char buffer[64]; + if (ts < 1234567890) + return ""; + + time_t tt = ts; + + struct tm tm; + + gmtime_r(&tt, &tm); + + strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M:%S", &tm); + + return std::string(buffer); +} + +void +pause_execution(uint64_t no_seconds, const string& text) +{ + + cout << "\nPausing " << text + << " for " << no_seconds << " seconds: " + << flush; + + for (size_t i = 0; i < no_seconds; ++i) { - char buffer[64]; - if (ts < 1234567890) - return ""; - - time_t tt = ts; - - struct tm tm; - - gmtime_r(&tt, &tm); - - strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M:%S", &tm); - - return std::string(buffer); + cout << "." << flush; + std::this_thread::sleep_for(std::chrono::seconds(1)); } - void - pause_execution(uint64_t no_seconds, const string& text) - { - - cout << "\nPausing " << text - << " for " << no_seconds << " seconds: " - << flush; - - for (size_t i = 0; i < no_seconds; ++i) - { - cout << "." << flush; - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - - cout << endl; - } + cout << endl; +} } From 6724398b825bf0bdaf78bd2a8a084fc055e22e28 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Mon, 18 Dec 2017 08:04:09 +0800 Subject: [PATCH 20/27] include #include --- src/tools.cpp | 10 +++++----- src/tools.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools.cpp b/src/tools.cpp index ac90da5..78604cd 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -1010,18 +1010,18 @@ parse_crow_post_data(const string& req_body) bool result = url_decode(req_body, tmp); if (result) { - boost::algorithm::split(vec, tmp, [](char x) {return x == '&'; }); + boost::algorithm::split(vec, tmp, + [](char x) {return x == '&'; + }); + for(auto &it : vec) { auto pos = it.find("="); + if (pos != string::npos) - { body[it.substr(0, pos)] = it.substr(pos + 1); - } else - { break; - } } } return body; diff --git a/src/tools.h b/src/tools.h index 1cc3431..dbd96a0 100644 --- a/src/tools.h +++ b/src/tools.h @@ -24,7 +24,7 @@ #include #include #include - +#include #include #include From d3b3e4904cf4afd15b881c5df361331cbdd87e27 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Wed, 20 Dec 2017 06:31:04 +0800 Subject: [PATCH 21/27] upgrade crow to latest version --- CMakeLists.txt | 1 + ext/crow/crow.h | 250 ++--------------------- ext/crow/{ => crow}/TinySHA1.hpp | 0 ext/crow/crow/app.h | 248 ++++++++++++++++++++++ ext/crow/{ => crow}/ci_map.h | 0 ext/crow/{ => crow}/common.h | 7 +- ext/crow/{ => crow}/dumb_timer_queue.h | 2 +- ext/crow/{ => crow}/http_connection.h | 31 ++- ext/crow/{ => crow}/http_parser_merged.h | 0 ext/crow/{ => crow}/http_request.h | 7 +- ext/crow/{ => crow}/http_response.h | 13 +- ext/crow/{ => crow}/http_server.h | 67 +++++- ext/crow/{ => crow}/json.h | 37 +++- ext/crow/{ => crow}/logging.h | 2 +- ext/crow/{ => crow}/middleware.h | 89 +++----- ext/crow/{ => crow}/middleware_context.h | 6 +- ext/crow/{ => crow}/mustache.h | 7 +- ext/crow/{ => crow}/parser.h | 5 +- ext/crow/{ => crow}/query_string.h | 69 ++++++- ext/crow/{ => crow}/routing.h | 59 ++++-- ext/crow/{ => crow}/settings.h | 14 +- ext/crow/{ => crow}/socket_adaptors.h | 2 +- ext/crow/{ => crow}/utility.h | 6 +- ext/crow/{ => crow}/websocket.h | 67 ++++-- main.cpp | 9 +- src/page.h | 2 +- 26 files changed, 622 insertions(+), 378 deletions(-) mode change 100755 => 100644 ext/crow/crow.h rename ext/crow/{ => crow}/TinySHA1.hpp (100%) mode change 100755 => 100644 create mode 100644 ext/crow/crow/app.h rename ext/crow/{ => crow}/ci_map.h (100%) rename ext/crow/{ => crow}/common.h (94%) mode change 100755 => 100644 rename ext/crow/{ => crow}/dumb_timer_queue.h (98%) rename ext/crow/{ => crow}/http_connection.h (96%) mode change 100755 => 100644 rename ext/crow/{ => crow}/http_parser_merged.h (100%) mode change 100755 => 100644 rename ext/crow/{ => crow}/http_request.h (95%) mode change 100755 => 100644 rename ext/crow/{ => crow}/http_response.h (93%) mode change 100755 => 100644 rename ext/crow/{ => crow}/http_server.h (74%) mode change 100755 => 100644 rename ext/crow/{ => crow}/json.h (97%) mode change 100755 => 100644 rename ext/crow/{ => crow}/logging.h (99%) mode change 100755 => 100644 rename ext/crow/{ => crow}/middleware.h (52%) mode change 100755 => 100644 rename ext/crow/{ => crow}/middleware_context.h (96%) rename ext/crow/{ => crow}/mustache.h (99%) mode change 100755 => 100644 rename ext/crow/{ => crow}/parser.h (98%) mode change 100755 => 100644 rename ext/crow/{ => crow}/query_string.h (81%) rename ext/crow/{ => crow}/routing.h (96%) mode change 100755 => 100644 rename ext/crow/{ => crow}/settings.h (76%) rename ext/crow/{ => crow}/socket_adaptors.h (98%) mode change 100755 => 100644 rename ext/crow/{ => crow}/utility.h (98%) mode change 100755 => 100644 rename ext/crow/{ => crow}/websocket.h (91%) mode change 100755 => 100644 diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d39c93..e0c44e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ endif() # include boost headers include_directories(${Boost_INCLUDE_DIRS}) include_directories("ext/mstch/include") +include_directories("ext/crow") # add ext/ subfolder add_subdirectory(ext/) diff --git a/ext/crow/crow.h b/ext/crow/crow.h old mode 100755 new mode 100644 index 00209c7..9a0c22e --- a/ext/crow/crow.h +++ b/ext/crow/crow.h @@ -1,229 +1,23 @@ #pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "settings.h" -#include "logging.h" -#include "utility.h" -#include "routing.h" -#include "middleware_context.h" -#include "http_request.h" -#include "http_server.h" - - -#ifdef CROW_MSVC_WORKAROUND -#define CROW_ROUTE(app, url) app.route_dynamic(url) -#else -#define CROW_ROUTE(app, url) app.route(url) -#endif - -namespace crow -{ -#ifdef CROW_ENABLE_SSL - using ssl_context_t = boost::asio::ssl::context; -#endif - template - class Crow - { - public: - using self_t = Crow; - using server_t = Server; -#ifdef CROW_ENABLE_SSL - using ssl_server_t = Server; -#endif - Crow() - { - } - - template - void handle_upgrade(const request& req, response& res, Adaptor&& adaptor) - { - router_.handle_upgrade(req, res, adaptor); - } - - void handle(const request& req, response& res) - { - router_.handle(req, res); - } - - DynamicRule& route_dynamic(std::string&& rule) - { - return router_.new_rule_dynamic(std::move(rule)); - } - - template - auto route(std::string&& rule) - -> typename std::result_of)(Router, std::string&&)>::type - { - return router_.new_rule_tagged(std::move(rule)); - } - - self_t& port(std::uint16_t port) - { - port_ = port; - return *this; - } - - self_t& bindaddr(std::string bindaddr) - { - bindaddr_ = bindaddr; - return *this; - } - - self_t& multithreaded() - { - return concurrency(std::thread::hardware_concurrency()); - } - - self_t& concurrency(std::uint16_t concurrency) - { - if (concurrency < 1) - concurrency = 1; - concurrency_ = concurrency; - return *this; - } - - void validate() - { - router_.validate(); - } - - void run() - { - validate(); -#ifdef CROW_ENABLE_SSL - if (use_ssl_) - { - ssl_server_ = std::move(std::unique_ptr(new ssl_server_t(this, bindaddr_, port_, &middlewares_, concurrency_, &ssl_context_))); - ssl_server_->run(); - } - else -#endif - { - server_ = std::move(std::unique_ptr(new server_t(this, bindaddr_, port_, &middlewares_, concurrency_, nullptr))); - server_->run(); - } - } - - void stop() - { -#ifdef CROW_ENABLE_SSL - if (use_ssl_) - { - ssl_server_->stop(); - } - else -#endif - { - server_->stop(); - } - } - - void debug_print() - { - CROW_LOG_DEBUG << "Routing:"; - router_.debug_print(); - } - -#ifdef CROW_ENABLE_SSL - self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename) - { - use_ssl_ = true; - ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer); - ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem); - ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem); - ssl_context_.set_options( - boost::asio::ssl::context::default_workarounds - | boost::asio::ssl::context::no_sslv2 - | boost::asio::ssl::context::no_sslv3 - ); - return *this; - } - - self_t& ssl_file(const std::string& pem_filename) - { - use_ssl_ = true; - ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer); - ssl_context_.load_verify_file(pem_filename); - ssl_context_.set_options( - boost::asio::ssl::context::default_workarounds - | boost::asio::ssl::context::no_sslv2 - | boost::asio::ssl::context::no_sslv3 - ); - return *this; - } - - self_t& ssl(boost::asio::ssl::context&& ctx) - { - use_ssl_ = true; - ssl_context_ = std::move(ctx); - return *this; - } - - - bool use_ssl_{false}; - ssl_context_t ssl_context_{boost::asio::ssl::context::sslv23}; - -#else - template - self_t& ssl_file(T&&, Remain&&...) - { - // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined. - static_assert( - // make static_assert dependent to T; always false - std::is_base_of::value, - "Define CROW_ENABLE_SSL to enable ssl support."); - return *this; - } - - template - self_t& ssl(T&&) - { - // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined. - static_assert( - // make static_assert dependent to T; always false - std::is_base_of::value, - "Define CROW_ENABLE_SSL to enable ssl support."); - return *this; - } -#endif - - // middleware - using context_t = detail::context; - template - typename T::context& get_context(const request& req) - { - static_assert(black_magic::contains::value, "App doesn't have the specified middleware type."); - auto& ctx = *reinterpret_cast(req.middleware_context); - return ctx.template get(); - } - - template - T& get_middleware() - { - return utility::get_element_by_type(middlewares_); - } - - private: - uint16_t port_ = 80; - uint16_t concurrency_ = 1; - std::string bindaddr_ = "0.0.0.0"; - Router router_; - - std::tuple middlewares_; - -#ifdef CROW_ENABLE_SSL - std::unique_ptr ssl_server_; -#endif - std::unique_ptr server_; - }; - template - using App = Crow; - using SimpleApp = Crow<>; -} +#include "crow/query_string.h" +#include "crow/http_parser_merged.h" +#include "crow/ci_map.h" +#include "crow/TinySHA1.hpp" +#include "crow/settings.h" +#include "crow/socket_adaptors.h" +#include "crow/json.h" +#include "crow/mustache.h" +#include "crow/logging.h" +#include "crow/dumb_timer_queue.h" +#include "crow/utility.h" +#include "crow/common.h" +#include "crow/http_request.h" +#include "crow/websocket.h" +#include "crow/parser.h" +#include "crow/http_response.h" +#include "crow/middleware.h" +#include "crow/routing.h" +#include "crow/middleware_context.h" +#include "crow/http_connection.h" +#include "crow/http_server.h" +#include "crow/app.h" diff --git a/ext/crow/TinySHA1.hpp b/ext/crow/crow/TinySHA1.hpp old mode 100755 new mode 100644 similarity index 100% rename from ext/crow/TinySHA1.hpp rename to ext/crow/crow/TinySHA1.hpp diff --git a/ext/crow/crow/app.h b/ext/crow/crow/app.h new file mode 100644 index 0000000..b454bf0 --- /dev/null +++ b/ext/crow/crow/app.h @@ -0,0 +1,248 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crow/settings.h" +#include "crow/logging.h" +#include "crow/utility.h" +#include "crow/routing.h" +#include "crow/middleware_context.h" +#include "crow/http_request.h" +#include "crow/http_server.h" + + +#ifdef CROW_MSVC_WORKAROUND +#define CROW_ROUTE(app, url) app.route_dynamic(url) +#else +#define CROW_ROUTE(app, url) app.route(url) +#endif + +namespace crow +{ +#ifdef CROW_ENABLE_SSL + using ssl_context_t = boost::asio::ssl::context; +#endif + template + class Crow + { + public: + using self_t = Crow; + using server_t = Server; +#ifdef CROW_ENABLE_SSL + using ssl_server_t = Server; +#endif + Crow() + { + } + + template + void handle_upgrade(const request& req, response& res, Adaptor&& adaptor) + { + router_.handle_upgrade(req, res, adaptor); + } + + void handle(const request& req, response& res) + { + router_.handle(req, res); + } + + DynamicRule& route_dynamic(std::string&& rule) + { + return router_.new_rule_dynamic(std::move(rule)); + } + + template + auto route(std::string&& rule) + -> typename std::result_of)(Router, std::string&&)>::type + { + return router_.new_rule_tagged(std::move(rule)); + } + + self_t& port(std::uint16_t port) + { + port_ = port; + return *this; + } + + self_t& bindaddr(std::string bindaddr) + { + bindaddr_ = bindaddr; + return *this; + } + + self_t& multithreaded() + { + return concurrency(std::thread::hardware_concurrency()); + } + + self_t& concurrency(std::uint16_t concurrency) + { + if (concurrency < 1) + concurrency = 1; + concurrency_ = concurrency; + return *this; + } + + void validate() + { + router_.validate(); + } + + void run() + { + validate(); +#ifdef CROW_ENABLE_SSL + if (use_ssl_) + { + ssl_server_ = std::move(std::unique_ptr(new ssl_server_t(this, bindaddr_, port_, &middlewares_, concurrency_, &ssl_context_))); + ssl_server_->set_tick_function(tick_interval_, tick_function_); + ssl_server_->run(); + } + else +#endif + { + server_ = std::move(std::unique_ptr(new server_t(this, bindaddr_, port_, &middlewares_, concurrency_, nullptr))); + server_->set_tick_function(tick_interval_, tick_function_); + server_->run(); + } + } + + void stop() + { +#ifdef CROW_ENABLE_SSL + if (use_ssl_) + { + ssl_server_->stop(); + } + else +#endif + { + server_->stop(); + } + } + + void debug_print() + { + CROW_LOG_DEBUG << "Routing:"; + router_.debug_print(); + } + + self_t& loglevel(crow::LogLevel level) + { + crow::logger::setLogLevel(level); + return *this; + } + +#ifdef CROW_ENABLE_SSL + self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename) + { + use_ssl_ = true; + ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer); + ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem); + ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem); + ssl_context_.set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::no_sslv3 + ); + return *this; + } + + self_t& ssl_file(const std::string& pem_filename) + { + use_ssl_ = true; + ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer); + ssl_context_.load_verify_file(pem_filename); + ssl_context_.set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::no_sslv3 + ); + return *this; + } + + self_t& ssl(boost::asio::ssl::context&& ctx) + { + use_ssl_ = true; + ssl_context_ = std::move(ctx); + return *this; + } + + + bool use_ssl_{false}; + ssl_context_t ssl_context_{boost::asio::ssl::context::sslv23}; + +#else + template + self_t& ssl_file(T&&, Remain&&...) + { + // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined. + static_assert( + // make static_assert dependent to T; always false + std::is_base_of::value, + "Define CROW_ENABLE_SSL to enable ssl support."); + return *this; + } + + template + self_t& ssl(T&&) + { + // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined. + static_assert( + // make static_assert dependent to T; always false + std::is_base_of::value, + "Define CROW_ENABLE_SSL to enable ssl support."); + return *this; + } +#endif + + // middleware + using context_t = detail::context; + template + typename T::context& get_context(const request& req) + { + static_assert(black_magic::contains::value, "App doesn't have the specified middleware type."); + auto& ctx = *reinterpret_cast(req.middleware_context); + return ctx.template get(); + } + + template + T& get_middleware() + { + return utility::get_element_by_type(middlewares_); + } + + template + self_t& tick(Duration d, Func f) { + tick_interval_ = std::chrono::duration_cast(d); + tick_function_ = f; + return *this; + } + + private: + uint16_t port_ = 80; + uint16_t concurrency_ = 1; + std::string bindaddr_ = "0.0.0.0"; + Router router_; + + std::chrono::milliseconds tick_interval_; + std::function tick_function_; + + std::tuple middlewares_; + +#ifdef CROW_ENABLE_SSL + std::unique_ptr ssl_server_; +#endif + std::unique_ptr server_; + }; + template + using App = Crow; + using SimpleApp = Crow<>; +} diff --git a/ext/crow/ci_map.h b/ext/crow/crow/ci_map.h similarity index 100% rename from ext/crow/ci_map.h rename to ext/crow/crow/ci_map.h diff --git a/ext/crow/common.h b/ext/crow/crow/common.h old mode 100755 new mode 100644 similarity index 94% rename from ext/crow/common.h rename to ext/crow/crow/common.h index 8203378..ac6e789 --- a/ext/crow/common.h +++ b/ext/crow/crow/common.h @@ -4,7 +4,7 @@ #include #include #include -#include "utility.h" +#include "crow/utility.h" namespace crow { @@ -19,6 +19,7 @@ namespace crow CONNECT, OPTIONS, TRACE, + PATCH = 24, #endif Delete = 0, @@ -29,6 +30,7 @@ namespace crow Connect, Options, Trace, + Patch = 24, }; inline std::string method_name(HTTPMethod method) @@ -51,6 +53,8 @@ namespace crow return "OPTIONS"; case HTTPMethod::Trace: return "TRACE"; + case HTTPMethod::Patch: + return "PATCH"; } return "invalid"; } @@ -132,6 +136,7 @@ constexpr crow::HTTPMethod operator "" _method(const char* str, size_t /*len*/) crow::black_magic::is_equ_p(str, "OPTIONS", 7) ? crow::HTTPMethod::Options : crow::black_magic::is_equ_p(str, "CONNECT", 7) ? crow::HTTPMethod::Connect : crow::black_magic::is_equ_p(str, "TRACE", 5) ? crow::HTTPMethod::Trace : + crow::black_magic::is_equ_p(str, "PATCH", 5) ? crow::HTTPMethod::Patch : throw std::runtime_error("invalid http method"); } #endif diff --git a/ext/crow/dumb_timer_queue.h b/ext/crow/crow/dumb_timer_queue.h similarity index 98% rename from ext/crow/dumb_timer_queue.h rename to ext/crow/crow/dumb_timer_queue.h index 6b690bb..fd51518 100644 --- a/ext/crow/dumb_timer_queue.h +++ b/ext/crow/crow/dumb_timer_queue.h @@ -6,7 +6,7 @@ #include #include -#include "logging.h" +#include "crow/logging.h" namespace crow { diff --git a/ext/crow/http_connection.h b/ext/crow/crow/http_connection.h old mode 100755 new mode 100644 similarity index 96% rename from ext/crow/http_connection.h rename to ext/crow/crow/http_connection.h index 5517521..3d214f3 --- a/ext/crow/http_connection.h +++ b/ext/crow/crow/http_connection.h @@ -7,15 +7,15 @@ #include #include -#include "http_parser_merged.h" +#include "crow/http_parser_merged.h" -#include "parser.h" -#include "http_response.h" -#include "logging.h" -#include "settings.h" -#include "dumb_timer_queue.h" -#include "middleware_context.h" -#include "socket_adaptors.h" +#include "crow/parser.h" +#include "crow/http_response.h" +#include "crow/logging.h" +#include "crow/settings.h" +#include "crow/dumb_timer_queue.h" +#include "crow/middleware_context.h" +#include "crow/socket_adaptors.h" namespace crow { @@ -176,7 +176,7 @@ namespace crow } #ifdef CROW_ENABLE_DEBUG - static int connectionCount; + static std::atomic connectionCount; #endif template class Connection @@ -374,6 +374,9 @@ namespace crow {401, "HTTP/1.1 401 Unauthorized\r\n"}, {403, "HTTP/1.1 403 Forbidden\r\n"}, {404, "HTTP/1.1 404 Not Found\r\n"}, + {413, "HTTP/1.1 413 Payload Too Large\r\n"}, + {422, "HTTP/1.1 422 Unprocessable Entity\r\n"}, + {429, "HTTP/1.1 429 Too Many Requests\r\n"}, {500, "HTTP/1.1 500 Internal Server Error\r\n"}, {501, "HTTP/1.1 501 Not Implemented\r\n"}, @@ -467,7 +470,7 @@ namespace crow if (!ec) { bool ret = parser_.feed(buffer_.data(), bytes_transferred); - if (ret && adaptor_.is_open() && !close_connection_) + if (ret && adaptor_.is_open()) { error_while_reading = false; } @@ -482,6 +485,14 @@ namespace crow CROW_LOG_DEBUG << this << " from read(1)"; check_destroy(); } + else if (close_connection_) + { + cancel_deadline_timer(); + parser_.done(); + is_reading = false; + check_destroy(); + // adaptor will close after write + } else if (!need_to_call_after_handlers_) { start_deadline(); diff --git a/ext/crow/http_parser_merged.h b/ext/crow/crow/http_parser_merged.h old mode 100755 new mode 100644 similarity index 100% rename from ext/crow/http_parser_merged.h rename to ext/crow/crow/http_parser_merged.h diff --git a/ext/crow/http_request.h b/ext/crow/crow/http_request.h old mode 100755 new mode 100644 similarity index 95% rename from ext/crow/http_request.h rename to ext/crow/crow/http_request.h index 535a1fd..a70c299 --- a/ext/crow/http_request.h +++ b/ext/crow/crow/http_request.h @@ -1,10 +1,11 @@ #pragma once -#include "common.h" -#include "ci_map.h" -#include "query_string.h" #include +#include "crow/common.h" +#include "crow/ci_map.h" +#include "crow/query_string.h" + namespace crow { template diff --git a/ext/crow/http_response.h b/ext/crow/crow/http_response.h old mode 100755 new mode 100644 similarity index 93% rename from ext/crow/http_response.h rename to ext/crow/crow/http_response.h index 23f312a..7940174 --- a/ext/crow/http_response.h +++ b/ext/crow/crow/http_response.h @@ -1,9 +1,10 @@ #pragma once #include #include -#include "json.h" -#include "http_request.h" -#include "ci_map.h" + +#include "crow/json.h" +#include "crow/http_request.h" +#include "crow/ci_map.h" namespace crow { @@ -85,6 +86,12 @@ namespace crow completed_ = false; } + void redirect(const std::string& location) + { + code = 301; + set_header("Location", location); + } + void write(const std::string& body_part) { body += body_part; diff --git a/ext/crow/http_server.h b/ext/crow/crow/http_server.h old mode 100755 new mode 100644 similarity index 74% rename from ext/crow/http_server.h rename to ext/crow/crow/http_server.h index 86943ee..6aa070e --- a/ext/crow/http_server.h +++ b/ext/crow/crow/http_server.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #ifdef CROW_ENABLE_SSL @@ -12,9 +13,9 @@ #include -#include "http_connection.h" -#include "logging.h" -#include "dumb_timer_queue.h" +#include "crow/http_connection.h" +#include "crow/logging.h" +#include "crow/dumb_timer_queue.h" namespace crow { @@ -28,6 +29,7 @@ namespace crow Server(Handler* handler, std::string bindaddr, uint16_t port, std::tuple* middlewares = nullptr, uint16_t concurrency = 1, typename Adaptor::context* adaptor_ctx = nullptr) : acceptor_(io_service_, tcp::endpoint(boost::asio::ip::address::from_string(bindaddr), port)), signals_(io_service_, SIGINT, SIGTERM), + tick_timer_(io_service_), handler_(handler), concurrency_(concurrency), port_(port), @@ -37,6 +39,24 @@ namespace crow { } + void set_tick_function(std::chrono::milliseconds d, std::function f) + { + tick_interval_ = d; + tick_function_ = f; + } + + void on_tick() + { + tick_function_(); + tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count())); + tick_timer_.async_wait([this](const boost::system::error_code& ec) + { + if (ec) + return; + on_tick(); + }); + } + void run() { if (concurrency_ < 0) @@ -101,15 +121,36 @@ namespace crow timer.async_wait(handler); init_count ++; - try + while(1) { - io_service_pool_[i]->run(); - } catch(std::exception& e) - { - CROW_LOG_ERROR << "Worker Crash: An uncaught exception occurred: " << e.what(); + try + { + if (io_service_pool_[i]->run() == 0) + { + // when io_service.run returns 0, there are no more works to do. + break; + } + } catch(std::exception& e) + { + CROW_LOG_ERROR << "Worker Crash: An uncaught exception occurred: " << e.what(); + } } })); - CROW_LOG_INFO << server_name_ << " server is running, local port " << port_; + + if (tick_function_ && tick_interval_.count() > 0) + { + tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count())); + tick_timer_.async_wait([this](const boost::system::error_code& ec) + { + if (ec) + return; + on_tick(); + }); + } + + CROW_LOG_INFO << server_name_ << " server is running at " << bindaddr_ <<":" << port_ + << " using " << concurrency_ << " threads"; + CROW_LOG_INFO << "Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs."; signals_.async_wait( [&](const boost::system::error_code& /*error*/, int /*signal_number*/){ @@ -161,6 +202,10 @@ namespace crow p->start(); }); } + else + { + delete p; + } do_accept(); }); } @@ -172,6 +217,7 @@ namespace crow std::vector> get_cached_date_str_pool_; tcp::acceptor acceptor_; boost::asio::signal_set signals_; + boost::asio::deadline_timer tick_timer_; Handler* handler_; uint16_t concurrency_{1}; @@ -180,6 +226,9 @@ namespace crow std::string bindaddr_; unsigned int roundrobin_index_{}; + std::chrono::milliseconds tick_interval_; + std::function tick_function_; + std::tuple* middlewares_; #ifdef CROW_ENABLE_SSL diff --git a/ext/crow/json.h b/ext/crow/crow/json.h old mode 100755 new mode 100644 similarity index 97% rename from ext/crow/json.h rename to ext/crow/crow/json.h index 9f06244..d8dbace --- a/ext/crow/json.h +++ b/ext/crow/crow/json.h @@ -12,6 +12,8 @@ #include #include +#include "crow/settings.h" + #if defined(__GNUG__) || defined(__clang__) #define crow_json_likely(x) __builtin_expect(x, 1) #define crow_json_unlikely(x) __builtin_expect(x, 0) @@ -1262,6 +1264,23 @@ namespace crow return *this; } + wvalue& operator=(std::vector&& v) + { + if (t_ != type::List) + reset(); + t_ = type::List; + if (!l) + l = std::unique_ptr>(new std::vector{}); + l->clear(); + l->resize(v.size()); + size_t idx = 0; + for(auto& x:v) + { + (*l)[idx++] = std::move(x); + } + return *this; + } + template wvalue& operator=(const std::vector& v) { @@ -1314,6 +1333,18 @@ namespace crow return (*o)[str]; } + std::vector keys() const + { + if (t_ != type::Object) + return {}; + std::vector result; + for (auto& kv:*o) + { + result.push_back(kv.first); + } + return result; + } + size_t estimate_length() const { switch(t_) @@ -1354,7 +1385,6 @@ namespace crow return 1; } - friend void dump_internal(const wvalue& v, std::string& out); friend std::string dump(const wvalue& v); }; @@ -1375,7 +1405,12 @@ namespace crow case type::Number: { char outbuf[128]; +#ifdef _MSC_VER + sprintf_s(outbuf, 128, "%g", v.d); +#else sprintf(outbuf, "%g", v.d); +#endif + out += outbuf; } break; diff --git a/ext/crow/logging.h b/ext/crow/crow/logging.h old mode 100755 new mode 100644 similarity index 99% rename from ext/crow/logging.h rename to ext/crow/crow/logging.h index 13cdad2..9c8bfbb --- a/ext/crow/logging.h +++ b/ext/crow/crow/logging.h @@ -7,7 +7,7 @@ #include #include -#include "settings.h" +#include "crow/settings.h" namespace crow { diff --git a/ext/crow/middleware.h b/ext/crow/crow/middleware.h old mode 100755 new mode 100644 similarity index 52% rename from ext/crow/middleware.h rename to ext/crow/crow/middleware.h index 534a87a..3858018 --- a/ext/crow/middleware.h +++ b/ext/crow/crow/middleware.h @@ -1,7 +1,7 @@ #pragma once #include -#include "http_request.h" -#include "http_response.h" +#include "crow/http_request.h" +#include "crow/http_response.h" namespace crow { @@ -35,10 +35,11 @@ namespace crow std::unordered_map jar; std::unordered_map cookies_to_add; - std::string get_cookie(const std::string& key) + std::string get_cookie(const std::string& key) const { - if (jar.count(key)) - return jar[key]; + auto cookie = jar.find(key); + if (cookie != jar.end()) + return cookie->second; return {}; } @@ -73,69 +74,22 @@ namespace crow if (pos == cookies.size()) break; - std::string value; + size_t pos_semicolon = cookies.find(';', pos); + std::string value = cookies.substr(pos, pos_semicolon-pos); - if (cookies[pos] == '"') + boost::trim(value); + if (value[0] == '"' && value[value.size()-1] == '"') { - int dquote_meet_count = 0; - pos ++; - size_t pos_dquote = pos-1; - do - { - pos_dquote = cookies.find('"', pos_dquote+1); - dquote_meet_count ++; - } while(pos_dquote < cookies.size() && cookies[pos_dquote-1] == '\\'); - if (pos_dquote == cookies.npos) - break; - - if (dquote_meet_count == 1) - value = cookies.substr(pos, pos_dquote - pos); - else - { - value.clear(); - value.reserve(pos_dquote-pos); - for(size_t p = pos; p < pos_dquote; p++) - { - // FIXME minimal escaping - if (cookies[p] == '\\' && p + 1 < pos_dquote) - { - p++; - if (cookies[p] == '\\' || cookies[p] == '"') - value += cookies[p]; - else - { - value += '\\'; - value += cookies[p]; - } - } - else - value += cookies[p]; - } - } - - ctx.jar.emplace(std::move(name), std::move(value)); - pos = cookies.find(";", pos_dquote+1); - if (pos == cookies.npos) - break; - pos++; - while(pos < cookies.size() && cookies[pos] == ' ') pos++; - if (pos == cookies.size()) - break; - } - else - { - size_t pos_semicolon = cookies.find(';', pos); - value = cookies.substr(pos, pos_semicolon - pos); - boost::trim(value); - ctx.jar.emplace(std::move(name), std::move(value)); - pos = pos_semicolon; - if (pos == cookies.npos) - break; - pos ++; - while(pos < cookies.size() && cookies[pos] == ' ') pos++; - if (pos == cookies.size()) - break; + value = value.substr(1, value.size()-2); } + + ctx.jar.emplace(std::move(name), std::move(value)); + + pos = pos_semicolon; + if (pos == cookies.npos) + break; + pos++; + while(pos < cookies.size() && cookies[pos] == ' ') pos++; } } @@ -143,7 +97,10 @@ namespace crow { for(auto& cookie:ctx.cookies_to_add) { - res.add_header("Set-Cookie", cookie.first + "=" + cookie.second); + if (cookie.second.empty()) + res.add_header("Set-Cookie", cookie.first + "=\"\""); + else + res.add_header("Set-Cookie", cookie.first + "=" + cookie.second); } } }; diff --git a/ext/crow/middleware_context.h b/ext/crow/crow/middleware_context.h similarity index 96% rename from ext/crow/middleware_context.h rename to ext/crow/crow/middleware_context.h index daaaa5c..6885c13 100644 --- a/ext/crow/middleware_context.h +++ b/ext/crow/crow/middleware_context.h @@ -1,8 +1,8 @@ #pragma once -#include "utility.h" -#include "http_request.h" -#include "http_response.h" +#include "crow/utility.h" +#include "crow/http_request.h" +#include "crow/http_response.h" namespace crow { diff --git a/ext/crow/mustache.h b/ext/crow/crow/mustache.h old mode 100755 new mode 100644 similarity index 99% rename from ext/crow/mustache.h rename to ext/crow/crow/mustache.h index 279f356..bfb9f14 --- a/ext/crow/mustache.h +++ b/ext/crow/crow/mustache.h @@ -4,7 +4,7 @@ #include #include #include -#include "json.h" +#include "crow/json.h" namespace crow { namespace mustache @@ -555,6 +555,11 @@ namespace crow detail::get_loader_ref() = std::move(loader); } + inline std::string load_text(const std::string& filename) + { + return detail::get_loader_ref()(filename); + } + inline template_t load(const std::string& filename) { return compile(detail::get_loader_ref()(filename)); diff --git a/ext/crow/parser.h b/ext/crow/crow/parser.h old mode 100755 new mode 100644 similarity index 98% rename from ext/crow/parser.h rename to ext/crow/crow/parser.h index b621850..61f5aee --- a/ext/crow/parser.h +++ b/ext/crow/crow/parser.h @@ -3,11 +3,10 @@ #include #include #include -#include #include -#include "http_parser_merged.h" -#include "http_request.h" +#include "crow/http_parser_merged.h" +#include "crow/http_request.h" namespace crow { diff --git a/ext/crow/query_string.h b/ext/crow/crow/query_string.h similarity index 81% rename from ext/crow/query_string.h rename to ext/crow/crow/query_string.h index 03e5cfd..ee61e30 100644 --- a/ext/crow/query_string.h +++ b/ext/crow/crow/query_string.h @@ -4,8 +4,12 @@ #include #include #include +#include #include +#include +namespace crow +{ // ---------------------------------------------------------------------------- // qs_parse (modified) // https://github.com/bartgrantham/qs_parse @@ -195,6 +199,48 @@ inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int return NULL; } +inline boost::optional> qs_dict_name2kv(const char * dict_name, char * const * qs_kv, int qs_kv_size, int nth = 0) +{ + int i; + size_t name_len, skip_to_eq, skip_to_brace_open, skip_to_brace_close; + + name_len = strlen(dict_name); + +#ifdef _qsSORTING +// TODO: binary search for key in the sorted qs_kv +#else // _qsSORTING + for(i=0; i 0 && + skip_to_brace_close > 0 && + nth == 0 ) + { + auto key = std::string(qs_kv[i] + skip_to_brace_open, skip_to_brace_close - skip_to_brace_open); + auto value = std::string(qs_kv[i] + skip_to_eq); + return boost::make_optional(std::make_pair(key, value)); + } + else + { + --nth; + } + } + } +#endif // _qsSORTING + + return boost::none; +} + inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len) { @@ -220,8 +266,12 @@ inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t { qs++; i = strcspn(qs, "&=#"); - strncpy(val, qs, (val_len-1)<(i+1) ? (val_len-1) : (i+1)); - qs_decode(val); +#ifdef _MSC_VER + strncpy_s(val, val_len, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1)); +#else + strncpy(val, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1)); +#endif + qs_decode(val); } else { @@ -231,6 +281,7 @@ inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t return val; } +} // ---------------------------------------------------------------------------- @@ -333,6 +384,20 @@ namespace crow return ret; } + std::unordered_map get_dict (const std::string& name) const + { + std::unordered_map ret; + + int count = 0; + while(1) + { + if (auto element = qs_dict_name2kv(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++)) + ret.insert(*element); + else + break; + } + return ret; + } private: std::string url_; diff --git a/ext/crow/routing.h b/ext/crow/crow/routing.h old mode 100755 new mode 100644 similarity index 96% rename from ext/crow/routing.h rename to ext/crow/crow/routing.h index ed84334..cdfa480 --- a/ext/crow/routing.h +++ b/ext/crow/crow/routing.h @@ -8,12 +8,12 @@ #include #include -#include "common.h" -#include "http_response.h" -#include "http_request.h" -#include "utility.h" -#include "logging.h" -#include "websocket.h" +#include "crow/common.h" +#include "crow/http_response.h" +#include "crow/http_request.h" +#include "crow/utility.h" +#include "crow/logging.h" +#include "crow/websocket.h" namespace crow { @@ -156,7 +156,7 @@ namespace crow struct Wrapped { template - void set2(Func f, typename std::enable_if< + void set_(Func f, typename std::enable_if< !std::is_same>::type, const request&>::value , int>::type = 0) { @@ -190,7 +190,7 @@ namespace crow }; template - void set2(Func f, typename std::enable_if< + void set_(Func f, typename std::enable_if< std::is_same>::type, const request&>::value && !std::is_same>::type, response&>::value , int>::type = 0) @@ -205,7 +205,7 @@ namespace crow } template - void set2(Func f, typename std::enable_if< + void set_(Func f, typename std::enable_if< std::is_same>::type, const request&>::value && std::is_same>::type, response&>::value , int>::type = 0) @@ -276,12 +276,12 @@ namespace crow void handle_upgrade(const request& req, response&, SocketAdaptor&& adaptor) override { - new crow::websocket::Connection(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_); + new crow::websocket::Connection(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_); } #ifdef CROW_ENABLE_SSL void handle_upgrade(const request& req, response&, SSLAdaptor&& adaptor) override { - new crow::websocket::Connection(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_); + new crow::websocket::Connection(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_); } #endif @@ -313,11 +313,19 @@ namespace crow return *this; } + template + self_t& onaccept(Func f) + { + accept_handler_ = f; + return *this; + } + protected: std::function open_handler_; std::function message_handler_; std::function close_handler_; std::function error_handler_; + std::function accept_handler_; }; template @@ -394,7 +402,7 @@ namespace crow #else template #endif - std::function + std::function wrap(Func f, black_magic::seq) { #ifdef CROW_MSVC_WORKAROUND @@ -403,14 +411,16 @@ namespace crow using function_t = utility::function_traits; #endif if (!black_magic::is_parameter_tag_compatible( - black_magic::get_parameter_tag_runtime(rule_.c_str()), + black_magic::get_parameter_tag_runtime(rule_.c_str()), black_magic::compute_parameter_tag_from_args_list< typename function_t::template arg...>::value)) { throw std::runtime_error("route_dynamic: Handler type is mismatched with URL parameters: " + rule_); } auto ret = detail::routing_handler_call_helper::Wrapped...>(); - ret.template set2...>(std::move(f)); + ret.template set_< + typename function_t::template arg... + >(std::move(f)); return ret; } @@ -454,10 +464,16 @@ namespace crow static_assert(!std::is_same()...))>::value, "Handler function cannot have void return type; valid return types: string, int, crow::resposne, crow::json::wvalue"); - handler_ = [f = std::move(f)](const request&, response& res, Args ... args){ + handler_ = ( +#ifdef CROW_CAN_USE_CPP14 + [f = std::move(f)] +#else + [f] +#endif + (const request&, response& res, Args ... args){ res = response(f(args...)); res.end(); - }; + }); } template @@ -473,10 +489,16 @@ namespace crow static_assert(!std::is_same(), std::declval()...))>::value, "Handler function cannot have void return type; valid return types: string, int, crow::resposne, crow::json::wvalue"); - handler_ = [f = std::move(f)](const crow::request& req, crow::response& res, Args ... args){ + handler_ = ( +#ifdef CROW_CAN_USE_CPP14 + [f = std::move(f)] +#else + [f] +#endif + (const crow::request& req, crow::response& res, Args ... args){ res = response(f(req, args...)); res.end(); - }; + }); } template @@ -981,7 +1003,6 @@ public: auto found = trie_.find(req.url); unsigned rule_index = found.first; - CROW_LOG_DEBUG << "???" << rule_index; if (!rule_index) { diff --git a/ext/crow/settings.h b/ext/crow/crow/settings.h similarity index 76% rename from ext/crow/settings.h rename to ext/crow/crow/settings.h index fc9392c..bd6259c 100644 --- a/ext/crow/settings.h +++ b/ext/crow/crow/settings.h @@ -3,21 +3,21 @@ // TODO - replace with runtime config. libucl? /* #ifdef - enables debug mode */ -#define CROW_ENABLE_DEBUG +//#define CROW_ENABLE_DEBUG /* #ifdef - enables logging */ #define CROW_ENABLE_LOGGING -/* #ifdef - enables SSL */ +/* #ifdef - enables ssl */ //#define CROW_ENABLE_SSL /* #define - specifies log level */ /* - DEBUG = 0 - INFO = 1 - WARNING = 2 - ERROR = 3 - CRITICAL = 4 + Debug = 0 + Info = 1 + Warning = 2 + Error = 3 + Critical = 4 default to INFO */ diff --git a/ext/crow/socket_adaptors.h b/ext/crow/crow/socket_adaptors.h old mode 100755 new mode 100644 similarity index 98% rename from ext/crow/socket_adaptors.h rename to ext/crow/crow/socket_adaptors.h index 634bd4b..eebd50f --- a/ext/crow/socket_adaptors.h +++ b/ext/crow/crow/socket_adaptors.h @@ -3,7 +3,7 @@ #ifdef CROW_ENABLE_SSL #include #endif -#include "settings.h" +#include "crow/settings.h" namespace crow { using namespace boost; diff --git a/ext/crow/utility.h b/ext/crow/crow/utility.h old mode 100755 new mode 100644 similarity index 98% rename from ext/crow/utility.h rename to ext/crow/crow/utility.h index b714d55..43503e8 --- a/ext/crow/utility.h +++ b/ext/crow/crow/utility.h @@ -8,6 +8,8 @@ #include #include +#include "crow/settings.h" + namespace crow { namespace black_magic @@ -500,7 +502,7 @@ template using arg = typename std::tuple_element>::type; }; - std::string base64encode(const char* data, size_t size, const char* key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") + inline static std::string base64encode(const char* data, size_t size, const char* key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") { std::string ret; ret.resize((size+2) / 3 * 4); @@ -536,7 +538,7 @@ template return ret; } - std::string base64encode_urlsafe(const char* data, size_t size) + inline static std::string base64encode_urlsafe(const char* data, size_t size) { return base64encode(data, size, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"); } diff --git a/ext/crow/websocket.h b/ext/crow/crow/websocket.h old mode 100755 new mode 100644 similarity index 91% rename from ext/crow/websocket.h rename to ext/crow/crow/websocket.h index 5299c1a..ee0885f --- a/ext/crow/websocket.h +++ b/ext/crow/crow/websocket.h @@ -1,7 +1,9 @@ #pragma once -#include "socket_adaptors.h" -#include "http_request.h" -#include "TinySHA1.hpp" +#include +#include +#include "crow/socket_adaptors.h" +#include "crow/http_request.h" +#include "crow/TinySHA1.hpp" namespace crow { @@ -22,6 +24,12 @@ namespace crow virtual void send_text(const std::string& msg) = 0; virtual void close(const std::string& msg = "quit") = 0; virtual ~connection(){} + + void userdata(void* u) { userdata_ = u; } + void* userdata() { return userdata_; } + + private: + void* userdata_; }; template @@ -32,15 +40,28 @@ namespace crow std::function open_handler, std::function message_handler, std::function close_handler, - std::function error_handler) + std::function error_handler, + std::function accept_handler) : adaptor_(std::move(adaptor)), open_handler_(std::move(open_handler)), message_handler_(std::move(message_handler)), close_handler_(std::move(close_handler)), error_handler_(std::move(error_handler)) + , accept_handler_(std::move(accept_handler)) { - if (req.get_header_value("upgrade") != "websocket") + if (!boost::iequals(req.get_header_value("upgrade"), "websocket")) { adaptor.close(); delete this; return; } + + if (accept_handler_) + { + if (!accept_handler_(req)) + { + adaptor.close(); + delete this; + return; + } + } + // Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== // Sec-WebSocket-Version: 13 std::string magic = req.get_header_value("Sec-WebSocket-Key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; @@ -125,13 +146,13 @@ namespace crow else if (size < 0x10000) { buf[1] += 126; - *(uint16_t*)(buf+2) = (uint16_t)size; + *(uint16_t*)(buf+2) = htons((uint16_t)size); return {buf, buf+4}; } else { buf[1] += 127; - *(uint64_t*)(buf+2) = (uint64_t)size; + *(uint64_t*)(buf+2) = ((1==htonl(1)) ? (uint64_t)size : ((uint64_t)htonl((size) & 0xFFFFFFFF) << 32) | htonl((size) >> 32)); return {buf, buf+10}; } } @@ -162,7 +183,12 @@ namespace crow { //boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&mini_header_, 1), adaptor_.socket().async_read_some(boost::asio::buffer(&mini_header_, 2), - [this](const boost::system::error_code& ec, std::size_t bytes_transferred) + [this](const boost::system::error_code& ec, std::size_t +#ifdef CROW_ENABLE_DEBUG + bytes_transferred +#endif + ) + { is_reading = false; mini_header_ = htons(mini_header_); @@ -205,11 +231,17 @@ namespace crow case WebSocketReadState::Len16: { remaining_length_ = 0; - boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length_, 2), - [this](const boost::system::error_code& ec, std::size_t bytes_transferred) + uint16_t remaining_length16_ = 0; + boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length16_, 2), + [this,&remaining_length16_](const boost::system::error_code& ec, std::size_t +#ifdef CROW_ENABLE_DEBUG + bytes_transferred +#endif + ) { is_reading = false; - remaining_length_ = ntohs(*(uint16_t*)&remaining_length_); + remaining_length16_ = ntohs(remaining_length16_); + remaining_length_ = remaining_length16_; #ifdef CROW_ENABLE_DEBUG if (!ec && bytes_transferred != 2) { @@ -236,7 +268,11 @@ namespace crow case WebSocketReadState::Len64: { boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length_, 8), - [this](const boost::system::error_code& ec, std::size_t bytes_transferred) + [this](const boost::system::error_code& ec, std::size_t +#ifdef CROW_ENABLE_DEBUG + bytes_transferred +#endif + ) { is_reading = false; remaining_length_ = ((1==ntohl(1)) ? (remaining_length_) : ((uint64_t)ntohl((remaining_length_) & 0xFFFFFFFF) << 32) | ntohl((remaining_length_) >> 32)); @@ -265,7 +301,11 @@ namespace crow break; case WebSocketReadState::Mask: boost::asio::async_read(adaptor_.socket(), boost::asio::buffer((char*)&mask_, 4), - [this](const boost::system::error_code& ec, std::size_t bytes_transferred) + [this](const boost::system::error_code& ec, std::size_t +#ifdef CROW_ENABLE_DEBUG + bytes_transferred +#endif + ) { is_reading = false; #ifdef CROW_ENABLE_DEBUG @@ -477,6 +517,7 @@ namespace crow std::function message_handler_; std::function close_handler_; std::function error_handler_; + std::function accept_handler_; }; } } diff --git a/main.cpp b/main.cpp index 4d7640f..1f428dc 100644 --- a/main.cpp +++ b/main.cpp @@ -285,12 +285,14 @@ main(int ac, const char* av[]) }); CROW_ROUTE(app, "/tx//") - ([&](string tx_hash, uint16_t with_ring_signatures) { + ([&](string tx_hash, uint16_t with_ring_signatures) + { return xmrblocks.show_tx(tx_hash, with_ring_signatures); }); CROW_ROUTE(app, "/myoutputs").methods("POST"_method) - ([&](const crow::request& req) { + ([&](const crow::request& req) + { map post_body = xmreg::parse_crow_post_data(req.body); @@ -319,7 +321,8 @@ main(int ac, const char* av[]) CROW_ROUTE(app, "/myoutputs///") ([&](const crow::request& req, string tx_hash, - string xmr_address, string viewkey) { + string xmr_address, string viewkey) + { string domain = get_domain(req); diff --git a/src/page.h b/src/page.h index fee3651..5796be3 100644 --- a/src/page.h +++ b/src/page.h @@ -20,7 +20,7 @@ #include "CurrentBlockchainStatus.h" #include "MempoolStatus.h" -#include "../ext/crow/http_request.h" +#include "../ext/crow/crow.h" #include "../ext/vpetrigocaches/cache.hpp" #include "../ext/vpetrigocaches/lru_cache_policy.hpp" From c26882897be7a4e610c7201175ed6a06caaa9695 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Wed, 20 Dec 2017 08:04:17 +0800 Subject: [PATCH 22/27] added asan compiler option, basic string cleaning https://github.com/moneroexamples/onion-monero-blockchain-explorer/issues/91 --- CMakeLists.txt | 10 +- main.cpp | 85 +++++---- src/page.h | 2 +- src/tools.h | 467 +++++++++++++++++++++++++------------------------ 4 files changed, 299 insertions(+), 265 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0c44e2..d25663c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,12 @@ set(PROJECT_NAME project(${PROJECT_NAME}) set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++14") + "${CMAKE_CXX_FLAGS} -std=c++14 -fsanitize=address -fno-omit-frame-pointer") + +set(CMAKE_C_FLAGS + "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -DLEAK_SANITIZER") + +# if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj -O3") @@ -102,16 +107,15 @@ set(LIBRARIES cryptonote_basic daemonizer cncrypto - blocks lmdb ringct common mnemonics - epee easylogging checkpoints version + epee ${Boost_LIBRARIES} pthread unbound diff --git a/main.cpp b/main.cpp index 1f428dc..73b9baf 100644 --- a/main.cpp +++ b/main.cpp @@ -11,6 +11,7 @@ #include using boost::filesystem::path; +using xmreg::remove_bad_chars; using namespace std; @@ -276,18 +277,18 @@ main(int ac, const char* av[]) CROW_ROUTE(app, "/block/") ([&](const crow::request& req, string block_hash) { - return crow::response(xmrblocks.show_block(block_hash)); + return crow::response(xmrblocks.show_block(remove_bad_chars(block_hash))); }); CROW_ROUTE(app, "/tx/") ([&](const crow::request& req, string tx_hash) { - return crow::response(xmrblocks.show_tx(tx_hash)); + return crow::response(xmrblocks.show_tx(remove_bad_chars(tx_hash))); }); CROW_ROUTE(app, "/tx//") ([&](string tx_hash, uint16_t with_ring_signatures) { - return xmrblocks.show_tx(tx_hash, with_ring_signatures); + return xmrblocks.show_tx(remove_bad_chars(tx_hash), with_ring_signatures); }); CROW_ROUTE(app, "/myoutputs").methods("POST"_method) @@ -304,13 +305,13 @@ main(int ac, const char* av[]) return string("xmr address, viewkey or tx hash not provided"); } - string tx_hash = post_body["tx_hash"]; - string xmr_address = post_body["xmr_address"]; - string viewkey = post_body["viewkey"]; + string tx_hash = remove_bad_chars(post_body["tx_hash"]); + string xmr_address = remove_bad_chars(post_body["xmr_address"]); + string viewkey = remove_bad_chars(post_body["viewkey"]); // this will be only not empty when checking raw tx data // using tx pusher - string raw_tx_data = post_body["raw_tx_data"]; + string raw_tx_data = remove_bad_chars(post_body["raw_tx_data"]); string domain = get_domain(req); @@ -326,8 +327,10 @@ main(int ac, const char* av[]) string domain = get_domain(req); - return xmrblocks.show_my_outputs(tx_hash, xmr_address, - viewkey, string {}, + return xmrblocks.show_my_outputs(remove_bad_chars(tx_hash), + remove_bad_chars(xmr_address), + remove_bad_chars(viewkey), + string {}, domain); }); @@ -345,18 +348,21 @@ main(int ac, const char* av[]) "tx hash not provided"); } - string tx_hash = post_body["txhash"]; - string tx_prv_key = post_body["txprvkey"]; - string xmr_address = post_body["xmraddress"]; + string tx_hash = remove_bad_chars(post_body["txhash"]); + string tx_prv_key = remove_bad_chars(post_body["txprvkey"]); + string xmr_address = remove_bad_chars(post_body["xmraddress"]); // this will be only not empty when checking raw tx data // using tx pusher - string raw_tx_data = post_body["raw_tx_data"]; + string raw_tx_data = remove_bad_chars(post_body["raw_tx_data"]); string domain = get_domain(req); - return xmrblocks.show_prove(tx_hash, xmr_address, - tx_prv_key, raw_tx_data, domain); + return xmrblocks.show_prove(tx_hash, + xmr_address, + tx_prv_key, + raw_tx_data, + domain); }); @@ -366,8 +372,11 @@ main(int ac, const char* av[]) string domain = get_domain(req); - return xmrblocks.show_prove(tx_hash, xmr_address, - tx_prv_key, string {}, domain); + return xmrblocks.show_prove(remove_bad_chars(tx_hash), + remove_bad_chars(xmr_address), + remove_bad_chars(tx_prv_key), + string {}, + domain); }); if (enable_pusher) @@ -388,8 +397,8 @@ main(int ac, const char* av[]) return string("Raw tx data or action not provided"); } - string raw_tx_data = post_body["rawtxdata"]; - string action = post_body["action"]; + string raw_tx_data = remove_bad_chars(post_body["rawtxdata"]); + string action = remove_bad_chars(post_body["action"]); if (action == "check") return xmrblocks.show_checkrawtx(raw_tx_data, action); @@ -423,8 +432,8 @@ main(int ac, const char* av[]) return string("Viewkey not provided. Cant decrypt key image file without it"); } - string raw_data = post_body["rawkeyimgsdata"]; - string viewkey = post_body["viewkey"]; + string raw_data = remove_bad_chars(post_body["rawkeyimgsdata"]); + string viewkey = remove_bad_chars(post_body["viewkey"]); return xmrblocks.show_checkrawkeyimgs(raw_data, viewkey); }); @@ -455,8 +464,8 @@ main(int ac, const char* av[]) "key image file without it"); } - string raw_data = post_body["rawoutputkeysdata"]; - string viewkey = post_body["viewkey"]; + string raw_data = remove_bad_chars(post_body["rawoutputkeysdata"]); + string viewkey = remove_bad_chars(post_body["viewkey"]); return xmrblocks.show_checkcheckrawoutput(raw_data, viewkey); }); @@ -465,7 +474,7 @@ main(int ac, const char* av[]) CROW_ROUTE(app, "/search").methods("GET"_method) ([&](const crow::request& req) { - return xmrblocks.search(string(req.url_params.get("value"))); + return xmrblocks.search(remove_bad_chars(string(req.url_params.get("value")))); }); CROW_ROUTE(app, "/mempool") @@ -496,7 +505,7 @@ main(int ac, const char* av[]) CROW_ROUTE(app, "/api/transaction/") ([&](const crow::request &req, string tx_hash) { - myxmr::jsonresponse r{xmrblocks.json_transaction(tx_hash)}; + myxmr::jsonresponse r{xmrblocks.json_transaction(remove_bad_chars(tx_hash))}; return r; }); @@ -504,7 +513,7 @@ main(int ac, const char* av[]) CROW_ROUTE(app, "/api/rawtransaction/") ([&](const crow::request &req, string tx_hash) { - myxmr::jsonresponse r{xmrblocks.json_rawtransaction(tx_hash)}; + myxmr::jsonresponse r{xmrblocks.json_rawtransaction(remove_bad_chars(tx_hash))}; return r; }); @@ -512,7 +521,7 @@ main(int ac, const char* av[]) CROW_ROUTE(app, "/api/block/") ([&](const crow::request &req, string block_no_or_hash) { - myxmr::jsonresponse r{xmrblocks.json_block(block_no_or_hash)}; + myxmr::jsonresponse r{xmrblocks.json_block(remove_bad_chars(block_no_or_hash))}; return r; }); @@ -520,7 +529,7 @@ main(int ac, const char* av[]) CROW_ROUTE(app, "/api/rawblock/") ([&](const crow::request &req, string block_no_or_hash) { - myxmr::jsonresponse r{xmrblocks.json_rawblock(block_no_or_hash)}; + myxmr::jsonresponse r{xmrblocks.json_rawblock(remove_bad_chars(block_no_or_hash))}; return r; }); @@ -534,7 +543,8 @@ main(int ac, const char* av[]) string limit = regex_search(req.raw_url, regex {"limit=\\d+"}) ? req.url_params.get("limit") : "25"; - myxmr::jsonresponse r{xmrblocks.json_transactions(page, limit)}; + myxmr::jsonresponse r{xmrblocks.json_transactions( + remove_bad_chars(page), remove_bad_chars(limit))}; return r; }); @@ -551,7 +561,8 @@ main(int ac, const char* av[]) string limit = regex_search(req.raw_url, regex {"limit=\\d+"}) ? req.url_params.get("limit") : "100000000"; - myxmr::jsonresponse r{xmrblocks.json_mempool(page, limit)}; + myxmr::jsonresponse r{xmrblocks.json_mempool( + remove_bad_chars(page), remove_bad_chars(limit))}; return r; }); @@ -559,7 +570,7 @@ main(int ac, const char* av[]) CROW_ROUTE(app, "/api/search/") ([&](const crow::request &req, string search_value) { - myxmr::jsonresponse r{xmrblocks.json_search(search_value)}; + myxmr::jsonresponse r{xmrblocks.json_search(remove_bad_chars(search_value))}; return r; }); @@ -605,7 +616,11 @@ main(int ac, const char* av[]) cerr << "Cant parse tx_prove as bool. Using default value" << endl; } - myxmr::jsonresponse r{xmrblocks.json_outputs(tx_hash, address, viewkey, tx_prove)}; + myxmr::jsonresponse r{xmrblocks.json_outputs( + remove_bad_chars(tx_hash), + remove_bad_chars(address), + remove_bad_chars(viewkey), + tx_prove)}; return r; }); @@ -635,7 +650,11 @@ main(int ac, const char* av[]) cerr << "Cant parse tx_prove as bool. Using default value" << endl; } - myxmr::jsonresponse r{xmrblocks.json_outputsblocks(limit, address, viewkey, in_mempool_aswell)}; + myxmr::jsonresponse r{xmrblocks.json_outputsblocks( + remove_bad_chars(limit), + remove_bad_chars(address), + remove_bad_chars(viewkey), + in_mempool_aswell)}; return r; }); diff --git a/src/page.h b/src/page.h index 5796be3..904f107 100644 --- a/src/page.h +++ b/src/page.h @@ -5458,7 +5458,7 @@ namespace xmreg {"has_payment_id8" , txd.payment_id8 != null_hash8}, {"confirmations" , txd.no_confirmations}, {"payment_id" , pid_str}, - {"payment_id_as_ascii" , std::regex_replace(txd.payment_id_as_ascii, e, " ")}, + {"payment_id_as_ascii" , remove_bad_chars(txd.payment_id_as_ascii)}, {"payment_id8" , pid8_str}, {"extra" , txd.get_extra_str()}, {"with_ring_signatures" , static_cast( diff --git a/src/tools.h b/src/tools.h index dbd96a0..ad185c1 100644 --- a/src/tools.h +++ b/src/tools.h @@ -41,318 +41,329 @@ namespace xmreg { - using namespace cryptonote; - using namespace crypto; - using namespace std; +using namespace cryptonote; +using namespace crypto; +using namespace std; - namespace bf = boost::filesystem; +namespace bf = boost::filesystem; - using json = nlohmann::json; +using json = nlohmann::json; - struct outputs_visitor +struct outputs_visitor +{ + std::vector& m_output_keys; + + const Blockchain& m_bch; + + outputs_visitor(std::vector& output_keys, const Blockchain& bch) : + m_output_keys(output_keys), m_bch(bch) { - std::vector& m_output_keys; + } - const Blockchain& m_bch; - - outputs_visitor(std::vector& output_keys, const Blockchain& bch) : - m_output_keys(output_keys), m_bch(bch) - { - } - - bool handle_output(uint64_t unlock_time, const crypto::public_key &pubkey) - { - m_output_keys.push_back(pubkey); - return true; - } - }; - - - template - bool - parse_str_secret_key(const string& key_str, T& secret_key); - - template - bool - parse_str_secret_key(const string& key_str, std::vector& secret_keys) + bool handle_output(uint64_t unlock_time, const crypto::public_key &pubkey) { - const size_t num_keys = key_str.size() / 64; - if (num_keys * 64 != key_str.size()) - return false; - secret_keys.resize(num_keys); - for (size_t i = 0; i < num_keys; ++i) - { - if (!parse_str_secret_key(key_str.substr(64*i, 64), secret_keys[i])) - return false; - } + m_output_keys.push_back(pubkey); return true; } +}; - bool - get_tx_pub_key_from_str_hash(Blockchain& core_storage, - const string& hash_str, - transaction& tx); +template +bool +parse_str_secret_key(const string& key_str, T& secret_key); - bool - parse_str_address(const string& address_str, - address_parse_info& address_info, - bool testnet = false); +template +bool +parse_str_secret_key(const string& key_str, std::vector& secret_keys) +{ + const size_t num_keys = key_str.size() / 64; + if (num_keys * 64 != key_str.size()) + return false; + secret_keys.resize(num_keys); + for (size_t i = 0; i < num_keys; ++i) + { + if (!parse_str_secret_key(key_str.substr(64*i, 64), secret_keys[i])) + return false; + } + return true; +} - inline bool - is_separator(char c); - string - print_address(const address_parse_info& address, +bool +get_tx_pub_key_from_str_hash(Blockchain& core_storage, + const string& hash_str, + transaction& tx); + +bool +parse_str_address(const string& address_str, + address_parse_info& address_info, bool testnet = false); - string - print_sig (const signature& sig); +inline bool +is_separator(char c); - string - remove_trailing_path_separator(const string& in_path); +string +print_address(const address_parse_info& address, + bool testnet = false); - bf::path - remove_trailing_path_separator(const bf::path& in_path); +string +print_sig (const signature& sig); - string - timestamp_to_str_gm(time_t timestamp, const char* format = "%F %T"); +string +remove_trailing_path_separator(const string& in_path); - ostream& - operator<< (ostream& os, const address_parse_info& addr_info); +bf::path +remove_trailing_path_separator(const bf::path& in_path); + +string +timestamp_to_str_gm(time_t timestamp, const char* format = "%F %T"); + +ostream& +operator<< (ostream& os, const address_parse_info& addr_info); - string - get_default_lmdb_folder(bool testnet = false); +string +get_default_lmdb_folder(bool testnet = false); - bool - generate_key_image(const crypto::key_derivation& derivation, - const std::size_t output_index, - const crypto::secret_key& sec_key, - const crypto::public_key& pub_key, - crypto::key_image& key_img); +bool +generate_key_image(const crypto::key_derivation& derivation, + const std::size_t output_index, + const crypto::secret_key& sec_key, + const crypto::public_key& pub_key, + crypto::key_image& key_img); - bool - get_blockchain_path(const boost::optional& bc_path, - bf::path& blockchain_path, - bool testnet = false); +bool +get_blockchain_path(const boost::optional& bc_path, + bf::path& blockchain_path, + bool testnet = false); - uint64_t - sum_money_in_outputs(const transaction& tx); +uint64_t +sum_money_in_outputs(const transaction& tx); - pair - sum_money_in_outputs(const string& json_str); +pair +sum_money_in_outputs(const string& json_str); - pair - sum_money_in_outputs(const json& _json); +pair +sum_money_in_outputs(const json& _json); - array - summary_of_in_out_rct( - const transaction& tx, - vector>& output_pub_keys, - vector& input_key_imgs); +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); +// this version for mempool txs from json +array +summary_of_in_out_rct(const json& _json); - uint64_t - sum_money_in_inputs(const transaction& tx); +uint64_t +sum_money_in_inputs(const transaction& tx); - pair - sum_money_in_inputs(const string& json_str); +pair +sum_money_in_inputs(const string& json_str); - pair - sum_money_in_inputs(const json& _json); +pair +sum_money_in_inputs(const json& _json); - uint64_t - count_nonrct_inputs(const transaction& tx); +uint64_t +count_nonrct_inputs(const transaction& tx); - uint64_t - count_nonrct_inputs(const string& json_str); +uint64_t +count_nonrct_inputs(const string& json_str); - uint64_t - count_nonrct_inputs(const json& _json); +uint64_t +count_nonrct_inputs(const json& _json); - array - sum_money_in_tx(const transaction& tx); +array +sum_money_in_tx(const transaction& tx); - array - sum_money_in_txs(const vector& txs); +array +sum_money_in_txs(const vector& txs); - uint64_t - sum_fees_in_txs(const vector& txs); +uint64_t +sum_fees_in_txs(const vector& txs); - uint64_t - get_mixin_no(const transaction& tx); +uint64_t +get_mixin_no(const transaction& tx); - vector - get_mixin_no(const string& json_str); +vector +get_mixin_no(const string& json_str); - vector - get_mixin_no(const json& _json); +vector +get_mixin_no(const json& _json); - vector - get_mixin_no_in_txs(const vector& txs); +vector +get_mixin_no_in_txs(const vector& txs); - vector> - get_ouputs(const transaction& tx); +vector> +get_ouputs(const transaction& tx); - vector> - get_ouputs_tuple(const transaction& tx); +vector> +get_ouputs_tuple(const transaction& tx); - vector - get_key_images(const transaction& tx); +vector +get_key_images(const transaction& tx); - bool - get_payment_id(const vector& extra, - crypto::hash& payment_id, - crypto::hash8& payment_id8); +bool +get_payment_id(const vector& extra, + crypto::hash& payment_id, + crypto::hash8& payment_id8); - bool - get_payment_id(const transaction& tx, - crypto::hash& payment_id, - crypto::hash8& payment_id8); +bool +get_payment_id(const transaction& tx, + crypto::hash& payment_id, + crypto::hash8& payment_id8); - inline double - get_xmr(uint64_t core_amount) - { - return static_cast(core_amount) / 1e12; - } +inline double +get_xmr(uint64_t core_amount) +{ + return static_cast(core_amount) / 1e12; +} - array - timestamp_difference(uint64_t t1, uint64_t t2); +array +timestamp_difference(uint64_t t1, uint64_t t2); - string - read(string filename); +string +read(string filename); - pair - timestamps_time_scale(const vector& timestamps, - uint64_t timeN, uint64_t resolution = 80, - uint64_t time0 = 1397818193 /* timestamp of the second block */); +pair +timestamps_time_scale(const vector& timestamps, + uint64_t timeN, uint64_t resolution = 80, + uint64_t time0 = 1397818193 /* timestamp of the second block */); - bool - decode_ringct(const rct::rctSig & rv, - const crypto::public_key pub, - const crypto::secret_key &sec, - unsigned int i, - rct::key & mask, - uint64_t & amount); +bool +decode_ringct(const rct::rctSig & rv, + const crypto::public_key pub, + const crypto::secret_key &sec, + unsigned int i, + rct::key & mask, + uint64_t & amount); - bool - decode_ringct(const rct::rctSig & rv, - const crypto::key_derivation &derivation, - unsigned int i, - rct::key & mask, - uint64_t & amount); +bool +decode_ringct(const rct::rctSig & rv, + const crypto::key_derivation &derivation, + unsigned int i, + rct::key & mask, + uint64_t & amount); - bool - url_decode(const std::string& in, std::string& out); +bool +url_decode(const std::string& in, std::string& out); - map - parse_crow_post_data(const string& req_body); +map +parse_crow_post_data(const string& req_body); // from wallet2::decrypt - string - decrypt(const std::string &ciphertext, - const crypto::secret_key &skey, - bool authenticated = true); +string +decrypt(const std::string &ciphertext, + const crypto::secret_key &skey, + bool authenticated = true); // based on // crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const - public_key - get_tx_pub_key_from_received_outs(const transaction &tx); +public_key +get_tx_pub_key_from_received_outs(const transaction &tx); - static - string - xmr_amount_to_str(const uint64_t& xmr_amount, - string _format="{:0.12f}", - bool zero_to_question_mark=true) +static +string +xmr_amount_to_str(const uint64_t& xmr_amount, + string _format="{:0.12f}", + bool zero_to_question_mark=true) +{ + string amount_str = "?"; + + if (!zero_to_question_mark) { - string amount_str = "?"; - - if (!zero_to_question_mark) + amount_str = fmt::format(_format, XMR_AMOUNT(xmr_amount)); + } + else + { + if (xmr_amount > 0 && zero_to_question_mark == true) { amount_str = fmt::format(_format, XMR_AMOUNT(xmr_amount)); } - else - { - if (xmr_amount > 0 && zero_to_question_mark == true) - { - amount_str = fmt::format(_format, XMR_AMOUNT(xmr_amount)); - } - } - - return amount_str; } - bool - is_output_ours(const size_t& output_index, - const transaction& tx, - const public_key& pub_tx_key, - const secret_key& private_view_key, - const public_key& public_spend_key); + return amount_str; +} - bool - get_real_output_for_key_image(const key_image& ki, - const transaction& tx, - const secret_key& private_view_key, - const public_key& public_spend_key, - uint64_t output_idx, - public_key output_pub_key); +bool +is_output_ours(const size_t& output_index, + const transaction& tx, + const public_key& pub_tx_key, + const secret_key& private_view_key, + const public_key& public_spend_key); + +bool +get_real_output_for_key_image(const key_image& ki, + const transaction& tx, + const secret_key& private_view_key, + const public_key& public_spend_key, + uint64_t output_idx, + public_key output_pub_key); // based on http://stackoverflow.com/a/9943098/248823 - template - void chunks(Iterator begin, - Iterator end, - iterator_traits::difference_type k, - Func f) +template +void chunks(Iterator begin, + Iterator end, + iterator_traits::difference_type k, + Func f) +{ + Iterator chunk_begin; + Iterator chunk_end; + chunk_end = chunk_begin = begin; + + do { - Iterator chunk_begin; - Iterator chunk_end; - chunk_end = chunk_begin = begin; - - do - { - if(std::distance(chunk_end, end) < k) - chunk_end = end; - else - std::advance(chunk_end, k); - f(chunk_begin,chunk_end); - chunk_begin = chunk_end; - } - while(std::distance(chunk_begin,end) > 0); + if(std::distance(chunk_end, end) < k) + chunk_end = end; + else + std::advance(chunk_end, k); + f(chunk_begin,chunk_end); + chunk_begin = chunk_end; } + while(std::distance(chunk_begin,end) > 0); +} + +/* + * Remove all characters in in_str that match the given + * regular expression + */ +inline string +remove_bad_chars(string const& in_str, std::regex const& rgx = std::regex {"[^a-zA-Z0-9]"}) +{ + return std::regex_replace(in_str, rgx, ""); +} - bool - make_tx_from_json(const string& json_str, transaction& tx); - string - make_printable(const string& in_s); +bool +make_tx_from_json(const string& json_str, transaction& tx); - string - get_human_readable_timestamp(uint64_t ts); +string +make_printable(const string& in_s); + +string +get_human_readable_timestamp(uint64_t ts); // Get the median of an unordered set of numbers of arbitrary // type without modifying the underlying dataset. // taken from http://stackoverflow.com/a/19695285 - template - typename std::iterator_traits::value_type - calc_median(It it_begin, It it_end) - { - using T = typename std::iterator_traits::value_type; - std::vector data(it_begin, it_end); - std::nth_element(data.begin(), data.begin() + data.size() / 2, data.end()); - return data[data.size() / 2]; - } +template +typename std::iterator_traits::value_type +calc_median(It it_begin, It it_end) +{ + using T = typename std::iterator_traits::value_type; + std::vector data(it_begin, it_end); + std::nth_element(data.begin(), data.begin() + data.size() / 2, data.end()); + return data[data.size() / 2]; +} - void - pause_execution(uint64_t no_seconds, const string& text = "now"); +void +pause_execution(uint64_t no_seconds, const string& text = "now"); } From 4146a478097d70531867fdeef5502ffe16f6557d Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Wed, 20 Dec 2017 08:40:09 +0800 Subject: [PATCH 23/27] make it compile on ubuntu 16.04 --- src/page.h | 2 +- src/tools.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/page.h b/src/page.h index 904f107..43852d3 100644 --- a/src/page.h +++ b/src/page.h @@ -30,7 +30,7 @@ #include #include #include -#include + #define TMPL_DIR "./templates" #define TMPL_PARIALS_DIR TMPL_DIR "/partials" diff --git a/src/tools.h b/src/tools.h index ad185c1..ba4d153 100644 --- a/src/tools.h +++ b/src/tools.h @@ -31,7 +31,7 @@ #include #include #include - +#include /** * Some helper functions used in the example. @@ -333,7 +333,7 @@ void chunks(Iterator begin, * regular expression */ inline string -remove_bad_chars(string const& in_str, std::regex const& rgx = std::regex {"[^a-zA-Z0-9]"}) +remove_bad_chars(string const& in_str, std::regex const& rgx = std::regex ("[^a-zA-Z0-9]")) { return std::regex_replace(in_str, rgx, ""); } From 599ad6170663d34101ed14c2f37ffc71607958ac Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Fri, 22 Dec 2017 07:52:14 +0800 Subject: [PATCH 24/27] add sanitizers-cmake to enable/disable ASAN --- CMakeLists.txt | 11 ++- README.md | 3 + cmake/FindASan.cmake | 59 ++++++++++++ cmake/FindMSan.cmake | 57 ++++++++++++ cmake/FindSanitizers.cmake | 87 ++++++++++++++++++ cmake/FindTSan.cmake | 65 ++++++++++++++ cmake/FindUBSan.cmake | 46 ++++++++++ cmake/asan-wrapper | 55 ++++++++++++ cmake/sanitize-helpers.cmake | 170 +++++++++++++++++++++++++++++++++++ 9 files changed, 547 insertions(+), 6 deletions(-) create mode 100644 cmake/FindASan.cmake create mode 100644 cmake/FindMSan.cmake create mode 100644 cmake/FindSanitizers.cmake create mode 100644 cmake/FindTSan.cmake create mode 100644 cmake/FindUBSan.cmake create mode 100755 cmake/asan-wrapper create mode 100644 cmake/sanitize-helpers.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d25663c..05424aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,12 +7,8 @@ set(PROJECT_NAME project(${PROJECT_NAME}) set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++14 -fsanitize=address -fno-omit-frame-pointer") + "${CMAKE_CXX_FLAGS} -std=c++14") -set(CMAKE_C_FLAGS - "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -DLEAK_SANITIZER") - -# if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj -O3") @@ -57,7 +53,8 @@ find_package(Boost COMPONENTS date_time REQUIRED) - +#info https://github.com/arsenm/sanitizers-cmake +find_package(Sanitizers) if(APPLE) include_directories(/usr/local/opt/openssl/include) @@ -90,6 +87,8 @@ set(SOURCE_FILES add_executable(${PROJECT_NAME} ${SOURCE_FILES}) +add_sanitizers(${PROJECT_NAME}) + create_git_version() configure_files(${CMAKE_CURRENT_SOURCE_DIR}/src/templates ${CMAKE_CURRENT_BINARY_DIR}/templates) diff --git a/README.md b/README.md index 51006d0..eca4249 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,9 @@ cmake .. # altearnatively can use: cmake -DMONERO_DIR=/path/to/monero_folder .. # if monero is not in ~/monero +# +# also can build with ASAN (sanitizers), for example +# cmake -DSANITIZE_ADDRESS=On .. # compile make diff --git a/cmake/FindASan.cmake b/cmake/FindASan.cmake new file mode 100644 index 0000000..98ea7cb --- /dev/null +++ b/cmake/FindASan.cmake @@ -0,0 +1,59 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +option(SANITIZE_ADDRESS "Enable AddressSanitizer for sanitized targets." Off) + +set(FLAG_CANDIDATES + # Clang 3.2+ use this version. The no-omit-frame-pointer option is optional. + "-g -fsanitize=address -fno-omit-frame-pointer" + "-g -fsanitize=address" + + # Older deprecated flag for ASan + "-g -faddress-sanitizer" +) + + +if (SANITIZE_ADDRESS AND (SANITIZE_THREAD OR SANITIZE_MEMORY)) + message(FATAL_ERROR "AddressSanitizer is not compatible with " + "ThreadSanitizer or MemorySanitizer.") +endif () + + +include(sanitize-helpers) + +if (SANITIZE_ADDRESS) + sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "AddressSanitizer" + "ASan") + + find_program(ASan_WRAPPER "asan-wrapper" PATHS ${CMAKE_MODULE_PATH}) + mark_as_advanced(ASan_WRAPPER) +endif () + +function (add_sanitize_address TARGET) + if (NOT SANITIZE_ADDRESS) + return() + endif () + + sanitizer_add_flags(${TARGET} "AddressSanitizer" "ASan") +endfunction () diff --git a/cmake/FindMSan.cmake b/cmake/FindMSan.cmake new file mode 100644 index 0000000..22d0050 --- /dev/null +++ b/cmake/FindMSan.cmake @@ -0,0 +1,57 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +option(SANITIZE_MEMORY "Enable MemorySanitizer for sanitized targets." Off) + +set(FLAG_CANDIDATES + "-g -fsanitize=memory" +) + + +include(sanitize-helpers) + +if (SANITIZE_MEMORY) + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + message(WARNING "MemorySanitizer disabled for target ${TARGET} because " + "MemorySanitizer is supported for Linux systems only.") + set(SANITIZE_MEMORY Off CACHE BOOL + "Enable MemorySanitizer for sanitized targets." FORCE) + elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) + message(WARNING "MemorySanitizer disabled for target ${TARGET} because " + "MemorySanitizer is supported for 64bit systems only.") + set(SANITIZE_MEMORY Off CACHE BOOL + "Enable MemorySanitizer for sanitized targets." FORCE) + else () + sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "MemorySanitizer" + "MSan") + endif () +endif () + +function (add_sanitize_memory TARGET) + if (NOT SANITIZE_MEMORY) + return() + endif () + + sanitizer_add_flags(${TARGET} "MemorySanitizer" "MSan") +endfunction () diff --git a/cmake/FindSanitizers.cmake b/cmake/FindSanitizers.cmake new file mode 100644 index 0000000..4f586a3 --- /dev/null +++ b/cmake/FindSanitizers.cmake @@ -0,0 +1,87 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# If any of the used compiler is a GNU compiler, add a second option to static +# link against the sanitizers. +option(SANITIZE_LINK_STATIC "Try to link static against sanitizers." Off) + + + + +set(FIND_QUIETLY_FLAG "") +if (DEFINED Sanitizers_FIND_QUIETLY) + set(FIND_QUIETLY_FLAG "QUIET") +endif () + +find_package(ASan ${FIND_QUIETLY_FLAG}) +find_package(TSan ${FIND_QUIETLY_FLAG}) +find_package(MSan ${FIND_QUIETLY_FLAG}) +find_package(UBSan ${FIND_QUIETLY_FLAG}) + + + + +function(sanitizer_add_blacklist_file FILE) + if(NOT IS_ABSOLUTE ${FILE}) + set(FILE "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}") + endif() + get_filename_component(FILE "${FILE}" REALPATH) + + sanitizer_check_compiler_flags("-fsanitize-blacklist=${FILE}" + "SanitizerBlacklist" "SanBlist") +endfunction() + +function(add_sanitizers ...) + # If no sanitizer is enabled, return immediately. + if (NOT (SANITIZE_ADDRESS OR SANITIZE_MEMORY OR SANITIZE_THREAD OR + SANITIZE_UNDEFINED)) + return() + endif () + + foreach (TARGET ${ARGV}) + # Check if this target will be compiled by exactly one compiler. Other- + # wise sanitizers can't be used and a warning should be printed once. + sanitizer_target_compilers(${TARGET} TARGET_COMPILER) + list(LENGTH TARGET_COMPILER NUM_COMPILERS) + if (NUM_COMPILERS GREATER 1) + message(WARNING "Can't use any sanitizers for target ${TARGET}, " + "because it will be compiled by incompatible compilers. " + "Target will be compiled without sanitizers.") + return() + + # If the target is compiled by no known compiler, ignore it. + elseif (NUM_COMPILERS EQUAL 0) + message(WARNING "Can't use any sanitizers for target ${TARGET}, " + "because it uses an unknown compiler. Target will be " + "compiled without sanitizers.") + return() + endif () + + # Add sanitizers for target. + add_sanitize_address(${TARGET}) + add_sanitize_thread(${TARGET}) + add_sanitize_memory(${TARGET}) + add_sanitize_undefined(${TARGET}) + endforeach () +endfunction(add_sanitizers) diff --git a/cmake/FindTSan.cmake b/cmake/FindTSan.cmake new file mode 100644 index 0000000..3cba3c0 --- /dev/null +++ b/cmake/FindTSan.cmake @@ -0,0 +1,65 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +option(SANITIZE_THREAD "Enable ThreadSanitizer for sanitized targets." Off) + +set(FLAG_CANDIDATES + "-g -fsanitize=thread" +) + + +# ThreadSanitizer is not compatible with MemorySanitizer. +if (SANITIZE_THREAD AND SANITIZE_MEMORY) + message(FATAL_ERROR "ThreadSanitizer is not compatible with " + "MemorySanitizer.") +endif () + + +include(sanitize-helpers) + +if (SANITIZE_THREAD) + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND + NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + message(WARNING "ThreadSanitizer disabled for target ${TARGET} because " + "ThreadSanitizer is supported for Linux systems and macOS only.") + set(SANITIZE_THREAD Off CACHE BOOL + "Enable ThreadSanitizer for sanitized targets." FORCE) + elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) + message(WARNING "ThreadSanitizer disabled for target ${TARGET} because " + "ThreadSanitizer is supported for 64bit systems only.") + set(SANITIZE_THREAD Off CACHE BOOL + "Enable ThreadSanitizer for sanitized targets." FORCE) + else () + sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "ThreadSanitizer" + "TSan") + endif () +endif () + +function (add_sanitize_thread TARGET) + if (NOT SANITIZE_THREAD) + return() + endif () + + sanitizer_add_flags(${TARGET} "ThreadSanitizer" "TSan") +endfunction () diff --git a/cmake/FindUBSan.cmake b/cmake/FindUBSan.cmake new file mode 100644 index 0000000..ae103f7 --- /dev/null +++ b/cmake/FindUBSan.cmake @@ -0,0 +1,46 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +option(SANITIZE_UNDEFINED + "Enable UndefinedBehaviorSanitizer for sanitized targets." Off) + +set(FLAG_CANDIDATES + "-g -fsanitize=undefined" +) + + +include(sanitize-helpers) + +if (SANITIZE_UNDEFINED) + sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" + "UndefinedBehaviorSanitizer" "UBSan") +endif () + +function (add_sanitize_undefined TARGET) + if (NOT SANITIZE_UNDEFINED) + return() + endif () + + sanitizer_add_flags(${TARGET} "UndefinedBehaviorSanitizer" "UBSan") +endfunction () diff --git a/cmake/asan-wrapper b/cmake/asan-wrapper new file mode 100755 index 0000000..5d54103 --- /dev/null +++ b/cmake/asan-wrapper @@ -0,0 +1,55 @@ +#!/bin/sh + +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# This script is a wrapper for AddressSanitizer. In some special cases you need +# to preload AddressSanitizer to avoid error messages - e.g. if you're +# preloading another library to your application. At the moment this script will +# only do something, if we're running on a Linux platform. OSX might not be +# affected. + + +# Exit immediately, if platform is not Linux. +if [ "$(uname)" != "Linux" ] +then + exec $@ +fi + + +# Get the used libasan of the application ($1). If a libasan was found, it will +# be prepended to LD_PRELOAD. +libasan=$(ldd $1 | grep libasan | sed "s/^[[:space:]]//" | cut -d' ' -f1) +if [ -n "$libasan" ] +then + if [ -n "$LD_PRELOAD" ] + then + export LD_PRELOAD="$libasan:$LD_PRELOAD" + else + export LD_PRELOAD="$libasan" + fi +fi + +# Execute the application. +exec $@ diff --git a/cmake/sanitize-helpers.cmake b/cmake/sanitize-helpers.cmake new file mode 100644 index 0000000..c51ee6a --- /dev/null +++ b/cmake/sanitize-helpers.cmake @@ -0,0 +1,170 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Helper function to get the language of a source file. +function (sanitizer_lang_of_source FILE RETURN_VAR) + get_filename_component(FILE_EXT "${FILE}" EXT) + string(TOLOWER "${FILE_EXT}" FILE_EXT) + string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) + + get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach (LANG ${ENABLED_LANGUAGES}) + list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) + if (NOT ${TEMP} EQUAL -1) + set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) + return() + endif () + endforeach() + + set(${RETURN_VAR} "" PARENT_SCOPE) +endfunction () + + +# Helper function to get compilers used by a target. +function (sanitizer_target_compilers TARGET RETURN_VAR) + # Check if all sources for target use the same compiler. If a target uses + # e.g. C and Fortran mixed and uses different compilers (e.g. clang and + # gfortran) this can trigger huge problems, because different compilers may + # use different implementations for sanitizers. + set(BUFFER "") + get_target_property(TSOURCES ${TARGET} SOURCES) + foreach (FILE ${TSOURCES}) + # If expression was found, FILE is a generator-expression for an object + # library. Object libraries will be ignored. + string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) + if ("${_file}" STREQUAL "") + sanitizer_lang_of_source(${FILE} LANG) + if (LANG) + list(APPEND BUFFER ${CMAKE_${LANG}_COMPILER_ID}) + endif () + endif () + endforeach () + + list(REMOVE_DUPLICATES BUFFER) + set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) +endfunction () + + +# Helper function to check compiler flags for language compiler. +function (sanitizer_check_compiler_flag FLAG LANG VARIABLE) + if (${LANG} STREQUAL "C") + include(CheckCCompilerFlag) + check_c_compiler_flag("${FLAG}" ${VARIABLE}) + + elseif (${LANG} STREQUAL "CXX") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("${FLAG}" ${VARIABLE}) + + elseif (${LANG} STREQUAL "Fortran") + # CheckFortranCompilerFlag was introduced in CMake 3.x. To be compatible + # with older Cmake versions, we will check if this module is present + # before we use it. Otherwise we will define Fortran coverage support as + # not available. + include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED) + if (INCLUDED) + check_fortran_compiler_flag("${FLAG}" ${VARIABLE}) + elseif (NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VARIABLE}") + message(STATUS "Performing Test ${VARIABLE}" + " - Failed (Check not supported)") + endif () + endif() +endfunction () + + +# Helper function to test compiler flags. +function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) + set(CMAKE_REQUIRED_QUIET ${${PREFIX}_FIND_QUIETLY}) + + get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach (LANG ${ENABLED_LANGUAGES}) + # Sanitizer flags are not dependend on language, but the used compiler. + # So instead of searching flags foreach language, search flags foreach + # compiler used. + set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) + if (NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS) + foreach (FLAG ${FLAG_CANDIDATES}) + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]") + endif() + + set(CMAKE_REQUIRED_FLAGS "${FLAG}") + unset(${PREFIX}_FLAG_DETECTED CACHE) + sanitizer_check_compiler_flag("${FLAG}" ${LANG} + ${PREFIX}_FLAG_DETECTED) + + if (${PREFIX}_FLAG_DETECTED) + # If compiler is a GNU compiler, search for static flag, if + # SANITIZE_LINK_STATIC is enabled. + if (SANITIZE_LINK_STATIC AND (${COMPILER} STREQUAL "GNU")) + string(TOLOWER ${PREFIX} PREFIX_lower) + sanitizer_check_compiler_flag( + "-static-lib${PREFIX_lower}" ${LANG} + ${PREFIX}_STATIC_FLAG_DETECTED) + + if (${PREFIX}_STATIC_FLAG_DETECTED) + set(FLAG "-static-lib${PREFIX_lower} ${FLAG}") + endif () + endif () + + set(${PREFIX}_${COMPILER}_FLAGS "${FLAG}" CACHE STRING + "${NAME} flags for ${COMPILER} compiler.") + mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) + break() + endif () + endforeach () + + if (NOT ${PREFIX}_FLAG_DETECTED) + set(${PREFIX}_${COMPILER}_FLAGS "" CACHE STRING + "${NAME} flags for ${COMPILER} compiler.") + mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) + + message(WARNING "${NAME} is not available for ${COMPILER} " + "compiler. Targets using this compiler will be " + "compiled without ${NAME}.") + endif () + endif () + endforeach () +endfunction () + + +# Helper to assign sanitizer flags for TARGET. +function (sanitizer_add_flags TARGET NAME PREFIX) + # Get list of compilers used by target and check, if sanitizer is available + # for this target. Other compiler checks like check for conflicting + # compilers will be done in add_sanitizers function. + sanitizer_target_compilers(${TARGET} TARGET_COMPILER) + list(LENGTH TARGET_COMPILER NUM_COMPILERS) + if ("${${PREFIX}_${TARGET_COMPILER}_FLAGS}" STREQUAL "") + return() + endif() + + # Set compile- and link-flags for target. + set_property(TARGET ${TARGET} APPEND_STRING + PROPERTY COMPILE_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") + set_property(TARGET ${TARGET} APPEND_STRING + PROPERTY COMPILE_FLAGS " ${SanBlist_${TARGET_COMPILER}_FLAGS}") + set_property(TARGET ${TARGET} APPEND_STRING + PROPERTY LINK_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") +endfunction () From 98571672fefced67d5eca3552a3cf4a212bc1726 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Fri, 22 Dec 2017 08:29:22 +0800 Subject: [PATCH 25/27] hard fork version added to network info --- src/MempoolStatus.cpp | 3 +++ src/MempoolStatus.h | 1 + src/page.h | 4 +++- src/templates/index2.html | 1 + src/tools.h | 5 +++-- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/MempoolStatus.cpp b/src/MempoolStatus.cpp index 380d087..4d186e0 100644 --- a/src/MempoolStatus.cpp +++ b/src/MempoolStatus.cpp @@ -249,10 +249,13 @@ MempoolStatus::read_network_info() local_copy.block_size_limit = rpc_network_info.block_size_limit; local_copy.start_time = rpc_network_info.start_time; + epee::string_tools::hex_to_pod(rpc_network_info.top_block_hash, local_copy.top_block_hash); local_copy.fee_per_kb = fee_estimated; local_copy.info_timestamp = static_cast(std::time(nullptr)); + local_copy.current_hf_version = core_storage->get_current_hard_fork_version(); + local_copy.current = true; current_network_info = local_copy; diff --git a/src/MempoolStatus.h b/src/MempoolStatus.h index 8a42ab5..32418e1 100644 --- a/src/MempoolStatus.h +++ b/src/MempoolStatus.h @@ -71,6 +71,7 @@ struct MempoolStatus uint64_t cumulative_difficulty {0}; uint64_t block_size_limit {0}; uint64_t start_time {0}; + uint64_t current_hf_version {0}; uint64_t hash_rate {0}; uint64_t fee_per_kb {0}; diff --git a/src/page.h b/src/page.h index 43852d3..f65bca8 100644 --- a/src/page.h +++ b/src/page.h @@ -747,6 +747,7 @@ namespace xmreg {"block_size_limit" , block_size_limit}, {"is_current_info" , current_network_info.current}, {"is_pool_size_zero" , (current_network_info.tx_pool_size == 0)}, + {"current_hf_version", current_network_info.current_hf_version}, {"age" , network_info_age.first}, {"age_format" , network_info_age.second}, }; @@ -6069,7 +6070,8 @@ namespace xmreg {"cumulative_difficulty" , local_copy_network_info.cumulative_difficulty}, {"block_size_limit" , local_copy_network_info.block_size_limit}, {"start_time" , local_copy_network_info.start_time}, - {"fee_per_kb" , local_copy_network_info.fee_per_kb} + {"fee_per_kb" , local_copy_network_info.fee_per_kb}, + {"current_hf_version" , local_copy_network_info.current_hf_version} }; return local_copy_network_info.current; diff --git a/src/templates/index2.html b/src/templates/index2.html index c83eb91..32ab590 100644 --- a/src/templates/index2.html +++ b/src/templates/index2.html @@ -37,6 +37,7 @@ {{#network_info}}

Network difficulty: {{difficulty}} + | Hard fork: v{{current_hf_version}} | Hash rate: {{hash_rate}} | Fee per kb: {{fee_per_kb}} | Median block size limit: {{block_size_limit}} kB diff --git a/src/tools.h b/src/tools.h index ba4d153..32d2236 100644 --- a/src/tools.h +++ b/src/tools.h @@ -332,10 +332,11 @@ void chunks(Iterator begin, * Remove all characters in in_str that match the given * regular expression */ +template inline string -remove_bad_chars(string const& in_str, std::regex const& rgx = std::regex ("[^a-zA-Z0-9]")) +remove_bad_chars(T&& in_str, std::regex const& rgx = std::regex ("[^a-zA-Z0-9]")) { - return std::regex_replace(in_str, rgx, ""); + return std::regex_replace(std::forward(in_str), rgx, ""); } From f9b8089168800b5cb0ce9d7445e797c63da2524c Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Thu, 28 Dec 2017 08:18:58 +0800 Subject: [PATCH 26/27] compile with latest monero master --- main.cpp | 3 --- src/page.h | 2 +- src/tools.cpp | 8 ++++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/main.cpp b/main.cpp index 73b9baf..18ac540 100644 --- a/main.cpp +++ b/main.cpp @@ -151,16 +151,13 @@ main(int ac, const char* av[]) string deamon_url {*deamon_url_opt}; if (testnet && deamon_url == "http:://127.0.0.1:18081") - { deamon_url = "http:://127.0.0.1:28081"; - } uint64_t mempool_info_timeout {5000}; try { mempool_info_timeout = boost::lexical_cast(*mempool_info_timeout_opt); - } catch (boost::bad_lexical_cast &e) { diff --git a/src/page.h b/src/page.h index f65bca8..ee4c63c 100644 --- a/src/page.h +++ b/src/page.h @@ -3160,7 +3160,7 @@ namespace xmreg const size_t header_lenght = 2 * sizeof(crypto::public_key); const size_t key_img_size = sizeof(crypto::key_image); const size_t record_lenght = key_img_size + sizeof(crypto::signature); - const size_t chacha_length = sizeof(crypto::chacha8_key); + const size_t chacha_length = sizeof(crypto::chacha_key); if (decoded_raw_data.size() < header_lenght) { diff --git a/src/tools.cpp b/src/tools.cpp index 78604cd..89049b4 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -1035,7 +1035,7 @@ decrypt(const std::string &ciphertext, bool authenticated) { - const size_t prefix_size = sizeof(chacha8_iv) + const size_t prefix_size = sizeof(chacha_iv) + (authenticated ? sizeof(crypto::signature) : 0); if (ciphertext.size() < prefix_size) { @@ -1043,10 +1043,10 @@ decrypt(const std::string &ciphertext, return {}; } - crypto::chacha8_key key; - crypto::generate_chacha8_key(&skey, sizeof(skey), key); + crypto::chacha_key key; + crypto::generate_chacha_key(&skey, sizeof(skey), key); - const crypto::chacha8_iv &iv = *(const crypto::chacha8_iv*)&ciphertext[0]; + const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0]; std::string plaintext; From d01f760404a03e4736cdc2159a957b985d89334b Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Thu, 28 Dec 2017 08:36:19 +0800 Subject: [PATCH 27/27] rpccalls::get_hardfork_info added https://github.com/moneroexamples/onion-monero-blockchain-explorer/issues/92 --- src/MempoolStatus.cpp | 9 ++++--- src/rpccalls.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++ src/rpccalls.h | 3 +++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/MempoolStatus.cpp b/src/MempoolStatus.cpp index 4d186e0..660d9be 100644 --- a/src/MempoolStatus.cpp +++ b/src/MempoolStatus.cpp @@ -211,9 +211,7 @@ MempoolStatus::read_network_info() COMMAND_RPC_GET_INFO::response rpc_network_info; if (!rpc.get_network_info(rpc_network_info)) - { return false; - } uint64_t fee_estimated; @@ -229,6 +227,11 @@ MempoolStatus::read_network_info() (void) error_msg; + COMMAND_RPC_HARD_FORK_INFO::response rpc_hardfork_info; + + if (!rpc.get_hardfork_info(rpc_hardfork_info)) + return false; + network_info local_copy; @@ -254,7 +257,7 @@ MempoolStatus::read_network_info() local_copy.fee_per_kb = fee_estimated; local_copy.info_timestamp = static_cast(std::time(nullptr)); - local_copy.current_hf_version = core_storage->get_current_hard_fork_version(); + local_copy.current_hf_version = rpc_hardfork_info.version; local_copy.current = true; diff --git a/src/rpccalls.cpp b/src/rpccalls.cpp index 036b8ff..d9711be 100644 --- a/src/rpccalls.cpp +++ b/src/rpccalls.cpp @@ -207,6 +207,68 @@ rpccalls::get_network_info(COMMAND_RPC_GET_INFO::response& response) } +bool +rpccalls::get_hardfork_info(COMMAND_RPC_HARD_FORK_INFO::response& response) +{ + epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); + epee::json_rpc::response resp_t = AUTO_VAL_INIT(resp_t); + + + bool r {false}; + + req_t.jsonrpc = "2.0"; + req_t.id = epee::serialization::storage_entry(0); + req_t.method = "hard_fork_info"; + + { + std::lock_guard guard(m_daemon_rpc_mutex); + + if (!connect_to_monero_deamon()) + { + cerr << "get_hardfork_info: not connected to deamon" << endl; + return false; + } + + r = epee::net_utils::invoke_http_json("/json_rpc", + req_t, resp_t, + m_http_client); + } + + + string err; + + if (r) + { + if (resp_t.result.status == CORE_RPC_STATUS_BUSY) + { + err = "daemon is busy. Please try again later."; + } + else if (resp_t.result.status != CORE_RPC_STATUS_OK) + { + err = resp_t.result.status; + } + + if (!err.empty()) + { + cerr << "Error connecting to Monero deamon due to " + << err << endl; + return false; + } + } + else + { + cerr << "Error connecting to Monero deamon at " + << deamon_url << endl; + return false; + } + + response = resp_t.result; + + return true; +} + + + bool rpccalls::get_dynamic_per_kb_fee_estimate( uint64_t grace_blocks, diff --git a/src/rpccalls.h b/src/rpccalls.h index 1e8ef83..720936e 100644 --- a/src/rpccalls.h +++ b/src/rpccalls.h @@ -99,6 +99,9 @@ public: bool get_network_info(COMMAND_RPC_GET_INFO::response& info); + bool + get_hardfork_info( COMMAND_RPC_HARD_FORK_INFO::response& res); + bool get_dynamic_per_kb_fee_estimate( uint64_t grace_blocks,