}
enum InboundHTLCState {
- /// Added by remote, to be included in next local commitment tx.
+ /// Offered by remote, to be included in next local commitment tx. I.e., the remote sent an
+ /// update_add_htlc message for this HTLC.
RemoteAnnounced(PendingHTLCStatus),
- /// Included in a received commitment_signed message (implying we've revoke_and_ack'ed it), but
- /// the remote side hasn't yet revoked their previous state, which we need them to do before we
- /// accept this HTLC. Implies AwaitingRemoteRevoke.
- /// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
- /// a remote revoke_and_ack on a previous state before we can do so.
+ /// Included in a received commitment_signed message (implying we've
+ /// revoke_and_ack'd it), but the remote hasn't yet revoked their previous
+ /// state (see the example below). We have not yet included this HTLC in a
+ /// commitment_signed message because we are waiting on the remote's
+ /// aforementioned state revocation. One reason this missing remote RAA
+ /// (revoke_and_ack) blocks us from constructing a commitment_signed message
+ /// is because every time we create a new "state", i.e. every time we sign a
+ /// new commitment tx (see [BOLT #2]), we need a new per_commitment_point,
+ /// which are provided one-at-a-time in each RAA. E.g., the last RAA they
+ /// sent provided the per_commitment_point for our current commitment tx.
+ /// The other reason we should not send a commitment_signed without their RAA
+ /// is because their RAA serves to ACK our previous commitment_signed.
+ ///
+ /// Here's an example of how an HTLC could come to be in this state:
+ /// remote --> update_add_htlc(prev_htlc) --> local
+ /// remote --> commitment_signed(prev_htlc) --> local
+ /// remote <-- revoke_and_ack <-- local
+ /// remote <-- commitment_signed(prev_htlc) <-- local
+ /// [note that here, the remote does not respond with a RAA]
+ /// remote --> update_add_htlc(this_htlc) --> local
+ /// remote --> commitment_signed(prev_htlc, this_htlc) --> local
+ /// Now `this_htlc` will be assigned this state. It's unable to be officially
+ /// accepted, i.e. included in a commitment_signed, because we're missing the
+ /// RAA that provides our next per_commitment_point. The per_commitment_point
+ /// is used to derive commitment keys, which are used to construct the
+ /// signatures in a commitment_signed message.
+ /// Implies AwaitingRemoteRevoke.
+ /// [BOLT #2]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md
AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus),
- /// Included in a received commitment_signed message (implying we've revoke_and_ack'ed it), but
- /// the remote side hasn't yet revoked their previous state, which we need them to do before we
- /// accept this HTLC. Implies AwaitingRemoteRevoke.
- /// We have included this HTLC in our latest commitment_signed and are now just waiting on a
- /// revoke_and_ack.
+ /// Included in a received commitment_signed message (implying we've revoke_and_ack'd it).
+ /// We have also included this HTLC in our latest commitment_signed and are now just waiting
+ /// on the remote's revoke_and_ack to make this HTLC an irrevocable part of the state of the
+ /// channel (before it can then get forwarded and/or removed).
+ /// Implies AwaitingRemoteRevoke.
AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus),
Committed,
/// Removed by us and a new commitment_signed was sent (if we were AwaitingRemoteRevoke when we
// revoke_and_ack is received and new commitment_signed is generated to be
// sent to the funder. Otherwise, the pending value is removed when receiving
// commitment_signed.
- pending_update_fee: Option<u64>,
+ pending_update_fee: Option<u32>,
// update_fee() during ChannelState::AwaitingRemoteRevoke is hold in
// holdina_cell_update_fee then moved to pending_udpate_fee when revoke_and_ack
// is received. holding_cell_update_fee is updated when there are additional
// update_fee() during ChannelState::AwaitingRemoteRevoke.
- holding_cell_update_fee: Option<u64>,
+ holding_cell_update_fee: Option<u32>,
next_local_htlc_id: u64,
next_remote_htlc_id: u64,
update_time_counter: u32,
- feerate_per_kw: u64,
+ feerate_per_kw: u32,
#[cfg(debug_assertions)]
/// Max to_local and to_remote outputs in a locally-generated commitment transaction
/// Max to_local and to_remote outputs in a remote-generated commitment transaction
max_commitment_tx_output_remote: ::std::sync::Mutex<(u64, u64)>,
- last_sent_closing_fee: Option<(u64, u64, Signature)>, // (feerate, fee, our_sig)
+ last_sent_closing_fee: Option<(u32, u64, Signature)>, // (feerate, fee, our_sig)
funding_txo: Option<OutPoint>,
cmp::min(channel_value_satoshis, cmp::max(q, 1000)) //TODO
}
- fn derive_our_dust_limit_satoshis(at_open_background_feerate: u64) -> u64 {
- cmp::max(at_open_background_feerate * B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT / 1000, 546) //TODO
+ fn derive_our_dust_limit_satoshis(at_open_background_feerate: u32) -> u64 {
+ cmp::max(at_open_background_feerate as u64 * B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT / 1000, 546) //TODO
}
// Constructors:
fn check_remote_fee<F: Deref>(fee_estimator: &F, feerate_per_kw: u32) -> Result<(), ChannelError>
where F::Target: FeeEstimator
{
- if (feerate_per_kw as u64) < fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) {
+ if feerate_per_kw < fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) {
return Err(ChannelError::Close("Peer's feerate much too low"));
}
- if (feerate_per_kw as u64) > fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) * 2 {
+ if feerate_per_kw as u64 > fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 * 2 {
return Err(ChannelError::Close("Peer's feerate much too high"));
}
Ok(())
// check if the funder's amount for the initial commitment tx is sufficient
// for full fee payment
let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat;
- if funders_amount_msat < background_feerate * COMMITMENT_TX_BASE_WEIGHT {
+ if funders_amount_msat < background_feerate as u64 * COMMITMENT_TX_BASE_WEIGHT {
return Err(ChannelError::Close("Insufficient funding amount for initial commitment"));
}
let to_local_msat = msg.push_msat;
- let to_remote_msat = funders_amount_msat - background_feerate * COMMITMENT_TX_BASE_WEIGHT;
+ let to_remote_msat = funders_amount_msat - background_feerate as u64 * COMMITMENT_TX_BASE_WEIGHT;
if to_local_msat <= msg.channel_reserve_satoshis * 1000 && to_remote_msat <= remote_channel_reserve_satoshis * 1000 {
return Err(ChannelError::Close("Insufficient funding amount for initial commitment"));
}
last_block_connected: Default::default(),
funding_tx_confirmations: 0,
- feerate_per_kw: msg.feerate_per_kw as u64,
+ feerate_per_kw: msg.feerate_per_kw,
channel_value_satoshis: msg.funding_satoshis,
their_dust_limit_satoshis: msg.dust_limit_satoshis,
our_dust_limit_satoshis: our_dust_limit_satoshis,
/// Note that below-dust HTLCs are included in the third return value, but not the second, and
/// sources are provided only for outbound HTLCs in the third return value.
#[inline]
- fn build_commitment_transaction<L: Deref>(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64, logger: &L) -> (Transaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) where L::Target: Logger {
+ fn build_commitment_transaction<L: Deref>(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u32, logger: &L) -> (Transaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) where L::Target: Logger {
let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
let txins = {
($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => {
if $outbound == local { // "offered HTLC output"
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
- if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
+ if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
txouts.push((TxOut {
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
}
} else {
let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
- if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) {
+ if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) {
log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
txouts.push((TxOut { // "received HTLC output"
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
max_commitment_tx_output.1 = cmp::max(max_commitment_tx_output.1, value_to_remote_msat as u64);
}
- let total_fee: u64 = feerate_per_kw * (COMMITMENT_TX_BASE_WEIGHT + (txouts.len() as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
+ let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (txouts.len() as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
let (value_to_self, value_to_remote) = if self.channel_outbound {
(value_to_self_msat / 1000 - total_fee as i64, value_to_remote_msat / 1000)
} else {
/// Builds the htlc-success or htlc-timeout transaction which spends a given HTLC output
/// @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: &Txid, htlc: &HTLCOutputInCommitment, local: bool, keys: &TxCreationKeys, feerate_per_kw: u64) -> Transaction {
+ fn build_htlc_transaction(&self, prev_hash: &Txid, htlc: &HTLCOutputInCommitment, local: bool, keys: &TxCreationKeys, feerate_per_kw: u32) -> Transaction {
chan_utils::build_htlc_transaction(prev_hash, feerate_per_kw, if local { self.their_to_self_delay } else { self.our_to_self_delay }, htlc, &keys.a_delayed_payment_key, &keys.revocation_key)
}
fn commit_tx_fee_msat(&self, num_htlcs: usize) -> u64 {
// Note that we need to divide before multiplying to round properly,
// since the lowest denomination of bitcoin on-chain is the satoshi.
- (COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * self.feerate_per_kw / 1000 * 1000
+ (COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * self.feerate_per_kw as u64 / 1000 * 1000
}
// Get the commitment tx fee for the local (i.e our) next commitment transaction
//If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
if update_fee {
let num_htlcs = local_commitment_tx.1;
- let total_fee: u64 = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
+ let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
let remote_reserve_we_require = Channel::<ChanSigner>::get_remote_channel_reserve_satoshis(self.channel_value_satoshis);
if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + remote_reserve_we_require {
/// Adds a pending update to this channel. See the doc for send_htlc for
/// further details on the optionness of the return value.
/// You MUST call send_commitment prior to any other calls on this Channel
- fn send_update_fee(&mut self, feerate_per_kw: u64) -> Option<msgs::UpdateFee> {
+ fn send_update_fee(&mut self, feerate_per_kw: u32) -> Option<msgs::UpdateFee> {
if !self.channel_outbound {
panic!("Cannot send fee from inbound channel");
}
Some(msgs::UpdateFee {
channel_id: self.channel_id,
- feerate_per_kw: feerate_per_kw as u32,
+ feerate_per_kw: feerate_per_kw,
})
}
- pub fn send_update_fee_and_commit<L: Deref>(&mut self, feerate_per_kw: u64, logger: &L) -> Result<Option<(msgs::UpdateFee, msgs::CommitmentSigned, ChannelMonitorUpdate)>, ChannelError> where L::Target: Logger {
+ pub fn send_update_fee_and_commit<L: Deref>(&mut self, feerate_per_kw: u32, logger: &L) -> Result<Option<(msgs::UpdateFee, msgs::CommitmentSigned, ChannelMonitorUpdate)>, ChannelError> where L::Target: Logger {
match self.send_update_fee(feerate_per_kw) {
Some(update_fee) => {
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish"));
}
Channel::<ChanSigner>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
- self.pending_update_fee = Some(msg.feerate_per_kw as u64);
+ self.pending_update_fee = Some(msg.feerate_per_kw);
self.update_time_counter += 1;
Ok(())
}
proposed_feerate = self.feerate_per_kw;
}
let tx_weight = Self::get_closing_transaction_weight(&self.get_closing_scriptpubkey(), self.their_shutdown_scriptpubkey.as_ref().unwrap());
- let proposed_total_fee_satoshis = proposed_feerate * tx_weight / 1000;
+ let proposed_total_fee_satoshis = proposed_feerate as u64 * tx_weight / 1000;
let (closing_tx, total_fee_satoshis) = self.build_closing_transaction(proposed_total_fee_satoshis, false);
let our_sig = self.local_keys
macro_rules! propose_new_feerate {
($new_feerate: expr) => {
let closing_tx_max_weight = Self::get_closing_transaction_weight(&self.get_closing_scriptpubkey(), self.their_shutdown_scriptpubkey.as_ref().unwrap());
- let (closing_tx, used_total_fee) = self.build_closing_transaction($new_feerate * closing_tx_max_weight / 1000, false);
+ let (closing_tx, used_total_fee) = self.build_closing_transaction($new_feerate as u64 * closing_tx_max_weight / 1000, false);
let our_sig = self.local_keys
.sign_closing_transaction(&closing_tx, &self.secp_ctx)
.map_err(|_| ChannelError::Close("External signer refused to sign closing transaction"))?;
}
}
- let proposed_sat_per_kw = msg.fee_satoshis * 1000 / closing_tx.get_weight() as u64;
+ let proposed_sat_per_kw = msg.fee_satoshis * 1000 / closing_tx.get_weight() as u64;
if self.channel_outbound {
let our_max_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
- if proposed_sat_per_kw > our_max_feerate {
+ if (proposed_sat_per_kw as u32) > our_max_feerate {
if let Some((last_feerate, _, _)) = self.last_sent_closing_fee {
if our_max_feerate <= last_feerate {
return Err(ChannelError::Close("Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate"));
}
} else {
let our_min_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
- if proposed_sat_per_kw < our_min_feerate {
+ if (proposed_sat_per_kw as u32) < our_min_feerate {
if let Some((last_feerate, _, _)) = self.last_sent_closing_fee {
if our_min_feerate >= last_feerate {
return Err(ChannelError::Close("Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate"));
}
#[cfg(test)]
- pub fn get_feerate(&self) -> u64 {
+ pub fn get_feerate(&self) -> u32 {
self.feerate_per_kw
}
// output value back into a transaction with the regular channel output:
// the fee cost of the HTLC-Success/HTLC-Timeout transaction:
- let mut res = self.feerate_per_kw * cmp::max(HTLC_TIMEOUT_TX_WEIGHT, HTLC_SUCCESS_TX_WEIGHT) / 1000;
+ let mut res = self.feerate_per_kw as u64 * cmp::max(HTLC_TIMEOUT_TX_WEIGHT, HTLC_SUCCESS_TX_WEIGHT) / 1000;
if self.channel_outbound {
// + the marginal fee increase cost to us in the commitment transaction:
- res += self.feerate_per_kw * COMMITMENT_TX_WEIGHT_PER_HTLC / 1000;
+ res += self.feerate_per_kw as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC / 1000;
}
// + the marginal cost of an input which spends the HTLC-Success/HTLC-Timeout output:
- res += fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal) * SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT / 1000;
+ res += fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal) as u64 * SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT / 1000;
res as u32
}
///
/// May return some HTLCs (and their payment_hash) which have timed out and should be failed
/// back.
- pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
+ pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[usize]) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
let mut timed_out_htlcs = Vec::new();
self.holding_cell_htlc_updates.retain(|htlc_update| {
match htlc_update {
}
}
}
+ if height > 0xff_ff_ff || (*index_in_block) > 0xff_ff_ff {
+ panic!("Block was bogus - either height 16 million or had > 16 million transactions");
+ }
+ assert!(txo_idx <= 0xffff); // txo_idx is a (u16 as usize), so this is just listed here for completeness
self.funding_tx_confirmations = 1;
self.short_channel_id = Some(((height as u64) << (5*8)) |
((*index_in_block as u64) << (2*8)) |
// Methods to get unprompted messages to send to the remote end (or where we already returned
// something in the handler for the message that prompted this message):
- pub fn get_open_channel<F: Deref>(&self, chain_hash: BlockHash, fee_estimator: &F) -> msgs::OpenChannel
- where F::Target: FeeEstimator
- {
+ pub fn get_open_channel(&self, chain_hash: BlockHash) -> msgs::OpenChannel {
if !self.channel_outbound {
panic!("Tried to open a channel for an inbound channel?");
}
max_htlc_value_in_flight_msat: Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
channel_reserve_satoshis: Channel::<ChanSigner>::get_remote_channel_reserve_satoshis(self.channel_value_satoshis),
htlc_minimum_msat: self.our_htlc_minimum_msat,
- feerate_per_kw: fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) as u32,
+ feerate_per_kw: self.feerate_per_kw as u32,
to_self_delay: self.our_to_self_delay,
max_accepted_htlcs: OUR_MAX_HTLCS,
funding_pubkey: local_keys.funding_pubkey,
use bitcoin::hashes::Hash;
use bitcoin::hash_types::{Txid, WPubkeyHash};
use std::sync::Arc;
- use rand::{thread_rng,Rng};
struct TestFeeEstimator {
- fee_est: u64
+ fee_est: u32
}
impl FeeEstimator for TestFeeEstimator {
- fn get_est_sat_per_1000_weight(&self, _: ConfirmationTarget) -> u64 {
+ fn get_est_sat_per_1000_weight(&self, _: ConfirmationTarget) -> u32 {
self.fee_est
}
}
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(hex).unwrap()[..]).unwrap())
}
+ // Check that, during channel creation, we use the same feerate in the open channel message
+ // as we do in the Channel object creation itself.
+ #[test]
+ fn test_open_channel_msg_fee() {
+ let original_fee = 253;
+ let mut fee_est = TestFeeEstimator{fee_est: original_fee };
+ let secp_ctx = Secp256k1::new();
+ let seed = [42; 32];
+ let network = Network::Testnet;
+ let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
+
+ let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
+ let config = UserConfig::default();
+ let node_a_chan = Channel::<EnforcingChannelKeys>::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, 10000000, 100000, 42, &config).unwrap();
+
+ // Now change the fee so we can check that the fee in the open_channel message is the
+ // same as the old fee.
+ fee_est.fee_est = 500;
+ let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.bitcoin_hash());
+ assert_eq!(open_channel_msg.feerate_per_kw, original_fee);
+ }
+
#[test]
fn channel_reestablish_no_updates() {
let feeest = TestFeeEstimator{fee_est: 15000};
let logger = test_utils::TestLogger::new();
let secp_ctx = Secp256k1::new();
- let mut seed = [0; 32];
- let mut rng = thread_rng();
- rng.fill_bytes(&mut seed);
+ let seed = [42; 32];
let network = Network::Testnet;
let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
let mut node_a_chan = Channel::<EnforcingChannelKeys>::new_outbound(&&feeest, &&keys_provider, node_a_node_id, 10000000, 100000, 42, &config).unwrap();
// Create Node B's channel by receiving Node A's open_channel message
- let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.bitcoin_hash(), &&feeest);
+ let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.bitcoin_hash());
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
let mut node_b_chan = Channel::<EnforcingChannelKeys>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, InitFeatures::known(), &open_channel_msg, 7, &config).unwrap();