@@ -3,13 +3,16 @@ use crate::error::{TxSyncError, InternalError};
33
44use electrum_client:: Client as ElectrumClient ;
55use electrum_client:: ElectrumApi ;
6+ use electrum_client:: GetMerkleRes ;
67
78use lightning:: util:: logger:: Logger ;
89use lightning:: { log_error, log_debug, log_trace} ;
910use lightning:: chain:: WatchedOutput ;
1011use lightning:: chain:: { Confirm , Filter } ;
1112
1213use bitcoin:: { BlockHash , BlockHeader , Script , Txid } ;
14+ use bitcoin:: hashes:: Hash ;
15+ use bitcoin:: hashes:: sha256d:: Hash as Sha256d ;
1316
1417use std:: ops:: Deref ;
1518use std:: sync:: Mutex ;
@@ -263,7 +266,10 @@ where
263266 debug_assert_eq ! ( prob_conf_height, merkle_res. block_height as u32 ) ;
264267 match self . client . block_header ( prob_conf_height as usize ) {
265268 Ok ( block_header) => {
266- // TODO can we check the merkle proof here to be sure?
269+ if !self . validate_merkle_proof ( * * txid, block_header. merkle_root . as_hash ( ) , & merkle_res) ? {
270+ log_trace ! ( self . logger, "Inconsistency: Block {} was unconfirmed during syncing." , block_header. block_hash( ) ) ;
271+ return Err ( InternalError :: Inconsistency ) ;
272+ }
267273 confirmed_txs. push ( ConfirmedTx { tx : tx. clone ( ) , block_header, block_height : prob_conf_height, pos : merkle_res. pos } ) ;
268274 }
269275 Err ( e) => {
@@ -301,7 +307,10 @@ where
301307 debug_assert_eq ! ( prob_conf_height, merkle_res. block_height as u32 ) ;
302308 match self . client . block_header ( prob_conf_height as usize ) {
303309 Ok ( block_header) => {
304- // TODO can we check the merkle proof here to be sure?
310+ if !self . validate_merkle_proof ( txid, block_header. merkle_root . as_hash ( ) , & merkle_res) ? {
311+ log_trace ! ( self . logger, "Inconsistency: Block {} was unconfirmed during syncing." , block_header. block_hash( ) ) ;
312+ return Err ( InternalError :: Inconsistency ) ;
313+ }
305314 confirmed_txs. push ( ConfirmedTx { tx : tx. clone ( ) , block_header, block_height : prob_conf_height, pos : merkle_res. pos } ) ;
306315 }
307316 Err ( e) => {
@@ -384,6 +393,31 @@ where
384393 & self . client
385394 }
386395
396+ fn validate_merkle_proof ( & self , txid : Txid , merkle_root : Sha256d , merkle_res : & GetMerkleRes ) -> Result < bool , InternalError > {
397+ let mut index = merkle_res. pos ;
398+ let mut cur = txid. as_hash ( ) ;
399+ for bytes in & merkle_res. merkle {
400+ let mut reversed = Vec :: with_capacity ( 32 ) ;
401+ reversed. truncate ( 0 ) ;
402+ reversed. extend ( bytes. iter ( ) . rev ( ) ) ;
403+ let next_hash = Sha256d :: from_slice ( & reversed) . map_err ( |_| {
404+ log_error ! ( self . logger, "Failed due to the server sending us bogus transaction data. This should not happen. Please verify server integrity." ) ;
405+ InternalError :: Failed
406+ } ) ?;
407+
408+ let ( left, right) = if index % 2 == 0 {
409+ ( cur, next_hash)
410+ } else {
411+ ( next_hash, cur)
412+ } ;
413+
414+ let data = [ & left[ ..] , & right[ ..] ] . concat ( ) ;
415+ cur = Sha256d :: hash ( & data) ;
416+ index /= 2 ;
417+ }
418+
419+ Ok ( cur == merkle_root)
420+ }
387421}
388422
389423impl < L : Deref > Filter for ElectrumSyncClient < L >
0 commit comments