@@ -10,6 +10,8 @@ use bdk_chain::{
1010 Anchor , ChainOracle , ChainPosition , Merge ,
1111} ;
1212use bdk_testenv:: { block_id, hash, utils:: new_tx} ;
13+ use bitcoin:: hex:: FromHex ;
14+ use bitcoin:: Witness ;
1315use bitcoin:: {
1416 absolute, hashes:: Hash , transaction, Amount , BlockHash , OutPoint , ScriptBuf , SignedAmount ,
1517 Transaction , TxIn , TxOut , Txid ,
@@ -282,6 +284,74 @@ fn insert_tx_displaces_txouts() {
282284 assert_eq ! ( tx_graph. get_txout( outpoint) , Some ( txout) ) ;
283285}
284286
287+ #[ test]
288+ fn insert_signed_tx_displaces_unsigned ( ) {
289+ let previous_output = OutPoint :: new ( hash ! ( "prev" ) , 2 ) ;
290+ let unsigned_tx = Transaction {
291+ version : transaction:: Version :: ONE ,
292+ lock_time : absolute:: LockTime :: ZERO ,
293+ input : vec ! [ TxIn {
294+ previous_output,
295+ script_sig: ScriptBuf :: default ( ) ,
296+ sequence: transaction:: Sequence :: ENABLE_RBF_NO_LOCKTIME ,
297+ witness: Witness :: default ( ) ,
298+ } ] ,
299+ output : vec ! [ TxOut {
300+ value: Amount :: from_sat( 24_000 ) ,
301+ script_pubkey: ScriptBuf :: default ( ) ,
302+ } ] ,
303+ } ;
304+ let signed_tx = Transaction {
305+ input : vec ! [ TxIn {
306+ previous_output,
307+ script_sig: ScriptBuf :: default ( ) ,
308+ sequence: transaction:: Sequence :: ENABLE_RBF_NO_LOCKTIME ,
309+ witness: Witness :: from_slice( & [
310+ // Random witness from mempool.space
311+ Vec :: from_hex( "d59118058bf9e8604cec5c0b4a13430b07286482784da313594e932faad074dc4bd27db7cbfff9ad32450db097342d0148ec21c3033b0c27888fd2fd0de2e9b5" )
312+ . unwrap( ) ,
313+ ] ) ,
314+ } ] ,
315+ ..unsigned_tx. clone ( )
316+ } ;
317+
318+ // Signed tx must displace unsigned.
319+ {
320+ let mut tx_graph = TxGraph :: < ConfirmationBlockTime > :: default ( ) ;
321+ let changeset_insert_unsigned = tx_graph. insert_tx ( unsigned_tx. clone ( ) ) ;
322+ let changeset_insert_signed = tx_graph. insert_tx ( signed_tx. clone ( ) ) ;
323+ assert_eq ! (
324+ changeset_insert_unsigned,
325+ ChangeSet {
326+ txs: [ Arc :: new( unsigned_tx. clone( ) ) ] . into( ) ,
327+ ..Default :: default ( )
328+ }
329+ ) ;
330+ assert_eq ! (
331+ changeset_insert_signed,
332+ ChangeSet {
333+ txs: [ Arc :: new( signed_tx. clone( ) ) ] . into( ) ,
334+ ..Default :: default ( )
335+ }
336+ ) ;
337+ }
338+
339+ // Unsigned tx must not displace signed.
340+ {
341+ let mut tx_graph = TxGraph :: < ConfirmationBlockTime > :: default ( ) ;
342+ let changeset_insert_signed = tx_graph. insert_tx ( signed_tx. clone ( ) ) ;
343+ let changeset_insert_unsigned = tx_graph. insert_tx ( unsigned_tx. clone ( ) ) ;
344+ assert_eq ! (
345+ changeset_insert_signed,
346+ ChangeSet {
347+ txs: [ Arc :: new( signed_tx) ] . into( ) ,
348+ ..Default :: default ( )
349+ }
350+ ) ;
351+ assert ! ( changeset_insert_unsigned. is_empty( ) ) ;
352+ }
353+ }
354+
285355#[ test]
286356fn insert_txout_does_not_displace_tx ( ) {
287357 let mut tx_graph = TxGraph :: < ConfirmationBlockTime > :: default ( ) ;
0 commit comments