Skip to content

Commit c727cd2

Browse files
ValuedMammalLagginTimes
authored andcommitted
test(rpc): add test_expect_tx_evicted
1 parent 71bf53d commit c727cd2

1 file changed

Lines changed: 106 additions & 0 deletions

File tree

crates/bitcoind_rpc/tests/test_emitter.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,3 +731,109 @@ 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 bitcoin::constants::genesis_block;
742+
use bitcoin::secp256k1::Secp256k1;
743+
use bitcoin::Network;
744+
use std::collections::HashMap;
745+
let env = TestEnv::new()?;
746+
747+
let s = bdk_testenv::utils::DESCRIPTORS[0];
748+
let desc = miniscript::Descriptor::parse_descriptor(&Secp256k1::new(), s)
749+
.unwrap()
750+
.0;
751+
let spk = desc.at_derivation_index(0)?.script_pubkey();
752+
753+
let mut chain = LocalChain::from_genesis_hash(genesis_block(Network::Regtest).block_hash()).0;
754+
let chain_tip = chain.tip().block_id();
755+
756+
let mut index = SpkTxOutIndex::default();
757+
index.insert_spk((), spk.clone());
758+
let mut graph = IndexedTxGraph::<BlockId, _>::new(index);
759+
760+
// Receive tx1.
761+
let _ = env.mine_blocks(100, None)?;
762+
let txid_1 = env.send(
763+
&Address::from_script(&spk, Network::Regtest)?,
764+
Amount::ONE_BTC,
765+
)?;
766+
767+
let mut emitter = Emitter::new(env.rpc_client(), chain.tip(), 1, HashSet::from([txid_1]));
768+
while let Some(emission) = emitter.next_block()? {
769+
let height = emission.block_height();
770+
chain.apply_update(CheckPoint::from_header(&emission.block.header, height))?;
771+
}
772+
773+
let changeset = graph.batch_insert_unconfirmed(emitter.mempool()?.new_txs);
774+
assert!(changeset
775+
.tx_graph
776+
.txs
777+
.iter()
778+
.any(|tx| tx.compute_txid() == txid_1));
779+
let seen_at = graph
780+
.graph()
781+
.get_tx_node(txid_1)
782+
.unwrap()
783+
.last_seen_unconfirmed
784+
.unwrap();
785+
786+
// Double spend tx1.
787+
788+
// Get `prevout` from core.
789+
let core = env.rpc_client();
790+
let tx1 = &core.get_raw_transaction(&txid_1, None)?;
791+
let txin = &tx1.input[0];
792+
let op = txin.previous_output;
793+
794+
// Create `tx1b` using the previous output from tx1.
795+
let utxo = CreateRawTransactionInput {
796+
txid: op.txid,
797+
vout: op.vout,
798+
sequence: None,
799+
};
800+
let addr = core.get_new_address(None, None)?.assume_checked();
801+
let tx = core.create_raw_transaction(
802+
&[utxo],
803+
&HashMap::from([(addr.to_string(), Amount::from_btc(49.99)?)]),
804+
None,
805+
None,
806+
)?;
807+
let res = core.sign_raw_transaction_with_wallet(&tx, None, None)?;
808+
let tx1b = res.transaction()?;
809+
810+
// Send the tx.
811+
let _txid_2 = core.send_raw_transaction(&tx1b)?;
812+
813+
// Retrieve the expected unconfirmed txids and spks from the graph.
814+
let exp_spk_txids = graph
815+
.list_expected_spk_txids(&chain, chain_tip, ..)
816+
.collect::<Vec<_>>();
817+
assert_eq!(exp_spk_txids, vec![(spk, txid_1)]);
818+
819+
// Check that mempool emission contains evicted txid.
820+
let mempool_event = emitter.mempool()?;
821+
assert!(mempool_event.evicted_txids.contains(&txid_1));
822+
823+
// Update graph with evicted tx.
824+
let exp_txids = exp_spk_txids.into_iter().map(|(_, txid)| txid);
825+
let evicted_txids = mempool_event.evicted_txids(exp_txids);
826+
for txid in evicted_txids {
827+
let _ = graph.insert_evicted_at(txid, seen_at);
828+
}
829+
830+
let canonical_txids = graph
831+
.graph()
832+
.list_canonical_txs(&chain, chain_tip)
833+
.map(|tx| tx.tx_node.compute_txid())
834+
.collect::<Vec<_>>();
835+
// tx1 should no longer be canonical.
836+
assert!(!canonical_txids.contains(&txid_1));
837+
838+
Ok(())
839+
}

0 commit comments

Comments
 (0)