diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp index 4ba5c73b..d1db79f3 100644 --- a/include/bitcoin/node/chasers/chaser_header.hpp +++ b/include/bitcoin/node/chasers/chaser_header.hpp @@ -76,10 +76,8 @@ class BCN_API chaser_header virtual bool get_is_strong(bool& strong, const uint256_t& work, size_t point) const NOEXCEPT; - /// Header timestamp is within configured span from current time, - /// or current header is a checkpoint or milestone. - virtual bool is_current(const system::chain::header& header, - size_t height) const NOEXCEPT; + /// Header timestamp is within configured span from current time. + virtual bool is_current(const system::chain::header& header) const NOEXCEPT; /// Save header to tree with validation context. virtual void save(const system::chain::header::cptr& header, @@ -105,6 +103,8 @@ class BCN_API chaser_header void do_handle_event(const code& ec, chase event_, link value) NOEXCEPT; // These are thread safe. + const uint256_t minimum_work_; + const system::chain::checkpoint& milestone_; const system::chain::checkpoints& checkpoints_; const network::wall_clock::duration currency_window_; const bool use_currency_window_; diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp index a267869a..09e14792 100644 --- a/src/chasers/chaser_header.cpp +++ b/src/chasers/chaser_header.cpp @@ -38,6 +38,8 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) chaser_header::chaser_header(full_node& node) NOEXCEPT : chaser(node), + minimum_work_(config().bitcoin.minimum_work), + milestone_(config().bitcoin.milestone), checkpoints_(config().bitcoin.checkpoints), currency_window_(config().node.currency_window()), use_currency_window_(to_bool(config().node.currency_window_minutes)) @@ -113,7 +115,7 @@ void chaser_header::do_organize(const header::cptr& header_ptr, const auto& coin = config().bitcoin; const auto hash = header.hash(); - // Skip existing, fail orphan. + // Skip existing, orphan. // ------------------------------------------------------------------------ if (closed()) @@ -141,7 +143,7 @@ void chaser_header::do_organize(const header::cptr& header_ptr, // Header validations are not bypassed when under checkpoint/milestone. // Rolling forward chain_state eliminates requery cost. - state_.reset(new chain_state(*state_, header, coin)); + state_.reset(new chain_state{ *state_, header, coin }); const auto context = state_->context(); const auto height = state_->height(); @@ -169,8 +171,11 @@ void chaser_header::do_organize(const header::cptr& header_ptr, // Compute relative work. // ------------------------------------------------------------------------ - if (!is_current(header, context.height) && - !checkpoint::is_at(checkpoints_, height)) + // A checkpointed or milestoned branch always gets disk stored. Otherwise + // branch must be both current and of sufficient chain work to be stored. + if (!checkpoint::is_at(checkpoints_, height) && + !milestone_.equals(hash, height) && + !(is_current(header) && state_->cumulative_work() >= minimum_work_)) { save(header_ptr, context); handler(error::success); @@ -194,9 +199,9 @@ void chaser_header::do_organize(const header::cptr& header_ptr, return; } - // Header is new top of current weak branch. if (!strong) { + // Header is new top of current weak branch. save(header_ptr, context); handler(error::success); return; @@ -261,8 +266,7 @@ void chaser_header::do_organize(const header::cptr& header_ptr, handler(error::success); } -bool chaser_header::is_current(const header& header, - size_t height) const NOEXCEPT +bool chaser_header::is_current(const header& header) const NOEXCEPT { if (!use_currency_window()) return true; diff --git a/src/parser.cpp b/src/parser.cpp index 91a9d11b..a4512bbf 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -20,7 +20,6 @@ #include #include -////#include #include #include #include @@ -365,7 +364,6 @@ options_metadata parser::load_settings() THROWS value(&configured.bitcoin.genesis_block), "The genesis block, defaults to mainnet." ) - // TODO: checkpoint/checkpoints fail to parse. ( "bitcoin.checkpoint", value(&configured.bitcoin.checkpoints), @@ -413,9 +411,14 @@ options_metadata parser::load_settings() THROWS "The hash:height checkpoint for bip9 bit0 activation, defaults to 000000000000000004a1b34462cb8aeebd5799177f7a29cf28f2d1961716b5b5:419328." ) ( - "bitcoin.bip9_bit1_active_checkpoint", - value(&configured.bitcoin.bip9_bit1_active_checkpoint), - "The hash:height checkpoint for bip9 bit1 activation, defaults to 0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893:481824." + "bitcoin.milestone", + value(&configured.bitcoin.milestone), + "A block presumed to be valid but not required to be present, defaults to 00000000000000000001a0a448d6cf2546b06801389cc030b2b18c6491266815:804000." + ) + ( + "bitcoin.minimum_work", + value(&configured.bitcoin.minimum_work), + "The minimum work for any branch to be considered valid, defaults to 000000000000000000000000000000000000000052b2559353df4117b7348b64." ) /* [network] */ diff --git a/test/chasers/chaser_header.cpp b/test/chasers/chaser_header.cpp index 0d040401..bb37e6b7 100644 --- a/test/chasers/chaser_header.cpp +++ b/test/chasers/chaser_header.cpp @@ -62,10 +62,9 @@ class mock_chaser_header return chaser_header::get_is_strong(strong, work, point); } - bool is_current(const system::chain::header& header, - size_t height) const NOEXCEPT override + bool is_current(const system::chain::header& header) const NOEXCEPT override { - return chaser_header::is_current(header, height); + return chaser_header::is_current(header); } void save(const system::chain::header::cptr& header, @@ -139,8 +138,8 @@ BOOST_AUTO_TEST_CASE(chaser_header_test__is_current__zero_currency_window__true) full_node node(query, config, log); mock_chaser_header instance(node); - BOOST_REQUIRE(instance.is_current(system::chain::header{ {}, {}, {}, 0, {}, {} }, 0)); - BOOST_REQUIRE(instance.is_current(system::chain::header{ {}, {}, {}, max_uint32, {}, {} }, 0)); + BOOST_REQUIRE(instance.is_current(system::chain::header{ {}, {}, {}, 0, {}, {} })); + BOOST_REQUIRE(instance.is_current(system::chain::header{ {}, {}, {}, max_uint32, {}, {} })); } BOOST_AUTO_TEST_CASE(chaser_header_test__is_current__one_minute_currency_window__expected) @@ -154,8 +153,8 @@ BOOST_AUTO_TEST_CASE(chaser_header_test__is_current__one_minute_currency_window_ full_node node(query, config, log); mock_chaser_header instance(node); - BOOST_REQUIRE(!instance.is_current(system::chain::header{ {}, {}, {}, 0, {}, {} }, 0)); - BOOST_REQUIRE(instance.is_current(system::chain::header{ {}, {}, {}, max_uint32, {}, {} }, 0)); + BOOST_REQUIRE(!instance.is_current(system::chain::header{ {}, {}, {}, 0, {}, {} })); + BOOST_REQUIRE(instance.is_current(system::chain::header{ {}, {}, {}, max_uint32, {}, {} })); } BOOST_AUTO_TEST_SUITE_END()