From c0b9af9a996c0ae90b6816d6b995006ff0b8e5b2 Mon Sep 17 00:00:00 2001 From: Eric Frias Date: Fri, 21 Aug 2015 19:53:35 -0400 Subject: [PATCH] Greatly reduce the amount of time the p2p network code will wait for a peer to return a requested block/transaction. Make this time dependent on the actual block interval. This should allow the the node to give up and request the block from another peer before the ~30 second undo interval has passed. Fix the merkle root calculation to avoid reading past the end of a vector. Modify the algorithm to do what was likely intended (this modification is currently disabled because it will yield different results than the currently-running testnet) Fix windows build errors. --- libraries/app/application.cpp | 5 +++ libraries/chain/block_database.cpp | 3 +- libraries/chain/protocol/block.cpp | 34 ++++++++++++++++++--- libraries/fc | 2 +- libraries/net/include/graphene/net/node.hpp | 2 ++ libraries/net/node.cpp | 23 +++++++++----- 6 files changed, 56 insertions(+), 13 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 00dc0dfc..4895bd2c 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -550,6 +550,11 @@ namespace detail { // notify GUI or something cool } + uint8_t get_current_block_interval_in_seconds() const override + { + return _chain_db->get_global_properties().parameters.block_interval; + } + application* _self; fc::path _data_dir; diff --git a/libraries/chain/block_database.cpp b/libraries/chain/block_database.cpp index cd1f1e29..e197a469 100644 --- a/libraries/chain/block_database.cpp +++ b/libraries/chain/block_database.cpp @@ -156,7 +156,8 @@ optional block_database::fetch_optional( const block_id_type& id ) vector data( e.block_size ); _blocks.seekg( e.block_pos ); - _blocks.read( data.data(), e.block_size ); + if (e.block_size) + _blocks.read( data.data(), e.block_size ); auto result = fc::raw::unpack(data); FC_ASSERT( result.id() == e.block_id ); return result; diff --git a/libraries/chain/protocol/block.cpp b/libraries/chain/protocol/block.cpp index 5ae676fb..808eb927 100644 --- a/libraries/chain/protocol/block.cpp +++ b/libraries/chain/protocol/block.cpp @@ -58,18 +58,44 @@ namespace graphene { namespace chain { checksum_type signed_block::calculate_merkle_root()const { - if( transactions.size() == 0 ) return checksum_type(); + if( transactions.size() == 0 ) + return checksum_type(); vector ids; ids.resize( ((transactions.size() + 1)/2)*2 ); for( uint32_t i = 0; i < transactions.size(); ++i ) ids[i] = transactions[i].merkle_digest(); - while( ids.size() > 1 ) + vector::size_type current_number_of_hashes = ids.size(); + while( true ) { +#define AUG_20_TESTNET_COMPATIBLE +#ifdef AUG_20_TESTNET_COMPATIBLE for( uint32_t i = 0; i < transactions.size(); i += 2 ) - ids[i/2] = digest_type::hash( std::make_pair( ids[i], ids[i+1] ) ); - ids.resize( ids.size() / 2 ); +#else + for( uint32_t i = 0; i < current_number_of_hashes; i += 2 ) +#endif + ids[i/2] = digest_type::hash( std::make_pair( ids[i], ids[i+1] ) ); + // since we're processing hashes in pairs, we need to ensure that we always + // have an even number of hashes in the ids list. If we would end up with + // an odd number, add a default-initialized hash to compensate + current_number_of_hashes /= 2; +#ifdef AUG_20_TESTNET_COMPATIBLE + if (current_number_of_hashes <= 1) + break; +#else + if (current_number_of_hashes == 1) + break; + if (current_number_of_hashes % 2) + { + ++current_number_of_hashes; + // TODO: HARD FORK: we should probably enable the next line the next time we fire + // up a new testnet; it will change the merkle roots we generate, but will + // give us a better-defined algorithm for calculating them + // + ids[current_number_of_hashes - 1] = digest_type(); + } +#endif } return checksum_type::hash( ids[0] ); } diff --git a/libraries/fc b/libraries/fc index 458b6017..71be796a 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 458b601774c36b702e2d4712320b5d53c6b2ee1c +Subproject commit 71be796af50c407281a40e61e4199a87e0a19314 diff --git a/libraries/net/include/graphene/net/node.hpp b/libraries/net/include/graphene/net/node.hpp index b8685ff9..c8e53f00 100644 --- a/libraries/net/include/graphene/net/node.hpp +++ b/libraries/net/include/graphene/net/node.hpp @@ -158,6 +158,8 @@ namespace graphene { namespace net { virtual uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const = 0; virtual void error_encountered(const std::string& message, const fc::oexception& error) = 0; + virtual uint8_t get_current_block_interval_in_seconds() const = 0; + }; /** diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index 08137457..c72a16be 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -289,7 +289,9 @@ namespace graphene { namespace net { namespace detail { (get_block_time) \ (get_head_block_id) \ (estimate_last_known_fork_from_git_revision_timestamp) \ - (error_encountered) + (error_encountered) \ + (get_current_block_interval_in_seconds) + #define DECLARE_ACCUMULATOR(r, data, method_name) \ mutable call_stats_accumulator BOOST_PP_CAT(_, BOOST_PP_CAT(method_name, _execution_accumulator)); \ @@ -390,6 +392,7 @@ namespace graphene { namespace net { namespace detail { item_hash_t get_head_block_id() const override; uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override; void error_encountered(const std::string& message, const fc::oexception& error) override; + uint8_t get_current_block_interval_in_seconds() const override; }; ///////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1282,9 +1285,10 @@ namespace graphene { namespace net { namespace detail { } // timeout for any active peers is two block intervals - uint32_t active_disconnect_timeout = std::max(5 * GRAPHENE_MAX_BLOCK_INTERVAL / 2, 30); - uint32_t active_send_keepalive_timeount = std::max(active_disconnect_timeout / 2, 11); - uint32_t active_ignored_request_timeount = std::max(GRAPHENE_MAX_BLOCK_INTERVAL / 4, 10); + uint8_t current_block_interval_in_seconds = _delegate->get_current_block_interval_in_seconds(); + uint32_t active_disconnect_timeout = 10 * current_block_interval_in_seconds; + uint32_t active_send_keepalive_timeount = active_disconnect_timeout / 2; + uint32_t active_ignored_request_timeount = 3 * current_block_interval_in_seconds; fc::time_point active_disconnect_threshold = fc::time_point::now() - fc::seconds(active_disconnect_timeout); fc::time_point active_send_keepalive_threshold = fc::time_point::now() - fc::seconds(active_send_keepalive_timeount); fc::time_point active_ignored_request_threshold = fc::time_point::now() - fc::seconds(active_ignored_request_timeount); @@ -1334,7 +1338,7 @@ namespace graphene { namespace net { namespace detail { peers_to_disconnect_forcibly.push_back(active_peer); } else if (active_peer->connection_initiation_time < active_send_keepalive_threshold && - active_peer->get_last_message_received_time() < active_send_keepalive_threshold) + active_peer->get_last_message_received_time() < active_send_keepalive_threshold) { wlog( "Sending a keepalive message to peer ${peer} who hasn't sent us any messages in the last ${timeout} seconds", ( "peer", active_peer->get_remote_endpoint() )("timeout", active_send_keepalive_timeount ) ); @@ -1387,11 +1391,11 @@ namespace graphene { namespace net { namespace detail { peers_to_send_keep_alive.clear(); for (const peer_connection_ptr& peer : peers_to_terminate ) - { + { assert(_terminating_connections.find(peer) != _terminating_connections.end()); _terminating_connections.erase(peer); schedule_peer_for_deletion(peer); - } + } if (!_node_is_shutting_down && !_terminate_inactive_connections_loop_done.canceled()) _terminate_inactive_connections_loop_done = fc::schedule( [this](){ terminate_inactive_connections_loop(); }, @@ -5217,6 +5221,11 @@ namespace graphene { namespace net { namespace detail { INVOKE_AND_COLLECT_STATISTICS(error_encountered, message, error); } + uint8_t statistics_gathering_node_delegate_wrapper::get_current_block_interval_in_seconds() const + { + INVOKE_AND_COLLECT_STATISTICS(get_current_block_interval_in_seconds); + } + #undef INVOKE_AND_COLLECT_STATISTICS } // end namespace detail