From 17b39ab7bc76c186cdf80cc0776fb1aa51ef212b Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 19 May 2019 03:02:33 +0100 Subject: [PATCH 01/10] Fix #5553 Make sure the tip hash still matches the cached block --- src/cryptonote_core/blockchain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index b4dc6692f..9a970e915 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1369,7 +1369,8 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, // just as we compare it, we'll just use a slightly old template, but // this would be the case anyway if we'd lock, and the change happened // just after the block template was created - if (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address)) && m_btc_nonce == ex_nonce && m_btc_pool_cookie == m_tx_pool.cookie()) { + if (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address)) && m_btc_nonce == ex_nonce + && m_btc_pool_cookie == m_tx_pool.cookie() && m_btc.prev_id == get_tail_id()) { MDEBUG("Using cached template"); m_btc.timestamp = time(NULL); // update timestamp unconditionally b = m_btc; From 502f96011ea1ab19b5a43630692c478977243c6f Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 20 May 2019 10:42:50 +0000 Subject: [PATCH 02/10] unit_tests: make the density test a bit less stringent It's an inherently random test --- tests/unit_tests/output_selection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_tests/output_selection.cpp b/tests/unit_tests/output_selection.cpp index 0094fc765..235b1c809 100644 --- a/tests/unit_tests/output_selection.cpp +++ b/tests/unit_tests/output_selection.cpp @@ -172,7 +172,7 @@ TEST(select_outputs, density) float chain_ratio = count_chain / (float)n_outs; MDEBUG(count_selected << "/" << NPICKS << " outputs selected in blocks of density " << d << ", " << 100.0f * selected_ratio << "%"); MDEBUG(count_chain << "/" << offsets.size() << " outputs in blocks of density " << d << ", " << 100.0f * chain_ratio << "%"); - ASSERT_LT(fabsf(selected_ratio - chain_ratio), 0.02f); + ASSERT_LT(fabsf(selected_ratio - chain_ratio), 0.025f); } } From ae876c7532736c23334cb28b8fe30a67f4787379 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 20 May 2019 13:41:57 +0000 Subject: [PATCH 03/10] functional_tests: fix rare get_output_distribution failure When the wallet auto refreshes after mining the last two blocks but before popping them, it will then try to use outputs which are not unlocked yet. This is really a wallet problem, which will be fixed later. --- tests/functional_tests/get_output_distribution.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/functional_tests/get_output_distribution.py b/tests/functional_tests/get_output_distribution.py index 2a0762d5e..061b8dbe2 100755 --- a/tests/functional_tests/get_output_distribution.py +++ b/tests/functional_tests/get_output_distribution.py @@ -213,5 +213,14 @@ class GetOutputDistributionTest(): assert d.distribution[h] == 0 +class Guard: + def __enter__(self): + for i in range(4): + Wallet(idx = i).auto_refresh(False) + def __exit__(self, exc_type, exc_value, traceback): + for i in range(4): + Wallet(idx = i).auto_refresh(True) + if __name__ == '__main__': - GetOutputDistributionTest().run_test() + with Guard() as guard: + GetOutputDistributionTest().run_test() From 8566d1f9a499f701038002587dc477123cb01ac4 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Tue, 21 May 2019 15:43:27 -0400 Subject: [PATCH 04/10] Fix configuration bug; wallet2 --daemon-ssl-allow-any-cert now works. --- src/wallet/wallet2.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index fd433a6f6..235deffa2 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -399,8 +399,11 @@ std::unique_ptr make_basic(const boost::program_options::variabl { const boost::string_ref real_daemon = boost::string_ref{daemon_address}.substr(0, daemon_address.rfind(':')); + /* If SSL or proxy is enabled, then a specific cert, CA or fingerprint must + be specified. This is specific to the wallet. */ const bool verification_required = - ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || use_proxy; + ssl_options.verification != epee::net_utils::ssl_verification_t::none && + (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || use_proxy); THROW_WALLET_EXCEPTION_IF( verification_required && !ssl_options.has_strong_verification(real_daemon), From 72c2f5c3e6bf9fd9551fd7144d3c55366943800a Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Wed, 22 May 2019 00:09:11 -0400 Subject: [PATCH 05/10] Add ssl_options support to monerod's rpc mode. --- contrib/epee/include/net/net_fwd.h | 38 ++++++++++++ src/common/rpc_client.h | 4 +- src/daemon/command_parser_executor.cpp | 3 +- src/daemon/command_parser_executor.h | 2 + src/daemon/command_server.cpp | 3 +- src/daemon/command_server.h | 2 + src/daemon/daemon.cpp | 3 +- src/daemon/main.cpp | 6 +- src/daemon/rpc_command_executor.cpp | 3 +- src/daemon/rpc_command_executor.h | 2 + src/rpc/core_rpc_server.cpp | 83 +------------------------- src/rpc/rpc_args.cpp | 82 ++++++++++++++++++++++++- src/rpc/rpc_args.h | 18 +++++- src/wallet/wallet_rpc_server.cpp | 51 +--------------- 14 files changed, 160 insertions(+), 140 deletions(-) create mode 100644 contrib/epee/include/net/net_fwd.h diff --git a/contrib/epee/include/net/net_fwd.h b/contrib/epee/include/net/net_fwd.h new file mode 100644 index 000000000..ba4fe6259 --- /dev/null +++ b/contrib/epee/include/net/net_fwd.h @@ -0,0 +1,38 @@ +// Copyright (c) 2019, 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 + +namespace epee +{ + namespace net_utils + { + struct ssl_authentication_t; + class ssl_options_t; + } +} diff --git a/src/common/rpc_client.h b/src/common/rpc_client.h index cb5f79da8..dab3e562d 100644 --- a/src/common/rpc_client.h +++ b/src/common/rpc_client.h @@ -36,6 +36,7 @@ #include "storages/http_abstract_invoke.h" #include "net/http_auth.h" #include "net/http_client.h" +#include "net/net_ssl.h" #include "string_tools.h" namespace tools @@ -49,11 +50,12 @@ namespace tools uint32_t ip , uint16_t port , boost::optional user + , epee::net_utils::ssl_options_t ssl_options ) : m_http_client{} { m_http_client.set_server( - epee::string_tools::get_ip_string_from_int32(ip), std::to_string(port), std::move(user) + epee::string_tools::get_ip_string_from_int32(ip), std::to_string(port), std::move(user), std::move(ssl_options) ); } diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index b431c3a16..a79eac8d8 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -40,10 +40,11 @@ t_command_parser_executor::t_command_parser_executor( uint32_t ip , uint16_t port , const boost::optional& login + , const epee::net_utils::ssl_options_t& ssl_options , bool is_rpc , cryptonote::core_rpc_server* rpc_server ) - : m_executor(ip, port, login, is_rpc, rpc_server) + : m_executor(ip, port, login, ssl_options, is_rpc, rpc_server) {} bool t_command_parser_executor::print_peer_list(const std::vector& args) diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index 098018642..2efd78ec0 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -40,6 +40,7 @@ #include "daemon/rpc_command_executor.h" #include "common/common_fwd.h" +#include "net/net_fwd.h" #include "rpc/core_rpc_server.h" namespace daemonize { @@ -53,6 +54,7 @@ public: uint32_t ip , uint16_t port , const boost::optional& login + , const epee::net_utils::ssl_options_t& ssl_options , bool is_rpc , cryptonote::core_rpc_server* rpc_server = NULL ); diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 6965fe80a..116b2ee92 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -43,10 +43,11 @@ t_command_server::t_command_server( uint32_t ip , uint16_t port , const boost::optional& login + , const epee::net_utils::ssl_options_t& ssl_options , bool is_rpc , cryptonote::core_rpc_server* rpc_server ) - : m_parser(ip, port, login, is_rpc, rpc_server) + : m_parser(ip, port, login, ssl_options, is_rpc, rpc_server) , m_command_lookup() , m_is_rpc(is_rpc) { diff --git a/src/daemon/command_server.h b/src/daemon/command_server.h index c8e77f551..da532223e 100644 --- a/src/daemon/command_server.h +++ b/src/daemon/command_server.h @@ -43,6 +43,7 @@ Passing RPC commands: #include "common/common_fwd.h" #include "console_handler.h" #include "daemon/command_parser_executor.h" +#include "net/net_fwd.h" namespace daemonize { @@ -57,6 +58,7 @@ public: uint32_t ip , uint16_t port , const boost::optional& login + , const epee::net_utils::ssl_options_t& ssl_options , bool is_rpc = true , cryptonote::core_rpc_server* rpc_server = NULL ); diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 531c080de..5084b6283 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -45,6 +45,7 @@ #include "daemon/command_server.h" #include "daemon/command_server.h" #include "daemon/command_line_args.h" +#include "net/net_ssl.h" #include "version.h" using namespace epee; @@ -163,7 +164,7 @@ bool t_daemon::run(bool interactive) if (interactive && mp_internals->rpcs.size()) { // The first three variables are not used when the fourth is false - rpc_commands.reset(new daemonize::t_command_server(0, 0, boost::none, false, mp_internals->rpcs.front()->get_server())); + rpc_commands.reset(new daemonize::t_command_server(0, 0, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_disabled, false, mp_internals->rpcs.front()->get_server())); rpc_commands->start_handling(std::bind(&daemonize::t_daemon::stop_p2p, this)); } diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 2a450ad59..50b8f97f4 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -324,7 +324,11 @@ int main(int argc, char const * argv[]) } } - daemonize::t_command_server rpc_commands{rpc_ip, rpc_port, std::move(login)}; + auto ssl_options = cryptonote::rpc_args::process_ssl(vm, true); + if (!ssl_options) + return 1; + + daemonize::t_command_server rpc_commands{rpc_ip, rpc_port, std::move(login), std::move(*ssl_options)}; if (rpc_commands.process_command_vec(command)) { return 0; diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 466f0d13f..ba02a0c38 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -127,6 +127,7 @@ t_rpc_command_executor::t_rpc_command_executor( uint32_t ip , uint16_t port , const boost::optional& login + , const epee::net_utils::ssl_options_t& ssl_options , bool is_rpc , cryptonote::core_rpc_server* rpc_server ) @@ -137,7 +138,7 @@ t_rpc_command_executor::t_rpc_command_executor( boost::optional http_login{}; if (login) http_login.emplace(login->username, login->password.password()); - m_rpc_client = new tools::t_rpc_client(ip, port, std::move(http_login)); + m_rpc_client = new tools::t_rpc_client(ip, port, std::move(http_login), ssl_options); } else { diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index 3c2686b3f..df2894d09 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -43,6 +43,7 @@ #include "common/common_fwd.h" #include "common/rpc_client.h" #include "cryptonote_basic/cryptonote_basic.h" +#include "net/net_fwd.h" #include "rpc/core_rpc_server.h" #undef MONERO_DEFAULT_LOG_CATEGORY @@ -61,6 +62,7 @@ public: uint32_t ip , uint16_t port , const boost::optional& user + , const epee::net_utils::ssl_options_t& ssl_options , bool is_rpc = true , cryptonote::core_rpc_server* rpc_server = NULL ); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 85cea5573..39083f732 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -90,15 +90,9 @@ namespace cryptonote command_line::add_arg(desc, arg_rpc_bind_port); command_line::add_arg(desc, arg_rpc_restricted_bind_port); command_line::add_arg(desc, arg_restricted_rpc); - command_line::add_arg(desc, arg_rpc_ssl); - command_line::add_arg(desc, arg_rpc_ssl_private_key); - command_line::add_arg(desc, arg_rpc_ssl_certificate); - command_line::add_arg(desc, arg_rpc_ssl_ca_certificates); - command_line::add_arg(desc, arg_rpc_ssl_allowed_fingerprints); - command_line::add_arg(desc, arg_rpc_ssl_allow_any_cert); command_line::add_arg(desc, arg_bootstrap_daemon_address); command_line::add_arg(desc, arg_bootstrap_daemon_login); - cryptonote::rpc_args::init_options(desc); + cryptonote::rpc_args::init_options(desc, true); } //------------------------------------------------------------------------------------------------------------------------------ core_rpc_server::core_rpc_server( @@ -118,7 +112,7 @@ namespace cryptonote m_restricted = restricted; m_net_server.set_threads_prefix("RPC"); - auto rpc_config = cryptonote::rpc_args::process(vm); + auto rpc_config = cryptonote::rpc_args::process(vm, true); if (!rpc_config) return false; @@ -151,46 +145,9 @@ namespace cryptonote if (rpc_config->login) http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password()); - epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect; - if (command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert)) - ssl_options.verification = epee::net_utils::ssl_verification_t::none; - else - { - std::string ssl_ca_path = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates); - const std::vector ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints); - std::vector> ssl_allowed_fingerprints{ ssl_allowed_fingerprint_strings.size() }; - std::transform(ssl_allowed_fingerprint_strings.begin(), ssl_allowed_fingerprint_strings.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector); - for (const auto &fpr: ssl_allowed_fingerprints) - { - if (fpr.size() != SSL_FINGERPRINT_SIZE) - { - MERROR("SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long."); - return false; - } - } - - if (!ssl_ca_path.empty() || !ssl_allowed_fingerprints.empty()) - ssl_options = epee::net_utils::ssl_options_t{std::move(ssl_allowed_fingerprints), std::move(ssl_ca_path)}; - } - - ssl_options.auth = epee::net_utils::ssl_authentication_t{ - command_line::get_arg(vm, arg_rpc_ssl_private_key), command_line::get_arg(vm, arg_rpc_ssl_certificate) - }; - - // user specified CA file or fingeprints implies enabled SSL by default - if (ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl)) - { - const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl); - if (!epee::net_utils::ssl_support_from_string(ssl_options.support, ssl)) - { - MFATAL("Invalid RPC SSL support: " << ssl); - return false; - } - } - auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); }; return epee::http_server_impl_base::init( - rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), std::move(ssl_options) + rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options) ); } //------------------------------------------------------------------------------------------------------------------------------ @@ -2439,40 +2396,6 @@ namespace cryptonote , false }; - const command_line::arg_descriptor core_rpc_server::arg_rpc_ssl = { - "rpc-ssl" - , "Enable SSL on RPC connections: enabled|disabled|autodetect" - , "autodetect" - }; - - const command_line::arg_descriptor core_rpc_server::arg_rpc_ssl_private_key = { - "rpc-ssl-private-key" - , "Path to a PEM format private key" - , "" - }; - - const command_line::arg_descriptor core_rpc_server::arg_rpc_ssl_certificate = { - "rpc-ssl-certificate" - , "Path to a PEM format certificate" - , "" - }; - - const command_line::arg_descriptor core_rpc_server::arg_rpc_ssl_ca_certificates = { - "rpc-ssl-ca-certificates" - , "Path to file containing concatenated PEM format certificate(s) to replace system CA(s)." - }; - - const command_line::arg_descriptor> core_rpc_server::arg_rpc_ssl_allowed_fingerprints = { - "rpc-ssl-allowed-fingerprints" - , "List of certificate fingerprints to allow" - }; - - const command_line::arg_descriptor core_rpc_server::arg_rpc_ssl_allow_any_cert = { - "rpc-ssl-allow-any-cert" - , "Allow any peer certificate" - , false - }; - const command_line::arg_descriptor core_rpc_server::arg_bootstrap_daemon_address = { "bootstrap-daemon-address" , "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced" diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp index f2be94f51..4479bd1f1 100644 --- a/src/rpc/rpc_args.cpp +++ b/src/rpc/rpc_args.cpp @@ -33,28 +33,95 @@ #include #include "common/command_line.h" #include "common/i18n.h" +#include "hex.h" namespace cryptonote { + namespace + { + boost::optional do_process_ssl(const boost::program_options::variables_map& vm, const rpc_args::descriptors& arg, const bool any_cert_option) + { + bool ssl_required = false; + epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled; + if (any_cert_option && command_line::get_arg(vm, arg.rpc_ssl_allow_any_cert)) + ssl_options.verification = epee::net_utils::ssl_verification_t::none; + else + { + std::string ssl_ca_file = command_line::get_arg(vm, arg.rpc_ssl_ca_certificates); + const std::vector ssl_allowed_fingerprints = command_line::get_arg(vm, arg.rpc_ssl_allowed_fingerprints); + + std::vector> allowed_fingerprints{ ssl_allowed_fingerprints.size() }; + std::transform(ssl_allowed_fingerprints.begin(), ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector); + for (const auto &fpr: allowed_fingerprints) + { + if (fpr.size() != SSL_FINGERPRINT_SIZE) + { + MERROR("SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long."); + return boost::none; + } + } + + if (!allowed_fingerprints.empty() || !ssl_ca_file.empty()) + { + ssl_required = true; + ssl_options = epee::net_utils::ssl_options_t{ + std::move(allowed_fingerprints), std::move(ssl_ca_file) + }; + + if (command_line::get_arg(vm, arg.rpc_ssl_allow_chained)) + ssl_options.verification = epee::net_utils::ssl_verification_t::user_ca; + } + } + + // user specified CA file or fingeprints implies enabled SSL by default + if (!ssl_required && !epee::net_utils::ssl_support_from_string(ssl_options.support, command_line::get_arg(vm, arg.rpc_ssl))) + { + MERROR("Invalid argument for " << std::string(arg.rpc_ssl.name)); + return boost::none; + } + + ssl_options.auth = epee::net_utils::ssl_authentication_t{ + command_line::get_arg(vm, arg.rpc_ssl_private_key), command_line::get_arg(vm, arg.rpc_ssl_certificate) + }; + + return {std::move(ssl_options)}; + } + } // anonymous + rpc_args::descriptors::descriptors() : rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"}) , rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true}) , confirm_external_bind({"confirm-external-bind", rpc_args::tr("Confirm rpc-bind-ip value is NOT a loopback (local) IP")}) , rpc_access_control_origins({"rpc-access-control-origins", rpc_args::tr("Specify a comma separated list of origins to allow cross origin resource sharing"), ""}) + , rpc_ssl({"rpc-ssl", rpc_args::tr("Enable SSL on RPC connections: enabled|disabled|autodetect"), "autodetect"}) + , rpc_ssl_private_key({"rpc-ssl-private-key", rpc_args::tr("Path to a PEM format private key"), ""}) + , rpc_ssl_certificate({"rpc-ssl-certificate", rpc_args::tr("Path to a PEM format certificate"), ""}) + , rpc_ssl_ca_certificates({"rpc-ssl-ca-certificates", rpc_args::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s)."), ""}) + , rpc_ssl_allowed_fingerprints({"rpc-ssl-allowed-fingerprints", rpc_args::tr("List of certificate fingerprints to allow")}) + , rpc_ssl_allow_chained({"rpc-ssl-allow-chained", rpc_args::tr("Allow user (via --rpc-ssl-certificates) chain certificates"), false}) + , rpc_ssl_allow_any_cert({"rpc-ssl-allow-any-cert", rpc_args::tr("Allow any peer certificate"), false}) {} const char* rpc_args::tr(const char* str) { return i18n_translate(str, "cryptonote::rpc_args"); } - void rpc_args::init_options(boost::program_options::options_description& desc) + void rpc_args::init_options(boost::program_options::options_description& desc, const bool any_cert_option) { const descriptors arg{}; command_line::add_arg(desc, arg.rpc_bind_ip); command_line::add_arg(desc, arg.rpc_login); command_line::add_arg(desc, arg.confirm_external_bind); command_line::add_arg(desc, arg.rpc_access_control_origins); + command_line::add_arg(desc, arg.rpc_ssl); + command_line::add_arg(desc, arg.rpc_ssl_private_key); + command_line::add_arg(desc, arg.rpc_ssl_certificate); + command_line::add_arg(desc, arg.rpc_ssl_ca_certificates); + command_line::add_arg(desc, arg.rpc_ssl_allowed_fingerprints); + command_line::add_arg(desc, arg.rpc_ssl_allow_chained); + if (any_cert_option) + command_line::add_arg(desc, arg.rpc_ssl_allow_any_cert); } - boost::optional rpc_args::process(const boost::program_options::variables_map& vm) + boost::optional rpc_args::process(const boost::program_options::variables_map& vm, const bool any_cert_option) { const descriptors arg{}; rpc_args config{}; @@ -118,6 +185,17 @@ namespace cryptonote config.access_control_origins = std::move(access_control_origins); } + auto ssl_options = do_process_ssl(vm, arg, any_cert_option); + if (!ssl_options) + return boost::none; + config.ssl_options = std::move(*ssl_options); + return {std::move(config)}; } + + boost::optional rpc_args::process_ssl(const boost::program_options::variables_map& vm, const bool any_cert_option) + { + const descriptors arg{}; + return do_process_ssl(vm, arg, any_cert_option); + } } diff --git a/src/rpc/rpc_args.h b/src/rpc/rpc_args.h index 216ba3712..619f02b42 100644 --- a/src/rpc/rpc_args.h +++ b/src/rpc/rpc_args.h @@ -35,6 +35,7 @@ #include "common/command_line.h" #include "common/password.h" +#include "net/net_ssl.h" namespace cryptonote { @@ -54,16 +55,29 @@ namespace cryptonote const command_line::arg_descriptor rpc_login; const command_line::arg_descriptor confirm_external_bind; const command_line::arg_descriptor rpc_access_control_origins; + const command_line::arg_descriptor rpc_ssl; + const command_line::arg_descriptor rpc_ssl_private_key; + const command_line::arg_descriptor rpc_ssl_certificate; + const command_line::arg_descriptor rpc_ssl_ca_certificates; + const command_line::arg_descriptor> rpc_ssl_allowed_fingerprints; + const command_line::arg_descriptor rpc_ssl_allow_chained; + const command_line::arg_descriptor rpc_ssl_allow_any_cert; }; + // `allow_any_cert` bool toggles `--rpc-ssl-allow-any-cert` configuration + static const char* tr(const char* str); - static void init_options(boost::program_options::options_description& desc); + static void init_options(boost::program_options::options_description& desc, const bool any_cert_option = false); //! \return Arguments specified by user, or `boost::none` if error - static boost::optional process(const boost::program_options::variables_map& vm); + static boost::optional process(const boost::program_options::variables_map& vm, const bool any_cert_option = false); + + //! \return SSL arguments specified by user, or `boost::none` if error + static boost::optional process_ssl(const boost::program_options::variables_map& vm, const bool any_cert_option = false); std::string bind_ip; std::vector access_control_origins; boost::optional login; // currently `boost::none` if unspecified by user + epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled; }; } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 298d72222..5a44e36fa 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -66,11 +66,6 @@ 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_rpc_ssl = {"rpc-ssl", tools::wallet2::tr("Enable SSL on wallet RPC connections: enabled|disabled|autodetect"), "autodetect"}; - const command_line::arg_descriptor arg_rpc_ssl_private_key = {"rpc-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""}; - const command_line::arg_descriptor arg_rpc_ssl_certificate = {"rpc-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""}; - const command_line::arg_descriptor arg_rpc_ssl_ca_certificates = {"rpc-ssl-ca-certificates", tools::wallet2::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s).")}; - const command_line::arg_descriptor> arg_rpc_ssl_allowed_fingerprints = {"rpc-ssl-allowed-fingerprints", tools::wallet2::tr("List of certificate fingerprints to allow")}; constexpr const char default_rpc_username[] = "wownero"; @@ -244,45 +239,6 @@ namespace tools assert(bool(http_login)); } // end auth enabled - auto rpc_ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key); - auto rpc_ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate); - auto rpc_ssl_ca_file = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates); - auto rpc_ssl_allowed_fingerprints = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints); - auto rpc_ssl = command_line::get_arg(vm, arg_rpc_ssl); - epee::net_utils::ssl_options_t rpc_ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled; - - if (!rpc_ssl_ca_file.empty() || !rpc_ssl_allowed_fingerprints.empty()) - { - std::vector> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() }; - std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector); - for (const auto &fpr: allowed_fingerprints) - { - if (fpr.size() != SSL_FINGERPRINT_SIZE) - { - MERROR("SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long."); - return false; - } - } - - rpc_ssl_options = epee::net_utils::ssl_options_t{ - std::move(allowed_fingerprints), std::move(rpc_ssl_ca_file) - }; - } - - // user specified CA file or fingeprints implies enabled SSL by default - if (rpc_ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl)) - { - if (!epee::net_utils::ssl_support_from_string(rpc_ssl_options.support, rpc_ssl)) - { - MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name)); - return false; - } - } - - rpc_ssl_options.auth = epee::net_utils::ssl_authentication_t{ - std::move(rpc_ssl_private_key), std::move(rpc_ssl_certificate) - }; - m_auto_refresh_period = DEFAULT_AUTO_REFRESH_PERIOD; m_last_auto_refresh_time = boost::posix_time::min_date_time; @@ -292,7 +248,7 @@ namespace tools auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); }; return epee::http_server_impl_base::init( rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), - std::move(rpc_ssl_options) + std::move(rpc_config->ssl_options) ); } //------------------------------------------------------------------------------------------------------------------------------ @@ -4412,11 +4368,6 @@ int main(int argc, char** argv) { command_line::add_arg(desc_params, arg_from_json); 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_ssl); - command_line::add_arg(desc_params, arg_rpc_ssl_private_key); - command_line::add_arg(desc_params, arg_rpc_ssl_certificate); - command_line::add_arg(desc_params, arg_rpc_ssl_ca_certificates); - command_line::add_arg(desc_params, arg_rpc_ssl_allowed_fingerprints); daemonizer::init_options(hidden_options, desc_params); desc_params.add(hidden_options); From 07e86b1e85986d8bd8798d29ae17f176dde84690 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Wed, 22 May 2019 00:15:14 -0400 Subject: [PATCH 06/10] Fix allow any cert mode in wallet rpc when configured over rpc --- 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 5a44e36fa..c5e1dc8a9 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -4123,7 +4123,11 @@ namespace tools std::move(req.ssl_private_key_path), std::move(req.ssl_certificate_path) }; - if (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled && !ssl_options.has_strong_verification(boost::string_ref{})) + const bool verification_required = + ssl_options.verification != epee::net_utils::ssl_verification_t::none && + ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled; + + if (verification_required && !ssl_options.has_strong_verification(boost::string_ref{})) { er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION; er.message = "SSL is enabled but no user certificate or fingerprints were provided"; From af1a741699863142f263807cd8bec86493ef24fe Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 24 May 2019 08:33:19 +0000 Subject: [PATCH 07/10] core: do not commit half constructed batch db txn --- src/blockchain_db/blockchain_db.h | 15 +++++++++++++++ src/blockchain_db/testdb.h | 1 + src/cryptonote_core/blockchain.cpp | 28 ++++++++++++++++------------ src/cryptonote_core/blockchain.h | 3 +++ src/cryptonote_core/tx_pool.cpp | 18 ++++++++++++++++-- 5 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 567be6a65..b6b8c6c3e 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -753,6 +753,21 @@ public: */ virtual void batch_stop() = 0; + /** + * @brief aborts a batch transaction + * + * If the subclass implements batching, this function should abort the + * batch it is currently on. + * + * If no batch is in-progress, this function should throw a DB_ERROR. + * This exception may change in the future if it is deemed necessary to + * have a more granular exception type for this scenario. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ + virtual void batch_abort() = 0; + /** * @brief sets whether or not to batch transactions * diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h index 6c97713d5..34e635899 100644 --- a/src/blockchain_db/testdb.h +++ b/src/blockchain_db/testdb.h @@ -54,6 +54,7 @@ public: virtual void unlock() override { } virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) override { return true; } virtual void batch_stop() override {} + virtual void batch_abort() override {} virtual void set_batch_transactions(bool) override {} virtual void block_wtxn_start() override {} virtual void block_wtxn_stop() override {} diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 9a970e915..b143751af 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -137,7 +137,8 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) : m_long_term_block_weights_cache_rolling_median(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE), m_difficulty_for_next_block_top_hash(crypto::null_hash), m_difficulty_for_next_block(1), - m_btc_valid(false) + m_btc_valid(false), + m_batch_success(true) { LOG_PRINT_L3("Blockchain::" << __func__); } @@ -574,14 +575,7 @@ void Blockchain::pop_blocks(uint64_t nblocks) CRITICAL_REGION_LOCAL(m_tx_pool); CRITICAL_REGION_LOCAL1(m_blockchain_lock); - while (!m_db->batch_start()) - { - m_blockchain_lock.unlock(); - m_tx_pool.unlock(); - epee::misc_utils::sleep_no_w(1000); - m_tx_pool.lock(); - m_blockchain_lock.lock(); - } + bool stop_batch = m_db->batch_start(); try { @@ -592,10 +586,14 @@ void Blockchain::pop_blocks(uint64_t nblocks) } catch (const std::exception& e) { - LOG_ERROR("Error when popping blocks, only " << i << " blocks are popped: " << e.what()); + LOG_ERROR("Error when popping blocks after processing " << i << " blocks: " << e.what()); + if (stop_batch) + m_db->batch_abort(); + return; } - m_db->batch_stop(); + if (stop_batch) + m_db->batch_stop(); } //------------------------------------------------------------------ // This function tells BlockchainDB to remove the top block from the @@ -3862,6 +3860,7 @@ leave: catch (const KEY_IMAGE_EXISTS& e) { LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); + m_batch_success = false; bvc.m_verifivation_failed = true; return_tx_to_pool(txs); return false; @@ -3870,6 +3869,7 @@ leave: { //TODO: figure out the best way to deal with this failure LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); + m_batch_success = false; bvc.m_verifivation_failed = true; return_tx_to_pool(txs); return false; @@ -4179,7 +4179,10 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) try { - m_db->batch_stop(); + if (m_batch_success) + m_db->batch_stop(); + else + m_db->batch_abort(); success = true; } catch (const std::exception &e) @@ -4403,6 +4406,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vectorheight(); if ((height + blocks_entry.size()) < m_blocks_hash_check.size()) diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 6200ec87e..32ed96b5b 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1102,6 +1102,9 @@ namespace cryptonote uint64_t m_btc_expected_reward; bool m_btc_valid; + + bool m_batch_success; + std::shared_ptr m_block_notify; std::shared_ptr m_reorg_notify; diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index bb3520873..1b286ae89 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -95,13 +95,17 @@ namespace cryptonote // the whole prepare/handle/cleanup incoming block sequence. class LockedTXN { public: - LockedTXN(Blockchain &b): m_blockchain(b), m_batch(false) { + LockedTXN(Blockchain &b): m_blockchain(b), m_batch(false), m_active(false) { m_batch = m_blockchain.get_db().batch_start(); + m_active = true; } - ~LockedTXN() { try { if (m_batch) { m_blockchain.get_db().batch_stop(); } } catch (const std::exception &e) { MWARNING("LockedTXN dtor filtering exception: " << e.what()); } } + void commit() { try { if (m_batch && m_active) { m_blockchain.get_db().batch_stop(); m_active = false; } } catch (const std::exception &e) { MWARNING("LockedTXN::commit filtering exception: " << e.what()); } } + void abort() { try { if (m_batch && m_active) { m_blockchain.get_db().batch_abort(); m_active = false; } } catch (const std::exception &e) { MWARNING("LockedTXN::abort filtering exception: " << e.what()); } } + ~LockedTXN() { abort(); } private: Blockchain &m_blockchain; bool m_batch; + bool m_active; }; } //--------------------------------------------------------------------------------- @@ -255,6 +259,7 @@ namespace cryptonote if (!insert_key_images(tx, id, kept_by_block)) return false; m_txs_by_fee_and_receive_time.emplace(std::pair(fee / (double)tx_weight, receive_time), id); + lock.commit(); } catch (const std::exception &e) { @@ -299,6 +304,7 @@ namespace cryptonote if (!insert_key_images(tx, id, kept_by_block)) return false; m_txs_by_fee_and_receive_time.emplace(std::pair(fee / (double)tx_weight, receive_time), id); + lock.commit(); } catch (const std::exception &e) { @@ -398,6 +404,7 @@ namespace cryptonote return; } } + lock.commit(); if (changed) ++m_cookie; if (m_txpool_weight > bytes) @@ -494,6 +501,7 @@ namespace cryptonote m_blockchain.remove_txpool_tx(id); m_txpool_weight -= tx_weight; remove_transaction_keyimages(tx, id); + lock.commit(); } catch (const std::exception &e) { @@ -578,6 +586,7 @@ namespace cryptonote // ignore error } } + lock.commit(); ++m_cookie; } return true; @@ -641,6 +650,7 @@ namespace cryptonote // continue } } + lock.commit(); } //--------------------------------------------------------------------------------- size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const @@ -1119,6 +1129,7 @@ namespace cryptonote } } } + lock.commit(); if (changed) ++m_cookie; } @@ -1271,6 +1282,7 @@ namespace cryptonote append_key_images(k_images, tx); LOG_PRINT_L2(" added, new block weight " << total_weight << "/" << max_total_weight << ", coinbase " << print_money(best_coinbase)); } + lock.commit(); expected_reward = best_coinbase; LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, weight " @@ -1336,6 +1348,7 @@ namespace cryptonote // continue } } + lock.commit(); } if (n_removed > 0) ++m_cookie; @@ -1395,6 +1408,7 @@ namespace cryptonote // ignore error } } + lock.commit(); } m_cookie = 0; From 19d4cbefe849c221439f2d406d77e5d03c1ce1cf Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 26 May 2019 16:50:35 +0000 Subject: [PATCH 08/10] blockchain: do not try to pop blocks down to the genesis block --- src/cryptonote_core/blockchain.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index b143751af..45ead00e3 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -579,6 +579,9 @@ void Blockchain::pop_blocks(uint64_t nblocks) try { + const uint64_t blockchain_height = m_db->height(); + if (blockchain_height > 0) + nblocks = std::min(nblocks, blockchain_height - 1); for (i=0; i < nblocks; ++i) { pop_block_from_blockchain(); From baddb899f7b593a605e6bc1957684673f146e4cc Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 28 May 2019 09:09:30 +0000 Subject: [PATCH 09/10] core: update pruning if using --prune-blockchain on a pruned blockchain Avoids a massive amount of spurious warnings if the last update before the daemon exited was a while ago and the daemon was syncing --- src/cryptonote_core/cryptonote_core.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 2ab91cbfd..dc4475ebd 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -675,8 +675,14 @@ namespace cryptonote { // display a message if the blockchain is not pruned yet if (m_blockchain_storage.get_current_blockchain_height() > 1 && !m_blockchain_storage.get_blockchain_pruning_seed()) + { MGINFO("Pruning blockchain..."); - CHECK_AND_ASSERT_MES(m_blockchain_storage.prune_blockchain(), false, "Failed to prune blockchain"); + CHECK_AND_ASSERT_MES(m_blockchain_storage.prune_blockchain(), false, "Failed to prune blockchain"); + } + else + { + CHECK_AND_ASSERT_MES(m_blockchain_storage.update_blockchain_pruning(), false, "Failed to update blockchain pruning"); + } } return load_state_data(); From 76de3683ac63bcf826c7bebee10704bd98bb5a1b Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 29 May 2019 11:45:25 +0000 Subject: [PATCH 10/10] functional_tests: fix python3 compatibility Also add missing bans test to the default tests --- tests/functional_tests/bans.py | 3 ++- tests/functional_tests/blockchain.py | 15 ++++++++------- tests/functional_tests/cold_signing.py | 11 +++++------ tests/functional_tests/daemon_info.py | 1 + .../functional_tests/functional_tests_rpc.py | 2 +- .../get_output_distribution.py | 7 +++---- tests/functional_tests/integrated_address.py | 13 ++++++------- tests/functional_tests/mining.py | 7 ++++--- tests/functional_tests/multisig.py | 4 ++-- tests/functional_tests/proofs.py | 4 ++-- tests/functional_tests/sign_message.py | 6 +++--- tests/functional_tests/speed.py | 2 +- tests/functional_tests/transfer.py | 8 ++++---- tests/functional_tests/txpool.py | 19 ++++++++++--------- tests/functional_tests/wallet_address.py | 17 ++++++++--------- 15 files changed, 60 insertions(+), 59 deletions(-) diff --git a/tests/functional_tests/bans.py b/tests/functional_tests/bans.py index bb3051a6a..e859e58c9 100755 --- a/tests/functional_tests/bans.py +++ b/tests/functional_tests/bans.py @@ -28,6 +28,7 @@ # 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. +from __future__ import print_function import time """Test peer baning RPC calls @@ -42,7 +43,7 @@ from framework.daemon import Daemon class BanTest(): def run_test(self): - print 'Testing bans' + print('Testing bans') daemon = Daemon() res = daemon.get_bans() diff --git a/tests/functional_tests/blockchain.py b/tests/functional_tests/blockchain.py index 6376b86d0..644597584 100755 --- a/tests/functional_tests/blockchain.py +++ b/tests/functional_tests/blockchain.py @@ -28,6 +28,7 @@ # 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. +from __future__ import print_function import time """Test daemon blockchain RPC calls @@ -50,7 +51,7 @@ class BlockchainTest(): self._test_alt_chains() def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() @@ -58,7 +59,7 @@ class BlockchainTest(): def _test_generateblocks(self, blocks): assert blocks >= 2 - print "Test generating", blocks, 'blocks' + print("Test generating", blocks, 'blocks') daemon = Daemon() @@ -182,14 +183,14 @@ class BlockchainTest(): for idx in tx.output_indices: assert idx == running_output_index running_output_index += 1 - res_out = daemon.get_outs([{'amount': 0, 'index': i} for i in tx.output_indices], get_txid = True) + res_out = daemon.get_outs([{'amount': 0, 'index': idx} for idx in tx.output_indices], get_txid = True) assert len(res_out.outs) == len(tx.output_indices) for out in res_out.outs: assert len(out.key) == 64 assert len(out.mask) == 64 assert not out.unlocked - assert out.height == i + 1 - assert out.txid == txids[i + 1] + assert out.height == i + assert out.txid == txids[i] for i in range(height + nblocks - 1): res_sum = daemon.get_coinbase_tx_sum(i, 1) @@ -255,7 +256,7 @@ class BlockchainTest(): alt_blocks[i] = txid nonce += 1 - print 'mining 3 on 1' + print('mining 3 on 1') # three more on [1] chain1 = [] res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 3, prev_block = alt_blocks[1], starting_nonce = nonce) @@ -275,7 +276,7 @@ class BlockchainTest(): for txid in alt_blocks: assert txid in res.blks_hashes or txid == alt_blocks[1] - print 'mining 4 on 3' + print('mining 4 on 3') # 4 more on [3], the chain will reorg when we mine the 4th top_block_hash = blk_hash prev_block = alt_blocks[3] diff --git a/tests/functional_tests/cold_signing.py b/tests/functional_tests/cold_signing.py index 59a879e0a..a722d8927 100755 --- a/tests/functional_tests/cold_signing.py +++ b/tests/functional_tests/cold_signing.py @@ -28,11 +28,10 @@ # 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. -import time - """Test cold tx signing """ +from __future__ import print_function from framework.daemon import Daemon from framework.wallet import Wallet @@ -44,13 +43,13 @@ class ColdSigningTest(): self.transfer() def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() def create(self, idx): - print 'Creating hot and cold wallet' + print('Creating hot and cold wallet') self.hot_wallet = Wallet(idx = 0) # close the wallet if any, will throw if none is loaded @@ -116,7 +115,7 @@ class ColdSigningTest(): assert len(res.unsigned_txset) > 0 unsigned_txset = res.unsigned_txset - print 'Signing transaction with cold wallet' + print('Signing transaction with cold wallet') res = self.cold_wallet.describe_transfer(unsigned_txset = unsigned_txset) assert len(res.desc) == 1 desc = res.desc[0] @@ -140,7 +139,7 @@ class ColdSigningTest(): txid = res.tx_hash_list[0] assert len(txid) == 64 - print 'Submitting transaction with hot wallet' + print('Submitting transaction with hot wallet') res = self.hot_wallet.submit_transfer(signed_txset) assert len(res.tx_hash_list) > 0 assert res.tx_hash_list[0] == txid diff --git a/tests/functional_tests/daemon_info.py b/tests/functional_tests/daemon_info.py index bd3528c3f..4fa768b03 100755 --- a/tests/functional_tests/daemon_info.py +++ b/tests/functional_tests/daemon_info.py @@ -36,6 +36,7 @@ Test the following RPCs: """ +from __future__ import print_function from framework.daemon import Daemon class DaemonGetInfoTest(): diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py index 1a1fa5490..25ab641ab 100755 --- a/tests/functional_tests/functional_tests_rpc.py +++ b/tests/functional_tests/functional_tests_rpc.py @@ -10,7 +10,7 @@ import string import os USAGE = 'usage: functional_tests_rpc.py [ | all]' -DEFAULT_TESTS = ['daemon_info', 'blockchain', 'wallet_address', 'integrated_address', 'mining', 'transfer', 'txpool', 'multisig', 'cold_signing', 'sign_message', 'proofs', 'get_output_distribution'] +DEFAULT_TESTS = ['bans', 'daemon_info', 'blockchain', 'wallet_address', 'integrated_address', 'mining', 'transfer', 'txpool', 'multisig', 'cold_signing', 'sign_message', 'proofs', 'get_output_distribution'] try: python = sys.argv[1] srcdir = sys.argv[2] diff --git a/tests/functional_tests/get_output_distribution.py b/tests/functional_tests/get_output_distribution.py index 061b8dbe2..93822e90a 100755 --- a/tests/functional_tests/get_output_distribution.py +++ b/tests/functional_tests/get_output_distribution.py @@ -28,11 +28,10 @@ # 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. -import time - """Test get_output_distribution RPC """ +from __future__ import print_function from framework.daemon import Daemon from framework.wallet import Wallet @@ -43,7 +42,7 @@ class GetOutputDistributionTest(): self.test_get_output_distribution() def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() @@ -56,7 +55,7 @@ class GetOutputDistributionTest(): res = self.wallet.restore_deterministic_wallet(seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted') def test_get_output_distribution(self): - print "Test get_output_distribution" + print("Test get_output_distribution") daemon = Daemon() diff --git a/tests/functional_tests/integrated_address.py b/tests/functional_tests/integrated_address.py index 338dd14ae..4e42261a6 100755 --- a/tests/functional_tests/integrated_address.py +++ b/tests/functional_tests/integrated_address.py @@ -28,8 +28,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. -import time - """Test integrated address RPC calls Test the following RPCs: @@ -38,6 +36,7 @@ Test the following RPCs: """ +from __future__ import print_function from framework.wallet import Wallet class IntegratedAddressTest(): @@ -46,7 +45,7 @@ class IntegratedAddressTest(): self.check() def create(self): - print 'Creating wallet' + print('Creating wallet') wallet = Wallet() # close the wallet if any, will throw if none is loaded try: wallet.close_wallet() @@ -59,7 +58,7 @@ class IntegratedAddressTest(): def check(self): wallet = Wallet() - print 'Checking local address' + print('Checking local address') res = wallet.make_integrated_address(payment_id = '0123456789abcdef') assert res.integrated_address == '4CMe2PUhs4J4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfSbLRB61BQVATzerHGj' assert res.payment_id == '0123456789abcdef' @@ -67,7 +66,7 @@ class IntegratedAddressTest(): assert res.standard_address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res.payment_id == '0123456789abcdef' - print 'Checking different address' + print('Checking different address') res = wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', payment_id = '1122334455667788') assert res.integrated_address == '4GYjoMG9Y2BBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCVSs1ZojwrDCGS5rUuo' assert res.payment_id == '1122334455667788' @@ -75,7 +74,7 @@ class IntegratedAddressTest(): assert res.standard_address == '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK' assert res.payment_id == '1122334455667788' - print 'Checking bad payment id' + print('Checking bad payment id') fails = 0 try: wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', payment_id = '11223344556677880') except: fails += 1 @@ -89,7 +88,7 @@ class IntegratedAddressTest(): except: fails += 1 assert fails == 5 - print 'Checking bad standard address' + print('Checking bad standard address') fails = 0 try: wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerr', payment_id = '1122334455667788') except: fails += 1 diff --git a/tests/functional_tests/mining.py b/tests/functional_tests/mining.py index 78dc68640..5c14d34fd 100755 --- a/tests/functional_tests/mining.py +++ b/tests/functional_tests/mining.py @@ -28,6 +28,7 @@ # 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. +from __future__ import print_function import time """Test daemon mining RPC calls @@ -48,13 +49,13 @@ class MiningTest(): self.mine() def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() def create(self): - print 'Creating wallet' + print('Creating wallet') wallet = Wallet() # close the wallet if any, will throw if none is loaded try: wallet.close_wallet() @@ -62,7 +63,7 @@ class MiningTest(): res = wallet.restore_deterministic_wallet(seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted') def mine(self): - print "Test mining" + print("Test mining") daemon = Daemon() wallet = Wallet() diff --git a/tests/functional_tests/multisig.py b/tests/functional_tests/multisig.py index 476e3a02d..3c8cd9c1d 100755 --- a/tests/functional_tests/multisig.py +++ b/tests/functional_tests/multisig.py @@ -28,7 +28,7 @@ # 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. -import time +from __future__ import print_function """Test multisig transfers """ @@ -70,7 +70,7 @@ class MultisigTest(): self.check_transaction(txid) def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() diff --git a/tests/functional_tests/proofs.py b/tests/functional_tests/proofs.py index 844131095..243929dc3 100755 --- a/tests/functional_tests/proofs.py +++ b/tests/functional_tests/proofs.py @@ -28,7 +28,7 @@ # 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. -import time +from __future__ import print_function """Test misc proofs (tx key, send, receive, reserve) """ @@ -47,7 +47,7 @@ class ProofsTest(): self.check_reserve_proof() def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() diff --git a/tests/functional_tests/sign_message.py b/tests/functional_tests/sign_message.py index 4c3ec3588..de8f0cee2 100755 --- a/tests/functional_tests/sign_message.py +++ b/tests/functional_tests/sign_message.py @@ -28,7 +28,7 @@ # 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. -import time +from __future__ import print_function """Test message signing/verification RPC calls @@ -46,7 +46,7 @@ class MessageSigningTest(): self.check_signing() def create(self): - print 'Creating wallets' + print('Creating wallets') seeds = [ 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted', 'peeled mixture ionic radar utopia puddle buying illness nuns gadget river spout cavernous bounced paradise drunk looking cottage jump tequila melting went winter adjust spout', @@ -66,7 +66,7 @@ class MessageSigningTest(): assert res.seed == seeds[i] def check_signing(self): - print 'Signing/verifing messages' + print('Signing/verifing messages') messages = ['foo', ''] for message in messages: res = self.wallet[0].sign(message) diff --git a/tests/functional_tests/speed.py b/tests/functional_tests/speed.py index bd8892df8..ed1e332e9 100755 --- a/tests/functional_tests/speed.py +++ b/tests/functional_tests/speed.py @@ -40,7 +40,7 @@ Test the following RPCs: import time from time import sleep -from decimal import Decimal +from __future__ import print_function from framework.daemon import Daemon from framework.wallet import Wallet diff --git a/tests/functional_tests/transfer.py b/tests/functional_tests/transfer.py index 1ff641d1f..7bf0f4957 100755 --- a/tests/functional_tests/transfer.py +++ b/tests/functional_tests/transfer.py @@ -28,7 +28,7 @@ # 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. -import time +from __future__ import print_function import json """Test simple transfers @@ -48,13 +48,13 @@ class TransferTest(): self.sweep_single() def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() def create(self): - print 'Creating wallets' + print('Creating wallets') seeds = [ 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted', 'peeled mixture ionic radar utopia puddle buying illness nuns gadget river spout cavernous bounced paradise drunk looking cottage jump tequila melting went winter adjust spout', @@ -297,7 +297,7 @@ class TransferTest(): assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 - print 'Creating multi out transfer' + print('Creating multi out transfer') self.wallet[0].refresh() diff --git a/tests/functional_tests/txpool.py b/tests/functional_tests/txpool.py index d74395f10..b6af4c84f 100755 --- a/tests/functional_tests/txpool.py +++ b/tests/functional_tests/txpool.py @@ -28,7 +28,7 @@ # 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. -import time +from __future__ import print_function """Test txpool """ @@ -44,13 +44,13 @@ class TransferTest(): self.check_txpool() def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() def create(self): - print 'Creating wallet' + print('Creating wallet') wallet = Wallet() # close the wallet if any, will throw if none is loaded try: wallet.close_wallet() @@ -114,15 +114,16 @@ class TransferTest(): assert sorted(res.tx_hashes) == sorted(txes.keys()) print('Flushing 2 transactions') - daemon.flush_txpool([txes.keys()[1], txes.keys()[3]]) + txes_keys = list(txes.keys()) + daemon.flush_txpool([txes_keys[1], txes_keys[3]]) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 - assert len([x for x in res.transactions if x.id_hash == txes.keys()[1]]) == 0 - assert len([x for x in res.transactions if x.id_hash == txes.keys()[3]]) == 0 + assert len([x for x in res.transactions if x.id_hash == txes_keys[1]]) == 0 + assert len([x for x in res.transactions if x.id_hash == txes_keys[3]]) == 0 - new_keys = txes.keys() - new_keys.remove(txes.keys()[1]) - new_keys.remove(txes.keys()[3]) + new_keys = list(txes.keys()) + new_keys.remove(txes_keys[1]) + new_keys.remove(txes_keys[3]) res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(new_keys) diff --git a/tests/functional_tests/wallet_address.py b/tests/functional_tests/wallet_address.py index 8a55521c6..4ff059a6f 100755 --- a/tests/functional_tests/wallet_address.py +++ b/tests/functional_tests/wallet_address.py @@ -29,8 +29,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. -import time - """Test transaction creation RPC calls Test the following RPCs: @@ -38,6 +36,7 @@ Test the following RPCs: """ +from __future__ import print_function from framework.wallet import Wallet from framework.daemon import Daemon @@ -52,13 +51,13 @@ class WalletAddressTest(): self.languages() def reset(self): - print 'Resetting blockchain' + print('Resetting blockchain') daemon = Daemon() daemon.pop_blocks(1000) daemon.flush_txpool() def create(self): - print 'Creating wallet' + print('Creating wallet') wallet = Wallet() # close the wallet if any, will throw if none is loaded try: wallet.close_wallet() @@ -69,7 +68,7 @@ class WalletAddressTest(): assert res.seed == seed def check_main_address(self): - print 'Getting address' + print('Getting address') wallet = Wallet() res = wallet.get_address() assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', res @@ -79,7 +78,7 @@ class WalletAddressTest(): assert res.addresses[0].used == False def check_keys(self): - print 'Checking keys' + print('Checking keys') wallet = Wallet() res = wallet.query_key('view_key') assert res.key == '49774391fa5e8d249fc2c5b45dadef13534bf2483dede880dac88f061e809100' @@ -89,7 +88,7 @@ class WalletAddressTest(): assert res.key == 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted' def create_subaddresses(self): - print 'Creating subaddresses' + print('Creating subaddresses') wallet = Wallet() res = wallet.create_account("idx1") assert res.account_index == 1, res @@ -160,7 +159,7 @@ class WalletAddressTest(): assert res.index == {'major': 1, 'minor': 0} def open_close(self): - print 'Testing open/close' + print('Testing open/close') wallet = Wallet() res = wallet.get_address() @@ -200,7 +199,7 @@ class WalletAddressTest(): except: pass languages = res.languages for language in languages: - print 'Creating ' + str(language) + ' wallet' + print('Creating ' + str(language) + ' wallet') wallet.create_wallet(filename = '', language = language) res = wallet.query_key('mnemonic') wallet.close_wallet()