109 lines
4 KiB
Nix
109 lines
4 KiB
Nix
# regtest-core — NixOS-native Lightning regtest integration test.
|
|
#
|
|
# A reproducible, hermetic replacement for the core of the docker
|
|
# `legend-regtest-enviroment` stack (aiolabs/omnixient#27): one VM running
|
|
# bitcoind(regtest) + Core Lightning + LND (the bitcoin pack's nix-bitcoin
|
|
# modules), driving a real payment flow and asserting it settles.
|
|
#
|
|
# Both LN nodes are co-located on one node and share the local bitcoind;
|
|
# lnd's p2p port is moved to 9736 so it doesn't clash with clightning's
|
|
# 9735. CLIs are run as the nix-bitcoin `operator` user, matching how
|
|
# nix-bitcoin's own test suite drives them.
|
|
#
|
|
# The node config is shared with the interactive dev VM via
|
|
# tests/regtest-node.nix so the two can never drift.
|
|
#
|
|
# Run headless:
|
|
# nix build .#checks.x86_64-linux.regtest-core -L
|
|
# Interactive driver (poke the node by hand):
|
|
# nix build .#checks.x86_64-linux.regtest-core.driverInteractive
|
|
# ./result/bin/nixos-test-driver
|
|
# Friendlier interactive shell (SSH, copy/paste, operator user, helpers):
|
|
# nix run .#regtest (see docs/regtest.md)
|
|
{
|
|
nixpkgs,
|
|
system ? "x86_64-linux",
|
|
nix-bitcoin,
|
|
...
|
|
}:
|
|
|
|
let
|
|
pkgs = import nixpkgs {
|
|
inherit system;
|
|
config.allowUnfree = true;
|
|
};
|
|
in
|
|
pkgs.testers.runNixOSTest {
|
|
name = "omni-regtest-core";
|
|
|
|
nodes.regtest = {
|
|
imports = [
|
|
nix-bitcoin.nixosModules.default
|
|
./regtest-node.nix # shared bitcoind + CLN + LND config
|
|
];
|
|
};
|
|
|
|
testScript = ''
|
|
def op(cmd):
|
|
"""Run a command as the nix-bitcoin operator and return stdout."""
|
|
return regtest.succeed(f"runuser -u operator -- {cmd}")
|
|
|
|
regtest.start()
|
|
|
|
# --- services up ---
|
|
regtest.wait_for_unit("bitcoind.service")
|
|
regtest.wait_for_unit("clightning.service")
|
|
regtest.wait_for_unit("lnd.service")
|
|
|
|
# CLIs answer (clightning/lnd take a moment past unit-active to be RPC-ready).
|
|
regtest.wait_until_succeeds("runuser -u operator -- lightning-cli getinfo", timeout=120)
|
|
regtest.wait_until_succeeds("runuser -u operator -- lncli getinfo", timeout=120)
|
|
|
|
# --- both LN nodes synced to the pre-mined regtest chain ---
|
|
regtest.wait_until_succeeds(
|
|
f"[[ $(runuser -u operator -- lightning-cli getinfo | jq -M .blockheight) == {110} ]]",
|
|
timeout=120,
|
|
)
|
|
regtest.wait_until_succeeds(
|
|
f"[[ $(runuser -u operator -- lncli getinfo | jq -M .block_height) == {110} ]]",
|
|
timeout=120,
|
|
)
|
|
|
|
# --- fund LND's on-chain wallet from the bitcoind test wallet ---
|
|
lnd_addr = op("lncli newaddress p2wkh | jq -r .address").strip()
|
|
op(f"bitcoin-cli -rpcwallet=test sendtoaddress {lnd_addr} 5")
|
|
mine_addr = op("bitcoin-cli -rpcwallet=test getnewaddress").strip()
|
|
op(f"bitcoin-cli -rpcwallet=test generatetoaddress 6 {mine_addr}")
|
|
regtest.wait_until_succeeds(
|
|
"[[ $(runuser -u operator -- lncli walletbalance | jq -M '.confirmed_balance | tonumber') -gt 0 ]]",
|
|
timeout=120,
|
|
)
|
|
|
|
# --- connect LND -> CLN and open a channel ---
|
|
cln_id = op("lightning-cli getinfo | jq -r .id").strip()
|
|
op(f"lncli connect {cln_id}@127.0.0.1:9735")
|
|
op(f"lncli openchannel --node_key={cln_id} --local_amt=1000000") # 0.01 BTC
|
|
|
|
# confirm the channel and wait for it to go active on the LND side
|
|
op(f"bitcoin-cli -rpcwallet=test generatetoaddress 6 {mine_addr}")
|
|
regtest.wait_until_succeeds(
|
|
"[[ $(runuser -u operator -- lncli listchannels | jq '[.channels[] | select(.active)] | length') -ge 1 ]]",
|
|
timeout=240,
|
|
)
|
|
|
|
# --- CLN issues an invoice, LND pays it ---
|
|
bolt11 = op(
|
|
"lightning-cli invoice 100000000 regtest-core-test 'regtest-core payment' | jq -r .bolt11"
|
|
).strip() # 100000 sat = 100,000,000 msat
|
|
op(f"lncli payinvoice --force {bolt11}")
|
|
|
|
# --- assert CLN saw the invoice settle ---
|
|
regtest.wait_until_succeeds(
|
|
"[[ $(runuser -u operator -- lightning-cli listinvoices regtest-core-test "
|
|
"| jq -r '.invoices[0].status') == paid ]]",
|
|
timeout=180,
|
|
)
|
|
|
|
print("regtest-core: LND -> CLN channel opened and invoice paid ✓")
|
|
'';
|
|
}
|