aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/base58.cpp1
-rw-r--r--src/common/int-util.h10
-rw-r--r--src/common/util.cpp1
-rw-r--r--src/common/util.h57
-rw-r--r--src/connectivity_tool/conn_tool.cpp6
-rw-r--r--src/cryptonote_core/blockchain_storage.cpp5
-rw-r--r--src/cryptonote_core/blockchain_storage.h2
-rw-r--r--src/cryptonote_core/connection_context.h45
-rw-r--r--src/cryptonote_core/cryptonote_basic_impl.cpp14
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp4
-rw-r--r--src/cryptonote_core/cryptonote_format_utils.h1
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h11
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl59
-rw-r--r--src/daemon/daemon.cpp18
-rw-r--r--src/daemon/daemon_commands_handler.h24
-rw-r--r--src/p2p/net_node.h2
-rw-r--r--src/p2p/net_node.inl57
-rw-r--r--src/p2p/net_node_common.h6
-rw-r--r--src/p2p/net_peerlist.h8
-rw-r--r--src/p2p/p2p_protocol_defs.h18
-rw-r--r--src/rpc/core_rpc_server.cpp105
-rw-r--r--src/rpc/core_rpc_server.h33
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h40
-rw-r--r--src/rpc/core_rpc_server_error_codes.h5
-rw-r--r--src/simplewallet/simplewallet.cpp272
-rw-r--r--src/simplewallet/simplewallet.h12
-rw-r--r--src/version.h.in2
-rw-r--r--src/wallet/wallet2.cpp113
-rw-r--r--src/wallet/wallet2.h186
29 files changed, 729 insertions, 388 deletions
diff --git a/src/common/base58.cpp b/src/common/base58.cpp
index 30042eeba..454c0db67 100644
--- a/src/common/base58.cpp
+++ b/src/common/base58.cpp
@@ -227,6 +227,7 @@ namespace tools
std::string addr_data;
bool r = decode(addr, addr_data);
if (!r) return false;
+ if (addr_data.size() <= addr_checksum_size) return false;
std::string checksum(addr_checksum_size, '\0');
checksum = addr_data.substr(addr_data.size() - addr_checksum_size);
diff --git a/src/common/int-util.h b/src/common/int-util.h
index ad0ef60e0..db9e9bea7 100644
--- a/src/common/int-util.h
+++ b/src/common/int-util.h
@@ -34,15 +34,15 @@ static inline uint64_t rol64(uint64_t x, int r) {
#endif
-inline uint64_t hi_dword(uint64_t val) {
+static inline uint64_t hi_dword(uint64_t val) {
return val >> 32;
}
-inline uint64_t lo_dword(uint64_t val) {
+static inline uint64_t lo_dword(uint64_t val) {
return val & 0xFFFFFFFF;
}
-inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) {
+static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) {
// multiplier = ab = a * 2^32 + b
// multiplicand = cd = c * 2^32 + d
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
@@ -68,14 +68,14 @@ inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* pro
return product_lo;
}
-inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) {
+static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) {
dividend |= ((uint64_t)*remainder) << 32;
*remainder = dividend % divisor;
return dividend / divisor;
}
// Long division with 2^32 base
-inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) {
+static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) {
uint64_t dividend_dwords[4];
uint32_t remainder = 0;
diff --git a/src/common/util.cpp b/src/common/util.cpp
index b24016cc3..c9c470851 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -21,6 +21,7 @@ using namespace epee;
namespace tools
{
+ std::function<void(void)> signal_handler::m_handler;
#ifdef WIN32
std::string get_windows_version_display_string()
diff --git a/src/common/util.h b/src/common/util.h
index a29a30fff..af92adf94 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -4,6 +4,7 @@
#pragma once
+#include <mutex>
#include <system_error>
#include <boost/filesystem.hpp>
@@ -26,4 +27,60 @@ namespace tools
s.append(reinterpret_cast<const char*>(&pot.time), sizeof(pot.time));
return crypto::cn_fast_hash(s.data(), s.size());
}
+
+
+ class signal_handler
+ {
+ public:
+ template<typename T>
+ static bool install(T t)
+ {
+#if defined(WIN32)
+ bool r = TRUE == ::SetConsoleCtrlHandler(&win_handler, TRUE);
+ if (r)
+ {
+ m_handler = t;
+ }
+ return r;
+#else
+ signal(SIGINT, posix_handler);
+ signal(SIGTERM, posix_handler);
+ m_handler = t;
+ return true;
+#endif
+ }
+
+ private:
+#if defined(WIN32)
+ static BOOL win_handler(DWORD type)
+ {
+ if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type)
+ {
+ handle_signal();
+ return TRUE;
+ }
+ else
+ {
+ LOG_PRINT_RED_L0("Got control signal " << type << ". Exiting without saving...");
+ return FALSE;
+ }
+ return TRUE;
+ }
+#else
+ static void posix_handler(int /*type*/)
+ {
+ handle_signal();
+ }
+#endif
+
+ static void handle_signal()
+ {
+ static std::mutex m_mutex;
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_handler();
+ }
+
+ private:
+ static std::function<void(void)> m_handler;
+ };
}
diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp
index 4b83b4f49..6743b4ae8 100644
--- a/src/connectivity_tool/conn_tool.cpp
+++ b/src/connectivity_tool/conn_tool.cpp
@@ -27,12 +27,12 @@ using namespace nodetool;
namespace
{
- const command_line::arg_descriptor<std::string, true> arg_ip = {"ip", "set ip"};
+ const command_line::arg_descriptor<std::string, true> arg_ip = {"ip", "set ip"};
const command_line::arg_descriptor<size_t> arg_port = {"port", "set port"};
const command_line::arg_descriptor<size_t> arg_rpc_port = {"rpc_port", "set rpc port"};
- const command_line::arg_descriptor<uint32_t, true> arg_timeout = {"timeout", "set timeout"};
+ const command_line::arg_descriptor<uint32_t, true> arg_timeout = {"timeout", "set timeout"};
const command_line::arg_descriptor<std::string> arg_priv_key = {"private_key", "private key to subscribe debug command", "", true};
- const command_line::arg_descriptor<boost::uint64_t> arg_peer_id = {"peer_id", "peer_id if known(if not - will be requested)", 0};
+ const command_line::arg_descriptor<uint64_t> arg_peer_id = {"peer_id", "peer_id if known(if not - will be requested)", 0};
const command_line::arg_descriptor<bool> arg_generate_keys = {"generate_keys_pair", "generate private and public keys pair"};
const command_line::arg_descriptor<bool> arg_request_stat_info = {"request_stat_info", "request statistics information"};
const command_line::arg_descriptor<bool> arg_request_net_state = {"request_net_state", "request network state information (peer list, connections count)"};
diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp
index 1ec186652..3eb7f86c0 100644
--- a/src/cryptonote_core/blockchain_storage.cpp
+++ b/src/cryptonote_core/blockchain_storage.cpp
@@ -104,6 +104,9 @@ bool blockchain_storage::init(const std::string& config_folder)
//------------------------------------------------------------------
bool blockchain_storage::store_blockchain()
{
+ m_is_blockchain_storing = true;
+ misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){m_is_blockchain_storing=false;});
+
LOG_PRINT_L0("Storing blockchain...");
if (!tools::create_directories_if_necessary(m_config_folder))
{
@@ -1029,7 +1032,7 @@ void blockchain_storage::print_blockchain(uint64_t start_index, uint64_t end_ind
for(size_t i = start_index; i != m_blocks.size() && i != end_index; i++)
{
- ss << "height " << i << ", timastamp " << m_blocks[i].bl.timestamp << ", cumul_dif " << m_blocks[i].cumulative_difficulty << ", cumul_size " << m_blocks[i].block_cumulative_size
+ ss << "height " << i << ", timestamp " << m_blocks[i].bl.timestamp << ", cumul_dif " << m_blocks[i].cumulative_difficulty << ", cumul_size " << m_blocks[i].block_cumulative_size
<< "\nid\t\t" << get_block_hash(m_blocks[i].bl)
<< "\ndifficulty\t\t" << block_difficulty(i) << ", nonce " << m_blocks[i].bl.nonce << ", tx_count " << m_blocks[i].bl.tx_hashes.size() << ENDL;
}
diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h
index 4ff5e83ff..c263f7503 100644
--- a/src/cryptonote_core/blockchain_storage.h
+++ b/src/cryptonote_core/blockchain_storage.h
@@ -110,6 +110,7 @@ namespace cryptonote
bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL);
bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id);
uint64_t get_current_comulative_blocksize_limit();
+ bool is_storing_blockchain(){return m_is_blockchain_storing;}
template<class t_ids_container, class t_blocks_container, class t_missed_container>
bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs)
@@ -188,6 +189,7 @@ namespace cryptonote
std::string m_config_folder;
checkpoints m_checkpoints;
std::atomic<bool> m_is_in_checkpoint_zone;
+ std::atomic<bool> m_is_blockchain_storing;
diff --git a/src/cryptonote_core/connection_context.h b/src/cryptonote_core/connection_context.h
index bf13449bc..53cac992d 100644
--- a/src/cryptonote_core/connection_context.h
+++ b/src/cryptonote_core/connection_context.h
@@ -6,32 +6,10 @@
#include <unordered_set>
#include <atomic>
#include "net/net_utils_base.h"
-
+#include "copyable_atomic.h"
namespace cryptonote
{
- class my_atomic: public std::atomic<uint32_t>
- {
- public:
- my_atomic()
- {};
- my_atomic(const my_atomic& a):std::atomic<uint32_t>(a.load())
- {}
- my_atomic& operator= (const my_atomic& a)
- {
- store(a.load());
- return *this;
- }
- uint32_t operator++()
- {
- return std::atomic<uint32_t>::operator++();
- }
- uint32_t operator++(int fake)
- {
- return std::atomic<uint32_t>::operator++(fake);
- }
- };
-
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
{
@@ -40,6 +18,7 @@ namespace cryptonote
{
state_befor_handshake = 0, //default state
state_synchronizing,
+ state_idle,
state_normal
};
@@ -48,7 +27,25 @@ namespace cryptonote
std::unordered_set<crypto::hash> m_requested_objects;
uint64_t m_remote_blockchain_height;
uint64_t m_last_response_height;
- my_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
+ epee::copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
//size_t m_score; TODO: add score calculations
};
+
+ inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
+ {
+ switch (s)
+ {
+ case cryptonote_connection_context::state_befor_handshake:
+ return "state_befor_handshake";
+ case cryptonote_connection_context::state_synchronizing:
+ return "state_synchronizing";
+ case cryptonote_connection_context::state_idle:
+ return "state_idle";
+ case cryptonote_connection_context::state_normal:
+ return "state_normal";
+ default:
+ return "unknown";
+ }
+ }
+
}
diff --git a/src/cryptonote_core/cryptonote_basic_impl.cpp b/src/cryptonote_core/cryptonote_basic_impl.cpp
index b320a3463..194b89052 100644
--- a/src/cryptonote_core/cryptonote_basic_impl.cpp
+++ b/src/cryptonote_core/cryptonote_basic_impl.cpp
@@ -109,25 +109,25 @@ namespace cryptonote {
uint64_t prefix;
if (!tools::base58::decode_addr(str, prefix, data))
{
- LOG_PRINT_L0("Invalid address format");
+ LOG_PRINT_L1("Invalid address format");
return false;
}
if (CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX != prefix)
{
- LOG_PRINT_L0("Wrong address prefix: " << prefix << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX);
+ LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX);
return false;
}
if (!::serialization::parse_binary(data, adr))
{
- LOG_PRINT_L0("Account public address keys can't be parsed");
+ LOG_PRINT_L1("Account public address keys can't be parsed");
return false;
}
if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key))
{
- LOG_PRINT_L0("Failed to validate address keys");
+ LOG_PRINT_L1("Failed to validate address keys");
return false;
}
}
@@ -140,7 +140,7 @@ namespace cryptonote {
if(buff.size()!=sizeof(public_address_outer_blob))
{
- LOG_PRINT_L0("Wrong public address size: " << buff.size() << ", expected size: " << sizeof(public_address_outer_blob));
+ LOG_PRINT_L1("Wrong public address size: " << buff.size() << ", expected size: " << sizeof(public_address_outer_blob));
return false;
}
@@ -149,13 +149,13 @@ namespace cryptonote {
if(blob.m_ver > CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER)
{
- LOG_PRINT_L0("Unknown version of public address: " << blob.m_ver << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER);
+ LOG_PRINT_L1("Unknown version of public address: " << blob.m_ver << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER);
return false;
}
if(blob.check_sum != get_account_address_checksum(blob))
{
- LOG_PRINT_L0("Wrong public address checksum");
+ LOG_PRINT_L1("Wrong public address checksum");
return false;
}
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index d5ab8d65a..a09f25d31 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -230,9 +230,9 @@ namespace cryptonote
return false;
}
- boost::uint64_t amount_in = 0;
+ uint64_t amount_in = 0;
get_inputs_money_amount(tx, amount_in);
- boost::uint64_t amount_out = get_outs_money_amount(tx);
+ uint64_t amount_out = get_outs_money_amount(tx);
if(amount_in <= amount_out)
{
diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h
index 1c50832b6..1bc180f8f 100644
--- a/src/cryptonote_core/cryptonote_format_utils.h
+++ b/src/cryptonote_core/cryptonote_format_utils.h
@@ -139,7 +139,6 @@ namespace cryptonote
{
if (0 == amount)
{
- chunk_handler(0);
return;
}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index f599cf40f..178ec2eb1 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -22,7 +22,7 @@ namespace cryptonote
template<class t_core>
class t_cryptonote_protocol_handler: public i_cryptonote_protocol
- {
+ {
public:
typedef cryptonote_connection_context connection_context;
typedef core_stat_info stat_info;
@@ -51,8 +51,8 @@ namespace cryptonote
bool get_stat_info(core_stat_info& stat_inf);
bool on_callback(cryptonote_connection_context& context);
t_core& get_core(){return m_core;}
-
-
+ bool is_synchronized(){return m_synchronized;}
+ void log_connections();
private:
//----------------- commands handlers ----------------------------------------------
int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context);
@@ -60,7 +60,6 @@ namespace cryptonote
int handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context);
int handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context);
int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context);
-// int handle_request_chain_entry(int command, NOTIFY_REQUEST_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context);
int handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context);
@@ -77,9 +76,7 @@ namespace cryptonote
nodetool::p2p_endpoint_stub<connection_context> m_p2p_stub;
nodetool::i_p2p_endpoint<connection_context>* m_p2p;
std::atomic<uint32_t> m_syncronized_connections_count;
- //std::atomic<uint32_t> m_syncronizing_connections_count;
- std::atomic<bool> m_welcome_showed;
-
+ std::atomic<bool> m_synchronized;
template<class t_parametr>
bool post_notify(typename t_parametr::request& arg, cryptonote_connection_context& context)
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 9c9668071..287461caa 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -13,7 +13,7 @@ namespace cryptonote
t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore),
m_p2p(p_net_layout),
m_syncronized_connections_count(0),
- m_welcome_showed(false)
+ m_synchronized(false)
{
if(!m_p2p)
@@ -68,6 +68,30 @@ namespace cryptonote
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
+ void t_cryptonote_protocol_handler<t_core>::log_connections()
+ {
+ std::stringstream ss;
+
+ ss << std::setw(25) << std::left << "Remote Host"
+ << std::setw(20) << "Peer id"
+ << std::setw(25) << "Recv/Sent (inactive,sec)"
+ << std::setw(25) << "State"
+ << std::setw(20) << "Livetime(seconds)" << ENDL;
+
+ m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
+ {
+ ss << std::setw(25) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
+ string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
+ << std::setw(20) << std::hex << peer_id
+ << std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
+ << std::setw(25) << get_protocol_state_string(cntxt.m_state)
+ << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started) << ENDL;
+ return true;
+ });
+ LOG_PRINT_L0("Connections: " << ENDL << ss.str());
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital)
{
if(context.m_state == cryptonote_connection_context::state_befor_handshake && !is_inital)
@@ -84,7 +108,7 @@ namespace cryptonote
return true;
}
- LOG_PRINT_CCONTEXT_BLUE("Sync data returned unknown top block " << "["<< m_core.get_current_blockchain_height() << "->" << hshd.current_height << "] " << hshd.top_id << ", set SYNCHRONIZATION mode", LOG_LEVEL_0);
+ LOG_PRINT_CCONTEXT_BLUE("Sync data returned unknown top block " << "["<< m_core.get_current_blockchain_height() << "->" << hshd.current_height << "] " << hshd.top_id << ", set SYNCHRONIZATION mode", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1));
context.m_state = cryptonote_connection_context::state_synchronizing;
context.m_remote_blockchain_height = hshd.current_height;
//let the socket to send response to handshake, but request callback, to let send request data after response
@@ -93,14 +117,6 @@ namespace cryptonote
m_p2p->request_callback(context);
return true;
}
- //------------------------------------------------------------------------------------------------------------------------
- /* template<class t_core>
- bool t_cryptonote_protocol_handler<t_core>::process_handshake_data(const blobdata& data, cryptonote_connection_context& context)
- {
- CORE_SYNC_DATA hsd = boost::value_initialized<CORE_SYNC_DATA>();
- StorageNamed::load_struct_from_storage_buff(hsd, data);
- return process_handshake_data(hsd, context);
- }*/
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(CORE_SYNC_DATA& hshd)
@@ -228,8 +244,10 @@ namespace cryptonote
context.m_remote_blockchain_height = arg.current_blockchain_height;
+ size_t count = 0;
BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
{
+ ++count;
block b;
if(!parse_and_validate_block_from_blob(block_entry.block, b))
{
@@ -237,6 +255,18 @@ namespace cryptonote
<< string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection");
m_p2p->drop_connection(context);
return 1;
+ }
+ //to avoid concurrency in core between connections, suspend connections which delivered block later then first one
+ if(count == 2)
+ {
+ if(m_core.have_block(get_block_hash(b)))
+ {
+ context.m_state = cryptonote_connection_context::state_idle;
+ context.m_needed_objects.clear();
+ context.m_requested_objects.clear();
+ LOG_PRINT_CCONTEXT_L1("Connection set to idle state.");
+ return 1;
+ }
}
auto req_it = context.m_requested_objects.find(get_block_hash(b));
@@ -380,10 +410,7 @@ namespace cryptonote
context.m_state = cryptonote_connection_context::state_normal;
LOG_PRINT_CCONTEXT_GREEN(" SYNCHRONIZED OK", LOG_LEVEL_0);
- if( true/*get_synchronizing_connections_count() == 0 && !m_welcome_showed*/)
- {
- on_connection_synchronized();
- }
+ on_connection_synchronized();
}
return true;
}
@@ -392,7 +419,7 @@ namespace cryptonote
bool t_cryptonote_protocol_handler<t_core>::on_connection_synchronized()
{
bool val_expected = false;
- if(m_welcome_showed.compare_exchange_strong(val_expected, true))
+ if(m_synchronized.compare_exchange_strong(val_expected, true))
{
LOG_PRINT_L0(ENDL << "**********************************************************************" << ENDL
<< "You are now synchronized with the network. You may now start simplewallet." << ENDL
@@ -411,7 +438,7 @@ namespace cryptonote
size_t t_cryptonote_protocol_handler<t_core>::get_synchronizing_connections_count()
{
size_t count = 0;
- m_p2p->for_each_connection([&](cryptonote_connection_context& context)->bool{
+ m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id)->bool{
if(context.m_state == cryptonote_connection_context::state_synchronizing)
++count;
return true;
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index d1ac3714b..528c024ba 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -38,6 +38,7 @@ namespace
const command_line::arg_descriptor<bool> arg_os_version = {"os-version", ""};
const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", "", ""};
const command_line::arg_descriptor<int> arg_log_level = {"log-level", "", LOG_LEVEL_0};
+ const command_line::arg_descriptor<bool> arg_console = {"no-console", "Disable daemon console commands"};
}
bool command_line_preprocessor(const boost::program_options::variables_map& vm);
@@ -67,6 +68,8 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, arg_log_file);
command_line::add_arg(desc_cmd_sett, arg_log_level);
+ command_line::add_arg(desc_cmd_sett, arg_console);
+
cryptonote::core::init_options(desc_cmd_sett);
cryptonote::core_rpc_server::init_options(desc_cmd_sett);
@@ -118,6 +121,7 @@ int main(int argc, char* argv[])
log_dir = log_file_path.has_parent_path() ? log_file_path.parent_path().string() : log_space::log_singletone::get_default_log_folder();
log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str());
+ LOG_PRINT_L0(CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG);
if (command_line_preprocessor(vm))
{
@@ -162,15 +166,23 @@ int main(int argc, char* argv[])
res = ccore.init(vm);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core");
LOG_PRINT_L0("Core initialized OK");
-
+
// start components
- dch.start_handling();
+ if(!command_line::has_arg(vm, arg_console))
+ {
+ dch.start_handling();
+ }
LOG_PRINT_L0("Starting core rpc server...");
res = rpc_server.run(2, false);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server.");
LOG_PRINT_L0("Core rpc server started ok");
+ tools::signal_handler::install([&dch, &p2psrv] {
+ dch.stop_handling();
+ p2psrv.send_stop_signal();
+ });
+
LOG_PRINT_L0("Starting p2p net loop...");
p2psrv.run();
LOG_PRINT_L0("p2p net loop stopped");
@@ -205,7 +217,7 @@ bool command_line_preprocessor(const boost::program_options::variables_map& vm)
bool exit = false;
if (command_line::get_arg(vm, command_line::arg_version))
{
- std::cout << CRYPTONOTE_NAME << PROJECT_VERSION_LONG << ENDL;
+ std::cout << CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL;
exit = true;
}
if (command_line::get_arg(vm, arg_os_version))
diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h
index 2edd5d414..7695508c9 100644
--- a/src/daemon/daemon_commands_handler.h
+++ b/src/daemon/daemon_commands_handler.h
@@ -38,10 +38,15 @@ public:
bool start_handling()
{
- m_cmd_binder.start_handling(&m_srv, "");
+ m_cmd_binder.start_handling(&m_srv, "", "");
return true;
}
+ void stop_handling()
+ {
+ m_cmd_binder.stop_handling();
+ }
+
private:
epee::srv_console_handlers_binder<nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > > m_cmd_binder;
@@ -77,7 +82,13 @@ private:
//--------------------------------------------------------------------------------
bool show_hr(const std::vector<std::string>& args)
{
- m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true);
+ if(!m_srv.get_payload_object().get_core().get_miner().is_mining())
+ {
+ std::cout << "Mining is not started. You need start mining before you can see hash rate." << ENDL;
+ } else
+ {
+ m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true);
+ }
return true;
}
//--------------------------------------------------------------------------------
@@ -100,7 +111,7 @@ private:
//--------------------------------------------------------------------------------
bool print_cn(const std::vector<std::string>& args)
{
- m_srv.log_connections();
+ m_srv.get_payload_object().log_connections();
return true;
}
//--------------------------------------------------------------------------------
@@ -263,7 +274,7 @@ private:
{
if(!args.size())
{
- std::cout << "target account address for mining is not set" << std::endl;
+ std::cout << "Please, specify wallet address to mine for: start_mining <addr> [threads=1]" << std::endl;
return true;
}
@@ -273,10 +284,11 @@ private:
std::cout << "target account address has wrong format" << std::endl;
return true;
}
- size_t threads_count = 1;
+ size_t threads_count = 1;
if(args.size() > 1)
{
- string_tools::get_xtype_from_string(threads_count, args[1]);
+ bool ok = string_tools::get_xtype_from_string(threads_count, args[1]);
+ threads_count = (ok && 0 < threads_count) ? threads_count : 1;
}
m_srv.get_payload_object().get_core().get_miner().start(adr, threads_count);
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 32249a6d1..794b97429 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -121,7 +121,7 @@ namespace nodetool
virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context);
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
virtual void request_callback(const epee::net_utils::connection_context_base& context);
- virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&)> f);
+ virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f);
//-----------------------------------------------------------------------------------------------
bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr);
bool handle_command_line(const boost::program_options::variables_map& vm);
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index a5e534f8a..2b46470d9 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -76,10 +76,10 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&)> f)
+ void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f)
{
m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){
- return f(cntx);
+ return f(cntx, cntx.peer_id);
});
}
//-----------------------------------------------------------------------------------
@@ -143,20 +143,59 @@ namespace nodetool
m_hide_my_port = true; return true;
}
//-----------------------------------------------------------------------------------
-#define ADD_HARDCODED_SEED_NODE(addr_str) { nodetool::net_address na = AUTO_VAL_INIT(na);bool r = parse_peer_from_string(na, addr_str); \
- CHECK_AND_ASSERT_MES(r, false, "Failed to parse seed address from string: " << addr_str); m_seed_nodes.push_back(na); }
+ namespace
+ {
+ template<typename T>
+ bool append_net_address(T& nodes, const std::string& addr)
+ {
+ using namespace boost::asio;
+
+ size_t pos = addr.find_last_of(':');
+ CHECK_AND_ASSERT_MES(std::string::npos != pos && addr.length() - 1 != pos && 0 != pos, false, "Failed to parse seed address from string: '" << addr << '\'');
+ std::string host = addr.substr(0, pos);
+ std::string port = addr.substr(pos + 1);
+
+ io_service io_srv;
+ ip::tcp::resolver resolver(io_srv);
+ ip::tcp::resolver::query query(host, port);
+ boost::system::error_code ec;
+ ip::tcp::resolver::iterator i = resolver.resolve(query, ec);
+ CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to resolve host name '" << host << "': " << ec.message() << ':' << ec.value());
+
+ ip::tcp::resolver::iterator iend;
+ for (; i != iend; ++i)
+ {
+ ip::tcp::endpoint endpoint = *i;
+ if (endpoint.address().is_v4())
+ {
+ nodetool::net_address na;
+ na.ip = boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong());
+ na.port = endpoint.port();
+ nodes.push_back(na);
+ LOG_PRINT_L4("Added seed node: " << endpoint.address().to_v4().to_string(ec) << ':' << na.port);
+ }
+ else
+ {
+ LOG_PRINT_L2("IPv6 doesn't supported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec));
+ }
+ }
+ return true;
+ }
+ }
+ #define ADD_HARDCODED_SEED_NODE(addr) append_net_address(m_seed_nodes, addr);
+ //-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm)
{
-
+ ADD_HARDCODED_SEED_NODE("seed.bytecoin.org:8080");
ADD_HARDCODED_SEED_NODE("85.25.201.95:8080");
ADD_HARDCODED_SEED_NODE("85.25.196.145:8080");
ADD_HARDCODED_SEED_NODE("85.25.196.146:8080");
ADD_HARDCODED_SEED_NODE("85.25.196.144:8080");
ADD_HARDCODED_SEED_NODE("5.199.168.138:8080");
- ADD_HARDCODED_SEED_NODE("62.75.236.152:8080");
+ ADD_HARDCODED_SEED_NODE("62.75.236.152:8080");
ADD_HARDCODED_SEED_NODE("85.25.194.245:8080");
ADD_HARDCODED_SEED_NODE("95.211.224.160:8080");
ADD_HARDCODED_SEED_NODE("144.76.200.44:8080");
@@ -290,7 +329,7 @@ namespace nodetool
bool r = net_utils::async_invoke_remote_command2<typename COMMAND_HANDSHAKE::response>(context_.m_connection_id, COMMAND_HANDSHAKE::ID, arg, m_net_server.get_config_object(),
[this, &pi, &ev, &hsh_result, &just_take_peerlist](int code, const typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context)
{
- misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){ev.rise();});
+ misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){ev.raise();});
if(code < 0)
{
@@ -542,7 +581,7 @@ namespace nodetool
LOG_PRINT_RED_L0("Failed to connect to any of seed peers, continuing without seeds");
break;
}
- if(++current_index > m_seed_nodes.size())
+ if(++current_index >= m_seed_nodes.size())
current_index = 0;
}
}
@@ -939,7 +978,7 @@ namespace nodetool
if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port)
{
peerid_type peer_id_l = arg.node_data.peer_id;
- boost::uint32_t port_l = arg.node_data.my_port;
+ uint32_t port_l = arg.node_data.my_port;
//try ping to be sure that we can add this peer to peer_list
try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]()
{
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index db8b63095..17ae20cbe 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -6,7 +6,7 @@
#include <boost/uuid/uuid.hpp>
#include "net/net_utils_base.h"
-
+#include "p2p_protocol_defs.h"
namespace nodetool
{
@@ -23,7 +23,7 @@ namespace nodetool
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
virtual void request_callback(const epee::net_utils::connection_context_base& context)=0;
virtual uint64_t get_connections_count()=0;
- virtual void for_each_connection(std::function<bool(t_connection_context&)> f)=0;
+ virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type)> f)=0;
};
template<class t_connection_context>
@@ -49,7 +49,7 @@ namespace nodetool
{
}
- virtual void for_each_connection(std::function<bool(t_connection_context&)> f)
+ virtual void for_each_connection(std::function<bool(t_connection_context&,peerid_type)> f)
{
}
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index 65dfd011a..ea541fcbc 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -49,7 +49,7 @@ namespace nodetool
bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
bool append_with_peer_white(const peerlist_entry& pr);
bool append_with_peer_gray(const peerlist_entry& pr);
- bool set_peer_just_seen(peerid_type peer, boost::uint32_t ip, boost::uint32_t port);
+ bool set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port);
bool set_peer_just_seen(peerid_type peer, const net_address& addr);
bool set_peer_unreachable(const peerlist_entry& pr);
bool is_ip_allowed(uint32_t ip);
@@ -284,7 +284,7 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::set_peer_just_seen(peerid_type peer, boost::uint32_t ip, boost::uint32_t port)
+ bool peerlist_manager::set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port)
{
net_address addr;
addr.ip = ip;
@@ -343,10 +343,6 @@ namespace nodetool
if(!is_ip_allowed(ple.adr.ip))
return true;
- if(ple.adr.port != 8080)
- assert(false);
-
-
CRITICAL_REGION_LOCAL(m_peerlist_lock);
//find in white list
auto by_addr_it_wt = m_peers_white.get<by_addr>().find(ple.adr);
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index 7ae6d08f3..9994dca4c 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -19,8 +19,8 @@ namespace nodetool
struct net_address
{
- boost::uint32_t ip;
- boost::uint32_t port;
+ uint32_t ip;
+ uint32_t port;
};
struct peerlist_entry
@@ -74,13 +74,13 @@ namespace nodetool
KV_SERIALIZE(config_id)
END_KV_SERIALIZE_MAP()
- boost::uint32_t connections_count;
- boost::uint32_t connection_timeout;
- boost::uint32_t ping_connection_timeout;
- boost::uint32_t handshake_interval;
- boost::uint32_t packet_max_size;
- boost::uint32_t config_id;
- boost::uint32_t send_peerlist_sz;
+ uint32_t connections_count;
+ uint32_t connection_timeout;
+ uint32_t ping_connection_timeout;
+ uint32_t handshake_interval;
+ uint32_t packet_max_size;
+ uint32_t config_id;
+ uint32_t send_peerlist_sz;
};
struct basic_node_data
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 984d9d8cd..68df17b9f 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -45,17 +45,35 @@ namespace cryptonote
m_net_server.set_threads_prefix("RPC");
bool r = handle_command_line(vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server");
- return epee::http_server_impl_base<core_rpc_server>::init(m_port, m_bind_ip);
+ return epee::http_server_impl_base<core_rpc_server, connection_context>::init(m_port, m_bind_ip);
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res)
+ bool core_rpc_server::check_core_ready()
{
+ if(!m_p2p.get_payload_object().is_synchronized())
+ {
+ return false;
+ }
+ if(m_p2p.get_payload_object().get_core().get_blockchain_storage().is_storing_blockchain())
+ {
+ return false;
+ }
+ return true;
+ }
+#define CHECK_CORE_READY() if(!check_core_ready()){res.status = CORE_RPC_STATUS_BUSY;return true;}
+
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, connection_context& cntx)
+ {
+ CHECK_CORE_READY();
res.height = m_core.get_current_blockchain_height();
+ res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res)
+ bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx)
{
+ CHECK_CORE_READY();
res.height = m_core.get_current_blockchain_height();
res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block();
res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase
@@ -66,21 +84,13 @@ namespace cryptonote
res.incoming_connections_count = total_conn - res.outgoing_connections_count;
res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count();
res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count();
+ res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_known_block_ids(const COMMAND_RPC_GET_KNOWN_BLOCK_IDS::request& req, COMMAND_RPC_GET_KNOWN_BLOCK_IDS::response& res)
- {
- std::list<crypto::hash> main, alt, invalid;
- m_core.get_all_known_block_ids(main, alt, invalid);
- BOOST_FOREACH(crypto::hash &h, main)
- res.main.push_back(string_tools::pod_to_hex(h));
-
- return true;
- }
- //------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res)
+ bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, connection_context& cntx)
{
+ CHECK_CORE_READY();
std::list<std::pair<block, std::list<transaction> > > bs;
if(!m_core.find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
{
@@ -102,8 +112,9 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)
+ bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx)
{
+ CHECK_CORE_READY();
res.status = "Failed";
if(!m_core.get_random_outs_for_amounts(req, res))
{
@@ -115,23 +126,24 @@ namespace cryptonote
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount;
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
std::for_each(res.outs.begin(), res.outs.end(), [&](outs_for_amount& ofa)
- {
- ss << "[" << ofa.amount << "]:";
- CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << ofa.amount);
- std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe)
- {
- ss << oe.global_amount_index << " ";
- });
- ss << ENDL;
- });
+ {
+ ss << "[" << ofa.amount << "]:";
+ CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << ofa.amount);
+ std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe)
+ {
+ ss << oe.global_amount_index << " ";
+ });
+ ss << ENDL;
+ });
std::string s = ss.str();
LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s);
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res)
+ bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx)
{
+ CHECK_CORE_READY();
bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes);
if(!r)
{
@@ -143,8 +155,9 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res)
+ bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, connection_context& cntx)
{
+ CHECK_CORE_READY();
std::vector<crypto::hash> vh;
BOOST_FOREACH(const auto& tx_hex_str, req.txs_hashes)
{
@@ -184,12 +197,7 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- /*bool core_rpc_server::on_get_outputs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res)
- {
- return true;
- }*/
- //------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res)
+ bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx)
{
std::string tx_blob;
if(!string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob))
@@ -231,8 +239,9 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res)
+ bool core_rpc_server::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx)
{
+ CHECK_CORE_READY();
account_public_address adr;
if(!get_account_address_from_str(adr, req.miner_address))
{
@@ -249,9 +258,9 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res)
+ bool core_rpc_server::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx)
{
-
+ CHECK_CORE_READY();
if(!m_core.get_miner().stop())
{
res.status = "Failed, mining not stopped";
@@ -261,14 +270,22 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res)
+ bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx)
{
- res = m_core.get_current_blockchain_height();
+ CHECK_CORE_READY();
+ res.count = m_core.get_current_blockchain_height();
+ res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp)
+ bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
{
+ if(!check_core_ready())
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
+ error_resp.message = "Core is busy";
+ return false;
+ }
if(req.size() != 1)
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
@@ -300,8 +317,15 @@ namespace cryptonote
return 0;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp)
+ bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
{
+ if(!check_core_ready())
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
+ error_resp.message = "Core is busy";
+ return false;
+ }
+
if(req.reserve_size > 255)
{
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE;
@@ -359,8 +383,9 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp)
+ bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
{
+ CHECK_CORE_READY();
if(req.size()!=1)
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 4425a1ce5..fb3e92216 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -21,17 +21,18 @@ namespace cryptonote
class core_rpc_server: public epee::http_server_impl_base<core_rpc_server>
{
public:
+ typedef epee::net_utils::connection_context_base connection_context;
+
core_rpc_server(core& cr, nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& p2p);
static void init_options(boost::program_options::options_description& desc);
bool init(const boost::program_options::variables_map& vm);
private:
- CHAIN_HTTP_TO_MAP2(); //forward http requests to uri map
+ CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map
BEGIN_URI_MAP2()
MAP_URI_AUTO_JON2("/getheight", on_get_height, COMMAND_RPC_GET_HEIGHT)
- MAP_URI_AUTO_JON2("/getknownblockids", on_get_known_block_ids, COMMAND_RPC_GET_KNOWN_BLOCK_IDS)
MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST)
MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES)
MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS)
@@ -48,24 +49,24 @@ namespace cryptonote
END_JSON_RPC_MAP()
END_URI_MAP2()
- bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res);
- bool on_get_known_block_ids(const COMMAND_RPC_GET_KNOWN_BLOCK_IDS::request& req, COMMAND_RPC_GET_KNOWN_BLOCK_IDS::response& res);
- bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res);
- bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res);
- bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res);
- bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res);
- bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res);
- bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res);
- bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res);
- bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
+ bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, connection_context& cntx);
+ bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, connection_context& cntx);
+ bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, connection_context& cntx);
+ bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx);
+ bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx);
+ bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx);
+ bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx);
+ bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx);
+ bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx);
//json_rpc
- bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res);
- bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp);
- bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp);
- bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp);
+ bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx);
+ bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
+ bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
+ bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
//-----------------------
bool handle_command_line(const boost::program_options::variables_map& vm);
+ bool check_core_ready();
core& m_core;
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index fbb7171a1..5e8210775 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -11,6 +11,7 @@ namespace cryptonote
{
//-----------------------------------------------
#define CORE_RPC_STATUS_OK "OK"
+#define CORE_RPC_STATUS_BUSY "BUSY"
struct COMMAND_RPC_GET_HEIGHT
{
@@ -23,35 +24,15 @@ namespace cryptonote
struct response
{
uint64_t height;
+ std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height)
+ KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
};
- struct COMMAND_RPC_GET_KNOWN_BLOCK_IDS
- {
- struct request
- {
- BEGIN_KV_SERIALIZE_MAP()
- END_KV_SERIALIZE_MAP()
- };
-
- struct response
- {
- std::list<std::string> main;
- std::list<std::string> alt;
- std::list<std::string> invalid;
-
- BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(main)
- KV_SERIALIZE(alt)
- KV_SERIALIZE(invalid)
- END_KV_SERIALIZE_MAP()
- };
- };
-
struct COMMAND_RPC_GET_BLOCKS_FAST
{
@@ -153,6 +134,7 @@ namespace cryptonote
{
uint64_t amount;
std::list<out_entry> outs;
+
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs)
@@ -283,7 +265,17 @@ namespace cryptonote
{
typedef std::list<std::string> request;
- typedef uint64_t response;
+ struct response
+ {
+ uint64_t count;
+ std::string status;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(count)
+ KV_SERIALIZE(status)
+ END_KV_SERIALIZE_MAP()
+ };
+
};
struct COMMAND_RPC_GETBLOCKHASH
@@ -313,12 +305,14 @@ namespace cryptonote
uint64_t height;
uint64_t reserved_offset;
blobdata blocktemplate_blob;
+ std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(difficulty)
KV_SERIALIZE(height)
KV_SERIALIZE(reserved_offset)
KV_SERIALIZE(blocktemplate_blob)
+ KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
};
diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h
index 5e3296d05..10785f8ab 100644
--- a/src/rpc/core_rpc_server_error_codes.h
+++ b/src/rpc/core_rpc_server_error_codes.h
@@ -12,3 +12,8 @@
#define CORE_RPC_ERROR_CODE_INTERNAL_ERROR -5
#define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB -6
#define CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED -7
+#define CORE_RPC_ERROR_CODE_CORE_BUSY -9
+
+
+
+
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index bda47019b..2ba031325 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -8,6 +8,7 @@
#include <boost/algorithm/string.hpp>
#include "include_base_utils.h"
#include "common/command_line.h"
+#include "common/util.h"
#include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "simplewallet.h"
@@ -40,21 +41,25 @@ namespace
const command_line::arg_descriptor<uint32_t> arg_log_level = {"set_log", "", 0, true};
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
-}
-/*const char *commands_help =
- "Commands:\n"
- " help Show this help\n"
- " address Show current account public address\n"
- " exit\n"
- " refresh\n"
- " start_mining Start mining\n"
- " set_log\n"
- " show_balance Show current account balance\n"
- " show_bc_height Show blockchain height\n"
- " show_incoming_transfers Show coins\n"
- " transfer <mixin_count> (<addr> <amount>)... Transfer <amount> to <addr>\n";*/
+ void print_success_msg(const std::string& msg, bool color = false)
+ {
+ LOG_PRINT_L4(msg);
+ if (color) epee::log_space::set_console_color(epee::log_space::console_color_green, false);
+ std::cout << msg;
+ if (color) epee::log_space::reset_console_color();
+ std::cout << std::endl;
+ }
+ void print_fail_msg(const std::string& msg)
+ {
+ LOG_PRINT_L1("Error:" << msg);
+ epee::log_space::set_console_color(epee::log_space::console_color_red, true);
+ std::cout << "Error: " << msg;
+ epee::log_space::reset_console_color();
+ std::cout << std::endl;
+ }
+}
std::string simple_wallet::get_commands_str()
@@ -68,7 +73,7 @@ std::string simple_wallet::get_commands_str()
return ss.str();
}
-bool simple_wallet::help(const std::vector<std::string> &args)
+bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
std::cout << get_commands_str();
return true;
@@ -76,15 +81,14 @@ bool simple_wallet::help(const std::vector<std::string> &args)
simple_wallet::simple_wallet()
: m_daemon_port(0)
- , m_tried_to_connect(false)
{
- m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "Start mining in daemon");
+ m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "Start mining in daemon, start_mining <threads_count>");
m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon");
m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance");
m_cmd_binder.set_handler("show_balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance");
m_cmd_binder.set_handler("show_incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "Show incoming transfers");
m_cmd_binder.set_handler("show_bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height");
- m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> <<addr> <amount>> Transfer <amount> to <address>. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)");
+ m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> {<addr> <amount>} Transfer <amount> to <address>. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)");
m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "Change current log detalization level, <level> is a number 0-4");
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address");
m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data");
@@ -98,13 +102,13 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
std::cout << "use: set_log <log_level_number_0-4>" << ENDL;
return true;
}
- int l = 0;
+ uint16_t l = 0;
if(!string_tools::get_xtype_from_string(l, args[0]))
{
std::cout << "wrong number format, use: set_log <log_level_number_0-4>" << ENDL;
return true;
}
- if(l < 0 || l > LOG_LEVEL_4)
+ if(LOG_LEVEL_4 < l)
{
std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << ENDL;
return true;
@@ -176,20 +180,17 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
return true;
}
//----------------------------------------------------------------------------------------------------
-void simple_wallet::try_connect_to_daemon()
+bool simple_wallet::try_connect_to_daemon()
{
- if (!m_tried_to_connect)
+ if (!m_wallet->check_connection())
{
- m_tried_to_connect = true;
-
- if(!m_wallet->check_connection())
- {
- std::cout <<
- "**********************************************************************" << ENDL <<
- "Wallet failed to connect to daemon. Daemon either is not started or passed wrong port. Please, make sure that daemon is running or restart the wallet with correct daemon address." << ENDL <<
- "**********************************************************************" << ENDL;
- }
+ std::string msg = "wallet failed to connect to daemon (" + m_daemon_address + "). " +
+ "Daemon either is not started or passed wrong port. " +
+ "Please, make sure that daemon is running or restart the wallet with correct daemon address.";
+ print_fail_msg(msg);
+ return false;
}
+ return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password)
@@ -231,7 +232,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
r = m_wallet->init(m_daemon_address);
CHECK_AND_ASSERT_MES(r, false, "failed to init wallet");
- refresh(vector<string>());
+ refresh(std::vector<std::string>());
std::cout << "**********************************************************************" << ENDL
<< "Use \"help\" command to see the list of available commands." << ENDL
<< "**********************************************************************" << ENDL ;
@@ -250,52 +251,72 @@ bool simple_wallet::close_wallet()
bool simple_wallet::save(const std::vector<std::string> &args)
{
bool r = m_wallet->store();
- CHECK_AND_ASSERT_MES(r, false, "failed to store wallet " + m_wallet_file);
- std::cout << "Wallet data saved" << ENDL;
+ if (r)
+ print_success_msg("Wallet data saved");
+ else
+ print_fail_msg("failed to store wallet " + m_wallet_file);
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::start_mining(const vector<string>& args)
+bool simple_wallet::start_mining(const std::vector<std::string>& args)
{
- try_connect_to_daemon();
+ if (!try_connect_to_daemon())
+ return true;
COMMAND_RPC_START_MINING::request req;
req.miner_address = m_wallet->get_account().get_public_address_str();
- req.threads_count = 1;
- if(args.size() == 1)
+
+ if (0 == args.size())
{
- if(!string_tools::get_xtype_from_string(req.threads_count, args[0]))
+ req.threads_count = 1;
+ }
+ else if (1 == args.size())
+ {
+ uint16_t num;
+ bool ok = string_tools::get_xtype_from_string(num, args[0]);
+ if(!ok || 0 == num)
{
- std::cout << "Threads count value invalid \"" << args[0] << "\"" << ENDL;
- return false;
+ print_fail_msg("wrong number of mining threads: \"" + args[0] + "\"");
+ return true;
}
+ req.threads_count = num;
+ }
+ else
+ {
+ print_fail_msg("wrong number of arguments, expected the number of mining threads");
+ return true;
}
+
COMMAND_RPC_START_MINING::response res;
bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/start_mining", req, res, m_http_client);
- if (!r)
- std::cout << "Mining has NOT been started" << std::endl;
- CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request");
- std::cout << "Mining started in daemon." << ENDL;
+ std::string err = tools::interpret_rpc_response(r, res.status);
+ if (err.empty())
+ print_success_msg("Mining started in daemon");
+ else
+ print_fail_msg("mining has NOT been started: " + err);
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::stop_mining(const vector<string>& args)
+bool simple_wallet::stop_mining(const std::vector<std::string>& args)
{
- try_connect_to_daemon();
+ if (!try_connect_to_daemon())
+ return true;
COMMAND_RPC_STOP_MINING::request req;
COMMAND_RPC_STOP_MINING::response res;
bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/stop_mining", req, res, m_http_client);
- if (!r)
- std::cout << "Mining has NOT been stopped" << std::endl;
- CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request");
- std::cout << "Mining stopped in daemon." << ENDL;
+ std::string err = tools::interpret_rpc_response(r, res.status);
+ if (err.empty())
+ print_success_msg("Mining stopped in daemon");
+ else
+ print_fail_msg("mining has NOT been stopped: " + err);
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::refresh(const vector<string>& args)
+bool simple_wallet::refresh(const std::vector<std::string>& args)
{
- try_connect_to_daemon();
+ if (!try_connect_to_daemon())
+ return true;
std::cout << "Starting refresh..." << endl;
std::atomic<bool> refresh_is_done(false);
@@ -304,132 +325,166 @@ bool simple_wallet::refresh(const vector<string>& args)
epee::misc_utils::sleep_no_w(1000);
while(!refresh_is_done)
{
- bool ok;
- uint64_t bc_height = get_daemon_blockchain_height(ok);
- if (ok)
+ std::string err;
+ uint64_t bc_height = get_daemon_blockchain_height(err);
+ if (err.empty())
cout << "Height " << m_wallet->get_blockchain_current_height() << " of " << bc_height << endl;
epee::misc_utils::sleep_no_w(1000);
}
});
+ uint64_t initial_height = m_wallet->get_blockchain_current_height();
uint64_t fetched_blocks = 0;
bool money_received = false;
- bool ok = m_wallet->refresh(fetched_blocks, money_received);
+ tools::wallet2::fail_details fd;
+ bool ok = m_wallet->refresh(fetched_blocks, money_received, fd);
refresh_is_done = true;
th.join();
if (ok)
- std::cout << "Refresh done, blocks received: " << fetched_blocks << endl;
+ {
+ std::stringstream ss;
+ ss << "Refresh done, blocks received: " << fetched_blocks;
+ print_success_msg(ss.str(), true);
+
+ show_balance();
+ }
else
- std::cout << "Refresh failed, no blocks received" << std::endl;
- show_balance(vector<string>());
+ {
+ fetched_blocks = m_wallet->get_blockchain_current_height() - initial_height;
+ std::stringstream ss;
+ ss << "refresh failed: " << fd.what() << ". Blocks received: " << fetched_blocks;
+ print_fail_msg(ss.str());
+ }
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::show_balance(const vector<string>& args)
+bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::vector<std::string>()*/)
{
- cout << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance()) << endl;
+ std::stringstream ss;
+ ss << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance());
+ print_success_msg(ss.str());
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::show_incoming_transfers(const vector<string>& args)
+bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args)
{
- m_wallet->show_incoming_transfers();
+ std::cout << " amount \tspent\tglobal index\t tx id" << std::endl;
+ bool ok = m_wallet->enum_incoming_transfers([](const cryptonote::transaction& tx, uint64_t global_out_index, uint64_t amount, bool spent) {
+ epee::log_space::set_console_color(spent ? epee::log_space::console_color_magenta : epee::log_space::console_color_green, true);
+ std::cout << std::setw(21) << print_money(amount) << '\t'
+ << std::setw(3) << (spent ? 'T' : 'F') << " \t"
+ << std::setw(12) << global_out_index << '\t'
+ << get_transaction_hash(tx)
+ << '\n';
+ });
+ epee::log_space::reset_console_color();
+ if (ok)
+ std::cout.flush();
+ else
+ print_fail_msg("No incoming transfers");
return true;
}
//----------------------------------------------------------------------------------------------------
-uint64_t simple_wallet::get_daemon_blockchain_height(bool& ok)
+uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err)
{
COMMAND_RPC_GET_HEIGHT::request req;
COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>();
- ok = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client);
- CHECK_AND_ASSERT_MES(ok, 0, "failed to invoke http request");
+ bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client);
+ err = tools::interpret_rpc_response(r, res.status);
return res.height;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::show_blockchain_height(const vector<string>& args)
+bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
{
- try_connect_to_daemon();
+ if (!try_connect_to_daemon())
+ return true;
- bool ok;
- uint64_t bc_height = get_daemon_blockchain_height(ok);
- if (ok)
- cout << "core returned height: " << bc_height << endl;
+ std::string err;
+ uint64_t bc_height = get_daemon_blockchain_height(err);
+ if (err.empty())
+ print_success_msg(boost::lexical_cast<std::string>(bc_height));
else
- std::cout << "Failed to get blockchain height" << std::endl;
+ print_fail_msg("failed to get blockchain height: " + err);
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::transfer(const vector<string> &args_)
+bool simple_wallet::transfer(const std::vector<std::string> &args_)
{
- try_connect_to_daemon();
+ if (!try_connect_to_daemon())
+ return true;
- vector<string> local_args = args_;
+ std::vector<std::string> local_args = args_;
if(local_args.size() < 3)
{
- std::cout << "wrong transfer arguments" << std::endl;
- help(vector<string>());
+ print_fail_msg("wrong number of arguments, expected at least 3, got " + boost::lexical_cast<std::string>(local_args.size()));
return true;
}
+
size_t fake_outs_count;
if(!string_tools::get_xtype_from_string(fake_outs_count, local_args[0]))
{
- std::cout << " ambiguity_degree set wrong" << std::endl;
- help(vector<string>());
+ print_fail_msg("mixin_count should be non-negative integer, got " + local_args[0]);
return true;
}
local_args.erase(local_args.begin());
- if(local_args.size() % 2 != 0)
- {
- cout << "wrong transfer arguments" << endl;
- help(vector<string>());
- return true;
- }
vector<cryptonote::tx_destination_entry> dsts;
uint64_t summary_amount = 0;
for (size_t i = 0; i < local_args.size(); i += 2)
{
cryptonote::tx_destination_entry de;
- if(!cryptonote::parse_amount(de.amount, local_args[i+1]))
+ if(!get_account_address_from_str(de.addr, local_args[i]))
{
- cout << "Wrong transfer arguments" << endl;;
- help(vector<string>());
+ print_fail_msg("wrong address: " + local_args[i]);
return true;
}
- if(de.amount <= 0)
+
+ if (local_args.size() <= i + 1)
{
- cout << "Wrong transfer amount: " << de.amount << endl;;
- help(vector<string>());
+ print_fail_msg("amount for the last address " + local_args[i] + " is not specified");
return true;
}
- summary_amount += de.amount;
- if(!get_account_address_from_str(de.addr, local_args[i]))
+
+ bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
+ if(!ok || 0 == de.amount)
{
- cout << "Wrong address: " << local_args[i] << endl;
- help(vector<string>());
+ print_fail_msg("amount is wrong: " + local_args[i] + " " + local_args[i + 1]);
return true;
}
+
+ summary_amount += de.amount;
dsts.push_back(de);
}
if(summary_amount > m_wallet->unlocked_balance())
{
- cout << "Not enough money to transfer " << print_money(summary_amount) << ", available(unlocked) only " << print_money(m_wallet->unlocked_balance()) << endl;
+ print_fail_msg("not enough money to transfer " + print_money(summary_amount) + ", available (unlocked) only " + print_money(m_wallet->unlocked_balance()));
return true;
}
- m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE);
+ cryptonote::transaction tx;
+ tools::wallet2::fail_details tfd;
+ bool ok = m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, tx, tfd);
+ if (ok)
+ print_success_msg("Money successfully sent", true);
+ else
+ print_fail_msg("failed to transfer money: " + tfd.what());
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::run()
{
- m_cmd_binder.run_handling("");
- return true;
+ return m_cmd_binder.run_handling("[wallet]# ", "");
+}
+//----------------------------------------------------------------------------------------------------
+void simple_wallet::stop()
+{
+ m_cmd_binder.stop_handling();
+ m_wallet->stop();
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::print_address(const std::vector<std::string> &args)
{
- std::cout << "Public address: " << m_wallet->get_account().get_public_address_str() << ENDL;
+ print_success_msg(m_wallet->get_account().get_public_address_str());
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -482,7 +537,7 @@ int main(int argc, char* argv[])
}
else if (command_line::get_arg(vm, command_line::arg_version))
{
- std::cout << "BYTECOIN WALLET v" << PROJECT_VERSION_LONG << ENDL;
+ std::cout << CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG << ENDL;
return false;
}
@@ -495,18 +550,19 @@ int main(int argc, char* argv[])
return 1;
//set up logging options
- log_space::get_set_log_detalisation_level(true, LOG_LEVEL_1);
- log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
+ log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
+ log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
log_space::log_singletone::add_logger(LOGGER_FILE,
log_space::log_singletone::get_default_log_file().c_str(),
- log_space::log_singletone::get_default_log_folder().c_str());
+ log_space::log_singletone::get_default_log_folder().c_str(), LOG_LEVEL_4);
+
+ LOG_PRINT_L0(CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG);
if(command_line::has_arg(vm, arg_log_level))
{
LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, arg_log_level));
log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, arg_log_level));
}
- LOG_PRINT("simplewallet starting", LOG_LEVEL_0);
r = w.init(vm);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");
@@ -514,6 +570,10 @@ int main(int argc, char* argv[])
std::vector<std::string> command = command_line::get_arg(vm, arg_command);
if (!command.empty())
w.process_command(command);
+
+ tools::signal_handler::install([&w] {
+ w.stop();
+ });
w.run();
w.deinit();
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 01d3ac4a7..c448467f8 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -29,6 +29,7 @@ namespace cryptonote
bool init(const boost::program_options::variables_map& vm);
bool deinit();
bool run();
+ void stop();
//wallet *create_wallet();
bool process_command(const std::vector<std::string> &args);
@@ -42,11 +43,11 @@ namespace cryptonote
bool open_wallet(const std::string &wallet_file, const std::string& password);
bool close_wallet();
- bool help(const std::vector<std::string> &args);
+ bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args);
bool refresh(const std::vector<std::string> &args);
- bool show_balance(const std::vector<std::string> &args);
+ bool show_balance(const std::vector<std::string> &args = std::vector<std::string>());
bool show_incoming_transfers(const std::vector<std::string> &args);
bool show_blockchain_height(const std::vector<std::string> &args);
bool transfer(const std::vector<std::string> &args);
@@ -54,8 +55,8 @@ namespace cryptonote
bool save(const std::vector<std::string> &args);
bool set_log(const std::vector<std::string> &args);
- uint64_t get_daemon_blockchain_height(bool& ok);
- void try_connect_to_daemon();
+ uint64_t get_daemon_blockchain_height(std::string& err);
+ bool try_connect_to_daemon();
std::string m_wallet_file;
std::string m_generate_new;
@@ -64,11 +65,10 @@ namespace cryptonote
std::string m_daemon_address;
std::string m_daemon_host;
int m_daemon_port;
- bool m_tried_to_connect;
epee::console_handlers_binder m_cmd_binder;
- std::auto_ptr<tools::wallet2> m_wallet;
+ std::unique_ptr<tools::wallet2> m_wallet;
net_utils::http::http_simple_client m_http_client;
};
}
diff --git a/src/version.h.in b/src/version.h.in
index 0e64c7a11..fd566680a 100644
--- a/src/version.h.in
+++ b/src/version.h.in
@@ -1,4 +1,4 @@
#define BUILD_COMMIT_ID "@VERSION@"
#define PROJECT_VERSION "0.8.2"
-#define PROJECT_VERSION_BUILD_NO "279"
+#define PROJECT_VERSION_BUILD_NO "284"
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index aa4e2f518..7b898755a 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -32,14 +32,16 @@ bool wallet2::init(const std::string& daemon_address, uint64_t upper_transaction
return true;
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t height)
+bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t height, fail_details& fd)
{
std::vector<size_t> outs;
uint64_t tx_money_got_in_outs = 0;
crypto::public_key tx_pub_key = null_pkey;
bool r = parse_and_validate_tx_extra(tx, tx_pub_key);
+ fd.reason = fail_details::error_to_parse_tx_extra;
CHECK_AND_ASSERT_MES(r && tx_pub_key != null_pkey, false, "process_new_transaction failed.");
r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs);
+ fd.reason = fail_details::error_invalid_tx;
CHECK_AND_ASSERT_MES(r, false, "call lookup_acc_outs failed");
if(outs.size() && tx_money_got_in_outs)
{
@@ -49,14 +51,24 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig
cryptonote::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response res = AUTO_VAL_INIT(res);
req.txid = get_transaction_hash(tx);
bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/get_o_indexes.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT);
- CHECK_AND_ASSERT_MES(r, false, "failed to get_o_indexes.bin");
- if(res.status != CORE_RPC_STATUS_OK)
- return false;// in case of split while lookup_acc_outs, transaction could be lost (especially if it is coinbase tx)
+ if (!r) fd.reason = fail_details::error_not_connected;
+ else if (CORE_RPC_STATUS_BUSY == res.status) fd.reason = fail_details::error_daemon_is_busy;
+ else if (CORE_RPC_STATUS_OK != res.status) fd.reason = fail_details::error_internal_error;
+ else fd.reason = fail_details::error_ok;
+ if (fail_details::error_ok != fd.reason)
+ {
+ // in case of split while lookup_acc_outs, transaction could be lost (especially if it is coinbase tx)
+ LOG_PRINT_L0("failed to invoke get_o_indexes.bin: " << interpret_rpc_response(r, res.status));
+ return false;
+ }
+
+ fd.reason = fail_details::error_internal_error;
CHECK_AND_ASSERT_MES(res.o_indexes.size() == tx.vout.size(), false, "internal error: transactions outputs size=" << tx.vout.size()
- << " not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response size=" << res.o_indexes.size());
+ << " not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response size=" << res.o_indexes.size());
BOOST_FOREACH(size_t o, outs)
{
+ fd.reason = fail_details::error_invalid_tx;
CHECK_AND_ASSERT_MES(o < tx.vout.size(), false, "wrong out in transaction: internal index=" << o << ", total_outs" << tx.vout.size());
m_transfers.push_back(boost::value_initialized<transfer_details>());
transfer_details& td = m_transfers.back();
@@ -67,10 +79,12 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig
td.m_spent = false;
cryptonote::keypair in_ephemeral;
cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, o, in_ephemeral, td.m_key_image);
+ fd.reason = fail_details::error_internal_error;
CHECK_AND_ASSERT_MES(in_ephemeral.pub == boost::get<cryptonote::txout_to_key>(tx.vout[o].target).key,
- false, "internal error: at key_image generating ephemeral public key not matched with output_key");
+ false, "internal error: at key_image generating ephemeral public key not matched with output_key");
m_key_images[td.m_key_image] = m_transfers.size()-1;
- LOG_PRINT_L1("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx));
+ LOG_PRINT_COLOR("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx),
+ LOG_LEVEL_0, epee::log_space::console_color_green);
}
}
// check all outputs for spending (compare key images)
@@ -81,22 +95,24 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig
auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
if(it != m_key_images.end())
{
- LOG_PRINT_L1("Spent money: " << print_money(boost::get<cryptonote::txin_to_key>(in).amount) << ", with tx: " << get_transaction_hash(tx));
+ LOG_PRINT_COLOR("Spent money: " << print_money(boost::get<cryptonote::txin_to_key>(in).amount) << ", with tx: " << get_transaction_hash(tx),
+ LOG_LEVEL_0, epee::log_space::console_color_magenta);
m_transfers[it->second].m_spent = true;
}
}
return true;
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height)
+bool wallet2::process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height, fail_details& fd)
{
//handle transactions from new block
+ fd.reason = fail_details::error_internal_error;
CHECK_AND_ASSERT_MES(height == m_blockchain.size(), false, "internal error: current_index=" << height << ", m_blockchain.size()=" << m_blockchain.size());
//optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup
if(b.timestamp + 60*60*24 > m_account.get_createtime())
{
TIME_MEASURE_START(miner_tx_handle_time);
- bool r = process_new_transaction(b.miner_tx, height);
+ bool r = process_new_transaction(b.miner_tx, height, fd);
TIME_MEASURE_FINISH(miner_tx_handle_time);
CHECK_AND_NO_ASSERT_MES(r, false, "failed to process transaction");
@@ -105,8 +121,9 @@ bool wallet2::process_new_blockchain_entry(cryptonote::block& b, cryptonote::blo
{
cryptonote::transaction tx;
r = parse_and_validate_tx_from_blob(txblob, tx);
+ fd.reason = fail_details::error_to_parse_tx;
CHECK_AND_ASSERT_MES(r, false, "failed to parse and validate transaction from blob");
- r = process_new_transaction(tx, height);
+ r = process_new_transaction(tx, height, fd);
CHECK_AND_ASSERT_MES(r, false, "failed to process transaction");
}
TIME_MEASURE_FINISH(txs_handle_time);
@@ -149,18 +166,26 @@ bool wallet2::get_short_chain_history(std::list<crypto::hash>& ids)
return true;
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::pull_blocks(size_t& blocks_added)
+bool wallet2::pull_blocks(size_t& blocks_added, fail_details& fd)
{
blocks_added = 0;
cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res);
get_short_chain_history(req.block_ids);
bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getblocks.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT);
- CHECK_AND_ASSERT_MES(r, false, "failed to get blocks");
- CHECK_AND_ASSERT_MES(res.status == CORE_RPC_STATUS_OK, false, "failed to get blocks");
+ if (!r) fd.reason = fail_details::error_not_connected;
+ else if (CORE_RPC_STATUS_BUSY == res.status) fd.reason = fail_details::error_daemon_is_busy;
+ else if (CORE_RPC_STATUS_OK != res.status) fd.reason = fail_details::error_internal_error;
+ else fd.reason = fail_details::error_ok;
+ if (fail_details::error_ok != fd.reason)
+ {
+ LOG_PRINT_L0("failed to get blocks: " << interpret_rpc_response(r, res.status));
+ return false;
+ }
//find split position, if split happened
+ fd.reason = fail_details::error_internal_error;
CHECK_AND_ASSERT_MES(res.start_height < m_blockchain.size(), false, "wrong daemon response: m_start_height="
<< res.start_height << " not less than local blockchain size=" << m_blockchain.size());
@@ -169,11 +194,12 @@ bool wallet2::pull_blocks(size_t& blocks_added)
{
cryptonote::block bl;
r = cryptonote::parse_and_validate_block_from_blob(bl_entry.block, bl);
+ fd.reason = fail_details::error_to_parse_block;
CHECK_AND_ASSERT_MES(r, false, "failed to parse/validate block");
crypto::hash bl_id = get_block_hash(bl);
if(current_index >= m_blockchain.size())
{
- r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index);
+ r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index, fd);
if(!r) return false;
++blocks_added;
}else
@@ -181,12 +207,12 @@ bool wallet2::pull_blocks(size_t& blocks_added)
if(bl_id != m_blockchain[current_index])
{
//split detected here !!!
+ fd.reason = fail_details::error_internal_error;
CHECK_AND_ASSERT_MES(current_index != res.start_height, false, "wrong daemon response: first block in response " << string_tools::pod_to_hex(bl_id)
<< "\nnot match with local block id " << string_tools::pod_to_hex(m_blockchain[current_index]));
detach_blockchain(current_index);
- r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index);
+ r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index, fd);
if(!r) return false;
-
}
}
++current_index;
@@ -194,19 +220,19 @@ bool wallet2::pull_blocks(size_t& blocks_added)
return true;
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::refresh()
+bool wallet2::refresh(fail_details& fd)
{
size_t blocks_fetched = 0;
- return refresh(blocks_fetched);
+ return refresh(blocks_fetched, fd);
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::refresh(size_t & blocks_fetched)
+bool wallet2::refresh(size_t & blocks_fetched, fail_details& fd)
{
bool received_money = false;
- return refresh(blocks_fetched, received_money);
+ return refresh(blocks_fetched, received_money, fd);
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::refresh(size_t & blocks_fetched, bool& received_money)
+bool wallet2::refresh(size_t & blocks_fetched, bool& received_money, fail_details& fd)
{
received_money = false;
blocks_fetched = 0;
@@ -214,19 +240,19 @@ bool wallet2::refresh(size_t & blocks_fetched, bool& received_money)
size_t try_count = 0;
crypto::hash last_tx_hash_id = m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash;
- while(true)
+ while(m_run.load(std::memory_order_relaxed))
{
- bool res = pull_blocks(added_blocks);
+ bool res = pull_blocks(added_blocks, fd);
if(!res)
{
if(try_count < 3)
{
- LOG_PRINT_L0("Another try pull_blocks(try_count=" << try_count << ")...");
+ LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
++try_count;
continue;
}else
{
- LOG_PRINT_L0("pull_blocks failed, try_count=" << try_count);
+ LOG_PRINT_L1("pull_blocks failed, try_count=" << try_count);
return false;
}
}
@@ -238,7 +264,7 @@ bool wallet2::refresh(size_t & blocks_fetched, bool& received_money)
if(last_tx_hash_id != (m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash))
received_money = true;
- LOG_PRINT_L2( "Refresh done, blocks received: " << blocks_fetched << ", balance: " << print_money(balance()) << ", unlocked: " << print_money(unlocked_balance()));
+ LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", balance: " << print_money(balance()) << ", unlocked: " << print_money(unlocked_balance()));
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -439,25 +465,6 @@ bool wallet2::store()
return r;
}
//----------------------------------------------------------------------------------------------------
-void wallet2::show_incoming_transfers()
-{
- uint64_t amount = 0;
- if(!m_transfers.size())
- {
- LOG_PRINT_L0("No incoming transfers");
- return;
- }
- BOOST_FOREACH(transfer_details& td, m_transfers)
- {
- LOG_PRINT_L0("transfer: " << print_money(td.amount())
- << ", spent: " << td.m_spent
- << ", global_index: " << td.m_global_output_index
- << ", tx_id: " << get_transaction_hash(td.m_tx));
- if(!td.m_spent)
- amount += td.amount();
- }
-}
-//----------------------------------------------------------------------------------------------------
uint64_t wallet2::unlocked_balance()
{
uint64_t amount = 0;
@@ -535,7 +542,7 @@ namespace
}
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::select_transfers(uint64_t needed_money, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers)
+uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers)
{
std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices;
@@ -551,19 +558,19 @@ uint64_t wallet2::select_transfers(uint64_t needed_money, uint64_t dust, std::li
}
}
- bool at_least_one_dust_selected = unused_dust_indices.empty();
+ bool select_one_dust = add_dust && !unused_dust_indices.empty();
uint64_t found_money = 0;
while (found_money < needed_money && (!unused_transfers_indices.empty() || !unused_dust_indices.empty()))
{
size_t idx;
- if (at_least_one_dust_selected)
+ if (select_one_dust)
{
- idx = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices);
+ idx = pop_random_value(unused_dust_indices);
+ select_one_dust = false;
}
else
{
- idx = pop_random_value(unused_dust_indices);
- at_least_one_dust_selected = true;
+ idx = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices);
}
transfer_container::iterator it = m_transfers.begin() + idx;
@@ -580,7 +587,7 @@ bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts
return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx);
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, transafer_fail_details& tfd)
+bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, fail_details& tfd)
{
return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx, tfd);
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 27799e2da..f26f8022e 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -25,11 +25,33 @@
namespace tools
{
+ inline std::string interpret_rpc_response(bool ok, const std::string& status)
+ {
+ std::string err;
+ if (ok)
+ {
+ if (status == CORE_RPC_STATUS_BUSY)
+ {
+ err = "daemon is busy. Please try later";
+ }
+ else if (status != CORE_RPC_STATUS_OK)
+ {
+ err = status;
+ }
+ }
+ else
+ {
+ err = "possible lost connection to daemon";
+ }
+ return err;
+ }
+
+
class wallet2
{
- wallet2(const wallet2&){};
+ wallet2(const wallet2&) : m_run(true) {};
public:
- wallet2(){};
+ wallet2() : m_run(true) {};
struct transfer_details
{
uint64_t m_block_height;
@@ -68,20 +90,46 @@ namespace tools
END_SERIALIZE()
};
- struct transafer_fail_details
+ struct fail_details
{
enum fail_reason
{
error_ok = 0,
error_not_connected,
+ error_daemon_is_busy,
error_rejected_by_daemon,
- error_too_big_transaction,
- error_not_enough_money,
+ error_too_big_transaction,
+ error_not_enough_money,
+ error_too_big_mixin,
+ error_to_parse_block,
+ error_to_parse_tx,
+ error_to_parse_tx_extra,
+ error_invalid_tx,
error_internal_error
};
fail_reason reason;
uint64_t tx_blob_size;
uint64_t max_expected_tx_blob_size;
+
+ std::string what() const
+ {
+ switch (reason)
+ {
+ case error_ok: return "OK";
+ case error_not_connected: return "not connected";
+ case error_daemon_is_busy: return "daemon is busy. Please try later";
+ case error_rejected_by_daemon: return "rejected by daemon";
+ case error_too_big_transaction: return "transaction size is too big";
+ case error_not_enough_money: return "not enough money";
+ case error_too_big_mixin: return "not enough outputs for specified mixin_count";
+ case error_to_parse_block: return "failed to parse/validate block";
+ case error_to_parse_tx: return "failed to parse/validate tx";
+ case error_to_parse_tx_extra: return "failed to parse/validate tx extra";
+ case error_invalid_tx: return "wrong tx";
+ case error_internal_error: return "internal error";
+ default: return "unknown error";
+ }
+ }
};
bool generate(const std::string& wallet, const std::string& password);
@@ -91,23 +139,26 @@ namespace tools
bool init(const std::string& daemon_address = "http://localhost:8080", uint64_t upper_transaction_size_limit = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE*2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
- bool refresh();
- bool refresh(size_t & blocks_fetched);
- bool refresh(size_t & blocks_fetched, bool& received_money);
+ bool refresh(fail_details& fd);
+ bool refresh(size_t & blocks_fetched, fail_details& fd);
+ bool refresh(size_t & blocks_fetched, bool& received_money, fail_details& fd);
bool deinit();
+ void stop() { m_run.store(false, std::memory_order_relaxed); }
+
uint64_t balance();
uint64_t unlocked_balance();
- void show_incoming_transfers();
+ template<typename T>
+ bool enum_incoming_transfers(const T& handler) const;
template<typename T>
bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy);
template<typename T>
- bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, transafer_fail_details& tfd);
+ bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, fail_details& tfd);
template<typename T>
bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx);
bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee);
bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx);
- bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, transafer_fail_details& tfd);
+ bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, fail_details& tfd);
bool check_connection();
bool get_transfers(wallet2::transfer_container& incoming_transfers);
uint64_t get_blockchain_current_height() const { return m_local_bc_height; }
@@ -125,15 +176,15 @@ namespace tools
private:
bool store_keys(const std::string& keys_file_name, const std::string& password);
bool load_keys(const std::string& keys_file_name, const std::string& password);
- bool process_new_transaction(cryptonote::transaction& tx, uint64_t height);
- bool process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height);
+ bool process_new_transaction(cryptonote::transaction& tx, uint64_t height, fail_details& fd);
+ bool process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height, fail_details& fd);
bool detach_blockchain(uint64_t height);
bool get_short_chain_history(std::list<crypto::hash>& ids);
bool is_tx_spendtime_unlocked(uint64_t unlock_time) const;
bool is_transfer_unlocked(const transfer_details& td) const;
bool clear();
- bool pull_blocks(size_t& blocks_added);
- uint64_t select_transfers(uint64_t needed_money, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers);
+ bool pull_blocks(size_t& blocks_added, fail_details& fd);
+ uint64_t select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers);
bool prepare_file_names(const std::string& file_path);
cryptonote::account_base m_account;
@@ -148,6 +199,8 @@ namespace tools
std::unordered_map<crypto::key_image, size_t> m_key_images;
cryptonote::account_public_address m_account_public_address;
uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
+
+ std::atomic<bool> m_run;
};
}
BOOST_CLASS_VERSION(tools::wallet2, 5)
@@ -229,12 +282,29 @@ namespace tools
{
std::string indexes;
std::for_each(src.outputs.begin(), src.outputs.end(), [&](const cryptonote::tx_source_entry::output_entry& s_e) { indexes += boost::to_string(s_e.first) + " "; });
- std::cout << "amount=" << cryptonote::print_money(src.amount) << ", real_output=" <<src.real_output << ", real_output_in_tx_index=" << src.real_output_in_tx_index << ", indexes: " << indexes << ENDL;
+ LOG_PRINT_L0("amount=" << cryptonote::print_money(src.amount) << ", real_output=" <<src.real_output << ", real_output_in_tx_index=" << src.real_output_in_tx_index << ", indexes: " << indexes);
}
//----------------------------------------------------------------------------------------------------
}
//----------------------------------------------------------------------------------------------------
template<typename T>
+ bool wallet2::enum_incoming_transfers(const T& handler) const
+ {
+ if(!m_transfers.empty())
+ {
+ BOOST_FOREACH(const transfer_details& td, m_transfers)
+ {
+ handler(td.m_tx, td.m_global_output_index, td.amount(), td.m_spent);
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ //----------------------------------------------------------------------------------------------------
+ template<typename T>
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy)
{
@@ -246,13 +316,13 @@ namespace tools
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx)
{
- transafer_fail_details stub = AUTO_VAL_INIT(stub);
+ fail_details stub = AUTO_VAL_INIT(stub);
return transfer(dsts, fake_outputs_count, unlock_time, fee, destination_split_strategy, dust_policy, tx, stub);
}
template<typename T>
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
- uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, transafer_fail_details& tfd)
+ uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, fail_details& tfd)
{
using namespace cryptonote;
@@ -264,12 +334,13 @@ namespace tools
}
std::list<transfer_container::iterator> selected_transfers;
- uint64_t found_money = select_transfers(needed_money, dust_policy.dust_threshold, selected_transfers);
+ uint64_t found_money = select_transfers(needed_money, 0 == fake_outputs_count, dust_policy.dust_threshold, selected_transfers);
if(found_money < needed_money)
{
- LOG_ERROR("not enough money, available only " << print_money(found_money) << ", expected " << print_money(needed_money) );
- tfd.reason = transafer_fail_details::error_not_enough_money;
+ LOG_ERROR("not enough money, available only " << print_money(found_money) << ", transaction amount " <<
+ print_money(needed_money) << " = " << print_money(needed_money - fee) << " + " << print_money(fee) << " (fee)");
+ tfd.reason = fail_details::error_not_enough_money;
return false;
}
//typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount;
@@ -279,7 +350,6 @@ namespace tools
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
if(fake_outputs_count)
{
-
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req);
req.outs_count = fake_outputs_count + 1;// add one to make possible (if need) to skip real output key
BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
@@ -288,15 +358,37 @@ namespace tools
<< it->m_internal_output_index << " more than " << it->m_tx.vout.size());
req.amounts.push_back(it->amount());
}
+
bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000);
- tfd.reason = transafer_fail_details::error_not_connected;
- CHECK_AND_ASSERT_MES(r, false, "failed to get getrandom_outs");
- tfd.reason = transafer_fail_details::error_internal_error;
- CHECK_AND_ASSERT_MES(daemon_resp.status == CORE_RPC_STATUS_OK, false, "failed to getrandom_outs.bin");
- CHECK_AND_ASSERT_MES(daemon_resp.outs.size() == selected_transfers.size(), false, "internal error: daemon returned wrong response for getrandom_outs, wrong amounts count = "
+ if (!r) tfd.reason = fail_details::error_not_connected;
+ else if (CORE_RPC_STATUS_BUSY == daemon_resp.status) tfd.reason = fail_details::error_daemon_is_busy;
+ else if (CORE_RPC_STATUS_OK != daemon_resp.status) tfd.reason = fail_details::error_internal_error;
+ else tfd.reason = fail_details::error_ok;
+ if (fail_details::error_ok != tfd.reason)
+ {
+ LOG_PRINT_L0("failed to invoke getrandom_outs.bin: " << interpret_rpc_response(r, daemon_resp.status));
+ return false;
+ }
+
+ tfd.reason = fail_details::error_internal_error;
+ CHECK_AND_ASSERT_MES(daemon_resp.outs.size() == selected_transfers.size(), false,
+ "internal error: daemon returned wrong response for getrandom_outs.bin, wrong amounts count = "
<< daemon_resp.outs.size() << ", expected " << selected_transfers.size());
+
+ tfd.reason = fail_details::error_ok;
+ BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs)
+ {
+ if (amount_outs.outs.size() != fake_outputs_count)
+ {
+ tfd.reason = fail_details::error_too_big_mixin;
+ LOG_PRINT_L0("not enough outputs to mix output " << print_money(amount_outs.amount) << ", requested " <<
+ fake_outputs_count << ", found " << amount_outs.outs.size());
+ }
+ }
+ if (fail_details::error_ok != tfd.reason)
+ return false;
}
- tfd.reason = transafer_fail_details::error_ok;
+ tfd.reason = fail_details::error_ok;
//prepare inputs
size_t i = 0;
@@ -356,34 +448,48 @@ namespace tools
{
splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust));
}
-
- tfd.reason = transafer_fail_details::error_internal_error;
+
+ tfd.reason = fail_details::error_internal_error;
bool r = cryptonote::construct_tx(m_account.get_keys(), sources, splitted_dsts, tx, unlock_time);
CHECK_AND_ASSERT_MES(r, false, "Transaction construction failed");
//check transaction size
if(get_object_blobsize(tx) >= m_upper_transaction_size_limit)
{
- LOG_PRINT_RED("Transaction size is too big: " << get_object_blobsize(tx) << ", expected size < " << m_upper_transaction_size_limit, LOG_LEVEL_2);
- tfd.reason = transafer_fail_details::error_too_big_transaction;
+ LOG_PRINT_L0("Transaction size is too big: " << get_object_blobsize(tx) << ", expected size < " << m_upper_transaction_size_limit);
+ tfd.reason = fail_details::error_too_big_transaction;
tfd.tx_blob_size = get_object_blobsize(tx);
tfd.max_expected_tx_blob_size = m_upper_transaction_size_limit;
return false;
}
-
COMMAND_RPC_SEND_RAW_TX::request req;
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx));
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
- tfd.reason = transafer_fail_details::error_not_connected;
r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
- CHECK_AND_ASSERT_MES(r, false, "failed to send transaction");
- if(daemon_send_resp.status != CORE_RPC_STATUS_OK)
+ if (!r)
+ {
+ tfd.reason = fail_details::error_not_connected;
+ LOG_PRINT_L0("failed to send transaction: " << interpret_rpc_response(r, daemon_send_resp.status));
+ return false;
+ }
+ else if (CORE_RPC_STATUS_BUSY == daemon_send_resp.status)
{
- tfd.reason = transafer_fail_details::error_rejected_by_daemon;
- LOG_ERROR("daemon failed to accept generated transaction, id: " << get_transaction_hash(tx) );
+ tfd.reason = fail_details::error_daemon_is_busy;
+ LOG_PRINT_L0("failed to send transaction: " << interpret_rpc_response(r, daemon_send_resp.status));
return false;
}
+ else if (CORE_RPC_STATUS_OK != daemon_send_resp.status)
+ {
+ tfd.reason = fail_details::error_rejected_by_daemon;
+ LOG_ERROR("daemon failed to accept generated transaction, id: " << get_transaction_hash(tx));
+ return false;
+ }
+ else
+ {
+ tfd.reason = fail_details::error_ok;
+ }
+
std::string key_images;
std::for_each(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
{
@@ -397,12 +503,12 @@ namespace tools
it->m_spent = true;
LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(tx) << ">" << ENDL
- << "Commission: " << print_money(fee+dust) << "(dust: " << print_money(dust) << ")" << ENDL
+ << "Commission: " << print_money(fee+dust) << " (dust: " << print_money(dust) << ")" << ENDL
<< "Balance: " << print_money(balance()) << ENDL
<< "Unlocked: " << print_money(unlocked_balance()) << ENDL
<< "Please, wait for confirmation for your balance to be unlocked.");
- tfd.reason = transafer_fail_details::error_ok;
+ tfd.reason = fail_details::error_ok;
return true;
}
}