use bitcoin::blockdata::script::{Script,Builder};
use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
use bitcoin::blockdata::opcodes;
-use bitcoin::util::hash::{BitcoinHash, Sha256dHash};
+use bitcoin::util::hash::BitcoinHash;
use bitcoin::util::bip143;
use bitcoin::consensus::encode::{self, Encodable, Decodable};
use bitcoin_hashes::{Hash, HashEngine};
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::hash160::Hash as Hash160;
+use bitcoin_hashes::sha256d::Hash as Sha256dHash;
use secp256k1::key::{PublicKey,SecretKey};
use secp256k1::{Secp256k1,Signature};
use chain::keysinterface::{ChannelKeys, KeysInterface};
use util::transaction_utils;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, WriterWriteAdaptor};
-use util::logger::Logger;
+use util::logger::{Logger, LogHolder};
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
}, None));
}
- transaction_utils::sort_outputs(&mut txouts);
+ transaction_utils::sort_outputs(&mut txouts, |a, b| {
+ if let &Some(ref a_htlc) = a {
+ if let &Some(ref b_htlc) = b {
+ a_htlc.0.cltv_expiry.cmp(&b_htlc.0.cltv_expiry)
+ // Note that due to hash collisions, we have to have a fallback comparison
+ // here for fuzztarget mode (otherwise at least chanmon_fail_consistency
+ // may fail)!
+ .then(a_htlc.0.payment_hash.0.cmp(&b_htlc.0.payment_hash.0))
+ // For non-HTLC outputs, if they're copying our SPK we don't really care if we
+ // close the channel due to mismatches - they're doing something dumb:
+ } else { cmp::Ordering::Equal }
+ } else { cmp::Ordering::Equal }
+ });
let mut outputs: Vec<TxOut> = Vec::with_capacity(txouts.len());
let mut htlcs_included: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(txouts.len() + included_dust_htlcs.len());
}, ()));
}
- transaction_utils::sort_outputs(&mut txouts);
+ transaction_utils::sort_outputs(&mut txouts, |_, _| { cmp::Ordering::Equal }); // Ordering doesnt matter if they used our pubkey...
let mut outputs: Vec<TxOut> = Vec::new();
for out in txouts.drain(..) {
_ => {}
}
}
+ log_trace!(self, "Adding HTLC claim to holding_cell! Current state: {}", self.channel_state);
self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::ClaimHTLC {
payment_preimage: payment_preimage_arg, htlc_id: htlc_id_arg,
});
debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to");
return Ok((None, Some(self.channel_monitor.clone())));
}
+ log_trace!(self, "Upgrading HTLC {} to LocalRemoved with a Fulfill!", log_bytes!(htlc.payment_hash.0));
htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(payment_preimage_arg.clone()));
}
self.monitor_pending_order = None;
}
+ log_trace!(self, "Updating HTLCs on receipt of RAA...");
let mut to_forward_infos = Vec::new();
let mut revoked_htlcs = Vec::new();
let mut update_fail_htlcs = Vec::new();
let mut update_fail_malformed_htlcs = Vec::new();
let mut require_commitment = false;
let mut value_to_self_msat_diff: i64 = 0;
- // We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug)
- self.pending_inbound_htlcs.retain(|htlc| {
- if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state {
- if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
- value_to_self_msat_diff += htlc.amount_msat as i64;
- }
- false
- } else { true }
- });
- self.pending_outbound_htlcs.retain(|htlc| {
- if let OutboundHTLCState::AwaitingRemovedRemoteRevoke = htlc.state {
- if let Some(reason) = htlc.fail_reason.clone() { // We really want take() here, but, again, non-mut ref :(
- revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
- } else {
- // They fulfilled, so we sent them money
- value_to_self_msat_diff -= htlc.amount_msat as i64;
- }
- false
- } else { true }
- });
- for htlc in self.pending_inbound_htlcs.iter_mut() {
- let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state {
- true
- } else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state {
- true
- } else { false };
- if swap {
- let mut state = InboundHTLCState::Committed;
- mem::swap(&mut state, &mut htlc.state);
-
- if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state {
- htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info);
- require_commitment = true;
- } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state {
- match forward_info {
- PendingHTLCStatus::Fail(fail_msg) => {
- require_commitment = true;
- match fail_msg {
- HTLCFailureMsg::Relay(msg) => {
- htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone()));
- update_fail_htlcs.push(msg)
- },
- HTLCFailureMsg::Malformed(msg) => {
- htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code)));
- update_fail_malformed_htlcs.push(msg)
- },
+
+ {
+ // Take references explicitly so that we can hold multiple references to self.
+ let pending_inbound_htlcs: &mut Vec<_> = &mut self.pending_inbound_htlcs;
+ let pending_outbound_htlcs: &mut Vec<_> = &mut self.pending_outbound_htlcs;
+ let logger = LogHolder { logger: &self.logger };
+
+ // We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug)
+ pending_inbound_htlcs.retain(|htlc| {
+ if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state {
+ log_trace!(logger, " ...removing inbound LocalRemoved {}", log_bytes!(htlc.payment_hash.0));
+ if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
+ value_to_self_msat_diff += htlc.amount_msat as i64;
+ }
+ false
+ } else { true }
+ });
+ pending_outbound_htlcs.retain(|htlc| {
+ if let OutboundHTLCState::AwaitingRemovedRemoteRevoke = htlc.state {
+ log_trace!(logger, " ...removing outbound AwaitingRemovedRemoteRevoke {}", log_bytes!(htlc.payment_hash.0));
+ if let Some(reason) = htlc.fail_reason.clone() { // We really want take() here, but, again, non-mut ref :(
+ revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
+ } else {
+ // They fulfilled, so we sent them money
+ value_to_self_msat_diff -= htlc.amount_msat as i64;
+ }
+ false
+ } else { true }
+ });
+ for htlc in pending_inbound_htlcs.iter_mut() {
+ let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state {
+ log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce {} to Committed", log_bytes!(htlc.payment_hash.0));
+ true
+ } else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state {
+ log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", log_bytes!(htlc.payment_hash.0));
+ true
+ } else { false };
+ if swap {
+ let mut state = InboundHTLCState::Committed;
+ mem::swap(&mut state, &mut htlc.state);
+
+ if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state {
+ htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info);
+ require_commitment = true;
+ } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state {
+ match forward_info {
+ PendingHTLCStatus::Fail(fail_msg) => {
+ require_commitment = true;
+ match fail_msg {
+ HTLCFailureMsg::Relay(msg) => {
+ htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone()));
+ update_fail_htlcs.push(msg)
+ },
+ HTLCFailureMsg::Malformed(msg) => {
+ htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code)));
+ update_fail_malformed_htlcs.push(msg)
+ },
+ }
+ },
+ PendingHTLCStatus::Forward(forward_info) => {
+ to_forward_infos.push((forward_info, htlc.htlc_id));
+ htlc.state = InboundHTLCState::Committed;
}
- },
- PendingHTLCStatus::Forward(forward_info) => {
- to_forward_infos.push((forward_info, htlc.htlc_id));
- htlc.state = InboundHTLCState::Committed;
}
}
}
}
- }
- for htlc in self.pending_outbound_htlcs.iter_mut() {
- if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
- htlc.state = OutboundHTLCState::Committed;
- } else if let OutboundHTLCState::AwaitingRemoteRevokeToRemove = htlc.state {
- htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke;
- require_commitment = true;
+ for htlc in pending_outbound_htlcs.iter_mut() {
+ if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
+ log_trace!(logger, " ...promoting outbound LocalAnnounced {} to Committed", log_bytes!(htlc.payment_hash.0));
+ htlc.state = OutboundHTLCState::Committed;
+ } else if let OutboundHTLCState::AwaitingRemoteRevokeToRemove = htlc.state {
+ log_trace!(logger, " ...promoting outbound AwaitingRemoteRevokeToRemove {} to AwaitingRemovedRemoteRevoke", log_bytes!(htlc.payment_hash.0));
+ htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke;
+ require_commitment = true;
+ }
}
}
self.value_to_self_msat = (self.value_to_self_msat as i64 + value_to_self_msat_diff) as u64;
}
}
+ log_trace!(self, "Regenerated latest commitment update with {} update_adds, {} update_fulfills, {} update_fails, and {} update_fail_malformeds",
+ update_add_htlcs.len(), update_fulfill_htlcs.len(), update_fail_htlcs.len(), update_fail_malformed_htlcs.len());
msgs::CommitmentUpdate {
update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs,
update_fee: None, //TODO: We need to support re-generating any update_fees in the last commitment_signed!
excess_data: Vec::new(),
};
- let msghash = hash_to_message!(&Sha256dHash::from_data(&msg.encode()[..])[..]);
+ let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
let sig = self.secp_ctx.sign(&msghash, &self.local_keys.funding_key);
Ok((msg, sig))
#[cfg(test)]
mod tests {
- use bitcoin::util::hash::{Sha256dHash, Hash160};
use bitcoin::util::bip143;
use bitcoin::consensus::encode::serialize;
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::blockdata::opcodes;
+ use bitcoin_hashes::hex::FromHex;
use hex;
use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys};
use secp256k1::{Secp256k1,Message,Signature};
use secp256k1::key::{SecretKey,PublicKey};
use bitcoin_hashes::sha256::Hash as Sha256;
+ use bitcoin_hashes::sha256d::Hash as Sha256dHash;
+ use bitcoin_hashes::hash160::Hash as Hash160;
use bitcoin_hashes::Hash;
use std::sync::Arc;
fn get_destination_script(&self) -> Script {
let secp_ctx = Secp256k1::signing_only();
let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
- let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
+ let our_channel_monitor_claim_key_hash = Hash160::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
}