Merge pull request #231 from philipr-za/philip-204-check-commitment-transaction-fee

Check funder can afford commitment transaction fee when receiving update_fee
This commit is contained in:
Matt Corallo 2018-11-20 16:29:21 -05:00 committed by GitHub
commit 86944d34a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 91 additions and 61 deletions

View file

@ -355,8 +355,9 @@ const UNCONF_THRESHOLD: u32 = 6;
const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO? const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO?
/// The amount of time we're willing to wait to claim money back to us /// The amount of time we're willing to wait to claim money back to us
const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 14; const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 14;
const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; /// Exposing these two constants for use in test in ChannelMonitor
const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; pub const COMMITMENT_TX_BASE_WEIGHT: u64 = 724;
pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172;
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 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?) 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?)
/// Maximmum `funding_satoshis` value, according to the BOLT #2 specification /// Maximmum `funding_satoshis` value, according to the BOLT #2 specification
@ -1663,7 +1664,9 @@ impl Channel {
let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?; let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?;
let mut update_fee = false;
let feerate_per_kw = if !self.channel_outbound && self.pending_update_fee.is_some() { let feerate_per_kw = if !self.channel_outbound && self.pending_update_fee.is_some() {
update_fee = true;
self.pending_update_fee.unwrap() self.pending_update_fee.unwrap()
} else { } else {
self.feerate_per_kw self.feerate_per_kw
@ -1674,6 +1677,16 @@ impl Channel {
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(); 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.unwrap()), "Invalid commitment tx signature from peer", self.channel_id()); secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid commitment tx signature from peer", self.channel_id());
//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.len();
let total_fee: u64 = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + self.their_channel_reserve_satoshis {
return Err(HandleError { err: "Funding remote cannot afford proposed new fee", action: Some(ErrorAction::DisconnectPeer { msg: None }) });
}
}
if msg.htlc_signatures.len() != local_commitment_tx.1.len() { if msg.htlc_signatures.len() != local_commitment_tx.1.len() {
return Err(HandleError{err: "Got wrong number of HTLC signatures from remote", action: None}); return Err(HandleError{err: "Got wrong number of HTLC signatures from remote", action: None});
} }
@ -1687,7 +1700,7 @@ impl Channel {
let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys, feerate_per_kw); let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys, feerate_per_kw);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &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(); 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", self.channel_id()); secp_call!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer", self.channel_id());
let htlc_sig = if htlc.offered { let htlc_sig = if htlc.offered {
let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, htlc, &local_keys)?; 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); new_local_commitment_txn.push(htlc_tx);
@ -1715,6 +1728,7 @@ impl Channel {
} }
} }
} }
if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 { if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 {
// This is a response to our post-monitor-failed unfreeze messages, so we can clear the // This is a response to our post-monitor-failed unfreeze messages, so we can clear the
// monitor_pending_order requirement as we won't re-send the monitor_pending messages. // monitor_pending_order requirement as we won't re-send the monitor_pending messages.
@ -2199,7 +2213,6 @@ impl Channel {
return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish")); return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish"));
} }
Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?; Channel::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 as u64);
self.channel_update_count += 1; self.channel_update_count += 1;
Ok(()) Ok(())

View file

@ -3211,6 +3211,7 @@ mod tests {
use chain::chaininterface::{ChainListener, ChainWatchInterface}; use chain::chaininterface::{ChainListener, ChainWatchInterface};
use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor}; use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor};
use chain::keysinterface; use chain::keysinterface;
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,OnionKeys,PaymentFailReason,RAACommitmentOrder}; use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,OnionKeys,PaymentFailReason,RAACommitmentOrder};
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS, ManyChannelMonitor}; use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS, ManyChannelMonitor};
use ln::router::{Route, RouteHop, Router}; use ln::router::{Route, RouteHop, Router};
@ -3503,6 +3504,17 @@ mod tests {
} }
} }
macro_rules! get_feerate {
($node: expr, $channel_id: expr) => {
{
let chan_lock = $node.node.channel_state.lock().unwrap();
let chan = chan_lock.by_id.get(&$channel_id).unwrap();
chan.get_feerate()
}
}
}
fn create_chan_between_nodes_with_value_init(node_a: &Node, node_b: &Node, channel_value: u64, push_msat: u64) -> Transaction { fn create_chan_between_nodes_with_value_init(node_a: &Node, node_b: &Node, channel_value: u64, push_msat: u64) -> Transaction {
node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42).unwrap(); node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42).unwrap();
node_b.node.handle_open_channel(&node_a.node.get_our_node_id(), &get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id())).unwrap(); node_b.node.handle_open_channel(&node_a.node.get_our_node_id(), &get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id())).unwrap();
@ -4136,14 +4148,6 @@ mod tests {
let chan = create_announced_chan_between_nodes(&nodes, 0, 1); let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
let channel_id = chan.2; let channel_id = chan.2;
macro_rules! get_feerate {
($node: expr) => {{
let chan_lock = $node.node.channel_state.lock().unwrap();
let chan = chan_lock.by_id.get(&channel_id).unwrap();
chan.get_feerate()
}}
}
// balancing // balancing
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000); send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
@ -4165,7 +4169,7 @@ mod tests {
// (6) RAA is delivered -> // (6) RAA is delivered ->
// First nodes[0] generates an update_fee // First nodes[0] generates an update_fee
nodes[0].node.update_fee(channel_id, get_feerate!(nodes[0]) + 20).unwrap(); nodes[0].node.update_fee(channel_id, get_feerate!(nodes[0], channel_id) + 20).unwrap();
check_added_monitors!(nodes[0], 1); check_added_monitors!(nodes[0], 1);
let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); let events_0 = nodes[0].node.get_and_clear_pending_msg_events();
@ -4254,19 +4258,11 @@ mod tests {
let chan = create_announced_chan_between_nodes(&nodes, 0, 1); let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
let channel_id = chan.2; let channel_id = chan.2;
macro_rules! get_feerate {
($node: expr) => {{
let chan_lock = $node.node.channel_state.lock().unwrap();
let chan = chan_lock.by_id.get(&channel_id).unwrap();
chan.get_feerate()
}}
}
// balancing // balancing
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000); send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
// First nodes[0] generates an update_fee // First nodes[0] generates an update_fee
nodes[0].node.update_fee(channel_id, get_feerate!(nodes[0]) + 20).unwrap(); nodes[0].node.update_fee(channel_id, get_feerate!(nodes[0], channel_id) + 20).unwrap();
check_added_monitors!(nodes[0], 1); check_added_monitors!(nodes[0], 1);
let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); let events_0 = nodes[0].node.get_and_clear_pending_msg_events();
@ -4312,14 +4308,6 @@ mod tests {
let chan = create_announced_chan_between_nodes(&nodes, 0, 1); let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
let channel_id = chan.2; let channel_id = chan.2;
macro_rules! get_feerate {
($node: expr) => {{
let chan_lock = $node.node.channel_state.lock().unwrap();
let chan = chan_lock.by_id.get(&channel_id).unwrap();
chan.get_feerate()
}}
}
// A B // A B
// update_fee/commitment_signed -> // update_fee/commitment_signed ->
// .- send (1) RAA and (2) commitment_signed // .- send (1) RAA and (2) commitment_signed
@ -4340,7 +4328,7 @@ mod tests {
// revoke_and_ack -> // revoke_and_ack ->
// First nodes[0] generates an update_fee // First nodes[0] generates an update_fee
let initial_feerate = get_feerate!(nodes[0]); let initial_feerate = get_feerate!(nodes[0], channel_id);
nodes[0].node.update_fee(channel_id, initial_feerate + 20).unwrap(); nodes[0].node.update_fee(channel_id, initial_feerate + 20).unwrap();
check_added_monitors!(nodes[0], 1); check_added_monitors!(nodes[0], 1);
@ -4424,16 +4412,8 @@ mod tests {
let chan = create_announced_chan_between_nodes(&nodes, 0, 1); let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
let channel_id = chan.2; let channel_id = chan.2;
macro_rules! get_feerate { let feerate = get_feerate!(nodes[0], channel_id);
($node: expr) => {{ nodes[0].node.update_fee(channel_id, feerate+25).unwrap();
let chan_lock = $node.node.channel_state.lock().unwrap();
let chan = chan_lock.by_id.get(&channel_id).unwrap();
chan.get_feerate()
}}
}
let feerate = get_feerate!(nodes[0]);
nodes[0].node.update_fee(channel_id, feerate+20).unwrap();
check_added_monitors!(nodes[0], 1); check_added_monitors!(nodes[0], 1);
let events_0 = nodes[0].node.get_and_clear_pending_msg_events(); let events_0 = nodes[0].node.get_and_clear_pending_msg_events();
@ -4464,24 +4444,69 @@ mod tests {
check_added_monitors!(nodes[1], 1); check_added_monitors!(nodes[1], 1);
} }
#[test]
fn test_update_fee_that_funder_cannot_afford() {
let mut nodes = create_network(2);
let channel_value = 1888;
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, 700000);
let channel_id = chan.2;
let feerate = 260;
nodes[0].node.update_fee(channel_id, feerate).unwrap();
check_added_monitors!(nodes[0], 1);
let update_msg = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), &update_msg.update_fee.unwrap()).unwrap();
commitment_signed_dance!(nodes[1], nodes[0], update_msg.commitment_signed, false);
//Confirm that the new fee based on the last local commitment txn is what we expected based on the feerate of 260 set above.
//This value results in a fee that is exactly what the funder can afford (277 sat + 1000 sat channel reserve)
{
let chan_lock = nodes[1].node.channel_state.lock().unwrap();
let chan = chan_lock.by_id.get(&channel_id).unwrap();
//We made sure neither party's funds are below the dust limit so -2 non-HTLC txns from number of outputs
let num_htlcs = chan.last_local_commitment_txn[0].output.len() - 2;
let total_fee: u64 = feerate * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
let mut actual_fee = chan.last_local_commitment_txn[0].output.iter().fold(0, |acc, output| acc + output.value);
actual_fee = channel_value - actual_fee;
assert_eq!(total_fee, actual_fee);
} //drop the mutex
//Add 2 to the previous fee rate to the final fee increases by 1 (with no HTLCs the fee is essentially
//fee_rate*(724/1000) so the increment of 1*0.724 is rounded back down)
nodes[0].node.update_fee(channel_id, feerate+2).unwrap();
check_added_monitors!(nodes[0], 1);
let update2_msg = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), &update2_msg.update_fee.unwrap());
//While producing the commitment_signed response after handling a received update_fee request the
//check to see if the funder, who sent the update_fee request, can afford the new fee (funder_balance >= fee+channel_reserve)
//Should produce and error.
let err = nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &update2_msg.commitment_signed).unwrap_err();
assert!(match err.err {
"Funding remote cannot afford proposed new fee" => true,
_ => false,
});
//clear the message we could not handle
nodes[1].node.get_and_clear_pending_msg_events();
}
#[test] #[test]
fn test_update_fee_with_fundee_update_add_htlc() { fn test_update_fee_with_fundee_update_add_htlc() {
let mut nodes = create_network(2); let mut nodes = create_network(2);
let chan = create_announced_chan_between_nodes(&nodes, 0, 1); let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
let channel_id = chan.2; let channel_id = chan.2;
macro_rules! get_feerate {
($node: expr) => {{
let chan_lock = $node.node.channel_state.lock().unwrap();
let chan = chan_lock.by_id.get(&channel_id).unwrap();
chan.get_feerate()
}}
}
// balancing // balancing
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000); send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
let feerate = get_feerate!(nodes[0]); let feerate = get_feerate!(nodes[0], channel_id);
nodes[0].node.update_fee(channel_id, feerate+20).unwrap(); nodes[0].node.update_fee(channel_id, feerate+20).unwrap();
check_added_monitors!(nodes[0], 1); check_added_monitors!(nodes[0], 1);
@ -4579,14 +4604,6 @@ mod tests {
let chan = create_announced_chan_between_nodes(&nodes, 0, 1); let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
let channel_id = chan.2; let channel_id = chan.2;
macro_rules! get_feerate {
($node: expr) => {{
let chan_lock = $node.node.channel_state.lock().unwrap();
let chan = chan_lock.by_id.get(&channel_id).unwrap();
chan.get_feerate()
}}
}
// A B // A B
// (1) update_fee/commitment_signed -> // (1) update_fee/commitment_signed ->
// <- (2) revoke_and_ack // <- (2) revoke_and_ack
@ -4602,7 +4619,7 @@ mod tests {
// revoke_and_ack -> // revoke_and_ack ->
// Create and deliver (1)... // Create and deliver (1)...
let feerate = get_feerate!(nodes[0]); let feerate = get_feerate!(nodes[0], channel_id);
nodes[0].node.update_fee(channel_id, feerate+20).unwrap(); nodes[0].node.update_fee(channel_id, feerate+20).unwrap();
check_added_monitors!(nodes[0], 1); check_added_monitors!(nodes[0], 1);
@ -4676,8 +4693,8 @@ mod tests {
check_added_monitors!(nodes[1], 1); check_added_monitors!(nodes[1], 1);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
assert_eq!(get_feerate!(nodes[0]), feerate + 30); assert_eq!(get_feerate!(nodes[0], channel_id), feerate + 30);
assert_eq!(get_feerate!(nodes[1]), feerate + 30); assert_eq!(get_feerate!(nodes[1], channel_id), feerate + 30);
close_channel(&nodes[0], &nodes[1], &chan.2, chan.3, true); close_channel(&nodes[0], &nodes[1], &chan.2, chan.3, true);
} }