Source code for btclib.block.build

# Copyright (c) The btclib developers
# Distributed under the MIT software license, see the accompanying
# LICENSE file or https://opensource.org/license/mit for the full text.

"""Build a coinbase and a block; mining.py keeps the header search.

`block/mining.py` already builds a candidate header and searches its
nonce; what it does not build is what that header commits to -- a
coinbase paying the chain's own subsidy, and a block over a list of
transactions with a witness commitment where one is owed. That
asymmetry, and not a preference for one file over two, is why this is a
module of its own beside `mining.py` rather than an addition to it: a
builder is the first code in `block/` that decides what a block *is*,
where every other function there reads one somebody else built.

`build_coinbase` validates what it returns by default, `check_validity`
`False` the escape -- the rule every constructor of this library already
has, `Block`, `Tx` and `BlockHeader` among them. `build_block` carries no
such parameter, and still validates everything a pre-mining candidate
can be asked for: `Block.assert_valid_structure` is every rule
`Block.assert_valid` asks except the header's own two -- which a
candidate cannot pass, and which `mining.candidate_block_header` has
already asked of the header the same way `BlockHeader` always does.
`build_block`'s own docstring has why the two remaining rules are left
to the caller. A caller wanting a block that is invalid on purpose, the
way Bitcoin Core's `create_block`
(`test/functional/test_framework/blocktools.py`) is meant to be driven
into invalid states, builds a `Tx` or a
`Block` by hand with `check_validity=False` and mutates the result, as a
caller already does for a regtest block whose proof-of-work `mainnet`'s
own default limit would refuse.
"""

from __future__ import annotations

from collections.abc import Sequence
from datetime import datetime

from btclib import var_bytes
from btclib.alias import Octets
from btclib.block.block import (
    Block,
    bip34_commitment,
    witness_commitment_output,
)
from btclib.block.mining import VERSION, candidate_block_header
from btclib.consensus import subsidy
from btclib.script.script_pub_key import ScriptPubKey
from btclib.script.witness import Witness
from btclib.tx import OutPoint, Tx, TxIn, TxOut

__all__ = [
    "build_block",
    "build_coinbase",
]

# BIP141's own default, and Bitcoin Core's: `GenerateCoinbaseCommitment`
# (`src/validation.cpp`, at bitcoin/bitcoin@9be056a8a7) writes an
# all-zero nonce into every block it assembles, nothing here reading a
# random one back -- a real miner's privacy is not what the nonce is for
_ZERO_WITNESS_NONCE = b"\x00" * 32


[docs] def build_coinbase( height: int, script_pub_key: Octets | ScriptPubKey, *, fees: int = 0, halving_interval: int = 210_000, extra_nonce: Octets = b"", version: int = 1, lock_time: int = 0, check_validity: bool = True, ) -> Tx: """Return a coinbase transaction paying the subsidy at `height`, plus fees. Bitcoin Core's `create_coinbase` (`test/functional/test_framework/blocktools.py`): a null-outpoint input committing to `height` (BIP34, `bip34_commitment`) and one output paying `consensus.subsidy(height, halving_interval) + fees` to `script_pub_key`. `halving_interval` defaults to mainnet's own; a caller building for another network passes that network's own row -- `CONSENSUS_PARAMS[name].subsidy_halving_interval`, regtest's 150 among them -- rather than this function asserting a chain's schedule for it. `extra_nonce` is pushed onto the script_sig after the height commitment, empty by default and padding a height of sixteen or below's one-byte commitment out to the two bytes a coinbase script_sig must carry: `var_bytes.serialize(b"")` is one more byte on its own, an empty push rather than nothing pushed at all. A caller mining several candidates from one height rolls this the way a real miner does once the header's own four nonce bytes are exhausted -- `mining.mine`'s own docstring has the reason -- a different `extra_nonce` being a different script_sig and hence a different merkle root to search under. """ script_sig = bip34_commitment(height) + var_bytes.serialize(extra_nonce) value = subsidy(height, halving_interval) + fees return Tx( version=version, lock_time=lock_time, vin=[TxIn(OutPoint(), script_sig, 0xFFFFFFFF)], vout=[TxOut(value, script_pub_key)], check_validity=check_validity, )
def _coinbase_with_commitment(coinbase: Tx, transactions: Sequence[Tx]) -> Tx: """Return a copy of `coinbase` carrying the BIP141 witness commitment. `witness_commitment_output` computes the output from `transactions`, the same implementation `Block.assert_valid_witness_commitment` checks a commitment against; the coinbase's own input gets the other half of the preimage, `_ZERO_WITNESS_NONCE`, in its witness stack. The caller's `coinbase` is not touched, `mining.mine` leaving its own argument alone for the same reason: a builder handing back a value the caller already holds a reference to is a builder inviting the two to drift apart under an edit meant for one of them alone. """ committed_in = TxIn( prev_out=coinbase.vin[0].prev_out, script_sig=coinbase.vin[0].script_sig, sequence=coinbase.vin[0].sequence, script_witness=Witness([_ZERO_WITNESS_NONCE], check_validity=False), check_validity=False, ) commitment_out = witness_commitment_output(transactions, _ZERO_WITNESS_NONCE) return Tx( version=coinbase.version, lock_time=coinbase.lock_time, vin=[committed_in], vout=[*coinbase.vout, commitment_out], check_validity=False, )
[docs] def build_block( previous_block_hash: Octets, transactions: Sequence[Tx], time: datetime, bits: Octets, *, version: int = VERSION, ) -> Block: """Return the unsolved block over `transactions`, ready for `mining.mine`. `transactions[0]` is the coinbase -- `build_coinbase`'s own shape, or a caller's -- and the rest are what it is paid to include. Where any of them carries a witness, the coinbase this returns is not the caller's own: it is a copy carrying the BIP141 commitment Bitcoin Core's `GenerateCoinbaseCommitment` writes into every block it assembles, `_coinbase_with_commitment`'s docstring has the pair this is built from. A block with no witness among its transactions gets neither the output nor the coinbase's own witness stack, the way a legacy block never carried one. `mining.candidate_block_header` is what builds the header, over the transactions actually carried rather than the caller's own copies of them: the merkle root it commits to and the one `Block.assert_valid_merkle_root` checks are the same computation, which is the whole of what makes a built block a block. No `check_validity`, unlike `build_coinbase`: what this returns has no proof-of-work, nonce zero rather than one that satisfies `bits`, and `Block.assert_valid` always asks for one, so there is no state in which the *complete* check could pass. That is not every check, though, and this still runs the rest: `Block.assert_valid_structure` is `assert_valid` minus the header's own two rules -- `candidate_block_header` has already asked those of the header, the same way `BlockHeader` always does -- so a caller handing this two coinbases, an over-weight block or a malformed transaction is refused here rather than handed back a `Block` nothing has looked at. `mining.mine` is this function's own next step, and `Block.assert_valid(pow_limit_bits)` is the caller's once it returns a solved header -- the one check this cannot itself perform. """ transactions = list(transactions) if ( transactions and transactions[0].vin and any(tx.is_segwit for tx in transactions) ): transactions[0] = _coinbase_with_commitment(transactions[0], transactions) header = candidate_block_header( previous_block_hash, transactions, time, bits, version=version ) block = Block(header, transactions, check_validity=False) block.assert_valid_structure() return block