Skip to content

Commit d7eac3e

Browse files
committed
test(electrum): tests for exploit fixes
1 parent 03be3e1 commit d7eac3e

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

crates/electrum/src/bdk_electrum_client.rs

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

0 commit comments

Comments
 (0)