The Gatekeeper
Before a transaction can enter the mempool (and eventually a block), it must pass through Bitcoin Core's validation engine. This is the most critical code path in the codebase; it determines what's valid and what's not.
Transaction validation happens in two contexts:
- Mempool acceptance: when a new unconfirmed transaction arrives (from wallet or P2P). Uses both consensus and policy rules.
- Block validation: when a mined block arrives. Uses only consensus rules (covered in Chapter 7).
Consensus rules are things every node must agree on - violating them means the block is invalid. Policy rules are stricter local rules for the mempool - a transaction can be policy-invalid but still end up in a block.
AcceptToMemoryPool (ATMP)
The main entry point for transaction validation is AcceptToMemoryPool() in validation.cpp. It uses the MemPoolAccept workhorse class:
If any step fails, the transaction is rejected with a specific error code (like TX_MISSING_INPUTS, TX_MEMPOOL_POLICY, etc.).
PreChecks: The Fast Path
PreChecks are lightweight validations that can quickly reject obviously invalid transactions:
What Gets Checked
- Already in mempool?: Reject duplicates (by txid or wtxid)
- Coinbase?: Coinbase transactions can't enter the mempool
- Standard size?: Transaction weight must be under 400,000 WU
- Version check: Transaction version must be 1 or 2
- Script standardness: Only accept known script types
- Input existence: All inputs must reference existing UTXOs (orphan handling if not)
- No double-spends: Inputs must not conflict with existing mempool transactions (unless RBF applies)
- Sequence lock checks: Relative timelocks must be satisfied
- Fee rate: Must meet minimum relay fee and mempool min fee
- Dust check: Outputs must be above the dust threshold
- Ancestor/descendant limits: Can't create overly long chains of unconfirmed transactions
If a transaction references inputs that don't exist yet (they might be in a transaction we haven't received), it becomes an orphan. Bitcoin Core stores a limited number of orphans and re-evaluates them when new transactions arrive.
Script Verification
If PreChecks pass, the real work begins: verifying every input's script.
PolicyScriptChecks
Runs scripts with policy flags, the strictest set of rules:
- Enforces clean stack (exactly one element after execution)
- Requires strict DER signature encoding
- Enforces low-S signatures
- Requires minimal push opcodes
- Enforces OP_NULLDUMMY
ConsensusScriptChecks
Runs scripts with consensus flags, the minimum rules required for validity:
- If policy checks pass but consensus doesn't → something is seriously wrong (this shouldn't happen)
- If policy checks fail but consensus passes → transaction is valid but non-standard (won't be relayed)
Parallel Verification
Script checks for different inputs are independent and can run in parallel. Bitcoin Core uses a CCheckQueue with multiple threads to verify scripts concurrently during block validation, significantly speeding up block connection.
CTxMemPool: The Transaction Pool
The mempool is implemented as CTxMemPool in txmempool.cpp. It's a complex multi-indexed data structure:
CTxMemPoolEntry
Each transaction in the mempool is wrapped in a CTxMemPoolEntry that tracks:
- Fee: the transaction's fee in satoshis
- Virtual size: weight ÷ 4 (includes witness discount)
- Time: when the transaction entered the mempool
- Height: the chain height when it was accepted
- Ancestor/descendant counts and fees: for fee-rate calculations involving chains of unconfirmed transactions
Fee Policies
Bitcoin Core enforces several fee-related policies:
Minimum Relay Fee
minRelayTxFee, the absolute minimum fee rate to relay a transaction (default: 1 sat/vB). Transactions below this are dropped.
Incremental Relay Fee
For RBF replacements, the new transaction must pay at least incrementalRelayFee more per virtual byte than the transaction it's replacing.
Mempool Minimum Fee
When the mempool is full (default 300 MB), a dynamic minimum fee rate kicks in. Transactions must pay more than the lowest-fee-rate transaction currently in the pool.
Dust Threshold
An output is "dust" if it would cost more in fees to spend than it's worth. The dust threshold is calculated based on the output type and the dust relay fee rate.
Replace-By-Fee (RBF)
BIP 125 allows unconfirmed transactions to be replaced by higher-fee versions:
Rules for Replacement
- The original transaction must signal replaceability (any input's
nSequence < 0xFFFFFFFE) - The replacement must pay a higher absolute fee
- The replacement must pay a higher fee rate
- The replacement must not introduce new unconfirmed inputs
- The number of original transactions being evicted must be limited (≤ 100)
- The replacement must pay for the bandwidth of all evicted transactions
As of Bitcoin Core 28.0, full RBF is enabled by default (-mempoolfullrbf=1). This means all transactions are replaceable, regardless of their sequence number signaling. This improves mempool convergence and fee bumping reliability.
Package Relay
Package relay (BIP 331) allows submitting a group of related transactions together. This solves the "stuck transaction" problem:
- Problem: A low-fee parent transaction can't enter the mempool, so its child (which pays a high fee) can't either, even though the package as a whole is worth mining.
- Solution: Evaluate the parent + child as a package. If the combined fee rate meets the threshold, accept both.
CPFP (Child Pays for Parent)
CPFP is the mechanism miners use to evaluate packages: a high-fee child transaction makes its low-fee parent attractive to mine. The mempool tracks "ancestor fee rate" specifically for this purpose.
Mempool Eviction
When the mempool reaches its size limit (default 300 MB):
- Transactions are sorted by descendant fee rate
- The lowest fee rate transactions are evicted first
- The minimum mempool fee rate rises to match the evicted transactions
- Transactions also expire after a configurable timeout (default 336 hours / 14 days)