Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bdk-reserves"
version = "3.1.0"
version = "3.1.1"
authors = ["Richard Ulrich <richard.ulrich@aminagroup.com>"]
edition = "2024"
description = "Proof of reserves for bitcoin dev kit"
Expand Down
44 changes: 43 additions & 1 deletion src/reserves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ pub enum ProofError {
Wallet(bdk_wallet::descriptor::error::Error),
/// Failed to sign a transaction
Sign(SignerError),
/// Most likely trying to inflate the amount
DuplicateUtxo,
}

impl From<AddForeignUtxoError> for ProofError {
Expand Down Expand Up @@ -229,6 +231,19 @@ pub fn verify_proof(
return Err(ProofError::WrongNumberOfInputs);
}

// verify that UTXOs are not duplicated
let mut utxos = tx
.input
.iter()
.skip(1)
.map(|inp| inp.previous_output)
.collect::<Vec<OutPoint>>();
utxos.sort_unstable();
utxos.dedup();
if utxos.len() + 1 != tx.input.len() {
return Err(ProofError::DuplicateUtxo);
}

// verify the challenge txin
let challenge_txin = challenge_txin(message);
if tx.input[0].previous_output != challenge_txin.previous_output {
Expand Down Expand Up @@ -282,7 +297,7 @@ pub fn verify_proof(
return Err(ProofError::InAndOutValueNotEqual);
}

// verify the unspendable output
// verify the unspendable (burn) output
let pkh = PubkeyHash::from_raw_hash(hash160::Hash::hash(&[0]));
let out_script_unspendable = ScriptBuf::new_p2pkh(&pkh);

Expand Down Expand Up @@ -367,6 +382,7 @@ mod test {
trust_witness_utxo: true,
..Default::default()
};
#[allow(deprecated)]
wallet.sign(&mut psbt, signopts).unwrap();

let spendable = wallet.verify_proof(&psbt, message, None).unwrap();
Expand Down Expand Up @@ -597,4 +613,30 @@ mod test {

wallet.verify_proof(&psbt, message, None).unwrap();
}

#[test]
#[should_panic(expected = "DuplicateUtxo")]
fn test_duplicate_utxo() {
let descriptor = "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)";
let (mut wallet, _) = get_funded_wallet_single(descriptor);

let message = "This belongs to me.";
let mut psbt = wallet.create_proof(message).unwrap();

psbt.inputs.push(psbt.inputs.last().unwrap().clone());
psbt.unsigned_tx
.input
.push(psbt.unsigned_tx.input.last().unwrap().clone());
psbt.unsigned_tx.output[0].value = Amount::from_sat(100_000);

let signopts = SignOptions {
trust_witness_utxo: true,
..Default::default()
};
#[allow(deprecated)]
wallet.sign(&mut psbt, signopts).unwrap();

let spendable = wallet.verify_proof(&psbt, message, None).unwrap();
assert_eq!(spendable, Amount::from_sat(100_000));
}
}
4 changes: 4 additions & 0 deletions tests/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn unconfirmed() -> Result<(), ProofError> {
trust_witness_utxo: true,
..Default::default()
};
#[allow(deprecated)]
let finalized = wallet.sign(&mut psbt, signopts.clone())?;
assert!(finalized);
client
Expand All @@ -53,6 +54,7 @@ fn unconfirmed() -> Result<(), ProofError> {

let message = "This belongs to me.";
let mut psbt = wallet.create_proof(message)?;
#[allow(deprecated)]
let finalized = wallet.sign(&mut psbt, signopts)?;
assert!(finalized);

Expand Down Expand Up @@ -105,6 +107,7 @@ fn confirmed() {
trust_witness_utxo: true,
..Default::default()
};
#[allow(deprecated)]
let finalized = wallet.sign(&mut psbt, signopts.clone()).unwrap();
assert!(finalized);
client
Expand All @@ -117,6 +120,7 @@ fn confirmed() {

let message = "This belongs to me.";
let mut psbt = wallet.create_proof(message).unwrap();
#[allow(deprecated)]
let finalized = wallet.sign(&mut psbt, signopts).unwrap();
assert!(finalized);

Expand Down
3 changes: 3 additions & 0 deletions tests/multi_sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,12 @@ fn test_proof_multisig(
//remove_partial_sigs: false,
..Default::default()
};
#[allow(deprecated)]
let finalized = wallets[0].sign(&mut psbt, signopts.clone())?;
assert_eq!(count_signatures(&psbt), (num_inp - 1, 1, 0));
assert!(!finalized);

#[allow(deprecated)]
let finalized = wallets[1].sign(&mut psbt, signopts.clone())?;
assert_eq!(
count_signatures(&psbt),
Expand All @@ -147,6 +149,7 @@ fn test_proof_multisig(
assert!(finalized);

// 2 signatures are enough. Just checking what happens...
#[allow(deprecated)]
let finalized = wallets[2].sign(&mut psbt, signopts.clone())?;
assert_eq!(
count_signatures(&psbt),
Expand Down
1 change: 1 addition & 0 deletions tests/regtestenv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ impl RegTestEnv {
let signopts = SignOptions {
..Default::default()
};
#[allow(deprecated)]
let finalized = wallets
.iter_mut()
.any(|wallet| wallet.sign(&mut psbt, signopts.clone()).unwrap());
Expand Down
1 change: 1 addition & 0 deletions tests/single_sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fn test_proof_singlesig(#[case] descriptor: &'static str) -> Result<(), ProofErr
num_inp
);

#[allow(deprecated)]
let finalized = wallet.sign(
&mut psbt,
SignOptions {
Expand Down
2 changes: 2 additions & 0 deletions tests/tampering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ fn tampered_proof_message() {
trust_witness_utxo: true,
..Default::default()
};
#[allow(deprecated)]
let _finalized = wallet.sign(&mut psbt_alice, signopt).unwrap();

let spendable = wallet
Expand Down Expand Up @@ -56,6 +57,7 @@ fn tampered_proof_miner_fee() {
// reduce the output value to grant a miner fee
psbt.unsigned_tx.output[0].value -= Amount::from_sat(100);

#[allow(deprecated)]
let _finalized = wallet.sign(&mut psbt, signopt).unwrap();

let _spendable = wallet.verify_proof(&psbt, message, None).unwrap();
Expand Down
Loading