Skip to content

Commit 4c62df8

Browse files
committed
test(electrum): tests for exploit fixes
1 parent 45c5351 commit 4c62df8

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

crates/electrum/src/bdk_electrum_client.rs

+84
Original file line numberDiff line numberDiff line change
@@ -559,3 +559,87 @@ fn chain_update(
559559
}
560560
Ok(tip)
561561
}
562+
563+
#[cfg(test)]
564+
mod test {
565+
use crate::{bdk_electrum_client::TxUpdate, BdkElectrumClient};
566+
use bdk_chain::bitcoin::{Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut};
567+
use bdk_testenv::{utils::new_tx, TestEnv};
568+
use std::{collections::BTreeMap, sync::Arc};
569+
570+
#[test]
571+
fn test_populate_with_txids_without_output() {
572+
let env = TestEnv::new().unwrap();
573+
let electrum_client =
574+
electrum_client::Client::new(env.electrsd.electrum_url.as_str()).unwrap();
575+
let client = BdkElectrumClient::new(electrum_client);
576+
577+
// Setup transaction with no outputs.
578+
let tx = new_tx(0);
579+
580+
// Populate tx_cache with `tx` to make it fetchable.
581+
client.populate_tx_cache(vec![tx.clone()]);
582+
583+
// Test that populate_with_txids does not panic or process a tx with no output.
584+
let mut tx_update = TxUpdate::default();
585+
let _ = client.populate_with_txids(&mut tx_update, vec![tx.compute_txid()]);
586+
587+
assert_eq!(tx_update.txs, Vec::new());
588+
}
589+
590+
#[test]
591+
fn test_fetch_prev_txout_with_coinbase() {
592+
let env = TestEnv::new().unwrap();
593+
let electrum_client =
594+
electrum_client::Client::new(env.electrsd.electrum_url.as_str()).unwrap();
595+
let client = BdkElectrumClient::new(electrum_client);
596+
597+
// Setup the transactions necessary for fetch_prev_txout to fetch `txouts` for `tx`.
598+
let expected_txout = TxOut {
599+
value: Amount::from_sat(10_000),
600+
script_pubkey: ScriptBuf::default(),
601+
};
602+
603+
let prev_tx = Transaction {
604+
output: vec![expected_txout.clone()],
605+
..new_tx(0)
606+
};
607+
608+
let expected_outpoint = OutPoint::new(prev_tx.compute_txid(), 0);
609+
610+
let tx = Transaction {
611+
input: vec![TxIn {
612+
previous_output: expected_outpoint,
613+
..Default::default()
614+
}],
615+
..new_tx(0)
616+
};
617+
618+
// Populate tx_cache with `prev_tx` to make it fetchable.
619+
client.populate_tx_cache(vec![prev_tx.clone()]);
620+
621+
// Test fetch_prev_txout to see if we get our expected `txouts`.
622+
let mut tx_update = TxUpdate {
623+
txs: vec![Arc::new(tx.clone())],
624+
..Default::default()
625+
};
626+
let _ = client.fetch_prev_txout(&mut tx_update);
627+
628+
assert_eq!(
629+
tx_update.txouts,
630+
BTreeMap::from([(expected_outpoint, expected_txout)])
631+
);
632+
633+
// Assert that `tx` is now a coinbase transaction.
634+
let _ = client.update_coinbase_txid(tx.compute_txid());
635+
636+
// Test that fetch_prev_txout does not fetch `txouts` for coinbase tx.
637+
let mut tx_update = TxUpdate {
638+
txs: vec![Arc::new(tx)],
639+
..Default::default()
640+
};
641+
let _ = client.fetch_prev_txout(&mut tx_update);
642+
643+
assert_eq!(tx_update.txouts, BTreeMap::default());
644+
}
645+
}

0 commit comments

Comments
 (0)