Skip to content
Merged
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
61 changes: 51 additions & 10 deletions lightning-transaction-sync/src/electrum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use lightning::util::logger::Logger;
use lightning::{log_debug, log_error, log_trace};

use bitcoin::block::Header;
use bitcoin::opcodes::all::OP_RETURN;
use bitcoin::opcodes::OP_FALSE;
use bitcoin::{BlockHash, Script, Transaction, Txid};

use std::collections::HashSet;
Expand Down Expand Up @@ -289,16 +291,55 @@ where
continue;
}

watched_txs.push((txid, tx.clone()));
if let Some(tx_out) = tx.output.first() {
// We watch an arbitrary output of the transaction of interest in order to
// retrieve the associated script history, before narrowing down our search
// through `filter`ing by `txid` below.
watched_script_pubkeys.push(tx_out.script_pubkey.clone());
} else {
debug_assert!(false, "Failed due to retrieving invalid tx data.");
log_error!(self.logger, "Failed due to retrieving invalid tx data.");
return Err(InternalError::Failed);
// We watch an arbitrary output of the transaction of interest in order to
// retrieve the associated script history, before narrowing down our search
// through `filter`ing by `txid` below. Electrum servers don't index
// provably-unspendable outputs, so picking one of those would always yield an
// empty history.
let mut spk = tx
.output
.iter()
.find(|txo| {
!txo.script_pubkey.is_op_return()
&& !txo
.script_pubkey
.as_bytes()
.starts_with(&[OP_FALSE.to_u8(), OP_RETURN.to_u8()])
})
.map(|txo| txo.script_pubkey.clone());

// Fall back to the script of an input's previous output: its history includes
// this transaction, as we spend from it.
if spk.is_none() && !tx.is_coinbase() {
for txin in &tx.input {
match self.client.transaction_get(&txin.previous_output.txid) {
Ok(parent) => {
if let Some(prev_out) =
parent.output.get(txin.previous_output.vout as usize)
{
spk = Some(prev_out.script_pubkey.clone());
break;
}
},
Err(electrum_client::Error::Protocol(_)) => continue,
Err(e) => {
log_error!(
self.logger,
"Failed to look up transaction {}: {}.",
txin.previous_output.txid,
e
);
return Err(InternalError::Failed);
},
}
}
}

// Nothing we could query a history for, e.g. a coinbase whose outputs are all
// unindexed. Skip it rather than failing the whole sync.
if let Some(spk) = spk {
watched_txs.push((txid, tx.clone()));
watched_script_pubkeys.push(spk);
}
},
Err(electrum_client::Error::Protocol(_)) => {
Expand Down
Loading