@@ -525,3 +525,114 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
525525
526526 Ok ( ( ) )
527527}
528+
529+ #[ test]
530+ fn test_check_fee_calculation ( ) -> anyhow:: Result < ( ) > {
531+ const SEND_AMOUNT : Amount = Amount :: from_sat ( 10_000 ) ;
532+ let env = TestEnv :: new ( ) ?;
533+ let electrum_client = electrum_client:: Client :: new ( env. electrsd . electrum_url . as_str ( ) ) ?;
534+ let client = BdkElectrumClient :: new ( electrum_client) ;
535+
536+ let spk_to_track = ScriptBuf :: new_p2wsh ( & WScriptHash :: all_zeros ( ) ) ;
537+ let addr_to_track = Address :: from_script ( & spk_to_track, bdk_chain:: bitcoin:: Network :: Regtest ) ?;
538+
539+ // Setup receiver.
540+ let ( mut recv_chain, _) = LocalChain :: from_genesis_hash ( env. bitcoind . client . get_block_hash ( 0 ) ?) ;
541+ let mut recv_graph = IndexedTxGraph :: < ConfirmationBlockTime , _ > :: new ( {
542+ let mut recv_index = SpkTxOutIndex :: default ( ) ;
543+ recv_index. insert_spk ( ( ) , spk_to_track. clone ( ) ) ;
544+ recv_index
545+ } ) ;
546+
547+ // Mine some blocks.
548+ env. mine_blocks ( 101 , None ) ?;
549+
550+ // Send a preliminary tx such that the new utxo in Core's wallet
551+ // becomes the input of the next tx
552+ let new_addr = env
553+ . rpc_client ( )
554+ . get_new_address ( None , None ) ?
555+ . assume_checked ( ) ;
556+ let prev_amt = SEND_AMOUNT + Amount :: from_sat ( 1650 ) ;
557+ env. send ( & new_addr, prev_amt) ?;
558+ let prev_hash_block = env. mine_blocks ( 1 , None ) ?. into_iter ( ) . nth ( 0 ) ;
559+
560+ let txid = env. send ( & addr_to_track, SEND_AMOUNT ) ?;
561+
562+ // Mine a block to confirm sent tx.
563+ let hash_block = env. mine_blocks ( 1 , None ) ?. into_iter ( ) . nth ( 0 ) ;
564+
565+ // Look at the tx we just sent, it should have 1 input and 1 output
566+ let tx = env. rpc_client ( ) . get_raw_transaction_info ( & txid, hash_block. as_ref ( ) ) ?;
567+ assert_eq ! ( tx. vin. len( ) , 1 ) ;
568+ assert_eq ! ( tx. vout. len( ) , 1 ) ;
569+ let vin = & tx. vin [ 0 ] ;
570+ let prev_txid = vin. txid . unwrap ( ) ;
571+ let vout = vin. vout . unwrap ( ) ;
572+ let outpoint = bdk_chain:: bitcoin:: OutPoint :: new ( prev_txid, vout) ;
573+
574+ // Get the txout of the previous tx
575+ let prev_tx = env
576+ . rpc_client ( )
577+ . get_raw_transaction_info ( & prev_txid, prev_hash_block. as_ref ( ) ) ?;
578+ let txout = prev_tx
579+ . vout
580+ . iter ( )
581+ . find ( |txout| txout. value == prev_amt)
582+ . unwrap ( ) ;
583+ let script_pubkey = ScriptBuf :: from_bytes ( txout. script_pub_key . hex . to_vec ( ) ) ;
584+ let txout = bdk_chain:: bitcoin:: TxOut {
585+ value : txout. value ,
586+ script_pubkey,
587+ } ;
588+
589+ // Sync up to tip.
590+ env. wait_until_electrum_sees_block ( Duration :: from_secs ( 6 ) ) ?;
591+ let _ = sync_with_electrum (
592+ & client,
593+ [ spk_to_track. clone ( ) ] ,
594+ & mut recv_chain,
595+ & mut recv_graph,
596+ ) ?;
597+
598+ // Check the graph update contains the right floating txout
599+ let graph_txout = recv_graph
600+ . graph ( )
601+ . all_txouts ( )
602+ . find ( |( _op, txout) | txout. value == prev_amt)
603+ . unwrap ( ) ;
604+ assert_eq ! ( graph_txout, ( outpoint, & txout) ) ;
605+
606+ // Check to see if tx is confirmed.
607+ assert_eq ! (
608+ get_balance( & recv_chain, & recv_graph) ?,
609+ Balance {
610+ confirmed: SEND_AMOUNT ,
611+ ..Balance :: default ( )
612+ } ,
613+ ) ;
614+
615+ for tx in recv_graph. graph ( ) . full_txs ( ) {
616+ // Retrieve the calculated fee from `TxGraph`, which will panic if we do not have the
617+ // floating txouts available from the transaction's previous outputs.
618+ let fee = recv_graph
619+ . graph ( )
620+ . calculate_fee ( & tx. tx )
621+ . expect ( "fee must exist" ) ;
622+
623+ // Retrieve the fee in the transaction data from `bitcoind`.
624+ let tx_fee = env
625+ . bitcoind
626+ . client
627+ . get_transaction ( & tx. txid , None )
628+ . expect ( "Tx must exist" )
629+ . fee
630+ . expect ( "Fee must exist" )
631+ . abs ( )
632+ . to_sat ( ) as u64 ;
633+
634+ // Check that the calculated fee matches the fee from the transaction data.
635+ assert_eq ! ( fee, Amount :: from_sat( tx_fee) ) ; // 1650sat
636+ }
637+ Ok ( ( ) )
638+ }
0 commit comments