Skip to content

Commit

Permalink
f Validate merkle inclusion proofs
Browse files Browse the repository at this point in the history
  • Loading branch information
tnull committed Oct 27, 2023
1 parent 5d6e258 commit e79d5cd
Showing 1 changed file with 36 additions and 2 deletions.
38 changes: 36 additions & 2 deletions lightning-transaction-sync/src/electrum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ use crate::error::{TxSyncError, InternalError};

use electrum_client::Client as ElectrumClient;
use electrum_client::ElectrumApi;
use electrum_client::GetMerkleRes;

use lightning::util::logger::Logger;
use lightning::{log_error, log_debug, log_trace};
use lightning::chain::WatchedOutput;
use lightning::chain::{Confirm, Filter};

use bitcoin::{BlockHash, BlockHeader, Script, Txid};
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256d::Hash as Sha256d;

use std::ops::Deref;
use std::sync::Mutex;
Expand Down Expand Up @@ -263,7 +266,10 @@ where
debug_assert_eq!(prob_conf_height, merkle_res.block_height as u32);
match self.client.block_header(prob_conf_height as usize) {
Ok(block_header) => {
// TODO can we check the merkle proof here to be sure?
if !self.validate_merkle_proof(**txid, block_header.merkle_root.as_hash(), &merkle_res)? {
log_trace!(self.logger, "Inconsistency: Block {} was unconfirmed during syncing.", block_header.block_hash());
return Err(InternalError::Inconsistency);
}
confirmed_txs.push(ConfirmedTx { tx: tx.clone(), block_header, block_height: prob_conf_height, pos: merkle_res.pos });
}
Err(e) => {
Expand Down Expand Up @@ -301,7 +307,10 @@ where
debug_assert_eq!(prob_conf_height, merkle_res.block_height as u32);
match self.client.block_header(prob_conf_height as usize) {
Ok(block_header) => {
// TODO can we check the merkle proof here to be sure?
if !self.validate_merkle_proof(txid, block_header.merkle_root.as_hash(), &merkle_res)? {
log_trace!(self.logger, "Inconsistency: Block {} was unconfirmed during syncing.", block_header.block_hash());
return Err(InternalError::Inconsistency);
}
confirmed_txs.push(ConfirmedTx { tx: tx.clone(), block_header, block_height: prob_conf_height, pos: merkle_res.pos });
}
Err(e) => {
Expand Down Expand Up @@ -384,6 +393,31 @@ where
&self.client
}

fn validate_merkle_proof(&self, txid: Txid, merkle_root: Sha256d, merkle_res: &GetMerkleRes) -> Result<bool, InternalError> {
let mut index = merkle_res.pos;
let mut cur = txid.as_hash();
for bytes in &merkle_res.merkle {
let mut reversed = Vec::with_capacity(32);
reversed.truncate(0);
reversed.extend(bytes.iter().rev());
let next_hash = Sha256d::from_slice(&reversed).map_err(|_| {
log_error!(self.logger, "Failed due to the server sending us bogus transaction data. This should not happen. Please verify server integrity.");
InternalError::Failed
})?;

let (left, right) = if index % 2 == 0 {
(cur, next_hash)
} else {
(next_hash, cur)
};

let data = [&left[..], &right[..]].concat();
cur = Sha256d::hash(&data);
index /= 2;
}

Ok(cur == merkle_root)
}
}

impl<L: Deref> Filter for ElectrumSyncClient<L>
Expand Down

0 comments on commit e79d5cd

Please sign in to comment.