Cache per-HTLC data in OnchainTxHandler::HTLCTxCache

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.
This commit is contained in:
Antoine Riard 2020-03-21 18:52:00 -04:00
parent 010fb3051c
commit 080afeb6ea
2 changed files with 36 additions and 5 deletions

View file

@ -1270,7 +1270,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
// 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(), local_keys.clone(), feerate_per_kw) {
if let Err(_) = self.onchain_tx_handler.provide_latest_local_tx(commitment_tx.clone(), local_keys.clone(), feerate_per_kw, htlc_outputs.clone()) {
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);
@ -1284,7 +1284,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
delayed_payment_key: local_keys.a_delayed_payment_key,
per_commitment_point: local_keys.per_commitment_point,
feerate_per_kw,
htlc_outputs,
htlc_outputs: htlc_outputs,
});
Ok(())
}

View file

@ -10,13 +10,14 @@ use bitcoin::util::bip143;
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
use secp256k1::Secp256k1;
use secp256k1::{Secp256k1, Signature};
use secp256k1;
use ln::msgs::DecodeError;
use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest};
use ln::channelmanager::HTLCSource;
use ln::chan_utils;
use ln::chan_utils::{HTLCType, LocalCommitmentTransaction, TxCreationKeys};
use ln::chan_utils::{HTLCType, LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment};
use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
use chain::keysinterface::ChannelKeys;
use util::logger::Logger;
@ -54,6 +55,7 @@ enum OnchainEvent {
struct HTLCTxCache {
local_keys: TxCreationKeys,
feerate_per_kw: u64,
per_htlc: HashMap<u32, (HTLCOutputInCommitment, Option<Signature>)>
}
/// Higher-level cache structure needed to re-generate bumped claim txn if needed
@ -202,6 +204,16 @@ impl<ChanSigner: ChannelKeys + Writeable> OnchainTxHandler<ChanSigner> {
($cache: expr) => {
$cache.local_keys.write(writer)?;
$cache.feerate_per_kw.write(writer)?;
writer.write_all(&byte_utils::be64_to_array($cache.per_htlc.len() as u64))?;
for (_, &(ref htlc, ref sig)) in $cache.per_htlc.iter() {
htlc.write(writer)?;
if let &Some(ref their_sig) = sig {
1u8.write(writer)?;
writer.write_all(&their_sig.serialize_compact())?;
} else {
0u8.write(writer)?;
}
}
}
}
@ -268,9 +280,21 @@ impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for OnchainTx
{
let local_keys = Readable::read(reader)?;
let feerate_per_kw = Readable::read(reader)?;
let htlcs_count: u64 = Readable::read(reader)?;
let mut per_htlc = HashMap::with_capacity(cmp::min(htlcs_count as usize, MAX_ALLOC_SIZE / 32));
for _ in 0..htlcs_count {
let htlc: HTLCOutputInCommitment = Readable::read(reader)?;
let sigs = match <u8 as Readable>::read(reader)? {
0 => None,
1 => Some(Readable::read(reader)?),
_ => return Err(DecodeError::InvalidValue),
};
per_htlc.insert(htlc.transaction_output_index.unwrap(), (htlc, sigs));
}
HTLCTxCache {
local_keys,
feerate_per_kw,
per_htlc
}
}
}
@ -821,7 +845,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
}
}
pub(super) fn provide_latest_local_tx(&mut self, tx: LocalCommitmentTransaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64) -> Result<(), ()> {
pub(super) fn provide_latest_local_tx(&mut self, tx: LocalCommitmentTransaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>) -> 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
@ -833,9 +857,16 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
self.prev_local_commitment = self.local_commitment.take();
self.local_commitment = Some(tx);
self.prev_htlc_cache = self.current_htlc_cache.take();
let mut per_htlc = HashMap::with_capacity(htlc_outputs.len());
for htlc in htlc_outputs {
if htlc.0.transaction_output_index.is_some() { // Discard dust HTLC as we will never have to generate onchain tx for them
per_htlc.insert(htlc.0.transaction_output_index.unwrap(), (htlc.0, htlc.1));
}
}
self.current_htlc_cache = Some(HTLCTxCache {
local_keys,
feerate_per_kw,
per_htlc
});
Ok(())
}