Skip to content

Commit 161d715

Browse files
committed
test(electrum): Chained mempool sync
Is an spk history contains a tx that spends another unconfirmed tx, the Electrum API will return the tx with a negative height. This should succeed and not panic.
1 parent 7502052 commit 161d715

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

crates/electrum/tests/test_electrum.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@ use bdk_chain::{
55
spk_txout::SpkTxOutIndex,
66
Balance, ConfirmationBlockTime, IndexedTxGraph, Indexer, Merge, TxGraph,
77
};
8+
use bdk_core::bitcoin::Network;
89
use bdk_electrum::BdkElectrumClient;
9-
use bdk_testenv::{anyhow, bitcoincore_rpc::RpcApi, TestEnv};
10+
use bdk_testenv::{
11+
anyhow,
12+
bitcoincore_rpc::{json::CreateRawTransactionInput, RawTx, RpcApi},
13+
TestEnv,
14+
};
1015
use core::time::Duration;
16+
use electrum_client::ElectrumApi;
1117
use std::collections::{BTreeSet, HashSet};
1218
use std::str::FromStr;
1319

@@ -54,6 +60,63 @@ where
5460
Ok(update)
5561
}
5662

63+
/// If an spk history contains a tx that spends another unconfirmed tx (chained mempool history),
64+
/// the Electrum API will return the tx with a negative height. This should succeed and not panic.
65+
#[test]
66+
pub fn chained_mempool_tx_sync() -> anyhow::Result<()> {
67+
let env = TestEnv::new()?;
68+
let rpc_client = env.rpc_client();
69+
let electrum_client = electrum_client::Client::new(env.electrsd.electrum_url.as_str())?;
70+
71+
let tracked_addr = rpc_client
72+
.get_new_address(None, None)?
73+
.require_network(Network::Regtest)?;
74+
75+
env.mine_blocks(100, None)?;
76+
77+
// First unconfirmed tx.
78+
env.send(&tracked_addr, Amount::from_btc(1.0)?)?;
79+
80+
// Create second unconfirmed tx that spends the first.
81+
let utxo = rpc_client
82+
.list_unspent(None, Some(0), None, Some(true), None)?
83+
.into_iter()
84+
.find(|utxo| utxo.script_pub_key == tracked_addr.script_pubkey())
85+
.expect("must find the newly created utxo");
86+
let tx_that_spends_unconfirmed = rpc_client.create_raw_transaction(
87+
&[CreateRawTransactionInput {
88+
txid: utxo.txid,
89+
vout: utxo.vout,
90+
sequence: None,
91+
}],
92+
&[(
93+
tracked_addr.to_string(),
94+
utxo.amount - Amount::from_sat(1000),
95+
)]
96+
.into(),
97+
None,
98+
None,
99+
)?;
100+
let signed_tx = rpc_client
101+
.sign_raw_transaction_with_wallet(tx_that_spends_unconfirmed.raw_hex(), None, None)?
102+
.transaction()?;
103+
rpc_client.send_raw_transaction(signed_tx.raw_hex())?;
104+
105+
env.wait_until_electrum_sees_txid(signed_tx.compute_txid(), Duration::from_secs(5))?;
106+
107+
let spk_history = electrum_client.script_get_history(&tracked_addr.script_pubkey())?;
108+
assert!(
109+
spk_history.into_iter().any(|tx_res| tx_res.height < 0),
110+
"must find tx with negative height"
111+
);
112+
113+
let client = BdkElectrumClient::new(electrum_client);
114+
let request = SyncRequest::builder().spks(core::iter::once(tracked_addr.script_pubkey()));
115+
let _response = client.sync(request, 1, false)?;
116+
117+
Ok(())
118+
}
119+
57120
#[test]
58121
pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
59122
let env = TestEnv::new()?;

0 commit comments

Comments
 (0)