From 8d91aac912ac7d45edd2332d7e08d5d670af9d33 Mon Sep 17 00:00:00 2001 From: Erik Kimmo Date: Fri, 18 Apr 2014 18:24:52 +0400 Subject: [PATCH 01/75] Mining protocol made compatible with MinerGate.com Fixed incorrect nonce offset in job data. --- src/miner/simpleminer.cpp | 19 +++++++++++++++---- src/miner/simpleminer_protocol_defs.h | 4 ++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp index a9f0ceab..7078eaaa 100644 --- a/src/miner/simpleminer.cpp +++ b/src/miner/simpleminer.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - #include "common/command_line.h" #include "misc_log_ex.h" #include "simpleminer.h" @@ -120,6 +119,7 @@ namespace mining COMMAND_RPC_LOGIN::request req = AUTO_VAL_INIT(req); req.login = m_login; req.pass = m_pass; + req.agent = "simpleminer/0.1"; COMMAND_RPC_LOGIN::response resp = AUTO_VAL_INIT(resp); if(!epee::net_utils::invoke_http_json_rpc("/", req, resp, m_http_client)) { @@ -137,7 +137,12 @@ namespace mining } pool_session_id = resp.id; //78 - if(!text_job_details_to_native_job_details(resp.job, job)) + if (resp.job.blob.empty() && resp.job.target.empty() && resp.job.job_id.empty()) + { + LOG_PRINT_L0("Job didn't change"); + continue; + } + else if(!text_job_details_to_native_job_details(resp.job, job)) { LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep...."); m_http_client.disconnect(); @@ -161,7 +166,8 @@ namespace mining COMMAND_RPC_SUBMITSHARE::response submit_response = AUTO_VAL_INIT(submit_response); submit_request.id = pool_session_id; submit_request.job_id = job.job_id; - submit_request.nonce = epee::string_tools::pod_to_hex((*((uint32_t*)&job.blob.data()[78]))); + submit_request.nonce = epee::string_tools::pod_to_hex((*((uint32_t*)&job.blob.data()[39]))); + submit_request.result = epee::string_tools::pod_to_hex(h); LOG_PRINT_L0("Share found: nonce=" << submit_request.nonce << " for job=" << job.job_id << ", submitting..."); if(!epee::net_utils::invoke_http_json_rpc("/", submit_request, submit_response, m_http_client)) { @@ -193,7 +199,12 @@ namespace mining epee::misc_utils::sleep_no_w(1000); break; } - if(!text_job_details_to_native_job_details(getjob_response, job)) + if (getjob_response.blob.empty() && getjob_response.target.empty() && getjob_response.job_id.empty()) + { + LOG_PRINT_L0("Job didn't change"); + continue; + } + else if(!text_job_details_to_native_job_details(getjob_response, job)) { LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep...."); m_http_client.disconnect(); diff --git a/src/miner/simpleminer_protocol_defs.h b/src/miner/simpleminer_protocol_defs.h index 9b70f8cb..06b6a905 100644 --- a/src/miner/simpleminer_protocol_defs.h +++ b/src/miner/simpleminer_protocol_defs.h @@ -36,10 +36,12 @@ namespace mining { std::string login; std::string pass; + std::string agent; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(login) KV_SERIALIZE(pass) + KV_SERIALIZE(agent) END_KV_SERIALIZE_MAP() }; @@ -82,11 +84,13 @@ namespace mining { std::string id; std::string nonce; + std::string result; std::string job_id; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(id) KV_SERIALIZE(nonce) + KV_SERIALIZE(result) KV_SERIALIZE(job_id) END_KV_SERIALIZE_MAP() }; From 905a91a656893508282d5f1ac54bd7a5541bc261 Mon Sep 17 00:00:00 2001 From: Erik Kimmo Date: Mon, 21 Apr 2014 15:18:13 +0400 Subject: [PATCH 02/75] Fix for reconnection issues in invoke_request in case the hostname is empty. --- contrib/epee/include/net/http_client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index 7e6b52d9..5897a017 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -856,7 +856,7 @@ using namespace std; http::url_content u_c; bool res = parse_url(url, u_c); - if(!tr.is_connected()) + if(!tr.is_connected() && !u_c.host.empty()) { CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); From 3f6cf176d4c0424a86cf33370989686e836fe49e Mon Sep 17 00:00:00 2001 From: thankful_for_today Date: Sun, 20 Apr 2014 00:53:40 +0400 Subject: [PATCH 03/75] mining bug fixed --- src/cryptonote_core/blockchain_storage.cpp | 4 +- src/cryptonote_core/tx_pool.cpp | 59 +++++----------------- 2 files changed, 15 insertions(+), 48 deletions(-) diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index cef988c4..c1b9619f 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -572,7 +572,7 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad diffic = get_difficulty_for_next_block(); CHECK_AND_ASSERT_MES(diffic, false, "difficulty owverhead."); - median_size = m_current_block_cumul_sz_limit; + median_size = m_current_block_cumul_sz_limit / 2; already_generated_coins = m_blocks.back().already_generated_coins; CRITICAL_REGION_END(); @@ -1603,4 +1603,4 @@ bool blockchain_storage::add_new_block(const block& bl_, block_verification_cont } return handle_block_to_main_chain(bl, id, bvc); -} \ No newline at end of file +} diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 6cd33a2d..24e5752a 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -348,60 +348,27 @@ namespace cryptonote return ss.str(); } //--------------------------------------------------------------------------------- - bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee) { - typedef transactions_container::value_type txv; + bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee) + { CRITICAL_REGION_LOCAL(m_transactions_lock); - std::vector txs(m_transactions.size()); - std::transform(m_transactions.begin(), m_transactions.end(), txs.begin(), [](txv &a) -> txv * { return &a; }); - std::sort(txs.begin(), txs.end(), [](txv *a, txv *b) -> bool { - uint64_t a_hi, a_lo = mul128(a->second.fee, b->second.blob_size, &a_hi); - uint64_t b_hi, b_lo = mul128(b->second.fee, a->second.blob_size, &b_hi); - return a_hi > b_hi || (a_hi == b_hi && a_lo > b_lo); - }); - - size_t current_size = 0; - uint64_t current_fee = 0; - uint64_t best_money; - if (!get_block_reward(median_size, CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, best_money)) { - LOG_ERROR("Block with just a miner transaction is already too large!"); - return false; - } - size_t best_position = 0; total_size = 0; fee = 0; + size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; std::unordered_set k_images; - - for (size_t i = 0; i < txs.size(); i++) { - txv &tx(*txs[i]); - - if(!is_transaction_ready_to_go(tx.second) || have_key_images(k_images, tx.second.tx)) { - txs[i] = NULL; + BOOST_FOREACH(transactions_container::value_type& tx, m_transactions) + { + if (max_total_size < total_size + tx.second.blob_size) continue; - } + + if (!is_transaction_ready_to_go(tx.second) || have_key_images(k_images, tx.second.tx)) + continue; + + bl.tx_hashes.push_back(tx.first); + total_size += tx.second.blob_size; + fee += tx.second.fee; append_key_images(k_images, tx.second.tx); - - current_size += tx.second.blob_size; - current_fee += tx.second.fee; - - uint64_t current_reward; - if (!get_block_reward(median_size, current_size + CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, current_reward)) { - break; - } - - if (best_money < current_reward + current_fee) { - best_money = current_reward + current_fee; - best_position = i + 1; - total_size = current_size; - fee = current_fee; - } - } - - for (size_t i = 0; i < best_position; i++) { - if (txs[i]) { - bl.tx_hashes.push_back(txs[i]->first); - } } return true; From 1e147966663a94437eda6290ec129b931a9d404b Mon Sep 17 00:00:00 2001 From: Otto Fourschaft Date: Fri, 25 Apr 2014 22:33:24 +0400 Subject: [PATCH 04/75] OSX compilation fixed --- .gitignore | 3 ++- CMakeLists.txt | 14 ++++++++++++-- .../keyvalue_serialization_overloads.h | 4 ++-- contrib/epee/include/storages/portable_storage.h | 4 ++-- src/crypto/oaes_lib.c | 1 + src/cryptonote_core/cryptonote_format_utils.h | 2 +- src/p2p/net_node.inl | 4 +++- src/p2p/p2p_protocol_defs.h | 4 ++-- src/rpc/core_rpc_server.cpp | 3 +-- src/simplewallet/simplewallet.cpp | 2 +- tests/core_tests/chaingen.cpp | 1 + tests/gtest/include/gtest/internal/gtest-port.h | 2 ++ tests/net_load_tests/net_load_tests.h | 14 +++++++------- tests/performance_tests/performance_utils.h | 8 ++++++-- 14 files changed, 43 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 2a68f647..20a3894a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +.DS_Store /build -/tags \ No newline at end of file +/tags diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b293cc7..8510b369 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,12 +3,22 @@ cmake_minimum_required(VERSION 2.8.6) set(VERSION "0.1") # $Format:Packaged from commit %H%nset(COMMIT %h)%nset(REFS "%d")$ +function(set_static_flags) +if (NOT APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") +endif() +endfunction(set_static_flags) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_CONFIGURATION_TYPES "Debug;Release") enable_testing() include_directories(src contrib/epee/include external "${CMAKE_BINARY_DIR}/version") +if(APPLE) +include_directories(SYSTEM /usr/include/malloc) +endif() + set(STATIC ${MSVC} CACHE BOOL "Link libraries statically") if(MSVC) @@ -65,7 +75,7 @@ else() set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") if(STATIC) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") + set_static_flags() endif() endif() @@ -81,7 +91,7 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) if(MINGW) set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock") elseif(NOT MSVC) - set(Boost_LIBRARIES "${Boost_LIBRARIES};rt") + set(Boost_LIBRARIES "${Boost_LIBRARIES}") endif() set(COMMIT_ID_IN_VERSION ON CACHE BOOL "Include commit ID in version") diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index 54535a40..33486d9e 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -281,7 +281,7 @@ namespace epee } }; template - struct base_serializable_types: public boost::mpl::vector::type + struct base_serializable_types: public boost::mpl::vector::type {}; //------------------------------------------------------------------------------------------------------------------- template struct selector; @@ -365,4 +365,4 @@ namespace epee return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); } } -} \ No newline at end of file +} diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h index c244dac1..eb8ee2d1 100644 --- a/contrib/epee/include/storages/portable_storage.h +++ b/contrib/epee/include/storages/portable_storage.h @@ -210,7 +210,7 @@ namespace epee template bool portable_storage::get_value(const std::string& value_name, t_value& val, hsection hparent_section) { - BOOST_MPL_ASSERT(( boost::mpl::contains )); + //BOOST_MPL_ASSERT(( boost::mpl::contains )); //TRY_ENTRY(); if(!hparent_section) hparent_section = &m_root; storage_entry* pentry = find_storage_entry(value_name, hparent_section); @@ -476,4 +476,4 @@ namespace epee } //--------------------------------------------------------------------------------------------------------------- } -} \ No newline at end of file +} diff --git a/src/crypto/oaes_lib.c b/src/crypto/oaes_lib.c index d77c52f1..126f0a2f 100644 --- a/src/crypto/oaes_lib.c +++ b/src/crypto/oaes_lib.c @@ -37,6 +37,7 @@ static const char _NR[] = { #include #include #include +#include #ifdef WIN32 #include diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 554e466c..075202d6 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -25,7 +25,7 @@ namespace cryptonote typedef std::pair output_entry; std::vector outputs; //index + key - uint64_t real_output; //index in outputs vector of real output_entry + size_t real_output; //index in outputs vector of real output_entry crypto::public_key real_out_tx_key; //incoming real tx public key size_t real_output_in_tx_index; //index in transaction outputs vector uint64_t amount; //money diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 4c43f9db..e7b1afe6 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -753,7 +753,9 @@ namespace nodetool template bool node_server::get_local_node_data(basic_node_data& node_data) { - time(&node_data.local_time); + time_t local_time; + time(&local_time); + node_data.local_time = local_time; node_data.peer_id = m_config.m_peer_id; if(!m_hide_my_port) node_data.my_port = m_external_port ? m_external_port : m_listenning_port; diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index 9994dca4..fdf784f4 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -86,7 +86,7 @@ namespace nodetool struct basic_node_data { uuid network_id; - time_t local_time; + uint64_t local_time; uint32_t my_port; peerid_type peer_id; @@ -153,7 +153,7 @@ namespace nodetool struct response { - time_t local_time; + uint64_t local_time; t_playload_type payload_data; std::list local_peerlist; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index bab373c8..a2ea1d91 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - #include #include "include_base_utils.h" using namespace epee; @@ -536,7 +535,7 @@ namespace cryptonote if (!have_block) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; - error_resp.message = "Internal error: can't get block by height. Height = " + req.height + '.'; + error_resp.message = "Internal error: can't get block by height. Height = " + std::to_string(req.height) + '.'; return false; } bool responce_filled = fill_block_header_responce(blk, false, req.height, block_hash, res.block_header); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index a4cae048..a9c171f6 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -469,7 +469,7 @@ bool simple_wallet::refresh(const std::vector& args) return true; message_writer() << "Starting refresh..."; - uint64_t fetched_blocks = 0; + size_t fetched_blocks = 0; bool ok = false; std::ostringstream ss; try diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index f0032351..2742abaf 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -425,6 +425,7 @@ bool fill_tx_sources(std::vector& sources, const std::vector Date: Tue, 29 Apr 2014 17:26:45 +0100 Subject: [PATCH 05/75] extra for transfers --- CMakeLists.txt | 22 ++- README | 4 +- ReleaseNotes.txt | 7 + contrib/epee/include/net/http_client.h | 2 +- .../epee/include/storages/portable_storage.h | 4 +- src/common/boost_serialization_helper.h | 48 +++++- ...unordered_containers_boost_serialization.h | 37 +++- src/common/util.h | 2 +- src/cryptonote_core/blockchain_storage.cpp | 63 ++++++- src/cryptonote_core/checkpoints_create.h | 2 + .../cryptonote_format_utils.cpp | 130 ++++++++------ src/cryptonote_core/cryptonote_format_utils.h | 23 ++- src/cryptonote_core/difficulty.cpp | 2 +- src/cryptonote_core/tx_extra.h | 87 +++++++++- src/cryptonote_core/tx_pool.h | 3 + src/miner/simpleminer.cpp | 1 + src/rpc/core_rpc_server.cpp | 3 +- src/serialization/serialization.h | 2 +- src/simplewallet/simplewallet.cpp | 163 ++++++++++++++++-- src/simplewallet/simplewallet.h | 3 + src/version.h.in | 4 +- src/wallet/wallet2.cpp | 111 +++++++++--- src/wallet/wallet2.h | 52 ++++-- src/wallet/wallet_errors.h | 23 --- src/wallet/wallet_rpc_server.cpp | 49 +++++- src/wallet/wallet_rpc_server.h | 10 +- src/wallet/wallet_rpc_server_commans_defs.h | 35 ++++ src/wallet/wallet_rpc_server_error_codes.h | 3 +- tests/core_tests/block_validation.cpp | 4 +- tests/core_tests/chaingen.cpp | 8 +- tests/core_tests/double_spend.inl | 4 +- tests/core_tests/integer_overflow.cpp | 8 +- tests/core_tests/transaction_tests.cpp | 6 +- .../transactions_flow_test.cpp | 4 +- .../gtest/include/gtest/internal/gtest-port.h | 2 - .../performance_tests/check_ring_signature.h | 2 +- tests/performance_tests/construct_tx.h | 2 +- tests/unit_tests/test_format_utils.cpp | 132 +++++++++++--- 38 files changed, 840 insertions(+), 227 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8510b369..9e3bb336 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,20 +3,19 @@ cmake_minimum_required(VERSION 2.8.6) set(VERSION "0.1") # $Format:Packaged from commit %H%nset(COMMIT %h)%nset(REFS "%d")$ -function(set_static_flags) -if (NOT APPLE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") -endif() -endfunction(set_static_flags) - set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_CONFIGURATION_TYPES "Debug;Release") enable_testing() -include_directories(src contrib/epee/include external "${CMAKE_BINARY_DIR}/version") +function(set_static_flags) + if (NOT APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") + endif() +endfunction(set_static_flags) +include_directories(src contrib/epee/include external "${CMAKE_BINARY_DIR}/version") if(APPLE) -include_directories(SYSTEM /usr/include/malloc) + include_directories(SYSTEM /usr/include/malloc) endif() set(STATIC ${MSVC} CACHE BOOL "Link libraries statically") @@ -61,6 +60,9 @@ else() endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}") + if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_TR1_TUPLE=0") + endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)) set(DEBUG_FLAGS "-g3 -Og") else() @@ -90,8 +92,10 @@ endif() include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) if(MINGW) set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock") -elseif(NOT MSVC) +elseif(APPLE) set(Boost_LIBRARIES "${Boost_LIBRARIES}") +elseif(NOT MSVC) + set(Boost_LIBRARIES "${Boost_LIBRARIES};rt") endif() set(COMMIT_ID_IN_VERSION ON CACHE BOOL "Include commit ID in version") diff --git a/README b/README index 6d9478f2..87a89c58 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ --= Building CyberNote =- +-= Building CryptoNote =- On *nix: @@ -29,4 +29,4 @@ cd build cmake -G "Visual Studio 11 Win64" .. And then do Build. -Good luck! +Good luck! \ No newline at end of file diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 0ce55002..ff2a2131 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -1,3 +1,10 @@ +Release notes 0.8.6 + +- Simplwallet can set extra for transfers +- Improvements in JSON RPC for wallet +- UX improvements in simplewallet +- Win32 compilation + Release notes 0.8.5 - Port mapping for daemon using UPnP diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index 5897a017..7e6b52d9 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -856,7 +856,7 @@ using namespace std; http::url_content u_c; bool res = parse_url(url, u_c); - if(!tr.is_connected() && !u_c.host.empty()) + if(!tr.is_connected()) { CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h index eb8ee2d1..c244dac1 100644 --- a/contrib/epee/include/storages/portable_storage.h +++ b/contrib/epee/include/storages/portable_storage.h @@ -210,7 +210,7 @@ namespace epee template bool portable_storage::get_value(const std::string& value_name, t_value& val, hsection hparent_section) { - //BOOST_MPL_ASSERT(( boost::mpl::contains )); + BOOST_MPL_ASSERT(( boost::mpl::contains )); //TRY_ENTRY(); if(!hparent_section) hparent_section = &m_root; storage_entry* pentry = find_storage_entry(value_name, hparent_section); @@ -476,4 +476,4 @@ namespace epee } //--------------------------------------------------------------------------------------------------------------- } -} +} \ No newline at end of file diff --git a/src/common/boost_serialization_helper.h b/src/common/boost_serialization_helper.h index 74016ae7..0bf92480 100644 --- a/src/common/boost_serialization_helper.h +++ b/src/common/boost_serialization_helper.h @@ -14,15 +14,55 @@ namespace tools bool serialize_obj_to_file(t_object& obj, const std::string& file_path) { TRY_ENTRY(); - std::ofstream data_file; - data_file.open( file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc); - if(data_file.fail()) +#if defined(_MSC_VER) + // Need to know HANDLE of file to call FlushFileBuffers + HANDLE data_file_handle = ::CreateFile(file_path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == data_file_handle) return false; + int data_file_descriptor = _open_osfhandle((intptr_t)data_file_handle, 0); + if (-1 == data_file_descriptor) + { + ::CloseHandle(data_file_handle); + return false; + } + + FILE* data_file_file = _fdopen(data_file_descriptor, "wb"); + if (0 == data_file_file) + { + // Call CloseHandle is not necessary + _close(data_file_descriptor); + return false; + } + + // HACK: undocumented constructor, this code may not compile + std::ofstream data_file(data_file_file); + if (data_file.fail()) + { + // Call CloseHandle and _close are not necessary + fclose(data_file_file); + return false; + } +#else + std::ofstream data_file; + data_file.open(file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc); + if (data_file.fail()) + return false; +#endif + boost::archive::binary_oarchive a(data_file); a << obj; + if (data_file.fail()) + return false; - return !data_file.fail(); + data_file.flush(); +#if defined(_MSC_VER) + // To make sure the file is fully stored on disk + ::FlushFileBuffers(data_file_handle); + fclose(data_file_file); +#endif + + return true; CATCH_ENTRY_L0("serialize_obj_to_file", false); } diff --git a/src/common/unordered_containers_boost_serialization.h b/src/common/unordered_containers_boost_serialization.h index a29896ee..84fa73b9 100644 --- a/src/common/unordered_containers_boost_serialization.h +++ b/src/common/unordered_containers_boost_serialization.h @@ -2,7 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#pragma once +#pragma once #include #include @@ -41,6 +41,35 @@ namespace boost } + template + inline void save(Archive &a, const std::unordered_multimap &x, const boost::serialization::version_type ver) + { + size_t s = x.size(); + a << s; + BOOST_FOREACH(auto& v, x) + { + a << v.first; + a << v.second; + } + } + + template + inline void load(Archive &a, std::unordered_multimap &x, const boost::serialization::version_type ver) + { + x.clear(); + size_t s = 0; + a >> s; + for(size_t i = 0; i != s; i++) + { + h_key k; + hval v; + a >> k; + a >> v; + x.emplace(k, v); + } + } + + template inline void save(Archive &a, const std::unordered_set &x, const boost::serialization::version_type ver) { @@ -73,6 +102,12 @@ namespace boost split_free(a, x, ver); } + template + inline void serialize(Archive &a, std::unordered_multimap &x, const boost::serialization::version_type ver) + { + split_free(a, x, ver); + } + template inline void serialize(Archive &a, std::unordered_set &x, const boost::serialization::version_type ver) { diff --git a/src/common/util.h b/src/common/util.h index af92adf9..8a1f4b04 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -52,7 +52,7 @@ namespace tools private: #if defined(WIN32) - static BOOL win_handler(DWORD type) + static BOOL WINAPI win_handler(DWORD type) { if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type) { diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index c1b9619f..0e20b454 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -582,6 +582,42 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) { return false; } +#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) + size_t real_txs_size = 0; + uint64_t real_fee = 0; + CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock); + BOOST_FOREACH(crypto::hash &cur_hash, b.tx_hashes) { + auto cur_res = m_tx_pool.m_transactions.find(cur_hash); + if (cur_res == m_tx_pool.m_transactions.end()) { + LOG_ERROR("Creating block template: error: transaction not found"); + continue; + } + tx_memory_pool::tx_details &cur_tx = cur_res->second; + real_txs_size += cur_tx.blob_size; + real_fee += cur_tx.fee; + if (cur_tx.blob_size != get_object_blobsize(cur_tx.tx)) { + LOG_ERROR("Creating block template: error: invalid transaction size"); + } + uint64_t inputs_amount; + if (!get_inputs_money_amount(cur_tx.tx, inputs_amount)) { + LOG_ERROR("Creating block template: error: cannot get inputs amount"); + } else if (cur_tx.fee != inputs_amount - get_outs_money_amount(cur_tx.tx)) { + LOG_ERROR("Creating block template: error: invalid fee"); + } + } + if (txs_size != real_txs_size) { + LOG_ERROR("Creating block template: error: wrongly calculated transaction size"); + } + if (fee != real_fee) { + LOG_ERROR("Creating block template: error: wrongly calculated fee"); + } + CRITICAL_REGION_END(); + LOG_PRINT_L1("Creating block template: height " << height << + ", median size " << median_size << + ", already generated coins " << already_generated_coins << + ", transaction size " << txs_size << + ", fee " << fee); +#endif /* two-phase miner transaction generation: we don't know exact block size until we prepare block, but we don't know reward until we know @@ -590,27 +626,32 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); -#ifdef _DEBUG - std::list try_val; - try_val.push_back(get_object_blobsize(b.miner_tx)); -#endif - size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx); +#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) + LOG_PRINT_L1("Creating block template: miner tx size " << get_object_blobsize(b.miner_tx) << + ", cumulative size " << cumulative_size); +#endif for (size_t try_count = 0; try_count != 10; ++try_count) { r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11); -#ifdef _DEBUG - try_val.push_back(get_object_blobsize(b.miner_tx)); -#endif CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance"); size_t coinbase_blob_size = get_object_blobsize(b.miner_tx); if (coinbase_blob_size > cumulative_size - txs_size) { cumulative_size = txs_size + coinbase_blob_size; +#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) + LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << + ", cumulative size " << cumulative_size << " is greater then before"); +#endif continue; } if (coinbase_blob_size < cumulative_size - txs_size) { size_t delta = cumulative_size - txs_size - coinbase_blob_size; +#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) + LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << + ", cumulative size " << txs_size + coinbase_blob_size << + " is less then before, adding " << delta << " zero bytes"); +#endif b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0); //here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len. if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) { @@ -626,6 +667,10 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad } } CHECK_AND_ASSERT_MES(cumulative_size == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx)); +#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) + LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << + ", cumulative size " << cumulative_size << " is now good"); +#endif return true; } LOG_ERROR("Failed to create_block_template with " << 10 << " tries"); @@ -1603,4 +1648,4 @@ bool blockchain_storage::add_new_block(const block& bl_, block_verification_cont } return handle_block_to_main_chain(bl, id, bvc); -} +} \ No newline at end of file diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h index 6046a011..207cd236 100644 --- a/src/cryptonote_core/checkpoints_create.h +++ b/src/cryptonote_core/checkpoints_create.h @@ -22,6 +22,8 @@ namespace cryptonote { ADD_CHECKPOINT(417000, "2dc96f8fc4d4a4d76b3ed06722829a7ab09d310584b8ecedc9b578b2c458a69f"); ADD_CHECKPOINT(427193, "00feabb08f2d5759ed04fd6b799a7513187478696bba2db2af10d4347134e311"); ADD_CHECKPOINT(453537, "d17de6916c5aa6ffcae575309c80b0f8fdcd0a84b5fa8e41a841897d4b5a4e97"); + ADD_CHECKPOINT(462250, "13468d210a5ec884cf839f0259f247ccf3efef0414ac45172033d32c739beb3e"); + ADD_CHECKPOINT(468000, "251bcbd398b1f593193a7210934a3d87f692b2cb0c45206150f59683dd7e9ba1"); return true; } diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index b160ab8d..aa2c82b2 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -61,8 +61,8 @@ namespace cryptonote keypair txkey = keypair::generate(); add_tx_pub_key_to_extra(tx, txkey.pub); - if(extra_nonce.size()) - if(!add_tx_extra_nonce(tx, extra_nonce)) + if(!extra_nonce.empty()) + if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) return false; txin_gen in; @@ -74,6 +74,10 @@ namespace cryptonote LOG_PRINT_L0("Block is too big"); return false; } +#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) + LOG_PRINT_L1("Creating block template: reward " << block_reward << + ", fee " << fee) +#endif block_reward += fee; std::vector out_amounts; @@ -204,51 +208,50 @@ namespace cryptonote return r; } //--------------------------------------------------------------- - crypto::public_key get_tx_pub_key_from_extra(const transaction& tx) + bool parse_tx_extra(const std::vector& tx_extra, std::vector& tx_extra_fields) { - crypto::public_key pk = null_pkey; - parse_and_validate_tx_extra(tx, pk); - return pk; + tx_extra_fields.clear(); + + if(tx_extra.empty()) + return true; + + std::string extra_str(reinterpret_cast(tx_extra.data()), tx_extra.size()); + std::istringstream iss(extra_str); + binary_archive ar(iss); + + bool eof = false; + while (!eof) + { + tx_extra_field field; + bool r = ::do_serialize(ar, field); + CHECK_AND_NO_ASSERT_MES(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); + tx_extra_fields.push_back(field); + + std::ios_base::iostate state = iss.rdstate(); + eof = (EOF == iss.peek()); + iss.clear(state); + } + CHECK_AND_NO_ASSERT_MES(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); + + return true; } //--------------------------------------------------------------- - bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key) + crypto::public_key get_tx_pub_key_from_extra(const std::vector& tx_extra) { - tx_pub_key = null_pkey; - bool padding_started = false; //let the padding goes only at the end - bool tx_extra_tag_pubkey_found = false; - bool tx_extra_extra_nonce_found = false; - for(size_t i = 0; i != tx.extra.size();) - { - if(padding_started) - { - CHECK_AND_ASSERT_MES(!tx.extra[i], false, "Failed to parse transaction extra (not 0 after padding) in tx " << get_transaction_hash(tx)); - } - else if(tx.extra[i] == TX_EXTRA_TAG_PUBKEY) - { - CHECK_AND_ASSERT_MES(sizeof(crypto::public_key) <= tx.extra.size()-1-i, false, "Failed to parse transaction extra (TX_EXTRA_TAG_PUBKEY have not enough bytes) in tx " << get_transaction_hash(tx)); - CHECK_AND_ASSERT_MES(!tx_extra_tag_pubkey_found, false, "Failed to parse transaction extra (duplicate TX_EXTRA_TAG_PUBKEY entry) in tx " << get_transaction_hash(tx)); - tx_pub_key = *reinterpret_cast(&tx.extra[i+1]); - i += 1 + sizeof(crypto::public_key); - tx_extra_tag_pubkey_found = true; - continue; - }else if(tx.extra[i] == TX_EXTRA_NONCE) - { - //CHECK_AND_ASSERT_MES(is_coinbase(tx), false, "Failed to parse transaction extra (TX_EXTRA_NONCE can be only in coinbase) in tx " << get_transaction_hash(tx)); - CHECK_AND_ASSERT_MES(!tx_extra_extra_nonce_found, false, "Failed to parse transaction extra (duplicate TX_EXTRA_NONCE entry) in tx " << get_transaction_hash(tx)); - CHECK_AND_ASSERT_MES(tx.extra.size()-1-i >= 1, false, "Failed to parse transaction extra (TX_EXTRA_NONCE have not enough bytes) in tx " << get_transaction_hash(tx)); - ++i; - CHECK_AND_ASSERT_MES(tx.extra.size()-1-i >= tx.extra[i], false, "Failed to parse transaction extra (TX_EXTRA_NONCE have wrong bytes counter) in tx " << get_transaction_hash(tx)); - tx_extra_extra_nonce_found = true; - i += tx.extra[i];//actually don't need to extract it now, just skip - } - else if(!tx.extra[i]) - { - padding_started = true; - continue; - } - ++i; - } - return true; + std::vector tx_extra_fields; + if (!parse_tx_extra(tx_extra, tx_extra_fields)) + return null_pkey; + + tx_extra_pub_key pub_key_field; + if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field)) + return null_pkey; + + return pub_key_field.pub_key; + } + //--------------------------------------------------------------- + crypto::public_key get_tx_pub_key_from_extra(const transaction& tx) + { + return get_tx_pub_key_from_extra(tx.extra); } //--------------------------------------------------------------- bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key) @@ -259,32 +262,50 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool add_tx_extra_nonce(transaction& tx, const blobdata& extra_nonce) + bool add_extra_nonce_to_tx_extra(std::vector& tx_extra, const blobdata& extra_nonce) { - CHECK_AND_ASSERT_MES(extra_nonce.size() <=255, false, "extra nonce could be 255 bytes max"); - size_t start_pos = tx.extra.size(); - tx.extra.resize(tx.extra.size() + 2 + extra_nonce.size()); + CHECK_AND_ASSERT_MES(extra_nonce.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max"); + size_t start_pos = tx_extra.size(); + tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size()); //write tag - tx.extra[start_pos] = TX_EXTRA_NONCE; + tx_extra[start_pos] = TX_EXTRA_NONCE; //write len ++start_pos; - tx.extra[start_pos] = static_cast(extra_nonce.size()); + tx_extra[start_pos] = static_cast(extra_nonce.size()); //write data ++start_pos; - memcpy(&tx.extra[start_pos], extra_nonce.data(), extra_nonce.size()); + memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size()); return true; } //--------------------------------------------------------------- - bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, transaction& tx, uint64_t unlock_time) + void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id) + { + extra_nonce.clear(); + extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID); + const uint8_t* payment_id_ptr = reinterpret_cast(&payment_id); + std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce)); + } + //--------------------------------------------------------------- + bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id) + { + if(sizeof(crypto::hash) + 1 != extra_nonce.size()) + return false; + if(TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0]) + return false; + payment_id = *reinterpret_cast(extra_nonce.data() + 1); + return true; + } + //--------------------------------------------------------------- + bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time) { tx.vin.clear(); tx.vout.clear(); tx.signatures.clear(); - tx.extra.clear(); tx.version = CURRENT_TRANSACTION_VERSION; tx.unlock_time = unlock_time; + tx.extra = extra; keypair txkey = keypair::generate(); add_tx_pub_key_to_extra(tx, txkey.pub); @@ -506,7 +527,10 @@ namespace cryptonote //--------------------------------------------------------------- bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered) { - return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, money_transfered); + crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); + if(null_pkey == tx_pub_key) + return false; + return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered); } //--------------------------------------------------------------- bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered) diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 075202d6..138fb522 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -25,7 +25,7 @@ namespace cryptonote typedef std::pair output_entry; std::vector outputs; //index + key - size_t real_output; //index in outputs vector of real output_entry + size_t real_output; //index in outputs vector of real output_entry crypto::public_key real_out_tx_key; //incoming real tx public key size_t real_output_in_tx_index; //index in transaction outputs vector uint64_t amount; //money @@ -41,11 +41,26 @@ namespace cryptonote }; //--------------------------------------------------------------- - bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, transaction& tx, uint64_t unlock_time); - bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key); + bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time); + + template + bool find_tx_extra_field_by_type(const std::vector& tx_extra_fields, T& field) + { + auto it = std::find_if(tx_extra_fields.begin(), tx_extra_fields.end(), [](const tx_extra_field& f) { return typeid(T) == f.type(); }); + if(tx_extra_fields.end() == it) + return false; + + field = boost::get(*it); + return true; + } + + bool parse_tx_extra(const std::vector& tx_extra, std::vector& tx_extra_fields); + crypto::public_key get_tx_pub_key_from_extra(const std::vector& tx_extra); crypto::public_key get_tx_pub_key_from_extra(const transaction& tx); bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key); - bool add_tx_extra_nonce(transaction& tx, const blobdata& extra_nonce); + bool add_extra_nonce_to_tx_extra(std::vector& tx_extra, const blobdata& extra_nonce); + void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id); + bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered); diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp index 052f4666..3dde6ad6 100644 --- a/src/cryptonote_core/difficulty.cpp +++ b/src/cryptonote_core/difficulty.cpp @@ -24,7 +24,7 @@ namespace cryptonote { #include static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) { - low = UnsignedMultiply128(a, b, &high); + low = mul128(a, b, &high); } #else diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h index 7e27cbc7..8cff085d 100644 --- a/src/cryptonote_core/tx_extra.h +++ b/src/cryptonote_core/tx_extra.h @@ -2,10 +2,93 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#pragma once +#pragma once +#define TX_EXTRA_PADDING_MAX_COUNT 255 +#define TX_EXTRA_NONCE_MAX_COUNT 255 -#define TX_EXTRA_PADDING_MAX_COUNT 40 +#define TX_EXTRA_TAG_PADDING 0x00 #define TX_EXTRA_TAG_PUBKEY 0x01 #define TX_EXTRA_NONCE 0x02 + +#define TX_EXTRA_NONCE_PAYMENT_ID 0x00 + +namespace cryptonote +{ + struct tx_extra_padding + { + size_t size; + + // load + template