@@ -8,19 +8,12 @@ extern crate log;
8
8
extern crate bitcoin;
9
9
extern crate miniscript;
10
10
11
- use bitcoincore_rpc:: { json , Auth , Client , RpcApi } ;
11
+ use bitcoincore_rpc:: { Auth , Client , RpcApi } ;
12
12
13
- use bitcoin:: secp256k1;
14
- use bitcoin:: util:: psbt;
15
- use bitcoin:: util:: psbt:: PartiallySignedTransaction as Psbt ;
16
- use bitcoin:: { Amount , OutPoint , Transaction , TxIn , TxOut , Txid } ;
17
- mod read_file;
18
- use miniscript:: miniscript:: iter;
19
- use miniscript:: psbt:: PsbtExt ;
20
- use miniscript:: DescriptorTrait ;
21
- use miniscript:: MiniscriptKey ;
22
- use miniscript:: { Miniscript , Segwitv0 } ;
23
- use std:: collections:: BTreeMap ;
13
+ mod test_cpp;
14
+ mod test_desc;
15
+ mod test_util;
16
+ use test_util:: TestData ;
24
17
25
18
struct StdLogger ;
26
19
@@ -45,11 +38,6 @@ impl log::Log for StdLogger {
45
38
46
39
static LOGGER : StdLogger = StdLogger ;
47
40
48
- /// Quickly create a BTC amount.
49
- fn btc < F : Into < f64 > > ( btc : F ) -> Amount {
50
- Amount :: from_btc ( btc. into ( ) ) . unwrap ( )
51
- }
52
-
53
41
fn get_rpc_url ( ) -> String {
54
42
return std:: env:: var ( "RPC_URL" ) . expect ( "RPC_URL must be set" ) ;
55
43
}
@@ -64,23 +52,6 @@ fn get_auth() -> bitcoincore_rpc::Auth {
64
52
} ;
65
53
}
66
54
67
- // Find the Outpoint by value.
68
- // Ideally, we should find by scriptPubkey, but this
69
- // works for temp test case
70
- fn get_vout ( cl : & Client , txid : Txid , value : u64 ) -> ( OutPoint , TxOut ) {
71
- let tx = cl
72
- . get_transaction ( & txid, None )
73
- . unwrap ( )
74
- . transaction ( )
75
- . unwrap ( ) ;
76
- for ( i, txout) in tx. output . into_iter ( ) . enumerate ( ) {
77
- if txout. value == value {
78
- return ( OutPoint :: new ( txid, i as u32 ) , txout) ;
79
- }
80
- }
81
- unreachable ! ( "Only call get vout on functions which have the expected outpoint" ) ;
82
- }
83
-
84
55
fn main ( ) {
85
56
log:: set_logger ( & LOGGER )
86
57
. map ( |( ) | log:: set_max_level ( log:: LevelFilter :: max ( ) ) )
@@ -95,173 +66,64 @@ fn main() {
95
66
cl. create_wallet ( "testwallet" , None , None , None , None )
96
67
. unwrap ( ) ;
97
68
98
- let testdata = read_file:: TestData :: new_fixed_data ( 50 ) ;
99
- let ms_vec = read_file:: parse_miniscripts ( & testdata. pubdata ) ;
100
- let sks = testdata. secretdata . sks ;
101
- let pks = testdata. pubdata . pks ;
102
- // Generate some blocks
103
- let blocks = cl
104
- . generate_to_address ( 500 , & cl. get_new_address ( None , None ) . unwrap ( ) )
105
- . unwrap ( ) ;
106
- assert_eq ! ( blocks. len( ) , 500 ) ;
107
-
108
- // Next send some btc to each address corresponding to the miniscript
109
- let mut txids = vec ! [ ] ;
110
- for ms in ms_vec. iter ( ) {
111
- let wsh = miniscript:: Descriptor :: new_wsh ( ms. clone ( ) ) . unwrap ( ) ;
112
- let txid = cl
113
- . send_to_address (
114
- & wsh. address ( bitcoin:: Network :: Regtest ) . unwrap ( ) ,
115
- btc ( 1 ) ,
116
- None ,
117
- None ,
118
- None ,
119
- None ,
120
- None ,
121
- None ,
122
- )
123
- . unwrap ( ) ;
124
- txids. push ( txid) ;
125
- }
126
- // Wait for the funds to mature.
127
- let blocks = cl
128
- . generate_to_address ( 50 , & cl. get_new_address ( None , None ) . unwrap ( ) )
129
- . unwrap ( ) ;
130
- assert_eq ! ( blocks. len( ) , 50 ) ;
131
- // Create a PSBT for each transaction.
132
- // Spend one input and spend one output for simplicity.
133
- let mut psbts = vec ! [ ] ;
134
- for ( ms, txid) in ms_vec. iter ( ) . zip ( txids) {
135
- let mut psbt = Psbt {
136
- unsigned_tx : Transaction {
137
- version : 2 ,
138
- lock_time : 1_603_866_330 , // time at 10/28/2020 @ 6:25am (UTC)
139
- input : vec ! [ ] ,
140
- output : vec ! [ ] ,
141
- } ,
142
- unknown : BTreeMap :: new ( ) ,
143
- proprietary : BTreeMap :: new ( ) ,
144
- xpub : BTreeMap :: new ( ) ,
145
- version : 0 ,
146
- inputs : vec ! [ ] ,
147
- outputs : vec ! [ ] ,
148
- } ;
149
- // figure out the outpoint from the txid
150
- let ( outpoint, witness_utxo) = get_vout ( & cl, txid, btc ( 1.0 ) . as_sat ( ) ) ;
151
- let mut txin = TxIn :: default ( ) ;
152
- txin. previous_output = outpoint;
153
- // set the sequence to a non-final number for the locktime transactions to be
154
- // processed correctly.
155
- // We waited 50 blocks, keep 49 for safety
156
- txin. sequence = 49 ;
157
- psbt. unsigned_tx . input . push ( txin) ;
158
- // Get a new script pubkey from the node so that
159
- // the node wallet tracks the receiving transaction
160
- // and we can check it by gettransaction RPC.
161
- let addr = cl
162
- . get_new_address ( None , Some ( json:: AddressType :: Bech32 ) )
163
- . unwrap ( ) ;
164
- psbt. unsigned_tx . output . push ( TxOut {
165
- value : 99_999_000 ,
166
- script_pubkey : addr. script_pubkey ( ) ,
167
- } ) ;
168
- let mut input = psbt:: Input :: default ( ) ;
169
- input. witness_utxo = Some ( witness_utxo) ;
170
- input. witness_script = Some ( ms. encode ( ) ) ;
171
- psbt. inputs . push ( input) ;
172
- psbt. outputs . push ( psbt:: Output :: default ( ) ) ;
173
- psbts. push ( psbt) ;
174
- }
175
-
176
- let mut spend_txids = vec ! [ ] ;
177
- // Sign the transactions with all keys
178
- // AKA the signer role of psbt
179
- for i in 0 ..psbts. len ( ) {
180
- // Get all the pubkeys and the corresponding secret keys
181
- let ms: Miniscript < miniscript:: bitcoin:: PublicKey , Segwitv0 > =
182
- Miniscript :: parse_insane ( psbts[ i] . inputs [ 0 ] . witness_script . as_ref ( ) . unwrap ( ) ) . unwrap ( ) ;
183
-
184
- let sks_reqd: Vec < _ > = ms
185
- . iter_pk_pkh ( )
186
- . map ( |pk_pkh| match pk_pkh {
187
- iter:: PkPkh :: PlainPubkey ( pk) => sks[ pks. iter ( ) . position ( |& x| x == pk) . unwrap ( ) ] ,
188
- iter:: PkPkh :: HashedPubkey ( hash) => {
189
- sks[ pks
190
- . iter ( )
191
- . position ( |& pk| pk. to_pubkeyhash ( ) == hash)
192
- . unwrap ( ) ]
193
- }
194
- } )
195
- . collect ( ) ;
196
- // Get the required sighash message
197
- let amt = btc ( 1 ) . as_sat ( ) ;
198
- let mut sighash_cache = bitcoin:: util:: sighash:: SigHashCache :: new ( & psbts[ i] . unsigned_tx ) ;
199
- let sighash_ty = bitcoin:: EcdsaSigHashType :: All ;
200
- let sighash = sighash_cache
201
- . segwit_signature_hash ( 0 , & ms. encode ( ) , amt, sighash_ty)
202
- . unwrap ( ) ;
69
+ let testdata = TestData :: new_fixed_data ( 50 ) ;
70
+ test_cpp:: test_from_cpp_ms ( & cl, & testdata) ;
203
71
204
- // requires both signing and verification because we check the tx
205
- // after we psbt extract it
206
- let secp = secp256k1:: Secp256k1 :: new ( ) ;
207
- let msg = secp256k1:: Message :: from_slice ( & sighash[ ..] ) . unwrap ( ) ;
208
-
209
- // Finally construct the signature and add to psbt
210
- for sk in sks_reqd {
211
- let sig = secp. sign_ecdsa ( & msg, & sk) ;
212
- let pk = pks[ sks. iter ( ) . position ( |& x| x == sk) . unwrap ( ) ] ;
213
- psbts[ i] . inputs [ 0 ] . partial_sigs . insert (
214
- pk. inner ,
215
- bitcoin:: EcdsaSig {
216
- sig,
217
- hash_ty : sighash_ty,
218
- } ,
219
- ) ;
220
- }
221
- // Add the hash preimages to the psbt
222
- psbts[ i] . inputs [ 0 ] . sha256_preimages . insert (
223
- testdata. pubdata . sha256 ,
224
- testdata. secretdata . sha256_pre . to_vec ( ) ,
225
- ) ;
226
- psbts[ i] . inputs [ 0 ] . hash256_preimages . insert (
227
- testdata. pubdata . hash256 ,
228
- testdata. secretdata . hash256_pre . to_vec ( ) ,
229
- ) ;
230
- println ! ( "{}" , ms) ;
231
- psbts[ i] . inputs [ 0 ] . hash160_preimages . insert (
232
- testdata. pubdata . hash160 ,
233
- testdata. secretdata . hash160_pre . to_vec ( ) ,
234
- ) ;
235
- psbts[ i] . inputs [ 0 ] . ripemd160_preimages . insert (
236
- testdata. pubdata . ripemd160 ,
237
- testdata. secretdata . ripemd160_pre . to_vec ( ) ,
238
- ) ;
239
- // Finalize the transaction using psbt
240
- // Let miniscript do it's magic!
241
- if let Err ( e) = psbts[ i] . finalize_mall_mut ( & secp) {
242
- // All miniscripts should satisfy
243
- panic ! ( "Could not satisfy: error{} ms:{} at ind:{}" , e[ 0 ] , ms, i) ;
244
- } else {
245
- let tx = psbts[ i] . extract ( & secp) . unwrap ( ) ;
72
+ test_descs ( & cl, & testdata) ;
73
+ }
246
74
247
- // Send the transactions to bitcoin node for mining.
248
- // Regtest mode has standardness checks
249
- // Check whether the node accepts the transactions
250
- let txid = cl
251
- . send_raw_transaction ( & tx)
252
- . expect ( & format ! ( "{} send tx failed for ms {}" , i, ms) ) ;
253
- spend_txids. push ( txid) ;
254
- }
255
- }
256
- // Finally mine the blocks and await confirmations
257
- let _blocks = cl
258
- . generate_to_address ( 10 , & cl. get_new_address ( None , None ) . unwrap ( ) )
259
- . unwrap ( ) ;
260
- // Get the required transactions from the node mined in the blocks.
261
- for txid in spend_txids {
262
- // Check whether the transaction is mined in blocks
263
- // Assert that the confirmations are > 0.
264
- let num_conf = cl. get_transaction ( & txid, None ) . unwrap ( ) . info . confirmations ;
265
- assert ! ( num_conf > 0 ) ;
266
- }
75
+ fn test_descs ( cl : & Client , testdata : & TestData ) {
76
+ // K : Compressed key available
77
+ // K!: Compressed key with corresponding secret key unknown
78
+ // X: X-only key available
79
+ // X!: X-only key with corresponding secret key unknown
80
+
81
+ // Test 1: Simple spend with internal key
82
+ let wit = test_desc:: test_desc_satisfy ( cl, testdata, "tr(X)" ) ;
83
+ assert ! ( wit. len( ) == 1 ) ;
84
+
85
+ // Test 2: Same as above, but with leaves
86
+ let wit = test_desc:: test_desc_satisfy ( cl, testdata, "tr(X,{pk(X1!),pk(X2!)})" ) ;
87
+ assert ! ( wit. len( ) == 1 ) ;
88
+
89
+ // Test 3: Force to spend with script spend. Unknown internal key and only one known script path
90
+ // X! -> Internal key unknown
91
+ // Leaf 1 -> pk(X1) with X1 known
92
+ // Leaf 2-> and_v(v:pk(X2),pk(X3!)) with partial witness only to X2 known
93
+ let wit = test_desc:: test_desc_satisfy ( cl, testdata, "tr(X!,{pk(X1),and_v(v:pk(X2),pk(X3!))})" ) ;
94
+ assert ! ( wit. len( ) == 3 ) ; // control block, script and signature
95
+
96
+ // Test 4: Force to spend with script spend. Unknown internal key and multiple script paths
97
+ // Should select the one with minimum weight
98
+ // X! -> Internal key unknown
99
+ // Leaf 1 -> pk(X1!) with X1 unknown
100
+ // Leaf 2-> and_v(v:pk(X2),pk(X3)) X2 and X3 known
101
+ let wit = test_desc:: test_desc_satisfy ( cl, testdata, "tr(X!,{pk(X1),and_v(v:pk(X2),pk(X3))})" ) ;
102
+ assert ! ( wit. len( ) == 3 ) ; // control block, script and one signatures
103
+
104
+ // Test 5: When everything is available, we should select the key spend path
105
+ let wit = test_desc:: test_desc_satisfy ( cl, testdata, "tr(X,{pk(X1),and_v(v:pk(X2),pk(X3!))})" ) ;
106
+ assert ! ( wit. len( ) == 1 ) ; // control block, script and signature
107
+
108
+ // Test 6: Test the new multi_a opcodes
109
+ test_desc:: test_desc_satisfy ( cl, testdata, "tr(X!,{pk(X1!),multi_a(1,X2,X3!,X4!,X5!)})" ) ;
110
+ test_desc:: test_desc_satisfy ( cl, testdata, "tr(X!,{pk(X1!),multi_a(2,X2,X3,X4!,X5!)})" ) ;
111
+ test_desc:: test_desc_satisfy ( cl, testdata, "tr(X!,{pk(X1!),multi_a(3,X2,X3,X4,X5!)})" ) ;
112
+ test_desc:: test_desc_satisfy ( cl, testdata, "tr(X!,{pk(X1!),multi_a(4,X2,X3,X4,X5)})" ) ;
113
+
114
+ // Misc tests for other descriptors that we support
115
+ // Keys
116
+ test_desc:: test_desc_satisfy ( cl, testdata, "wpkh(K)" ) ;
117
+ test_desc:: test_desc_satisfy ( cl, testdata, "pkh(K)" ) ;
118
+ test_desc:: test_desc_satisfy ( cl, testdata, "sh(wpkh(K))" ) ;
119
+
120
+ // sorted multi
121
+ test_desc:: test_desc_satisfy ( cl, testdata, "sh(sortedmulti(2,K1,K2,K3))" ) ;
122
+ test_desc:: test_desc_satisfy ( cl, testdata, "wsh(sortedmulti(2,K1,K2,K3))" ) ;
123
+ test_desc:: test_desc_satisfy ( cl, testdata, "sh(wsh(sortedmulti(2,K1,K2,K3)))" ) ;
124
+
125
+ // Miniscripts
126
+ test_desc:: test_desc_satisfy ( cl, testdata, "sh(and_v(v:pk(K1),pk(K2)))" ) ;
127
+ test_desc:: test_desc_satisfy ( cl, testdata, "wsh(and_v(v:pk(K1),pk(K2)))" ) ;
128
+ test_desc:: test_desc_satisfy ( cl, testdata, "sh(wsh(and_v(v:pk(K1),pk(K2))))" ) ;
267
129
}
0 commit comments