2021-05-19 15:52:51 +10:00
use crate ::testutils ::TestIncomingTx ;
use bitcoin ::consensus ::encode ::{ deserialize , serialize } ;
use bitcoin ::hashes ::hex ::{ FromHex , ToHex } ;
use bitcoin ::hashes ::sha256d ;
use bitcoin ::{ Address , Amount , Script , Transaction , Txid } ;
2021-10-27 13:42:01 -07:00
pub use bitcoincore_rpc ::bitcoincore_rpc_json ::AddressType ;
pub use bitcoincore_rpc ::{ Auth , Client as RpcClient , RpcApi } ;
2021-05-19 15:52:51 +10:00
use core ::str ::FromStr ;
2021-06-28 15:04:17 +02:00
use electrsd ::bitcoind ::BitcoinD ;
2021-10-27 13:42:01 -07:00
use electrsd ::{ bitcoind , ElectrsD } ;
2021-05-19 15:52:51 +10:00
pub use electrum_client ::{ Client as ElectrumClient , ElectrumApi } ;
#[ allow(unused_imports) ]
2021-08-03 12:15:16 +02:00
use log ::{ debug , error , info , log_enabled , trace , Level } ;
2021-05-19 15:52:51 +10:00
use std ::collections ::HashMap ;
use std ::env ;
use std ::ops ::Deref ;
use std ::time ::Duration ;
pub struct TestClient {
2021-06-17 13:48:46 +02:00
pub bitcoind : BitcoinD ,
pub electrsd : ElectrsD ,
2021-05-19 15:52:51 +10:00
}
impl TestClient {
2021-06-17 13:48:46 +02:00
pub fn new ( bitcoind_exe : String , electrs_exe : String ) -> Self {
debug! ( " launching {} and {} " , & bitcoind_exe , & electrs_exe ) ;
2021-10-27 13:42:01 -07:00
let mut conf = bitcoind ::Conf ::default ( ) ;
conf . view_stdout = log_enabled! ( Level ::Debug ) ;
2021-08-03 12:15:16 +02:00
let bitcoind = BitcoinD ::with_conf ( bitcoind_exe , & conf ) . unwrap ( ) ;
2021-06-18 14:28:40 +02:00
2021-10-27 13:42:01 -07:00
let mut conf = electrsd ::Conf ::default ( ) ;
conf . view_stderr = log_enabled! ( Level ::Debug ) ;
conf . http_enabled = cfg! ( feature = " test-esplora " ) ;
2021-06-18 14:28:40 +02:00
2021-07-26 17:03:09 +02:00
let electrsd = ElectrsD ::with_conf ( electrs_exe , & bitcoind , & conf ) . unwrap ( ) ;
2021-06-17 13:48:46 +02:00
let node_address = bitcoind . client . get_new_address ( None , None ) . unwrap ( ) ;
bitcoind
. client
. generate_to_address ( 101 , & node_address )
. unwrap ( ) ;
2021-05-19 15:52:51 +10:00
2021-06-17 13:48:46 +02:00
let mut test_client = TestClient { bitcoind , electrsd } ;
TestClient ::wait_for_block ( & mut test_client , 101 ) ;
test_client
2021-05-19 15:52:51 +10:00
}
fn wait_for_tx ( & mut self , txid : Txid , monitor_script : & Script ) {
// wait for electrs to index the tx
exponential_backoff_poll ( | | {
2021-06-17 16:03:33 +02:00
self . electrsd . trigger ( ) . unwrap ( ) ;
2021-05-19 15:52:51 +10:00
trace! ( " wait_for_tx {} " , txid ) ;
2021-06-17 13:48:46 +02:00
self . electrsd
. client
2021-05-19 15:52:51 +10:00
. script_get_history ( monitor_script )
. unwrap ( )
. iter ( )
. position ( | entry | entry . tx_hash = = txid )
} ) ;
}
fn wait_for_block ( & mut self , min_height : usize ) {
2021-06-17 13:48:46 +02:00
self . electrsd . client . block_headers_subscribe ( ) . unwrap ( ) ;
2021-05-19 15:52:51 +10:00
loop {
let header = exponential_backoff_poll ( | | {
2021-06-17 16:03:33 +02:00
self . electrsd . trigger ( ) . unwrap ( ) ;
2021-06-17 13:48:46 +02:00
self . electrsd . client . ping ( ) . unwrap ( ) ;
self . electrsd . client . block_headers_pop ( ) . unwrap ( )
2021-05-19 15:52:51 +10:00
} ) ;
if header . height > = min_height {
break ;
}
}
}
pub fn receive ( & mut self , meta_tx : TestIncomingTx ) -> Txid {
assert! (
! meta_tx . output . is_empty ( ) ,
" can't create a transaction with no outputs "
) ;
let mut map = HashMap ::new ( ) ;
let mut required_balance = 0 ;
for out in & meta_tx . output {
required_balance + = out . value ;
map . insert ( out . to_address . clone ( ) , Amount ::from_sat ( out . value ) ) ;
}
if self . get_balance ( None , None ) . unwrap ( ) < Amount ::from_sat ( required_balance ) {
panic! ( " Insufficient funds in bitcoind. Please generate a few blocks with: `bitcoin-cli generatetoaddress 10 {} ` " , self . get_new_address ( None , None ) . unwrap ( ) ) ;
}
// FIXME: core can't create a tx with two outputs to the same address
let tx = self
. create_raw_transaction_hex ( & [ ] , & map , meta_tx . locktime , meta_tx . replaceable )
. unwrap ( ) ;
let tx = self . fund_raw_transaction ( tx , None , None ) . unwrap ( ) ;
let mut tx : Transaction = deserialize ( & tx . hex ) . unwrap ( ) ;
if let Some ( true ) = meta_tx . replaceable {
// for some reason core doesn't set this field right
for input in & mut tx . input {
input . sequence = 0xFFFFFFFD ;
}
}
let tx = self
. sign_raw_transaction_with_wallet ( & serialize ( & tx ) , None , None )
. unwrap ( ) ;
// broadcast through electrum so that it caches the tx immediately
2021-06-17 13:48:46 +02:00
2021-05-19 15:52:51 +10:00
let txid = self
2021-06-17 13:48:46 +02:00
. electrsd
. client
2021-05-19 15:52:51 +10:00
. transaction_broadcast ( & deserialize ( & tx . hex ) . unwrap ( ) )
. unwrap ( ) ;
2021-06-17 13:48:46 +02:00
debug! ( " broadcasted to electrum {} " , txid ) ;
2021-05-19 15:52:51 +10:00
if let Some ( num ) = meta_tx . min_confirmations {
self . generate ( num , None ) ;
}
let monitor_script = Address ::from_str ( & meta_tx . output [ 0 ] . to_address )
. unwrap ( )
. script_pubkey ( ) ;
self . wait_for_tx ( txid , & monitor_script ) ;
debug! ( " Sent tx: {} " , txid ) ;
txid
}
pub fn bump_fee ( & mut self , txid : & Txid ) -> Txid {
let tx = self . get_raw_transaction_info ( txid , None ) . unwrap ( ) ;
assert! (
tx . confirmations . is_none ( ) ,
" Can't bump tx {} because it's already confirmed " ,
txid
) ;
let bumped : serde_json ::Value = self . call ( " bumpfee " , & [ txid . to_string ( ) . into ( ) ] ) . unwrap ( ) ;
let new_txid = Txid ::from_str ( & bumped [ " txid " ] . as_str ( ) . unwrap ( ) . to_string ( ) ) . unwrap ( ) ;
let monitor_script =
tx . vout [ 0 ] . script_pub_key . addresses . as_ref ( ) . unwrap ( ) [ 0 ] . script_pubkey ( ) ;
self . wait_for_tx ( new_txid , & monitor_script ) ;
debug! ( " Bumped {}, new txid {} " , txid , new_txid ) ;
new_txid
}
pub fn generate_manually ( & mut self , txs : Vec < Transaction > ) -> String {
use bitcoin ::blockdata ::block ::{ Block , BlockHeader } ;
use bitcoin ::blockdata ::script ::Builder ;
use bitcoin ::blockdata ::transaction ::{ OutPoint , TxIn , TxOut } ;
use bitcoin ::hash_types ::{ BlockHash , TxMerkleNode } ;
let block_template : serde_json ::Value = self
. call ( " getblocktemplate " , & [ json! ( { " rules " : [ " segwit " ] } ) ] )
. unwrap ( ) ;
trace! ( " getblocktemplate: {:#?} " , block_template ) ;
let header = BlockHeader {
version : block_template [ " version " ] . as_i64 ( ) . unwrap ( ) as i32 ,
prev_blockhash : BlockHash ::from_hex (
block_template [ " previousblockhash " ] . as_str ( ) . unwrap ( ) ,
)
. unwrap ( ) ,
merkle_root : TxMerkleNode ::default ( ) ,
time : block_template [ " curtime " ] . as_u64 ( ) . unwrap ( ) as u32 ,
bits : u32 ::from_str_radix ( block_template [ " bits " ] . as_str ( ) . unwrap ( ) , 16 ) . unwrap ( ) ,
nonce : 0 ,
} ;
debug! ( " header: {:#?} " , header ) ;
let height = block_template [ " height " ] . as_u64 ( ) . unwrap ( ) as i64 ;
let witness_reserved_value : Vec < u8 > = sha256d ::Hash ::default ( ) . as_ref ( ) . into ( ) ;
// burn block subsidy and fees, not a big deal
let mut coinbase_tx = Transaction {
version : 1 ,
lock_time : 0 ,
input : vec ! [ TxIn {
previous_output : OutPoint ::null ( ) ,
script_sig : Builder ::new ( ) . push_int ( height ) . into_script ( ) ,
sequence : 0xFFFFFFFF ,
witness : vec ! [ witness_reserved_value ] ,
} ] ,
output : vec ! [ ] ,
} ;
let mut txdata = vec! [ coinbase_tx . clone ( ) ] ;
txdata . extend_from_slice ( & txs ) ;
let mut block = Block { header , txdata } ;
let witness_root = block . witness_root ( ) ;
let witness_commitment =
Block ::compute_witness_commitment ( & witness_root , & coinbase_tx . input [ 0 ] . witness [ 0 ] ) ;
// now update and replace the coinbase tx
let mut coinbase_witness_commitment_script = vec! [ 0x6a , 0x24 , 0xaa , 0x21 , 0xa9 , 0xed ] ;
coinbase_witness_commitment_script . extend_from_slice ( & witness_commitment ) ;
coinbase_tx . output . push ( TxOut {
value : 0 ,
script_pubkey : coinbase_witness_commitment_script . into ( ) ,
} ) ;
block . txdata [ 0 ] = coinbase_tx ;
// set merkle root
let merkle_root = block . merkle_root ( ) ;
block . header . merkle_root = merkle_root ;
assert! ( block . check_merkle_root ( ) ) ;
assert! ( block . check_witness_commitment ( ) ) ;
// now do PoW :)
let target = block . header . target ( ) ;
while block . header . validate_pow ( & target ) . is_err ( ) {
block . header . nonce = block . header . nonce . checked_add ( 1 ) . unwrap ( ) ; // panic if we run out of nonces
}
let block_hex : String = serialize ( & block ) . to_hex ( ) ;
debug! ( " generated block hex: {} " , block_hex ) ;
2021-06-17 13:48:46 +02:00
self . electrsd . client . block_headers_subscribe ( ) . unwrap ( ) ;
2021-05-19 15:52:51 +10:00
let submit_result : serde_json ::Value =
self . call ( " submitblock " , & [ block_hex . into ( ) ] ) . unwrap ( ) ;
debug! ( " submitblock: {:?} " , submit_result ) ;
assert! (
submit_result . is_null ( ) ,
" submitblock error: {:?} " ,
submit_result . as_str ( )
) ;
self . wait_for_block ( height as usize ) ;
block . header . block_hash ( ) . to_hex ( )
}
pub fn generate ( & mut self , num_blocks : u64 , address : Option < Address > ) {
let address = address . unwrap_or_else ( | | self . get_new_address ( None , None ) . unwrap ( ) ) ;
let hashes = self . generate_to_address ( num_blocks , & address ) . unwrap ( ) ;
let best_hash = hashes . last ( ) . unwrap ( ) ;
let height = self . get_block_info ( best_hash ) . unwrap ( ) . height ;
self . wait_for_block ( height ) ;
debug! ( " Generated blocks to new height {} " , height ) ;
}
pub fn invalidate ( & mut self , num_blocks : u64 ) {
2021-06-17 13:48:46 +02:00
self . electrsd . client . block_headers_subscribe ( ) . unwrap ( ) ;
2021-05-19 15:52:51 +10:00
let best_hash = self . get_best_block_hash ( ) . unwrap ( ) ;
let initial_height = self . get_block_info ( & best_hash ) . unwrap ( ) . height ;
let mut to_invalidate = best_hash ;
for i in 1 ..= num_blocks {
trace! (
" Invalidating block {}/{} ({}) " ,
i ,
num_blocks ,
to_invalidate
) ;
self . invalidate_block ( & to_invalidate ) . unwrap ( ) ;
to_invalidate = self . get_best_block_hash ( ) . unwrap ( ) ;
}
self . wait_for_block ( initial_height - num_blocks as usize ) ;
debug! (
" Invalidated {} blocks to new height of {} " ,
num_blocks ,
initial_height - num_blocks as usize
) ;
}
pub fn reorg ( & mut self , num_blocks : u64 ) {
self . invalidate ( num_blocks ) ;
self . generate ( num_blocks , None ) ;
}
pub fn get_node_address ( & self , address_type : Option < AddressType > ) -> Address {
Address ::from_str (
& self
. get_new_address ( None , address_type )
. unwrap ( )
. to_string ( ) ,
)
. unwrap ( )
}
}
pub fn get_electrum_url ( ) -> String {
env ::var ( " BDK_ELECTRUM_URL " ) . unwrap_or_else ( | _ | " tcp://127.0.0.1:50001 " . to_string ( ) )
}
impl Deref for TestClient {
type Target = RpcClient ;
fn deref ( & self ) -> & Self ::Target {
2021-06-17 13:48:46 +02:00
& self . bitcoind . client
2021-05-19 15:52:51 +10:00
}
}
impl Default for TestClient {
fn default ( ) -> Self {
2021-06-23 14:47:45 +02:00
let bitcoind_exe = env ::var ( " BITCOIND_EXE " )
. ok ( )
2021-06-28 15:04:17 +02:00
. or ( bitcoind ::downloaded_exe_path ( ) )
2021-06-23 14:47:45 +02:00
. expect (
" you should provide env var BITCOIND_EXE or specifiy a bitcoind version feature " ,
) ;
2021-06-28 15:04:17 +02:00
let electrs_exe = env ::var ( " ELECTRS_EXE " )
. ok ( )
. or ( electrsd ::downloaded_exe_path ( ) )
. expect (
" you should provide env var ELECTRS_EXE or specifiy a electrsd version feature " ,
) ;
2021-06-17 13:48:46 +02:00
Self ::new ( bitcoind_exe , electrs_exe )
2021-05-19 15:52:51 +10:00
}
}
fn exponential_backoff_poll < T , F > ( mut poll : F ) -> T
where
F : FnMut ( ) -> Option < T > ,
{
let mut delay = Duration ::from_millis ( 64 ) ;
loop {
match poll ( ) {
Some ( data ) = > break data ,
None if delay . as_millis ( ) < 512 = > delay = delay . mul_f32 ( 2.0 ) ,
None = > { }
}
std ::thread ::sleep ( delay ) ;
}
}
2021-05-16 15:07:55 +10:00
/// This macro runs blockchain tests against a `Blockchain` implementation. It requires access to a
/// Bitcoin core wallet via RPC. At the moment you have to dig into the code yourself and look at
/// the setup required to run the tests yourself.
#[ macro_export ]
macro_rules ! bdk_blockchain_tests {
2021-05-19 13:04:32 +10:00
(
2021-06-16 12:39:59 +02:00
fn $_fn_name :ident ( $( $test_client :ident : & TestClient ) ? $(, ) ? ) -> $blockchain :ty $block :block ) = > {
2021-05-19 13:04:32 +10:00
#[ cfg(test) ]
2021-05-16 15:07:55 +10:00
mod bdk_blockchain_tests {
2021-05-19 13:04:32 +10:00
use $crate ::bitcoin ::Network ;
2021-05-19 15:52:51 +10:00
use $crate ::testutils ::blockchain_tests ::TestClient ;
2021-05-19 13:04:32 +10:00
use $crate ::blockchain ::noop_progress ;
use $crate ::database ::MemoryDatabase ;
use $crate ::types ::KeychainKind ;
use $crate ::{ Wallet , FeeRate } ;
use $crate ::testutils ;
2021-05-16 15:07:55 +10:00
use super ::* ;
2021-06-16 12:39:59 +02:00
#[ allow(unused_variables) ]
fn get_blockchain ( test_client : & TestClient ) -> $blockchain {
$( let $test_client = test_client ; ) ?
2021-05-16 15:07:55 +10:00
$block
}
2021-06-16 12:39:59 +02:00
fn get_wallet_from_descriptors ( descriptors : & ( String , Option < String > ) , test_client : & TestClient ) -> Wallet < $blockchain , MemoryDatabase > {
Wallet ::new ( & descriptors . 0. to_string ( ) , descriptors . 1. as_ref ( ) , Network ::Regtest , MemoryDatabase ::new ( ) , get_blockchain ( test_client ) ) . unwrap ( )
2021-05-16 15:07:55 +10:00
}
fn init_single_sig ( ) -> ( Wallet < $blockchain , MemoryDatabase > , ( String , Option < String > ) , TestClient ) {
2021-05-21 13:21:59 +10:00
let _ = env_logger ::try_init ( ) ;
2021-05-16 15:07:55 +10:00
let descriptors = testutils! {
@ descriptors ( " wpkh(Alice) " ) ( " wpkh(Alice) " ) ( @ keys ( " Alice " = > ( @ generate_xprv " /44'/0'/0'/0/* " , " /44'/0'/0'/1/* " ) ) )
} ;
let test_client = TestClient ::default ( ) ;
2021-06-16 12:39:59 +02:00
let wallet = get_wallet_from_descriptors ( & descriptors , & test_client ) ;
2021-05-16 15:07:55 +10:00
2021-05-17 17:20:32 +02:00
// rpc need to call import_multi before receiving any tx, otherwise will not see tx in the mempool
2021-06-01 14:18:40 +02:00
#[ cfg(feature = " test-rpc " ) ]
2021-05-17 17:20:32 +02:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
( wallet , descriptors , test_client )
}
#[ test ]
fn test_sync_simple ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let tx = testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ;
println! ( " {:?} " , tx ) ;
let txid = test_client . receive ( tx ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
assert_eq! ( wallet . list_unspent ( ) . unwrap ( ) [ 0 ] . keychain , KeychainKind ::External , " incorrect keychain kind " ) ;
2021-05-16 15:07:55 +10:00
let list_tx_item = & wallet . list_transactions ( false ) . unwrap ( ) [ 0 ] ;
2021-05-17 17:20:32 +02:00
assert_eq! ( list_tx_item . txid , txid , " incorrect txid " ) ;
assert_eq! ( list_tx_item . received , 50_000 , " incorrect received " ) ;
assert_eq! ( list_tx_item . sent , 0 , " incorrect sent " ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( list_tx_item . confirmation_time , None , " incorrect confirmation time " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_stop_gap_20 ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 5 ) = > 50_000 )
} ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 25 ) = > 50_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 100_000 , " incorrect balance " ) ;
assert_eq! ( wallet . list_transactions ( false ) . unwrap ( ) . len ( ) , 2 , " incorrect number of txs " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_before_and_after_receive ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 0 ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
assert_eq! ( wallet . list_transactions ( false ) . unwrap ( ) . len ( ) , 1 , " incorrect number of txs " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_multiple_outputs_same_tx ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let txid = test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 , ( @ external descriptors , 1 ) = > 25_000 , ( @ external descriptors , 5 ) = > 30_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 105_000 , " incorrect balance " ) ;
assert_eq! ( wallet . list_transactions ( false ) . unwrap ( ) . len ( ) , 1 , " incorrect number of txs " ) ;
assert_eq! ( wallet . list_unspent ( ) . unwrap ( ) . len ( ) , 3 , " incorrect number of unspents " ) ;
2021-05-16 15:07:55 +10:00
let list_tx_item = & wallet . list_transactions ( false ) . unwrap ( ) [ 0 ] ;
2021-05-17 17:20:32 +02:00
assert_eq! ( list_tx_item . txid , txid , " incorrect txid " ) ;
assert_eq! ( list_tx_item . received , 105_000 , " incorrect received " ) ;
assert_eq! ( list_tx_item . sent , 0 , " incorrect sent " ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( list_tx_item . confirmation_time , None , " incorrect confirmation_time " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_receive_multi ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 5 ) = > 25_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 75_000 , " incorrect balance " ) ;
assert_eq! ( wallet . list_transactions ( false ) . unwrap ( ) . len ( ) , 2 , " incorrect number of txs " ) ;
assert_eq! ( wallet . list_unspent ( ) . unwrap ( ) . len ( ) , 2 , " incorrect number of unspent " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_address_reuse ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 25_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 75_000 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_receive_rbf_replaced ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let txid = test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 ) ( @ replaceable true )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
assert_eq! ( wallet . list_transactions ( false ) . unwrap ( ) . len ( ) , 1 , " incorrect number of txs " ) ;
assert_eq! ( wallet . list_unspent ( ) . unwrap ( ) . len ( ) , 1 , " incorrect unspent " ) ;
2021-05-16 15:07:55 +10:00
let list_tx_item = & wallet . list_transactions ( false ) . unwrap ( ) [ 0 ] ;
2021-05-17 17:20:32 +02:00
assert_eq! ( list_tx_item . txid , txid , " incorrect txid " ) ;
assert_eq! ( list_tx_item . received , 50_000 , " incorrect received " ) ;
assert_eq! ( list_tx_item . sent , 0 , " incorrect sent " ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( list_tx_item . confirmation_time , None , " incorrect confirmation_time " ) ;
2021-05-16 15:07:55 +10:00
let new_txid = test_client . bump_fee ( & txid ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance after bump " ) ;
assert_eq! ( wallet . list_transactions ( false ) . unwrap ( ) . len ( ) , 1 , " incorrect number of txs after bump " ) ;
assert_eq! ( wallet . list_unspent ( ) . unwrap ( ) . len ( ) , 1 , " incorrect unspent after bump " ) ;
2021-05-16 15:07:55 +10:00
let list_tx_item = & wallet . list_transactions ( false ) . unwrap ( ) [ 0 ] ;
2021-05-17 17:20:32 +02:00
assert_eq! ( list_tx_item . txid , new_txid , " incorrect txid after bump " ) ;
assert_eq! ( list_tx_item . received , 50_000 , " incorrect received after bump " ) ;
assert_eq! ( list_tx_item . sent , 0 , " incorrect sent after bump " ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( list_tx_item . confirmation_time , None , " incorrect height after bump " ) ;
2021-05-16 15:07:55 +10:00
}
2021-05-18 15:21:48 +10:00
// FIXME: I would like this to be cfg_attr(not(feature = "test-esplora"), ignore) but it
// doesn't work for some reason.
2021-05-19 13:04:32 +10:00
#[ cfg(not(feature = " esplora " )) ]
2021-05-16 15:07:55 +10:00
#[ test ]
fn test_sync_reorg_block ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let txid = test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 ) ( @ confirmations 1 ) ( @ replaceable true )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
assert_eq! ( wallet . list_transactions ( false ) . unwrap ( ) . len ( ) , 1 , " incorrect number of txs " ) ;
assert_eq! ( wallet . list_unspent ( ) . unwrap ( ) . len ( ) , 1 , " incorrect number of unspents " ) ;
2021-05-16 15:07:55 +10:00
let list_tx_item = & wallet . list_transactions ( false ) . unwrap ( ) [ 0 ] ;
2021-05-17 17:20:32 +02:00
assert_eq! ( list_tx_item . txid , txid , " incorrect txid " ) ;
2021-06-12 15:01:44 +02:00
assert! ( list_tx_item . confirmation_time . is_some ( ) , " incorrect confirmation_time " ) ;
2021-05-16 15:07:55 +10:00
// Invalidate 1 block
test_client . invalidate ( 1 ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance after invalidate " ) ;
2021-05-16 15:07:55 +10:00
let list_tx_item = & wallet . list_transactions ( false ) . unwrap ( ) [ 0 ] ;
2021-05-17 17:20:32 +02:00
assert_eq! ( list_tx_item . txid , txid , " incorrect txid after invalidate " ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( list_tx_item . confirmation_time , None , " incorrect confirmation time after invalidate " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_after_send ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
println! ( " {} " , descriptors . 0 ) ;
let node_addr = test_client . get_node_address ( None ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_tx ( ) ;
builder . add_recipient ( node_addr . script_pubkey ( ) , 25_000 ) ;
let ( mut psbt , details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
let tx = psbt . extract_tx ( ) ;
println! ( " {} " , bitcoin ::consensus ::encode ::serialize_hex ( & tx ) ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & tx ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , details . received , " incorrect balance after send " ) ;
2021-05-16 15:07:55 +10:00
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . list_transactions ( false ) . unwrap ( ) . len ( ) , 2 , " incorrect number of txs " ) ;
assert_eq! ( wallet . list_unspent ( ) . unwrap ( ) . len ( ) , 1 , " incorrect number of unspents " ) ;
2021-05-16 15:07:55 +10:00
}
2021-06-12 15:01:44 +02:00
#[ test ]
fn test_update_confirmation_time_after_generate ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
println! ( " {} " , descriptors . 0 ) ;
let node_addr = test_client . get_node_address ( None ) ;
let received_txid = test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
let tx_map = wallet . list_transactions ( false ) . unwrap ( ) . into_iter ( ) . map ( | tx | ( tx . txid , tx ) ) . collect ::< std ::collections ::HashMap < _ , _ > > ( ) ;
let details = tx_map . get ( & received_txid ) . unwrap ( ) ;
assert! ( details . confirmation_time . is_none ( ) ) ;
test_client . generate ( 1 , Some ( node_addr ) ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
let tx_map = wallet . list_transactions ( false ) . unwrap ( ) . into_iter ( ) . map ( | tx | ( tx . txid , tx ) ) . collect ::< std ::collections ::HashMap < _ , _ > > ( ) ;
let details = tx_map . get ( & received_txid ) . unwrap ( ) ;
assert! ( details . confirmation_time . is_some ( ) ) ;
}
2021-05-16 15:07:55 +10:00
#[ test ]
fn test_sync_outgoing_from_scratch ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let node_addr = test_client . get_node_address ( None ) ;
let received_txid = test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_tx ( ) ;
builder . add_recipient ( node_addr . script_pubkey ( ) , 25_000 ) ;
let ( mut psbt , details ) = builder . finish ( ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
2021-05-16 15:07:55 +10:00
let finalized = wallet . sign ( & mut psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
let sent_txid = wallet . broadcast ( & psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , details . received , " incorrect balance after receive " ) ;
2021-05-16 15:07:55 +10:00
// empty wallet
2021-06-16 12:39:59 +02:00
let wallet = get_wallet_from_descriptors ( & descriptors , & test_client ) ;
2021-05-16 15:07:55 +10:00
2021-05-17 17:20:32 +02:00
#[ cfg(feature = " rpc " ) ] // rpc cannot see mempool tx before importmulti
test_client . generate ( 1 , Some ( node_addr ) ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
let tx_map = wallet . list_transactions ( false ) . unwrap ( ) . into_iter ( ) . map ( | tx | ( tx . txid , tx ) ) . collect ::< std ::collections ::HashMap < _ , _ > > ( ) ;
let received = tx_map . get ( & received_txid ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( received . received , 50_000 , " incorrect received from receiver " ) ;
assert_eq! ( received . sent , 0 , " incorrect sent from receiver " ) ;
2021-05-16 15:07:55 +10:00
let sent = tx_map . get ( & sent_txid ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( sent . received , details . received , " incorrect received from sender " ) ;
assert_eq! ( sent . sent , details . sent , " incorrect sent from sender " ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( sent . fee . unwrap_or ( 0 ) , details . fee . unwrap_or ( 0 ) , " incorrect fees from sender " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_long_change_chain ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let node_addr = test_client . get_node_address ( None ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
let mut total_sent = 0 ;
for _ in 0 .. 5 {
let mut builder = wallet . build_tx ( ) ;
builder . add_recipient ( node_addr . script_pubkey ( ) , 5_000 ) ;
let ( mut psbt , details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-06-12 15:01:44 +02:00
total_sent + = 5_000 + details . fee . unwrap_or ( 0 ) ;
2021-05-16 15:07:55 +10:00
}
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 - total_sent , " incorrect balance after chain " ) ;
2021-05-16 15:07:55 +10:00
// empty wallet
2021-05-17 17:20:32 +02:00
2021-06-16 12:39:59 +02:00
let wallet = get_wallet_from_descriptors ( & descriptors , & test_client ) ;
2021-05-17 17:20:32 +02:00
#[ cfg(feature = " rpc " ) ] // rpc cannot see mempool tx before importmulti
test_client . generate ( 1 , Some ( node_addr ) ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 - total_sent , " incorrect balance empty wallet " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
2021-05-17 17:20:32 +02:00
fn test_sync_bump_fee_basic ( ) {
2021-05-16 15:07:55 +10:00
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let node_addr = test_client . get_node_address ( None ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 ) ( @ confirmations 1 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_tx ( ) ;
builder . add_recipient ( node_addr . script_pubkey ( ) . clone ( ) , 5_000 ) . enable_rbf ( ) ;
let ( mut psbt , details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 - details . fee . unwrap_or ( 0 ) - 5_000 , " incorrect balance from fees " ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , details . received , " incorrect balance from received " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_fee_bump ( details . txid ) . unwrap ( ) ;
builder . fee_rate ( FeeRate ::from_sat_per_vb ( 2.1 ) ) ;
let ( mut new_psbt , new_details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut new_psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & new_psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 - new_details . fee . unwrap_or ( 0 ) - 5_000 , " incorrect balance from fees after bump " ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , new_details . received , " incorrect balance from received after bump " ) ;
2021-05-16 15:07:55 +10:00
2021-06-12 15:01:44 +02:00
assert! ( new_details . fee . unwrap_or ( 0 ) > details . fee . unwrap_or ( 0 ) , " incorrect fees " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_bump_fee_remove_change ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let node_addr = test_client . get_node_address ( None ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 ) ( @ confirmations 1 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_tx ( ) ;
builder . add_recipient ( node_addr . script_pubkey ( ) . clone ( ) , 49_000 ) . enable_rbf ( ) ;
let ( mut psbt , details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 1_000 - details . fee . unwrap_or ( 0 ) , " incorrect balance after send " ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , details . received , " incorrect received after send " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_fee_bump ( details . txid ) . unwrap ( ) ;
builder . fee_rate ( FeeRate ::from_sat_per_vb ( 5.0 ) ) ;
let ( mut new_psbt , new_details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut new_psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & new_psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 0 , " incorrect balance after change removal " ) ;
assert_eq! ( new_details . received , 0 , " incorrect received after change removal " ) ;
2021-05-16 15:07:55 +10:00
2021-06-12 15:01:44 +02:00
assert! ( new_details . fee . unwrap_or ( 0 ) > details . fee . unwrap_or ( 0 ) , " incorrect fees " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
2021-06-12 15:01:44 +02:00
fn test_sync_bump_fee_add_input_simple ( ) {
2021-05-16 15:07:55 +10:00
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let node_addr = test_client . get_node_address ( None ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 , ( @ external descriptors , 1 ) = > 25_000 ) ( @ confirmations 1 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 75_000 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_tx ( ) ;
builder . add_recipient ( node_addr . script_pubkey ( ) . clone ( ) , 49_000 ) . enable_rbf ( ) ;
let ( mut psbt , details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 26_000 - details . fee . unwrap_or ( 0 ) , " incorrect balance after send " ) ;
assert_eq! ( details . received , 1_000 - details . fee . unwrap_or ( 0 ) , " incorrect received after send " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_fee_bump ( details . txid ) . unwrap ( ) ;
builder . fee_rate ( FeeRate ::from_sat_per_vb ( 10.0 ) ) ;
let ( mut new_psbt , new_details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut new_psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & new_psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( new_details . sent , 75_000 , " incorrect sent " ) ;
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , new_details . received , " incorrect balance after add input " ) ;
2021-05-16 15:07:55 +10:00
}
#[ test ]
fn test_sync_bump_fee_add_input_no_change ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let node_addr = test_client . get_node_address ( None ) ;
test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 , ( @ external descriptors , 1 ) = > 25_000 ) ( @ confirmations 1 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 75_000 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_tx ( ) ;
builder . add_recipient ( node_addr . script_pubkey ( ) . clone ( ) , 49_000 ) . enable_rbf ( ) ;
let ( mut psbt , details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-06-12 15:01:44 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 26_000 - details . fee . unwrap_or ( 0 ) , " incorrect balance after send " ) ;
assert_eq! ( details . received , 1_000 - details . fee . unwrap_or ( 0 ) , " incorrect received after send " ) ;
2021-05-16 15:07:55 +10:00
let mut builder = wallet . build_fee_bump ( details . txid ) . unwrap ( ) ;
builder . fee_rate ( FeeRate ::from_sat_per_vb ( 123.0 ) ) ;
let ( mut new_psbt , new_details ) = builder . finish ( ) . unwrap ( ) ;
println! ( " {:#?} " , new_details ) ;
let finalized = wallet . sign ( & mut new_psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
2021-10-20 15:34:29 +10:30
wallet . broadcast ( & new_psbt . extract_tx ( ) ) . unwrap ( ) ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( new_details . sent , 75_000 , " incorrect sent " ) ;
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 0 , " incorrect balance after add input " ) ;
assert_eq! ( new_details . received , 0 , " incorrect received after add input " ) ;
2021-05-16 15:07:55 +10:00
}
2021-10-27 16:56:46 +02:00
#[ test ]
fn test_add_data ( ) {
let ( wallet , descriptors , mut test_client ) = init_single_sig ( ) ;
let node_addr = test_client . get_node_address ( None ) ;
let _ = test_client . receive ( testutils! {
@ tx ( ( @ external descriptors , 0 ) = > 50_000 )
} ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 , " incorrect balance " ) ;
let mut builder = wallet . build_tx ( ) ;
let data = [ 42 u8 ; 80 ] ;
builder . add_data ( & data ) ;
let ( mut psbt , details ) = builder . finish ( ) . unwrap ( ) ;
let finalized = wallet . sign ( & mut psbt , Default ::default ( ) ) . unwrap ( ) ;
assert! ( finalized , " Cannot finalize transaction " ) ;
let tx = psbt . extract_tx ( ) ;
let serialized_tx = bitcoin ::consensus ::encode ::serialize ( & tx ) ;
assert! ( serialized_tx . windows ( data . len ( ) ) . any ( | e | e = = data ) , " cannot find op_return data in transaction " ) ;
2021-11-09 15:35:34 +01:00
let sent_txid = wallet . broadcast ( & tx ) . unwrap ( ) ;
2021-10-27 16:56:46 +02:00
test_client . generate ( 1 , Some ( node_addr ) ) ;
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 50_000 - details . fee . unwrap_or ( 0 ) , " incorrect balance after send " ) ;
let tx_map = wallet . list_transactions ( false ) . unwrap ( ) . into_iter ( ) . map ( | tx | ( tx . txid , tx ) ) . collect ::< std ::collections ::HashMap < _ , _ > > ( ) ;
let _ = tx_map . get ( & sent_txid ) . unwrap ( ) ;
}
2021-05-16 15:07:55 +10:00
#[ test ]
fn test_sync_receive_coinbase ( ) {
2021-05-19 13:04:32 +10:00
let ( wallet , _ , mut test_client ) = init_single_sig ( ) ;
2021-05-17 17:20:32 +02:00
let wallet_addr = wallet . get_address ( $crate ::wallet ::AddressIndex ::New ) . unwrap ( ) . address ;
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert_eq! ( wallet . get_balance ( ) . unwrap ( ) , 0 , " incorrect balance " ) ;
2021-05-16 15:07:55 +10:00
test_client . generate ( 1 , Some ( wallet_addr ) ) ;
2021-05-17 17:20:32 +02:00
#[ cfg(feature = " rpc " ) ]
{
// rpc consider coinbase only when mature (100 blocks)
let node_addr = test_client . get_node_address ( None ) ;
test_client . generate ( 100 , Some ( node_addr ) ) ;
}
2021-05-16 15:07:55 +10:00
wallet . sync ( noop_progress ( ) , None ) . unwrap ( ) ;
2021-05-17 17:20:32 +02:00
assert! ( wallet . get_balance ( ) . unwrap ( ) > 0 , " incorrect balance after receiving coinbase " ) ;
2021-05-16 15:07:55 +10:00
}
}
2021-06-16 12:39:59 +02:00
} ;
( fn $fn_name :ident ( $( $tt :tt ) + ) -> $blockchain :ty $block :block ) = > {
compile_error! ( concat! ( " Invalid arguments ` " , stringify! ( $( $tt ) * ) , " ` in the blockchain tests fn. " ) ) ;
compile_error! ( " Only the exact `&TestClient` type is supported, **without** any leading path items. " ) ;
} ;
2021-05-16 15:07:55 +10:00
}