Merge branch 'dev-v0.6' into wow
This commit is contained in:
commit
29e13fe96a
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -762,6 +762,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
|
||||
*
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -578,17 +578,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();
|
||||
|
@ -596,10 +592,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
|
||||
|
@ -1390,7 +1390,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;
|
||||
|
@ -3932,6 +3933,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;
|
||||
|
@ -3940,6 +3942,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;
|
||||
|
@ -4249,7 +4252,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)
|
||||
|
@ -4473,6 +4479,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())
|
||||
|
|
|
@ -1091,6 +1091,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;
|
||||
|
||||
|
|
|
@ -687,8 +687,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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -2452,40 +2409,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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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[] = "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<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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -36,6 +36,7 @@ Test the following RPCs:
|
|||
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
from framework.daemon import Daemon
|
||||
|
||||
class DaemonGetInfoTest():
|
||||
|
|
|
@ -10,7 +10,7 @@ import string
|
|||
import os
|
||||
|
||||
USAGE = 'usage: functional_tests_rpc.py <python> <srcdir> <builddir> [<tests-to-run> | 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]
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
@ -213,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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue