The Blockchain Chief Bitcoin Book / Part V: Applications
Chapter 09

The Wallet

How Bitcoin Core manages keys, tracks funds, selects coins, constructs transactions, and signs them: from internal architecture to fee estimation.

Wallet Architecture

The Bitcoin Core wallet is responsible for everything a user cares about: managing keys, knowing their balance, and sending bitcoin. It sits on top of the validation layer, watching the blockchain for relevant transactions.

๐Ÿฆ

CWallet

The main wallet class. Owns keys, tracks transactions, initiates sends.

๐Ÿ”‘

ScriptPubKeyMan

Manages specific groups of keys/scripts. Multiple SPKMs per wallet.

๐Ÿ’ฐ

CWalletTx

Wallet's view of a transaction, includes metadata like confirmation count, labels.

Key Design Decisions

Key Management

Modern Bitcoin Core wallets use HD key derivation (BIP 32) to generate all keys from a single master seed:

Master SeedRandom entropy โ†’ 256-bit HD seed (Bitcoin Core does not use BIP 39 mnemonics)
โ†“
Master Key (m)HMAC-SHA512 of seed produces master private key + chain code
โ†“
Derivation Pathe.g., m/84'/0'/0'/0/n for native SegWit receive addresses
โ†“
Child KeysIndividual private โ†’ public โ†’ address for each index n

Key Pool

The wallet pre-generates a pool of keys (default: 1,000) so that backups remain valid for future addresses. When a key is used, a new one is generated to refill the pool.

Descriptor Wallets

Since Bitcoin Core v0.21, wallets use output descriptors: a compact language that describes exactly how to derive scriptPubKeys:

pkh(KEY)P2PKH, legacy addresses starting with 1
sh(wpkh(KEY))P2SH-P2WPKH, wrapped SegWit addresses starting with 3
wpkh(KEY)P2WPKH, native SegWit addresses starting with bc1q
tr(KEY)P2TR, Taproot addresses starting with bc1p
multi(k, KEY1, KEY2, ...)k-of-n multisig
โœ… Why Descriptors?

Descriptors solve the backup problem. Instead of backing up every key, you back up one descriptor string (containing the xpub/xprv and derivation path). This single string can regenerate every address the wallet will ever use.

Tracking Funds

The wallet needs to know which UTXOs belong to it. Here's how:

  1. IsMine check: when a new transaction/block arrives, the wallet checks every output's scriptPubKey against its ScriptPubKeyMans. If a SPKM recognizes the script, the output is "ours."
  2. CWalletTx: matched transactions are stored as CWalletTx objects with additional metadata (which outputs are ours, confirmation depth, time received).
  3. Balance calculation: the wallet iterates over all CWalletTx entries, summing spendable UTXOs based on confirmation status.

Balance Types

AvailableConfirmed UTXOs ready to spend (not locked, not immature coinbase)
PendingUnconfirmed incoming transactions (0-conf)
ImmatureCoinbase rewards that haven't reached 100 confirmations yet

Coin Selection

When creating a transaction, the wallet must choose which UTXOs to spend as inputs. This matters for fees, privacy, and UTXO set management.

Available Algorithms

Branch and Bound (BnB)Tries to find an exact-match combination (no change output), saves fees
CoinGrinderMinimizes the input weight (lowest fee), optimal for high-fee environments
KnapsackRandomized solver, a classic heuristic approach
Single Random Draw (SRD)Randomly selects UTXOs until the target is met, simple but creates change

The wallet runs all applicable algorithms and picks the solution with the lowest waste metric: a score that accounts for current fees, long-term fee predictions, and the cost of creating change.

โ„น๏ธ Waste Metric

Waste = input cost at current rate โˆ’ input cost at long-term rate + excess amount (change cost or overpayment). A negative waste score means the current selection is beneficial at today's fee rates.

Creating a Transaction

The CreateTransaction function orchestrates the full spending flow:

1. Gather RecipientsParse destination addresses and amounts from the send request
โ†“
2. Select CoinsRun coin selection algorithms to choose inputs
โ†“
3. Build TransactionConstruct CMutableTransaction with inputs, outputs, and change
โ†“
4. Estimate FeeCalculate fee based on virtual size and target fee rate
โ†“
5. Adjust & Re-selectIf fee estimate changed the tx size, re-run coin selection
โ†“
6. SignSign all inputs (or leave unsigned for PSBT)

Change Output

If the selected inputs exceed the payment + fee, the wallet creates a change output back to itself. The change address is derived from the wallet's key pool. If the change amount would be below the dust threshold, it's added to the fee instead.

Transaction Signing

Signing proves ownership of the UTXOs being spent. The wallet signs each input based on its script type:

P2PKHECDSA signature + public key in scriptSig
P2WPKHECDSA signature + public key in witness data
P2SH-P2WPKHRedeem script in scriptSig, signature in witness
P2TR (key path)Single Schnorr signature in witness
P2TR (script path)Script satisfaction + script + control block in witness

Sighash Types

The sighash type controls what parts of the transaction the signature commits to:

Fee Estimation

Bitcoin Core estimates the fee rate needed for confirmation within a target number of blocks:

โš ๏ธ Fee Estimation Limits

Fee estimation only works well when the node has been running long enough to observe fee patterns. On a freshly started or rarely-used node, estimates may be unreliable. A fallback fee rate is used when no estimate is available.

Partially Signed Bitcoin Transactions (PSBT)

PSBT (BIP 174) is a format for passing unsigned or partially signed transactions between wallets, signers, and tools:

CreatorCreates the unsigned transaction skeleton
โ†“
UpdaterAdds UTXO info, scripts, derivation paths
โ†“
Signer(s)Each signer adds their signature(s)
โ†“
CombinerMerges signatures from multiple signers
โ†“
FinalizerAssembles the final scriptSig/witness from signatures
โ†“
ExtractorProduces the network-ready transaction

PSBT Use Cases

Wallet Storage

The wallet database stores keys, transactions, and metadata:

SQLiteDefault for descriptor wallets (v0.21+). Modern, well-tested, single-file.
BerkeleyDB (BDB)Legacy format. Used by older wallets. Being phased out.

Wallet files are stored in the data directory under wallets/. Each wallet has its own subdirectory containing the database and any lock files.