Skip to content

Commit 0133739

Browse files
authored
Merge pull request #647 from valentinewallace/test-remote-fee-spike-buffer-violation
Test remote fee spike buffer violation
2 parents 8fae0c0 + 940d7ac commit 0133739

File tree

3 files changed

+179
-4
lines changed

3 files changed

+179
-4
lines changed

lightning/src/ln/channel.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,8 +1755,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17551755
self.commit_tx_fee_msat(their_acked_htlcs + addl_htlcs)
17561756
}
17571757

1758-
pub fn update_add_htlc<F>(&mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus, create_pending_htlc_status: F) -> Result<(), ChannelError>
1759-
where F: for<'a> Fn(&'a Self, PendingHTLCStatus, u16) -> PendingHTLCStatus {
1758+
pub fn update_add_htlc<F, L: Deref>(&mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus, create_pending_htlc_status: F, logger: &L) -> Result<(), ChannelError>
1759+
where F: for<'a> Fn(&'a Self, PendingHTLCStatus, u16) -> PendingHTLCStatus, L::Target: Logger {
17601760
// We can't accept HTLCs sent after we've sent a shutdown.
17611761
let local_sent_shutdown = (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::LocalShutdownSent as u32)) != (ChannelState::ChannelFunded as u32);
17621762
if local_sent_shutdown {
@@ -1845,6 +1845,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
18451845
if pending_remote_value_msat - msg.amount_msat - chan_reserve_msat < remote_fee_cost_incl_stuck_buffer_msat {
18461846
// Note that if the pending_forward_status is not updated here, then it's because we're already failing
18471847
// the HTLC, i.e. its status is already set to failing.
1848+
log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation");
18481849
pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
18491850
}
18501851
} else {

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2519,7 +2519,7 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
25192519
_ => pending_forward_info
25202520
}
25212521
};
2522-
try_chan_entry!(self, chan.get_mut().update_add_htlc(&msg, pending_forward_info, create_pending_htlc_status), channel_state, chan);
2522+
try_chan_entry!(self, chan.get_mut().update_add_htlc(&msg, pending_forward_info, create_pending_htlc_status, &self.logger), channel_state, chan);
25232523
},
25242524
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel", msg.channel_id))
25252525
}

lightning/src/ln/functional_tests.rs

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use util::config::UserConfig;
2525

2626
use bitcoin::util::hash::BitcoinHash;
2727
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
28-
use bitcoin::hash_types::{Txid, BlockHash};
28+
use bitcoin::hashes::HashEngine;
29+
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
2930
use bitcoin::util::bip143;
3031
use bitcoin::util::address::Address;
3132
use bitcoin::util::bip32::{ChildNumber, ExtendedPubKey, ExtendedPrivKey};
@@ -1553,6 +1554,179 @@ fn test_basic_channel_reserve() {
15531554
send_payment(&nodes[0], &vec![&nodes[1]], max_can_send, max_can_send);
15541555
}
15551556

1557+
#[test]
1558+
fn test_fee_spike_violation_fails_htlc() {
1559+
let chanmon_cfgs = create_chanmon_cfgs(2);
1560+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1561+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
1562+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1563+
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
1564+
let logger = test_utils::TestLogger::new();
1565+
1566+
macro_rules! get_route_and_payment_hash {
1567+
($recv_value: expr) => {{
1568+
let (payment_preimage, payment_hash) = get_payment_preimage_hash!(nodes[1]);
1569+
let net_graph_msg_handler = &nodes[0].net_graph_msg_handler;
1570+
let route = get_route(&nodes[0].node.get_our_node_id(), net_graph_msg_handler, &nodes.last().unwrap().node.get_our_node_id(), None, &Vec::new(), $recv_value, TEST_FINAL_CLTV, &logger).unwrap();
1571+
(route, payment_hash, payment_preimage)
1572+
}}
1573+
};
1574+
1575+
let (route, payment_hash, _) = get_route_and_payment_hash!(3460001);
1576+
// Need to manually create the update_add_htlc message to go around the channel reserve check in send_htlc()
1577+
let secp_ctx = Secp256k1::new();
1578+
let session_priv = SecretKey::from_slice(&[42; 32]).expect("RNG is bad!");
1579+
1580+
let cur_height = nodes[1].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
1581+
1582+
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1583+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &None, cur_height).unwrap();
1584+
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
1585+
let msg = msgs::UpdateAddHTLC {
1586+
channel_id: chan.2,
1587+
htlc_id: 0,
1588+
amount_msat: htlc_msat,
1589+
payment_hash: payment_hash,
1590+
cltv_expiry: htlc_cltv,
1591+
onion_routing_packet: onion_packet,
1592+
};
1593+
1594+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &msg);
1595+
1596+
// Now manually create the commitment_signed message corresponding to the update_add
1597+
// nodes[0] just sent. In the code for construction of this message, "local" refers
1598+
// to the sender of the message, and "remote" refers to the receiver.
1599+
1600+
let feerate_per_kw = get_feerate!(nodes[0], chan.2);
1601+
1602+
// Get the EnforcingChannelKeys for each channel, which will be used to (1) get the keys
1603+
// needed to sign the new commitment tx and (2) sign the new commitment tx.
1604+
let (local_revocation_basepoint, local_htlc_basepoint, local_payment_point, local_chan_commitment_seed) = {
1605+
let chan_lock = nodes[0].node.channel_state.lock().unwrap();
1606+
let local_chan = chan_lock.by_id.get(&chan.2).unwrap();
1607+
let chan_keys = local_chan.get_local_keys();
1608+
let pubkeys = chan_keys.pubkeys();
1609+
(pubkeys.revocation_basepoint, pubkeys.htlc_basepoint, pubkeys.payment_point, *chan_keys.commitment_seed())
1610+
};
1611+
let (remote_delayed_payment_basepoint, remote_htlc_basepoint, remote_payment_point, remote_chan_commitment_seed) = {
1612+
let chan_lock = nodes[1].node.channel_state.lock().unwrap();
1613+
let remote_chan = chan_lock.by_id.get(&chan.2).unwrap();
1614+
let chan_keys = remote_chan.get_local_keys();
1615+
let pubkeys = chan_keys.pubkeys();
1616+
(pubkeys.delayed_payment_basepoint, pubkeys.htlc_basepoint, pubkeys.payment_point, *chan_keys.commitment_seed())
1617+
};
1618+
1619+
// Assemble the set of keys we can use for signatures for our commitment_signed message.
1620+
const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
1621+
let commitment_secret = {
1622+
let res = chan_utils::build_commitment_secret(&remote_chan_commitment_seed, INITIAL_COMMITMENT_NUMBER - 1);
1623+
SecretKey::from_slice(&res).unwrap()
1624+
};
1625+
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &commitment_secret);
1626+
let commit_tx_keys = chan_utils::TxCreationKeys::new(&secp_ctx, &per_commitment_point, &remote_delayed_payment_basepoint,
1627+
&remote_htlc_basepoint, &local_revocation_basepoint, &local_htlc_basepoint).unwrap();
1628+
1629+
// Build the remote commitment transaction so we can sign it, and then later use the
1630+
// signature for the commitment_signed message.
1631+
let local_chan_balance = 1313;
1632+
let static_payment_pk = local_payment_point.serialize();
1633+
let remote_commit_tx_output = TxOut {
1634+
script_pubkey: Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0)
1635+
.push_slice(&WPubkeyHash::hash(&static_payment_pk)[..])
1636+
.into_script(),
1637+
value: local_chan_balance as u64
1638+
};
1639+
1640+
let local_commit_tx_output = TxOut {
1641+
script_pubkey: chan_utils::get_revokeable_redeemscript(&commit_tx_keys.revocation_key,
1642+
BREAKDOWN_TIMEOUT,
1643+
&commit_tx_keys.a_delayed_payment_key).to_v0_p2wsh(),
1644+
value: 95000,
1645+
};
1646+
1647+
let accepted_htlc_info = chan_utils::HTLCOutputInCommitment {
1648+
offered: false,
1649+
amount_msat: 3460001,
1650+
cltv_expiry: htlc_cltv,
1651+
payment_hash: payment_hash,
1652+
transaction_output_index: Some(1),
1653+
};
1654+
1655+
let htlc_output = TxOut {
1656+
script_pubkey: chan_utils::get_htlc_redeemscript(&accepted_htlc_info, &commit_tx_keys).to_v0_p2wsh(),
1657+
value: 3460001 / 1000
1658+
};
1659+
1660+
let commit_tx_obscure_factor = {
1661+
let mut sha = Sha256::engine();
1662+
let remote_payment_point = &remote_payment_point.serialize();
1663+
sha.input(&local_payment_point.serialize());
1664+
sha.input(remote_payment_point);
1665+
let res = Sha256::from_engine(sha).into_inner();
1666+
1667+
((res[26] as u64) << 5*8) |
1668+
((res[27] as u64) << 4*8) |
1669+
((res[28] as u64) << 3*8) |
1670+
((res[29] as u64) << 2*8) |
1671+
((res[30] as u64) << 1*8) |
1672+
((res[31] as u64) << 0*8)
1673+
};
1674+
let commitment_number = 1;
1675+
let obscured_commitment_transaction_number = commit_tx_obscure_factor ^ commitment_number;
1676+
let lock_time = ((0x20 as u32) << 8*3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32);
1677+
let input = TxIn {
1678+
previous_output: BitcoinOutPoint { txid: chan.3.txid(), vout: 0 },
1679+
script_sig: Script::new(),
1680+
sequence: ((0x80 as u32) << 8*3) | ((obscured_commitment_transaction_number >> 3*8) as u32),
1681+
witness: Vec::new(),
1682+
};
1683+
1684+
let commit_tx = Transaction {
1685+
version: 2,
1686+
lock_time,
1687+
input: vec![input],
1688+
output: vec![remote_commit_tx_output, htlc_output, local_commit_tx_output],
1689+
};
1690+
let res = {
1691+
let local_chan_lock = nodes[0].node.channel_state.lock().unwrap();
1692+
let local_chan = local_chan_lock.by_id.get(&chan.2).unwrap();
1693+
let local_chan_keys = local_chan.get_local_keys();
1694+
local_chan_keys.sign_remote_commitment(feerate_per_kw, &commit_tx, &commit_tx_keys, &[&accepted_htlc_info],
1695+
BREAKDOWN_TIMEOUT, &secp_ctx).unwrap()
1696+
};
1697+
1698+
let commit_signed_msg = msgs::CommitmentSigned {
1699+
channel_id: chan.2,
1700+
signature: res.0,
1701+
htlc_signatures: res.1
1702+
};
1703+
1704+
// Send the commitment_signed message to the nodes[1].
1705+
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &commit_signed_msg);
1706+
let _ = nodes[1].node.get_and_clear_pending_msg_events();
1707+
1708+
// Send the RAA to nodes[1].
1709+
let per_commitment_secret = chan_utils::build_commitment_secret(&local_chan_commitment_seed, INITIAL_COMMITMENT_NUMBER);
1710+
let next_secret = SecretKey::from_slice(&chan_utils::build_commitment_secret(&local_chan_commitment_seed, INITIAL_COMMITMENT_NUMBER - 2)).unwrap();
1711+
let next_per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &next_secret);
1712+
let raa_msg = msgs::RevokeAndACK{ channel_id: chan.2, per_commitment_secret, next_per_commitment_point};
1713+
nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &raa_msg);
1714+
1715+
let events = nodes[1].node.get_and_clear_pending_msg_events();
1716+
assert_eq!(events.len(), 1);
1717+
// Make sure the HTLC failed in the way we expect.
1718+
match events[0] {
1719+
MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate { ref update_fail_htlcs, .. }, .. } => {
1720+
assert_eq!(update_fail_htlcs.len(), 1);
1721+
update_fail_htlcs[0].clone()
1722+
},
1723+
_ => panic!("Unexpected event"),
1724+
};
1725+
nodes[1].logger.assert_log("lightning::ln::channel".to_string(), "Attempting to fail HTLC due to fee spike buffer violation".to_string(), 1);
1726+
1727+
check_added_monitors!(nodes[1], 2);
1728+
}
1729+
15561730
#[test]
15571731
fn test_chan_reserve_violation_outbound_htlc_inbound_chan() {
15581732
let mut chanmon_cfgs = create_chanmon_cfgs(2);

0 commit comments

Comments
 (0)