Skip to content

Commit ee8b846

Browse files
committed
Cover the saturating sub of the fee and anchors from funder's balance
The saturating subtractions used in `ChannelContext::build_commitment_transaction` are there for a reason; when the remote party updates the fees, we build the new commitment transaction before checking whether the remote party has enough balance to cover the new fee, so we cannot guarantee that the remote party's balance will be greater than or equal to the sum of the fee and the anchors.
1 parent ae52809 commit ee8b846

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

lightning/src/ln/functional_tests.rs

+84
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,90 @@ pub fn test_update_fee_that_funder_cannot_afford() {
789789
[nodes[0].node.get_our_node_id()], channel_value);
790790
}
791791

792+
#[xtest(feature = "_externalize_tests")]
793+
pub fn test_update_fee_that_saturates_subs() {
794+
// Check that when a remote party sends us an `update_fee` message that results in a total fee
795+
// on the commitment transaction that is greater than her balance, we saturate the subtractions,
796+
// and force close the channel.
797+
798+
let mut default_config = test_default_channel_config();
799+
let secp_ctx = Secp256k1::new();
800+
801+
let chanmon_cfgs = create_chanmon_cfgs(2);
802+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
803+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(default_config), Some(default_config)]);
804+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
805+
806+
let chan_id = create_chan_between_nodes_with_value(&nodes[0], &nodes[1], 10_000, 8_500_000).3;
807+
808+
const FEERATE: u32 = 250 * 10; // 10sat/vb
809+
810+
// Assert that the new feerate will completely exhaust the balance of node 0, and saturate the
811+
// subtraction of the total fee from node 0's balance.
812+
let total_fee_sat = chan_utils::commit_tx_fee_sat(FEERATE, 0, &ChannelTypeFeatures::empty());
813+
assert!(total_fee_sat > 1500);
814+
815+
const INITIAL_COMMITMENT_NUMBER: u64 = 281474976710654;
816+
817+
// We build a commitment transcation here only to pass node 1's check of node 0's signature
818+
// in `commitment_signed`.
819+
820+
let remote_point = {
821+
let per_peer_state = nodes[1].node.per_peer_state.read().unwrap();
822+
let chan_lock = per_peer_state.get(&nodes[0].node.get_our_node_id()).unwrap().lock().unwrap();
823+
let remote_chan = chan_lock.channel_by_id.get(&chan_id).and_then(Channel::as_funded).unwrap();
824+
let chan_signer = remote_chan.get_signer();
825+
chan_signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER, &secp_ctx).unwrap()
826+
};
827+
828+
let res = {
829+
let per_peer_state = nodes[0].node.per_peer_state.read().unwrap();
830+
let local_chan_lock = per_peer_state.get(&nodes[1].node.get_our_node_id()).unwrap().lock().unwrap();
831+
let local_chan = local_chan_lock.channel_by_id.get(&chan_id).and_then(Channel::as_funded).unwrap();
832+
let local_chan_signer = local_chan.get_signer();
833+
let mut htlcs: Vec<(HTLCOutputInCommitment, ())> = vec![];
834+
let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
835+
INITIAL_COMMITMENT_NUMBER,
836+
&remote_point,
837+
8500,
838+
// Set a zero balance here: this is the transaction that node 1 will expect a signature for, as
839+
// he will do a saturating subtraction of the total fees from node 0's balance.
840+
0,
841+
FEERATE,
842+
&mut htlcs,
843+
&local_chan.funding.channel_transaction_parameters.as_counterparty_broadcastable(),
844+
&secp_ctx,
845+
);
846+
local_chan_signer.as_ecdsa().unwrap().sign_counterparty_commitment(
847+
&local_chan.funding.channel_transaction_parameters, &commitment_tx, Vec::new(),
848+
Vec::new(), &secp_ctx,
849+
).unwrap()
850+
};
851+
852+
let commit_signed_msg = msgs::CommitmentSigned {
853+
channel_id: chan_id,
854+
signature: res.0,
855+
htlc_signatures: res.1,
856+
batch: None,
857+
#[cfg(taproot)]
858+
partial_signature_with_nonce: None,
859+
};
860+
861+
let update_fee = msgs::UpdateFee {
862+
channel_id: chan_id,
863+
feerate_per_kw: FEERATE,
864+
};
865+
866+
nodes[1].node.handle_update_fee(nodes[0].node.get_our_node_id(), &update_fee);
867+
868+
nodes[1].node.handle_commitment_signed(nodes[0].node.get_our_node_id(), &commit_signed_msg);
869+
nodes[1].logger.assert_log_contains("lightning::ln::channelmanager", "Funding remote cannot afford proposed new fee", 3);
870+
check_added_monitors!(nodes[1], 1);
871+
check_closed_broadcast!(nodes[1], true);
872+
check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: String::from("Funding remote cannot afford proposed new fee") },
873+
[nodes[0].node.get_our_node_id()], 10_000);
874+
}
875+
792876
#[xtest(feature = "_externalize_tests")]
793877
pub fn test_update_fee_with_fundee_update_add_htlc() {
794878
let chanmon_cfgs = create_chanmon_cfgs(2);

0 commit comments

Comments
 (0)