From: Antoine Riard Date: Tue, 7 Apr 2020 22:46:14 +0000 (-0400) Subject: Cache HTLC transaction material inside OnchainTxHandler X-Git-Tag: v0.0.12~84^2~8 X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=rust-lightning;a=commitdiff_plain;h=010fb3051c7df052df6d487d57309cd750eb0e2d Cache HTLC transaction material inside OnchainTxHandler Splitting further parsing from transaction generation, we cache transaction elements needed for local HTLC transaction inside OnchainTxHandler. Duplicated data will be removed from ChannelMonitor in future commits. --- diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index 560ace94..b0b31193 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -1270,7 +1270,7 @@ impl ChannelMonitor { // reject update as we do, you MAY have the latest local valid commitment tx onchain // for which you want to spend outputs. We're NOT robust again this scenario right // now but we should consider it later. - if let Err(_) = self.onchain_tx_handler.provide_latest_local_tx(commitment_tx.clone()) { + if let Err(_) = self.onchain_tx_handler.provide_latest_local_tx(commitment_tx.clone(), local_keys.clone(), feerate_per_kw) { return Err(MonitorUpdateError("Local commitment signed has already been signed, no further update of LOCAL commitment transaction is allowed")); } self.current_local_commitment_number = 0xffff_ffff_ffff - ((((commitment_tx.without_valid_witness().input[0].sequence as u64 & 0xffffff) << 3*8) | (commitment_tx.without_valid_witness().lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor); diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index 68c71dd8..43d3ec9a 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -15,7 +15,8 @@ use secp256k1; use ln::msgs::DecodeError; use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest}; -use ln::chan_utils::{HTLCType, LocalCommitmentTransaction}; +use ln::chan_utils; +use ln::chan_utils::{HTLCType, LocalCommitmentTransaction, TxCreationKeys}; use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT}; use chain::keysinterface::ChannelKeys; use util::logger::Logger; @@ -47,6 +48,14 @@ enum OnchainEvent { } } +/// Cache public keys and feerate used to compute any HTLC transaction. +/// We only keep state for latest 2 commitment transactions as we should +/// never have to generate HTLC txn for revoked local commitment +struct HTLCTxCache { + local_keys: TxCreationKeys, + feerate_per_kw: u64, +} + /// Higher-level cache structure needed to re-generate bumped claim txn if needed #[derive(Clone, PartialEq)] pub struct ClaimTxBumpMaterial { @@ -144,6 +153,8 @@ pub struct OnchainTxHandler { funding_redeemscript: Script, local_commitment: Option, prev_local_commitment: Option, + current_htlc_cache: Option, + prev_htlc_cache: Option, key_storage: ChanSigner, @@ -187,6 +198,27 @@ impl OnchainTxHandler { self.local_commitment.write(writer)?; self.prev_local_commitment.write(writer)?; + macro_rules! serialize_htlc_cache { + ($cache: expr) => { + $cache.local_keys.write(writer)?; + $cache.feerate_per_kw.write(writer)?; + } + } + + if let Some(ref current) = self.current_htlc_cache { + writer.write_all(&[1; 1])?; + serialize_htlc_cache!(current); + } else { + writer.write_all(&[0; 1])?; + } + + if let Some(ref prev) = self.prev_htlc_cache { + writer.write_all(&[1; 1])?; + serialize_htlc_cache!(prev); + } else { + writer.write_all(&[0; 1])?; + } + self.key_storage.write(writer)?; writer.write_all(&byte_utils::be64_to_array(self.pending_claim_requests.len() as u64))?; @@ -231,6 +263,35 @@ impl ReadableArgs> for OnchainTx let local_commitment = Readable::read(reader)?; let prev_local_commitment = Readable::read(reader)?; + macro_rules! read_htlc_cache { + () => { + { + let local_keys = Readable::read(reader)?; + let feerate_per_kw = Readable::read(reader)?; + HTLCTxCache { + local_keys, + feerate_per_kw, + } + } + } + } + + let current_htlc_cache = match ::read(reader)? { + 0 => None, + 1 => { + Some(read_htlc_cache!()) + } + _ => return Err(DecodeError::InvalidValue), + }; + + let prev_htlc_cache = match ::read(reader)? { + 0 => None, + 1 => { + Some(read_htlc_cache!()) + } + _ => return Err(DecodeError::InvalidValue), + }; + let key_storage = Readable::read(reader)?; let pending_claim_requests_len: u64 = Readable::read(reader)?; @@ -281,6 +342,8 @@ impl ReadableArgs> for OnchainTx funding_redeemscript, local_commitment, prev_local_commitment, + current_htlc_cache, + prev_htlc_cache, key_storage, claimable_outpoints, pending_claim_requests, @@ -301,6 +364,8 @@ impl OnchainTxHandler { funding_redeemscript, local_commitment: None, prev_local_commitment: None, + current_htlc_cache: None, + prev_htlc_cache: None, key_storage, pending_claim_requests: HashMap::new(), claimable_outpoints: HashMap::new(), @@ -756,7 +821,7 @@ impl OnchainTxHandler { } } - pub(super) fn provide_latest_local_tx(&mut self, tx: LocalCommitmentTransaction) -> Result<(), ()> { + pub(super) fn provide_latest_local_tx(&mut self, tx: LocalCommitmentTransaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64) -> Result<(), ()> { // To prevent any unsafe state discrepancy between offchain and onchain, once local // commitment transaction has been signed due to an event (either block height for // HTLC-timeout or channel force-closure), don't allow any further update of local @@ -767,6 +832,11 @@ impl OnchainTxHandler { } self.prev_local_commitment = self.local_commitment.take(); self.local_commitment = Some(tx); + self.prev_htlc_cache = self.current_htlc_cache.take(); + self.current_htlc_cache = Some(HTLCTxCache { + local_keys, + feerate_per_kw, + }); Ok(()) }