+
+ /// Check if any transaction broadcasted is resolving HTLC output by a success or timeout on a local
+ /// or remote commitment tx, if so send back the source, preimage if found and payment_hash of resolved HTLC
+ fn is_resolving_htlc_output(&mut self, tx: &Transaction, height: u32) -> Vec<(HTLCSource, Option<PaymentPreimage>, PaymentHash)> {
+ let mut htlc_updated = Vec::new();
+
+ 'outer_loop: for input in &tx.input {
+ let mut payment_data = None;
+ let revocation_sig_claim = (input.witness.len() == 3 && input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT && input.witness[1].len() == 33)
+ || (input.witness.len() == 3 && input.witness[2].len() == ACCEPTED_HTLC_SCRIPT_WEIGHT && input.witness[1].len() == 33);
+ let accepted_preimage_claim = input.witness.len() == 5 && input.witness[4].len() == ACCEPTED_HTLC_SCRIPT_WEIGHT;
+ let offered_preimage_claim = input.witness.len() == 3 && input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT;
+
+ macro_rules! log_claim {
+ ($tx_info: expr, $local_tx: expr, $htlc: expr, $source_avail: expr) => {
+ // We found the output in question, but aren't failing it backwards
+ // as we have no corresponding source and no valid remote commitment txid
+ // to try a weak source binding with same-hash, same-value still-valid offered HTLC.
+ // This implies either it is an inbound HTLC or an outbound HTLC on a revoked transaction.
+ let outbound_htlc = $local_tx == $htlc.offered;
+ if ($local_tx && revocation_sig_claim) ||
+ (outbound_htlc && !$source_avail && (accepted_preimage_claim || offered_preimage_claim)) {
+ log_error!(self, "Input spending {} ({}:{}) in {} resolves {} HTLC with payment hash {} with {}!",
+ $tx_info, input.previous_output.txid, input.previous_output.vout, tx.txid(),
+ if outbound_htlc { "outbound" } else { "inbound" }, log_bytes!($htlc.payment_hash.0),
+ if revocation_sig_claim { "revocation sig" } else { "preimage claim after we'd passed the HTLC resolution back" });
+ } else {
+ log_info!(self, "Input spending {} ({}:{}) in {} resolves {} HTLC with payment hash {} with {}",
+ $tx_info, input.previous_output.txid, input.previous_output.vout, tx.txid(),
+ if outbound_htlc { "outbound" } else { "inbound" }, log_bytes!($htlc.payment_hash.0),
+ if revocation_sig_claim { "revocation sig" } else if accepted_preimage_claim || offered_preimage_claim { "preimage" } else { "timeout" });
+ }
+ }
+ }
+
+ macro_rules! check_htlc_valid_remote {
+ ($remote_txid: expr, $htlc_output: expr) => {
+ if let &Some(txid) = $remote_txid {
+ for &(ref pending_htlc, ref pending_source) in self.remote_claimable_outpoints.get(&txid).unwrap() {
+ if pending_htlc.payment_hash == $htlc_output.payment_hash && pending_htlc.amount_msat == $htlc_output.amount_msat {
+ if let &Some(ref source) = pending_source {
+ log_claim!("revoked remote commitment tx", false, pending_htlc, true);
+ payment_data = Some(((**source).clone(), $htlc_output.payment_hash));
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ macro_rules! scan_commitment {
+ ($htlcs: expr, $tx_info: expr, $local_tx: expr) => {
+ for (ref htlc_output, source_option) in $htlcs {
+ if Some(input.previous_output.vout) == htlc_output.transaction_output_index {
+ if let Some(ref source) = source_option {
+ log_claim!($tx_info, $local_tx, htlc_output, true);
+ // We have a resolution of an HTLC either from one of our latest
+ // local commitment transactions or an unrevoked remote commitment
+ // transaction. This implies we either learned a preimage, the HTLC
+ // has timed out, or we screwed up. In any case, we should now
+ // resolve the source HTLC with the original sender.
+ payment_data = Some(((*source).clone(), htlc_output.payment_hash));
+ } else if !$local_tx {
+ if let Storage::Local { ref current_remote_commitment_txid, .. } = self.key_storage {
+ check_htlc_valid_remote!(current_remote_commitment_txid, htlc_output);
+ }
+ if payment_data.is_none() {
+ if let Storage::Local { ref prev_remote_commitment_txid, .. } = self.key_storage {
+ check_htlc_valid_remote!(prev_remote_commitment_txid, htlc_output);
+ }
+ }
+ }
+ if payment_data.is_none() {
+ log_claim!($tx_info, $local_tx, htlc_output, false);
+ continue 'outer_loop;
+ }
+ }
+ }
+ }
+ }
+
+ if let Some(ref current_local_signed_commitment_tx) = self.current_local_signed_commitment_tx {
+ if input.previous_output.txid == current_local_signed_commitment_tx.txid {
+ scan_commitment!(current_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, ref b)| (a, b.as_ref())),
+ "our latest local commitment tx", true);
+ }
+ }
+ if let Some(ref prev_local_signed_commitment_tx) = self.prev_local_signed_commitment_tx {
+ if input.previous_output.txid == prev_local_signed_commitment_tx.txid {
+ scan_commitment!(prev_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, ref b)| (a, b.as_ref())),
+ "our previous local commitment tx", true);
+ }
+ }
+ if let Some(ref htlc_outputs) = self.remote_claimable_outpoints.get(&input.previous_output.txid) {
+ scan_commitment!(htlc_outputs.iter().map(|&(ref a, ref b)| (a, (b.as_ref().clone()).map(|boxed| &**boxed))),
+ "remote commitment tx", false);
+ }
+
+ // Check that scan_commitment, above, decided there is some source worth relaying an
+ // HTLC resolution backwards to and figure out whether we learned a preimage from it.
+ if let Some((source, payment_hash)) = payment_data {
+ let mut payment_preimage = PaymentPreimage([0; 32]);
+ if accepted_preimage_claim {
+ payment_preimage.0.copy_from_slice(&input.witness[3]);
+ htlc_updated.push((source, Some(payment_preimage), payment_hash));
+ } else if offered_preimage_claim {
+ payment_preimage.0.copy_from_slice(&input.witness[1]);
+ htlc_updated.push((source, Some(payment_preimage), payment_hash));
+ } else {
+ log_info!(self, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting for confirmation (at height{})", log_bytes!(payment_hash.0), height + ANTI_REORG_DELAY - 1);
+ match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) {
+ hash_map::Entry::Occupied(mut entry) => {
+ let e = entry.get_mut();
+ e.retain(|ref event| {
+ match **event {
+ OnchainEvent::HTLCUpdate { ref htlc_update } => {
+ return htlc_update.0 != source
+ },
+ _ => return true
+ }
+ });
+ e.push(OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash)});
+ }
+ hash_map::Entry::Vacant(entry) => {
+ entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash)}]);
+ }
+ }
+ }
+ }
+ }
+ htlc_updated
+ }
+}
+
+const MAX_ALLOC_SIZE: usize = 64*1024;
+
+impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelMonitor) {
+ fn read(reader: &mut R, logger: Arc<Logger>) -> Result<Self, DecodeError> {
+ let secp_ctx = Secp256k1::new();
+ macro_rules! unwrap_obj {
+ ($key: expr) => {
+ match $key {
+ Ok(res) => res,
+ Err(_) => return Err(DecodeError::InvalidValue),
+ }
+ }
+ }
+
+ let _ver: u8 = Readable::read(reader)?;
+ let min_ver: u8 = Readable::read(reader)?;
+ if min_ver > SERIALIZATION_VERSION {
+ return Err(DecodeError::UnknownVersion);
+ }
+
+ let commitment_transaction_number_obscure_factor = <U48 as Readable<R>>::read(reader)?.0;
+
+ let key_storage = match <u8 as Readable<R>>::read(reader)? {
+ 0 => {
+ let revocation_base_key = Readable::read(reader)?;
+ let htlc_base_key = Readable::read(reader)?;
+ let delayed_payment_base_key = Readable::read(reader)?;
+ let payment_base_key = Readable::read(reader)?;
+ let shutdown_pubkey = Readable::read(reader)?;
+ let prev_latest_per_commitment_point = Readable::read(reader)?;
+ let latest_per_commitment_point = Readable::read(reader)?;
+ // Technically this can fail and serialize fail a round-trip, but only for serialization of
+ // barely-init'd ChannelMonitors that we can't do anything with.
+ let outpoint = OutPoint {
+ txid: Readable::read(reader)?,
+ index: Readable::read(reader)?,
+ };
+ let funding_info = Some((outpoint, Readable::read(reader)?));
+ let current_remote_commitment_txid = Readable::read(reader)?;
+ let prev_remote_commitment_txid = Readable::read(reader)?;
+ Storage::Local {
+ revocation_base_key,
+ htlc_base_key,
+ delayed_payment_base_key,
+ payment_base_key,
+ shutdown_pubkey,
+ prev_latest_per_commitment_point,
+ latest_per_commitment_point,
+ funding_info,
+ current_remote_commitment_txid,
+ prev_remote_commitment_txid,
+ }
+ },
+ _ => return Err(DecodeError::InvalidValue),
+ };
+
+ let their_htlc_base_key = Some(Readable::read(reader)?);
+ let their_delayed_payment_base_key = Some(Readable::read(reader)?);
+
+ let their_cur_revocation_points = {
+ let first_idx = <U48 as Readable<R>>::read(reader)?.0;
+ if first_idx == 0 {
+ None
+ } else {
+ let first_point = Readable::read(reader)?;
+ let second_point_slice: [u8; 33] = Readable::read(reader)?;
+ if second_point_slice[0..32] == [0; 32] && second_point_slice[32] == 0 {
+ Some((first_idx, first_point, None))
+ } else {
+ Some((first_idx, first_point, Some(unwrap_obj!(PublicKey::from_slice(&second_point_slice)))))
+ }
+ }
+ };
+
+ let our_to_self_delay: u16 = Readable::read(reader)?;
+ let their_to_self_delay: Option<u16> = Some(Readable::read(reader)?);
+
+ let mut old_secrets = [([0; 32], 1 << 48); 49];
+ for &mut (ref mut secret, ref mut idx) in old_secrets.iter_mut() {
+ *secret = Readable::read(reader)?;
+ *idx = Readable::read(reader)?;
+ }
+
+ macro_rules! read_htlc_in_commitment {
+ () => {
+ {
+ let offered: bool = Readable::read(reader)?;
+ let amount_msat: u64 = Readable::read(reader)?;
+ let cltv_expiry: u32 = Readable::read(reader)?;
+ let payment_hash: PaymentHash = Readable::read(reader)?;
+ let transaction_output_index: Option<u32> = Readable::read(reader)?;
+
+ HTLCOutputInCommitment {
+ offered, amount_msat, cltv_expiry, payment_hash, transaction_output_index
+ }
+ }
+ }
+ }
+
+ let remote_claimable_outpoints_len: u64 = Readable::read(reader)?;
+ let mut remote_claimable_outpoints = HashMap::with_capacity(cmp::min(remote_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64));
+ for _ in 0..remote_claimable_outpoints_len {
+ let txid: Sha256dHash = Readable::read(reader)?;
+ let htlcs_count: u64 = Readable::read(reader)?;
+ let mut htlcs = Vec::with_capacity(cmp::min(htlcs_count as usize, MAX_ALLOC_SIZE / 32));
+ for _ in 0..htlcs_count {
+ htlcs.push((read_htlc_in_commitment!(), <Option<HTLCSource> as Readable<R>>::read(reader)?.map(|o: HTLCSource| Box::new(o))));
+ }
+ if let Some(_) = remote_claimable_outpoints.insert(txid, htlcs) {
+ return Err(DecodeError::InvalidValue);
+ }
+ }
+
+ let remote_commitment_txn_on_chain_len: u64 = Readable::read(reader)?;
+ let mut remote_commitment_txn_on_chain = HashMap::with_capacity(cmp::min(remote_commitment_txn_on_chain_len as usize, MAX_ALLOC_SIZE / 32));
+ for _ in 0..remote_commitment_txn_on_chain_len {
+ let txid: Sha256dHash = Readable::read(reader)?;
+ let commitment_number = <U48 as Readable<R>>::read(reader)?.0;
+ let outputs_count = <u64 as Readable<R>>::read(reader)?;
+ let mut outputs = Vec::with_capacity(cmp::min(outputs_count as usize, MAX_ALLOC_SIZE / 8));
+ for _ in 0..outputs_count {
+ outputs.push(Readable::read(reader)?);
+ }
+ if let Some(_) = remote_commitment_txn_on_chain.insert(txid, (commitment_number, outputs)) {
+ return Err(DecodeError::InvalidValue);
+ }
+ }
+
+ let remote_hash_commitment_number_len: u64 = Readable::read(reader)?;
+ let mut remote_hash_commitment_number = HashMap::with_capacity(cmp::min(remote_hash_commitment_number_len as usize, MAX_ALLOC_SIZE / 32));
+ for _ in 0..remote_hash_commitment_number_len {
+ let payment_hash: PaymentHash = Readable::read(reader)?;
+ let commitment_number = <U48 as Readable<R>>::read(reader)?.0;
+ if let Some(_) = remote_hash_commitment_number.insert(payment_hash, commitment_number) {
+ return Err(DecodeError::InvalidValue);
+ }
+ }
+
+ macro_rules! read_local_tx {
+ () => {
+ {
+ let tx = match Transaction::consensus_decode(reader.by_ref()) {
+ Ok(tx) => tx,
+ Err(e) => match e {
+ encode::Error::Io(ioe) => return Err(DecodeError::Io(ioe)),
+ _ => return Err(DecodeError::InvalidValue),
+ },
+ };
+
+ if tx.input.is_empty() {
+ // Ensure tx didn't hit the 0-input ambiguity case.
+ return Err(DecodeError::InvalidValue);
+ }
+
+ let revocation_key = Readable::read(reader)?;
+ let a_htlc_key = Readable::read(reader)?;
+ let b_htlc_key = Readable::read(reader)?;
+ let delayed_payment_key = Readable::read(reader)?;
+ let feerate_per_kw: u64 = Readable::read(reader)?;
+
+ let htlcs_len: u64 = Readable::read(reader)?;
+ let mut htlcs = Vec::with_capacity(cmp::min(htlcs_len as usize, MAX_ALLOC_SIZE / 128));
+ for _ in 0..htlcs_len {
+ let htlc = read_htlc_in_commitment!();
+ let sigs = match <u8 as Readable<R>>::read(reader)? {
+ 0 => None,
+ 1 => Some((Readable::read(reader)?, Readable::read(reader)?)),
+ _ => return Err(DecodeError::InvalidValue),
+ };
+ htlcs.push((htlc, sigs, Readable::read(reader)?));
+ }
+
+ LocalSignedTx {
+ txid: tx.txid(),
+ tx, revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, feerate_per_kw,
+ htlc_outputs: htlcs
+ }
+ }
+ }
+ }
+
+ let prev_local_signed_commitment_tx = match <u8 as Readable<R>>::read(reader)? {
+ 0 => None,
+ 1 => {
+ Some(read_local_tx!())
+ },
+ _ => return Err(DecodeError::InvalidValue),
+ };
+
+ let current_local_signed_commitment_tx = match <u8 as Readable<R>>::read(reader)? {
+ 0 => None,
+ 1 => {
+ Some(read_local_tx!())
+ },
+ _ => return Err(DecodeError::InvalidValue),
+ };
+
+ let current_remote_commitment_number = <U48 as Readable<R>>::read(reader)?.0;
+
+ let payment_preimages_len: u64 = Readable::read(reader)?;
+ let mut payment_preimages = HashMap::with_capacity(cmp::min(payment_preimages_len as usize, MAX_ALLOC_SIZE / 32));
+ for _ in 0..payment_preimages_len {
+ let preimage: PaymentPreimage = Readable::read(reader)?;
+ let hash = PaymentHash(Sha256::hash(&preimage.0[..]).into_inner());
+ if let Some(_) = payment_preimages.insert(hash, preimage) {
+ return Err(DecodeError::InvalidValue);
+ }
+ }
+
+ let last_block_hash: Sha256dHash = Readable::read(reader)?;
+ let destination_script = Readable::read(reader)?;
+
+ let our_claim_txn_waiting_first_conf_len: u64 = Readable::read(reader)?;
+ let mut our_claim_txn_waiting_first_conf = HashMap::with_capacity(cmp::min(our_claim_txn_waiting_first_conf_len as usize, MAX_ALLOC_SIZE / 128));
+ for _ in 0..our_claim_txn_waiting_first_conf_len {
+ let outpoint = Readable::read(reader)?;
+ let height_target = Readable::read(reader)?;
+ let tx_material = match <u8 as Readable<R>>::read(reader)? {
+ 0 => {
+ let script = Readable::read(reader)?;
+ let pubkey = Readable::read(reader)?;
+ let key = Readable::read(reader)?;
+ let is_htlc = match <u8 as Readable<R>>::read(reader)? {
+ 0 => true,
+ 1 => false,
+ _ => return Err(DecodeError::InvalidValue),
+ };
+ let amount = Readable::read(reader)?;
+ TxMaterial::Revoked {
+ script,
+ pubkey,
+ key,
+ is_htlc,
+ amount
+ }
+ },
+ 1 => {
+ let script = Readable::read(reader)?;
+ let key = Readable::read(reader)?;
+ let preimage = Readable::read(reader)?;
+ let amount = Readable::read(reader)?;
+ TxMaterial::RemoteHTLC {
+ script,
+ key,
+ preimage,
+ amount
+ }
+ },
+ 2 => {
+ let script = Readable::read(reader)?;
+ let their_sig = Readable::read(reader)?;
+ let our_sig = Readable::read(reader)?;
+ let preimage = Readable::read(reader)?;
+ let amount = Readable::read(reader)?;
+ TxMaterial::LocalHTLC {
+ script,
+ sigs: (their_sig, our_sig),
+ preimage,
+ amount
+ }
+ }
+ _ => return Err(DecodeError::InvalidValue),
+ };
+ let last_fee = Readable::read(reader)?;
+ let timelock_expiration = Readable::read(reader)?;
+ let height = Readable::read(reader)?;
+ our_claim_txn_waiting_first_conf.insert(outpoint, (height_target, tx_material, last_fee, timelock_expiration, height));
+ }
+
+ let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
+ let mut onchain_events_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
+ for _ in 0..waiting_threshold_conf_len {
+ let height_target = Readable::read(reader)?;
+ let events_len: u64 = Readable::read(reader)?;
+ let mut events = Vec::with_capacity(cmp::min(events_len as usize, MAX_ALLOC_SIZE / 128));
+ for _ in 0..events_len {
+ let ev = match <u8 as Readable<R>>::read(reader)? {
+ 0 => {
+ let outpoint = Readable::read(reader)?;
+ OnchainEvent::Claim {
+ outpoint
+ }
+ },
+ 1 => {
+ let htlc_source = Readable::read(reader)?;
+ let hash = Readable::read(reader)?;
+ OnchainEvent::HTLCUpdate {
+ htlc_update: (htlc_source, hash)
+ }
+ },
+ _ => return Err(DecodeError::InvalidValue),
+ };
+ events.push(ev);
+ }
+ onchain_events_waiting_threshold_conf.insert(height_target, events);
+ }
+
+ Ok((last_block_hash.clone(), ChannelMonitor {
+ commitment_transaction_number_obscure_factor,
+
+ key_storage,
+ their_htlc_base_key,
+ their_delayed_payment_base_key,
+ their_cur_revocation_points,
+
+ our_to_self_delay,
+ their_to_self_delay,
+
+ old_secrets,
+ remote_claimable_outpoints,
+ remote_commitment_txn_on_chain,
+ remote_hash_commitment_number,
+
+ prev_local_signed_commitment_tx,
+ current_local_signed_commitment_tx,
+ current_remote_commitment_number,
+
+ payment_preimages,
+
+ destination_script,
+
+ our_claim_txn_waiting_first_conf,
+
+ onchain_events_waiting_threshold_conf,
+
+ last_block_hash,
+ secp_ctx,
+ logger,
+ }))
+ }
+