From 5770265a166e4a319e53e26a2e42f41b0e13a9b0 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Fri, 1 Oct 2021 12:42:48 +0200 Subject: [PATCH 001/186] wallet2: keep around transaction prefix for confirmed transfers --- src/wallet/wallet2.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index facf9878dc1..4167165fe2e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -453,6 +453,7 @@ namespace tools struct confirmed_transfer_details { + cryptonote::transaction_prefix m_tx; uint64_t m_amount_in; uint64_t m_amount_out; uint64_t m_change; @@ -467,10 +468,12 @@ namespace tools confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(crypto::null_hash), m_timestamp(0), m_unlock_time(0), m_subaddr_account((uint32_t)-1) {} confirmed_transfer_details(const unconfirmed_transfer_details &utd, uint64_t height): - m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp), m_unlock_time(utd.m_tx.unlock_time), m_subaddr_account(utd.m_subaddr_account), m_subaddr_indices(utd.m_subaddr_indices), m_rings(utd.m_rings) {} + m_tx(utd.m_tx), m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp), m_unlock_time(utd.m_tx.unlock_time), m_subaddr_account(utd.m_subaddr_account), m_subaddr_indices(utd.m_subaddr_indices), m_rings(utd.m_rings) {} BEGIN_SERIALIZE_OBJECT() - VERSION_FIELD(0) + VERSION_FIELD(1) + if (version >= 1) + FIELD(m_tx) VARINT_FIELD(m_amount_in) VARINT_FIELD(m_amount_out) VARINT_FIELD(m_change) From af08c83e2569a4ad81184373dfb87ddbbf106f45 Mon Sep 17 00:00:00 2001 From: selsta Date: Sat, 7 May 2022 21:49:02 +0200 Subject: [PATCH 002/186] utils: delete outdated windows build script --- utils/build_scripts/windows.bat | 45 --------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 utils/build_scripts/windows.bat diff --git a/utils/build_scripts/windows.bat b/utils/build_scripts/windows.bat deleted file mode 100644 index 77ffd1c96f1..00000000000 --- a/utils/build_scripts/windows.bat +++ /dev/null @@ -1,45 +0,0 @@ -:: Copyright (c) 2014-2022, The Monero Project -:: -:: All rights reserved. -:: -:: Redistribution and use in source and binary forms, with or without modification, are -:: permitted provided that the following conditions are met: -:: -:: 1. Redistributions of source code must retain the above copyright notice, this list of -:: conditions and the following disclaimer. -:: -:: 2. Redistributions in binary form must reproduce the above copyright notice, this list -:: of conditions and the following disclaimer in the documentation and/or other -:: materials provided with the distribution. -:: -:: 3. Neither the name of the copyright holder nor the names of its contributors may be -:: used to endorse or promote products derived from this software without specific -:: prior written permission. -:: -:: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -:: EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -:: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -:: THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -:: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -:: PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -:: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -:: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -:: THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -:: Set the following variables according to your environment -set BuildProcessorArchitecture=64 -set LocationDependencyBoostRoot=D:\Development\boost_1_55_0 -set LocationEnvironmentVariableSetterMsbuild=C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat - -call "%LocationEnvironmentVariableSetterMsbuild%" -set LocationDependencyBoostLibrary=%LocationDependencyBoostRoot%\lib%BuildProcessorArchitecture%-msvc-%VisualStudioVersion% - -cd ..\.. -set LocationBuildSource=%CD% -mkdir build\win%BuildProcessorArchitecture% -cd build\win%BuildProcessorArchitecture% - -cmake -G "Visual Studio %VisualStudioVersion:.0=% Win%BuildProcessorArchitecture%" -DBOOST_ROOT="%LocationDependencyBoostRoot%" -DBOOST_LIBRARYDIR="%LocationDependencyBoostLibrary%" "%LocationBuildSource%" -msbuild Project.sln /p:Configuration=Release - -pause From bae4a1ad8f35af12fa1c4a45302c19c14c99c0b4 Mon Sep 17 00:00:00 2001 From: j-berman Date: Wed, 11 May 2022 18:41:24 -0700 Subject: [PATCH 003/186] Don't send peerlist larger than max allowed --- src/p2p/net_node.inl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index a3bc3bf24de..cabd82de84d 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -2462,8 +2462,12 @@ namespace nodetool const epee::net_utils::zone zone_type = context.m_remote_address.get_zone(); network_zone& zone = m_network_zones.at(zone_type); + //will add self to peerlist if in same zone as outgoing later in this function + const bool outgoing_to_same_zone = !context.m_is_income && zone.m_our_address.get_zone() == zone_type; + const uint32_t max_peerlist_size = P2P_DEFAULT_PEERS_IN_HANDSHAKE - (outgoing_to_same_zone ? 1 : 0); + std::vector local_peerlist_new; - zone.m_peerlist.get_peerlist_head(local_peerlist_new, true, P2P_DEFAULT_PEERS_IN_HANDSHAKE); + zone.m_peerlist.get_peerlist_head(local_peerlist_new, true, max_peerlist_size); //only include out peers we did not already send rsp.local_peerlist_new.reserve(local_peerlist_new.size()); @@ -2483,7 +2487,7 @@ namespace nodetool etc., because someone could give faulty addresses over Tor/I2P to get the real peer with that identity banned/blacklisted. */ - if(!context.m_is_income && zone.m_our_address.get_zone() == zone_type) + if(outgoing_to_same_zone) rsp.local_peerlist_new.push_back(peerlist_entry{zone.m_our_address, zone.m_config.m_peer_id, std::time(nullptr)}); LOG_DEBUG_CC(context, "COMMAND_TIMED_SYNC"); From b9d2c788bc51364ccd8728345aeef64f5cbd3a15 Mon Sep 17 00:00:00 2001 From: j-berman Date: Thu, 12 May 2022 08:39:51 -0700 Subject: [PATCH 004/186] fix backoff delay logic when re-relaying txs --- src/cryptonote_core/tx_pool.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index c27261860e3..a68da0e62ca 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -97,9 +97,9 @@ namespace cryptonote constexpr const std::chrono::seconds forward_delay_average{CRYPTONOTE_FORWARD_DELAY_AVERAGE}; // a kind of increasing backoff within min/max bounds - uint64_t get_relay_delay(time_t now, time_t received) + uint64_t get_relay_delay(time_t last_relay, time_t received) { - time_t d = (now - received + MIN_RELAY_TIME) / MIN_RELAY_TIME * MIN_RELAY_TIME; + time_t d = (last_relay - received + MIN_RELAY_TIME) / MIN_RELAY_TIME * MIN_RELAY_TIME; if (d > MAX_RELAY_TIME) d = MAX_RELAY_TIME; return d; @@ -779,7 +779,7 @@ namespace cryptonote case relay_method::local: case relay_method::fluff: case relay_method::block: - if (now - meta.last_relayed_time <= get_relay_delay(now, meta.receive_time)) + if (now - meta.last_relayed_time <= get_relay_delay(meta.last_relayed_time, meta.receive_time)) return true; // continue to next tx break; } @@ -812,7 +812,7 @@ namespace cryptonote function is only called every ~2 minutes, so this resetting should be unnecessary, but is primarily a precaution against potential changes to the callback routines. */ - elem.second.last_relayed_time = now + get_relay_delay(now, elem.second.receive_time); + elem.second.last_relayed_time = now + get_relay_delay(elem.second.last_relayed_time, elem.second.receive_time); m_blockchain.update_txpool_tx(elem.first, elem.second); } From 62914e7e3d75884473bfd84f93afd4ffa034916b Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Thu, 12 May 2022 10:38:29 -0500 Subject: [PATCH 005/186] Ignore gitian build files --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index a39168ac563..9f62575e5ab 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,12 @@ external/miniupnpc/Makefile miniupnpcstrings.h version/ ClangBuildAnalyzerSession.txt + +# gitian +contrib/gitian/builder/ +contrib/gitian/docker/ +contrib/gitian/sigs/ + # Created by https://www.gitignore.io ### C++ ### From fde7c96b5cd44962fe08cdb8d23115ed51b30915 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 15 May 2022 11:50:28 +0000 Subject: [PATCH 006/186] wallet2: fix spurious reorg detection with untrusted nodes When forced to deal with an untrusted node, a wallet will quantize its current height to disguise the real height to the adversary, to try and minimize the daemon's ability to distinguish returning wallets. Daemons will thus return more blocks than the wallet needs, starting from earlier in the chain. These extra blocks will be disregarded by the wallet, which had already scanned them. However, for the purposes of reorg size detection, the wallet assumes all blocks the daemon sends are different, which is only correct if the wallet hasn't been coy, which is only the case for trusted daemons (which you should use). This causes an issue when the size of this "fake reorg" is above the sanity check threshold at which the wallet refuses a reorg. To fix this, the reorg size check is moved later on, when the reorg is about to actually happen, after the wallet has checked which blocks are actually different from the ones it expects. --- src/wallet/wallet2.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f4a5a585539..6885db953bf 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2882,6 +2882,11 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector m_max_reorg_depth, error::reorg_depth_error, + tr("reorg exceeds maximum allowed depth, use 'set max-reorg-depth N' to allow it, reorg depth: ") + + std::to_string(reorg_depth)); + detach_blockchain(current_index, output_tracker_cache); process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache); } @@ -3532,15 +3537,6 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo first = false; - if (!next_blocks.empty()) - { - const uint64_t expected_start_height = std::max(static_cast(m_blockchain.size()), uint64_t(1)) - 1; - const uint64_t reorg_depth = expected_start_height - std::min(expected_start_height, next_blocks_start_height); - THROW_WALLET_EXCEPTION_IF(reorg_depth > m_max_reorg_depth, error::reorg_depth_error, - tr("reorg exceeds maximum allowed depth, use 'set max-reorg-depth N' to allow it, reorg depth: ") + - std::to_string(reorg_depth)); - } - // if we've got at least 10 blocks to refresh, assume we're starting // a long refresh, and setup a tracking output cache if we need to if (m_track_uses && (!output_tracker_cache || output_tracker_cache->empty()) && next_blocks.size() >= 10) From 1164874afc29212155de615531266c91cfdb7e4e Mon Sep 17 00:00:00 2001 From: selsta Date: Tue, 17 May 2022 00:33:10 +0200 Subject: [PATCH 007/186] src, epee: fix a couple compiler warnings --- contrib/epee/include/storages/portable_storage_from_json.h | 1 - src/cryptonote_basic/account.h | 2 -- src/simplewallet/simplewallet.cpp | 2 -- 3 files changed, 5 deletions(-) diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h index 3021598f5f9..69192ca6bd7 100644 --- a/contrib/epee/include/storages/portable_storage_from_json.h +++ b/contrib/epee/include/storages/portable_storage_from_json.h @@ -51,7 +51,6 @@ namespace epee { CHECK_AND_ASSERT_THROW_MES(recursion < EPEE_JSON_RECURSION_LIMIT_INTERNAL, "Wrong JSON data: recursion limitation (" << EPEE_JSON_RECURSION_LIMIT_INTERNAL << ") exceeded"); - std::string::const_iterator sub_element_start; std::string name; typename t_storage::harray h_array = nullptr; enum match_state diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h index 6e887db6d5e..2ee9545d4c1 100644 --- a/src/cryptonote_basic/account.h +++ b/src/cryptonote_basic/account.h @@ -55,8 +55,6 @@ namespace cryptonote KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv) END_KV_SERIALIZE_MAP() - account_keys& operator=(account_keys const&) = default; - void encrypt(const crypto::chacha_key &key); void decrypt(const crypto::chacha_key &key); void encrypt_viewkey(const crypto::chacha_key &key); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index d3e40ab747a..a013036f108 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6560,7 +6560,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector dsts_info; vector dsts; - size_t num_subaddresses = 0; for (size_t i = 0; i < local_args.size(); ) { dsts_info.emplace_back(); @@ -6619,7 +6618,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector Date: Mon, 16 May 2022 19:13:02 -0500 Subject: [PATCH 008/186] GCC: Fix -Wstringop-overflow= warnings Resolves #8320 --- external/boost/archive/portable_binary_archive.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/external/boost/archive/portable_binary_archive.hpp b/external/boost/archive/portable_binary_archive.hpp index 7ae01a225fa..cdbd38aad5d 100644 --- a/external/boost/archive/portable_binary_archive.hpp +++ b/external/boost/archive/portable_binary_archive.hpp @@ -44,9 +44,12 @@ reverse_bytes(signed char size, char *address){ char * first = address; char * last = first + size - 1; for(;first < last;++first, --last){ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow=" char x = *last; *last = *first; *first = x; +#pragma GCC diagnostic pop } } From 29794742211b7fbd35b1c7b0b707cb495001b3e8 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 14 May 2022 19:49:48 +0000 Subject: [PATCH 009/186] disable multisig by default There are vulnerabilities in multisig protocol if the parties do not trust each other, and while there is a patch for it, it has not been throroughly reviewed yet, so it is felt safer to disable multisig by default for now. If all parties in a multisig setup trust each other, then it is safe to enable multisig. --- src/simplewallet/simplewallet.cpp | 55 ++++++++++++++++++++ src/simplewallet/simplewallet.h | 1 + src/wallet/wallet2.cpp | 9 +++- src/wallet/wallet2.h | 3 ++ src/wallet/wallet_rpc_server.cpp | 33 ++++++++++++ src/wallet/wallet_rpc_server_commands_defs.h | 3 ++ src/wallet/wallet_rpc_server_error_codes.h | 1 + tests/functional_tests/multisig.py | 10 ++-- utils/python-rpc/framework/wallet.py | 3 +- 9 files changed, 111 insertions(+), 7 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index d3e40ab747a..05d10b7345a 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -142,6 +142,19 @@ typedef cryptonote::simple_wallet sw; #define MIN_PAYMENT_RATE 0.01f // per hash #define MAX_MNEW_ADDRESSES 1000 +#define CHECK_MULTISIG_ENABLED() \ + do \ + { \ + if (!m_wallet->is_multisig_enabled()) \ + { \ + fail_msg_writer() << tr("Multisig is disabled."); \ + fail_msg_writer() << tr("Multisig is an experimental feature and may have bugs. Things that could go wrong include: funds sent to a multisig wallet can't be spent at all, can only be spent with the participation of a malicious group member, or can be stolen by a malicious group member."); \ + fail_msg_writer() << tr("You can enable it with:"); \ + fail_msg_writer() << tr(" set enable-multisig-experimental 1"); \ + return false; \ + } \ + } while(0) + enum TransferType { Transfer, TransferLocked, @@ -986,12 +999,14 @@ bool simple_wallet::print_fee_info(const std::vector &args/* = std: bool simple_wallet::prepare_multisig(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); prepare_multisig_main(args, false); return true; } bool simple_wallet::prepare_multisig_main(const std::vector &args, bool called_by_mms) { + CHECK_MULTISIG_ENABLED(); if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); @@ -1031,12 +1046,14 @@ bool simple_wallet::prepare_multisig_main(const std::vector &args, bool simple_wallet::make_multisig(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); make_multisig_main(args, false); return true; } bool simple_wallet::make_multisig_main(const std::vector &args, bool called_by_mms) { + CHECK_MULTISIG_ENABLED(); if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); @@ -1121,11 +1138,13 @@ bool simple_wallet::make_multisig_main(const std::vector &args, boo bool simple_wallet::exchange_multisig_keys(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); exchange_multisig_keys_main(args, false); return true; } bool simple_wallet::exchange_multisig_keys_main(const std::vector &args, bool called_by_mms) { + CHECK_MULTISIG_ENABLED(); bool ready; if (m_wallet->key_on_device()) { @@ -1189,12 +1208,14 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector & bool simple_wallet::export_multisig(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); export_multisig_main(args, false); return true; } bool simple_wallet::export_multisig_main(const std::vector &args, bool called_by_mms) { + CHECK_MULTISIG_ENABLED(); bool ready; if (m_wallet->key_on_device()) { @@ -1254,12 +1275,14 @@ bool simple_wallet::export_multisig_main(const std::vector &args, b bool simple_wallet::import_multisig(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); import_multisig_main(args, false); return true; } bool simple_wallet::import_multisig_main(const std::vector &args, bool called_by_mms) { + CHECK_MULTISIG_ENABLED(); bool ready; uint32_t threshold, total; if (m_wallet->key_on_device()) @@ -1349,12 +1372,14 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::multisig_tx_set &txs) bool simple_wallet::sign_multisig(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); sign_multisig_main(args, false); return true; } bool simple_wallet::sign_multisig_main(const std::vector &args, bool called_by_mms) { + CHECK_MULTISIG_ENABLED(); bool ready; if (m_wallet->key_on_device()) { @@ -1464,12 +1489,14 @@ bool simple_wallet::sign_multisig_main(const std::vector &args, boo bool simple_wallet::submit_multisig(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); submit_multisig_main(args, false); return true; } bool simple_wallet::submit_multisig_main(const std::vector &args, bool called_by_mms) { + CHECK_MULTISIG_ENABLED(); bool ready; uint32_t threshold; if (m_wallet->key_on_device()) @@ -1551,6 +1578,7 @@ bool simple_wallet::submit_multisig_main(const std::vector &args, b bool simple_wallet::export_raw_multisig(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); bool ready; uint32_t threshold; if (m_wallet->key_on_device()) @@ -3074,6 +3102,25 @@ bool simple_wallet::set_load_deprecated_formats(const std::vector & return true; } +bool simple_wallet::set_enable_multisig(const std::vector &args/* = std::vector()*/) +{ + if (args.size() < 2) + { + fail_msg_writer() << tr("Value not specified"); + return true; + } + + const auto pwd_container = get_and_verify_password(); + if (pwd_container) + { + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->enable_multisig(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); + } + return true; +} + bool simple_wallet::help(const std::vector &args/* = std::vector()*/) { if(args.empty()) @@ -3391,6 +3438,8 @@ simple_wallet::simple_wallet() " The RPC payment credits balance to target (0 for default).\n " "show-wallet-name-when-locked <1|0>\n " " Set this if you would like to display the wallet name when locked.\n " + "enable-multisig-experimental <1|0>\n " + " Set this to allow multisig commands. Multisig may currently be exploitable if parties do not trust each other.\n " "inactivity-lock-timeout \n " " How many seconds to wait before locking the wallet (0 to disable).")); m_cmd_binder.set_handler("encrypted_seed", @@ -3806,6 +3855,7 @@ bool simple_wallet::set_variable(const std::vector &args) success_msg_writer() << "auto-mine-for-rpc-payment-threshold = " << m_wallet->auto_mine_for_rpc_payment_threshold(); success_msg_writer() << "credits-target = " << m_wallet->credits_target(); success_msg_writer() << "load-deprecated-formats = " << m_wallet->load_deprecated_formats(); + success_msg_writer() << "enable-multisig-experimental = " << m_wallet->is_multisig_enabled(); return true; } else @@ -3872,6 +3922,7 @@ bool simple_wallet::set_variable(const std::vector &args) CHECK_SIMPLE_VARIABLE("persistent-rpc-client-id", set_persistent_rpc_client_id, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("auto-mine-for-rpc-payment-threshold", set_auto_mine_for_rpc_payment_threshold, tr("floating point >= 0")); CHECK_SIMPLE_VARIABLE("credits-target", set_credits_target, tr("unsigned integer")); + CHECK_SIMPLE_VARIABLE("enable-multisig-experimental", set_enable_multisig, tr("0 or 1")); } fail_msg_writer() << tr("set: unrecognized argument(s)"); return true; @@ -6980,6 +7031,7 @@ bool simple_wallet::sweep_unmixable(const std::vector &args_) // actually commit the transactions if (m_wallet->multisig()) { + CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); if (!r) { @@ -7284,6 +7336,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co // actually commit the transactions if (m_wallet->multisig()) { + CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); if (!r) { @@ -7518,6 +7571,7 @@ bool simple_wallet::sweep_single(const std::vector &args_) // actually commit the transactions if (m_wallet->multisig()) { + CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); if (!r) { @@ -11549,6 +11603,7 @@ void simple_wallet::mms_auto_config(const std::vector &args) bool simple_wallet::mms(const std::vector &args) { + CHECK_MULTISIG_ENABLED(); try { m_wallet->get_multisig_wallet_state(); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 4c005c53a0c..6c4ddd4e75b 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -153,6 +153,7 @@ namespace cryptonote bool set_device_name(const std::vector &args = std::vector()); bool set_export_format(const std::vector &args = std::vector()); bool set_load_deprecated_formats(const std::vector &args = std::vector()); + bool set_enable_multisig(const std::vector &args = std::vector()); bool set_persistent_rpc_client_id(const std::vector &args = std::vector()); bool set_auto_mine_for_rpc_payment_threshold(const std::vector &args = std::vector()); bool set_credits_target(const std::vector &args = std::vector()); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f4a5a585539..5076286c406 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1216,7 +1216,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std m_rpc_version(0), m_export_format(ExportFormat::Binary), m_load_deprecated_formats(false), - m_credits_target(0) + m_credits_target(0), + m_enable_multisig(false) { set_rpc_client_secret_key(rct::rct2sk(rct::skGen())); } @@ -4051,6 +4052,9 @@ boost::optional wallet2::get_keys_file_data(const epee: value2.SetUint64(m_credits_target); json.AddMember("credits_target", value2, json.GetAllocator()); + value2.SetInt(m_enable_multisig ? 1 : 0); + json.AddMember("enable_multisig", value2, json.GetAllocator()); + // Serialize the JSON object rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -4199,6 +4203,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st m_persistent_rpc_client_id = false; m_auto_mine_for_rpc_payment_threshold = -1.0f; m_credits_target = 0; + m_enable_multisig = false; } else if(json.IsObject()) { @@ -4431,6 +4436,8 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st m_auto_mine_for_rpc_payment_threshold = field_auto_mine_for_rpc_payment; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, credits_target, uint64_t, Uint64, false, 0); m_credits_target = field_credits_target; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, enable_multisig, int, Int, false, false); + m_enable_multisig = field_enable_multisig; } else { diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 660e6a14baf..8a9a2e519a1 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1297,6 +1297,8 @@ namespace tools void set_rpc_client_secret_key(const crypto::secret_key &key) { m_rpc_client_secret_key = key; m_node_rpc_proxy.set_client_secret_key(key); } uint64_t credits_target() const { return m_credits_target; } void credits_target(uint64_t threshold) { m_credits_target = threshold; } + bool is_multisig_enabled() const { return m_enable_multisig; } + void enable_multisig(bool enable) { m_enable_multisig = enable; } bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector &additional_tx_keys) const; void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress = boost::none); @@ -1811,6 +1813,7 @@ namespace tools crypto::secret_key m_rpc_client_secret_key; rpc_payment_state_t m_rpc_payment_state; uint64_t m_credits_target; + bool m_enable_multisig; // Aux transaction data from device serializable_unordered_map m_tx_device; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 57baf428fac..7ec5fc7a1fd 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -61,6 +61,17 @@ using namespace epee; #define DEFAULT_AUTO_REFRESH_PERIOD 20 // seconds +#define CHECK_MULTISIG_ENABLED() \ + do \ + { \ + if (m_wallet->multisig() && !m_wallet->is_multisig_enabled()) \ + { \ + er.code = WALLET_RPC_ERROR_CODE_DISABLED; \ + er.message = "This wallet is multisig, and multisig is disabled. Multisig is an experimental feature and may have bugs. Things that could go wrong include: funds sent to a multisig wallet can't be spent at all, can only be spent with the participation of a malicious group member, or can be stolen by a malicious group member. You can enable it by running this once in monero-wallet-cli: set enable-multisig-experimental 1"; \ + return false; \ + } \ + } while(0) + namespace { const command_line::arg_descriptor arg_rpc_bind_port = {"rpc-bind-port", "Sets bind port for server"}; @@ -1057,6 +1068,8 @@ namespace tools return false; } + CHECK_MULTISIG_ENABLED(); + // validate the transfer requested and populate dsts & extra if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er)) { @@ -1109,6 +1122,8 @@ namespace tools return false; } + CHECK_MULTISIG_ENABLED(); + // validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types. if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er)) { @@ -1163,6 +1178,8 @@ namespace tools return false; } + CHECK_MULTISIG_ENABLED(); + cryptonote::blobdata blob; if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob)) { @@ -1511,6 +1528,8 @@ namespace tools return false; } + CHECK_MULTISIG_ENABLED(); + try { std::vector ptx_vector = m_wallet->create_unmixable_sweep_transactions(); @@ -1539,6 +1558,8 @@ namespace tools return false; } + CHECK_MULTISIG_ENABLED(); + // validate the transfer requested and populate dsts & extra std::list destination; destination.push_back(wallet_rpc::transfer_destination()); @@ -1604,6 +1625,8 @@ namespace tools return false; } + CHECK_MULTISIG_ENABLED(); + // validate the transfer requested and populate dsts & extra std::list destination; destination.push_back(wallet_rpc::transfer_destination()); @@ -3933,6 +3956,9 @@ namespace tools er.message = "This wallet is already multisig"; return false; } + if (req.enable_multisig_experimental) + m_wallet->enable_multisig(true); + CHECK_MULTISIG_ENABLED(); if (m_wallet->watch_only()) { er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY; @@ -3959,6 +3985,7 @@ namespace tools er.message = "This wallet is already multisig"; return false; } + CHECK_MULTISIG_ENABLED(); if (m_wallet->watch_only()) { er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY; @@ -4003,6 +4030,7 @@ namespace tools er.message = "This wallet is multisig, but not yet finalized"; return false; } + CHECK_MULTISIG_ENABLED(); cryptonote::blobdata info; try @@ -4044,6 +4072,7 @@ namespace tools er.message = "This wallet is multisig, but not yet finalized"; return false; } + CHECK_MULTISIG_ENABLED(); if (req.info.size() < threshold - 1) { @@ -4096,6 +4125,7 @@ namespace tools //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_finalize_multisig(const wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx) { + CHECK_MULTISIG_ENABLED(); return false; } //------------------------------------------------------------------------------------------------------------------------------ @@ -4123,6 +4153,7 @@ namespace tools er.message = "This wallet is multisig, and already finalized"; return false; } + CHECK_MULTISIG_ENABLED(); if (req.multisig_info.size() + 1 < total) { @@ -4172,6 +4203,7 @@ namespace tools er.message = "This wallet is multisig, but not yet finalized"; return false; } + CHECK_MULTISIG_ENABLED(); cryptonote::blobdata blob; if (!epee::string_tools::parse_hexstr_to_binbuff(req.tx_data_hex, blob)) @@ -4241,6 +4273,7 @@ namespace tools er.message = "This wallet is multisig, but not yet finalized"; return false; } + CHECK_MULTISIG_ENABLED(); cryptonote::blobdata blob; if (!epee::string_tools::parse_hexstr_to_binbuff(req.tx_data_hex, blob)) diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index fe53e293f5c..ecfc8e673a7 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -2416,7 +2416,10 @@ namespace wallet_rpc { struct request_t { + bool enable_multisig_experimental; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_OPT(enable_multisig_experimental, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init request; diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h index 91493957364..73422938024 100644 --- a/src/wallet/wallet_rpc_server_error_codes.h +++ b/src/wallet/wallet_rpc_server_error_codes.h @@ -78,3 +78,4 @@ #define WALLET_RPC_ERROR_CODE_ATTRIBUTE_NOT_FOUND -45 #define WALLET_RPC_ERROR_CODE_ZERO_AMOUNT -46 #define WALLET_RPC_ERROR_CODE_INVALID_SIGNATURE_TYPE -47 +#define WALLET_RPC_ERROR_CODE_DISABLED -48 diff --git a/tests/functional_tests/multisig.py b/tests/functional_tests/multisig.py index 89cb2fdc7c3..1c5894f4712 100755 --- a/tests/functional_tests/multisig.py +++ b/tests/functional_tests/multisig.py @@ -107,7 +107,7 @@ def create_multisig_wallets(self, M_threshold, N_total, expected_address): try: self.wallet[i].close_wallet() except: pass res = self.wallet[i].restore_deterministic_wallet(seed = seeds[i]) - res = self.wallet[i].prepare_multisig() + res = self.wallet[i].prepare_multisig(enable_multisig_experimental = True) assert len(res.multisig_info) > 0 info.append(res.multisig_info) @@ -172,7 +172,7 @@ def test_states(self): res = wallet2of2[i].restore_deterministic_wallet(seed = seeds[i]) res = wallet2of2[i].is_multisig() assert not res.multisig - res = wallet2of2[i].prepare_multisig() + res = wallet2of2[i].prepare_multisig(enable_multisig_experimental = True) assert len(res.multisig_info) > 0 info2of2.append(res.multisig_info) @@ -187,7 +187,7 @@ def test_states(self): assert res.ready ok = False - try: res = wallet2of2[0].prepare_multisig() + try: res = wallet2of2[0].prepare_multisig(enable_multisig_experimental = True) except: ok = True assert ok @@ -205,7 +205,7 @@ def test_states(self): res = wallet2of3[i].restore_deterministic_wallet(seed = seeds[i]) res = wallet2of3[i].is_multisig() assert not res.multisig - res = wallet2of3[i].prepare_multisig() + res = wallet2of3[i].prepare_multisig(enable_multisig_experimental = True) assert len(res.multisig_info) > 0 info2of3.append(res.multisig_info) @@ -223,7 +223,7 @@ def test_states(self): assert not res.ready ok = False - try: res = wallet2of3[1].prepare_multisig() + try: res = wallet2of3[1].prepare_multisig(enable_multisig_experimental = True) except: ok = True assert ok diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py index 037beee84fa..01e9376274a 100644 --- a/utils/python-rpc/framework/wallet.py +++ b/utils/python-rpc/framework/wallet.py @@ -490,10 +490,11 @@ def is_multisig(self): } return self.rpc.send_json_rpc_request(is_multisig) - def prepare_multisig(self): + def prepare_multisig(self, enable_multisig_experimental = False): prepare_multisig = { 'method': 'prepare_multisig', 'params' : { + 'enable_multisig_experimental': enable_multisig_experimental, }, 'jsonrpc': '2.0', 'id': '0' From a66a52d14497c3295274e54fb9e0d2d0980004bb Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Tue, 17 May 2022 22:40:36 +0200 Subject: [PATCH 010/186] common: update sha256sum to use OpenSSL 3.0 API As of OpenSSL 3.0, `SHA256_Init`, `SHA256_Update`, and `SHA256_Final` are deprectaed in favor of the higher-level `EVP_*` class of functions. This causes compiler warnings, and sooner or later, will cause build errors as these functions are excluded from distro headers. Also add some documentation. --- src/common/util.cpp | 19 ++++++------------- src/common/util.h | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/common/util.cpp b/src/common/util.cpp index 89dcf4feffa..f0de73a0668 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -85,7 +85,7 @@ using namespace epee; #include #include #include -#include +#include #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "util" @@ -941,14 +941,7 @@ std::string get_nix_version_display_string() bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash) { - SHA256_CTX ctx; - if (!SHA256_Init(&ctx)) - return false; - if (!SHA256_Update(&ctx, data, len)) - return false; - if (!SHA256_Final((unsigned char*)hash.data, &ctx)) - return false; - return true; + return EVP_Digest(data, len, (unsigned char*) hash.data, NULL, EVP_sha256(), NULL) != 0; } bool sha256sum(const std::string &filename, crypto::hash &hash) @@ -961,8 +954,8 @@ std::string get_nix_version_display_string() if (!f) return false; std::ifstream::pos_type file_size = f.tellg(); - SHA256_CTX ctx; - if (!SHA256_Init(&ctx)) + std::unique_ptr ctx(EVP_MD_CTX_new(), &EVP_MD_CTX_free); + if (!EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr)) return false; size_t size_left = file_size; f.seekg(0, std::ios::beg); @@ -973,12 +966,12 @@ std::string get_nix_version_display_string() f.read(buf, read_size); if (!f || !f.good()) return false; - if (!SHA256_Update(&ctx, buf, read_size)) + if (!EVP_DigestUpdate(ctx.get(), buf, read_size)) return false; size_left -= read_size; } f.close(); - if (!SHA256_Final((unsigned char*)hash.data, &ctx)) + if (!EVP_DigestFinal_ex(ctx.get(), (unsigned char*)hash.data, nullptr)) return false; return true; } diff --git a/src/common/util.h b/src/common/util.h index 25f5ceb479a..f489594e890 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -231,7 +231,27 @@ namespace tools bool is_privacy_preserving_network(const std::string &address); int vercmp(const char *v0, const char *v1); // returns < 0, 0, > 0, similar to strcmp, but more human friendly than lexical - does not attempt to validate + /** + * \brief Creates a SHA-256 digest of a data buffer + * + * \param[in] data pointer to the buffer + * \param[in] len size of the buffer in bytes + * \param[out] hash where message digest will be written to + * + * \returns true if successful, false otherwise + */ bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash); + + /** + * \brief Creates a SHA-256 digest of a file's contents, equivalent to the sha256sum command in Linux + * + * \param[in] filename path to target file + * \param[out] hash where message digest will be written to + * + * \returns true if successful, false if the file can not be opened or there is an OpenSSL failure + * + * \throws ios_base::failure if after the file is successfully opened, an error occurs during reading + */ bool sha256sum(const std::string &filename, crypto::hash &hash); boost::optional is_hdd(const char *path); From 08080df2d9de877ae79028f20960b6b2417d4f20 Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Tue, 17 May 2022 22:41:22 +0200 Subject: [PATCH 011/186] unit_tests: add more sha256sum test cases --- tests/CMakeLists.txt | 1 + tests/data/sha256sum/CLSAG.pdf | Bin 0 -> 374754 bytes tests/data/sha256sum/empty.txt | 0 tests/data/sha256sum/small_file.txt | 19 +++++++++++++++++++ tests/unit_tests/sha256.cpp | 22 ++++++++++++++++++++++ 5 files changed, 42 insertions(+) create mode 100644 tests/data/sha256sum/CLSAG.pdf create mode 100644 tests/data/sha256sum/empty.txt create mode 100644 tests/data/sha256sum/small_file.txt diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5a3c4956083..2cabb1ba5bc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -78,6 +78,7 @@ file(COPY data/outputs data/unsigned_monero_tx data/signed_monero_tx + data/sha256sum DESTINATION data) if (CMAKE_BUILD_TYPE STREQUAL "fuzz" OR OSSFUZZ) diff --git a/tests/data/sha256sum/CLSAG.pdf b/tests/data/sha256sum/CLSAG.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6d7bb79aedee3fbef5feffa9627bc79923e55f02 GIT binary patch literal 374754 zcmeFXW0Y*)vn5)#U8j^~oU)Bmwr$(CZQD9!+qP}nRi~^zzx%)U^}XHqy^lTKht4r_ z>|85%#?CcY>>05mCaIi|2n_=*3k+$`bHNu3D+_=gU~6Cj!_5t#lQOq4)^{-XFg5}( z{2c+9*qGT^m;rQR08Ib`Gcyx_nTZ*o4WN?+uyO$CgaHf;tjzy>F9Tp?0?;Y_b3Q!> z3xJmw#@NQ_AESW(V=ow1*8j8+C3ibx0G*nGvB}?M7~7aSnE^Qdu1Lh(%E{Q_@6k%% z$ymtP(AMbhS^ql9={s0E0{#I((ALV?+Qt#U0-%#~Fg7wbbh32-FfjgI6@X6lA0Pls zf8T#m5VtWhcKbW=7eWR`#(&M2*aBFY{{9gK0G)!ZtrLKi?Oy}Mzn}sb*xCNgrpv#8 zV*Ovip%WJZXmT?fvN5ykvoUcP85__uGBPr;vN9VnGcwUL8!($N(;M(|bFeb9GBE3# zFwrxza2Oe~>l@P3Gnz27voRTR80s4s@M{0F1&&S*#`@MUZdrx~MtZxZdIoxW?9fE& zrGaZ?fCO{YG;Ii?HZni4x?;e*6-}7Z3`o2@tUyr#W}K1IIwVFL5Yf?fpjeeLoK)1e zb#(7BJ$+2VfdAnpV;Wm@ys4Dcn*LF|T`dlM-C-`c8vz4cP=_ zZ+>uF5c8QRaEEBZLnGL~>N}(irJ`iF3AZ@nN00J8E+ z%e$Pb#ME|UAZFl$$GFGMRE4^JQ_a9p-+J^V3}6drYq}WZf9Jiw;qZS(Q9)Z9Cu18Y zM*tiBzxG-BZxqr0W&2O8_-BTNgN2rnjTOMo%s|V|@lV|N8+`u$0Ko8X!T6uhVeDw@ z>|prUSJ)Z;W#V71@{j-gCqMZ&`~Trv|E-_=yMr+P4b1<=L$cK*6E|9syWdq$#gxOf z{K0gSCt}#{j`uG6T$B+S9DBu(g5d~Y#MW~@AI~r;@b;M8l`|r&3Xw6Mu_6NLSaJ=?0v(y2JULuLoXSu}a-Dznre8T4O+(R0N!81m!m8 z!)R&R-!xQc;NpwedSawMjYcDGFhXCcGbx#{dt!q# zEZo~8s<~oCvSTElP7eNK%sJ`kh%B5jxgPw{g%t0sGRV1Ff=g$&!T*RJE*!z9&-lI< z!Sq6PCH&y!TRZdsI+FWkuQPZmDhG0VrBGYFGEAY^1~XEfl9rXy>(-1KX=P9f}d^Mh&>ZUjJLR{5qeOeM4wzJXslqdsZJS-_94C)Aiw2PEIFy*`R?g z8MtH>WRsqlLbsYjDxT*+wopQiJ556cqXmiYbqsZ&6^?1fR%|4!EcP%x_Dp}x5I$Xd zNIP=8ZE7?p@~>uXoF^7H>n?YfCY)w_?9ThN3rtoGrl26;d^ePGZ>16xL3Yc|%fqP} z&tgrsSp$kQAT60q+zr%%u|^et%Y59TRk6SycT`iL1A5?sIsPyjJRs=#N`nEEP^;a$ z>P@F#{5sb|JprGA(j*dFnULXWs&`A=h`1Cb2LeyP3AQ%uGln2_vu*7|-rbjawF0)o z9(H^E#Nn%REX_lxeZ6OuP&%h^K$Q8aUND4UwsfmZD8jkxp-L?CIda|KV%wgq$V6j9ifZ|@Sx>N4vA_T1EZ=b z*=Ox}er84UU8_0y9>TEI?a#u7EEqUo$jy|GZ%8x;gN&=-?jiz&U*HW5OQIn5%&pGY zT?-;0gQJIN_{m3i&$a8l~}0?5BRdjO67!)%X*t44?wPJTTI8$Vw-FWZu^7S}xmg`~@507Eb& zR9+Trybf~%*Glsn9I}O<04x62F%DbpFT?k3r4&(l&m4&|(0PGV700*-dQD*X?a`G%fDm&Y-2o`4#VDga{)Ve&l4Oj>3^=UWnMKJas_{$ijTD zD-*My^ZL~^N`{|kb*KKMz36`6o`aszLT73f#pwX%xT=T zwC=E2vXGF5;kAP8ATjeFFPW`ESW3+`;Ml~?cD))YxE$)&ayqQp>_GP~HElRatf#ar zQQN3iGo*Lo$S*TYJ*4z0^LR(NN74*kdG#50bgip^34((`vJKIt+&bKWF5&W`H?ksE zEp~xN=-LXSQBnVf?Q@l*=fyQnG~SkI<*y|G{s3oA`kTt8G?k23?emy@B3{pnYE z1llJHQbADmXYMiM!D0U>sFPjO+--k1lP_jbDcbjG3o4n6G6LM1b{yRLS{?NFtN;9; zQMZ{0Io(oz1#d86+i#}!F(l+4CqNU29V|@}9Q{ zUZoc?!C_RmaQBpgl#KWV=d>Z9n{+2SWpGYZ(BLROqh%2l+KjpvHdKBq?iWYioxN0? z;pSvM@t;je`>TSN*0d-pXtT;g!wqN9iS`x~x*|qqTG$~WsG`>hB%p|(Kj9l>aa;Lg zq0JhPw@gtk7dfnvHy@8ze z9VyRrbCSKjHOk^ z5ZMu%e3uWoWH(>;M_azYMZZEE{`V}9?Vn`rKk~7EWo)tr7K%>R|4*jQ!py|_|5ApK z0kHk84v3gLI6D1J92x#gx^|_d>4-X(;IpGU7u&($-*KH9hDr_sI_x*)W_6AF0I2QF zh^G^~hr6uVnWU3cXewp}!I{q5ismmnKQFHwmprO6O0ZE%lq$@&POz3LB41hMm+ih= zW~OBBJ0Tk)`?*rIXl5;#=ulWCv$$er>y_wSSXjUiMEP^e=vOh6wM#TZ{F}F77OXTv zV^F?(9Ro)@S?TZ(4bqcgPFb;}f+2I%jJVZGC_L}1h>vmB>4FiK>HHD4X-LuN*;c(* zWh*VGM)Bkysg1=VB_a7&7E5kdPz}q`u^}er3olZCkcFk?qSQOcz@}=vP!kSR^TTx> zD#hRjq8A4*(-8;JWrNJmrNcS&!t7+#n)a&9B*Wlr2~pO5{N$9y3eycDMS&UkBsYmC znadw37by~ibVk!aMzURI_?Hfw3S}D!1$dxr=Q~Xb6C*xSmc<~vnSZ(u(DbJp9Ap0( zBctclARZayQYgZZxQk(Kf}_MJLu|tRnG`yIi@;q5Kjx=d#4ZHaL%K94;7CA;NOSph zK=5t0p8e3E9thDz6sC$9&y%K(^tS%_I2A3b91cs_gT~?ECe)EBE@!wudO$%vB`u>~ecd zZ+ zc+mM$?=C^DJEs|@ZT~<=&PipT81v-koj8p7*DQI?w2#<6Rc{89149oAxQVj-@@ZeXI2CJ5i_G zpl`0ny;Z})-?UU+*ycE5=UjRsp=NRuiS0n3^t;bXRKWIvjWac;I!$jyG^{VH(TW3 zSdhzgV~PTh3_$_Ca;(=5DNh@jr%w;4dadP|=S+U7;Ns9ReYYQLo04y-Z;fS73*~G5 z(r)k#A%+EO=9o~3jn{EUF%JNUOX5xN=94FQ1JV6ipUA;4h@z+rhy?u zdDiOH6kv*k2|2HybDqnx4TFMuMVAvQ73s|HkG%G;K$b6Cp)2jH7t$D0B^!hXU@FV%G(Qyi#~Z6XOAg#ynil1ZdaGtXNX zTwmZaM+8|a{KP#aTCx&qU9L9mw|Kvz6*&yd40Anx@#MWU_GR=BQ7khiyaPB!rNeN> zphf>ExSJTwv4`pa)glSE$Y6zAO|6eoB;^c{!hM#i6aT*3AM;P?;?27){AYJ599nuy z2TA9DTucgfj4(`Hs;#OgtLvyr7UOeZF}b6%__lZ_aYDvjxIfEa{umX?b5lmSq(sU6)q2W{pagX96k1O99!`mokEmaya2Y#4N=0Scs zZ*Zl#Vm)A`uR|G2vLncwk%>{|uZofEBcGvAQrk1{nhD`D?oO&BfL_WPkSiVky1?S& zfSjG!L`*B5D{0#$TVwS=m|U4ms7q&Q57F-C82EUM!HaY3L>0Y)lfI3Ei5`QN)2B)4 zdYnZH#J^CVL2Hy?s1frucM2lm{uAK358^m3JZyZRbz;VInHY_F5knahYm4^X;+rN@ znr;g&lC_I|s^1O1{E0CMJ;q^eX7}Q1Me$ z3l_iIRw2ax-Uog8Y5wA>?dg6uxiXMcI}A}9Mc0aHsVD3Y-AQ5#c0+B2Nlvc4KC$8~ z3xispMVg0H=`F_vN27I0>pG>X!z3BMMt7>>$=R-S!4GcPO@uV0un)RMrk=S64d1Wa z)7%A34ICu(zCMPNPpkWBd*0Mx%ckJ3l4@mdo?)>wFaDyoW|-vyb1n3KTg7Hl6SDr z$F3);w59f;60wqDwe*MwY!FP|(Mh^HTH{i_Q%IVUm{G~Nx}o+$hYq{`Ns?Jok0v9t z_lIfjv;#>gauG7g&Y%v4&m!k);9$!1?W;b5Bj06Zfau9ig*X8o-NF zrBhGj4d_`~KUs92e=-u6#6B~Y${@=sy#@Eot&?m9i`}eRKh;qtE({LMfO?9-Zze0# zZG;RCJ1&-Vf|O216HSvJMR9XRplQffIZbb9F9Z?FT930!;L?hN`4*`xaqvfccdVRZ zVA5zE;cL%+r|rP2Xqp|v;rx?PQ%y6gKmBvJ7i(@au!7%X*TZ89&(iLZkNDA@tM4^XWShMVtcX_PM9my? zw9=RcpQg$q$uUY9pi;>I=uUcS-+J^OzZ{|+w<+!gqTu-wZlX3l z{pFM-W_Yra`JOed`gTYV#mZDFzZLxn^7mV^Uz#sP*t~q4n82cz3ou18)SCP6b=9(a zA6n^nY4gmmN?%&(vnpfUxC+VG(Sk{>s1#&c#;a-2U#yRsd&!O981Uf+>qYcGB;6Go z`I1n63owikK9quD**P#%ffww+s23hN9>qjiK3I7adoyyE4g} zfJJ!1{Q7_>uu1HE=Otp4s#gui;u3KWHIulF{jyunIn|jxo%k%V-)1sHn7d3Kgmncx zF1%b|YRv2)kUpdA%OaK}Kyz$C0j0gYrerul7rgnudgVMMc+Ze#+&0aB`;8L?5HB(| z2;iHN%tMhX8o=Sl!?iStgeyQKi%Ay?PeSCsL4o#4VEy|cg3eKfs97j{P<2fHZe!| zt^&!$-FHMNu9q&=6qbi{K^xl}R&Hn)#l(e)yWeysD-)U@@sdXWdn8qO+dCb^LmMxz@#v&beVc|g>^8LtHBgd^KOZg z%*UtA>`%aVs$w9i#=4X0hSQnPkVLp#YJrg<_? z?kuc!?o9{pSTN9>h`-<7yUA?LQV?o#BL)-eh^k^P(b}sVH&E~0!YweP*h9}lY>kMt z@}NOs2z@Kj?(Bf3X8$?*bI+{!TtQIFR+%xic1@zbi>&py);%46#TnRVTC7y=d^~%9 zf-xc0IHk%%3Gb2C@aevKeY?d3)LBMuRj^eDz`nS0SZ1|X_Fro^z8Uq@-o z;317k=rxLtg(ah0Xrxi2&^rkvO7}tG@m<~L3@{qgD>A;ZWpnzpbJd8Kg3d$u;V zdA}Dw);I6++YDDDZfBlWeLl!;TtyBDgIA7By%+DC>^QYv4ZB1e`rQ6pU#~&_kct&; z*gJ#$2)B78cU#K6X{v$oJZqit6?;kkz}$viN&V27*e5j&F4Noi5#qfardNVxFs?zU#`&TcKE(RUuFK5zlKp(I6Eu3Q!)<_P)a1UaVx zc>!IdohnK-ly9fwJt*idZ-=anZldqJ0;a@SwC{G6L3|%+ki_z>P*^Iy&jH~ zUalCc`{EbKn{IQ>I@^_=mpxI)=@y4Mbmm#)nVFYQ$;O^lZ)G|hB-4Bxs=?gNU=be# zCMGDO(m~(ZhM@&q>4FP&CJC{R2Q-%t1Dh@;dEt}6q7O;8jLfwD8s99{0)wa4@gLoN zC^oLI<)nj|@5g@S#N#F9m>Zs+j_)8AoA34k*$B@GxX=dTOu9E^VZI8 ziOs(4%q~?r{;Zo~nu?8*t7mv=mT3s;riGu2SiZ>_@1mZbp0@nbr^RHi8zm-)(@<~s{^J`iS~SdofAq@;9*Xu3j`X7ZnsF9l zR*VpOe7&#j7`n3(QoK94bKzrmVi+vG0HAjy(&5OmqV)^L;|wkJTkP#>n>Ar1l=GDR zDwe-2T$NW{cW`lWYas}p-d;8B9kSyh)!R9QJ!ImQE6$R1^G~NLL_IrV(}{Kj<=UNV zwCe+e3kJbd)(*9baPU=|M!_%3!Bi{nzWOpTW!b&C;k^H>-w4`rsNj{a zCG?IFQoj?+&`T;07oVSR@N67ET(CUTPcPrM<_V*s&xE>R;G6F_nCqBe zu+E_%yYb^PEeUvI8iZC~NL;r96oQ`$X!WDyT| z58;3FV8N1lC6W5hoBRlZBFIKyBbt$8PJf+Q$1CMmcP-Oo(1>jz;N?I$e`^5CaJk^z zCcM!&TFrXmT1UOp+Bg8wmD-93)aBTkLB!|wc7)o07c_r{7kT&CclAWvSEZo;(i94{ zEUt#vEUV~T zEp~MJm{oSc!W zTjsvy{pVxq8rf05_|UmQYgdwcH3|cx>?pT+-xU>4qhEsMY7U^bs6(M^CJV z+!(O{r!i1nyHHJu`sA4m^U=BQ7<`f|A1cxJCQ)%^wi4=LF3@vEhadpB1)C;#)0qF7 zewQ~rF*O@?ylmN{BODg-gFV={f6+Nwzu50-;&UrI)z#PI*2}aA8oVF9 zA>GmgflA|z>Z0+JD@K9UaLmedfrUlC*x=8to$bxim+ZUf#%GWfQV-Zf&115Pet1QkES^TfPv$$s_Wl17L0!-UaTB{3$*|0sQ)AJ`VaL50~0&@KkBgmDY%M$ z1eep=SO$jy?b{+%JGhpyb8Xp$XYMPucMY(N1N3br>|TSpB3@trxQut4?&5fU|1N(n zuV{Zx<2+tBtS%u^ls83TXOz zy^37c$gf8(>B;rwD;yRmz<;8e2{!x6A~&~<05~xK)jI&HwSV{oVofa|@l%wQUUe{W=J1Z44im4a3I1vfN+^1()CX5ui-E{Ct-e+Y!dAn%%-Spmy| za`^XF1DJYm;(;ajHD~z>8Hg2tnW?F>zg+%W;OYSG1N2t(4bP()o&3qzH!y_&0oCaM zT{K1q8b<(h^aP@RA?Sg9II;t=nlyi>ypzAX5=wUTB>0z zOZcy?ZKWdvH8Q>9K{eXf`%Xc&gV0#}k<|eE%0q$_2`K~ju0VgM&y1m2o$X!@UK*J{ zc#5R#80*BU&reHjZZBgPom>XJWab8uVi~=8T;o%JcWPO3d9rcUd;=UMxtJby4Aa`! zYt7cxIoth=NWa3}SqQ)Cyn#4CTh-Ln-CJLQ0HQ#nTZ;iluAuOUkh8in%{#{{*j}Bu zmv}(OHHLm()KdaAd|^5={HjR3*q0#pcW*5RzQ{y4IK7kei`aS~Z+hmTFQso4*hXJ$ zKHlGYlCFOE7Zo3?K$Sgw-`>%xk>%|LB~k1He8k@?lw>A12)73N z`#|({j&;DRtL!g8+**}Dx!+ZVAdMfPkQcdH>RgVVKs!55x-(~dN!s6YKv#UQzaU?B zG$fvC#=(KjzM-^plOvb@JVsu9H*9`OyndJ7?1By5e2^c*dg1E~4HNFriAB zF2V4fII`_Hz7cMyYXmJ@CZ)&P>Ss;vATd2ZJ(S*}?LU8o@YcJS9pJ@M6)SWjQi z{M=@Ap|t@*f`jk?)OSmSXGg;B4n4KUm;j!8l;HIAn;Tqxq=7pTPC)5fAc?Gb=uNC1ZuRTz9W5daU$1x062c&f9PJ;2R{%Gy@Zcbd~a=U z2wvLBYGxm0Iah3Zx?o>)A9VzIKVZ9M-fJ8xYZ|M*!FAm?{*F;vK0()X!Z$wu`S?wD z=oRh#dGnI`p8VG1R@=qu@;30WboR%?^uxX2bRycx^~`SA<~RIJhiB!a z*=Tc5CA$aXZOeg)>`xQUb4UJh!eWCm^?lT5CSXBU~2la+Ot z3TLb-)zF(7nXEKh0g*fU2C@GhkYAQB+jUi)k-X#=Q>ItHF&4sMP*L&0?p`SHQW zgCPx%zpBjmMW=0zu3$lm1r09*U*1K4_lwOkQS<9c%5jtoK;K!<)vaIB)|R-16J@PL z+{0wbtvh5}bK=n#uy+A_yp|`1=ufe^9jI1f0X62q`WsKY*Q7J{GpL78kN2-K^NS>% zFX4kT4Vj1R7tS8QTkjesE@^(XA}A6akmBez0+M#jEn18g~QE~x1H)`_+~_8 zQxUq=3kV)!UxWbx+C0w{+oc2BQVgh4dwUMTqx|o?H{8lY{CYkPZnRSyA+ZG25jM(U zucDS@5@Z8$PgCWClPI0!Mv^14zl`9v`qAd7CWiUZP*6&((v5M~!`<=rCI=2uuN)>@ zHyx7~20_YxfJK0c9ya~z)AP~@a47C2VAoBEXA7X14?cIU;-GXiOrMjp1i2+GLX?N)Ow=dAF6riN+iD!Gbr0O#rs7_33a*zWv0%D7mfkm`m%-VV zYG}%FNS4xDG7}?=GVdo+A5ZQu>9-?i)enb=z6WH%c9u}|gz5prk8W;;0N-jD&t7Is z6jiull2B0gza& zBBu;r*kA5Ol=Mq7&;1Q6=yoY^w8>@c}UC96y z2OflF?DZ3V;*F3cxZI0@Ue)U?@AWpJxFM}JIskjPgs;D(cBg4@twjBLGuEVDz^{ii z8CUxe<}4)}t_CW0DC*Yc_vx?o>!Ch{)c_KuYO?u=f!0i@1HP>X^mZ5xF&C_}*(dkG zV5+U+{<-@un)M;3gADXh?YTYbVDsaCqDUUWWn|gVPbzUDS5(DimA@h_KI^>1!04SM zDFwy!uU0+59eN(A(eIq!DdJ(H`hF*5WdiwU`Nt!j*Qo^i-AjB{)i*U0#Ppd{ybVXO zw+&z)AYK5&!7u;S_CwU{z;e!UJBX2y{3CEPNrmXA{Bu??m2Zo*~-tCG4)ma-{M?F%Xl>y#-2QL^V^*zN2waR0MqF#bW>--`N=L)UW;Pd zt*X+)_LnDW+H}Q2mzpf=lNZWoQWY)>p!Z6_!qkmu~!BPj&Hk4cz)|4PLL^AET@KcX> zaU~kgwg}^rk|q$l?G6)M)|2%{q&LCu5{D}Pg20lLayf6x0e+%x-RcyYlL7}*rPB7E z51ms248p4Hk)IKFW(%Dt#7rK&V^veFj)G7XM4~KRT|aoTc~cgAM$w-N!iV)No@?gB z?`=**tC_%YA{4KW10PlZA6KpEteyFuz7E zFn^ky$+zUk7GokbYfl0#qu1ie{#%+*UE6L%A?CeLWe9>PrmBx*S8v?!;g#w;$KZX< zY)BEEb8dWqL@xG`Fo}TvNbyS7SNLF1I1bkiFXnQPvWV%~@=|CE{S=$uXNOfY zlD!Og=sEqJoo$R<>kh`f!$15~%-cnnsw2uE{>;NXO+>WY38?(E{1Y}`+uVn4QK0@# z>&PA4+0TYN`X~Il`?K!|#~>6Iv{^cO?GeND$|uk?yewd0L}-%>oJGQwX7`KB;8bTiF!m({5>FqZ>=yE0S8!gv_4gibr2y7zM2R0 zQS)wIe_WNftj-I<@tEKmZ=dRmN@h6QUo1D#;o*W0+cjbM*K2Wnlm~dt(TPRQD5h;6m3F1^6jv{XuW&pH{`8q{0eOR| zd42jkPTr^LM{3da`X*X3%YHdY)}cbE5_G18k28dOA0anbqeW%ol5U-<1@fRO6-SlK zFt=9TYm&EmK(YHb2V9LyhONY%jng;3SbLOHYKeS|Jl{yJ{q7CteQs{U7BR1=AbYTe1 z*SFo_Zi3^eLrH4fZg(E#8+@AtcL#Mh&YxhRm+3A`zdwjwmM;^+4+qb~gf3kGx~;Ww{J-fc0;UUlcI!9S;e<&bk1L?j0E zFTnVy!zFH?x>g|up|h%-=yDyVf^z(RgkOQr+j_OWElw2>GDf6a~zTg2_8hp9b1sxR6c$nw1$)`w1@Qf=!6kEIt?ecpJnV$GofHhiRU$(VNgpwWZS~1RN*d zwnR6_#;U%PmEQ>r+dLNyHByJx-E|a+EY>oDvLM9AuC-fcG<{69Hi%iVp_B;jRZY7K zns8tluWzk@+F@Ahy-LYR?JCtIgCd2%6JY>yTHh2TqS{0~ahk1CVl585!(7%8A$6>N zz0!6i;~~eLUfjj+44)lRpvVDV{Z?|(1H2WwBaJ;foJC7?Z>tNmmU$mcUYnBA`K!K# zt+>IYr#I5;@V=;o>wmV_KY)svPiyA8>7>(YBJ6s=yw~f_p z#K}Dj_UBchj5x?2k#6l4(VU6~mwXOqNm1W&i90C2I8HHm9sAR2eeymVsmr_gV%@Sn zR8#`gdn6e})*pUB=6h0oUWYqkZze=-nN`MrMKf$=&Mvn7SVCX&+d2_TlOzZ)&1Ye| z#_X0uS&Hj+t(%_pL`#Z8cvl%JB!*ayWhRZI`8%>KClhgsV=yQCYN-ywwvNvx!=bX*> zsniJ?a@&y`_+2c2zBNe1SBk6PAoHhm*)>KP4$1U4*nswF#_r&bHX~P0-vF*F`zwJ z1x5}y!6*1WwtH+}YM@ztC08Y6LZw%D0*s^fW9Xl~>i_H;3mB~kDa@It?Xi#y38v41^ zopT1G6I1YpWRZxG-q0P@5!YLl(&qI0pct$BVV@-=z zS5<2+My&4d_{!Q`;s$19yK4FC!IIbUU78|mdA5_kmMQ6E@ zuW;*_zfSsf8}XpScr-`+0uAqRKQt=gd6yLQd1OZ<<7$2^lx|ze)d{Bb)}av8La8q0 zz*Z);WC8MPUzvlHWkmp z#4|*PfBR4bfyy}Kc$8=0py8ej+ zM~JPc=gH!obF6`^W8A-5oO-PD1FLpB_KR1jh}Rijs>n}uN8lkc$uMlEl|M<8ds#KK z&y2iDI{KG~q*BGm8sL|~5L|Ip2%LV(l5ZeyuQB>@=}Gb!#`a3@Vogw}@$NI~NbpWF zQMbvGytWLImtSb>sc%J@pfv-^FdkdYX0zw3rL~4<(r4x#(U&$ZNqMQ$(j9TH0;Q)z z-IOMS&6)OK>6c&~Ny3N^Q+8sj#^ptt2%b1Wm@W1QAt4vQ zdeWq@iy8-K35EKaTut(Qf7cI;(*L}*1$QBrz)0yfrTa9Pk8`%ZDaIXy>;%jKOakY~<_XF4eE1wL_*)0?(Q`ZM(-7dT?XzPKM)qP> z$$VTsP>4qrK98sTr+Og0NSVNGK6Dmxrt5TRuf-m#ljc|%p6ZO8n^jA%pKC*~ggk|z zyy3wXI*Nyc`!j`wsnJpR(9kWmA!X77Th!zl9{_Kf5r+t&v!61!f+`JriP80Eh*cE2 z(Igr*6TXSke+%I#1hzMUJX(~+84djeW%$9FYBdJ=2%%i<4X5ibNhRr~>hNQlAw6yy z1J-(O?`KjjtsTYO45Q#QLA=t^d5(_;g)tvVxvx|CH>W3DZs!r9v%wnhL9$3NK@wg| z^W6b(y>lvh2op7JvnK051~CVp*a8*l^tu%yL+ZZp_M^Ewmc^+^+;#nn37;3?F%k1n zhT6(0@o!qUc#P|FmQZG^eR2&*h^nMO4A29C@36pOxVbeiXfZNrqx5~C#y=_?=*Z0 zj!KTp^~cqyM_i=A^-Vo7+4os<2*VM2!rCmJGRRzHS=|;*BWhdjKlX}uhGHyUt86yT z%n62!71%r?#DkR`{)-rzaI2SQlhsUNwG*EpB|DeX%?{M&nKhI8&|oi_mtL$f_k2-1 z+ckmK1HMVfTJqU%Ln*lwLOEJW3POVLbG4z=*`8wE3xS{=-U_|GEO*>8hLEb08&d4t zE^#;>$;vkm(G0PvXe=V=Wd<0x3o#jl;FA2Hd$UWHv4>D47uH?Zblxldp72(vn=Q+! z&RN=hdudADFhfJL{`-RoAxhui0B2X~TO?oR@fH&8pe9n}wXq+21ML8$FUE@eq+v)~ zOc%b%ZvUyPERCX-y@s~4;89oYY6m**Qd5}nC^QYXy=77`ODoMyxoYoNI_?X|p?A!8 zgEL#o67SF+!KRQjrPqqyMtYQ6DHBb8dvsO8fDspS$~7OF&{K5LYI{ydTn%9raUxn> z)CyQ+yB+Ihxx6Do0P&0t>sI`+M8OBGUo4rax8MHEPg+jx@!cU||LX~B;=wK9WgmqG zRBlZ{CK3*RM>YUW{|2(A9W&eLjvEyWNJ}>7vsGD|7*#EnPYbk)~`=`)P+UMbT z9<|~+4`l{{>PSU%hShptT?A7J1b^T&5~n&f$bb~HVNNtQL_vK7(W9~BW4GTRIz=|Q zI+q?7TlV-G)L%?wxfhdgOGVuFT;A0=rf_BIp*1N|q7A?H0$|FLjN|uGr|W*KLM?)- zoKMH}=Oabt6J8&esPrK{khsA%#u`;A+KN@%;?hTY-XL|7wr>Pc#$U$EY^Q5iw-~?1 zDpk4k#rxWq8dhDpdm6nh-qT2UR0yDfjjCqE30B1>Cks?S6Gw_0QTOgs_g)y8ZyyHi zdz}TWQ8^i$Br~=5{)&fFUQMJSdAioCvDh{_c2PsUrRof>8cXJES=qm^D%TXg-Cpmr zQ({nUYO}b)P?w`!Zq7M>hdK4pII>Q;SdV5F*7jGpqrztrujgvtwH%7GIRlN=6u2oE`4V@ zMmuB;>_hvwOTAIuQIGa%QWmU8vTx$*nm8eTk%{!OYlfQ&?6KBUYx6}F#T&*?3%WZq z^$v`cz%EyX{}2w}WcziG(Kb|k{;m?^ISRbi#RJ=Mu{#T7Wq{Z8jvkw=6%S3VMX9yn z(Mn9j?2j0R9w0S30|zlIdyd^u!hr;mHEH;2g-7JmM!g4p${}BH=m}9n~yQ zKp5FJBqQQVDm?HYvD09c6+K4U)Svz)%v$NNU*|cr+p!6Z%#D2rX0@BUv@b~FBi51_ zTSu}@H*nG?R64WI^agox;9RIf_PSe7ZZ$sup}s=HZ3wRIqu}Tv+AxQ{a0F8}fT%uz zART0MKp%N&0i{l~YI!%wZR>#hKNx$bCSjPU%d%|Swr$(CZQHhO`zhPDZQHi1-@cfM zo|rEt<}c($MxK*@Hl?rdA`oBOu3ww!DMABw59N;0f*^Ihc0=x- znhLaJ74CVMILyP?3BMMO84?qFTCB6N_q2r-Zy&f4SpzNEdfOxg>(?;V@bFGb$Z&i{ zYa{1nx3=;9&N?`RJ9AuF|N5#Cc|*Xj1|D*NVz6-ihlumr)SCKJ(2q1XOAzPeOlOvg zZoL0#(_EpG+UGTb6b5cf4DQK=1jHOHLxZ@Hn)p-D?Oh-(#8mg8mb}Sz8W%)^rM0`Y zg_X;cZ$2E{I`<@qx4l5ds;<${h4n7{U_nU9T?iUN)WPN@)eIs~v7+_LL$D-G{{U(d zb8ocRO=Fag4{+z3Yv4xKZyry?zrnx_{qd`>*FYR0tOJ!#?+TO zp>-m?DfLs-zn8@8I1;ue=Z(|w!rNw2BT+;YGHCd)=U6EIxJbGx3(>aji2OPf?OUHK z&=FjSuWWV6G_e?2rD!I-oN-Sfb1&9II6dmoslQ6{tAn^Oso42bhY>fmSN}H)FFEzcO-jCOuuf_sbf% z`a;7Lq8hM<-Mf4VzW<@)w65S>XkcBiX!~{+S2WwyMf9`Nx+lNszH?7OwEo49)ko|~ z<|9PWEZ(bjIpG5>0=e?>uqjX{ro#RBA``1!BzEW@!i zKTJTV!B-eoy6^r)VtkeS+fm4W#|euM%OgJLy|+&IW7KN$fEDQyg#j=jCdLsi0f*+1 zHHh|XZ!}W4UaC(WNzRl@bPURA7?05 zr7!P+Mct)GgwSZ|Pf%Wu&HLY10uJa{ZZijG#7D)9`Ki#BP&p{WT0HPk4a)oX?xuSs z-IEmg!~wRG6>?dUh$E2pOrVxX9e(FE71G0PeezV6Vm-%q$sOWyZFuuh#QuRWFz)hB zwr_z^j&>)pIds~1+TRPYY|A`7Eus=+GXI{XRQ5mDg6T|YTc zQeewdWd1IuF>`q3oibe-oXPRNr5KCyatvvJuyfe^d1@P)Lg*S=UudnO`El@(_u#*f zZ=W34tSBR7}Tof&t=6#NtvlOQ;Hz(dG4UT z3u;IMv)hV46ikNdZ$okLg$aHyM*bC0TeW&qXW$|v4t=HtJq~K^6GBU5ckdCWq*W|jnRINuP#yo-$0(Xg4%FHBb;>6QQq_tGv znyU7R{;aM^{+_dp-`OZQhM`<;i&#iREhJ5r3NazUY@vsgphUE!6hCv3cjQimz73pF zyDLmJ1XX(1v0vvyt|A>3aqvLXwlREFoEc8Qr7bL!7?fJVRJIm9+CxO;bou6OaEnaiQ z*bYopkWwbzzk&{+#7#6aWJ995BJv=Dit0w;HRied9G4zZBwZoHd=e4{&7;D-aF!NQ z-t8N>$$^Pb4a3$n*pvco)nnX1=OlMVv`$_)&7HSIwsrzh{d6^f+Ul%zg;e4tLYe$9 zSdQOYwFc$gLgC=^$Xg&oN1$xUGg|OCuRg(1m8*#b0@I%<!tNh)!DntlNy;L9)gZCRGI{M})ybI0t*9Cm5BzQR$ zU-cxn1X20{z1)A9i!AtYjk#_R2>2fp6U77VT&yI}+s4(36v9{hx@j1YBfjRziQixW zh>xxMR!9(CbRdk}0zh1*m;sc<)G zq`@Suml1cGR#h`VAAZ}h7iaC__s4HkdoVhPzb?~y#6xZI(iaY7)@XEuWO(#8lwi_jw9mPw6^D$t-NM5ioYzY zKkdX~J6n zguiMz%0r{G*gi*|*I$WgN7t^8F@5!E5Y%M32$5{(g=c)JHo$GKsy^-RmgE=yHPDI#88TpN+vDn6 z-p~wL1ekd$V^J(J|^SF;z|f@{f|)wNUB%f^~<{r zVoL?X=bNkX!*V?RtcAta{IH8izV6y+PW6R6tKqkCAVE91DklGf2^oYvFb}Ob4D)E0 z=VW%#IC;L^oTK^SDIJ!q#De^gJg^oR0-cNmPllIOpYF*v1Mqib#z=h84&@V_t_e|v z5gcN#kko&*IHeYj7j0GTpVGxHno<^0@w zrh)V!JP82|vnToMifEccn($SO5(Yb{d5XS>kdZuu%tmmsk{o=w z84SYn+lNT8_Y%o7^9s2W4c1{gZcZ+lIO!l`UaQro?Q1 zmxdo_K-OMb;0!!T%LV>U^MbT@fT=HY)kRX_c9~~K(USl{`eA=7{unL9-r0OXG^54} zP1>jAHKC790kkLAiSL-&w2t?*t`M7&340$8?! zbYD*Dt7%w{*JX%uIBi>?Am6_jbtB9IehVmHRq_~1BdPN8@C$=d{_F^6WCo>a4A0tR z8Kz_=rtBhfR#vv@n}s@tMS_+!iPcvhs8qsku;@%+M!_pSzh$PJx~&hAkG%16zX>*> zmUNtzusYLqyZxipVcHQZq*9u&?3TSTC*F9@JFv{gsfs+)F@{9n`j(v6;NyB8I5+*a z&%zhx*^bBdzd*4}tiVg@w#)6q&1nc*0XLVt227wIT6D8T`aaMW#SsE5Ewd?lP))xJ zog>CpprErG)j^P1m_tS2+HH5{2gr0{Mc(}Il@}ZnVwZLN`+;kXPK37(#G(%=fb&|# z%d$(#`{GRmVR?K4h^Ik<&%}n3(l+3`l4<2ZnfR?TYIj~Fa8B7YDP`A*@%aCSw~HlT z6C;$?W%_tKMG5ep!l%sd0G3jLGV@Gm@62!I@l;VOuSJvK z?-^tiF{$p{FzSl)Pn7ag~&xn%nb2`VvO4uj?`Z)RVM z9`*QjtEPNCBSd&QMs-Vjv-QKgebk&Q`_^;*B_Gd0@v=#5RYT)K3ef!=2r`lwS@TvcL8ljEdcz#@1`5VaeiVk3+9|HWunRykCcecYu#-@|1sE~+|;a7zX z<+2iU?Q%a1XM)Jkp2=Ge4sfY+ZLLbcT52WCFLuRLn;=G$Pj;A*dg#pj(-7YT)W|>G ztI#{V3hzIA<$&e3)1go@uHSxp|9P`oJrvLb@)t63Pj2r+Reipc-xKVW)jY7RhxSU| zWSm`zdO)F4C?g;gZ^CuP$!KVn5%D^&ZmnqUGhUK3X(NioWU0BBsLCzD!_dkjsb?;7 zqc$;VvmPoDreH%GjfJ9^ammAukS_W&EBd;xXSlJNWu3*-5wh>DeD&yynBsVha?q~B z9~UFGrqW|#RCNMMbBY{63HvRN(Uq;|>#jk!lQ;hgN&TBOfRr$0I8Pi9c{=xcxt%5;$mRA6m2EmYzp55jzi?j+K_Q3gVQCu7LNNqS( zm;DhDQbwgx%RkYY7)gu!kh~+TK#ovk-#Gmw)BY*s)GUQN_&VPpy9JD%(~fTK{-sIv zx!Ql-(4i!&_E66l67T6At1q`U5yq;dqkd+xSt#bJ(!nl%S1!F@tV}A2`xzw!z`e?3 zkzjufr+fjQsoN!)cyr)1D=W66n;)j|Kzz%2CD#kT5|^K^sMNO}Y4}Dx0A*|Rjvxx- z$zDW%NI?PfIQh@ z3m9>NdwVHzq)P5%6Q-`+xP4I|I*$?j)1qn|!~{CkH}vm9#EU>=aj6j5Zrk+yoeE4h zh^UHa;S6UWC6d9hnk@c_ax041u!)~X!*0i3dSq%hUWI$v74#;hD_z3*v=ws2mRwpX z_H>r!IFxRpJ1B4+>kR%!u(jmu9OA!$BHx|!W;)|(#@+#kXN8Z&_NXW%R<+t?ZF})i zr+^a)o+oLze8NDt7xS~MeBE_(#pRuiMe9C2((}3$C#0Oijq*r=Hl4N)cE$0kwRwQL zsSM$B^%yH9AJbYWph9SfLIwzt($BWlfy?D!lO&wy+HZ36RY$sE;%u@;-lmXtvytzD zmDU+wY;H5l>4eP4)$>uSR<+Com95At5GxW!C~cc1g0aWbNsr$a@=YWW7HKaVj_6ze zQ1rUKSpCH(IMr?QuR6ZIfHHqHiI+AU6sD_Od@SkfkYU46;V{CqZ|Wcf*5%;6V&nx; zFOkVdHoP1n2zyNNw`t-)B&~MQKvEl-H4zNU{n<-*364px4Pd?7slxDt+jS|xkt;JG z-j|p3&BSeQG+rOub&ZZ%&U~5&`KvS_xyz4_yDC$a=q}mJ z@3aa_lSF?Z2SV3*E$^Q|GlwJ_Y!AYsy$U`Bhn8-H-{itnvjh(gwLa{}=sQ!5m~v+D z^?2w%@bHG0+sg;p!o?nPPN-b=$xNA|z-z~75~(+C2z(FX>nV~ajOS5;e>aq^vO3DZ z1OLr&=x^_?U4DCzV?5pGt+0?N`+8`3)JzRRD7| zQkBBLPf{*3T(IQ`qAP9?wNRTZw7$1Gsh2U#SQ(}3$va%^U|Zt+R~2Bc%kNRGXhcT! zbW0$A;cIJ&5ub!c^_#48Iz&Q6al>_?M9Q3!N8>?@wilHmh_cF#%#w09TI0X%@T2qJ=h87b&}=+zCZ zOAvrgt` zmEpOLMc{9Ea){;tppd^wwE2P`v+G9`AgwPf81;TngUSKKnh+q(U&0RJ5IB>VPUmk< z<&XIIFaDrU@zpPmw!Ib8c2kHL=54`6))@;Wkh-6&)j{Qgu(rU-QS z2p$SJAcvtHng}F-Viw&1(tYr^C;!_ApkUa31wV;^9-!i-jf4aMAm}d<1W=&KpM(%# z{@XqhT2O}I*d8$v@_vr)r{(|*fcBtP?k`H9f8)nkoCZ`F<-08iJrMq{EhfN4AOY0w z0UiXMXv?3_iBQV%7yO|O#8DVW_wPS*_-`r_1YyU}pC({p0{ZZU{D}X{`u55Mq~rKE zBX9)ld;IrUBv_z_z;pxp*}*B%0NY*gR-F}T#WrVeT=Wcs?~1JP$-SP-r9;oan2cG? zgjdt43t{5-1@XXS8qCyOy0lAQcV8QeL0Ah}W!ui@cIL3PjIZsGUIqzv2E`|x;+}l4 z=uF{@)7V*halBjstrfIWI*@W+aTP(Y7T`mwcYcnzum8uR#re1TOD>k5XinFoWgNzh z#ZdpEW|>dZH767p3_4tv_*|qM58m8wcLw2Pu1A4##DAU%-iQOr*H!&9KX2Z%7Oj6H zH`}rwDN6Z4U@zng=gZ9Y6Fn%Pk8``GqzzDoilk{Qqfax3xbXvV-LB8N(M2c3$k@av zdonhua+KhaYq2wR#x&Tr_M>M9qA`5vk!573Rz zrmlmz%843+8;E;sNG~?{a3cpZKI{;e!^HNhz^%z@YRH|Ofc zpPOC^{umRwT~?s>Z(Vc?M1B3r*0^Npn}pa!E!nbuSy^;cePGs)U)Bp5I=$U?es|=R zrh8F}PaFp@`KJ8kN}GX&EX|0|%v6~Fh$8zd>j_{il6@(|RFXzd9j~ zld`uMaPuzsGB-MK+L=?(%VQbqOw*l`yn%arZ=071h0~ znV-7YC83DM(#NmpmXi=ZXY{3%ZY2ew%y!(&k3GN5kpQ z=b^3cGf>eX4Zpw-&dZX!^H-Kaf`lD79QkjqGiw(^_n-P}ep*enaraD#Mu^xWMLZ}K z9uRBWX!!t1lX52#UUq*zYu&i{-?JRfJ_N+_xpsvY)T}n^ZJ}uE5Iq1*x%LD#DFzv) zX9>Gf8AKhF7 zHpxZ=1)Xx_wCAt~+bOQ%j=vjMEQw)-`9zlnG~oSe|AxvNoU-p6YhBsg*PccUGP4jD z$={K>mpf(Yq3V1;*Ua$Z>#8JCjbZe>OBQ$y!9Yk<}Ei9ckFU%-Q7o9u5-Ly$Sio9*v({Z!zh_P6z74fqvjg-cYN0d?m zoaXjs5xAeuA%5PLEA_tJGru9dD+RDnB)eMn^6(7$?d( z8uA00`ot@0n__Cw@rUMHa=&spx(Xv$PEW;Q(k>imA<+A&Mo`|^6l@B7?jn<7Y_Vk7 zw$#`Z>WRP+wEu_m6$q=98khtdV02dJkTH1p&TdGe=l`d#$aw!Zonj-#T^u%|z zxFgpGMXD7!9gtp%L_NpwFC5jA=0DT9noYPCChs9>8CvRECa2^bXZQlYMq{(f9F$K>4VNUXk&d<#V04L8+CVtTh|yPmXSKb$q%A|rLj z6MQ0q-231pwMQcR!Hb)S4j=nKo{5SB^IHqbs8L3e&D4d1^|ThGAIYZnmNT{46b+7@ zz&?5kW*vGQLLPdmIW{NGT)PVj_H|TX=3#dW1&uO!pb0qhn~&l-9Phz@1rktqYsBig z@3O?%xJnlA=FDJcd~k8vK5@Ib+MGi%9o9rlt?z@~6iOerrTctPRF#Obi=&e{JthVs zLl)$)GwTe&F0MXQOW;XQqw(jY!1L=yMLH~ScNj{G&qV0)XL;OoB1K3=Su8k$`WIxH zZn8l$`o1--AkAAhS4Ilz)6?pExs( zRcI$_v+f)V5E+$3rvWyI3NUMT5fes}K3-dFD`PA$Q>yyI&=7S!GKQTcWTi8B{SxZ? z`(}f+TjLoA%;8 zbiT(`&d#30^rTlKi!qrzWlwY7Fo_5Qd`7cxzusWv(pz0wUG5_!M)6WHf{8fpC5@m) zSl3TyHuIGj%-u*%*98UFFzTRtpt^=Z)j6kKJO(8bvMNMo57;dRe!ubI0UmFdDYGjebfql1_UNh0TdN$4$F}L)iT*#}Ex1#+ zOCb8kjB@?kpi+9Xee)a?)z!VuU&1&1x|qY5J%Bby%aO+V$KVH1p8w`lnhaaU}jTeS66C!t=@fW0=3_YH;v| zFDC91NHIM3S(w4d*x4NR=h`Bhmc&s5BXYmjxb8W3M>^_!QGcMEL0t%(Kd=)%W8c-Y z0epq&ZWw8`m0!P*6T~J_lY(y&QS}uT#(eMuaYznc??0ExnV1lkI`;69M$zse_+Zo4nq4=WW(7w52Uz&Nt~5t@)2cP6246X67RI_6?u^7S_LU3B5n``!I6f><~2Hvyrt_oQ3(&I7c^$c)q z@#%4V#dHA80u^Gev{Tzh&+lNZ^4as{Hzp9i-lur|q|b+A*j!%N^7{(Yx}j82RVtj# zZ1bfdj+D66H+1wYb#~lD#kcZ_1+DAm)u_h$_)5BO{-=XZ%W6!|L0K>3nf(z0CKs{Z z$jck=>kmE8@>h3}O7B7n((FXUWgfW6eg+WrHM(Fs9(bIuPm6Q4a48arShg#G}){4oUut>*GB^n8YO2L24T^T5hKivF;NfOnmzvaQ$8Qb@$VrmgG*KCpbjZtF!I96G$- z@ap7@d6MrtKk95Y2}<)+pGaUf18O!D)_>47Hxq^&*-7FdK1!1pQ`VQ>Bw6rN8Jmji zN7ncC)=@es3On#Q86AcN%%elBzg^9ypVQ^d|Lt9u)}Vz;F`?Va!sUV3b8f>R8@rEk z%zI)N>lO ztlD7if;K|1Qm+w;Mne<7w;rDk00il;K`nRN*H_^l4A*SMxw>*TpO~NZznmI|UsH+c zz!yr^MLv^VhrOd*)gjO0WtTk4uUyen?`br6U!Z>`Xu)7^#Lq&X;IfJ>!gGOz1f$v3 zWzmfDcUJ?!brsn3#9(GilIJc^=1p1jcvL~S*>{Q??e=P9zC_c+ad=UAhRnCvSt4M+ zTt_+!C_>Wo1u<18SI3?Yg+fgfSgb|*ay9fFv7VE4( z3PjB$>3jb?!yx9kXd?ke{zZ*#X0m}uY;dh zX5hSN0)2elwR@OzWXN}*@Yq}P^_kyolW)RQ%zO)^jn(>ZhvRTl9h2L{R9cc;XSl$A|7$X6K4{j6ve=vS;okppJvTmh%B|3`5I6!PH{Z&S6u z%?Edz>$Z~+EW=t&bAHyY_VIN0Z;z1ZJseXIraGg$lLgwv&30kq-lfC*g8~tfHRoL z{6Bu%Qw{fFs`CBZ_Fk99vcG=EZa~o?Ehp>7ZDO|~opEC-&v!tUU0BcNkQp!GGlAFb zAWr4Y;a}_A3L%wXAzIC^&=gG>=qD%W_G!N|@4vjyXv^L_t^I`z2}NZ2J?PweA-Ox} zo#r=UkswqZ^GTevpHMGw{yq%9Ws-FMXk!#qLkeY2!u*3e0}pEvxS+oN03pg%h-iTUb$o8b~8qb#*7 zb*9L+8WdhBZea=CaUlGjB=sUwVew;Hyf^ToUtFgYEk#&VnLOJ6dhBsZVx@wbUL5TS zY5vT^C;;7~mkAql`!2WiY=_f9NM}OLS@?>ZWts4pQ#*w@@0(Y|8|2#83n*S^AcsW) zz{#04x+n$6Y+$ju#q4 z0@0H4gp}hCO#%=L6P15VrC>>zz;3fc3o|*R{X&CN5c~cHI=rd??IPtcEhOml?|2(P{3Tq0~JPkWEvq|sModWNXm-Rk2_&SJTE*g+;cJ7ys(pxc_hKE#`i&B z-~XHE`L;QE0MzOmg3Vp7Fj7?f6)^mf3OSi%PQ{w9b1Gh=$7+G9z#&?3cp0TD`U&RR z;N4@#z57qmHX{4c^mu5!HkZ*-m}IwMz?5U6p{6l)uJydpew>w)1{r3!(-t=SiIKMh z$_iq3KJrh7S0G5)tm?E);vEi%D!aT$LIj|@+w1o?;Y=w;1kInL)n>*n zS-H;N6Z^60wXs!?MTR?9Yf?mi*Gdf0bwM>=hV4GIrdWH8Q@gung>Al=bn{mI+<&(c z#G?8sQ2VC>g9EXW{&(YoPL7^#r0Zoc5A8j7DbdXX!QYU!h*)Uh3^;MW0}TB~{()~Z zyMLgtlhN?loEtJcLqm2ZYK^otReyC0x8b(hIs80a7_70>iW&QA?;dU|itah2?oCaT zgA6_Jj-YNSPxd0(!s?ld8+;+Rr})>77LPPa6WhFL1WZmT-`(5Qh{oAfpu~_jS1m)+T+10txZX+R;H>{&VeN6d$*i6ZWUoV}Xr1hMF(?(1;8S`$gi@-skJ7I|LEyAla-C{C^ujhV#@hj}|tJm!JC^3n-)X>H4!wp^~dX=nx85er!%=?u^#ZVc< zlV=3LE?4``f+O}Zi8WSJuZxkhD3^px;ER5qz6u-VFH}qPA;SGv_WN73Db4#Mh8Uyj z1_^8NtNzv(pnr{acP~c=XG{7~rBm74Zn~T&?@~PHQmw?pV=dS;nvA0Me2_n#DpkzQ zaUzb?QnNHR`zEniZHemK4T#uiBVKT%j}>GwWu?YPE%OYoh_@|HxIH%|6TJyWz5eII z17lnNwZ2GXEDGk6bG(d!G_&h(`yF0mV__!Wfoyf}>VWN}pvo>)1@vQ90(gZsv+6^5xy`%x7aJU1>7E2whY60OxfyS}>) zjgFU2U5-=z>*iZzqQ;Enob>rAKAF!rI$$(uxN_Py=G=wZO<4Q2_f`hdh(zVRZkXAW z8q`pG9e=2-3qIHwRO+;6g&5erH&WjgHmK3tOaiDN?t z+7#G2ZE9i1M^4~h7hRAX= zJqK?dwbSpiNlO8GYpTXR``$BFfw$e+k3e9R8@61|*4X7*tI+*iZZ@FBlC-&hl|S(@ zeCD}e*Fl^t*=MiOE$|$d3uLB9X=J`0#$6xqnF;ecEFlM+CM%MH_Kit#ZJri$jhd7< z?@>qDo@K?{)rIRL$1AY21KCNq$)|}ytV|!t9X97h@|tabNZvv4e{MRFb~K&R`HGg> zq*#+A4K8w;M1WF6jj!q;ia)$b;W{?Af?5pUho~PNM%WU6>tUac)nts$ZOSa>ELno4 zbP#>WOQP-r`ES^@3VyGwr+c4Z)cj~^3wVU>pSM|)T2pyfU(RN2T1}^oN0k8^CJ0$< z`vvDAt-8w#^Gu6OF?tpN*xSdb(=#OGBXfDi$eRhnplf?Bzd z4chPZr{%1_1+QD-_9EHXUGsa(PPs$8H|J(nd8Q=T)mOsr_Tq*wYr5w|QZJBBOfc-Y zUJ|BB(m<3LkZ`-yjsG-9@gl+=?(N4~U7AJLbL#na{vwj)GHZxtJq>y>qZGIRD3xLV zA?22!e|qgw@rS-8$#lnJ*-+7#pd%-kY|VEt-3w+M{Q6O<&XgPyKh%_kx;TU{m5s{s z#RqK|*fvt}$aE6H`L2}TeKsdw?)gyaLb6q_Woa$h)WEZFDtaqdJS_jsmpB+j@hG+F zt2`-g`)aR6RWzgL`BwJoTv>TZa`eSxk2XPhm4ysvs1`}BfPK%csxoM86Yl1dm)zSc z1m-!TGed)f)LO6P*y({McF=d!bZU8c=sX>0%$_dh*#vO{lzg1@w7RO<_)NC@e3t}y zmebl^wZL<8-9rp2Ghrq3Oo5S2PtM>03dYXY9s1)%153qGMnTz`LX7kt_;t87mwX%M z6VCj`xJBg!G#w*%nZwwDTmA+>H*5%D~FX!%MqV{<!m>OVr@=Kte8Rl^g>0uR z**NgTifYX3%^KL=&KDxC3%ivr97)MWjme8~yU$9IW4y!fj?qx?P}q^Kv-E(SwZS?< z&+{AElK!{%m+bw_*zSO}1o06eYNfd}C`ExW)e718vOx(5TQrd`Cuz;u8wS?m(*jp9 zdEbq$R@u!g>2r3=R}X?0HiTO{goj@YCEiAVE6T@D}z}A|MZwI0< zz=hCbS5>3-n{q;BupDR-vC(SD%se6wyRovs6N>Q1cJI>X=Ly9ND7e4U+RJU_#i|XZ zB*S)99%I?XZY?1}0>=+Q{vQoLixG)pK~UdLGxg+4(2SqImj0L#$HU-hFX50hd`NlA(6~w=z}hJ>;eAr4x6a>FBL?pq?KY(psbnr5)I9 z?*M(>G)<_zRvg)@7}bkZ`|JY!Gk_=0flQ2wB0o-me!~ZIu5^Mcb4iL(&3O6ecK;?A z%13eJgNgTTX2SUO7&CVQ3)My}i+vDpSq^j~YApIe0nX}SBFYs&pr*w_x8W4N;b?;ixzxK2tgma zgsPl&UKFv_ zekIgK^>nKP0(K20nI8eb4jlVb_uIocBt?z0#WmE8bXK)Cm3@{FT2VZ(;TQ;da0+cY zY|U_&bFl9|62(Wqc7c9w(=?N946q?fHq`VzoCe3q>ATo(a;682liSpEY%|f;{%yQ` zpJ87wA=yeGNX;MDm61Ko(QxMymXx(fup(LbxCXfAH{siwDTJ^zWMoSQW3n}?Xi*S9 z;}X7Zqi^aQ`E3NgEzNX8PavFRkEavh6QVMeP2mD^!VR*R=TXMy$^LiARsBpcY`*aOQ|MSVu0veCWA@Olc({mAUK zNX@ejVcJKd>vWSNqx9zl{C8m6d_ksTzJehl199W2I5fKeT|F>c42qYaQ>MOYo~3tN zdGZTx24|tA_@0KxvsGGk_bYSmyocZpi)~C_+)a(%97mhX&6L2d8y#(wEF{ThQlDSE zUZ$#qb@Im>bNwGN`XJZDXerI3K1{tZz`{KiUboeOKB_jykG6gfa&2p8jLVt0fzXYO zSfVm*-_~HGm5jVuU9sDbVTDDpBGIp7s)fp)I4DBYax|#v&MOpeq3rpKMpNR~=hhxS zlN+*24dsgqJos`LMNU%kiHh4!j+taesU}yRy6I5%myA}d^WElU{h^EPqdl&nv=S;b zm^48qT`2gh@$)TJNVklKk#R^RIihuI_o`q$zwqL+^A!I>(v0Q*Z_(E2x6*Rx2&k03ir09kjbUU;;oG27zx2lx%uH)2nsXvE0Hmgxp7#8G*u%b5C*2k zd1fZ2q2$DW8XTIyf5c(r%D`M4TI(B5e?tQ6fEMQ$AH%1B27skRng~@c>fBQ~=26 z=-@Z{w*Z3J1;L>Wg|q^z^Ak80z(y==&0rK;nA!lj+kdD*No(5^6M5Nz11l@3yYr)o zyR!o^@lj~|RtF|<3P4;yxHj#0dlX_Lk{KLZ%oUqjK5k%AQQu=ABtd_~%)nfL>lm1rob4I_{c`{X*$tdS zclT7cul;=~GJPWjFx|X2H~$MwK(fE=0j8iNfZi6SK+r#UPe(%+Ai&AN8R+f#PsP6x zJQEYZ#KPDKU<5R?u!a8<9V7;t{*6J+cd&2+XfuLlj|sr|`|rO`x}fngv9q;y|6~4F ze;EX|6ciNXY5vamzd9iyJ2!wQ9V;V%j+u=S!1Q~_I6x2H{|=*IXz`z8{KHq$*3=Hb z_4jE(W%{2JyZmPWDF3q@RDgfSlCuL%Ef7HYXUKIJ*%*yMKTQA6qyCr6|KEiFj`DvS z^8bAxF=uP*ztog}>Hj}!LmLZg_x~7xhSu2$v;eYppf#}l-=^xozn4}PXky`P^S`x{ zPKKaG5VSS3{%;vA9K|f$fF=qSPR8bcPs`tO)!$oYZD9*kuyeHdeXRiKK&|;-I?!qv zTY;_)N6<+Ar2>LB=iii~w#IfQzgLWzjU8a<;9%$u4{9<9u>m}pK)YxHbo*p zASM8V_#ea!V37EOSO5%?e-MaI<_`k#$^JngKDj>##3%n>#0lb4_=7+UN`DZDLHQ42 z1u&@mL7;3^{~!>b`hO7@2pRrCAaA zA~sMkV>@e5kN-!)%KBSkWAlgbck>xc{sBRhz&{Z{g#!MIf&I7svomO6{>vD$pp-2C0YT-r`UeD+?4PND>S^7n+Xm?Jk4CV8 zf;fU+F8@70sCd4=w1{W^gih0RCefK_zo?wflzyD2DStAgFsT|A3&A zx&CAFK;CZufS~a1|A3%!dHgvXD3S-z;cu#c-F(K*4xsKh{q=4FU5o#N|N7DZ0^NYd z@JsV{#ymlmH9>7ZzYF5J((R3Znjza$PobjoTyki4e)<5DL{*g$u;Fkom^9Rbyt*Sw zc_*+;_~LoeTnF=|B|)+Em)Em?oYK@@EBxXl#*c}D6T#Ykd^kKh6@h)Pm(N~m{#Fpp z;GI%rIiH<5KPcp({dDaUcdP9$T^S9T-&5SLVwXmEE}f=}QjOH{FPbIGHOidBB8GON z!-u6ty>vsGy}O@5&7OE8l!~K)_dbncDfHCZWR8BE^H?iaVRr1oCdJmm!iTs+9i1Zg z6go_n!d&nyE?oVw=+?|zNSKXC`*oELnf{PDy~;u2@phq`vYw^ zp}M3IUEhIN{$o|Eegv9RHH#Gx|FFYUXszvDt=rV{E8a5KbnP2p7E#mu#ILE_^H<&H zwV~l3bPpk4TYe5T4)1h(s~7S2^W&MhGEs|~Ylp9{aHr#cg(`I#d)K87ltf3SU3N+0 ze147EPA1zXCy`-#*l+ zcJ+!QgsZIbGmpe$6RdY(dTfViWNL@h)4D>Zh_$Z?z{3`q3Sk{bPPDM&mv*!9i83<$ z)ik_mUDZ{vZW*sSef9@%<8*KoQiuemorMvdZ~RmOP*6gVu`W|cgZ?(3kY%~;kty&* z7}NBr(ov^o9sQ0sxa^ZomnJyrh6sPC>M`8p{xf@0_OzRLuA=Qg8E#rQ_O3-0*?eLa z(ZUqG3^N#JwRTn-%I!{}FBMUwX|P5BtnndA1T5GN?;HjCU`!jcZDWocTsHMIdVX1L2DW_5}@?K94=vek@coKiL$==DXleu|`IoyPs2!@j3 z4`K^uuEb(&i7~EM%AurQRd4=wioD|o<6jXFrVM-k4DvtbM>+8RNPv;-PHsHVENItzi#(oX8Q;dE2rWo4Sfzxm`e@lyh9 z83~bxJ+-;X+d4@c5nyN4ultmgworF_G&D4zdy*n1c{Hu>K0h!Lm=L{1 zc~%!9?R5PI$(FqD7qwN-AAjr{N8m7S;Fn#?N-_8mymQF@ zJd{Svg8k_MA~92CT2q>SRT}Gfh^m_wQ+!z3(=b$6OGrGc9i9N+eTDKvxHLsbFS9)3 zjM~>qc1Z7Q>V33e?#o=K`fhk~B0zAS$~KOs=4&g@2b$oZK_#$>v32iNYz zXO~HhA#zaYlR)+D(-{$Ce79z%fFyOt7)e%kVN$$b>t#(F!lwMK#bY8;%oiFC)w=YtjJQXNuM!Bks3sJnE`;ZO zphgu7xvD(4Vu4MYd*Q!cbfJWb(S%Xh-YOO~08!emkV${oE(1B`=k^ow8eAhTDAcMLS(*VOd%qAK&$ZG~IR6So z7K}qRHJ-)Xwz1He4~VFh^7Qgqn-;WfoSbFz1c9f$A;D(ZpL9NL3J{BJK1qxHRLM2^ zl@iyX<{xcMX>C^7ow;l@T@kfL)O1)nmpnJ3v-R?5$g0SM`F+#}P{y_WS*@_CXtWRz z@2F>Wmgi^^oo@TVBd!}3rXv5KfO{TKCd&g`HyY)#)Bz#9Ft0SwMNXt6LROrEi&Rp^ z;*~r>aM28R%hsCR9sG+FT#T4}{WY&N+}?@8Sb==Bpdi+;OGtw6`m}W(`9b|p&Ao*> ziluQd_2tREK=Q6UMt^C*EB41U1`9ZgrDG{yj@l7e$NAP$x}p2%p;8bUvDDiMLtZW#{^ zhrLdLs~a||=C(Mz-Wr=|<=E<6){SUW=S&8xoX+$& z&NSycOTP%v86X&ysUpD||uQqW} z^=@kJclFCCQ<=oNBpyCkUyJNruDcO4@k8QL?-%=v=^cc)!bm^bHfai12s1tPIhC3S zkUSJ~f=yb$L1?8Aj$Pllc@+EIb`_oVgoFY$OzbHVu5A zp@*-&7EI2}>WW%o?SZgQI?JqnfmY+X7X0H>p3CShe~(!HTQ=J8n0ha@7^?0X!#4x> z(n!T>xX__Q9mS*`Truj>RSOl2tEfXgIl#S%e!i?hU_pp7nM$o(i!?_}6)cTX>ins; zLt*;!pypja+L`8Opm$sKBHsJLh=)bZFA7h$@Z)0Os-k(PH?NVGGtz-wb4U`A6gBmH z;980T<4BTAn@(i;yKl)EUE0M|9DU>+&pGDfwwdp%v5zz*Y*8dQ3(C^Q^=XE#zA zZ1ruEAf#k+F%V!WlLg>w4su2&)8H%WR^jn;c?k9{!C3}mYEbzxTw z3siH#oBKVVLs4C}FJv}WTlVu<6K9Yy{uV9h1;|e%xH!YHdJJr?!47c^G!Q zyR=J3HxlrSbDu|mB@z}UjPS%XhNV~c)oM7sAlPTbv_;r7vJW=H=0rC%fDQ91l2JLHy`-(|K9 z7W&=sP21hVmtGBU!+au6?70FP_~ex@SZ1zEL@@BMKRNcq;4}r?m34itg0tVHRyL(GL^U>=VM*X>tXGNS~ z9vxW|jhIE~mTl?gdH?5@gbwjcnKtxKrsVO|Gh;TnpIoK(e9RnDtwJw1^^Ob>=iv=z zl(!{r9~EgoIPqy$ZgY+$h&%Q-`EwI0k#gy>qmzd|*|=9yS=3{Py9^y!_S~x%N67Rk z3F+Z02^m^zC}n zzJ~5q!m79?c)r9#>rO@cxDcGOJl`3ru8@Yz$NIu+hA18wWo(M~dd+v-yH1c&)s_Os z=x$}TfufX*;=?@SEgx4DKfjAE8A!BJp=iF$LgvZhjs1*kySVG@?_@0_%#@(f2Vfh+ z`3nCzZlUkS+Y?nTwRvbb&-E|FZZsntAF#p)cT>fPDjchGxV42`Y|m?9cU z)=WA*274r$1($@K)!Zwd$;Or@J2Wm7t!g?Y_?7-iXlYbZ7uQc2n&|;Rax>F{V*X)N zTQNk&yi}8JFTh9H;nm%c4IrzaDPA%+$wR;e8HJ|{Su%yG35F37EWqX$zqT<&i39&L zBaROtvp2ADNJPT&OCIu$<41>&0dA|w@cZ;Ve9M#bRaLnYR$nWZt^0V$ldDL050=xu zUjt*QOs96mJkkvs2O9bFb|j6#1e7JnlX>5u+Tzb4fiAXSoM`@;VgYzMJ8IRXEd4iz z6@o9ZkJHW0Y($Duk&GB45r>J8_DS>Bi{ygh{a2iQ7R57Ol2LX zU}gz5)Ky=+pYQ7%n>73Cqx2B`W*5jT#|DTbIxZsQCEj3%#-a)J9~&Zg4!_ilU;D;w zOEtOVeyH)+T_u4hU4kh^TA>g&=l5qzuTcVz4l2tLbUEV!+~M{muoy(x8Px(mLnGce9#kukJbb zZbqSJ_|!8o4_dS;<>J%0z2TuAg8!oViM$nrL1yE5`i}k2r}q_{&hD$E4%f+RH%ZR$ zrryS%duiCZ-F=8&)^z7GpKyP6oqkZItpM+E%Awk~;Fh?~>5vcZTcNDf2g>^&;ftwt zyndd9#^5V=KHTi16Xy=yy6W=?%nDAI(9$7`Q9W~6>;fY|ob=ey!`d7XigG9OlT+Dl zYGC<HP+vBBJjnkNs0a>{qDtu!f(Ka9+hHD zd8bFDb#%$v{h1JpBLO4tz2@D#aBW4u%~8ExLzTEQo4$BD%+LBIrfk3@RJ{m0QO*e~6-}A7QK^M3V zoU}sjN;-VL5G-af6%5$WM6qx#_v=~P?Y(ZFx;ULi)pS5U!WX%_=Z=Y5HX(pfDuh@A zBnUd8yg#8Ujip7W+HNr{Ef{Js-=5&oo-J~IgH=Aj;*yTX4npZukuEXRAl-E}8%k)9 z57gd%=N5tcc_1*~9a54q`K`?onN6msRIw0zYQXWYgdhjBO6S2jEZLE_qgJ8L!BBD;J(lG*tfWrF$}^)^|l=TelR5PD?fbC zyWiIhY5zjK0SYE{&-ROBbPA&_^#{)nRo47kB_1~sNyDfSd`$rvq8SX~MI@gKiOr`SnqG>$2uQipHPriGiZhJRqcK^o8ufeR_6U$mG zkv5i>zHptU*FE`J25484k)nEbH`ei@^8@~LunCI$(}&(iUolJ*HF24FTABk4$B*UWuLYZW3{54U>v|!F z?!nC?`;p2YAGHX|J%U6^oCMypJOEMC(z6d`7X|n%sd&}R4R&SQLiyen@`m1gwt$;w zY9dl|USC^UG?2Wfii91)2Qh!B30fb;U8H=6)~j{||glM2`6b*uys(di37lyIJ9e^cy#nM|R`RAd=6;&CHsiY8>a zAygjaF10j5Ia?uXa*~RJVc;9im47?Wz;{qv_wT`W)BWBI-Nr|?eUaT=uj^->`3S*g z*MY2kkUJ^HgG?(&UQB^zQ4+3GEvMKmc`Y$Jb~{Pf#jnDBCa@@Wfq5YJh5)0i(Y?l4 z&09{@YQCvH5AEO1YT7I&(r6yDLcdt6@{USR8ET4-AlTN``-K)ER7Fo7YbBoO&22;#OKi#c6DiA_7%PWFHBffs%OOUt# zlIlD%yCi}RVQSF9>OJ2x_mGa^4lo zFohUhDhR$)*eD*R5{(VzL<)FTEzEdwrK-F%Lkl1I_<5Fl)5Mabu(@jWW2iaI=K+Mm zj5bF*M7m~ycz9_DagLZB;tDUt$uIBrOP}@tTGt+qUcmw0`F%2Tb;@Yrh1`CorE@lI zMLmKn7cujf$_UJTpRnWRwQEfp7ZaYPGIUmJF$gN~t}%>Hm$CewACbJEN1Qq=nWlcE z3m!PUhJUQ=nyP%o9+h(Gp_L}|0*AY<3!X?)TaS&+fKPc&R}8AtUR~!^?bhJNgA7<+ z;WwtaC)=!sJCkc&6;fv73i%n>T?-ynnnm0@-FLrn^Z zbcHVec}Vp!JThS?SPxx}$f2TF)1#2LFoYb_;VX}ziKH;D0Yj+2H$0ss0G!=JXT3CyQf3J6JA8XN52O()SA`pS$edP3=Yv}rp!St%n$)`ywVTj# z0f;B>t;QvUNQ`C};R$`j9}z@(qDu(|Qz7NPPK&jD?7H1GvHSUG-Y>G~4ldj%!J=rp zy$3()w@W+v!CV_dm>dzVp+6hUBHQcr^#*uU=d=+RM#4%LK~fpIMNk#GT{a=-=kUzw+(+#b;&2=J zDsD{vEBbZ~i(2~I$9c_n5j!rT`&`CH9Bv!GKwq{O2k!C68}IA*ytDcmf$fp)eH91f z^Q*R(PxZidR?n7$v&Z0k9L=ej9F$|olZVBkh<1y7cIx?DGvQ9PH%m??!#SiL@rohs z?{QcgiYTgpK#iw`ZFLGTNn!*zt~`LcO$Sl8T5m<65UolACLZiWIo1b}CtQtU-pTZ3b|YTT!QK z0rz5Xyw*1lzGe~)JnwCk*;0wgo+R`~g{?IM>xgGcCWzgY;_E|%N)|G03%|TjC!!Zy z_P$?;+vkg8wLcT1BZY)V6kgEm%hGwPaX?AUjRN*+8Gi zFx})}b!Sq(Lv^NA=0*KWpa0ENn@4>YG3o{_-}8$ewHBB)3%9cSma8Y^TIb$d#GN*$ zx73O9k4e|pw&DkqwCl1rRQ_LsiVg!n(O)j(=$4GXYYzl^u<$xmv2$xaEtQ{k? z(Fc4(>OQAJc6Leby<%amxtHkd%+>tvGdCoxya$`$HZc{c%dEN1@vx`cEjO?e+0_)v zLT#49W|l4^2~qSq+>K3euB?WqHKsnwambW?oO&odCAerMm`|)56C&qM@XaP;7;cL3 z@s)um0ppq9?6nVEU09+8BH|eLimVQHkCnIKpqa-}2Jaick+L)qcvm76 z>I+t|sfSNtP#G}Ql;wW$@5Nekzd=8ACaYDlmK+5i2ny2O63S30xR8(JtOj)

HX@ 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

F@jE<_jXvDpjOvA%-=fqCixO3jW&E+ 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⁢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%0A=n-@%LX{qB-(U($%8{KgaDRp<+a6>V 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�`9)SQq6WG_4u1?2K4_U7k5&%>>2R2XX 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 yhg!0kN@%0j0sd70 literal 0 HcmV?d00001 diff --git a/tests/data/sha256sum/empty.txt b/tests/data/sha256sum/empty.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/data/sha256sum/small_file.txt b/tests/data/sha256sum/small_file.txt new file mode 100644 index 00000000000..74ca63e8d35 --- /dev/null +++ b/tests/data/sha256sum/small_file.txt @@ -0,0 +1,19 @@ +From: https://localmonero.co/knowledge/monero-circular-economies + +How does Monero uniquely enable these circular economies? + +While Monero shares some of the core attributes of Bitcoin that enable circular economies in a new way (censorship-resistant payments, p2p transactions, etc.), it brings an absolutely unique empowerment to those wishing to build and engage in circular economies. + +1. Monero enables global p2p transactions without fear of surveillance or censorship +Monero users do not need to worry about mass surveillance or even targeted censorship of their transactions, enabling unique peace of mind and preventing any burdens on commerce. You can transact with anyone in the world, at any time, without any surveillance using the Monero wallet of your choice. + +2. Fungibility removes the risk of tainted coins and ensures trust +As Monero is fungible (1 XMR equals 1 XMR, no matter what), participants in the circular economy don’t need to worry about the funds they are sending or receiving. Any Monero they send cannot be traced back to their other transactions and has no history and thus cannot be censored based on history, and Monero received will always be able to be spent freely at full market value. This fungibility adds to the peace of mind of participants, ensures that chain analysis firms cannot force their way into circular economies, and prevents a breakdown of trust in Monero as a method of exchange. +The current breakdown of trust in Bitcoin as a method of exchange is leading to it rapidly losing traction in circular economies where Monero is present. People don’t want to have to check funds for taint, worry about if they will be able to spend them freely, or feel the need to use any chain analysis tools to protect themselves from legal or regulatory issues. + +3. Monero’s low fees ensure a free flow of commerce +One of the simplest points to grasp about Monero transactions is that transaction fees are incredibly low and will remain reasonable in the long-term thanks to the tail emission and dynamic block size. +These low fees make sure that commerce can flow freely no matter the amount of blockchain congestion, further reducing the mental burden and stress on participants to try and time their transactions or wait hours/days to confirm low-fee transactions. With fees around 1c today, you can transact freely with any size of transaction without worry about fees down the line. + +Conclusion +Ultimately, Monero is digital cash as it should be. The peace of mind, fungibility, and privacy of transacting in cash but with all of the advantages of digital, global, and p2p transactions detached from the states control or surveillance. This ability to act as digital cash is uniquely enabling circular economies today and helping them to grow and prosper over time in ways that other cryptocurrencies like Bitcoin simply can’t. diff --git a/tests/unit_tests/sha256.cpp b/tests/unit_tests/sha256.cpp index 486f31c5bce..7a96a783bb1 100644 --- a/tests/unit_tests/sha256.cpp +++ b/tests/unit_tests/sha256.cpp @@ -26,10 +26,13 @@ // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include + #include "gtest/gtest.h" #include "common/util.h" #include "string_tools.h" +#include "unit_tests_utils.h" static bool check(const std::string &data, const char *expected_hash_hex) { @@ -39,7 +42,26 @@ static bool check(const std::string &data, const char *expected_hash_hex) return tools::sha256sum((const uint8_t*)data.data(), data.size(), hash) && hash == expected_hash; } +static std::string file_to_hex_hash(const std::string& filename) + { + const boost::filesystem::path full_path = unit_test::data_dir / "sha256sum" / filename; + + crypto::hash hash; + if (!tools::sha256sum(full_path.string(), hash)) { + throw std::runtime_error("sha256sum failed"); + } + + const std::string data_cstr(hash.data, sizeof(hash.data)); + const std::string hex_hash = epee::string_tools::buff_to_hex_nodelimer(data_cstr); + + return hex_hash; + } + TEST(sha256, empty) { ASSERT_TRUE(check(std::string(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); } TEST(sha256, small) { ASSERT_TRUE(check("0123456789", "84d89877f0d4041efb6bf91a16f0248f2fd573e6af05c19f96bedb9f882f7882")); } TEST(sha256, large) { ASSERT_TRUE(check(std::string(65536*256, 0), "080acf35a507ac9849cfcba47dc2ad83e01b75663a516279c8b9d243b719643e")); } +TEST(sha256, emptyfile) { EXPECT_EQ(file_to_hex_hash("empty.txt"), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); } +TEST(sha256, smallfile) { EXPECT_EQ(file_to_hex_hash("small_file.txt"), "91c60f6d9ad0235306115913febccb93a5014bf4cea1ecd1fa33f3cf07ad9e8d"); } +TEST(sha256, largefile) { EXPECT_EQ(file_to_hex_hash("CLSAG.pdf"), "c38699c9a235a70285165ff8cce0bf3e48989de8092c15514116ca4c95d41e3f"); } +TEST(sha256, noexist) { crypto::hash hash; EXPECT_FALSE(tools::sha256sum("this_file_does_not_exist.exe", hash)); } From 2dab31f62f3e7aff14afd7897848143456b0c47d Mon Sep 17 00:00:00 2001 From: j-berman Date: Sat, 14 May 2022 20:11:53 -0700 Subject: [PATCH 012/186] Don't exclusively drop tor/i2p outgoing cxns in idle loop --- .../cryptonote_protocol_handler.h | 18 +++++- .../cryptonote_protocol_handler.inl | 62 ++++++++++++------- src/p2p/net_node.inl | 10 ++- tests/unit_tests/node_server.cpp | 4 +- 4 files changed, 65 insertions(+), 29 deletions(-) diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index a1e4df56306..515b78c9459 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -113,12 +113,23 @@ namespace cryptonote const block_queue &get_block_queue() const { return m_block_queue; } void stop(); void on_connection_close(cryptonote_connection_context &context); - void set_max_out_peers(unsigned int max) { m_max_out_peers = max; } + void set_max_out_peers(epee::net_utils::zone zone, unsigned int max) { CRITICAL_REGION_LOCAL(m_max_out_peers_lock); m_max_out_peers[zone] = max; } + unsigned int get_max_out_peers(epee::net_utils::zone zone) const + { + CRITICAL_REGION_LOCAL(m_max_out_peers_lock); + const auto it = m_max_out_peers.find(zone); + if (it == m_max_out_peers.end()) + { + MWARNING(epee::net_utils::zone_to_string(zone) << " max out peers not set, using default"); + return P2P_DEFAULT_CONNECTIONS_COUNT; + } + return it->second; + } bool no_sync() const { return m_no_sync; } void set_no_sync(bool value) { m_no_sync = value; } std::string get_peers_overview() const; std::pair get_next_needed_pruning_stripe() const; - bool needs_new_sync_connections() const; + bool needs_new_sync_connections(epee::net_utils::zone zone) const; bool is_busy_syncing(); private: @@ -171,7 +182,8 @@ namespace cryptonote epee::math_helper::once_a_time_milliseconds<100> m_standby_checker; epee::math_helper::once_a_time_seconds<101> m_sync_search_checker; epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker; - std::atomic m_max_out_peers; + std::unordered_map m_max_out_peers; + mutable epee::critical_section m_max_out_peers_lock; tools::PerformanceTimer m_sync_timer, m_add_timer; uint64_t m_last_add_end_time; uint64_t m_sync_spans_downloaded, m_sync_old_spans_downloaded, m_sync_bad_spans_downloaded; diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 891ee109d2e..af3031263a1 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -1776,33 +1776,49 @@ skip: return true; MTRACE("Checking for outgoing syncing peers..."); - unsigned n_syncing = 0, n_synced = 0; - boost::uuids::uuid last_synced_peer_id(boost::uuids::nil_uuid()); + std::unordered_map n_syncing, n_synced; + std::unordered_map last_synced_peer_id; + std::vector zones; m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool { if (!peer_id || context.m_is_income) // only consider connected outgoing peers return true; + + const epee::net_utils::zone zone = context.m_remote_address.get_zone(); + if (n_syncing.find(zone) == n_syncing.end()) + { + n_syncing[zone] = 0; + n_synced[zone] = 0; + last_synced_peer_id[zone] = boost::uuids::nil_uuid(); + zones.push_back(zone); + } + if (context.m_state == cryptonote_connection_context::state_synchronizing) - ++n_syncing; + ++n_syncing[zone]; if (context.m_state == cryptonote_connection_context::state_normal) { - ++n_synced; + ++n_synced[zone]; if (!context.m_anchor) - last_synced_peer_id = context.m_connection_id; + last_synced_peer_id[zone] = context.m_connection_id; } return true; }); - MTRACE(n_syncing << " syncing, " << n_synced << " synced"); - // if we're at max out peers, and not enough are syncing - if (n_synced + n_syncing >= m_max_out_peers && n_syncing < P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT && last_synced_peer_id != boost::uuids::nil_uuid()) + for (const auto& zone : zones) { - if (!m_p2p->for_connection(last_synced_peer_id, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{ - MINFO(ctx << "dropping synced peer, " << n_syncing << " syncing, " << n_synced << " synced"); - drop_connection(ctx, false, false); - return true; - })) - MDEBUG("Failed to find peer we wanted to drop"); + const unsigned int max_out_peers = get_max_out_peers(zone); + MTRACE("[" << epee::net_utils::zone_to_string(zone) << "] " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers"); + + // if we're at max out peers, and not enough are syncing, drop the last sync'd non-anchor + if (n_synced[zone] + n_syncing[zone] >= max_out_peers && n_syncing[zone] < P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT && last_synced_peer_id[zone] != boost::uuids::nil_uuid()) + { + if (!m_p2p->for_connection(last_synced_peer_id[zone], [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{ + MINFO(ctx << "dropping synced peer, " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers"); + drop_connection(ctx, false, false); + return true; + })) + MDEBUG("Failed to find peer we wanted to drop"); + } } return true; @@ -1987,11 +2003,13 @@ skip: ++n_peers_on_next_stripe; return true; }); + // TODO: investigate tallying by zone and comparing to max out peers by zone + const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_); const uint32_t distance = (peer_stripe + (1<= m_max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2) + if ((n_out_peers >= max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2) { MDEBUG(context << "we want seed " << next_stripe << ", and either " << n_out_peers << " is at max out peers (" - << m_max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe << + << max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe << " is too large and we have only " << n_peers_on_next_stripe << " peers on next seed, dropping connection to make space"); return true; } @@ -2812,11 +2830,13 @@ skip: } return true; }); - const bool use_next = (n_next > m_max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0); + // TODO: investigate tallying by zone and comparing to max out peers by zone + const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_); + const bool use_next = (n_next > max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0); const uint32_t ret_stripe = use_next ? subsequent_pruning_stripe: next_pruning_stripe; MIDEBUG(const std::string po = get_peers_overview(), "get_next_needed_pruning_stripe: want height " << want_height << " (" << want_height_from_blockchain << " from blockchain, " << want_height_from_block_queue << " from block queue), stripe " << - next_pruning_stripe << " (" << n_next << "/" << m_max_out_peers << " on it and " << n_subsequent << " on " << + next_pruning_stripe << " (" << n_next << "/" << max_out_peers << " on it and " << n_subsequent << " on " << subsequent_pruning_stripe << ", " << n_others << " others) -> " << ret_stripe << " (+" << (ret_stripe - next_pruning_stripe + (1 << CRYPTONOTE_PRUNING_LOG_STRIPES)) % (1 << CRYPTONOTE_PRUNING_LOG_STRIPES) << "), current peers " << po); @@ -2824,7 +2844,7 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template - bool t_cryptonote_protocol_handler::needs_new_sync_connections() const + bool t_cryptonote_protocol_handler::needs_new_sync_connections(epee::net_utils::zone zone) const { const uint64_t target = m_core.get_target_blockchain_height(); const uint64_t height = m_core.get_current_blockchain_height(); @@ -2832,11 +2852,11 @@ skip: return false; size_t n_out_peers = 0; m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{ - if (!ctx.m_is_income) + if (!ctx.m_is_income && ctx.m_remote_address.get_zone() == zone) ++n_out_peers; return true; }); - if (n_out_peers >= m_max_out_peers) + if (n_out_peers >= get_max_out_peers(zone)) return false; return true; } diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index a3bc3bf24de..872c1a6330f 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -538,7 +538,7 @@ namespace nodetool if ( !set_max_out_peers(public_zone, command_line::get_arg(vm, arg_out_peers) ) ) return false; else - m_payload_handler.set_max_out_peers(public_zone.m_config.m_net_config.max_out_connection_count); + m_payload_handler.set_max_out_peers(epee::net_utils::zone::public_, public_zone.m_config.m_net_config.max_out_connection_count); if ( !set_max_in_peers(public_zone, command_line::get_arg(vm, arg_in_peers) ) ) @@ -575,6 +575,8 @@ namespace nodetool if (!set_max_out_peers(zone, proxy.max_connections)) return false; + else + m_payload_handler.set_max_out_peers(proxy.zone, proxy.max_connections); epee::byte_slice this_noise = nullptr; if (proxy.noise) @@ -2758,7 +2760,7 @@ namespace nodetool public_zone->second.m_config.m_net_config.max_out_connection_count = count; if(current > count) public_zone->second.m_net_server.get_config_object().del_out_connections(current - count); - m_payload_handler.set_max_out_peers(count); + m_payload_handler.set_max_out_peers(epee::net_utils::zone::public_, count); } } @@ -2887,10 +2889,12 @@ namespace nodetool { if (m_offline) return true; if (!m_exclusive_peers.empty()) return true; - if (m_payload_handler.needs_new_sync_connections()) return true; for (auto& zone : m_network_zones) { + if (m_payload_handler.needs_new_sync_connections(zone.first)) + continue; + if (zone.second.m_net_server.is_stop_signal_sent()) return false; diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp index 134fa6ece0f..6c8cd9f8d1f 100644 --- a/tests/unit_tests/node_server.cpp +++ b/tests/unit_tests/node_server.cpp @@ -1026,12 +1026,12 @@ TEST(node_server, race_condition) } void stop() {} void on_connection_close(context_t &context) {} - void set_max_out_peers(unsigned int max) {} + void set_max_out_peers(epee::net_utils::zone zone, unsigned int max) {} bool no_sync() const { return {}; } void set_no_sync(bool value) {} string_t get_peers_overview() const { return {}; } stripes_t get_next_needed_pruning_stripe() const { return {}; } - bool needs_new_sync_connections() const { return {}; } + bool needs_new_sync_connections(epee::net_utils::zone zone) const { return {}; } bool is_busy_syncing() { return {}; } }; using node_server_t = nodetool::node_server; From b15aee2b0dd3a06725f4b4cdf3c20ba0257aef7f Mon Sep 17 00:00:00 2001 From: Gingeropolous Date: Sun, 22 May 2022 22:59:18 -0400 Subject: [PATCH 013/186] readme edits squash --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ad31b127a2f..a676da7f264 100644 --- a/README.md +++ b/README.md @@ -111,10 +111,11 @@ See [LICENSE](LICENSE). If you want to help out, see [CONTRIBUTING](docs/CONTRIBUTING.md) for a set of guidelines. -## Scheduled software upgrades +## Scheduled software/network upgrades -Monero uses a fixed-schedule software upgrade (hard fork) mechanism to implement new features. This means that users of Monero (end users and service providers) should run current versions and upgrade their software on a regular schedule. Software upgrades occur during the months of April and October. The required software for these upgrades will be available prior to the scheduled date. Please check the repository prior to this date for the proper Monero software version. Below is the historical schedule and the projected schedule for the next upgrade. -Dates are provided in the format YYYY-MM-DD. +Monero uses a scheduled software/network upgrade (hard fork) mechanism to implement new features into the Monero software and network. This means that users of Monero (end users and service providers) should run current versions and upgrade their software when new releases are available. Software upgrades occur when new features are developed and implemented in the codebase. Network upgrades occur in tandem with software upgrades that modify the consensus rules of the Monero network. The required software for network upgrades will be available prior to the scheduled network upgrade date. Please check the repository prior to this date for the proper Monero software version. Below is the historical schedule and the projected schedule for the next upgrade. + +Dates are provided in the format YYYY-MM-DD. The "Minimum" is the software version that follows the new consensus rules. The "Recommended" version may include bug fixes and other new features that do not affect the consensus rules. | Software upgrade block height | Date | Fork version | Minimum Monero version | Recommended Monero version | Details | From a4cb77f9f3e3b37e5f9a87cee53392c8114a1b37 Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Sun, 22 May 2022 23:41:41 -0500 Subject: [PATCH 014/186] epee: update 'http_server_handlers_map2.h' macros to use fully qualified names quick patch which fixes the issue where if you use some macros from `http_server_handlers_map2.h` you have to be in the `epee` namespace or it doesn't compile. Now can remove `using namespace epee;` from header file `core_rpc_server.h`, which caused a couple of name qualifying mistakes --- contrib/epee/include/net/http_server_handlers_map2.h | 8 ++++---- src/daemon/main.cpp | 2 +- src/daemon/rpc_command_executor.cpp | 2 +- src/rpc/core_rpc_server.h | 4 ---- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index ffb3f3b7ea5..f52e61817f0 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -71,7 +71,7 @@ else if((query_info.m_URI == s_pattern) && (cond)) \ { \ handled = true; \ - uint64_t ticks = misc_utils::get_tick_count(); \ + uint64_t ticks = epee::misc_utils::get_tick_count(); \ boost::value_initialized req; \ bool parse_res = epee::serialization::load_t_from_json(static_cast(req), query_info.m_body); \ if (!parse_res) \ @@ -107,7 +107,7 @@ else if(query_info.m_URI == s_pattern) \ { \ handled = true; \ - uint64_t ticks = misc_utils::get_tick_count(); \ + uint64_t ticks = epee::misc_utils::get_tick_count(); \ boost::value_initialized req; \ bool parse_res = epee::serialization::load_t_from_binary(static_cast(req), epee::strspan(query_info.m_body)); \ if (!parse_res) \ @@ -117,7 +117,7 @@ response_info.m_response_comment = "Bad request"; \ return true; \ } \ - uint64_t ticks1 = misc_utils::get_tick_count(); \ + uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ boost::value_initialized resp;\ MINFO(m_conn_context << "calling " << s_pattern); \ bool res = false; \ @@ -129,7 +129,7 @@ response_info.m_response_comment = "Internal Server Error"; \ return true; \ } \ - uint64_t ticks2 = misc_utils::get_tick_count(); \ + uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ epee::byte_slice buffer; \ epee::serialization::store_t_to_binary(static_cast(resp), buffer, 64 * 1024); \ uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 73d9ebce1b3..3d90e0855fc 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -83,7 +83,7 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm) } uint16_t rpc_port; - if (!string_tools::get_xtype_from_string(rpc_port, rpc_port_str)) + if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str)) { throw std::runtime_error("invalid RPC port " + rpc_port_str); } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index b6364ff7702..0d3688c7655 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -1063,7 +1063,7 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash, cryptonote::blobdata blob; std::string source = as_hex.empty() ? pruned_as_hex + prunable_as_hex : as_hex; bool pruned = !pruned_as_hex.empty() && prunable_as_hex.empty(); - if (!string_tools::parse_hexstr_to_binbuff(source, blob)) + if (!epee::string_tools::parse_hexstr_to_binbuff(source, blob)) { tools::fail_msg_writer() << "Failed to parse tx to get json format"; } diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 0274f4db84b..b87412ca67d 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -47,10 +47,6 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc" -// yes, epee doesn't properly use its full namespace when calling its -// functions from macros. *sigh* -using namespace epee; - namespace cryptonote { /************************************************************************/ From 285d9f04d5005bb3abc637877a385189e7c5899f Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Mon, 23 May 2022 15:31:13 -0500 Subject: [PATCH 015/186] http_server_handlers_map2: dead macros --- .../include/net/http_server_handlers_map2.h | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index ffb3f3b7ea5..be8787669fc 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -63,10 +63,6 @@ bool handled = false; \ if(false) return true; //just a stub to have "else if" -#define MAP_URI2(pattern, callback) else if(std::string::npos != query_info.m_URI.find(pattern)) return callback(query_info, response_info, &m_conn_context); - -#define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format - #define MAP_URI_AUTO_JON2_IF(s_pattern, callback_f, command_type, cond) \ else if((query_info.m_URI == s_pattern) && (cond)) \ { \ @@ -139,8 +135,6 @@ MDEBUG( s_pattern << "() processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms"); \ } -#define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);handled = true;} - #define END_URI_MAP2() return handled;} @@ -225,26 +219,6 @@ #define MAP_JON_RPC_WE(method_name, callback_f, command_type) MAP_JON_RPC_WE_IF(method_name, callback_f, command_type, true) -#define MAP_JON_RPC_WERI(method_name, callback_f, command_type) \ - else if(callback_name == method_name) \ -{ \ - PREPARE_OBJECTS_FROM_JSON(command_type) \ - epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ - fail_resp.jsonrpc = "2.0"; \ - fail_resp.id = req.id; \ - MINFO(m_conn_context << "calling RPC method " << method_name); \ - bool res = false; \ - try { res = callback_f(req.params, resp.result, fail_resp.error, response_info, &m_conn_context); } \ - catch (const std::exception &e) { MERROR(m_conn_context << "Failed to " << #callback_f << "(): " << e.what()); } \ - if (!res) \ - { \ - epee::serialization::store_t_to_json(static_cast(fail_resp), response_info.m_body); \ - return true; \ - } \ - FINALIZE_OBJECTS_TO_JSON(method_name) \ - return true;\ -} - #define MAP_JON_RPC(method_name, callback_f, command_type) \ else if(callback_name == method_name) \ { \ From 3ee217489220fc9cf27e3c81a743648bfad95126 Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Mon, 23 May 2022 15:52:01 -0500 Subject: [PATCH 016/186] string_coding: unused functions --- contrib/epee/include/string_coding.h | 94 ---------------------------- 1 file changed, 94 deletions(-) diff --git a/contrib/epee/include/string_coding.h b/contrib/epee/include/string_coding.h index 82050ef96bd..0d9c6c244ee 100644 --- a/contrib/epee/include/string_coding.h +++ b/contrib/epee/include/string_coding.h @@ -34,100 +34,6 @@ namespace epee { namespace string_encoding { - inline std::string convert_to_ansii(const std::wstring& str_from) - { - - std::string res(str_from.begin(), str_from.end()); - return res; - /* - std::string result; - std::locale loc; - for(unsigned int i= 0; i < str_from.size(); ++i) - { - result += std::use_facet >(loc).narrow(str_from[i]); - } - return result; - */ - - //return boost::lexical_cast(str_from); - /* - std::string str_trgt; - if(!str_from.size()) - return str_trgt; - int cb = ::WideCharToMultiByte( code_page, 0, str_from.data(), (__int32)str_from.size(), 0, 0, 0, 0 ); - if(!cb) - return str_trgt; - str_trgt.resize(cb); - ::WideCharToMultiByte( code_page, 0, str_from.data(), (int)str_from.size(), - (char*)str_trgt.data(), (int)str_trgt.size(), 0, 0); - return str_trgt;*/ - } - - inline std::string convert_to_ansii(const std::string& str_from) - { - return str_from; - } - - inline std::wstring convert_to_unicode(const std::string& str_from) - { - std::wstring result; - std::locale loc; - for(unsigned int i= 0; i < str_from.size(); ++i) - { - result += std::use_facet >(loc).widen(str_from[i]); - } - return result; - - //return boost::lexical_cast(str_from); - /* - std::wstring str_trgt; - if(!str_from.size()) - return str_trgt; - - int cb = ::MultiByteToWideChar( code_page, 0, str_from.data(), (int)str_from.size(), 0, 0 ); - if(!cb) - return str_trgt; - - str_trgt.resize(cb); - ::MultiByteToWideChar( code_page, 0, str_from.data(),(int)str_from.size(), - (wchar_t*)str_trgt.data(),(int)str_trgt.size()); - return str_trgt;*/ - } - inline std::wstring convert_to_unicode(const std::wstring& str_from) - { - return str_from; - } - - template - inline target_string convert_to_t(const std::wstring& str_from); - - template<> - inline std::string convert_to_t(const std::wstring& str_from) - { - return convert_to_ansii(str_from); - } - - template<> - inline std::wstring convert_to_t(const std::wstring& str_from) - { - return str_from; - } - - template - inline target_string convert_to_t(const std::string& str_from); - - template<> - inline std::string convert_to_t(const std::string& str_from) - { - return str_from; - } - - template<> - inline std::wstring convert_to_t(const std::string& str_from) - { - return convert_to_unicode(str_from); - } - inline std::string& base64_chars() { From 5bb2369b5556637a92164b62e5d739034aac55ac Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 25 May 2022 09:02:27 +0000 Subject: [PATCH 017/186] wallet_rpc_server: add --no-initial-sync flag for quicker network binding --- src/wallet/wallet_rpc_server.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 57baf428fac..c55e6d84a13 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -68,6 +68,7 @@ namespace const command_line::arg_descriptor arg_restricted = {"restricted-rpc", "Restricts to view-only commands", false}; const command_line::arg_descriptor arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"}; const command_line::arg_descriptor arg_prompt_for_password = {"prompt-for-password", "Prompts for password when not provided", false}; + const command_line::arg_descriptor arg_no_initial_sync = {"no-initial-sync", "Skips the initial sync before listening for connections", false}; constexpr const char default_rpc_username[] = "monero"; @@ -4495,6 +4496,7 @@ class t_daemon const auto password_file = command_line::get_arg(vm, arg_password_file); const auto prompt_for_password = command_line::get_arg(vm, arg_prompt_for_password); const auto password_prompt = prompt_for_password ? password_prompter : nullptr; + const auto no_initial_sync = command_line::get_arg(vm, arg_no_initial_sync); if(!wallet_file.empty() && !from_json.empty()) { @@ -4563,7 +4565,8 @@ class t_daemon try { - wal->refresh(wal->is_trusted_daemon()); + if (!no_initial_sync) + wal->refresh(wal->is_trusted_daemon()); } catch (const std::exception& e) { @@ -4674,6 +4677,7 @@ int main(int argc, char** argv) { command_line::add_arg(desc_params, arg_wallet_dir); command_line::add_arg(desc_params, arg_prompt_for_password); command_line::add_arg(desc_params, arg_rpc_client_secret_key); + command_line::add_arg(desc_params, arg_no_initial_sync); daemonizer::init_options(hidden_options, desc_params); desc_params.add(hidden_options); From de2f0d010252ad1abf0f0c8ca9e32d81817c80ab Mon Sep 17 00:00:00 2001 From: selsta Date: Thu, 26 May 2022 03:43:54 +0200 Subject: [PATCH 018/186] wallet_api: add scanTransactions function --- src/wallet/api/wallet.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/wallet/api/wallet.h | 1 + src/wallet/api/wallet2_api.h | 7 +++++++ 3 files changed, 44 insertions(+) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 7cd8656e11a..260caa551a8 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1280,6 +1280,42 @@ bool WalletImpl::importOutputs(const string &filename) return true; } +bool WalletImpl::scanTransactions(const std::vector &txids) +{ + if (txids.empty()) + { + setStatusError(string(tr("Failed to scan transactions: no transaction ids provided."))); + return false; + } + + // Parse and dedup args + std::unordered_set txids_u; + for (const auto &s : txids) + { + crypto::hash txid; + if (!epee::string_tools::hex_to_pod(s, txid)) + { + setStatusError(string(tr("Invalid txid specified: ")) + s); + return false; + } + txids_u.insert(txid); + } + std::vector txids_v(txids_u.begin(), txids_u.end()); + + try + { + m_wallet->scan_tx(txids_v); + } + catch (const std::exception &e) + { + LOG_ERROR("Failed to scan transaction: " << e.what()); + setStatusError(string(tr("Failed to scan transaction: ")) + e.what()); + return false; + } + + return true; +} + void WalletImpl::addSubaddressAccount(const std::string& label) { m_wallet->add_subaddress_account(label); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 0e61ee330ac..018b2a0ed9a 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -169,6 +169,7 @@ class WalletImpl : public Wallet bool importKeyImages(const std::string &filename) override; bool exportOutputs(const std::string &filename, bool all = false) override; bool importOutputs(const std::string &filename) override; + bool scanTransactions(const std::vector &txids) override; virtual void disposeTransaction(PendingTransaction * t) override; virtual uint64_t estimateTransactionFee(const std::vector> &destinations, diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index c6f81f0e4a1..b67bce60cf6 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -927,6 +927,13 @@ struct Wallet */ virtual bool importOutputs(const std::string &filename) = 0; + /*! + * \brief scanTransactions - scan a list of transaction ids, this operation may reveal the txids to the remote node and affect your privacy + * \param txids - list of transaction ids + * \return - true on success + */ + virtual bool scanTransactions(const std::vector &txids) = 0; + virtual TransactionHistory * history() = 0; virtual AddressBook * addressBook() = 0; virtual Subaddress * subaddress() = 0; From bc05d2dfa8ea68fbcb99ce62150154c63aa1a018 Mon Sep 17 00:00:00 2001 From: garth-xmr <87672640+garth-xmr@users.noreply.github.com> Date: Thu, 26 May 2022 19:20:51 +0000 Subject: [PATCH 019/186] README.md: Add v15/v16 network upgrade Remade #8270 (includes edits from UkoeHB) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b3422280d61..a2c2788734a 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,8 @@ Dates are provided in the format YYYY-MM-DD. | 1978433 | 2019-11-30 | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs | 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.3.2 | New CLSAG transaction format | 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.3.2 | forbid old MLSAG transaction format +| 2668888 | 2022-07-16 | v15 | v0.18.0.0 | v0.18.0.0 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm +| 2669608 | 2022-07-17 | v16 | v0.18.0.0 | v0.18.0.0 | forbid old v14 transaction format | XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX | X's indicate that these details have not been determined as of commit date. From fb3f7cebbfc3d41a4186d5f7560dd7f7769517bb Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Fri, 27 May 2022 19:48:59 -0500 Subject: [PATCH 020/186] clang warning fix for #8338 Unlike some other warnings, clang does not have a `stringop-overflow` group so it doesn't recognize the `#pragma GCC ...` directive in #8338 --- external/boost/archive/portable_binary_archive.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/external/boost/archive/portable_binary_archive.hpp b/external/boost/archive/portable_binary_archive.hpp index cdbd38aad5d..b1d6ae73e6d 100644 --- a/external/boost/archive/portable_binary_archive.hpp +++ b/external/boost/archive/portable_binary_archive.hpp @@ -44,12 +44,16 @@ reverse_bytes(signed char size, char *address){ char * first = address; char * last = first + size - 1; for(;first < last;++first, --last){ +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-overflow=" +#endif char x = *last; *last = *first; *first = x; +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop +#endif } } From da0715e503f5a5a5f9c8fcf4f81c01a423aab6ab Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Wed, 1 Jun 2022 18:20:11 -0400 Subject: [PATCH 021/186] Improve consistency between on_money_received and on_money_received_unconfirmed unconfirmed solely uses a - b, and received now accepts b so it can provide more detailed logs on what occurred (printing a - b, yet with a and b). --- src/simplewallet/simplewallet.cpp | 8 ++++++-- src/simplewallet/simplewallet.h | 2 +- src/wallet/api/wallet.cpp | 8 +++++--- src/wallet/wallet2.cpp | 7 ++++--- src/wallet/wallet2.h | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index f6e313089e7..41a11b53c43 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -5673,14 +5673,18 @@ void simple_wallet::on_new_block(uint64_t height, const cryptonote::block& block m_refresh_progress_reporter.update(height, false); } //---------------------------------------------------------------------------------------------------- -void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) +void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) { if (m_locked) return; + std::stringstream burn; + if (burnt != 0) { + burn << " (" << print_money(amount) << " yet " << print_money(burnt) << " was burnt)"; + } message_writer(console_color_green, false) << "\r" << tr("Height ") << height << ", " << tr("txid ") << txid << ", " << - print_money(amount) << ", " << + print_money(amount - burnt) << burn.str() << ", " << tr("idx ") << subaddr_index; const uint64_t warn_height = m_wallet->nettype() == TESTNET ? 1000000 : m_wallet->nettype() == STAGENET ? 50000 : 1650000; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 6c4ddd4e75b..6a9fa149d7a 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -346,7 +346,7 @@ namespace cryptonote //----------------- i_wallet2_callback --------------------- virtual void on_new_block(uint64_t height, const cryptonote::block& block); - virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time); + virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time); virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index); virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index); virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx); diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 7cd8656e11a..fdf55ae2183 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -154,18 +154,20 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback } } - virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) + virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) { std::string tx_hash = epee::string_tools::pod_to_hex(txid); LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height << ", tx: " << tx_hash - << ", amount: " << print_money(amount) + << ", amount: " << print_money(amount - burnt), + << ", burnt: " << print_money(burnt), + << ", raw_output_value: " << print_money(amount), << ", idx: " << subaddr_index); // do not signal on received tx if wallet is not syncronized completely if (m_listener && m_wallet->synchronized()) { - m_listener->moneyReceived(tx_hash, amount); + m_listener->moneyReceived(tx_hash, amount - burnt); m_listener->updated(); } } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b2a6c0f5a2..37f7e29c50b 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2208,7 +2208,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid); if (0 != m_callback) - m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time); + m_callback->on_money_received(height, txid, tx, td.m_amount, 0, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time); } total_received_1 += amount; notify = true; @@ -2242,7 +2242,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote tx_money_got_in_outs[tx_scan_info[o].received->index] -= m_transfers[kit->second].amount(); uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount; - uint64_t extra_amount = amount - m_transfers[kit->second].amount(); + uint64_t burnt = m_transfers[kit->second].amount(); + uint64_t extra_amount = amount - burnt; if (!pool) { transfer_details &td = m_transfers[kit->second]; @@ -2285,7 +2286,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid); if (0 != m_callback) - m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time); + m_callback->on_money_received(height, txid, tx, td.m_amount, burnt, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time); } total_received_1 += extra_amount; notify = true; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e051946add2..fbea1b46f27 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -137,7 +137,7 @@ namespace tools public: // Full wallet callbacks virtual void on_new_block(uint64_t height, const cryptonote::block& block) {} - virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) {} + virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) {} virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {} virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index) {} virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx) {} From 16f8e042b5af06bc5ef194eaabaf4df0f27fbe1c Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Wed, 1 Jun 2022 19:38:42 -0400 Subject: [PATCH 022/186] Remove erraneous commas --- src/wallet/api/wallet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index fdf55ae2183..f8ab2438399 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -161,9 +161,9 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height << ", tx: " << tx_hash - << ", amount: " << print_money(amount - burnt), - << ", burnt: " << print_money(burnt), - << ", raw_output_value: " << print_money(amount), + << ", amount: " << print_money(amount - burnt) + << ", burnt: " << print_money(burnt) + << ", raw_output_value: " << print_money(amount) << ", idx: " << subaddr_index); // do not signal on received tx if wallet is not syncronized completely if (m_listener && m_wallet->synchronized()) { From 23fde151ee0d27a48f350f67893d548c21f82583 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 25 May 2022 09:30:58 +0000 Subject: [PATCH 023/186] wallet_rpc_server: chunk refresh to keep responding to RPC while refreshing --- src/wallet/wallet2.cpp | 4 ++-- src/wallet/wallet2.h | 2 +- src/wallet/wallet_rpc_server.cpp | 10 ++++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1eeb893c0a3..9efbcfac68e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3360,7 +3360,7 @@ std::shared_ptr, size_t>> wallet2::create return cache; } //---------------------------------------------------------------------------------------------------- -void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money, bool check_pool) +void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money, bool check_pool, uint64_t max_blocks) { if (m_offline) { @@ -3452,7 +3452,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo update_pool_state(process_pool_txs, true); bool first = true, last = false; - while(m_run.load(std::memory_order_relaxed)) + while(m_run.load(std::memory_order_relaxed) && blocks_fetched < max_blocks) { uint64_t next_blocks_start_height; std::vector next_blocks; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e9e5bc95e3a..2b2e5041065 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -974,7 +974,7 @@ namespace tools bool is_deprecated() const; void refresh(bool trusted_daemon); void refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched); - void refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money, bool check_pool = true); + void refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money, bool check_pool = true, uint64_t max_blocks = std::numeric_limits::max()); bool refresh(bool trusted_daemon, uint64_t & blocks_fetched, bool& received_money, bool& ok); void set_refresh_type(RefreshType refresh_type) { m_refresh_type = refresh_type; } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index c55e6d84a13..32f79aa7f89 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -60,6 +60,7 @@ using namespace epee; #define MONERO_DEFAULT_LOG_CATEGORY "wallet.rpc" #define DEFAULT_AUTO_REFRESH_PERIOD 20 // seconds +#define REFRESH_INFICATIVE_BLOCK_CHUNK_SIZE 256 // just to split refresh in separate calls to play nicer with other threads namespace { @@ -139,12 +140,17 @@ namespace tools return true; if (boost::posix_time::microsec_clock::universal_time() < m_last_auto_refresh_time + boost::posix_time::seconds(m_auto_refresh_period)) return true; + uint64_t blocks_fetched = 0; try { - if (m_wallet) m_wallet->refresh(m_wallet->is_trusted_daemon()); + bool received_money = false; + if (m_wallet) m_wallet->refresh(m_wallet->is_trusted_daemon(), 0, blocks_fetched, received_money, true, REFRESH_INFICATIVE_BLOCK_CHUNK_SIZE); } catch (const std::exception& ex) { LOG_ERROR("Exception at while refreshing, what=" << ex.what()); } - m_last_auto_refresh_time = boost::posix_time::microsec_clock::universal_time(); + // if we got the max amount of blocks, do not set the last refresh time, we did only part of the refresh and will + // continue asap, and only set the last refresh time once the refresh is actually finished + if (blocks_fetched < REFRESH_INFICATIVE_BLOCK_CHUNK_SIZE) + m_last_auto_refresh_time = boost::posix_time::microsec_clock::universal_time(); return true; }, 1000); m_net_server.add_idle_handler([this](){ From 747f5d3594566e4a9f56595cfd0feef7004e3485 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 21 Feb 2016 18:29:40 +0000 Subject: [PATCH 024/186] Preliminary raw partition support Autodetects that a block device is being used. --- external/db_drivers/liblmdb/mdb.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c index 6314d577546..0d01d295978 100644 --- a/external/db_drivers/liblmdb/mdb.c +++ b/external/db_drivers/liblmdb/mdb.c @@ -1473,6 +1473,8 @@ struct MDB_env { #define MDB_ENV_TXKEY 0x10000000U /** fdatasync is unreliable */ #define MDB_FSYNCONLY 0x08000000U + /** using a raw block device */ +#define MDB_RAWPART 0x04000000U uint32_t me_flags; /**< @ref mdb_env */ unsigned int me_psize; /**< DB page size, inited from me_os_psize */ unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */ @@ -4081,6 +4083,8 @@ mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta) p = (MDB_page *)&pbuf; if (!F_ISSET(p->mp_flags, P_META)) { + if (env->me_flags & MDB_RAWPART) + return ENOENT; DPRINTF(("page %"Yu" not a meta page", p->mp_pgno)); return MDB_INVALID; } @@ -4410,7 +4414,7 @@ mdb_env_map(MDB_env *env, void *addr) int prot = PROT_READ; if (flags & MDB_WRITEMAP) { prot |= PROT_WRITE; - if (ftruncate(env->me_fd, env->me_mapsize) < 0) + if (!(flags & MDB_RAWPART) && ftruncate(env->me_fd, env->me_mapsize) < 0) return ErrCode(); } env->me_map = mmap(addr, env->me_mapsize, prot, MAP_SHARED, @@ -5448,6 +5452,17 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode if (rc) goto leave; #endif +#endif +#ifndef _WIN32 + { + struct stat st; + rc = stat(path, &st); + if (rc) + return ErrCode(); + flags &= ~MDB_RAWPART; + if (S_ISBLK(st.st_mode)) + flags |= MDB_RAWPART | MDB_NOSUBDIR; + } #endif flags |= MDB_ENV_ACTIVE; /* tell mdb_env_close0() to clean up */ From 4e7586c9e41689b116108b806ab322b30f771082 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 11 Jun 2018 10:12:03 +0100 Subject: [PATCH 025/186] More RAWPART support Use mmap to read and initialize the meta pages, raw device may not support read/write syscalls. --- external/db_drivers/liblmdb/mdb.c | 44 ++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c index 0d01d295978..52ad844e9eb 100644 --- a/external/db_drivers/liblmdb/mdb.c +++ b/external/db_drivers/liblmdb/mdb.c @@ -4040,6 +4040,8 @@ mdb_txn_commit(MDB_txn *txn) return rc; } +static int ESECT mdb_env_map(MDB_env *env, void *addr); + /** Read the environment parameters of a DB environment before * mapping it into memory. * @param[in] env the environment handle @@ -4056,6 +4058,31 @@ mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta) int i, rc, off; enum { Size = sizeof(pbuf) }; + if (env->me_flags & MDB_RAWPART) { +#define VM_ALIGN 0x200000 + env->me_mapsize += VM_ALIGN-1; + env->me_mapsize &= ~(VM_ALIGN-1); + env->me_psize = env->me_os_psize; + rc = mdb_env_map(env, NULL); + if (rc) { + DPRINTF(("mdb_env_map: %s", mdb_strerror(rc))); + return rc; + } + p = (MDB_page *)env->me_map; + for (i=0; imp_flags, P_META)) + return ENOENT; + if (env->me_metas[i]->mm_magic != MDB_MAGIC) + return MDB_INVALID; + if (env->me_metas[i]->mm_version != MDB_DATA_VERSION) + return MDB_VERSION_MISMATCH; + if (i == 0 || env->me_metas[i]->mm_txnid > meta->mm_txnid) + *meta = *env->me_metas[i]; + p = (MDB_page *)((char *)p + env->me_psize); + } + return 0; + } + /* We don't know the page size yet, so use a minimum value. * Read both meta pages so we can use the latest one. */ @@ -4152,6 +4179,18 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta) psize = env->me_psize; + if ((env->me_flags & (MDB_RAWPART|MDB_WRITEMAP)) == (MDB_RAWPART|MDB_WRITEMAP)) { + p = (MDB_page *)env->me_map; + p->mp_pgno = 0; + p->mp_flags = P_META; + *(MDB_meta *)METADATA(p) = *meta; + q = (MDB_page *)((char *)p + psize); + q->mp_pgno = 1; + q->mp_flags = P_META; + *(MDB_meta *)METADATA(q) = *meta; + return 0; + } + p = calloc(NUM_METAS, psize); if (!p) return ENOMEM; @@ -5460,8 +5499,11 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode if (rc) return ErrCode(); flags &= ~MDB_RAWPART; - if (S_ISBLK(st.st_mode)) + if (S_ISBLK(st.st_mode)) { flags |= MDB_RAWPART | MDB_NOSUBDIR; + if (!env->me_mapsize) + env->me_mapsize = DEFAULT_MAPSIZE; + } } #endif flags |= MDB_ENV_ACTIVE; /* tell mdb_env_close0() to clean up */ From b46a60e3907c597b8b4b272eca357d38534f5e40 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 11 Oct 2020 01:32:30 +0100 Subject: [PATCH 026/186] Fix rawpart flag collision --- external/db_drivers/liblmdb/mdb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c index 52ad844e9eb..c30a8e52a72 100644 --- a/external/db_drivers/liblmdb/mdb.c +++ b/external/db_drivers/liblmdb/mdb.c @@ -1467,14 +1467,14 @@ struct MDB_env { #endif /** Failed to update the meta page. Probably an I/O error. */ #define MDB_FATAL_ERROR 0x80000000U + /** using a raw block device */ +#define MDB_RAWPART 0x40000000U /** Some fields are initialized. */ #define MDB_ENV_ACTIVE 0x20000000U /** me_txkey is set */ #define MDB_ENV_TXKEY 0x10000000U /** fdatasync is unreliable */ #define MDB_FSYNCONLY 0x08000000U - /** using a raw block device */ -#define MDB_RAWPART 0x04000000U uint32_t me_flags; /**< @ref mdb_env */ unsigned int me_psize; /**< DB page size, inited from me_os_psize */ unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */ From 493577a6cd016ee56465f5adb8e1dc8f10f2daa5 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 7 Jul 2021 12:26:18 +0100 Subject: [PATCH 027/186] Silence spurious fallthru warning --- external/db_drivers/liblmdb/mdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c index c30a8e52a72..f29a75de801 100644 --- a/external/db_drivers/liblmdb/mdb.c +++ b/external/db_drivers/liblmdb/mdb.c @@ -7725,7 +7725,7 @@ mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data, offset *= 4; /* space for 4 more */ break; } - /* FALLTHRU: Big enough MDB_DUPFIXED sub-page */ + /* FALLTHRU *//* Big enough MDB_DUPFIXED sub-page */ case MDB_CURRENT: fp->mp_flags |= P_DIRTY; COPY_PGNO(fp->mp_pgno, mp->mp_pgno); From b096e16699a189d619dad8a7319c6eb4dc5d46c5 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 7 Jul 2021 16:26:35 +0100 Subject: [PATCH 028/186] Revert "db_lmdb: test for mmap support at init time" This reverts commit bd96536637724413173271e8d5df1777f7879c29. The check interferes with raw device/partition support. --- src/blockchain_db/lmdb/db_lmdb.cpp | 30 ------------------------------ src/blockchain_db/lmdb/db_lmdb.h | 1 - 2 files changed, 31 deletions(-) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index e2ac9df0b48..01f91209d83 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -25,13 +25,6 @@ // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef _WIN32 -#include -#include -#include -#include -#endif - #include "db_lmdb.h" #include @@ -1303,26 +1296,6 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB() m_hardfork = nullptr; } -void BlockchainLMDB::check_mmap_support() -{ -#ifndef _WIN32 - const boost::filesystem::path mmap_test_file = m_folder / boost::filesystem::unique_path(); - int mmap_test_fd = ::open(mmap_test_file.string().c_str(), O_RDWR | O_CREAT, 0600); - if (mmap_test_fd < 0) - throw0(DB_ERROR((std::string("Failed to check for mmap support: open failed: ") + strerror(errno)).c_str())); - epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([mmap_test_fd, &mmap_test_file]() { - ::close(mmap_test_fd); - boost::filesystem::remove(mmap_test_file.string()); - }); - if (write(mmap_test_fd, "mmaptest", 8) != 8) - throw0(DB_ERROR((std::string("Failed to check for mmap support: write failed: ") + strerror(errno)).c_str())); - void *mmap_res = mmap(NULL, 8, PROT_READ, MAP_SHARED, mmap_test_fd, 0); - if (mmap_res == MAP_FAILED) - throw0(DB_ERROR("This filesystem does not support mmap: use --data-dir to place the blockchain on a filesystem which does")); - munmap(mmap_res, 8); -#endif -} - void BlockchainLMDB::open(const std::string& filename, const int db_flags) { int result; @@ -1364,9 +1337,6 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) m_folder = filename; - try { check_mmap_support(); } - catch(...) { MERROR("Failed to check for mmap support, proceeding"); } - #ifdef __OpenBSD__ if ((mdb_flags & MDB_WRITEMAP) == 0) { MCLOG_RED(el::Level::Info, "global", "Running on OpenBSD: forcing WRITEMAP"); diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index 20edab2e9a0..bdae44948d3 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -359,7 +359,6 @@ class BlockchainLMDB : public BlockchainDB static int compare_string(const MDB_val *a, const MDB_val *b); private: - void check_mmap_support(); void do_resize(uint64_t size_increase=0); bool need_resize(uint64_t threshold_size=0) const; From 033a32a20b100d8159a95da832e695e7b953de24 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 7 Jul 2021 16:28:27 +0100 Subject: [PATCH 029/186] Remove check is_directory check on lmdb path The check interferes with raw device/partition support. --- src/blockchain_db/lmdb/db_lmdb.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 01f91209d83..db7fa6c7c61 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -1307,14 +1307,8 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) throw0(DB_OPEN_FAILURE("Attempted to open db, but it's already open")); boost::filesystem::path direc(filename); - if (boost::filesystem::exists(direc)) - { - if (!boost::filesystem::is_directory(direc)) - throw0(DB_OPEN_FAILURE("LMDB needs a directory path, but a file was passed")); - } - else - { - if (!boost::filesystem::create_directories(direc)) + if (!boost::filesystem::exists(direc) && + !boost::filesystem::create_directories(direc)) { throw0(DB_OPEN_FAILURE(std::string("Failed to create directory ").append(filename).c_str())); } From ade464a5a0adaa166171f803078e9ac31b99bb06 Mon Sep 17 00:00:00 2001 From: Kris Zyp Date: Mon, 2 Nov 2020 20:33:09 +0000 Subject: [PATCH 030/186] ITS#9385 fix using MDB_NOSUBDIR with nonexistent file --- external/db_drivers/liblmdb/mdb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c index f29a75de801..bf60c70133c 100644 --- a/external/db_drivers/liblmdb/mdb.c +++ b/external/db_drivers/liblmdb/mdb.c @@ -5495,11 +5495,8 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode #ifndef _WIN32 { struct stat st; - rc = stat(path, &st); - if (rc) - return ErrCode(); flags &= ~MDB_RAWPART; - if (S_ISBLK(st.st_mode)) { + if (!stat(path, &st) && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) { flags |= MDB_RAWPART | MDB_NOSUBDIR; if (!env->me_mapsize) env->me_mapsize = DEFAULT_MAPSIZE; From 61d0712ed508127edf5216a215f81affaec37ea8 Mon Sep 17 00:00:00 2001 From: mj-xmr <63722585+mj-xmr@users.noreply.github.com> Date: Wed, 27 Apr 2022 06:41:15 +0200 Subject: [PATCH 031/186] Gitian: refresh the stale Monero dir via --setup switch --- contrib/gitian/README.md | 3 ++- contrib/gitian/gitian-build.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md index 9852b07ba35..24cf26fa37a 100644 --- a/contrib/gitian/README.md +++ b/contrib/gitian/README.md @@ -133,10 +133,11 @@ Common setup part: su - gitianuser GH_USER=YOUR_GITHUB_USER_NAME -VERSION=v0.17.2.0 +VERSION=v0.17.3.2 ``` Where `GH_USER` is your GitHub user name and `VERSION` is the version tag you want to build. +The `gitian-build.py`'s `--setup` switch will also refresh the environment of any stale files and submodules. Setup for LXC: diff --git a/contrib/gitian/gitian-build.py b/contrib/gitian/gitian-build.py index 859c2c645a0..859f460a78b 100755 --- a/contrib/gitian/gitian-build.py +++ b/contrib/gitian/gitian-build.py @@ -31,8 +31,10 @@ def setup(): subprocess.check_call(['git', 'checkout', 'c0f77ca018cb5332bfd595e0aff0468f77542c23']) os.makedirs('inputs', exist_ok=True) os.chdir('inputs') - if not os.path.isdir('monero'): - subprocess.check_call(['git', 'clone', args.url, 'monero']) + if os.path.isdir('monero'): + # Remove the potentially stale monero dir. Otherwise you might face submodule mismatches. + subprocess.check_call(['rm', 'monero', '-fR']) + subprocess.check_call(['git', 'clone', args.url, 'monero']) os.chdir('..') make_image_prog = ['bin/make-base-vm', '--suite', 'bionic', '--arch', 'amd64'] if args.docker: From 8460fcc32bfb381aa47dfe5293c5ad7dcc539361 Mon Sep 17 00:00:00 2001 From: j-berman Date: Mon, 13 Jun 2022 18:44:09 +0100 Subject: [PATCH 032/186] Revert "Merge pull request #7937" This reverts commit 50410d1f7d04bf60053f2263410c39e81d3ddad1, reversing changes made to d054def63f9b8950fe20b2d8e841f5a9ae09418f. --- src/rpc/core_rpc_server.cpp | 50 +++++++++++-------------------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 0fe28465f8b..5304333ffa6 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -492,7 +492,6 @@ namespace cryptonote } CHECK_PAYMENT_MIN1(req, res, COST_PER_GET_INFO, false); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); const bool restricted = m_restricted && ctx; @@ -598,7 +597,6 @@ namespace cryptonote } CHECK_PAYMENT(req, res, 1); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); // quick check for noop if (!req.block_ids.empty()) @@ -609,7 +607,7 @@ namespace cryptonote if (last_block_hash == req.block_ids.front()) { res.start_height = 0; - res.current_height = last_block_height + 1; + res.current_height = m_core.get_current_blockchain_height(); res.status = CORE_RPC_STATUS_OK; return true; } @@ -730,7 +728,6 @@ namespace cryptonote res.blocks.clear(); res.blocks.reserve(req.heights.size()); CHECK_PAYMENT_MIN1(req, res, req.heights.size() * COST_PER_BLOCK, false); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); for (uint64_t height : req.heights) { block blk; @@ -1592,7 +1589,6 @@ namespace cryptonote return r; CHECK_PAYMENT(req, res, 1); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); const bool restricted = m_restricted && ctx; const bool request_has_rpc_origin = ctx != NULL; @@ -1617,7 +1613,6 @@ namespace cryptonote return r; CHECK_PAYMENT(req, res, 1); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); const bool restricted = m_restricted && ctx; const bool request_has_rpc_origin = ctx != NULL; @@ -1720,14 +1715,11 @@ namespace cryptonote error_resp.message = "Wrong parameters, expected height"; return false; } - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); uint64_t h = req[0]; - uint64_t blockchain_height = m_core.get_current_blockchain_height(); - if(blockchain_height <= h) + if(m_core.get_current_blockchain_height() <= h) { error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; - error_resp.message = std::string("Requested block height: ") + std::to_string(h) + " greater than current top block height: " + std::to_string(blockchain_height - 1); - return false; + error_resp.message = std::string("Requested block height: ") + std::to_string(h) + " greater than current top block height: " + std::to_string(m_core.get_current_blockchain_height() - 1); } res = string_tools::pod_to_hex(m_core.get_block_id_by_height(h)); return true; @@ -1877,7 +1869,6 @@ namespace cryptonote return false; } } - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); crypto::hash seed_hash, next_seed_hash; if (!get_block_template(info.address, req.prev_block.empty() ? NULL : &prev_block, blob_reserve, reserved_offset, wdiff, res.height, res.expected_reward, b, res.seed_height, seed_hash, next_seed_hash, error_resp)) return false; @@ -2351,7 +2342,6 @@ namespace cryptonote CHECK_CORE_READY(); CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); uint64_t last_block_height; crypto::hash last_block_hash; m_core.get_blockchain_top(last_block_height, last_block_hash); @@ -2392,8 +2382,6 @@ namespace cryptonote return false; } - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); - auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool { crypto::hash block_hash; bool hash_parsed = parse_hash256(hash, block_hash); @@ -2453,6 +2441,13 @@ namespace cryptonote if (use_bootstrap_daemon_if_necessary(invoke_http_mode::JON_RPC, "getblockheadersrange", req, res, r)) return r; + const uint64_t bc_height = m_core.get_current_blockchain_height(); + if (req.start_height >= bc_height || req.end_height >= bc_height || req.start_height > req.end_height) + { + error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; + error_resp.message = "Invalid start/end heights."; + return false; + } const bool restricted = m_restricted && ctx; if (restricted && req.end_height - req.start_height > RESTRICTED_BLOCK_HEADER_RANGE) { @@ -2462,16 +2457,6 @@ namespace cryptonote } CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); - - const uint64_t bc_height = m_core.get_current_blockchain_height(); - if (req.start_height >= bc_height || req.end_height >= bc_height || req.start_height > req.end_height) - { - error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; - error_resp.message = "Invalid start/end heights."; - return false; - } - for (uint64_t h = req.start_height; h <= req.end_height; ++h) { crypto::hash block_hash = m_core.get_block_id_by_height(h); @@ -2516,12 +2501,10 @@ namespace cryptonote if (use_bootstrap_daemon_if_necessary(invoke_http_mode::JON_RPC, "getblockheaderbyheight", req, res, r)) return r; - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); - uint64_t blockchain_height = m_core.get_current_blockchain_height(); - if(blockchain_height <= req.height) + if(m_core.get_current_blockchain_height() <= req.height) { error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; - error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(blockchain_height - 1); + error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(m_core.get_current_blockchain_height() - 1); return false; } CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false); @@ -2554,7 +2537,6 @@ namespace cryptonote return r; CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK, false); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); crypto::hash block_hash; if (!req.hash.empty()) @@ -2569,11 +2551,10 @@ namespace cryptonote } else { - uint64_t blockchain_height = m_core.get_current_blockchain_height(); - if(blockchain_height <= req.height) + if(m_core.get_current_blockchain_height() <= req.height) { error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; - error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(blockchain_height - 1); + error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(m_core.get_current_blockchain_height() - 1); return false; } block_hash = m_core.get_block_id_by_height(req.height); @@ -2881,7 +2862,6 @@ namespace cryptonote bool core_rpc_server::on_get_coinbase_tx_sum(const COMMAND_RPC_GET_COINBASE_TX_SUM::request& req, COMMAND_RPC_GET_COINBASE_TX_SUM::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx) { RPC_TRACKER(get_coinbase_tx_sum); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); const uint64_t bc_height = m_core.get_current_blockchain_height(); if (req.height >= bc_height || req.count > bc_height) { @@ -2923,7 +2903,6 @@ namespace cryptonote bool core_rpc_server::on_get_alternate_chains(const COMMAND_RPC_GET_ALTERNATE_CHAINS::request& req, COMMAND_RPC_GET_ALTERNATE_CHAINS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx) { RPC_TRACKER(get_alternate_chains); - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); try { std::vector>> chains = m_core.get_blockchain_storage().get_alternative_chains(); @@ -3226,7 +3205,6 @@ namespace cryptonote bool r; if (use_bootstrap_daemon_if_necessary(invoke_http_mode::JON_RPC, "get_txpool_backlog", req, res, r)) return r; - db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db()); size_t n_txes = m_core.get_pool_transactions_count(); CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_POOL_STATS * n_txes, false); From 552528b0eae75ac16eb456102aa22422d84fc5d6 Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Fri, 17 Jun 2022 00:27:06 -0500 Subject: [PATCH 033/186] Remove async_blocked_mode_client --- contrib/epee/include/net/net_helper.h | 113 -------------------------- 1 file changed, 113 deletions(-) diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 0a35797fddf..ee344561df4 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -688,119 +688,6 @@ namespace net_utils std::atomic m_bytes_sent; std::atomic m_bytes_received; }; - - - /************************************************************************/ - /* */ - /************************************************************************/ - class async_blocked_mode_client: public blocked_mode_client - { - public: - async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service) - { - - // No deadline is required until the first socket operation is started. We - // set the deadline to positive infinity so that the actor takes no action - // until a specific deadline is set. - m_send_deadline.expires_at(boost::posix_time::pos_infin); - - // Start the persistent actor that checks for deadline expiry. - check_send_deadline(); - } - ~async_blocked_mode_client() - { - m_send_deadline.cancel(); - } - - bool shutdown() - { - blocked_mode_client::shutdown(); - m_send_deadline.cancel(); - return true; - } - - inline - bool send(const void* data, size_t sz) - { - try - { - /* - m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - boost::system::error_code ec = boost::asio::error::would_block; - - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); - - // Block until the asynchronous operation has completed. - while(ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - }*/ - - boost::system::error_code ec; - - size_t writen = write(data, sz, ec); - - if (!writen || ec) - { - LOG_PRINT_L3("Problems at write: " << ec.message()); - return false; - }else - { - m_send_deadline.expires_at(boost::posix_time::pos_infin); - } - } - - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at connect, message: " << er.what()); - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems."); - return false; - } - - return true; - } - - - private: - - boost::asio::deadline_timer m_send_deadline; - - void check_send_deadline() - { - // Check whether the deadline has passed. We compare the deadline against - // the current time since a new asynchronous operation may have moved the - // deadline before this actor had a chance to run. - if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) - { - // The deadline has passed. The socket is closed so that any outstanding - // asynchronous operations are cancelled. This allows the blocked - // connect(), read_line() or write_line() functions to return. - LOG_PRINT_L3("Timed out socket"); - m_ssl_socket->next_layer().close(); - - // There is no longer an active deadline. The expiry is set to positive - // infinity so that the actor takes no action until a new deadline is set. - m_send_deadline.expires_at(boost::posix_time::pos_infin); - } - - // Put the actor back to sleep. - m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this)); - } - }; } } From 41b1a6b0dd3386a8d70095ab811bc31c03c05d58 Mon Sep 17 00:00:00 2001 From: "hinto.janaiyo" Date: Sat, 18 Jun 2022 10:13:02 -0400 Subject: [PATCH 034/186] simplewallet: print usage when given no args --- src/simplewallet/simplewallet.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index f6e313089e7..c1ecf1af9e6 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6960,18 +6960,33 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector &args_) { + if (args_.size() < 1) + { + PRINT_USAGE(USAGE_TRANSFER); + return true; + } transfer_main(Transfer, args_, false); return true; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::locked_transfer(const std::vector &args_) { + if (args_.size() < 1) + { + PRINT_USAGE(USAGE_LOCKED_TRANSFER); + return true; + } transfer_main(TransferLocked, args_, false); return true; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::locked_sweep_all(const std::vector &args_) { + if (args_.size() < 1) + { + PRINT_USAGE(USAGE_LOCKED_SWEEP_ALL); + return true; + } sweep_main(m_current_subaddress_account, 0, true, args_); return true; } @@ -7670,6 +7685,7 @@ bool simple_wallet::sweep_below(const std::vector &args_) if (args_.size() < 1) { fail_msg_writer() << tr("missing threshold amount"); + PRINT_USAGE(USAGE_SWEEP_BELOW); return true; } if (!cryptonote::parse_amount(below, args_[0])) From a0df140fd641c46878a3086dbf5a3cd62aa2f9ec Mon Sep 17 00:00:00 2001 From: Dusan Klinec Date: Tue, 12 Apr 2022 02:06:19 +0200 Subject: [PATCH 035/186] feat(trezor): add HF15 support, BP+ - BP+ support added for Trezor - old Trezor firmware version support removed, code cleanup --- src/device_trezor/device_trezor.cpp | 28 +--- src/device_trezor/trezor/protocol.cpp | 225 +++++++++++--------------- src/device_trezor/trezor/protocol.hpp | 45 ++++-- tests/core_tests/chaingen.cpp | 2 +- tests/trezor/trezor_tests.cpp | 94 +++++++++-- tests/trezor/trezor_tests.h | 17 +- 6 files changed, 231 insertions(+), 180 deletions(-) diff --git a/src/device_trezor/device_trezor.cpp b/src/device_trezor/device_trezor.cpp index 6f7ae9a6b09..58c36f2c917 100644 --- a/src/device_trezor/device_trezor.cpp +++ b/src/device_trezor/device_trezor.cpp @@ -324,8 +324,8 @@ namespace trezor { std::vector mtds; std::vector kis; - protocol::ki::key_image_data(wallet, transfers, mtds, client_version() <= 1); - protocol::ki::generate_commitment(mtds, transfers, req, client_version() <= 1); + protocol::ki::key_image_data(wallet, transfers, mtds); + protocol::ki::generate_commitment(mtds, transfers, req); EVENT_PROGRESS(0.); this->set_msg_addr(req.get()); @@ -635,11 +635,7 @@ namespace trezor { } // Step: sort - auto perm_req = signer->step_permutation(); - if (perm_req){ - auto perm_ack = this->client_exchange(perm_req); - signer->step_permutation_ack(perm_ack); - } + signer->sort_ki(); EVENT_PROGRESS(3, 1, 1); // Step: input_vini @@ -697,13 +693,13 @@ namespace trezor { unsigned device_trezor::client_version() { auto trezor_version = get_version(); - if (trezor_version <= pack_version(2, 0, 10)){ - throw exc::TrezorException("Trezor firmware 2.0.10 and lower are not supported. Please update."); + if (trezor_version < pack_version(2, 4, 3)){ + throw exc::TrezorException("Minimal Trezor firmware version is 2.4.3. Please update."); } - unsigned client_version = 1; - if (trezor_version >= pack_version(2, 3, 1)){ - client_version = 3; + unsigned client_version = 3; + if (trezor_version >= pack_version(2, 5, 2)){ + client_version = 4; } #ifdef WITH_TREZOR_DEBUGGING @@ -739,14 +735,6 @@ namespace trezor { CHECK_AND_ASSERT_THROW_MES(init_msg, "TransactionInitRequest is empty"); CHECK_AND_ASSERT_THROW_MES(init_msg->has_tsx_data(), "TransactionInitRequest has no transaction data"); CHECK_AND_ASSERT_THROW_MES(m_features, "Device state not initialized"); // make sure the caller did not reset features - const bool nonce_required = init_msg->tsx_data().has_payment_id() && init_msg->tsx_data().payment_id().size() > 0; - - if (nonce_required && init_msg->tsx_data().payment_id().size() == 8){ - // Versions 2.0.9 and lower do not support payment ID - if (get_version() <= pack_version(2, 0, 9)) { - throw exc::TrezorException("Trezor firmware 2.0.9 and lower does not support transactions with short payment IDs or integrated addresses. Please update."); - } - } } void device_trezor::transaction_check(const protocol::tx::TData & tdata, const hw::tx_aux_data & aux_data) diff --git a/src/device_trezor/trezor/protocol.cpp b/src/device_trezor/trezor/protocol.cpp index a400e82c7ed..0e59a16ba54 100644 --- a/src/device_trezor/trezor/protocol.cpp +++ b/src/device_trezor/trezor/protocol.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "cryptonote_config.h" #include #include @@ -145,8 +146,7 @@ namespace ki { bool key_image_data(wallet_shim * wallet, const std::vector & transfers, - std::vector & res, - bool need_all_additionals) + std::vector & res) { for(auto & td : transfers){ ::crypto::public_key tx_pub_key = wallet->get_tx_pub_key_from_received_outs(td); @@ -159,11 +159,7 @@ namespace ki { cres.set_internal_output_index(td.m_internal_output_index); cres.set_sub_addr_major(td.m_subaddr_index.major); cres.set_sub_addr_minor(td.m_subaddr_index.minor); - if (need_all_additionals) { - for (auto &aux : additional_tx_pub_keys) { - cres.add_additional_tx_pub_keys(key_to_string(aux)); - } - } else if (!additional_tx_pub_keys.empty() && additional_tx_pub_keys.size() > td.m_internal_output_index) { + if (!additional_tx_pub_keys.empty() && additional_tx_pub_keys.size() > td.m_internal_output_index) { cres.add_additional_tx_pub_keys(key_to_string(additional_tx_pub_keys[td.m_internal_output_index])); } } @@ -194,8 +190,7 @@ namespace ki { void generate_commitment(std::vector & mtds, const std::vector & transfers, - std::shared_ptr & req, - bool need_subaddr_indices) + std::shared_ptr & req) { req = std::make_shared(); @@ -219,16 +214,6 @@ namespace ki { auto & st = search.first->second; st.insert(cur.m_subaddr_index.minor); } - - if (need_subaddr_indices) { - for (auto &x: sub_indices) { - auto subs = req->add_subs(); - subs->set_account(x.first); - for (auto minor : x.second) { - subs->add_minor_indices(minor); - } - } - } } void live_refresh_ack(const ::crypto::secret_key & view_key_priv, @@ -399,7 +384,7 @@ namespace tx { m_tx_idx = tx_idx; m_ct.tx_data = cur_src_tx(); m_multisig = false; - m_client_version = 1; + m_client_version = 3; } void Signer::extract_payment_id(){ @@ -474,25 +459,19 @@ namespace tx { auto & cur = src.outputs[i]; auto out = dst->add_outputs(); - if (i == src.real_output || need_ring_indices || client_version() <= 1) { + if (i == src.real_output || need_ring_indices) { out->set_idx(cur.first); } - if (i == src.real_output || need_ring_keys || client_version() <= 1) { + if (i == src.real_output || need_ring_keys) { translate_rct_key(out->mutable_key(), &(cur.second)); } } dst->set_real_out_tx_key(key_to_string(src.real_out_tx_key)); dst->set_real_output_in_tx_index(src.real_output_in_tx_index); - - if (client_version() <= 1) { - for (auto &cur : src.real_out_additional_tx_keys) { - dst->add_real_out_additional_tx_keys(key_to_string(cur)); - } - } else if (!src.real_out_additional_tx_keys.empty()) { + if (!src.real_out_additional_tx_keys.empty()) { dst->add_real_out_additional_tx_keys(key_to_string(src.real_out_additional_tx_keys.at(src.real_output_in_tx_index))); } - dst->set_amount(src.amount); dst->set_rct(src.rct); dst->set_mask(key_to_string(src.mask)); @@ -532,7 +511,7 @@ namespace tx { m_ct.tx.version = 2; m_ct.tx.unlock_time = tx.unlock_time; - m_client_version = (m_aux_data->client_version ? m_aux_data->client_version.get() : 1); + m_client_version = (m_aux_data->client_version ? m_aux_data->client_version.get() : 3); tsx_data.set_version(1); tsx_data.set_client_version(client_version()); @@ -543,18 +522,13 @@ namespace tx { tsx_data.set_monero_version(std::string(MONERO_VERSION) + "|" + MONERO_VERSION_TAG); tsx_data.set_hard_fork(m_aux_data->hard_fork ? m_aux_data->hard_fork.get() : 0); - if (client_version() <= 1){ - assign_to_repeatable(tsx_data.mutable_minor_indices(), tx.subaddr_indices.begin(), tx.subaddr_indices.end()); - } - // Rsig decision auto rsig_data = tsx_data.mutable_rsig_data(); m_ct.rsig_type = get_rsig_type(tx.rct_config, tx.splitted_dsts.size()); rsig_data->set_rsig_type(m_ct.rsig_type); - if (tx.rct_config.range_proof_type != rct::RangeProofBorromean){ - m_ct.bp_version = (m_aux_data->bp_version ? m_aux_data->bp_version.get() : 1); - rsig_data->set_bp_version((uint32_t) m_ct.bp_version); - } + CHECK_AND_ASSERT_THROW_MES(tx.rct_config.range_proof_type != rct::RangeProofBorromean, "Borromean rsig not supported"); + m_ct.bp_version = (m_aux_data->bp_version ? m_aux_data->bp_version.get() : 1); + rsig_data->set_bp_version((uint32_t) m_ct.bp_version); generate_rsig_batch_sizes(m_ct.grouping_vct, m_ct.rsig_type, tx.splitted_dsts.size()); assign_to_repeatable(rsig_data->mutable_grouping(), m_ct.grouping_vct.begin(), m_ct.grouping_vct.end()); @@ -652,22 +626,6 @@ namespace tx { }); } - std::shared_ptr Signer::step_permutation(){ - sort_ki(); - if (client_version() >= 2){ - return nullptr; - } - - auto res = std::make_shared(); - assign_to_repeatable(res->mutable_perm(), m_ct.source_permutation.begin(), m_ct.source_permutation.end()); - - return res; - } - - void Signer::step_permutation_ack(std::shared_ptr ack){ - - } - std::shared_ptr Signer::step_set_vini_input(size_t idx){ CHECK_AND_ASSERT_THROW_MES(idx < m_ct.tx_data.sources.size(), "Invalid transaction index"); CHECK_AND_ASSERT_THROW_MES(idx < m_ct.tx.vin.size(), "Invalid transaction index"); @@ -711,8 +669,10 @@ namespace tx { } void Signer::step_set_output_ack(std::shared_ptr ack){ + CHECK_AND_ASSERT_THROW_MES(is_req_bulletproof(), "Borromean rsig not supported"); cryptonote::tx_out tx_out; rct::Bulletproof bproof{}; + rct::BulletproofPlus bproof_plus{}; rct::ctkey out_pk{}; rct::ecdhTuple ecdh{}; @@ -727,7 +687,7 @@ namespace tx { rsig_buff = rsig_data.rsig(); } - if (client_version() >= 1 && rsig_data.has_mask()){ + if (rsig_data.has_mask()){ rct::key cmask{}; string_to_key(cmask, rsig_data.mask()); m_ct.rsig_gamma.emplace_back(cmask); @@ -751,22 +711,32 @@ namespace tx { memcpy(ecdh.amount.bytes, ack->ecdh_info().data(), 8); } - if (has_rsig && is_req_bulletproof() && !cn_deserialize(rsig_buff, bproof)){ - throw exc::ProtocolException("Cannot deserialize bulletproof rangesig"); - } - m_ct.tx.vout.emplace_back(tx_out); m_ct.tx_out_hmacs.push_back(ack->vouti_hmac()); m_ct.tx_out_pk.emplace_back(out_pk); m_ct.tx_out_ecdh.emplace_back(ecdh); - // ClientV0, if no rsig was generated on Trezor, do not continue. - // ClientV1+ generates BP after all masks in the current batch are generated - if (!has_rsig || (client_version() >= 1 && is_offloading())){ + rsig_v bp_obj{}; + if (has_rsig) { + bool deserialize_success; + if (is_req_bulletproof_plus()) { + deserialize_success = cn_deserialize(rsig_buff, bproof_plus); + bp_obj = bproof_plus; + } else { + deserialize_success = cn_deserialize(rsig_buff, bproof); + bp_obj = bproof; + } + if (!deserialize_success) { + throw exc::ProtocolException("Cannot deserialize bulletproof rangesig"); + } + } + + // Generates BP after all masks in the current batch are generated + if (!has_rsig || is_offloading()){ return; } - process_bproof(bproof); + process_bproof(bp_obj); m_ct.cur_batch_idx += 1; m_ct.cur_output_in_batch_idx = 0; } @@ -791,13 +761,21 @@ namespace tx { masks.push_back(m_ct.rsig_gamma[bidx]); } - auto bp = bulletproof_PROVE(amounts, masks); - auto serRsig = cn_serialize(bp); - m_ct.tx_out_rsigs.emplace_back(bp); + std::string serRsig; + if (is_req_bulletproof_plus()) { + auto bp = bulletproof_plus_PROVE(amounts, masks); + serRsig = cn_serialize(bp); + m_ct.tx_out_rsigs.emplace_back(bp); + } else { + auto bp = bulletproof_PROVE(amounts, masks); + serRsig = cn_serialize(bp); + m_ct.tx_out_rsigs.emplace_back(bp); + } + rsig_data.set_rsig(serRsig); } - void Signer::process_bproof(rct::Bulletproof & bproof){ + void Signer::process_bproof(rsig_v & bproof){ CHECK_AND_ASSERT_THROW_MES(m_ct.cur_batch_idx < m_ct.grouping_vct.size(), "Invalid batch index"); auto batch_size = m_ct.grouping_vct[m_ct.cur_batch_idx]; for (size_t i = 0; i < batch_size; ++i){ @@ -806,12 +784,22 @@ namespace tx { rct::key commitment = m_ct.tx_out_pk[bidx].mask; commitment = rct::scalarmultKey(commitment, rct::INV_EIGHT); - bproof.V.push_back(commitment); + if (is_req_bulletproof_plus()) { + boost::get(bproof).V.push_back(commitment); + } else { + boost::get(bproof).V.push_back(commitment); + } } m_ct.tx_out_rsigs.emplace_back(bproof); - if (!rct::bulletproof_VERIFY(boost::get(m_ct.tx_out_rsigs.back()))) { - throw exc::ProtocolException("Returned range signature is invalid"); + if (is_req_bulletproof_plus()) { + if (!rct::bulletproof_plus_VERIFY(boost::get(m_ct.tx_out_rsigs.back()))) { + throw exc::ProtocolException("Returned range signature is invalid"); + } + } else { + if (!rct::bulletproof_VERIFY(boost::get(m_ct.tx_out_rsigs.back()))) { + throw exc::ProtocolException("Returned range signature is invalid"); + } } } @@ -840,6 +828,7 @@ namespace tx { } void Signer::step_all_outs_set_ack(std::shared_ptr ack, hw::device &hwdev){ + CHECK_AND_ASSERT_THROW_MES(is_req_bulletproof(), "Borromean rsig not supported"); m_ct.rv = std::make_shared(); m_ct.rv->txnFee = ack->rv().txn_fee(); m_ct.rv->type = static_cast(ack->rv().rv_type()); @@ -864,24 +853,15 @@ namespace tx { // RctSig auto num_sources = m_ct.tx_data.sources.size(); - if (is_simple() || is_req_bulletproof()){ - auto dst = &m_ct.rv->pseudoOuts; - if (is_bulletproof()){ - dst = &m_ct.rv->p.pseudoOuts; - } - - dst->clear(); - for (const auto &pseudo_out : m_ct.pseudo_outs) { - dst->emplace_back(); - string_to_key(dst->back(), pseudo_out); - } - - m_ct.rv->mixRing.resize(num_sources); - } else { - m_ct.rv->mixRing.resize(m_ct.tsx_data.mixin()); - m_ct.rv->mixRing[0].resize(num_sources); + auto dst = &m_ct.rv->p.pseudoOuts; + dst->clear(); + for (const auto &pseudo_out : m_ct.pseudo_outs) { + dst->emplace_back(); + string_to_key(dst->back(), pseudo_out); } + m_ct.rv->mixRing.resize(num_sources); + CHECK_AND_ASSERT_THROW_MES(m_ct.tx_out_pk.size() == m_ct.tx_out_ecdh.size(), "Invalid vector sizes"); for(size_t i = 0; i < m_ct.tx_out_ecdh.size(); ++i){ m_ct.rv->outPk.push_back(m_ct.tx_out_pk[i]); @@ -889,10 +869,10 @@ namespace tx { } for(size_t i = 0; i < m_ct.tx_out_rsigs.size(); ++i){ - if (is_bulletproof()){ - m_ct.rv->p.bulletproofs.push_back(boost::get(m_ct.tx_out_rsigs[i])); + if (is_req_bulletproof_plus()) { + m_ct.rv->p.bulletproofs_plus.push_back(boost::get(m_ct.tx_out_rsigs[i])); } else { - m_ct.rv->p.rangeSigs.push_back(boost::get(m_ct.tx_out_rsigs[i])); + m_ct.rv->p.bulletproofs.push_back(boost::get(m_ct.tx_out_rsigs[i])); } } @@ -936,8 +916,8 @@ namespace tx { void Signer::step_sign_input_ack(std::shared_ptr ack){ m_ct.signatures.push_back(ack->signature()); - // Sync updated pseudo_outputs, client_version>=1, HF10+ - if (client_version() >= 1 && ack->has_pseudo_out()){ + // Sync updated pseudo_outputs + if (ack->has_pseudo_out()){ CHECK_AND_ASSERT_THROW_MES(m_ct.cur_input_idx < m_ct.pseudo_outs.size(), "Invalid pseudo-out index"); m_ct.pseudo_outs[m_ct.cur_input_idx] = ack->pseudo_out(); if (is_bulletproof()){ @@ -955,6 +935,8 @@ namespace tx { } void Signer::step_final_ack(std::shared_ptr ack){ + CHECK_AND_ASSERT_THROW_MES(is_clsag(), "Only CLSAGs signatures are supported"); + if (m_multisig){ auto & cout_key = ack->cout_key(); for(auto & cur : m_ct.couts){ @@ -975,47 +957,34 @@ namespace tx { m_ct.enc_keys = ack->tx_enc_keys(); // Opening the sealed signatures - if (client_version() >= 3){ - if(!ack->has_opening_key()){ - throw exc::ProtocolException("Client version 3+ requires sealed signatures"); - } + if(!ack->has_opening_key()){ + throw exc::ProtocolException("Client version 3+ requires sealed signatures"); + } - for(size_t i = 0; i < m_ct.signatures.size(); ++i){ - CHECK_AND_ASSERT_THROW_MES(m_ct.signatures[i].size() > crypto::chacha::TAG_SIZE, "Invalid signature size"); - std::string nonce = compute_sealing_key(ack->opening_key(), i, true); - std::string key = compute_sealing_key(ack->opening_key(), i, false); - size_t plen = m_ct.signatures[i].size() - crypto::chacha::TAG_SIZE; - std::unique_ptr plaintext(new uint8_t[plen]); - uint8_t * buff = plaintext.get(); - - protocol::crypto::chacha::decrypt( - m_ct.signatures[i].data(), - m_ct.signatures[i].size(), - reinterpret_cast(key.data()), - reinterpret_cast(nonce.data()), - reinterpret_cast(buff), &plen); - m_ct.signatures[i].assign(reinterpret_cast(buff), plen); - } + for(size_t i = 0; i < m_ct.signatures.size(); ++i){ + CHECK_AND_ASSERT_THROW_MES(m_ct.signatures[i].size() > crypto::chacha::TAG_SIZE, "Invalid signature size"); + std::string nonce = compute_sealing_key(ack->opening_key(), i, true); + std::string key = compute_sealing_key(ack->opening_key(), i, false); + size_t plen = m_ct.signatures[i].size() - crypto::chacha::TAG_SIZE; + std::unique_ptr plaintext(new uint8_t[plen]); + uint8_t * buff = plaintext.get(); + + protocol::crypto::chacha::decrypt( + m_ct.signatures[i].data(), + m_ct.signatures[i].size(), + reinterpret_cast(key.data()), + reinterpret_cast(nonce.data()), + reinterpret_cast(buff), &plen); + m_ct.signatures[i].assign(reinterpret_cast(buff), plen); } - if (m_ct.rv->type == rct::RCTTypeCLSAG){ - m_ct.rv->p.CLSAGs.reserve(m_ct.signatures.size()); - for (size_t i = 0; i < m_ct.signatures.size(); ++i) { - rct::clsag clsag; - if (!cn_deserialize(m_ct.signatures[i], clsag)) { - throw exc::ProtocolException("Cannot deserialize clsag[i]"); - } - m_ct.rv->p.CLSAGs.push_back(clsag); - } - } else { - m_ct.rv->p.MGs.reserve(m_ct.signatures.size()); - for (size_t i = 0; i < m_ct.signatures.size(); ++i) { - rct::mgSig mg; - if (!cn_deserialize(m_ct.signatures[i], mg)) { - throw exc::ProtocolException("Cannot deserialize mg[i]"); - } - m_ct.rv->p.MGs.push_back(mg); + m_ct.rv->p.CLSAGs.reserve(m_ct.signatures.size()); + for (size_t i = 0; i < m_ct.signatures.size(); ++i) { + rct::clsag clsag; + if (!cn_deserialize(m_ct.signatures[i], clsag)) { + throw exc::ProtocolException("Cannot deserialize clsag[i]"); } + m_ct.rv->p.CLSAGs.push_back(clsag); } m_ct.tx.rct_signatures = *(m_ct.rv); diff --git a/src/device_trezor/trezor/protocol.hpp b/src/device_trezor/trezor/protocol.hpp index 858db152007..fa83552003a 100644 --- a/src/device_trezor/trezor/protocol.hpp +++ b/src/device_trezor/trezor/protocol.hpp @@ -116,8 +116,7 @@ namespace ki { */ bool key_image_data(wallet_shim * wallet, const std::vector & transfers, - std::vector & res, - bool need_all_additionals=false); + std::vector & res); /** * Computes a hash over MoneroTransferDetails. Commitment used in the KI sync. @@ -129,8 +128,7 @@ namespace ki { */ void generate_commitment(std::vector & mtds, const std::vector & transfers, - std::shared_ptr & req, - bool need_subaddr_indices=false); + std::shared_ptr & req); /** * Processes Live refresh step response, parses KI, checks the signature @@ -166,7 +164,7 @@ namespace tx { ::crypto::secret_key compute_enc_key(const ::crypto::secret_key & private_view_key, const std::string & aux, const std::string & salt); std::string compute_sealing_key(const std::string & master_key, size_t idx, bool is_iv=false); - typedef boost::variant rsig_v; + typedef boost::variant rsig_v; /** * Transaction signer state holder. @@ -247,7 +245,7 @@ namespace tx { void compute_integrated_indices(TsxData * tsx_data); bool should_compute_bp_now() const; void compute_bproof(messages::monero::MoneroTransactionRsigData & rsig_data); - void process_bproof(rct::Bulletproof & bproof); + void process_bproof(rsig_v & bproof); void set_tx_input(MoneroTransactionSourceEntry * dst, size_t idx, bool need_ring_keys=false, bool need_ring_indices=false); public: @@ -260,8 +258,6 @@ namespace tx { void step_set_input_ack(std::shared_ptr ack); void sort_ki(); - std::shared_ptr step_permutation(); - void step_permutation_ack(std::shared_ptr ack); std::shared_ptr step_set_vini_input(size_t idx); void step_set_vini_input_ack(std::shared_ptr ack); @@ -290,11 +286,15 @@ namespace tx { return m_client_version; } - bool is_simple() const { + uint8_t get_rv_type() const { if (!m_ct.rv){ throw std::invalid_argument("RV not initialized"); } - auto tp = m_ct.rv->type; + return m_ct.rv->type; + } + + bool is_simple() const { + auto tp = get_rv_type(); return tp == rct::RCTTypeSimple; } @@ -302,12 +302,27 @@ namespace tx { return m_ct.tx_data.rct_config.range_proof_type != rct::RangeProofBorromean; } + bool is_req_clsag() const { + return is_req_bulletproof() && m_ct.tx_data.rct_config.bp_version >= 3; + } + + bool is_req_bulletproof_plus() const { + return is_req_bulletproof() && m_ct.tx_data.rct_config.bp_version == 4; // rct::genRctSimple + } + bool is_bulletproof() const { - if (!m_ct.rv){ - throw std::invalid_argument("RV not initialized"); - } - auto tp = m_ct.rv->type; - return tp == rct::RCTTypeBulletproof || tp == rct::RCTTypeBulletproof2 || tp == rct::RCTTypeCLSAG; + auto tp = get_rv_type(); + return rct::is_rct_bulletproof(tp) || rct::is_rct_bulletproof_plus(tp); + } + + bool is_bulletproof_plus() const { + auto tp = get_rv_type(); + return rct::is_rct_bulletproof_plus(tp); + } + + bool is_clsag() const { + auto tp = get_rv_type(); + return rct::is_rct_clsag(tp); } bool is_offloading() const { diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 61195c7b0e7..f9a2aff1ae9 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -661,7 +661,7 @@ void block_tracker::process(const block* blk, const transaction * tx, size_t i) for (size_t j = 0; j < tx->vout.size(); ++j) { const tx_out &out = tx->vout[j]; - if (typeid(cryptonote::txout_to_key) != out.target.type()) { // out_to_key + if (typeid(cryptonote::txout_to_key) != out.target.type() && typeid(cryptonote::txout_to_tagged_key) != out.target.type()) { continue; } diff --git a/tests/trezor/trezor_tests.cpp b/tests/trezor/trezor_tests.cpp index 0db05760af5..0d61610be10 100644 --- a/tests/trezor/trezor_tests.cpp +++ b/tests/trezor/trezor_tests.cpp @@ -52,7 +52,6 @@ namespace po = boost::program_options; namespace { const command_line::arg_descriptor arg_filter = { "filter", "Regular expression filter for which tests to run" }; - const command_line::arg_descriptor arg_generate_and_play_test_data = {"generate_and_play_test_data", ""}; const command_line::arg_descriptor arg_trezor_path = {"trezor_path", "Path to the trezor device to use, has to support debug link", ""}; const command_line::arg_descriptor arg_heavy_tests = {"heavy_tests", "Runs expensive tests (volume tests with real device)", false}; const command_line::arg_descriptor arg_chain_path = {"chain_path", "Path to the serialized blockchain, speeds up testing", ""}; @@ -138,7 +137,7 @@ int main(int argc, char* argv[]) hw::register_device(HW_TREZOR_NAME, ensure_trezor_test_device()); // shim device for call tracking // Bootstrapping common chain & accounts - const uint8_t initial_hf = (uint8_t)get_env_long("TEST_MIN_HF", 12); + const uint8_t initial_hf = (uint8_t)get_env_long("TEST_MIN_HF", HF_VERSION_CLSAG); const uint8_t max_hf = (uint8_t)get_env_long("TEST_MAX_HF", HF_VERSION_CLSAG); auto sync_test = get_env_long("TEST_KI_SYNC", 1); MINFO("Test versions " << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"); @@ -162,6 +161,10 @@ int main(int argc, char* argv[]) // Transaction tests for(uint8_t hf=initial_hf; hf <= max_hf + 1; ++hf) { + if (hf == 14) { // HF 14 is skipped. + continue; + } + if (hf > initial_hf || hf > max_hf) { daemon->stop_and_deinit(); @@ -201,12 +204,14 @@ int main(int argc, char* argv[]) TREZOR_COMMON_TEST_CASE(gen_trezor_4utxo_to_1norm_2sub, core, trezor_base); TREZOR_COMMON_TEST_CASE(gen_trezor_2utxo_sub_acc_to_1norm_2sub, core, trezor_base); TREZOR_COMMON_TEST_CASE(gen_trezor_4utxo_to_7outs, core, trezor_base); + TREZOR_COMMON_TEST_CASE(gen_trezor_4utxo_to_15outs, core, trezor_base); TREZOR_COMMON_TEST_CASE(wallet_api_tests, core, trezor_base); } if (trezor_base.heavy_tests()) { TREZOR_COMMON_TEST_CASE(gen_trezor_many_utxo, core, trezor_base); + TREZOR_COMMON_TEST_CASE(gen_trezor_many_utxo_many_txo, core, trezor_base); } core->deinit(); @@ -555,7 +560,7 @@ static void expand_tsx(cryptonote::transaction &tx) rv.p.MGs[n].II[0] = rct::ki2rct(boost::get(tx.vin[n]).k_image); } } - else if (rv.type == rct::RCTTypeCLSAG) + else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus) { if (!tx.pruned) { @@ -1269,6 +1274,8 @@ void gen_trezor_base::set_hard_fork(uint8_t hf) rct_config({rct::RangeProofPaddedBulletproof, 2}); } else if (hf == HF_VERSION_CLSAG){ rct_config({rct::RangeProofPaddedBulletproof, 3}); + } else if (hf == HF_VERSION_BULLETPROOF_PLUS){ + rct_config({rct::RangeProofPaddedBulletproof, 4}); } else { throw std::runtime_error("Unsupported HF"); } @@ -1655,7 +1662,7 @@ bool gen_trezor_1utxo::generate(std::vector& events) { TREZOR_TEST_PREFIX(); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(boost::none, MK_COINS(1), -1, -1) @@ -1671,7 +1678,7 @@ bool gen_trezor_1utxo_paymentid_short::generate(std::vector& e TREZOR_TEST_PREFIX(); TREZOR_SKIP_IF_VERSION_LEQ(hw::trezor::pack_version(2, 0, 9)); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(boost::none, MK_COINS(1), -1, -1) @@ -1688,7 +1695,7 @@ bool gen_trezor_1utxo_paymentid_short_integrated::generate(std::vectorcur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(boost::none, MK_COINS(1), -1, -1) @@ -1705,7 +1712,7 @@ bool gen_trezor_4utxo::generate(std::vector& events) { TREZOR_TEST_PREFIX(); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(4, MK_COINS(1), -1, -1) @@ -1720,7 +1727,7 @@ bool gen_trezor_4utxo_acc1::generate(std::vector& events) { TREZOR_TEST_PREFIX(); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 1) ->compute_sources(4, MK_COINS(1), -1, -1) @@ -1735,7 +1742,7 @@ bool gen_trezor_4utxo_to_sub::generate(std::vector& events) { TREZOR_TEST_PREFIX(); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(4, MK_COINS(1), -1, -1) @@ -1750,7 +1757,7 @@ bool gen_trezor_4utxo_to_2sub::generate(std::vector& events) { TREZOR_TEST_PREFIX(); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(4, MK_COINS(1), -1, -1) @@ -1766,7 +1773,7 @@ bool gen_trezor_4utxo_to_1norm_2sub::generate(std::vector& eve { TREZOR_TEST_PREFIX(); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(4, MK_COINS(1), -1, -1) @@ -1783,7 +1790,7 @@ bool gen_trezor_2utxo_sub_acc_to_1norm_2sub::generate(std::vectorcur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources_to_sub_acc(2, MK_COINS(1) >> 2, -1, -1) @@ -1800,7 +1807,7 @@ bool gen_trezor_4utxo_to_7outs::generate(std::vector& events) { TREZOR_TEST_PREFIX(); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(4, MK_COINS(1), -1, -1) @@ -1817,11 +1824,39 @@ bool gen_trezor_4utxo_to_7outs::generate(std::vector& events) TREZOR_TEST_SUFFIX(); } +bool gen_trezor_4utxo_to_15outs::generate(std::vector& events) +{ + TREZOR_TEST_PREFIX(); + t_builder->cur_height(num_blocks(events) - 1) + ->mixin(num_mixin()) + ->fee(TREZOR_TEST_FEE) + ->from(m_wl_alice.get(), 0) + ->compute_sources(4, MK_COINS(1), -1, -1) + ->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 2}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 3}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 4}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 2}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 3}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 4}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 4}), true, 1000) + ->add_destination(m_wl_eve.get(), false, 1000) + ->rct_config(m_rct_config) + ->build_tx(); + + TREZOR_TEST_SUFFIX(); +} + bool gen_trezor_many_utxo::generate(std::vector& events) { TREZOR_TEST_PREFIX(); t_builder->cur_height(num_blocks(events) - 1) - ->mixin(TREZOR_TEST_MIXIN) + ->mixin(num_mixin()) ->fee(TREZOR_TEST_FEE) ->from(m_wl_alice.get(), 0) ->compute_sources(110, MK_COINS(1), -1, -1) @@ -1832,6 +1867,35 @@ bool gen_trezor_many_utxo::generate(std::vector& events) TREZOR_TEST_SUFFIX(); } +bool gen_trezor_many_utxo_many_txo::generate(std::vector& events) +{ + TREZOR_TEST_PREFIX(); + t_builder->cur_height(num_blocks(events) - 1) + ->mixin(num_mixin()) + ->fee(TREZOR_TEST_FEE) + ->from(m_wl_alice.get(), 0) + ->compute_sources(40, MK_COINS(1), -1, -1) + ->add_destination(m_eve_account, false, 1000) + ->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 2}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 3}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 4}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 2}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({0, 3}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({1, 4}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({2, 4}), true, 1000) + ->add_destination(m_wl_eve->get_subaddress({3, 4}), true, 1000) + ->rct_config(m_rct_config) + ->build_tx(); + + TREZOR_TEST_SUFFIX(); +} + void wallet_api_tests::init() { m_wallet_dir = boost::filesystem::unique_path(); @@ -1873,7 +1937,7 @@ bool wallet_api_tests::generate(std::vector& events) Monero::PendingTransaction * transaction = w->createTransaction(recepient_address, "", MK_COINS(10), - TREZOR_TEST_MIXIN, + num_mixin(), Monero::PendingTransaction::Priority_Medium, 0, std::set{}); diff --git a/tests/trezor/trezor_tests.h b/tests/trezor/trezor_tests.h index 2953cc2bdd9..f7684da12d2 100644 --- a/tests/trezor/trezor_tests.h +++ b/tests/trezor/trezor_tests.h @@ -37,7 +37,9 @@ #include "../core_tests/wallet_tools.h" #define TREZOR_TEST_FEE 90000000000 -#define TREZOR_TEST_MIXIN 11 +#define TREZOR_TEST_CLSAG_MIXIN 11 +#define TREZOR_TEST_HF15_MIXIN 16 +#define TREZOR_TEST_MIXIN TREZOR_TEST_CLSAG_MIXIN /************************************************************************/ /* */ @@ -93,6 +95,7 @@ class gen_trezor_base : public test_chain_unit_base bool heavy_tests() const { return m_heavy_tests; } void rct_config(rct::RCTConfig rct_config) { m_rct_config = rct_config; } uint8_t cur_hf() const { return m_hard_forks.size() > 0 ? m_hard_forks.back().first : 0; } + size_t num_mixin() const { return m_top_hard_fork >= HF_VERSION_BULLETPROOF_PLUS ? TREZOR_TEST_HF15_MIXIN : TREZOR_TEST_CLSAG_MIXIN; } cryptonote::network_type nettype() const { return m_network_type; } std::shared_ptr daemon() const { return m_daemon; } void daemon(std::shared_ptr daemon){ m_daemon = std::move(daemon); } @@ -306,12 +309,24 @@ class gen_trezor_4utxo_to_7outs : public gen_trezor_base bool generate(std::vector& events) override; }; +class gen_trezor_4utxo_to_15outs : public gen_trezor_base +{ +public: + bool generate(std::vector& events) override; +}; + class gen_trezor_many_utxo : public gen_trezor_base { public: bool generate(std::vector& events) override; }; +class gen_trezor_many_utxo_many_txo : public gen_trezor_base +{ +public: + bool generate(std::vector& events) override; +}; + // Wallet::API tests class wallet_api_tests : public gen_trezor_base { From 4278a3a7e32ced988474260e0ed6ad21228a41e5 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 20 Jun 2022 18:45:10 +0000 Subject: [PATCH 036/186] cryptonote_basic: catch crypto api errors --- src/cryptonote_basic/cryptonote_format_utils.cpp | 4 ++-- src/device/device_ledger.cpp | 12 ++++++++---- src/wallet/wallet2.cpp | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index f101f10c532..388013f96d1 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1042,7 +1042,7 @@ namespace cryptonote crypto::public_key subaddress_spendkey; if (out_can_be_to_acc(view_tag_opt, derivation, output_index)) { - hwdev.derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey); + CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey), boost::none, "Failed to derive subaddress public key"); auto found = subaddresses.find(subaddress_spendkey); if (found != subaddresses.end()) return subaddress_receive_info{ found->second, derivation }; @@ -1054,7 +1054,7 @@ namespace cryptonote CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations"); if (out_can_be_to_acc(view_tag_opt, additional_derivations[output_index], output_index)) { - hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey); + CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey), boost::none, "Failed to derive subaddress public key"); auto found = subaddresses.find(subaddress_spendkey); if (found != subaddresses.end()) return subaddress_receive_info{ found->second, additional_derivations[output_index] }; diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index 51e65dfa53a..aa73e998c78 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -694,7 +694,8 @@ namespace hw { log_hexbuffer("derive_subaddress_public_key: [[IN]] pub ", pub_x.data, 32); log_hexbuffer("derive_subaddress_public_key: [[IN]] derivation", derivation_x.data, 32); log_message ("derive_subaddress_public_key: [[IN]] index ", std::to_string((int)output_index_x)); - this->controle_device->derive_subaddress_public_key(pub_x, derivation_x,output_index_x,derived_pub_x); + if (!this->controle_device->derive_subaddress_public_key(pub_x, derivation_x,output_index_x,derived_pub_x)) + return false; log_hexbuffer("derive_subaddress_public_key: [[OUT]] derived_pub", derived_pub_x.data, 32); #endif @@ -702,7 +703,8 @@ namespace hw { //If we are in TRANSACTION_PARSE, the given derivation has been retrieved uncrypted (wihtout the help //of the device), so continue that way. MDEBUG( "derive_subaddress_public_key : PARSE mode with known viewkey"); - crypto::derive_subaddress_public_key(pub, derivation, output_index,derived_pub); + if (!crypto::derive_subaddress_public_key(pub, derivation, output_index,derived_pub)) + return false; } else { AUTO_LOCK_CMD(); int offset = set_command_header_noopt(INS_DERIVE_SUBADDRESS_PUBLIC_KEY); @@ -1052,7 +1054,8 @@ namespace hw { crypto::key_derivation derivation_x; log_hexbuffer("generate_key_derivation: [[IN]] pub ", pub_x.data, 32); log_hexbuffer("generate_key_derivation: [[IN]] sec ", sec_x.data, 32); - this->controle_device->generate_key_derivation(pub_x, sec_x, derivation_x); + if (!this->controle_device->generate_key_derivation(pub_x, sec_x, derivation_x)) + return false; log_hexbuffer("generate_key_derivation: [[OUT]] derivation", derivation_x.data, 32); #endif @@ -1207,7 +1210,8 @@ namespace hw { log_hexbuffer("derive_public_key: [[IN]] derivation ", derivation_x.data, 32); log_message ("derive_public_key: [[IN]] output_index", std::to_string(output_index_x)); log_hexbuffer("derive_public_key: [[IN]] pub ", pub_x.data, 32); - this->controle_device->derive_public_key(derivation_x, output_index_x, pub_x, derived_pub_x); + if (!this->controle_device->derive_public_key(derivation_x, output_index_x, pub_x, derived_pub_x)) + return false; log_hexbuffer("derive_public_key: [[OUT]] derived_pub ", derived_pub_x.data, 32); #endif diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b2a6c0f5a2..0c9032947fc 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -12090,7 +12090,8 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr crypto::key_derivation derivation; THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(proof.shared_secret, rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation"); crypto::public_key subaddr_spendkey; - crypto::derive_subaddress_public_key(output_public_key, derivation, proof.index_in_tx, subaddr_spendkey); + THROW_WALLET_EXCEPTION_IF(!crypto::derive_subaddress_public_key(output_public_key, derivation, proof.index_in_tx, subaddr_spendkey), + error::wallet_internal_error, "Failed to derive subaddress public key"); THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(subaddr_spendkey) == 0, error::wallet_internal_error, "The address doesn't seem to have received the fund"); From 6f3abbead534650377aa8362f8c37623831ee5af Mon Sep 17 00:00:00 2001 From: TheCharlatan Date: Wed, 22 Jun 2022 22:50:55 +0200 Subject: [PATCH 037/186] Depends: Unbound disable getentropy()/reallocarray() (glibc < 2.26) --- contrib/depends/packages/unbound.mk | 9 ++++++++- .../unbound/disable-glibc-reallocarray.patch | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 contrib/depends/patches/unbound/disable-glibc-reallocarray.patch diff --git a/contrib/depends/packages/unbound.mk b/contrib/depends/packages/unbound.mk index a85c47e4e28..9336524f385 100644 --- a/contrib/depends/packages/unbound.mk +++ b/contrib/depends/packages/unbound.mk @@ -4,6 +4,8 @@ $(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=a480dc6c8937447b98d161fe911ffc76cfaffa2da18788781314e81339f1126f $(package)_dependencies=openssl expat ldns +$(package)_patches=disable-glibc-reallocarray.patch + define $(package)_set_vars $(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) --with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only @@ -12,8 +14,13 @@ define $(package)_set_vars $(package)_build_opts_mingw32=LDFLAGS="$($(package)_ldflags) -lpthread" endef +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/disable-glibc-reallocarray.patch &&\ + autoconf +endef + define $(package)_config_cmds - $($(package)_autoconf) + $($(package)_autoconf) ac_cv_func_getentropy=no endef define $(package)_build_cmds diff --git a/contrib/depends/patches/unbound/disable-glibc-reallocarray.patch b/contrib/depends/patches/unbound/disable-glibc-reallocarray.patch new file mode 100644 index 00000000000..d66a821ad59 --- /dev/null +++ b/contrib/depends/patches/unbound/disable-glibc-reallocarray.patch @@ -0,0 +1,14 @@ +diff --git a/configure.ac b/configure.ac +index 5c7da197..e2b25288 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1702,6 +1702,9 @@ AC_LINK_IFELSE([AC_LANG_SOURCE(AC_INCLUDES_DEFAULT + #ifndef _OPENBSD_SOURCE + #define _OPENBSD_SOURCE 1 + #endif ++#ifdef __linux__ ++# error reallocarray() is currently disabled on Linux to support glibc < 2.26 ++#endif + #include + int main(void) { + void* p = reallocarray(NULL, 10, 100); From 50ccc7e72646f2ef2d502d0115fdeb84b17b7ad0 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Fri, 24 Jun 2022 21:58:07 +0200 Subject: [PATCH 038/186] wallet2: remove obsolete rpc version check --- src/wallet/wallet2.cpp | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b2a6c0f5a2..5800217fa6e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3622,32 +3622,7 @@ bool wallet2::refresh(bool trusted_daemon, uint64_t & blocks_fetched, bool& rece //---------------------------------------------------------------------------------------------------- bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector &distribution) { - uint32_t rpc_version; - boost::optional result = m_node_rpc_proxy.get_rpc_version(rpc_version); - // no error - if (!!result) - { - // empty string -> not connection - THROW_WALLET_EXCEPTION_IF(result->empty(), tools::error::no_connection_to_daemon, "getversion"); - THROW_WALLET_EXCEPTION_IF(*result == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, "getversion"); - if (*result != CORE_RPC_STATUS_OK) - { - MDEBUG("Cannot determine daemon RPC version, not requesting rct distribution"); - return false; - } - } - else - { - if (rpc_version >= MAKE_CORE_RPC_VERSION(1, 19)) - { - MDEBUG("Daemon is recent enough, requesting rct distribution"); - } - else - { - MDEBUG("Daemon is too old, not requesting rct distribution"); - return false; - } - } + MDEBUG("Requesting rct distribution"); cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request req = AUTO_VAL_INIT(req); cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response res = AUTO_VAL_INIT(res); From db8181adf8ea52e97f9dd5fd72ca63e74488f5f3 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Fri, 24 Jun 2022 23:53:09 +0200 Subject: [PATCH 039/186] wallet2: force using output distribution for ringct outs Co-authored-by: j-berman --- src/wallet/wallet2.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b2a6c0f5a2..486810e00ff 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -8049,8 +8049,13 @@ void wallet2::get_outs(std::vector> has_rct = true; max_rct_index = std::max(max_rct_index, m_transfers[idx].m_global_output_index); } - const bool has_rct_distribution = has_rct && (!rct_offsets.empty() || get_rct_distribution(rct_start_height, rct_offsets)); - if (has_rct_distribution) + + if (has_rct && rct_offsets.empty()) { + THROW_WALLET_EXCEPTION_IF(!get_rct_distribution(rct_start_height, rct_offsets), + error::get_output_distribution, "Could not obtain output distribution."); + } + + if (has_rct) { // check we're clear enough of rct start, to avoid corner cases below THROW_WALLET_EXCEPTION_IF(rct_offsets.size() <= CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, @@ -8062,11 +8067,11 @@ void wallet2::get_outs(std::vector> // get histogram for the amounts we need cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t); - // request histogram for all outputs, except 0 if we have the rct distribution + // request histogram for all pre-rct outputs req_t.amounts.reserve(selected_transfers.size()); for(size_t idx: selected_transfers) - if (!m_transfers[idx].is_rct() || !has_rct_distribution) - req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); + if (!m_transfers[idx].is_rct()) + req_t.amounts.push_back(m_transfers[idx].amount()); if (!req_t.amounts.empty()) { std::sort(req_t.amounts.begin(), req_t.amounts.end()); @@ -8166,7 +8171,7 @@ void wallet2::get_outs(std::vector> COMMAND_RPC_GET_OUTPUTS_BIN::response daemon_resp = AUTO_VAL_INIT(daemon_resp); std::unique_ptr gamma; - if (has_rct_distribution) + if (has_rct) gamma.reset(new gamma_picker(rct_offsets)); size_t num_selected_transfers = 0; @@ -8181,7 +8186,7 @@ void wallet2::get_outs(std::vector> // request more for rct in base recent (locked) coinbases are picked, since they're locked for longer size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0); size_t start = req.outputs.size(); - bool use_histogram = amount != 0 || !has_rct_distribution; + bool use_histogram = amount != 0; const bool output_is_pre_fork = td.m_block_height < segregation_fork_height; uint64_t num_outs = 0, num_recent_outs = 0; @@ -8368,7 +8373,7 @@ void wallet2::get_outs(std::vector> uint64_t i; const char *type = ""; - if (amount == 0 && has_rct_distribution) + if (amount == 0) { THROW_WALLET_EXCEPTION_IF(!gamma, error::wallet_internal_error, "No gamma picker"); // gamma distribution @@ -8530,7 +8535,7 @@ void wallet2::get_outs(std::vector> break; } } - bool use_histogram = amount != 0 || !has_rct_distribution; + bool use_histogram = amount != 0; if (!use_histogram) num_outs = rct_offsets[rct_offsets.size() - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE]; From 04c0da29869ceccbc51d3237404fcf9639a5444a Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 27 Jun 2022 21:23:12 +0200 Subject: [PATCH 040/186] Chunk /gettransactions to avoid hitting restricted RPC limit --- src/wallet/wallet2.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b2a6c0f5a2..186f8d260cc 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3159,14 +3159,18 @@ void wallet2::update_pool_state(std::vector(SLICE_SIZE, txids.size() - offset); + for (size_t n = offset; n < (offset + n_txids); ++n) { + req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txids.at(n).first)); + } + MDEBUG("asking for " << req.txs_hashes.size() << " transactions"); req.decode_as_json = false; req.prune = true; @@ -3183,7 +3187,7 @@ void wallet2::update_pool_state(std::vector Date: Tue, 28 Jun 2022 23:12:03 +0200 Subject: [PATCH 041/186] wallet2: don't use DNS to obtain segregation heights --- src/wallet/wallet2.cpp | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b2a6c0f5a2..b127c75c0fd 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14022,43 +14022,6 @@ uint64_t wallet2::get_segregation_fork_height() const if (m_segregation_height > 0) return m_segregation_height; - if (m_use_dns && !m_offline) - { - // All four MoneroPulse domains have DNSSEC on and valid - static const std::vector dns_urls = { - "segheights.moneropulse.org", - "segheights.moneropulse.net", - "segheights.moneropulse.co", - "segheights.moneropulse.se" - }; - - const uint64_t current_height = get_blockchain_current_height(); - uint64_t best_diff = std::numeric_limits::max(), best_height = 0; - std::vector records; - if (tools::dns_utils::load_txt_records_from_dns(records, dns_urls)) - { - for (const auto& record : records) - { - std::vector fields; - boost::split(fields, record, boost::is_any_of(":")); - if (fields.size() != 2) - continue; - uint64_t height; - if (!string_tools::get_xtype_from_string(height, fields[1])) - continue; - - MINFO("Found segregation height via DNS: " << fields[0] << " fork height at " << height); - uint64_t diff = height > current_height ? height - current_height : current_height - height; - if (diff < best_diff) - { - best_diff = diff; - best_height = height; - } - } - if (best_height) - return best_height; - } - } return SEGREGATION_FORK_HEIGHT; } //---------------------------------------------------------------------------------------------------- From 83aa817b63cf6ba8f8bfa692fbedaa8109c51b81 Mon Sep 17 00:00:00 2001 From: Klaus Frank Date: Wed, 29 Jun 2022 04:51:43 +0200 Subject: [PATCH 042/186] (fix): Confusingly named CI-Job Rename the "build-macos" job within "depends", as it is not building on macOS as the similarly named job within build.yml does. Also, both names overlap which is confusing when looking for step-by-step build instruction examples or when looking at the logfile. --- .github/workflows/depends.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml index f20bf949fd5..32df7dc4211 100644 --- a/.github/workflows/depends.yml +++ b/.github/workflows/depends.yml @@ -17,7 +17,7 @@ env: ccache --set-config=compression=true jobs: - build-macos: + build-cross: runs-on: ubuntu-18.04 env: CCACHE_TEMPDIR: /tmp/.ccache-temp From 8e9c60a682a7d6229a0f765f9bc3c22ed6711a0c Mon Sep 17 00:00:00 2001 From: selsta Date: Wed, 29 Jun 2022 05:19:04 +0200 Subject: [PATCH 043/186] README: depends has only been tested on ubuntu 18.04 and 20.04 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3422280d61..54827c23a5b 100644 --- a/README.md +++ b/README.md @@ -579,7 +579,7 @@ You can also cross-compile static binaries on Linux for Windows and macOS with t * ```make depends target=aarch64-linux-android``` for 64bit android binaries -The required packages are the names for each toolchain on apt. Depending on your distro, they may have different names. +The required packages are the names for each toolchain on apt. Depending on your distro, they may have different names. The `depends` system has been tested on Ubuntu 18.04 and 20.04. Using `depends` might also be easier to compile Monero on Windows than using MSYS. Activate Windows Subsystem for Linux (WSL) with a distro (for example Ubuntu), install the apt build-essentials and follow the `depends` steps as depicted above. From c7b2944f8960c208ceddeb3075a673630ae000cd Mon Sep 17 00:00:00 2001 From: anon Date: Mon, 6 Dec 2021 10:25:01 +0000 Subject: [PATCH 044/186] multisig: fix critical vulnerabilities in signing --- src/cryptonote_config.h | 1 + src/cryptonote_core/CMakeLists.txt | 1 - src/cryptonote_core/cryptonote_tx_utils.cpp | 27 +- src/cryptonote_core/cryptonote_tx_utils.h | 4 +- src/multisig/CMakeLists.txt | 5 +- src/multisig/multisig_clsag_context.cpp | 257 ++++++ src/multisig/multisig_clsag_context.h | 137 +++ src/multisig/multisig_tx_builder_ringct.cpp | 943 ++++++++++++++++++++ src/multisig/multisig_tx_builder_ringct.h | 119 +++ src/ringct/rctSigs.cpp | 164 +--- src/ringct/rctSigs.h | 19 +- src/wallet/wallet2.cpp | 306 +++++-- src/wallet/wallet2.h | 23 +- tests/core_tests/chaingen.cpp | 2 +- tests/core_tests/multisig.cpp | 181 ++-- tests/core_tests/multisig.h | 2 +- tests/core_tests/rct.cpp | 2 +- tests/core_tests/wallet_tools.cpp | 2 +- tests/performance_tests/rct_mlsag.h | 4 +- tests/performance_tests/sig_clsag.h | 2 +- tests/performance_tests/sig_mlsag.h | 2 +- tests/unit_tests/bulletproofs.cpp | 3 +- tests/unit_tests/ringct.cpp | 34 +- tests/unit_tests/serialization.cpp | 4 +- 24 files changed, 1857 insertions(+), 387 deletions(-) create mode 100644 src/multisig/multisig_clsag_context.cpp create mode 100644 src/multisig/multisig_clsag_context.h create mode 100644 src/multisig/multisig_tx_builder_ringct.cpp create mode 100644 src/multisig/multisig_tx_builder_ringct.h diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index f2a8e9b79d9..962346017c3 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -239,6 +239,7 @@ namespace config const unsigned char HASH_KEY_MEMORY = 'k'; const unsigned char HASH_KEY_MULTISIG[] = {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const unsigned char HASH_KEY_MULTISIG_KEY_AGGREGATION[] = "Multisig_key_agg"; + const unsigned char HASH_KEY_CLSAG_ROUND_MULTISIG[] = "CLSAG_round_ms_merge_factor"; const unsigned char HASH_KEY_TXPROOF_V2[] = "TXPROOF_V2"; const unsigned char HASH_KEY_CLSAG_ROUND[] = "CLSAG_round"; const unsigned char HASH_KEY_CLSAG_AGG_0[] = "CLSAG_agg_0"; diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index e272b94f060..69411e37965 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -49,7 +49,6 @@ target_link_libraries(cryptonote_core common cncrypto blockchain_db - multisig ringct device hardforks diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 1d2024a0521..472026217dc 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -203,7 +203,7 @@ namespace cryptonote return addr.m_view_public_key; } //--------------------------------------------------------------- - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, bool shuffle_outs, bool use_view_tags) + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags) { hw::device &hwdev = sender_account_keys.get_device(); @@ -216,10 +216,6 @@ namespace cryptonote std::vector amount_keys; tx.set_null(); amount_keys.clear(); - if (msout) - { - msout->c.clear(); - } tx.version = rct ? 2 : 1; tx.unlock_time = unlock_time; @@ -333,8 +329,8 @@ namespace cryptonote return false; } - //check that derivated key is equal with real output key (if non multisig) - if(!msout && !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) ) + //check that derivated key is equal with real output key + if(!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) ) { LOG_ERROR("derived public key mismatch with output public key at index " << idx << ", real out " << src_entr.real_output << "! "<< ENDL << "derived_key:" << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" @@ -347,7 +343,7 @@ namespace cryptonote //put key image into tx input txin_to_key input_to_key; input_to_key.amount = src_entr.amount; - input_to_key.k_image = msout ? rct::rct2ki(src_entr.multisig_kLRki.ki) : img; + input_to_key.k_image = img; //fill outputs array and use relative offsets for(const tx_source_entry::output_entry& out_entry: src_entr.outputs) @@ -529,7 +525,6 @@ namespace cryptonote rct::keyV destinations; std::vector inamounts, outamounts; std::vector index; - std::vector kLRki; for (size_t i = 0; i < sources.size(); ++i) { rct::ctkey ctkey; @@ -543,10 +538,6 @@ namespace cryptonote memwipe(&ctkey, sizeof(rct::ctkey)); // inPk: (public key, commitment) // will be done when filling in mixRing - if (msout) - { - kLRki.push_back(sources[i].multisig_kLRki); - } } for (size_t i = 0; i < tx.vout.size(); ++i) { @@ -598,9 +589,9 @@ namespace cryptonote get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev); rct::ctkeyV outSk; if (use_simple_rct) - tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, rct_config, hwdev); + tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, index, outSk, rct_config, hwdev); else - tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption + tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption memwipe(inSk.data(), inSk.size() * sizeof(rct::ctkey)); CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout"); @@ -613,7 +604,7 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, bool use_view_tags) + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool use_view_tags) { hw::device &hwdev = sender_account_keys.get_device(); hwdev.open_tx(tx_key); @@ -634,7 +625,7 @@ namespace cryptonote } bool shuffle_outs = true; - bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, msout, shuffle_outs, use_view_tags); + bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, shuffle_outs, use_view_tags); hwdev.close_tx(); return r; } catch(...) { @@ -650,7 +641,7 @@ namespace cryptonote crypto::secret_key tx_key; std::vector additional_tx_keys; std::vector destinations_copy = destinations; - return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0}, NULL, false); + return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0}); } //--------------------------------------------------------------- bool generate_genesis_block( diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index f4ffb98ff09..12d6b8ce512 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -119,8 +119,8 @@ namespace cryptonote //--------------------------------------------------------------- crypto::public_key get_destination_view_key_pub(const std::vector &destinations, const boost::optional& change_addr); bool construct_tx(const account_keys& sender_account_keys, std::vector &sources, const std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time); - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, rct::multisig_out *msout = NULL, bool shuffle_outs = true, bool use_view_tags = false); - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, rct::multisig_out *msout = NULL, bool use_view_tags = false); + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false); + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false); bool generate_output_ephemeral_keys(const size_t tx_version, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key, const cryptonote::tx_destination_entry &dst_entr, const boost::optional &change_addr, const size_t output_index, const bool &need_additional_txkeys, const std::vector &additional_tx_keys, diff --git a/src/multisig/CMakeLists.txt b/src/multisig/CMakeLists.txt index 294a1721fe0..61e658a394d 100644 --- a/src/multisig/CMakeLists.txt +++ b/src/multisig/CMakeLists.txt @@ -30,7 +30,9 @@ set(multisig_sources multisig.cpp multisig_account.cpp multisig_account_kex_impl.cpp - multisig_kex_msg.cpp) + multisig_clsag_context.cpp + multisig_kex_msg.cpp + multisig_tx_builder_ringct.cpp) set(multisig_headers) @@ -48,6 +50,7 @@ target_link_libraries(multisig PUBLIC ringct cryptonote_basic + cryptonote_core common cncrypto PRIVATE diff --git a/src/multisig/multisig_clsag_context.cpp b/src/multisig/multisig_clsag_context.cpp new file mode 100644 index 00000000000..e3417b89655 --- /dev/null +++ b/src/multisig/multisig_clsag_context.cpp @@ -0,0 +1,257 @@ +// Copyright (c) 2021, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "multisig_clsag_context.h" + +#include "int-util.h" + +#include "crypto/crypto.h" +#include "cryptonote_config.h" +#include "ringct/rctOps.h" +#include "ringct/rctTypes.h" + +#include +#include +#include + +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "multisig" + +namespace multisig { + +namespace signing { +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +template +static rct::key string_to_key(const unsigned char (&str)[N]) { + rct::key tmp{}; + static_assert(sizeof(tmp.bytes) >= N, ""); + std::memcpy(tmp.bytes, str, N); + return tmp; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static void encode_int_to_key_le(const unsigned int i, rct::key &k_out) +{ + static_assert(sizeof(unsigned int) <= sizeof(std::uint64_t), "unsigned int max too large"); + static_assert(sizeof(std::uint64_t) <= sizeof(rct::key), ""); + std::uint64_t temp_i{SWAP64LE(i)}; + std::memcpy(k_out.bytes, &temp_i, sizeof(temp_i)); +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +bool CLSAG_context_t::init( + const rct::keyV& P, + const rct::keyV& C_nonzero, + const rct::key& C_offset, + const rct::key& message, + const rct::key& I, + const rct::key& D, + const unsigned int l, + const rct::keyV& s, + const std::size_t num_alpha_components +) +{ + initialized = false; + + n = P.size(); + if (n <= 0) + return false; + if (C_nonzero.size() != n) + return false; + if (s.size() != n) + return false; + if (l >= n) + return false; + + c_params.clear(); + c_params.reserve(n * 2 + 5); + b_params.clear(); + b_params.reserve(n * 3 + 2 * num_alpha_components + 7); + + c_params.push_back(string_to_key(config::HASH_KEY_CLSAG_ROUND)); + b_params.push_back(string_to_key(config::HASH_KEY_CLSAG_ROUND_MULTISIG)); + c_params.insert(c_params.end(), P.begin(), P.end()); + b_params.insert(b_params.end(), P.begin(), P.end()); + c_params.insert(c_params.end(), C_nonzero.begin(), C_nonzero.end()); + b_params.insert(b_params.end(), C_nonzero.begin(), C_nonzero.end()); + c_params.emplace_back(C_offset); + b_params.emplace_back(C_offset); + c_params.emplace_back(message); + b_params.emplace_back(message); + c_params_L_offset = c_params.size(); + b_params_L_offset = b_params.size(); + c_params.resize(c_params.size() + 1); //this is where L will be inserted later + b_params.resize(b_params.size() + num_alpha_components); //multisig aggregate public nonces for L will be inserted here later + c_params_R_offset = c_params.size(); + b_params_R_offset = b_params.size(); + c_params.resize(c_params.size() + 1); //this is where R will be inserted later + b_params.resize(b_params.size() + num_alpha_components); //multisig aggregate public nonces for R will be inserted here later + b_params.emplace_back(I); + b_params.emplace_back(D); + b_params.insert(b_params.end(), s.begin(), s.begin() + l); //fake responses before 'l' + b_params.insert(b_params.end(), s.begin() + l + 1, s.end()); //fake responses after 'l' + b_params.emplace_back(); + encode_int_to_key_le(l, b_params.back()); //real signing index 'l' + b_params.emplace_back(); + encode_int_to_key_le(num_alpha_components, b_params.back()); //number of parallel nonces + b_params.emplace_back(); + encode_int_to_key_le(n, b_params.back()); //number of ring members + + rct::keyV mu_P_params; + rct::keyV mu_C_params; + mu_P_params.reserve(n * 2 + 4); + mu_C_params.reserve(n * 2 + 4); + + mu_P_params.push_back(string_to_key(config::HASH_KEY_CLSAG_AGG_0)); + mu_C_params.push_back(string_to_key(config::HASH_KEY_CLSAG_AGG_1)); + mu_P_params.insert(mu_P_params.end(), P.begin(), P.end()); + mu_C_params.insert(mu_C_params.end(), P.begin(), P.end()); + mu_P_params.insert(mu_P_params.end(), C_nonzero.begin(), C_nonzero.end()); + mu_C_params.insert(mu_C_params.end(), C_nonzero.begin(), C_nonzero.end()); + mu_P_params.emplace_back(I); + mu_C_params.emplace_back(I); + mu_P_params.emplace_back(scalarmultKey(D, rct::INV_EIGHT)); + mu_C_params.emplace_back(mu_P_params.back()); + mu_P_params.emplace_back(C_offset); + mu_C_params.emplace_back(C_offset); + mu_P = hash_to_scalar(mu_P_params); + mu_C = hash_to_scalar(mu_C_params); + + rct::geDsmp I_precomp; + rct::geDsmp D_precomp; + rct::precomp(I_precomp.k, I); + rct::precomp(D_precomp.k, D); + rct::key wH_l; + rct::addKeys3(wH_l, mu_P, I_precomp.k, mu_C, D_precomp.k); + rct::precomp(wH_l_precomp.k, wH_l); + W_precomp.resize(n); + H_precomp.resize(n); + for (std::size_t i = 0; i < n; ++i) { + rct::geDsmp P_precomp; + rct::geDsmp C_precomp; + rct::key C; + rct::subKeys(C, C_nonzero[i], C_offset); + rct::precomp(P_precomp.k, P[i]); + rct::precomp(C_precomp.k, C); + rct::key W; + rct::addKeys3(W, mu_P, P_precomp.k, mu_C, C_precomp.k); + rct::precomp(W_precomp[i].k, W); + ge_p3 Hi_p3; + rct::hash_to_p3(Hi_p3, P[i]); + ge_dsm_precomp(H_precomp[i].k, &Hi_p3); + } + rct::precomp(G_precomp.k, rct::G); + this->l = l; + this->s = s; + this->num_alpha_components = num_alpha_components; + + initialized = true; + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +bool CLSAG_context_t::combine_alpha_and_compute_challenge( + const rct::keyV& total_alpha_G, + const rct::keyV& total_alpha_H, + const rct::keyV& alpha, + rct::key& alpha_combined, + rct::key& c_0, + rct::key& c +) +{ + if (not initialized) + return false; + + if (num_alpha_components != total_alpha_G.size()) + return false; + if (num_alpha_components != total_alpha_H.size()) + return false; + if (num_alpha_components != alpha.size()) + return false; + + // insert aggregate public nonces for L and R components + for (std::size_t i = 0; i < num_alpha_components; ++i) { + b_params[b_params_L_offset + i] = total_alpha_G[i]; + b_params[b_params_R_offset + i] = total_alpha_H[i]; + } + + // musig2-style combination factor 'b' + const rct::key b = rct::hash_to_scalar(b_params); + + // 1) store combined public nonces in the 'L' and 'R' slots for computing the initial challenge + // - L = sum_i(b^i total_alpha_G[i]) + // - R = sum_i(b^i total_alpha_H[i]) + // 2) compute the local signer's combined private nonce + // - alpha_combined = sum_i(b^i * alpha[i]) + rct::key& L_l = c_params[c_params_L_offset]; + rct::key& R_l = c_params[c_params_R_offset]; + rct::key b_i = rct::identity(); + L_l = rct::identity(); + R_l = rct::identity(); + alpha_combined = rct::zero(); + for (std::size_t i = 0; i < num_alpha_components; ++i) { + rct::addKeys(L_l, L_l, rct::scalarmultKey(total_alpha_G[i], b_i)); + rct::addKeys(R_l, R_l, rct::scalarmultKey(total_alpha_H[i], b_i)); + sc_muladd(alpha_combined.bytes, alpha[i].bytes, b_i.bytes, alpha_combined.bytes); + sc_mul(b_i.bytes, b_i.bytes, b.bytes); + } + + // compute initial challenge from real spend components + c = rct::hash_to_scalar(c_params); + + // 1) c_0: find the CLSAG's challenge for index '0', which will be stored in the proof + // note: in the CLSAG implementation in ringct/rctSigs, c_0 is denoted 'c1' (a notation error) + // 2) c: find the final challenge for the multisig signers to respond to + for (std::size_t i = (l + 1) % n; i != l; i = (i + 1) % n) { + if (i == 0) + c_0 = c; + rct::addKeys3(c_params[c_params_L_offset], s[i], G_precomp.k, c, W_precomp[i].k); + rct::addKeys3(c_params[c_params_R_offset], s[i], H_precomp[i].k, c, wH_l_precomp.k); + c = rct::hash_to_scalar(c_params); + } + if (l == 0) + c_0 = c; + + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +bool CLSAG_context_t::get_mu( + rct::key& mu_P, + rct::key& mu_C +) const +{ + if (not initialized) + return false; + mu_P = this->mu_P; + mu_C = this->mu_C; + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +} //namespace signing + +} //namespace multisig diff --git a/src/multisig/multisig_clsag_context.h b/src/multisig/multisig_clsag_context.h new file mode 100644 index 00000000000..5017e8688b2 --- /dev/null +++ b/src/multisig/multisig_clsag_context.h @@ -0,0 +1,137 @@ +// Copyright (c) 2021, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//// +// References +// - CLSAG (base signature scheme): https://eprint.iacr.org/2019/654 +// - MuSig2 (style for multisig signing): https://eprint.iacr.org/2020/1261 +/// + + +#pragma once + +#include "ringct/rctTypes.h" + +#include + + +namespace multisig { + +namespace signing { + +class CLSAG_context_t final { +private: + // is the CLSAG context initialized? + bool initialized; + // challenge components: c = H(domain-separator, {P}, {C}, C_offset, message, L, R) + rct::keyV c_params; + // indices in c_params where L and R will be + std::size_t c_params_L_offset; + std::size_t c_params_R_offset; + // musig2-style nonce combination factor components for multisig signing + // b = H(domain-separator, {P}, {C}, C_offset, message, {L_combined_alphas}, {R_combined_alphas}, I, D, {s_non_l}, l, k, n) + // - {P} = ring of one-time addresses + // - {C} = ring of amount commitments (1:1 with one-time addresses) + // - C_offset = pseudo-output commitment to offset all amount commitments with + // - message = message the CLSAG will sign + // - {L_combined_alphas} = set of summed-together public nonces from all multisig signers for this CLSAG's L component + // - {R_combined_alphas} = set of summed-together public nonces from all multisig signers for this CLSAG's R component + // - I = key image for one-time address at {P}[l] + // - D = auxiliary key image for the offsetted amount commitment '{C}[l] - C_offset' + // - {s_non_l} = fake responses for this proof + // - l = real signing index in {P} and '{C} - C_offset' + // - k = number of parallel nonces that each participant provides + // - n = number of ring members + rct::keyV b_params; + // indices in b_params where L and R 'alpha' components will be + std::size_t b_params_L_offset; + std::size_t b_params_R_offset; + // CLSAG 'concise' coefficients for {P} and '{C} - C_offset' + // mu_x = H(domain-separator, {P}, {C}, I, (1/8)*D, C_offset) + // - note: 'D' is stored in the form '(1/8)*D' in transaction data + rct::key mu_P; + rct::key mu_C; + // ring size + std::size_t n; + // aggregate key image: mu_P*I + mu_C*D + rct::geDsmp wH_l_precomp; + // aggregate ring members: mu_P*P_i + mu_C*(C_i - C_offset) + std::vector W_precomp; + // key image component base keys: H_p(P_i) + std::vector H_precomp; + // cache for later: generator 'G' in 'precomp' representation + rct::geDsmp G_precomp; + // real signing index in this CLSAG + std::size_t l; + // signature responses + rct::keyV s; + // number of signing nonces expected per signer + std::size_t num_alpha_components; +public: + CLSAG_context_t() : initialized{false} {} + + // prepare CLSAG challenge context + bool init( + const rct::keyV& P, + const rct::keyV& C_nonzero, + const rct::key& C_offset, + const rct::key& message, + const rct::key& I, + const rct::key& D, + const unsigned int l, + const rct::keyV& s, + const std::size_t num_alpha_components + ); + + // get the local signer's combined musig2-style private nonce and compute the CLSAG challenge + bool combine_alpha_and_compute_challenge( + // set of summed-together musig2-style public nonces from all multisig signers for this CLSAG's L component + const rct::keyV& total_alpha_G, + // set of summed-together musig2-style public nonces from all multisig signers for this CLSAG's R component + const rct::keyV& total_alpha_H, + // local signer's private musig2-style nonces + const rct::keyV& alpha, + // local signer's final private nonce, using musig2-style combination with factor 'b' + // alpha_combined = sum_i(b^i * alpha[i]) + rct::key& alpha_combined, + // CLSAG challenge to store in the proof + rct::key& c_0, + // final CLSAG challenge to respond to (need this to make multisig partial signatures) + rct::key& c + ); + + // getter for CLSAG 'concise' coefficients + bool get_mu( + rct::key& mu_P, + rct::key& mu_C + ) const; +}; + +} //namespace signing + +} //namespace multisig diff --git a/src/multisig/multisig_tx_builder_ringct.cpp b/src/multisig/multisig_tx_builder_ringct.cpp new file mode 100644 index 00000000000..cbc556b71bc --- /dev/null +++ b/src/multisig/multisig_tx_builder_ringct.cpp @@ -0,0 +1,943 @@ +// Copyright (c) 2021, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "multisig_tx_builder_ringct.h" + +#include "int-util.h" +#include "memwipe.h" + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/account.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_tx_utils.h" +#include "device/device.hpp" +#include "multisig_clsag_context.h" +#include "ringct/bulletproofs.h" +#include "ringct/bulletproofs_plus.h" +#include "ringct/rctSigs.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "multisig" + +namespace multisig { + +namespace signing { +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +bool view_tag_required(const int bp_version) +{ + // view tags were introduced at the same time as BP+, so they are needed after BP+ (v4 and later) + if (bp_version <= 3) + return false; + else + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static void sort_sources( + std::vector& sources +) +{ + std::sort(sources.begin(), sources.end(), [](const auto& lhs, const auto& rhs){ + const rct::key& ki0 = lhs.multisig_kLRki.ki; + const rct::key& ki1 = rhs.multisig_kLRki.ki; + return memcmp(&ki0, &ki1, sizeof(rct::key)) > 0; + }); +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool compute_keys_for_sources( + const cryptonote::account_keys& account_keys, + const std::vector& sources, + const std::uint32_t subaddr_account, + const std::set& subaddr_minor_indices, + rct::keyV& input_secret_keys +) +{ + const std::size_t num_sources = sources.size(); + hw::device& hwdev = account_keys.get_device(); + std::unordered_map subaddresses; + for (const std::uint32_t minor_index: subaddr_minor_indices) { + subaddresses[hwdev.get_subaddress_spend_public_key( + account_keys, + {subaddr_account, minor_index} + )] = {subaddr_account, minor_index}; + } + input_secret_keys.resize(num_sources); + for (std::size_t i = 0; i < num_sources; ++i) { + const auto& src = sources[i]; + crypto::key_image tmp_key_image; + cryptonote::keypair tmp_keys; + if (src.real_output >= src.outputs.size()) + return false; + if (not cryptonote::generate_key_image_helper( + account_keys, + subaddresses, + rct::rct2pk(src.outputs[src.real_output].second.dest), + src.real_out_tx_key, + src.real_out_additional_tx_keys, + src.real_output_in_tx_index, + tmp_keys, + tmp_key_image, + hwdev + )) { + return false; + } + input_secret_keys[i] = rct::sk2rct(tmp_keys.sec); + } + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static void shuffle_destinations( + std::vector& destinations +) +{ + std::shuffle(destinations.begin(), destinations.end(), crypto::random_device{}); +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool set_tx_extra( + const cryptonote::account_keys& account_keys, + const std::vector& destinations, + const cryptonote::tx_destination_entry& change, + const crypto::secret_key& tx_secret_key, + const crypto::public_key& tx_public_key, + const std::vector& tx_aux_public_keys, + const std::vector& extra, + cryptonote::transaction& tx +) +{ + hw::device &hwdev = account_keys.get_device(); + tx.extra = extra; + // if we have a stealth payment id, find it and encrypt it with the tx key now + std::vector tx_extra_fields; + if (cryptonote::parse_tx_extra(tx.extra, tx_extra_fields)) + { + bool add_dummy_payment_id = true; + cryptonote::tx_extra_nonce extra_nonce; + if (cryptonote::find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) + { + crypto::hash payment_id = crypto::null_hash; + crypto::hash8 payment_id8 = crypto::null_hash8; + if (cryptonote::get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) + { + LOG_PRINT_L2("Encrypting payment id " << payment_id8); + crypto::public_key view_key_pub = cryptonote::get_destination_view_key_pub(destinations, change.addr); + if (view_key_pub == crypto::null_pkey) + { + // valid combinations: + // - 1 output with encrypted payment ID, dummy change output (0 amount) + // - 0 outputs, 1 change output with encrypted payment ID + // - 1 output with encrypted payment ID, 1 change output + LOG_ERROR("Destinations have to have exactly one output to support encrypted payment ids"); + return false; + } + + if (!hwdev.encrypt_payment_id(payment_id8, view_key_pub, tx_secret_key)) + { + LOG_ERROR("Failed to encrypt payment id"); + return false; + } + + std::string extra_nonce_updated; + cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce_updated, payment_id8); + cryptonote::remove_field_from_tx_extra(tx.extra, typeid(cryptonote::tx_extra_nonce)); + if (!cryptonote::add_extra_nonce_to_tx_extra(tx.extra, extra_nonce_updated)) + { + LOG_ERROR("Failed to add encrypted payment id to tx extra"); + return false; + } + LOG_PRINT_L1("Encrypted payment ID: " << payment_id8); + add_dummy_payment_id = false; + } + else if (cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + { + add_dummy_payment_id = false; + } + } + + // we don't add one if we've got more than the usual 1 destination plus change + if (destinations.size() > 2) + add_dummy_payment_id = false; + + if (add_dummy_payment_id) + { + // if we have neither long nor short payment id, add a dummy short one, + // this should end up being the vast majority of txes as time goes on + std::string extra_nonce_updated; + crypto::hash8 payment_id8 = crypto::null_hash8; + crypto::public_key view_key_pub = cryptonote::get_destination_view_key_pub(destinations, change.addr); + if (view_key_pub == crypto::null_pkey) + { + LOG_ERROR("Failed to get key to encrypt dummy payment id with"); + } + else + { + hwdev.encrypt_payment_id(payment_id8, view_key_pub, tx_secret_key); + cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce_updated, payment_id8); + if (!cryptonote::add_extra_nonce_to_tx_extra(tx.extra, extra_nonce_updated)) + { + LOG_ERROR("Failed to add dummy encrypted payment id to tx extra"); + // continue anyway + } + } + } + } + else + { + MWARNING("Failed to parse tx extra"); + tx_extra_fields.clear(); + } + + cryptonote::remove_field_from_tx_extra(tx.extra, typeid(cryptonote::tx_extra_pub_key)); + cryptonote::add_tx_pub_key_to_extra(tx.extra, tx_public_key); + cryptonote::remove_field_from_tx_extra(tx.extra, typeid(cryptonote::tx_extra_additional_pub_keys)); + LOG_PRINT_L2("tx pubkey: " << tx_public_key); + if (tx_aux_public_keys.size()) + { + LOG_PRINT_L2("additional tx pubkeys: "); + for (size_t i = 0; i < tx_aux_public_keys.size(); ++i) + LOG_PRINT_L2(tx_aux_public_keys[i]); + cryptonote::add_additional_tx_pub_keys_to_extra(tx.extra, tx_aux_public_keys); + } + if (not cryptonote::sort_tx_extra(tx.extra, tx.extra)) + return false; + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool compute_keys_for_destinations( + const cryptonote::account_keys& account_keys, + const std::uint32_t subaddr_account, + const std::vector& destinations, + const cryptonote::tx_destination_entry& change, + const std::vector& extra, + const bool use_view_tags, + const bool reconstruction, + crypto::secret_key& tx_secret_key, + std::vector& tx_aux_secret_keys, + rct::keyV& output_public_keys, + rct::keyV& output_amount_secret_keys, + std::vector& view_tags, + cryptonote::transaction& unsigned_tx +) +{ + hw::device &hwdev = account_keys.get_device(); + + // check non-zero change amount case + if (change.amount > 0) + { + // the change output must be directed to the local account + if (change.addr != hwdev.get_subaddress(account_keys, {subaddr_account})) + return false; + + // expect the change destination to be in the destination set + if (std::find_if(destinations.begin(), destinations.end(), + [&change](const auto &destination) -> bool + { + return destination.addr == change.addr; + }) == destinations.end()) + return false; + } + + // collect non-change recipients into normal/subaddress buckets + std::unordered_set unique_subbaddr_recipients; + std::unordered_set unique_std_recipients; + for(const auto& dst_entr: destinations) { + if (dst_entr.addr == change.addr) + continue; + if (dst_entr.is_subaddress) + unique_subbaddr_recipients.insert(dst_entr.addr); + else + unique_std_recipients.insert(dst_entr.addr); + } + + if (not reconstruction) { + tx_secret_key = rct::rct2sk(rct::skGen()); + } + + // tx pub key: R + crypto::public_key tx_public_key; + if (unique_std_recipients.empty() && unique_subbaddr_recipients.size() == 1) { + // if there is exactly 1 non-change recipient, and it's to a subaddress, then the tx pubkey = r*Ksi_nonchange_recipient + tx_public_key = rct::rct2pk( + hwdev.scalarmultKey( + rct::pk2rct(unique_subbaddr_recipients.begin()->m_spend_public_key), + rct::sk2rct(tx_secret_key) + )); + } + else { + // otherwise, the tx pub key = r*G + // - if there are > 1 non-change recipients, with at least one to a subaddress, then the tx pubkey is not used + // (additional tx keys will be used instead) + // - if all non-change recipients are to normal addresses, then the tx pubkey will be used by all recipients + // (including change recipient, even if change is to a subaddress) + tx_public_key = rct::rct2pk(hwdev.scalarmultBase(rct::sk2rct(tx_secret_key))); + } + + // additional tx pubkeys: R_t + // - add if there are > 1 non-change recipients, with at least one to a subaddress + const std::size_t num_destinations = destinations.size(); + + const bool need_tx_aux_keys = unique_subbaddr_recipients.size() + bool(unique_std_recipients.size()) > 1; + if (not reconstruction and need_tx_aux_keys) { + tx_aux_secret_keys.clear(); + tx_aux_secret_keys.reserve(num_destinations); + for(std::size_t i = 0; i < num_destinations; ++i) + tx_aux_secret_keys.push_back(rct::rct2sk(rct::skGen())); + } + + output_public_keys.resize(num_destinations); + view_tags.resize(num_destinations); + std::vector tx_aux_public_keys; + crypto::public_key temp_output_public_key; + + for (std::size_t i = 0; i < num_destinations; ++i) { + if (not hwdev.generate_output_ephemeral_keys( + unsigned_tx.version, + account_keys, + tx_public_key, + tx_secret_key, + destinations[i], + change.addr, + i, + need_tx_aux_keys, + tx_aux_secret_keys, + tx_aux_public_keys, + output_amount_secret_keys, + temp_output_public_key, + use_view_tags, + view_tags[i] //unused variable if use_view_tags is not set + )) { + return false; + } + output_public_keys[i] = rct::pk2rct(temp_output_public_key); + } + + if (num_destinations != output_amount_secret_keys.size()) + return false; + + CHECK_AND_ASSERT_MES( + tx_aux_public_keys.size() == tx_aux_secret_keys.size(), + false, + "Internal error creating additional public keys" + ); + + if (not set_tx_extra(account_keys, destinations, change, tx_secret_key, tx_public_key, tx_aux_public_keys, extra, unsigned_tx)) + return false; + + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static void set_tx_inputs( + const std::vector& sources, + cryptonote::transaction& unsigned_tx +) +{ + const std::size_t num_sources = sources.size(); + unsigned_tx.vin.resize(num_sources); + for (std::size_t i = 0; i < num_sources; ++i) { + std::vector offsets; + offsets.reserve(sources[i].outputs.size()); + for (const auto& e: sources[i].outputs) + offsets.emplace_back(e.first); + unsigned_tx.vin[i] = cryptonote::txin_to_key{ + .amount = 0, + .key_offsets = cryptonote::absolute_output_offsets_to_relative(offsets), + .k_image = rct::rct2ki(sources[i].multisig_kLRki.ki), + }; + } +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool onetime_addresses_are_unique(const rct::keyV& output_public_keys) +{ + for (auto addr_it = output_public_keys.begin(); addr_it != output_public_keys.end(); ++addr_it) + { + if (std::find(output_public_keys.begin(), addr_it, *addr_it) != addr_it) + return false; + } + + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool set_tx_outputs(const rct::keyV& output_public_keys, cryptonote::transaction& unsigned_tx) +{ + // sanity check: all onetime addresses should be unique + if (not onetime_addresses_are_unique(output_public_keys)) + return false; + + // set the tx outputs + const std::size_t num_destinations = output_public_keys.size(); + unsigned_tx.vout.resize(num_destinations); + for (std::size_t i = 0; i < num_destinations; ++i) + cryptonote::set_tx_out(0, rct::rct2pk(output_public_keys[i]), false, crypto::view_tag{}, unsigned_tx.vout[i]); + + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool set_tx_outputs_with_view_tags( + const rct::keyV& output_public_keys, + const std::vector& view_tags, + cryptonote::transaction& unsigned_tx +) +{ + // sanity check: all onetime addresses should be unique + if (not onetime_addresses_are_unique(output_public_keys)) + return false; + + // set the tx outputs (with view tags) + const std::size_t num_destinations = output_public_keys.size(); + CHECK_AND_ASSERT_MES(view_tags.size() == num_destinations, false, + "multisig signing protocol: internal error, view tag size mismatch."); + unsigned_tx.vout.resize(num_destinations); + for (std::size_t i = 0; i < num_destinations; ++i) + cryptonote::set_tx_out(0, rct::rct2pk(output_public_keys[i]), true, view_tags[i], unsigned_tx.vout[i]); + + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static void make_new_range_proofs(const int bp_version, + const std::vector& output_amounts, + const rct::keyV& output_amount_masks, + rct::rctSigPrunable& sigs) +{ + sigs.bulletproofs.clear(); + sigs.bulletproofs_plus.clear(); + + if (bp_version == 3) + sigs.bulletproofs.push_back(rct::bulletproof_PROVE(output_amounts, output_amount_masks)); + else if (bp_version == 4) + sigs.bulletproofs_plus.push_back(rct::bulletproof_plus_PROVE(output_amounts, output_amount_masks)); +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool try_reconstruct_range_proofs(const int bp_version, + const rct::rctSigPrunable& original_sigs, + const std::size_t num_destinations, + const rct::ctkeyV& output_public_keys, + rct::rctSigPrunable& reconstructed_sigs) +{ + auto try_reconstruct_range_proofs = + [&](const auto &original_range_proofs, auto &new_range_proofs) -> bool + { + if (original_range_proofs.size() != 1) + return false; + + new_range_proofs = original_range_proofs; + new_range_proofs[0].V.resize(num_destinations); + for (std::size_t i = 0; i < num_destinations; ++i) + new_range_proofs[0].V[i] = rct::scalarmultKey(output_public_keys[i].mask, rct::INV_EIGHT); + + return true; + }; + + if (bp_version == 3) + { + if (not try_reconstruct_range_proofs(original_sigs.bulletproofs, reconstructed_sigs.bulletproofs)) + return false; + return rct::bulletproof_VERIFY(reconstructed_sigs.bulletproofs); + } + else if (bp_version == 4) + { + if (not try_reconstruct_range_proofs(original_sigs.bulletproofs_plus, reconstructed_sigs.bulletproofs_plus)) + return false; + return rct::bulletproof_plus_VERIFY(reconstructed_sigs.bulletproofs_plus); + } + + return false; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool set_tx_rct_signatures( + const std::uint64_t fee, + const std::vector& sources, + const std::vector& destinations, + const rct::keyV& input_secret_keys, + const rct::keyV& output_public_keys, + const rct::keyV& output_amount_secret_keys, + const rct::RCTConfig& rct_config, + const bool reconstruction, + cryptonote::transaction& unsigned_tx, + std::vector& CLSAG_contexts, + rct::keyV& cached_w +) +{ + if (rct_config.bp_version != 3 && + rct_config.bp_version != 4) + return false; + if (rct_config.range_proof_type != rct::RangeProofPaddedBulletproof) + return false; + + const std::size_t num_destinations = destinations.size(); + const std::size_t num_sources = sources.size(); + + // rct_signatures component of tx + rct::rctSig rv{}; + + // set misc. fields + if (rct_config.bp_version == 3) + rv.type = rct::RCTTypeCLSAG; + else if (rct_config.bp_version == 4) + rv.type = rct::RCTTypeBulletproofPlus; + else + return false; + rv.txnFee = fee; + rv.message = rct::hash2rct(cryptonote::get_transaction_prefix_hash(unsigned_tx)); + + // define outputs + std::vector output_amounts(num_destinations); + rct::keyV output_amount_masks(num_destinations); + rv.ecdhInfo.resize(num_destinations); + rv.outPk.resize(num_destinations); + for (std::size_t i = 0; i < num_destinations; ++i) { + rv.outPk[i].dest = output_public_keys[i]; + output_amounts[i] = destinations[i].amount; + output_amount_masks[i] = genCommitmentMask(output_amount_secret_keys[i]); + rv.ecdhInfo[i].amount = rct::d2h(output_amounts[i]); + rct::addKeys2( + rv.outPk[i].mask, + output_amount_masks[i], + rv.ecdhInfo[i].amount, + rct::H + ); + rct::ecdhEncode(rv.ecdhInfo[i], output_amount_secret_keys[i], true); + } + + // output range proofs + if (not reconstruction) { + make_new_range_proofs(rct_config.bp_version, output_amounts, output_amount_masks, rv.p); + } + else { + if (not try_reconstruct_range_proofs(rct_config.bp_version, + unsigned_tx.rct_signatures.p, + num_destinations, + rv.outPk, + rv.p)) + return false; + } + + // prepare rings for input CLSAGs + rv.mixRing.resize(num_sources); + for (std::size_t i = 0; i < num_sources; ++i) { + const std::size_t ring_size = sources[i].outputs.size(); + rv.mixRing[i].resize(ring_size); + for (std::size_t j = 0; j < ring_size; ++j) { + rv.mixRing[i][j].dest = sources[i].outputs[j].second.dest; + rv.mixRing[i][j].mask = sources[i].outputs[j].second.mask; + } + } + + // make pseudo-output commitments + rct::keyV a; //pseudo-output commitment blinding factors + auto a_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(static_cast(a.data()), a.size() * sizeof(rct::key)); + }); + if (not reconstruction) { + a.resize(num_sources); + rv.p.pseudoOuts.resize(num_sources); + a[num_sources - 1] = rct::zero(); + for (std::size_t i = 0; i < num_destinations; ++i) { + sc_add( + a[num_sources - 1].bytes, + a[num_sources - 1].bytes, + output_amount_masks[i].bytes + ); + } + for (std::size_t i = 0; i < num_sources - 1; ++i) { + rct::skGen(a[i]); + sc_sub( + a[num_sources - 1].bytes, + a[num_sources - 1].bytes, + a[i].bytes + ); + rct::genC(rv.p.pseudoOuts[i], a[i], sources[i].amount); + } + rct::genC( + rv.p.pseudoOuts[num_sources - 1], + a[num_sources - 1], + sources[num_sources - 1].amount + ); + } + // check balance if reconstructing the tx + else { + rv.p.pseudoOuts = unsigned_tx.rct_signatures.p.pseudoOuts; + if (num_sources != rv.p.pseudoOuts.size()) + return false; + rct::key balance_accumulator = rct::scalarmultH(rct::d2h(fee)); + for (const auto& e: rv.outPk) + rct::addKeys(balance_accumulator, balance_accumulator, e.mask); + for (const auto& pseudoOut: rv.p.pseudoOuts) + rct::subKeys(balance_accumulator, balance_accumulator, pseudoOut); + if (not (balance_accumulator == rct::identity())) + return false; + } + + // prepare input CLSAGs for signing + const rct::key message = get_pre_mlsag_hash(rv, hw::get_device("default")); + + rv.p.CLSAGs.resize(num_sources); + if (reconstruction) { + if (num_sources != unsigned_tx.rct_signatures.p.CLSAGs.size()) + return false; + } + + CLSAG_contexts.resize(num_sources); + if (not reconstruction) + cached_w.resize(num_sources); + + for (std::size_t i = 0; i < num_sources; ++i) { + const std::size_t ring_size = rv.mixRing[i].size(); + const rct::key& I = sources[i].multisig_kLRki.ki; + const std::size_t l = sources[i].real_output; + if (l >= ring_size) + return false; + rct::keyV& s = rv.p.CLSAGs[i].s; + const rct::key& C_offset = rv.p.pseudoOuts[i]; + rct::keyV P(ring_size); + rct::keyV C_nonzero(ring_size); + + if (not reconstruction) { + s.resize(ring_size); + for (std::size_t j = 0; j < ring_size; ++j) { + if (j != l) + s[j] = rct::skGen(); //make fake responses + } + } + else { + if (ring_size != unsigned_tx.rct_signatures.p.CLSAGs[i].s.size()) + return false; + s = unsigned_tx.rct_signatures.p.CLSAGs[i].s; + } + + for (std::size_t j = 0; j < ring_size; ++j) { + P[j] = rv.mixRing[i][j].dest; + C_nonzero[j] = rv.mixRing[i][j].mask; + } + + rct::key D; + rct::key z; + auto z_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(static_cast(&z), sizeof(rct::key)); + }); + if (not reconstruction) { + sc_sub(z.bytes, sources[i].mask.bytes, a[i].bytes); //commitment to zero privkey + ge_p3 H_p3; + rct::hash_to_p3(H_p3, rv.mixRing[i][l].dest); + rct::key H_l; + ge_p3_tobytes(H_l.bytes, &H_p3); + D = rct::scalarmultKey(H_l, z); //auxilliary key image (for commitment to zero) + rv.p.CLSAGs[i].D = rct::scalarmultKey(D, rct::INV_EIGHT); + rv.p.CLSAGs[i].I = I; + } + else { + rv.p.CLSAGs[i].D = unsigned_tx.rct_signatures.p.CLSAGs[i].D; + rv.p.CLSAGs[i].I = I; + D = rct::scalarmultKey(rv.p.CLSAGs[i].D, rct::EIGHT); + } + + if (not CLSAG_contexts[i].init(P, C_nonzero, C_offset, message, I, D, l, s, kAlphaComponents)) + return false; + + if (not reconstruction) { + rct::key mu_P; + rct::key mu_C; + if (not CLSAG_contexts[i].get_mu(mu_P, mu_C)) + return false; + sc_mul(cached_w[i].bytes, mu_P.bytes, input_secret_keys[i].bytes); + sc_muladd(cached_w[i].bytes, mu_C.bytes, z.bytes, cached_w[i].bytes); + } + } + unsigned_tx.rct_signatures = std::move(rv); + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool compute_tx_fee( + const std::vector& sources, + const std::vector& destinations, + std::uint64_t& fee +) +{ + boost::multiprecision::uint128_t in_amount = 0; + for (const auto& src: sources) + in_amount += src.amount; + + boost::multiprecision::uint128_t out_amount = 0; + for (const auto& dst: destinations) + out_amount += dst.amount; + + if (out_amount > in_amount) + return false; + + if (in_amount - out_amount > std::numeric_limits::max()) + return false; + + fee = static_cast(in_amount - out_amount); + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +tx_builder_ringct_t::tx_builder_ringct_t(): initialized(false) {} +//---------------------------------------------------------------------------------------------------------------------- +tx_builder_ringct_t::~tx_builder_ringct_t() +{ + memwipe(static_cast(cached_w.data()), cached_w.size() * sizeof(rct::key)); +} +//---------------------------------------------------------------------------------------------------------------------- +bool tx_builder_ringct_t::init( + const cryptonote::account_keys& account_keys, + const std::vector& extra, + const std::uint64_t unlock_time, + const std::uint32_t subaddr_account, + const std::set& subaddr_minor_indices, + std::vector& sources, + std::vector& destinations, + const cryptonote::tx_destination_entry& change, + const rct::RCTConfig& rct_config, + const bool use_rct, + const bool reconstruction, + crypto::secret_key& tx_secret_key, + std::vector& tx_aux_secret_keys, + cryptonote::transaction& unsigned_tx +) +{ + initialized = false; + this->reconstruction = reconstruction; + if (not use_rct) + return false; + if (sources.empty()) + return false; + + if (not reconstruction) + unsigned_tx.set_null(); + + std::uint64_t fee; + if (not compute_tx_fee(sources, destinations, fee)) + return false; + + // decide if view tags are needed + const bool use_view_tags{view_tag_required(rct_config.bp_version)}; + + // misc. fields + unsigned_tx.version = 2; //rct = 2 + unsigned_tx.unlock_time = unlock_time; + + // sort inputs + sort_sources(sources); + + // get secret keys for signing input CLSAGs (multisig: or for the initial partial signature) + rct::keyV input_secret_keys; + auto input_secret_keys_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(static_cast(input_secret_keys.data()), input_secret_keys.size() * sizeof(rct::key)); + }); + if (not compute_keys_for_sources(account_keys, sources, subaddr_account, subaddr_minor_indices, input_secret_keys)) + return false; + + // randomize output order + if (not reconstruction) + shuffle_destinations(destinations); + + // prepare outputs + rct::keyV output_public_keys; + rct::keyV output_amount_secret_keys; + std::vector view_tags; + auto output_amount_secret_keys_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(static_cast(output_amount_secret_keys.data()), output_amount_secret_keys.size() * sizeof(rct::key)); + }); + if (not compute_keys_for_destinations(account_keys, + subaddr_account, + destinations, + change, + extra, + use_view_tags, + reconstruction, + tx_secret_key, + tx_aux_secret_keys, + output_public_keys, + output_amount_secret_keys, + view_tags, + unsigned_tx)) + return false; + + // add inputs to tx + set_tx_inputs(sources, unsigned_tx); + + // add output one-time addresses to tx + bool set_tx_outputs_result{false}; + if (use_view_tags) + set_tx_outputs_result = set_tx_outputs_with_view_tags(output_public_keys, view_tags, unsigned_tx); + else + set_tx_outputs_result = set_tx_outputs(output_public_keys, unsigned_tx); + + if (not set_tx_outputs_result) + return false; + + // prepare input signatures + if (not set_tx_rct_signatures(fee, sources, destinations, input_secret_keys, output_public_keys, output_amount_secret_keys, + rct_config, reconstruction, unsigned_tx, CLSAG_contexts, cached_w)) + return false; + + initialized = true; + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +bool tx_builder_ringct_t::first_partial_sign( + const std::size_t source, + const rct::keyV& total_alpha_G, + const rct::keyV& total_alpha_H, + const rct::keyV& alpha, + rct::key& c_0, + rct::key& s +) +{ + if (not initialized or reconstruction) + return false; + const std::size_t num_sources = CLSAG_contexts.size(); + if (source >= num_sources) + return false; + rct::key c; + rct::key alpha_combined; + auto alpha_combined_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(static_cast(&alpha_combined), sizeof(rct::key)); + }); + if (not CLSAG_contexts[source].combine_alpha_and_compute_challenge( + total_alpha_G, + total_alpha_H, + alpha, + alpha_combined, + c_0, + c + )) { + return false; + } + + // initial partial response: + // s = alpha_combined_local - challenge*[mu_P*(local keys and sender-receiver secret and subaddress material) + + // mu_C*(commitment-to-zero secret)] + sc_mulsub(s.bytes, c.bytes, cached_w[source].bytes, alpha_combined.bytes); + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +bool tx_builder_ringct_t::next_partial_sign( + const rct::keyM& total_alpha_G, + const rct::keyM& total_alpha_H, + const rct::keyM& alpha, + const rct::key& x, + rct::keyV& c_0, + rct::keyV& s +) +{ + if (not initialized or not reconstruction) + return false; + const std::size_t num_sources = CLSAG_contexts.size(); + if (num_sources != total_alpha_G.size()) + return false; + if (num_sources != total_alpha_H.size()) + return false; + if (num_sources != alpha.size()) + return false; + if (num_sources != c_0.size()) + return false; + if (num_sources != s.size()) + return false; + for (std::size_t i = 0; i < num_sources; ++i) { + rct::key c; + rct::key alpha_combined; + auto alpha_combined_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(static_cast(&alpha_combined), sizeof(rct::key)); + }); + if (not CLSAG_contexts[i].combine_alpha_and_compute_challenge( + total_alpha_G[i], + total_alpha_H[i], + alpha[i], + alpha_combined, + c_0[i], + c + )) { + return false; + } + rct::key mu_P; + rct::key mu_C; + if (not CLSAG_contexts[i].get_mu(mu_P, mu_C)) + return false; + rct::key w; + auto w_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(static_cast(&w), sizeof(rct::key)); + }); + sc_mul(w.bytes, mu_P.bytes, x.bytes); + + // include local signer's response: + // s += alpha_combined_local - challenge*[mu_P*(local keys)] + sc_add(s[i].bytes, s[i].bytes, alpha_combined.bytes); + sc_mulsub(s[i].bytes, c.bytes, w.bytes, s[i].bytes); + } + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +bool tx_builder_ringct_t::finalize_tx( + const std::vector& sources, + const rct::keyV& c_0, + const rct::keyV& s, + cryptonote::transaction& unsigned_tx +) +{ + const std::size_t num_sources = sources.size(); + if (num_sources != unsigned_tx.rct_signatures.p.CLSAGs.size()) + return false; + if (num_sources != c_0.size()) + return false; + if (num_sources != s.size()) + return false; + for (std::size_t i = 0; i < num_sources; ++i) { + const std::size_t ring_size = unsigned_tx.rct_signatures.p.CLSAGs[i].s.size(); + if (sources[i].real_output >= ring_size) + return false; + unsigned_tx.rct_signatures.p.CLSAGs[i].s[sources[i].real_output] = s[i]; + unsigned_tx.rct_signatures.p.CLSAGs[i].c1 = c_0[i]; + } + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +} //namespace signing + +} //namespace multisig diff --git a/src/multisig/multisig_tx_builder_ringct.h b/src/multisig/multisig_tx_builder_ringct.h new file mode 100644 index 00000000000..67ef9e065dd --- /dev/null +++ b/src/multisig/multisig_tx_builder_ringct.h @@ -0,0 +1,119 @@ +// Copyright (c) 2021, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#pragma once + +#include "ringct/rctTypes.h" + +#include +#include + +namespace cryptonote { + +class transaction; +struct tx_source_entry; +struct tx_destination_entry; +struct account_keys; + +} + +namespace multisig { + +namespace signing { + +class CLSAG_context_t; + +// number of parallel signing nonces to use per signer (2 nonces as in musig2 and FROST) +constexpr std::size_t kAlphaComponents = 2; + +class tx_builder_ringct_t final { +private: + // the tx builder has been initialized + bool initialized; + // the tx builder is 'reconstructing' a tx that has already been created using this object + bool reconstruction; + // cached: mu_P*(local keys and sender-receiver secret and subaddress material) + mu_C*(commitment-to-zero secret) + // - these are only used for the initial building of a tx (not reconstructions) + rct::keyV cached_w; + // contexts for making CLSAG challenges with multisig nonces + std::vector CLSAG_contexts; +public: + tx_builder_ringct_t(); + ~tx_builder_ringct_t(); + + // prepare an unsigned transaction (and get tx privkeys for outputs) + bool init( + const cryptonote::account_keys& account_keys, + const std::vector& extra, + const std::uint64_t unlock_time, + const std::uint32_t subaddr_account, + const std::set& subaddr_minor_indices, + std::vector& sources, + std::vector& destinations, + const cryptonote::tx_destination_entry& change, + const rct::RCTConfig& rct_config, + const bool use_rct, + const bool reconstruction, + crypto::secret_key& tx_secret_key, + std::vector& tx_aux_secret_keys, + cryptonote::transaction& unsigned_tx + ); + + // get the first partial signature for the specified input ('source') + bool first_partial_sign( + const std::size_t source, + const rct::keyV& total_alpha_G, + const rct::keyV& total_alpha_H, + const rct::keyV& alpha, + rct::key& c_0, + rct::key& s + ); + + // get intermediate partial signatures for all the inputs + bool next_partial_sign( + const rct::keyM& total_alpha_G, + const rct::keyM& total_alpha_H, + const rct::keyM& alpha, + const rct::key& x, + rct::keyV& c_0, + rct::keyV& s + ); + + // finalize an unsigned transaction (add challenges and real responses to incomplete CLSAG signatures) + static bool finalize_tx( + const std::vector& sources, + const rct::keyV& c_0, + const rct::keyV& s, + cryptonote::transaction& unsigned_tx + ); +}; + +} //namespace signing + +} //namespace multisig diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index bd67778eca8..21040317c33 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -238,14 +238,12 @@ namespace rct { // P[l] == p*G // C[l] == z*G // C[i] == C_nonzero[i] - C_offset (for hashing purposes) for all i - clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, const multisig_kLRki *kLRki, key *mscout, key *mspout, hw::device &hwdev) { + clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev) { clsag sig; size_t n = P.size(); // ring size CHECK_AND_ASSERT_THROW_MES(n == C.size(), "Signing and commitment key vector sizes must match!"); CHECK_AND_ASSERT_THROW_MES(n == C_nonzero.size(), "Signing and commitment key vector sizes must match!"); CHECK_AND_ASSERT_THROW_MES(l < n, "Signing index out of range!"); - CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present"); - CHECK_AND_ASSERT_THROW_MES((mscout && mspout) || !kLRki, "Multisig pointers are not all present"); // Key images ge_p3 H_p3; @@ -260,16 +258,7 @@ namespace rct { key aG; key aH; - // Multisig - if (kLRki) - { - sig.I = kLRki->ki; - scalarmultKey(D,H,z); - } - else - { - hwdev.clsag_prepare(p,z,sig.I,D,H,a,aG,aH); - } + hwdev.clsag_prepare(p,z,sig.I,D,H,a,aG,aH); geDsmp I_precomp; geDsmp D_precomp; @@ -317,18 +306,9 @@ namespace rct { c_to_hash[2*n+1] = C_offset; c_to_hash[2*n+2] = message; - // Multisig data is present - if (kLRki) - { - a = kLRki->k; - c_to_hash[2*n+3] = kLRki->L; - c_to_hash[2*n+4] = kLRki->R; - } - else - { - c_to_hash[2*n+3] = aG; - c_to_hash[2*n+4] = aH; - } + c_to_hash[2*n+3] = aG; + c_to_hash[2*n+4] = aH; + hwdev.clsag_hash(c_to_hash,c); size_t i; @@ -380,16 +360,11 @@ namespace rct { hwdev.clsag_sign(c,a,p,z,mu_P,mu_C,sig.s[l]); memwipe(&a, sizeof(key)); - if (mscout) - *mscout = c; - if (mspout) - *mspout = mu_P; - return sig; } clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l) { - return CLSAG_Gen(message, P, p, C, z, C_nonzero, C_offset, l, NULL, NULL, NULL, hw::get_device("default")); + return CLSAG_Gen(message, P, p, C, z, C_nonzero, C_offset, l, hw::get_device("default")); } // MLSAG signatures @@ -397,7 +372,7 @@ namespace rct { // This generalization allows for some dimensions not to require linkability; // this is used in practice for commitment data within signatures // Note that using more than one linkable dimension is not recommended. - mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev) { + mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows, hw::device &hwdev) { mgSig rv; size_t cols = pk.size(); CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!"); @@ -409,8 +384,6 @@ namespace rct { } CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "Bad xx size"); CHECK_AND_ASSERT_THROW_MES(dsRows <= rows, "Bad dsRows size"); - CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present"); - CHECK_AND_ASSERT_THROW_MES(!kLRki || dsRows == 1, "Multisig requires exactly 1 dsRows"); size_t i = 0, j = 0, ii = 0; key c, c_old, L, R, Hi; @@ -428,20 +401,11 @@ namespace rct { DP("here1"); for (i = 0; i < dsRows; i++) { toHash[3 * i + 1] = pk[index][i]; - if (kLRki) { - // multisig - alpha[i] = kLRki->k; - toHash[3 * i + 2] = kLRki->L; - toHash[3 * i + 3] = kLRki->R; - rv.II[i] = kLRki->ki; - } - else { - hash_to_p3(Hi_p3, pk[index][i]); - ge_p3_tobytes(Hi.bytes, &Hi_p3); - hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]); - toHash[3 * i + 2] = aG[i]; - toHash[3 * i + 3] = aHP[i]; - } + hash_to_p3(Hi_p3, pk[index][i]); + ge_p3_tobytes(Hi.bytes, &Hi_p3); + hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]); + toHash[3 * i + 2] = aG[i]; + toHash[3 * i + 3] = aHP[i]; precomp(Ip[i].k, rv.II[i]); } size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper) @@ -485,8 +449,6 @@ namespace rct { } } hwdev.mlsag_sign(c, xx, alpha, rows, dsRows, rv.ss[index]); - if (mscout) - *mscout = c; return rv; } @@ -722,7 +684,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, const key &txnFeeKey, hw::device &hwdev) { + mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, const key &txnFeeKey, hw::device &hwdev) { //setup vars size_t cols = pubs.size(); CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); @@ -733,7 +695,6 @@ namespace rct { } CHECK_AND_ASSERT_THROW_MES(inSk.size() == rows, "Bad inSk size"); CHECK_AND_ASSERT_THROW_MES(outSk.size() == outPk.size(), "Bad outSk/outPk size"); - CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present"); keyV sk(rows + 1); keyV tmp(rows + 1); @@ -766,7 +727,7 @@ namespace rct { for (size_t j = 0; j < outPk.size(); j++) { sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row.. } - mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev); + mgSig result = MLSAG_Gen(message, M, sk, index, rows, hwdev); memwipe(sk.data(), sk.size() * sizeof(key)); return result; } @@ -779,12 +740,11 @@ namespace rct { // inSk is x, a_in corresponding to signing index // a_out, Cout is for the output commitment // index is the signing index.. - mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev) { + mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, unsigned int index, hw::device &hwdev) { //setup vars size_t rows = 1; size_t cols = pubs.size(); CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); - CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present"); keyV tmp(rows + 1); keyV sk(rows + 1); size_t i; @@ -796,17 +756,16 @@ namespace rct { M[i][0] = pubs[i].dest; subKeys(M[i][1], pubs[i].mask, Cout); } - mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev); + mgSig result = MLSAG_Gen(message, M, sk, index, rows, hwdev); memwipe(sk.data(), sk.size() * sizeof(key)); return result; } - clsag proveRctCLSAGSimple(const key &message, const ctkeyV &pubs, const ctkey &inSk, const key &a, const key &Cout, const multisig_kLRki *kLRki, key *mscout, key *mspout, unsigned int index, hw::device &hwdev) { + clsag proveRctCLSAGSimple(const key &message, const ctkeyV &pubs, const ctkey &inSk, const key &a, const key &Cout, unsigned int index, hw::device &hwdev) { //setup vars size_t rows = 1; size_t cols = pubs.size(); CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); - CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present"); keyV tmp(rows + 1); keyV sk(rows + 1); keyM M(cols, tmp); @@ -826,7 +785,7 @@ namespace rct { sk[0] = copy(inSk.dest); sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); - clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], C_nonzero, Cout, index, kLRki, mscout, mspout, hwdev); + clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], C_nonzero, Cout, index, hwdev); memwipe(sk.data(), sk.size() * sizeof(key)); return result; } @@ -1084,14 +1043,13 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number // Note: For txn fees, the last index in the amounts vector should contain that // Thus the amounts vector will be "one" longer than the destinations vectort - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev) { CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations"); CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations"); CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing"); for (size_t n = 0; n < mixRing.size(); ++n) { CHECK_AND_ASSERT_THROW_MES(mixRing[n].size() == inSk.size(), "Bad mixRing size"); } - CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present"); CHECK_AND_ASSERT_THROW_MES(inSk.size() < 2, "genRct is not suitable for 2+ rings"); rctSig rv; @@ -1130,23 +1088,21 @@ namespace rct { key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; - if (msout) - msout->c.resize(1); - rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv, hwdev), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey,hwdev)); + rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv, hwdev), rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey,hwdev)); return rv; } - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, const RCTConfig &rct_config, hw::device &hwdev) { + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const keyV &amount_keys, const int mixin, const RCTConfig &rct_config, hw::device &hwdev) { unsigned int index; ctkeyM mixRing; ctkeyV outSk; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, rct_config, hwdev); + return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk, rct_config, hwdev); } //RCT simple //for post-rct only - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector *kLRki, multisig_out *msout, const std::vector & index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector & index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev) { const bool bulletproof_or_plus = rct_config.range_proof_type > RangeProofBorromean; CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk"); @@ -1157,10 +1113,6 @@ namespace rct { for (size_t n = 0; n < mixRing.size(); ++n) { CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing"); } - CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present"); - if (kLRki && msout) { - CHECK_AND_ASSERT_THROW_MES(kLRki->size() == inamounts.size(), "Mismatched kLRki/inamounts sizes"); - } rctSig rv; if (bulletproof_or_plus) @@ -1322,11 +1274,7 @@ namespace rct { DP(pseudoOuts[i]); key full_message = get_pre_mlsag_hash(rv,hwdev); - if (msout) - { - msout->c.resize(inamounts.size()); - msout->mu_p.resize(is_rct_clsag(rv.type) ? inamounts.size() : 0); - } + for (i = 0 ; i < inamounts.size(); i++) { if (is_rct_clsag(rv.type)) @@ -1334,17 +1282,17 @@ namespace rct { if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE) rv.p.CLSAGs[i] = make_dummy_clsag(rv.mixRing[i].size()); else - rv.p.CLSAGs[i] = proveRctCLSAGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, msout ? &msout->mu_p[i] : NULL, index[i], hwdev); + rv.p.CLSAGs[i] = proveRctCLSAGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], index[i], hwdev); } else { - rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i], hwdev); + rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], index[i], hwdev); } } return rv; } - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, const keyV &amount_keys, const std::vector *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, hw::device &hwdev) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, hw::device &hwdev) { std::vector index; index.resize(inPk.size()); ctkeyM mixRing; @@ -1354,7 +1302,7 @@ namespace rct { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, rct_config, hwdev); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev); } //RingCT protocol @@ -1700,60 +1648,4 @@ namespace rct { key mask; return decodeRctSimple(rv, sk, i, mask, hwdev); } - - bool signMultisigMLSAG(rctSig &rv, const std::vector &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { - CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2, - false, "unsupported rct type"); - CHECK_AND_ASSERT_MES(!is_rct_clsag(rv.type), false, "CLSAG signature type in MLSAG signature function"); - CHECK_AND_ASSERT_MES(indices.size() == k.size(), false, "Mismatched k/indices sizes"); - CHECK_AND_ASSERT_MES(k.size() == rv.p.MGs.size(), false, "Mismatched k/MGs size"); - CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size"); - CHECK_AND_ASSERT_MES(rv.p.CLSAGs.empty(), false, "CLSAGs not empty for MLSAGs"); - if (rv.type == RCTTypeFull) - { - CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "MGs not a single element"); - } - for (size_t n = 0; n < indices.size(); ++n) { - CHECK_AND_ASSERT_MES(indices[n] < rv.p.MGs[n].ss.size(), false, "Index out of range"); - CHECK_AND_ASSERT_MES(!rv.p.MGs[n].ss[indices[n]].empty(), false, "empty ss line"); - } - - // MLSAG: each player contributes a share to the secret-index ss: k - cc*secret_key_share - // cc: msout.c[n], secret_key_share: secret_key - for (size_t n = 0; n < indices.size(); ++n) { - rct::key diff; - sc_mulsub(diff.bytes, msout.c[n].bytes, secret_key.bytes, k[n].bytes); - sc_add(rv.p.MGs[n].ss[indices[n]][0].bytes, rv.p.MGs[n].ss[indices[n]][0].bytes, diff.bytes); - } - return true; - } - - bool signMultisigCLSAG(rctSig &rv, const std::vector &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { - CHECK_AND_ASSERT_MES(is_rct_clsag(rv.type), false, "unsupported rct type"); - CHECK_AND_ASSERT_MES(indices.size() == k.size(), false, "Mismatched k/indices sizes"); - CHECK_AND_ASSERT_MES(k.size() == rv.p.CLSAGs.size(), false, "Mismatched k/CLSAGs size"); - CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size"); - CHECK_AND_ASSERT_MES(rv.p.MGs.empty(), false, "MGs not empty for CLSAGs"); - CHECK_AND_ASSERT_MES(msout.c.size() == msout.mu_p.size(), false, "Bad mu_p size"); - for (size_t n = 0; n < indices.size(); ++n) { - CHECK_AND_ASSERT_MES(indices[n] < rv.p.CLSAGs[n].s.size(), false, "Index out of range"); - } - - // CLSAG: each player contributes a share to the secret-index ss: k - cc*mu_p*secret_key_share - // cc: msout.c[n], mu_p, msout.mu_p[n], secret_key_share: secret_key - for (size_t n = 0; n < indices.size(); ++n) { - rct::key diff, sk; - sc_mul(sk.bytes, msout.mu_p[n].bytes, secret_key.bytes); - sc_mulsub(diff.bytes, msout.c[n].bytes, sk.bytes, k[n].bytes); - sc_add(rv.p.CLSAGs[n].s[indices[n]].bytes, rv.p.CLSAGs[n].s[indices[n]].bytes, diff.bytes); - } - return true; - } - - bool signMultisig(rctSig &rv, const std::vector &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { - if (is_rct_clsag(rv.type)) - return signMultisigCLSAG(rv, indices, k, msout, secret_key); - else - return signMultisigMLSAG(rv, indices, k, msout, secret_key); - } } diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index a0346b34ea2..17cfd77b96e 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -74,12 +74,12 @@ namespace rct { // Gen creates a signature which proves that for some column in the keymatrix "pk" // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly - mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev); + mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows, hw::device &hwdev); bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &sig, size_t dsRows); - clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, const multisig_kLRki *kLRki, key *mscout, key *mspout, hw::device &hwdev); + clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev); clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l); - clsag proveRctCLSAGSimple(const key &, const ctkeyV &, const ctkey &, const key &, const key &, const multisig_kLRki *, key *, key *, unsigned int, hw::device &); + clsag proveRctCLSAGSimple(const key &, const ctkeyV &, const ctkey &, const key &, const key &, unsigned int, hw::device &); bool verRctCLSAGSimple(const key &, const clsag &, const ctkeyV &, const key &); //proveRange and verRange @@ -100,8 +100,8 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, const key &txnFee, const key &message, hw::device &hwdev); - mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev); + mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, unsigned int index, const key &txnFee, const key &message, hw::device &hwdev); + mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, unsigned int index, hw::device &hwdev); bool verRctMG(const mgSig &mg, const ctkeyM & pubs, const ctkeyV & outPk, const key &txnFee, const key &message); bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C); @@ -123,10 +123,10 @@ namespace rct { //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev); - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, const RCTConfig &rct_config, hw::device &hwdev); - rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector & inamounts, const std::vector & outamounts, const keyV &amount_keys, const std::vector *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, hw::device &hwdev); - rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector & inamounts, const std::vector & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector *kLRki, multisig_out *msout, const std::vector & index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev); + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev); + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector & amounts, const keyV &amount_keys, const int mixin, const RCTConfig &rct_config, hw::device &hwdev); + rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector & inamounts, const std::vector & outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, hw::device &hwdev); + rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector & inamounts, const std::vector & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector & index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev); bool verRct(const rctSig & rv, bool semantics); static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); } bool verRctSemanticsSimple(const rctSig & rv); @@ -138,7 +138,6 @@ namespace rct { xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev); xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev); key get_pre_mlsag_hash(const rctSig &rv, hw::device &hwdev); - bool signMultisig(rctSig &rv, const std::vector &indices, const keyV &k, const multisig_out &msout, const key &secret_key); } #endif /* RCTSIGS_H */ diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b2a6c0f5a2..aa95fa01e5e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -62,6 +62,7 @@ using namespace epee; #include "multisig/multisig.h" #include "multisig/multisig_account.h" #include "multisig/multisig_kex_msg.h" +#include "multisig/multisig_tx_builder_ringct.h" #include "common/boost_serialization_helper.h" #include "common/command_line.h" #include "common/threadpool.h" @@ -5070,7 +5071,6 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, m_multisig_rounds_passed = 1; // derivations stored (should be empty in last round) - // TODO: make use of the origins map for aggregation-style signing (instead of round-robin) m_multisig_derivations.clear(); m_multisig_derivations.reserve(multisig_account.get_kex_keys_to_origins_map().size()); @@ -5127,7 +5127,6 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor expanded_msgs.emplace_back(msg); // reconstruct multisig account - crypto::public_key dummy; multisig::multisig_keyset_map_memsafe_t kex_origins_map; for (const auto &derivation : m_multisig_derivations) @@ -5163,7 +5162,6 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor "Failed to update multisig wallet account due to bad keys"); // derivations stored (should be empty in last round) - // TODO: make use of the origins map for aggregation-style signing (instead of round-robin) m_multisig_derivations.clear(); m_multisig_derivations.reserve(multisig_account.get_kex_keys_to_origins_map().size()); @@ -6642,8 +6640,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector additional_tx_keys; - rct::multisig_out msout; - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, rct_config, m_multisig ? &msout : NULL, sd.use_view_tags); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, rct_config, sd.use_view_tags); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype); // we don't test tx size, because we don't know the current limit, due to not having a blockchain, // and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway, @@ -7151,77 +7148,113 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector indices; - for (const auto &source: sources) - indices.push_back(source.real_output); + // reconstruct the partially-signed transaction attempt to verify we are signing something that at least looks like a transaction + // note: the caller should further verify that the tx details are acceptable (inputs/outputs/memos/tx type) + multisig::signing::tx_builder_ringct_t multisig_tx_builder; + THROW_WALLET_EXCEPTION_IF( + not multisig_tx_builder.init( + m_account.get_keys(), + ptx.construction_data.extra, + ptx.construction_data.unlock_time, + ptx.construction_data.subaddr_account, + ptx.construction_data.subaddr_indices, + ptx.construction_data.sources, + ptx.construction_data.splitted_dsts, + ptx.construction_data.change_dts, + ptx.construction_data.rct_config, + ptx.construction_data.use_rct, + true, //true = we are reconstructing the tx (it was first constructed by the tx proposer) + ptx.tx_key, + ptx.additional_tx_keys, + ptx.tx + ), + error::wallet_internal_error, + "error: multisig::signing::tx_builder_ringct_t::init" + ); + // go through each signing attempt for this transaction (each signing attempt corresponds to some subgroup of signers + // of size 'threshold') for (auto &sig: ptx.multisig_sigs) { + // skip this partial tx if it's intended for a subgroup of signers that doesn't include the local signer + // note: this check can only weed out signers who provided multisig_infos to the multisig tx proposer's + // (initial author's) last call to import_multisig() before making this tx proposal; all other signers + // will encounter a 'need to export multisig' wallet error in get_multisig_k() below + // note2: the 'need to export multisig' wallet error can also appear if a bad/buggy tx proposer adds duplicate + // 'used_L' to the set of tx attempts, or if two different tx proposals use the same 'used_L' values and the + // local signer calls this function on both of them if (sig.ignore.find(local_signer) == sig.ignore.end()) { - ptx.tx.rct_signatures = sig.sigs; - - rct::keyV k; + rct::keyM local_nonces_k(sd.selected_transfers.size(), rct::keyV(multisig::signing::kAlphaComponents)); rct::key skey = rct::zero(); - auto wiper = epee::misc_utils::create_scope_leave_handler([&](){ memwipe(k.data(), k.size() * sizeof(k[0])); memwipe(&skey, sizeof(skey)); }); - - for (size_t idx: sd.selected_transfers) - k.push_back(get_multisig_k(idx, sig.used_L)); + auto wiper = epee::misc_utils::create_scope_leave_handler([&]{ + for (auto& e: local_nonces_k) + memwipe(e.data(), e.size() * sizeof(rct::key)); + memwipe(&skey, sizeof(rct::key)); + }); + + // get local signer's nonces for this transaction attempt's inputs + // note: whoever created 'exported_txs' has full power to match proposed tx inputs (selected_transfers) + // with the public nonces of the multisig signers who call this function (via 'used_L' as identifiers), however + // the local signer will only use a given nonce exactly once (even if a used_L is repeated) + for (std::size_t i = 0; i < local_nonces_k.size(); ++i) { + for (std::size_t j = 0; j < multisig::signing::kAlphaComponents; ++j) { + get_multisig_k(sd.selected_transfers[i], sig.used_L, local_nonces_k[i][j]); + } + } - for (const auto &msk: get_account().get_multisig_keys()) + // round-robin signing: sign with all local multisig key shares that other signers have not signed with yet + for (const auto &multisig_skey: get_account().get_multisig_keys()) { - crypto::public_key pmsk = get_multisig_signing_public_key(msk); + crypto::public_key multisig_pkey = get_multisig_signing_public_key(multisig_skey); - if (sig.signing_keys.find(pmsk) == sig.signing_keys.end()) + if (sig.signing_keys.find(multisig_pkey) == sig.signing_keys.end()) { - sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes); - sig.signing_keys.insert(pmsk); + sc_add(skey.bytes, skey.bytes, rct::sk2rct(multisig_skey).bytes); + sig.signing_keys.insert(multisig_pkey); } } - THROW_WALLET_EXCEPTION_IF(!rct::signMultisig(ptx.tx.rct_signatures, indices, k, sig.msout, skey), - error::wallet_internal_error, "Failed signing, transaction likely malformed"); - sig.sigs = ptx.tx.rct_signatures; + THROW_WALLET_EXCEPTION_IF( + not multisig_tx_builder.next_partial_sign(sig.total_alpha_G, sig.total_alpha_H, local_nonces_k, skey, sig.c_0, sig.s), + error::wallet_internal_error, + "error: multisig::signing::tx_builder_ringct_t::next_partial_sign" + ); } } const bool is_last = exported_txs.m_signers.size() + 1 >= m_multisig_threshold; if (is_last) { - // when the last signature on a multisig tx is made, we select the right - // signature to plug into the final tx + // if there are signatures from enough signers (assuming the local signer signed 1+ tx attempts), find the tx + // attempt with a full set of signatures so this tx can be finalized bool found = false; for (const auto &sig: ptx.multisig_sigs) { if (sig.ignore.find(local_signer) == sig.ignore.end() && !keys_intersect(sig.ignore, exported_txs.m_signers)) { THROW_WALLET_EXCEPTION_IF(found, error::wallet_internal_error, "More than one transaction is final"); - ptx.tx.rct_signatures = sig.sigs; + THROW_WALLET_EXCEPTION_IF( + not multisig_tx_builder.finalize_tx(ptx.construction_data.sources, sig.c_0, sig.s, ptx.tx), + error::wallet_internal_error, + "error: multisig::signing::tx_builder_ringct_t::finalize_tx" + ); found = true; } } THROW_WALLET_EXCEPTION_IF(!found, error::wallet_internal_error, - "Final signed transaction not found: this transaction was likely made without our export data, so we cannot sign it"); + "Unable to finalize the transaction: the ignore sets for these tx attempts seem to be malformed."); const crypto::hash txid = get_transaction_hash(ptx.tx); if (store_tx_info()) { @@ -7232,7 +7265,8 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector additional_tx_keys; - rct::multisig_out msout; LOG_PRINT_L2("constructing tx"); - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, {}, m_multisig ? &msout : NULL, use_view_tags); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, {}, use_view_tags); LOG_PRINT_L2("constructed tx, r="< sources; - std::unordered_set used_L; for(size_t idx: selected_transfers) { sources.resize(sources.size()+1); @@ -8952,10 +8988,8 @@ void wallet2::transfer_selected_rct(std::vector() : ignore_sets.front(); - src.multisig_kLRki = get_multisig_composite_kLRki(idx, ignore_set, used_L, used_L); - } + // note: multisig_kLRki is a legacy struct, currently only used as a key image shuttle into the multisig tx builder + src.multisig_kLRki = {.k = {}, .L = {}, .R = {}, .ki = rct::ki2rct(td.m_key_image)}; else src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()}); detail::print_source_entry(src); @@ -8992,12 +9026,41 @@ void wallet2::transfer_selected_rct(std::vector additional_tx_keys; - rct::multisig_out msout; LOG_PRINT_L2("constructing tx"); auto sources_copy = sources; - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, m_multisig ? &msout : NULL, use_view_tags); - LOG_PRINT_L2("constructed tx, r="< subaddr_minor_indices; + for (size_t idx: selected_transfers) { + subaddr_minor_indices.insert(m_transfers[idx].m_subaddr_index.minor); + } + THROW_WALLET_EXCEPTION_IF( + not multisig_tx_builder.init(m_account.get_keys(), + extra, + unlock_time, + subaddr_account, + subaddr_minor_indices, + sources, + splitted_dsts, + change_dts, + rct_config, + true, + false, + tx_key, + additional_tx_keys, + tx + ), + error::wallet_internal_error, + "error: multisig::signing::tx_builder_ringct_t::init" + ); + } + else { + // make a normal tx + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags); + LOG_PRINT_L2("constructed tx, r="< multisig_sigs; - if (m_multisig) - { - auto ignore = ignore_sets.empty() ? std::unordered_set() : ignore_sets.front(); - multisig_sigs.push_back({tx.rct_signatures, ignore, used_L, std::unordered_set(), msout}); - - if (m_multisig_threshold < m_multisig_signers.size()) - { - const crypto::hash prefix_hash = cryptonote::get_transaction_prefix_hash(tx); - - // create the other versions, one for every other participant (the first one's already done above) - for (size_t ignore_index = 1; ignore_index < ignore_sets.size(); ++ignore_index) - { - std::unordered_set new_used_L; - size_t src_idx = 0; - THROW_WALLET_EXCEPTION_IF(selected_transfers.size() != sources.size(), error::wallet_internal_error, "mismatched selected_transfers and sources sixes"); - for(size_t idx: selected_transfers) - { - cryptonote::tx_source_entry& src = sources_copy[src_idx]; - src.multisig_kLRki = get_multisig_composite_kLRki(idx, ignore_sets[ignore_index], used_L, new_used_L); - ++src_idx; + if (m_multisig) { + if (ignore_sets.empty()) + ignore_sets.emplace_back(); + const std::size_t num_multisig_attempts = ignore_sets.size(); + multisig_sigs.resize(num_multisig_attempts); + std::unordered_set all_used_L; + std::unordered_set signing_keys; + for (const crypto::secret_key &multisig_skey: get_account().get_multisig_keys()) + signing_keys.insert(get_multisig_signing_public_key(multisig_skey)); + const std::size_t num_sources = sources.size(); + const std::size_t num_alpha_components = multisig::signing::kAlphaComponents; + + // initiate a multisig tx attempt for each unique set of signers that + // a) includes the local signer + // b) includes other signers who most recently sent the local signer LR public nonces via 'export_multisig() -> import_multisig()' + for (std::size_t i = 0; i < num_multisig_attempts; ++i) { + multisig_sig& sig = multisig_sigs[i]; + sig.total_alpha_G.resize(num_sources, rct::keyV(num_alpha_components)); + sig.total_alpha_H.resize(num_sources, rct::keyV(num_alpha_components)); + sig.s.resize(num_sources); + sig.c_0.resize(num_sources); + + // for each tx input, get public musig2-style nonces from + // a) temporary local-generated private nonces (used to make the local partial signatures on each tx attempt) + // b) other signers' public nonces, sent to the local signer via 'export_multisig() -> import_multisig()' + // - WARNING: If two multisig players initiate multisig tx attempts separately, but spend the same funds (and hence rely on the same LR public nonces), + // then if two signers partially sign different tx attempt sets, then all attempts that require both signers will become garbage, + // because LR nonces can only be used for one tx attempt. + for (std::size_t j = 0; j < num_sources; ++j) { + rct::keyV alpha(num_alpha_components); + auto alpha_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(static_cast(alpha.data()), alpha.size() * sizeof(rct::key)); + }); + for (std::size_t m = 0; m < num_alpha_components; ++m) { + const rct::multisig_kLRki kLRki = get_multisig_composite_kLRki( + selected_transfers[ins_order[j]], + ignore_sets[i], + all_used_L, //collect all public L nonces used by this tx proposal (set of tx attempts) to avoid duplicates + sig.used_L //record the public L nonces used by this tx input to this tx attempt, for coordination with other signers + ); + alpha[m] = kLRki.k; + sig.total_alpha_G[j][m] = kLRki.L; + sig.total_alpha_H[j][m] = kLRki.R; } - LOG_PRINT_L2("Creating supplementary multisig transaction"); - cryptonote::transaction ms_tx; - auto sources_copy_copy = sources_copy; - bool shuffle_outs = false; - bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources_copy_copy, splitted_dsts, change_dts.addr, extra, ms_tx, unlock_time,tx_key, additional_tx_keys, true, rct_config, &msout, shuffle_outs, use_view_tags); - LOG_PRINT_L2("constructed tx, r="<(), msout}); - - ms_tx.rct_signatures = tx.rct_signatures; - THROW_WALLET_EXCEPTION_IF(cryptonote::get_transaction_hash(ms_tx) != cryptonote::get_transaction_hash(tx), error::wallet_internal_error, "Multisig txes differ by more than the signatures"); - } + // local signer: initial partial signature on this tx input for this tx attempt + // note: sign here with sender-receiver secret component, subaddress component, and ALL of the local signer's multisig key shares + // (this ultimately occurs deep in generate_key_image_helper_precomp()) + THROW_WALLET_EXCEPTION_IF( + not multisig_tx_builder.first_partial_sign(j, sig.total_alpha_G[j], sig.total_alpha_H[j], alpha, sig.c_0[j], sig.s[j]), + error::wallet_internal_error, + "error: multisig::signing::tx_builder_ringct_t::first_partial_sign" + ); + } + + // note: record the ignore set so when other signers go to add their signatures (sign_multisig_tx()), they + // can skip this tx attempt if they aren't supposed to sign it; this only works for signers who provided + // multisig_infos to the last 'import_multisig()' call by the local signer, all 'other signers' will encounter + // a 'need to export multisig_info' wallet error if they try to sign this partial tx, which means if they want to sign a tx + // they need to export_multisig() -> send to the local signer -> local signer calls import_multisig() with fresh + // multisig_infos from all signers -> local signer makes completely new tx attempts (or a different signer makes tx attempts) + sig.ignore = ignore_sets[i]; + sig.signing_keys = signing_keys; //the local signer signed with ALL of their multisig key shares, record their pubkeys for reference by other signers + } + if (m_multisig_threshold <= 1) { + // local signer: finish signing the tx inputs if we are the only signer (ignore all but the first 'attempt') + THROW_WALLET_EXCEPTION_IF( + not multisig_tx_builder.finalize_tx(sources, multisig_sigs[0].c_0, multisig_sigs[0].s, tx), + error::wallet_internal_error, + "error: multisig::signing::tx_builder_ringct_t::finalize_tx" + ); } } @@ -13336,19 +13434,26 @@ crypto::public_key wallet2::get_multisig_signing_public_key(size_t idx) const return get_multisig_signing_public_key(get_account().get_multisig_keys()[idx]); } //---------------------------------------------------------------------------------------------------- -rct::key wallet2::get_multisig_k(size_t idx, const std::unordered_set &used_L) const +void wallet2::get_multisig_k(size_t idx, const std::unordered_set &used_L, rct::key &nonce) { CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig"); CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "idx out of range"); - for (const auto &k: m_transfers[idx].m_multisig_k) + for (auto &k: m_transfers[idx].m_multisig_k) { + if (k == rct::zero()) + continue; + + // decide whether or not to return a nonce just based on if its pubkey 'L = k*G' is attached to the transfer 'idx' rct::key L; rct::scalarmultBase(L, k); if (used_L.find(L) != used_L.end()) - return k; + { + nonce = k; + memwipe(static_cast(&k), sizeof(rct::key)); //CRITICAL: a nonce may only be used once! + return; + } } THROW_WALLET_EXCEPTION(tools::error::multisig_export_needed); - return rct::zero(); } //---------------------------------------------------------------------------------------------------- rct::multisig_kLRki wallet2::get_multisig_kLRki(size_t n, const rct::key &k) const @@ -13414,15 +13519,23 @@ cryptonote::blobdata wallet2::export_multisig() const crypto::public_key signer = get_multisig_signer_public_key(); + // For each transfer (output owned by the multisig wallet): + // 1) Record the output's partial key image (from the local signer), so other signers can assemble the output's full key image. + // 2) Prepare enough signing nonces for one signing attempt with each possible combination of 'threshold' signers + // from the multisig group (only groups that include the local signer). + // - Calling this function will reset any nonces recorded by the previous call to this function. Doing so will + // invalidate any in-progress signing attempts that rely on the previous output of this function. info.resize(m_transfers.size()); for (size_t n = 0; n < m_transfers.size(); ++n) { transfer_details &td = m_transfers[n]; crypto::key_image ki; - memwipe(td.m_multisig_k.data(), td.m_multisig_k.size() * sizeof(td.m_multisig_k[0])); + if (td.m_multisig_k.size()) + memwipe(td.m_multisig_k.data(), td.m_multisig_k.size() * sizeof(td.m_multisig_k[0])); info[n].m_LR.clear(); info[n].m_partial_key_images.clear(); + // record the partial key images for (size_t m = 0; m < get_account().get_multisig_keys().size(); ++m) { // we want to export the partial key image, not the full one, so we can't use td.m_key_image @@ -13435,6 +13548,15 @@ cryptonote::blobdata wallet2::export_multisig() // if we have 2/4 wallet with signers: A, B, C, D and A is a transaction creator it will need to pick up 1 signer from 3 wallets left. // That means counting combinations for excluding 2-of-3 wallets (k = total signers count - threshold, n = total signers count - 1). size_t nlr = tools::combinations_count(m_multisig_signers.size() - m_multisig_threshold, m_multisig_signers.size() - 1); + + // 'td.m_multisig_k' is an expansion of [{alpha_0, alpha_1, ...}, {alpha_0, alpha_1, ...}, {alpha_0, alpha_1, ...}], + // - A '{alpha_0, alpha_1, ...}' tuple contains a set of 'kAlphaComponents' nonces, which can be used for one + // signing attempt. Each output will gain 'nlr' tuples, so that every signing group can make one signing attempt. + // - All tuples are always cleared after 1+ of them is used to sign a tx attempt (in sign_multisig_tx()), so + // in practice, a call to this function only allows _one_ multisig signing cycle for each output (which can + // include signing attempts for multiple signer groups). + nlr *= multisig::signing::kAlphaComponents; + for (size_t m = 0; m < nlr; ++m) { td.m_multisig_k.push_back(rct::skGen()); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e051946add2..ae9b83a2887 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -594,13 +594,24 @@ namespace tools std::unordered_set signing_keys; rct::multisig_out msout; + rct::keyM total_alpha_G; + rct::keyM total_alpha_H; + rct::keyV c_0; + rct::keyV s; + BEGIN_SERIALIZE_OBJECT() - VERSION_FIELD(0) + VERSION_FIELD(1) + if (version < 1) + return false; FIELD(sigs) FIELD(ignore) FIELD(used_L) FIELD(signing_keys) FIELD(msout) + FIELD(total_alpha_G) + FIELD(total_alpha_H) + FIELD(c_0) + FIELD(s) END_SERIALIZE() }; @@ -1679,7 +1690,7 @@ namespace tools crypto::key_image get_multisig_composite_key_image(size_t n) const; rct::multisig_kLRki get_multisig_composite_kLRki(size_t n, const std::unordered_set &ignore_set, std::unordered_set &used_L, std::unordered_set &new_used_L) const; rct::multisig_kLRki get_multisig_kLRki(size_t n, const rct::key &k) const; - rct::key get_multisig_k(size_t idx, const std::unordered_set &used_L) const; + void get_multisig_k(size_t idx, const std::unordered_set &used_L, rct::key &nonce); void update_multisig_rescan_info(const std::vector> &multisig_k, const std::vector> &info, size_t n); bool add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx); bool add_rings(const cryptonote::transaction_prefix &tx); @@ -1878,7 +1889,7 @@ BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0) BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 1) BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 4) BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 3) -BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 0) +BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 1) namespace boost { @@ -2316,6 +2327,12 @@ namespace boost a & x.used_L; a & x.signing_keys; a & x.msout; + if (ver < 1) + return; + a & x.total_alpha_G; + a & x.total_alpha_H; + a & x.c_0; + a & x.s; } template diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 61195c7b0e7..144e87bc285 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1076,7 +1076,7 @@ bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std:: std::vector additional_tx_keys; std::vector destinations_copy = destinations; rct::RCTConfig rct_config = {range_proof_type, bp_version}; - return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, nullptr); + return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config); } transaction construct_tx_with_fee(std::vector& events, const block& blk_head, diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp index 3db3d405994..28d176e5687 100644 --- a/tests/core_tests/multisig.cpp +++ b/tests/core_tests/multisig.cpp @@ -28,6 +28,11 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include "ringct/rctSigs.h" +#include "cryptonote_basic/cryptonote_basic.h" +#include "multisig/multisig.h" +#include "multisig/multisig_tx_builder_ringct.h" +#include "common/apply_permutation.h" #include "chaingen.h" #include "multisig.h" @@ -113,7 +118,7 @@ static bool make_multisig_accounts(std::vector &accoun bool gen_multisig_tx_validation_base::generate_with(std::vector& events, size_t inputs, size_t mixin, uint64_t amount_paid, bool valid, - size_t threshold, size_t total, size_t creator, std::vector signers, + size_t threshold, size_t total, size_t creator, std::vector other_signers, const std::function &sources, std::vector &destinations)> &pre_tx, const std::function &post_tx) const { @@ -122,30 +127,18 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector= 2, false, "Bad scheme"); CHECK_AND_ASSERT_MES(threshold <= total, false, "Bad scheme"); -#ifdef NO_MULTISIG - CHECK_AND_ASSERT_MES(total <= 5, false, "Unsupported scheme"); -#endif CHECK_AND_ASSERT_MES(inputs >= 1 && inputs <= 8, false, "Inputs should between 1 and 8"); // given as 1 based for clarity --creator; - for (size_t &signer: signers) + for (size_t &signer: other_signers) --signer; CHECK_AND_ASSERT_MES(creator < total, false, "invalid creator"); - for (size_t signer: signers) + for (size_t signer: other_signers) CHECK_AND_ASSERT_MES(signer < total, false, "invalid signer"); -#ifdef NO_MULTISIG - GENERATE_ACCOUNT(acc0); - GENERATE_ACCOUNT(acc1); - GENERATE_ACCOUNT(acc2); - GENERATE_ACCOUNT(acc3); - GENERATE_ACCOUNT(acc4); - account_base miner_account[5] = {acc0, acc1, acc2, acc3, acc4}; -#else GENERATE_MULTISIG_ACCOUNT(miner_account, threshold, total); -#endif MAKE_GENESIS_BLOCK(events, blk_0, miner_account[creator], ts_start); @@ -193,14 +186,13 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector(blocks[n].miner_tx.vout[0].target).key; + cryptonote::get_output_public_key(blocks[n].miner_tx.vout[0], output_pub_key[n]); MDEBUG("output_pub_key: " << output_pub_key); } std::unordered_map subaddresses; subaddresses[miner_account[0].get_keys().m_account_address.m_spend_public_key] = {0,0}; -#ifndef NO_MULTISIG // create k/L/R/ki for that output we're going to spend std::vector>> account_k(total); std::vector>> account_L(total); @@ -213,6 +205,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector kLRkis; @@ -257,34 +249,6 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector pkis; for (size_t msidx = 0; msidx < total; ++msidx) for (size_t n = 0; n < account_ki[msidx][tdidx].size(); ++n) @@ -292,8 +256,6 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector sources; for (size_t n = 0; n < inputs; ++n) { @@ -322,7 +283,9 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector(blocks[m].miner_tx.vout[0].target).key); + crypto::public_key output_public_key; + cryptonote::get_output_public_key(blocks[m].miner_tx.vout[0], output_public_key); + ctkey.dest = rct::pk2rct(output_public_key); MDEBUG("using " << (m == n ? "real" : "fake") << " input " << ctkey.dest); ctkey.mask = rct::commit(blocks[m].miner_tx.vout[0].amount, rct::identity()); // since those are coinbases, the masks are known src.outputs.push_back(std::make_pair(m, ctkey)); @@ -333,11 +296,8 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector destinations; + std::vector destinations; //tx need two outputs since HF_VERSION_MIN_2_OUTPUTS destinations.push_back(td); - cryptonote::account_base dummy; - dummy.generate(); - td.addr = dummy.get_keys().m_account_address; td.amount = 0; destinations.push_back(td); @@ -346,18 +306,11 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector additional_tx_secret_keys; auto sources_copy = sources; - r = construct_tx_and_get_tx_key(miner_account[creator].get_keys(), subaddresses, sources, destinations, boost::none, std::vector(), tx, 0, tx_key, additional_tx_secret_keys, true, { rct::RangeProofPaddedBulletproof, 0 }, msoutp); - CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); + multisig::signing::tx_builder_ringct_t tx_builder; + CHECK_AND_ASSERT_MES(tx_builder.init(miner_account[creator].get_keys(), {}, 0, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, false, tx_key, additional_tx_secret_keys, tx), false, "error: multisig::signing::tx_builder_t::init"); -#ifndef NO_MULTISIG // work out the permutation done on sources std::vector ins_order; for (size_t n = 0; n < sources.size(); ++n) @@ -371,15 +324,50 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector used_keys; const std::vector &msk0 = miner_account[creator].get_multisig_keys(); for (const auto &sk: msk0) - used_keys.insert(sk); - for (size_t signer: signers) + used_keys.insert(sk); //these were used in 'tx_builder.init() -> tx_builder.first_partial_sign()' + for (size_t signer: other_signers) { rct::key skey = rct::zero(); const std::vector &msk1 = miner_account[signer].get_multisig_keys(); @@ -393,38 +381,37 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector indices; - for (const auto &src: sources_copy) - indices.push_back(src.real_output); - rct::keyV k; - for (size_t tdidx = 0; tdidx < inputs; ++tdidx) - { - k.push_back(rct::zero()); - for (size_t n = 0; n < account_k[signer][tdidx].size(); ++n) - { - crypto::public_key L; - rct::scalarmultBase((rct::key&)L, rct::sk2rct(account_k[signer][tdidx][n])); - if (used_L.find(L) != used_L.end()) - { - sc_add(k.back().bytes, k.back().bytes, rct::sk2rct(account_k[signer][tdidx][n]).bytes); + rct::keyM k(sources.size(), rct::keyV(multisig::signing::kAlphaComponents)); + for (std::size_t i = 0; i < sources.size(); ++i) { + for (std::size_t j = 0; j < multisig::signing::kAlphaComponents; ++j) { + for (std::size_t n = 0; n < account_k[signer][i].size(); ++n) { + crypto::public_key L; + rct::scalarmultBase((rct::key&)L, rct::sk2rct(account_k[signer][i][n])); + if (used_L.find(L) != used_L.end()) { + k[i][j] = rct::sk2rct(account_k[signer][i][n]); + account_k[signer][i][n] = rct::rct2sk(rct::zero()); //demo: always clear nonces from long-term storage after use + break; + } } + CHECK_AND_ASSERT_MES(!(k[i][j] == rct::zero()), false, "failed to find k to sign transaction"); } - CHECK_AND_ASSERT_MES(!(k.back() == rct::zero()), false, "failed to find k to sign transaction"); } - tools::apply_permutation(ins_order, indices); tools::apply_permutation(ins_order, k); + multisig::signing::tx_builder_ringct_t signer_tx_builder; + CHECK_AND_ASSERT_MES(signer_tx_builder.init(miner_account[signer].get_keys(), {}, 0, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, true, tx_key, additional_tx_secret_keys, tx), false, "error: multisig::signing::tx_builder_t::init"); MDEBUG("signing with k size " << k.size()); - MDEBUG("signing with k " << k.back()); + for (size_t n = 0; n < multisig::signing::kAlphaComponents; ++n) + MDEBUG("signing with k " << k.back()[n]); MDEBUG("signing with sk " << skey); for (const auto &sk: used_keys) MDEBUG(" created with sk " << sk); - MDEBUG("signing with c size " << msout.c.size()); - MDEBUG("signing with c " << msout.c.back()); - r = rct::signMultisig(tx.rct_signatures, indices, k, msout, skey); - CHECK_AND_ASSERT_MES(r, false, "failed to sign transaction"); + CHECK_AND_ASSERT_MES(signer_tx_builder.next_partial_sign(sig.total_alpha_G, sig.total_alpha_H, k, skey, sig.c_0, sig.s), false, "error: multisig::signing::tx_builder_ringct_t::next_partial_sign"); + + // in round-robin signing, the last signer finalizes the tx + if (signer == other_signers.back()) + CHECK_AND_ASSERT_MES(signer_tx_builder.finalize_tx(sources, sig.c_0, sig.s, tx), false, "error: multisig::signing::tx_builder_ringct_t::finalize_tx"); } -#endif // verify this tx is really to the expected address const crypto::public_key tx_pub_key2 = get_tx_pub_key_from_extra(tx, 0); @@ -433,10 +420,12 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector additional_derivations; + crypto::public_key output_public_key; for (size_t n = 0; n < tx.vout.size(); ++n) { - CHECK_AND_ASSERT_MES(typeid(txout_to_key) == tx.vout[n].target.type(), false, "Unexpected tx out type"); - if (is_out_to_acc_precomp(subaddresses, boost::get(tx.vout[n].target).key, derivation, additional_derivations, n, hw::get_device(("default")))) + CHECK_AND_ASSERT_MES(typeid(txout_to_tagged_key) == tx.vout[n].target.type(), false, "Unexpected tx out type"); + cryptonote::get_output_public_key(tx.vout[n], output_public_key); + if (is_out_to_acc_precomp(subaddresses, output_public_key, derivation, additional_derivations, n, hw::get_device(("default")))) { ++n_outs; CHECK_AND_ASSERT_MES(tx.vout[n].amount == 0, false, "Destination amount is not zero"); @@ -451,7 +440,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector& events, size_t inputs, size_t mixin, uint64_t amount_paid, bool valid, - size_t threshold, size_t total, size_t creator, std::vector signers, + size_t threshold, size_t total, size_t creator, std::vector other_signers, const std::function &sources, std::vector &destinations)> &pre_tx, const std::function &post_tx) const; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 0926483fe96..4e51ed71326 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -229,7 +229,7 @@ bool gen_rct_tx_validation_base::generate_with_full(std::vector additional_tx_keys; std::unordered_map subaddresses; subaddresses[miner_accounts[0].get_keys().m_account_address.m_spend_public_key] = {0,0}; - bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector(), tx, 0, tx_key, additional_tx_keys, true, rct_config, NULL, use_view_tags); + bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector(), tx, 0, tx_key, additional_tx_keys, true, rct_config, use_view_tags); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx) diff --git a/tests/core_tests/wallet_tools.cpp b/tests/core_tests/wallet_tools.cpp index fdc4753f9ab..a3b66e835de 100644 --- a/tests/core_tests/wallet_tools.cpp +++ b/tests/core_tests/wallet_tools.cpp @@ -280,5 +280,5 @@ bool construct_tx_rct(tools::wallet2 * sender_wallet, std::vector additional_tx_keys; std::vector destinations_copy = destinations; rct::RCTConfig rct_config = {range_proof_type, bp_version}; - return construct_tx_and_get_tx_key(sender_wallet->get_account().get_keys(), subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, nullptr); + return construct_tx_and_get_tx_key(sender_wallet->get_account().get_keys(), subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config); } diff --git a/tests/performance_tests/rct_mlsag.h b/tests/performance_tests/rct_mlsag.h index 4cdbcd601b8..2163431fe38 100644 --- a/tests/performance_tests/rct_mlsag.h +++ b/tests/performance_tests/rct_mlsag.h @@ -65,7 +65,7 @@ class test_ringct_mlsag : public single_tx_test_base { sk[j] = xm[ind][j]; } - IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default")); + IIccss = MLSAG_Gen(rct::identity(), P, sk, ind, rows-1, hw::get_device("default")); return true; } @@ -75,7 +75,7 @@ class test_ringct_mlsag : public single_tx_test_base if (ver) MLSAG_Ver(rct::identity(), P, IIccss, rows-1); else - MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default")); + MLSAG_Gen(rct::identity(), P, sk, ind, rows-1, hw::get_device("default")); return true; } diff --git a/tests/performance_tests/sig_clsag.h b/tests/performance_tests/sig_clsag.h index 53c38c56b12..043830ee606 100644 --- a/tests/performance_tests/sig_clsag.h +++ b/tests/performance_tests/sig_clsag.h @@ -117,7 +117,7 @@ class test_sig_clsag sk.dest = r[u]; sk.mask = s[u]; - sigs.push_back(proveRctCLSAGSimple(messages[u],pubs,sk,s1[u],C_offsets[u],NULL,NULL,NULL,u,hw::get_device("default"))); + sigs.push_back(proveRctCLSAGSimple(messages[u],pubs,sk,s1[u],C_offsets[u],u,hw::get_device("default"))); } return true; diff --git a/tests/performance_tests/sig_mlsag.h b/tests/performance_tests/sig_mlsag.h index 60a306753d5..46bdcde6305 100644 --- a/tests/performance_tests/sig_mlsag.h +++ b/tests/performance_tests/sig_mlsag.h @@ -117,7 +117,7 @@ class test_sig_mlsag sk.dest = r[u]; sk.mask = s[u]; - sigs.push_back(proveRctMGSimple(messages[u],pubs,sk,s1[u],C_offsets[u],NULL,NULL,u,hw::get_device("default"))); + sigs.push_back(proveRctMGSimple(messages[u],pubs,sk,s1[u],C_offsets[u],u,hw::get_device("default"))); } return true; diff --git a/tests/unit_tests/bulletproofs.cpp b/tests/unit_tests/bulletproofs.cpp index 493eb9426ec..65f0d85f8e3 100644 --- a/tests/unit_tests/bulletproofs.cpp +++ b/tests/unit_tests/bulletproofs.cpp @@ -132,7 +132,8 @@ TEST(bulletproofs, multi_splitting) rct::ctkeyV outSk; rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, 4 }; - rct::rctSig s = rct::genRctSimple(rct::zero(), sc, destinations, inamounts, outamounts, available, mixRing, amount_keys, NULL, NULL, index, outSk, rct_config, hw::get_device("default")); + + rct::rctSig s = rct::genRctSimple(rct::zero(), sc, destinations, inamounts, outamounts, available, mixRing, amount_keys, index, outSk, rct_config, hw::get_device("default")); ASSERT_TRUE(rct::verRctSimple(s)); for (size_t i = 0; i < n_outputs; ++i) { diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index f3ca2b2b4b1..920ec7c5e76 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -113,7 +113,7 @@ TEST(ringct, MG_sigs) sk[j] = xm[ind][j]; } key message = identity(); - mgSig IIccss = MLSAG_Gen(message, P, sk, NULL, NULL, ind, R, hw::get_device("default")); + mgSig IIccss = MLSAG_Gen(message, P, sk, ind, R, hw::get_device("default")); ASSERT_TRUE(MLSAG_Ver(message, P, IIccss, R)); //#MG sig: false one @@ -134,7 +134,7 @@ TEST(ringct, MG_sigs) sk[j] = xx[ind][j]; } sk[2] = skGen();//assume we don't know one of the private keys.. - IIccss = MLSAG_Gen(message, P, sk, NULL, NULL, ind, R, hw::get_device("default")); + IIccss = MLSAG_Gen(message, P, sk, ind, R, hw::get_device("default")); ASSERT_FALSE(MLSAG_Ver(message, P, IIccss, R)); } @@ -178,13 +178,13 @@ TEST(ringct, CLSAG) insk.mask = t; // bad message - clsag = rct::proveRctCLSAGSimple(zero(),pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + clsag = rct::proveRctCLSAGSimple(zero(),pubs,insk,t2,Cout,idx,hw::get_device("default")); ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); // bad index at creation try { - clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,(idx + 1) % N,hw::get_device("default")); + clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,(idx + 1) % N,hw::get_device("default")); ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } @@ -195,7 +195,7 @@ TEST(ringct, CLSAG) ctkey insk2; insk2.dest = insk.dest; insk2.mask = skGen(); - clsag = rct::proveRctCLSAGSimple(message,pubs,insk2,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + clsag = rct::proveRctCLSAGSimple(message,pubs,insk2,t2,Cout,idx,hw::get_device("default")); ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } @@ -205,7 +205,7 @@ TEST(ringct, CLSAG) pubs[idx].mask = scalarmultBase(skGen()); try { - clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,idx,hw::get_device("default")); ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } @@ -217,7 +217,7 @@ TEST(ringct, CLSAG) ctkey insk2; insk2.dest = skGen(); insk2.mask = insk.mask; - clsag = rct::proveRctCLSAGSimple(message,pubs,insk2,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + clsag = rct::proveRctCLSAGSimple(message,pubs,insk2,t2,Cout,idx,hw::get_device("default")); ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } @@ -227,14 +227,14 @@ TEST(ringct, CLSAG) pubs[idx].dest = scalarmultBase(skGen()); try { - clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,idx,hw::get_device("default")); ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } pubs[idx] = backup; // Test correct signature - clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default")); + clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,idx,hw::get_device("default")); ASSERT_TRUE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); // empty s @@ -340,12 +340,12 @@ TEST(ringct, range_proofs) //compute rct data with mixin 3 - should fail since full type with > 1 input bool ok = false; - try { genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, rct_config, hw::get_device("default")); } + try { genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, 3, rct_config, hw::get_device("default")); } catch(...) { ok = true; } ASSERT_TRUE(ok); //compute rct data with mixin 3 - rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config, hw::get_device("default")); + rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default")); //verify rct data ASSERT_TRUE(verRctSimple(s)); @@ -362,7 +362,7 @@ TEST(ringct, range_proofs) //compute rct data with mixin 3 - s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config, hw::get_device("default")); + s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default")); //verify rct data ASSERT_FALSE(verRctSimple(s)); @@ -410,7 +410,7 @@ TEST(ringct, range_proofs_with_fee) const rct::RCTConfig rct_config { RangeProofBorromean, 0 }; //compute rct data with mixin 3 - rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 1, 3, rct_config, hw::get_device("default")); + rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, 1, 3, rct_config, hw::get_device("default")); //verify rct data ASSERT_TRUE(verRctSimple(s)); @@ -427,7 +427,7 @@ TEST(ringct, range_proofs_with_fee) //compute rct data with mixin 3 - s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 500, 3, rct_config, hw::get_device("default")); + s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, 500, 3, rct_config, hw::get_device("default")); //verify rct data ASSERT_FALSE(verRctSimple(s)); @@ -486,7 +486,7 @@ TEST(ringct, simple) xmr_amount txnfee = 1; const rct::RCTConfig rct_config { RangeProofBorromean, 0 }; - rctSig s = genRctSimple(message, sc, pc, destinations,inamounts, outamounts, amount_keys, NULL, NULL, txnfee, 2, rct_config, hw::get_device("default")); + rctSig s = genRctSimple(message, sc, pc, destinations,inamounts, outamounts, amount_keys, txnfee, 2, rct_config, hw::get_device("default")); //verify ring ct signature ASSERT_TRUE(verRctSimple(s)); @@ -521,7 +521,7 @@ static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amount } const rct::RCTConfig rct_config { RangeProofBorromean, 0 }; - return genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, rct_config, hw::get_device("default")); + return genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, 3, rct_config, hw::get_device("default")); } static rct::rctSig make_sample_simple_rct_sig(int n_inputs, const uint64_t input_amounts[], int n_outputs, const uint64_t output_amounts[], uint64_t fee) @@ -548,7 +548,7 @@ static rct::rctSig make_sample_simple_rct_sig(int n_inputs, const uint64_t input } const rct::RCTConfig rct_config { RangeProofBorromean, 0 }; - return genRctSimple(rct::zero(), sc, pc, destinations, inamounts, outamounts, amount_keys, NULL, NULL, fee, 3, rct_config, hw::get_device("default")); + return genRctSimple(rct::zero(), sc, pc, destinations, inamounts, outamounts, amount_keys, fee, 3, rct_config, hw::get_device("default")); } static bool range_proof_test(bool expected_valid, diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 9e8a28f7c3f..87571e5b5dc 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -594,7 +594,7 @@ TEST(Serialization, serializes_ringct_types) destinations.push_back(Pk); //compute rct data with mixin 3 const rct::RCTConfig rct_config{ rct::RangeProofPaddedBulletproof, 2 }; - s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config, hw::get_device("default")); + s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default")); ASSERT_FALSE(s0.p.MGs.empty()); ASSERT_TRUE(s0.p.CLSAGs.empty()); @@ -619,7 +619,7 @@ TEST(Serialization, serializes_ringct_types) ASSERT_EQ(bp0, bp1); const rct::RCTConfig rct_config_clsag{ rct::RangeProofPaddedBulletproof, 3 }; - s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config_clsag, hw::get_device("default")); + s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, 0, 3, rct_config_clsag, hw::get_device("default")); ASSERT_FALSE(s0.p.CLSAGs.empty()); ASSERT_TRUE(s0.p.MGs.empty()); From d486c0322fc524c6a85442bf05c336254dfa5327 Mon Sep 17 00:00:00 2001 From: Leo Nerone Date: Fri, 17 Jun 2022 18:49:39 -0300 Subject: [PATCH 045/186] utils: add fish shell completions Fish shell completions for monerod, monero-wallet-cli, and monero-wallet-rpc. --- utils/fish/README.md | 2 + utils/fish/monero-wallet-cli.fish | 61 ++++++++++++++++ utils/fish/monero-wallet-rpc.fish | 65 +++++++++++++++++ utils/fish/monerod.fish | 113 ++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 utils/fish/README.md create mode 100644 utils/fish/monero-wallet-cli.fish create mode 100644 utils/fish/monero-wallet-rpc.fish create mode 100644 utils/fish/monerod.fish diff --git a/utils/fish/README.md b/utils/fish/README.md new file mode 100644 index 00000000000..7d7c58c2832 --- /dev/null +++ b/utils/fish/README.md @@ -0,0 +1,2 @@ +## Fish shell completions for Monero +This folder has basic Fish completions for `monerod`, `monero-wallet-cli`, and `monero-wallet-rpc`. To use them, put those files (or symlink them) inside `~/.config/fish/completions/` or wherever your Fish completion files are (see [https://fishshell.com/docs/current/completions.html#where-to-put-completions](https://fishshell.com/docs/current/completions.html#where-to-put-completions)) diff --git a/utils/fish/monero-wallet-cli.fish b/utils/fish/monero-wallet-cli.fish new file mode 100644 index 00000000000..c9c878dba67 --- /dev/null +++ b/utils/fish/monero-wallet-cli.fish @@ -0,0 +1,61 @@ +complete -c monero-wallet-cli -f + +complete -c monero-wallet-cli -l help -d "Produce help message" +complete -c monero-wallet-cli -l version -d "Output version information" +complete -c monero-wallet-cli -l daemon-address -r -d "Use daemon instance at :" +complete -c monero-wallet-cli -l daemon-host -r -d "Use daemon instance at host instead of localhost" +complete -c monero-wallet-cli -l proxy -r -d "[:] socks proxy to use for daemon connections" +complete -c monero-wallet-cli -l trusted-daemon -d "Enable commands which rely on a trusted" +complete -c monero-wallet-cli -l untrusted-daemon -d "Disableâ‹…commandsâ‹…whichâ‹…relyâ‹…onâ‹…a trusted daemon" +complete -c monero-wallet-cli -l password -r -d "Walletâ‹…passwordâ‹…(escape/quoteâ‹…as needed)" +complete -c monero-wallet-cli -l password-file -r -F -d "Walletâ‹…passwordâ‹…file" +complete -c monero-wallet-cli -l daemon-port -r -d "Use daemon instance at port instead of 18081" +complete -c monero-wallet-cli -l daemon-login -r -d "Specify username[:password] for daemon RPC client" +complete -c monero-wallet-cli -l daemon-ssl -x -a "enabled disabled autodetect" -d "Enable SSL on daemon RPC connections. Default: autodetect" +complete -c monero-wallet-cli -l daemon-ssl-private-key -r -k -a "(__fish_complete_suffix .pem)" -d "Path to a PEM format private key" +complete -c monero-wallet-cli -l daemon-ssl-certificate -r -k -a "(__fish_complete_suffix .pem)" -d "Path to a PEM format certificate" +complete -c monero-wallet-cli -l daemon-ssl-ca-certificates -r -F -d "Path to file containing concatenated PEM format certificate(s) to replace system CA(s)." +complete -c monero-wallet-cli -l daemon-ssl-allowed-fingerprints -r -d "List of valid fingerprints of allowed RPC servers" +complete -c monero-wallet-cli -l daemon-ssl-allow-any-cert -d "Allow any SSL certificate from the daemon" +complete -c monero-wallet-cli -l daemon-ssl-allow-chained -d "Allow user (via --daemon-ssl-ca-certifi cates) chain certificates" +complete -c monero-wallet-cli -l testnet -d "For testnet. Daemon must also be launched with --testnet flag" +complete -c monero-wallet-cli -l stagenet -d "For stagenet. Daemon must also be launched with --stagenet flag" +complete -c monero-wallet-cli -l shared-ringdb-dir -r -F -d "Set shared ring database path" +complete -c monero-wallet-cli -l kdf-rounds -r -d "Number of rounds for the key derivation function. Default: 1" +complete -c monero-wallet-cli -l bitmessage-address -r -d "Use PyBitmessage instance at URL . Default: http://localhost:8442/" +complete -c monero-wallet-cli -l bitmessage-login -r -d "Specify as username:password for PyBitmessage API. Default: username:password" +complete -c monero-wallet-cli -l hw-device -r -d "HW device to use" +complete -c monero-wallet-cli -l hw-device-deriv-path -r -d "HW device wallet derivation path (e.g., SLIP-10)" +complete -c monero-wallet-cli -l tx-notify -r -d "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" +complete -c monero-wallet-cli -l no-dns -d "Do not use DNS" +complete -c monero-wallet-cli -l offline -d "Do not connect to a daemon, nor use DNS" +complete -c monero-wallet-cli -l extra-entropy -r -F -d "File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)" +complete -c monero-wallet-cli -l wallet-file -r -F -d "Use wallet " +complete -c monero-wallet-cli -l generate-new-wallet -r -F -d "Generate new wallet and save it to " +complete -c monero-wallet-cli -l generate-from-device -r -F -d "Generate new wallet from device and save it to " +complete -c monero-wallet-cli -l generate-from-view-key -r -d "Generate incoming-only wallet from view key" +complete -c monero-wallet-cli -l generate-from-spend-key -r -d "Generate deterministic wallet from spend key" +complete -c monero-wallet-cli -l generate-from-keys -r -d "Generate wallet from private keys" +complete -c monero-wallet-cli -l generate-from-multisig-keys -r -d "Generate a master wallet from multisig wallet keys" +complete -c monero-wallet-cli -l generate-from-json -r -k -a "(__fish_complete_suffix .json)" -d "Generate wallet from JSON format file" +complete -c monero-wallet-cli -l mnemonic-language -r -d "Language for mnemonic" +complete -c monero-wallet-cli -l command -d "" +complete -c monero-wallet-cli -l restore-deterministic-wallet -d "Recover wallet using Electrum-style mnemonic seed" +complete -c monero-wallet-cli -l restore-from-seed -d "alias for --restore-deterministic-wallet" +complete -c monero-wallet-cli -l restore-multisig-wallet -d "Recover multisig wallet using Electrum-style mnemonic seed" +complete -c monero-wallet-cli -l non-deterministic -d "Generate non-deterministic view and spend keys" +complete -c monero-wallet-cli -l electrum-seed -r -d "Specify Electrum seed for wallet recovery/creation" +complete -c monero-wallet-cli -l allow-mismatched-daemon-version -d "Allow communicating with a daemon that uses a different RPC version" +complete -c monero-wallet-cli -l restore-height -r -d "Restore from specific blockchain height. Default: 0" +complete -c monero-wallet-cli -l restore-date -r -d "Restore from estimated blockchain height on specified date" +complete -c monero-wallet-cli -l do-not-relay -d "The newly created transaction will not be relayed to the monero network" +complete -c monero-wallet-cli -l create-address-file -d "Create an address file for new wallets" +complete -c monero-wallet-cli -l subaddress-lookahead -r -d "Set subaddress lookahead sizes to :" +complete -c monero-wallet-cli -l use-english-language-names -d "Display English language names" +complete -c monero-wallet-cli -l rpc-client-secret-key -r -d "Set RPC client secret key for RPC payments" +complete -c monero-wallet-cli -l log-file -r -F -d "Specify log file" +complete -c monero-wallet-cli -l log-level -r -a "0 1 2 3 4" -d "0-4 or categories" +complete -c monero-wallet-cli -l max-log-file-size -r -d "Specify maximum log file size [B]. Default: 104850000" +complete -c monero-wallet-cli -l max-log-files -r -d "Specify maximum number of rotated log files to be saved (no limit by setting to 0). Default: 50" +complete -c monero-wallet-cli -l max-concurrency -d "Max number of threads to use for a parallel job. Default: 1" +complete -c monero-wallet-cli -l config-file -r -F -d "Config file" diff --git a/utils/fish/monero-wallet-rpc.fish b/utils/fish/monero-wallet-rpc.fish new file mode 100644 index 00000000000..a64e112ef07 --- /dev/null +++ b/utils/fish/monero-wallet-rpc.fish @@ -0,0 +1,65 @@ +complete -c monero-wallet-rpc -f + +complete -c monero-wallet-rpc -l help -d "Produce help message" +complete -c monero-wallet-rpc -l version -d "Output version information " +complete -c monero-wallet-rpc -l daemon-address -r -d "Use daemon instance at :" +complete -c monero-wallet-rpc -l daemon-host -r -d "Use daemon instance at host instead of localhost" +complete -c monero-wallet-rpc -l proxy -r -d "[:] socks proxy to use for daemon connections" +complete -c monero-wallet-rpc -l trusted-daemon -d "Enable commands which rely on a trusted daemon" +complete -c monero-wallet-rpc -l untrusted-daemon -d "Disable commands which rely on a trusted daemon" +complete -c monero-wallet-rpc -l password -r -d "Wallet password (escape/quote as needed)" +complete -c monero-wallet-rpc -l password-file -r -F -d "Wallet password file" +complete -c monero-wallet-rpc -l daemon-port -r -d "Use daemon instance at port instead of 18081. Default: 0" +complete -c monero-wallet-rpc -l daemon-login -r -d "Specify username[:password] for daemon RPC client" +complete -c monero-wallet-rpc -l daemon-ssl -x -a "enabled disabled autodetect" -d "Enable SSL on daemon RPC connections. Default: autodetect" +complete -c monero-wallet-rpc -l daemon-ssl-private-key -r -k -a "(__fish_complete_suffix .pem)" -d "Path to a PEM format private key" +complete -c monero-wallet-rpc -l daemon-ssl-certificate -r -k -a "(__fish_complete_suffix .pem)" -d "Path to a PEM format certificate" +complete -c monero-wallet-rpc -l daemon-ssl-ca-certificates -r -F -d "Path to file containing concatenated PEM format certificate(s) to replace system CA(s)." +complete -c monero-wallet-rpc -l daemon-ssl-allowed-fingerprints -r -d "List of valid fingerprints of allowed RPC servers" +complete -c monero-wallet-rpc -l daemon-ssl-allow-any-cert -d "Allow any SSL certificate from the daemon" +complete -c monero-wallet-rpc -l daemon-ssl-allow-chained -d "Allow user (via --daemon-ssl-ca-certifi cates) chain certificates" +complete -c monero-wallet-rpc -l testnet -d "For testnet. Daemon must also be launched with --testnet flag" +complete -c monero-wallet-rpc -l stagenet -d "For stagenet. Daemon must also be launched with --stagenet flag" +complete -c monero-wallet-rpc -l shared-ringdb-dir -r -F -d "Set shared ring database path" +complete -c monero-wallet-rpc -l kdf-rounds -r -d "Number of rounds for the key derivation function. Default: 1" +complete -c monero-wallet-rpc -l bitmessage-address -r -d "Use PyBitmessage instance at URL . Default: http://localhost:8442/" +complete -c monero-wallet-rpc -l bitmessage-login -r -d "Specify as username:password for PyBitmessage API. Default: username:password" +complete -c monero-wallet-rpc -l hw-device -r -d "HW device to use" +complete -c monero-wallet-rpc -l hw-device-deriv-path -r -d "HW device wallet derivation path (e.g., SLIP-10)" +complete -c monero-wallet-rpc -l tx-notify -r -d "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" +complete -c monero-wallet-rpc -l no-dns -d "Do not use DNS" +complete -c monero-wallet-rpc -l offline -d "Do not connect to a daemon, nor use DNS" +complete -c monero-wallet-rpc -l extra-entropy -r -F -d "File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)" +complete -c monero-wallet-rpc -l rpc-bind-port -r -d "Sets bind port for server" +complete -c monero-wallet-rpc -l disable-rpc-login -d "Disable HTTP authentication for RPC connections served by this process" +complete -c monero-wallet-rpc -l restricted-rpc -d "Restricts to view-only commands" +complete -c monero-wallet-rpc -l rpc-bind-ip -r -d "Specify IP to bind RPC server. Default: 127.0.0.1" +complete -c monero-wallet-rpc -l rpc-bind-ipv6-address -r -d "Specify IPv6 address to bind RPC server. Default: ::1" +complete -c monero-wallet-rpc -l rpc-restricted-bind-ip -r -d "Specify IP to bind restricted RPC server. Default: 127.0.0.1" +complete -c monero-wallet-rpc -l rpc-restricted-bind-ipv6-address -r -d "Specify IPv6 address to bind restricted RPC server. Default: ::1" +complete -c monero-wallet-rpc -l rpc-use-ipv6 -d "Allow IPv6 for RPC" +complete -c monero-wallet-rpc -l rpc-ignore-ipv4 -d "Ignore unsuccessful IPv4 bind for RPC" +complete -c monero-wallet-rpc -l rpc-login -r -d "Specify username[:password] required for RPC server" +complete -c monero-wallet-rpc -l confirm-external-bind -d "Confirm rpc-bind-ip value is NOT a loopback (local) IP" +complete -c monero-wallet-rpc -l rpc-access-control-origins -r -d "Specify a comma separated list of origins to allow cross origin resource sharing" +complete -c monero-wallet-rpc -l rpc-ssl -x -a "enabled disabled autodetect" -d "Enable SSL on RPC connections. Default: autodetect" +complete -c monero-wallet-rpc -l rpc-ssl-private-key -r -k -a "(__fish_complete_suffix .pem)" -d "Path to a PEM format private key" +complete -c monero-wallet-rpc -l rpc-ssl-certificate -r -k -a "(__fish_complete_suffix .pem)" -d "Path to a PEM format certificate" +complete -c monero-wallet-rpc -l rpc-ssl-ca-certificates -r -F -d "Path to file containing concatenated PEM format certificate(s) to replace system CA(s)." +complete -c monero-wallet-rpc -l rpc-ssl-allowed-fingerprints -r -d "List of certificate fingerprints to allow" +complete -c monero-wallet-rpc -l rpc-ssl-allow-chained -d "Allow user (via --rpc-ssl-certificates) chain certificates" +complete -c monero-wallet-rpc -l disable-rpc-ban -d "Do not ban hosts on RPC errors" +complete -c monero-wallet-rpc -l wallet-file -r -F -d "Use wallet " +complete -c monero-wallet-rpc -l generate-from-json -r -k -a "(__fish_complete_suffix .json)" -d "Generate wallet from JSON format file" +complete -c monero-wallet-rpc -l wallet-dir -r -F -d "Directory for newly created wallets" +complete -c monero-wallet-rpc -l prompt-for-password -d "Prompts for password when not provided" +complete -c monero-wallet-rpc -l rpc-client-secret-key -r -d "Set RPC client secret key for RPC payments" +complete -c monero-wallet-rpc -l detach -d "Run as daemon" +complete -c monero-wallet-rpc -l pidfile -r -F -d "File path to write the daemon's PID to (optional, requires --detach)" +complete -c monero-wallet-rpc -l non-interactive -d "Run non-interactive" +complete -c monero-wallet-rpc -l log-file -r -F -d "Specify log file" +complete -c monero-wallet-rpc -l log-level -r -a "0 1 2 3 4" -d "0-4 or categories" +complete -c monero-wallet-rpc -l max-log-file-size -r -d "Specify maximum log file size [B]. Default: 104850000" +complete -c monero-wallet-rpc -l max-log-files -r -d "Specify maximum number of rotated log files to be saved (no limit by setting to 0). Default: 50" +complete -c monero-wallet-rpc -l max-concurrency -d "Max number of threads to use for a parallel job. Default: 1" +complete -c monero-wallet-rpc -l config-file -r -F -d "Config file" diff --git a/utils/fish/monerod.fish b/utils/fish/monerod.fish new file mode 100644 index 00000000000..d2836a6b2a4 --- /dev/null +++ b/utils/fish/monerod.fish @@ -0,0 +1,113 @@ +complete -c monerod -f + +complete -c monerod -l help -d "Produce help message" +complete -c monerod -l version -d "Output version information" +complete -c monerod -l os-version -d "OS for which this executable was compiled" +complete -c monerod -l config-file -r -d "Specify configuration file" +complete -c monerod -l detach -d "Run as daemon" +complete -c monerod -l pidfile -r -F -d "File path to write the daemon's PID to (optional, requires --detach)" +complete -c monerod -l non-interactive -d "Run non-interactive" +complete -c monerod -l log-file -r -F -d "Specify log file" +complete -c monerod -l log-level -r -d "" +complete -c monerod -l max-log-file-size -r -d "Specify maximum log file size [B]. Default: 104850000" +complete -c monerod -l max-log-files -r -d "Specify maximum number of rotated log files to be saved (no limit by setting to 0). Default: 50" +complete -c monerod -l max-concurrency -r -d "Max number of threads to use for a parallel job. Default: 0" +complete -c monerod -l proxy -r -d "Network communication through proxy: i.e. \"127.0.0.1:9050\"" +complete -c monerod -l proxy-allow-dns-leaks -d "Allow DNS leaks outside of proxy" +complete -c monerod -l public-node -d "Allow other users to use the node as a remote (restricted RPC mode, view-only commands) and advertise it over P2P" +complete -c monerod -l zmq-rpc-bind-ip -r -d "IP for ZMQ RPC server to listen on. Default: 127.0.0.1" +complete -c monerod -l zmq-rpc-bind-port -r -d "Port for ZMQ RPC server to listen on. Default: 18082, 28082 if 'testnet', 38082 if 'stagenet'" +complete -c monerod -l zmq-pub -r -d "Address for ZMQ pub - tcp://ip:port or ipc://path " +complete -c monerod -l no-zmq -d "Disable ZMQ RPC server [114/349]" +complete -c monerod -l data-dir -x -a "(__fish_complete_directories)" -d "Specify data directory" +complete -c monerod -l test-drop-download -d "For net tests: in download, discard ALL blocks instead checking/saving them (very fast)" +complete -c monerod -l test-drop-download-height -r -d "Like test-drop-download but discards only after around certain height. Default: 0" +complete -c monerod -l testnet -d "Run on testnet. The wallet must be launched with --testnet flag." +complete -c monerod -l stagenet -d "Run on stagenet. The wallet must be launched with --stagenet flag." +complete -c monerod -l regtest -d "Run in a regression testing mode." +complete -c monerod -l keep-fakechain -d "Don't delete any existing database when in fakechain mode." +complete -c monerod -l fixed-difficulty -r -d "Fixed difficulty used for testing. Default: 0" +complete -c monerod -l enforce-dns-checkpointing -d "checkpoints from DNS server will be enforced" +complete -c monerod -l prep-blocks-threads -r -d "Max number of threads to use when preparing block hashes in groups. Default: 4" +complete -c monerod -l fast-block-sync -r -d "Sync up most of the way by using embedded, known block hashes. Default: 1" +complete -c monerod -l show-time-stats -r -d "(=0) Show time-stats when processing blocks/txs and disk synchronization. Default: 0" +complete -c monerod -l block-sync-size -r -d "(=0) How many blocks to sync at once during chain synchronization (0 = adaptive). Default: 0" +complete -c monerod -l check-updates -x -a "disabled notify download update" -d "Check for new versions of monero. Default: notify" +complete -c monerod -l fluffy-blocks -d "Relay blocks as fluffy blocks (obsolete, now default)" +complete -c monerod -l no-fluffy-blocks -d "Relay blocks as normal blocks" +complete -c monerod -l test-dbg-lock-sleep -r -d "Sleep time in ms, defaults to 0 (off), used to debug before/after locking mutex. Values 100 to 1000 are good for tests." +complete -c monerod -l offline -d "Do not listen for peers, nor connect to any" +complete -c monerod -l disable-dns-checkpoints -d "Do not retrieve checkpoints from DNS" +complete -c monerod -l block-download-max-size -r -d "Set maximum size of block download queue in bytes (0 for default)" +complete -c monerod -l sync-pruned-blocks -d "Allow syncing from nodes with only pruned blocks" +complete -c monerod -l max-txpool-weight -r -d "Set maximum txpool weight in bytes. Default: 648000000" +complete -c monerod -l block-notify -r -d "Run a program for each new block, '%s' will be replaced by the block hash" +complete -c monerod -l prune-blockchain -d "Prune blockchain" +complete -c monerod -l reorg-notify -r -d "Run a program for each reorg, '%s' will be replaced by the split height, '%h' will be replaced by the new blockchain height, '%n' will be replaced by the number of new blocks in the new chain, and '%d' will be replaced by the number of blocks discarded from the old chain" +complete -c monerod -l block-rate-notify -r -d "Run a program when the block rate undergoes large fluctuations. This might be a sign of large amounts of hash rate going on and off the Monero network, and thus be of potential interest in predicting attacks. %t will be replaced by the number of minutes for the observation window, %b by the number of blocks observed within that window, and %e by the number of blocks that was expected in that window. It is suggested that this notification is used to automatically increase the number of confirmations required before a payment is acted upon." +complete -c monerod -l keep-alt-blocks -d "Keep alternative blocks on restart" +complete -c monerod -l extra-messages-file -r -F -d "Specify file for extra messages to include into coinbase transactions" +complete -c monerod -l start-mining -r -d "Specify wallet address to mining for" +complete -c monerod -l mining-threads -r -d "Specify mining threads count" +complete -c monerod -l bg-mining-enable -d "Enable background mining" +complete -c monerod -l bg-mining-ignore-battery -d "If true, assumes plugged in when unable to query system power status" +complete -c monerod -l bg-mining-min-idle-interval -r -d "Specify min lookback interval in seconds for determining idle state" +complete -c monerod -l bg-mining-idle-threshold -r -d "Specify minimum avg idle percentage over lookback interval" +complete -c monerod -l bg-mining-miner-target -r -d "Specify maximum percentage cpu use by miner(s)" +complete -c monerod -l db-sync-mode -r -d "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[[blocks]| [bytes]]. Default: fast:async:250000000bytes" +complete -c monerod -l db-salvage -d "Try to salvage a blockchain database if it seems corrupted" +complete -c monerod -l p2p-bind-ip -r -d "Interface for p2p network protocol (IPv4). Default: 0.0.0.0" +complete -c monerod -l p2p-bind-ipv6-address -r -d "Interface for p2p network protocol (IPv6). Default: ::" +complete -c monerod -l p2p-bind-port -r -d "Port for p2p network protocol (IPv4). Default: 18080, 28080 if 'testnet', 38080 if 'stagenet'" +complete -c monerod -l p2p-bind-port-ipv6 -d "Port for p2p network protocol (IPv6). Default: 18080, 28080 if 'testnet', 38080 if 'stagenet'" +complete -c monerod -l p2p-use-ipv6 -d "Enable IPv6 for p2p" +complete -c monerod -l p2p-ignore-ipv4 -d "Ignore unsuccessful IPv4 bind for p2p" +complete -c monerod -l p2p-external-port -r -d "External port for p2p network protocol (if port forwarding used with NAT). Default: 0" +complete -c monerod -l allow-local-ip -d "Allow local ip add to peer list, mostly in debug purposes" +complete -c monerod -l add-peer -r -d "Manually add peer to local peerlist" +complete -c monerod -l add-priority-node -r -d "Specify list of peers to connect to and attempt to keep the connection open" +complete -c monerod -l add-exclusive-node -r -d "Specify list of peers to connect to only. If this option is given the options add-priority-node and seed-node are ignored" +complete -c monerod -l seed-node -r -d "Connect to a node to retrieve peer addresses, and disconnect" +complete -c monerod -l tx-proxy -r -d "Send local txes through proxy: ,[,max_con nections][,disable_noise] i.e. \"tor,127.0.0.1:9050,100,disable_noise\"" +complete -c monerod -l anonymous-inbound -r -d ",<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\"" +complete -c monerod -l ban-list -r -F -d "Specify ban list file, one IP address per line" +complete -c monerod -l hide-my-port -d "Do not announce yourself as peerlist candidate" +complete -c monerod -l no-sync -d "Don't synchronize the blockchain with other peers" +complete -c monerod -l enable-dns-blocklist -d "Apply realtime blocklist from DNS" +complete -c monerod -l no-igd -d "Disable UPnP port mapping" +complete -c monerod -l igd -r -a "Enabled disabled enabled" -d "UPnP port mapping. Default: delayed" +complete -c monerod -l out-peers -r -d "Set max number of out peers. Default: -1" +complete -c monerod -l in-peers -r -d "Set max number of in peers. Default: -1" +complete -c monerod -l tos-flag -r -d "Set TOS flag. Default: -1" +complete -c monerod -l limit-rate-up -r -d "Set limit-rate-up [kB/s]. Default: 2048" +complete -c monerod -l limit-rate-down -r -d "Set limit-rate-down [kB/s]. Default: 8192" +complete -c monerod -l limit-rate -r -d "Set limit-rate [kB/s]. Default: -1" +complete -c monerod -l pad-transactions -d "Pad relayed transactions to help defend against traffic volume analysis" +complete -c monerod -l max-connections-per-ip -r -d "Maximum number of connections allowed from the same IP address. Default: 1" +complete -c monerod -l rpc-bind-port -r -d "Port for RPC server. Default: 18081, 28081 if 'testnet', 38081 if 'stagenet'" +complete -c monerod -l rpc-restricted-bind-port -r -d "Port for restricted RPC server" +complete -c monerod -l restricted-rpc -d "Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls" +complete -c monerod -l bootstrap-daemon-address -r -d "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced. Use 'auto' to enable automatic public nodes discovering and bootstrap daemon switching" +complete -c monerod -l bootstrap-daemon-login -r -d "Specify username:password for the bootstrap daemon login" +complete -c monerod -l bootstrap-daemon-proxy -r -d ": socks proxy to use for bootstrap daemon connections" +complete -c monerod -l rpc-bind-ip -r -d "Specify IP to bind RPC server. Default: 127.0.0.1" +complete -c monerod -l rpc-bind-ipv6-address -r -d "Specify IPv6 address to bind RPC server. Default: ::1" +complete -c monerod -l rpc-restricted-bind-ip -r -d "Specify IP to bind restricted RPC server. Default: 127.0.0.1" +complete -c monerod -l rpc-restricted-bind-ipv6-address -r -d "Specify IPv6 address to bind restricted RPC server. Default: ::1" +complete -c monerod -l rpc-use-ipv6 -d "Allow IPv6 for RPC" +complete -c monerod -l rpc-ignore-ipv4 -d "Ignore unsuccessful IPv4 bind for RPC" +complete -c monerod -l rpc-login -d "Specify username[:password] required for RPC server" +complete -c monerod -l confirm-external-bind -d "Confirm rpc-bind-ip value is NOT a loopback (local) IP" +complete -c monerod -l rpc-access-control-origins -r -d "Specify a comma separated list of origins to allow cross origin resource sharing" +complete -c monerod -l rpc-ssl -x -a "enabled disabled autodetect" -d "Enable SSL on RPC connections. Default: autodetect" +complete -c monerod -l rpc-ssl-private-key -r -k -a "(__fish_complete_suffix .pem)" -d "Path to a PEM format private key" +complete -c monerod -l rpc-ssl-certificate -r -k -a "(__fish_complete_suffix .pem)" -d "Path to a PEM format certificate" +complete -c monerod -l rpc-ssl-ca-certificates -r -F -d "Path to file containing concatenated PEM format certificate(s) to replace system CA(s)." +complete -c monerod -l rpc-ssl-allowed-fingerprints -r -d "List of certificate fingerprints to allow" +complete -c monerod -l rpc-ssl-allow-chained -d "Allow user (via --rpc-ssl-certificates) chain certificates" +complete -c monerod -l disable-rpc-ban -d "Do not ban hosts on RPC errors" +complete -c monerod -l rpc-ssl-allow-any-cert -d "Allow any peer certificate" +complete -c monerod -l rpc-payment-address -r -d "Restrict RPC to clients sending micropayment to this address" +complete -c monerod -l rpc-payment-difficulty -r -d "Restrict RPC to clients sending micropayment at this difficulty. Default: 1000" +complete -c monerod -l rpc-payment-credits -r -d "Restrict RPC to clients sending micropayment, yields that many credits per payment. Default: 100" +complete -c monerod -l rpc-payment-allow-free-loopback -d "Allow free access from the loopback address (ie, the local host)" From 2ba391f02cc97efa0b798afa842f85f0c2609692 Mon Sep 17 00:00:00 2001 From: selsta Date: Fri, 1 Jul 2022 00:53:22 +0200 Subject: [PATCH 046/186] hardforks: set mainnet and stagenet v15/16 fork height --- src/hardforks/hardforks.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hardforks/hardforks.cpp b/src/hardforks/hardforks.cpp index 0dd0cf5f0ce..336ef651973 100644 --- a/src/hardforks/hardforks.cpp +++ b/src/hardforks/hardforks.cpp @@ -71,8 +71,8 @@ const hardfork_t mainnet_hard_forks[] = { { 13, 2210000, 0, 1598180817 }, { 14, 2210720, 0, 1598180818 }, - { 15, 8000000, 0, 1608223241 }, // temp so tests test with these consensus rules - { 16, 8000001, 0, 1608223242 }, // temp so tests test with these consensus rules + { 15, 2688888, 0, 1656629117 }, + { 16, 2689608, 0, 1656629118 }, }; const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); const uint64_t mainnet_hard_fork_version_1_till = 1009826; @@ -122,5 +122,7 @@ const hardfork_t stagenet_hard_forks[] = { { 12, 454721, 0, 1571419280 }, { 13, 675405, 0, 1598180817 }, { 14, 676125, 0, 1598180818 }, + { 15, 1151000, 0, 1656629117 }, + { 16, 1151720, 0, 1656629118 }, }; const size_t num_stagenet_hard_forks = sizeof(stagenet_hard_forks) / sizeof(stagenet_hard_forks[0]); From 628fdcdd490b35fae2149c69bd3ffab3e3f63a20 Mon Sep 17 00:00:00 2001 From: j-berman Date: Fri, 1 Jul 2022 08:30:49 -0700 Subject: [PATCH 047/186] continue pool pruning even if a tx can't be found --- src/cryptonote_core/tx_pool.cpp | 29 ++++++++++++++++++++++++----- src/cryptonote_core/tx_pool.h | 7 +++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index a68da0e62ca..b44f9c2a358 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -402,6 +402,19 @@ namespace cryptonote m_txpool_max_weight = bytes; } //--------------------------------------------------------------------------------- + void tx_memory_pool::reduce_txpool_weight(size_t weight) + { + if (weight > m_txpool_weight) + { + MERROR("Underflow in txpool weight"); + m_txpool_weight = 0; + } + else + { + m_txpool_weight -= weight; + } + } + //--------------------------------------------------------------------------------- void tx_memory_pool::prune(size_t bytes) { CRITICAL_REGION_LOCAL(m_transactions_lock); @@ -423,8 +436,14 @@ namespace cryptonote txpool_tx_meta_t meta; if (!m_blockchain.get_txpool_tx_meta(txid, meta)) { - MERROR("Failed to find tx_meta in txpool"); - return; + static bool warned = false; + if (!warned) + { + MERROR("Failed to find tx_meta in txpool (will only print once)"); + warned = true; + } + --it; + continue; } // don't prune the kept_by_block ones, they're likely added because we're adding a block with those if (meta.kept_by_block) @@ -442,7 +461,7 @@ namespace cryptonote // remove first, in case this throws, so key images aren't removed MINFO("Pruning tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first); m_blockchain.remove_txpool_tx(txid); - m_txpool_weight -= meta.weight; + reduce_txpool_weight(meta.weight); remove_transaction_keyimages(tx, txid); MINFO("Pruned tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first); m_txs_by_fee_and_receive_time.erase(it--); @@ -562,7 +581,7 @@ namespace cryptonote // remove first, in case this throws, so key images aren't removed m_blockchain.remove_txpool_tx(id); - m_txpool_weight -= tx_weight; + reduce_txpool_weight(tx_weight); remove_transaction_keyimages(tx, id); lock.commit(); } @@ -725,7 +744,7 @@ namespace cryptonote { // remove first, so we only remove key images if the tx removal succeeds m_blockchain.remove_txpool_tx(txid); - m_txpool_weight -= entry.second; + reduce_txpool_weight(entry.second); remove_transaction_keyimages(tx, txid); } } diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 62bef6c06e2..ee2643547f7 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -406,6 +406,13 @@ namespace cryptonote */ void set_txpool_max_weight(size_t bytes); + /** + * @brief reduce the cumulative txpool weight by the weight provided + * + * @param weight the weight to reduce the total txpool weight by + */ + void reduce_txpool_weight(size_t weight); + #define CURRENT_MEMPOOL_ARCHIVE_VER 11 #define CURRENT_MEMPOOL_TX_DETAILS_ARCHIVE_VER 13 From 8ea6c339e47ff86ff974e2401c2090f62074f64d Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 5 Jul 2022 20:04:37 +0100 Subject: [PATCH 048/186] Fix some paths for toolchain / build --- contrib/depends/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contrib/depends/README.md b/contrib/depends/README.md index 1aa5b276fc6..2f1d8424a00 100644 --- a/contrib/depends/README.md +++ b/contrib/depends/README.md @@ -1,6 +1,6 @@ ### Usage -To build dependencies for the current arch+OS: +To build dependencies for the current arch+OS, from this working directory: ```bash make @@ -20,10 +20,12 @@ make HOST=x86_64-w64-mingw32 -j4 A toolchain will be generated that's suitable for plugging into Monero's cmake. In the above example, a dir named x86_64-w64-mingw32 will be -created. To use it for Monero: +created. To use it for Monero, from the top of the Monero source tree: ```bash -cmake -DCMAKE_TOOLCHAIN=`pwd`/contrib/depends/x86_64-w64-mingw32 +mkdir build +cd build +cmake -DCMAKE_TOOLCHAIN_FILE=$PWD/../contrib/depends/x86_64-w64-mingw32/share/toolchain.cmake .. ``` Common `host-platform-triplets` for cross compilation are: From 6d8fa2b9a9bbad040aaafb66094602f45ab14427 Mon Sep 17 00:00:00 2001 From: selsta Date: Tue, 5 Jul 2022 21:32:21 +0200 Subject: [PATCH 049/186] workflows: add android to depends --- .github/workflows/depends.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml index f20bf949fd5..cc69e47b417 100644 --- a/.github/workflows/depends.yml +++ b/.github/workflows/depends.yml @@ -55,6 +55,9 @@ jobs: - name: "x86_64 Freebsd" host: "x86_64-unknown-freebsd" packages: "clang-8 gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev" + - name: "ARMv8 Android" + host: "aarch64-linux-android" + packages: "gperf cmake python3" name: ${{ matrix.toolchain.name }} steps: - uses: actions/checkout@v1 From bd1e7c56356a7b282403bcff934360ae5523b848 Mon Sep 17 00:00:00 2001 From: j-berman Date: Tue, 5 Jul 2022 21:39:59 -0700 Subject: [PATCH 050/186] wallet2: prevent crash when reading tx w/fewer outputs than expected --- src/wallet/wallet2.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e051946add2..81345f26897 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -349,6 +349,8 @@ namespace tools uint64_t amount() const { return m_amount; } const crypto::public_key get_public_key() const { crypto::public_key output_public_key; + THROW_WALLET_EXCEPTION_IF(m_tx.vout.size() <= m_internal_output_index, + error::wallet_internal_error, "Too few outputs, outputs may be corrupted"); THROW_WALLET_EXCEPTION_IF(!get_output_public_key(m_tx.vout[m_internal_output_index], output_public_key), error::wallet_internal_error, "Unable to get output public key from output"); return output_public_key; From 724ff214471012ca76544bec6fa8690c622cb864 Mon Sep 17 00:00:00 2001 From: anon Date: Mon, 28 Jun 2021 19:13:02 +0000 Subject: [PATCH 051/186] connection: add segfault and deadlocks demo --- tests/unit_tests/epee_boosted_tcp_server.cpp | 254 ++++++++++++++++++- 1 file changed, 252 insertions(+), 2 deletions(-) diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp index 54d27be1bc0..d64431edf89 100644 --- a/tests/unit_tests/epee_boosted_tcp_server.cpp +++ b/tests/unit_tests/epee_boosted_tcp_server.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include "gtest/gtest.h" @@ -276,6 +278,11 @@ TEST(test_epee_connection, test_lifetime) ASSERT_TRUE(shared_state->get_connections_count() == 0); constexpr auto DELAY = 30; constexpr auto TIMEOUT = 1; + while (server.get_connections_count()) { + server.get_config_shared()->del_in_connections( + server.get_config_shared()->get_in_connections_count() + ); + } server.get_config_shared()->set_handler(new command_handler_t(DELAY), &command_handler_t::destroy); for (auto i = 0; i < N; ++i) { tag = create_connection(); @@ -332,7 +339,7 @@ TEST(test_epee_connection, test_lifetime) ), &command_handler_t::destroy ); - for (auto i = 0; i < N; ++i) { + for (auto i = 0; i < N * N * N; ++i) { { connection_ptr conn(new connection_t(io_context, shared_state, {}, {})); conn->socket().connect(endpoint); @@ -342,6 +349,7 @@ TEST(test_epee_connection, test_lifetime) } ASSERT_TRUE(shared_state->get_connections_count() == 1); shared_state->del_out_connections(1); + while (shared_state->sock_count); ASSERT_TRUE(shared_state->get_connections_count() == 0); } @@ -452,7 +460,11 @@ TEST(test_epee_connection, test_lifetime) } for (;workers.size(); workers.pop_back()) workers.back().join(); - + while (server.get_connections_count()) { + server.get_config_shared()->del_in_connections( + server.get_config_shared()->get_in_connections_count() + ); + } }); for (auto& w: workers) { @@ -462,3 +474,241 @@ TEST(test_epee_connection, test_lifetime) server.timed_wait_server_stop(5 * 1000); server.deinit_server(); } + +TEST(test_epee_connection, ssl_shutdown) +{ + struct context_t: epee::net_utils::connection_context_base { + static constexpr size_t get_max_bytes(int) noexcept { return -1; } + static constexpr int handshake_command() noexcept { return 1001; } + static constexpr bool handshake_complete() noexcept { return true; } + }; + + struct command_handler_t: epee::levin::levin_commands_handler { + virtual int invoke(int, const epee::span, epee::byte_stream&, context_t&) override { return {}; } + virtual int notify(int, const epee::span, context_t&) override { return {}; } + virtual void callback(context_t&) override {} + virtual void on_connection_new(context_t&) override {} + virtual void on_connection_close(context_t&) override { } + virtual ~command_handler_t() override {} + static void destroy(epee::levin::levin_commands_handler* ptr) { delete ptr; } + }; + + using handler_t = epee::levin::async_protocol_handler; + using io_context_t = boost::asio::io_service; + using endpoint_t = boost::asio::ip::tcp::endpoint; + using server_t = epee::net_utils::boosted_tcp_server; + using socket_t = boost::asio::ip::tcp::socket; + using ssl_socket_t = boost::asio::ssl::stream; + using ssl_context_t = boost::asio::ssl::context; + using ec_t = boost::system::error_code; + + endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 5263); + server_t server(epee::net_utils::e_connection_type_P2P); + server.init_server(endpoint.port(), + endpoint.address().to_string(), + 0, + "", + false, + true, + epee::net_utils::ssl_support_t::e_ssl_support_enabled + ); + server.get_config_shared()->set_handler(new command_handler_t, &command_handler_t::destroy); + server.run_server(2, false); + + ssl_context_t ssl_context{boost::asio::ssl::context::sslv23}; + io_context_t io_context; + ssl_socket_t socket(io_context, ssl_context); + ec_t ec; + socket.next_layer().connect(endpoint, ec); + EXPECT_EQ(ec.value(), 0); + socket.handshake(boost::asio::ssl::stream_base::client, ec); + EXPECT_EQ(ec.value(), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + while (server.get_config_shared()->get_connections_count() < 1); + server.get_config_shared()->del_in_connections(1); + while (server.get_config_shared()->get_connections_count() > 0); + server.send_stop_signal(); + EXPECT_TRUE(server.timed_wait_server_stop(5 * 1000)); + server.deinit_server(); + socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + socket.next_layer().close(ec); + socket.shutdown(ec); +} + +TEST(test_epee_connection, ssl_handshake) +{ + using io_context_t = boost::asio::io_service; + using work_t = boost::asio::io_service::work; + using work_ptr = std::shared_ptr; + using workers_t = std::vector; + using socket_t = boost::asio::ip::tcp::socket; + using ssl_socket_t = boost::asio::ssl::stream; + using ssl_socket_ptr = std::unique_ptr; + using ssl_options_t = epee::net_utils::ssl_options_t; + io_context_t io_context; + work_ptr work(std::make_shared(io_context)); + workers_t workers; + auto constexpr N = 2; + while (workers.size() < N) { + workers.emplace_back([&io_context]{ + io_context.run(); + }); + } + ssl_options_t ssl_options{{}}; + auto ssl_context = ssl_options.create_context(); + for (size_t i = 0; i < N * N * N; ++i) { + ssl_socket_ptr ssl_socket(new ssl_socket_t(io_context, ssl_context)); + ssl_socket->next_layer().open(boost::asio::ip::tcp::v4()); + for (size_t i = 0; i < N; ++i) { + io_context.post([]{ + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + }); + } + EXPECT_EQ( + ssl_options.handshake( + *ssl_socket, + ssl_socket_t::server, + {}, + {}, + std::chrono::milliseconds(0) + ), + false + ); + ssl_socket->next_layer().close(); + ssl_socket.reset(); + } + work.reset(); + for (;workers.size(); workers.pop_back()) + workers.back().join(); +} + + +TEST(boosted_tcp_server, strand_deadlock) +{ + using context_t = epee::net_utils::connection_context_base; + using lock_t = std::mutex; + using unique_lock_t = std::unique_lock; + + struct config_t { + using condition_t = std::condition_variable_any; + using lock_guard_t = std::lock_guard; + void notify_success() + { + lock_guard_t guard(lock); + success = true; + condition.notify_all(); + } + lock_t lock; + condition_t condition; + bool success; + }; + + struct handler_t { + using config_type = config_t; + using connection_context = context_t; + using byte_slice_t = epee::byte_slice; + using socket_t = epee::net_utils::i_service_endpoint; + + handler_t(socket_t *socket, config_t &config, context_t &context): + socket(socket), + config(config), + context(context) + {} + void after_init_connection() + { + unique_lock_t guard(lock); + if (not context.m_is_income) { + guard.unlock(); + socket->do_send(byte_slice_t{"."}); + } + } + void handle_qued_callback() + { + } + bool handle_recv(const char *data, size_t bytes_transferred) + { + unique_lock_t guard(lock); + if (not context.m_is_income) { + if (context.m_recv_cnt == 1024) { + guard.unlock(); + socket->do_send(byte_slice_t{"."}); + } + } + else { + if (context.m_recv_cnt == 1) { + for(size_t i = 0; i < 1024; ++i) { + guard.unlock(); + socket->do_send(byte_slice_t{"."}); + guard.lock(); + } + } + else if(context.m_recv_cnt == 2) { + guard.unlock(); + socket->close(); + } + } + return true; + } + void release_protocol() + { + unique_lock_t guard(lock); + if(not context.m_is_income + and context.m_recv_cnt == 1024 + and context.m_send_cnt == 2 + ) { + guard.unlock(); + config.notify_success(); + } + } + + lock_t lock; + socket_t *socket; + config_t &config; + context_t &context; + }; + + using server_t = epee::net_utils::boosted_tcp_server; + using endpoint_t = boost::asio::ip::tcp::endpoint; + + endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 5262); + server_t server(epee::net_utils::e_connection_type_P2P); + server.init_server( + endpoint.port(), + endpoint.address().to_string(), + {}, + {}, + {}, + true, + epee::net_utils::ssl_support_t::e_ssl_support_disabled + ); + server.run_server(2, {}); + server.async_call( + [&]{ + context_t context; + ASSERT_TRUE( + server.connect( + endpoint.address().to_string(), + std::to_string(endpoint.port()), + 5, + context, + "0.0.0.0", + epee::net_utils::ssl_support_t::e_ssl_support_disabled + ) + ); + } + ); + { + unique_lock_t guard(server.get_config_object().lock); + EXPECT_TRUE( + server.get_config_object().condition.wait_for( + guard, + std::chrono::seconds(5), + [&] { return server.get_config_object().success; } + ) + ); + } + + server.send_stop_signal(); + server.timed_wait_server_stop(5 * 1000); + server.deinit_server(); +} From 3be1dbd0963a76a05fd7f72f28100726daa1c4e7 Mon Sep 17 00:00:00 2001 From: anon Date: Mon, 28 Jun 2021 19:13:02 +0000 Subject: [PATCH 052/186] connection: fix implementation --- CMakeLists.txt | 1 + .../epee/include/net/abstract_tcp_server2.h | 231 ++- .../epee/include/net/abstract_tcp_server2.inl | 1708 +++++++++-------- contrib/epee/include/net/net_ssl.h | 5 + contrib/epee/src/net_ssl.cpp | 121 +- 5 files changed, 1230 insertions(+), 836 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3abd0722a1b..b05c087cf89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1076,6 +1076,7 @@ if(STATIC) set(Boost_USE_STATIC_RUNTIME ON) endif() find_package(Boost 1.58 QUIET REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options locale) +add_definitions(-DBOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES}) if(NOT Boost_FOUND) diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index 51aa9f275f3..0684573f2fa 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -44,12 +44,16 @@ #include #include #include +#include #include #include +#include +#include #include #include #include +#include #include "byte_slice.h" #include "net_utils_base.h" #include "syncobj.h" @@ -85,6 +89,181 @@ namespace net_utils public i_service_endpoint, public connection_basic { + private: + using string_t = std::string; + using handler_t = t_protocol_handler; + using context_t = typename handler_t::connection_context; + using connection_t = connection; + using connection_ptr = boost::shared_ptr; + using ssl_support_t = epee::net_utils::ssl_support_t; + using timer_t = boost::asio::steady_timer; + using duration_t = timer_t::duration; + using lock_t = std::mutex; + using condition_t = std::condition_variable_any; + using lock_guard_t = std::lock_guard; + using unique_lock_t = std::unique_lock; + using byte_slice_t = epee::byte_slice; + using ec_t = boost::system::error_code; + using handshake_t = boost::asio::ssl::stream_base::handshake_type; + + using io_context_t = boost::asio::io_service; + using strand_t = boost::asio::io_service::strand; + using socket_t = boost::asio::ip::tcp::socket; + + using write_queue_t = std::deque; + using read_buffer_t = std::array; + using network_throttle_t = epee::net_utils::network_throttle; + using network_throttle_manager_t = epee::net_utils::network_throttle_manager; + + unsigned int host_count(int delta = 0); + duration_t get_default_timeout(); + duration_t get_timeout_from_bytes_read(size_t bytes) const; + + void start_timer(duration_t duration, bool add = {}); + void async_wait_timer(); + void cancel_timer(); + + void start_handshake(); + void start_read(); + void start_write(); + void start_shutdown(); + void cancel_socket(); + + void cancel_handler(); + + void interrupt(); + void on_interrupted(); + + void terminate(); + void on_terminating(); + + bool send(byte_slice_t message); + bool start_internal( + bool is_income, + bool is_multithreaded, + boost::optional real_remote + ); + + struct state_t { + struct stat_t { + struct { + network_throttle_t throttle{"speed_in", "throttle_speed_in"}; + } in; + struct { + network_throttle_t throttle{"speed_out", "throttle_speed_out"}; + } out; + }; + + struct data_t { + struct { + read_buffer_t buffer; + } read; + struct { + write_queue_t queue; + bool wait_consume; + } write; + }; + + struct ssl_t { + bool enabled; + bool forced; + bool detected; + bool handshaked; + }; + + struct socket_t { + bool connected; + + bool wait_handshake; + bool cancel_handshake; + + bool wait_read; + bool handle_read; + bool cancel_read; + + bool wait_write; + bool handle_write; + bool cancel_write; + + bool wait_shutdown; + bool cancel_shutdown; + }; + + struct timer_t { + bool wait_expire; + bool cancel_expire; + bool reset_expire; + }; + + struct timers_t { + struct throttle_t { + timer_t in; + timer_t out; + }; + + timer_t general; + throttle_t throttle; + }; + + enum status_t { + TERMINATED, + RUNNING, + INTERRUPTED, + TERMINATING, + WASTED, + }; + + struct protocol_t { + size_t reference_counter; + bool released; + bool initialized; + + bool wait_release; + bool wait_init; + size_t wait_callback; + }; + + lock_t lock; + condition_t condition; + status_t status; + socket_t socket; + ssl_t ssl; + timers_t timers; + protocol_t protocol; + stat_t stat; + data_t data; + }; + + using status_t = typename state_t::status_t; + + struct timers_t { + timers_t(io_context_t &io_context): + general(io_context), + throttle(io_context) + {} + struct throttle_t { + throttle_t(io_context_t &io_context): + in(io_context), + out(io_context) + {} + timer_t in; + timer_t out; + }; + + timer_t general; + throttle_t throttle; + }; + + io_context_t &io_context; + t_connection_type connection_type; + context_t context{}; + strand_t strand; + timers_t timers; + connection_ptr self{}; + bool local{}; + string_t host{}; + state_t state{}; + handler_t handler; public: typedef typename t_protocol_handler::connection_context t_connection_context; @@ -141,58 +320,6 @@ namespace net_utils virtual bool add_ref(); virtual bool release(); //------------------------------------------------------ - bool do_send_chunk(byte_slice chunk); ///< will send (or queue) a part of data. internal use only - - boost::shared_ptr > safe_shared_from_this(); - bool shutdown(); - /// Handle completion of a receive operation. - void handle_receive(const boost::system::error_code& e, - std::size_t bytes_transferred); - - /// Handle completion of a read operation. - void handle_read(const boost::system::error_code& e, - std::size_t bytes_transferred); - - /// Handle completion of a write operation. - void handle_write(const boost::system::error_code& e, size_t cb); - - /// reset connection timeout timer and callback - void reset_timer(boost::posix_time::milliseconds ms, bool add); - boost::posix_time::milliseconds get_default_timeout(); - boost::posix_time::milliseconds get_timeout_from_bytes_read(size_t bytes); - - /// host connection count tracking - unsigned int host_count(const std::string &host, int delta = 0); - - /// Buffer for incoming data. - boost::array buffer_; - size_t buffer_ssl_init_fill; - - t_connection_context context; - - // TODO what do they mean about wait on destructor?? --rfree : - //this should be the last one, because it could be wait on destructor, while other activities possible on other threads - t_protocol_handler m_protocol_handler; - //typename t_protocol_handler::config_type m_dummy_config; - size_t m_reference_count = 0; // reference count managed through add_ref/release support - boost::shared_ptr > m_self_ref; // the reference to hold - critical_section m_self_refs_lock; - critical_section m_chunking_lock; // held while we add small chunks of the big do_send() to small do_send_chunk() - critical_section m_shutdown_lock; // held while shutting down - - t_connection_type m_connection_type; - - // for calculate speed (last 60 sec) - network_throttle m_throttle_speed_in; - network_throttle m_throttle_speed_out; - boost::mutex m_throttle_speed_in_mutex; - boost::mutex m_throttle_speed_out_mutex; - - boost::asio::deadline_timer m_timer; - bool m_local; - bool m_ready_to_close; - std::string m_host; - public: void setRpcStation(); }; diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 0c3b457bcde..0fc9228b1cd 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -76,859 +76,1049 @@ namespace net_utils /************************************************************************/ /* */ /************************************************************************/ - template - connection::connection( boost::asio::io_service& io_service, - std::shared_ptr state, - t_connection_type connection_type, - ssl_support_t ssl_support - ) - : connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type, ssl_support) + template + unsigned int connection::host_count(int delta) { + static lock_t hosts_mutex; + lock_guard_t guard(hosts_mutex); + static std::map hosts; + unsigned int &val = hosts[host]; + if (delta > 0) + MTRACE("New connection from host " << host << ": " << val); + else if (delta < 0) + MTRACE("Closed connection from host " << host << ": " << val); + CHECK_AND_ASSERT_THROW_MES(delta >= 0 || val >= (unsigned)-delta, "Count would go negative"); + CHECK_AND_ASSERT_THROW_MES(delta <= 0 || val <= std::numeric_limits::max() - (unsigned)delta, "Count would wrap"); + val += delta; + return val; } - template - connection::connection( boost::asio::ip::tcp::socket&& sock, - std::shared_ptr state, - t_connection_type connection_type, - ssl_support_t ssl_support - ) - : - connection_basic(std::move(sock), state, ssl_support), - m_protocol_handler(this, check_and_get(state), context), - buffer_ssl_init_fill(0), - m_connection_type( connection_type ), - m_throttle_speed_in("speed_in", "throttle_speed_in"), - m_throttle_speed_out("speed_out", "throttle_speed_out"), - m_timer(GET_IO_SERVICE(socket_)), - m_local(false), - m_ready_to_close(false) + template + typename connection::duration_t connection::get_default_timeout() { - MDEBUG("test, connection constructor set m_connection_type="< AGGRESSIVE_TIMEOUT_THRESHOLD ? + std::min(std::max(count, 1u) - 1, 8u) : + 0 + ); + return ( + local ? + std::chrono::milliseconds(DEFAULT_TIMEOUT_MS_LOCAL >> shift) : + std::chrono::milliseconds(DEFAULT_TIMEOUT_MS_REMOTE >> shift) + ); } - //--------------------------------------------------------------------------------- - template - connection::~connection() noexcept(false) - { - if(!m_was_shutdown) - { - _dbg3("[sock " << socket().native_handle() << "] Socket destroyed without shutdown."); - shutdown(); - } - - _dbg3("[sock " << socket().native_handle() << "] Socket destroyed"); - } - //--------------------------------------------------------------------------------- - template - boost::shared_ptr > connection::safe_shared_from_this() + template + typename connection::duration_t connection::get_timeout_from_bytes_read(size_t bytes) const { - try - { - return connection::shared_from_this(); - } - catch (const boost::bad_weak_ptr&) - { - // It happens when the connection is being deleted - return boost::shared_ptr >(); - } + return std::chrono::duration_cast::duration_t>( + std::chrono::duration( + bytes * TIMEOUT_EXTRA_MS_PER_BYTE + ) + ); } - //--------------------------------------------------------------------------------- - template - bool connection::start(bool is_income, bool is_multithreaded) - { - TRY_ENTRY(); - - boost::system::error_code ec; - auto remote_ep = socket().remote_endpoint(ec); - CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get remote endpoint: " << ec.message() << ':' << ec.value()); - CHECK_AND_NO_ASSERT_MES(remote_ep.address().is_v4() || remote_ep.address().is_v6(), false, "only IPv4 and IPv6 supported here"); - if (remote_ep.address().is_v4()) - { - const unsigned long ip_ = boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong()); - return start(is_income, is_multithreaded, ipv4_network_address{uint32_t(ip_), remote_ep.port()}); - } - else - { - const auto ip_ = remote_ep.address().to_v6(); - return start(is_income, is_multithreaded, ipv6_network_address{ip_, remote_ep.port()}); - } - CATCH_ENTRY_L0("connection::start()", false); - } - //--------------------------------------------------------------------------------- - template - bool connection::start(bool is_income, bool is_multithreaded, network_address real_remote) + template + void connection::start_timer(duration_t duration, bool add) { - TRY_ENTRY(); - - // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted - auto self = safe_shared_from_this(); - if(!self) - return false; - - m_is_multithreaded = is_multithreaded; - m_local = real_remote.is_loopback() || real_remote.is_local(); - - // create a random uuid, we don't need crypto strength here - const boost::uuids::uuid random_uuid = boost::uuids::random_generator()(); - - context = t_connection_context{}; - bool ssl = m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled; - context.set_details(random_uuid, std::move(real_remote), is_income, ssl); - - boost::system::error_code ec; - auto local_ep = socket().local_endpoint(ec); - CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value()); - - _dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) << - " to " << local_ep.address().to_string() << ':' << local_ep.port() << - ", total sockets objects " << get_state().sock_count); - - if(static_cast(get_state()).pfilter && !static_cast(get_state()).pfilter->is_remote_host_allowed(context.m_remote_address)) - { - _dbg2("[sock " << socket().native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection"); - close(); - return false; + if (state.timers.general.wait_expire) { + state.timers.general.cancel_expire = true; + state.timers.general.reset_expire = true; + ec_t ec; + timers.general.expires_from_now( + std::min( + duration + (add ? timers.general.expires_from_now() : duration_t{}), + get_default_timeout() + ), + ec + ); + } + else { + ec_t ec; + timers.general.expires_from_now( + std::min( + duration + (add ? timers.general.expires_from_now() : duration_t{}), + get_default_timeout() + ), + ec + ); + async_wait_timer(); } - - m_host = context.m_remote_address.host_str(); - try { host_count(m_host, 1); } catch(...) { /* ignore */ } - - m_protocol_handler.after_init_connection(); - - reset_timer(boost::posix_time::milliseconds(m_local ? NEW_CONNECTION_TIMEOUT_LOCAL : NEW_CONNECTION_TIMEOUT_REMOTE), false); - - // first read on the raw socket to detect SSL for the server - buffer_ssl_init_fill = 0; - if (is_income && m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled) - socket().async_receive(boost::asio::buffer(buffer_), - strand_.wrap( - std::bind(&connection::handle_receive, self, - std::placeholders::_1, - std::placeholders::_2))); - else - async_read_some(boost::asio::buffer(buffer_), - strand_.wrap( - std::bind(&connection::handle_read, self, - std::placeholders::_1, - std::placeholders::_2))); -#if !defined(_WIN32) || !defined(__i686) - // not supported before Windows7, too lazy for runtime check - // Just exclude for 32bit windows builds - //set ToS flag - int tos = get_tos_flag(); - boost::asio::detail::socket_option::integer< IPPROTO_IP, IP_TOS > - optionTos( tos ); - socket().set_option( optionTos ); - //_dbg1("Set ToS flag to " << tos); -#endif - - boost::asio::ip::tcp::no_delay noDelayOption(false); - socket().set_option(noDelayOption); - - return true; - - CATCH_ENTRY_L0("connection::start()", false); } - //--------------------------------------------------------------------------------- - template - bool connection::request_callback() - { - TRY_ENTRY(); - _dbg2("[" << print_connection_context_short(context) << "] request_callback"); - // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted - auto self = safe_shared_from_this(); - if(!self) - return false; - strand_.post(boost::bind(&connection::call_back_starter, self)); - CATCH_ENTRY_L0("connection::request_callback()", false); - return true; - } - //--------------------------------------------------------------------------------- - template - boost::asio::io_service& connection::get_io_service() + template + void connection::async_wait_timer() { - return GET_IO_SERVICE(socket()); + if (state.timers.general.wait_expire) + return; + state.timers.general.wait_expire = true; + auto self = connection::shared_from_this(); + timers.general.async_wait([this, self](const ec_t & ec){ + lock_guard_t guard(state.lock); + state.timers.general.wait_expire = false; + if (state.timers.general.cancel_expire) { + state.timers.general.cancel_expire = false; + if (state.timers.general.reset_expire) { + state.timers.general.reset_expire = false; + async_wait_timer(); + } + else if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + } + else if (state.status == status_t::RUNNING) + interrupt(); + else if (state.status == status_t::INTERRUPTED) + terminate(); + }); } - //--------------------------------------------------------------------------------- - template - bool connection::add_ref() - { - TRY_ENTRY(); - // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted - auto self = safe_shared_from_this(); - if(!self) - return false; - //_dbg3("[sock " << socket().native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number); - CRITICAL_REGION_LOCAL(self->m_self_refs_lock); - //_dbg3("[sock " << socket().native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number); - ++m_reference_count; - m_self_ref = std::move(self); - return true; - CATCH_ENTRY_L0("connection::add_ref()", false); - } - //--------------------------------------------------------------------------------- - template - bool connection::release() - { - TRY_ENTRY(); - boost::shared_ptr > back_connection_copy; - LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] release"); - CRITICAL_REGION_BEGIN(m_self_refs_lock); - CHECK_AND_ASSERT_MES(m_reference_count, false, "[sock " << socket().native_handle() << "] m_reference_count already at 0 at connection::release() call"); - // is this the last reference? - if (--m_reference_count == 0) { - // move the held reference to a local variable, keeping the object alive until the function terminates - std::swap(back_connection_copy, m_self_ref); - } - CRITICAL_REGION_END(); - return true; - CATCH_ENTRY_L0("connection::release()", false); - } - //--------------------------------------------------------------------------------- - template - void connection::call_back_starter() + template + void connection::cancel_timer() { - TRY_ENTRY(); - _dbg2("[" << print_connection_context_short(context) << "] fired_callback"); - m_protocol_handler.handle_qued_callback(); - CATCH_ENTRY_L0("connection::call_back_starter()", void()); + if (not state.timers.general.wait_expire) + return; + state.timers.general.cancel_expire = true; + state.timers.general.reset_expire = false; + ec_t ec; + timers.general.cancel(ec); } - //--------------------------------------------------------------------------------- - template - void connection::save_dbg_log() - { - std::string address, port; - boost::system::error_code e; - boost::asio::ip::tcp::endpoint endpoint = socket().remote_endpoint(e); - if (e) - { - address = ""; - port = ""; - } - else - { - address = endpoint.address().to_string(); - port = boost::lexical_cast(endpoint.port()); - } - MDEBUG(" connection type " << to_string( m_connection_type ) << " " - << socket().local_endpoint().address().to_string() << ":" << socket().local_endpoint().port() - << " <--> " << context.m_remote_address.str() << " (via " << address << ":" << port << ")"); - } - //--------------------------------------------------------------------------------- - template - void connection::handle_read(const boost::system::error_code& e, - std::size_t bytes_transferred) + template + void connection::start_handshake() { - TRY_ENTRY(); - //_info("[sock " << socket().native_handle() << "] Async read calledback."); - - if (m_was_shutdown) - return; + if (state.socket.wait_handshake) + return; + static_assert( + epee::net_utils::get_ssl_magic_size() <= sizeof(state.data.read.buffer), + "" + ); + auto self = connection::shared_from_this(); + if (not state.ssl.forced and not state.ssl.detected) { + state.socket.wait_read = true; + boost::asio::async_read( + connection_basic::socket_.next_layer(), + boost::asio::buffer( + state.data.read.buffer.data(), + state.data.read.buffer.size() + ), + boost::asio::transfer_exactly(epee::net_utils::get_ssl_magic_size()), + strand.wrap( + [this, self](const ec_t &ec, size_t bytes_transferred){ + lock_guard_t guard(state.lock); + state.socket.wait_read = false; + if (state.socket.cancel_read) { + state.socket.cancel_read = false; + if (state.status == status_t::RUNNING) + interrupt(); + else if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + } + else if (ec.value()) { + terminate(); + } + else if ( + not epee::net_utils::is_ssl( + static_cast( + state.data.read.buffer.data() + ), + bytes_transferred + ) + ) { + state.ssl.enabled = false; + state.socket.handle_read = true; + connection_basic::strand_.post( + [this, self, bytes_transferred]{ + bool success = handler.handle_recv( + reinterpret_cast(state.data.read.buffer.data()), + bytes_transferred + ); + lock_guard_t guard(state.lock); + state.socket.handle_read = false; + if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + else if (not success) + interrupt(); + else { + start_read(); + } + } + ); + } + else { + state.ssl.detected = true; + start_handshake(); + } + } + ) + ); + return; + } - if (!e) - { - double current_speed_down; - { - CRITICAL_REGION_LOCAL(m_throttle_speed_in_mutex); - m_throttle_speed_in.handle_trafic_exact(bytes_transferred); - current_speed_down = m_throttle_speed_in.get_current_speed(); - } - context.m_current_speed_down = current_speed_down; - context.m_max_speed_down = std::max(context.m_max_speed_down, current_speed_down); - - { - CRITICAL_REGION_LOCAL( epee::net_utils::network_throttle_manager::network_throttle_manager::m_lock_get_global_throttle_in ); - epee::net_utils::network_throttle_manager::network_throttle_manager::get_global_throttle_in().handle_trafic_exact(bytes_transferred); - } - - double delay=0; // will be calculated - how much we should sleep to obey speed limit etc - - - if (speed_limit_is_enabled()) { - do // keep sleeping if we should sleep - { - { //_scope_dbg1("CRITICAL_REGION_LOCAL"); - CRITICAL_REGION_LOCAL( epee::net_utils::network_throttle_manager::m_lock_get_global_throttle_in ); - delay = epee::net_utils::network_throttle_manager::get_global_throttle_in().get_sleep_time_after_tick( bytes_transferred ); - } - - if (m_was_shutdown) - return; - - delay *= 0.5; - long int ms = (long int)(delay * 100); - if (ms > 0) { - reset_timer(boost::posix_time::milliseconds(ms + 1), true); - boost::this_thread::sleep_for(boost::chrono::milliseconds(ms)); - } - } while(delay > 0); - } // any form of sleeping - - //_info("[sock " << socket().native_handle() << "] RECV " << bytes_transferred); - logger_handle_net_read(bytes_transferred); - context.m_last_recv = time(NULL); - context.m_recv_cnt += bytes_transferred; - m_ready_to_close = false; - bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred); - if(!recv_res) - { - //_info("[sock " << socket().native_handle() << "] protocol_want_close"); - //some error in protocol, protocol handler ask to close connection - m_want_close_connection = true; - bool do_shutdown = false; - CRITICAL_REGION_BEGIN(m_send_que_lock); - if(!m_send_que.size()) - do_shutdown = true; - CRITICAL_REGION_END(); - if(do_shutdown) - shutdown(); - }else - { - reset_timer(get_timeout_from_bytes_read(bytes_transferred), false); - async_read_some(boost::asio::buffer(buffer_), - strand_.wrap( - boost::bind(&connection::handle_read, connection::shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred))); - //_info("[sock " << socket().native_handle() << "]Async read requested."); + state.socket.wait_handshake = true; + auto on_handshake = [this, self](const ec_t &ec, size_t bytes_transferred){ + lock_guard_t guard(state.lock); + state.socket.wait_handshake = false; + if (state.socket.cancel_handshake) { + state.socket.cancel_handshake = false; + if (state.status == status_t::RUNNING) + interrupt(); + else if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); } - }else - { - _dbg3("[sock " << socket().native_handle() << "] Some not success at read: " << e.message() << ':' << e.value()); - if(e.value() != 2) - { - _dbg3("[sock " << socket().native_handle() << "] Some problems at read: " << e.message() << ':' << e.value()); - shutdown(); + else if (ec.value()) { + ec_t ec; + connection_basic::socket_.next_layer().shutdown( + socket_t::shutdown_both, + ec + ); + connection_basic::socket_.next_layer().close(ec); + state.socket.connected = false; + interrupt(); } - else - { - _dbg3("[sock " << socket().native_handle() << "] peer closed connection"); - bool do_shutdown = false; - CRITICAL_REGION_BEGIN(m_send_que_lock); - if(!m_send_que.size()) - do_shutdown = true; - CRITICAL_REGION_END(); - if (m_ready_to_close || do_shutdown) - shutdown(); + else { + state.ssl.handshaked = true; + start_write(); + start_read(); } - m_ready_to_close = true; - } - // If an error occurs then no new asynchronous operations are started. This - // means that all shared_ptr references to the connection object will - // disappear and the object will be destroyed automatically after this - // handler returns. The connection class's destructor closes the socket. - CATCH_ENTRY_L0("connection::handle_read", void()); + }; + const auto handshake = handshake_t::server; + static_cast( + connection_basic::get_state() + ).ssl_options().configure(connection_basic::socket_, handshake); + strand.post( + [this, self, on_handshake]{ + connection_basic::socket_.async_handshake( + handshake, + boost::asio::buffer( + state.data.read.buffer.data(), + state.ssl.forced ? 0 : + epee::net_utils::get_ssl_magic_size() + ), + strand.wrap(on_handshake) + ); + } + ); } - //--------------------------------------------------------------------------------- - template - void connection::handle_receive(const boost::system::error_code& e, - std::size_t bytes_transferred) - { - TRY_ENTRY(); - - if (m_was_shutdown) return; - if (e) - { - // offload the error case - handle_read(e, bytes_transferred); + template + void connection::start_read() + { + if (state.timers.throttle.in.wait_expire || state.socket.wait_read || + state.socket.handle_read + ) return; + auto self = connection::shared_from_this(); + if (connection_type != e_connection_type_RPC) { + auto calc_duration = []{ + CRITICAL_REGION_LOCAL( + network_throttle_manager_t::m_lock_get_global_throttle_in + ); + return std::chrono::duration_cast::duration_t>( + std::chrono::duration( + std::min( + network_throttle_manager_t::get_global_throttle_in( + ).get_sleep_time_after_tick(1), + 1.0 + ) + ) + ); + }; + const auto duration = calc_duration(); + if (duration > duration_t{}) { + ec_t ec; + timers.throttle.in.expires_from_now(duration, ec); + state.timers.throttle.in.wait_expire = true; + timers.throttle.in.async_wait([this, self](const ec_t &ec){ + lock_guard_t guard(state.lock); + state.timers.throttle.in.wait_expire = false; + if (state.timers.throttle.in.cancel_expire) { + state.timers.throttle.in.cancel_expire = false; + if (state.status == status_t::RUNNING) + interrupt(); + else if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + } + else if (ec.value()) + interrupt(); + else + start_read(); + }); + return; + } } + state.socket.wait_read = true; + auto on_read = [this, self](const ec_t &ec, size_t bytes_transferred){ + lock_guard_t guard(state.lock); + state.socket.wait_read = false; + if (state.socket.cancel_read) { + state.socket.cancel_read = false; + if (state.status == status_t::RUNNING) + interrupt(); + else if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + } + else if (ec.value()) + terminate(); + else { + { + state.stat.in.throttle.handle_trafic_exact(bytes_transferred); + const auto speed = state.stat.in.throttle.get_current_speed(); + context.m_current_speed_down = speed; + context.m_max_speed_down = std::max( + context.m_max_speed_down, + speed + ); + { + CRITICAL_REGION_LOCAL( + network_throttle_manager_t::m_lock_get_global_throttle_in + ); + network_throttle_manager_t::get_global_throttle_in( + ).handle_trafic_exact(bytes_transferred); + } + connection_basic::logger_handle_net_read(bytes_transferred); + context.m_last_recv = time(NULL); + context.m_recv_cnt += bytes_transferred; + start_timer(get_timeout_from_bytes_read(bytes_transferred), true); + } + state.socket.handle_read = true; + connection_basic::strand_.post( + [this, self, bytes_transferred]{ + bool success = handler.handle_recv( + reinterpret_cast(state.data.read.buffer.data()), + bytes_transferred + ); + lock_guard_t guard(state.lock); + state.socket.handle_read = false; + if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + else if (not success) + interrupt(); + else { + start_read(); + } + } + ); + } + }; + if (not state.ssl.enabled) + connection_basic::socket_.next_layer().async_read_some( + boost::asio::buffer( + state.data.read.buffer.data(), + state.data.read.buffer.size() + ), + strand.wrap(on_read) + ); + else + strand.post( + [this, self, on_read]{ + connection_basic::socket_.async_read_some( + boost::asio::buffer( + state.data.read.buffer.data(), + state.data.read.buffer.size() + ), + strand.wrap(on_read) + ); + } + ); + } - buffer_ssl_init_fill += bytes_transferred; - MTRACE("we now have " << buffer_ssl_init_fill << "/" << get_ssl_magic_size() << " bytes needed to detect SSL"); - if (buffer_ssl_init_fill < get_ssl_magic_size()) - { - socket().async_receive(boost::asio::buffer(buffer_.data() + buffer_ssl_init_fill, buffer_.size() - buffer_ssl_init_fill), - strand_.wrap( - boost::bind(&connection::handle_receive, connection::shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred))); + template + void connection::start_write() + { + if (state.timers.throttle.out.wait_expire || state.socket.wait_write || + state.data.write.queue.empty() || + (state.ssl.enabled && not state.ssl.handshaked) + ) return; + auto self = connection::shared_from_this(); + if (connection_type != e_connection_type_RPC) { + auto calc_duration = [this]{ + CRITICAL_REGION_LOCAL( + network_throttle_manager_t::m_lock_get_global_throttle_out + ); + return std::chrono::duration_cast::duration_t>( + std::chrono::duration( + std::min( + network_throttle_manager_t::get_global_throttle_out( + ).get_sleep_time_after_tick( + state.data.write.queue.back().size() + ), + 1.0 + ) + ) + ); + }; + const auto duration = calc_duration(); + if (duration > duration_t{}) { + ec_t ec; + timers.throttle.out.expires_from_now(duration, ec); + state.timers.throttle.out.wait_expire = true; + timers.throttle.out.async_wait([this, self](const ec_t &ec){ + lock_guard_t guard(state.lock); + state.timers.throttle.out.wait_expire = false; + if (state.timers.throttle.out.cancel_expire) { + state.timers.throttle.out.cancel_expire = false; + if (state.status == status_t::RUNNING) + interrupt(); + else if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + } + else if (ec.value()) + interrupt(); + else + start_write(); + }); + } } - // detect SSL - if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect) - { - if (is_ssl((const unsigned char*)buffer_.data(), buffer_ssl_init_fill)) - { - MDEBUG("That looks like SSL"); - m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; // read/write to the SSL socket + state.socket.wait_write = true; + auto on_write = [this, self](const ec_t &ec, size_t bytes_transferred){ + lock_guard_t guard(state.lock); + state.socket.wait_write = false; + if (state.socket.cancel_write) { + state.socket.cancel_write = false; + state.data.write.queue.clear(); + if (state.status == status_t::RUNNING) + interrupt(); + else if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); } - else - { - MDEBUG("That does not look like SSL"); - m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; // read/write to the raw socket + else if (ec.value()) { + state.data.write.queue.clear(); + interrupt(); } - } + else { + { + state.stat.out.throttle.handle_trafic_exact(bytes_transferred); + const auto speed = state.stat.out.throttle.get_current_speed(); + context.m_current_speed_up = speed; + context.m_max_speed_down = std::max( + context.m_max_speed_down, + speed + ); + { + CRITICAL_REGION_LOCAL( + network_throttle_manager_t::m_lock_get_global_throttle_out + ); + network_throttle_manager_t::get_global_throttle_out( + ).handle_trafic_exact(bytes_transferred); + } + connection_basic::logger_handle_net_write(bytes_transferred); + context.m_last_send = time(NULL); + context.m_send_cnt += bytes_transferred; - if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled) - { - // Handshake - if (!handshake(boost::asio::ssl::stream_base::server, boost::asio::const_buffer(buffer_.data(), buffer_ssl_init_fill))) - { - MERROR("SSL handshake failed"); - m_want_close_connection = true; - m_ready_to_close = true; - bool do_shutdown = false; - CRITICAL_REGION_BEGIN(m_send_que_lock); - if(!m_send_que.size()) - do_shutdown = true; - CRITICAL_REGION_END(); - if(do_shutdown) - shutdown(); - return; + start_timer(get_default_timeout(), true); + } + assert(bytes_transferred == state.data.write.queue.back().size()); + state.data.write.queue.pop_back(); + state.condition.notify_all(); + start_write(); } - } + }; + if (not state.ssl.enabled) + boost::asio::async_write( + connection_basic::socket_.next_layer(), + boost::asio::buffer( + state.data.write.queue.back().data(), + state.data.write.queue.back().size() + ), + strand.wrap(on_write) + ); else - { - handle_read(e, buffer_ssl_init_fill); - return; - } + strand.post( + [this, self, on_write]{ + boost::asio::async_write( + connection_basic::socket_, + boost::asio::buffer( + state.data.write.queue.back().data(), + state.data.write.queue.back().size() + ), + strand.wrap(on_write) + ); + } + ); + } - async_read_some(boost::asio::buffer(buffer_), - strand_.wrap( - boost::bind(&connection::handle_read, connection::shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred))); - - // If an error occurs then no new asynchronous operations are started. This - // means that all shared_ptr references to the connection object will - // disappear and the object will be destroyed automatically after this - // handler returns. The connection class's destructor closes the socket. - CATCH_ENTRY_L0("connection::handle_receive", void()); + template + void connection::start_shutdown() + { + if (state.socket.wait_shutdown) + return; + auto self = connection::shared_from_this(); + state.socket.wait_shutdown = true; + auto on_shutdown = [this, self](const ec_t &ec){ + lock_guard_t guard(state.lock); + state.socket.wait_shutdown = false; + if (state.socket.cancel_shutdown) { + state.socket.cancel_shutdown = false; + if (state.status == status_t::RUNNING) + interrupt(); + else if (state.status == status_t::INTERRUPTED) + terminate(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + } + else if (ec.value()) + terminate(); + else { + cancel_timer(); + on_interrupted(); + } + }; + strand.post( + [this, self, on_shutdown]{ + connection_basic::socket_.async_shutdown( + strand.wrap(on_shutdown) + ); + } + ); + start_timer(get_default_timeout()); } - //--------------------------------------------------------------------------------- - template - bool connection::call_run_once_service_io() + + template + void connection::cancel_socket() { - TRY_ENTRY(); - if(!m_is_multithreaded) - { - //single thread model, we can wait in blocked call - size_t cnt = GET_IO_SERVICE(socket()).run_one(); - if(!cnt)//service is going to quit - return false; - }else - { - //multi thread model, we can't(!) wait in blocked call - //so we make non blocking call and releasing CPU by calling sleep(0); - //if no handlers were called - //TODO: Maybe we need to have have critical section + event + callback to upper protocol to - //ask it inside(!) critical region if we still able to go in event wait... - size_t cnt = GET_IO_SERVICE(socket()).poll_one(); - if(!cnt) - misc_utils::sleep_no_w(1); + bool wait_socket = false; + if (state.socket.wait_handshake) + wait_socket = state.socket.cancel_handshake = true; + if (state.timers.throttle.in.wait_expire) { + state.timers.throttle.in.cancel_expire = true; + ec_t ec; + timers.throttle.in.cancel(ec); + } + if (state.socket.wait_read) + wait_socket = state.socket.cancel_read = true; + if (state.timers.throttle.out.wait_expire) { + state.timers.throttle.out.cancel_expire = true; + ec_t ec; + timers.throttle.out.cancel(ec); + } + if (state.socket.wait_write) + wait_socket = state.socket.cancel_write = true; + if (state.socket.wait_shutdown) + wait_socket = state.socket.cancel_shutdown = true; + if (wait_socket) { + ec_t ec; + connection_basic::socket_.next_layer().cancel(ec); } - - return true; - CATCH_ENTRY_L0("connection::call_run_once_service_io", false); } - //--------------------------------------------------------------------------------- - template - bool connection::do_send(byte_slice message) { - TRY_ENTRY(); - - // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted - auto self = safe_shared_from_this(); - if (!self) return false; - if (m_was_shutdown) return false; - // TODO avoid copy - - std::uint8_t const* const message_data = message.data(); - const std::size_t message_size = message.size(); - - const double factor = 32; // TODO config - typedef long long signed int t_safe; // my t_size to avoid any overunderflow in arithmetic - const t_safe chunksize_good = (t_safe)( 1024 * std::max(1.0,factor) ); - const t_safe chunksize_max = chunksize_good * 2 ; - const bool allow_split = (m_connection_type == e_connection_type_RPC) ? false : true; // do not split RPC data - - CHECK_AND_ASSERT_MES(! (chunksize_max<0), false, "Negative chunksize_max" ); // make sure it is unsigned before removin sign with cast: - long long unsigned int chunksize_max_unsigned = static_cast( chunksize_max ) ; - - if (allow_split && (message_size > chunksize_max_unsigned)) { - { // LOCK: chunking - epee::critical_region_t send_guard(m_chunking_lock); // *** critical *** - MDEBUG("do_send() will SPLIT into small chunks, from packet="< + void connection::cancel_handler() + { + if (state.protocol.released || state.protocol.wait_release) + return; + state.protocol.wait_release = true; + state.lock.unlock(); + handler.release_protocol(); + state.lock.lock(); + state.protocol.wait_release = false; + state.protocol.released = true; + if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + } - MDEBUG("do_send() DONE SPLIT from packet="<::do_send", false); - } // do_send() + template + void connection::on_terminating() + { + assert(state.status == status_t::TERMINATING); + if (state.timers.general.wait_expire) + return; + if (state.socket.wait_handshake) + return; + if (state.timers.throttle.in.wait_expire) + return; + if (state.socket.wait_read) + return; + if (state.socket.handle_read) + return; + if (state.timers.throttle.out.wait_expire) + return; + if (state.socket.wait_write) + return; + if (state.socket.wait_shutdown) + return; + if (state.protocol.wait_init) + return; + if (state.protocol.wait_callback) + return; + if (state.protocol.wait_release) + return; + if (state.socket.connected) { + ec_t ec; + connection_basic::socket_.next_layer().shutdown( + socket_t::shutdown_both, + ec + ); + connection_basic::socket_.next_layer().close(ec); + state.socket.connected = false; + } + state.status = status_t::WASTED; + } - //--------------------------------------------------------------------------------- - template - bool connection::do_send_chunk(byte_slice chunk) + template + bool connection::send(byte_slice_t message) { - TRY_ENTRY(); - // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted - auto self = safe_shared_from_this(); - if(!self) - return false; - if(m_was_shutdown) + lock_guard_t guard(state.lock); + if (state.status != status_t::RUNNING || state.socket.wait_handshake) return false; - double current_speed_up; - { - CRITICAL_REGION_LOCAL(m_throttle_speed_out_mutex); - m_throttle_speed_out.handle_trafic_exact(chunk.size()); - current_speed_up = m_throttle_speed_out.get_current_speed(); - } - context.m_current_speed_up = current_speed_up; - context.m_max_speed_up = std::max(context.m_max_speed_up, current_speed_up); - - //_info("[sock " << socket().native_handle() << "] SEND " << cb); - context.m_last_send = time(NULL); - context.m_send_cnt += chunk.size(); - //some data should be wrote to stream - //request complete - - // No sleeping here; sleeping is done once and for all in "handle_write" - - m_send_que_lock.lock(); // *** critical *** - epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){m_send_que_lock.unlock();}); - - long int retry=0; - const long int retry_limit = 5*4; - while (m_send_que.size() > ABSTRACT_SERVER_SEND_QUE_MAX_COUNT) - { - retry++; - - /* if ( ::cryptonote::core::get_is_stopping() ) { // TODO re-add fast stop - _fact("ABORT queue wait due to stopping"); - return false; // aborted - }*/ - + auto wait_consume = [this] { + auto random_delay = []{ using engine = std::mt19937; - - engine rng; std::random_device dev; - std::seed_seq::result_type rand[engine::state_size]{}; // Use complete bit space - + std::seed_seq::result_type rand[ + engine::state_size // Use complete bit space + ]{}; std::generate_n(rand, engine::state_size, std::ref(dev)); std::seed_seq seed(rand, rand + engine::state_size); - rng.seed(seed); - - long int ms = 250 + (rng() % 50); - MDEBUG("Sleeping because QUEUE is FULL, in " << __FUNCTION__ << " for " << ms << " ms before packet_size="< retry_limit) { - MWARNING("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection"); - shutdown(); - return false; + engine rng(seed); + return std::chrono::milliseconds( + std::uniform_int_distribution<>(5000, 6000)(rng) + ); + }; + if (state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT) + return true; + state.data.write.wait_consume = true; + bool success = state.condition.wait_for( + state.lock, + random_delay(), + [this]{ + return ( + state.status != status_t::RUNNING || + state.data.write.queue.size() <= + ABSTRACT_SERVER_SEND_QUE_MAX_COUNT + ); + } + ); + state.data.write.wait_consume = false; + if (not success) { + terminate(); + return false; + } + else + return state.status == status_t::RUNNING; + }; + auto wait_sender = [this] { + state.condition.wait( + state.lock, + [this] { + return ( + state.status != status_t::RUNNING || + not state.data.write.wait_consume + ); } + ); + return state.status == status_t::RUNNING; + }; + if (not wait_sender()) + return false; + constexpr size_t CHUNK_SIZE = 32 * 1024; + if (connection_type == e_connection_type_RPC || + message.size() <= 2 * CHUNK_SIZE + ) { + if (not wait_consume()) + return false; + state.data.write.queue.emplace_front(std::move(message)); + start_write(); } - - m_send_que.push_back(std::move(chunk)); - - if(m_send_que.size() > 1) - { // active operation should be in progress, nothing to do, just wait last operation callback - auto size_now = m_send_que.back().size(); - MDEBUG("do_send_chunk() NOW just queues: packet="< + bool connection::start_internal( + bool is_income, + bool is_multithreaded, + boost::optional real_remote + ) + { + unique_lock_t guard(state.lock); + if (state.status != status_t::TERMINATED) + return false; + if (not real_remote) { + ec_t ec; + auto endpoint = connection_basic::socket_.next_layer().remote_endpoint( + ec + ); + if (ec.value()) + return false; + real_remote = ( + endpoint.address().is_v6() ? + network_address{ + ipv6_network_address{endpoint.address().to_v6(), endpoint.port()} + } : + network_address{ + ipv4_network_address{ + uint32_t{ + boost::asio::detail::socket_ops::host_to_network_long( + endpoint.address().to_v4().to_ulong() + ) + }, + endpoint.port() + } } - - auto size_now = m_send_que.front().size(); - MDEBUG("do_send_chunk() NOW SENSD: packet="<::handle_write, self, std::placeholders::_1, std::placeholders::_2) - ) - ); - //_dbg3("(chunk): " << size_now); - //logger_handle_net_write(size_now); - //_info("[sock " << socket().native_handle() << "] Async send requested " << m_send_que.front().size()); + ); } - - //do_send_handler_stop( ptr , cb ); // empty function - + auto *filter = static_cast( + connection_basic::get_state() + ).pfilter; + if (filter and not filter->is_remote_host_allowed(*real_remote)) + return false; + ec_t ec; + #if !defined(_WIN32) || !defined(__i686) + connection_basic::socket_.next_layer().set_option( + boost::asio::detail::socket_option::integer{ + connection_basic::get_tos_flag() + }, + ec + ); + if (ec.value()) + return false; + #endif + connection_basic::socket_.next_layer().set_option( + boost::asio::ip::tcp::no_delay{false}, + ec + ); + if (ec.value()) + return false; + connection_basic::m_is_multithreaded = is_multithreaded; + context.set_details( + boost::uuids::random_generator()(), + *real_remote, + is_income, + connection_basic::m_ssl_support == ssl_support_t::e_ssl_support_enabled + ); + host = real_remote->host_str(); + try { host_count(1); } catch(...) { /* ignore */ } + local = real_remote->is_loopback() || real_remote->is_local(); + state.ssl.enabled = ( + connection_basic::m_ssl_support != ssl_support_t::e_ssl_support_disabled + ); + state.ssl.forced = ( + connection_basic::m_ssl_support == ssl_support_t::e_ssl_support_enabled + ); + state.socket.connected = true; + state.status = status_t::RUNNING; + start_timer( + std::chrono::milliseconds( + local ? NEW_CONNECTION_TIMEOUT_LOCAL : NEW_CONNECTION_TIMEOUT_REMOTE + ) + ); + state.protocol.wait_init = true; + guard.unlock(); + handler.after_init_connection(); + guard.lock(); + state.protocol.wait_init = false; + state.protocol.initialized = true; + if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + else if (not is_income || not state.ssl.enabled) + start_read(); + else + start_handshake(); return true; + } - CATCH_ENTRY_L0("connection::do_send_chunk", false); - } // do_send_chunk - //--------------------------------------------------------------------------------- - template - boost::posix_time::milliseconds connection::get_default_timeout() + template + connection::connection( + io_context_t &io_context, + std::shared_ptr shared_state, + t_connection_type connection_type, + ssl_support_t ssl_support + ): + connection( + std::move(socket_t{io_context}), + std::move(shared_state), + connection_type, + ssl_support + ) { - unsigned count; - try { count = host_count(m_host); } catch (...) { count = 0; } - const unsigned shift = get_state().sock_count > AGGRESSIVE_TIMEOUT_THRESHOLD ? std::min(std::max(count, 1u) - 1, 8u) : 0; - boost::posix_time::milliseconds timeout(0); - if (m_local) - timeout = boost::posix_time::milliseconds(DEFAULT_TIMEOUT_MS_LOCAL >> shift); - else - timeout = boost::posix_time::milliseconds(DEFAULT_TIMEOUT_MS_REMOTE >> shift); - return timeout; } - //--------------------------------------------------------------------------------- - template - boost::posix_time::milliseconds connection::get_timeout_from_bytes_read(size_t bytes) + + template + connection::connection( + socket_t &&socket, + std::shared_ptr shared_state, + t_connection_type connection_type, + ssl_support_t ssl_support + ): + connection_basic(std::move(socket), shared_state, ssl_support), + handler(this, *shared_state, context), + connection_type(connection_type), + io_context{GET_IO_SERVICE(connection_basic::socket_)}, + strand{io_context}, + timers{io_context} { - boost::posix_time::milliseconds ms = (boost::posix_time::milliseconds)(unsigned)(bytes * TIMEOUT_EXTRA_MS_PER_BYTE); - const auto cur = m_timer.expires_from_now().total_milliseconds(); - if (cur > 0) - ms += (boost::posix_time::milliseconds)cur; - if (ms > get_default_timeout()) - ms = get_default_timeout(); - return ms; } - //--------------------------------------------------------------------------------- - template - unsigned int connection::host_count(const std::string &host, int delta) + + template + connection::~connection() noexcept(false) { - static boost::mutex hosts_mutex; - CRITICAL_REGION_LOCAL(hosts_mutex); - static std::map hosts; - unsigned int &val = hosts[host]; - if (delta > 0) - MTRACE("New connection from host " << host << ": " << val); - else if (delta < 0) - MTRACE("Closed connection from host " << host << ": " << val); - CHECK_AND_ASSERT_THROW_MES(delta >= 0 || val >= (unsigned)-delta, "Count would go negative"); - CHECK_AND_ASSERT_THROW_MES(delta <= 0 || val <= std::numeric_limits::max() - (unsigned)delta, "Count would wrap"); - val += delta; - return val; + lock_guard_t guard(state.lock); + assert(state.status == status_t::TERMINATED || + state.status == status_t::WASTED || + io_context.stopped() + ); + if (state.status != status_t::WASTED) + return; + try { host_count(-1); } catch (...) { /* ignore */ } } - //--------------------------------------------------------------------------------- - template - void connection::reset_timer(boost::posix_time::milliseconds ms, bool add) + + template + bool connection::start( + bool is_income, + bool is_multithreaded + ) { - const auto tms = ms.total_milliseconds(); - if (tms < 0 || (add && tms == 0)) - { - MWARNING("Ignoring negative timeout " << ms); - return; - } - MTRACE((add ? "Adding" : "Setting") << " " << ms << " expiry"); - auto self = safe_shared_from_this(); - if(!self) - { - MERROR("Resetting timer on a dead object"); - return; - } - if (m_was_shutdown) - { - MERROR("Setting timer on a shut down object"); - return; - } - if (add) - { - const auto cur = m_timer.expires_from_now().total_milliseconds(); - if (cur > 0) - ms += (boost::posix_time::milliseconds)cur; - } - m_timer.expires_from_now(ms); - m_timer.async_wait([=](const boost::system::error_code& ec) - { - if(ec == boost::asio::error::operation_aborted) - return; - MDEBUG(context << "connection timeout, closing"); - self->close(); - }); + return start_internal(is_income, is_multithreaded, {}); } - //--------------------------------------------------------------------------------- - template - bool connection::shutdown() + + template + bool connection::start( + bool is_income, + bool is_multithreaded, + network_address real_remote + ) { - CRITICAL_REGION_BEGIN(m_shutdown_lock); - if (m_was_shutdown) - return true; - m_was_shutdown = true; - // Initiate graceful connection closure. - m_timer.cancel(); - boost::system::error_code ignored_ec; - if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled) - { - const shared_state &state = static_cast(get_state()); - if (!state.stop_signal_sent) - socket_.shutdown(ignored_ec); - } - socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); - if (!m_host.empty()) - { - try { host_count(m_host, -1); } catch (...) { /* ignore */ } - m_host = ""; - } - CRITICAL_REGION_END(); - m_protocol_handler.release_protocol(); - return true; + return start_internal(is_income, is_multithreaded, real_remote); } - //--------------------------------------------------------------------------------- - template - bool connection::close() + + template + void connection::save_dbg_log() { - TRY_ENTRY(); - auto self = safe_shared_from_this(); - if(!self) - return false; - //_info("[sock " << socket().native_handle() << "] Que Shutdown called."); - m_timer.cancel(); - size_t send_que_size = 0; - CRITICAL_REGION_BEGIN(m_send_que_lock); - send_que_size = m_send_que.size(); - CRITICAL_REGION_END(); - m_want_close_connection = true; - if(!send_que_size) - { - shutdown(); + lock_guard_t guard(state.lock); + string_t address; + string_t port; + ec_t ec; + auto endpoint = connection_basic::socket().remote_endpoint(ec); + if (ec.value()) { + address = ""; + port = ""; } - - return true; - CATCH_ENTRY_L0("connection::close", false); + else { + address = endpoint.address().to_string(); + port = std::to_string(endpoint.port()); + } + MDEBUG( + " connection type " << std::to_string(connection_type) << + " " << connection_basic::socket().local_endpoint().address().to_string() << + ":" << connection_basic::socket().local_endpoint().port() << + " <--> " << context.m_remote_address.str() << + " (via " << address << ":" << port << ")" + ); } - //--------------------------------------------------------------------------------- - template - bool connection::send_done() + + template + bool connection::speed_limit_is_enabled() const { - if (m_ready_to_close) - return close(); - m_ready_to_close = true; - return true; + return connection_type != e_connection_type_RPC; } - //--------------------------------------------------------------------------------- - template - bool connection::cancel() + + template + bool connection::cancel() { return close(); } - //--------------------------------------------------------------------------------- - template - void connection::handle_write(const boost::system::error_code& e, size_t cb) + + template + bool connection::do_send(byte_slice message) { - TRY_ENTRY(); - LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] Async send calledback " << cb); + return send(std::move(message)); + } - if (e) - { - _dbg1("[sock " << socket().native_handle() << "] Some problems at write: " << e.message() << ':' << e.value()); - shutdown(); - return; - } - logger_handle_net_write(cb); + template + bool connection::send_done() + { + return true; + } - // The single sleeping that is needed for correctly handling "out" speed throttling - if (speed_limit_is_enabled()) { - sleep_before_packet(cb, 1, 1); - } + template + bool connection::close() + { + lock_guard_t guard(state.lock); + if (state.status != status_t::RUNNING) + return false; + terminate(); + return true; + } - bool do_shutdown = false; - CRITICAL_REGION_BEGIN(m_send_que_lock); - if(m_send_que.empty()) - { - _erro("[sock " << socket().native_handle() << "] m_send_que.size() == 0 at handle_write!"); - return; + template + bool connection::call_run_once_service_io() + { + if(connection_basic::m_is_multithreaded) { + if (not io_context.poll_one()) + misc_utils::sleep_no_w(1); } - - m_send_que.pop_front(); - if(m_send_que.empty()) - { - if(m_want_close_connection) - { - do_shutdown = true; - } - }else - { - //have more data to send - reset_timer(get_default_timeout(), false); - auto size_now = m_send_que.front().size(); - MDEBUG("handle_write() NOW SENDS: packet="<::handle_write, connection::shared_from_this(), std::placeholders::_1, std::placeholders::_2) - ) - ); - //_dbg3("(normal)" << size_now); + else { + if (!io_context.run_one()) + return false; } - CRITICAL_REGION_END(); + return true; + } - if(do_shutdown) - { - shutdown(); - } - CATCH_ENTRY_L0("connection::handle_write", void()); + template + bool connection::request_callback() + { + lock_guard_t guard(state.lock); + if (state.status != status_t::RUNNING) + return false; + auto self = connection::shared_from_this(); + ++state.protocol.wait_callback; + connection_basic::strand_.post([this, self]{ + handler.handle_qued_callback(); + lock_guard_t guard(state.lock); + --state.protocol.wait_callback; + if (state.status == status_t::INTERRUPTED) + on_interrupted(); + else if (state.status == status_t::TERMINATING) + on_terminating(); + }); + return true; } - //--------------------------------------------------------------------------------- - template - void connection::setRpcStation() + template + typename connection::io_context_t &connection::get_io_service() { - m_connection_type = e_connection_type_RPC; - MDEBUG("set m_connection_type = RPC "); + return io_context; } + template + bool connection::add_ref() + { + try { + auto self = connection::shared_from_this(); + lock_guard_t guard(state.lock); + this->self = std::move(self); + ++state.protocol.reference_counter; + return true; + } + catch (boost::bad_weak_ptr &exception) { + return false; + } + } - template - bool connection::speed_limit_is_enabled() const { - return m_connection_type != e_connection_type_RPC ; - } + template + bool connection::release() + { + connection_ptr self; + lock_guard_t guard(state.lock); + if (not --state.protocol.reference_counter) + self = std::move(this->self); + return true; + } - /************************************************************************/ - /* */ - /************************************************************************/ + template + void connection::setRpcStation() + { + lock_guard_t guard(state.lock); + connection_type = e_connection_type_RPC; + } template boosted_tcp_server::boosted_tcp_server( t_connection_type connection_type ) : diff --git a/contrib/epee/include/net/net_ssl.h b/contrib/epee/include/net/net_ssl.h index 108e6771bd6..c79a3acc1ff 100644 --- a/contrib/epee/include/net/net_ssl.h +++ b/contrib/epee/include/net/net_ssl.h @@ -110,6 +110,11 @@ namespace net_utils //! Search against internal fingerprints. Always false if `behavior() != user_certificate_check`. bool has_fingerprint(boost::asio::ssl::verify_context &ctx) const; + //! configure ssl_stream handshake verification + void configure( + boost::asio::ssl::stream &socket, + boost::asio::ssl::stream_base::handshake_type type, + const std::string& host = {}) const; boost::asio::ssl::context create_context() const; /*! \note If `this->support == autodetect && this->verification != none`, diff --git a/contrib/epee/src/net_ssl.cpp b/contrib/epee/src/net_ssl.cpp index 7dfb56068a3..7dda65bb5eb 100644 --- a/contrib/epee/src/net_ssl.cpp +++ b/contrib/epee/src/net_ssl.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -488,12 +490,10 @@ bool ssl_options_t::has_fingerprint(boost::asio::ssl::verify_context &ctx) const return false; } -bool ssl_options_t::handshake( +void ssl_options_t::configure( boost::asio::ssl::stream &socket, boost::asio::ssl::stream_base::handshake_type type, - boost::asio::const_buffer buffer, - const std::string& host, - std::chrono::milliseconds timeout) const + const std::string& host) const { socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true)); @@ -538,30 +538,101 @@ bool ssl_options_t::handshake( return true; }); } +} + +bool ssl_options_t::handshake( + boost::asio::ssl::stream &socket, + boost::asio::ssl::stream_base::handshake_type type, + boost::asio::const_buffer buffer, + const std::string& host, + std::chrono::milliseconds timeout) const +{ + configure(socket, type, host); + + auto start_handshake = [&]{ + using ec_t = boost::system::error_code; + using timer_t = boost::asio::steady_timer; + using strand_t = boost::asio::io_service::strand; + using lock_t = std::mutex; + using lock_guard_t = std::lock_guard; + using condition_t = std::condition_variable_any; + using socket_t = boost::asio::ip::tcp::socket; + + auto &io_context = GET_IO_SERVICE(socket); + if (io_context.stopped()) + io_context.reset(); + strand_t strand(io_context); + timer_t deadline(io_context, timeout); + + struct state_t { + lock_t lock; + condition_t condition; + ec_t result; + bool wait_timer; + bool wait_handshake; + bool cancel_timer; + bool cancel_handshake; + }; + state_t state{}; + + state.wait_timer = true; + auto on_timer = [&](const ec_t &ec){ + lock_guard_t guard(state.lock); + state.wait_timer = false; + state.condition.notify_all(); + if (not state.cancel_timer) { + state.cancel_handshake = true; + ec_t ec; + socket.next_layer().cancel(ec); + } + }; + + state.wait_handshake = true; + auto on_handshake = [&](const ec_t &ec, size_t bytes_transferred){ + lock_guard_t guard(state.lock); + state.wait_handshake = false; + state.condition.notify_all(); + state.result = ec; + if (not state.cancel_handshake) { + state.cancel_timer = true; + ec_t ec; + deadline.cancel(ec); + } + }; + + deadline.async_wait(on_timer); + strand.post( + [&]{ + socket.async_handshake( + type, + boost::asio::buffer(buffer), + strand.wrap(on_handshake) + ); + } + ); - auto& io_service = GET_IO_SERVICE(socket); - boost::asio::steady_timer deadline(io_service, timeout); - deadline.async_wait([&socket](const boost::system::error_code& error) { - if (error != boost::asio::error::operation_aborted) + while (!io_context.stopped()) { - socket.next_layer().close(); + io_context.poll_one(); + lock_guard_t guard(state.lock); + state.condition.wait_for( + state.lock, + std::chrono::milliseconds(30), + [&]{ + return not state.wait_timer and not state.wait_handshake; + } + ); + if (not state.wait_timer and not state.wait_handshake) + break; } - }); - - boost::system::error_code ec = boost::asio::error::would_block; - socket.async_handshake(type, boost::asio::buffer(buffer), boost::lambda::var(ec) = boost::lambda::_1); - if (io_service.stopped()) - { - io_service.reset(); - } - while (ec == boost::asio::error::would_block && !io_service.stopped()) - { - // should poll_one(), can't run_one() because it can block if there is - // another worker thread executing io_service's tasks - // TODO: once we get Boost 1.66+, replace with run_one_for/run_until - std::this_thread::sleep_for(std::chrono::milliseconds(30)); - io_service.poll_one(); - } + if (state.result.value()) { + ec_t ec; + socket.next_layer().shutdown(socket_t::shutdown_both, ec); + socket.next_layer().close(ec); + } + return state.result; + }; + const auto ec = start_handshake(); if (ec) { From a82fba4b7b944a54d2a14922f44d7eee367e4912 Mon Sep 17 00:00:00 2001 From: j-berman Date: Wed, 6 Jul 2022 16:47:34 -0700 Subject: [PATCH 053/186] address PR comments --- .../epee/include/net/abstract_tcp_server2.h | 82 +-- .../epee/include/net/abstract_tcp_server2.inl | 672 +++++++++--------- contrib/epee/src/net_ssl.cpp | 21 +- tests/unit_tests/epee_boosted_tcp_server.cpp | 10 +- 4 files changed, 390 insertions(+), 395 deletions(-) diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index 0684573f2fa..bc0da66e299 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -89,20 +89,14 @@ namespace net_utils public i_service_endpoint, public connection_basic { + public: + typedef typename t_protocol_handler::connection_context t_connection_context; private: - using string_t = std::string; - using handler_t = t_protocol_handler; - using context_t = typename handler_t::connection_context; - using connection_t = connection; + using connection_t = connection; using connection_ptr = boost::shared_ptr; using ssl_support_t = epee::net_utils::ssl_support_t; using timer_t = boost::asio::steady_timer; using duration_t = timer_t::duration; - using lock_t = std::mutex; - using condition_t = std::condition_variable_any; - using lock_guard_t = std::lock_guard; - using unique_lock_t = std::unique_lock; - using byte_slice_t = epee::byte_slice; using ec_t = boost::system::error_code; using handshake_t = boost::asio::ssl::stream_base::handshake_type; @@ -110,8 +104,6 @@ namespace net_utils using strand_t = boost::asio::io_service::strand; using socket_t = boost::asio::ip::tcp::socket; - using write_queue_t = std::deque; - using read_buffer_t = std::array; using network_throttle_t = epee::net_utils::network_throttle; using network_throttle_manager_t = epee::net_utils::network_throttle_manager; @@ -119,6 +111,8 @@ namespace net_utils duration_t get_default_timeout(); duration_t get_timeout_from_bytes_read(size_t bytes) const; + void state_status_check(); + void start_timer(duration_t duration, bool add = {}); void async_wait_timer(); void cancel_timer(); @@ -137,13 +131,21 @@ namespace net_utils void terminate(); void on_terminating(); - bool send(byte_slice_t message); + bool send(epee::byte_slice message); bool start_internal( bool is_income, bool is_multithreaded, boost::optional real_remote ); + enum status_t { + TERMINATED, + RUNNING, + INTERRUPTED, + TERMINATING, + WASTED, + }; + struct state_t { struct stat_t { struct { @@ -156,10 +158,10 @@ namespace net_utils struct data_t { struct { - read_buffer_t buffer; + std::array buffer; } read; struct { - write_queue_t queue; + std::deque queue; bool wait_consume; } write; }; @@ -171,7 +173,7 @@ namespace net_utils bool handshaked; }; - struct socket_t { + struct socket_status_t { bool connected; bool wait_handshake; @@ -189,30 +191,22 @@ namespace net_utils bool cancel_shutdown; }; - struct timer_t { + struct timer_status_t { bool wait_expire; bool cancel_expire; bool reset_expire; }; - struct timers_t { + struct timers_status_t { struct throttle_t { - timer_t in; - timer_t out; + timer_status_t in; + timer_status_t out; }; - timer_t general; + timer_status_t general; throttle_t throttle; }; - enum status_t { - TERMINATED, - RUNNING, - INTERRUPTED, - TERMINATING, - WASTED, - }; - struct protocol_t { size_t reference_counter; bool released; @@ -223,19 +217,17 @@ namespace net_utils size_t wait_callback; }; - lock_t lock; - condition_t condition; + std::mutex lock; + std::condition_variable_any condition; status_t status; - socket_t socket; + socket_status_t socket; ssl_t ssl; - timers_t timers; + timers_status_t timers; protocol_t protocol; stat_t stat; data_t data; }; - using status_t = typename state_t::status_t; - struct timers_t { timers_t(io_context_t &io_context): general(io_context), @@ -254,19 +246,17 @@ namespace net_utils throttle_t throttle; }; - io_context_t &io_context; - t_connection_type connection_type; - context_t context{}; - strand_t strand; - timers_t timers; + io_context_t &m_io_context; + t_connection_type m_connection_type; + t_connection_context m_conn_context{}; + strand_t m_strand; + timers_t m_timers; connection_ptr self{}; - bool local{}; - string_t host{}; - state_t state{}; - handler_t handler; + bool m_local{}; + std::string m_host{}; + state_t m_state{}; + t_protocol_handler m_handler; public: - typedef typename t_protocol_handler::connection_context t_connection_context; - struct shared_state : connection_basic_shared_state, t_protocol_handler::config_type { shared_state() @@ -298,7 +288,7 @@ namespace net_utils // `real_remote` is the actual endpoint (if connection is to proxy, etc.) bool start(bool is_income, bool is_multithreaded, network_address real_remote); - void get_context(t_connection_context& context_){context_ = context;} + void get_context(t_connection_context& context_){context_ = m_conn_context;} void call_back_starter(); diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 0fc9228b1cd..81aa725d1e2 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -79,14 +79,14 @@ namespace net_utils template unsigned int connection::host_count(int delta) { - static lock_t hosts_mutex; - lock_guard_t guard(hosts_mutex); - static std::map hosts; - unsigned int &val = hosts[host]; + static std::mutex hosts_mutex; + std::lock_guard guard(hosts_mutex); + static std::map hosts; + unsigned int &val = hosts[m_host]; if (delta > 0) - MTRACE("New connection from host " << host << ": " << val); + MTRACE("New connection from host " << m_host << ": " << val); else if (delta < 0) - MTRACE("Closed connection from host " << host << ": " << val); + MTRACE("Closed connection from host " << m_host << ": " << val); CHECK_AND_ASSERT_THROW_MES(delta >= 0 || val >= (unsigned)-delta, "Count would go negative"); CHECK_AND_ASSERT_THROW_MES(delta <= 0 || val <= std::numeric_limits::max() - (unsigned)delta, "Count would wrap"); val += delta; @@ -104,7 +104,7 @@ namespace net_utils 0 ); return ( - local ? + m_local ? std::chrono::milliseconds(DEFAULT_TIMEOUT_MS_LOCAL >> shift) : std::chrono::milliseconds(DEFAULT_TIMEOUT_MS_REMOTE >> shift) ); @@ -120,16 +120,35 @@ namespace net_utils ); } + template + void connection::state_status_check() + { + switch (m_state.status) + { + case status_t::RUNNING: + interrupt(); + break; + case status_t::INTERRUPTED: + on_interrupted(); + break; + case status_t::TERMINATING: + on_terminating(); + break; + default: + break; + } + } + template void connection::start_timer(duration_t duration, bool add) { - if (state.timers.general.wait_expire) { - state.timers.general.cancel_expire = true; - state.timers.general.reset_expire = true; + if (m_state.timers.general.wait_expire) { + m_state.timers.general.cancel_expire = true; + m_state.timers.general.reset_expire = true; ec_t ec; - timers.general.expires_from_now( + m_timers.general.expires_from_now( std::min( - duration + (add ? timers.general.expires_from_now() : duration_t{}), + duration + (add ? m_timers.general.expires_from_now() : duration_t{}), get_default_timeout() ), ec @@ -137,9 +156,9 @@ namespace net_utils } else { ec_t ec; - timers.general.expires_from_now( + m_timers.general.expires_from_now( std::min( - duration + (add ? timers.general.expires_from_now() : duration_t{}), + duration + (add ? m_timers.general.expires_from_now() : duration_t{}), get_default_timeout() ), ec @@ -151,27 +170,27 @@ namespace net_utils template void connection::async_wait_timer() { - if (state.timers.general.wait_expire) + if (m_state.timers.general.wait_expire) return; - state.timers.general.wait_expire = true; + m_state.timers.general.wait_expire = true; auto self = connection::shared_from_this(); - timers.general.async_wait([this, self](const ec_t & ec){ - lock_guard_t guard(state.lock); - state.timers.general.wait_expire = false; - if (state.timers.general.cancel_expire) { - state.timers.general.cancel_expire = false; - if (state.timers.general.reset_expire) { - state.timers.general.reset_expire = false; + m_timers.general.async_wait([this, self](const ec_t & ec){ + std::lock_guard guard(m_state.lock); + m_state.timers.general.wait_expire = false; + if (m_state.timers.general.cancel_expire) { + m_state.timers.general.cancel_expire = false; + if (m_state.timers.general.reset_expire) { + m_state.timers.general.reset_expire = false; async_wait_timer(); } - else if (state.status == status_t::INTERRUPTED) + else if (m_state.status == status_t::INTERRUPTED) on_interrupted(); - else if (state.status == status_t::TERMINATING) + else if (m_state.status == status_t::TERMINATING) on_terminating(); } - else if (state.status == status_t::RUNNING) + else if (m_state.status == status_t::RUNNING) interrupt(); - else if (state.status == status_t::INTERRUPTED) + else if (m_state.status == status_t::INTERRUPTED) terminate(); }); } @@ -179,72 +198,67 @@ namespace net_utils template void connection::cancel_timer() { - if (not state.timers.general.wait_expire) + if (!m_state.timers.general.wait_expire) return; - state.timers.general.cancel_expire = true; - state.timers.general.reset_expire = false; + m_state.timers.general.cancel_expire = true; + m_state.timers.general.reset_expire = false; ec_t ec; - timers.general.cancel(ec); + m_timers.general.cancel(ec); } template void connection::start_handshake() { - if (state.socket.wait_handshake) + if (m_state.socket.wait_handshake) return; static_assert( - epee::net_utils::get_ssl_magic_size() <= sizeof(state.data.read.buffer), + epee::net_utils::get_ssl_magic_size() <= sizeof(m_state.data.read.buffer), "" ); auto self = connection::shared_from_this(); - if (not state.ssl.forced and not state.ssl.detected) { - state.socket.wait_read = true; + if (!m_state.ssl.forced && !m_state.ssl.detected) { + m_state.socket.wait_read = true; boost::asio::async_read( connection_basic::socket_.next_layer(), boost::asio::buffer( - state.data.read.buffer.data(), - state.data.read.buffer.size() + m_state.data.read.buffer.data(), + m_state.data.read.buffer.size() ), boost::asio::transfer_exactly(epee::net_utils::get_ssl_magic_size()), - strand.wrap( + m_strand.wrap( [this, self](const ec_t &ec, size_t bytes_transferred){ - lock_guard_t guard(state.lock); - state.socket.wait_read = false; - if (state.socket.cancel_read) { - state.socket.cancel_read = false; - if (state.status == status_t::RUNNING) - interrupt(); - else if (state.status == status_t::INTERRUPTED) - on_interrupted(); - else if (state.status == status_t::TERMINATING) - on_terminating(); + std::lock_guard guard(m_state.lock); + m_state.socket.wait_read = false; + if (m_state.socket.cancel_read) { + m_state.socket.cancel_read = false; + state_status_check(); } else if (ec.value()) { terminate(); } else if ( - not epee::net_utils::is_ssl( + !epee::net_utils::is_ssl( static_cast( - state.data.read.buffer.data() + m_state.data.read.buffer.data() ), bytes_transferred ) ) { - state.ssl.enabled = false; - state.socket.handle_read = true; + m_state.ssl.enabled = false; + m_state.socket.handle_read = true; connection_basic::strand_.post( [this, self, bytes_transferred]{ - bool success = handler.handle_recv( - reinterpret_cast(state.data.read.buffer.data()), + bool success = m_handler.handle_recv( + reinterpret_cast(m_state.data.read.buffer.data()), bytes_transferred ); - lock_guard_t guard(state.lock); - state.socket.handle_read = false; - if (state.status == status_t::INTERRUPTED) + std::lock_guard guard(m_state.lock); + m_state.socket.handle_read = false; + if (m_state.status == status_t::INTERRUPTED) on_interrupted(); - else if (state.status == status_t::TERMINATING) + else if (m_state.status == status_t::TERMINATING) on_terminating(); - else if (not success) + else if (!success) interrupt(); else { start_read(); @@ -253,7 +267,7 @@ namespace net_utils ); } else { - state.ssl.detected = true; + m_state.ssl.detected = true; start_handshake(); } } @@ -262,18 +276,13 @@ namespace net_utils return; } - state.socket.wait_handshake = true; + m_state.socket.wait_handshake = true; auto on_handshake = [this, self](const ec_t &ec, size_t bytes_transferred){ - lock_guard_t guard(state.lock); - state.socket.wait_handshake = false; - if (state.socket.cancel_handshake) { - state.socket.cancel_handshake = false; - if (state.status == status_t::RUNNING) - interrupt(); - else if (state.status == status_t::INTERRUPTED) - on_interrupted(); - else if (state.status == status_t::TERMINATING) - on_terminating(); + std::lock_guard guard(m_state.lock); + m_state.socket.wait_handshake = false; + if (m_state.socket.cancel_handshake) { + m_state.socket.cancel_handshake = false; + state_status_check(); } else if (ec.value()) { ec_t ec; @@ -282,11 +291,11 @@ namespace net_utils ec ); connection_basic::socket_.next_layer().close(ec); - state.socket.connected = false; + m_state.socket.connected = false; interrupt(); } else { - state.ssl.handshaked = true; + m_state.ssl.handshaked = true; start_write(); start_read(); } @@ -295,16 +304,16 @@ namespace net_utils static_cast( connection_basic::get_state() ).ssl_options().configure(connection_basic::socket_, handshake); - strand.post( + m_strand.post( [this, self, on_handshake]{ connection_basic::socket_.async_handshake( handshake, boost::asio::buffer( - state.data.read.buffer.data(), - state.ssl.forced ? 0 : + m_state.data.read.buffer.data(), + m_state.ssl.forced ? 0 : epee::net_utils::get_ssl_magic_size() ), - strand.wrap(on_handshake) + m_strand.wrap(on_handshake) ); } ); @@ -313,12 +322,13 @@ namespace net_utils template void connection::start_read() { - if (state.timers.throttle.in.wait_expire || state.socket.wait_read || - state.socket.handle_read - ) + if (m_state.timers.throttle.in.wait_expire || m_state.socket.wait_read || + m_state.socket.handle_read + ) { return; + } auto self = connection::shared_from_this(); - if (connection_type != e_connection_type_RPC) { + if (m_connection_type != e_connection_type_RPC) { auto calc_duration = []{ CRITICAL_REGION_LOCAL( network_throttle_manager_t::m_lock_get_global_throttle_in @@ -336,19 +346,14 @@ namespace net_utils const auto duration = calc_duration(); if (duration > duration_t{}) { ec_t ec; - timers.throttle.in.expires_from_now(duration, ec); - state.timers.throttle.in.wait_expire = true; - timers.throttle.in.async_wait([this, self](const ec_t &ec){ - lock_guard_t guard(state.lock); - state.timers.throttle.in.wait_expire = false; - if (state.timers.throttle.in.cancel_expire) { - state.timers.throttle.in.cancel_expire = false; - if (state.status == status_t::RUNNING) - interrupt(); - else if (state.status == status_t::INTERRUPTED) - on_interrupted(); - else if (state.status == status_t::TERMINATING) - on_terminating(); + m_timers.throttle.in.expires_from_now(duration, ec); + m_state.timers.throttle.in.wait_expire = true; + m_timers.throttle.in.async_wait([this, self](const ec_t &ec){ + std::lock_guard guard(m_state.lock); + m_state.timers.throttle.in.wait_expire = false; + if (m_state.timers.throttle.in.cancel_expire) { + m_state.timers.throttle.in.cancel_expire = false; + state_status_check(); } else if (ec.value()) interrupt(); @@ -358,28 +363,23 @@ namespace net_utils return; } } - state.socket.wait_read = true; + m_state.socket.wait_read = true; auto on_read = [this, self](const ec_t &ec, size_t bytes_transferred){ - lock_guard_t guard(state.lock); - state.socket.wait_read = false; - if (state.socket.cancel_read) { - state.socket.cancel_read = false; - if (state.status == status_t::RUNNING) - interrupt(); - else if (state.status == status_t::INTERRUPTED) - on_interrupted(); - else if (state.status == status_t::TERMINATING) - on_terminating(); + std::lock_guard guard(m_state.lock); + m_state.socket.wait_read = false; + if (m_state.socket.cancel_read) { + m_state.socket.cancel_read = false; + state_status_check(); } else if (ec.value()) terminate(); else { { - state.stat.in.throttle.handle_trafic_exact(bytes_transferred); - const auto speed = state.stat.in.throttle.get_current_speed(); - context.m_current_speed_down = speed; - context.m_max_speed_down = std::max( - context.m_max_speed_down, + m_state.stat.in.throttle.handle_trafic_exact(bytes_transferred); + const auto speed = m_state.stat.in.throttle.get_current_speed(); + m_conn_context.m_current_speed_down = speed; + m_conn_context.m_max_speed_down = std::max( + m_conn_context.m_max_speed_down, speed ); { @@ -390,24 +390,30 @@ namespace net_utils ).handle_trafic_exact(bytes_transferred); } connection_basic::logger_handle_net_read(bytes_transferred); - context.m_last_recv = time(NULL); - context.m_recv_cnt += bytes_transferred; + m_conn_context.m_last_recv = time(NULL); + m_conn_context.m_recv_cnt += bytes_transferred; start_timer(get_timeout_from_bytes_read(bytes_transferred), true); } - state.socket.handle_read = true; + + // Post handle_recv to a separate `strand_`, distinct from `m_strand` + // which is listening for reads/writes. This avoids a circular dep. + // handle_recv can queue many writes, and `m_strand` will process those + // writes until the connection terminates without deadlocking waiting + // for handle_recv. + m_state.socket.handle_read = true; connection_basic::strand_.post( [this, self, bytes_transferred]{ - bool success = handler.handle_recv( - reinterpret_cast(state.data.read.buffer.data()), + bool success = m_handler.handle_recv( + reinterpret_cast(m_state.data.read.buffer.data()), bytes_transferred ); - lock_guard_t guard(state.lock); - state.socket.handle_read = false; - if (state.status == status_t::INTERRUPTED) + std::lock_guard guard(m_state.lock); + m_state.socket.handle_read = false; + if (m_state.status == status_t::INTERRUPTED) on_interrupted(); - else if (state.status == status_t::TERMINATING) + else if (m_state.status == status_t::TERMINATING) on_terminating(); - else if (not success) + else if (!success) interrupt(); else { start_read(); @@ -416,23 +422,23 @@ namespace net_utils ); } }; - if (not state.ssl.enabled) + if (!m_state.ssl.enabled) connection_basic::socket_.next_layer().async_read_some( boost::asio::buffer( - state.data.read.buffer.data(), - state.data.read.buffer.size() + m_state.data.read.buffer.data(), + m_state.data.read.buffer.size() ), - strand.wrap(on_read) + m_strand.wrap(on_read) ); else - strand.post( + m_strand.post( [this, self, on_read]{ connection_basic::socket_.async_read_some( boost::asio::buffer( - state.data.read.buffer.data(), - state.data.read.buffer.size() + m_state.data.read.buffer.data(), + m_state.data.read.buffer.size() ), - strand.wrap(on_read) + m_strand.wrap(on_read) ); } ); @@ -441,13 +447,14 @@ namespace net_utils template void connection::start_write() { - if (state.timers.throttle.out.wait_expire || state.socket.wait_write || - state.data.write.queue.empty() || - (state.ssl.enabled && not state.ssl.handshaked) - ) + if (m_state.timers.throttle.out.wait_expire || m_state.socket.wait_write || + m_state.data.write.queue.empty() || + (m_state.ssl.enabled && !m_state.ssl.handshaked) + ) { return; + } auto self = connection::shared_from_this(); - if (connection_type != e_connection_type_RPC) { + if (m_connection_type != e_connection_type_RPC) { auto calc_duration = [this]{ CRITICAL_REGION_LOCAL( network_throttle_manager_t::m_lock_get_global_throttle_out @@ -457,7 +464,7 @@ namespace net_utils std::min( network_throttle_manager_t::get_global_throttle_out( ).get_sleep_time_after_tick( - state.data.write.queue.back().size() + m_state.data.write.queue.back().size() ), 1.0 ) @@ -467,19 +474,14 @@ namespace net_utils const auto duration = calc_duration(); if (duration > duration_t{}) { ec_t ec; - timers.throttle.out.expires_from_now(duration, ec); - state.timers.throttle.out.wait_expire = true; - timers.throttle.out.async_wait([this, self](const ec_t &ec){ - lock_guard_t guard(state.lock); - state.timers.throttle.out.wait_expire = false; - if (state.timers.throttle.out.cancel_expire) { - state.timers.throttle.out.cancel_expire = false; - if (state.status == status_t::RUNNING) - interrupt(); - else if (state.status == status_t::INTERRUPTED) - on_interrupted(); - else if (state.status == status_t::TERMINATING) - on_terminating(); + m_timers.throttle.out.expires_from_now(duration, ec); + m_state.timers.throttle.out.wait_expire = true; + m_timers.throttle.out.async_wait([this, self](const ec_t &ec){ + std::lock_guard guard(m_state.lock); + m_state.timers.throttle.out.wait_expire = false; + if (m_state.timers.throttle.out.cancel_expire) { + m_state.timers.throttle.out.cancel_expire = false; + state_status_check(); } else if (ec.value()) interrupt(); @@ -489,31 +491,26 @@ namespace net_utils } } - state.socket.wait_write = true; + m_state.socket.wait_write = true; auto on_write = [this, self](const ec_t &ec, size_t bytes_transferred){ - lock_guard_t guard(state.lock); - state.socket.wait_write = false; - if (state.socket.cancel_write) { - state.socket.cancel_write = false; - state.data.write.queue.clear(); - if (state.status == status_t::RUNNING) - interrupt(); - else if (state.status == status_t::INTERRUPTED) - on_interrupted(); - else if (state.status == status_t::TERMINATING) - on_terminating(); + std::lock_guard guard(m_state.lock); + m_state.socket.wait_write = false; + if (m_state.socket.cancel_write) { + m_state.socket.cancel_write = false; + m_state.data.write.queue.clear(); + state_status_check(); } else if (ec.value()) { - state.data.write.queue.clear(); + m_state.data.write.queue.clear(); interrupt(); } else { { - state.stat.out.throttle.handle_trafic_exact(bytes_transferred); - const auto speed = state.stat.out.throttle.get_current_speed(); - context.m_current_speed_up = speed; - context.m_max_speed_down = std::max( - context.m_max_speed_down, + m_state.stat.out.throttle.handle_trafic_exact(bytes_transferred); + const auto speed = m_state.stat.out.throttle.get_current_speed(); + m_conn_context.m_current_speed_up = speed; + m_conn_context.m_max_speed_down = std::max( + m_conn_context.m_max_speed_down, speed ); { @@ -524,36 +521,36 @@ namespace net_utils ).handle_trafic_exact(bytes_transferred); } connection_basic::logger_handle_net_write(bytes_transferred); - context.m_last_send = time(NULL); - context.m_send_cnt += bytes_transferred; + m_conn_context.m_last_send = time(NULL); + m_conn_context.m_send_cnt += bytes_transferred; start_timer(get_default_timeout(), true); } - assert(bytes_transferred == state.data.write.queue.back().size()); - state.data.write.queue.pop_back(); - state.condition.notify_all(); + assert(bytes_transferred == m_state.data.write.queue.back().size()); + m_state.data.write.queue.pop_back(); + m_state.condition.notify_all(); start_write(); } }; - if (not state.ssl.enabled) + if (!m_state.ssl.enabled) boost::asio::async_write( connection_basic::socket_.next_layer(), boost::asio::buffer( - state.data.write.queue.back().data(), - state.data.write.queue.back().size() + m_state.data.write.queue.back().data(), + m_state.data.write.queue.back().size() ), - strand.wrap(on_write) + m_strand.wrap(on_write) ); else - strand.post( + m_strand.post( [this, self, on_write]{ boost::asio::async_write( connection_basic::socket_, boost::asio::buffer( - state.data.write.queue.back().data(), - state.data.write.queue.back().size() + m_state.data.write.queue.back().data(), + m_state.data.write.queue.back().size() ), - strand.wrap(on_write) + m_strand.wrap(on_write) ); } ); @@ -562,21 +559,29 @@ namespace net_utils template void connection::start_shutdown() { - if (state.socket.wait_shutdown) + if (m_state.socket.wait_shutdown) return; auto self = connection::shared_from_this(); - state.socket.wait_shutdown = true; + m_state.socket.wait_shutdown = true; auto on_shutdown = [this, self](const ec_t &ec){ - lock_guard_t guard(state.lock); - state.socket.wait_shutdown = false; - if (state.socket.cancel_shutdown) { - state.socket.cancel_shutdown = false; - if (state.status == status_t::RUNNING) - interrupt(); - else if (state.status == status_t::INTERRUPTED) - terminate(); - else if (state.status == status_t::TERMINATING) - on_terminating(); + std::lock_guard guard(m_state.lock); + m_state.socket.wait_shutdown = false; + if (m_state.socket.cancel_shutdown) { + m_state.socket.cancel_shutdown = false; + switch (m_state.status) + { + case status_t::RUNNING: + interrupt(); + break; + case status_t::INTERRUPTED: + terminate(); + break; + case status_t::TERMINATING: + on_terminating(); + break; + default: + break; + } } else if (ec.value()) terminate(); @@ -585,10 +590,10 @@ namespace net_utils on_interrupted(); } }; - strand.post( + m_strand.post( [this, self, on_shutdown]{ connection_basic::socket_.async_shutdown( - strand.wrap(on_shutdown) + m_strand.wrap(on_shutdown) ); } ); @@ -599,24 +604,24 @@ namespace net_utils void connection::cancel_socket() { bool wait_socket = false; - if (state.socket.wait_handshake) - wait_socket = state.socket.cancel_handshake = true; - if (state.timers.throttle.in.wait_expire) { - state.timers.throttle.in.cancel_expire = true; + if (m_state.socket.wait_handshake) + wait_socket = m_state.socket.cancel_handshake = true; + if (m_state.timers.throttle.in.wait_expire) { + m_state.timers.throttle.in.cancel_expire = true; ec_t ec; - timers.throttle.in.cancel(ec); + m_timers.throttle.in.cancel(ec); } - if (state.socket.wait_read) - wait_socket = state.socket.cancel_read = true; - if (state.timers.throttle.out.wait_expire) { - state.timers.throttle.out.cancel_expire = true; + if (m_state.socket.wait_read) + wait_socket = m_state.socket.cancel_read = true; + if (m_state.timers.throttle.out.wait_expire) { + m_state.timers.throttle.out.cancel_expire = true; ec_t ec; - timers.throttle.out.cancel(ec); + m_timers.throttle.out.cancel(ec); } - if (state.socket.wait_write) - wait_socket = state.socket.cancel_write = true; - if (state.socket.wait_shutdown) - wait_socket = state.socket.cancel_shutdown = true; + if (m_state.socket.wait_write) + wait_socket = m_state.socket.cancel_write = true; + if (m_state.socket.wait_shutdown) + wait_socket = m_state.socket.cancel_shutdown = true; if (wait_socket) { ec_t ec; connection_basic::socket_.next_layer().cancel(ec); @@ -626,136 +631,139 @@ namespace net_utils template void connection::cancel_handler() { - if (state.protocol.released || state.protocol.wait_release) + if (m_state.protocol.released || m_state.protocol.wait_release) return; - state.protocol.wait_release = true; - state.lock.unlock(); - handler.release_protocol(); - state.lock.lock(); - state.protocol.wait_release = false; - state.protocol.released = true; - if (state.status == status_t::INTERRUPTED) + m_state.protocol.wait_release = true; + m_state.lock.unlock(); + m_handler.release_protocol(); + m_state.lock.lock(); + m_state.protocol.wait_release = false; + m_state.protocol.released = true; + if (m_state.status == status_t::INTERRUPTED) on_interrupted(); - else if (state.status == status_t::TERMINATING) + else if (m_state.status == status_t::TERMINATING) on_terminating(); } template void connection::interrupt() { - if (state.status != status_t::RUNNING) + if (m_state.status != status_t::RUNNING) return; - state.status = status_t::INTERRUPTED; + m_state.status = status_t::INTERRUPTED; cancel_timer(); cancel_socket(); on_interrupted(); - state.condition.notify_all(); + m_state.condition.notify_all(); cancel_handler(); } template void connection::on_interrupted() { - assert(state.status == status_t::INTERRUPTED); - if (state.timers.general.wait_expire) + assert(m_state.status == status_t::INTERRUPTED); + if (m_state.timers.general.wait_expire) return; - if (state.socket.wait_handshake) + if (m_state.socket.wait_handshake) return; - if (state.timers.throttle.in.wait_expire) + if (m_state.timers.throttle.in.wait_expire) return; - if (state.socket.wait_read) + if (m_state.socket.wait_read) return; - if (state.socket.handle_read) + if (m_state.socket.handle_read) return; - if (state.timers.throttle.out.wait_expire) + if (m_state.timers.throttle.out.wait_expire) return; - if (state.socket.wait_write) + if (m_state.socket.wait_write) return; - if (state.socket.wait_shutdown) + if (m_state.socket.wait_shutdown) return; - if (state.protocol.wait_init) + if (m_state.protocol.wait_init) return; - if (state.protocol.wait_callback) + if (m_state.protocol.wait_callback) return; - if (state.protocol.wait_release) + if (m_state.protocol.wait_release) return; - if (state.socket.connected) { - if (not state.ssl.enabled) { + if (m_state.socket.connected) { + if (!m_state.ssl.enabled) { ec_t ec; connection_basic::socket_.next_layer().shutdown( socket_t::shutdown_both, ec ); connection_basic::socket_.next_layer().close(ec); - state.socket.connected = false; - state.status = status_t::WASTED; + m_state.socket.connected = false; + m_state.status = status_t::WASTED; } else start_shutdown(); } else - state.status = status_t::WASTED; + m_state.status = status_t::WASTED; } template void connection::terminate() { - if (state.status != status_t::RUNNING && - state.status != status_t::INTERRUPTED + if (m_state.status != status_t::RUNNING && + m_state.status != status_t::INTERRUPTED ) return; - state.status = status_t::TERMINATING; + m_state.status = status_t::TERMINATING; cancel_timer(); cancel_socket(); on_terminating(); - state.condition.notify_all(); + m_state.condition.notify_all(); cancel_handler(); } template void connection::on_terminating() { - assert(state.status == status_t::TERMINATING); - if (state.timers.general.wait_expire) + assert(m_state.status == status_t::TERMINATING); + if (m_state.timers.general.wait_expire) return; - if (state.socket.wait_handshake) + if (m_state.socket.wait_handshake) return; - if (state.timers.throttle.in.wait_expire) + if (m_state.timers.throttle.in.wait_expire) return; - if (state.socket.wait_read) + if (m_state.socket.wait_read) return; - if (state.socket.handle_read) + if (m_state.socket.handle_read) return; - if (state.timers.throttle.out.wait_expire) + if (m_state.timers.throttle.out.wait_expire) return; - if (state.socket.wait_write) + if (m_state.socket.wait_write) return; - if (state.socket.wait_shutdown) + if (m_state.socket.wait_shutdown) return; - if (state.protocol.wait_init) + if (m_state.protocol.wait_init) return; - if (state.protocol.wait_callback) + if (m_state.protocol.wait_callback) return; - if (state.protocol.wait_release) + if (m_state.protocol.wait_release) return; - if (state.socket.connected) { + if (m_state.socket.connected) { ec_t ec; connection_basic::socket_.next_layer().shutdown( socket_t::shutdown_both, ec ); connection_basic::socket_.next_layer().close(ec); - state.socket.connected = false; + m_state.socket.connected = false; } - state.status = status_t::WASTED; + m_state.status = status_t::WASTED; } template - bool connection::send(byte_slice_t message) + bool connection::send(epee::byte_slice message) { - lock_guard_t guard(state.lock); - if (state.status != status_t::RUNNING || state.socket.wait_handshake) + std::lock_guard guard(m_state.lock); + if (m_state.status != status_t::RUNNING || m_state.socket.wait_handshake) return false; + + // Wait for the write queue to fall below the max. If it doesn't after a + // randomized delay, drop the connection. auto wait_consume = [this] { auto random_delay = []{ using engine = std::mt19937; @@ -770,62 +778,62 @@ namespace net_utils std::uniform_int_distribution<>(5000, 6000)(rng) ); }; - if (state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT) + if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT) return true; - state.data.write.wait_consume = true; - bool success = state.condition.wait_for( - state.lock, + m_state.data.write.wait_consume = true; + bool success = m_state.condition.wait_for( + m_state.lock, random_delay(), [this]{ return ( - state.status != status_t::RUNNING || - state.data.write.queue.size() <= + m_state.status != status_t::RUNNING || + m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT ); } ); - state.data.write.wait_consume = false; - if (not success) { + m_state.data.write.wait_consume = false; + if (!success) { terminate(); return false; } else - return state.status == status_t::RUNNING; + return m_state.status == status_t::RUNNING; }; auto wait_sender = [this] { - state.condition.wait( - state.lock, + m_state.condition.wait( + m_state.lock, [this] { return ( - state.status != status_t::RUNNING || - not state.data.write.wait_consume + m_state.status != status_t::RUNNING || + !m_state.data.write.wait_consume ); } ); - return state.status == status_t::RUNNING; + return m_state.status == status_t::RUNNING; }; - if (not wait_sender()) + if (!wait_sender()) return false; constexpr size_t CHUNK_SIZE = 32 * 1024; - if (connection_type == e_connection_type_RPC || + if (m_connection_type == e_connection_type_RPC || message.size() <= 2 * CHUNK_SIZE ) { - if (not wait_consume()) + if (!wait_consume()) return false; - state.data.write.queue.emplace_front(std::move(message)); + m_state.data.write.queue.emplace_front(std::move(message)); start_write(); } else { while (!message.empty()) { - if (not wait_consume()) + if (!wait_consume()) return false; - state.data.write.queue.emplace_front( + m_state.data.write.queue.emplace_front( message.take_slice(CHUNK_SIZE) ); start_write(); } } - state.condition.notify_all(); + m_state.condition.notify_all(); return true; } @@ -836,10 +844,10 @@ namespace net_utils boost::optional real_remote ) { - unique_lock_t guard(state.lock); - if (state.status != status_t::TERMINATED) + std::unique_lock guard(m_state.lock); + if (m_state.status != status_t::TERMINATED) return false; - if (not real_remote) { + if (!real_remote) { ec_t ec; auto endpoint = connection_basic::socket_.next_layer().remote_endpoint( ec @@ -866,7 +874,7 @@ namespace net_utils auto *filter = static_cast( connection_basic::get_state() ).pfilter; - if (filter and not filter->is_remote_host_allowed(*real_remote)) + if (filter && !filter->is_remote_host_allowed(*real_remote)) return false; ec_t ec; #if !defined(_WIN32) || !defined(__i686) @@ -886,39 +894,39 @@ namespace net_utils if (ec.value()) return false; connection_basic::m_is_multithreaded = is_multithreaded; - context.set_details( + m_conn_context.set_details( boost::uuids::random_generator()(), *real_remote, is_income, connection_basic::m_ssl_support == ssl_support_t::e_ssl_support_enabled ); - host = real_remote->host_str(); + m_host = real_remote->host_str(); try { host_count(1); } catch(...) { /* ignore */ } - local = real_remote->is_loopback() || real_remote->is_local(); - state.ssl.enabled = ( + m_local = real_remote->is_loopback() || real_remote->is_local(); + m_state.ssl.enabled = ( connection_basic::m_ssl_support != ssl_support_t::e_ssl_support_disabled ); - state.ssl.forced = ( + m_state.ssl.forced = ( connection_basic::m_ssl_support == ssl_support_t::e_ssl_support_enabled ); - state.socket.connected = true; - state.status = status_t::RUNNING; + m_state.socket.connected = true; + m_state.status = status_t::RUNNING; start_timer( std::chrono::milliseconds( - local ? NEW_CONNECTION_TIMEOUT_LOCAL : NEW_CONNECTION_TIMEOUT_REMOTE + m_local ? NEW_CONNECTION_TIMEOUT_LOCAL : NEW_CONNECTION_TIMEOUT_REMOTE ) ); - state.protocol.wait_init = true; + m_state.protocol.wait_init = true; guard.unlock(); - handler.after_init_connection(); + m_handler.after_init_connection(); guard.lock(); - state.protocol.wait_init = false; - state.protocol.initialized = true; - if (state.status == status_t::INTERRUPTED) + m_state.protocol.wait_init = false; + m_state.protocol.initialized = true; + if (m_state.status == status_t::INTERRUPTED) on_interrupted(); - else if (state.status == status_t::TERMINATING) + else if (m_state.status == status_t::TERMINATING) on_terminating(); - else if (not is_income || not state.ssl.enabled) + else if (!is_income || !m_state.ssl.enabled) start_read(); else start_handshake(); @@ -949,23 +957,23 @@ namespace net_utils ssl_support_t ssl_support ): connection_basic(std::move(socket), shared_state, ssl_support), - handler(this, *shared_state, context), - connection_type(connection_type), - io_context{GET_IO_SERVICE(connection_basic::socket_)}, - strand{io_context}, - timers{io_context} + m_handler(this, *shared_state, m_conn_context), + m_connection_type(connection_type), + m_io_context{GET_IO_SERVICE(connection_basic::socket_)}, + m_strand{m_io_context}, + m_timers{m_io_context} { } template connection::~connection() noexcept(false) { - lock_guard_t guard(state.lock); - assert(state.status == status_t::TERMINATED || - state.status == status_t::WASTED || - io_context.stopped() + std::lock_guard guard(m_state.lock); + assert(m_state.status == status_t::TERMINATED || + m_state.status == status_t::WASTED || + m_io_context.stopped() ); - if (state.status != status_t::WASTED) + if (m_state.status != status_t::WASTED) return; try { host_count(-1); } catch (...) { /* ignore */ } } @@ -992,9 +1000,9 @@ namespace net_utils template void connection::save_dbg_log() { - lock_guard_t guard(state.lock); - string_t address; - string_t port; + std::lock_guard guard(m_state.lock); + std::string address; + std::string port; ec_t ec; auto endpoint = connection_basic::socket().remote_endpoint(ec); if (ec.value()) { @@ -1006,10 +1014,10 @@ namespace net_utils port = std::to_string(endpoint.port()); } MDEBUG( - " connection type " << std::to_string(connection_type) << + " connection type " << std::to_string(m_connection_type) << " " << connection_basic::socket().local_endpoint().address().to_string() << ":" << connection_basic::socket().local_endpoint().port() << - " <--> " << context.m_remote_address.str() << + " <--> " << m_conn_context.m_remote_address.str() << " (via " << address << ":" << port << ")" ); } @@ -1017,7 +1025,7 @@ namespace net_utils template bool connection::speed_limit_is_enabled() const { - return connection_type != e_connection_type_RPC; + return m_connection_type != e_connection_type_RPC; } template @@ -1041,8 +1049,8 @@ namespace net_utils template bool connection::close() { - lock_guard_t guard(state.lock); - if (state.status != status_t::RUNNING) + std::lock_guard guard(m_state.lock); + if (m_state.status != status_t::RUNNING) return false; terminate(); return true; @@ -1052,11 +1060,11 @@ namespace net_utils bool connection::call_run_once_service_io() { if(connection_basic::m_is_multithreaded) { - if (not io_context.poll_one()) + if (!m_io_context.poll_one()) misc_utils::sleep_no_w(1); } else { - if (!io_context.run_one()) + if (!m_io_context.run_one()) return false; } return true; @@ -1065,18 +1073,18 @@ namespace net_utils template bool connection::request_callback() { - lock_guard_t guard(state.lock); - if (state.status != status_t::RUNNING) + std::lock_guard guard(m_state.lock); + if (m_state.status != status_t::RUNNING) return false; auto self = connection::shared_from_this(); - ++state.protocol.wait_callback; + ++m_state.protocol.wait_callback; connection_basic::strand_.post([this, self]{ - handler.handle_qued_callback(); - lock_guard_t guard(state.lock); - --state.protocol.wait_callback; - if (state.status == status_t::INTERRUPTED) + m_handler.handle_qued_callback(); + std::lock_guard guard(m_state.lock); + --m_state.protocol.wait_callback; + if (m_state.status == status_t::INTERRUPTED) on_interrupted(); - else if (state.status == status_t::TERMINATING) + else if (m_state.status == status_t::TERMINATING) on_terminating(); }); return true; @@ -1085,7 +1093,7 @@ namespace net_utils template typename connection::io_context_t &connection::get_io_service() { - return io_context; + return m_io_context; } template @@ -1093,9 +1101,9 @@ namespace net_utils { try { auto self = connection::shared_from_this(); - lock_guard_t guard(state.lock); + std::lock_guard guard(m_state.lock); this->self = std::move(self); - ++state.protocol.reference_counter; + ++m_state.protocol.reference_counter; return true; } catch (boost::bad_weak_ptr &exception) { @@ -1107,8 +1115,8 @@ namespace net_utils bool connection::release() { connection_ptr self; - lock_guard_t guard(state.lock); - if (not --state.protocol.reference_counter) + std::lock_guard guard(m_state.lock); + if (!(--m_state.protocol.reference_counter)) self = std::move(this->self); return true; } @@ -1116,8 +1124,8 @@ namespace net_utils template void connection::setRpcStation() { - lock_guard_t guard(state.lock); - connection_type = e_connection_type_RPC; + std::lock_guard guard(m_state.lock); + m_connection_type = e_connection_type_RPC; } template diff --git a/contrib/epee/src/net_ssl.cpp b/contrib/epee/src/net_ssl.cpp index 7dda65bb5eb..2d0b7d79112 100644 --- a/contrib/epee/src/net_ssl.cpp +++ b/contrib/epee/src/net_ssl.cpp @@ -553,9 +553,6 @@ bool ssl_options_t::handshake( using ec_t = boost::system::error_code; using timer_t = boost::asio::steady_timer; using strand_t = boost::asio::io_service::strand; - using lock_t = std::mutex; - using lock_guard_t = std::lock_guard; - using condition_t = std::condition_variable_any; using socket_t = boost::asio::ip::tcp::socket; auto &io_context = GET_IO_SERVICE(socket); @@ -565,8 +562,8 @@ bool ssl_options_t::handshake( timer_t deadline(io_context, timeout); struct state_t { - lock_t lock; - condition_t condition; + std::mutex lock; + std::condition_variable_any condition; ec_t result; bool wait_timer; bool wait_handshake; @@ -577,10 +574,10 @@ bool ssl_options_t::handshake( state.wait_timer = true; auto on_timer = [&](const ec_t &ec){ - lock_guard_t guard(state.lock); + std::lock_guard guard(state.lock); state.wait_timer = false; state.condition.notify_all(); - if (not state.cancel_timer) { + if (!state.cancel_timer) { state.cancel_handshake = true; ec_t ec; socket.next_layer().cancel(ec); @@ -589,11 +586,11 @@ bool ssl_options_t::handshake( state.wait_handshake = true; auto on_handshake = [&](const ec_t &ec, size_t bytes_transferred){ - lock_guard_t guard(state.lock); + std::lock_guard guard(state.lock); state.wait_handshake = false; state.condition.notify_all(); state.result = ec; - if (not state.cancel_handshake) { + if (!state.cancel_handshake) { state.cancel_timer = true; ec_t ec; deadline.cancel(ec); @@ -614,15 +611,15 @@ bool ssl_options_t::handshake( while (!io_context.stopped()) { io_context.poll_one(); - lock_guard_t guard(state.lock); + std::lock_guard guard(state.lock); state.condition.wait_for( state.lock, std::chrono::milliseconds(30), [&]{ - return not state.wait_timer and not state.wait_handshake; + return !state.wait_timer && !state.wait_handshake; } ); - if (not state.wait_timer and not state.wait_handshake) + if (!state.wait_timer && !state.wait_handshake) break; } if (state.result.value()) { diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp index d64431edf89..c08a86a5e9d 100644 --- a/tests/unit_tests/epee_boosted_tcp_server.cpp +++ b/tests/unit_tests/epee_boosted_tcp_server.cpp @@ -617,7 +617,7 @@ TEST(boosted_tcp_server, strand_deadlock) void after_init_connection() { unique_lock_t guard(lock); - if (not context.m_is_income) { + if (!context.m_is_income) { guard.unlock(); socket->do_send(byte_slice_t{"."}); } @@ -628,7 +628,7 @@ TEST(boosted_tcp_server, strand_deadlock) bool handle_recv(const char *data, size_t bytes_transferred) { unique_lock_t guard(lock); - if (not context.m_is_income) { + if (!context.m_is_income) { if (context.m_recv_cnt == 1024) { guard.unlock(); socket->do_send(byte_slice_t{"."}); @@ -652,9 +652,9 @@ TEST(boosted_tcp_server, strand_deadlock) void release_protocol() { unique_lock_t guard(lock); - if(not context.m_is_income - and context.m_recv_cnt == 1024 - and context.m_send_cnt == 2 + if(!context.m_is_income + && context.m_recv_cnt == 1024 + && context.m_send_cnt == 2 ) { guard.unlock(); config.notify_success(); From 7a31d25b67dc7aa18f09a68720b1a3ecffaad93a Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 11 Jul 2022 17:43:59 +0000 Subject: [PATCH 054/186] keccak: error out if passed mdlen 100 If we were to call it with 100, it would cause rsiz to be 0, leading to an infinite loop. This is really a pedantic patch, but since there's already a range test, might as well make it better. --- src/crypto/keccak.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c index f098cbdf039..6616d353088 100644 --- a/src/crypto/keccak.c +++ b/src/crypto/keccak.c @@ -123,7 +123,7 @@ void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen) size_t i, rsiz, rsizw; static_assert(HASH_DATA_AREA <= sizeof(temp), "Bad keccak preconditions"); - if (mdlen <= 0 || (mdlen > 100 && sizeof(st) != (size_t)mdlen)) + if (mdlen <= 0 || (mdlen >= 100 && sizeof(st) != (size_t)mdlen)) { local_abort("Bad keccak use"); } From 4d7f6f5cd51c0c02ab00c4f652015331e69ea1e0 Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Sat, 28 May 2022 13:09:07 -0500 Subject: [PATCH 055/186] GCC: fix some unused warnings hash_extra: don't test for success in `jh_hash` and `skein_hash` since its guaranteed device_ledger: move anonymous global variable apdu_verbose into .cpp file Add comments to `refreshed` method variable in wallet2 --- src/crypto/hash-extra-jh.c | 6 ++++-- src/crypto/hash-extra-skein.c | 6 ++++-- src/device/device_ledger.cpp | 4 ++++ src/device/device_ledger.hpp | 4 ---- src/wallet/wallet2.cpp | 4 ++++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/crypto/hash-extra-jh.c b/src/crypto/hash-extra-jh.c index 4d7481c07a3..52efd4ae3f3 100644 --- a/src/crypto/hash-extra-jh.c +++ b/src/crypto/hash-extra-jh.c @@ -36,7 +36,9 @@ #include "jh.h" #include "hash-ops.h" +#define JH_HASH_BITLEN HASH_SIZE * 8 + void hash_extra_jh(const void *data, size_t length, char *hash) { - int r = jh_hash(HASH_SIZE * 8, data, 8 * length, (uint8_t*)hash); - assert(SUCCESS == r); + // No need to check for failure b/c jh_hash only fails for invalid hash size + jh_hash(JH_HASH_BITLEN, data, 8 * length, (uint8_t*)hash); } diff --git a/src/crypto/hash-extra-skein.c b/src/crypto/hash-extra-skein.c index 9ea9c4faad0..3eacaba5840 100644 --- a/src/crypto/hash-extra-skein.c +++ b/src/crypto/hash-extra-skein.c @@ -34,7 +34,9 @@ #include "hash-ops.h" #include "skein.h" +#define SKEIN_HASH_BITLEN HASH_SIZE * 8 + void hash_extra_skein(const void *data, size_t length, char *hash) { - int r = skein_hash(8 * HASH_SIZE, data, 8 * length, (uint8_t*)hash); - assert(SKEIN_SUCCESS == r); + // No need to check for failure b/c skein_hash only fails for invalid hash size + skein_hash(SKEIN_HASH_BITLEN, data, 8 * length, (uint8_t*)hash); } diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index 51e65dfa53a..bfc756f2197 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -43,6 +43,10 @@ namespace hw { #ifdef WITH_DEVICE_LEDGER + namespace { + bool apdu_verbose =true; + } + #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger" diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp index 074bfaa8dcc..ce0820927af 100644 --- a/src/device/device_ledger.hpp +++ b/src/device/device_ledger.hpp @@ -87,10 +87,6 @@ namespace hw { #define SW_PROTOCOL_NOT_SUPPORTED 0x6e00 #define SW_UNKNOWN 0x6f00 - namespace { - bool apdu_verbose =true; - } - void set_apdu_verbose(bool verbose); class ABPkeys { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b2a6c0f5a2..c218d071c17 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3418,6 +3418,10 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo uint64_t blocks_start_height; std::vector blocks; std::vector parsed_blocks; + // TODO moneromooo-monero says this about the "refreshed" variable: + // "I had to reorder some code to fix... a timing info leak IIRC. In turn, this undid something I had fixed before, ... a subtle race condition with the txpool. + // It was pretty subtle IIRC, and so I needed time to think about how to refix it after the move, and I never got to it." + // https://github.com/monero-project/monero/pull/6097 bool refreshed = false; std::shared_ptr, size_t>> output_tracker_cache; hw::device &hwdev = m_account.get_device(); From 0093bc230a204deee8599c4993330ffb6649b320 Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Mon, 16 May 2022 01:05:28 -0500 Subject: [PATCH 056/186] Focus Doxygen documentation Right now Doxygen is documenting everything in the repo including submodules, everything in contrib, util, tests, etc. This bogs down the documentation to the point where it is very hard to navigate. I think it would be a good move to focus on documenting only the main C++ code which is specific to this repo. Right now this means documenting `src/` (without SUPERCOP), `contrib/epee/`, `external/easylogging++`. After this commit, Doxygen went from running >6000 graphs to about 2200 graphs. --- Doxyfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index 81b2009865b..9ce0d2247f1 100644 --- a/Doxyfile +++ b/Doxyfile @@ -754,7 +754,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = . +INPUT = contrib/epee external/easylogging++ src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -805,7 +805,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = */build/* */contrib/depends/* +EXCLUDE_PATTERNS = */src/crypto/crypto_ops_builder/ref10* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the From edcc094558779a25811f2736beca97d78a26bff5 Mon Sep 17 00:00:00 2001 From: koe Date: Sat, 30 Apr 2022 16:54:24 -0500 Subject: [PATCH 057/186] derive multisig tx secret keys from an entropy source plus the tx inputs' key images --- src/cryptonote_config.h | 2 + src/multisig/multisig_tx_builder_ringct.cpp | 142 ++++++++++++++++++-- src/multisig/multisig_tx_builder_ringct.h | 1 + src/wallet/wallet2.cpp | 4 + src/wallet/wallet2.h | 8 ++ tests/core_tests/multisig.cpp | 5 +- 6 files changed, 147 insertions(+), 15 deletions(-) diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 962346017c3..2ec194ef865 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -246,6 +246,8 @@ namespace config const unsigned char HASH_KEY_CLSAG_AGG_1[] = "CLSAG_agg_1"; const char HASH_KEY_MESSAGE_SIGNING[] = "MoneroMessageSignature"; const unsigned char HASH_KEY_MM_SLOT = 'm'; + const constexpr char HASH_KEY_MULTISIG_TX_PRIVKEYS_SEED[] = "multisig_tx_privkeys_seed"; + const constexpr char HASH_KEY_MULTISIG_TX_PRIVKEYS[] = "multisig_tx_privkeys"; // Multisig const uint32_t MULTISIG_MAX_SIGNERS{16}; diff --git a/src/multisig/multisig_tx_builder_ringct.cpp b/src/multisig/multisig_tx_builder_ringct.cpp index cbc556b71bc..e5c9ac48324 100644 --- a/src/multisig/multisig_tx_builder_ringct.cpp +++ b/src/multisig/multisig_tx_builder_ringct.cpp @@ -34,6 +34,7 @@ #include "cryptonote_basic/cryptonote_basic.h" #include "cryptonote_basic/account.h" #include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_config.h" #include "cryptonote_core/cryptonote_tx_utils.h" #include "device/device.hpp" #include "multisig_clsag_context.h" @@ -47,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -242,6 +244,80 @@ static bool set_tx_extra( } //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- +static void make_tx_secret_key_seed(const crypto::secret_key& tx_secret_key_entropy, + const std::vector& sources, + crypto::secret_key& tx_secret_key_seed) +{ + // seed = H(H("domain separator"), entropy, {KI}) + static const std::string domain_separator{config::HASH_KEY_MULTISIG_TX_PRIVKEYS_SEED}; + + rct::keyV hash_context; + hash_context.reserve(2 + sources.size()); + auto hash_context_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(hash_context.data(), hash_context.size()); + }); + hash_context.emplace_back(); + rct::cn_fast_hash(hash_context.back(), domain_separator.data(), domain_separator.size()); //domain sep + hash_context.emplace_back(rct::sk2rct(tx_secret_key_entropy)); //entropy + + for (const cryptonote::tx_source_entry& source : sources) + hash_context.emplace_back(source.multisig_kLRki.ki); //{KI} + + // set the seed + tx_secret_key_seed = rct::rct2sk(rct::cn_fast_hash(hash_context)); +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static void make_tx_secret_keys(const crypto::secret_key& tx_secret_key_seed, + const std::size_t num_tx_keys, + std::vector& tx_secret_keys) +{ + // make tx secret keys as a hash chain of the seed + // h1 = H_n(seed || H("domain separator")) + // h2 = H_n(seed || h1) + // h3 = H_n(seed || h2) + // ... + static const std::string domain_separator{config::HASH_KEY_MULTISIG_TX_PRIVKEYS}; + + rct::keyV hash_context; + hash_context.resize(2); + auto hash_context_wiper = epee::misc_utils::create_scope_leave_handler([&]{ + memwipe(hash_context.data(), hash_context.size()); + }); + hash_context[0] = rct::sk2rct(tx_secret_key_seed); + rct::cn_fast_hash(hash_context[1], domain_separator.data(), domain_separator.size()); + + tx_secret_keys.clear(); + tx_secret_keys.resize(num_tx_keys); + + for (crypto::secret_key& tx_secret_key : tx_secret_keys) + { + // advance the hash chain + hash_context[1] = rct::hash_to_scalar(hash_context); + + // set this key + tx_secret_key = rct::rct2sk(hash_context[1]); + } +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +static bool collect_tx_secret_keys(const std::vector& tx_secret_keys, + crypto::secret_key& tx_secret_key, + std::vector& tx_aux_secret_keys) +{ + if (tx_secret_keys.size() == 0) + return false; + + tx_secret_key = tx_secret_keys[0]; + tx_aux_secret_keys.clear(); + tx_aux_secret_keys.reserve(tx_secret_keys.size() - 1); + for (std::size_t tx_key_index{1}; tx_key_index < tx_secret_keys.size(); ++tx_key_index) + tx_aux_secret_keys.emplace_back(tx_secret_keys[tx_key_index]); + + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- static bool compute_keys_for_destinations( const cryptonote::account_keys& account_keys, const std::uint32_t subaddr_account, @@ -250,6 +326,7 @@ static bool compute_keys_for_destinations( const std::vector& extra, const bool use_view_tags, const bool reconstruction, + const crypto::secret_key& tx_secret_key_seed, crypto::secret_key& tx_secret_key, std::vector& tx_aux_secret_keys, rct::keyV& output_public_keys, @@ -288,8 +365,35 @@ static bool compute_keys_for_destinations( unique_std_recipients.insert(dst_entr.addr); } - if (not reconstruction) { - tx_secret_key = rct::rct2sk(rct::skGen()); + // figure out how many tx secret keys are needed + // - tx aux keys: add if there are > 1 non-change recipients, with at least one to a subaddress + const std::size_t num_destinations = destinations.size(); + const bool need_tx_aux_keys = unique_subbaddr_recipients.size() + bool(unique_std_recipients.size()) > 1; + + const std::size_t num_tx_keys = 1 + (need_tx_aux_keys ? num_destinations : 0); + + // make tx secret keys + std::vector all_tx_secret_keys; + make_tx_secret_keys(tx_secret_key_seed, num_tx_keys, all_tx_secret_keys); + + // split up tx secret keys + crypto::secret_key tx_secret_key_temp; + std::vector tx_aux_secret_keys_temp; + if (not collect_tx_secret_keys(all_tx_secret_keys, tx_secret_key_temp, tx_aux_secret_keys_temp)) + return false; + + if (reconstruction) + { + // when reconstructing, the tx secret keys should be reproducible from input seed + if (!(tx_secret_key == tx_secret_key_temp)) + return false; + if (!(tx_aux_secret_keys == tx_aux_secret_keys_temp)) + return false; + } + else + { + tx_secret_key = tx_secret_key_temp; + tx_aux_secret_keys = std::move(tx_aux_secret_keys_temp); } // tx pub key: R @@ -312,17 +416,6 @@ static bool compute_keys_for_destinations( } // additional tx pubkeys: R_t - // - add if there are > 1 non-change recipients, with at least one to a subaddress - const std::size_t num_destinations = destinations.size(); - - const bool need_tx_aux_keys = unique_subbaddr_recipients.size() + bool(unique_std_recipients.size()) > 1; - if (not reconstruction and need_tx_aux_keys) { - tx_aux_secret_keys.clear(); - tx_aux_secret_keys.reserve(num_destinations); - for(std::size_t i = 0; i < num_destinations; ++i) - tx_aux_secret_keys.push_back(rct::rct2sk(rct::skGen())); - } - output_public_keys.resize(num_destinations); view_tags.resize(num_destinations); std::vector tx_aux_public_keys; @@ -738,6 +831,7 @@ bool tx_builder_ringct_t::init( const bool reconstruction, crypto::secret_key& tx_secret_key, std::vector& tx_aux_secret_keys, + crypto::secret_key& tx_secret_key_entropy, cryptonote::transaction& unsigned_tx ) { @@ -765,6 +859,23 @@ bool tx_builder_ringct_t::init( // sort inputs sort_sources(sources); + // prepare tx secret key seed (must be AFTER sorting sources) + // - deriving the seed from sources plus entropy ensures uniqueness for every new tx attempt + // - the goal is that two multisig txs added to the chain will never have outputs with the same onetime addresses, + // which would burn funds (embedding the inputs' key images guarantees this) + // - it is acceptable if two tx attempts use the same input set and entropy (only a malicious tx proposer will do + // that, but all it can accomplish is leaking information about the recipients - which a malicious proposer can + // easily do outside the signing ritual anyway) + if (not reconstruction) + tx_secret_key_entropy = rct::rct2sk(rct::skGen()); + + // expect not null (note: wallet serialization code may set this to null if handling an old partial tx) + if (tx_secret_key_entropy == crypto::null_skey) + return false; + + crypto::secret_key tx_secret_key_seed; + make_tx_secret_key_seed(tx_secret_key_entropy, sources, tx_secret_key_seed); + // get secret keys for signing input CLSAGs (multisig: or for the initial partial signature) rct::keyV input_secret_keys; auto input_secret_keys_wiper = epee::misc_utils::create_scope_leave_handler([&]{ @@ -791,6 +902,7 @@ bool tx_builder_ringct_t::init( extra, use_view_tags, reconstruction, + tx_secret_key_seed, tx_secret_key, tx_aux_secret_keys, output_public_keys, @@ -921,6 +1033,7 @@ bool tx_builder_ringct_t::finalize_tx( cryptonote::transaction& unsigned_tx ) { + // checks const std::size_t num_sources = sources.size(); if (num_sources != unsigned_tx.rct_signatures.p.CLSAGs.size()) return false; @@ -928,6 +1041,8 @@ bool tx_builder_ringct_t::finalize_tx( return false; if (num_sources != s.size()) return false; + + // finalize tx signatures for (std::size_t i = 0; i < num_sources; ++i) { const std::size_t ring_size = unsigned_tx.rct_signatures.p.CLSAGs[i].s.size(); if (sources[i].real_output >= ring_size) @@ -935,6 +1050,7 @@ bool tx_builder_ringct_t::finalize_tx( unsigned_tx.rct_signatures.p.CLSAGs[i].s[sources[i].real_output] = s[i]; unsigned_tx.rct_signatures.p.CLSAGs[i].c1 = c_0[i]; } + return true; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/multisig/multisig_tx_builder_ringct.h b/src/multisig/multisig_tx_builder_ringct.h index 67ef9e065dd..853934659d7 100644 --- a/src/multisig/multisig_tx_builder_ringct.h +++ b/src/multisig/multisig_tx_builder_ringct.h @@ -82,6 +82,7 @@ class tx_builder_ringct_t final { const bool reconstruction, crypto::secret_key& tx_secret_key, std::vector& tx_aux_secret_keys, + crypto::secret_key& tx_secret_key_entropy, cryptonote::transaction& unsigned_tx ); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ed153d681c2..ca6670143f6 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -7157,6 +7157,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector additional_tx_keys; + crypto::secret_key multisig_tx_key_entropy; LOG_PRINT_L2("constructing tx"); auto sources_copy = sources; multisig::signing::tx_builder_ringct_t multisig_tx_builder; @@ -9029,6 +9031,7 @@ void wallet2::transfer_selected_rct(std::vector additional_tx_keys; std::vector dests; std::vector multisig_sigs; + crypto::secret_key multisig_tx_key_entropy; tx_construction_data construction_data; BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(1) FIELD(tx) FIELD(dust) FIELD(fee) @@ -648,6 +650,12 @@ namespace tools FIELD(dests) FIELD(construction_data) FIELD(multisig_sigs) + if (version < 1) + { + multisig_tx_key_entropy = crypto::null_skey; + return true; + } + FIELD(multisig_tx_key_entropy) END_SERIALIZE() }; diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp index 28d176e5687..28b44d293f2 100644 --- a/tests/core_tests/multisig.cpp +++ b/tests/core_tests/multisig.cpp @@ -307,9 +307,10 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector additional_tx_secret_keys; + crypto::secret_key multisig_tx_key_entropy; auto sources_copy = sources; multisig::signing::tx_builder_ringct_t tx_builder; - CHECK_AND_ASSERT_MES(tx_builder.init(miner_account[creator].get_keys(), {}, 0, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, false, tx_key, additional_tx_secret_keys, tx), false, "error: multisig::signing::tx_builder_t::init"); + CHECK_AND_ASSERT_MES(tx_builder.init(miner_account[creator].get_keys(), {}, 0, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, false, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init"); // work out the permutation done on sources std::vector ins_order; @@ -398,7 +399,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector Date: Wed, 6 Jul 2022 23:49:21 +0200 Subject: [PATCH 058/186] build: prepare v0.18.0.0 --- README.md | 12 ++++++------ contrib/gitian/README.md | 2 +- contrib/gitian/gitian-android.yml | 2 +- contrib/gitian/gitian-freebsd.yml | 2 +- contrib/gitian/gitian-linux.yml | 2 +- contrib/gitian/gitian-osx.yml | 2 +- contrib/gitian/gitian-win.yml | 2 +- src/blocks/checkpoints.dat | Bin 272772 -> 332676 bytes src/checkpoints/checkpoints.cpp | 1 + src/cryptonote_core/blockchain.cpp | 2 +- src/version.cpp.in | 4 ++-- 11 files changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a2c2788734a..5153d523ed0 100644 --- a/README.md +++ b/README.md @@ -138,8 +138,8 @@ Dates are provided in the format YYYY-MM-DD. | 1978433 | 2019-11-30 | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs | 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.3.2 | New CLSAG transaction format | 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.3.2 | forbid old MLSAG transaction format -| 2668888 | 2022-07-16 | v15 | v0.18.0.0 | v0.18.0.0 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm -| 2669608 | 2022-07-17 | v16 | v0.18.0.0 | v0.18.0.0 | forbid old v14 transaction format +| 2688888 | 2022-08-13 | v15 | v0.18.0.0 | v0.18.0.0 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm +| 2689608 | 2022-08-14 | v16 | v0.18.0.0 | v0.18.0.0 | forbid old v14 transaction format | XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX | X's indicate that these details have not been determined as of commit date. @@ -266,7 +266,7 @@ invokes cmake commands as needed. ```bash cd monero - git checkout release-v0.17 + git checkout release-v0.18 make ``` @@ -345,7 +345,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch ( ```bash git clone https://github.com/monero-project/monero.git cd monero - git checkout v0.17.3.2 + git checkout v0.18.0.0 ``` * Build: @@ -464,10 +464,10 @@ application. cd monero ``` -* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.3.2'. If you don't care about the version and just want binaries from master, skip this step: +* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.18.0.0'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.17.3.2 + git checkout v0.18.0.0 ``` * If you are on a 64-bit system, run: diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md index 24cf26fa37a..5211b84094e 100644 --- a/contrib/gitian/README.md +++ b/contrib/gitian/README.md @@ -133,7 +133,7 @@ Common setup part: su - gitianuser GH_USER=YOUR_GITHUB_USER_NAME -VERSION=v0.17.3.2 +VERSION=v0.18.0.0 ``` Where `GH_USER` is your GitHub user name and `VERSION` is the version tag you want to build. diff --git a/contrib/gitian/gitian-android.yml b/contrib/gitian/gitian-android.yml index 23cb7d0e8a4..7e9ca817828 100644 --- a/contrib/gitian/gitian-android.yml +++ b/contrib/gitian/gitian-android.yml @@ -1,5 +1,5 @@ --- -name: "monero-android-0.17" +name: "monero-android-0.18" enable_cache: true suites: - "bionic" diff --git a/contrib/gitian/gitian-freebsd.yml b/contrib/gitian/gitian-freebsd.yml index 134823b9508..7a17f0750c6 100644 --- a/contrib/gitian/gitian-freebsd.yml +++ b/contrib/gitian/gitian-freebsd.yml @@ -1,5 +1,5 @@ --- -name: "monero-freebsd-0.17" +name: "monero-freebsd-0.18" enable_cache: true suites: - "bionic" diff --git a/contrib/gitian/gitian-linux.yml b/contrib/gitian/gitian-linux.yml index 7ab628fbc59..63d2bc5d2bf 100644 --- a/contrib/gitian/gitian-linux.yml +++ b/contrib/gitian/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "monero-linux-0.17" +name: "monero-linux-0.18" enable_cache: true suites: - "bionic" diff --git a/contrib/gitian/gitian-osx.yml b/contrib/gitian/gitian-osx.yml index b4929e8220c..648688bcd71 100644 --- a/contrib/gitian/gitian-osx.yml +++ b/contrib/gitian/gitian-osx.yml @@ -1,5 +1,5 @@ --- -name: "monero-osx-0.17" +name: "monero-osx-0.18" enable_cache: true suites: - "bionic" diff --git a/contrib/gitian/gitian-win.yml b/contrib/gitian/gitian-win.yml index 7d5a249c8f3..4c607898eb5 100644 --- a/contrib/gitian/gitian-win.yml +++ b/contrib/gitian/gitian-win.yml @@ -1,5 +1,5 @@ --- -name: "monero-win-0.17" +name: "monero-win-0.18" enable_cache: true suites: - "bionic" diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat index e75e379f2db475ecceb9f693b5b1e24739d589e4..2ed1d630fc7f48eeb4b1be949ae2bbfc8dd383a8 100644 GIT binary patch delta 60401 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 Date: Wed, 13 Jul 2022 22:44:43 -0700 Subject: [PATCH 059/186] Template hash func to fix compiler error on < gcc-6 --- contrib/epee/include/net/enums.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/contrib/epee/include/net/enums.h b/contrib/epee/include/net/enums.h index 8c402da2021..b9e05a3eb56 100644 --- a/contrib/epee/include/net/enums.h +++ b/contrib/epee/include/net/enums.h @@ -64,3 +64,13 @@ namespace net_utils } // net_utils } // epee +namespace std +{ + template<> struct hash + { + std::size_t operator()(const epee::net_utils::zone _z) const + { + return static_cast(_z); + } + }; +} // std From bb955d1a737e6fc6398e5888604c4fa1ff49765e Mon Sep 17 00:00:00 2001 From: Seth For Privacy Date: Mon, 18 Jul 2022 08:32:55 -0400 Subject: [PATCH 060/186] Bump Gitian build instructions to v0.18.0.0 --- contrib/gitian/DOCKRUN.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/gitian/DOCKRUN.md b/contrib/gitian/DOCKRUN.md index 96998b1fe3f..1f19a6eec65 100644 --- a/contrib/gitian/DOCKRUN.md +++ b/contrib/gitian/DOCKRUN.md @@ -57,7 +57,7 @@ The dockrun.sh script will do everything to build the binaries. Just specify the version to build as its only argument, e.g. ```bash -./dockrun.sh v0.17.3.0 +./dockrun.sh v0.18.0.0 ``` The build should run to completion with no errors, and will display the SHA256 checksums @@ -78,7 +78,7 @@ e.g. ```bash # Run build processes with 8 threads -OPT="-j 8" ./dockrun.sh v0.17.3.0 +OPT="-j 8" ./dockrun.sh v0.18.0.0 ``` Post-build @@ -98,16 +98,16 @@ more builder/var/install-linux.log more builder/var/build-linux.log ``` -You can find the compiled archives inside of the container at the following directory (be sure to replace `v0.17.3.0` with the version being built): +You can find the compiled archives inside of the container at the following directory (be sure to replace `v0.18.0.0` with the version being built): ```bash docker exec -it gitrun /bin/bash -ls -la out/v0.17.3.0/ +ls -la out/v0.18.0.0/ ``` -To copy the compiled archives to the local host out of the Docker container, you can run the following (be sure to replace `v0.17.3.0` with the version being built): +To copy the compiled archives to the local host out of the Docker container, you can run the following (be sure to replace `v0.18.0.0` with the version being built): ```bash mkdir out -docker cp gitrun:/home/ubuntu/out/v0.17.3.0 out +docker cp gitrun:/home/ubuntu/out/v0.18.0.0 out ``` From b83874e9bdba564e8f2262ba4e87d2f8d728c5ed Mon Sep 17 00:00:00 2001 From: Seth For Privacy Date: Mon, 18 Jul 2022 10:14:44 -0400 Subject: [PATCH 061/186] Set version in ENV var --- contrib/gitian/DOCKRUN.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contrib/gitian/DOCKRUN.md b/contrib/gitian/DOCKRUN.md index 1f19a6eec65..8ea2779400b 100644 --- a/contrib/gitian/DOCKRUN.md +++ b/contrib/gitian/DOCKRUN.md @@ -41,6 +41,7 @@ set your GitHub account name for the script to use: ```bash export GH_USER= +export VERSION=v0.18.0.0 ``` * PGP keys - if you don't have one already, you can use `gpg --quick-gen-key` to generate it. @@ -57,7 +58,7 @@ The dockrun.sh script will do everything to build the binaries. Just specify the version to build as its only argument, e.g. ```bash -./dockrun.sh v0.18.0.0 +./dockrun.sh $VERSION ``` The build should run to completion with no errors, and will display the SHA256 checksums @@ -78,7 +79,7 @@ e.g. ```bash # Run build processes with 8 threads -OPT="-j 8" ./dockrun.sh v0.18.0.0 +OPT="-j 8" ./dockrun.sh $VERSION ``` Post-build @@ -98,16 +99,16 @@ more builder/var/install-linux.log more builder/var/build-linux.log ``` -You can find the compiled archives inside of the container at the following directory (be sure to replace `v0.18.0.0` with the version being built): +You can find the compiled archives inside of the container at the following directory: ```bash docker exec -it gitrun /bin/bash -ls -la out/v0.18.0.0/ +ls -la out/$VERSION/ ``` -To copy the compiled archives to the local host out of the Docker container, you can run the following (be sure to replace `v0.18.0.0` with the version being built): +To copy the compiled archives to the local host out of the Docker container, you can run the following: ```bash mkdir out -docker cp gitrun:/home/ubuntu/out/v0.18.0.0 out +docker cp gitrun:/home/ubuntu/out/$VERSION out ``` From 89a2df67cd8b345d0e00e3fdf6b18a8af6abf877 Mon Sep 17 00:00:00 2001 From: Seth For Privacy Date: Mon, 18 Jul 2022 10:32:54 -0400 Subject: [PATCH 062/186] Migrate VERSION variable to non-export --- contrib/gitian/DOCKRUN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/gitian/DOCKRUN.md b/contrib/gitian/DOCKRUN.md index 8ea2779400b..4d48e02dbcc 100644 --- a/contrib/gitian/DOCKRUN.md +++ b/contrib/gitian/DOCKRUN.md @@ -41,7 +41,6 @@ set your GitHub account name for the script to use: ```bash export GH_USER= -export VERSION=v0.18.0.0 ``` * PGP keys - if you don't have one already, you can use `gpg --quick-gen-key` to generate it. @@ -58,6 +57,7 @@ The dockrun.sh script will do everything to build the binaries. Just specify the version to build as its only argument, e.g. ```bash +VERSION=v0.18.0.0 ./dockrun.sh $VERSION ``` From 308e3fa302008313df1555dd6c1807499b9a426c Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Mon, 18 Jul 2022 12:55:43 -0500 Subject: [PATCH 063/186] gpg_keys: add jeffro256 key --- utils/gpg_keys/jeffro256.asc | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 utils/gpg_keys/jeffro256.asc diff --git a/utils/gpg_keys/jeffro256.asc b/utils/gpg_keys/jeffro256.asc new file mode 100644 index 00000000000..b99e8dbeef4 --- /dev/null +++ b/utils/gpg_keys/jeffro256.asc @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +ZeTE2atjLCrJcplAywUoeF0sGp0FmOfgzDY= +=zEHW +-----END PGP PUBLIC KEY BLOCK----- From 4a4936b8af99ba8b64f8fba81c49f49ddc25ac88 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 7 Jun 2022 20:27:11 +0100 Subject: [PATCH 064/186] Fix use of rtxn without a mdb_txn_safe wrapper --- src/blockchain_db/blockchain_db.h | 16 +++--- src/blockchain_db/lmdb/db_lmdb.cpp | 86 ++++++++++++++++-------------- 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 263948fa2a9..a163ef98cc7 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -1883,16 +1883,18 @@ class db_txn_guard } virtual ~db_txn_guard() { - if (active) - stop(); + stop(); } void stop() { - if (readonly) - db->block_rtxn_stop(); - else - db->block_wtxn_stop(); - active = false; + if (active) + { + if (readonly) + db->block_rtxn_stop(); + else + db->block_wtxn_stop(); + active = false; + } } void abort() { diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index e2ac9df0b48..1ae40dbe9fa 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -472,6 +472,32 @@ void mdb_txn_safe::increment_txns(int i) num_active_txns += i; } +#define TXN_PREFIX(flags); \ + mdb_txn_safe auto_txn; \ + mdb_txn_safe* txn_ptr = &auto_txn; \ + if (m_batch_active) \ + txn_ptr = m_write_txn; \ + else \ + { \ + if (auto mdb_res = lmdb_txn_begin(m_env, NULL, flags, auto_txn)) \ + throw0(DB_ERROR(lmdb_error(std::string("Failed to create a transaction for the db in ")+__FUNCTION__+": ", mdb_res).c_str())); \ + } \ + +#define TXN_PREFIX_RDONLY() \ + MDB_txn *m_txn; \ + mdb_txn_cursors *m_cursors; \ + mdb_txn_safe auto_txn; \ + bool my_rtxn = block_rtxn_start(&m_txn, &m_cursors); \ + if (my_rtxn) auto_txn.m_tinfo = m_tinfo.get(); \ + else auto_txn.uncheck() +#define TXN_POSTFIX_RDONLY() + +#define TXN_POSTFIX_SUCCESS() \ + do { \ + if (! m_batch_active) \ + auto_txn.commit(); \ + } while(0) + void lmdb_resized(MDB_env *env, int isactive) { mdb_txn_safe::prevent_new_txns(); @@ -720,21 +746,20 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks, uin } else { - MDB_txn *rtxn; - mdb_txn_cursors *rcurs; - bool my_rtxn = block_rtxn_start(&rtxn, &rcurs); - for (uint64_t block_num = block_start; block_num <= block_stop; ++block_num) { - // we have access to block weight, which will be greater or equal to block size, - // so use this as a proxy. If it's too much off, we might have to check actual size, - // which involves reading more data, so is not really wanted - size_t block_weight = get_block_weight(block_num); - total_block_size += block_weight; - // Track number of blocks being totalled here instead of assuming, in case - // some blocks were to be skipped for being outliers. - ++num_blocks_used; + TXN_PREFIX_RDONLY(); + for (uint64_t block_num = block_start; block_num <= block_stop; ++block_num) + { + // we have access to block weight, which will be greater or equal to block size, + // so use this as a proxy. If it's too much off, we might have to check actual size, + // which involves reading more data, so is not really wanted + size_t block_weight = get_block_weight(block_num); + total_block_size += block_weight; + // Track number of blocks being totalled here instead of assuming, in case + // some blocks were to be skipped for being outliers. + ++num_blocks_used; + } } - if (my_rtxn) block_rtxn_stop(); avg_block_size = total_block_size / (num_blocks_used ? num_blocks_used : 1); MDEBUG("average block size across recent " << num_blocks_used << " blocks: " << avg_block_size); } @@ -1714,32 +1739,6 @@ void BlockchainLMDB::unlock() check_open(); } -#define TXN_PREFIX(flags); \ - mdb_txn_safe auto_txn; \ - mdb_txn_safe* txn_ptr = &auto_txn; \ - if (m_batch_active) \ - txn_ptr = m_write_txn; \ - else \ - { \ - if (auto mdb_res = lmdb_txn_begin(m_env, NULL, flags, auto_txn)) \ - throw0(DB_ERROR(lmdb_error(std::string("Failed to create a transaction for the db in ")+__FUNCTION__+": ", mdb_res).c_str())); \ - } \ - -#define TXN_PREFIX_RDONLY() \ - MDB_txn *m_txn; \ - mdb_txn_cursors *m_cursors; \ - mdb_txn_safe auto_txn; \ - bool my_rtxn = block_rtxn_start(&m_txn, &m_cursors); \ - if (my_rtxn) auto_txn.m_tinfo = m_tinfo.get(); \ - else auto_txn.uncheck() -#define TXN_POSTFIX_RDONLY() - -#define TXN_POSTFIX_SUCCESS() \ - do { \ - if (! m_batch_active) \ - auto_txn.commit(); \ - } while(0) - // The below two macros are for DB access within block add/remove, whether // regular batch txn is in use or not. m_write_txn is used as a batch txn, even @@ -3959,13 +3958,20 @@ void BlockchainLMDB::block_rtxn_stop() const LOG_PRINT_L3("BlockchainLMDB::" << __func__); mdb_txn_reset(m_tinfo->m_ti_rtxn); memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags)); + /* cancel out the increment from rtxn_start */ + mdb_txn_safe::increment_txns(-1); } bool BlockchainLMDB::block_rtxn_start() const { MDB_txn *mtxn; mdb_txn_cursors *mcur; - return block_rtxn_start(&mtxn, &mcur); + /* auto_txn is only used for the create gate */ + mdb_txn_safe auto_txn; + bool ret = block_rtxn_start(&mtxn, &mcur); + if (ret) + auto_txn.increment_txns(1); /* remember there is an active readtxn */ + return ret; } void BlockchainLMDB::block_wtxn_start() From ac6db928c23310c7472fea540e6d54478c7981c8 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 21 Jul 2022 11:35:35 +0000 Subject: [PATCH 065/186] functional_tests: silence the cpu power test program it's very spammy and drowns the test output --- tests/functional_tests/functional_tests_rpc.py | 2 ++ tests/functional_tests/mining.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py index 450552cf82d..322e74e9559 100755 --- a/tests/functional_tests/functional_tests_rpc.py +++ b/tests/functional_tests/functional_tests_rpc.py @@ -97,6 +97,8 @@ os.environ['MAKE_TEST_SIGNATURE'] = FUNCTIONAL_TESTS_DIRECTORY + '/make_test_signature' os.environ['SEEDHASH_EPOCH_BLOCKS'] = "8" os.environ['SEEDHASH_EPOCH_LAG'] = "4" + if not 'MINING_SILENT' in os.environ: + os.environ['MINING_SILENT'] = "1" for i in range(len(command_lines)): #print('Running: ' + str(command_lines[i])) diff --git a/tests/functional_tests/mining.py b/tests/functional_tests/mining.py index f1aa15c147c..a315ae97fcd 100755 --- a/tests/functional_tests/mining.py +++ b/tests/functional_tests/mining.py @@ -221,7 +221,7 @@ def get_available_ram(self): available_ram = util_resources.available_ram_gb() threshold_ram = 3 self.print_mining_info("Available RAM = " + str(round(available_ram, 1)) + " GB") - if available_ram < threshold_ram: + if available_ram < threshold_ram and not self.is_mining_silent(): print("Warning! Available RAM =", round(available_ram, 1), "GB is less than the reasonable threshold =", threshold_ram, ". The RX init might exceed the calculated timeout.") @@ -255,7 +255,7 @@ def submitblock(self): assert res.hash == block_hash def is_mining_silent(self): - return 'MINING_SILENT' in os.environ + return 'MINING_SILENT' in os.environ and os.environ['MINING_SILENT'] != "0" def print_mining_info(self, msg): if self.is_mining_silent(): From 600de07bcfecc5e31b52257849fa42589167ee51 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 21 Jul 2022 11:36:55 +0000 Subject: [PATCH 066/186] wallet_rpc_server: longer timeout for stop_mining That RPC will wait for mining to actually stop, which can be a while if randomx has just started on randomx_init_dataset. This fixes occasional failures in the mining functional test --- src/wallet/wallet_rpc_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 7ec5fc7a1fd..7a6d39a4350 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -3254,7 +3254,7 @@ namespace tools if (!m_wallet) return not_open(er); cryptonote::COMMAND_RPC_STOP_MINING::request daemon_req; cryptonote::COMMAND_RPC_STOP_MINING::response daemon_res; - bool r = m_wallet->invoke_http_json("/stop_mining", daemon_req, daemon_res); + bool r = m_wallet->invoke_http_json("/stop_mining", daemon_req, daemon_res, std::chrono::seconds(60)); // this waits till stopped, and if randomx has just started initializing its dataset, it might be a while if (!r || daemon_res.status != CORE_RPC_STATUS_OK) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; From 1fc60cac588b9bd5ca113cc79a2a9ef900a92232 Mon Sep 17 00:00:00 2001 From: j-berman Date: Sat, 9 Jul 2022 15:08:06 -0700 Subject: [PATCH 067/186] Publish submitted txs via zmq --- .github/workflows/build.yml | 2 +- src/cryptonote_core/cryptonote_core.cpp | 51 +++++++++++++++++-- src/cryptonote_core/cryptonote_core.h | 7 +++ src/cryptonote_core/tx_pool.cpp | 10 +++- src/cryptonote_core/tx_pool.h | 4 +- tests/README.md | 2 +- tests/functional_tests/CMakeLists.txt | 4 +- .../functional_tests/functional_tests_rpc.py | 4 +- tests/functional_tests/txpool.py | 20 ++++++++ utils/python-rpc/framework/zmq.py | 49 ++++++++++++++++++ 10 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 utils/python-rpc/framework/zmq.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69040d0afe8..ccc4f56fce3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -151,7 +151,7 @@ jobs: - name: install monero dependencies run: ${{env.APT_INSTALL_LINUX}} - name: install Python dependencies - run: pip install requests psutil monotonic + run: pip install requests psutil monotonic zmq - name: tests env: CTEST_OUTPUT_ON_FAILURE: ON diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index a78f5d673f0..95cd1c83b0b 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1406,21 +1406,66 @@ namespace cryptonote return true; } //----------------------------------------------------------------------------------------------- + bool core::notify_txpool_event(const epee::span tx_blobs, epee::span tx_hashes, epee::span txs, const std::vector &just_broadcasted) const + { + if (!m_zmq_pub) + return true; + + if (tx_blobs.size() != tx_hashes.size() || tx_blobs.size() != txs.size() || tx_blobs.size() != just_broadcasted.size()) + return false; + + /* Publish txs via ZMQ that are "just broadcasted" by the daemon. This is + done here in addition to `handle_incoming_txs` in order to guarantee txs + are pub'd via ZMQ when we know the daemon has/will broadcast to other + nodes & *after* the tx is visible in the pool. This should get called + when the user submits a tx to a daemon in the "fluff" epoch relaying txs + via a public network. */ + if (std::count(just_broadcasted.begin(), just_broadcasted.end(), true) == 0) + return true; + + std::vector results{}; + results.resize(tx_blobs.size()); + for (std::size_t i = 0; i < results.size(); ++i) + { + results[i].tx = std::move(txs[i]); + results[i].hash = std::move(tx_hashes[i]); + results[i].blob_size = tx_blobs[i].size(); + results[i].weight = results[i].tx.pruned ? get_pruned_transaction_weight(results[i].tx) : get_transaction_weight(results[i].tx, results[i].blob_size); + results[i].res = just_broadcasted[i]; + } + + m_zmq_pub(std::move(results)); + + return true; + } + //----------------------------------------------------------------------------------------------- void core::on_transactions_relayed(const epee::span tx_blobs, const relay_method tx_relay) { + // lock ensures duplicate txs aren't pub'd via zmq + CRITICAL_REGION_LOCAL(m_incoming_tx_lock); + std::vector tx_hashes{}; tx_hashes.resize(tx_blobs.size()); + std::vector txs{}; + txs.resize(tx_blobs.size()); + for (std::size_t i = 0; i < tx_blobs.size(); ++i) { - cryptonote::transaction tx{}; - if (!parse_and_validate_tx_from_blob(tx_blobs[i], tx, tx_hashes[i])) + if (!parse_and_validate_tx_from_blob(tx_blobs[i], txs[i], tx_hashes[i])) { LOG_ERROR("Failed to parse relayed transaction"); return; } } - m_mempool.set_relayed(epee::to_span(tx_hashes), tx_relay); + + std::vector just_broadcasted{}; + just_broadcasted.reserve(tx_hashes.size()); + + m_mempool.set_relayed(epee::to_span(tx_hashes), tx_relay, just_broadcasted); + + if (m_zmq_pub && matches_category(tx_relay, relay_category::legacy)) + notify_txpool_event(tx_blobs, epee::to_span(tx_hashes), epee::to_span(txs), just_broadcasted); } //----------------------------------------------------------------------------------------------- bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash) diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 0b36730b6ef..5f134a99916 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -1035,6 +1035,13 @@ namespace cryptonote */ bool relay_txpool_transactions(); + /** + * @brief sends notification of txpool events to subscribers + * + * @return true on success, false otherwise + */ + bool notify_txpool_event(const epee::span tx_blobs, epee::span tx_hashes, epee::span txs, const std::vector &just_broadcasted) const; + /** * @brief checks DNS versions * diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index a68da0e62ca..0c18b2a34bc 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -820,8 +820,10 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- - void tx_memory_pool::set_relayed(const epee::span hashes, const relay_method method) + void tx_memory_pool::set_relayed(const epee::span hashes, const relay_method method, std::vector &just_broadcasted) { + just_broadcasted.clear(); + crypto::random_poisson_seconds embargo_duration{dandelionpp_embargo_average}; const auto now = std::chrono::system_clock::now(); uint64_t next_relay = uint64_t{std::numeric_limits::max()}; @@ -831,12 +833,14 @@ namespace cryptonote LockedTXN lock(m_blockchain.get_db()); for (const auto& hash : hashes) { + bool was_just_broadcasted = false; try { txpool_tx_meta_t meta; if (m_blockchain.get_txpool_tx_meta(hash, meta)) { // txes can be received as "stem" or "fluff" in either order + const bool already_broadcasted = meta.matches(relay_category::broadcasted); meta.upgrade_relay_method(method); meta.relayed = true; @@ -849,6 +853,9 @@ namespace cryptonote meta.last_relayed_time = std::chrono::system_clock::to_time_t(now); m_blockchain.update_txpool_tx(hash, meta); + + // wait until db update succeeds to ensure tx is visible in the pool + was_just_broadcasted = !already_broadcasted && meta.matches(relay_category::broadcasted); } } catch (const std::exception &e) @@ -856,6 +863,7 @@ namespace cryptonote MERROR("Failed to update txpool transaction metadata: " << e.what()); // continue } + just_broadcasted.emplace_back(was_just_broadcasted); } lock.commit(); set_if_less(m_next_check, time_t(next_relay)); diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 62bef6c06e2..65c39f87c80 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -353,8 +353,10 @@ namespace cryptonote * * @param hashes list of tx hashes that are about to be relayed * @param tx_relay update how the tx left this node + * @param just_broadcasted true if a tx was just broadcasted + * */ - void set_relayed(epee::span hashes, relay_method tx_relay); + void set_relayed(epee::span hashes, relay_method tx_relay, std::vector &just_broadcasted); /** * @brief get the total number of transactions in the pool diff --git a/tests/README.md b/tests/README.md index 908482c99f7..c63294e9b4a 100644 --- a/tests/README.md +++ b/tests/README.md @@ -54,7 +54,7 @@ Functional tests are located under the `tests/functional_tests` directory. Building all the tests requires installing the following dependencies: ```bash -pip install requests psutil monotonic +pip install requests psutil monotonic zmq ``` First, run a regtest daemon in the offline mode and with a fixed difficulty: diff --git a/tests/functional_tests/CMakeLists.txt b/tests/functional_tests/CMakeLists.txt index 5511cab1c3b..f7747b515ce 100644 --- a/tests/functional_tests/CMakeLists.txt +++ b/tests/functional_tests/CMakeLists.txt @@ -67,7 +67,7 @@ target_link_libraries(make_test_signature monero_add_minimal_executable(cpu_power_test cpu_power_test.cpp) find_program(PYTHON3_FOUND python3 REQUIRED) -execute_process(COMMAND ${PYTHON3_FOUND} "-c" "import requests; import psutil; import monotonic; print('OK')" OUTPUT_VARIABLE REQUESTS_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process(COMMAND ${PYTHON3_FOUND} "-c" "import requests; import psutil; import monotonic; import zmq; print('OK')" OUTPUT_VARIABLE REQUESTS_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE) if (REQUESTS_OUTPUT STREQUAL "OK") add_test( NAME functional_tests_rpc @@ -76,6 +76,6 @@ if (REQUESTS_OUTPUT STREQUAL "OK") NAME check_missing_rpc_methods COMMAND ${PYTHON3_FOUND} "${CMAKE_CURRENT_SOURCE_DIR}/check_missing_rpc_methods.py" "${CMAKE_SOURCE_DIR}") else() - message(WARNING "functional_tests_rpc and check_missing_rpc_methods skipped, needs the 'requests', 'psutil' and 'monotonic' python modules") + message(WARNING "functional_tests_rpc and check_missing_rpc_methods skipped, needs the 'requests', 'psutil', 'monotonic', and 'zmq' python modules") set(CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} functional_tests_rpc check_missing_rpc_methods) endif() diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py index 450552cf82d..eb8d51f083a 100755 --- a/tests/functional_tests/functional_tests_rpc.py +++ b/tests/functional_tests/functional_tests_rpc.py @@ -47,7 +47,7 @@ FUNCTIONAL_TESTS_DIRECTORY = builddir + "/tests/functional_tests" DIFFICULTY = 10 -monerod_base = [builddir + "/bin/monerod", "--regtest", "--fixed-difficulty", str(DIFFICULTY), "--no-igd", "--p2p-bind-port", "monerod_p2p_port", "--rpc-bind-port", "monerod_rpc_port", "--zmq-rpc-bind-port", "monerod_zmq_port", "--non-interactive", "--disable-dns-checkpoints", "--check-updates", "disabled", "--rpc-ssl", "disabled", "--data-dir", "monerod_data_dir", "--log-level", "1"] +monerod_base = [builddir + "/bin/monerod", "--regtest", "--fixed-difficulty", str(DIFFICULTY), "--no-igd", "--p2p-bind-port", "monerod_p2p_port", "--rpc-bind-port", "monerod_rpc_port", "--zmq-rpc-bind-port", "monerod_zmq_port", "--zmq-pub", "monerod_zmq_pub", "--non-interactive", "--disable-dns-checkpoints", "--check-updates", "disabled", "--rpc-ssl", "disabled", "--data-dir", "monerod_data_dir", "--log-level", "1"] monerod_extra = [ ["--offline"], ["--rpc-payment-address", "44SKxxLQw929wRF6BA9paQ1EWFshNnKhXM3qz6Mo3JGDE2YG3xyzVutMStEicxbQGRfrYvAAYxH6Fe8rnD56EaNwUiqhcwR", "--rpc-payment-difficulty", str(DIFFICULTY), "--rpc-payment-credits", "5000", "--offline"], @@ -69,7 +69,7 @@ ports = [] for i in range(N_MONERODS): - command_lines.append([str(18180+i) if x == "monerod_rpc_port" else str(18280+i) if x == "monerod_p2p_port" else str(18380+i) if x == "monerod_zmq_port" else builddir + "/functional-tests-directory/monerod" + str(i) if x == "monerod_data_dir" else x for x in monerod_base]) + command_lines.append([str(18180+i) if x == "monerod_rpc_port" else str(18280+i) if x == "monerod_p2p_port" else str(18380+i) if x == "monerod_zmq_port" else "tcp://127.0.0.1:" + str(18480+i) if x == "monerod_zmq_pub" else builddir + "/functional-tests-directory/monerod" + str(i) if x == "monerod_data_dir" else x for x in monerod_base]) if i < len(monerod_extra): command_lines[-1] += monerod_extra[i] outputs.append(open(FUNCTIONAL_TESTS_DIRECTORY + '/monerod' + str(i) + '.log', 'a+')) diff --git a/tests/functional_tests/txpool.py b/tests/functional_tests/txpool.py index e92b5a53030..b7f55d04c78 100755 --- a/tests/functional_tests/txpool.py +++ b/tests/functional_tests/txpool.py @@ -35,6 +35,7 @@ from framework.daemon import Daemon from framework.wallet import Wallet +from framework.zmq import Zmq class TransferTest(): def run_test(self): @@ -105,6 +106,10 @@ def check_empty_pool(self): def check_txpool(self): daemon = Daemon() wallet = Wallet() + zmq = Zmq() + + zmq_topic = "json-minimal-txpool_add" + zmq.sub(zmq_topic) res = daemon.get_info() height = res.height @@ -142,6 +147,21 @@ def check_txpool(self): min_bytes = min(min_bytes, x.blob_size) max_bytes = max(max_bytes, x.blob_size) + print('Checking all txs received via zmq') + for i in range(len(txes.keys())): + zmq_event = zmq.recv(zmq_topic) + assert len(zmq_event) == 1 + + zmq_tx = zmq_event[0] + + x = [x for x in res.transactions if x.id_hash == zmq_tx["id"]] + assert len(x) == 1 + + x = x[0] + assert x.blob_size == zmq_tx["blob_size"] + assert x.weight == zmq_tx["weight"] + assert x.fee == zmq_tx["fee"] + res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(txes.keys()) diff --git a/utils/python-rpc/framework/zmq.py b/utils/python-rpc/framework/zmq.py new file mode 100644 index 00000000000..91ab7075654 --- /dev/null +++ b/utils/python-rpc/framework/zmq.py @@ -0,0 +1,49 @@ +# Copyright (c) 2018-2022, The Monero Project + +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Class to subscribe to and receive ZMQ events.""" + +import zmq +import json + +class Zmq(object): + + def __init__(self, protocol='tcp', host='127.0.0.1', port=0, idx=0): + self.host = host + self.port = port + self.socket = zmq.Context().socket(zmq.SUB) + self.socket.connect('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else 18480+idx)) + + def sub(self, topic): + self.socket.setsockopt_string(zmq.SUBSCRIBE, topic) + + def recv(self, topic): + msg = self.socket.recv() + data = msg.decode().split(topic + ":")[1] + return json.loads(data) From 564fa30966324ff6c4e7e4fa3c07421ebdc89f55 Mon Sep 17 00:00:00 2001 From: Jeffrey Ryan Date: Wed, 11 May 2022 13:30:09 -0500 Subject: [PATCH 068/186] DOCS: Rework Portable storage format example @jtgrassie pointed out that the example I provided was colored incorrectly. He also made the good point that the image wasn't easy to review/correct. I reworked the example so that it's text-only. It's easier to review and edit, and reveals the structure better in my opinion. Also this is easier for people who can't distinguish colors as easily. Make sure to double-check this work because there's a decent chance I screwed up the comments. The actual byte data was generated and should be solid. --- docs/PORTABLE_STORAGE.md | 48 +++++++++++++++++++++++-- docs/images/storage_binary_example.png | Bin 538682 -> 0 bytes 2 files changed, 45 insertions(+), 3 deletions(-) delete mode 100644 docs/images/storage_binary_example.png diff --git a/docs/PORTABLE_STORAGE.md b/docs/PORTABLE_STORAGE.md index 675ca818c6b..70e7ff954d8 100644 --- a/docs/PORTABLE_STORAGE.md +++ b/docs/PORTABLE_STORAGE.md @@ -158,7 +158,7 @@ that most will be familiar with): ```json { - "short_quote": "Give me liberty or give me death!", + "short_quote": "Give me liberty or give me death", "long_quote": "Monero is more than just a technology. It's also what the technology stands for.", "signed_32bit_int": 20140418, "array_of_bools": [true, false, true, true], @@ -169,9 +169,51 @@ that most will be familiar with): } ``` -This would translate to: +This object would translate into the following bytes when serialized into epee portable storage format. The bytes are represented in hex, with comments and whitespace added for readability. -![Epee binary storage format example](/docs/images/storage_binary_example.png) +``` +01 11 01 01 01 01 02 01 // Signature +01 // Version +14 // Varint number of section entries (5) +0b // Length of next section key (11) +73 68 6f 72 74 5f 71 75 6f 74 65 // Section key ("short_quote") +0a // Type code (STRING) +80 // Varint length of string (32) +47 69 76 65 20 6d 65 20 6c 69 62 65 72 74 79 20 // STRING value ("Give me liberty ") +6f 72 20 67 69 76 65 20 6d 65 20 64 65 61 74 68 // STRING value cont. ("or give me death") +0a // Length of next section key (10) +6c 6f 6e 67 5f 71 75 6f 74 65 // Section key ("long_quote") +0a // Type code (STRING) +41 01 // Varint length of string (80). Note it's 2 bytes +4d 6f 6e 65 72 6f 20 69 73 20 6d 6f 72 65 20 74 // STRING value ("Monero is more t") +68 61 6e 20 6a 75 73 74 20 61 20 74 65 63 68 6e // STRING value cont. ("han just a techn") +6f 6c 6f 67 79 2e 20 49 74 27 73 20 61 6c 73 6f // STRING value cont. ("ology. It's also") +20 77 68 61 74 20 74 68 65 20 74 65 63 68 6e 6f // STRING value cont. (" what the techno") +6c 6f 67 79 20 73 74 61 6e 64 73 20 66 6f 72 2e // STRING value cont. ("logy stands for.") +10 // Length of next section key (16) +73 69 67 6e 65 64 5f 33 32 62 69 74 5f 69 6e 74 // Section key ("signed_32bit_int") +02 // type code (INT32) +82 51 33 01 // INT32 value (20140418) +0e // Length of next section key (14) +61 72 72 61 79 5f 6f 66 5f 62 6f 6f 6c 73 // Section key ("array_of_bools") +8b // Type code (BOOL | FLAG_ARRAY) +10 // Varint number of array elements (4) +01 00 01 01 // Array BOOL values [true, false, true, true] +0e // Length of next section key (14) +6e 65 73 74 65 64 5f 73 65 63 74 69 6f 6e // Section key ("nested_section") +0c // Type code (OBJECT) +08 // Varint number of inner section entries (2) +06 // Length of first inner section key (6) +64 6f 75 62 6c 65 // Section key ("double") +09 // Type code (DOUBLE) +9a 99 99 99 99 99 1b c0 // DOUBLE value (-6.9) +12 // Length of second inner section key (18) +75 6e 73 69 67 6e 65 64 5f 36 34 62 69 74 5f 69 // Section key ("unsigned_64bit_i") +6e 74 // Section key cont ("nt") +05 // Type code (UINT64) +c7 71 ac b5 af 98 32 9a // UINT64 value (11111111111111111111) + +``` ## Monero specifics diff --git a/docs/images/storage_binary_example.png b/docs/images/storage_binary_example.png deleted file mode 100644 index 1baa20cc11029b3aa4dc03745679c644698e5f6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 538682 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¨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 z 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