mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-03-04 10:58:11 +01:00
Rewrite channelmonitor framework and implement a bunch of it
This commit is contained in:
parent
7400b3bb7c
commit
2d8afeccdb
6 changed files with 1169 additions and 459 deletions
|
@ -15,7 +15,7 @@ use crypto::sha2::Sha256;
|
|||
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;
|
||||
|
@ -93,7 +93,7 @@ impl FeeEstimator for FuzzEstimator {
|
|||
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
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;
|
||||
|
@ -11,6 +12,9 @@ use crypto::ripemd160::Ripemd160;
|
|||
|
||||
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.
|
||||
|
||||
|
@ -233,3 +237,33 @@ pub fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, a
|
|||
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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ use ln::msgs;
|
|||
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};
|
||||
|
@ -254,6 +254,12 @@ pub struct Channel {
|
|||
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
|
||||
|
@ -307,8 +313,6 @@ const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO?
|
|||
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?)
|
||||
|
||||
|
@ -362,7 +366,7 @@ impl Channel {
|
|||
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 {
|
||||
|
@ -385,6 +389,8 @@ impl 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(),
|
||||
|
@ -477,9 +483,10 @@ impl Channel {
|
|||
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,
|
||||
|
@ -500,6 +507,8 @@ impl 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(),
|
||||
|
@ -855,40 +864,25 @@ impl Channel {
|
|||
/// @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(),
|
||||
});
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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)
|
||||
});
|
||||
|
||||
Transaction {
|
||||
version: 2,
|
||||
lock_time: if htlc.offered { htlc.cltv_expiry } else { 0 },
|
||||
input: txins,
|
||||
output: txouts,
|
||||
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)
|
||||
}
|
||||
|
||||
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 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 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!");
|
||||
}
|
||||
|
@ -896,13 +890,7 @@ impl Channel {
|
|||
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
|
||||
|
||||
|
@ -924,10 +912,10 @@ impl Channel {
|
|||
|
||||
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,
|
||||
|
@ -989,19 +977,21 @@ impl Channel {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
@ -1067,10 +1057,12 @@ impl Channel {
|
|||
}))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -1122,6 +1114,7 @@ impl Channel {
|
|||
|
||||
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;
|
||||
|
||||
|
@ -1146,7 +1139,7 @@ impl Channel {
|
|||
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});
|
||||
}
|
||||
|
@ -1160,7 +1153,7 @@ impl Channel {
|
|||
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);
|
||||
|
@ -1169,24 +1162,22 @@ impl Channel {
|
|||
|
||||
// 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});
|
||||
}
|
||||
|
@ -1200,16 +1191,19 @@ impl Channel {
|
|||
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> {
|
||||
|
@ -1342,7 +1336,7 @@ impl Channel {
|
|||
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});
|
||||
}
|
||||
|
@ -1352,9 +1346,9 @@ impl Channel {
|
|||
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> {
|
||||
|
@ -1374,7 +1368,7 @@ impl Channel {
|
|||
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});
|
||||
}
|
||||
|
@ -1382,7 +1376,7 @@ impl Channel {
|
|||
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");
|
||||
|
@ -1391,17 +1385,31 @@ impl Channel {
|
|||
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() {
|
||||
|
@ -1425,24 +1433,26 @@ impl Channel {
|
|||
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);
|
||||
|
@ -1470,7 +1480,7 @@ impl Channel {
|
|||
},
|
||||
&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);
|
||||
}
|
||||
|
@ -1494,12 +1504,13 @@ impl Channel {
|
|||
//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)
|
||||
}
|
||||
|
@ -1513,7 +1524,7 @@ impl Channel {
|
|||
/// 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});
|
||||
}
|
||||
|
@ -1522,7 +1533,7 @@ impl Channel {
|
|||
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
|
||||
|
@ -1572,18 +1583,19 @@ impl Channel {
|
|||
|
||||
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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1789,6 +1801,13 @@ impl Channel {
|
|||
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> {
|
||||
|
@ -1837,13 +1856,6 @@ impl Channel {
|
|||
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;
|
||||
|
@ -2006,7 +2018,7 @@ impl Channel {
|
|||
})
|
||||
}
|
||||
|
||||
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()?;
|
||||
|
@ -2014,7 +2026,7 @@ impl Channel {
|
|||
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
|
||||
|
@ -2023,7 +2035,7 @@ impl Channel {
|
|||
/// 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!");
|
||||
}
|
||||
|
@ -2036,8 +2048,8 @@ impl 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);
|
||||
|
@ -2047,18 +2059,18 @@ impl Channel {
|
|||
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
|
||||
|
@ -2170,7 +2182,7 @@ impl Channel {
|
|||
}
|
||||
|
||||
/// 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});
|
||||
}
|
||||
|
@ -2190,7 +2202,7 @@ impl Channel {
|
|||
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
|
||||
|
@ -2221,23 +2233,26 @@ impl Channel {
|
|||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
@ -2283,6 +2298,16 @@ impl Channel {
|
|||
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)]
|
||||
|
|
|
@ -608,6 +608,7 @@ impl ChannelManager {
|
|||
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 (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}),
|
||||
|
@ -630,19 +631,28 @@ impl ChannelManager {
|
|||
panic!("payment_hash was repeated! Don't let this happen");
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
match res {
|
||||
Some(msgs) => msgs,
|
||||
None => return Ok(None),
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
|
||||
unimplemented!(); // maybe remove from claimable_htlcs?
|
||||
}
|
||||
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
|
||||
|
@ -653,15 +663,9 @@ impl ChannelManager {
|
|||
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 {
|
||||
|
@ -741,25 +745,25 @@ impl ChannelManager {
|
|||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -774,10 +778,19 @@ impl ChannelManager {
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -844,13 +857,18 @@ impl ChannelManager {
|
|||
};
|
||||
|
||||
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 => {},
|
||||
|
@ -910,7 +928,7 @@ impl ChannelManager {
|
|||
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
|
||||
|
@ -918,7 +936,7 @@ impl ChannelManager {
|
|||
|
||||
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;
|
||||
|
@ -928,25 +946,21 @@ impl ChannelManager {
|
|||
|
||||
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
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -955,6 +969,13 @@ impl ChannelManager {
|
|||
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 {
|
||||
|
@ -972,14 +993,14 @@ impl ChainListener 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 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)
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
new_funding_locked_messages.push(events::Event::SendFundingLocked {
|
||||
|
@ -988,10 +1009,31 @@ impl ChainListener for ChannelManager {
|
|||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
@ -1078,7 +1120,7 @@ impl ChannelMessageHandler for ChannelManager {
|
|||
//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) => {
|
||||
|
@ -1086,8 +1128,8 @@ impl ChannelMessageHandler for ChannelManager {
|
|||
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);
|
||||
|
@ -1100,27 +1142,31 @@ impl ChannelMessageHandler for ChannelManager {
|
|||
// 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,
|
||||
|
@ -1446,13 +1492,14 @@ impl ChannelMessageHandler for ChannelManager {
|
|||
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(())
|
||||
}
|
||||
|
||||
|
@ -1545,38 +1592,41 @@ impl ChannelMessageHandler for ChannelManager {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1673,8 +1723,10 @@ impl ChannelMessageHandler for ChannelManager {
|
|||
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
|
||||
|
@ -1723,6 +1775,7 @@ mod tests {
|
|||
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
|
||||
|
@ -1940,6 +1993,12 @@ mod 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);
|
||||
|
@ -2084,6 +2143,11 @@ mod tests {
|
|||
|
||||
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),
|
||||
|
@ -2143,6 +2207,11 @@ mod tests {
|
|||
_ => 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);
|
||||
}
|
||||
|
@ -2165,13 +2234,23 @@ mod tests {
|
|||
|
||||
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());
|
||||
|
@ -2197,7 +2276,7 @@ mod tests {
|
|||
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();
|
||||
|
@ -2214,7 +2293,7 @@ mod tests {
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -2226,8 +2305,10 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
@ -2237,7 +2318,7 @@ mod tests {
|
|||
}
|
||||
|
||||
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());
|
||||
|
@ -2264,30 +2345,47 @@ mod tests {
|
|||
|
||||
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 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();
|
||||
}
|
||||
let revoke_and_ack = $prev_node.node.handle_commitment_signed(&$node.node.get_our_node_id(), &revoke_and_commit.1.unwrap()).unwrap();
|
||||
{
|
||||
let mut added_monitors = $prev_node.chan_monitor.added_monitors.lock().unwrap();
|
||||
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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -2299,7 +2397,7 @@ mod tests {
|
|||
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();
|
||||
|
@ -2316,7 +2414,7 @@ mod tests {
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -2406,7 +2504,7 @@ mod tests {
|
|||
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;
|
||||
|
@ -2429,7 +2527,7 @@ mod tests {
|
|||
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;
|
||||
|
@ -2468,4 +2566,233 @@ mod tests {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,6 @@
|
|||
use chain::chaininterface;
|
||||
use chain::chaininterface::ConfirmationTarget;
|
||||
use ln::channelmonitor;
|
||||
use ln::msgs::HandleError;
|
||||
|
||||
use bitcoin::blockdata::transaction::Transaction;
|
||||
use bitcoin::util::hash::Sha256dHash;
|
||||
|
@ -30,7 +29,7 @@ impl TestChannelMonitor {
|
|||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue