Skip to content

Commit

Permalink
Merge pull request #1401 from evoskuil/master
Browse files Browse the repository at this point in the history
Restore bip30, and bip9 checkpoint-based "activations".
  • Loading branch information
evoskuil committed Feb 18, 2024
2 parents 2d42307 + 79aa9e1 commit 91b0c97
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 73 deletions.
22 changes: 20 additions & 2 deletions include/bitcoin/system/chain/chain_state.hpp
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
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
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
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

0 comments on commit 91b0c97

Please sign in to comment.