Bitcoin Protocol, Wallet & Custody Engineering
Bitcoin development is not “Ethereum without contracts.” It is UTXO accounting, restrictive Script, peer policy, fee operations, wallet standards, and explicit custody boundaries.
1. Local node and safe network choice
Use regtest for deterministic integration tests, signet for public integration, and testnet only when a dependency specifically requires it. Never use mainnet keys in a course project.
# Start Bitcoin Core in regtest mode (adjust paths for your install).
bitcoind -regtest -daemon -fallbackfee=0.0002
alias btc='bitcoin-cli -regtest'
btc createwallet "lab"
ADDR=$(btc -rpcwallet=lab getnewaddress "funding" bech32)
btc generatetoaddress 101 "$ADDR"
btc getblockchaininfo
btc listunspent
Learn the RPC surface: getblockchaininfo, getmempoolinfo, listunspent, decoderawtransaction, testmempoolaccept, sendrawtransaction, and estimatesmartfee. Use Esplora/electrs as an indexing boundary when a product should not expose a Core wallet directly.
2. UTXO transactions, not account transactions
| Component | What to understand |
|---|---|
| Input | Outpoint (txid:vout), sequence, unlocking witness/script data, and the previous output being spent |
| Output | Value in sats and locking script; recipient plus deliberate change output |
| Fee | Inputs − outputs; selected from feerate × virtual bytes, never a “gas price” field |
| Policy | Dust, standardness, mempool acceptance, ancestor/descendant limits, and confirmation targets |
| Finality | nLockTime, sequence, and timelocks; these are part of the spending policy |
Implement coin selection with a privacy and fee policy: avoid needless address reuse, identify change, respect dust, and surface the exact fee in sats and sat/vB. Test RBF and CPFP as operational recovery tools, not as trivia.
3. Script, SegWit, and Taproot
- Read scripts as spending conditions:
scriptPubKeylocks an output; witness/unlocking data satisfies it. Learn P2PKH, P2SH, P2WPKH, P2WSH, and Bech32/Bech32m address encodings. - SegWit separates witness data, fixes transaction-ID malleability for relevant paths, and introduces virtual size/weight accounting.
- Taproot combines key-path Schnorr spending with optional script-path spending. Learn BIP340/341/342 concepts, control blocks, and why key-path spends improve common-case privacy.
- Study sighash flags and transaction commitments before signing anything outside a trusted library.
4. Wallet standards and custody boundaries
| Standard / primitive | Use |
|---|---|
| BIP-32 / BIP-39 / BIP-44/84/86 | Seed handling, HD derivation, and purpose-specific paths; never log a mnemonic or xprv. |
| Descriptors | Explicit wallet policy and derivation definition; avoid opaque “address-only” wallet state. |
| PSBT (BIP-174/370) | Separate construction, signing, and finalization; supports hardware-wallet and multisig flows. |
| Miniscript / multisig | Analyseable spending policies, threshold custody, recovery and timelock branches. |
| Hardware signer | Key isolation; display and confirm destination, amount, fee, and policy on a trusted device. |
5. Practical lab — PSBT-backed treasury flow
- Run Core on regtest and create a descriptor wallet. Fund at least two UTXOs, then inspect their outpoints and scripts with
listunspentandgettxout. - Construct a PSBT that pays a recipient and produces a change output. Decode it before signing; show inputs, outputs, fee in sats/sat-vB, locktime, and change classification in a CLI or small service.
- Sign in a separate wallet process or hardware-wallet emulator, finalize, run
testmempoolaccept, broadcast, mine a block, and verify the resulting UTXO set. - Create an RBF replacement and a CPFP child in regtest. Write tests/assertions for the intended fee and confirmation behavior.
- Implement a 2-of-3 descriptor policy with a timelocked recovery branch. Document the signer locations, recovery drill, and the policy’s failure modes.
6. Recommended implementation stack
For browser/server JavaScript, evaluate bitcoinjs-lib carefully with pinned versions and independent transaction decoding. For Rust, use rust-bitcoin and BDK; for mobile/native wallets, prefer a well-maintained descriptor/PSBT-capable library. Do not invent signing or serialization code for a production wallet without deep review and test vectors.
labs/phase-25-bitcoin/).