Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore bip30, and bip9 checkpoint-based "activations". #1401

Merged
merged 4 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
6 changes: 2 additions & 4 deletions src/chain/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ bool block::is_unspent_coinbase_collision() const NOEXCEPT
if (txs_->empty() || txs_->front()->inputs_ptr()->empty())
return false;

// May only commit a coinbase that has already been confirmed spent.
// May only commit duplicate coinbase that is already confirmed spent.
return !txs_->front()->inputs_ptr()->front()->metadata.spent;
}

Expand Down Expand Up @@ -741,10 +741,8 @@ code block::accept(const context& ctx, size_t subsidy_interval,
code block::confirm(const context& ctx) const NOEXCEPT
{
const auto bip30 = ctx.is_enabled(bip30_rule);
const auto bip34 = ctx.is_enabled(bip34_rule);

// confirmations required.
if (bip30 && !bip34 && is_unspent_coinbase_collision())
if (bip30 && is_unspent_coinbase_collision())
return error::unspent_coinbase_collision;

return confirm_transactions(ctx);
Expand Down
143 changes: 100 additions & 43 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 All @@ -75,6 +76,9 @@ constexpr bool is_retarget_height(size_t height,
return is_zero(retarget_distance(height, retargeting_interval));
}

// bip30 is active for all but two mainnet blocks that violate the rule.
// These two blocks each have a coinbase transaction that exactly duplicates
// another that is not spent by the arrival of the corresponding duplicate.
inline bool is_bip30_exception(const checkpoint& check, bool mainnet) NOEXCEPT
{
return mainnet &&
Expand All @@ -101,10 +105,7 @@ chain_state::activations chain_state::activation(const data& values,
const auto height = values.height;
const auto version = values.version.self;
const auto& history = values.version.ordered;
const auto frozen = script::is_enabled(forks, forks::bip90_rule);
////const auto difficult = script::is_enabled(forks, forks::difficult);
////const auto retarget = script::is_enabled(forks, forks::retarget);
////const auto mainnet = retarget && difficult;
const auto bip90 = script::is_enabled(forks, forks::bip90_rule);

//*************************************************************************
// CONSENSUS: Though unspecified in bip34, the satoshi implementation
Expand All @@ -124,14 +125,15 @@ chain_state::activations chain_state::activation(const data& values,
settings.bip65_version); };

// Compute bip34-based activation version summaries.
// TODO: avoid these computations if forks not configured.
const auto count_2 = std::count_if(history.begin(), history.end(), ge_2);
const auto count_3 = std::count_if(history.begin(), history.end(), ge_3);
const auto count_4 = std::count_if(history.begin(), history.end(), ge_4);

// Frozen activations (require version and enforce above freeze height).
const auto bip34_ice = frozen && height >= settings.bip34_freeze;
const auto bip66_ice = frozen && height >= settings.bip66_freeze;
const auto bip65_ice = frozen && height >= settings.bip65_freeze;
const auto bip90_34 = bip90 && height >= settings.bip34_freeze;
const auto bip90_66 = bip90 && height >= settings.bip66_freeze;
const auto bip90_65 = bip90 && height >= settings.bip65_freeze;

// Initialize activation results with genesis values.
activations result{ forks::no_rules, settings.first_version };
Expand All @@ -157,60 +159,82 @@ 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);
}

////// bip30 is active for all but two mainnet blocks that violate the rule.
////// These two blocks each have a coinbase transaction that exactly duplicates
////// another that is not spent by the arrival of the corresponding duplicate.
////// This was later applied to the full history in implementation (a no-op).
////if (!is_bip30_exception({ values.hash, height }, mainnet))
////{
//// result.forks |= (forks::bip30_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 (bip90_34 || (is_active(count_2, settings.bip34_activation_threshold) &&
version >= settings.bip34_version))
{
// TODO: check is_enabled(bip34_rule, forks) before above calculations.
result.forks |= (forks::bip34_rule & forks);
}
else
{
const auto difficult = script::is_enabled(forks, forks::difficult);
const auto retarget = script::is_enabled(forks, forks::retarget);
const auto mainnet = retarget && difficult;

// 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 (bip90_66 || (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 (bip90_65 || (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 (bip90_65 || 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 (bip90_66 || 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 (bip90_34 || is_enforced(count_2, settings.bip34_enforcement_threshold))
{
// TODO: requires is_enabled(bip34_rule, forks).
result.minimum_block_version = settings.bip34_version;
}
else
{
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 @@ -234,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 @@ -407,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 @@ -434,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 @@ -499,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 @@ -544,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 @@ -557,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 @@ -587,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 Expand Up @@ -666,16 +733,6 @@ chain::context chain_state::context() const NOEXCEPT
};
}

/// Current zulu (utc) time in seconds since epoch, using the wall clock.
/// Although not defined, epoch is almost always: 00:00, Jan 1 1970 UTC.
/// BUGBUG: en.wikipedia.org/wiki/Year_2038_problem
inline uint64_t zulu_time_seconds() NOEXCEPT
{
using wall_clock = std::chrono::system_clock;
const auto now = wall_clock::now();
return sign_cast<uint64_t>(wall_clock::to_time_t(now));
}

} // namespace chain
} // namespace system
} // namespace libbitcoin
Loading