Skip to content

Commit a868de8

Browse files
committed
Negotiate 0FC channels if configured
1 parent cada867 commit a868de8

6 files changed

Lines changed: 100 additions & 8 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: CI Checks - 0FC Integration Tests
2+
3+
on: [push, pull_request]
4+
5+
concurrency:
6+
group: ${{ github.workflow }}-${{ github.ref }}
7+
cancel-in-progress: true
8+
9+
jobs:
10+
build-and-test:
11+
timeout-minutes: 60
12+
runs-on: self-hosted
13+
steps:
14+
- name: Checkout source code
15+
uses: actions/checkout@v4
16+
- name: Install Rust stable toolchain
17+
run: |
18+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain stable
19+
- name: Enable caching for bitcoind
20+
id: cache-bitcoind
21+
uses: actions/cache@v4
22+
with:
23+
path: bin/bitcoind-${{ runner.os }}-${{ runner.arch }}
24+
key: bitcoind-29.0-${{ runner.os }}-${{ runner.arch }}
25+
- name: Enable caching for electrs
26+
id: cache-electrs
27+
uses: actions/cache@v4
28+
with:
29+
path: bin/electrs-${{ runner.os }}-${{ runner.arch }}
30+
key: electrs-submit-package-${{ runner.os }}-${{ runner.arch }}
31+
- name: Download bitcoind
32+
if: "steps.cache-bitcoind.outputs.cache-hit != 'true'"
33+
run: |
34+
source ./scripts/download_bitcoind_electrs.sh
35+
mkdir -p bin
36+
mv "$BITCOIND_EXE" bin/bitcoind-${{ runner.os }}-${{ runner.arch }}
37+
- name: Download electrs
38+
if: "steps.cache-electrs.outputs.cache-hit != 'true'"
39+
run: |
40+
source ./scripts/build_electrs.sh
41+
mkdir -p bin
42+
mv "$ELECTRS_EXE" bin/electrs-${{ runner.os }}-${{ runner.arch }}
43+
- name: Set bitcoind/electrs environment variables
44+
run: |
45+
echo "BITCOIND_EXE=$( pwd )/bin/bitcoind-${{ runner.os }}-${{ runner.arch }}" >> "$GITHUB_ENV"
46+
echo "ELECTRS_EXE=$( pwd )/bin/electrs-${{ runner.os }}-${{ runner.arch }}" >> "$GITHUB_ENV"
47+
- name: Test with 0FC enabled
48+
run: |
49+
RUSTFLAGS="--cfg no_download --cfg cycle_tests --cfg tokio_unstable --cfg zero_fee_commitment_tests" cargo test -- --test-threads=1

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ check-cfg = [
135135
"cfg(eclair_test)",
136136
"cfg(cycle_tests)",
137137
"cfg(hrn_tests)",
138+
"cfg(zero_fee_commitment_tests)",
138139
]
139140

140141
[[bench]]

scripts/build_electrs.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/bash
2+
set -eox pipefail
3+
4+
# Our Esplora-based tests require `electrs` binaries. Here, we
5+
# download the code, build the binaries, and export their location
6+
# via `ELECTRS_EXE` which will be used by the `electrsd` crates in
7+
# our tests.
8+
9+
HOST_PLATFORM="$(rustc --version --verbose | grep "host:" | awk '{ print $2 }')"
10+
ELECTRS_GIT_REPO="https://github.com/tankyleo/blockstream-electrs.git"
11+
ELECTRS_TAG="2026-05-26-electrum-submit-package"
12+
ELECTRS_REV="8c06d8010e43f793b1a65f83695ea846e5cd83ed"
13+
if [[ "$HOST_PLATFORM" != *linux* && "$HOST_PLATFORM" != *darwin* ]]; then
14+
printf "\n\n"
15+
echo "Unsupported platform: $HOST_PLATFORM Exiting.."
16+
exit 1
17+
fi
18+
19+
DL_TMP_DIR=$(mktemp -d)
20+
trap 'rm -rf -- "$DL_TMP_DIR"' EXIT
21+
22+
pushd "$DL_TMP_DIR"
23+
git clone --branch "$ELECTRS_TAG" --depth 1 "$ELECTRS_GIT_REPO" blockstream-electrs
24+
cd blockstream-electrs
25+
CURRENT_HEAD=$(git rev-parse HEAD)
26+
if [ "$CURRENT_HEAD" != "$ELECTRS_REV" ]; then
27+
echo "ERROR: HEAD does not match expected commit"
28+
echo "expected: $ELECTRS_REV"
29+
echo "actual: $CURRENT_HEAD"
30+
exit 1
31+
fi
32+
RUSTFLAGS="" cargo build
33+
export ELECTRS_EXE="$DL_TMP_DIR"/blockstream-electrs/target/debug/electrs
34+
chmod +x "$ELECTRS_EXE"
35+
popd

src/config.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ pub struct Config {
188188
/// used to send pre-flight probes.
189189
pub probing_liquidity_limit_multiplier: u64,
190190
/// Configuration options pertaining to Anchor channels, i.e., channels for which the
191-
/// `option_anchors_zero_fee_htlc_tx` channel type is negotiated.
191+
/// `option_zero_fee_commitments` or `option_anchors_zero_fee_htlc_tx` channel type is
192+
/// negotiated.
192193
///
193194
/// Please refer to [`AnchorChannelsConfig`] for further information on Anchor channels.
194195
pub anchor_channels_config: AnchorChannelsConfig,
@@ -287,7 +288,7 @@ impl Default for HumanReadableNamesConfig {
287288
}
288289

289290
/// Configuration options pertaining to 'Anchor' channels, i.e., channels for which the
290-
/// `option_anchors_zero_fee_htlc_tx` channel type is negotiated.
291+
/// `option_zero_fee_commitments` or `option_anchors_zero_fee_htlc_tx` channel type is negotiated.
291292
///
292293
/// Prior to the introduction of Anchor channels, the on-chain fees paying for the transactions
293294
/// issued on channel closure were pre-determined and locked-in at the time of the channel
@@ -424,6 +425,8 @@ pub(crate) fn default_user_config(config: &Config) -> UserConfig {
424425
// will mostly be relevant for inbound channels.
425426
let mut user_config = UserConfig::default();
426427
user_config.channel_handshake_limits.force_announced_channel_preference = false;
428+
user_config.channel_handshake_config.negotiate_anchor_zero_fee_commitments =
429+
config.anchor_channels_config.enable_zero_fee_commitments;
427430
user_config.reject_inbound_splices = false;
428431

429432
if may_announce_channel(config).is_err() {

tests/common/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,11 @@ pub(crate) fn random_node_alias() -> Option<NodeAlias> {
382382
pub(crate) fn random_config() -> TestConfig {
383383
let mut node_config = Config::default();
384384

385+
#[cfg(zero_fee_commitment_tests)]
386+
{
387+
node_config.anchor_channels_config.enable_zero_fee_commitments = true;
388+
}
389+
385390
node_config.network = Network::Regtest;
386391
println!("Setting network: {}", node_config.network);
387392

@@ -1579,10 +1584,8 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
15791584
let node_a_outbound_capacity_msat = node_a.list_channels()[0].outbound_capacity_msat;
15801585
let node_a_reserve_msat =
15811586
node_a.list_channels()[0].unspendable_punishment_reserve.unwrap() * 1000;
1582-
// TODO: Zero-fee commitment channels are anchor channels, but do not allocate any
1583-
// funds to the anchor, so this will need to be updated when we ship these channels
1584-
// in ldk-node.
1585-
let node_a_anchors_msat = if expect_anchor_channel { 2 * 330 * 1000 } else { 0 };
1587+
let zero_fee_commitments = node_a.list_channels()[0].feerate_sat_per_1000_weight == 0;
1588+
let node_a_anchors_msat = if zero_fee_commitments { 0 } else { 2 * 330 * 1000 };
15861589
let funding_amount_msat = node_a.list_channels()[0].channel_value_sats * 1000;
15871590
// Node B does not have any reserve, so we only subtract a few items on node A's
15881591
// side to arrive at node B's capacity

tests/integration_tests_rust.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,8 +1543,9 @@ async fn splice_channel() {
15431543
let user_channel_id_b = expect_channel_ready_event!(node_b, node_a.node_id());
15441544

15451545
let opening_transaction_fee_sat = 156;
1546-
let closing_transaction_fee_sat = 614;
1547-
let anchor_output_sat = 330;
1546+
let zero_fee_commitments = node_a.list_channels()[0].feerate_sat_per_1000_weight == 0;
1547+
let closing_transaction_fee_sat = if zero_fee_commitments { 0 } else { 614 };
1548+
let anchor_output_sat = if zero_fee_commitments { 0 } else { 330 };
15481549

15491550
assert_eq!(
15501551
node_a.list_balances().total_onchain_balance_sats,

0 commit comments

Comments
 (0)