/// An error enum representing a failure to persist a channel monitor update.
#[derive(Clone)]
pub enum ChannelMonitorUpdateErr {
- /// Used to indicate a temporary failure (eg connection to a watchtower failed, but is expected
- /// to succeed at some point in the future).
+ /// Used to indicate a temporary failure (eg connection to a watchtower or remote backup of
+ /// our state failed, but is expected to succeed at some point in the future).
///
/// Such a failure will "freeze" a channel, preventing us from revoking old states or
/// submitting new commitment transactions to the remote party.
/// Note that even if updates made after TemporaryFailure succeed you must still call
/// test_restore_channel_monitor to ensure you have the latest monitor and re-enable normal
/// channel operation.
+ ///
+ /// For deployments where a copy of ChannelMonitors and other local state are backed up in a
+ /// remote location (with local copies persisted immediately), it is anticipated that all
+ /// updates will return TemporaryFailure until the remote copies could be updated.
TemporaryFailure,
/// Used to indicate no further channel monitor updates will be allowed (eg we've moved on to a
/// different watchtower and cannot update with all watchtowers that were previously informed
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. This implies either it is an
- // inbound HTLC or an outbound HTLC on a revoked transaction.
+ // 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)) {
}
}
+ 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 {
// 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 {
+ } 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;
}