Merge branch 'dev-v0.6' into wow

pull/203/head
Hiroji Kiyotake 5 years ago committed by GitHub
commit 29e13fe96a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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; 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 * @brief sets whether or not to batch transactions
* *

@ -54,6 +54,7 @@ public:
virtual void unlock() override { } virtual void unlock() override { }
virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) override { return true; } 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_stop() override {}
virtual void batch_abort() override {}
virtual void set_batch_transactions(bool) override {} virtual void set_batch_transactions(bool) override {}
virtual void block_wtxn_start() override {} virtual void block_wtxn_start() override {}
virtual void block_wtxn_stop() override {} virtual void block_wtxn_stop() override {}

@ -36,6 +36,7 @@
#include "storages/http_abstract_invoke.h" #include "storages/http_abstract_invoke.h"
#include "net/http_auth.h" #include "net/http_auth.h"
#include "net/http_client.h" #include "net/http_client.h"
#include "net/net_ssl.h"
#include "string_tools.h" #include "string_tools.h"
namespace tools namespace tools
@ -49,11 +50,12 @@ namespace tools
uint32_t ip uint32_t ip
, uint16_t port , uint16_t port
, boost::optional<epee::net_utils::http::login> user , boost::optional<epee::net_utils::http::login> user
, epee::net_utils::ssl_options_t ssl_options
) )
: m_http_client{} : m_http_client{}
{ {
m_http_client.set_server( 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_LOCAL(m_tx_pool);
CRITICAL_REGION_LOCAL1(m_blockchain_lock); CRITICAL_REGION_LOCAL1(m_blockchain_lock);
while (!m_db->batch_start()) bool stop_batch = 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();
}
try 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) for (i=0; i < nblocks; ++i)
{ {
pop_block_from_blockchain(); pop_block_from_blockchain();
@ -596,10 +592,14 @@ void Blockchain::pop_blocks(uint64_t nblocks)
} }
catch (const std::exception& e) 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 // 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 // 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 // this would be the case anyway if we'd lock, and the change happened
// just after the block template was created // 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"); MDEBUG("Using cached template");
m_btc.timestamp = time(NULL); // update timestamp unconditionally m_btc.timestamp = time(NULL); // update timestamp unconditionally
b = m_btc; b = m_btc;
@ -3932,6 +3933,7 @@ leave:
catch (const KEY_IMAGE_EXISTS& e) catch (const KEY_IMAGE_EXISTS& e)
{ {
LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what());
m_batch_success = false;
bvc.m_verifivation_failed = true; bvc.m_verifivation_failed = true;
return_tx_to_pool(txs); return_tx_to_pool(txs);
return false; return false;
@ -3940,6 +3942,7 @@ leave:
{ {
//TODO: figure out the best way to deal with this failure //TODO: figure out the best way to deal with this failure
LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what());
m_batch_success = false;
bvc.m_verifivation_failed = true; bvc.m_verifivation_failed = true;
return_tx_to_pool(txs); return_tx_to_pool(txs);
return false; return false;
@ -4249,7 +4252,10 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
try try
{ {
m_db->batch_stop(); if (m_batch_success)
m_db->batch_stop();
else
m_db->batch_abort();
success = true; success = true;
} }
catch (const std::exception &e) 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_tx_pool.lock();
m_blockchain_lock.lock(); m_blockchain_lock.lock();
} }
m_batch_success = true;
const uint64_t height = m_db->height(); const uint64_t height = m_db->height();
if ((height + blocks_entry.size()) < m_blocks_hash_check.size()) if ((height + blocks_entry.size()) < m_blocks_hash_check.size())

@ -1091,6 +1091,9 @@ namespace cryptonote
uint64_t m_btc_expected_reward; uint64_t m_btc_expected_reward;
bool m_btc_valid; bool m_btc_valid;
bool m_batch_success;
std::shared_ptr<tools::Notify> m_block_notify; std::shared_ptr<tools::Notify> m_block_notify;
std::shared_ptr<tools::Notify> m_reorg_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 // 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()) if (m_blockchain_storage.get_current_blockchain_height() > 1 && !m_blockchain_storage.get_blockchain_pruning_seed())
{
MGINFO("Pruning blockchain..."); 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(); return load_state_data();

@ -95,13 +95,17 @@ namespace cryptonote
// the whole prepare/handle/cleanup incoming block sequence. // the whole prepare/handle/cleanup incoming block sequence.
class LockedTXN { class LockedTXN {
public: 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_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: private:
Blockchain &m_blockchain; Blockchain &m_blockchain;
bool m_batch; bool m_batch;
bool m_active;
}; };
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
@ -255,6 +259,7 @@ namespace cryptonote
if (!insert_key_images(tx, id, kept_by_block)) if (!insert_key_images(tx, id, kept_by_block))
return false; return false;
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id); 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) catch (const std::exception &e)
{ {
@ -299,6 +304,7 @@ namespace cryptonote
if (!insert_key_images(tx, id, kept_by_block)) if (!insert_key_images(tx, id, kept_by_block))
return false; return false;
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id); 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) catch (const std::exception &e)
{ {
@ -398,6 +404,7 @@ namespace cryptonote
return; return;
} }
} }
lock.commit();
if (changed) if (changed)
++m_cookie; ++m_cookie;
if (m_txpool_weight > bytes) if (m_txpool_weight > bytes)
@ -494,6 +501,7 @@ namespace cryptonote
m_blockchain.remove_txpool_tx(id); m_blockchain.remove_txpool_tx(id);
m_txpool_weight -= tx_weight; m_txpool_weight -= tx_weight;
remove_transaction_keyimages(tx, id); remove_transaction_keyimages(tx, id);
lock.commit();
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@ -578,6 +586,7 @@ namespace cryptonote
// ignore error // ignore error
} }
} }
lock.commit();
++m_cookie; ++m_cookie;
} }
return true; return true;
@ -641,6 +650,7 @@ namespace cryptonote
// continue // continue
} }
} }
lock.commit();
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const
@ -1119,6 +1129,7 @@ namespace cryptonote
} }
} }
} }
lock.commit();
if (changed) if (changed)
++m_cookie; ++m_cookie;
} }
@ -1271,6 +1282,7 @@ namespace cryptonote
append_key_images(k_images, tx); append_key_images(k_images, tx);
LOG_PRINT_L2(" added, new block weight " << total_weight << "/" << max_total_weight << ", coinbase " << print_money(best_coinbase)); LOG_PRINT_L2(" added, new block weight " << total_weight << "/" << max_total_weight << ", coinbase " << print_money(best_coinbase));
} }
lock.commit();
expected_reward = best_coinbase; expected_reward = best_coinbase;
LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, weight " LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, weight "
@ -1336,6 +1348,7 @@ namespace cryptonote
// continue // continue
} }
} }
lock.commit();
} }
if (n_removed > 0) if (n_removed > 0)
++m_cookie; ++m_cookie;
@ -1395,6 +1408,7 @@ namespace cryptonote
// ignore error // ignore error
} }
} }
lock.commit();
} }
m_cookie = 0; m_cookie = 0;

@ -40,10 +40,11 @@ t_command_parser_executor::t_command_parser_executor(
uint32_t ip uint32_t ip
, uint16_t port , uint16_t port
, const boost::optional<tools::login>& login , const boost::optional<tools::login>& login
, const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc , bool is_rpc
, cryptonote::core_rpc_server* rpc_server , 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) 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 "daemon/rpc_command_executor.h"
#include "common/common_fwd.h" #include "common/common_fwd.h"
#include "net/net_fwd.h"
#include "rpc/core_rpc_server.h" #include "rpc/core_rpc_server.h"
namespace daemonize { namespace daemonize {
@ -53,6 +54,7 @@ public:
uint32_t ip uint32_t ip
, uint16_t port , uint16_t port
, const boost::optional<tools::login>& login , const boost::optional<tools::login>& login
, const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc , bool is_rpc
, cryptonote::core_rpc_server* rpc_server = NULL , cryptonote::core_rpc_server* rpc_server = NULL
); );

@ -43,10 +43,11 @@ t_command_server::t_command_server(
uint32_t ip uint32_t ip
, uint16_t port , uint16_t port
, const boost::optional<tools::login>& login , const boost::optional<tools::login>& login
, const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc , bool is_rpc
, cryptonote::core_rpc_server* rpc_server , 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_command_lookup()
, m_is_rpc(is_rpc) , m_is_rpc(is_rpc)
{ {

@ -43,6 +43,7 @@ Passing RPC commands:
#include "common/common_fwd.h" #include "common/common_fwd.h"
#include "console_handler.h" #include "console_handler.h"
#include "daemon/command_parser_executor.h" #include "daemon/command_parser_executor.h"
#include "net/net_fwd.h"
namespace daemonize { namespace daemonize {
@ -57,6 +58,7 @@ public:
uint32_t ip uint32_t ip
, uint16_t port , uint16_t port
, const boost::optional<tools::login>& login , const boost::optional<tools::login>& login
, const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc = true , bool is_rpc = true
, cryptonote::core_rpc_server* rpc_server = NULL , cryptonote::core_rpc_server* rpc_server = NULL
); );

@ -45,6 +45,7 @@
#include "daemon/command_server.h" #include "daemon/command_server.h"
#include "daemon/command_server.h" #include "daemon/command_server.h"
#include "daemon/command_line_args.h" #include "daemon/command_line_args.h"
#include "net/net_ssl.h"
#include "version.h" #include "version.h"
using namespace epee; using namespace epee;
@ -163,7 +164,7 @@ bool t_daemon::run(bool interactive)
if (interactive && mp_internals->rpcs.size()) if (interactive && mp_internals->rpcs.size())
{ {
// The first three variables are not used when the fourth is false // 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)); 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)) if (rpc_commands.process_command_vec(command))
{ {
return 0; return 0;

@ -127,6 +127,7 @@ t_rpc_command_executor::t_rpc_command_executor(
uint32_t ip uint32_t ip
, uint16_t port , uint16_t port
, const boost::optional<tools::login>& login , const boost::optional<tools::login>& login
, const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc , bool is_rpc
, cryptonote::core_rpc_server* rpc_server , 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{}; boost::optional<epee::net_utils::http::login> http_login{};
if (login) if (login)
http_login.emplace(login->username, login->password.password()); 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 else
{ {

@ -43,6 +43,7 @@
#include "common/common_fwd.h" #include "common/common_fwd.h"
#include "common/rpc_client.h" #include "common/rpc_client.h"
#include "cryptonote_basic/cryptonote_basic.h" #include "cryptonote_basic/cryptonote_basic.h"
#include "net/net_fwd.h"
#include "rpc/core_rpc_server.h" #include "rpc/core_rpc_server.h"
#undef MONERO_DEFAULT_LOG_CATEGORY #undef MONERO_DEFAULT_LOG_CATEGORY
@ -61,6 +62,7 @@ public:
uint32_t ip uint32_t ip
, uint16_t port , uint16_t port
, const boost::optional<tools::login>& user , const boost::optional<tools::login>& user
, const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc = true , bool is_rpc = true
, cryptonote::core_rpc_server* rpc_server = NULL , 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_bind_port);
command_line::add_arg(desc, arg_rpc_restricted_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_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_address);
command_line::add_arg(desc, arg_bootstrap_daemon_login); 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( core_rpc_server::core_rpc_server(
@ -118,7 +112,7 @@ namespace cryptonote
m_restricted = restricted; m_restricted = restricted;
m_net_server.set_threads_prefix("RPC"); 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) if (!rpc_config)
return false; return false;
@ -151,46 +145,9 @@ namespace cryptonote
if (rpc_config->login) if (rpc_config->login)
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password()); 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); }; 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( 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 , 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 = { const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_address = {
"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" , "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 <boost/bind.hpp>
#include "common/command_line.h" #include "common/command_line.h"
#include "common/i18n.h" #include "common/i18n.h"
#include "hex.h"
namespace cryptonote 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_args::descriptors::descriptors()
: rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"}) : 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}) , 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")}) , 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_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"); } 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{}; const descriptors arg{};
command_line::add_arg(desc, arg.rpc_bind_ip); command_line::add_arg(desc, arg.rpc_bind_ip);
command_line::add_arg(desc, arg.rpc_login); command_line::add_arg(desc, arg.rpc_login);
command_line::add_arg(desc, arg.confirm_external_bind); 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_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{}; const descriptors arg{};
rpc_args config{}; rpc_args config{};
@ -118,6 +185,17 @@ namespace cryptonote
config.access_control_origins = std::move(access_control_origins); 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)}; 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/command_line.h"
#include "common/password.h" #include "common/password.h"
#include "net/net_ssl.h"
namespace cryptonote namespace cryptonote
{ {
@ -54,16 +55,29 @@ namespace cryptonote
const command_line::arg_descriptor<std::string> rpc_login; const command_line::arg_descriptor<std::string> rpc_login;
const command_line::arg_descriptor<bool> confirm_external_bind; 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_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 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 //! \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::string bind_ip;
std::vector<std::string> access_control_origins; std::vector<std::string> access_control_origins;
boost::optional<tools::login> login; // currently `boost::none` if unspecified by user 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(':')); 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 = 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( THROW_WALLET_EXCEPTION_IF(
verification_required && !ssl_options.has_strong_verification(real_daemon), 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<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<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<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"; constexpr const char default_rpc_username[] = "wownero";
@ -244,45 +239,6 @@ namespace tools
assert(bool(http_login)); assert(bool(http_login));
} // end auth enabled } // 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_auto_refresh_period = DEFAULT_AUTO_REFRESH_PERIOD;
m_last_auto_refresh_time = boost::posix_time::min_date_time; 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); }; 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( 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), 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) 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.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
er.message = "SSL is enabled but no user certificate or fingerprints were provided"; 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_from_json);
command_line::add_arg(desc_params, arg_wallet_dir); 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_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); daemonizer::init_options(hidden_options, desc_params);
desc_params.add(hidden_options); desc_params.add(hidden_options);

@ -28,6 +28,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
import time import time
"""Test peer baning RPC calls """Test peer baning RPC calls
@ -42,7 +43,7 @@ from framework.daemon import Daemon
class BanTest(): class BanTest():
def run_test(self): def run_test(self):
print 'Testing bans' print('Testing bans')
daemon = Daemon() daemon = Daemon()
res = daemon.get_bans() res = daemon.get_bans()

@ -28,6 +28,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
import time import time
"""Test daemon blockchain RPC calls """Test daemon blockchain RPC calls
@ -50,7 +51,7 @@ class BlockchainTest():
self._test_alt_chains() self._test_alt_chains()
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() daemon.flush_txpool()
@ -58,7 +59,7 @@ class BlockchainTest():
def _test_generateblocks(self, blocks): def _test_generateblocks(self, blocks):
assert blocks >= 2 assert blocks >= 2
print "Test generating", blocks, 'blocks' print("Test generating", blocks, 'blocks')
daemon = Daemon() daemon = Daemon()
@ -182,14 +183,14 @@ class BlockchainTest():
for idx in tx.output_indices: for idx in tx.output_indices:
assert idx == running_output_index assert idx == running_output_index
running_output_index += 1 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) assert len(res_out.outs) == len(tx.output_indices)
for out in res_out.outs: for out in res_out.outs:
assert len(out.key) == 64 assert len(out.key) == 64
assert len(out.mask) == 64 assert len(out.mask) == 64
assert not out.unlocked assert not out.unlocked
assert out.height == i + 1 assert out.height == i
assert out.txid == txids[i + 1] assert out.txid == txids[i]
for i in range(height + nblocks - 1): for i in range(height + nblocks - 1):
res_sum = daemon.get_coinbase_tx_sum(i, 1) res_sum = daemon.get_coinbase_tx_sum(i, 1)
@ -255,7 +256,7 @@ class BlockchainTest():
alt_blocks[i] = txid alt_blocks[i] = txid
nonce += 1 nonce += 1
print 'mining 3 on 1' print('mining 3 on 1')
# three more on [1] # three more on [1]
chain1 = [] chain1 = []
res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 3, prev_block = alt_blocks[1], starting_nonce = nonce) res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 3, prev_block = alt_blocks[1], starting_nonce = nonce)
@ -275,7 +276,7 @@ class BlockchainTest():
for txid in alt_blocks: for txid in alt_blocks:
assert txid in res.blks_hashes or txid == alt_blocks[1] 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 # 4 more on [3], the chain will reorg when we mine the 4th
top_block_hash = blk_hash top_block_hash = blk_hash
prev_block = alt_blocks[3] prev_block = alt_blocks[3]

@ -28,11 +28,10 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time
"""Test cold tx signing """Test cold tx signing
""" """
from __future__ import print_function
from framework.daemon import Daemon from framework.daemon import Daemon
from framework.wallet import Wallet from framework.wallet import Wallet
@ -44,13 +43,13 @@ class ColdSigningTest():
self.transfer() self.transfer()
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() daemon.flush_txpool()
def create(self, idx): def create(self, idx):
print 'Creating hot and cold wallet' print('Creating hot and cold wallet')
self.hot_wallet = Wallet(idx = 0) self.hot_wallet = Wallet(idx = 0)
# close the wallet if any, will throw if none is loaded # close the wallet if any, will throw if none is loaded
@ -116,7 +115,7 @@ class ColdSigningTest():
assert len(res.unsigned_txset) > 0 assert len(res.unsigned_txset) > 0
unsigned_txset = res.unsigned_txset 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) res = self.cold_wallet.describe_transfer(unsigned_txset = unsigned_txset)
assert len(res.desc) == 1 assert len(res.desc) == 1
desc = res.desc[0] desc = res.desc[0]
@ -140,7 +139,7 @@ class ColdSigningTest():
txid = res.tx_hash_list[0] txid = res.tx_hash_list[0]
assert len(txid) == 64 assert len(txid) == 64
print 'Submitting transaction with hot wallet' print('Submitting transaction with hot wallet')
res = self.hot_wallet.submit_transfer(signed_txset) res = self.hot_wallet.submit_transfer(signed_txset)
assert len(res.tx_hash_list) > 0 assert len(res.tx_hash_list) > 0
assert res.tx_hash_list[0] == txid 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 from framework.daemon import Daemon
class DaemonGetInfoTest(): class DaemonGetInfoTest():

@ -10,7 +10,7 @@ import string
import os import os
USAGE = 'usage: functional_tests_rpc.py <python> <srcdir> <builddir> [<tests-to-run> | all]' 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: try:
python = sys.argv[1] python = sys.argv[1]
srcdir = sys.argv[2] srcdir = sys.argv[2]

@ -28,11 +28,10 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time
"""Test get_output_distribution RPC """Test get_output_distribution RPC
""" """
from __future__ import print_function
from framework.daemon import Daemon from framework.daemon import Daemon
from framework.wallet import Wallet from framework.wallet import Wallet
@ -43,7 +42,7 @@ class GetOutputDistributionTest():
self.test_get_output_distribution() self.test_get_output_distribution()
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() 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') 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): def test_get_output_distribution(self):
print "Test get_output_distribution" print("Test get_output_distribution")
daemon = Daemon() daemon = Daemon()
@ -213,5 +212,14 @@ class GetOutputDistributionTest():
assert d.distribution[h] == 0 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__': 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 # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time
"""Test integrated address RPC calls """Test integrated address RPC calls
Test the following RPCs: Test the following RPCs:
@ -38,6 +36,7 @@ Test the following RPCs:
""" """
from __future__ import print_function
from framework.wallet import Wallet from framework.wallet import Wallet
class IntegratedAddressTest(): class IntegratedAddressTest():
@ -46,7 +45,7 @@ class IntegratedAddressTest():
self.check() self.check()
def create(self): def create(self):
print 'Creating wallet' print('Creating wallet')
wallet = Wallet() wallet = Wallet()
# close the wallet if any, will throw if none is loaded # close the wallet if any, will throw if none is loaded
try: wallet.close_wallet() try: wallet.close_wallet()
@ -59,7 +58,7 @@ class IntegratedAddressTest():
def check(self): def check(self):
wallet = Wallet() wallet = Wallet()
print 'Checking local address' print('Checking local address')
res = wallet.make_integrated_address(payment_id = '0123456789abcdef') res = wallet.make_integrated_address(payment_id = '0123456789abcdef')
assert res.integrated_address == '4CMe2PUhs4J4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfSbLRB61BQVATzerHGj' assert res.integrated_address == '4CMe2PUhs4J4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfSbLRB61BQVATzerHGj'
assert res.payment_id == '0123456789abcdef' assert res.payment_id == '0123456789abcdef'
@ -67,7 +66,7 @@ class IntegratedAddressTest():
assert res.standard_address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res.standard_address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
assert res.payment_id == '0123456789abcdef' assert res.payment_id == '0123456789abcdef'
print 'Checking different address' print('Checking different address')
res = wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', payment_id = '1122334455667788') res = wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', payment_id = '1122334455667788')
assert res.integrated_address == '4GYjoMG9Y2BBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCVSs1ZojwrDCGS5rUuo' assert res.integrated_address == '4GYjoMG9Y2BBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCVSs1ZojwrDCGS5rUuo'
assert res.payment_id == '1122334455667788' assert res.payment_id == '1122334455667788'
@ -75,7 +74,7 @@ class IntegratedAddressTest():
assert res.standard_address == '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK' assert res.standard_address == '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK'
assert res.payment_id == '1122334455667788' assert res.payment_id == '1122334455667788'
print 'Checking bad payment id' print('Checking bad payment id')
fails = 0 fails = 0
try: wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', payment_id = '11223344556677880') try: wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', payment_id = '11223344556677880')
except: fails += 1 except: fails += 1
@ -89,7 +88,7 @@ class IntegratedAddressTest():
except: fails += 1 except: fails += 1
assert fails == 5 assert fails == 5
print 'Checking bad standard address' print('Checking bad standard address')
fails = 0 fails = 0
try: wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerr', payment_id = '1122334455667788') try: wallet.make_integrated_address(standard_address = '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerr', payment_id = '1122334455667788')
except: fails += 1 except: fails += 1

@ -28,6 +28,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
import time import time
"""Test daemon mining RPC calls """Test daemon mining RPC calls
@ -48,13 +49,13 @@ class MiningTest():
self.mine() self.mine()
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() daemon.flush_txpool()
def create(self): def create(self):
print 'Creating wallet' print('Creating wallet')
wallet = Wallet() wallet = Wallet()
# close the wallet if any, will throw if none is loaded # close the wallet if any, will throw if none is loaded
try: wallet.close_wallet() 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') 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): def mine(self):
print "Test mining" print("Test mining")
daemon = Daemon() daemon = Daemon()
wallet = Wallet() wallet = Wallet()

@ -28,7 +28,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time from __future__ import print_function
"""Test multisig transfers """Test multisig transfers
""" """
@ -70,7 +70,7 @@ class MultisigTest():
self.check_transaction(txid) self.check_transaction(txid)
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() daemon.flush_txpool()

@ -28,7 +28,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # 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) """Test misc proofs (tx key, send, receive, reserve)
""" """
@ -47,7 +47,7 @@ class ProofsTest():
self.check_reserve_proof() self.check_reserve_proof()
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() daemon.flush_txpool()

@ -28,7 +28,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # 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 """Test message signing/verification RPC calls
@ -46,7 +46,7 @@ class MessageSigningTest():
self.check_signing() self.check_signing()
def create(self): def create(self):
print 'Creating wallets' print('Creating wallets')
seeds = [ 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', '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', '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] assert res.seed == seeds[i]
def check_signing(self): def check_signing(self):
print 'Signing/verifing messages' print('Signing/verifing messages')
messages = ['foo', ''] messages = ['foo', '']
for message in messages: for message in messages:
res = self.wallet[0].sign(message) res = self.wallet[0].sign(message)

@ -40,7 +40,7 @@ Test the following RPCs:
import time import time
from time import sleep from time import sleep
from decimal import Decimal from __future__ import print_function
from framework.daemon import Daemon from framework.daemon import Daemon
from framework.wallet import Wallet from framework.wallet import Wallet

@ -28,7 +28,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time from __future__ import print_function
import json import json
"""Test simple transfers """Test simple transfers
@ -48,13 +48,13 @@ class TransferTest():
self.sweep_single() self.sweep_single()
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() daemon.flush_txpool()
def create(self): def create(self):
print 'Creating wallets' print('Creating wallets')
seeds = [ 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', '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', '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.unlocked_balance <= res.balance
assert res.blocks_to_unlock == 9 assert res.blocks_to_unlock == 9
print 'Creating multi out transfer' print('Creating multi out transfer')
self.wallet[0].refresh() self.wallet[0].refresh()

@ -28,7 +28,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time from __future__ import print_function
"""Test txpool """Test txpool
""" """
@ -44,13 +44,13 @@ class TransferTest():
self.check_txpool() self.check_txpool()
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() daemon.flush_txpool()
def create(self): def create(self):
print 'Creating wallet' print('Creating wallet')
wallet = Wallet() wallet = Wallet()
# close the wallet if any, will throw if none is loaded # close the wallet if any, will throw if none is loaded
try: wallet.close_wallet() try: wallet.close_wallet()
@ -114,15 +114,16 @@ class TransferTest():
assert sorted(res.tx_hashes) == sorted(txes.keys()) assert sorted(res.tx_hashes) == sorted(txes.keys())
print('Flushing 2 transactions') 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() res = daemon.get_transaction_pool()
assert len(res.transactions) == txpool_size - 2 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[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[3]]) == 0
new_keys = txes.keys() new_keys = list(txes.keys())
new_keys.remove(txes.keys()[1]) new_keys.remove(txes_keys[1])
new_keys.remove(txes.keys()[3]) new_keys.remove(txes_keys[3])
res = daemon.get_transaction_pool_hashes() res = daemon.get_transaction_pool_hashes()
assert sorted(res.tx_hashes) == sorted(new_keys) 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 # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time
"""Test transaction creation RPC calls """Test transaction creation RPC calls
Test the following RPCs: Test the following RPCs:
@ -38,6 +36,7 @@ Test the following RPCs:
""" """
from __future__ import print_function
from framework.wallet import Wallet from framework.wallet import Wallet
from framework.daemon import Daemon from framework.daemon import Daemon
@ -52,13 +51,13 @@ class WalletAddressTest():
self.languages() self.languages()
def reset(self): def reset(self):
print 'Resetting blockchain' print('Resetting blockchain')
daemon = Daemon() daemon = Daemon()
daemon.pop_blocks(1000) daemon.pop_blocks(1000)
daemon.flush_txpool() daemon.flush_txpool()
def create(self): def create(self):
print 'Creating wallet' print('Creating wallet')
wallet = Wallet() wallet = Wallet()
# close the wallet if any, will throw if none is loaded # close the wallet if any, will throw if none is loaded
try: wallet.close_wallet() try: wallet.close_wallet()
@ -69,7 +68,7 @@ class WalletAddressTest():
assert res.seed == seed assert res.seed == seed
def check_main_address(self): def check_main_address(self):
print 'Getting address' print('Getting address')
wallet = Wallet() wallet = Wallet()
res = wallet.get_address() res = wallet.get_address()
assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', res assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', res
@ -79,7 +78,7 @@ class WalletAddressTest():
assert res.addresses[0].used == False assert res.addresses[0].used == False
def check_keys(self): def check_keys(self):
print 'Checking keys' print('Checking keys')
wallet = Wallet() wallet = Wallet()
res = wallet.query_key('view_key') res = wallet.query_key('view_key')
assert res.key == '49774391fa5e8d249fc2c5b45dadef13534bf2483dede880dac88f061e809100' 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' 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): def create_subaddresses(self):
print 'Creating subaddresses' print('Creating subaddresses')
wallet = Wallet() wallet = Wallet()
res = wallet.create_account("idx1") res = wallet.create_account("idx1")
assert res.account_index == 1, res assert res.account_index == 1, res
@ -160,7 +159,7 @@ class WalletAddressTest():
assert res.index == {'major': 1, 'minor': 0} assert res.index == {'major': 1, 'minor': 0}
def open_close(self): def open_close(self):
print 'Testing open/close' print('Testing open/close')
wallet = Wallet() wallet = Wallet()
res = wallet.get_address() res = wallet.get_address()
@ -200,7 +199,7 @@ class WalletAddressTest():
except: pass except: pass
languages = res.languages languages = res.languages
for language in languages: for language in languages:
print 'Creating ' + str(language) + ' wallet' print('Creating ' + str(language) + ' wallet')
wallet.create_wallet(filename = '', language = language) wallet.create_wallet(filename = '', language = language)
res = wallet.query_key('mnemonic') res = wallet.query_key('mnemonic')
wallet.close_wallet() wallet.close_wallet()

@ -172,7 +172,7 @@ TEST(select_outputs, density)
float chain_ratio = count_chain / (float)n_outs; 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_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 << "%"); 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…
Cancel
Save