Skip to content

Commit

Permalink
Restore bip9 checkpoint-based "activations".
Browse files Browse the repository at this point in the history
  • Loading branch information
evoskuil committed Feb 18, 2024
1 parent 8eeb96e commit 36df431
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 39 deletions.
22 changes: 20 additions & 2 deletions include/bitcoin/system/chain/chain_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <memory>
#include <deque>
#include <bitcoin/system/chain/checkpoint.hpp>
#include <bitcoin/system/chain/context.hpp>
#include <bitcoin/system/chain/enums/forks.hpp>
#include <bitcoin/system/define.hpp>
Expand Down Expand Up @@ -79,6 +80,12 @@ class BC_API chain_state

/// (block - (block % 2016 == 0 ? 2016 : block % 2016))
size_t timestamp_retarget{};

/// mainnet: 419328, testnet: 770112 (or map::unrequested)
size_t bip9_bit0_height;

/// mainnet: 481824, testnet: 834624 (or map::unrequested)
size_t bip9_bit1_height;
};

/// Values used to populate chain state at the target height.
Expand All @@ -90,6 +97,12 @@ class BC_API chain_state
/// Hash of the candidate block or null_hash for memory pool.
hash_digest hash{};

/// Hash of the bip9_bit0 block or null_hash if unrequested.
hash_digest bip9_bit0_hash;

/// Hash of the bip9_bit1 block or null_hash if unrequested.
hash_digest bip9_bit1_hash;

/// Values must be ordered by height with high (block - 1) last.
struct
{
Expand Down Expand Up @@ -193,14 +206,19 @@ class BC_API chain_state
static size_t bits_count(size_t height, uint32_t forks,
size_t retargeting_interval) NOEXCEPT;
static size_t version_count(size_t height, uint32_t forks,
size_t activation_sample) NOEXCEPT;
size_t bip34_activation_sample) NOEXCEPT;
static size_t timestamp_count(size_t height, uint32_t forks) NOEXCEPT;
static size_t retarget_height(size_t height, uint32_t forks,
size_t retargeting_interval) NOEXCEPT;
static size_t bip9_bit0_height(size_t height,
const checkpoint& bip9_bit0_active_checkpoint) NOEXCEPT;
static size_t bip9_bit1_height(size_t height,
const checkpoint& bip9_bit1_active_checkpoint) NOEXCEPT;

static data to_pool(const chain_state& top,
const system::settings& settings) NOEXCEPT;
static data to_block(const chain_state& pool, const block& block) NOEXCEPT;
static data to_block(const chain_state& pool, const block& block,
const system::settings& settings) NOEXCEPT;
static data to_header(const chain_state& parent, const header& header,
const system::settings& settings) NOEXCEPT;

Expand Down
6 changes: 3 additions & 3 deletions include/bitcoin/system/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ class BC_API settings
uint32_t bip9_version_base;

/// Activation parameters (bip34-style activations).
size_t activation_threshold{};
size_t enforcement_threshold{};
size_t activation_sample{};
size_t bip34_activation_threshold{};
size_t bip34_enforcement_threshold{};
size_t bip34_activation_sample{};

/// Frozen activation heights (frozen_activations).
size_t bip65_freeze{};
Expand Down
97 changes: 75 additions & 22 deletions src/chain/chain_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace system {
namespace chain {

// github.com/bitcoin/bips/blob/master/bip-0030.mediawiki#specification
// As bip30 exceptions apply only to bitcoin mainnet these can be embedded.
static const checkpoint mainnet_bip30_exception_checkpoint1
{
"00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec", 91842
Expand All @@ -51,14 +52,14 @@ static const checkpoint mainnet_bip30_exception_checkpoint2
// Inlines.
// ----------------------------------------------------------------------------

constexpr bool is_active(size_t count, size_t activation_threshold) NOEXCEPT
constexpr bool is_active(size_t count, size_t bip34_activation_threshold) NOEXCEPT
{
return count >= activation_threshold;
return count >= bip34_activation_threshold;
}

constexpr bool is_enforced(size_t count, size_t enforcement_threshold) NOEXCEPT
constexpr bool is_enforced(size_t count, size_t bip34_enforcement_threshold) NOEXCEPT
{
return count >= enforcement_threshold;
return count >= bip34_enforcement_threshold;
}

// Determine the number of blocks back to the closest retarget height.
Expand Down Expand Up @@ -158,14 +159,15 @@ chain_state::activations chain_state::activation(const data& values,
// scrypt_proof_of_work is activated based on configuration alone (hard fork).
result.forks |= (forks::scrypt_proof_of_work & forks);

// bip16 was activated based on manual inspection of history (~55% rule).
// bip16 was activated based on manual inspection of signal history (~55% rule).
if (values.timestamp.self >= settings.bip16_activation_time)
{
result.forks |= (forks::bip16_rule & forks);
}

// bip34 is activated based on 75% of preceding 1000 mainnet blocks.
if (bip34_ice || (is_active(count_2, settings.activation_threshold) &&
// bip30 is disabled by bip34 or unconditional activation of it by bip90.
if (bip34_ice || (is_active(count_2, settings.bip34_activation_threshold) &&
version >= settings.bip34_version))
{
// TODO: check is_enabled(bip34_rule, forks) before above calculations.
Expand All @@ -177,45 +179,41 @@ chain_state::activations chain_state::activation(const data& values,
const auto retarget = script::is_enabled(forks, forks::retarget);
const auto mainnet = retarget && difficult;

// If not a bip30 exception block (unspent duplicate coinbase allowed) and
// bip34 not active (duplicate coinbase presumed impossible) then must
// ensure spentness of any existing duplicate coinbase. The bip30 rule is
// always disabled by retroactive application to all blocks prior to bip34
// with the unconditional activation of bip34 by bip90 (hard fork).
// If not bip30 exception, existing duplicate coinbase must be spent.
if (!is_bip30_exception({ values.hash, height }, mainnet))
{
result.forks |= (forks::bip30_rule & forks);
}
}

// bip66 is activated based on 75% of preceding 1000 mainnet blocks.
if (bip66_ice || (is_active(count_3, settings.activation_threshold) &&
if (bip66_ice || (is_active(count_3, settings.bip34_activation_threshold) &&
version >= settings.bip66_version))
{
// TODO: check is_enabled(bip66_rule, forks) before above calculations.
result.forks |= (forks::bip66_rule & forks);
}

// bip65 is activated based on 75% of preceding 1000 mainnet blocks.
if (bip65_ice || (is_active(count_4, settings.activation_threshold) &&
if (bip65_ice || (is_active(count_4, settings.bip34_activation_threshold) &&
version >= settings.bip65_version))
{
// TODO: check is_enabled(bip65_rule, forks) before above calculations.
result.forks |= (forks::bip65_rule & forks);
}

// version 4/3/2 enforced based on 95% of preceding 1000 mainnet blocks.
if (bip65_ice || is_enforced(count_4, settings.enforcement_threshold))
if (bip65_ice || is_enforced(count_4, settings.bip34_enforcement_threshold))
{
// TODO: requires is_enabled(bip65_rule, forks).
result.minimum_block_version = settings.bip65_version;
}
else if (bip66_ice || is_enforced(count_3, settings.enforcement_threshold))
else if (bip66_ice || is_enforced(count_3, settings.bip34_enforcement_threshold))
{
// TODO: requires is_enabled(bip66_rule, forks).
result.minimum_block_version = settings.bip66_version;
}
else if (bip34_ice || is_enforced(count_2, settings.enforcement_threshold))
else if (bip34_ice || is_enforced(count_2, settings.bip34_enforcement_threshold))
{
// TODO: requires is_enabled(bip34_rule, forks).
result.minimum_block_version = settings.bip34_version;
Expand All @@ -225,6 +223,18 @@ chain_state::activations chain_state::activation(const data& values,
result.minimum_block_version = settings.first_version;
}

// bip9_bit0 forks are enforced above the bip9_bit0 checkpoint.
if (values.bip9_bit0_hash == settings.bip9_bit0_active_checkpoint.hash())
{
result.forks |= (forks::bip9_bit0_group & forks);
}

// bip9_bit1 forks are enforced above the bip9_bit1 checkpoint.
if (values.bip9_bit1_hash == settings.bip9_bit1_active_checkpoint.hash())
{
result.forks |= (forks::bip9_bit1_group & forks);
}

return result;
}

Expand All @@ -248,15 +258,15 @@ size_t chain_state::bits_count(size_t height, uint32_t forks,
}

size_t chain_state::version_count(size_t height, uint32_t forks,
size_t activation_sample) NOEXCEPT
size_t bip34_activation_sample) NOEXCEPT
{
if (script::is_enabled(forks, forks::bip90_rule) ||
!script::is_enabled(forks, forks::bip34_activations))
{
return zero;
}

return std::min(height, activation_sample);
return std::min(height, bip34_activation_sample);
}

size_t chain_state::timestamp_count(size_t height, uint32_t) NOEXCEPT
Expand Down Expand Up @@ -421,6 +431,24 @@ uint32_t chain_state::easy_work_required(const data& values,
return proof_of_work_limit;
}

size_t chain_state::bip9_bit0_height(size_t height,
const checkpoint& bip9_bit0_active_checkpoint) NOEXCEPT
{
const auto activation_height = bip9_bit0_active_checkpoint.height();

// Require bip9_bit0 hash at heights above historical bip9_bit0 activation.
return height > activation_height ? activation_height : map::unrequested;
}

size_t chain_state::bip9_bit1_height(size_t height,
const checkpoint& bip9_bit1_active_checkpoint) NOEXCEPT
{
const auto activation_height = bip9_bit1_active_checkpoint.height();

// Require bip9_bit1 hash at heights above historical bip9_bit1 activation.
return height > activation_height ? activation_height : map::unrequested;
}

// Public static
// ----------------------------------------------------------------------------

Expand Down Expand Up @@ -448,10 +476,19 @@ chain_state::map chain_state::get_map(size_t height,
map.version_self = height;
map.version.high = sub1(height);
map.version.count = version_count(height, forks,
settings.activation_sample);
settings.bip34_activation_sample);

// The most recent past retarget height.
map.timestamp_retarget = retarget_height(height, forks, interval);

// The checkpoint above which bip9_bit0 rules are enforced.
map.bip9_bit0_height = bip9_bit0_height(height,
settings.bip9_bit0_active_checkpoint);

// The checkpoint above which bip9_bit1 rules are enforced.
map.bip9_bit1_height = bip9_bit1_height(height,
settings.bip9_bit1_active_checkpoint);

return map;
}

Expand Down Expand Up @@ -513,7 +550,7 @@ chain_state::data chain_state::to_pool(const chain_state& top,

// If version collection overflows, dequeue oldest member.
if (data.version.ordered.size() > version_count(height, forks,
settings.activation_sample))
settings.bip34_activation_sample))
data.version.ordered.pop_front();

// If timestamp collection overflows, dequeue oldest member.
Expand Down Expand Up @@ -558,7 +595,7 @@ chain_state::chain_state(const chain_state& top,
}

chain_state::data chain_state::to_block(const chain_state& pool,
const block& block) NOEXCEPT
const block& block, const system::settings& settings) NOEXCEPT
{
// Copy data from presumed same-height pool state.
chain_state::data data{ pool.data_ };
Expand All @@ -571,14 +608,22 @@ chain_state::data chain_state::to_block(const chain_state& pool,
data.version.self = header.version();
data.timestamp.self = header.timestamp();

// Cache hash of bip9 bit0 height block, otherwise use preceding state.
if (data.height == settings.bip9_bit0_active_checkpoint.height())
data.bip9_bit0_hash = data.hash;

// Cache hash of bip9 bit1 height block, otherwise use preceding state.
if (data.height == settings.bip9_bit1_active_checkpoint.height())
data.bip9_bit1_hash = data.hash;

return data;
}

// Pool to block.
// This assumes that the pool state is the same height as the block.
chain_state::chain_state(const chain_state& pool, const block& block,
const system::settings& settings) NOEXCEPT
: data_(to_block(pool, block)),
: data_(to_block(pool, block, settings)),
forks_(pool.forks_),
active_(activation(data_, forks_, settings)),
work_required_(work_required(data_, forks_, settings)),
Expand All @@ -601,6 +646,14 @@ chain_state::data chain_state::to_header(const chain_state& parent,
data.version.self = header.version();
data.timestamp.self = header.timestamp();

// Cache hash of bip9 bit0 height block, otherwise use preceding state.
if (data.height == settings.bip9_bit0_active_checkpoint.height())
data.bip9_bit0_hash = data.hash;

// Cache hash of bip9 bit1 height block, otherwise use preceding state.
if (data.height == settings.bip9_bit1_active_checkpoint.height())
data.bip9_bit1_hash = data.hash;

return data;
}

Expand Down
12 changes: 6 additions & 6 deletions src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ settings::settings(chain::selection context) NOEXCEPT
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f,
0xac, 0x00, 0x00, 0x00, 0x00
}, false);
activation_threshold = 750;
enforcement_threshold = 950;
activation_sample = 1000;
bip34_activation_threshold = 750;
bip34_enforcement_threshold = 950;
bip34_activation_sample = 1000;
bip65_freeze = 388381;
bip66_freeze = 363725;
bip34_freeze = 227931;
Expand Down Expand Up @@ -168,9 +168,9 @@ settings::settings(chain::selection context) NOEXCEPT
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f,
0xac, 0x00, 0x00, 0x00, 0x00
}, false);
activation_threshold = 51;
enforcement_threshold = 75;
activation_sample = 100;
bip34_activation_threshold = 51;
bip34_enforcement_threshold = 75;
bip34_activation_sample = 100;

bip65_freeze = 581885;
bip66_freeze = 330776;
Expand Down
12 changes: 6 additions & 6 deletions test/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ BOOST_AUTO_TEST_CASE(settings__construct__mainnet_context__expected)
BOOST_REQUIRE_EQUAL(configuration.bip9_version_bit0, 1u);
BOOST_REQUIRE_EQUAL(configuration.bip9_version_bit1, 2u);
BOOST_REQUIRE_EQUAL(configuration.bip9_version_base, 0x20000000u);
BOOST_REQUIRE_EQUAL(configuration.activation_threshold, 750u);
BOOST_REQUIRE_EQUAL(configuration.enforcement_threshold, 950u);
BOOST_REQUIRE_EQUAL(configuration.activation_sample, 1000u);
BOOST_REQUIRE_EQUAL(configuration.bip34_activation_threshold, 750u);
BOOST_REQUIRE_EQUAL(configuration.bip34_enforcement_threshold, 950u);
BOOST_REQUIRE_EQUAL(configuration.bip34_activation_sample, 1000u);
BOOST_REQUIRE_EQUAL(configuration.bip65_freeze, 388381u);
BOOST_REQUIRE_EQUAL(configuration.bip66_freeze, 363725u);
BOOST_REQUIRE_EQUAL(configuration.bip34_freeze, 227931u);
Expand Down Expand Up @@ -100,9 +100,9 @@ BOOST_AUTO_TEST_CASE(settings__construct__testnet_context__expected)
BOOST_REQUIRE_EQUAL(configuration.bip9_version_bit0, 1u);
BOOST_REQUIRE_EQUAL(configuration.bip9_version_bit1, 2u);
BOOST_REQUIRE_EQUAL(configuration.bip9_version_base, 0x20000000u);
BOOST_REQUIRE_EQUAL(configuration.activation_threshold, 51u);
BOOST_REQUIRE_EQUAL(configuration.enforcement_threshold, 75u);
BOOST_REQUIRE_EQUAL(configuration.activation_sample, 100u);
BOOST_REQUIRE_EQUAL(configuration.bip34_activation_threshold, 51u);
BOOST_REQUIRE_EQUAL(configuration.bip34_enforcement_threshold, 75u);
BOOST_REQUIRE_EQUAL(configuration.bip34_activation_sample, 100u);
BOOST_REQUIRE_EQUAL(configuration.bip65_freeze, 581885u);
BOOST_REQUIRE_EQUAL(configuration.bip66_freeze, 330776u);
BOOST_REQUIRE_EQUAL(configuration.bip34_freeze, 21111u);
Expand Down

0 comments on commit 36df431

Please sign in to comment.