Skip to content

Commit 507c118

Browse files
author
Antoine Riard
committed
Add basic bumping test
This test check we broadcast a commitment transaction and its corresponding CPFP after a feerate increase.
1 parent 6d5f15d commit 507c118

File tree

4 files changed

+101
-18
lines changed

4 files changed

+101
-18
lines changed

lightning/src/ln/channelmonitor.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ pub struct SimpleManyChannelMonitor<Key, ChanSigner: ChannelKeys, T: Deref, F: D
202202
chain_monitor: C,
203203
broadcaster: T,
204204
logger: L,
205+
#[cfg(test)]
206+
pub fee_estimator: F,
207+
#[cfg(not(test))]
205208
fee_estimator: F,
206209
utxo_pool: U,
207210
}

lightning/src/ln/functional_test_utils.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
140140
// Check that if we serialize and then deserialize all our channel monitors we get the
141141
// same set of outputs to watch for on chain as we have now. Note that if we write
142142
// tests that fully close channels and remove the monitors at some point this may break.
143-
let feeest = test_utils::TestFeeEstimator { sat_per_kw: 253 };
143+
let feeest = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
144144
let mut deserialized_monitors = Vec::new();
145145
{
146146
let old_monitors = self.chan_monitor.simple_monitor.monitors.lock().unwrap();
@@ -166,7 +166,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
166166
<(BlockHash, ChannelManager<EnforcingChannelKeys, &test_utils::TestChannelMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut ::std::io::Cursor::new(w.0), ChannelManagerReadArgs {
167167
default_config: UserConfig::default(),
168168
keys_manager: self.keys_manager,
169-
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: 253 },
169+
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) },
170170
monitor: self.chan_monitor,
171171
tx_broadcaster: self.tx_broadcaster.clone(),
172172
logger: &test_utils::TestLogger::new(),
@@ -1069,7 +1069,7 @@ pub fn create_chanmon_cfgs(node_count: usize) -> Vec<TestChanMonCfg> {
10691069
let mut chan_mon_cfgs = Vec::new();
10701070
for i in 0..node_count {
10711071
let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())};
1072-
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
1072+
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
10731073
let chain_monitor = chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet);
10741074
let logger = test_utils::TestLogger::with_id(format!("node {}", i));
10751075
let utxo_pool = test_utils::TestPool::new();
@@ -1129,6 +1129,7 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
11291129

11301130
pub const ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 138; //Here we have a diff due to HTLC CLTV expiry being < 2^15 in test
11311131
pub const OFFERED_HTLC_SCRIPT_WEIGHT: usize = 133;
1132+
pub const ANCHOR_SCRIPT_WEIGHT: usize = 40;
11321133

11331134
#[derive(PartialEq)]
11341135
pub enum HTLCType { NONE, TIMEOUT, SUCCESS }

lightning/src/ln/functional_tests.rs

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use bitcoin::blockdata::opcodes;
4545
use bitcoin::blockdata::constants::genesis_block;
4646
use bitcoin::network::constants::Network;
4747
use bitcoin::consensus::encode;
48+
use bitcoin::consensus::serialize;
4849

4950
use bitcoin::hashes::sha256::Hash as Sha256;
5051
use bitcoin::hashes::Hash;
@@ -1761,8 +1762,8 @@ fn test_chan_reserve_violation_outbound_htlc_inbound_chan() {
17611762
// Set the fee rate for the channel very high, to the point where the fundee
17621763
// sending any amount would result in a channel reserve violation. In this test
17631764
// we check that we would be prevented from sending an HTLC in this situation.
1764-
chanmon_cfgs[0].fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 6000 };
1765-
chanmon_cfgs[1].fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 6000 };
1765+
chanmon_cfgs[0].fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(6000) };
1766+
chanmon_cfgs[1].fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(6000) };
17661767
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
17671768
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
17681769
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
@@ -1793,8 +1794,8 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
17931794
// to channel reserve violation. This close could also happen if the fee went
17941795
// up a more realistic amount, but many HTLCs were outstanding at the time of
17951796
// the update_add_htlc.
1796-
chanmon_cfgs[0].fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 6000 };
1797-
chanmon_cfgs[1].fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 6000 };
1797+
chanmon_cfgs[0].fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(6000) };
1798+
chanmon_cfgs[1].fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(6000) };
17981799
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
17991800
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
18001801
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
@@ -4324,7 +4325,7 @@ fn test_no_txn_manager_serialize_deserialize() {
43244325
nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap().iter().next().unwrap().1.write_for_disk(&mut chan_0_monitor_serialized).unwrap();
43254326

43264327
logger = test_utils::TestLogger::new();
4327-
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
4328+
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
43284329
utxo_pool = test_utils::TestPool::new();
43294330
new_chan_monitor = test_utils::TestChannelMonitor::new(nodes[0].chain_monitor.clone(), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &utxo_pool);
43304331
nodes[0].chan_monitor = &new_chan_monitor;
@@ -4433,7 +4434,7 @@ fn test_manager_serialize_deserialize_events() {
44334434
let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new());
44344435
nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap().iter().next().unwrap().1.write_for_disk(&mut chan_0_monitor_serialized).unwrap();
44354436

4436-
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
4437+
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
44374438
logger = test_utils::TestLogger::new();
44384439
utxo_pool = test_utils::TestPool::new();
44394440
new_chan_monitor = test_utils::TestChannelMonitor::new(nodes[0].chain_monitor.clone(), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &utxo_pool);
@@ -4527,7 +4528,7 @@ fn test_simple_manager_serialize_deserialize() {
45274528
nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap().iter().next().unwrap().1.write_for_disk(&mut chan_0_monitor_serialized).unwrap();
45284529

45294530
logger = test_utils::TestLogger::new();
4530-
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
4531+
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
45314532
utxo_pool = test_utils::TestPool::new();
45324533
new_chan_monitor = test_utils::TestChannelMonitor::new(nodes[0].chain_monitor.clone(), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &utxo_pool);
45334534
nodes[0].chan_monitor = &new_chan_monitor;
@@ -4607,7 +4608,7 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
46074608
}
46084609

46094610
logger = test_utils::TestLogger::new();
4610-
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
4611+
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
46114612
utxo_pool = test_utils::TestPool::new();
46124613
new_chan_monitor = test_utils::TestChannelMonitor::new(nodes[0].chain_monitor.clone(), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &utxo_pool);
46134614
nodes[0].chan_monitor = &new_chan_monitor;
@@ -7386,7 +7387,7 @@ fn test_user_configurable_csv_delay() {
73867387

73877388
// We test config.our_to_self > BREAKDOWN_TIMEOUT is enforced in Channel::new_outbound()
73887389
let keys_manager: Arc<KeysInterface<ChanKeySigner = EnforcingChannelKeys>> = Arc::new(test_utils::TestKeysInterface::new(&nodes[0].node_seed, Network::Testnet));
7389-
if let Err(error) = Channel::new_outbound(&&test_utils::TestFeeEstimator { sat_per_kw: 253 }, &keys_manager, nodes[1].node.get_our_node_id(), 1000000, 1000000, 0, &low_our_to_self_config) {
7390+
if let Err(error) = Channel::new_outbound(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &keys_manager, nodes[1].node.get_our_node_id(), 1000000, 1000000, 0, &low_our_to_self_config) {
73907391
match error {
73917392
APIError::APIMisuseError { err } => { assert!(regex::Regex::new(r"Configured with an unreasonable our_to_self_delay \(\d+\) putting user funds at risks").unwrap().is_match(err.as_str())); },
73927393
_ => panic!("Unexpected event"),
@@ -7397,7 +7398,7 @@ fn test_user_configurable_csv_delay() {
73977398
nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
73987399
let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
73997400
open_channel.to_self_delay = 200;
7400-
if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: 253 }, &keys_manager, nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel, 0, &low_our_to_self_config) {
7401+
if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &keys_manager, nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel, 0, &low_our_to_self_config) {
74017402
match error {
74027403
ChannelError::Close(err) => { assert!(regex::Regex::new(r"Configured with an unreasonable our_to_self_delay \(\d+\) putting user funds at risks").unwrap().is_match(err.as_str())); },
74037404
_ => panic!("Unexpected event"),
@@ -7423,7 +7424,7 @@ fn test_user_configurable_csv_delay() {
74237424
nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
74247425
let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
74257426
open_channel.to_self_delay = 200;
7426-
if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: 253 }, &keys_manager, nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel, 0, &high_their_to_self_config) {
7427+
if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &keys_manager, nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel, 0, &high_their_to_self_config) {
74277428
match error {
74287429
ChannelError::Close(err) => { assert!(regex::Regex::new(r"They wanted our payments to be delayed by a needlessly long period\. Upper limit: \d+\. Actual: \d+").unwrap().is_match(err.as_str())); },
74297430
_ => panic!("Unexpected event"),
@@ -7468,7 +7469,7 @@ fn test_data_loss_protect() {
74687469
let mut chan_monitor = <(BlockHash, ChannelMonitor<EnforcingChannelKeys>)>::read(&mut ::std::io::Cursor::new(previous_chan_monitor_state.0)).unwrap().1;
74697470
chain_monitor = ChainWatchInterfaceUtil::new(Network::Testnet);
74707471
tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())};
7471-
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
7472+
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
74727473
keys_manager = test_utils::TestKeysInterface::new(&nodes[0].node_seed, Network::Testnet);
74737474
utxo_pool = test_utils::TestPool::new();
74747475
monitor = test_utils::TestChannelMonitor::new(&chain_monitor, &tx_broadcaster, &logger, &fee_estimator, &utxo_pool);
@@ -8446,3 +8447,75 @@ fn test_concurrent_monitor_claim() {
84468447
check_spends!(txn[2], chan_1.3);
84478448
}
84488449
}
8450+
8451+
#[test]
8452+
fn test_basic_commitment_cpfp() {
8453+
// Node A sends a HTLC to Node B, who holds it. We propagate blocks until HTLC
8454+
// reach its deadine and Node A must close the channnel. We observe a broadcast
8455+
// of a commitment transaction and its anchor-output CPFP. After few blocks we
8456+
// observe a feerate-bump of the CPFP.
8457+
8458+
// Create Alice and Bob
8459+
let chanmon_cfgs = create_chanmon_cfgs(2);
8460+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
8461+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
8462+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
8463+
8464+
// Create a channel between Alice and Bob
8465+
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
8466+
8467+
// Route a HTLC from Alice to Bob without settlement
8468+
route_payment(&nodes[0], &vec!(&nodes[1])[..], 9_000_000).0;
8469+
8470+
// Connect block on Alice's chain view until offered HTLC must be settled onchain
8471+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
8472+
nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![] }, 135);
8473+
check_closed_broadcast!(nodes[0], false);
8474+
check_added_monitors!(nodes[0], 1);
8475+
8476+
{
8477+
let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8478+
assert_eq!(node_txn.len(), 2);
8479+
8480+
// Verify 1st transaction spend channel funding
8481+
check_spends!(node_txn[0], chan_1.3);
8482+
8483+
// Verify 2nd transaction is a HTLC-timeout
8484+
assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
8485+
check_spends!(node_txn[1], node_txn[0]);
8486+
node_txn.clear();
8487+
}
8488+
8489+
nodes[0].chan_monitor.simple_monitor.fee_estimator.set_sat_per_kw(5000);
8490+
8491+
// Verify that CPFP logic is triggered after a feerate increase
8492+
nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![] }, 136);
8493+
{
8494+
let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8495+
assert_eq!(node_txn.len(), 2);
8496+
8497+
// Verify 1st transaction spend channel funding
8498+
check_spends!(node_txn[0], chan_1.3);
8499+
8500+
// Verify 2nd transaction is a Child-Pay-For-Parent
8501+
assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), ANCHOR_SCRIPT_WEIGHT);
8502+
assert_eq!(node_txn[1].output.len(), 1);
8503+
let mut check_anchor = false;
8504+
for (idx, outp) in node_txn[0].output.iter().enumerate() {
8505+
if outp.value == ANCHOR_OUTPUT_VALUE {
8506+
let tx = serialize(&node_txn[1]);
8507+
if let Ok(_) = node_txn[0].output[idx].script_pubkey.verify(0, ANCHOR_OUTPUT_VALUE, tx.as_slice()) { check_anchor = true }
8508+
}
8509+
}
8510+
if !check_anchor { panic!("Invalid anchor output spent"); }
8511+
8512+
// Verify that CPFP fee is correct. The effective fee must be superior or equal to
8513+
// the required feerare multiply by the effective weight.
8514+
// Effective weight is expected to differ from predicted weight as some fields
8515+
// are inflated to prevent worst-case scenarios (73-bytes ECDSA sigs, count_tx_out, ..)
8516+
let effective_package_weight = node_txn[0].get_weight() + node_txn[1].get_weight();
8517+
let required_fee = 5000 * (effective_package_weight as u64) / 1000;
8518+
let effective_fee = (test_utils::TEST_BUMP_VALUE + ANCHOR_OUTPUT_VALUE) - node_txn[1].output[0].value;
8519+
assert!(effective_fee >= required_fee);
8520+
}
8521+
}

lightning/src/util/test_utils.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use util::logger::{Logger, Level, Record};
2424
use util::ser::{Readable, Writer, Writeable};
2525

2626
use bitcoin::blockdata::constants::genesis_block;
27-
use bitcoin::blockdata::transaction::{Transaction, OutPoint as BitcoinOutPoint};
27+
use bitcoin::blockdata::transaction::{Transaction, TxOut, OutPoint as BitcoinOutPoint};
2828
use bitcoin::blockdata::script::{Builder, Script};
2929
use bitcoin::blockdata::block::Block;
3030
use bitcoin::blockdata::opcodes;
@@ -54,11 +54,17 @@ impl Writer for TestVecWriter {
5454
}
5555

5656
pub struct TestFeeEstimator {
57-
pub sat_per_kw: u32,
57+
pub sat_per_kw: Mutex<u32>,
5858
}
5959
impl chaininterface::FeeEstimator for TestFeeEstimator {
6060
fn get_est_sat_per_1000_weight(&self, _confirmation_target: ConfirmationTarget) -> u32 {
61-
self.sat_per_kw
61+
*self.sat_per_kw.lock().unwrap()
62+
}
63+
}
64+
65+
impl TestFeeEstimator {
66+
pub fn set_sat_per_kw(&self, new_feerate: u32) {
67+
*(self.sat_per_kw.lock().unwrap()) = new_feerate;
6268
}
6369
}
6470

0 commit comments

Comments
 (0)