aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/epee/include/net/net_fwd.h38
-rw-r--r--src/blockchain_db/blockchain_db.h15
-rw-r--r--src/blockchain_db/testdb.h1
-rw-r--r--src/common/rpc_client.h4
-rw-r--r--src/cryptonote_core/blockchain.cpp34
-rw-r--r--src/cryptonote_core/blockchain.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp8
-rw-r--r--src/cryptonote_core/tx_pool.cpp18
-rw-r--r--src/daemon/command_parser_executor.cpp3
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp3
-rw-r--r--src/daemon/command_server.h2
-rw-r--r--src/daemon/daemon.cpp3
-rw-r--r--src/daemon/main.cpp6
-rw-r--r--src/daemon/rpc_command_executor.cpp3
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/rpc/core_rpc_server.cpp83
-rw-r--r--src/rpc/rpc_args.cpp82
-rw-r--r--src/rpc/rpc_args.h18
-rw-r--r--src/wallet/wallet2.cpp5
-rw-r--r--src/wallet/wallet_rpc_server.cpp57
-rwxr-xr-xtests/functional_tests/get_output_distribution.py11
-rw-r--r--tests/unit_tests/output_selection.cpp2
23 files changed, 243 insertions, 160 deletions
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/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
@@ -754,6 +754,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
*
* If the subclass implements batching, this function tells it to begin
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/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<epee::net_utils::http::login> 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/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 39c9f8695..3841aa1cf 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -182,7 +182,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__);
}
@@ -619,17 +620,13 @@ 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
{
+ 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();
@@ -637,10 +634,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
@@ -1373,7 +1374,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;
@@ -3844,6 +3846,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;
@@ -3852,6 +3855,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;
@@ -4161,7 +4165,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)
@@ -4385,6 +4392,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
m_tx_pool.lock();
m_blockchain_lock.lock();
}
+ m_batch_success = true;
const uint64_t height = m_db->height();
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<tools::Notify> m_block_notify;
std::shared_ptr<tools::Notify> m_reorg_notify;
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index be1ea5a17..55e1b287f 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();
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index c1cbe2acd..49d5a8ccc 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<double, std::time_t>(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<double, std::time_t>(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;
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 17b945c9a..0b452800e 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<tools::login>& 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<std::string>& 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<tools::login>& 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 69ad6ff10..f665eec9c 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<tools::login>& 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<tools::login>& 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 dbbb2308c..690d4d60e 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 151baa33f..cca0f75f9 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<tools::login>& 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<epee::net_utils::http::login> 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<tools::login>& 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 5777370fc..5ca5f3fe7 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<std::string> ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
- std::vector<std::vector<uint8_t>> 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<core_rpc_server, connection_context>::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<std::string> core_rpc_server::arg_rpc_ssl = {
- "rpc-ssl"
- , "Enable SSL on RPC connections: enabled|disabled|autodetect"
- , "autodetect"
- };
-
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_private_key = {
- "rpc-ssl-private-key"
- , "Path to a PEM format private key"
- , ""
- };
-
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_certificate = {
- "rpc-ssl-certificate"
- , "Path to a PEM format certificate"
- , ""
- };
-
- const command_line::arg_descriptor<std::string> 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<std::vector<std::string>> core_rpc_server::arg_rpc_ssl_allowed_fingerprints = {
- "rpc-ssl-allowed-fingerprints"
- , "List of certificate fingerprints to allow"
- };
-
- const command_line::arg_descriptor<bool> core_rpc_server::arg_rpc_ssl_allow_any_cert = {
- "rpc-ssl-allow-any-cert"
- , "Allow any peer certificate"
- , false
- };
-
const command_line::arg_descriptor<std::string> 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 <boost/bind.hpp>
#include "common/command_line.h"
#include "common/i18n.h"
+#include "hex.h"
namespace cryptonote
{
+ namespace
+ {
+ boost::optional<epee::net_utils::ssl_options_t> 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<std::string> ssl_allowed_fingerprints = command_line::get_arg(vm, arg.rpc_ssl_allowed_fingerprints);
+
+ std::vector<std::vector<uint8_t>> 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> rpc_args::process(const boost::program_options::variables_map& vm)
+ boost::optional<rpc_args> 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<epee::net_utils::ssl_options_t> 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<std::string> rpc_login;
const command_line::arg_descriptor<bool> confirm_external_bind;
const command_line::arg_descriptor<std::string> rpc_access_control_origins;
+ const command_line::arg_descriptor<std::string> rpc_ssl;
+ const command_line::arg_descriptor<std::string> rpc_ssl_private_key;
+ const command_line::arg_descriptor<std::string> rpc_ssl_certificate;
+ const command_line::arg_descriptor<std::string> rpc_ssl_ca_certificates;
+ const command_line::arg_descriptor<std::vector<std::string>> rpc_ssl_allowed_fingerprints;
+ const command_line::arg_descriptor<bool> rpc_ssl_allow_chained;
+ const command_line::arg_descriptor<bool> 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<rpc_args> process(const boost::program_options::variables_map& vm);
+ static boost::optional<rpc_args> 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<epee::net_utils::ssl_options_t> process_ssl(const boost::program_options::variables_map& vm, const bool any_cert_option = false);
std::string bind_ip;
std::vector<std::string> access_control_origins;
boost::optional<tools::login> 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/wallet2.cpp b/src/wallet/wallet2.cpp
index c87947e39..8f3f30da1 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -399,8 +399,11 @@ std::unique_ptr<tools::wallet2> 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),
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 16a2b3808..8b8d832dc 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<bool> arg_restricted = {"restricted-rpc", "Restricts to view-only commands", false};
const command_line::arg_descriptor<std::string> arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"};
const command_line::arg_descriptor<bool> arg_prompt_for_password = {"prompt-for-password", "Prompts for password when not provided", false};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl = {"rpc-ssl", tools::wallet2::tr("Enable SSL on wallet RPC connections: enabled|disabled|autodetect"), "autodetect"};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key = {"rpc-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate = {"rpc-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
- const command_line::arg_descriptor<std::string> 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<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints = {"rpc-ssl-allowed-fingerprints", tools::wallet2::tr("List of certificate fingerprints to allow")};
constexpr const char default_rpc_username[] = "monero";
@@ -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<std::vector<uint8_t>> 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<wallet_rpc_server, connection_context>::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)
);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -4167,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";
@@ -4412,11 +4372,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);
diff --git a/tests/functional_tests/get_output_distribution.py b/tests/functional_tests/get_output_distribution.py
index 81c606465..93822e90a 100755
--- a/tests/functional_tests/get_output_distribution.py
+++ b/tests/functional_tests/get_output_distribution.py
@@ -212,5 +212,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()
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);
}
}