diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 612e2b41..b75a9eca 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -899,9 +899,7 @@ POP_WARNINGS boost::bind(&boosted_tcp_server::handle_accept, this, boost::asio::placeholders::error)); - bool r = conn->start(true, 1 < m_threads_count); - if (!r) - _erro("[sock " << conn->socket().native_handle() << "] Failed to start connection, connections_count = " << m_sock_count); + conn->start(true, 1 < m_threads_count); conn->save_dbg_log(); }else { diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 6053387a..33005660 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -105,6 +105,11 @@ #define P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT 5000 //5 seconds #define P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT 70 +#define P2P_FAILED_ADDR_FORGET_SECONDS (60*60) //1 hour +#define P2P_IP_BLOCKTIME (60*60*24) //24 hour +#define P2P_IP_FAILS_BEFORE_BLOCK 10 +#define P2P_IDLE_CONNECTION_KILL_INTERVAL (5*60) //5 minutes + #define ALLOW_DEBUG_COMMANDS #define CRYPTONOTE_NAME "bitmonero" diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 8bb63ad0..af771397 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -257,13 +257,13 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet) if (testnet) { m_hardfork = new HardFork(*db, 1, testnet_hard_fork_version_1_till); for (size_t n = 0; n < sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); ++n) - m_hardfork->add(testnet_hard_forks[n].version, testnet_hard_forks[n].height, testnet_hard_forks[n].threshold, testnet_hard_forks[n].time); + m_hardfork->add_fork(testnet_hard_forks[n].version, testnet_hard_forks[n].height, testnet_hard_forks[n].threshold, testnet_hard_forks[n].time); } else { m_hardfork = new HardFork(*db, 1, mainnet_hard_fork_version_1_till); for (size_t n = 0; n < sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); ++n) - m_hardfork->add(mainnet_hard_forks[n].version, mainnet_hard_forks[n].height, mainnet_hard_forks[n].threshold, mainnet_hard_forks[n].time); + m_hardfork->add_fork(mainnet_hard_forks[n].version, mainnet_hard_forks[n].height, mainnet_hard_forks[n].threshold, mainnet_hard_forks[n].time); } m_hardfork->init(); @@ -2338,7 +2338,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& // this is a cheap test if (!m_hardfork->check(bl)) { - LOG_PRINT_L1("Block with id: " << id << std::endl << "has old version: " << bl.major_version << std::endl << "current: " << m_hardfork->get_current_version()); + LOG_PRINT_L1("Block with id: " << id << std::endl << "has old version: " << (unsigned)bl.major_version << std::endl << "current: " << (unsigned)m_hardfork->get_current_version()); return false; } diff --git a/src/cryptonote_core/hardfork.cpp b/src/cryptonote_core/hardfork.cpp index edc2f33a..2a2e2563 100644 --- a/src/cryptonote_core/hardfork.cpp +++ b/src/cryptonote_core/hardfork.cpp @@ -46,6 +46,11 @@ static uint8_t get_block_vote(const cryptonote::block &b) return b.minor_version; } +static uint8_t get_block_version(const cryptonote::block &b) +{ + return b.major_version; +} + HardFork::HardFork(cryptonote::BlockchainDB &db, uint8_t original_version, uint64_t original_version_till_height, time_t forked_time, time_t update_time, uint64_t window_size, uint8_t default_threshold_percent): db(db), original_version(original_version), @@ -61,7 +66,7 @@ HardFork::HardFork(cryptonote::BlockchainDB &db, uint8_t original_version, uint6 throw "default_threshold_percent needs to be between 0 and 100"; } -bool HardFork::add(uint8_t version, uint64_t height, uint8_t threshold, time_t time) +bool HardFork::add_fork(uint8_t version, uint64_t height, uint8_t threshold, time_t time) { CRITICAL_REGION_LOCAL(lock); @@ -82,42 +87,43 @@ bool HardFork::add(uint8_t version, uint64_t height, uint8_t threshold, time_t t return true; } -bool HardFork::add(uint8_t version, uint64_t height, time_t time) +bool HardFork::add_fork(uint8_t version, uint64_t height, time_t time) { - return add(version, height, default_threshold_percent, time); + return add_fork(version, height, default_threshold_percent, time); } -uint8_t HardFork::get_effective_version(uint8_t version) const +uint8_t HardFork::get_effective_version(uint8_t voting_version) const { if (!heights.empty()) { uint8_t max_version = heights.back().version; - if (version > max_version) - version = max_version; + if (voting_version > max_version) + voting_version = max_version; } - return version; + return voting_version; } -bool HardFork::do_check(uint8_t version) const +bool HardFork::do_check(uint8_t block_version, uint8_t voting_version) const { - return version >= heights[current_fork_index].version; + return block_version >= heights[current_fork_index].version + && voting_version >= heights[current_fork_index].version; } bool HardFork::check(const cryptonote::block &block) const { CRITICAL_REGION_LOCAL(lock); - return do_check(get_block_vote(block)); + return do_check(::get_block_version(block), ::get_block_vote(block)); } -bool HardFork::add(uint8_t block_version, uint64_t height) +bool HardFork::add(uint8_t block_version, uint8_t voting_version, uint64_t height) { CRITICAL_REGION_LOCAL(lock); - if (!do_check(block_version)) + if (!do_check(block_version, voting_version)) return false; db.set_hard_fork_version(height, heights[current_fork_index].version); - const uint8_t version = get_effective_version(block_version); + voting_version = get_effective_version(voting_version); while (versions.size() >= window_size) { const uint8_t old_version = versions.front(); @@ -126,8 +132,8 @@ bool HardFork::add(uint8_t block_version, uint64_t height) versions.pop_front(); } - last_versions[version]++; - versions.push_back(version); + last_versions[voting_version]++; + versions.push_back(voting_version); uint8_t voted = get_voted_fork_index(height + 1); if (voted > current_fork_index) { @@ -143,7 +149,7 @@ bool HardFork::add(uint8_t block_version, uint64_t height) bool HardFork::add(const cryptonote::block &block, uint64_t height) { - return add(get_block_vote(block), height); + return add(::get_block_version(block), ::get_block_vote(block), height); } void HardFork::init() @@ -185,7 +191,7 @@ uint8_t HardFork::get_block_version(uint64_t height) const return original_version; const cryptonote::block &block = db.get_block_from_height(height); - return get_block_vote(block); + return ::get_block_version(block); } bool HardFork::reorganize_from_block_height(uint64_t height) @@ -225,7 +231,7 @@ bool HardFork::reorganize_from_block_height(uint64_t height) const uint64_t bc_height = db.height(); for (uint64_t h = height + 1; h < bc_height; ++h) { - add(get_block_version(h), h); + add(db.get_block_from_height(h), h); } db.batch_stop(); @@ -258,7 +264,7 @@ bool HardFork::rescan_from_block_height(uint64_t height) versions.push_back(v); } - uint8_t lastv = db.get_hard_fork_version(height); + uint8_t lastv = db.get_hard_fork_version(db.height() - 1); current_fork_index = 0; while (current_fork_index + 1 < heights.size() && heights[current_fork_index].version != lastv) ++current_fork_index; diff --git a/src/cryptonote_core/hardfork.h b/src/cryptonote_core/hardfork.h index 6800749d..6d2a3c55 100644 --- a/src/cryptonote_core/hardfork.h +++ b/src/cryptonote_core/hardfork.h @@ -71,7 +71,7 @@ namespace cryptonote * @param threshold The threshold of votes needed for this fork (0-100) * @param time Approximate time of the hardfork (seconds since epoch) */ - bool add(uint8_t version, uint64_t height, uint8_t threshold, time_t time); + bool add_fork(uint8_t version, uint64_t height, uint8_t threshold, time_t time); /** * @brief add a new hardfork height @@ -79,10 +79,11 @@ namespace cryptonote * returns true if no error, false otherwise * * @param version the major block version for the fork + * @param voting_version the minor block version for the fork, used for voting * @param height The height the hardfork takes effect * @param time Approximate time of the hardfork (seconds since epoch) */ - bool add(uint8_t version, uint64_t height, time_t time); + bool add_fork(uint8_t version, uint64_t height, time_t time); /** * @brief initialize the object @@ -203,10 +204,10 @@ namespace cryptonote private: uint8_t get_block_version(uint64_t height) const; - bool do_check(uint8_t version) const; + bool do_check(uint8_t block_version, uint8_t voting_version) const; int get_voted_fork_index(uint64_t height) const; - uint8_t get_effective_version(uint8_t version) const; - bool add(uint8_t block_version, uint64_t height); + uint8_t get_effective_version(uint8_t voting_version) const; + bool add(uint8_t block_version, uint8_t voting_version, uint64_t height); bool rescan_from_block_height(uint64_t height); bool rescan_from_chain_height(uint64_t height); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 83c7233b..a6761101 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -571,6 +571,7 @@ namespace cryptonote { LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection"); m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); m_core.cleanup_handle_incoming_blocks(); return 1; } @@ -578,6 +579,7 @@ namespace cryptonote { LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection"); m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); m_core.cleanup_handle_incoming_blocks(); return 1; } @@ -728,6 +730,7 @@ namespace cryptonote { LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection"); m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); return 1; } @@ -736,6 +739,7 @@ namespace cryptonote LOG_ERROR_CCONTEXT("sent m_block_ids starting from unknown id: " << epee::string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection"); m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); return 1; } diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 3eb12520..4aaac813 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "cryptonote_config.h" #include "warnings.h" @@ -66,7 +67,8 @@ namespace nodetool template class node_server: public epee::levin::levin_commands_handler >, - public i_p2p_endpoint + public i_p2p_endpoint, + public epee::net_utils::i_connection_filter { struct by_conn_id{}; struct by_peer_id{}; @@ -169,6 +171,10 @@ namespace nodetool 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 f); + virtual bool block_ip(uint32_t adress); + virtual bool add_ip_fail(uint32_t address); + //----------------- i_connection_filter -------------------------------------------------------- + virtual bool is_remote_ip_allowed(uint32_t adress); //----------------------------------------------------------------------------------------------- bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr); bool handle_command_line( @@ -196,6 +202,8 @@ namespace nodetool template bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb); 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); bool is_priority_node(const net_address& na); template @@ -282,6 +290,15 @@ namespace nodetool //keep connections to initiate some interactions net_server m_net_server; boost::uuids::uuid m_network_id; + + std::map m_conn_fails_cache; + epee::critical_section m_conn_fails_cache_lock; + + epee::critical_section m_blocked_ips_lock; + std::map m_blocked_ips; + + epee::critical_section m_ip_fails_score_lock; + std::map m_ip_fails_score; }; } diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index d92b4bb2..11df7ee4 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -28,6 +28,8 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +// IP blocking adapted from Boolberry + #pragma once #include @@ -161,6 +163,22 @@ namespace nodetool } //----------------------------------------------------------------------------------- template + bool node_server::is_remote_ip_allowed(uint32_t addr) + { + CRITICAL_REGION_LOCAL(m_blocked_ips_lock); + auto it = m_blocked_ips.find(addr); + if(it == m_blocked_ips.end()) + return true; + if(time(nullptr) - it->second > P2P_IP_BLOCKTIME ) + { + m_blocked_ips.erase(it); + LOG_PRINT_CYAN("IP " << epee::string_tools::get_ip_string_from_int32(addr) << "is unblocked.", LOG_LEVEL_0); + return true; + } + return false; + } + //----------------------------------------------------------------------------------- + template bool node_server::make_default_config() { m_config.m_peer_id = crypto::rand(); @@ -168,6 +186,31 @@ namespace nodetool } //----------------------------------------------------------------------------------- template + bool node_server::block_ip(uint32_t addr) + { + CRITICAL_REGION_LOCAL(m_blocked_ips_lock); + m_blocked_ips[addr] = time(nullptr); + LOG_PRINT_CYAN("IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.", LOG_LEVEL_0); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::add_ip_fail(uint32_t address) + { + CRITICAL_REGION_LOCAL(m_ip_fails_score_lock); + uint64_t fails = ++m_ip_fails_score[address]; + LOG_PRINT_CYAN("IP " << epee::string_tools::get_ip_string_from_int32(address) << " fail score=" << fails, LOG_LEVEL_1); + if(fails > P2P_IP_FAILS_BEFORE_BLOCK) + { + auto it = m_ip_fails_score.find(address); + CHECK_AND_ASSERT_MES(it != m_ip_fails_score.end(), false, "internal error"); + it->second = P2P_IP_FAILS_BEFORE_BLOCK/2; + block_ip(address); + } + return true; + } + //----------------------------------------------------------------------------------- + template bool node_server::parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr) { return epee::string_tools::parse_peer_from_string(pe.ip, pe.port, node_addr); @@ -428,6 +471,7 @@ namespace nodetool m_net_server.set_threads_prefix("P2P"); m_net_server.get_config_object().m_pcommands_handler = this; m_net_server.get_config_object().m_invoke_timeout = P2P_DEFAULT_INVOKE_TIMEOUT; + m_net_server.set_connection_filter(this); //try to bind LOG_PRINT_L0("Binding on " << m_bind_ip << ":" << m_port); @@ -624,6 +668,7 @@ namespace nodetool if(!handle_remote_peerlist(rsp.local_peerlist, rsp.node_data.local_time, context)) { LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE: failed to handle_remote_peerlist(...), closing connection."); + add_ip_fail(context.m_remote_ip); return; } hsh_result = true; @@ -685,6 +730,7 @@ namespace nodetool { LOG_ERROR_CCONTEXT("COMMAND_TIMED_SYNC: failed to handle_remote_peerlist(...), closing connection."); m_net_server.get_config_object().close(context.m_connection_id ); + add_ip_fail(context.m_remote_ip); } if(!context.m_is_income) m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_ip, context.m_remote_port); @@ -829,6 +875,20 @@ namespace nodetool #undef LOG_PRINT_CC_PRIORITY_NODE + //----------------------------------------------------------------------------------- + template + bool node_server::is_addr_recently_failed(const net_address& addr) + { + CRITICAL_REGION_LOCAL(m_conn_fails_cache_lock); + auto it = m_conn_fails_cache.find(addr); + if(it == m_conn_fails_cache.end()) + return false; + + if(time(NULL) - it->second > P2P_FAILED_ADDR_FORGET_SECONDS) + return false; + else + return true; + } //----------------------------------------------------------------------------------- template bool node_server::make_new_connection_from_peerlist(bool use_white_list) @@ -866,7 +926,13 @@ namespace nodetool continue; } - LOG_PRINT_L1("Selected peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) + if(!is_remote_ip_allowed(pe.adr.ip)) + continue; + + if(is_addr_recently_failed(pe.adr)) + continue; + + LOG_PRINT_L2("Selected peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast(pe.adr.port) << "[white=" << use_white_list << "] last_seen: " << (pe.last_seen ? epee::misc_utils::get_time_interval_string(time(NULL) - pe.last_seen) : "never")); @@ -1270,6 +1336,7 @@ namespace nodetool LOG_PRINT_CCONTEXT_L1("WRONG NETWORK AGENT CONNECTED! id=" << epee::string_tools::get_str_from_guid_a(arg.node_data.network_id)); drop_connection(context); + add_ip_fail(context.m_remote_ip); return 1; } @@ -1277,6 +1344,7 @@ namespace nodetool { LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE came not from incoming connection"); drop_connection(context); + add_ip_fail(context.m_remote_ip); return 1; } diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index a7b8bf6f..93b29deb 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -50,6 +50,8 @@ namespace nodetool 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 f)=0; + virtual bool block_ip(uint32_t adress)=0; + virtual bool add_ip_fail(uint32_t adress)=0; }; template @@ -84,5 +86,13 @@ namespace nodetool { return false; } + virtual bool block_ip(uint32_t adress) + { + return true; + } + virtual bool add_ip_fail(uint32_t adress) + { + return true; + } }; } diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index f738c68f..3d8b08ce 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -53,6 +53,7 @@ #include "net_peerlist_boost_serialization.h" +#define CURRENT_PEERLIST_STORAGE_ARCHIVE_VER 4 namespace nodetool { @@ -394,4 +395,4 @@ namespace nodetool //-------------------------------------------------------------------------------------------------- } -BOOST_CLASS_VERSION(nodetool::peerlist_manager, 4) +BOOST_CLASS_VERSION(nodetool::peerlist_manager, CURRENT_PEERLIST_STORAGE_ARCHIVE_VER) diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index 1f6ef5bf..254dece5 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -135,6 +135,7 @@ private: static cryptonote::block mkblock(uint8_t version) { cryptonote::block b; + b.major_version = version; b.minor_version = version; return b; } @@ -144,7 +145,7 @@ TEST(empty_hardforks, Success) TestDB db; HardFork hf(db); - ASSERT_TRUE(hf.add(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); hf.init(); ASSERT_TRUE(hf.get_state(time(NULL)) == HardFork::Ready); ASSERT_TRUE(hf.get_state(time(NULL) + 3600*24*400) == HardFork::Ready); @@ -163,13 +164,13 @@ TEST(ordering, Success) TestDB db; HardFork hf(db); - ASSERT_TRUE(hf.add(2, 2, 1)); - ASSERT_FALSE(hf.add(3, 3, 1)); - ASSERT_FALSE(hf.add(3, 2, 2)); - ASSERT_FALSE(hf.add(2, 3, 2)); - ASSERT_TRUE(hf.add(3, 10, 2)); - ASSERT_TRUE(hf.add(4, 20, 3)); - ASSERT_FALSE(hf.add(5, 5, 4)); + ASSERT_TRUE(hf.add_fork(2, 2, 1)); + ASSERT_FALSE(hf.add_fork(3, 3, 1)); + ASSERT_FALSE(hf.add_fork(3, 2, 2)); + ASSERT_FALSE(hf.add_fork(2, 3, 2)); + ASSERT_TRUE(hf.add_fork(3, 10, 2)); + ASSERT_TRUE(hf.add_fork(4, 20, 3)); + ASSERT_FALSE(hf.add_fork(5, 5, 4)); } TEST(states, Success) @@ -177,8 +178,8 @@ TEST(states, Success) TestDB db; HardFork hf(db); - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(2, BLOCKS_PER_YEAR, SECONDS_PER_YEAR)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(2, BLOCKS_PER_YEAR, SECONDS_PER_YEAR)); ASSERT_TRUE(hf.get_state(0) == HardFork::Ready); ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR / 2) == HardFork::Ready); @@ -186,7 +187,7 @@ TEST(states, Success) ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR + (HardFork::DEFAULT_UPDATE_TIME + HardFork::DEFAULT_FORKED_TIME) / 2) == HardFork::UpdateNeeded); ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR + HardFork::DEFAULT_FORKED_TIME * 2) == HardFork::LikelyForked); - ASSERT_TRUE(hf.add(3, BLOCKS_PER_YEAR * 5, SECONDS_PER_YEAR * 5)); + ASSERT_TRUE(hf.add_fork(3, BLOCKS_PER_YEAR * 5, SECONDS_PER_YEAR * 5)); ASSERT_TRUE(hf.get_state(0) == HardFork::Ready); ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR / 2) == HardFork::Ready); @@ -201,10 +202,10 @@ TEST(steps_asap, Success) HardFork hf(db, 1,0,1,1,1); // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(4, 2, 1)); - ASSERT_TRUE(hf.add(7, 4, 2)); - ASSERT_TRUE(hf.add(9, 6, 3)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(4, 2, 1)); + ASSERT_TRUE(hf.add_fork(7, 4, 2)); + ASSERT_TRUE(hf.add_fork(9, 6, 3)); hf.init(); for (uint64_t h = 0; h < 10; ++h) { @@ -229,9 +230,9 @@ TEST(steps_1, Success) TestDB db; HardFork hf(db, 1,0,1,1,1); - ASSERT_TRUE(hf.add(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); for (int n = 1 ; n < 10; ++n) - ASSERT_TRUE(hf.add(n+1, n, n)); + ASSERT_TRUE(hf.add_fork(n+1, n, n)); hf.init(); for (uint64_t h = 0 ; h < 10; ++h) { @@ -251,10 +252,10 @@ TEST(reorganize, Same) HardFork hf(db, 1, 0, 1, 1, history, 100); // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(4, 2, 1)); - ASSERT_TRUE(hf.add(7, 4, 2)); - ASSERT_TRUE(hf.add(9, 6, 3)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(4, 2, 1)); + ASSERT_TRUE(hf.add_fork(7, 4, 2)); + ASSERT_TRUE(hf.add_fork(9, 6, 3)); hf.init(); // index 0 1 2 3 4 5 6 7 8 9 @@ -270,6 +271,10 @@ TEST(reorganize, Same) uint8_t version = hh >= history ? block_versions[hh - history] : 1; ASSERT_EQ(hf.get(hh), version); } + ASSERT_EQ(hf.get_start_height(1), 0); + ASSERT_EQ(hf.get_start_height(4), 2 + history); + ASSERT_EQ(hf.get_start_height(7), 4 + history); + ASSERT_EQ(hf.get_start_height(9), 6 + history); } } } @@ -281,15 +286,15 @@ TEST(reorganize, Changed) HardFork hf(db, 1, 0, 1, 1, 4, 100); // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(4, 2, 1)); - ASSERT_TRUE(hf.add(7, 4, 2)); - ASSERT_TRUE(hf.add(9, 6, 3)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(4, 2, 1)); + ASSERT_TRUE(hf.add_fork(7, 4, 2)); + ASSERT_TRUE(hf.add_fork(9, 6, 3)); hf.init(); - // fork 4 7 9 - // index 0 1 2 3 4 5 6 7 8 9 - static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; + // fork 4 7 9 + // index 0 1 2 3 4 5 6 7 8 9 + static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9 }; for (uint64_t h = 0; h < 16; ++h) { db.add_block(mkblock(block_versions[h]), 0, 0, 0, crypto::hash()); @@ -301,6 +306,10 @@ TEST(reorganize, Changed) for (int hh = 0; hh < 16; ++hh) { ASSERT_EQ(hf.get(hh), expected_versions[hh]); } + ASSERT_EQ(hf.get_start_height(1), 0); + ASSERT_EQ(hf.get_start_height(4), 6); + ASSERT_EQ(hf.get_start_height(7), 8); + ASSERT_EQ(hf.get_start_height(9), 10); } // delay a bit for 9, and go back to 1 to check it stays at 9 @@ -321,6 +330,10 @@ TEST(reorganize, Changed) for (int hh = 0; hh < 15; ++hh) { ASSERT_EQ(hf.get(hh), expected_versions_new[hh]); } + ASSERT_EQ(hf.get_start_height(1), 0); + ASSERT_EQ(hf.get_start_height(4), 6); + ASSERT_EQ(hf.get_start_height(7), 11); + ASSERT_EQ(hf.get_start_height(9), 14); } TEST(voting, threshold) @@ -330,8 +343,8 @@ TEST(voting, threshold) HardFork hf(db, 1, 0, 1, 1, 8, threshold); // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(2, 2, 1)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(2, 2, 1)); hf.init(); for (uint64_t h = 0; h <= 8; ++h) { @@ -359,10 +372,10 @@ TEST(voting, different_thresholds) HardFork hf(db, 1, 0, 1, 1, 4, 50); // window size 4 // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(2, 5, 0, 1)); // asap - ASSERT_TRUE(hf.add(3, 10, 100, 2)); // all votes - ASSERT_TRUE(hf.add(4, 15, 3)); // default 50% votes + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(2, 5, 0, 1)); // asap + ASSERT_TRUE(hf.add_fork(3, 10, 100, 2)); // all votes + ASSERT_TRUE(hf.add_fork(4, 15, 3)); // default 50% votes hf.init(); // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 @@ -386,8 +399,8 @@ TEST(new_blocks, denied) HardFork hf(db, 1, 0, 1, 1, 4, 50); // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(2, 2, 1)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(2, 2, 1)); hf.init(); ASSERT_TRUE(hf.add(mkblock(1), 0)); @@ -411,8 +424,8 @@ TEST(new_version, early) HardFork hf(db, 1, 0, 1, 1, 4, 50); // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(2, 4, 1)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(2, 4, 1)); hf.init(); ASSERT_TRUE(hf.add(mkblock(2), 0)); @@ -433,9 +446,9 @@ TEST(reorganize, changed) HardFork hf(db, 1, 0, 1, 1, 4, 50); // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(2, 2, 1)); - ASSERT_TRUE(hf.add(3, 5, 2)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(2, 2, 1)); + ASSERT_TRUE(hf.add_fork(3, 5, 2)); hf.init(); #define ADD(v, h, a) \ @@ -487,9 +500,9 @@ TEST(get, higher) HardFork hf(db, 1, 0, 1, 1, 4, 50); // v h t - ASSERT_TRUE(hf.add(1, 0, 0)); - ASSERT_TRUE(hf.add(2, 2, 1)); - ASSERT_TRUE(hf.add(3, 5, 2)); + ASSERT_TRUE(hf.add_fork(1, 0, 0)); + ASSERT_TRUE(hf.add_fork(2, 2, 1)); + ASSERT_TRUE(hf.add_fork(3, 5, 2)); hf.init(); ASSERT_EQ(hf.get_ideal_version(0), 1);