2021-03-03 13:22:05 -08:00
// Bitcoin Dev Kit
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
2020-08-31 11:26:36 +02:00
//
2021-03-03 13:22:05 -08:00
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
2020-08-31 11:26:36 +02:00
//
2021-03-03 13:22:05 -08:00
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
2021-05-19 13:04:32 +10:00
#![ allow(missing_docs) ]
2020-08-31 11:26:36 +02:00
2021-05-19 15:52:51 +10:00
#[ cfg(feature = " test-blockchains " ) ]
pub mod blockchain_tests ;
2020-08-10 10:49:34 +02:00
2021-02-02 20:06:40 -05:00
use bitcoin ::secp256k1 ::{ Secp256k1 , Verification } ;
2021-05-19 15:52:51 +10:00
use bitcoin ::{ Address , PublicKey } ;
2021-02-02 20:06:40 -05:00
use miniscript ::descriptor ::DescriptorPublicKey ;
use miniscript ::{ Descriptor , MiniscriptKey , TranslatePk } ;
2020-08-10 10:49:34 +02:00
#[ derive(Clone, Debug) ]
pub struct TestIncomingOutput {
pub value : u64 ,
pub to_address : String ,
}
impl TestIncomingOutput {
pub fn new ( value : u64 , to_address : Address ) -> Self {
Self {
value ,
to_address : to_address . to_string ( ) ,
}
}
}
#[ derive(Clone, Debug) ]
pub struct TestIncomingTx {
pub output : Vec < TestIncomingOutput > ,
pub min_confirmations : Option < u64 > ,
pub locktime : Option < i64 > ,
pub replaceable : Option < bool > ,
}
impl TestIncomingTx {
pub fn new (
output : Vec < TestIncomingOutput > ,
min_confirmations : Option < u64 > ,
locktime : Option < i64 > ,
replaceable : Option < bool > ,
) -> Self {
Self {
output ,
min_confirmations ,
locktime ,
replaceable ,
}
}
pub fn add_output ( & mut self , output : TestIncomingOutput ) {
self . output . push ( output ) ;
}
}
2021-02-02 20:06:40 -05:00
#[ doc(hidden) ]
pub trait TranslateDescriptor {
// derive and translate a `Descriptor<DescriptorPublicKey>` into a `Descriptor<PublicKey>`
fn derive_translated < C : Verification > (
& self ,
secp : & Secp256k1 < C > ,
index : u32 ,
) -> Descriptor < PublicKey > ;
}
impl TranslateDescriptor for Descriptor < DescriptorPublicKey > {
fn derive_translated < C : Verification > (
& self ,
secp : & Secp256k1 < C > ,
index : u32 ,
) -> Descriptor < PublicKey > {
let translate = | key : & DescriptorPublicKey | -> PublicKey {
match key {
DescriptorPublicKey ::XPub ( xpub ) = > {
xpub . xkey
. derive_pub ( secp , & xpub . derivation_path )
. expect ( " hardened derivation steps " )
. public_key
}
DescriptorPublicKey ::SinglePub ( key ) = > key . key ,
}
} ;
self . derive ( index )
. translate_pk_infallible ( | pk | translate ( pk ) , | pkh | translate ( pkh ) . to_pubkeyhash ( ) )
}
}
2021-05-19 13:04:32 +10:00
#[ doc(hidden) ]
2020-08-10 10:49:34 +02:00
#[ macro_export ]
macro_rules ! testutils {
( @ external $descriptors :expr , $child :expr ) = > ( {
2020-11-16 22:07:38 +01:00
use bitcoin ::secp256k1 ::Secp256k1 ;
2021-02-02 20:06:40 -05:00
use miniscript ::descriptor ::{ Descriptor , DescriptorPublicKey , DescriptorTrait } ;
2021-05-19 13:04:32 +10:00
use $crate ::testutils ::TranslateDescriptor ;
2020-08-12 12:51:50 +02:00
2020-11-16 22:07:38 +01:00
let secp = Secp256k1 ::new ( ) ;
2021-02-02 20:06:40 -05:00
let parsed = Descriptor ::< DescriptorPublicKey > ::parse_descriptor ( & secp , & $descriptors . 0 ) . expect ( " Failed to parse descriptor in `testutils!(@external)` " ) . 0 ;
parsed . derive_translated ( & secp , $child ) . address ( bitcoin ::Network ::Regtest ) . expect ( " No address form " )
2020-08-10 10:49:34 +02:00
} ) ;
( @ internal $descriptors :expr , $child :expr ) = > ( {
2021-02-02 20:06:40 -05:00
use bitcoin ::secp256k1 ::Secp256k1 ;
use miniscript ::descriptor ::{ Descriptor , DescriptorPublicKey , DescriptorTrait } ;
2020-08-12 12:51:50 +02:00
2021-05-19 13:04:32 +10:00
use $crate ::testutils ::TranslateDescriptor ;
2021-02-02 20:06:40 -05:00
let secp = Secp256k1 ::new ( ) ;
let parsed = Descriptor ::< DescriptorPublicKey > ::parse_descriptor ( & secp , & $descriptors . 1. expect ( " Missing internal descriptor " ) ) . expect ( " Failed to parse descriptor in `testutils!(@internal)` " ) . 0 ;
parsed . derive_translated ( & secp , $child ) . address ( bitcoin ::Network ::Regtest ) . expect ( " No address form " )
2020-08-10 10:49:34 +02:00
} ) ;
( @ e $descriptors :expr , $child :expr ) = > ( { testutils! ( @ external $descriptors , $child ) } ) ;
( @ i $descriptors :expr , $child :expr ) = > ( { testutils! ( @ internal $descriptors , $child ) } ) ;
2021-05-19 16:10:06 +10:00
( @ tx ( $( ( $( $addr :tt ) * ) = > $amount :expr ) , + ) $( ( @ locktime $locktime :expr ) ) ? $( ( @ confirmations $confirmations :expr ) ) ? $( ( @ replaceable $replaceable :expr ) ) ? ) = > ( {
let outs = vec! [ $( $crate ::testutils ::TestIncomingOutput ::new ( $amount , testutils! ( $( $addr ) * ) ) ) , + ] ;
2020-08-10 10:49:34 +02:00
2021-05-19 16:10:06 +10:00
let locktime = None ::< i64 > $( . or ( Some ( $locktime ) ) ) ? ;
2020-08-10 10:49:34 +02:00
2021-05-19 16:10:06 +10:00
let min_confirmations = None ::< u64 > $( . or ( Some ( $confirmations ) ) ) ? ;
let replaceable = None ::< bool > $( . or ( Some ( $replaceable ) ) ) ? ;
2020-08-10 10:49:34 +02:00
2021-05-19 13:04:32 +10:00
$crate ::testutils ::TestIncomingTx ::new ( outs , min_confirmations , locktime , replaceable )
2020-08-10 10:49:34 +02:00
} ) ;
( @ literal $key :expr ) = > ( {
let key = $key . to_string ( ) ;
( key , None ::< String > , None ::< String > )
} ) ;
2021-05-19 13:04:32 +10:00
( @ generate_xprv $( $external_path :expr ) ? $( , $internal_path :expr ) ? ) = > ( {
2020-08-10 10:49:34 +02:00
use rand ::Rng ;
let mut seed = [ 0 u8 ; 32 ] ;
rand ::thread_rng ( ) . fill ( & mut seed [ .. ] ) ;
let key = bitcoin ::util ::bip32 ::ExtendedPrivKey ::new_master (
bitcoin ::Network ::Testnet ,
& seed ,
) ;
2021-05-19 16:10:06 +10:00
let external_path = None ::< String > $( . or ( Some ( $external_path . to_string ( ) ) ) ) ? ;
let internal_path = None ::< String > $( . or ( Some ( $internal_path . to_string ( ) ) ) ) ? ;
2020-08-10 10:49:34 +02:00
( key . unwrap ( ) . to_string ( ) , external_path , internal_path )
} ) ;
( @ generate_wif ) = > ( {
use rand ::Rng ;
let mut key = [ 0 u8 ; bitcoin ::secp256k1 ::constants ::SECRET_KEY_SIZE ] ;
rand ::thread_rng ( ) . fill ( & mut key [ .. ] ) ;
( bitcoin ::PrivateKey {
compressed : true ,
network : bitcoin ::Network ::Testnet ,
key : bitcoin ::secp256k1 ::SecretKey ::from_slice ( & key ) . unwrap ( ) ,
} . to_string ( ) , None ::< String > , None ::< String > )
} ) ;
( @ keys ( $( $alias :expr = > ( $( $key_type :tt ) * ) ) , + ) ) = > ( {
let mut map = std ::collections ::HashMap ::new ( ) ;
$(
let alias : & str = $alias ;
map . insert ( alias , testutils! ( $( $key_type ) * ) ) ;
) +
map
} ) ;
2021-05-19 16:10:06 +10:00
( @ descriptors ( $external_descriptor :expr ) $( ( $internal_descriptor :expr ) ) ? $( ( @ keys $( $keys :tt ) * ) ) * ) = > ( {
2020-08-10 10:49:34 +02:00
use std ::str ::FromStr ;
use std ::collections ::HashMap ;
2021-05-19 13:04:32 +10:00
use miniscript ::descriptor ::Descriptor ;
2021-02-02 20:06:40 -05:00
use miniscript ::TranslatePk ;
2020-08-12 12:51:50 +02:00
2021-05-19 13:04:32 +10:00
#[ allow(unused_assignments, unused_mut) ]
2020-08-10 10:49:34 +02:00
let mut keys : HashMap < & 'static str , ( String , Option < String > , Option < String > ) > = HashMap ::new ( ) ;
$(
keys = testutils! { @ keys $( $keys ) * } ;
) *
let external : Descriptor < String > = FromStr ::from_str ( $external_descriptor ) . unwrap ( ) ;
2021-02-02 20:06:40 -05:00
let external : Descriptor < String > = external . translate_pk_infallible ::< _ , _ > ( | k | {
2020-08-10 10:49:34 +02:00
if let Some ( ( key , ext_path , _ ) ) = keys . get ( & k . as_str ( ) ) {
2021-02-02 20:06:40 -05:00
format! ( " {} {} " , key , ext_path . as_ref ( ) . unwrap_or ( & " " . into ( ) ) )
2020-08-10 10:49:34 +02:00
} else {
2021-02-02 20:06:40 -05:00
k . clone ( )
2020-08-10 10:49:34 +02:00
}
} , | kh | {
if let Some ( ( key , ext_path , _ ) ) = keys . get ( & kh . as_str ( ) ) {
2021-02-02 20:06:40 -05:00
format! ( " {} {} " , key , ext_path . as_ref ( ) . unwrap_or ( & " " . into ( ) ) )
2020-08-10 10:49:34 +02:00
} else {
2021-02-02 20:06:40 -05:00
kh . clone ( )
2020-08-10 10:49:34 +02:00
}
2021-02-02 20:06:40 -05:00
} ) ;
2020-08-12 12:51:50 +02:00
let external = external . to_string ( ) ;
2020-08-10 10:49:34 +02:00
2021-05-19 16:10:06 +10:00
let internal = None ::< String > $( . or ( {
2020-08-10 10:49:34 +02:00
let string_internal : Descriptor < String > = FromStr ::from_str ( $internal_descriptor ) . unwrap ( ) ;
2021-02-02 20:06:40 -05:00
let string_internal : Descriptor < String > = string_internal . translate_pk_infallible ::< _ , _ > ( | k | {
2020-08-10 10:49:34 +02:00
if let Some ( ( key , _ , int_path ) ) = keys . get ( & k . as_str ( ) ) {
2021-02-02 20:06:40 -05:00
format! ( " {} {} " , key , int_path . as_ref ( ) . unwrap_or ( & " " . into ( ) ) )
2020-08-10 10:49:34 +02:00
} else {
2021-02-02 20:06:40 -05:00
k . clone ( )
2020-08-10 10:49:34 +02:00
}
} , | kh | {
if let Some ( ( key , _ , int_path ) ) = keys . get ( & kh . as_str ( ) ) {
2021-02-02 20:06:40 -05:00
format! ( " {} {} " , key , int_path . as_ref ( ) . unwrap_or ( & " " . into ( ) ) )
2020-08-10 10:49:34 +02:00
} else {
2021-02-02 20:06:40 -05:00
kh . clone ( )
2020-08-10 10:49:34 +02:00
}
2021-02-02 20:06:40 -05:00
} ) ;
2021-05-19 16:10:06 +10:00
Some ( string_internal . to_string ( ) )
} ) ) ? ;
2020-08-10 10:49:34 +02:00
( external , internal )
} )
}