diff --git a/Cargo.lock b/Cargo.lock index 1b36bb4..7c2aa38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,6 +307,7 @@ name = "miradord" version = "0.0.2" dependencies = [ "backtrace", + "bitcoinconsensus", "dirs", "fastrand", "fern", diff --git a/Cargo.toml b/Cargo.toml index a8e6cd3..b3495cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Antoine Poinsot "] edition = "2018" [dependencies] +bitcoinconsensus = "0.19.0-2" revault_tx = { version = "0.5", features = ["use-serde"] } revault_net = "0.3" diff --git a/src/coordinator.rs b/src/coordinator.rs index 72d2711..23856e4 100644 --- a/src/coordinator.rs +++ b/src/coordinator.rs @@ -60,7 +60,9 @@ impl CoordinatorClient { transport.send_req(&req) } - // Get Spend transaction spending the vault with the given deposit outpoint. + /// Get Spend transaction spending the vault with the given deposit outpoint. + /// Beware that the spend transaction may be invalid and needs to be verified against + /// libbitcoinconsensus. pub fn get_spend_transaction( &self, deposit_outpoint: OutPoint, diff --git a/src/poller.rs b/src/poller.rs index 488060e..eacbd55 100644 --- a/src/poller.rs +++ b/src/poller.rs @@ -18,7 +18,7 @@ use revault_tx::{ CancelTransaction, RevaultPresignedTransaction, RevaultTransaction, UnvaultTransaction, }, txins::{DepositTxIn, RevaultTxIn, UnvaultTxIn}, - txouts::DepositTxOut, + txouts::{DepositTxOut, RevaultTxOut}, }; use revault_net::noise::SecretKey as NoisePrivkey; @@ -400,7 +400,38 @@ fn check_for_unvault( let candidate_tx = if let Some(client) = coordinator_client { match client.get_spend_transaction(db_vault.deposit_outpoint.clone()) { - Ok(res) => res, + Ok(Some(tx)) => { + let spent_unvault_outpoint = unvault_txin.outpoint(); + if let Some(i) = tx + .input + .iter() + .position(|input| input.previous_output == spent_unvault_outpoint) + { + let txout = unvault_txin.txout().txout(); + if let Err(e) = bitcoinconsensus::verify( + &txout.script_pubkey.as_bytes(), + txout.value, + &encode::serialize(&tx), + i, + ) { + log::error!( + "Coordinator sent a suspicious tx {}, libbitcoinconsensus error: {:?}", + tx.txid(), + e + ); + None + } else { + Some(tx) + } + } else { + log::error!( + "Coordinator sent a suspicious tx {}, the transaction does not spend the vault", + tx.txid(), + ); + None + } + } + Ok(None) => None, Err(_e) => { // Because we do not trust the coordinator, we consider it refuses to deliver the // spend tx if a communication error happened.