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.h46
-rw-r--r--src/ringct/rctSigs.cpp34
-rw-r--r--src/rpc/core_rpc_server.cpp10
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/wallet/wallet2.cpp53
13 files changed, 265 insertions, 53 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..4797eb82b 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:
@@ -396,6 +398,50 @@ namespace nodetool
return true;
}
//--------------------------------------------------------------------------------------------------
+ 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);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ 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);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
}
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/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/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];