Code and benchmarking pipeline for the paper Predicting Channel Closures in the Lightning Network with Machine Learning (Antonelli et al., 2026, arXiv:2605.12759).
The task is temporal link classification: at each timestamp
uv syncAfter
uv sync, install PyG's C-extension wheels (replace+cpuwith+cu121etc. on GPU):uv pip install --no-deps \ torch-scatter torch-cluster torch-sparse torch-spline-conv \ --find-links https://data.pyg.org/whl/torch-2.5.0+cpu.html
The gossip dataset (LN events, 2022-06-09 → 2024-10-14, ~293MB CSV) is
hosted publicly on HuggingFace Datasets at
Amboss-Tech/ln-gossip
and the pipeline downloads it on first run — no authentication required.
The processed tensors are cached at
~/.cache/ln-gossip-benchmark/tgbl-ln_processed.pkl so subsequent runs
skip the parse step. Override the cache location with LN_GOSSIP_CACHE_DIR.
uv run python scripts/train.py \
model=mlp \
data.warm_start=true \
model.seed=0All paper results use the warm-start configuration, model.seed=0,1,2 with model.seed=0.
The MLP and TGN headline configs are baked into conf/model/mlp.yaml and
conf/model/temporal_gnn.yaml respectively (architecture flags are not
specified on the command line — that proved error-prone earlier).
# Random baselines
uv run python scripts/train.py \
model=random model.strategy=uniform data.warm_start=true model.seed=0,1,2 -m
uv run python scripts/train.py \
model=random model.strategy=majority data.warm_start=true model.seed=0,1,2 -m
uv run python scripts/train.py \
model=random model.strategy=stratified data.warm_start=true model.seed=0,1,2 -m
# Static (snapshot) GNN
uv run python scripts/train.py \
model=snapshot_gnn data.warm_start=true model.seed=0,1,2 -m
# TGN
uv run python scripts/train.py \
model=temporal_gnn data.warm_start=true model.seed=0,1,2 -m
# MLP + Spectral
uv run python scripts/train.py \
model=edge_predictor_spectral data.warm_start=true model.seed=0,1,2 -m
# Tabular baselines
uv run python scripts/train.py \
model=xgboost data.warm_start=true model.seed=0,1,2 -m
uv run python scripts/train.py \
model=lightgbm data.warm_start=true model.seed=0,1,2 -m
# MLP (best, paper headline — 0.38)
uv run python scripts/train.py \
model=mlp data.warm_start=true model.seed=0,1,2 -m# Time only
uv run python scripts/train.py \
model=mlp model.use_edge_features=false model.use_node_history=false \
data.warm_start=true model.seed=0,1,2 -m
# + Edge feat.
uv run python scripts/train.py \
model=mlp model.use_node_history=false \
data.warm_start=true model.seed=0,1,2 -m
# + Node feat. (== best MLP)
uv run python scripts/train.py \
model=mlp data.warm_start=true model.seed=0,1,2 -m
# Edge + Time + GNN
uv run python scripts/train.py \
model=temporal_gnn model.use_node_history=false \
data.warm_start=true model.seed=0,1,2 -m
# All + GNN (== best TGN)
uv run python scripts/train.py \
model=temporal_gnn data.warm_start=true model.seed=0,1,2 -mVary model.mlp_num_hidden_layers ∈ {0, 1, 2} for model=mlp and
model=temporal_gnn.
for dt in 30 90 180 365; do
uv run python scripts/train.py \
model=mlp \
model.ground_truth_oracle.time_window_days=$dt \
data.warm_start=true model.seed=0,1,2 -m
doneVary model.criterion.weight.data (e.g. [1,5,5], [1,1,1], [1,3,6], ...)
and/or downsampling ratio r per the paper.
uv run python scripts/train.py \
model=mlp data.warm_start=true model.seed=0 \
+model.save_model_path=checkpoints/best_mlp.pt
uv run python scripts/feature_importance.py \
+checkpoint_path=checkpoints/best_mlp.ptWeights & Biases is installed but disabled by default (we set
WANDB_MODE=disabled in the example commands). To send metrics to wandb
instead:
wandb login
unset WANDB_MODE # or `export WANDB_MODE=online`MIT.
@misc{antonelli2026predicting,
title={Predicting Channel Closures in the Lightning Network with Machine Learning},
author={Simone Antonelli and Vincent Davis and Harrison Rush and Anthony Potdevin and Jesse Shrader and Vikash Singh and Emanuele Rossi},
year={2026},
eprint={2605.12759},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2605.12759}
}