The chain types (chain/) are the block, header, transaction, input,
output, script, operation and witness. Each implements the consensus rules
that apply to it, and blocks and transactions delegate to their parts.
Paths are relative to include/bitcoin/system/ in
libbitcoin-system, at
master 0585b079 (2026-11-03).
1. Consensus rules#
The consensus rules are implemented by the chain types, divided into validation stages by what each needs. The rules of BIP54, which is proposed, are shown in blue.
| Stage | Requires | Rules |
|---|---|---|
header::check() |
Proof of work, future timestamp | |
header::accept(context) |
Version, median time past, work required, time warp (BIP94, BIP54), timespan (BIP54) | |
block::check() |
Empty block, size, coinbase position and count, forward references, internal double spends, merkle root, empty transactions, coinbase script size, null previous outputs | |
block::check(context) |
Weight (BIP141), coinbase height (BIP34), transaction size (BIP54), coinbase locktime (BIP54), witness commitment (BIP141), signet solution, absolute locktime (BIP113) | |
block::accept(context) |
Prevout values | Coinbase value against subsidy and fees, sigop limit, missing previous outputs, spends exceeding value, transaction sigop limit (BIP54) |
block::connect(context) |
Prevout scripts | Script execution of each input, including signatures |
block::confirm(context) |
Prevout metadata | Coinbase collision (BIP30), relative locktime (BIP68), unconfirmed spends, coinbase maturity, confirmed double spends |
The division lets a node run each stage as soon as what it requires exists: check a block when it has it, accept and connect it once its previous outputs are available, for many blocks at once, and confirm it in chain order. The node performs the confirmation rules as store queries. See Node Architecture.
These stages contain every consensus rule, including script evaluation,
which connect performs through the machine. One rule is
outside of them: chain organization, the selection among valid chains.
Competing branches, valid chains seen in isolation by different nodes, are each perfectly valid in the scope of the node that sees it. The rule of most cumulative proof of work applies only to break what would otherwise be a tie between two valid chains. A node that sees two chains of the same work generally prefers the first seen, but that choice is arbitrary, and in some situations not applied. To compare chains, the node uses the cumulative work of each header.
Each stage is a method of the chain type it applies to, and each lists its
consensus rules in order, one predicate per rule, each returning its own
error code. A block stage applies its block rules, then delegates to the
same stage of each transaction (check_transactions, and so on). The
sources below are from src/chain/header.cpp, src/chain/block.cpp and
src/chain/transaction.cpp.
1.1 Header#
A header is checked alone, then accepted in its context:
code header::check() const NOEXCEPT
{
if (is_invalid_proof_of_work())
return error::invalid_proof_of_work;
if (is_futuristic_timestamp())
return error::futuristic_timestamp;
return error::block_success;
}
code header::accept(const context& ctx) const NOEXCEPT
{
const auto bip54_timespan = ctx.is_enabled(bip54_timespan_rule);
if (is_insufficient_version(ctx))
return error::insufficient_block_version;
if (is_anachronistic_timestamp(ctx))
return error::anachronistic_timestamp;
if (is_invalid_work(ctx))
return error::incorrect_proof_of_work;
if (is_early_timestamp(ctx))
return error::early_timestamp;
if (bip54_timespan && is_negative_timespan(ctx))
return error::negative_timespan;
return error::block_success;
}
1.2 Check#
The rules of the block alone:
code block::check() const NOEXCEPT
{
if (is_empty())
return error::empty_block;
if (is_oversized())
return error::block_size_limit;
if (is_first_non_coinbase())
return error::first_not_coinbase;
if (is_extra_coinbases())
return error::extra_coinbases;
if (is_forward_reference())
return error::forward_reference;
if (is_internal_double_spend())
return error::block_internal_double_spend;
if (is_invalid_merkle_root())
return error::invalid_transaction_commitment;
return check_transactions();
}
code transaction::check() const NOEXCEPT
{
const auto coinbase = is_coinbase();
if (is_empty())
return error::empty_transaction;
if (coinbase && is_invalid_coinbase_size())
return error::invalid_coinbase_script_size;
if (!coinbase && is_null_non_coinbase())
return error::previous_output_null;
return error::transaction_success;
}
1.3 Check in context#
The rules that depend on the block's height and active forks, but not on previous outputs:
code block::check(const context& ctx) const NOEXCEPT
{
const auto bip141 = ctx.is_enabled(bip141_rule);
const auto bip34 = ctx.is_enabled(bip34_rule);
const auto bip54_txsize = ctx.is_enabled(bip54_txsize_rule);
const auto bip54_coinbase = ctx.is_enabled(bip54_coinbase_rule);
const auto signet = ctx.is_enabled(signet_rule);
if (bip141 && is_overweight())
return error::block_weight_limit;
if (bip34 && is_invalid_coinbase_script(ctx))
return error::coinbase_height_mismatch;
if (bip54_txsize && is_invalid_transaction_size())
return error::invalid_transaction_size;
if (bip54_coinbase && is_invalid_coinbase_locktime(ctx))
return error::coinbase_locktime_mismatch;
if (bip54_coinbase && is_final_coinbase_sequence())
return error::coinbase_sequence_final;
if (bip141 && is_invalid_witness_commitment())
return error::invalid_witness_commitment;
if (signet && is_invalid_signet_solution())
return error::invalid_signet_solution;
return check_transactions(ctx);
}
code transaction::check(const context& ctx) const NOEXCEPT
{
const auto bip113 = ctx.is_enabled(bip113_rule);
if (is_absolute_locked(ctx, bip113))
return error::absolute_time_locked;
return error::transaction_success;
}
1.4 Accept#
The rules that require the values of previous outputs:
code block::accept(const context& ctx) const NOEXCEPT
{
const auto bip16 = ctx.is_enabled(bip16_rule);
const auto bip42 = ctx.is_enabled(bip42_rule);
const auto bip141 = ctx.is_enabled(bip141_rule);
// prevouts required.
if (is_overspent(ctx, bip42))
return error::coinbase_value_limit;
if (is_signature_operations_limited(bip16, bip141))
return error::block_sigop_limit;
return accept_transactions(ctx);
}
code transaction::accept(const context& ctx) const NOEXCEPT
{
const auto bip54 = ctx.is_enabled(bip54_sigops_rule);
if (is_coinbase())
return error::transaction_success;
if (is_missing_prevouts())
return error::missing_previous_output;
if (is_overspent())
return error::spend_exceeds_value;
if (bip54 && is_prevout_signature_operations_limited())
return error::transaction_prevout_sigop_limit;
return error::transaction_success;
}
1.5 Connect#
Script execution of each input against its previous output, by the machine:
code block::connect(const context& ctx) const NOEXCEPT
{
return connect_transactions(ctx);
}
code transaction::connect(const context& ctx) const NOEXCEPT
{
if (is_coinbase())
return error::transaction_success;
for (const auto& input: *inputs_)
if (const auto ec = connect_input(ctx, input))
return ec;
return error::transaction_success;
}
connect_input is the glue between the chain and the machine. It selects
the interpreter's stack container for the input (see
Rock and roll), and the interpreter connects the
input's scripts to those of its previous output:
code transaction::connect_input(const context& ctx,
const input& input) const NOEXCEPT
{
if (!input.prevout)
return error::missing_previous_output;
if (input.is_roller())
return interpreter<linked_stack>::connect(ctx, *this, input);
return interpreter<contiguous_stack>::connect(ctx, *this, input);
}
1.6 Confirm#
The rules that depend on the confirmed chain:
code block::confirm(const context& ctx) const NOEXCEPT
{
const auto bip30 = ctx.is_enabled(bip30_rule);
if (bip30 && is_unspent_coinbase_collision())
return error::unspent_coinbase_collision;
return confirm_transactions(ctx);
}
code transaction::confirm(const context& ctx) const NOEXCEPT
{
const auto bip68 = ctx.is_enabled(bip68_rule);
if (is_coinbase())
return error::transaction_success;
if (bip68 && is_relative_locked(ctx))
return error::relative_time_locked;
if (is_unconfirmed_spend(ctx))
return error::unconfirmed_spend;
if (is_immature(ctx))
return error::coinbase_maturity;
if (is_confirmed_double_spend(ctx))
return error::confirmed_double_spend;
return error::transaction_success;
}
The node does not call confirm, as these rules are optimized as
database queries.
1.7 Rules#
The stages above enumerate thirty-five consensus rules, and script evaluation.
connect applies the script rules to each input, through the
machine, so they are not listed here.
| # | Error | Stage | Object | Rule | Fork |
|---|---|---|---|---|---|
| 1 | invalid_proof_of_work |
Header check | Header | Proof of work meets its own target, within the proof of work limit | |
| 2 | futuristic_timestamp |
Header check | Header | Timestamp not too far in the future | |
| 3 | insufficient_block_version |
Header accept | Header | Version at least the minimum required at its height | BIP34, BIP66, BIP65 |
| 4 | anachronistic_timestamp |
Header accept | Header | Timestamp after the median time past | |
| 5 | incorrect_proof_of_work |
Header accept | Header | Bits equal to the work required | |
| 6 | early_timestamp |
Header accept | Header | At a retarget height, timestamp no earlier than the time warp allowance before its predecessor (BIP94 600 seconds, BIP54 7,200 seconds) | BIP94, BIP54 |
| 7 | negative_timespan |
Header accept | Header | At the last height of a retarget period, timestamp no earlier than that of the period's first block | BIP54 |
| 8 | empty_block |
Check | Block | At least one transaction | |
| 9 | block_size_limit |
Check | Block | Serialized size within the limit | |
| 10 | first_not_coinbase |
Check | Block | First transaction is a coinbase | |
| 11 | extra_coinbases |
Check | Block | No other coinbase | |
| 12 | forward_reference |
Check | Block | No spend of a later transaction in the block | |
| 13 | block_internal_double_spend |
Check | Block | No output spent twice within the block | |
| 14 | invalid_transaction_commitment |
Check | Block | Merkle root commits to the transactions | |
| 15 | empty_transaction |
Check | Transaction | At least one input and one output | |
| 16 | invalid_coinbase_script_size |
Check | Transaction | Coinbase script size within bounds | |
| 17 | previous_output_null |
Check | Transaction | No null previous output outside the coinbase | |
| 18 | block_weight_limit |
Check in context | Block | Weight within the limit | BIP141 |
| 19 | coinbase_height_mismatch |
Check in context | Block | Coinbase script begins with the height | BIP34 |
| 20 | invalid_transaction_size |
Check in context | Block | No transaction of 64 bytes, witness stripped | BIP54 |
| 21 | coinbase_locktime_mismatch |
Check in context | Block | Coinbase locktime is the height of the parent | BIP54 |
| 22 | coinbase_sequence_final |
Check in context | Block | Coinbase input sequence is not final | BIP54 |
| 23 | invalid_witness_commitment |
Check in context | Block | Witness commitment matches the witnesses | BIP141 |
| 24 | invalid_signet_solution |
Check in context | Block | Signet solution satisfies the challenge | Signet |
| 25 | absolute_time_locked |
Check in context | Transaction | Absolute locktime satisfied | BIP113 (median time past) |
| 26 | coinbase_value_limit |
Accept | Block | Coinbase claims no more than subsidy plus fees | BIP42 (subsidy) |
| 27 | block_sigop_limit |
Accept | Block | Signature operations within the limit | BIP16, BIP141 |
| 28 | missing_previous_output |
Accept | Transaction | Every previous output present | |
| 29 | spend_exceeds_value |
Accept | Transaction | Outputs spend no more than inputs | |
| 30 | transaction_prevout_sigop_limit |
Accept | Transaction | Legacy signature operations of the inputs and their previous outputs, counted accurately, no more than 2,500 | BIP54 |
| 31 | unspent_coinbase_collision |
Confirm | Block | Coinbase does not duplicate an unspent coinbase, except the two mainnet exception blocks | BIP30 |
| 32 | relative_time_locked |
Confirm | Transaction | Relative locktime satisfied | BIP68 |
| 33 | unconfirmed_spend |
Confirm | Transaction | No spend of an unconfirmed output | |
| 34 | coinbase_maturity |
Confirm | Transaction | Coinbase outputs spent only after maturity | |
| 35 | confirmed_double_spend |
Confirm | Transaction | No spend of an already spent output |
Chain organization, the selection among valid chains by cumulative work, is outside the stages (see above). The node performs BIP30 (rule 31), with the other confirmation rules, by its queries in the store.
2. DoS guards#
The same sources contain guards. They protect against denial of service, and are not consensus rules: the consensus rules above are complete without them, and validation cannot assume that any guard has been called. Some may appear to be missing from the rules above, but none is a rule.
2.1 Block guards#
The block's check_guard establishes its identity: that its transactions
are those its header commits to, by the merkle root and, where active, the
witness commitment.
It is distinct from validity: a block that fails identification is not the
block its header names, such as a copy with a malleated transaction list
(merkle root weaknesses),
so the failure says nothing about the header, which remains valid for the
correct block.
Its purpose is to keep such a copy from being cached: a node that stored a malleated copy, or stored its failure against the header, would reject or withhold the valid block. Witness data is identified in the same way: before BIP141 nothing commits to it, so a block that arrives with it is not the block its header names, though the block without it may be valid.
code block::check_guard() const NOEXCEPT
{
if (is_malleated())
return error::invalid_transaction_commitment;
if (is_invalid_merkle_root())
return error::invalid_transaction_commitment;
return error::block_success;
}
code block::check_guard(const context& ctx) const NOEXCEPT
{
const auto bip141 = ctx.is_enabled(bip141_rule);
if (bip141 && is_invalid_witness_commitment())
return error::invalid_witness_commitment;
if (!bip141 && is_segregated())
return error::invalid_witness_commitment;
return error::block_success;
}
2.2 Transaction guards#
A transaction received alone, for the pool, is not yet in a block, so the
block rules that would reject it have not run. The guards apply those
rules to the transaction alone, each redundant with a block rule
(src/chain/transaction.cpp):
// Pools do not have coinbases.
// Redundant with block is_internal_double_spend check.
// Redundant with block max_block_size check.
code transaction::check_guard() const NOEXCEPT
{
if (is_coinbase())
return error::coinbase_transaction;
if (is_internal_double_spend())
return error::transaction_internal_double_spend;
if (is_oversized())
return error::transaction_size_limit;
return error::transaction_success;
}
// Redundant with block max_block_weight accept.
code transaction::check_guard(const context& ctx) const NOEXCEPT
{
const auto bip141 = ctx.is_enabled(flags::bip141_rule);
if (!bip141 && is_segregated())
return error::unexpected_witness_transaction;
if (bip141 && is_overweight())
return error::transaction_weight_limit;
return error::transaction_success;
}
// Redundant with block max_block_sigops accept.
code transaction::accept_guard(const context& ctx) const NOEXCEPT
{
const auto bip16 = ctx.is_enabled(flags::bip16_rule);
const auto bip141 = ctx.is_enabled(flags::bip141_rule);
if (is_missing_prevouts())
return error::missing_previous_output;
if (is_signature_operations_limited(bip16, bip141))
return error::transaction_sigop_limit;
return error::transaction_success;
}
// Redundant with block confirmation, which is by confirmed height.
code transaction::confirm_guard(const context& ctx) const NOEXCEPT
{
const auto bip68 = ctx.is_enabled(bip68_rule);
if (is_coinbase())
return error::transaction_success;
if (bip68 && is_relative_locked(ctx))
return error::relative_time_locked;
if (is_unconfirmed_immature(ctx))
return error::coinbase_maturity;
// A confirmed conflict precedes, as a spender may not evade it with one.
if (is_confirmed_conflict())
return error::confirmed_double_spend;
if (is_unconfirmed_conflict())
return error::double_spend;
return error::transaction_success;
}
The node applies the transaction guards to each pool transaction: the check guards with the checks, before it reads the store to populate the transaction, and the accept and confirm guards after, before script execution, the most costly stage. A transaction in a block is under proof of work, and is not subject to them.
3. Context#
The context of a block (chain/context.hpp) is a small value: its height,
timestamp, median time past, required work, minimum block version and the
fork flags active at its height. chain_state computes it from the
preceding headers and the configured forks, and is the only use of the
network settings, so the chain types depend on no configuration.
Each soft or hard fork is one flag
(chain/enums/flags.hpp), from BIP16
through BIP341 and BIP342, the five rules of BIP54, and the testnet4 and
signet forks. A fork
is applied where context::is_enabled reports its flag active, so the
forks of every height and every network are those of one code base. Every
fork can be disabled, by its member of system::forks (forks.hpp), held
by system::settings (settings.hpp). Bitcoin Server exposes these as the
[forks] section of its
configuration.
4. Chain state#
The context of a block is computed from values of the headers that
precede it, such as the bits, versions and timestamps of recent headers.
chain_state (chain/chain_state.hpp) holds the values that the context
requires and computes the context from them.
4.1 Rolling forward#
A chain state is constructed from the store only once. get_map gives the
heights to query for a given height and network, and the queried values
construct the state:
static map get_map(size_t height, const system::settings& settings) NOEXCEPT;
chain_state(data&& values, const system::settings& settings) NOEXCEPT;
Each later state is constructed from its parent and the new header, without querying the store. The parent's windows are promoted by one height, and the header's bits, version, timestamp and work are added:
/// Create header state from header pool chain state of parent block.
chain_state(const chain_state& parent, const chain::header& header,
const system::settings& settings) NOEXCEPT;
Sync rolls the state forward header by header in this way. The same
construction produces the state of the transaction pool from the top
block, and of a block from the pool state at its height. A state is
immutable and shared by pointer (chain_state::cptr), so each header and
block can keep the state of its own height.
4.2 Isolated context logic#
Every rule that depends on a block's position in the chain is evaluated in
chain_state: which forks are active (activation), the minimum block
version, the median time past, and the work required, including retargets
and the testnet minimum difficulty. Each is a static function of the
state's values, the configured forks and the network settings. Its result
is the small context value that the chain types consume, so the
settings, fork activation and difficulty logic are in one place, and the
chain types depend on none of them.
This also makes the logic testable without a chain or a store: a test
constructs a state from given values and checks the context it computes
(test/chain/chain_state.cpp, 132 cases).
4.3 Activation#
activation sets the flag of each configured fork that is active at the
state's height. Each fork activates by one method:
| Method | Forks | Bit | Active | Mainnet | Testnet3 | Testnet4 | Signet | Regtest |
|---|---|---|---|---|---|---|---|---|
| Configuration | BIP30, BIP42, BIP90 | At every height, BIP30 except its two exception blocks | genesis | genesis | genesis | genesis | genesis | |
| Flag day | BIP16 | By a coinbase vote of miners, read by manual inspection and later fixed as a block timestamp | 2012‑04‑01 | 2012‑02‑15 | 2012‑02‑15 | 2012‑02‑15 | 2012‑02‑15 | |
| Version (BIP34) | BIP34, BIP66, BIP65 | When an activation threshold of the preceding sample of blocks, and the block, have the version; the version is required at an enforcement threshold (750 and 950 of 1,000 on mainnet, 51 and 75 of 100 on testnet3; zero on testnet4, signet and regtest, so every block above genesis) | 227,931, 363,725, 388,381 | 21,111, 330,776, 581,885 | 1 | 1 | 1 | |
| Signaling (BIP9) | BIP68, BIP112, BIP113 | 0 | From the versions of the chain's own blocks: after the period in which its bit reaches the threshold and one locked-in period, and no earlier than its minimum activation height | 419,328 | 770,112 | 1 | 1 | 1 |
| BIP141, BIP143, BIP147 | 1 | 481,824 | 834,624 | 1 | 1 | 1 | ||
| BIP341, BIP342 | 2 | 709,632 | 2,011,968 | 1 | 1 | 1 | ||
| BIP54 timewarp | 5 | TBD | TBD | TBD | TBD | 1 | ||
| BIP54 timespan | 6 | TBD | TBD | TBD | TBD | 1 | ||
| BIP54 sigops | 7 | TBD | TBD | TBD | TBD | 1 | ||
| BIP54 txsize | 8 | TBD | TBD | TBD | TBD | 1 | ||
| BIP54 coinbase | 9 | TBD | TBD | TBD | TBD | 1 |
BIP90 is a rule of its own, active by configuration. It imposes the rules of BIP34, BIP66 and BIP65 above specified blocks. It does not change the activation of those forks, which remains as documented, but effectively supersedes them when active.
BIP16 was coordinated, not activated: miners voted with /P2SH/ in their
coinbase scripts, the vote was read by inspection, and the result was fixed
as a time. There is no activation logic. With forks.bip16 the rule is
enforced on every block whose timestamp is at or after
bip16_activation_time, by the block's own timestamp, not median time past.
BIP34 defined activation by block version, which BIP66 and BIP65 also use.
A block activates its rule when its version is at least the rule's (2, 3
and 4) and at least bip34_activation_threshold of the preceding
bip34_activation_sample blocks are of that version: 750 of 1,000 on
mainnet, 51 of 100 on testnet3, testnet4 and signet. The comparison is of
signed versions, as in the original implementation. Activation is per
block, so it follows each block's version until enforcement: at
bip34_enforcement_threshold (950 of 1,000, 75 of 100) the version becomes
the minimum block version, lower versions are rejected, and the rule holds
from then on. The preceding versions are the chain state's version history,
requested by get_map as bip34_activation_sample blocks below the
height. The method is used only with forks.bip90 off: BIP90 buries the
three rules at their heights instead, and with it on no version history is
collected. On regtest the thresholds are zero, so a block of the version
activates the rule by itself.
A BIP9 deployment (chain_state::deployment) has a version bit, a start and
a timeout in median time past, a threshold of signaling blocks per period,
a minimum activation height, and whether it is a speedy trial. A block
signals when the top three bits of its version are 001 and its
deployment's bit is set. The state of each deployment
(chain_state::deployment_state) changes only at a period boundary, by the
median time past at the boundary and the signaling blocks of the period
that it closes:
Original BIP9, used by the bit0 and bit1 groups, fails a deployment at its
timeout before counting its period. A speedy trial, used by the bit2 group
(BIP341) and the BIP54 rules, counts the period first, so a deployment that
reaches its threshold in the period of its timeout locks in. The minimum
activation height is independent of the trial: any deployment holds in
locked_in until the first boundary at or above its minimum height, and
one with no minimum (bit0, bit1) activates at the boundary after lock in.
The period is bip9_activation_period (2,016 on mainnet). The mainnet
deployments of bits 0 to 2 are those of their release, and those of BIP54
are not yet set:
| Group | Bit | Start | Timeout | Threshold | Minimum height | Speedy |
|---|---|---|---|---|---|---|
| BIP68, BIP112, BIP113 | 0 | 2016-05-01 | 2017-05-01 | 1,916 | ||
| BIP141, BIP143, BIP147 | 1 | 2016-11-15 | 2017-11-15 | 1,916 | ||
| BIP341, BIP342 | 2 | 2021-04-24 | 2021-08-11 | 1,815 | 709,632 | ✔ |
| BIP54 timewarp | 5 | TBD | TBD | TBD | TBD | ✔ |
| BIP54 timespan | 6 | TBD | TBD | TBD | TBD | ✔ |
| BIP54 sigops | 7 | TBD | TBD | TBD | TBD | ✔ |
| BIP54 txsize | 8 | TBD | TBD | TBD | TBD | ✔ |
| BIP54 coinbase | 9 | TBD | TBD | TBD | TBD | ✔ |
The chain state carries each deployment's state, and the count of
signaling blocks in the current period, so rolling forward steps a state
only at a boundary. Constructed from the store, get_map gives each
signaled deployment's period boundary at or below the height, with its
start and timeout. The store reads back one boundary at a time, by the
median time past of each, to the first before the start, as every earlier
period is defined, and counts versions only in the periods that can be
started.
BIP54 is implemented as five independent rules, each with its own fork
switch and deployment: bip54_timewarp, bip54_timespan, bip54_sigops,
bip54_txsize and bip54_coinbase. Each is a speedy trial. Their version
bits, 5 through 9, are provisional, and their thresholds are zero on
mainnet, testnet3, testnet4 and signet, so none is signaled or active
there. On regtest each is active above genesis.
A fork's flags are stored with each header once it is active. A fork enabled after its activation is therefore enforced only on the headers archived from then on, as is any soft fork adopted late: the node does not split from the chain, the archived range is not enforced, and a resync enforces it.
5. Compact number#
A header's bits field encodes its proof of work target, a 256 bit number,
in 32 bits. The encoding is exponential in base 256: a mantissa of three
bytes and an exponent of one, the value being the mantissa shifted left by
the exponent in bytes. All but the highest 24 bits of the target are lost.
5.1 The radix base#
The general form is a radix template, base2n<Base, Precision, Span>
(radix/base_2n.hpp), which compresses a value of Span bits to
Precision bits of mantissa and an exponent in Base. The bits encoding
is one instantiation of it:
/// chain::header.bits
using base256e = base2n<256, 24, 256>;
base2n is a normal form: its compress produces the minimal exponent,
and its expand inverts it, both constexpr. Since the base is a power of
two, both reduce to shifts.
5.2 The sign artifact#
The original implementation computed targets with OpenSSL's big numbers, and derived the compact form from OpenSSL's MPI serialization: a length followed by a big-endian magnitude, in which the high bit of the first byte is reserved as a sign. The length became the exponent, and the first three bytes of the magnitude the mantissa. Since a target is never negative, the sign bit served no purpose, but it had to be avoided: where the high bit of the magnitude was set, MPI prepended a zero byte, which shifted the mantissa right by one byte and incremented the exponent. When OpenSSL's big numbers were later replaced, the shift was reproduced as an explicit adjustment, since the encoding is consensus.
The result is a hack around a sign that an unsigned value never needed.
Values whose mantissa would have its high bit set keep only 23 bits of
precision, so the encoding is not uniform, and the bit can still be set on
decoding, making a negative target that must be rejected. This alone is why
chain::compact exists as a wrapper over base256e (chain/compact.hpp).
It applies the hack on both sides of the base256e normal form
(impl/chain/compact.ipp). compress encodes in normal form, then shifts
a mantissa that would read as negative:
constexpr compact::small_type
compact::compress(const span_type& number) NOEXCEPT
{
auto compact = to_compact(base256e::compress(number));
// Below exists only to work around negatives being inadvertently excluded.
if (compact.negative)
{
compact.exponent++;
compact.mantissa >>= raise(one);
compact.negative = false;
}
return from_compact(compact);
}
base256e::expand accepts a non-minimal exponent, so a shifted value
decodes in normal form without adjustment. expand rejects a negative
mantissa, and undoes the shift only where it carried the exponent past the
range of the normal form (e_max):
constexpr compact::span_type
compact::expand(small_type exponential) NOEXCEPT
{
auto compact = to_compact(exponential);
if (compact.negative)
return 0;
// This is strict validation.
if (compact.exponent == add1(e_max) &&
is_negated(compact.mantissa) &&
byte_width(compact.mantissa) == sub1(m_bytes))
{
compact.exponent--;
compact.mantissa <<= raise(one);
}
// Above exists only because negatives were inadvertently excluded.
return base256e::expand(from_compact(compact));
}
Zero is the sentinel for any invalid encoding, as for a zero target. Its
validation is stricter than the original's, which also accepts exponents
that compress cannot produce, but it is consensus-compliant: bits is
generated by compress at each retarget and must match exactly, so no such
value can be valid (impl/chain/compact.ipp).
chain_state compresses the retargeted work into bits, and header
expands bits to check proof of work against the target and to compute
the header's work.
6. Population#
accept, connect and confirm need data from chain history: the previous
output of each input and, for confirmation, where it was confirmed. These
are populated onto the inputs before the stage runs. Previous outputs
within the same block are populated by the block itself
(block::populate), and the rest by the caller, in the node from the
store. The rules themselves read only the block, its context, and its
populated inputs.
This separation has significant advantages for testing. Since the rules read no store and no chain, each can be tested in isolation: a test constructs a block or transaction, populates its inputs with whatever previous outputs and confirmation state the case requires, and calls the stage directly, with no chain to build and no store to query.