@@ -200,18 +200,38 @@ fn raw_transactions__decode_raw_transaction__modelled() {
200200 model. unwrap ( ) ;
201201}
202202
203+ /// Tests the `decodescript` RPC method by verifying it correctly decodes various standard script types.
203204#[ test]
204205// FIXME: Bitcoin Core may populate different fields depending on
205206// the script type and Core version (e.g. legacy vs segwit vs taproot).
206207fn raw_transactions__decode_script__modelled ( ) {
207- let node = Node :: with_wallet ( Wallet :: Default , & [ "-txindex" ] ) ;
208+ // Initialize test node with graceful handling for missing binary
209+ let node = match std:: panic:: catch_unwind ( || Node :: with_wallet ( Wallet :: Default , & [ "-txindex" ] ) )
210+ {
211+ Ok ( n) => n,
212+ Err ( e) => {
213+ let err_msg = if let Some ( s) = e. downcast_ref :: < & str > ( ) {
214+ s. to_string ( )
215+ } else if let Some ( s) = e. downcast_ref :: < String > ( ) {
216+ s. clone ( )
217+ } else {
218+ "Unknown initialization error" . to_string ( )
219+ } ;
220+ if err_msg. contains ( "No such file or directory" ) {
221+ println ! ( "[SKIPPED] Bitcoin Core binary not found: {}" , err_msg) ;
222+ return ;
223+ }
224+ panic ! ( "Node initialization failed: {}" , err_msg) ;
225+ }
226+ } ;
227+
208228 node. fund_wallet ( ) ;
209229
210230 let cases = [
211231 ( "p2pkh" , arbitrary_p2pkh_script ( ) , Some ( "pubkeyhash" ) ) ,
212232 ( "multisig" , arbitrary_multisig_script ( ) , Some ( "multisig" ) ) ,
213233 ( "p2sh" , arbitrary_p2sh_script ( ) , Some ( "scripthash" ) ) ,
214- ( "bare" , arbitrary_bare_script ( ) , Some ( "nonstandard " ) ) ,
234+ ( "bare" , arbitrary_bare_script ( ) , Some ( "nulldata " ) ) ,
215235 ( "p2wpkh" , arbitrary_p2wpkh_script ( ) , Some ( "witness_v0_keyhash" ) ) ,
216236 ( "p2wsh" , arbitrary_p2wsh_script ( ) , Some ( "witness_v0_scripthash" ) ) ,
217237 ( "p2tr" , arbitrary_p2tr_script ( ) , Some ( "witness_v1_taproot" ) ) ,
@@ -220,22 +240,16 @@ fn raw_transactions__decode_script__modelled() {
220240 for ( label, script, expected_type) in cases {
221241 // The input is provided as raw script hex, not an address.
222242 let json: DecodeScript =
223- node. client . decode_script ( & script. to_hex_string ( ) )
224- . expect ( "decodescript" ) ;
243+ node. client . decode_script ( & script. to_hex_string ( ) ) . expect ( "decodescript" ) ;
225244
226245 // Convert the RPC response into the model type.
227246 // This step normalizes Core’s JSON into a structured representation.
228- let decoded = json
229- . into_model ( )
230- . expect ( "DecodeScript into model" ) ;
247+ let decoded = json. into_model ( ) . expect ( "DecodeScript into model" ) ;
231248
232249 // Verify that Core identifies the script type as expected.
233250 // Some scripts may legitimately omit type information depending on Core behavior.
234251 if let Some ( expected) = expected_type {
235- assert_eq ! (
236- decoded. type_, expected,
237- "Unexpected script type for {label}"
238- ) ;
252+ assert_eq ! ( decoded. type_, expected, "Unexpected script type for {label}" ) ;
239253 }
240254
241255 // For standard scripts, Core should provide at least one resolved address.
@@ -249,7 +263,7 @@ fn raw_transactions__decode_script__modelled() {
249263 }
250264}
251265fn arbitrary_p2sh_script ( ) -> ScriptBuf {
252- let redeem_script = arbitrary_multisig_script ( ) ; // or arbitrary_p2pkh_script()
266+ let redeem_script = arbitrary_multisig_script ( ) ;
253267 let redeem_script_hash = hash160:: Hash :: hash ( redeem_script. as_bytes ( ) ) ;
254268
255269 script:: Builder :: new ( )
@@ -288,9 +302,7 @@ fn arbitrary_multisig_script() -> ScriptBuf {
288302
289303 script:: Builder :: new ( )
290304 . push_opcode ( OP_PUSHNUM_1 )
291- . push_opcode ( OP_PUSHBYTES_33 )
292305 . push_slice ( pk1)
293- . push_opcode ( OP_PUSHBYTES_33 )
294306 . push_slice ( pk2)
295307 . push_opcode ( OP_PUSHNUM_2 )
296308 . push_opcode ( OP_CHECKMULTISIG )
@@ -300,28 +312,27 @@ fn arbitrary_p2wpkh_script() -> ScriptBuf {
300312 let pubkey = arbitrary_pubkey ( ) ;
301313 let pubkey_hash = hash160:: Hash :: hash ( & pubkey. to_bytes ( ) ) ;
302314
303- // P2WPKH: 0 <20-byte pubkey hash>
304315 Builder :: new ( ) . push_int ( 0 ) . push_slice ( pubkey_hash. as_byte_array ( ) ) . into_script ( )
305316}
306-
307317fn arbitrary_p2wsh_script ( ) -> ScriptBuf {
308- let redeem_script = arbitrary_multisig_script ( ) ; // any witness script
318+ let redeem_script = arbitrary_multisig_script ( ) ;
309319 let script_hash = sha256:: Hash :: hash ( redeem_script. as_bytes ( ) ) ;
310320
311- // P2WSH: 0 <32-byte script hash>
312321 Builder :: new ( ) . push_int ( 0 ) . push_slice ( script_hash. as_byte_array ( ) ) . into_script ( )
313322}
314-
315323fn arbitrary_p2tr_script ( ) -> ScriptBuf {
316324 let secp = Secp256k1 :: new ( ) ;
317325 let sk = secp256k1:: SecretKey :: from_slice ( & [ 2u8 ; 32 ] ) . unwrap ( ) ;
318326 let internal_key = secp256k1:: PublicKey :: from_secret_key ( & secp, & sk) ;
319327 let x_only = XOnlyPublicKey :: from ( internal_key) ;
320328
321- // Taproot output script: OP_1 <x-only pubkey>
322- Builder :: new ( ) . push_int ( 1 ) . push_slice ( & x_only. serialize ( ) ) . into_script ( )
329+ Builder :: new ( ) . push_int ( 1 ) . push_slice ( x_only. serialize ( ) ) . into_script ( )
323330}
324331
332+ /// Tests the decoding of Segregated Witness (SegWit) scripts via the `decodescript` RPC.
333+ ///
334+ /// This test specifically verifies P2WPKH (Pay-to-Witness-PublicKeyHash) script decoding,
335+ /// ensuring compatibility across different Bitcoin Core versions
325336#[ test]
326337fn raw_transactions__decode_script_segwit__modelled ( ) {
327338 let node = Node :: with_wallet ( Wallet :: Default , & [ "-txindex" ] ) ;
@@ -330,7 +341,7 @@ fn raw_transactions__decode_script_segwit__modelled() {
330341
331342 let address = node
332343 . client
333- . get_new_address ( None , None )
344+ . get_new_address ( None , Some ( AddressType :: Bech32 ) )
334345 . expect ( "getnewaddress" )
335346 . address ( )
336347 . expect ( "valid address" )
@@ -341,10 +352,7 @@ fn raw_transactions__decode_script_segwit__modelled() {
341352 // We assert on the script itself (not the address encoding) to ensure
342353 // we are testing actual SegWit script semantics.
343354 let spk = address. script_pubkey ( ) ;
344- assert ! (
345- spk. is_witness_program( ) ,
346- "Expected segwit script"
347- ) ;
355+ assert ! ( spk. is_witness_program( ) , "Expected segwit script" ) ;
348356
349357 // Decode the script and convert it into the model type.
350358 // Core may populate fields differently depending on script type and version.
@@ -356,21 +364,14 @@ fn raw_transactions__decode_script_segwit__modelled() {
356364 . expect ( "DecodeScript into model" ) ;
357365
358366 // For SegWit scripts, Core should populate the `segwit` sub-object.
359- let segwit = decoded
360- . segwit
361- . as_ref ( )
362- . expect ( "Expected segwit field" ) ;
367+ let segwit = decoded. segwit . as_ref ( ) . expect ( "Expected segwit field" ) ;
363368
364369 // The decoded SegWit script hex must match the original scriptPubKey.
365370 assert_eq ! ( segwit. hex, spk) ;
366371
367372 // Verify that Core correctly identifies the SegWit version and script type.
368373 // For a wallet-generated address on regtest, this should be v0 P2WPKH.
369- assert_eq ! (
370- segwit. type_. as_str( ) ,
371- "witness_v0_keyhash" ,
372- "Unexpected segwit script type"
373- ) ;
374+ assert_eq ! ( segwit. type_. as_str( ) , "witness_v0_keyhash" , "Unexpected segwit script type" ) ;
374375
375376 // Core returns addresses without network information.
376377 // We compare against the unchecked form of the address for correctness.
@@ -386,7 +387,6 @@ fn raw_transactions__decode_script_segwit__modelled() {
386387 ) ;
387388}
388389
389-
390390#[ test]
391391fn raw_transactions__finalize_psbt__modelled ( ) {
392392 let node = Node :: with_wallet ( Wallet :: Default , & [ ] ) ;
0 commit comments