Skip to content

Commit 5a5d260

Browse files
committed
p2qrh: rust related test vectors and examples.
1 parent 8d4d553 commit 5a5d260

15 files changed

+1452
-206
lines changed

bip-0360/ref-impl/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ rust-bitcoin
22
rust-miniscript
33
target
44
.btcdeb_history
5+
*.swp

bip-0360/ref-impl/rust/tests/data/p2qrh_construction.json renamed to bip-0360/ref-impl/common/tests/data/p2qrh_construction.json

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@
2828
"leafHashes": [
2929
"c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
3030
],
31-
"merkleRoot": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
31+
"quantumRoot": "27e8a6af1f05d3dbfebfc4073a8391cf8db28746767c2b34d606900ad721127b"
3232
},
3333
"expected": {
34-
"scriptPubKey": "5320c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
35-
"bip350Address": "bc1rc5jhzjnlf8pg4mdmhfuvqpvnr2quyd9j7mye5uly6psg9twghu4s0glfcg",
34+
"scriptPubKey": "532027e8a6af1f05d3dbfebfc4073a8391cf8db28746767c2b34d606900ad721127b",
35+
"bip350Address": "bc1ryl52dtclqhfahl4lcsrn4qu3e7xm9p6xwe7zkdxkq6gq44epzfasklalkw",
3636
"scriptPathControlBlocks": [
37-
"c0"
37+
"c1"
3838
]
3939
}
4040
},
4141
{
4242
"id": "p2qrh_different_version_leaves",
43-
"objective": "Tests P2QRH with two script leaves of different versions",
43+
"objective": "Tests P2QRH with two script leaves of different versions. TO-DO: currently ignores given leaf version and over-rides. Probably better to throw error",
4444
"given": {
4545
"scriptTree": [
4646
{
@@ -63,14 +63,14 @@
6363
"8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7",
6464
"f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
6565
],
66-
"merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef"
66+
"quantumRoot": "af8e7912e4794d9234f22ae3c03905d50d1015572617efc74f482aa6c8ba0376"
6767
},
6868
"expected": {
69-
"scriptPubKey": "53206c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
70-
"bip350Address": "bc1rdskuzp4ts94h87ws0c7drmev3sf9dagewj8qsylyahfyqhf800hszs9g88",
69+
"scriptPubKey": "5320af8e7912e4794d9234f22ae3c03905d50d1015572617efc74f482aa6c8ba0376",
70+
"bip350Address": "bc1r4788jyhy09xeyd8j9t3uqwg965x3q92hyct7l360fq42dj96qdmqtpftcg",
7171
"scriptPathControlBlocks": [
72-
"c0f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
73-
"fa8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
72+
"c1f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
73+
"c18ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
7474
]
7575
}
7676
},
@@ -100,14 +100,14 @@
100100
"c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9",
101101
"632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42"
102102
],
103-
"merkleRoot": "41646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b"
103+
"quantumRoot": "04b74fb166133f6700927ce4f83ad08cbef5209bdc253b6e727b0206a78fbfd9"
104104
},
105105
"expected": {
106-
"scriptPubKey": "532041646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b",
107-
"bip350Address": "bc1rg9jxlrqlu25kmkkh74r3h387uldfs72wlrz95n60c6j4n4svna4s258v28",
106+
"scriptPubKey": "532004b74fb166133f6700927ce4f83ad08cbef5209bdc253b6e727b0206a78fbfd9",
107+
"bip350Address": "bc1rqjm5lvtxzvlkwqyj0nj0swks3jl02gymmsjnkmnj0vpqdfu0hlvsn5j95l",
108108
"scriptPathControlBlocks": [
109-
"c0c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9",
110-
"c0632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42"
109+
"c1c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9",
110+
"c1632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42"
111111
]
112112
}
113113
},
@@ -136,14 +136,14 @@
136136
"64512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89",
137137
"2cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb"
138138
],
139-
"merkleRoot": "ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc"
139+
"quantumRoot": "f2916fd14cd711482f5262fef02d61647602493e94a3b5ec48d2cc1beee78fa5"
140140
},
141141
"expected": {
142-
"scriptPubKey": "5320ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
143-
"bip350Address": "bc1r4vtegvwz35ak37me39tl4a2f045u3q7xlv0pek0czjpas7avjrxqapldh6",
142+
"scriptPubKey": "5320f2916fd14cd711482f5262fef02d61647602493e94a3b5ec48d2cc1beee78fa5",
143+
"bip350Address": "bc1r72gkl52v6ug5st6jvtl0qttpv3mqyjf7jj3mtmzg6txphmh837jsv2ydgs",
144144
"scriptPathControlBlocks": [
145-
"c02cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
146-
"c064512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89"
145+
"c12cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
146+
"c164512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89"
147147
]
148148
}
149149
},
@@ -181,15 +181,15 @@
181181
"ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c",
182182
"9e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf6"
183183
],
184-
"merkleRoot": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2"
184+
"quantumRoot": "6035c881af058a8135592c019cab755a0b41692e408eebe3ca9f0ee32d1b020c"
185185
},
186186
"expected": {
187-
"scriptPubKey": "5320ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
188-
"bip350Address": "bc1rej7kd3hhar76k3an5jr0t8fgyc47s4lnp4rh8uk4afrlwasuur3qarfta7",
187+
"scriptPubKey": "53206035c881af058a8135592c019cab755a0b41692e408eebe3ca9f0ee32d1b020c",
188+
"bip350Address": "bc1rvq6u3qd0qk9gzd2e9sqee2m4tg95z6fwgz8whc72nu8wxtgmqgxqu3r6wq",
189189
"scriptPathControlBlocks": [
190-
"c0ffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
191-
"c0ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
192-
"c09e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
190+
"c1ffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
191+
"c1ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
192+
"c19e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
193193
]
194194
}
195195
},
@@ -227,15 +227,15 @@
227227
"737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711",
228228
"d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7"
229229
],
230-
"merkleRoot": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def"
230+
"quantumRoot": "4de1ac7ff4cef472d80e44e1873ff7e4c61cc109f8cf87b49aa5309d3f2b8994"
231231
},
232232
"expected": {
233-
"scriptPubKey": "53202f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
234-
"bip350Address": "bc1r9a4jc5uhkmtgegvwpx3lq5tpv68layaf3pvz64wx7paatvejnhhsnl669j",
233+
"scriptPubKey": "53204de1ac7ff4cef472d80e44e1873ff7e4c61cc109f8cf87b49aa5309d3f2b8994",
234+
"bip350Address": "bc1rfhs6cll5em689kqwgnscw0lhunrpesgflr8c0dy655cf60et3x2q2vmn2f",
235235
"scriptPathControlBlocks": [
236-
"c03cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
237-
"c0737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
238-
"c0d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
236+
"c13cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
237+
"c1737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
238+
"c1d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
239239
]
240240
}
241241
}
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
:scrollbar:
2+
:data-uri:
3+
:toc2:
4+
:linkattrs:
5+
6+
= P2QRH End-to-End Tutorial
7+
8+
:numbered:
9+
10+
This tutorial is inspired from the link:https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature[script-path-spend-signature] example of the _learnmeabitcoin_ tutorial.
11+
12+
It is customized to create, fund and spend from a P2QRH UTXO to a P2WPKH address.
13+
14+
Execute in Bitcoin Core `regtest` mode.
15+
16+
== Pre-reqs
17+
18+
=== Bitcoin Core
19+
20+
The link:https://github.com/jbride/bitcoin/tree/p2qrh[p2qrh branch] of bitcoin core is needed.
21+
22+
Build instructions for the `p2qrh` branch are the same as `master` and is documented link:https://github.com/bitcoin/bitcoin/blob/master/doc/build-unix.md[here].
23+
24+
As such, the following is an example series of steps (on a Fedora 42 host) to compile and run the `p2qrh` branch of bitcoin core:
25+
26+
. build
27+
+
28+
-----
29+
$ cmake -B build \
30+
-DWITH_ZMQ=ON \
31+
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
32+
-DBUILD_BENCH=ON \
33+
-DBUILD_DAEMON=ON \
34+
-DSANITIZERS=address,undefined
35+
36+
$ cmake --build build -j$(nproc)
37+
-----
38+
39+
. run in `regtest` mode
40+
+
41+
-----
42+
$ ./build/bin/bitcoind -daemon=0 -regtest=1 -txindex
43+
-----
44+
45+
=== Shell Environment
46+
47+
. *b-reg* command line alias:
48+
+
49+
Configure an alias to the `bitcoin-cli` command that connects to your customized bitcoin-core node running in `regtest` mode.
50+
. *jq*: ensure json parsing utility is installed and available via your $PATH.
51+
. *awk* : standard utility for all Linux distros (often packaged as `gawk`).
52+
53+
=== Bitcoin Core Wallet
54+
55+
This tutorial assumes that a bitcoin core wallet is available.
56+
For example, the following would be sufficient:
57+
58+
-----
59+
$ export W_NAME=regtest \
60+
&& export WPASS=regtest
61+
62+
$ b-reg -named createwallet \
63+
wallet_name=$W_NAME \
64+
descriptors=true \
65+
passphrase="$WPASS" \
66+
load_on_startup=true
67+
-----
68+
69+
== Fund P2QRH UTXO
70+
71+
. OPTIONAL: Define number of leaves in tap tree as well as the tap leaf to later use as the unlocking script:
72+
+
73+
-----
74+
$ export TOTAL_LEAF_COUNT=5 \
75+
&& export LEAF_OF_INTEREST=4
76+
-----
77+
+
78+
NOTE: Defaults are 4 leaves with the first leaf (leaf 0 ) as the script to later use as the unlocking script.
79+
80+
. Generate a P2QRH scripPubKey with multi-leaf taptree:
81+
+
82+
-----
83+
$ export BITCOIN_NETWORK=regtest \
84+
&& export BITCOIN_ADDRESS_INFO=$( cargo run --example p2qrh_construction ) \
85+
&& echo $BITCOIN_ADDRESS_INFO | jq -r .
86+
-----
87+
+
88+
NOTE: In `regtest`, you can expect a P2QRH address that starts with: `bcrt1r` .
89+
+
90+
NOTE: In the context of P2QRH, the _tree_root_hex_ from the response is in reference to the _quantum_root_ used in this tutorial.
91+
92+
. Set some env vars (for use in later steps in this tutorial) based on previous result:
93+
+
94+
-----
95+
$ export QUANTUM_ROOT=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.tree_root_hex' ) \
96+
&& export LEAF_SCRIPT_PRIV_KEY_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_priv_key_hex' ) \
97+
&& export LEAF_SCRIPT_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_hex' ) \
98+
&& export CONTROL_BLOCK_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.control_block_hex' ) \
99+
&& export FUNDING_SCRIPT_PUBKEY=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.script_pubkey_hex' ) \
100+
&& export P2QRH_ADDR=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.bech32m_address' )
101+
-----
102+
103+
. View tapscript used in target leaf of taptree:
104+
+
105+
-----
106+
$ b-reg decodescript $LEAF_SCRIPT_HEX | jq -r '.asm'
107+
-----
108+
+
109+
NOTE: Notice that this script commits to a Schnorr 32-byte x-only public key.
110+
111+
112+
. fund this P2QRH address with the coinbase reward of a newly generated block:
113+
+
114+
-----
115+
$ export COINBASE_REWARD_TX_ID=$( b-reg -named generatetoaddress 1 $P2QRH_ADDR 5 | jq -r '.[]' ) \
116+
&& echo $COINBASE_REWARD_TX_ID
117+
-----
118+
+
119+
NOTE: Sometimes Bitcoin Core may not hit a block (even on regtest). If so, just try the above command again.
120+
121+
. view summary of all txs that have funded P2QRH address
122+
+
123+
-----
124+
$ export P2QRH_DESC=$( b-reg getdescriptorinfo "addr($P2QRH_ADDR)" | jq -r '.descriptor' ) \
125+
&& echo $P2QRH_DESC \
126+
&& b-reg scantxoutset start '[{"desc": "'''$P2QRH_DESC'''"}]'
127+
-----
128+
129+
. grab txid of first tx with unspent funds:
130+
+
131+
-----
132+
$ export FUNDING_TX_ID=$( b-reg scantxoutset start '[{"desc": "'''$P2QRH_DESC'''"}]' | jq -r '.unspents[0].txid' ) \
133+
&& echo $FUNDING_TX_ID
134+
-----
135+
136+
. Set FUNDING_UTXO_INDEX env var (used later to correctly identify funding UTXO when generating the spending tx)
137+
+
138+
-----
139+
$ export FUNDING_UTXO_INDEX=0
140+
-----
141+
142+
. view details of funding UTXO to the P2QRH address:
143+
+
144+
-----
145+
$ export FUNDING_UTXO=$( b-reg getrawtransaction $FUNDING_TX_ID 1 | jq -r '.vout['''$FUNDING_UTXO_INDEX''']' ) \
146+
&& echo $FUNDING_UTXO | jq -r .
147+
-----
148+
+
149+
NOTE: the above only works when Bitcoin Core is started with the following arg: -txindex
150+
151+
== Spend P2QRH UTXO
152+
153+
154+
. Determine value (in sats) of funding utxo:
155+
+
156+
-----
157+
$ export FUNDING_UTXO_AMOUNT_SATS=$(echo $FUNDING_UTXO | jq -r '.value' | awk '{printf "%.0f", $1 * 100000000}') \
158+
&& echo $FUNDING_UTXO_AMOUNT_SATS
159+
-----
160+
161+
. Generate additional blocks.
162+
+
163+
This is necessary if you have only previously generated less than 100 blocks.
164+
+
165+
-----
166+
$ b-reg -generate 110
167+
-----
168+
+
169+
Otherwise, you may see an error from bitcoin core such as the following when attempting to spend:
170+
+
171+
_bad-txns-premature-spend-of-coinbase, tried to spend coinbase at depth 1_
172+
173+
174+
. Referencing the funding tx (via $FUNDING_TX_ID and $FUNDING_UTXO_INDEX), create the spending tx:
175+
+
176+
-----
177+
$ export SPEND_DETAILS=$( cargo run --example p2qrh_spend )
178+
179+
$ export RAW_P2QRH_SPEND_TX=$( echo $SPEND_DETAILS | jq -r '.tx_hex' ) \
180+
&& echo "RAW_P2QRH_SPEND_TX = $RAW_P2QRH_SPEND_TX" \
181+
&& export SIG_HASH=$( echo $SPEND_DETAILS | jq -r '.sighash' ) \
182+
&& echo "SIG_HASH = $SIG_HASH" \
183+
&& export SIG_BYTES=$( echo $SPEND_DETAILS | jq -r '.sig_bytes' ) \
184+
&& echo "SIG_BYTES = $SIG_BYTES"
185+
-----
186+
187+
. Inspect the spending tx:
188+
+
189+
-----
190+
$ b-reg decoderawtransaction $RAW_P2QRH_SPEND_TX
191+
-----
192+
+
193+
Pay particular attention to the `vin.txinwitness` field.
194+
Do the three elements (script input, script and control block) of the witness stack for this script path spend make sense ?
195+
What do you observe as the first byte of the `control block` element ?
196+
197+
. Test standardness of the spending tx by sending to local mempool of p2qrh enabled Bitcoin Core:
198+
+
199+
-----
200+
$ b-reg testmempoolaccept '["'''$RAW_P2QRH_SPEND_TX'''"]'
201+
-----
202+
203+
. Submit tx:
204+
+
205+
-----
206+
$ export P2QRH_SPENDING_TX_ID=$( b-reg sendrawtransaction $RAW_P2QRH_SPEND_TX ) \
207+
&& echo $P2QRH_SPENDING_TX_ID
208+
-----
209+
+
210+
NOTE: Should return same tx id as was included in $RAW_P2QRH_SPEND_TX
211+
212+
== Mine P2QRH Spend TX
213+
214+
. View tx in mempool:
215+
+
216+
-----
217+
$ b-reg getrawtransaction $P2QRH_SPENDING_TX_ID 1
218+
-----
219+
+
220+
NOTE: There will not yet be a field `blockhash` in the response.
221+
222+
. Mine 1 block:
223+
+
224+
-----
225+
$ b-reg -generate 1
226+
-----
227+
228+
. Obtain `blockhash` field of mined tx:
229+
+
230+
-----
231+
$ export BLOCK_HASH=$( b-reg getrawtransaction $P2QRH_SPENDING_TX_ID 1 | jq -r '.blockhash' ) \
232+
&& echo $BLOCK_HASH
233+
-----
234+
235+
. View tx in block:
236+
+
237+
-----
238+
$ b-reg getblock $BLOCK_HASH | jq -r .tx
239+
-----
240+
241+
== TO-DO
242+
243+
=== Import P2QRH address into wallet
244+
245+
NOTE: currently fails with: "message": "Cannot import descriptor without private keys to a wallet with private keys enabled"
246+
247+
-----
248+
$ b-reg -rpcwallet=$W_NAME walletpassphrase $WPASS 120
249+
$ echo $P2QRH_ADDR
250+
$ export P2QRH_DESC=$( b-reg getdescriptorinfo "addr($P2QRH_ADDR)" | jq -r '.descriptor' ) \
251+
&& echo $P2QRH_DESC
252+
253+
# Set as non-active address (because can't generate subsequent p2qrh addresses yet)
254+
$ b-reg importdescriptors '[{
255+
"desc": "'''$P2QRH_DESC'''",
256+
"timestamp": "now",
257+
"active": false,
258+
"label": "p2qrh"
259+
}]'
260+
-----

0 commit comments

Comments
 (0)