-
Notifications
You must be signed in to change notification settings - Fork 50
31.0 Release Candidate Testing Guide
For feedback on this guide, please visit this issue.
This document outlines some of the upcoming Bitcoin Core 31.0 release changes and provides steps to help test them. This guide is meant to be the starting point for experimentation and further testing, but is in no way comprehensive! After running through the steps in this guide, you are encouraged to do your own testing. To do additional tests can be as simple as testing the same features in this guide but trying it a different way. Even better, think of features you use regularly and test that they still work as expected in the release candidate. You can also read the release notes to find something not covered in this guide. This is a great way to be involved with Bitcoin's development and helps keep Bitcoin running smoothly and bug-minimized! Your help in this endeavour is greatly appreciated.
The Bitcoin Core 31.0 release introduces a range of updates.
The guide describes how to test the following updates:
- 1.1 Cluster mempool: new RPCs
- 1.2 Cluster mempool: high-fee parent, low-fee child (two chunks) + feerate diagram
- 1.3 Cluster mempool: cluster limits enforcement
- 2.1 Private broadcast (#29415)
- 3.1 Updated
getblockRPC:coinbase_txfield (#34512) - 4.1
txospenderindexandgettxspendingprevout(#24539)
Settings:
- 5.1 Default
-dbcachesize increase - 5.2 Embedded ASMap:
-asmapnow loads bundled data (#28792) - 6.1 REST API:
blockpartendpoint
For a comprehensive list of changes in Bitcoin Core 31.0, check out the release notes.
This chapter outlines the steps to configure a proper testing environment. Skip to the tests
Choose a directory to work from. Set the RC_TEST_DIR environment variable to the chosen directory for testing, e.g., export RC_TEST_DIR=~/rctesting. This designates a workspace/folder in your home directory (~) named rctesting for test-related files.
export RC_TEST_DIR=~/rctesting
mkdir $RC_TEST_DIR
cd $RC_TEST_DIRCurrent Release Candidate: Bitcoin Core 31.0rc4 (release-notes)
There are two ways to grab the latest release candidate: from source code or pre-compiled binary. Choose one of the two.
The source code for the release candidate can be obtained from the releases page, or by using git directly:
cd $RC_TEST_DIR
git clone https://github.com/bitcoin/bitcoin.git -b v31.0rc4 --depth 1
cd bitcoin(continue to step 3 compile)
If using a pre-compiled binary is preferred, make sure to obtain the correct one for your systems architecture. When using the pre-compiled binary, extract the package to the folder set in RC_TEST_DIR. (example for x86_64-linux):
cd $RC_TEST_DIR
wget https://bitcoincore.org/bin/bitcoin-core-31.0/test.rc4/bitcoin-31.0rc4-x86_64-linux-gnu.tar.gz
tar xf bitcoin-31.0rc4-x86_64-linux-gnu.tar.gz(continue on step 4)
Note: This step is only needed when working from source
Before compiling, make sure that your system has all the correct dependencies installed.
Compiling from source is highly dependent on your systems architecture and operating system. Refer to the Bitcoin Core compilation guide for details;
Some testing in this guide involves using previous releases such as v30.2.
Obtain the v30.2 binary from here and extract it to the folder set in RC_TEST_DIR, (example for v30.2 x86_64-linux):
cd $RC_TEST_DIR
wget https://bitcoincore.org/bin/bitcoin-core-30.2/bitcoin-30.2-x86_64-linux-gnu.tar.gz
tar xf bitcoin-30.2-x86_64-linux-gnu.tar.gzCreate temporary data directories for each version.
export DATA_DIR_31=/tmp/31-rc-test
mkdir $DATA_DIR_31
export DATA_DIR_30=/tmp/30-test
mkdir $DATA_DIR_30Specify path for executable binary, which depend on your selection in step 2: compiling from source or using a pre-compiled binary.
If testing with v31 from compiled source, set:
export BINARY_PATH_31=$RC_TEST_DIR/bitcoin/build/binIf testing from v31 downloaded binaries, set:
export BINARY_PATH_31=$RC_TEST_DIR/bitcoin-31.0rc4/binSpecify path for the executable binary from the previous release, e.g. for v30.2:
export BINARY_PATH_30=$RC_TEST_DIR/bitcoin-30.2/binTo avoid specifying the data directory (-datadir=$DATA_DIR) on each command, create these aliases:
alias bitcoind31="$BINARY_PATH_31/bitcoind -datadir=$DATA_DIR_31"
alias bcli31="$BINARY_PATH_31/bitcoin-cli -datadir=$DATA_DIR_31"alias bitcoind30="$BINARY_PATH_30/bitcoind -datadir=$DATA_DIR_30"
alias bcli30="$BINARY_PATH_30/bitcoin-cli -datadir=$DATA_DIR_30"The alias datadir-cleanup is created to make resetting the data directory easier between tests.
alias datadir-cleanup='rm -rf $DATA_DIR_31; mkdir -p $DATA_DIR_31; rm -rf $DATA_DIR_30; mkdir -p $DATA_DIR_30;'Verify that all versions are correct (e.g. that there are no accidental duplicates):
bcli31 --version | grep version
bitcoind31 --version | grep version
bcli30 --version | grep version
bitcoind30 --version | grep versionExpected results:
Bitcoin Core RPC client version v31.0.0rc4
Bitcoin Core daemon version v31.0.0rc4 bitcoind
Bitcoin Core RPC client version v30.2.0
Bitcoin Core daemon version v30.2.0 bitcoindIf the output of the commands is as expected, the testing environment is set up correctly to continue with this testing guide!
In this guide, we will be using jq for the first time, which is a handy tool to extract and transform data from JSON, much like grep is used for finding occurrences of given strings in text files.
For example, to extract just the chain type and block height from JSON shaped getblockchaininfo RPC response:
echo '
{
"chain": "regtest",
"blocks": 101,
"headers": 101,
"bestblockhash": "5e92b027a2ccfa426f0b4c2dbb621d933968845e93f557a386ace88f33db53f5",
"bits": "207fffff",
"target": "7fffff0000000000000000000000000000000000000000000000000000000000",
"difficulty": 4.656542373906925e-10,
"time": 1770902382,
"mediantime": 1770902381,
"verificationprogress": 0.03334778403975056,
"initialblockdownload": true,
"chainwork": "00000000000000000000000000000000000000000000000000000000000000cc",
"size_on_disk": 30375,
"pruned": false,
"warnings": []
}' | jq '{chain: .chain, blocks: .blocks}'
Expected output:
{
"chain": "regtest",
"blocks": 101
}Of course, you are invited to run the commands without the jq extractions as well to check the whole structure. It just makes for a clean guide, with clear focus on the important parts.
Bitcoin Core 31.0 introduces a new cluster mempool design. Two new RPCs have been added: getmempoolcluster returns the set of transactions in the same cluster as a given transaction along with chunk ordering, and getmempoolfeeratediagram returns the feerate diagram of the entire mempool. Additionally, getmempoolentry now includes chunkweight and fees.chunk fields. #33629
Start Bitcoin Core 31.0 in regtest:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -daemonGenerate a wallet, address, and mine 101 blocks:
bcli31 createwallet "satoshi"
bcli31 generatetoaddress 101 $(bcli31 getnewaddress)Send a transaction with a low fee rate and capture the txid:
addr1=$(bcli31 getnewaddress)
parent_txid=$(bcli31 -named sendtoaddress address=$addr1 amount=1 fee_rate=1)Now spend that unconfirmed output with a high-fee child (CPFP)
addr2=$(bcli31 getnewaddress)
child_txid=$(bcli31 -named sendtoaddress address=$addr2 amount=0.5 fee_rate=20)Check getmempoolentry for the new chunkweight and chunk_fees fields:
bcli31 getmempoolentry $parent_txid | jq '{chunkweight: .chunkweight, chunk_fees: .fees.chunk}'Validate that both fields are present in the output, for example:
{
"chunkweight": 1122,
"chunk_fees": 0.00005640
}Now call getmempoolcluster with the txid:
bcli31 getmempoolcluster $parent_txidValidate that the response contains both the transactions and their fee/weight information, for example:
[
{
"clusterweight": 1122,
"txcount": 2,
"chunks": [
{
"chunkfee": 0.00005640,
"chunkweight": 1122,
"txs": [
"bd0b9573d240ae664af8bd89fdf98a4423a5a8398f4148b6f7e41a7d8b34346e",
"5926ec40f41c008ec9089967179ab2215fafd966cc4dced86c2dee5f5cb78bf6"
]
}
]
}
]Call getmempoolfeeratediagram:
bcli31 getmempoolfeeratediagramValidate that a feerate diagram is returned, for example:
[
{
"weight": 0,
"fee": 0.00000000
},
{
"weight": 1122,
"fee": 0.00005640
}
]Stop node and clean up:
bcli31 stop && datadir-cleanupSection 1.1 showed CPFP: a low-fee parent is "pulled up" by a high-fee child into a single chunk with a blended feerate. This test shows the opposite scenario: when the parent has the higher fee, cluster mempool splits them into two separate chunks. The parent is worth mining on its own at its high feerate; the low-fee child will be included later in a separate, lower-priority chunk.
Start Bitcoin Core 31.0 in regtest:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -daemon
sleep 5
bcli31 createwallet "satoshi"
bcli31 generatetoaddress 101 $(bcli31 getnewaddress)Send a high-fee parent, then a low-fee child that spends the parent's change output:
parent=$(bcli31 -named sendtoaddress address=$(bcli31 getnewaddress) amount=1 fee_rate=20)
child=$(bcli31 -named sendtoaddress address=$(bcli31 getnewaddress) amount=0.5 fee_rate=2)Call getmempoolcluster on the parent:
bcli31 getmempoolcluster $parentValidate that the cluster has two chunks: the parent (high-feerate) in the first chunk, and the child (low-feerate) in the second. (Compare this to section 1.1, where both transactions were merged into a single chunk)
[
{
"clusterweight": 1122,
"txcount": 2,
"chunks": [
{
"chunkfee": 0.00002820,
"chunkweight": 561,
"txs": [ "<parent>" ]
},
{
"chunkfee": 0.00000282,
"chunkweight": 561,
"txs": [ "<child>" ]
}
]
}
]With two chunks already in the mempool, call getmempoolfeeratediagram to see them as two separate steps. This RPC represents the entire mempool as chunks ordered from highest to lowest feerate:
bcli31 getmempoolfeeratediagramValidate that the diagram has three points: the origin (0, 0), then the high-feerate parent chunk as the first step, then the low-feerate child chunk added on top:
[
{
"weight": 0,
"fee": 0.00000000
},
{
"weight": 561,
"fee": 0.00002820
},
{
"weight": 1122,
"fee": 0.00003102
}
]Stop node and clean up:
bcli31 stop && datadir-cleanupWith cluster mempool there are new limitation on chains of unconfirmed transactions. The mempool is now partitioned into connected clusters of transactions, limited to 64 transactions and 101 kvB per cluster by default. Previously, chains of unconfirmed transactions were constrained by per-transaction ancestor and descendant limits (default: 25 ancestors, 25 descendants). These are no longer enforced but replaced with cluster count and vsize limits.
Start Bitcoin Core 31.0 in regtest:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -daemonGenerate a wallet, address, and mine 101 blocks:
bcli31 createwallet "satoshi"
bcli31 generatetoaddress 101 $(bcli31 getnewaddress)Run the following script to generate transactions:
#!/usr/bin/env bash
set -euo pipefail
UTXO=$(bcli31 -regtest listunspent | jq -r '.[0] | [.txid, (.vout|tostring)] | join(":")')
TXID=${UTXO%:*}
VOUT=${UTXO#*:}
ADDR=$(bcli31 -regtest getnewaddress)
PARENT_RAW_TX=$(bcli31 -regtest createrawtransaction "[{\"txid\":\"$TXID\",\"vout\":$VOUT}]" "{\"$ADDR\":49.999}")
SIGNED=$(bcli31 -regtest signrawtransactionwithwallet "$PARENT_RAW_TX" | jq -r .hex)
CURRENT_TXID=$(bcli31 -regtest sendrawtransaction "$SIGNED" 0)
COUNT=1
SATS=4999900000
while [ $COUNT -lt 80 ]; do
SATS=$((SATS - 1000)) #fee
WHOLE=$((SATS / 100000000))
FRAC_PAD=$((100000000 + (SATS % 100000000)))
AMOUNT="${WHOLE}.${FRAC_PAD#1}"
NEW_ADDR=$(bcli31 -regtest getnewaddress)
RAW_TX=$(bcli31 -regtest createrawtransaction "[{\"txid\":\"$CURRENT_TXID\",\"vout\":0}]" "{\"$NEW_ADDR\":$AMOUNT}")
SIGNED=$(bcli31 -regtest signrawtransactionwithwallet "$RAW_TX" | jq -r .hex)
RESULT=$(bcli31 -regtest sendrawtransaction "$SIGNED" 0 2>&1 || true)
if echo "$RESULT" | grep -qi "cluster\|too-long"; then
echo "Cluster limit hit at tx #$((COUNT+1)) (expected: #65)"; break
elif echo "$RESULT" | grep -qi "error\|invalid"; then
echo "Unexpected error at tx #$((COUNT+1)): $RESULT"
break
else
echo " Tx #$((COUNT+1)): $RESULT"
CURRENT_TXID="$RESULT"
COUNT=$((COUNT+1))
fi
doneValidate that the script now succeeds with the following message:
Cluster limit hit at tx #65 (expected: #65)
Stop node and clean up:
bcli31 stop && datadir-cleanupA new boolean option -privatebroadcast has been added. When enabled, transactions submitted via sendrawtransaction are broadcast only via Tor or I2P networks, improving privacy of the transaction originator. Two new RPCs support this: getprivatebroadcastinfo and abortprivatebroadcast. #29415
First, start Bitcoin Core 31.0 without -privatebroadcast in regtest and prepare a signed transaction:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -daemon
sleep 5
bcli31 createwallet "satoshi"
bcli31 generatetoaddress 101 $(bcli31 getnewaddress)
addr=$(bcli31 getnewaddress)
raw_tx=$(bcli31 createrawtransaction "[]" "[{\"$addr\":1}]")
funded_tx=$(bcli31 fundrawtransaction $raw_tx '{"fee_rate": 10}' | jq -r .hex)
signed_tx=$(bcli31 signrawtransactionwithwallet $funded_tx | jq -r .hex)Verify that sendrawtransaction succeeds normally (no private broadcast):
bcli31 sendrawtransaction $signed_txValidate that a txid is returned without error.
Now restart the node with -privatebroadcast enabled:
bcli31 stop
bitcoind31 -privatebroadcast -daemonAttempt to submit the same transaction via sendrawtransaction:
bcli31 sendrawtransaction $signed_txValidate that the command now fails with an error indicating Tor or I2P is required:
error code: -1
error message:
-privatebroadcast is enabled, but none of the Tor or I2P networks is reachable.This confirms that -privatebroadcast is enforced - the node refuses to broadcast the transaction over clearnet and requires a privacy network.
Stop node and clean up:
bcli31 stop && datadir-cleanupThe getblock RPC now returns a coinbase_tx object at verbosity levels 1, 2, and 3. It contains version, locktime, sequence, coinbase, and witness. This allows for efficiently querying coinbase transaction properties without fetching the full transaction data. #34512
Start Bitcoin Core 31.0 in regtest:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -daemonGenerate a wallet and mine a block:
bcli31 createwallet "satoshi"
bcli31 generatetoaddress 1 $(bcli31 getnewaddress)Get the best block hash and call getblock at verbosity 1:
block_hash=$(bcli31 getbestblockhash)
bcli31 getblock $block_hash 1 | jq '.coinbase_tx'Validate that the coinbase_tx field is present and contains the expected fields:
{
"version": 2,
"locktime": 0,
"sequence": 4294967294,
"coinbase": "...",
"witness": [...]
}Now compare with Bitcoin Core v30, which does not include this field. Stop v31 first to avoid port conflicts, then start v30 in regtest:
bcli31 stop
sleep 5
echo "regtest=1" > $DATA_DIR_30/bitcoin.conf
bitcoind30 -daemon
sleep 5
bcli30 createwallet "satoshi"
bcli30 generatetoaddress 1 $(bcli30 getnewaddress)
block_hash30=$(bcli30 getbestblockhash)
bcli30 getblock $block_hash30 1 | jq '.coinbase_tx'Validate that the output is null (field absent) in v30.0:
nullStop node and clean up:
bcli30 stop && datadir-cleanupA new -txospenderindex startup option enables an index that tracks which transaction spends each output. When available, gettxspendingprevout will scan this index for confirmed spending transactions. Two new optional arguments have been added: mempool_only limits scans to the mempool, and return_spending_tx returns the full spending transaction. When a confirmed spending transaction is found, its block hash is also returned. #24539
Start Bitcoin Core 31.0 in regtest with the new index:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -txospenderindex -daemonCreate wallet, mine 101 blocks, and send a transaction:
bcli31 createwallet "satoshi"
bcli31 generatetoaddress 101 $(bcli31 getnewaddress)
coinbase_txid=$(bcli31 listunspent | jq -r ".[0].txid")
addr=$(bcli31 getnewaddress)
spend_txid=$(bcli31 -named sendtoaddress address=$addr amount=1 fee_rate=10)Mine the spending transaction into a block:
bcli31 generatetoaddress 1 $(bcli31 getnewaddress)Query gettxspendingprevout with return_spending_tx=true - this uses the index to find the confirmed spending transaction:
bcli31 -named gettxspendingprevout outputs="[{\"txid\":\"$coinbase_txid\",\"vout\":0}]" return_spending_tx=trueValidate that the spending transaction and block hash are returned (found via the index):
[
{
"txid": "<coinbase_txid>",
"vout": 0,
"spendingtxid": "<spend_txid>",
"blockhash": "...",
"spendingtx": "..."
}
]Now query again with mempool_only=true to show that the index is bypassed - since the spending transaction is confirmed (not in the mempool), it will not be found:
bcli31 -named gettxspendingprevout outputs="[{\"txid\":\"$coinbase_txid\",\"vout\":0}]" mempool_only=trueValidate that no spending transaction is returned (mempool only, index not used):
[
{
"txid": "<coinbase_txid>",
"vout": 0
}
]Stop node and clean up:
bcli31 stop && datadir-cleanupThe default -dbcache value has been increased to 1024 MiB from 450 MiB on systems where at least 4096 MiB of RAM is detected. This is a performance improvement but will use more memory. To revert to the previous behaviour, set -dbcache=450.
Start Bitcoin Core 31.0 without specifying -dbcache:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -daemonCheck the debug log to confirm the cache allocation being used:
grep "* Using.*MiB" $DATA_DIR_31/regtest/debug.logValidate that the total cache (1024 MiB) is allocated across the three components if your system has at least 4 GiB of RAM: 2 MiB for the block index database, 8 MiB for the chain state database, and the remaining 1014 MiB for the in-memory UTXO set (2 + 8 + 1014 = 1024), for example:
2026-03-16T04:30:34Z * Using 2.0 MiB for block index database
2026-03-16T04:30:34Z * Using 8.0 MiB for chain state database
2026-03-16T04:30:34Z * Using 1014.0 MiB for in-memory UTXO set (plus up to 286.1 MiB of unused mempool space)Stop node and clean up:
bcli31 stop && datadir-cleanupASMap data maps IP addresses to their Autonomous System Numbers (ASNs), which Bitcoin Core uses to select peers from diverse network paths - improving resistance to eclipse attacks.
In previous releases, -asmap without a filename looked for a file called ip_asn.map in the datadir, which usually didn't exist. In 31.0, ASMap data is embedded directly in the binary: passing -asmap alone is now enough to enable it. An explicit file can still be used with -asmap=<filename>. #28792
Start Bitcoin Core 31.0 with embedded asmap enabled:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -asmap -daemon
sleep 5Check the debug log to confirm embedded asmap data was loaded:
grep -i "asmap" $DATA_DIR_31/regtest/debug.logValidate that a line like this appears, confirming the embedded data was used:
2026-03-(...) Opened asmap data (1519688 bytes) from embedded byte array
2026-03-(...) Using asmap version 68adb8c892c488e6d6fbd55492a314578ce3ea1376f138fea1ef160fcf6fc049 for IP bucketingNow compare with starting without -asmap. Clean up first so the debug log starts fresh:
bcli31 stop && datadir-cleanup
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -daemon
sleep 5
grep -i "asmap" $DATA_DIR_31/regtest/debug.logValidate that no asmap line appears in the log (empty output from 'grep').
Stop node and clean up:
bcli31 stop && datadir-cleanupA new REST API endpoint /rest/blockpart/<BLOCK-HASH>.<bin|hex>?offset=<OFFSET>&size=<SIZE> has been introduced for efficiently fetching a range of bytes from a block. #33657
Start Bitcoin Core 31.0 in regtest with REST enabled:
echo "regtest=1" > $DATA_DIR_31/bitcoin.conf
bitcoind31 -rest -daemonMine a block:
bcli31 createwallet "satoshi"
bcli31 generatetoaddress 1 $(bcli31 getnewaddress)
block_hash=$(bcli31 getbestblockhash)Fetch the first 80 bytes of the block (the block header) using the new endpoint:
curl -s "http://127.0.0.1:18443/rest/blockpart/$block_hash.hex?offset=0&size=80"Validate that a non-empty hex string is returned.
Stop node and clean up:
bcli31 stop && datadir-cleanupKudos if you made it this far 👏🎉
Thanks for your contribution and for taking the time to make this Bitcoin release awesome.
For feedback on this guide, please visit this issue.
Release notes & Testing guide (v31)
IRC Meetings & Working groups
Build & Dev
- CMake Goals and Guidelines
- GitHub-alternatives-for-Bitcoin-Core
- Fuzz Trophies
- Developer Notes for Qt Code
P2P & Network
- [P2P] known TxOrphanage problems
- Addrman and eclipse attacks
- Mempool and mining
- P2P Current Priorities
- P2P Design Philosophy
Wallet
- Improving Large Wallet Performance
- Wallet Class Structure Changes
- Wallet Transaction Conflict Tracking
- Wallet Use Cases
External Resources
**Archival Testing Guides **