aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cryptonote_config.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp5
-rw-r--r--src/cryptonote_core/cryptonote_core.h14
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h47
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h7
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl338
-rw-r--r--src/daemon/rpc_command_executor.cpp2
-rw-r--r--src/p2p/net_node.h8
-rw-r--r--src/p2p/net_node.inl52
-rw-r--r--src/p2p/net_node_common.h4
-rw-r--r--src/p2p/p2p_protocol_defs.h23
-rw-r--r--src/wallet/api/wallet.cpp40
-rw-r--r--src/wallet/api/wallet.h3
-rw-r--r--src/wallet/wallet2.cpp15
-rw-r--r--src/wallet/wallet2_api.h16
15 files changed, 547 insertions, 30 deletions
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index 175a5d26e..95cbf74f0 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -113,6 +113,9 @@
#define P2P_IP_FAILS_BEFORE_BLOCK 10
#define P2P_IDLE_CONNECTION_KILL_INTERVAL (5*60) //5 minutes
+#define P2P_SUPPORT_FLAG_FLUFFY_BLOCKS 0x01
+#define P2P_SUPPORT_FLAGS P2P_SUPPORT_FLAG_FLUFFY_BLOCKS
+
#define ALLOW_DEBUG_COMMANDS
#define CRYPTONOTE_NAME "bitmonero"
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 95c49f627..9deb8863d 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -915,6 +915,11 @@ namespace cryptonote
m_mempool.get_transactions(txs);
return true;
}
+ //-----------------------------------------------------------------------------------------------
+ bool core::get_pool_transaction(const crypto::hash &id, transaction& tx) const
+ {
+ return m_mempool.get_transaction(id, tx);
+ }
//-----------------------------------------------------------------------------------------------
bool core::get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const
{
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index a5a97a5ad..5ddab4ed4 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -379,6 +379,13 @@ namespace cryptonote
* @note see tx_memory_pool::get_transactions
*/
bool get_pool_transactions(std::list<transaction>& txs) const;
+
+ /**
+ * @copydoc tx_memory_pool::get_transaction
+ *
+ * @note see tx_memory_pool::get_transaction
+ */
+ bool get_pool_transaction(const crypto::hash& id, transaction& tx) const;
/**
* @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info
@@ -611,6 +618,13 @@ namespace cryptonote
* @return the number of blocks to sync in one go
*/
std::pair<uint64_t, uint64_t> get_coinbase_tx_sum(const uint64_t start_offset, const size_t count);
+
+ /**
+ * @brief get whether we're on testnet or not
+ *
+ * @return are we on testnet?
+ */
+ bool get_testnet() const { return m_testnet; };
private:
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
index edcf2af8e..7adc69080 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_defs.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -69,6 +69,8 @@ namespace cryptonote
uint64_t avg_upload;
uint64_t current_upload;
+
+ uint32_t support_flags;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(incoming)
@@ -87,6 +89,7 @@ namespace cryptonote
KV_SERIALIZE(current_download)
KV_SERIALIZE(avg_upload)
KV_SERIALIZE(current_upload)
+ KV_SERIALIZE(support_flags)
END_KV_SERIALIZE_MAP()
};
@@ -223,5 +226,49 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
};
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct NOTIFY_NEW_FLUFFY_BLOCK
+ {
+ const static int ID = BC_COMMANDS_POOL_BASE + 8;
+
+ struct request
+ {
+ block_complete_entry b;
+ uint64_t current_blockchain_height;
+ uint32_t hop;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(b)
+ KV_SERIALIZE(current_blockchain_height)
+ KV_SERIALIZE(hop)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct NOTIFY_REQUEST_FLUFFY_MISSING_TX
+ {
+ const static int ID = BC_COMMANDS_POOL_BASE + 9;
+ struct request
+ {
+ block_complete_entry b;
+ uint64_t current_blockchain_height;
+ std::vector<size_t> missing_tx_indices;
+ uint32_t hop;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(b)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missing_tx_indices)
+ KV_SERIALIZE(hop)
+ KV_SERIALIZE(current_blockchain_height)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index 1c92958c9..ab5d8230d 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -91,6 +91,8 @@ namespace cryptonote
HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_GET_OBJECTS, &cryptonote_protocol_handler::handle_response_get_objects)
HANDLE_NOTIFY_T2(NOTIFY_REQUEST_CHAIN, &cryptonote_protocol_handler::handle_request_chain)
HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_CHAIN_ENTRY, &cryptonote_protocol_handler::handle_response_chain_entry)
+ HANDLE_NOTIFY_T2(NOTIFY_NEW_FLUFFY_BLOCK, &cryptonote_protocol_handler::handle_notify_new_fluffy_block)
+ HANDLE_NOTIFY_T2(NOTIFY_REQUEST_FLUFFY_MISSING_TX, &cryptonote_protocol_handler::handle_request_fluffy_missing_tx)
END_INVOKE_MAP2()
bool on_idle();
@@ -115,8 +117,9 @@ namespace cryptonote
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_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context);
-
-
+ int handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context);
+ int handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context);
+
//----------------- i_bc_protocol_layout ---------------------------------------
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context);
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context);
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 10756a8ad..65377f990 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -37,6 +37,7 @@
#include <boost/interprocess/detail/atomic.hpp>
#include <list>
+#include <unordered_map>
#include "cryptonote_core/cryptonote_format_utils.h"
#include "profile_tools.h"
@@ -124,6 +125,7 @@ namespace cryptonote
ss << std::setw(30) << std::left << "Remote Host"
<< std::setw(20) << "Peer id"
+ << std::setw(20) << "Support Flags"
<< std::setw(30) << "Recv/Sent (inactive,sec)"
<< std::setw(25) << "State"
<< std::setw(20) << "Livetime(sec)"
@@ -134,7 +136,7 @@ namespace cryptonote
<< ENDL;
uint32_t ip;
- m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
+ m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
{
bool local_ip = false;
ip = ntohl(cntxt.m_remote_ip);
@@ -145,6 +147,7 @@ namespace cryptonote
ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
epee::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(20) << std::hex << support_flags
<< std::setw(30) << 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)
@@ -184,7 +187,7 @@ namespace cryptonote
{
std::list<connection_info> connections;
- m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
+ m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
{
connection_info cnx;
auto timestamp = time(NULL);
@@ -197,6 +200,8 @@ namespace cryptonote
std::stringstream peer_id_str;
peer_id_str << std::hex << peer_id;
peer_id_str >> cnx.peer_id;
+
+ cnx.support_flags = support_flags;
cnx.recv_count = cntxt.m_recv_cnt;
cnx.recv_idle_time = timestamp - cntxt.m_last_recv;
@@ -361,6 +366,312 @@ 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 << ")");
+ if(context.m_state != cryptonote_connection_context::state_normal)
+ return 1;
+
+ m_core.pause_mine();
+
+ block new_block;
+ transaction miner_tx;
+ if(parse_and_validate_block_from_blob(arg.b.block, new_block))
+ {
+ // This is a seccond notification, we must have asked for some missing tx
+ if(!context.m_requested_objects.empty())
+ {
+ // What we asked for != to what we received ..
+ if(context.m_requested_objects.size() != arg.b.txs.size())
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "NOTIFY_NEW_FLUFFY_BLOCK -> request/response mismatch, "
+ << "block = " << epee::string_tools::pod_to_hex(get_blob_hash(arg.b.block))
+ << ", requested = " << context.m_requested_objects.size()
+ << ", received = " << new_block.tx_hashes.size()
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+ }
+
+ std::list<blobdata> have_tx;
+
+ // Instead of requesting missing transactions by hash like BTC,
+ // we do it by index (thanks to a suggestion from moneromooo) because
+ // we're way cooler .. and also because they're smaller than hashes.
+ //
+ // Also, remember to pepper some whitespace changes around to bother
+ // moneromooo ... only because I <3 him.
+ std::vector<size_t> need_tx_indices;
+
+ transaction tx;
+ crypto::hash tx_hash;
+
+ BOOST_FOREACH(auto& tx_blob, arg.b.txs)
+ {
+ if(parse_and_validate_tx_from_blob(tx_blob, tx))
+ {
+ try
+ {
+ if(!get_transaction_hash(tx, tx_hash))
+ {
+ LOG_PRINT_CCONTEXT_L1
+ (
+ "NOTIFY_NEW_FLUFFY_BLOCK: get_transaction_hash failed"
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+ }
+ catch(...)
+ {
+ LOG_PRINT_CCONTEXT_L1
+ (
+ "NOTIFY_NEW_FLUFFY_BLOCK: get_transaction_hash failed"
+ << ", exception thrown"
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+
+ // hijacking m_requested objects in connection context to patch up
+ // a possible DOS vector pointed out by @monero-moo where peers keep
+ // sending (0...n-1) transactions.
+ // If requested objects is not empty, then we must have asked for
+ // some missing transacionts, make sure that they're all there.
+ //
+ // Can I safely re-use this field? I think so, but someone check me!
+ if(!context.m_requested_objects.empty())
+ {
+ auto req_tx_it = context.m_requested_objects.find(tx_hash);
+ if(req_tx_it == context.m_requested_objects.end())
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "Peer sent wrong transaction (NOTIFY_NEW_FLUFFY_BLOCK): "
+ << "transaction with id = " << tx_hash << " wasn't requested, "
+ << "dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+
+ context.m_requested_objects.erase(req_tx_it);
+ }
+
+ // we might already have the tx that the peer
+ // sent in our pool, so don't verify again..
+ if(!m_core.get_pool_transaction(tx_hash, tx))
+ {
+ cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
+ if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true) || tvc.m_verifivation_failed)
+ {
+ LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+
+ //
+ // future todo:
+ // tx should only not be added to pool if verification failed, but
+ // maybe in the future could not be added for other reasons
+ // according to monero-moo so keep track of these separately ..
+ //
+ }
+ }
+ else
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "sent wrong tx: failed to parse and validate transaction: \r\n"
+ << epee::string_tools::buff_to_hex_nodelimer(tx_blob)
+ << "\r\n dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+ }
+
+ // The initial size equality check could have been fooled if the sender
+ // gave us the number of transactions we asked for, but not the right
+ // ones. This check make sure the transactions we asked for were the
+ // ones we received.
+ if(context.m_requested_objects.size())
+ {
+ LOG_PRINT_CCONTEXT_RED
+ (
+ "NOTIFY_NEW_FLUFFY_BLOCK: peer sent the number of transaction requested"
+ << ", but not the actual transactions requested"
+ << ", context.m_requested_objects.size() = " << context.m_requested_objects.size()
+ << ", dropping connection", LOG_LEVEL_0
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+
+ size_t tx_idx = 0;
+ BOOST_FOREACH(auto& tx_hash, new_block.tx_hashes)
+ {
+ if(m_core.get_pool_transaction(tx_hash, tx))
+ {
+ have_tx.push_back(tx_to_blob(tx));
+ }
+ else
+ {
+ need_tx_indices.push_back(tx_idx);
+ }
+
+ ++tx_idx;
+ }
+
+ if(!need_tx_indices.empty()) // drats, we don't have everything..
+ {
+ // request non-mempool txs
+ NOTIFY_REQUEST_FLUFFY_MISSING_TX::request missing_tx_req;
+ missing_tx_req.b = arg.b;
+ missing_tx_req.hop = arg.hop;
+ missing_tx_req.current_blockchain_height = arg.current_blockchain_height;
+ missing_tx_req.missing_tx_indices = std::move(need_tx_indices);
+
+ m_core.resume_mine();
+ post_notify<NOTIFY_REQUEST_FLUFFY_MISSING_TX>(missing_tx_req, context);
+ }
+ else // whoo-hoo we've got em all ..
+ {
+ block_complete_entry b;
+ b.block = arg.b.block;
+ b.txs = have_tx;
+
+ std::list<block_complete_entry> blocks;
+ blocks.push_back(b);
+ m_core.prepare_handle_incoming_blocks(blocks);
+
+ block_verification_context bvc = boost::value_initialized<block_verification_context>();
+ m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block
+ m_core.cleanup_handle_incoming_blocks(true);
+ m_core.resume_mine();
+
+ if( bvc.m_verifivation_failed )
+ {
+ LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ if( bvc.m_added_to_main_chain )
+ {
+ ++arg.hop;
+ //TODO: Add here announce protocol usage
+ NOTIFY_NEW_BLOCK::request reg_arg = AUTO_VAL_INIT(reg_arg);
+ reg_arg.hop = arg.hop;
+ reg_arg.current_blockchain_height = arg.current_blockchain_height;
+ reg_arg.b.block = b.block;
+ relay_block(reg_arg, context);
+ }
+ else if( bvc.m_marked_as_orphaned )
+ {
+ context.m_state = cryptonote_connection_context::state_synchronizing;
+ NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized<NOTIFY_REQUEST_CHAIN::request>();
+ m_core.get_short_chain_history(r.block_ids);
+ LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
+ post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
+ }
+ }
+ }
+ else
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "sent wrong block: failed to parse and validate block: \r\n"
+ << epee::string_tools::buff_to_hex_nodelimer(arg.b.block)
+ << "\r\n dropping connection"
+ );
+
+ m_core.resume_mine();
+ m_p2p->drop_connection(context);
+
+ return 1;
+ }
+
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ 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");
+
+ std::list<block> local_blocks;
+ std::list<transaction> local_txs;
+ if(!m_core.get_blocks(arg.current_blockchain_height - 1, 1, local_blocks, local_txs))
+ {
+
+ LOG_ERROR_CCONTEXT
+ (
+ "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
+ << ", get_blocks( start_offset = " << (arg.current_blockchain_height - 1) << " ) failed"
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+
+ NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
+ fluffy_response.b = arg.b;
+ fluffy_response.current_blockchain_height = m_core.get_current_blockchain_height();
+ fluffy_response.hop = arg.hop;
+ size_t local_txs_count = local_txs.size();
+ BOOST_FOREACH(auto& tx_idx, arg.missing_tx_indices)
+ {
+ if(tx_idx < local_txs_count)
+ {
+ fluffy_response.b.txs.push_back(t_serializable_object_to_blob( *(std::next(local_txs.begin(), tx_idx)) ));
+ }
+ else
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
+ << ", request is asking for a tx whose index is out of bounds "
+ << ", tx index = " << tx_idx << ", block_height = " << arg.current_blockchain_height
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ }
+
+ LOG_PRINT_CCONTEXT_L2
+ (
+ "-->>NOTIFY_RESPONSE_FLUFFY_MISSING_TX: "
+ << ", txs.size()=" << fluffy_response.b.txs.size()
+ << ", rsp.current_blockchain_height=" << fluffy_response.current_blockchain_height
+ );
+
+ post_notify<NOTIFY_NEW_FLUFFY_BLOCK>(fluffy_response, context);
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ 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");
@@ -775,7 +1086,28 @@ namespace cryptonote
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
{
- return relay_post_notify<NOTIFY_NEW_BLOCK>(arg, exclude_context);
+ NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_arg = AUTO_VAL_INIT(fluffy_arg);
+ fluffy_arg.hop = arg.hop;
+ fluffy_arg.current_blockchain_height = arg.current_blockchain_height;
+ std::list<blobdata> fluffy_txs;
+ fluffy_arg.b = arg.b;
+ fluffy_arg.b.txs = fluffy_txs;
+
+ m_p2p->for_each_connection([this, &arg, &fluffy_arg](connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
+ {
+ if(m_core.get_testnet() && support_flags & P2P_SUPPORT_FLAG_FLUFFY_BLOCKS)
+ {
+ LOG_PRINT_YELLOW("PEER SUPPORTS FLUFFY BLOCKS - RELAYING THIN/COMPACT WHATEVER BLOCK", LOG_LEVEL_1);
+ return post_notify<NOTIFY_NEW_FLUFFY_BLOCK>(fluffy_arg, cntxt);
+ }
+ else
+ {
+ LOG_PRINT_YELLOW("PEER DOESN'T SUPPORT FLUFFY BLOCKS - RELAYING FULL BLOCK", LOG_LEVEL_1);
+ return post_notify<NOTIFY_NEW_BLOCK>(arg, cntxt);
+ }
+ });
+
+ return 1;
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 7d50ae76b..65b42cc47 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -404,6 +404,7 @@ bool t_rpc_command_executor::print_connections() {
tools::msg_writer() << std::setw(30) << std::left << "Remote Host"
<< std::setw(20) << "Peer id"
+ << std::setw(20) << "Support Flags"
<< std::setw(30) << "Recv/Sent (inactive,sec)"
<< std::setw(25) << "State"
<< std::setw(20) << "Livetime(sec)"
@@ -422,6 +423,7 @@ bool t_rpc_command_executor::print_connections() {
//<< std::setw(30) << std::left << in_out
<< std::setw(30) << std::left << address
<< std::setw(20) << info.peer_id
+ << std::setw(20) << info.support_flags
<< std::setw(30) << std::to_string(info.recv_count) + "(" + std::to_string(info.recv_idle_time) + ")/" + std::to_string(info.send_count) + "(" + std::to_string(info.send_idle_time) + ")"
<< std::setw(25) << info.state
<< std::setw(20) << info.live_time
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 5943c248f..619bad40f 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -63,6 +63,7 @@ namespace nodetool
struct p2p_connection_context_t: base_type //t_payload_net_handler::connection_context //public net_utils::connection_context_base
{
peerid_type peer_id;
+ uint32_t support_flags;
};
template<class t_payload_net_handler>
@@ -146,6 +147,7 @@ namespace nodetool
HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
#endif
+ HANDLE_INVOKE_T2(COMMAND_REQUEST_SUPPORT_FLAGS, &node_server::handle_get_support_flags)
CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&)
END_INVOKE_MAP2()
@@ -158,6 +160,7 @@ namespace nodetool
int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context);
int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context);
#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_config();
bool store_config();
@@ -174,7 +177,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&, peerid_type)> f);
+ virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f);
virtual bool add_ip_fail(uint32_t address);
//----------------- i_connection_filter --------------------------------------------------------
virtual bool is_remote_ip_allowed(uint32_t adress);
@@ -204,6 +207,7 @@ namespace nodetool
bool is_addr_connected(const net_address& peer);
template<class t_callback>
bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb);
+ bool try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f);
bool make_expected_connections_count(bool white_list, size_t expected_connections);
void cache_connect_fail_info(const net_address& addr);
bool is_addr_recently_failed(const net_address& addr);
@@ -240,10 +244,12 @@ namespace nodetool
{
network_config m_net_config;
uint64_t m_peer_id;
+ uint32_t m_support_flags;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_net_config)
KV_SERIALIZE(m_peer_id)
+ KV_SERIALIZE(m_support_flags)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 04d73ba95..d8dadae1f 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -158,6 +158,7 @@ namespace nodetool
m_config.m_net_config.connection_timeout = P2P_DEFAULT_CONNECTION_TIMEOUT;
m_config.m_net_config.ping_connection_timeout = P2P_DEFAULT_PING_CONNECTION_TIMEOUT;
m_config.m_net_config.send_peerlist_sz = P2P_DEFAULT_PEERS_IN_HANDSHAKE;
+ m_config.m_support_flags = P2P_SUPPORT_FLAGS;
m_first_connection_maker_call = true;
CATCH_ENTRY_L0("node_server::init_config", false);
@@ -165,10 +166,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&, peerid_type)> f)
+ void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f)
{
m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){
- return f(cntx, cntx.peer_id);
+ return f(cntx, cntx.peer_id, cntx.support_flags);
});
}
//-----------------------------------------------------------------------------------
@@ -730,6 +731,13 @@ namespace nodetool
LOG_PRINT_CC_L1(context_, "COMMAND_HANDSHAKE Failed");
m_net_server.get_config_object().close(context_.m_connection_id);
}
+ else
+ {
+ try_get_support_flags(context_, [](p2p_connection_context& flags_context, const uint32_t& support_flags)
+ {
+ flags_context.support_flags = support_flags;
+ });
+ }
return hsh_result;
}
@@ -1221,6 +1229,13 @@ namespace nodetool
#endif
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ int node_server<t_payload_net_handler>::handle_get_support_flags(int command, COMMAND_REQUEST_SUPPORT_FLAGS::request& arg, COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context)
+ {
+ rsp.support_flags = m_config.m_support_flags;
+ return 1;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
void node_server<t_payload_net_handler>::request_callback(const epee::net_utils::connection_context_base& context)
{
m_net_server.get_config_object().request_callback(context.m_connection_id);
@@ -1338,6 +1353,32 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f)
+ {
+ COMMAND_REQUEST_SUPPORT_FLAGS::request support_flags_request;
+ bool r = epee::net_utils::async_invoke_remote_command2<typename COMMAND_REQUEST_SUPPORT_FLAGS::response>
+ (
+ context.m_connection_id,
+ COMMAND_REQUEST_SUPPORT_FLAGS::ID,
+ support_flags_request,
+ m_net_server.get_config_object(),
+ [=](int code, const typename COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context_)
+ {
+ if(code < 0)
+ {
+ LOG_PRINT_CC_RED(context_, "COMMAND_REQUEST_SUPPORT_FLAGS invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")", LOG_LEVEL_1);
+ return;
+ }
+
+ f(context_, rsp.support_flags);
+ },
+ P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT
+ );
+
+ return r;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
int node_server<t_payload_net_handler>::handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context)
{
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, false))
@@ -1394,7 +1435,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;
- 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]()
{
@@ -1410,6 +1451,11 @@ namespace nodetool
LOG_PRINT_CCONTEXT_L2("PING SUCCESS " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l);
});
}
+
+ try_get_support_flags(context, [](p2p_connection_context& flags_context, const uint32_t& support_flags)
+ {
+ flags_context.support_flags = support_flags;
+ });
//fill response
m_peerlist.get_peerlist_head(rsp.local_peerlist);
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 5e7645365..846c07779 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -49,7 +49,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&, peerid_type)> f)=0;
+ virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
virtual bool block_ip(uint32_t adress, time_t seconds = 0)=0;
virtual bool unblock_ip(uint32_t adress)=0;
virtual std::map<uint32_t, time_t> get_blocked_ips()=0;
@@ -79,7 +79,7 @@ namespace nodetool
{
}
- virtual void for_each_connection(std::function<bool(t_connection_context&,peerid_type)> f)
+ virtual void for_each_connection(std::function<bool(t_connection_context&,peerid_type,uint32_t)> f)
{
}
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index bad4c89e3..ce1ee1449 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -332,6 +332,29 @@ namespace nodetool
};
};
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct COMMAND_REQUEST_SUPPORT_FLAGS
+ {
+ const static int ID = P2P_COMMANDS_POOL_BASE + 7;
+
+ struct request
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ uint32_t support_flags;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(support_flags)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
#endif
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 6c1c1fea2..134ea601c 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -201,6 +201,7 @@ WalletImpl::WalletImpl(bool testnet)
, m_wallet2Callback(nullptr)
, m_recoveringFromSeed(false)
, m_synchronized(false)
+ , m_rebuildWalletCache(false)
{
m_wallet = new tools::wallet2(testnet);
m_history = new TransactionHistoryImpl(this);
@@ -269,6 +270,14 @@ bool WalletImpl::open(const std::string &path, const std::string &password)
m_recoveringFromSeed = false;
try {
// TODO: handle "deprecated"
+ // Check if wallet cache exists
+ bool keys_file_exists;
+ bool wallet_file_exists;
+ tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists);
+ if(!wallet_file_exists){
+ // Rebuilding wallet cache, using refresh height from .keys file
+ m_rebuildWalletCache = true;
+ }
m_wallet->load(path, password);
m_password = password;
@@ -540,15 +549,14 @@ int WalletImpl::autoRefreshInterval() const
// - unconfirmed_transfer_details;
// - confirmed_transfer_details)
-PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count,
+PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority priority)
{
clearStatus();
// Pause refresh thread while creating transaction
pauseRefresh();
- vector<cryptonote::tx_destination_entry> dsts;
- cryptonote::tx_destination_entry de;
+ cryptonote::account_public_address addr;
// indicates if dst_addr is integrated address (address + payment_id)
bool has_payment_id;
@@ -561,7 +569,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
do {
- if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, payment_id_short, m_wallet->testnet(), dst_addr)) {
+ if(!cryptonote::get_account_integrated_address_from_str(addr, has_payment_id, payment_id_short, m_wallet->testnet(), dst_addr)) {
// TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982
m_status = Status_Error;
m_errorString = "Invalid destination address";
@@ -595,14 +603,23 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
}
}
- de.amount = amount;
- dsts.push_back(de);
//std::vector<tools::wallet2::pending_tx> ptx_vector;
try {
- transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
- static_cast<uint32_t>(priority),
- extra, m_trustedDaemon);
+ if (amount) {
+ vector<cryptonote::tx_destination_entry> dsts;
+ cryptonote::tx_destination_entry de;
+ de.addr = addr;
+ de.amount = *amount;
+ dsts.push_back(de);
+ transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
+ static_cast<uint32_t>(priority),
+ extra, m_trustedDaemon);
+ } else {
+ transaction->m_pending_tx = m_wallet->create_transactions_all(addr, fake_outs_count, 0 /* unlock_time */,
+ static_cast<uint32_t>(priority),
+ extra, m_trustedDaemon);
+ }
} catch (const tools::error::daemon_busy&) {
// TODO: make it translatable with "tr"?
@@ -990,8 +1007,9 @@ bool WalletImpl::isNewWallet() const
{
// in case wallet created without daemon connection, closed and opened again,
// it's the same case as if it created from scratch, i.e. we need "fast sync"
- // with the daemon (pull hashes instead of pull blocks)
- return !(blockChainHeight() > 1 || m_recoveringFromSeed);
+ // with the daemon (pull hashes instead of pull blocks).
+ // If wallet cache is rebuilt, creation height stored in .keys is used.
+ return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_rebuildWalletCache);
}
void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit)
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index f40551fac..372d6efd7 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -89,7 +89,7 @@ public:
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
- uint64_t amount, uint32_t mixin_count,
+ optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority priority = PendingTransaction::Priority_Low);
virtual PendingTransaction * createSweepUnmixableTransaction();
@@ -145,6 +145,7 @@ private:
// instead of pulling hashes (fast-refresh)
bool m_recoveringFromSeed;
std::atomic<bool> m_synchronized;
+ bool m_rebuildWalletCache;
};
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index ac8802ca4..1e3bb6253 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -2972,9 +2972,9 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
break;
}
}
- LOG_PRINT_L1("" << num_outs << " outputs of size " << print_money(amount));
+ LOG_PRINT_L1("" << num_outs << " unlocked outputs of size " << print_money(amount));
THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error,
- "histogram reports no outputs for " + boost::lexical_cast<std::string>(amount) + ", not even ours");
+ "histogram reports no unlocked outputs for " + boost::lexical_cast<std::string>(amount) + ", not even ours");
THROW_WALLET_EXCEPTION_IF(num_recent_outs > num_outs, error::wallet_internal_error,
"histogram reports more recent outs than outs for " + boost::lexical_cast<std::string>(amount));
@@ -2984,7 +2984,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
recent_outputs_count = 1; // ensure we have at least one, if possible
if (recent_outputs_count > num_recent_outs)
recent_outputs_count = num_recent_outs;
- if (td.m_global_output_index >= num_outs - num_recent_outs)
+ if (td.m_global_output_index >= num_outs - num_recent_outs && recent_outputs_count > 0)
--recent_outputs_count; // if the real out is recent, pick one less recent fake out
LOG_PRINT_L1("Using " << recent_outputs_count << " recent outputs");
@@ -3023,6 +3023,9 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
uint64_t r = crypto::rand<uint64_t>() % ((uint64_t)1 << 53);
double frac = std::sqrt((double)r / ((uint64_t)1 << 53));
i = (uint64_t)(frac*num_recent_outs) + num_outs - num_recent_outs;
+ // just in case rounding up to 1 occurs after calc
+ if (i == num_outs)
+ --i;
LOG_PRINT_L2("picking " << i << " as recent");
}
else
@@ -3031,11 +3034,11 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
uint64_t r = crypto::rand<uint64_t>() % ((uint64_t)1 << 53);
double frac = std::sqrt((double)r / ((uint64_t)1 << 53));
i = (uint64_t)(frac*num_outs);
+ // just in case rounding up to 1 occurs after calc
+ if (i == num_outs)
+ --i;
LOG_PRINT_L2("picking " << i << " as triangular");
}
- // just in case rounding up to 1 occurs after calc
- if (i == num_outs)
- --i;
if (seen_indices.count(i))
continue;
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index f0a9ea68b..6fe15d1e3 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -41,6 +41,20 @@ namespace Bitmonero {
namespace Utils {
bool isAddressLocal(const std::string &hostaddr);
}
+
+ template<typename T>
+ class optional {
+ public:
+ optional(): set(false) {}
+ optional(const T &t): t(t), set(true) {}
+ const T &operator*() const { return t; }
+ T &operator*() { return t; }
+ operator bool() const { return set; }
+ private:
+ T t;
+ bool set;
+ };
+
/**
* @brief Transaction-like interface for sending money
*/
@@ -332,7 +346,7 @@ struct Wallet
*/
virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
- uint64_t amount, uint32_t mixin_count,
+ optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0;
/*!