aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/stack_trace.cpp2
-rw-r--r--src/cryptonote_core/blockchain.cpp6
-rw-r--r--src/cryptonote_core/blockchain.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp33
-rw-r--r--src/cryptonote_core/cryptonote_core.h4
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl25
-rw-r--r--src/p2p/net_node.h12
-rw-r--r--src/p2p/net_node.inl88
-rw-r--r--src/p2p/net_peerlist.h43
-rw-r--r--src/ringct/rctSigs.cpp34
-rw-r--r--src/ringct/rctTypes.h2
-rw-r--r--src/rpc/core_rpc_server.cpp10
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/wallet/api/wallet.cpp130
-rw-r--r--src/wallet/api/wallet.h6
-rw-r--r--src/wallet/api/wallet_manager.cpp16
-rw-r--r--src/wallet/api/wallet_manager.h7
-rw-r--r--src/wallet/wallet2.cpp53
-rw-r--r--src/wallet/wallet2_api.h21
-rw-r--r--src/wallet/wallet_args.cpp2
-rw-r--r--src/wallet/wallet_rpc_server.cpp2
21 files changed, 445 insertions, 56 deletions
diff --git a/src/common/stack_trace.cpp b/src/common/stack_trace.cpp
index ce05b7e04..99e4bda2c 100644
--- a/src/common/stack_trace.cpp
+++ b/src/common/stack_trace.cpp
@@ -38,7 +38,7 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "stacktrace"
-#define ST_LOG(x) CERROR(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
+#define ST_LOG(x) CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
// from http://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 8f1f0b260..789687ce0 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -636,7 +636,7 @@ crypto::hash Blockchain::get_block_id_by_height(uint64_t height) const
return null_hash;
}
//------------------------------------------------------------------
-bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk) const
+bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -645,6 +645,8 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk) const
try
{
blk = m_db->get_block(h);
+ if (orphan)
+ *orphan = false;
return true;
}
// try to find block in alternative chain
@@ -654,6 +656,8 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk) const
if (m_alternative_chains.end() != it_alt)
{
blk = it_alt->second.bl;
+ if (orphan)
+ *orphan = true;
return true;
}
}
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 245dc6e73..ca665e1d4 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -197,10 +197,11 @@ namespace cryptonote
*
* @param h the hash to look for
* @param blk return-by-reference variable to put result block in
+ * @param orphan if non-NULL, will be set to true if not in the main chain, false otherwise
*
* @return true if the block was found, else false
*/
- bool get_block_by_hash(const crypto::hash &h, block &blk) const;
+ bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan = NULL) const;
/**
* @brief get all block hashes (main chain, alt chains, and invalid blocks)
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 5294431d6..22d473b35 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -487,6 +487,13 @@ namespace cryptonote
}
//std::cout << "!"<< tx.vin.size() << std::endl;
+ if (bad_semantics_txes.find(tx_hash) != bad_semantics_txes.end())
+ {
+ LOG_PRINT_L1("Transaction already seen with bad semantics, rejected");
+ tvc.m_verifivation_failed = true;
+ return false;
+ }
+
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = version == 1 ? 1 : 2;
if (tx.version == 0 || tx.version > max_tx_version)
@@ -496,6 +503,18 @@ namespace cryptonote
return false;
}
+ if(m_mempool.have_tx(tx_hash))
+ {
+ LOG_PRINT_L2("tx " << tx_hash << "already have transaction in tx_pool");
+ return true;
+ }
+
+ if(m_blockchain_storage.have_tx(tx_hash))
+ {
+ LOG_PRINT_L2("tx " << tx_hash << " already have transaction in blockchain");
+ return true;
+ }
+
if(!check_tx_syntax(tx))
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected");
@@ -522,6 +541,7 @@ namespace cryptonote
if(!check_tx_semantic(tx, keeped_by_block))
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
+ bad_semantics_txes.insert(tx_hash);
tvc.m_verifivation_failed = true;
return false;
}
@@ -977,9 +997,9 @@ namespace cryptonote
return m_blockchain_storage.get_block_id_by_height(height);
}
//-----------------------------------------------------------------------------------------------
- bool core::get_block_by_hash(const crypto::hash &h, block &blk) const
+ bool core::get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan) const
{
- return m_blockchain_storage.get_block_by_hash(h, blk);
+ return m_blockchain_storage.get_block_by_hash(h, blk, orphan);
}
//-----------------------------------------------------------------------------------------------
std::string core::print_pool(bool short_format) const
@@ -1000,12 +1020,11 @@ namespace cryptonote
MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
<< "The daemon will start synchronizing with the network. It may take up to several hours." << ENDL
<< ENDL
- << "You can set the level of process detailization* through \"set_log <level|categories>\" command*, where <level> is between 0 (no details) and 4 (very verbose), or custom category based levels (eg, *:WARNING)" << ENDL
- << ENDL
- << "Use \"help\" command to see the list of available commands." << ENDL
+ << "You can set the level of process detailization* through \"set_log <level|categories>\" command*," << ENDL
+ << "where <level> is between 0 (no details) and 4 (very verbose), or custom category based levels (eg, *:WARNING)" << ENDL
<< ENDL
- << "Note: in case you need to interrupt the process, use \"exit\" command. Otherwise, the current progress won't be saved." << ENDL
- << "**********************************************************************");
+ << "Use the \"help\" command to see the list of available commands." << ENDL
+ << "**********************************************************************" << ENDL);
m_starter_message_showed = true;
}
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index fa67ff265..1b9518c96 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -330,7 +330,7 @@ namespace cryptonote
*
* @note see Blockchain::get_block_by_hash
*/
- bool get_block_by_hash(const crypto::hash &h, block &blk) const;
+ bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan = NULL) const;
/**
* @copydoc Blockchain::get_alternative_blocks
@@ -824,6 +824,8 @@ namespace cryptonote
size_t block_sync_size;
time_t start_time;
+
+ std::unordered_set<crypto::hash> bad_semantics_txes;
};
}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 58388f8f7..73e4fa72f 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -46,6 +46,8 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
+#define MLOG_P2P_MESSAGE(x) MCINFO("net.p2p.msg", context << x)
+
namespace cryptonote
{
@@ -314,7 +316,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_BLOCK (hop " << arg.hop << ")");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
m_core.pause_mine();
@@ -365,7 +367,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_FLUFFY_BLOCK (hop " << arg.hop << ")");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
@@ -613,7 +615,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_FLUFFY_MISSING_TX");
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes)");
std::list<block> local_blocks;
std::list<transaction> local_txs;
@@ -671,7 +673,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_TRANSACTIONS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
@@ -703,7 +705,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_GET_OBJECTS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
NOTIFY_RESPONSE_GET_OBJECTS::request rsp;
if(!m_core.handle_get_objects(arg, rsp, context))
{
@@ -743,7 +745,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_RESPONSE_GET_OBJECTS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
// calculate size of request - mainly for logging/debug
size_t size = 0;
@@ -933,7 +935,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << arg.block_ids.size());
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
NOTIFY_RESPONSE_CHAIN_ENTRY::request r;
if(!m_core.find_blockchain_supplement(arg.block_ids, r))
{
@@ -1020,13 +1022,10 @@ namespace cryptonote
bool val_expected = false;
if(m_synchronized.compare_exchange_strong(val_expected, true))
{
- MGINFO_GREEN(ENDL << "**********************************************************************" << ENDL
+ MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
<< "You are now synchronized with the network. You may now start monero-wallet-cli." << ENDL
<< ENDL
- << "Please note, that the blockchain will be saved only after you quit the daemon with \"exit\" command or if you use \"save\" command." << ENDL
- << "Otherwise, you will possibly need to synchronize the blockchain again." << ENDL
- << ENDL
- << "Use \"help\" command to see the list of available commands." << ENDL
+ << "Use the \"help\" command to see the list of available commands." << ENDL
<< "**********************************************************************");
m_core.on_synchronized();
}
@@ -1048,7 +1047,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
+ MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
if(!arg.m_block_ids.size())
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 3f5a5ad93..40598fc0f 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -110,7 +110,12 @@ namespace nodetool
void serialize(Archive &a, const t_version_type ver)
{
a & m_peerlist;
- a & m_config.m_peer_id;
+ if (ver == 0)
+ {
+ // from v1, we do not store the peer id anymore
+ peerid_type peer_id;
+ a & peer_id;
+ }
}
// debug functions
bool log_peerlist();
@@ -162,6 +167,7 @@ namespace nodetool
#endif
int handle_get_support_flags(int command, COMMAND_REQUEST_SUPPORT_FLAGS::request& arg, COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context);
bool init_config();
+ bool make_default_peer_id();
bool make_default_config();
bool store_config();
bool check_trust(const proof_of_trust& tr);
@@ -229,6 +235,9 @@ namespace nodetool
bool has_too_many_connections(const uint32_t ip);
+ bool check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp);
+ bool gray_peerlist_housekeeping();
+
void kill() { ///< will be called e.g. from deinit()
_info("Killing the net_node");
is_closing = true;
@@ -289,6 +298,7 @@ namespace nodetool
epee::math_helper::once_a_time_seconds<P2P_DEFAULT_HANDSHAKE_INTERVAL> m_peer_handshake_idle_maker_interval;
epee::math_helper::once_a_time_seconds<1> m_connections_maker_interval;
epee::math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval;
+ epee::math_helper::once_a_time_seconds<60> m_gray_peerlist_housekeeping_interval;
std::string m_bind_ip;
std::string m_port;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 60e51c222..0e43d9579 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -173,6 +173,9 @@ namespace nodetool
make_default_config();
}
+ // always recreate a new peer id
+ make_default_peer_id();
+
//at this moment we have hardcoded config
m_config.m_net_config.handshake_interval = P2P_DEFAULT_HANDSHAKE_INTERVAL;
m_config.m_net_config.packet_max_size = P2P_DEFAULT_PACKET_MAX_SIZE; //20 MB limit
@@ -205,20 +208,26 @@ namespace nodetool
if(time(nullptr) >= it->second)
{
m_blocked_ips.erase(it);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
return true;
}
return false;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::make_default_config()
+ bool node_server<t_payload_net_handler>::make_default_peer_id()
{
m_config.m_peer_id = crypto::rand<uint64_t>();
return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::make_default_config()
+ {
+ return make_default_peer_id();
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::block_ip(uint32_t addr, time_t seconds)
{
CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
@@ -237,7 +246,7 @@ namespace nodetool
for (const auto &c: conns)
m_net_server.get_config_object().close(c);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.");
return true;
}
//-----------------------------------------------------------------------------------
@@ -249,7 +258,7 @@ namespace nodetool
if (i == m_blocked_ips.end())
return false;
m_blocked_ips.erase(i);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
return true;
}
//-----------------------------------------------------------------------------------
@@ -926,6 +935,50 @@ namespace nodetool
return true;
}
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp)
+ {
+ LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":"
+ << epee::string_tools::num_to_string_fast(na.port) << "(last_seen: "
+ << (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never")
+ << ")...");
+
+ typename net_server::t_connection_context con = AUTO_VAL_INIT(con);
+ bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(na.ip),
+ epee::string_tools::num_to_string_fast(na.port),
+ m_config.m_net_config.connection_timeout,
+ con);
+
+ if (!res) {
+ bool is_priority = is_priority_node(na);
+
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to "
+ << epee::string_tools::get_ip_string_from_int32(na.ip)
+ << ":" << epee::string_tools::num_to_string_fast(na.port));
+
+ return false;
+ }
+
+ peerid_type pi = AUTO_VAL_INIT(pi);
+ res = do_handshake_with_peer(pi, con, true);
+
+ if (!res) {
+ bool is_priority = is_priority_node(na);
+
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer "
+ << epee::string_tools::get_ip_string_from_int32(na.ip)
+ << ":" << epee::string_tools::num_to_string_fast(na.port));
+
+ return false;
+ }
+
+ m_net_server.get_config_object().close(con.m_connection_id);
+
+ LOG_DEBUG_CC(con, "CONNECTION HANDSHAKED OK AND CLOSED.");
+
+ return true;
+ }
+
#undef LOG_PRINT_CC_PRIORITY_NODE
//-----------------------------------------------------------------------------------
@@ -1097,6 +1150,7 @@ namespace nodetool
{
m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::peer_sync_idle_maker, this));
m_connections_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::connections_maker, this));
+ m_gray_peerlist_housekeeping_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::gray_peerlist_housekeeping, this));
m_peerlist_store_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::store_config, this));
return true;
}
@@ -1704,4 +1758,30 @@ namespace nodetool
return count > max_connections;
}
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::gray_peerlist_housekeeping()
+ {
+ peerlist_entry pe = AUTO_VAL_INIT(pe);
+
+ if (!m_peerlist.get_random_gray_peer(pe)) {
+ return false;
+ }
+
+ bool success = check_connection_and_handshake_with_peer(pe.adr, pe.last_seen);
+
+ if (!success) {
+ m_peerlist.remove_from_peer_gray(pe);
+
+ LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id);
+
+ return true;
+ }
+
+ m_peerlist.set_peer_just_seen(pe.id, pe.adr);
+
+ LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id);
+
+ return true;
+ }
}
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index db9387ceb..160206ed3 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -81,6 +81,8 @@ namespace nodetool
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);
+ bool get_random_gray_peer(peerlist_entry& pe);
+ bool remove_from_peer_gray(const peerlist_entry& pe);
private:
@@ -393,9 +395,50 @@ namespace nodetool
}
return true;
CATCH_ENTRY_L0("peerlist_manager::append_with_peer_gray()", false);
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::get_random_gray_peer(peerlist_entry& pe)
+ {
+ TRY_ENTRY();
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+
+ if (m_peers_gray.empty()) {
+ return false;
+ }
+
+ size_t x = crypto::rand<size_t>() % (m_peers_gray.size() + 1);
+ size_t res = (x * x * x) / (m_peers_gray.size() * m_peers_gray.size()); //parabola \/
+
+ LOG_PRINT_L3("Random gray peer index=" << res << "(x="<< x << ", max_index=" << m_peers_gray.size() << ")");
+
+ peers_indexed::index<by_time>::type& by_time_index = m_peers_gray.get<by_time>();
+ pe = *epee::misc_utils::move_it_backward(--by_time_index.end(), res);
+
return true;
+
+ CATCH_ENTRY_L0("peerlist_manager::get_random_gray_peer()", false);
}
//--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::remove_from_peer_gray(const peerlist_entry& pe)
+ {
+ TRY_ENTRY();
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+
+ peers_indexed::index_iterator<by_addr>::type iterator = m_peers_gray.get<by_addr>().find(pe.adr);
+
+ if (iterator != m_peers_gray.get<by_addr>().end()) {
+ m_peers_gray.erase(iterator);
+ }
+
+ return true;
+
+ CATCH_ENTRY_L0("peerlist_manager::remove_from_peer_gray()", false);
+ }
+ //--------------------------------------------------------------------------------------------------
}
BOOST_CLASS_VERSION(nodetool::peerlist_manager, CURRENT_PEERLIST_STORAGE_ARCHIVE_VER)
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 74fed0ede..b8f3596e8 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -797,23 +797,6 @@ namespace rct {
tools::thread_group threadpool(tools::thread_group::optimal_with_max(threads));
if (semantics) {
- results.clear();
- results.resize(rv.outPk.size());
- tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
- for (size_t i = 0; i < rv.outPk.size(); i++) {
- region.run([&, i] {
- results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
- });
- }
- });
-
- for (size_t i = 0; i < results.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("Range proof verified failed for output " << i);
- return false;
- }
- }
-
key sumOutpks = identity();
for (size_t i = 0; i < rv.outPk.size(); i++) {
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
@@ -833,6 +816,23 @@ namespace rct {
LOG_PRINT_L1("Sum check failed");
return false;
}
+
+ results.clear();
+ results.resize(rv.outPk.size());
+ tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
+ for (size_t i = 0; i < rv.outPk.size(); i++) {
+ region.run([&, i] {
+ results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
+ });
+ }
+ });
+
+ for (size_t i = 0; i < results.size(); ++i) {
+ if (!results[i]) {
+ LOG_PRINT_L1("Range proof verified failed for output " << i);
+ return false;
+ }
+ }
}
else {
const key message = get_pre_mlsag_hash(rv);
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index b1aa243b9..0c27745e1 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -40,11 +40,11 @@
#include <cinttypes>
extern "C" {
-#include "crypto/generic-ops.h"
#include "crypto/crypto-ops.h"
#include "crypto/random.h"
#include "crypto/keccak.h"
}
+#include "crypto/generic-ops.h"
#include "crypto/crypto.h"
#include "serialization/serialization.h"
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 1c5c321da..7d896e491 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -985,7 +985,8 @@ namespace cryptonote
return false;
}
block blk;
- bool have_block = m_core.get_block_by_hash(block_hash, blk);
+ bool orphan = false;
+ bool have_block = m_core.get_block_by_hash(block_hash, blk, &orphan);
if (!have_block)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
@@ -999,7 +1000,7 @@ namespace cryptonote
return false;
}
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
- bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.block_header);
+ bool response_filled = fill_block_header_response(blk, orphan, block_height, block_hash, res.block_header);
if (!response_filled)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
@@ -1123,7 +1124,8 @@ namespace cryptonote
block_hash = m_core.get_block_id_by_height(req.height);
}
block blk;
- bool have_block = m_core.get_block_by_hash(block_hash, blk);
+ bool orphan = false;
+ bool have_block = m_core.get_block_by_hash(block_hash, blk, &orphan);
if (!have_block)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
@@ -1137,7 +1139,7 @@ namespace cryptonote
return false;
}
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
- bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.block_header);
+ bool response_filled = fill_block_header_response(blk, orphan, block_height, block_hash, res.block_header);
if (!response_filled)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 84871e8bb..767bcc715 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -194,3 +194,5 @@ private:
bool m_restricted;
};
}
+
+BOOST_CLASS_VERSION(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >, 1);
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 52ecc2e6a..c1cc5d10d 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -197,6 +197,44 @@ bool Wallet::addressValid(const std::string &str, bool testnet)
return get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, str);
}
+bool Wallet::keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error)
+{
+ bool has_payment_id;
+ cryptonote::account_public_address address;
+ crypto::hash8 pid;
+ if(!get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, address_string)) {
+ error = tr("Failed to parse address");
+ return false;
+ }
+
+ cryptonote::blobdata key_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(secret_key_string, key_data) || key_data.size() != sizeof(crypto::secret_key))
+ {
+ error = tr("Failed to parse key");
+ return false;
+ }
+ crypto::secret_key key = *reinterpret_cast<const crypto::secret_key*>(key_data.data());
+
+ // check the key match the given address
+ crypto::public_key pkey;
+ if (!crypto::secret_key_to_public_key(key, pkey)) {
+ error = tr("failed to verify key");
+ return false;
+ }
+ bool matchAddress = false;
+ if(isViewKey)
+ matchAddress = address.m_view_public_key == pkey;
+ else
+ matchAddress = address.m_spend_public_key == pkey;
+
+ if(!matchAddress) {
+ error = tr("key does not match address");
+ return false;
+ }
+
+ return true;
+}
+
std::string Wallet::paymentIdFromAddress(const std::string &str, bool testnet)
{
bool has_payment_id;
@@ -337,6 +375,98 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas
return true;
}
+bool WalletImpl::recoverFromKeys(const std::string &path,
+ const std::string &language,
+ const std::string &address_string,
+ const std::string &viewkey_string,
+ const std::string &spendkey_string)
+{
+ cryptonote::account_public_address address;
+ bool has_payment_id;
+ crypto::hash8 new_payment_id;
+ if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, m_wallet->testnet(), address_string))
+ {
+ m_errorString = tr("failed to parse address");
+ m_status = Status_Error;
+ return false;
+ }
+
+ // parse optional spend key
+ crypto::secret_key spendkey;
+ bool has_spendkey = false;
+ if (!spendkey_string.empty()) {
+ cryptonote::blobdata spendkey_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key))
+ {
+ m_errorString = tr("failed to parse secret spend key");
+ m_status = Status_Error;
+ return false;
+ }
+ has_spendkey = true;
+ spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data());
+ }
+
+ // parse view secret key
+ if (viewkey_string.empty()) {
+ m_errorString = tr("No view key supplied, cancelled");
+ m_status = Status_Error;
+ return false;
+ }
+ cryptonote::blobdata viewkey_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key))
+ {
+ m_errorString = tr("failed to parse secret view key");
+ m_status = Status_Error;
+ return false;
+ }
+ crypto::secret_key viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data());
+
+ // check the spend and view keys match the given address
+ crypto::public_key pkey;
+ if(has_spendkey) {
+ if (!crypto::secret_key_to_public_key(spendkey, pkey)) {
+ m_errorString = tr("failed to verify secret spend key");
+ m_status = Status_Error;
+ return false;
+ }
+ if (address.m_spend_public_key != pkey) {
+ m_errorString = tr("spend key does not match address");
+ m_status = Status_Error;
+ return false;
+ }
+ }
+ if (!crypto::secret_key_to_public_key(viewkey, pkey)) {
+ m_errorString = tr("failed to verify secret view key");
+ m_status = Status_Error;
+ return false;
+ }
+ if (address.m_view_public_key != pkey) {
+ m_errorString = tr("view key does not match address");
+ m_status = Status_Error;
+ return false;
+ }
+
+ try
+ {
+ if (has_spendkey) {
+ m_wallet->generate(path, "", address, spendkey, viewkey);
+ LOG_PRINT_L1("Generated new wallet from keys");
+ }
+ else {
+ m_wallet->generate(path, "", address, viewkey);
+ LOG_PRINT_L1("Generated new view only wallet from keys");
+ }
+
+ }
+ catch (const std::exception& e) {
+ m_errorString = string(tr("failed to generate new wallet: ")) + e.what();
+ m_status = Status_Error;
+ return false;
+ }
+ return true;
+}
+
+
bool WalletImpl::open(const std::string &path, const std::string &password)
{
clearStatus();
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index e3df7fd01..16a7f5d95 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -58,6 +58,11 @@ public:
const std::string &language) const;
bool open(const std::string &path, const std::string &password);
bool recover(const std::string &path, const std::string &seed);
+ bool recoverFromKeys(const std::string &path,
+ const std::string &language,
+ const std::string &address_string,
+ const std::string &viewkey_string,
+ const std::string &spendkey_string = "");
bool close();
std::string seed() const;
std::string getSeedLanguage() const;
@@ -94,6 +99,7 @@ public:
void setRecoveringFromSeed(bool recoveringFromSeed);
bool watchOnly() const;
bool rescanSpent();
+ bool testnet() const {return m_wallet->testnet();}
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 904338a72..fcb39d1f3 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -72,6 +72,22 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::st
return wallet;
}
+Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path,
+ const std::string &language,
+ bool testnet,
+ uint64_t restoreHeight,
+ const std::string &addressString,
+ const std::string &viewKeyString,
+ const std::string &spendKeyString)
+{
+ WalletImpl * wallet = new WalletImpl(testnet);
+ if(restoreHeight > 0){
+ wallet->setRefreshFromBlockHeight(restoreHeight);
+ }
+ wallet->recoverFromKeys(path, language, addressString, viewKeyString, spendKeyString);
+ return wallet;
+}
+
bool WalletManagerImpl::closeWallet(Wallet *wallet)
{
WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index ca9570254..ce9b70e96 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -41,6 +41,13 @@ public:
const std::string &language, bool testnet);
Wallet * openWallet(const std::string &path, const std::string &password, bool testnet);
virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet, uint64_t restoreHeight);
+ virtual Wallet * createWalletFromKeys(const std::string &path,
+ const std::string &language,
+ bool testnet,
+ uint64_t restoreHeight,
+ const std::string &addressString,
+ const std::string &viewKeyString,
+ const std::string &spendKeyString = "");
virtual bool closeWallet(Wallet *wallet);
bool walletExists(const std::string &path);
std::vector<std::string> findWallets(const std::string &path);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index c08b16a5f..4348b8a62 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -87,6 +87,8 @@ using namespace cryptonote;
#define FEE_ESTIMATE_GRACE_BLOCKS 10 // estimate fee valid for that many blocks
+#define SECOND_OUTPUT_RELATEDNESS_THRESHOLD 0.0f
+
#define KILL_IOSERVICE() \
do { \
work.reset(); \
@@ -2720,6 +2722,19 @@ namespace
vec.pop_back();
return res;
}
+
+ template<typename T>
+ void pop_if_present(std::vector<T>& vec, T e)
+ {
+ for (size_t i = 0; i < vec.size(); ++i)
+ {
+ if (e == vec[i])
+ {
+ pop_index (vec, i);
+ return;
+ }
+ }
+ }
}
//----------------------------------------------------------------------------------------------------
// This returns a handwavy estimation of how much two outputs are related
@@ -4028,6 +4043,17 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money) co
return picks;
}
+static bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices)
+{
+ if (!use_rct)
+ return false;
+ if (n_transfers > 1)
+ return false;
+ if (unused_dust_indices.empty() && unused_transfers_indices.empty())
+ return false;
+ return true;
+}
+
// Another implementation of transaction creation that is hopefully better
// While there is anything left to pay, it goes through random outputs and tries
// to fill the next destination/amount. If it fully fills it, it will use the
@@ -4152,9 +4178,19 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// - we have something to send
// - or we need to gather more fee
// - or we have just one input in that tx, which is rct (to try and make all/most rct txes 2/2)
- while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || (use_rct && txes.back().selected_transfers.size() == 1)) {
+ while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), unused_transfers_indices, unused_dust_indices)) {
TX &tx = txes.back();
+ LOG_PRINT_L2("Start of loop with " << unused_transfers_indices.size() << " " << unused_dust_indices.size());
+ LOG_PRINT_L2("unused_transfers_indices:");
+ for (auto t: unused_transfers_indices)
+ LOG_PRINT_L2(" " << t);
+ LOG_PRINT_L2("unused_dust_indices:");
+ for (auto t: unused_dust_indices)
+ LOG_PRINT_L2(" " << t);
+ LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? -1 : dsts[0].amount));
+ LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct);
+
// if we need to spend money and don't have any left, we fail
if (unused_dust_indices.empty() && unused_transfers_indices.empty()) {
LOG_PRINT_L2("No more outputs to choose from");
@@ -4167,9 +4203,20 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee)
// the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too
idx = pop_best_value(unused_dust_indices.empty() ? unused_transfers_indices : unused_dust_indices, tx.selected_transfers, true);
- else if (!prefered_inputs.empty())
+ else if (!prefered_inputs.empty()) {
idx = pop_back(prefered_inputs);
- else
+ pop_if_present(unused_transfers_indices, idx);
+ pop_if_present(unused_dust_indices, idx);
+
+ // since we're trying to add a second output which is not strictly needed,
+ // we only add it if it's unrelated enough to the first one
+ float relatedness = get_output_relatedness(m_transfers[idx], m_transfers[tx.selected_transfers.front()]);
+ if (relatedness > SECOND_OUTPUT_RELATEDNESS_THRESHOLD)
+ {
+ LOG_PRINT_L2("Second outout was not strictly needed, and relatedness " << relatedness << ", not adding");
+ break;
+ }
+ } else
idx = pop_best_value(unused_transfers_indices.empty() ? unused_dust_indices : unused_transfers_indices, tx.selected_transfers);
const transfer_details &td = m_transfers[idx];
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 78caddc0b..563f16eaa 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -295,6 +295,7 @@ struct Wallet
virtual bool setPassword(const std::string &password) = 0;
virtual std::string address() const = 0;
virtual std::string path() const = 0;
+ virtual bool testnet() const = 0;
/*!
* \brief integratedAddress - returns integrated address for current wallet address and given payment_id.
@@ -434,6 +435,7 @@ struct Wallet
static std::string genPaymentId();
static bool paymentIdValid(const std::string &paiment_id);
static bool addressValid(const std::string &str, bool testnet);
+ static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error);
static std::string paymentIdFromAddress(const std::string &str, bool testnet);
static uint64_t maximumAllowedAmount();
@@ -613,6 +615,25 @@ struct WalletManager
*/
virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet = false, uint64_t restoreHeight = 0) = 0;
+ /*!
+ * \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted
+ * \param path Name of wallet file to be created
+ * \param language language
+ * \param testnet testnet
+ * \param restoreHeight restore from start height
+ * \param addressString public address
+ * \param viewKeyString view key
+ * \param spendKeyString spend key (optional)
+ * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
+ */
+ virtual Wallet * createWalletFromKeys(const std::string &path,
+ const std::string &language,
+ bool testnet,
+ uint64_t restoreHeight,
+ const std::string &addressString,
+ const std::string &viewKeyString,
+ const std::string &spendKeyString = "") = 0;
+
/*!
* \brief Closes wallet. In case operation succeded, wallet object deleted. in case operation failed, wallet object not deleted
* \param wallet previously opened / created wallet instance
diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp
index 7ec4ad6e4..b7a4532fd 100644
--- a/src/wallet/wallet_args.cpp
+++ b/src/wallet/wallet_args.cpp
@@ -137,7 +137,7 @@ namespace wallet_args
if (!vm["log-file"].defaulted())
log_path = command_line::get_arg(vm, arg_log_file);
else
- log_path = mlog_get_default_log_path("monero-wallet-cli,log");
+ log_path = mlog_get_default_log_path("monero-wallet-cli.log");
mlog_configure(log_path, false);
if (!vm["log-level"].defaulted())
{
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 33e099ceb..d35e51068 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -369,7 +369,7 @@ namespace tools
cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, long_payment_id);
}
/* or short payment ID */
- else if (!wallet2::parse_short_payment_id(payment_id_str, short_payment_id)) {
+ else if (wallet2::parse_short_payment_id(payment_id_str, short_payment_id)) {
cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, short_payment_id);
}
else {