use crypto::digest::Digest;
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
-use lightning::ln::{channelmonitor,msgs};
+use lightning::ln::channelmonitor;
use lightning::ln::channelmanager::ChannelManager;
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
use lightning::ln::router::Router;
struct TestChannelMonitor {}
impl channelmonitor::ManyChannelMonitor for TestChannelMonitor {
- fn add_update_monitor(&self, _funding_txo: (Sha256dHash, u16), _monitor: channelmonitor::ChannelMonitor) -> Result<(), msgs::HandleError> {
+ fn add_update_monitor(&self, _funding_txo: (Sha256dHash, u16), _monitor: channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> {
//TODO!
Ok(())
}
use bitcoin::blockdata::script::{Script,Builder};
use bitcoin::blockdata::opcodes;
-use bitcoin::util::hash::Hash160;
+use bitcoin::blockdata::transaction::{TxIn,TxOut,Transaction};
+use bitcoin::util::hash::{Hash160,Sha256dHash};
use secp256k1::key::{PublicKey,SecretKey};
use secp256k1::Secp256k1;
use util::sha2::Sha256;
+pub const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
+pub const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
+
// Various functions for key derivation and transaction creation for use within channels. Primarily
// used in Channel and ChannelMonitor.
pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Script {
get_htlc_redeemscript_with_explicit_keys(htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key)
}
+
+pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
+ let mut txins: Vec<TxIn> = Vec::new();
+ txins.push(TxIn {
+ prev_hash: prev_hash.clone(),
+ prev_index: htlc.transaction_output_index,
+ script_sig: Script::new(),
+ sequence: 0,
+ witness: Vec::new(),
+ });
+
+ let total_fee = if htlc.offered {
+ feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000
+ } else {
+ feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000
+ };
+
+ let mut txouts: Vec<TxOut> = Vec::new();
+ txouts.push(TxOut {
+ script_pubkey: get_revokeable_redeemscript(revocation_key, to_self_delay, a_delayed_payment_key).to_v0_p2wsh(),
+ value: htlc.amount_msat / 1000 - total_fee //TODO: BOLT 3 does not specify if we should add amount_msat before dividing or if we should divide by 1000 before subtracting (as we do here)
+ });
+
+ Transaction {
+ version: 2,
+ lock_time: if htlc.offered { htlc.cltv_expiry } else { 0 },
+ input: txins,
+ output: txouts,
+ }
+}
use ln::msgs::{HandleError, MsgEncodable};
use ln::channelmonitor::ChannelMonitor;
use ln::channelmanager::{PendingForwardHTLCInfo, HTLCFailReason};
-use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment};
+use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
use util::{transaction_utils,rng};
channel_update_count: u32,
feerate_per_kw: u64,
+ #[cfg(test)]
+ // Used in ChannelManager's tests to send a revoked transaction
+ pub last_local_commitment_txn: Vec<Transaction>,
+ #[cfg(not(test))]
+ last_local_commitment_txn: Vec<Transaction>,
+
last_sent_closing_fee: Option<(u64, u64)>, // (feerate, fee)
/// The hash of the block in which the funding transaction reached our CONF_TARGET. We use this
const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 14;
const COMMITMENT_TX_BASE_WEIGHT: u64 = 724;
const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172;
-const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
-const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
const SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT: u64 = 79; // prevout: 36, nSequence: 4, script len: 1, witness lengths: (3+1)/4, sig: 73/4, if-selector: 1, redeemScript: (6 ops + 2*33 pubkeys + 1*2 delay)/4
const B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT: u64 = 104; // prevout: 40, nSequence: 4, script len: 1, witness lengths: 3/4, sig: 73/4, pubkey: 33/4, output: 31 (TODO: Wrong? Useless?)
let our_channel_monitor_claim_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script();
let channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key,
&PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key).unwrap(),
- &PublicKey::from_secret_key(&secp_ctx, &chan_keys.htlc_base_key).unwrap(),
+ &chan_keys.htlc_base_key,
BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script);
Channel {
next_remote_htlc_id: 0,
channel_update_count: 0,
+ last_local_commitment_txn: Vec::new(),
+
last_sent_closing_fee: None,
funding_tx_confirmed_in: Default::default(),
let our_channel_monitor_claim_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script();
let mut channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key,
&PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key).unwrap(),
- &PublicKey::from_secret_key(&secp_ctx, &chan_keys.htlc_base_key).unwrap(),
+ &chan_keys.htlc_base_key,
BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script);
channel_monitor.set_their_htlc_base_key(&msg.htlc_basepoint);
+ channel_monitor.set_their_to_self_delay(msg.to_self_delay);
let mut chan = Channel {
user_id: user_id,
next_remote_htlc_id: 0,
channel_update_count: 0,
+ last_local_commitment_txn: Vec::new(),
+
last_sent_closing_fee: None,
funding_tx_confirmed_in: Default::default(),
/// @local is used only to convert relevant internal structures which refer to remote vs local
/// to decide value of outputs and direction of HTLCs.
fn build_htlc_transaction(&self, prev_hash: &Sha256dHash, htlc: &HTLCOutputInCommitment, local: bool, keys: &TxCreationKeys) -> Transaction {
- let mut txins: Vec<TxIn> = Vec::new();
- txins.push(TxIn {
- prev_hash: prev_hash.clone(),
- prev_index: htlc.transaction_output_index,
- script_sig: Script::new(),
- sequence: 0,
- witness: Vec::new(),
- });
+ chan_utils::build_htlc_transaction(prev_hash, self.feerate_per_kw, if local { self.their_to_self_delay } else { BREAKDOWN_TIMEOUT }, htlc, &keys.a_delayed_payment_key, &keys.revocation_key)
+ }
- let total_fee = if htlc.offered {
- self.feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000
- } else {
- self.feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000
- };
+ fn create_htlc_tx_signature(&self, tx: &Transaction, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<(Script, Signature, bool), HandleError> {
+ if tx.input.len() != 1 {
+ panic!("Tried to sign HTLC transaction that had input count != 1!");
+ }
- let mut txouts: Vec<TxOut> = Vec::new();
- txouts.push(TxOut {
- script_pubkey: chan_utils::get_revokeable_redeemscript(&keys.revocation_key,
- if local { self.their_to_self_delay } else { BREAKDOWN_TIMEOUT },
- &keys.a_delayed_payment_key).to_v0_p2wsh(),
- value: htlc.amount_msat / 1000 - total_fee //TODO: BOLT 3 does not specify if we should add amount_msat before dividing or if we should divide by 1000 before subtracting (as we do here)
- });
+ let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
- Transaction {
- version: 2,
- lock_time: if htlc.offered { htlc.cltv_expiry } else { 0 },
- input: txins,
- output: txouts,
- }
+ let our_htlc_key = secp_derived_key!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, &self.local_keys.htlc_base_key));
+ let sighash = Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
+ let is_local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key).unwrap() == keys.a_htlc_key;
+ Ok((htlc_redeemscript, self.secp_ctx.sign(&sighash, &our_htlc_key).unwrap(), is_local_tx))
}
/// Signs a transaction created by build_htlc_transaction. If the transaction is an
/// HTLC-Success transaction (ie htlc.offered is false), preimate must be set!
- fn sign_htlc_transaction(&self, tx: &mut Transaction, their_sig: &Signature, preimage: &Option<[u8; 32]>, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<(), HandleError> {
+ fn sign_htlc_transaction(&self, tx: &mut Transaction, their_sig: &Signature, preimage: &Option<[u8; 32]>, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<Signature, HandleError> {
if tx.input.len() != 1 {
panic!("Tried to sign HTLC transaction that had input count != 1!");
}
panic!("Tried to re-sign HTLC transaction");
}
- let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
-
- let our_htlc_key = secp_derived_key!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, &self.local_keys.htlc_base_key));
- let sighash = Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
- let our_sig = self.secp_ctx.sign(&sighash, &our_htlc_key).unwrap();
-
- let local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key).unwrap() == keys.a_htlc_key;
+ let (htlc_redeemscript, our_sig, local_tx) = self.create_htlc_tx_signature(tx, htlc, keys)?;
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
tx.input[0].witness.push(htlc_redeemscript.into_vec());
- Ok(())
+ Ok(our_sig)
}
- pub fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result<Option<msgs::UpdateFulfillHTLC>, HandleError> {
+ pub fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result<Option<(msgs::UpdateFulfillHTLC, ChannelMonitor)>, HandleError> {
// Either ChannelFunded got set (which means it wont bet unset) or there is no way any
// caller thought we could have something claimed (cause we wouldn't have accepted in an
// incoming HTLC anyway). If we got to ShutdownComplete, callers aren't allowed to call us,
if htlc_amount_msat == 0 {
return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None});
}
- self.channel_monitor.provide_payment_preimage(&payment_preimage_arg);
+ self.channel_monitor.provide_payment_preimage(&payment_hash_calc, &payment_preimage_arg);
- Ok(Some(msgs::UpdateFulfillHTLC {
+ Ok(Some((msgs::UpdateFulfillHTLC {
channel_id: self.channel_id(),
htlc_id: htlc_id,
payment_preimage: payment_preimage_arg,
- }))
+ }, self.channel_monitor.clone())))
}
- pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result<Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)>, HandleError> {
+ pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result<Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
match self.get_update_fulfill_htlc(payment_preimage)? {
- Some(update_fulfill_htlc) =>
- Ok(Some((update_fulfill_htlc, self.send_commitment_no_status_check()?))),
+ Some(update_fulfill_htlc) => {
+ let (commitment, monitor_update) = self.send_commitment_no_status_check()?;
+ Ok(Some((update_fulfill_htlc.0, commitment, monitor_update)))
+ },
None => Ok(None)
}
}
}))
}
- pub fn get_update_fail_htlc_and_commit(&mut self, payment_hash: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result<Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned)>, HandleError> {
+ pub fn get_update_fail_htlc_and_commit(&mut self, payment_hash: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result<Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
match self.get_update_fail_htlc(payment_hash, err_packet)? {
- Some(update_fail_htlc) =>
- Ok(Some((update_fail_htlc, self.send_commitment_no_status_check()?))),
+ Some(update_fail_htlc) => {
+ let (commitment, monitor_update) = self.send_commitment_no_status_check()?;
+ Ok(Some((update_fail_htlc, commitment, monitor_update)))
+ },
None => Ok(None)
}
}
let obscure_factor = self.get_commitment_transaction_number_obscure_factor();
self.channel_monitor.set_commitment_obscure_factor(obscure_factor);
+ self.channel_monitor.set_their_to_self_delay(msg.to_self_delay);
self.channel_state = ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32;
Ok((remote_initial_commitment_tx, self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap()))
}
- pub fn funding_created(&mut self, msg: &msgs::FundingCreated) -> Result<msgs::FundingSigned, HandleError> {
+ pub fn funding_created(&mut self, msg: &msgs::FundingCreated) -> Result<(msgs::FundingSigned, ChannelMonitor), HandleError> {
if self.channel_outbound {
return Err(HandleError{err: "Received funding_created for an outbound channel?", msg: None});
}
self.channel_monitor.set_funding_info(msg.funding_txid, msg.funding_output_index);
let (remote_initial_commitment_tx, our_signature) = match self.funding_created_signature(&msg.signature) {
- Ok((remote_initial_commitment_tx, sig)) => (remote_initial_commitment_tx, sig),
+ Ok(res) => res,
Err(e) => {
self.channel_monitor.unset_funding_info();
return Err(e);
// Now that we're past error-generating stuff, update our local state:
- //TODO: Determine which tx index in remote_initial_commitment_transaction's outputs
- //represent a revokeable script!
- self.channel_monitor.provide_tx_info(&remote_initial_commitment_tx, 0, Vec::new());
+ self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_initial_commitment_tx, Vec::new());
self.channel_state = ChannelState::FundingSent as u32;
let funding_txo = self.channel_monitor.get_funding_txo().unwrap();
self.channel_id = funding_txo.0.into_be() ^ Uint256::from_u64(funding_txo.1 as u64).unwrap(); //TODO: or le?
self.cur_remote_commitment_transaction_number -= 1;
self.cur_local_commitment_transaction_number -= 1;
- Ok(msgs::FundingSigned {
+ Ok((msgs::FundingSigned {
channel_id: self.channel_id,
signature: our_signature
- })
+ }, self.channel_monitor.clone()))
}
/// Handles a funding_signed message from the remote end.
/// If this call is successful, broadcast the funding transaction (and not before!)
- pub fn funding_signed(&mut self, msg: &msgs::FundingSigned) -> Result<(), HandleError> {
+ pub fn funding_signed(&mut self, msg: &msgs::FundingSigned) -> Result<ChannelMonitor, HandleError> {
if !self.channel_outbound {
return Err(HandleError{err: "Received funding_signed for an inbound channel?", msg: None});
}
let funding_script = self.get_funding_redeemscript();
let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?;
- let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false).0;
+ let mut local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false).0;
let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
// They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish.
secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey), "Invalid funding_signed signature from peer");
+ self.sign_commitment_transaction(&mut local_initial_commitment_tx, &msg.signature);
+ self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, Vec::new());
+ self.last_local_commitment_txn = vec![local_initial_commitment_tx];
self.channel_state = ChannelState::FundingSent as u32;
self.cur_local_commitment_transaction_number -= 1;
- Ok(())
+ Ok(self.channel_monitor.clone())
}
pub fn funding_locked(&mut self, msg: &msgs::FundingLocked) -> Result<(), HandleError> {
Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", msg: None})
}
- pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(), HandleError> {
+ pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<ChannelMonitor, HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None});
}
let mut payment_hash = [0; 32];
sha.result(&mut payment_hash);
- self.channel_monitor.provide_payment_preimage(&msg.payment_preimage);
+ self.channel_monitor.provide_payment_preimage(&payment_hash, &msg.payment_preimage);
self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)?;
- Ok(())
+ Ok(self.channel_monitor.clone())
}
pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<[u8; 32], HandleError> {
Ok(())
}
- pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option<msgs::CommitmentSigned>), HandleError> {
+ pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option<msgs::CommitmentSigned>, ChannelMonitor), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got commitment signed message when channel was not in an operational state", msg: None});
}
let funding_script = self.get_funding_redeemscript();
let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?;
- let local_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false);
+ let mut local_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false);
let local_commitment_txid = local_commitment_tx.0.txid();
let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_commitment_tx.0).sighash_all(&local_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey), "Invalid commitment tx signature from peer");
return Err(HandleError{err: "Got wrong number of HTLC signatures from remote", msg: None});
}
+ let mut new_local_commitment_txn = Vec::with_capacity(local_commitment_tx.1.len() + 1);
+ self.sign_commitment_transaction(&mut local_commitment_tx.0, &msg.signature);
+ new_local_commitment_txn.push(local_commitment_tx.0.clone());
+
+ let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.1.len());
for (idx, ref htlc) in local_commitment_tx.1.iter().enumerate() {
- let htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys);
+ let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
secp_call!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx siganture from peer");
+ let htlc_sig = if htlc.offered {
+ let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, htlc, &local_keys)?;
+ new_local_commitment_txn.push(htlc_tx);
+ htlc_sig
+ } else {
+ self.create_htlc_tx_signature(&htlc_tx, htlc, &local_keys)?.1
+ };
+ htlcs_and_sigs.push(((*htlc).clone(), msg.htlc_signatures[idx], htlc_sig));
}
let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1)).unwrap();
let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, self.cur_local_commitment_transaction_number + 1);
// Update state now that we've passed all the can-fail calls...
+ self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs);
let mut need_our_commitment = false;
for htlc in self.pending_htlcs.iter_mut() {
self.value_to_self_msat += claimed_value_msat;
self.cur_local_commitment_transaction_number -= 1;
+ self.last_local_commitment_txn = new_local_commitment_txn;
- let our_commitment_signed = if need_our_commitment && (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == 0 {
+ let (our_commitment_signed, monitor_update) = if need_our_commitment && (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == 0 {
// If we're AwaitingRemoteRevoke we can't send a new commitment here, but that's ok -
// we'll send one right away when we get the revoke_and_ack when we
// free_holding_cell_htlcs().
- Some(self.send_commitment_no_status_check()?)
- } else { None };
+ let (msg, monitor) = self.send_commitment_no_status_check()?;
+ (Some(msg), monitor)
+ } else { (None, self.channel_monitor.clone()) };
Ok((msgs::RevokeAndACK {
channel_id: self.channel_id,
per_commitment_secret: per_commitment_secret,
next_per_commitment_point: next_per_commitment_point,
- }, our_commitment_signed))
+ }, our_commitment_signed, monitor_update))
}
/// Used to fulfill holding_cell_htlcs when we get a remote ack (or implicitly get it by them
/// fulfilling or failing the last pending HTLC)
- fn free_holding_cell_htlcs(&mut self) -> Result<Option<msgs::CommitmentUpdate>, HandleError> {
+ fn free_holding_cell_htlcs(&mut self) -> Result<Option<(msgs::CommitmentUpdate, ChannelMonitor)>, HandleError> {
if self.holding_cell_htlc_updates.len() != 0 {
let mut htlc_updates = Vec::new();
mem::swap(&mut htlc_updates, &mut self.holding_cell_htlc_updates);
},
&HTLCUpdateAwaitingACK::ClaimHTLC { payment_preimage, .. } => {
match self.get_update_fulfill_htlc(payment_preimage) {
- Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.unwrap()),
+ Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.unwrap().0),
Err(e) => {
err = Some(e);
}
//fail it back the route, if its a temporary issue we can ignore it...
match err {
None => {
- Ok(Some(msgs::CommitmentUpdate {
+ let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?;
+ Ok(Some((msgs::CommitmentUpdate {
update_add_htlcs,
update_fulfill_htlcs,
update_fail_htlcs,
- commitment_signed: self.send_commitment_no_status_check()?
- }))
+ commitment_signed,
+ }, monitor_update)))
},
Some(e) => Err(e)
}
/// waiting on this revoke_and_ack. The generation of this new commitment_signed may also fail,
/// generating an appropriate error *after* the channel state has been updated based on the
/// revoke_and_ack message.
- pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK) -> Result<(Option<msgs::CommitmentUpdate>, Vec<PendingForwardHTLCInfo>, Vec<([u8; 32], HTLCFailReason)>), HandleError> {
+ pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK) -> Result<(Option<msgs::CommitmentUpdate>, Vec<PendingForwardHTLCInfo>, Vec<([u8; 32], HTLCFailReason)>, ChannelMonitor), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got revoke/ACK message when channel was not in an operational state", msg: None});
}
return Err(HandleError{err: "Got a revoke commitment secret which didn't correspond to their current pubkey", msg: None});
}
}
- self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number + 1, msg.per_commitment_secret)?;
+ self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number + 1, msg.per_commitment_secret, Some((self.cur_remote_commitment_transaction_number - 1, msg.next_per_commitment_point)))?;
// Update state now that we've passed all the can-fail calls...
// (note that we may still fail to generate the new commitment_signed message, but that's
match self.free_holding_cell_htlcs()? {
Some(commitment_update) => {
- Ok((Some(commitment_update), to_forward_infos, revoked_htlcs))
+ Ok((Some(commitment_update.0), to_forward_infos, revoked_htlcs, commitment_update.1))
},
None => {
if require_commitment {
+ let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?;
Ok((Some(msgs::CommitmentUpdate {
update_add_htlcs: Vec::new(),
update_fulfill_htlcs: Vec::new(),
update_fail_htlcs: Vec::new(),
- commitment_signed: self.send_commitment_no_status_check()?
- }), to_forward_infos, revoked_htlcs))
+ commitment_signed
+ }), to_forward_infos, revoked_htlcs, monitor_update))
} else {
- Ok((None, to_forward_infos, revoked_htlcs))
+ Ok((None, to_forward_infos, revoked_htlcs, self.channel_monitor.clone()))
}
}
}
self.user_id
}
+ pub fn channel_monitor(&self) -> ChannelMonitor {
+ if self.channel_state < ChannelState::FundingCreated as u32 {
+ panic!("Can't get a channel monitor until funding has been created");
+ }
+ self.channel_monitor.clone()
+ }
+
/// Guaranteed to be Some after both FundingLocked messages have been exchanged (and, thus,
/// is_usable() returns true).
pub fn get_short_channel_id(&self) -> Option<u64> {
res as u32
}
- pub fn channel_monitor(&self) -> ChannelMonitor {
- if self.channel_state < ChannelState::FundingCreated as u32 {
- panic!("Can't get a channel monitor until funding has been created");
- }
- self.channel_monitor.clone()
- }
-
/// Returns true if this channel is fully established and not known to be closing.
pub fn is_usable(&self) -> bool {
let mask = ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK;
})
}
- fn get_outbound_funding_created_signature(&mut self) -> Result<Signature, HandleError> {
+ fn get_outbound_funding_created_signature(&mut self) -> Result<(Signature, Transaction), HandleError> {
let funding_script = self.get_funding_redeemscript();
let remote_keys = self.build_remote_transaction_keys()?;
let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
- Ok(self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap())
+ Ok((self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap(), remote_initial_commitment_tx))
}
/// Updates channel state with knowledge of the funding transaction's txid/index, and generates
/// or if called on an inbound channel.
/// Note that channel_id changes during this call!
/// Do NOT broadcast the funding transaction until after a successful funding_signed call!
- pub fn get_outbound_funding_created(&mut self, funding_txid: Sha256dHash, funding_output_index: u16) -> Result<msgs::FundingCreated, HandleError> {
+ pub fn get_outbound_funding_created(&mut self, funding_txid: Sha256dHash, funding_output_index: u16) -> Result<(msgs::FundingCreated, ChannelMonitor), HandleError> {
if !self.channel_outbound {
panic!("Tried to create outbound funding_created message on an inbound channel!");
}
self.channel_monitor.set_funding_info(funding_txid, funding_output_index);
- let our_signature = match self.get_outbound_funding_created_signature() {
- Ok(sig) => sig,
+ let (our_signature, commitment_tx) = match self.get_outbound_funding_created_signature() {
+ Ok(res) => res,
Err(e) => {
self.channel_monitor.unset_funding_info();
return Err(e);
let temporary_channel_id = self.channel_id;
// Now that we're past error-generating stuff, update our local state:
-
+ self.channel_monitor.provide_latest_remote_commitment_tx_info(&commitment_tx, Vec::new());
self.channel_state = ChannelState::FundingCreated as u32;
let funding_txo = self.channel_monitor.get_funding_txo().unwrap();
self.channel_id = funding_txo.0.into_be() ^ Uint256::from_u64(funding_txo.1 as u64).unwrap(); //TODO: or le?
self.cur_remote_commitment_transaction_number -= 1;
- Ok(msgs::FundingCreated {
+ Ok((msgs::FundingCreated {
temporary_channel_id: temporary_channel_id,
funding_txid: funding_txid,
funding_output_index: funding_output_index,
signature: our_signature
- })
+ }, self.channel_monitor.clone()))
}
/// Gets an UnsignedChannelAnnouncement, as well as a signature covering it using our
}
/// Creates a signed commitment transaction to send to the remote peer.
- pub fn send_commitment(&mut self) -> Result<msgs::CommitmentSigned, HandleError> {
+ pub fn send_commitment(&mut self) -> Result<(msgs::CommitmentSigned, ChannelMonitor), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Cannot create commitment tx until channel is fully established", msg: None});
}
self.send_commitment_no_status_check()
}
/// Only fails in case of bad keys
- fn send_commitment_no_status_check(&mut self) -> Result<msgs::CommitmentSigned, HandleError> {
+ fn send_commitment_no_status_check(&mut self) -> Result<(msgs::CommitmentSigned, ChannelMonitor), HandleError> {
let funding_script = self.get_funding_redeemscript();
// We can upgrade the status of some HTLCs that are waiting on a commitment, even if we
}
// Update state now that we've passed all the can-fail calls...
+ self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx.0, remote_commitment_tx.1);
self.channel_state |= ChannelState::AwaitingRemoteRevoke as u32;
- Ok(msgs::CommitmentSigned {
+ Ok((msgs::CommitmentSigned {
channel_id: self.channel_id,
signature: our_sig,
htlc_signatures: htlc_sigs,
- })
+ }, self.channel_monitor.clone()))
}
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
/// to send to the remote peer in one go.
/// Shorthand for calling send_htlc() followed by send_commitment(), see docs on those for
/// more info.
- pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, onion_routing_packet: msgs::OnionPacket) -> Result<Option<(msgs::UpdateAddHTLC, msgs::CommitmentSigned)>, HandleError> {
+ pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, onion_routing_packet: msgs::OnionPacket) -> Result<Option<(msgs::UpdateAddHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
match self.send_htlc(amount_msat, payment_hash, cltv_expiry, onion_routing_packet)? {
- Some(update_add_htlc) =>
- Ok(Some((update_add_htlc, self.send_commitment_no_status_check()?))),
+ Some(update_add_htlc) => {
+ let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?;
+ Ok(Some((update_add_htlc, commitment_signed, monitor_update)))
+ },
None => Ok(None)
}
}
scriptpubkey: our_closing_script,
}, dropped_outbound_htlcs))
}
+
+ /// Gets the latest commitment transaction and any dependant transactions for relay (forcing
+ /// shutdown of this channel - no more calls into this Channel may be made afterwards.
+ pub fn force_shutdown(&mut self) -> Vec<Transaction> {
+ assert!(self.channel_state != ChannelState::ShutdownComplete as u32);
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+ let mut res = Vec::new();
+ mem::swap(&mut res, &mut self.last_local_commitment_txn);
+ res
+ }
}
#[cfg(test)]
let (onion_payloads, htlc_msat, htlc_cltv) = ChannelManager::build_onion_payloads(&route)?;
let onion_packet = ChannelManager::construct_onion_packet(onion_payloads, onion_keys, associated_data)?;
- let mut channel_state = self.channel_state.lock().unwrap();
- let id = match channel_state.short_to_id.get(&route.hops.first().unwrap().short_channel_id) {
- None => return Err(HandleError{err: "No channel available with first hop!", msg: None}),
- Some(id) => id.clone()
- };
- let res = {
- let chan = channel_state.by_id.get_mut(&id).unwrap();
- if chan.get_their_node_id() != route.hops.first().unwrap().pubkey {
- return Err(HandleError{err: "Node ID mismatch on first hop!", msg: None});
+ let (update_add, commitment_signed, chan_monitor) = {
+ let mut channel_state = self.channel_state.lock().unwrap();
+ let id = match channel_state.short_to_id.get(&route.hops.first().unwrap().short_channel_id) {
+ None => return Err(HandleError{err: "No channel available with first hop!", msg: None}),
+ Some(id) => id.clone()
+ };
+ let res = {
+ let chan = channel_state.by_id.get_mut(&id).unwrap();
+ if chan.get_their_node_id() != route.hops.first().unwrap().pubkey {
+ return Err(HandleError{err: "Node ID mismatch on first hop!", msg: None});
+ }
+ chan.send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, onion_packet)?
+ };
+
+ if channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute {
+ route,
+ session_priv,
+ }).is_some() {
+ // TODO: We need to track these better, we're not generating these, so a
+ // third-party might make this happen:
+ panic!("payment_hash was repeated! Don't let this happen");
+ }
+
+ match res {
+ Some(msgs) => msgs,
+ None => return Ok(None),
}
- chan.send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, onion_packet)?
};
- if channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute {
- route,
- session_priv,
- }).is_some() {
- // TODO: We need to track these better, we're not generating these, so a
- // third-party might make this happen:
- panic!("payment_hash was repeated! Don't let this happen");
+ if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
+ unimplemented!(); // maybe remove from claimable_htlcs?
}
-
- Ok(res)
+ Ok(Some((update_add, commitment_signed)))
}
/// Call this upon creation of a funding transaction for the given channel.
/// Panics if a funding transaction has already been provided for this channel.
pub fn funding_transaction_generated(&self, temporary_channel_id: &Uint256, funding_txo: (Sha256dHash, u16)) {
- let (chan, msg) = {
+ let (chan, msg, chan_monitor) = {
let mut channel_state = self.channel_state.lock().unwrap();
match channel_state.by_id.remove(&temporary_channel_id) {
Some(mut chan) => {
match chan.get_outbound_funding_created(funding_txo.0, funding_txo.1) {
Ok(funding_msg) => {
- (chan, funding_msg)
+ (chan, funding_msg.0, funding_msg.1)
},
Err(_e) => {
//TODO: Push e to pendingevents
None => return
}
}; // Release channel lock for install_watch_outpoint call,
- let chan_monitor = chan.channel_monitor();
- match self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
- Ok(()) => {},
- Err(_e) => {
- //TODO: Push e to pendingevents?
- return;
- }
- };
-
+ if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
+ unimplemented!(); // maybe remove from claimable_htlcs?
+ }
{
let mut pending_events = self.pending_events.lock().unwrap();
pending_events.push(events::Event::SendFundingCreated {
}
if !add_htlc_msgs.is_empty() {
- let commitment_msg = match forward_chan.send_commitment() {
- Ok(msg) => msg,
+ let (commitment_msg, monitor) = match forward_chan.send_commitment() {
+ Ok(res) => res,
Err(_) => {
//TODO: Handle...this is bad!
continue;
},
};
- new_events.push(events::Event::SendHTLCs {
+ new_events.push((Some(monitor), events::Event::SendHTLCs {
node_id: forward_chan.get_their_node_id(),
msgs: add_htlc_msgs,
commitment_msg: commitment_msg,
- });
+ }));
}
} else {
for forward_info in pending_forwards {
- new_events.push(events::Event::PaymentReceived {
+ new_events.push((None, events::Event::PaymentReceived {
payment_hash: forward_info.payment_hash,
amt: forward_info.amt_to_forward,
- });
+ }));
}
}
}
if new_events.is_empty() { return }
+ new_events.retain(|event| {
+ if let &Some(ref monitor) = &event.0 {
+ if let Err(_e) = self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor.clone()) {
+ unimplemented!();// but def dont push the event...
+ }
+ }
+ true
+ });
+
let mut events = self.pending_events.lock().unwrap();
events.reserve(new_events.len());
for event in new_events.drain(..) {
- events.push(event);
+ events.push(event.1);
}
}
};
match fail_msgs {
- Some(msgs) => {
+ Some((msg, commitment_msg, chan_monitor)) => {
mem::drop(channel_state);
+
+ if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
+ unimplemented!();// but def dont push the event...
+ }
+
let mut pending_events = self.pending_events.lock().unwrap();
pending_events.push(events::Event::SendFailHTLC {
node_id,
- msg: msgs.0,
- commitment_msg: msgs.1,
+ msg: msg,
+ commitment_msg: commitment_msg,
});
},
None => {},
false
},
PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, .. } => {
- let (node_id, fulfill_msgs, monitor) = {
+ let (node_id, fulfill_msgs) = {
let chan_id = match channel_state.short_to_id.get(&source_short_channel_id) {
Some(chan_id) => chan_id.clone(),
None => return false
let chan = channel_state.by_id.get_mut(&chan_id).unwrap();
match chan.get_update_fulfill_htlc_and_commit(payment_preimage) {
- Ok(msg) => (chan.get_their_node_id(), msg, if from_user { Some(chan.channel_monitor()) } else { None }),
+ Ok(msg) => (chan.get_their_node_id(), msg),
Err(_e) => {
//TODO: Do something with e?
return false;
mem::drop(channel_state);
match fulfill_msgs {
- Some(msgs) => {
+ Some((msg, commitment_msg, chan_monitor)) => {
+ if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
+ unimplemented!();// but def dont push the event...
+ }
+
let mut pending_events = self.pending_events.lock().unwrap();
pending_events.push(events::Event::SendFulfillHTLC {
node_id: node_id,
- msg: msgs.0,
- commitment_msg: msgs.1,
+ msg,
+ commitment_msg,
});
},
None => {},
}
-
- //TODO: It may not be possible to handle add_update_monitor fails gracefully, maybe
- //it should return no Err? Sadly, panic!()s instead doesn't help much :(
- if from_user {
- match self.monitor.add_update_monitor(monitor.as_ref().unwrap().get_funding_txo().unwrap(), monitor.unwrap()) {
- Ok(()) => true,
- Err(_) => true,
- }
- } else { true }
+ true
},
}
}
pub fn get_our_node_id(&self) -> PublicKey {
PublicKey::from_secret_key(&self.secp_ctx, &self.our_network_key).unwrap()
}
+
+ /// Used to restore channels to normal operation after a
+ /// ChannelMonitorUpdateErr::TemporaryFailure was returned from a channel monitor update
+ /// operation.
+ pub fn test_restore_channel_monitor(&self) {
+ unimplemented!();
+ }
}
impl events::EventsProvider for ChannelManager {
{
let mut channel_state = self.channel_state.lock().unwrap();
let mut short_to_ids_to_insert = Vec::new();
- for channel in channel_state.by_id.values_mut() {
- match channel.block_connected(header, height, txn_matched, indexes_of_txn_matched) {
- Some(funding_locked) => {
- let announcement_sigs = match self.get_announcement_sigs(channel) {
- Ok(res) => res,
- Err(_e) => {
- //TODO: push e on events and blow up the channel (it has bad keys)
- continue;
+ let mut short_to_ids_to_remove = Vec::new();
+ channel_state.by_id.retain(|_, channel| {
+ if let Some(funding_locked) = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched) {
+ let announcement_sigs = match self.get_announcement_sigs(channel) {
+ Ok(res) => res,
+ Err(_e) => {
+ //TODO: push e on events and blow up the channel (it has bad keys)
+ return true;
+ }
+ };
+ new_funding_locked_messages.push(events::Event::SendFundingLocked {
+ node_id: channel.get_their_node_id(),
+ msg: funding_locked,
+ announcement_sigs: announcement_sigs
+ });
+ short_to_ids_to_insert.push((channel.get_short_channel_id().unwrap(), channel.channel_id()));
+ }
+ if let Some(funding_txo) = channel.get_funding_txo() {
+ for tx in txn_matched {
+ for inp in tx.input.iter() {
+ if inp.prev_hash == funding_txo.0 && inp.prev_index == funding_txo.1 as u32 {
+ if let Some(short_id) = channel.get_short_channel_id() {
+ short_to_ids_to_remove.push(short_id);
+ }
+ channel.force_shutdown();
+ return false;
}
- };
- new_funding_locked_messages.push(events::Event::SendFundingLocked {
- node_id: channel.get_their_node_id(),
- msg: funding_locked,
- announcement_sigs: announcement_sigs
- });
- short_to_ids_to_insert.push((channel.get_short_channel_id().unwrap(), channel.channel_id()));
- },
- None => {}
+ }
+ }
}
- //TODO: Check if channel was closed (or disabled) here
+ if channel.channel_monitor().would_broadcast_at_height(height) {
+ if let Some(short_id) = channel.get_short_channel_id() {
+ short_to_ids_to_remove.push(short_id);
+ }
+ channel.force_shutdown();
+ return false;
+ }
+ true
+ });
+ for to_remove in short_to_ids_to_remove {
+ channel_state.short_to_id.remove(&to_remove);
}
for to_insert in short_to_ids_to_insert {
channel_state.short_to_id.insert(to_insert.0, to_insert.1);
//TODO: broke this - a node shouldn't be able to get their channel removed by sending a
//funding_created a second time, or long after the first, or whatever (note this also
//leaves the short_to_id map in a busted state.
- let chan = {
+ let (chan, funding_msg, monitor_update) = {
let mut channel_state = self.channel_state.lock().unwrap();
match channel_state.by_id.remove(&msg.temporary_channel_id) {
Some(mut chan) => {
return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
}
match chan.funding_created(msg) {
- Ok(funding_msg) => {
- (chan, funding_msg)
+ Ok((funding_msg, monitor_update)) => {
+ (chan, funding_msg, monitor_update)
},
Err(e) => {
return Err(e);
// note that this means if the remote end is misbehaving and sends a message for the same
// channel back-to-back with funding_created, we'll end up thinking they sent a message
// for a bogus channel.
- let chan_monitor = chan.0.channel_monitor();
- self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor)?;
+ if let Err(_e) = self.monitor.add_update_monitor(monitor_update.get_funding_txo().unwrap(), monitor_update) {
+ unimplemented!();
+ }
let mut channel_state = self.channel_state.lock().unwrap();
- channel_state.by_id.insert(chan.1.channel_id, chan.0);
- Ok(chan.1)
+ channel_state.by_id.insert(funding_msg.channel_id, chan);
+ Ok(funding_msg)
}
fn handle_funding_signed(&self, their_node_id: &PublicKey, msg: &msgs::FundingSigned) -> Result<(), HandleError> {
- let (funding_txo, user_id) = {
+ let (funding_txo, user_id, monitor) = {
let mut channel_state = self.channel_state.lock().unwrap();
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
}
- chan.funding_signed(&msg)?;
- (chan.get_funding_txo().unwrap(), chan.get_user_id())
+ let chan_monitor = chan.funding_signed(&msg)?;
+ (chan.get_funding_txo().unwrap(), chan.get_user_id(), chan_monitor)
},
None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
}
};
+ if let Err(_e) = self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor) {
+ unimplemented!();
+ }
let mut pending_events = self.pending_events.lock().unwrap();
pending_events.push(events::Event::FundingBroadcastSafe {
funding_txo: funding_txo,
if chan.get_their_node_id() != *their_node_id {
return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
}
- chan.update_fulfill_htlc(&msg)?;
- chan.channel_monitor()
+ chan.update_fulfill_htlc(&msg)?
},
None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
}
};
- self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor)?;
+ if let Err(_e) = self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor) {
+ unimplemented!();
+ }
Ok(())
}
}
fn handle_commitment_signed(&self, their_node_id: &PublicKey, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option<msgs::CommitmentSigned>), HandleError> {
- let (res, monitor) = {
+ let (revoke_and_ack, commitment_signed, chan_monitor) = {
let mut channel_state = self.channel_state.lock().unwrap();
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
}
- (chan.commitment_signed(&msg)?, chan.channel_monitor())
+ chan.commitment_signed(&msg)?
},
None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
}
};
- //TODO: Only if we store HTLC sigs
- self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor)?;
+ if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
+ unimplemented!();
+ }
- Ok(res)
+ Ok((revoke_and_ack, commitment_signed))
}
fn handle_revoke_and_ack(&self, their_node_id: &PublicKey, msg: &msgs::RevokeAndACK) -> Result<Option<msgs::CommitmentUpdate>, HandleError> {
- let ((res, mut pending_forwards, mut pending_failures), monitor) = {
+ let (res, mut pending_forwards, mut pending_failures, chan_monitor) = {
let mut channel_state = self.channel_state.lock().unwrap();
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
}
- (chan.revoke_and_ack(&msg)?, chan.channel_monitor())
+ chan.revoke_and_ack(&msg)?
},
None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
}
};
- self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor)?;
+ if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
+ unimplemented!();
+ }
for failure in pending_failures.drain(..) {
self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), &failure.0, failure.1);
}
if let Some(short_id) = chan.get_short_channel_id() {
short_to_id.remove(&short_id);
}
- //TODO: get the latest commitment tx, any HTLC txn built on top of it, etc out
- //of the channel and throw those into the announcement blackhole.
+ let txn_to_broadcast = chan.force_shutdown();
+ for tx in txn_to_broadcast {
+ self.tx_broadcaster.broadcast_transaction(&tx);
+ }
false
} else {
true
use std::default::Default;
use std::sync::{Arc, Mutex};
use std::time::Instant;
+ use std::mem;
fn build_test_onion_keys() -> Vec<OnionKeys> {
// Keys from BOLT 4, used in both test vector tests
};
node_a.node.handle_funding_signed(&node_b.node.get_our_node_id(), &funding_signed).unwrap();
+ {
+ let mut added_monitors = node_a.chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), 1);
+ assert_eq!(added_monitors[0].0, funding_output);
+ added_monitors.clear();
+ }
let events_3 = node_a.node.get_and_clear_pending_events();
assert_eq!(events_3.len(), 1);
let mut payment_event = {
let msgs = origin_node.node.send_payment(route, our_payment_hash).unwrap().unwrap();
+ {
+ let mut added_monitors = origin_node.chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), 1);
+ added_monitors.clear();
+ }
SendEvent {
node_id: expected_route[0].node.get_our_node_id(),
msgs: vec!(msgs.0),
_ => panic!("Unexpected event"),
}
} else {
+ {
+ let mut added_monitors = node.chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), 1);
+ added_monitors.clear();
+ }
for event in events_2.drain(..) {
payment_event = SendEvent::from_event(event);
}
let mut next_msgs: Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)> = None;
macro_rules! update_fulfill_dance {
- ($node: expr, $prev_node: expr) => {
+ ($node: expr, $prev_node: expr, $last_node: expr) => {
{
$node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0).unwrap();
+ {
+ let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap();
+ if $last_node {
+ assert_eq!(added_monitors.len(), 1);
+ } else {
+ assert_eq!(added_monitors.len(), 2);
+ assert!(added_monitors[0].0 != added_monitors[1].0);
+ }
+ added_monitors.clear();
+ }
let revoke_and_commit = $node.node.handle_commitment_signed(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().1).unwrap();
{
let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 2);
+ assert_eq!(added_monitors.len(), 1);
added_monitors.clear();
}
assert!($prev_node.node.handle_revoke_and_ack(&$node.node.get_our_node_id(), &revoke_and_commit.0).unwrap().is_none());
for node in expected_route.iter().rev() {
assert_eq!(expected_next_node, node.node.get_our_node_id());
if next_msgs.is_some() {
- update_fulfill_dance!(node, prev_node);
+ update_fulfill_dance!(node, prev_node, false);
}
let events = node.node.get_and_clear_pending_events();
}
assert_eq!(expected_next_node, origin_node.node.get_our_node_id());
- update_fulfill_dance!(origin_node, expected_route.first().unwrap());
+ update_fulfill_dance!(origin_node, expected_route.first().unwrap(), true);
let events = origin_node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
}
}
+ const TEST_FINAL_CLTV: u32 = 32;
+
fn route_payment(origin_node: &Node, expected_route: &[&Node], recv_value: u64) -> ([u8; 32], [u8; 32]) {
- let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &Vec::new(), recv_value, 142).unwrap();
+ let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &Vec::new(), recv_value, TEST_FINAL_CLTV).unwrap();
assert_eq!(route.hops.len(), expected_route.len());
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
assert_eq!(hop.pubkey, node.node.get_our_node_id());
}
fn route_over_limit(origin_node: &Node, expected_route: &[&Node], recv_value: u64) {
- let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &Vec::new(), recv_value, 142).unwrap();
+ let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &Vec::new(), recv_value, TEST_FINAL_CLTV).unwrap();
assert_eq!(route.hops.len(), expected_route.len());
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
assert_eq!(hop.pubkey, node.node.get_our_node_id());
fn fail_payment(origin_node: &Node, expected_route: &[&Node], our_payment_hash: [u8; 32]) {
assert!(expected_route.last().unwrap().node.fail_htlc_backwards(&our_payment_hash));
+ {
+ let mut added_monitors = expected_route.last().unwrap().chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), 1);
+ added_monitors.clear();
+ }
let mut next_msgs: Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned)> = None;
macro_rules! update_fail_dance {
- ($node: expr, $prev_node: expr) => {
+ ($node: expr, $prev_node: expr, $last_node: expr) => {
{
$node.node.handle_update_fail_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0).unwrap();
let revoke_and_commit = $node.node.handle_commitment_signed(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().1).unwrap();
+
{
let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap();
assert_eq!(added_monitors.len(), 1);
added_monitors.clear();
}
assert!($prev_node.node.handle_revoke_and_ack(&$node.node.get_our_node_id(), &revoke_and_commit.0).unwrap().is_none());
+ {
+ let mut added_monitors = $prev_node.chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), 1);
+ added_monitors.clear();
+ }
let revoke_and_ack = $prev_node.node.handle_commitment_signed(&$node.node.get_our_node_id(), &revoke_and_commit.1.unwrap()).unwrap();
- assert!(revoke_and_ack.1.is_none());
{
let mut added_monitors = $prev_node.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 2);
+ assert_eq!(added_monitors.len(), 1);
added_monitors.clear();
}
+ assert!(revoke_and_ack.1.is_none());
+ assert!($node.node.get_and_clear_pending_events().is_empty());
assert!($node.node.handle_revoke_and_ack(&$prev_node.node.get_our_node_id(), &revoke_and_ack.0).unwrap().is_none());
{
let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap();
- assert_eq!(added_monitors.len(), 1);
+ if $last_node {
+ assert_eq!(added_monitors.len(), 1);
+ } else {
+ assert_eq!(added_monitors.len(), 2);
+ assert!(added_monitors[0].0 != added_monitors[1].0);
+ }
added_monitors.clear();
}
}
for node in expected_route.iter().rev() {
assert_eq!(expected_next_node, node.node.get_our_node_id());
if next_msgs.is_some() {
- update_fail_dance!(node, prev_node);
+ update_fail_dance!(node, prev_node, false);
}
let events = node.node.get_and_clear_pending_events();
}
assert_eq!(expected_next_node, origin_node.node.get_our_node_id());
- update_fail_dance!(origin_node, expected_route.first().unwrap());
+ update_fail_dance!(origin_node, expected_route.first().unwrap(), true);
let events = origin_node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
pubkey: nodes[1].node.get_our_node_id(),
short_channel_id: chan_4.0.contents.short_channel_id,
fee_msat: 1000000,
- cltv_expiry_delta: 142,
+ cltv_expiry_delta: TEST_FINAL_CLTV,
});
hops[1].fee_msat = chan_4.1.contents.fee_base_msat as u64 + chan_4.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000;
hops[0].fee_msat = chan_3.0.contents.fee_base_msat as u64 + chan_3.0.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000;
pubkey: nodes[1].node.get_our_node_id(),
short_channel_id: chan_2.0.contents.short_channel_id,
fee_msat: 1000000,
- cltv_expiry_delta: 142,
+ cltv_expiry_delta: TEST_FINAL_CLTV,
});
hops[1].fee_msat = chan_2.1.contents.fee_base_msat as u64 + chan_2.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000;
hops[0].fee_msat = chan_3.1.contents.fee_base_msat as u64 + chan_3.1.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000;
assert_eq!(node.chan_monitor.added_monitors.lock().unwrap().len(), 0);
}
}
+
+ #[derive(PartialEq)]
+ enum HTLCType { NONE, TIMEOUT, SUCCESS }
+ fn test_txn_broadcast(node: &Node, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, Uint256, Transaction), commitment_tx: Option<Transaction>, has_htlc_tx: HTLCType) -> Vec<Transaction> {
+ let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert!(node_txn.len() >= if commitment_tx.is_some() { 0 } else { 1 } + if has_htlc_tx == HTLCType::NONE { 0 } else { 1 });
+
+ let mut res = Vec::with_capacity(2);
+
+ if let Some(explicit_tx) = commitment_tx {
+ res.push(explicit_tx.clone());
+ } else {
+ for tx in node_txn.iter() {
+ if tx.input.len() == 1 && tx.input[0].prev_hash == chan.3.txid() {
+ let mut funding_tx_map = HashMap::new();
+ funding_tx_map.insert(chan.3.txid(), chan.3.clone());
+ tx.verify(&funding_tx_map).unwrap();
+ res.push(tx.clone());
+ }
+ }
+ }
+ assert_eq!(res.len(), 1);
+
+ if has_htlc_tx != HTLCType::NONE {
+ for tx in node_txn.iter() {
+ if tx.input.len() == 1 && tx.input[0].prev_hash == res[0].txid() {
+ let mut funding_tx_map = HashMap::new();
+ funding_tx_map.insert(res[0].txid(), res[0].clone());
+ tx.verify(&funding_tx_map).unwrap();
+ if has_htlc_tx == HTLCType::TIMEOUT {
+ assert!(tx.lock_time != 0);
+ } else {
+ assert!(tx.lock_time == 0);
+ }
+ res.push(tx.clone());
+ break;
+ }
+ }
+ assert_eq!(res.len(), 2);
+ }
+ node_txn.clear();
+ res
+ }
+
+ fn check_preimage_claim(node: &Node, prev_txn: &Vec<Transaction>) -> Vec<Transaction> {
+ let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap();
+
+ assert!(node_txn.len() >= 1);
+ assert_eq!(node_txn[0].input.len(), 1);
+ let mut found_prev = false;
+
+ for tx in prev_txn {
+ if node_txn[0].input[0].prev_hash == tx.txid() {
+ let mut funding_tx_map = HashMap::new();
+ funding_tx_map.insert(tx.txid(), tx.clone());
+ node_txn[0].verify(&funding_tx_map).unwrap();
+
+ assert!(node_txn[0].input[0].witness[2].len() > 106); // must spend an htlc output
+ assert_eq!(tx.input.len(), 1); // must spend a commitment tx
+
+ found_prev = true;
+ break;
+ }
+ }
+ assert!(found_prev);
+
+ let mut res = Vec::new();
+ mem::swap(&mut *node_txn, &mut res);
+ res
+ }
+
+ #[test]
+ fn channel_monitor_network_test() {
+ // Simple test which builds a network of ChannelManagers, connects them to each other, and
+ // tests that ChannelMonitor is able to recover from various states.
+ let nodes = create_network(5);
+
+ // Create some initial channels
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
+ let chan_3 = create_announced_chan_between_nodes(&nodes, 2, 3);
+ let chan_4 = create_announced_chan_between_nodes(&nodes, 3, 4);
+
+ // Rebalance the network a bit by relaying one payment through all the channels...
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3], &nodes[4])[..], 8000000);
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3], &nodes[4])[..], 8000000);
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3], &nodes[4])[..], 8000000);
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3], &nodes[4])[..], 8000000);
+
+ // Simple case with no pending HTLCs:
+ nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), true);
+ {
+ let node_txn = test_txn_broadcast(&nodes[1], &chan_1, None, HTLCType::NONE);
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[0].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]);
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 0);
+ }
+ assert_eq!(nodes[0].node.list_channels().len(), 0);
+ assert_eq!(nodes[1].node.list_channels().len(), 1);
+
+ // One pending HTLC is discarded by the force-close:
+ let payment_preimage_1 = route_payment(&nodes[1], &vec!(&nodes[2], &nodes[3])[..], 3000000).0;
+
+ // Simple case of one pending HTLC to HTLC-Timeout
+ nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id(), true);
+ {
+ let node_txn = test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::TIMEOUT);
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[2].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]);
+ assert_eq!(nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 0);
+ }
+ assert_eq!(nodes[1].node.list_channels().len(), 0);
+ assert_eq!(nodes[2].node.list_channels().len(), 1);
+
+ macro_rules! claim_funds {
+ ($node: expr, $prev_node: expr, $preimage: expr) => {
+ {
+ assert!($node.node.claim_funds($preimage));
+ {
+ let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), 1);
+ added_monitors.clear();
+ }
+
+ let events = $node.node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ Event::SendFulfillHTLC { ref node_id, .. } => {
+ assert_eq!(*node_id, $prev_node.node.get_our_node_id());
+ },
+ _ => panic!("Unexpected event"),
+ };
+ }
+ }
+ }
+
+ // nodes[3] gets the preimage, but nodes[2] already disconnected, resulting in a nodes[2]
+ // HTLC-Timeout and a nodes[3] claim against it (+ its own announces)
+ nodes[2].node.peer_disconnected(&nodes[3].node.get_our_node_id(), true);
+ {
+ let node_txn = test_txn_broadcast(&nodes[2], &chan_3, None, HTLCType::TIMEOUT);
+
+ // Claim the payment on nodes[3], giving it knowledge of the preimage
+ claim_funds!(nodes[3], nodes[2], payment_preimage_1);
+
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[3].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]);
+
+ check_preimage_claim(&nodes[3], &node_txn);
+ }
+ assert_eq!(nodes[2].node.list_channels().len(), 0);
+ assert_eq!(nodes[3].node.list_channels().len(), 1);
+
+ // One pending HTLC to time out:
+ let payment_preimage_2 = route_payment(&nodes[3], &vec!(&nodes[4])[..], 3000000).0;
+
+ {
+ let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[3].chain_monitor.block_connected_checked(&header, 1, &Vec::new()[..], &[0; 0]);
+ for i in 2..TEST_FINAL_CLTV - 5 {
+ header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[3].chain_monitor.block_connected_checked(&header, i, &Vec::new()[..], &[0; 0]);
+ }
+
+ let node_txn = test_txn_broadcast(&nodes[3], &chan_4, None, HTLCType::TIMEOUT);
+
+ // Claim the payment on nodes[3], giving it knowledge of the preimage
+ claim_funds!(nodes[4], nodes[3], payment_preimage_2);
+
+ header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[4].chain_monitor.block_connected_checked(&header, 1, &Vec::new()[..], &[0; 0]);
+ for i in 2..TEST_FINAL_CLTV - 5 {
+ header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[4].chain_monitor.block_connected_checked(&header, i, &Vec::new()[..], &[0; 0]);
+ }
+
+ test_txn_broadcast(&nodes[4], &chan_4, None, HTLCType::SUCCESS);
+
+ header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[4].chain_monitor.block_connected_checked(&header, TEST_FINAL_CLTV - 5, &[&node_txn[0]; 1], &[4; 1]);
+
+ check_preimage_claim(&nodes[4], &node_txn);
+ }
+ assert_eq!(nodes[3].node.list_channels().len(), 0);
+ assert_eq!(nodes[4].node.list_channels().len(), 0);
+
+ // TODO: Need to reenable this when we fix local route tracking
+ // Create some new channels:
+ /*let chan_5 = create_announced_chan_between_nodes(&nodes, 0, 1);
+
+ // A pending HTLC which will be revoked:
+ let payment_preimage_3 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
+ // Get the will-be-revoked local txn from nodes[0]
+ let revoked_local_txn = nodes[0].node.channel_state.lock().unwrap().by_id.iter().next().unwrap().1.last_local_commitment_txn.clone();
+ // Revoke the old state
+ claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_3);
+
+ {
+ let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[1].chain_monitor.block_connected_checked(&header, 1, &vec![&revoked_local_txn[0]; 1], &[4; 1]);
+ {
+ let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert_eq!(node_txn.len(), 1);
+ assert_eq!(node_txn[0].input.len(), 1);
+
+ let mut funding_tx_map = HashMap::new();
+ funding_tx_map.insert(revoked_local_txn[0].txid(), revoked_local_txn[0].clone());
+ node_txn[0].verify(&funding_tx_map).unwrap();
+ node_txn.clear();
+ }
+
+ nodes[0].chain_monitor.block_connected_checked(&header, 1, &vec![&revoked_local_txn[0]; 1], &[4; 0]);
+ let node_txn = test_txn_broadcast(&nodes[0], &chan_5, Some(revoked_local_txn[0].clone()), HTLCType::TIMEOUT);
+ header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[1].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[1]; 1], &[4; 1]);
+
+ //TODO: At this point nodes[1] should claim the revoked HTLC-Timeout output, but that's
+ //not yet implemented in ChannelMonitor
+ }
+ get_announce_close_broadcast_events(&nodes, 0, 1);
+ assert_eq!(nodes[0].node.list_channels().len(), 0);
+ assert_eq!(nodes[1].node.list_channels().len(), 0);*/
+
+ // Check that we processed all pending events
+ for node in nodes {
+ assert_eq!(node.node.get_and_clear_pending_events().len(), 0);
+ assert_eq!(node.chan_monitor.added_monitors.lock().unwrap().len(), 0);
+ }
+ }
}
use std::sync::{Arc,Mutex};
use std::{hash,cmp};
+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).
+ /// Such a failure will "freeze" a channel, preventing us from revoking old states or
+ /// submitting new commitment transactions to the remote party.
+ /// ChannelManager::test_restore_channel_monitor can be used to retry the update(s) and restore
+ /// the channel to an operational state.
+ 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
+ /// of this channel). This will force-close the channel in question.
+ PermanentFailure,
+}
+
/// Simple trait indicating ability to track a set of ChannelMonitors and multiplex events between
/// them. Generally should be implemented by keeping a local SimpleManyChannelMonitor and passing
/// events to it, while also taking any add_update_monitor events and passing them to some remote
/// server(s).
+/// Note that any updates to a channel's monitor *must* be applied to each instance of the
+/// channel's monitor everywhere (including remote watchtowers) *before* this function returns. If
+/// an update occurs and a remote watchtower is left with old state, it may broadcast transactions
+/// which we have revoked, allowing our counterparty to claim all funds in the channel!
pub trait ManyChannelMonitor: Send + Sync {
/// Adds or updates a monitor for the given funding_txid+funding_output_index.
- fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: ChannelMonitor) -> Result<(), HandleError>;
+ fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>;
}
/// A simple implementation of a ManyChannelMonitor and ChainListener. Can be used to create a
}
impl ManyChannelMonitor for SimpleManyChannelMonitor<(Sha256dHash, u16)> {
- fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: ChannelMonitor) -> Result<(), HandleError> {
- self.add_update_monitor_by_key(funding_txo, monitor)
+ fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> {
+ match self.add_update_monitor_by_key(funding_txo, monitor) {
+ Ok(_) => Ok(()),
+ Err(_) => Err(ChannelMonitorUpdateErr::PermanentFailure),
+ }
}
}
-/// If an HTLC expires within this many blocks, don't try to claim it directly, instead broadcast
-/// the HTLC-Success/HTLC-Timeout transaction and claim the revocation from that.
-const CLTV_CLAIM_BUFFER: u32 = 12;
+/// If an HTLC expires within this many blocks, don't try to claim it in a shared transaction,
+/// instead claiming it in its own individual transaction.
+const CLTV_SHARED_CLAIM_BUFFER: u32 = 12;
+/// If an HTLC expires within this many blocks, force-close the channel to broadcast the
+/// HTLC-Success transaction.
+const CLTV_CLAIM_BUFFER: u32 = 6;
#[derive(Clone)]
-enum RevocationStorage {
+enum KeyStorage {
PrivMode {
revocation_base_key: SecretKey,
+ htlc_base_key: SecretKey,
},
SigsMode {
revocation_base_key: PublicKey,
+ htlc_base_key: PublicKey,
sigs: HashMap<Sha256dHash, Signature>,
}
}
#[derive(Clone)]
-struct PerCommitmentTransactionData {
- revoked_output_index: u32,
- htlcs: Vec<(HTLCOutputInCommitment, Signature)>,
+struct LocalSignedTx {
+ txid: Sha256dHash,
+ tx: Transaction,
+ revocation_key: PublicKey,
+ a_htlc_key: PublicKey,
+ b_htlc_key: PublicKey,
+ delayed_payment_key: PublicKey,
+ feerate_per_kw: u64,
+ htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>,
}
-#[derive(Clone)]
pub struct ChannelMonitor {
funding_txo: Option<(Sha256dHash, u16)>,
commitment_transaction_number_obscure_factor: u64,
- revocation_base_key: RevocationStorage,
+ key_storage: KeyStorage,
delayed_payment_base_key: PublicKey,
- htlc_base_key: PublicKey,
their_htlc_base_key: Option<PublicKey>,
- to_self_delay: u16,
+ // first is the idx of the first of the two revocation points
+ their_cur_revocation_points: Option<(u64, PublicKey, Option<PublicKey>)>,
+
+ our_to_self_delay: u16,
+ their_to_self_delay: Option<u16>,
old_secrets: [([u8; 32], u64); 49],
- claimable_outpoints: HashMap<Sha256dHash, PerCommitmentTransactionData>,
- payment_preimages: Vec<[u8; 32]>,
+ remote_claimable_outpoints: HashMap<Sha256dHash, Vec<HTLCOutputInCommitment>>,
+ remote_htlc_outputs_on_chain: Mutex<HashMap<Sha256dHash, u64>>,
+
+ // We store two local commitment transactions to avoid any race conditions where we may update
+ // some monitors (potentially on watchtowers) but then fail to update others, resulting in the
+ // various monitors for one channel being out of sync, and us broadcasting a local
+ // transaction for which we have deleted claim information on some watchtowers.
+ prev_local_signed_commitment_tx: Option<LocalSignedTx>,
+ current_local_signed_commitment_tx: Option<LocalSignedTx>,
+
+ payment_preimages: HashMap<[u8; 32], [u8; 32]>,
destination_script: Script,
secp_ctx: Secp256k1, //TODO: dedup this a bit...
}
+impl Clone for ChannelMonitor {
+ fn clone(&self) -> Self {
+ ChannelMonitor {
+ funding_txo: self.funding_txo.clone(),
+ commitment_transaction_number_obscure_factor: self.commitment_transaction_number_obscure_factor.clone(),
+
+ key_storage: self.key_storage.clone(),
+ delayed_payment_base_key: self.delayed_payment_base_key.clone(),
+ their_htlc_base_key: self.their_htlc_base_key.clone(),
+ their_cur_revocation_points: self.their_cur_revocation_points.clone(),
+
+ our_to_self_delay: self.our_to_self_delay,
+ their_to_self_delay: self.their_to_self_delay,
+
+ old_secrets: self.old_secrets.clone(),
+ remote_claimable_outpoints: self.remote_claimable_outpoints.clone(),
+ remote_htlc_outputs_on_chain: Mutex::new((*self.remote_htlc_outputs_on_chain.lock().unwrap()).clone()),
+
+ prev_local_signed_commitment_tx: self.prev_local_signed_commitment_tx.clone(),
+ current_local_signed_commitment_tx: self.current_local_signed_commitment_tx.clone(),
+
+ payment_preimages: self.payment_preimages.clone(),
+
+ destination_script: self.destination_script.clone(),
+ secp_ctx: self.secp_ctx.clone(),
+ }
+ }
+}
impl ChannelMonitor {
- pub fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &PublicKey, htlc_base_key: &PublicKey, to_self_delay: u16, destination_script: Script) -> ChannelMonitor {
+ pub fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &PublicKey, htlc_base_key: &SecretKey, our_to_self_delay: u16, destination_script: Script) -> ChannelMonitor {
ChannelMonitor {
funding_txo: None,
commitment_transaction_number_obscure_factor: 0,
- revocation_base_key: RevocationStorage::PrivMode {
+ key_storage: KeyStorage::PrivMode {
revocation_base_key: revocation_base_key.clone(),
+ htlc_base_key: htlc_base_key.clone(),
},
delayed_payment_base_key: delayed_payment_base_key.clone(),
- htlc_base_key: htlc_base_key.clone(),
their_htlc_base_key: None,
- to_self_delay: to_self_delay,
+ their_cur_revocation_points: None,
+
+ our_to_self_delay: our_to_self_delay,
+ their_to_self_delay: None,
old_secrets: [([0; 32], 1 << 48); 49],
- claimable_outpoints: HashMap::new(),
- payment_preimages: Vec::new(),
+ remote_claimable_outpoints: HashMap::new(),
+ remote_htlc_outputs_on_chain: Mutex::new(HashMap::new()),
+
+ prev_local_signed_commitment_tx: None,
+ current_local_signed_commitment_tx: None,
+
+ payment_preimages: HashMap::new(),
destination_script: destination_script,
secp_ctx: Secp256k1::new(),
res
}
- /// Inserts a revocation secret into this channel monitor. Requires the revocation_base_key of
- /// the node which we are monitoring the channel on behalf of in order to generate signatures
- /// over revocation-claim transactions.
- pub fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), HandleError> {
+ /// Inserts a revocation secret into this channel monitor. Also optionally tracks the next
+ /// revocation point which may be required to claim HTLC outputs which we know the preimage of
+ /// in case the remote end force-closes using their latest state.
+ pub fn provide_secret(&mut self, idx: u64, secret: [u8; 32], their_next_revocation_point: Option<(u64, PublicKey)>) -> Result<(), HandleError> {
let pos = ChannelMonitor::place_secret(idx);
for i in 0..pos {
let (old_secret, old_idx) = self.old_secrets[i as usize];
}
}
self.old_secrets[pos as usize] = (secret, idx);
+
+ if let Some(new_revocation_point) = their_next_revocation_point {
+ match self.their_cur_revocation_points {
+ Some(old_points) => {
+ if old_points.0 == new_revocation_point.0 + 1 {
+ self.their_cur_revocation_points = Some((old_points.0, old_points.1, Some(new_revocation_point.1)));
+ } else if old_points.0 == new_revocation_point.0 + 2 {
+ if let Some(old_second_point) = old_points.2 {
+ self.their_cur_revocation_points = Some((old_points.0 - 1, old_second_point, Some(new_revocation_point.1)));
+ } else {
+ self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None));
+ }
+ } else {
+ self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None));
+ }
+ },
+ None => {
+ self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None));
+ }
+ }
+ }
+ // TODO: Prune payment_preimages no longer needed by the revocation (just have to check
+ // that non-revoked remote commitment tx(n) do not need it, and our latest local commitment
+ // tx does not need it.
Ok(())
}
- /// Informs this watcher of the set of HTLC outputs in a commitment transaction which our
- /// counterparty may broadcast. This allows us to reconstruct the commitment transaction's
- /// outputs fully, claiming revoked, unexpired HTLC outputs as well as revoked refund outputs.
- /// TODO: Doc new params!
- /// TODO: This seems to be wrong...we should be calling this from commitment_signed, but we
- /// should be calling this about remote transactions, ie ones that they can revoke_and_ack...
- pub fn provide_tx_info(&mut self, commitment_tx: &Transaction, revokeable_out_index: u32, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature)>) {
+ /// Informs this monitor of the latest remote (ie non-broadcastable) commitment transaction.
+ /// The monitor watches for it to be broadcasted and then uses the HTLC information (and
+ /// possibly future revocation/preimage information) to claim outputs where possible.
+ pub fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<HTLCOutputInCommitment>) {
// TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction
// so that a remote monitor doesn't learn anything unless there is a malicious close.
- self.claimable_outpoints.insert(commitment_tx.txid(), PerCommitmentTransactionData{
- revoked_output_index: revokeable_out_index,
- htlcs: htlc_outputs
+ // (only maybe, sadly we cant do the same for local info, as we need to be aware of
+ // timeouts)
+ self.remote_claimable_outpoints.insert(unsigned_commitment_tx.txid(), htlc_outputs);
+ }
+
+ /// Informs this monitor of the latest local (ie broadcastable) commitment transaction. The
+ /// monitor watches for timeouts and may broadcast it if we approach such a timeout. Thus, it
+ /// is important that any clones of this channel monitor (including remote clones) by kept
+ /// up-to-date as our local commitment transaction is updated.
+ /// Panics if set_their_to_self_delay has never been called.
+ pub fn provide_latest_local_commitment_tx_info(&mut self, signed_commitment_tx: Transaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>) {
+ assert!(self.their_to_self_delay.is_some());
+ self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take();
+ self.current_local_signed_commitment_tx = Some(LocalSignedTx {
+ txid: signed_commitment_tx.txid(),
+ tx: signed_commitment_tx,
+ revocation_key: local_keys.revocation_key,
+ a_htlc_key: local_keys.a_htlc_key,
+ b_htlc_key: local_keys.b_htlc_key,
+ delayed_payment_key: local_keys.a_delayed_payment_key,
+ feerate_per_kw,
+ htlc_outputs,
});
}
- pub fn insert_combine(&mut self, other: ChannelMonitor) -> Result<(), HandleError> {
+ /// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all
+ /// commitment_tx_infos which contain the payment hash have been revoked.
+ pub fn provide_payment_preimage(&mut self, payment_hash: &[u8; 32], payment_preimage: &[u8; 32]) {
+ self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
+ }
+
+ pub fn insert_combine(&mut self, mut other: ChannelMonitor) -> Result<(), HandleError> {
match self.funding_txo {
Some(txo) => if other.funding_txo.is_some() && other.funding_txo.unwrap() != txo {
return Err(HandleError{err: "Funding transaction outputs are not identical!", msg: None});
self.funding_txo = other.funding_txo;
}
}
- let other_max_secret = other.get_min_seen_secret();
- if self.get_min_seen_secret() > other_max_secret {
- self.provide_secret(other_max_secret, other.get_secret(other_max_secret).unwrap())
- } else { Ok(()) }
+ let other_min_secret = other.get_min_seen_secret();
+ let our_min_secret = self.get_min_seen_secret();
+ if our_min_secret > other_min_secret {
+ self.provide_secret(other_min_secret, other.get_secret(other_min_secret).unwrap(), None)?;
+ }
+ if our_min_secret >= other_min_secret {
+ self.their_cur_revocation_points = other.their_cur_revocation_points;
+ for (txid, htlcs) in other.remote_claimable_outpoints.drain() {
+ self.remote_claimable_outpoints.insert(txid, htlcs);
+ }
+ if let Some(local_tx) = other.prev_local_signed_commitment_tx {
+ self.prev_local_signed_commitment_tx = Some(local_tx);
+ }
+ if let Some(local_tx) = other.current_local_signed_commitment_tx {
+ self.current_local_signed_commitment_tx = Some(local_tx);
+ }
+ self.payment_preimages = other.payment_preimages;
+ }
+ Ok(())
}
/// Panics if commitment_transaction_number_obscure_factor doesn't fit in 48 bits
self.their_htlc_base_key = Some(their_htlc_base_key.clone());
}
+ pub fn set_their_to_self_delay(&mut self, their_to_self_delay: u16) {
+ self.their_to_self_delay = Some(their_to_self_delay);
+ }
+
pub fn unset_funding_info(&mut self) {
self.funding_txo = None;
}
min
}
- pub fn provide_payment_preimage(&mut self, payment_preimage: &[u8; 32]) {
- //TODO: Some kind of timeout here or ability to mark all states containing this preimage
- //revoked?
- self.payment_preimages.push(payment_preimage.clone());
- }
-
- #[inline]
- fn check_spend_transaction(&self, tx: &Transaction, height: u32) -> Vec<Transaction> {
+ /// Attempts to claim a remote commitment transaction's outputs using the revocation key and
+ /// data in remote_claimable_outpoints. Will directly claim any HTLC outputs which expire at a
+ /// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for
+ /// HTLC-Success/HTLC-Timeout transactions, and claim them using the revocation key (if
+ /// applicable) as well.
+ fn check_spend_remote_transaction(&self, tx: &Transaction, height: u32) -> Vec<Transaction> {
// Most secp and related errors trying to create keys means we have no hope of constructing
// a spend transaction...so we return no transactions to broadcast
+ let mut txn_to_broadcast = Vec::new();
macro_rules! ignore_error {
( $thing : expr ) => {
match $thing {
Ok(a) => a,
- Err(_) => return Vec::new()
+ Err(_) => return txn_to_broadcast
}
};
}
- let mut txn_to_broadcast = Vec::new();
+ let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
+ let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid);
let commitment_number = (((tx.input[0].sequence as u64 & 0xffffff) << 3*8) | (tx.lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor;
if commitment_number >= self.get_min_seen_secret() {
let secret = self.get_secret(commitment_number).unwrap();
let per_commitment_key = ignore_error!(SecretKey::from_slice(&self.secp_ctx, &secret));
- let revocation_pubkey = match self.revocation_base_key {
- RevocationStorage::PrivMode { ref revocation_base_key } => {
- ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key))))
+ let (revocation_pubkey, b_htlc_key) = match self.key_storage {
+ KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key } => {
+ let per_commitment_point = ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key));
+ (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key)))),
+ ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key)))))
},
- RevocationStorage::SigsMode { ref revocation_base_key, .. } => {
- ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &revocation_base_key))
+ KeyStorage::SigsMode { ref revocation_base_key, ref htlc_base_key, .. } => {
+ let per_commitment_point = ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key));
+ (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &revocation_base_key)),
+ ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &htlc_base_key)))
},
};
let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &self.delayed_payment_base_key));
- let a_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &self.htlc_base_key));
- let b_htlc_key = match self.their_htlc_base_key {
- None => return Vec::new(),
+ let a_htlc_key = match self.their_htlc_base_key {
+ None => return txn_to_broadcast,
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &their_htlc_base_key)),
};
- let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.to_self_delay, &delayed_key);
-
- let commitment_txid = tx.txid();
+ let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key);
+ let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh();
let mut total_value = 0;
let mut values = Vec::new();
- let inputs = match self.claimable_outpoints.get(&commitment_txid) {
- Some(per_commitment_data) => {
- let mut inp = Vec::with_capacity(per_commitment_data.htlcs.len() + 1);
-
- if per_commitment_data.revoked_output_index as usize >= tx.output.len() || tx.output[per_commitment_data.revoked_output_index as usize].script_pubkey != revokeable_redeemscript.to_v0_p2wsh() {
- return Vec::new(); // Corrupted per_commitment_data, not much we can do
- }
+ let mut inputs = Vec::new();
+ let mut htlc_idxs = Vec::new();
- inp.push(TxIn {
+ for (idx, outp) in tx.output.iter().enumerate() {
+ if outp.script_pubkey == revokeable_p2wsh {
+ inputs.push(TxIn {
prev_hash: commitment_txid,
- prev_index: per_commitment_data.revoked_output_index,
+ prev_index: idx as u32,
script_sig: Script::new(),
- sequence: 0xffffffff,
+ sequence: 0xfffffffd,
witness: Vec::new(),
});
- values.push(tx.output[per_commitment_data.revoked_output_index as usize].value);
- total_value += tx.output[per_commitment_data.revoked_output_index as usize].value;
-
- for &(ref htlc, ref _next_tx_sig) in per_commitment_data.htlcs.iter() {
- let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
- if htlc.transaction_output_index as usize >= tx.output.len() ||
- tx.output[htlc.transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
- tx.output[htlc.transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
- return Vec::new(); // Corrupted per_commitment_data, fuck this user
- }
- if htlc.cltv_expiry > height + CLTV_CLAIM_BUFFER {
- inp.push(TxIn {
- prev_hash: commitment_txid,
- prev_index: htlc.transaction_output_index,
- script_sig: Script::new(),
- sequence: 0xffffffff,
- witness: Vec::new(),
- });
- values.push(tx.output[htlc.transaction_output_index as usize].value);
- total_value += htlc.amount_msat / 1000;
+ htlc_idxs.push(None);
+ values.push(outp.value);
+ total_value += outp.value;
+ break; // There can only be one of these
+ }
+ }
+
+ macro_rules! sign_input {
+ ($sighash_parts: expr, $input: expr, $htlc_idx: expr, $amount: expr) => {
+ {
+ let (sig, redeemscript) = match self.key_storage {
+ KeyStorage::PrivMode { ref revocation_base_key, .. } => {
+ let redeemscript = if $htlc_idx.is_none() { revokeable_redeemscript.clone() } else {
+ let htlc = &per_commitment_option.unwrap()[$htlc_idx.unwrap()];
+ chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey)
+ };
+ let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
+ let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key));
+ (ignore_error!(self.secp_ctx.sign(&sighash, &revocation_key)), redeemscript)
+ },
+ KeyStorage::SigsMode { .. } => {
+ unimplemented!();
+ }
+ };
+ $input.witness.push(sig.serialize_der(&self.secp_ctx).to_vec());
+ $input.witness[0].push(SigHashType::All as u8);
+ if $htlc_idx.is_none() {
+ $input.witness.push(vec!(1));
} else {
- //TODO: Mark as "bad"
- //then broadcast using next_tx_sig
+ $input.witness.push(revocation_pubkey.serialize().to_vec());
}
+ $input.witness.push(redeemscript.into_vec());
}
- inp
- }, None => {
- let mut inp = Vec::new(); // This is unlikely to succeed
- for (idx, outp) in tx.output.iter().enumerate() {
- if outp.script_pubkey == revokeable_redeemscript.to_v0_p2wsh() {
- inp.push(TxIn {
- prev_hash: commitment_txid,
- prev_index: idx as u32,
- script_sig: Script::new(),
- sequence: 0xffffffff,
- witness: Vec::new(),
- });
- values.push(outp.value);
- total_value += outp.value;
- break; // There can only be one of these
- }
+ }
+ }
+
+ if let Some(per_commitment_data) = per_commitment_option {
+ inputs.reserve_exact(per_commitment_data.len());
+
+ for (idx, htlc) in per_commitment_data.iter().enumerate() {
+ let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
+ if htlc.transaction_output_index as usize >= tx.output.len() ||
+ tx.output[htlc.transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
+ tx.output[htlc.transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
+ return txn_to_broadcast; // Corrupted per_commitment_data, fuck this user
+ }
+ let input = TxIn {
+ prev_hash: commitment_txid,
+ prev_index: htlc.transaction_output_index,
+ script_sig: Script::new(),
+ sequence: 0xfffffffd,
+ witness: Vec::new(),
+ };
+ if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
+ inputs.push(input);
+ htlc_idxs.push(Some(idx));
+ values.push(tx.output[htlc.transaction_output_index as usize].value);
+ total_value += htlc.amount_msat / 1000;
+ } else {
+ let mut single_htlc_tx = Transaction {
+ version: 2,
+ lock_time: 0,
+ input: vec![input],
+ output: vec!(TxOut {
+ script_pubkey: self.destination_script.clone(),
+ value: htlc.amount_msat / 1000, //TODO: - fee
+ }),
+ };
+ let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
+ sign_input!(sighash_parts, single_htlc_tx.input[0], Some(idx), htlc.amount_msat / 1000);
+ txn_to_broadcast.push(single_htlc_tx); // TODO: This is not yet tested in ChannelManager!
}
- if inp.is_empty() { return Vec::new(); } // Nothing to be done...probably a false positive
- inp
}
- };
+ }
+
+ if !inputs.is_empty() || !txn_to_broadcast.is_empty() {
+ // We're definitely a remote commitment transaction!
+ // TODO: Register commitment_txid with the ChainWatchInterface!
+ self.remote_htlc_outputs_on_chain.lock().unwrap().insert(commitment_txid, commitment_number);
+ }
+ if inputs.is_empty() { return txn_to_broadcast; } // Nothing to be done...probably a false positive/local tx
let outputs = vec!(TxOut {
script_pubkey: self.destination_script.clone(),
};
let mut values_drain = values.drain(..);
-
- // First input is the generic revokeable_redeemscript
let sighash_parts = bip143::SighashComponents::new(&spend_tx);
- {
- let sig = match self.revocation_base_key {
- RevocationStorage::PrivMode { ref revocation_base_key } => {
- let sighash = ignore_error!(Message::from_slice(&sighash_parts.sighash_all(&spend_tx.input[0], &revokeable_redeemscript, values_drain.next().unwrap())[..]));
- let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key));
- ignore_error!(self.secp_ctx.sign(&sighash, &revocation_key))
- },
- RevocationStorage::SigsMode { .. } => {
- unimplemented!();
- }
- };
- spend_tx.input[0].witness.push(sig.serialize_der(&self.secp_ctx).to_vec());
- spend_tx.input[0].witness[0].push(SigHashType::All as u8);
- spend_tx.input[0].witness.push(vec!(1)); // First if branch is revocation_key
+ for (input, htlc_idx) in spend_tx.input.iter_mut().zip(htlc_idxs.iter()) {
+ let value = values_drain.next().unwrap();
+ sign_input!(sighash_parts, input, htlc_idx, value);
}
- match self.claimable_outpoints.get(&commitment_txid) {
- None => {},
- Some(per_commitment_data) => {
- let mut htlc_idx = 0;
- for (idx, input) in spend_tx.input.iter_mut().enumerate() {
- if idx == 0 { continue; } // We already signed the first input
-
- let mut htlc;
- while {
- htlc = &per_commitment_data.htlcs[htlc_idx].0;
- htlc_idx += 1;
- htlc.cltv_expiry > height + CLTV_CLAIM_BUFFER
- } {}
-
- let sig = match self.revocation_base_key {
- RevocationStorage::PrivMode { ref revocation_base_key } => {
- let htlc_redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
- let sighash = ignore_error!(Message::from_slice(&sighash_parts.sighash_all(&input, &htlc_redeemscript, values_drain.next().unwrap())[..]));
+ txn_to_broadcast.push(spend_tx);
+ } else if let Some(per_commitment_data) = per_commitment_option {
+ if let Some(revocation_points) = self.their_cur_revocation_points {
+ let revocation_point_option =
+ if revocation_points.0 == commitment_number { Some(&revocation_points.1) }
+ else if let Some(point) = revocation_points.2.as_ref() {
+ if revocation_points.0 == commitment_number + 1 { Some(point) } else { None }
+ } else { None };
+ if let Some(revocation_point) = revocation_point_option {
+ let (revocation_pubkey, b_htlc_key) = match self.key_storage {
+ KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key } => {
+ (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key)))),
+ ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key)))))
+ },
+ KeyStorage::SigsMode { ref revocation_base_key, ref htlc_base_key, .. } => {
+ (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &revocation_base_key)),
+ ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &htlc_base_key)))
+ },
+ };
+ let a_htlc_key = match self.their_htlc_base_key {
+ None => return txn_to_broadcast,
+ Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)),
+ };
+
+ let mut total_value = 0;
+ let mut values = Vec::new();
+ let mut inputs = Vec::new();
+
+ macro_rules! sign_input {
+ ($sighash_parts: expr, $input: expr, $amount: expr, $preimage: expr) => {
+ {
+ let (sig, redeemscript) = match self.key_storage {
+ KeyStorage::PrivMode { ref htlc_base_key, .. } => {
+ let htlc = &per_commitment_option.unwrap()[$input.sequence as usize];
+ let redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
+ let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
+ let htlc_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &htlc_base_key));
+ (ignore_error!(self.secp_ctx.sign(&sighash, &htlc_key)), redeemscript)
+ },
+ KeyStorage::SigsMode { .. } => {
+ unimplemented!();
+ }
+ };
+ $input.witness.push(sig.serialize_der(&self.secp_ctx).to_vec());
+ $input.witness[0].push(SigHashType::All as u8);
+ $input.witness.push($preimage);
+ $input.witness.push(redeemscript.into_vec());
+ }
+ }
+ }
- let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key));
- ignore_error!(self.secp_ctx.sign(&sighash, &revocation_key))
- },
- RevocationStorage::SigsMode { .. } => {
- unimplemented!();
+ for (idx, htlc) in per_commitment_data.iter().enumerate() {
+ if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
+ let input = TxIn {
+ prev_hash: commitment_txid,
+ prev_index: htlc.transaction_output_index,
+ script_sig: Script::new(),
+ sequence: idx as u32, // reset to 0xfffffffd in sign_input
+ witness: Vec::new(),
+ };
+ if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
+ inputs.push(input);
+ values.push((tx.output[htlc.transaction_output_index as usize].value, payment_preimage));
+ total_value += htlc.amount_msat / 1000;
+ } else {
+ let mut single_htlc_tx = Transaction {
+ version: 2,
+ lock_time: 0,
+ input: vec![input],
+ output: vec!(TxOut {
+ script_pubkey: self.destination_script.clone(),
+ value: htlc.amount_msat / 1000, //TODO: - fee
+ }),
+ };
+ let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
+ sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.to_vec());
+ txn_to_broadcast.push(single_htlc_tx);
}
- };
+ }
+ }
- input.witness.push(revocation_pubkey.serialize().to_vec()); // First if branch is revocation_key
- input.witness.push(sig.serialize_der(&self.secp_ctx).to_vec());
- input.witness[0].push(SigHashType::All as u8);
+ if inputs.is_empty() { return txn_to_broadcast; } // Nothing to be done...probably a false positive/local tx
+
+ let outputs = vec!(TxOut {
+ script_pubkey: self.destination_script.clone(),
+ value: total_value, //TODO: - fee
+ });
+ let mut spend_tx = Transaction {
+ version: 2,
+ lock_time: 0,
+ input: inputs,
+ output: outputs,
+ };
+
+ let mut values_drain = values.drain(..);
+ let sighash_parts = bip143::SighashComponents::new(&spend_tx);
+
+ for input in spend_tx.input.iter_mut() {
+ let value = values_drain.next().unwrap();
+ sign_input!(sighash_parts, input, value.0, value.1.to_vec());
}
+
+ txn_to_broadcast.push(spend_tx);
}
}
-
- txn_to_broadcast.push(spend_tx);
+ } else {
+ //TODO: For each input check if its in our remote_htlc_outputs_on_chain map!
}
txn_to_broadcast
}
- fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface) {
- for tx in txn_matched {
- if tx.input.len() != 1 {
- // We currently only ever sign something spending a commitment or HTLC
- // transaction with 1 input, so we can skip most transactions trivially.
- continue;
+ fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx) -> Vec<Transaction> {
+ let mut res = Vec::with_capacity(local_tx.htlc_outputs.len());
+
+ for &(ref htlc, ref their_sig, ref our_sig) in local_tx.htlc_outputs.iter() {
+ if htlc.offered {
+ let mut htlc_timeout_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
+
+ htlc_timeout_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
+
+ htlc_timeout_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
+ htlc_timeout_tx.input[0].witness[1].push(SigHashType::All as u8);
+ htlc_timeout_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
+ htlc_timeout_tx.input[0].witness[2].push(SigHashType::All as u8);
+
+ htlc_timeout_tx.input[0].witness.push(Vec::new());
+ htlc_timeout_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_vec());
+
+ res.push(htlc_timeout_tx);
+ } else {
+ if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
+ let mut htlc_success_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
+
+ htlc_success_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
+
+ htlc_success_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
+ htlc_success_tx.input[0].witness[1].push(SigHashType::All as u8);
+ htlc_success_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
+ htlc_success_tx.input[0].witness[2].push(SigHashType::All as u8);
+
+ htlc_success_tx.input[0].witness.push(payment_preimage.to_vec());
+ htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_vec());
+
+ res.push(htlc_success_tx);
+ }
}
+ }
+
+ res
+ }
+
+ /// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet)
+ /// revoked using data in local_claimable_outpoints.
+ /// Should not be used if check_spend_revoked_transaction succeeds.
+ fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> Vec<Transaction> {
+ let commitment_txid = tx.txid();
+ if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
+ if local_tx.txid == commitment_txid {
+ return self.broadcast_by_local_state(local_tx);
+ }
+ }
+ if let &Some(ref local_tx) = &self.prev_local_signed_commitment_tx {
+ if local_tx.txid == commitment_txid {
+ return self.broadcast_by_local_state(local_tx);
+ }
+ }
+ Vec::new()
+ }
+ fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface) {
+ for tx in txn_matched {
for txin in tx.input.iter() {
if self.funding_txo.is_none() || (txin.prev_hash == self.funding_txo.unwrap().0 && txin.prev_index == self.funding_txo.unwrap().1 as u32) {
- for tx in self.check_spend_transaction(tx, height).iter() {
+ let mut txn = self.check_spend_remote_transaction(tx, height);
+ if txn.is_empty() {
+ txn = self.check_spend_local_transaction(tx, height);
+ }
+ for tx in txn.iter() {
broadcaster.broadcast_transaction(tx);
}
}
}
}
+ if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
+ let mut needs_broadcast = false;
+ for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() {
+ if htlc.cltv_expiry <= height + CLTV_CLAIM_BUFFER {
+ if htlc.offered || self.payment_preimages.contains_key(&htlc.payment_hash) {
+ needs_broadcast = true;
+ }
+ }
+ }
+
+ if needs_broadcast {
+ broadcaster.broadcast_transaction(&cur_local_tx.tx);
+ for tx in self.broadcast_by_local_state(&cur_local_tx) {
+ broadcaster.broadcast_transaction(&tx);
+ }
+ }
+ }
+ }
+
+ pub fn would_broadcast_at_height(&self, height: u32) -> bool {
+ if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
+ for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() {
+ if htlc.cltv_expiry <= height + CLTV_CLAIM_BUFFER {
+ if htlc.offered || self.payment_preimages.contains_key(&htlc.payment_hash) {
+ return true;
+ }
+ }
+ }
+ }
+ false
}
}
{
// insert_secret correct sequence
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
- monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
- monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
- monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
- monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
- monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
- monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
}
{
// insert_secret #1 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
- assert_eq!(monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #2 incorrect (#1 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap());
- monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
- monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #3 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
- monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap());
- monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #4 incorrect (1,2,3 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap());
- monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap());
- monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("ba65d7b0ef55a3ba300d4e87af29868f394f8f138d78a7011669c79b37b936f4").unwrap());
- monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
- monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
- monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
- monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
- assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #5 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
- monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
- monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap());
- monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
- assert_eq!(monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #6 incorrect (5 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
- monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
- monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap());
- monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("b7e76a83668bde38b373970155c868a653304308f9896692f904a23731224bb1").unwrap());
- monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
- monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
- assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #7 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
- monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
- monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
- monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
- monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("e7971de736e01da8ed58b94c2fc216cb1dca9e326f3a96e7194fe8ea8af6c0a3").unwrap());
- monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
- assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #8 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
- monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
- monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
- monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
- monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
- monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
- monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a7efbc61aac46d34f77778bac22c8a20c6a46ca460addc49009bda875ec88fa4").unwrap());
- assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
}
+
+ // Further testing is done in the ChannelManager integration tests.
}
use chain::chaininterface;
use chain::chaininterface::ConfirmationTarget;
use ln::channelmonitor;
-use ln::msgs::HandleError;
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::util::hash::Sha256dHash;
}
}
impl channelmonitor::ManyChannelMonitor for TestChannelMonitor {
- fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: channelmonitor::ChannelMonitor) -> Result<(), HandleError> {
+ fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> {
self.added_monitors.lock().unwrap().push((funding_txo, monitor.clone()));
self.simple_monitor.add_update_monitor(funding_txo, monitor)
}