-
Notifications
You must be signed in to change notification settings - Fork 50
27.0 Release Candidate Testing Guide
For feedback on this guide, please visit #29685
This document outlines some of the upcoming Bitcoin Core 27.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.
This 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 endeavor is greatly appreciated.
Changes covered in this testing guide include:
- Mempool.dat v1/v2 compatibility (#28207)
- v2 Transport on by default (#29347)
-
-netinfo
backward compatibility with pre-v26 nodes (#29212) - v3 Transaction Policy (#28948)
- CoinGrinder coin selection algorithm (#27877)
-
migratewallet
RPC is no longer experimental (#28037)
For a comprehensive list of changes in Bitcoin Core 27.0, check out the release notes.
Choose a directory to work from, for example:
export RC_TEST_DIR=~/rctesting
mkdir $RC_TEST_DIR
cd $RC_TEST_DIR
Current Release Candidate: Bitcoin Core 27.0rc1 (release-notes)
There are two ways to grab the latest release candidate: 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 (and extracted), or by using git directly:
cd $RC_TEST_DIR
git clone https://github.com/bitcoin/bitcoin.git
cd bitcoin
git checkout tags/v27.0rc1
(ensure source is present in RC_TEST_DIR/bitcoin in either instance (run mv
if necessary))
If using a binary is preferred, make sure to obtain the correct one for your system. When working from binary, extract (example for x86_64):
cd $RC_TEST_DIR
wget https://bitcoincore.org/bin/bitcoin-core-27.0/test.rc1/bitcoin-27.0rc1-x86_64-linux-gnu.tar.gz
tar xf bitcoin-27.0rc1-x86_64-linux-gnu.tar.gz
(directory $RC_TEST_DIR/bitcoin-27.0rc1/
now exists)
If testing v27 from binary (rather than building from source), skip this step
Before compiling, make sure that your system has all the correct dependencies installed.
For the migratewallet
test, BDB wallet support is required, please refer to the Bitcoin
Core build guides for instructions on compiling with BDB support.
For more information on compiling from source, here are some guides to compile Bitcoin Core for UNIX/Linux, macOS, Windows, FreeBSD, NetBSD, and OpenBSD.
Some testing in this guide involves using previous releases, v26.0 and v25.1.
Obtain the v26.0 binary from here and extract within RC_TEST_DIR
:
cd $RC_TEST_DIR
wget https://bitcoincore.org/bin/bitcoin-core-26.0/bitcoin-26.0-x86_64-linux-gnu.tar.gz
tar xf bitcoin-26.0-x86_64-linux-gnu.tar.gz
(directory $RC_TEST_DIR/bitcoin-26.0
now exists)
Obtain the v25.1 binary from here and extract within RC_TEST_DIR
:
cd $RC_TEST_DIR
wget https://bitcoincore.org/bin/bitcoin-core-25.1/bitcoin-25.1-x86_64-linux-gnu.tar.gz
tar xf bitcoin-25.1-x86_64-linux-gnu.tar.gz
(directory $RC_TEST_DIR/bitcoin-25.1
now exists)
Create temporary data directories for each version.
export DATA_DIR_27=/tmp/27-rc-test
mkdir $DATA_DIR_27
export DATA_DIR_26=/tmp/26-test
mkdir $DATA_DIR_26
export DATA_DIR_25=/tmp/25-test
mkdir $DATA_DIR_25
Define paths containing binaries that will be executed.
If testing with v27 compiled source, run:
export BINARY_PATH_27=$RC_TEST_DIR/bitcoin/src
If testing from v27 downloaded binaries, run:
export BINARY_PATH_27=$RC_TEST_DIR/bitcoin-27.0rc1/bin
Specify the binary path for the v26.0 and v25.1 binaries.
export BINARY_PATH_26=$RC_TEST_DIR/bitcoin-26.0/bin
export BINARY_PATH_25=$RC_TEST_DIR/bitcoin-25.1/bin
To avoid specifying the data directory (-datadir=$DATA_DIR
) on each command, below are a few extra variables to set.
alias bitcoind-test="$BINARY_PATH_27/bitcoind -datadir=$DATA_DIR_27"
alias bcli="$BINARY_PATH_27/bitcoin-cli -datadir=$DATA_DIR_27"
alias bitcoind-test-26="$BINARY_PATH_26/bitcoind -datadir=$DATA_DIR_26"
alias bcli26="$BINARY_PATH_26/bitcoin-cli -datadir=$DATA_DIR_26"
alias bitcoind-test-25="$BINARY_PATH_25/bitcoind -datadir=$DATA_DIR_25"
alias bcli25="$BINARY_PATH_25/bitcoin-cli -datadir=$DATA_DIR_25"
datadir-cleanup
is created to make cleaning easier between tests.
alias datadir-cleanup='rm -r $DATA_DIR_27; mkdir $DATA_DIR_27; rm -r $DATA_DIR_26; mkdir $DATA_DIR_26; rm -r $DATA_DIR_25; mkdir $DATA_DIR_25'
(Expand for special instructions for macOS Big Sur 11+).
In macOS 11 on Macs with Apple silicon, and starting in macOS Big Sur 11 beta 6, the operating system enforces that any executable must be signed before it’s allowed to run. This is a very simple process:
codesign --sign - $BINARY_PATH/*
Due to macOS security settings, you are likely to be unable to execute any of the downloaded binaries from the terminal before you have manually marked them as trusted. To do so, run the below command to remove quarantine flags or navigate to your $BINARY_DIR
in Finder, and launch each of the 3 binaries (bitcoind
, bitcoin-qt
, bitcoin-cli
) by right-clicking, and then selecting "Open" twice. Afterwards, you should be able to execute them from the terminal as usual.
xattr -dr com.apple.quarantine $BINARY_PATH
(Expand for NixOS-only instructions).
Patch up binaries to use a valid ld-linux-x86-64.so.2
.
file /mnt/tmp/rctesting/bitcoin-25.1/bin/bitcoin-cli
/mnt/tmp/rctesting/bitcoin-25.1/bin/bitcoin-cli: ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, stripped
We see above that the binary's "interpreter" is using a path that doesn't exist on NixOS. Use fzf
or some other tool to find a valid ld-linux-x86-64.so.2
under /nix/store/
. Then proceed to patch them:
patchelf --set-interpreter /nix/store/qn3ggz5sf3hkjs2c797xf7nan3amdxmp-glibc-2.38-27/lib/ld-linux-x86-64.so.2 $BINARY_PATH_25/bitcoin-cli
patchelf --set-interpreter /nix/store/qn3ggz5sf3hkjs2c797xf7nan3amdxmp-glibc-2.38-27/lib/ld-linux-x86-64.so.2 $BINARY_PATH_25/bitcoind
patchelf --set-interpreter /nix/store/qn3ggz5sf3hkjs2c797xf7nan3amdxmp-glibc-2.38-27/lib/ld-linux-x86-64.so.2 $BINARY_PATH_26/bitcoin-cli
patchelf --set-interpreter /nix/store/qn3ggz5sf3hkjs2c797xf7nan3amdxmp-glibc-2.38-27/lib/ld-linux-x86-64.so.2 $BINARY_PATH_26/bitcoind
(Do the same for v27 if using downloaded binaries).
Verify that all versions are correct (e.g. that there are no accidental duplicates):
bcli --version | grep version
bitcoind-test --version | grep version
bcli26 --version | grep version
bitcoind-test-26 --version | grep version
bcli25 --version | grep version
bitcoind-test-25 --version | grep version
Expected results:
Bitcoin Core RPC client version v27.0.0rc1
Bitcoin Core version v27.0.0rc1
Bitcoin Core RPC client version v26.0.0
Bitcoin Core version v26.0.0
Bitcoin Core RPC client version v25.1.0
Bitcoin Core version v25.1.0
Throughout the rest of the guide, command execution will look similar to the following:
When using RPC:
bcli [cli args]
Starting a node in the foreground:
bitcoind-test
Use CTRL-C
to stop a node running in the foreground.
Note: When starting a node, allow a few seconds to pass (e.g. 10 seconds) for the node to listen for RPC before running subsequent bcli
commands
For the rest of the guide, bitcoind will be started in daemon mode (-daemonwait
) and as such CTRL-C
will not stop the process. Instead, use bcli stop
.
The mempool.dat
file uses a new format (v2, storing XOR'd data instead of raw data), which isn't understood by previous versions of Bitcoin Core. This new file format obfuscates the data stored by XORing with a key. This aids in preventing another program from mistakely misinterpreting the file (e.g. anti-virus software). A temporary setting -persistmempoolv1
allows fallback to the legacy format.
In general, the goal is to exercise a subset of functionality and basic migration from the legacy v1 to the new v2 format.
A wallet is created and funded in order to generate transactions for the mempool.
Following this, the persistmempoolv1
parameter is exercised, then a migration from the legacy file format to the new file format is exercised. If the tester has the resources availalbe, a subset of these activities are performed in a mainnet environment.
This test will require us to set up both v26 and v27 regtest nodes. First, let's setup the
bitcoin.conf
for our v27 node:
echo "regtest=1" > $DATA_DIR_27/bitcoin.conf
Now we'll set up our v26 node, using ports different than those used by default in Bitcoin Core so that they don't conflict with our v27 node:
echo "regtest=1" > $DATA_DIR_26/bitcoin.conf
echo "[regtest]" >> $DATA_DIR_26/bitcoin.conf
echo "rpcallowip=127.0.0.1" >> $DATA_DIR_26/bitcoin.conf
echo "rpcbind=127.0.0.1:18343" >> $DATA_DIR_26/bitcoin.conf
echo "rpcport=18343" >> $DATA_DIR_26/bitcoin.conf
echo "bind=127.0.0.1:18344" >> $DATA_DIR_26/bitcoin.conf
echo "bind=127.0.0.1:18345=onion" >> $DATA_DIR_26/bitcoin.conf
Start the v26 node:
bitcoind-test-26 -daemonwait
Create a wallet, and fund it with 50 tBTC:
bcli26 createwallet test
bcli26 -rpcwallet=test -generate 101
Expected results:
{
"name": "test"
}
//...
{
"address": "bcrt1q...",
"blocks": [
"57d09495e62df6a4e51f5ebe517b11b1913d7e9ba6dccbbbf5f3989bb2b43b37",
// ...
"659b4ed5400f14c3c901fa5646b40da3be8b9d526a03d9b5b6684fd99ce82c6e",
"79cef426a1e3a909ebc238c85498cd05c15a79442df46e2d3017f3f84f3a881e"
]
}
(your block hashes will differ)
Create two transactions (a child and parent transaction) and add them to the mempool.
address=$(bcli26 -rpcwallet=test getnewaddress)
bcli26 -rpcwallet=test -named send outputs="{\"$address\": 1}" fee_rate=10
bcli26 -rpcwallet=test -named send outputs="{\"$address\": 1}" fee_rate=10
Expected results: txids specified for each transaction.
{
"txid": "2fdc4aa2755f29d4ba8104f31e488b3e5df814a360ddb0b97ebc273a125a5971",
"complete": true
}
// ...
{
"txid": "28b8215819e7bc428787fc5e71c3927e20ad13c1a60d79ee1a409acded6efda3",
"complete": true
}
Stop the v26 node (saving the mempool).
bcli26 stop
Copy the v26 data into the v27 datadir and restore the v27 config.
mv $DATA_DIR_27/bitcoin.conf $DATA_DIR_27/bitcoin.conf.backup
cp -r $DATA_DIR_26/* $DATA_DIR_27/
mv $DATA_DIR_27/bitcoin.conf.backup $DATA_DIR_27/bitcoin.conf
Start the v27 node with the new persistmempoolv1
parameter.
bitcoind-test -daemonwait -persistmempoolv1=1
View the contents of the mempool. Verify that the mempool contains the same two transactions created earlier.
bcli getmempoolinfo
bcli getrawmempool
{
"loaded": true,
"size": 2,
"bytes": 282,
"usage": 2416,
"total_fee": 0.00002820,
"maxmempool": 300000000,
"mempoolminfee": 0.00001000,
"minrelaytxfee": 0.00001000,
"incrementalrelayfee": 0.00001000,
"unbroadcastcount": 2,
"fullrbf": false
}
// ...
[
"2fdc4aa2755f29d4ba8104f31e488b3e5df814a360ddb0b97ebc273a125a5971",
"28b8215819e7bc428787fc5e71c3927e20ad13c1a60d79ee1a409acded6efda3"
]
Stop the node and verify use of the legacy v1 format.
bcli stop
ls --full-time $DATA_DIR_27/regtest/mempool.dat
hexdump -n8 $DATA_DIR_27/regtest/mempool.dat
ℹ️ Note: If
ls --full-time
fails, you may have an implementation ofls
wherels -lT
will give you the precise time information.
Take note of the modified date.
Expected results:
-rw------- 1 dev dev 558 2024-03-17 18:18:13.224229360 -0400 /tmp/27-rc-test/regtest/mempool.dat
...
0000000 0001 0000 0000 0000
0000008
Start the node using the new mempool.dat format (by omitting -persistmempoolv1=1
).
Verify that the mempool contains the same two transactions created earlier.
bitcoind-test -daemonwait
bcli getmempoolinfo
bcli getrawmempool
Expected results:
{
"loaded": true,
"size": 2,
"bytes": 282,
"usage": 2416,
"total_fee": 0.00002820,
"maxmempool": 300000000,
"mempoolminfee": 0.00001000,
"minrelaytxfee": 0.00001000,
"incrementalrelayfee": 0.00001000,
"unbroadcastcount": 2,
"fullrbf": false
}
// ...
[
"2fdc4aa2755f29d4ba8104f31e488b3e5df814a360ddb0b97ebc273a125a5971",
"28b8215819e7bc428787fc5e71c3927e20ad13c1a60d79ee1a409acded6efda3"
]
Save the mempool to mempool.dat
in the new v2 format.
Verify that mempool.dat
has been modified, and is in the new v2 format.
bcli savemempool
ls --full-time $DATA_DIR_27/regtest/mempool.dat
hexdump -n8 $DATA_DIR_27/regtest/mempool.dat
Expected results:
{
"filename": "/tmp/27-rc-test/regtest/mempool.dat"
}
...
-rw------- 1 dev dev 567 2024-03-17 18:19:48.700777882 -0400 /tmp/27-rc-test/regtest/mempool.dat
...
0000000 0002 0000 0000 0000
0000008
Restart the node and verify successful loading of the new v2 format. Verify that the mempool contains the same two transactions created earlier.
bcli stop
bitcoind-test -daemonwait
bcli getmempoolinfo
bcli getrawmempool
Stop the node.
bcli stop
Cleanup the datadirs.
datadir-cleanup
The above tests using RegTest and a small mempool. If you have a fully synced v26.0 or older node (non-critical/non-production environment) that has been online for some time (e.g. at least several hours), the following outlines steps to test migration with a much larger mempool using Mainnet. Please do not run these steps if your Mainnet node's uptime is considered essential/critical. That being said, there is value to running this test on v27, as those running this Test Guide may find issues before the much larger adoption/migration to v27 after final release. This tests the most common migration expected.
If not already done, obtain the v27 RC on your Mainnet node (see Obtain Latest Release Candidate). For example, the directory /home/<user>/rctesting/bitcoin-27.0rc1/bin
exists and contains bitcoind
and bitcoin-cli
.
Stop your Mainnet node (either using bitcoin-cli
or using systemctl stop bitcoind.service
if your node uses a systemd service (in this example named bitcoind.service
)):
bitcoin-cli stop
Wait for your node to fully stop (e.g. monitor tail -f /path/to/your/existing/datadir/debug.log
).
Make a backup copy of your existing mempool.dat file, so it can be restored later.
cp /path/to/your/existing/datadir/mempool.dat /path/to/your/existing/datadir/mempool.dat.backup
Add debug=mempool
to bitcoin.conf to see mempool additional mempool focused logging messages in debug.log
.
Start the v27 node using the datadir and config for your mainnet node. If your bitcoin.conf and datadir are not the default location (i.e. ~/.bitcoin
), you may need to include the -conf
and -datadir
command line arguments when lauching /home/<user>/rctesting/bitcoin-27.0rc1/bin/bitcoind
.
/home/<user>/rctesting/bitcoin-27.0rc1/bin/bitcoind
You should see a set of mempool related message, including:
2024-03-19T02:36:43Z Loading 53296 mempool transactions from disk...
and "progress" messages such as:
2024-03-19T02:38:48Z Progress loading mempool transactions from disk: 30% (tried 15989, 37307 remaining)
Additionally, many "accepted" messages such as the following may be observed:
2024-03-19T02:41:23Z [mempool] AcceptToMemoryPool: peer=9: accepted fa491be58fcbb12022d85a28a0d40fd6350ec91d2fac0fa648015408ad4da6a3 (wtxid=f0abf597a69ba7e06a896049cf9b8121435b0da29e7cbf01c8f2185c54bc3d67) (poolsz 17510 txn, 84518 kB)
It may take several minutes to complete the process, and the following message should be present:
2024-03-19T02:47:52Z Imported mempool transactions from disk: 52778 succeeded, 494 failed, 0 expired, 24 already there, 0 waiting for initial broadcast
If you see error related to mempool activity, this would be noteworthy.
Stop the node (with CTRL-C
). This will save the mempool to mempool.dat
(assuming bitcoin.conf does not prohibit mempool persist).
Check that the mempool.dat
file is the new v2 format:
hexdump -n8 /path/to/your/datadir/mempool.dat
0000000 0002 0000 0000 0000
0000008
Start the v27 node again to ensure that the node successfully loads the new mempool.dat
:
/home/<user>/rctesting/bitcoin-27.0rc1/bin/bitcoind
Stop the node (with CTRL-C
).
Remove debug=mempool
from bitcoin.conf
.
Overwrite the new mempool.dat
with the backup mempool.dat.backup
to restore the v1 version.
mv /path/to/your/existing/datadir/mempool.dat.backup /path/to/your/existing/datadir/mempool.dat
Start the existing (non-v27) bitcoind through usual methods (e.g. systemctl start bitcoind.service
).
Bitcoin Core 27.0 enables v2 P2P Transport by default
for automatic connection and for bitcoind
and bitcoin-cli
command line flags and RPC
commands.
For the following manual v2 connection tests, we will want to connect to signet nodes that support v2 transport. Two such nodes that we will use in the examples below are:
bitcoin.achow101.com:38333
74.208.205.30:38333
Before the following tests, let's add signet=1 the bitcoin.conf to use the signet network
for testing, and turn off DNS seeds and fixed seeds so that we have more control over who
we connect to. We will also use debug=net
to enable logging of BCLOG::NET
messages.
{
echo "signet=1"
echo "dnsseed=0"
echo "fixedseeds=0"
echo "debug=net"
} > $DATA_DIR_27/bitcoin.conf
First, let's try using a v2 seednode to fill up our peer address book (addrman
):
bitcoind-test -daemonwait -seednode=bitcoin.achow101.com:38333
After ~30 seconds, we can run bitcoin-cli
with the -netinfo
flag to make sure our node
has succeeded in bootstrapping its connection from the seed node. -netinfo
takes an
optional integer between 0
and 4
that controls what information is output. We can use
values higher than 0
to see the transport versions of our connections in the v
column.
(2
and 4
give you an address column).
☝ We can also use the
getpeerinfo
command to see the status of our node's connections.
bcli -netinfo 3
bcli -netinfo 3
Bitcoin Core client v27.0rc1 - server 70016/Satoshi:27.0.0/
<-> type net v mping ping send recv txn blk hb addrp addrl age id version
out block ipv4 1 20 131 2 2 * 0 . 6 13 70016/Satoshi:25.0.0/
out full ipv4 1 43 669 0 0 0 1007 6 4 70016/Satoshi:25.0.0/
out full ipv4 1 51 649 0 0 0 1003 6 5 70016/Satoshi:25.0.0/
out full ipv4 1 58 58 35 46 1004 6 6 70016/Satoshi:22.0.0(FutureBit-Apollo-Node)/
out block ipv4 1 101 101 5 4 * 0 . 5 15 70016/Satoshi:24.0.1/
out full ipv4 1 103 420 0 0 0 1006 6 1 70015/Satoshi:0.20.1/
out full ipv4 1 110 634 0 0 0 1003 5 19 70016/Satoshi:26.0.0/
out full ipv4 1 161 164 0 0 0 1008 6 11 70016/Satoshi:23.0.0/
out full ipv4 1 200 382 0 0 0 1003 3 21 70016/Satoshi:25.1.0/
out full ipv4 1 248 6699 0 0 0 1005 6 12 70016/Satoshi:26.0.0/
ms ms sec sec min min min
ipv4 ipv6 total block
in 0 0 0
out 10 0 10 2
total 10 0 10
Local addresses: n/a
To ensure that you have successfully made an addrfetch
connection to the seed node using
v2 Transport, you can view logs related to v2
and peer=0
with the following:
cat $DATA_DIR_27/signet/debug.log | grep "v2\|peer=0"
cat $DATA_DIR_27/signet/debug.log | grep "v2\|peer=0"
2024-03-16T17:15:05Z Bitcoin Core version v27.0rc1 (release build)
2024-03-16T17:15:05Z [net] trying v2 connection bitcoin.achow101.com:38333 lastseen=0.0hrs
2024-03-16T17:15:05Z [net] Added connection peer=0
2024-03-16T17:15:05Z [net] sending version (102 bytes) peer=0
2024-03-16T17:15:05Z [net] send version message: version 70016, blocks=0, txrelay=1, peer=0
2024-03-16T17:15:05Z [net] start sending v2 handshake to peer=0
2024-03-16T17:15:05Z [net] received: version (103 bytes) peer=0
2024-03-16T17:15:05Z [net] sending wtxidrelay (0 bytes) peer=0
2024-03-16T17:15:05Z [net] sending sendaddrv2 (0 bytes) peer=0
2024-03-16T17:15:05Z [net] sending verack (0 bytes) peer=0
2024-03-16T17:15:05Z [net] sending getaddr (0 bytes) peer=0
2024-03-16T17:15:05Z [net] receive version message: /Satoshi:27.99.0/: version 70016, blocks=187042, us=76.151.248.21:49556, txrelay=1, peer=0
2024-03-16T17:15:05Z [net] received: wtxidrelay (0 bytes) peer=0
2024-03-16T17:15:05Z [net] received: sendaddrv2 (0 bytes) peer=0
2024-03-16T17:15:05Z [net] received: verack (0 bytes) peer=0
2024-03-16T17:15:05Z New addr-fetch v2 peer connected: version: 70016, blocks=187042, peer=0
2024-03-16T17:15:05Z [net] sending sendcmpct (9 bytes) peer=0
2024-03-16T17:15:05Z [net] sending ping (8 bytes) peer=0
2024-03-16T17:15:05Z [net] sending feefilter (8 bytes) peer=0
2024-03-16T17:15:05Z [net] received: sendcmpct (9 bytes) peer=0
2024-03-16T17:15:05Z [net] received: ping (8 bytes) peer=0
2024-03-16T17:15:05Z [net] sending pong (8 bytes) peer=0
2024-03-16T17:15:05Z [net] received: getheaders (965 bytes) peer=0
2024-03-16T17:15:05Z [net] Ignoring getheaders from peer=0 because active chain has too little work; sending empty response
2024-03-16T17:15:05Z [net] sending headers (1 bytes) peer=0
2024-03-16T17:15:05Z [net] received: feefilter (8 bytes) peer=0
2024-03-16T17:15:05Z [net] received: feefilter of 0.00001000 BTC/kvB from peer=0
2024-03-16T17:15:05Z [net] received: addrv2 (19582 bytes) peer=0
2024-03-16T17:15:05Z [net] Received addr: 999 addresses (999 processed, 0 rate-limited) from peer=0
2024-03-16T17:15:05Z [net] addrfetch connection completed peer=0; disconnecting
2024-03-16T17:15:06Z [net] disconnecting peer=0
2024-03-16T17:15:06Z [net] Cleared nodestate for peer=0
Some lines of note in the output from debug.log
:
-
trying v2 connection <peer host or ip>:38333
: We attempted to initiate the connection over v2. -
New addr-fetch v2 peer connected // [...] peer=0
: The v2 peer handshake has succeeded and we have connected to the seed node as anaddr-fetch
peer. -
Received addr: <number of addresses> from peer=0
: Our addrfetch peer has sent us anADDR
orADDRV2
message and we've processed it and are about to store in ouraddrman
. -
addrfetch connection complete peer=0
: We've stored the addresses we've received in ouraddrman
and are now disconnecting from theseednode
Now let's try to add a manual connection to a v2 capable peer and make sure that Bitcoin Core successfully makes a v2 connection to them.
☝ We can probably reuse the address or hostname we used as our
-seednode
since addrfetch connections are terminated once they've given us enough peers. If you decide to reuse the same v2 peer that you seeded from, usegetpeerinfo
to make sure they are not one of our curent connections, and if they are, usedisconnectnode
to drop them.
bcli addnode 74.208.205.30:38333 add
Check that our manual addnode
connection succeeded with getaddednodeinfo
:
bcli getaddednodeinfo
bcli getaddednodeinfo
[
{
"addednode": "74.208.205.30:38333",
"connected": true,
"addresses": [
{
"address": "74.208.205.30:38333",
"connected": "outbound"
}
]
}
]
Now verify that your connection to the added node is a v2 connection using getpeerinfo
:
bcli getpeerinfo
bcli getpeerinfo
{
"id": 18,
"addr": "<hostname/ip>:38333",
"servicesnames": [
"NETWORK",
"WITNESS",
"COMPACT_FILTERS",
"NETWORK_LIMITED",
"P2P_V2"
],
// [...]
"connection_type": "manual",
"transport_protocol_type": "v2",
"session_id": "92e0c037b75edf14d0e85032f5aedc8ff450e1b708bd03ceee38eef065dd5e87"
},
Once the test is successful, don't forget to stop your node, and reset your testing environment for the next test:
bcli stop
datadir-cleanup
If you are interested in learning more about v2 Transport, we encourage you to read BIP324 and the BIP324 tracking issue.
-netinfo
capability of a newer (e.g. v26) RPC client (bitcoin-cli) was broken when
communicating with an older node (e.g. v25). This PR fixes this, and displays "v1" for
the transport protocol used in the -netinfo
output.
First, let's configure our v25 regtest node so that it can run simultaneously with our v27 node:
echo "regtest=1" > $DATA_DIR_25/bitcoin.conf
echo "[regtest]" >> $DATA_DIR_25/bitcoin.conf
echo "rpcallowip=127.0.0.1" >> $DATA_DIR_25/bitcoin.conf
echo "rpcbind=127.0.0.1:18243" >> $DATA_DIR_25/bitcoin.conf
echo "rpcport=18243" >> $DATA_DIR_25/bitcoin.conf
echo "bind=127.0.0.1:18244" >> $DATA_DIR_25/bitcoin.conf
echo "bind=127.0.0.1:18245=onion" >> $DATA_DIR_25/bitcoin.conf
Start up our v25 regtest node:
bitcoind-test-25 -daemonwait
Start up our v27 regtest node:
echo "regtest=1" > $DATA_DIR_27/bitcoin.conf
bitcoind-test -daemonwait
Connect the two nodes:
bcli addnode 127.0.0.1:18244 add
Run netinfo
with the v27 RPC client calling the v27 node.
Verify that the v
column (transport version) is 1
(since this is a v1 connection).
bcli -netinfo 4
Run netinfo
with the v27 RPC client calling the v25 node.
Verify that the v
column (transport version) is 1
(since this is a v1 connection).
bcli -conf=$DATA_DIR_25/bitcoin.conf -rpccookiefile=$DATA_DIR_25/regtest/.cookie -netinfo 4
Once the test is successful, don't forget to stop your node, and reset your testing environment for the next test:
bcli stop
bcli25 stop
datadir-cleanup
This release includes part of v3 transaction policy support for testnets (not on Mainnet yet since they are still considered non-standard).
This policy is motivated by an effort to prevent pinning attacks. These attacks involve chaining child transactions onto a neutral parent to lower the average fee rate so as to make it unlikely to get accepted into a block, making it uneconomical or otherwise hard for the another party who depends on the transaction confirming soon (maybe to fulfill some L2 protocol constraints).
The new relay policy changes the rules for when transactions are allowed/blocked from entering the local mempool and relayed to peers. Previous rules allowed having up to 25 pending transaction ancestors/descendants in the mempool, and later added a special CPFP carve out rule. The new v3 policy only allows up to 2 related transactions - parent+child. This together with lower total transaction size limits should help make countering pinning-attempts more economically viable.
We will only be using the v27 node for this test.
Switch to regtest and start the node:
echo "regtest=1" > $DATA_DIR_27/bitcoin.conf
bitcoind-test -daemonwait
Create our wallet and generate 2 addresses:
bcli createwallet v3txwallet
address_a=$(bcli getnewaddress)
address_b=$(bcli getnewaddress)
Generate a regtest block paying the coinbase to our wallet:
bcli generatetoaddress 1 $address_a
Age our coinbase UTXO to make it spendable through generating 100 blocks.
bcli -generate 100
Confirm that we have a spendable transaction. (Your txid
, address
and scriptPubKey
will differ).
bcli listunspent
[
{
"txid": "fff75e2f62aad3e859c5b66d2c047b87291ce79a77193ba510b65363d82421d8",
"vout": 0,
"address": "bcrt1qddzc7pg8h3u7s4m5hvkm06pq4k64062c84p8sm",
"label": "",
"scriptPubKey": "00146b458f0507bc79e85774bb2db7e820adb557e958",
"amount": 50.00000000,
"confirmations": 101,
"spendable": true,
// ...
}
]
For the following tests we will be creating 3 chained transactions, to see how the mempool behaves when trying to submit them as v2 transactions vs v3 transactions.
Create our first transaction from the unspent coinbase UTXO, leaving a few sats on the table for the fee:
coinbase_txid=$(bcli listunspent | jq -r ".[0].txid")
parent_raw_tx=$(bcli createrawtransaction "[{\"txid\": \"$coinbase_txid\", \"vout\": 0}]" "[{\"$address_b\": 1},{\"$address_a\": 48.999}]")
echo $parent_raw_tx
0200000001d82124d86353b610a53b19779ae71c29877b042c6db6c559e8d3aa622f5ef7ff0000000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0608a0e24010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000
Sign our first transaction:
signed_parent_tx_result=$(bcli signrawtransactionwithwallet $parent_raw_tx)
echo $signed_parent_tx_result
{
"hex": "02000000000101d82124d86353b610a53b19779ae71c29877b042c6db6c559e8d3aa622f5ef7ff0000000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0608a0e24010000001600146b458f0507bc79e85774bb2db7e820adb557e9580247304402202ced690736814eb6b609105f53260e39026f28ec54f01865d457bfaa93487548022033a06d19ad715c035a62ad6c7b8760ec9f2dd8d79c6863219bdd05227d4fb96b012102fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa900000000",
"complete": true
}
Now decode the transaction to see txid
, outputs, scriptPubKey
, witness script (second hex blob in txinwitness
). We will need these when signing the child:
signed_parent_tx=$(echo $signed_parent_tx_result | jq -r .hex)
decoded_parent_tx=$(bcli decoderawtransaction $signed_parent_tx)
echo "$decoded_parent_tx"
{
"txid": "b6b81ebcdcc9e35e4d19ea03b66d24f9836483eb14ec9f0d16f1dc54b7c6ffbc",
"hash": "2381e183a8766e0caa59b10626113851737a560a306daac6d930d9f1e7efa20b",
"version": 2,
// ...
"vin": [
{
"txid": "fff75e2f62aad3e859c5b66d2c047b87291ce79a77193ba510b65363d82421d8",
"vout": 0,
// ...
"txinwitness": [
"304402202ced690736814eb6b609105f53260e39026f28ec54f01865d457bfaa93487548022033a06d19ad715c035a62ad6c7b8760ec9f2dd8d79c6863219bdd05227d4fb96b01",
"02fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa9"
]
}
],
"vout": [
{
"value": 1.00000000,
"n": 0,
// ...
},
{
"value": 48.99900000,
"n": 1,
"scriptPubKey": {
// ...
"hex": "00146b458f0507bc79e85774bb2db7e820adb557e958"
}
}
]
}
Create a child transaction spending the second output ("n": 1
) of 48.999 tBTC:
parent_txid=$(echo $decoded_parent_tx | jq -r .txid)
child_raw_tx=$(bcli createrawtransaction "[{\"txid\": \"$parent_txid\", \"vout\": 1}]" "[{\"$address_b\": 1},{\"$address_a\": 47.998}]")
echo $child_raw_tx
0200000001bcffc6b754dcf1160d9fec14eb836483f9246db603ea194d5ee3c9dcbc1eb8b60100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0c022171e010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000
Sign the child:
parent_spk=$(echo $decoded_parent_tx | jq -r ".vout[1].scriptPubKey.hex")
parent_witness_script=$(echo $decoded_parent_tx | jq -r ".vin[0].txinwitness[1]")
signed_child_tx_result=$(bcli signrawtransactionwithwallet $child_raw_tx "[{\"txid\":\"$parent_txid\", \"vout\": 1, \"scriptPubKey\": \"$parent_spk\", \"witnessScript\": \"$parent_witness_script\", \"amount\": 48.999}]")
signed_child_tx=$(echo $signed_child_tx_result | jq -r .hex)
echo "$signed_child_tx_result"
{
"hex": "02000000000101bcffc6b754dcf1160d9fec14eb836483f9246db603ea194d5ee3c9dcbc1eb8b60100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0c022171e010000001600146b458f0507bc79e85774bb2db7e820adb557e958024730440220049298a8593e99b8d91b2e9c1777fcb0fbf6c09c74cde5c8487cacf12d04e61902200c0da87edf9f88665a845cea1eda25d33d1bce1651266f697c2b0f0fe026846f012102fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa900000000",
"complete": true
}
Decode the child to see txid
, outputs, scriptPubKey
, witness script:
decoded_child_tx=$(bcli decoderawtransaction $signed_child_tx)
echo "$decoded_child_tx"
{
"txid": "cf177c1070c81b292cd94537c2a66b54cb4b63f3b1fe7d36bb9c24b4d33c4206",
// ...
"version": 2,
// ...
"vin": [
{
"txid": "b6b81ebcdcc9e35e4d19ea03b66d24f9836483eb14ec9f0d16f1dc54b7c6ffbc",
"vout": 1,
// ...
"txinwitness": [
"30440220049298a8593e99b8d91b2e9c1777fcb0fbf6c09c74cde5c8487cacf12d04e61902200c0da87edf9f88665a845cea1eda25d33d1bce1651266f697c2b0f0fe026846f01",
"02fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa9"
]
}
],
"vout": [
{
"value": 1.00000000,
"n": 0,
// ...
},
{
"value": 47.99800000,
"n": 1,
"scriptPubKey": {
// ...
"hex": "00146b458f0507bc79e85774bb2db7e820adb557e958"
}
}
]
}
Create a grandchild transaction:
child_txid=$(echo $decoded_child_tx | jq -r .txid)
child_spk=$(echo $decoded_child_tx | jq -r ".vout[1].scriptPubKey.hex")
child_witness_script=$(echo $decoded_child_tx | jq -r ".vin[0].txinwitness[1]")
grandchild_raw_tx=$(bcli createrawtransaction "[{\"txid\": \"$child_txid\", \"vout\": 1}]" "[{\"$address_b\": 1},{\"$address_a\": 46.997}]")
echo $grandchild_raw_tx
020000000106423cd3b4249cbb367dfeb1f3634bcb546ba6c23745d92c291bc870107c17cf0100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d020bb1f18010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000
Sign the grandchild:
signed_grandchild_tx_result=$(bcli signrawtransactionwithwallet $grandchild_raw_tx "[{\"txid\":\"$child_txid\", \"vout\": 1, \"scriptPubKey\": \"$child_spk\", \"witnessScript\": \"$child_witness_script\", \"amount\": 47.998}]")
signed_grandchild_tx=$(echo $signed_grandchild_tx_result | jq -r .hex)
echo "$signed_grandchild_tx_result"
{
"hex": "0200000000010106423cd3b4249cbb367dfeb1f3634bcb546ba6c23745d92c291bc870107c17cf0100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d020bb1f18010000001600146b458f0507bc79e85774bb2db7e820adb557e95802473044022071b22ccef6bf40eb04bc43271c272ed0bf75d3b5cdf61a7778d643f3629eebc702204edeb3eac993ee3973a174f8dda0537d5c37f76d67a0b3a394b70d92153697b8012102fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa900000000",
"complete": true
}
See if the mempool would accept all 3 together:
bcli testmempoolaccept "[\"$signed_parent_tx\",\"$signed_child_tx\",\"$signed_grandchild_tx\"]"
[
{
"txid": "b6b81ebcdcc9e35e4d19ea03b66d24f9836483eb14ec9f0d16f1dc54b7c6ffbc",
"wtxid": "2381e183a8766e0caa59b10626113851737a560a306daac6d930d9f1e7efa20b",
"allowed": true,
"vsize": 141,
"fees": {
"base": 0.00100000,
"effective-feerate": 0.00709219,
"effective-includes": [
"2381e183a8766e0caa59b10626113851737a560a306daac6d930d9f1e7efa20b"
]
}
},
{
"txid": "cf177c1070c81b292cd94537c2a66b54cb4b63f3b1fe7d36bb9c24b4d33c4206",
"wtxid": "25f4049612ae54b71fa799dffe696bc0f86bafdecfed6efa6a7a366817d91ddb",
"allowed": true,
"vsize": 141,
"fees": {
"base": 0.00100000,
"effective-feerate": 0.00709219,
"effective-includes": [
"25f4049612ae54b71fa799dffe696bc0f86bafdecfed6efa6a7a366817d91ddb"
]
}
},
{
"txid": "a6734c9721960da6fe538d65919b09a0bfbaa6c96c29c66cb634029c07336ede",
"wtxid": "41af8505f072023992b62c3727d2142b76a67c3ca6de732c435cf41624b5789c",
"allowed": true,
"vsize": 141,
"fees": {
"base": 0.00100000,
"effective-feerate": 0.00709219,
"effective-includes": [
"41af8505f072023992b62c3727d2142b76a67c3ca6de732c435cf41624b5789c"
]
}
}
]
This shows that 3 chained v2 transactions would be accepted into the mempool.
Now we are going to do the same thing but for v3 transactions.
Take the first createrawtransaction
result...
echo $parent_raw_tx
0200000001d82124d86353b610a53b19779ae71c29877b042c6db6c559e8d3aa622f5ef7ff0000000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0608a0e24010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000
...but edit the initial version from being little endian 2 - 02000000
, to 3 - 03000000
, and sign it:
v3_parent_signed_tx_result=$(bcli signrawtransactionwithwallet 0300000001d82124d86353b610a53b19779ae71c29877b042c6db6c559e8d3aa622f5ef7ff0000000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0608a0e24010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000)
v3_parent_signed_tx=$(echo $v3_parent_signed_tx_result | jq -r .hex)
echo "$v3_parent_signed_tx_result"
{
"hex": "03000000000101d82124d86353b610a53b19779ae71c29877b042c6db6c559e8d3aa622f5ef7ff0000000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0608a0e24010000001600146b458f0507bc79e85774bb2db7e820adb557e958024730440220119e8a137e023990c5deeef0d64483c0832c9f7d84e78bac8f8d5706cc2c57d202206ab3b45535c12ae99b9f88cc8b6b217eaad37ab818a0f509e82ce723593ab2a4012102fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa900000000",
"complete": true
}
The modified version results in a different txid.
See if it will be accepted into the mempool:
bcli testmempoolaccept "[\"$v3_parent_signed_tx\"]"
[
{
"txid": "893803395981efb80af450a5958587e1c54d03e44149a8ff7ec1dd54955eee84",
"wtxid": "d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa",
"allowed": false,
"reject-reason": "version"
}
]
What happened?!
v3 transactions are still treated as non-standard, but we are able to enable them on regtest. Let's do that:
bcli stop
bitcoind-test -daemonwait -acceptnonstdtxn
Reload the wallet:
bcli loadwallet v3txwallet
Retry:
bcli testmempoolaccept "[\"$v3_parent_signed_tx\"]"
[
{
"txid": "893803395981efb80af450a5958587e1c54d03e44149a8ff7ec1dd54955eee84",
"wtxid": "d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa",
"allowed": true,
"vsize": 141,
"fees": {
"base": 0.00100000,
"effective-feerate": 0.00709219,
"effective-includes": [
"d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa"
]
}
}
]
Woho, our regtest mempool now accepts v3!
Time to grab the tx details for our new child:
decoded_v3_parent_tx=$(bcli decoderawtransaction $v3_parent_signed_tx)
echo "$decoded_v3_parent_tx"
{
"txid": "893803395981efb80af450a5958587e1c54d03e44149a8ff7ec1dd54955eee84",
// ...
"version": 3,
// ...
"vin": [
{
"txid": "fff75e2f62aad3e859c5b66d2c047b87291ce79a77193ba510b65363d82421d8",
"vout": 0,
// ...
"txinwitness": [
"30440220119e8a137e023990c5deeef0d64483c0832c9f7d84e78bac8f8d5706cc2c57d202206ab3b45535c12ae99b9f88cc8b6b217eaad37ab818a0f509e82ce723593ab2a401",
"02fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa9"
]
}
],
"vout": [
{
"value": 1.00000000,
"n": 0,
// ...
},
{
"value": 48.99900000,
"n": 1,
"scriptPubKey": {
// ...
"hex": "00146b458f0507bc79e85774bb2db7e820adb557e958"
}
}
]
}
Create the v3 child transaction:
v3_parent_txid=$(echo $decoded_v3_parent_tx | jq -r .txid)
v3_parent_spk=$(echo $decoded_v3_parent_tx | jq -r ".vout[1].scriptPubKey.hex")
v3_parent_witness_script=$(echo $decoded_v3_parent_tx | jq -r ".vin[0].txinwitness[1]")
bcli createrawtransaction "[{\"txid\": \"$v3_parent_txid\", \"vout\": 1}]" "[{\"$address_b\": 1},{\"$address_a\": 47.998}]"
020000000184ee5e9554ddc17effa84941e4034dc5e1878595a550f40ab8ef8159390338890100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0c022171e010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000
Tweak the version again and sign:
v3_child_signed_tx_result=$(bcli signrawtransactionwithwallet 030000000184ee5e9554ddc17effa84941e4034dc5e1878595a550f40ab8ef8159390338890100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0c022171e010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000 "[{\"txid\":\"$v3_parent_txid\", \"vout\": 1, \"scriptPubKey\": \"$v3_parent_spk\", \"witnessScript\": \"$v3_parent_witness_script\", \"amount\": 48.999}]")
v3_child_signed_tx=$(echo $v3_child_signed_tx_result | jq -r .hex)
echo "$v3_child_signed_tx_result"
{
"hex": "0300000000010184ee5e9554ddc17effa84941e4034dc5e1878595a550f40ab8ef8159390338890100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0c022171e010000001600146b458f0507bc79e85774bb2db7e820adb557e9580247304402203db6610092c1f7bbc38b232ddd0bed0ad5f2cffc245517a53c3bb856cf9aea8e0220707f18fbfa6fcdb4860d6d92721c8e2d243cabbba0045dcf14955b634c0b652b012102fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa900000000",
"complete": true
}
Decode it for the grandchild:
decoded_v3_child_tx=$(bcli decoderawtransaction $v3_child_signed_tx)
echo "$decoded_v3_child_tx"
{
"txid": "863889eecf327d63c164e5689bf77924ef8b573cfd699120e3a0eeb2da4463d8",
// ...
"version": 3,
// ...
"vin": [
{
"txid": "893803395981efb80af450a5958587e1c54d03e44149a8ff7ec1dd54955eee84",
"vout": 1,
// ...
"txinwitness": [
"304402203db6610092c1f7bbc38b232ddd0bed0ad5f2cffc245517a53c3bb856cf9aea8e0220707f18fbfa6fcdb4860d6d92721c8e2d243cabbba0045dcf14955b634c0b652b01",
"02fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa9"
],
"sequence": 4294967293
}
],
"vout": [
{
"value": 1.00000000,
"n": 0,
// ...
},
{
"value": 47.99800000,
"n": 1,
"scriptPubKey": {
// ...
"hex": "00146b458f0507bc79e85774bb2db7e820adb557e958"
}
}
]
}
Create v3 grandchild transaction:
v3_child_txid=$(echo $decoded_v3_child_tx | jq -r .txid)
v3_child_spk=$(echo $decoded_v3_child_tx | jq -r ".vout[1].scriptPubKey.hex")
v3_child_witness_script=$(echo $decoded_v3_child_tx | jq -r ".vin[0].txinwitness[1]")
bcli createrawtransaction "[{\"txid\": \"$v3_child_txid\", \"vout\": 1}]" "[{\"$address_b\": 1},{\"$address_a\": 46.997}]"
0200000001d86344dab2eea0e3209169fd3c578bef2479f79b68e564c1637d32cfee8938860100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d020bb1f18010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000
Tweak version and sign:
v3_grandchild_signed_tx_result=$(bcli signrawtransactionwithwallet 0300000001d86344dab2eea0e3209169fd3c578bef2479f79b68e564c1637d32cfee8938860100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d020bb1f18010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000 "[{\"txid\":\"$v3_child_txid\", \"vout\": 1, \"scriptPubKey\": \"$v3_child_spk\", \"witnessScript\": \"$v3_child_witness_script\", \"amount\": 47.998}]")
v3_grandchild_signed_tx=$(echo $v3_grandchild_signed_tx_result | jq -r .hex)
echo "$v3_grandchild_signed_tx_result"
{
"hex": "03000000000101d86344dab2eea0e3209169fd3c578bef2479f79b68e564c1637d32cfee8938860100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d020bb1f18010000001600146b458f0507bc79e85774bb2db7e820adb557e9580247304402206b91fc223fe2ec13929bd39dea494997bf8bd85092c0119697f96d18070c6f1d0220157fe6e6885dc988fd6cee9ed13397da95d977ac017bdf5607c8d4f7b76bf338012102fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa900000000",
"complete": true
}
See whether our mempool will accept all 3 together:
bcli testmempoolaccept "[\"$v3_parent_signed_tx\",\"$v3_child_signed_tx\",\"$v3_grandchild_signed_tx\"]"
[
{
"txid": "893803395981efb80af450a5958587e1c54d03e44149a8ff7ec1dd54955eee84",
"wtxid": "d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa",
"package-error": "v3-violation, tx 1a46bb68edb4808bc3122d59f0aa9f43d350fc5d311986ff630d2ad89504c74a (wtxid=db1c0c79bf895a2e7810819ce15a53d0d42e25832357590d83084d1004c104d4) would have too many ancestors"
},
{
"txid": "863889eecf327d63c164e5689bf77924ef8b573cfd699120e3a0eeb2da4463d8",
"wtxid": "9754824e40a51f617aa3b0e7611e1229b7094894619cd948d8597202491add81",
"package-error": "v3-violation, tx 1a46bb68edb4808bc3122d59f0aa9f43d350fc5d311986ff630d2ad89504c74a (wtxid=db1c0c79bf895a2e7810819ce15a53d0d42e25832357590d83084d1004c104d4) would have too many ancestors"
},
{
"txid": "1a46bb68edb4808bc3122d59f0aa9f43d350fc5d311986ff630d2ad89504c74a",
"wtxid": "db1c0c79bf895a2e7810819ce15a53d0d42e25832357590d83084d1004c104d4",
"package-error": "v3-violation, tx 1a46bb68edb4808bc3122d59f0aa9f43d350fc5d311986ff630d2ad89504c74a (wtxid=db1c0c79bf895a2e7810819ce15a53d0d42e25832357590d83084d1004c104d4) would have too many ancestors"
}
]
No cigar. Let's try with just the first 2:
bcli testmempoolaccept "[\"$v3_parent_signed_tx\",\"$v3_child_signed_tx\"]"
[
{
"txid": "893803395981efb80af450a5958587e1c54d03e44149a8ff7ec1dd54955eee84",
"wtxid": "d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa",
"allowed": true,
"vsize": 141,
"fees": {
"base": 0.00100000,
"effective-feerate": 0.00709219,
"effective-includes": [
"d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa"
]
}
},
{
"txid": "863889eecf327d63c164e5689bf77924ef8b573cfd699120e3a0eeb2da4463d8",
"wtxid": "9754824e40a51f617aa3b0e7611e1229b7094894619cd948d8597202491add81",
"allowed": true,
"vsize": 141,
"fees": {
"base": 0.00100000,
"effective-feerate": 0.00709219,
"effective-includes": [
"9754824e40a51f617aa3b0e7611e1229b7094894619cd948d8597202491add81"
]
}
}
]
Good, the v3 transaction policy only allows for 2 connected pending transactions in the mempool.
Let's see if we are able to RBF the child. First, let us submit the transactions to our mempool:
bcli submitpackage "[\"$v3_parent_signed_tx\",\"$v3_child_signed_tx\"]"
{
"package_msg": "success",
"tx-results": {
"d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa": {
"txid": "893803395981efb80af450a5958587e1c54d03e44149a8ff7ec1dd54955eee84",
"vsize": 141,
"fees": {
"base": 0.00100000,
"effective-feerate": 0.00709219,
"effective-includes": [
"d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa"
]
}
},
"9754824e40a51f617aa3b0e7611e1229b7094894619cd948d8597202491add81": {
"txid": "863889eecf327d63c164e5689bf77924ef8b573cfd699120e3a0eeb2da4463d8",
"vsize": 141,
"fees": {
"base": 0.00100000,
"effective-feerate": 0.00709219,
"effective-includes": [
"9754824e40a51f617aa3b0e7611e1229b7094894619cd948d8597202491add81"
]
}
}
},
"replaced-transactions": [
]
}
Create a new version of the child paying higher fees:
bcli createrawtransaction "[{\"txid\": \"$v3_parent_txid\", \"vout\": 1}]" "[{\"$address_b\": 1},{\"$address_a\": 47.997}]"
020000000184ee5e9554ddc17effa84941e4034dc5e1878595a550f40ab8ef8159390338890100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0209c151e010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000
Tweak to v3 and sign:
high_fee_child_signed_tx_result=$(bcli signrawtransactionwithwallet 030000000184ee5e9554ddc17effa84941e4034dc5e1878595a550f40ab8ef8159390338890100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0209c151e010000001600146b458f0507bc79e85774bb2db7e820adb557e95800000000 "[{\"txid\":\"$v3_parent_txid\", \"vout\": 1, \"scriptPubKey\": \"$v3_parent_spk\", \"witnessScript\": \"$v3_parent_witness_script\", \"amount\": 48.999}]")
high_fee_child_signed_tx=$(echo $high_fee_child_signed_tx_result | jq -r .hex)
echo "$high_fee_child_signed_tx_result"
{
"hex": "0300000000010184ee5e9554ddc17effa84941e4034dc5e1878595a550f40ab8ef8159390338890100000000fdffffff0200e1f50500000000160014623affcf6334d7e50a9757b80f702e4129aa02d0209c151e010000001600146b458f0507bc79e85774bb2db7e820adb557e958024730440220011d8df0b2615bcd6506b81f799544188538f7a43f9cb0f45fea9db6915258f102204b7d190d63b9d4e1bdb7bb3654215b9c74dfd8a2046421fb797279d325d27568012102fa562c1af027c39ee03a9892b388f854904c99fbf80b77f69aba3f48305f2aa900000000",
"complete": true
}
Submit the replacement child together with the parent:
bcli submitpackage "[\"$v3_parent_signed_tx\",\"$high_fee_child_signed_tx\"]"
{
"package_msg": "success",
"tx-results": {
"d5ef8955a5b7d0d2a865690156354a98602b7aaca3133b4685b596bafdcf04aa": {
"txid": "893803395981efb80af450a5958587e1c54d03e44149a8ff7ec1dd54955eee84",
"vsize": 141,
"fees": {
"base": 0.00100000
}
},
"10b7cd4b26ef17eaaa8c6844334675a55ee7ebaa7eafe8feefc1eb4b640216c8": {
"txid": "598fb5e9b7909cdf7c03910864ff396dffa1e2e8f03096c5f538267f13074598",
"vsize": 141,
"fees": {
"base": 0.00200000,
"effective-feerate": 0.01418439,
"effective-includes": [
"10b7cd4b26ef17eaaa8c6844334675a55ee7ebaa7eafe8feefc1eb4b640216c8"
]
}
}
},
"replaced-transactions": [
"863889eecf327d63c164e5689bf77924ef8b573cfd699120e3a0eeb2da4463d8"
]
}
Once the test is successful, don't forget to stop your node, and reset your testing environment for the next test:
bcli stop
datadir-cleanup
Note: v3 sibling eviction (#29306) is currently not included as of v27.0rc1.
There are a bunch of cases that we haven't tested above. Like mixing v3 with confirmed and unconfirmed non-v3 transactions. See version3_transactions.md and mempool_accept_v3.py for further test ideas.
Bitcoin Core 27.0 includes a new coin selection algorithm called CoinGrinder. The goal of this algorithm is to minimize the total weight of the inputs when constructing a transaction with change in a high feerate environment. Previously, there have been issues where a ton of small inputs were used in a transaction even when there was a single UTXO that would have sufficed, resulting in an unnecessarily high transaction fee. Currently, CoinGrinder is only used when the feerate is greater than 3*long_term_feerate
(3 x 10 sats/vb by default).
For this test, we will simulate the situation described in the link above, configuring a wallet to contain many small utxos and one larger utxo and then seeing whether input set weight is minimized when a transaction is constructed in a high fee environment.
First, make sure your data directories are clean. Then start up a v27 node on regtest.
echo "regtest=1" > $DATA_DIR_27/bitcoin.conf
bitcoind-test -daemonwait
Create two wallets. One will be used to receive block rewards and to fund the other one, which will be configured with a certain set of UTXOs (bunch of small, one big).
bcli createwallet coinbasewallet
bcli createwallet testwallet
Mine blocks so that our coinbase UTXO is spendable.
bcli -rpcwallet=coinbasewallet generatetoaddress 101 $(bcli -rpcwallet=coinbasewallet getnewaddress)
Now, we'll send 200 UTXOs of 0.003 tBTC to our test wallet. We send them in 10 batches of 20 transactions, mining a block in between to confirm each batch.
num_batches=10
tx_per_batch=20
for batch in $(seq 1 $num_batches); do
echo "Creating batch $batch of $tx_per_batch transactions..."
for tx in $(seq 1 $tx_per_batch); do
bcli -named -rpcwallet=coinbasewallet sendtoaddress address=$(bcli -rpcwallet=testwallet getnewaddress) amount=0.003 fee_rate=15
done
echo "Generating 1 block to confirm the batch..."
bcli -rpcwallet=coinbasewallet generatetoaddress 1 $(bcli -rpcwallet=coinbasewallet getnewaddress)
done
Use this command to see the 0.003 UTXOs:
bcli -rpcwallet=testwallet listunspent
Send one UTXO of 0.5 tBTC to our test wallet. This will output a transaction hash, which will be important for later so be sure to save it. Your hash will be different than the one shown below.
bcli -rpcwallet=coinbasewallet -named sendtoaddress address=$(bcli -rpcwallet=testwallet getnewaddress) amount=0.5 fee_rate=15
2254455264eb3e6e02471594f4eebe9c140de9c09074e6a52485f4de4fa0936d
Mine 6 blocks to ensure CoinGrinder is used. Coin selection takes number of confirmations into account, so we need all UTXOs in our test wallet to have at least 6 confirmations.
bcli -rpcwallet=coinbasewallet generatetoaddress 6 $(bcli -rpcwallet=coinbasewallet getnewaddress)
Use this command to confirm that there is an unspent transaction worth 0.5 tBTC available in the test wallet. Make sure to have jq
installed.
bcli -rpcwallet=testwallet listunspent | jq '.[] | select(.amount == 0.5)'
The output should look something like this:
{
"txid": "2254455264eb3e6e02471594f4eebe9c140de9c09074e6a52485f4de4fa0936d",
"vout": 1,
"address": "bcrt1qy5u5fwdccrrzs4uxvattzqdqtaa4n0n4ys5a6s",
"label": "",
"scriptPubKey": "0014253944b9b8c0c62857866756b101a05f7b59be75",
"amount": 0.50000000,
"confirmations": 6,
"spendable": true,
"solvable": true,
"desc": "wpkh([3e076eb4/84h/1h/0h/0/200]03ffe1a4c98b32e1bc92a6dc274ede70db57a8636d2d88e5160c71b855c47e3852)#2jf4twkm",
"parent_descs": [
"wpkh(tpubD6NzVbkrYhZ4Y5fXoTkdAoaUGD9SdbXu5wz9tfVf6LSF4x7pnBww3LSQRy2RzUhGvujYj12Sw8CVo1cRYM18oLdyzazc3DqwnUSBZzj4wMB/84h/1h/0h/0/*)#w6awyanv"
],
"safe": true
}
Finally, we send our test transaction. We'll send 0.47 tBTC from our test wallet so that either the UTXO of 0.5 tBTC is used or multiple 0.003 UTXOs are used. Be sure that fee_rate
is set to above 30 sats/vb in order for CoinGrinder to be used. This command should output a transaction hash, like the one shown below. Your hash will be different.
bcli -rpcwallet=testwallet -named sendtoaddress address=$(bcli -rpcwallet=coinbasewallet getnewaddress) amount=0.47 fee_rate=31
7bb3bfceadce62cbe5da379975bca01e26675e576883773333a2f1baaf0e3206
To check that only the 0.5 UTXO was used in the transaction, run
bcli getrawtransaction 7bb3bfceadce62cbe5da379975bca01e26675e576883773333a2f1baaf0e3206 true
using the hash you got from the test transaction. The output should look something like this:
{
"txid": "7bb3bfceadce62cbe5da379975bca01e26675e576883773333a2f1baaf0e3206",
"hash": "99dfd8043440914cdcf9d39dfd43309de692a2204dd1cf8f15afae5faebdf72d",
"version": 2,
"size": 222,
"vsize": 141,
"weight": 561,
"locktime": 117,
"vin": [
{
"txid": "2254455264eb3e6e02471594f4eebe9c140de9c09074e6a52485f4de4fa0936d",
"vout": 1,
"scriptSig": {
"asm": "",
"hex": ""
},
"txinwitness": [
"30440220023fae967610f77c8088b70c71907b1a3c8bb391896b32b5511a614e5210676e02203ec5a6b383b8ca3faf0bfda4cdaaae461ed8ff3c38768e414a06958c371182fd01",
"03ffe1a4c98b32e1bc92a6dc274ede70db57a8636d2d88e5160c71b855c47e3852"
],
"sequence": 4294967293
}
],
"vout": [
{
"value": 0.47000000,
"n": 0,
"scriptPubKey": {
"asm": "0 05607b74c06528cdb9a887a9ae67ce1ef6f65f26",
"desc": "addr(bcrt1qq4s8kaxqv55vmwdgs756ue7wrmm0vhex567xe0)#sxeyrgqv",
"hex": "001405607b74c06528cdb9a887a9ae67ce1ef6f65f26",
"address": "bcrt1qq4s8kaxqv55vmwdgs756ue7wrmm0vhex567xe0",
"type": "witness_v0_keyhash"
}
},
{
"value": 0.02995629,
"n": 1,
"scriptPubKey": {
"asm": "0 60db6f5dc994ac3e40b6c916c6819e2354bbe21a",
"desc": "addr(bcrt1qvrdk7hwfjjkrus9keytvdqv7yd2thcs6aa2eew)#jr9t8fwp",
"hex": "001460db6f5dc994ac3e40b6c916c6819e2354bbe21a",
"address": "bcrt1qvrdk7hwfjjkrus9keytvdqv7yd2thcs6aa2eew",
"type": "witness_v0_keyhash"
}
}
],
"hex": "020000000001016d93a04fdef48524a5e67490c0e90d149cbeeef4941547026e3eeb64524554220100000000fdffffff02c029cd020000000016001405607b74c06528cdb9a887a9ae67ce1ef6f65f26adb52d000000000016001460db6f5dc994ac3e40b6c916c6819e2354bbe21a024730440220023fae967610f77c8088b70c71907b1a3c8bb391896b32b5511a614e5210676e02203ec5a6b383b8ca3faf0bfda4cdaaae461ed8ff3c38768e414a06958c371182fd012103ffe1a4c98b32e1bc92a6dc274ede70db57a8636d2d88e5160c71b855c47e385275000000"
}
Notice in the vin
section that there is only one input used and that the txid
in that section (2254455264eb3e6e02471594f4eebe9c140de9c09074e6a52485f4de4fa0936d
in this specific case) is the same hash as the hash we saved from the step above. If we run the getrawtransaction
command with the saved hash, we'll see that one of its outpoint values is 0.5. This means that the 0.5 UTXO was the only one selected and that the weight of the inputs was minimized for the test transaction, confirming that the CoinGrinder algorithm was used.
If we were to run these same steps but set the test transaction fee rate to 30 sats/vb or less, we'd notice that a lot more inputs are selected from the test wallet to send 0.47 tBTC. The raw transaction will be a lot larger (therefore paying a lot higher of a transaction fee) than the one created above when CoinGrinder was activated in the high fee environment (>30 sats/vb).
This test is by no means comprehensive, but it should provide a baseline for further testing on regtest with the CoinGrinder algorithm.
Once finished with CoinGrinder testing, stop the node
bcli stop
and clean up the data directories.
datadir-cleanup
⚠ This test requires that Bitcoin Core be built with
bdb
support. If you are building the release candidate from source, refer to your platform's build instructions for details on building withbdb
. Binary releases are built withbdb
and legacy wallet support by default.
First added in Bitcoin Core v24.0, the
migratewallet
RPC is no longer
experimental in Bitcoin Core v27. This
change is part of the long road to deprecating legacy wallets and BDB in Bitcoin Core. At
some point, maybe in v29.0, support for Legacy Wallets and BDB may be completely
removed from Bitcoin Core, and the only
path forward for legacy wallet users will be to use the migratewallet
RPC or to migrate
their wallets using the Bitcoin Core GUI. More information about the timeline for
deprecating BDB and Legacy Wallets can be found in issue
#20160.
First, let's start up a node on the regtest network with the deprecatedrpc=create_bdb
flag set so that Bitcoin Core doesn't complain when we try to create a legacy wallet:
{
echo "regtest=1"
echo "deprecatedrpc=create_bdb"
} > $DATA_DIR_27/bitcoin.conf
bitcoind-test -daemonwait
Now let's create the legacy wallet we will use later in this test.
bcli -named createwallet wallet_name=legacy_wallet descriptors=false
bcli -named createwallet wallet_name=legacy_wallet descriptors=false
{
"name": "legacy",
"warnings": [
"Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future."
]
}
Let's create an alias for using the wallet with future RPC commands:
alias wallet="bcli -rpcwallet=legacy_wallet"
Let's also create a 'helper' wallet and alias that will come in handy later on:
bcli -named createwallet wallet_name=helper_wallet descriptors=false
alias helper="bcli -rpcwallet=helper_wallet"
Let's make one of each kind of receive address supported by the legacy wallet and fund each with a coinbase reward.
legacy_receive=$(wallet getnewaddress "my-P2PKH" legacy)
bcli generatetoaddress 1 "$legacy_receive"
p2sh_segwit_receive=$(wallet getnewaddress "my-P2SH(P2WPKH)" p2sh-segwit)
bcli generatetoaddress 1 "$p2sh_segwit_receive"
bech32_receive=$(wallet getnewaddress "my-P2WPKH" bech32)
bcli generatetoaddress 1 "$bech32_receive"
Coinbase rewards cannot be spent until they are 100 blocks old.
helper -generate 100
For wallets containing non-HD keys, each key will have its own combo descriptor.
To test for this behavior, we will use the helper wallet to export a one-off key for our legacy wallet to import.
non_hd_address=$(helper getnewaddress)
non_hd_key=$(helper dumpprivkey $non_hd_address)
wallet importprivkey $non_hd_key "non-hd"
Let's send our one-off address some coin:
wallet -named send outputs="{\"$non_hd_address\": 1}" fee_rate=10
wallet -named send outputs="{\"$non_hd_address\": 1}" fee_rate=10
{
"txid": "{32-byte-txid}",
"complete": true
}
Because descriptor wallets do not support having both private keys and watch-only scripts, there may be up to two additional wallets created after migration. The one that contains all of the watchonly scripts will be named _watchonly.
☝ Legacy wallets allow for addresses with private keys and watch-only addresses to mix together because it used to not be possible to have different wallet files for different purposes. Multiwallet is relatively recent. Discussion here: https://bitcoincore.reviews/19602#l-96
To test for this behavior, we will use the helper wallet.
watch_address=$(helper getnewaddress)
wallet importaddress $watch_address "watch_address"
Solvable scripts are any scripts for which we have the public key, and which the Bitcoin Core wallet has enough information to spend. For example, a 1-of-2 multisig P2(W)SH address, where we know the redeem script and one of the private keys. Because the user can spend the corresponding P2(W)SH scripts they are placed in an additional wallet named <wallet_name>_solvables.
☝ The solvables wallet can update a PSBT with the UTXO, scripts, and pubkeys, for inputs that spend any of the scripts it contains since it backs up the redeem script.
To test for this behavior, we will again use the helper-wallet to create a multisig with some keys that do not belong to this wallet.
not_my_address=$(helper getnewaddress)
not_my_pubkey=$(helper getaddressinfo $not_my_address | jq -r ".pubkey")
my_address=$(wallet getnewaddress)
multisig_address=$(wallet addmultisigaddress 1 '''["'$my_address'", "'$not_my_pubkey'"]''' "multisig" | jq -r ".address")
Before migrating, let's use the getwalletinfo
and getaddressinfo
RPC's to observe how our wallet understands our
newly created addresses.
Take note of the 'format' (bdb), 'descriptors' (true), and
balance
values in the output of getwalletinfo
.
wallet getwalletinfo
wallet getwalletinfo
{
"walletname": "legacy_wallet",
"walletversion": 169900,
"format": "bdb",
"balance": 149.99997810,
"unconfirmed_balance": 0.00000000,
"immature_balance": 0.00000000,
"txcount": 4,
"keypoololdest": 1711381628,
"keypoolsize": 999,
"hdseedid": "68070250fe5ded18d944a9e0baeb07989755f9aa",
"keypoolsize_hd_internal": 1000,
"paytxfee": 0.00000000,
"private_keys_enabled": true,
"avoid_reuse": false,
"scanning": false,
"descriptors": false,
"external_signer": false,
"blank": false,
"birthtime": 1,
"lastprocessedblock": {
"hash": "63321203c9276d117a6b8bbc6da1170270a9e5543d320e60698c377f7a143488",
"height": 103
}
}
☝ Run the following commands one at a time and inspect the output, giving extra attention to the values of
ismine
,solvable
,iswatchonly
, andlabels
.
wallet getaddressinfo $legacy_receive
wallet getaddressinfo $p2sh_segwit_receive
wallet getaddressinfo $bech32_receive
wallet getaddressinfo $non_hd_address
wallet getaddressinfo $watch_address
wallet getaddressinfo $multisig_address
Now, let's run the migration (it may take a few moments):
bcli migratewallet legacy_wallet
If you followed all the steps, at the end of the migration you should see something like:
{
"wallet_name": "legacy_wallet",
"watchonly_name": "legacy_wallet_watchonly",
"solvables_name": "legacy__wallet_solvables",
"backup_path": "/tmp/27-rc-test/regtest/wallets/legacy_wallet/legacy_wallet-1710977436.legacy.bak"
}
Now let's restart our node.
bcli stop
bitcoind-test -daemonwait
And load our wallet:
bcli loadwallet legacy_wallet
And verify that our legacy wallets have been migrated:
bcli listwallets
bcli listwallets
[
"legacy_wallet_watchonly",
"legacy_wallet_solvables",
"legacy_wallet"
]
Let's run getwalletinfo
and compare it's output to what we got before the migration:
wallet getwalletinfo
wallet getwalletinfo
{
"walletname": "legacy_wallet",
"walletversion": 169900,
"format": "sqlite",
"balance": 149.99997810,
"unconfirmed_balance": 0.00000000,
"immature_balance": 0.00000000,
"txcount": 4,
"keypoolsize": 4000,
"keypoolsize_hd_internal": 4000,
"paytxfee": 0.00000000,
"private_keys_enabled": true,
"avoid_reuse": false,
"scanning": false,
"descriptors": true,
"external_signer": false,
"blank": false,
"birthtime": 0,
"lastprocessedblock": {
"hash": "63321203c9276d117a6b8bbc6da1170270a9e5543d320e60698c377f7a143488",
"height": 103
}
}
The 'format' value should now be 'sqlite', and 'descriptors' should be true.
Let's now see what getaddressinfo
reports for each of our receive addresses:
wallet getaddressinfo $legacy_receive
wallet getaddressinfo $p2sh_segwit_receive
wallet getaddressinfo $bech32_receive
wallet getaddressinfo $non_hd_address
wallet getaddressinfo $watch_address
wallet getaddressinfo $multisig_address
Here's an example with the expected differences between
wallet getaddressinfo $legacy_receive
before and after migration
highlighted :
{
"address": "mhU5hTx7kEMN6msDvBJw4bk5fDkgEtMF4M",
"scriptPubKey": "76a91415652f1654156e309d987ab3c4f7c6fc5040943488ac",
"ismine": true,
"solvable": true,
"desc": "pkh([8a98783b/0h/0h/0h]02b8f17f42dad2151b7304df808699813579c08dd6deda647a4153bb3af5ddb6b6)#ahcte5wq",
+ "parent_desc": "combo(tpubD6NzVbkrYhZ4WZoqNF6UHicVrFYT4Zb5ApP7oGCrA9utxDi1gxmhJncPCC7KFBUyZHA6LvSQSfAYsVCD2qXrr4TggNcgHnooTXSoq8gqCjL/0h/0h/*h)#lgzh23ul",
"iswatchonly": false,
"isscript": false,
"iswitness": false,
"pubkey": "02b8f17f42dad2151b7304df808699813579c08dd6deda647a4153bb3af5ddb6b6",
"iscompressed": true,
"ischange": false,
- "timestamp": 1711381628,
+ "timestamp": 0,
- "hdkeypath": "m/0'/0'/0'",
+ "hdkeypath": "m/0h/0h/0h",
- "hdseedid": "68070250fe5ded18d944a9e0baeb07989755f9aa"
+ "hdseedid": "0000000000000000000000000000000000000000",
"hdmasterfingerprint": "8a98783b",
"labels": [
"my-P2PKH"
]
}
Now let's check the status of our migrated wallet's descriptors:
wallet listdescriptors
wallet listdescriptors
{
"wallet_name": "legacy_wallet",
"descriptors": [
{
"desc": "combo([92c1c7b0][...])#2k5hveg2",
"timestamp": 1,
"active": false
},
{
"desc": "combo([aaf95597][...])#rku6wtl2",
"timestamp": 1711381627,
"active": false
},
{
"desc": "combo(tpub[...]/0h/0h/*h)#lgzh23ul",
"timestamp": 0,
"active": false,
// ...
},
{
"desc": "combo(tpub[...]/0h/1h/*h)#0wgx6pfx",
"timestamp": 0,
"active": false,
// ...
},
{
"desc": "pkh([8a98783b/44h/1h/0h]tpub[...]/0/*)#3x0kynxu",
"timestamp": 1711381968,
"active": true,
"internal": false,
// ...
},
{
"desc": "pkh([8a98783b/44h/1h/0h]tpub[...]/1/*)#qj2hexky",
"timestamp": 1711381968,
"active": true,
"internal": true,
// ...
},
{
"desc": "sh(wpkh([8a98783b/49h/1h/0h]tpub[...]/0/*))#x84nrnlf",
"timestamp": 1711381968,
"active": true,
"internal": false,
// ...
},
{
"desc": "sh(wpkh([8a98783b/49h/1h/0h]tpub[...]/1/*))#nxm9mv2k",
"timestamp": 1711381968,
"active": true,
"internal": true,
// ...
},
{
"desc": "tr([8a98783b/86h/1h/0h]tpub[...]/0/*)#g9ul454z",
"timestamp": 1711381968,
"active": true,
"internal": false,
// ...
},
{
"desc": "tr([8a98783b/86h/1h/0h]tpub[...]/1/*)#e3e7gp96",
"timestamp": 1711381968,
"active": true,
"internal": true,
// ...
},
{
"desc": "wpkh([8a98783b/84h/1h/0h]tpub[...]/0/*)#vrwex429",
"timestamp": 1711381968,
"active": true,
"internal": false,
// ...
},
{
"desc": "wpkh([8a98783b/84h/1h/0h]tpub[...]/1/*)#ahtcmq6a",
"timestamp": 1711381968,
"active": true,
"internal": true,
// ...
}
]
}
We expect to have 12 descriptors in total here. All four address types should
have one 'receive' address (internal: false
), and one 'change' address (internal: true
),
there should be two combo descriptors, one internal (/0h/0h/1h/*h
) and one external (`/0h/0h/0h/*h, for representing our legacy HD
chains, and one combo descriptor to represent the HD master seed. A combo descriptor will also be used
to represent each of the non-HD keys present in our legacy wallet. (Just one in our case).
If everything looks good, our migration was successful!
Once you've completed the test, don't forget to stop your node and reset your testing environment for the next test:
bcli stop
datadir-cleanup
These steps only test a small fraction of the capabilities of the Bitcoin Core wallet, so we encourage you to use these instructions as a starting point for your own tests in use cases we haven't covered here that are interesting to you.
Kudos if you make it this far 👏🎉
Thanks for your contribution and for taking the time to make Bitcoin awesome. For feedback on this guide, please visit #29685