Skip to content

Commit ef753fa

Browse files
ValuedMammalLagginTimes
authored andcommitted
test(rpc): add test_expect_tx_evicted
1 parent 6d2bbb3 commit ef753fa

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

crates/bitcoind_rpc/tests/test_emitter.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,3 +731,108 @@ fn no_agreement_point() -> anyhow::Result<()> {
731731

732732
Ok(())
733733
}
734+
735+
#[test]
736+
fn test_expect_tx_evicted() -> anyhow::Result<()> {
737+
use bdk_bitcoind_rpc::bitcoincore_rpc::bitcoin;
738+
use bdk_bitcoind_rpc::bitcoincore_rpc::bitcoincore_rpc_json::CreateRawTransactionInput;
739+
use bdk_chain::miniscript;
740+
use bdk_chain::spk_txout::SpkTxOutIndex;
741+
use bdk_chain::ConfirmationBlockTime;
742+
use bitcoin::constants::genesis_block;
743+
use bitcoin::secp256k1::Secp256k1;
744+
use bitcoin::Network;
745+
use std::collections::HashMap;
746+
let env = TestEnv::new()?;
747+
748+
let s = bdk_testenv::utils::DESCRIPTORS[0];
749+
let desc = miniscript::Descriptor::parse_descriptor(&Secp256k1::new(), s)
750+
.unwrap()
751+
.0;
752+
let spk = desc.at_derivation_index(0)?.script_pubkey();
753+
754+
let chain = LocalChain::from_genesis_hash(genesis_block(Network::Regtest).block_hash()).0;
755+
let chain_tip = chain.tip().block_id();
756+
757+
let mut index = SpkTxOutIndex::default();
758+
index.insert_spk(("external", 0u32), spk.clone());
759+
let mut graph = IndexedTxGraph::<ConfirmationBlockTime, _>::new(index);
760+
761+
// Receive tx1.
762+
let _ = env.mine_blocks(100, None)?;
763+
let txid_1 = env.send(
764+
&Address::from_script(&spk, Network::Regtest)?,
765+
Amount::ONE_BTC,
766+
)?;
767+
768+
let mut emitter = Emitter::new(env.rpc_client(), chain.tip(), 1);
769+
let changeset = graph.batch_insert_unconfirmed(emitter.mempool()?);
770+
assert!(changeset
771+
.tx_graph
772+
.txs
773+
.iter()
774+
.any(|tx| tx.compute_txid() == txid_1));
775+
let seen_at = graph
776+
.graph()
777+
.get_tx_node(txid_1)
778+
.unwrap()
779+
.last_seen_unconfirmed
780+
.unwrap();
781+
782+
// Double spend tx1.
783+
784+
// Get `prevout` from core.
785+
let core = env.rpc_client();
786+
let tx1 = &core.get_raw_transaction(&txid_1, None)?;
787+
let txin = &tx1.input[0];
788+
let op = txin.previous_output;
789+
790+
// Create `tx1b` using the previous output from tx1.
791+
let utxo = CreateRawTransactionInput {
792+
txid: op.txid,
793+
vout: op.vout,
794+
sequence: None,
795+
};
796+
let addr = core.get_new_address(None, None)?.assume_checked();
797+
let tx = core.create_raw_transaction(
798+
&[utxo],
799+
&HashMap::from([(addr.to_string(), Amount::from_btc(49.99)?)]),
800+
None,
801+
None,
802+
)?;
803+
let res = core.sign_raw_transaction_with_wallet(&tx, None, None)?;
804+
let tx1b = res.transaction()?;
805+
806+
// Send the tx.
807+
let txid_2 = core.send_raw_transaction(&tx1b)?;
808+
809+
// Retrieve the expected unconfirmed txids and spks from the graph.
810+
let exp_spk_txids = graph
811+
.list_expected_spk_txids(&chain, chain_tip, ..)
812+
.collect::<Vec<_>>();
813+
assert_eq!(exp_spk_txids, vec![(spk, txid_1)]);
814+
815+
// Check that mempool emission contains evicted txid.
816+
let mempool_event = emitter.mempool()?;
817+
let unseen_txids: Vec<Txid> = mempool_event
818+
.new_txs
819+
.iter()
820+
.map(|(tx, _)| tx.compute_txid())
821+
.collect();
822+
assert!(unseen_txids.contains(&txid_2));
823+
824+
// Update graph with evicted tx.
825+
let exp_txids = exp_spk_txids.into_iter().map(|(_, txid)| txid);
826+
let evicted_txids = mempool_event.evicted_txids(exp_txids);
827+
for txid in evicted_txids {
828+
let _ = graph.insert_evicted_at(txid, seen_at);
829+
}
830+
831+
assert!(graph
832+
.graph()
833+
.list_canonical_txs(&chain, chain_tip)
834+
.next()
835+
.is_none());
836+
837+
Ok(())
838+
}

0 commit comments

Comments
 (0)