diff --git a/nano/core_test/bootstrap.cpp b/nano/core_test/bootstrap.cpp index 36ab5744..e8decb3c 100644 --- a/nano/core_test/bootstrap.cpp +++ b/nano/core_test/bootstrap.cpp @@ -866,6 +866,47 @@ TEST (bootstrap_processor, multiple_attempts) node2->stop (); } +TEST (bootstrap_processor, bootstrap_fork) +{ + nano::system system; + nano::node_config config (nano::get_available_port (), system.logging); + config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; + nano::node_flags node_flags; + node_flags.disable_bootstrap_bulk_push_client = true; + node_flags.disable_lazy_bootstrap = true; + node_flags.disable_legacy_bootstrap = true; + auto node0 (system.add_node (config, node_flags)); + nano::keypair key; + auto send (std::make_shared (nano::test_genesis_key.pub, node0->latest (nano::test_genesis_key.pub), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (node0->latest (nano::test_genesis_key.pub)))); + ASSERT_EQ (nano::process_result::progress, node0->process (*send).code); + // Confirm send block to vote later + node0->block_confirm (send); + { + auto election = node0->active.election (send->qualified_root ()); + ASSERT_NE (nullptr, election); + nano::lock_guard guard (node0->active.mutex); + election->confirm_once (); + } + ASSERT_TIMELY (2s, node0->block_confirmed (send->hash ())); + node0->active.erase (*send); + auto open_work (*system.work.generate (key.pub)); + auto open (std::make_shared (key.pub, 0, key.pub, nano::Gxrb_ratio, send->hash (), key.prv, key.pub, open_work)); + ASSERT_EQ (nano::process_result::progress, node0->process (*open).code); + system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); + // Create forked node + config.peering_port = nano::get_available_port (); + node_flags.disable_legacy_bootstrap = false; + auto node1 (system.add_node (config, node_flags)); + ASSERT_EQ (nano::process_result::progress, node1->process (*send).code); + auto open_fork (std::make_shared (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, send->hash (), key.prv, key.pub, open_work)); + ASSERT_EQ (nano::process_result::progress, node1->process (*open_fork).code); + // Resolve fork + node1->bootstrap_initiator.bootstrap (node0->network.endpoint ()); + ASSERT_TIMELY (10s, node1->ledger.block_exists (open->hash ())); + ASSERT_FALSE (node1->ledger.block_exists (open_fork->hash ())); + node1->stop (); +} + TEST (frontier_req_response, DISABLED_destruction) { { diff --git a/nano/node/blockprocessor.cpp b/nano/node/blockprocessor.cpp index 32bf0613..6629aa2b 100644 --- a/nano/node/blockprocessor.cpp +++ b/nano/node/blockprocessor.cpp @@ -432,7 +432,7 @@ nano::process_return nano::block_processor::process_one (nano::write_transaction } case nano::process_result::fork: { - node.process_fork (transaction_a, info_a.block); + node.process_fork (transaction_a, info_a.block, info_a.modified); node.stats.inc (nano::stat::type::ledger, nano::stat::detail::fork); if (node.config.logging.ledger_logging ()) { diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 80b16e3e..2ab421f2 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -518,13 +518,13 @@ bool nano::node::copy_with_compaction (boost::filesystem::path const & destinati return store.copy_db (destination); } -void nano::node::process_fork (nano::transaction const & transaction_a, std::shared_ptr block_a) +void nano::node::process_fork (nano::transaction const & transaction_a, std::shared_ptr block_a, uint64_t modified_a) { auto root (block_a->root ()); if (!store.block_exists (transaction_a, block_a->type (), block_a->hash ()) && store.root_exists (transaction_a, block_a->root ())) { std::shared_ptr ledger_block (ledger.forked_block (transaction_a, *block_a)); - if (ledger_block && !block_confirmed_or_being_confirmed (transaction_a, ledger_block->hash ()) && ledger.can_vote (transaction_a, *ledger_block)) + if (ledger_block && !block_confirmed_or_being_confirmed (transaction_a, ledger_block->hash ()) && (ledger.can_vote (transaction_a, *ledger_block) || modified_a < nano::seconds_since_epoch () - 300 || !block_arrival.recent (block_a->hash ()))) { std::weak_ptr this_w (shared_from_this ()); auto election = active.insert (ledger_block, boost::none, [this_w, root](std::shared_ptr) { diff --git a/nano/node/node.hpp b/nano/node/node.hpp index b89c8173..57647090 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -139,7 +139,7 @@ public: void block_confirm (std::shared_ptr); bool block_confirmed (nano::block_hash const &); bool block_confirmed_or_being_confirmed (nano::transaction const &, nano::block_hash const &); - void process_fork (nano::transaction const &, std::shared_ptr); + void process_fork (nano::transaction const &, std::shared_ptr, uint64_t); void do_rpc_callback (boost::asio::ip::tcp::resolver::iterator i_a, std::string const &, uint16_t, std::shared_ptr, std::shared_ptr, std::shared_ptr); nano::uint128_t delta () const; void ongoing_online_weight_calculation ();