Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
25.09.3
v25.09.4
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [25.09.4] - 2025-12-01: "Hot Wallet Guardian V"

This is a recommended upgrade. Note that after upgrade: your node
will start querying bitcoind for prior blocks, which can take hours,
but will still be usable normally while that is occurring.

### Fixed

- lightningd: we could miss tx spends which happened in the past blocks when we restarted. ([#8735])

[#8735]: https://github.com/ElementsProject/lightning/pull/8735
[25.09.4]: https://github.com/ElementsProject/lightning/releases/tag/v25.09.4


## [25.09.3] - 2025-11-06: "Hot Wallet Guardian IV"

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion contrib/pyln-client/pyln/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .gossmapstats import GossmapStats
from .version import NodeVersion

__version__ = "25.09.3"
__version__ = "v25.09.4"

__all__ = [
"LightningRpc",
Expand Down
2 changes: 1 addition & 1 deletion contrib/pyln-client/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pyln-client"
version = "25.09.3"
version = "v25.09.4"
description = "Client library and plugin library for Core Lightning"
authors = [{ name = "Christian Decker", email = "[email protected]" }]
license = { text = "BSD-MIT" }
Expand Down
2 changes: 1 addition & 1 deletion contrib/pyln-proto/pyln/proto/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .onion import OnionPayload, TlvPayload, LegacyOnionPayload
from .wire import LightningConnection, LightningServerSocket

__version__ = "25.09.3"
__version__ = "v25.09.4"

__all__ = [
"Invoice",
Expand Down
2 changes: 1 addition & 1 deletion contrib/pyln-proto/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pyln-proto"
version = "25.09.3"
version = "v25.09.4"
description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)."
authors = [
{name = "Christian Decker", email = "[email protected]"}
Expand Down
2 changes: 1 addition & 1 deletion contrib/pyln-testing/pyln/testing/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "25.09.3"
__version__ = "v25.09.4"

__all__ = [
"__version__",
Expand Down
2 changes: 1 addition & 1 deletion contrib/pyln-testing/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pyln-testing"
version = "25.09.3"
version = "v25.09.4"
description = "Test your Core Lightning integration, plugins or whatever you want"
authors = [{ name = "Christian Decker", email = "[email protected]" }]
license = { text = "BSD-MIT" }
Expand Down
66 changes: 56 additions & 10 deletions lightningd/chaintopology.c
Original file line number Diff line number Diff line change
Expand Up @@ -866,8 +866,8 @@ static void updates_complete(struct chain_topology *topo)
}

static void record_wallet_spend(struct lightningd *ld,
struct bitcoin_outpoint *outpoint,
struct bitcoin_txid *txid,
const struct bitcoin_outpoint *outpoint,
const struct bitcoin_txid *txid,
u32 tx_blockheight)
{
struct utxo *utxo;
Expand All @@ -889,31 +889,34 @@ static void record_wallet_spend(struct lightningd *ld,
/**
* topo_update_spends -- Tell the wallet about all spent outpoints
*/
static void topo_update_spends(struct chain_topology *topo, struct block *b)
static void topo_update_spends(struct chain_topology *topo,
struct bitcoin_tx **txs,
const struct bitcoin_txid *txids,
u32 blockheight)
{
const struct short_channel_id *spent_scids;
const size_t num_txs = tal_count(b->full_txs);
const size_t num_txs = tal_count(txs);
for (size_t i = 0; i < num_txs; i++) {
const struct bitcoin_tx *tx = b->full_txs[i];
const struct bitcoin_tx *tx = txs[i];

for (size_t j = 0; j < tx->wtx->num_inputs; j++) {
struct bitcoin_outpoint outpoint;

bitcoin_tx_input_get_outpoint(tx, j, &outpoint);

if (wallet_outpoint_spend(tmpctx, topo->ld->wallet,
b->height, &outpoint))
blockheight, &outpoint))
record_wallet_spend(topo->ld, &outpoint,
&b->txids[i], b->height);
&txids[i], blockheight);

}
}

/* Retrieve all potential channel closes from the UTXO set and
* tell gossipd about them. */
spent_scids =
wallet_utxoset_get_spent(tmpctx, topo->ld->wallet, b->height);
gossipd_notify_spends(topo->bitcoind->ld, b->height, spent_scids);
wallet_utxoset_get_spent(tmpctx, topo->ld->wallet, blockheight);
gossipd_notify_spends(topo->bitcoind->ld, blockheight, spent_scids);
}

static void topo_add_utxos(struct chain_topology *topo, struct block *b)
Expand Down Expand Up @@ -960,7 +963,7 @@ static void add_tip(struct chain_topology *topo, struct block *b)
trace_span_end(b);

trace_span_start("topo_update_spends", b);
topo_update_spends(topo, b);
topo_update_spends(topo, b->full_txs, b->txids, b->height);
trace_span_end(b);

/* Only keep the transactions we care about. */
Expand Down Expand Up @@ -1369,6 +1372,7 @@ void setup_topology(struct chain_topology *topo)
struct bitcoin_block *blk;
bool blockscan_start_set;
u32 blockscan_start;
s64 fixup;

/* This waits for bitcoind. */
bitcoind_check_commands(topo->bitcoind);
Expand All @@ -1394,6 +1398,15 @@ void setup_topology(struct chain_topology *topo)
blockscan_start = blocknum_reduce(blockscan_start, topo->ld->config.rescan);
}

fixup = db_get_intvar(topo->ld->wallet->db, "fixup_block_scan", -1);
if (fixup == -1) {
/* Never done fixup: this is set to non-zero if we have blocks. */
topo->old_block_scan = wallet_blocks_minheight(topo->ld->wallet);
db_set_intvar(topo->ld->wallet->db, "fixup_block_scan",
topo->old_block_scan);
} else {
topo->old_block_scan = fixup;
}
db_commit_transaction(topo->ld->wallet->db);

/* Sanity checks, then topology initialization. */
Expand Down Expand Up @@ -1485,6 +1498,36 @@ void setup_topology(struct chain_topology *topo)
tal_add_destructor(topo, destroy_chain_topology);
}

static void fixup_scan_block(struct bitcoind *bitcoind,
u32 height,
struct bitcoin_blkid *blkid,
struct bitcoin_block *blk,
struct chain_topology *topo)
{
log_debug(topo->ld->log, "fixup_scan: block %u with %zu txs", height, tal_count(blk->tx));
topo_update_spends(topo, blk->tx, blk->txids, height);

/* Caught up. */
if (height == get_block_height(topo)) {
log_info(topo->ld->log, "Scanning for missed UTXOs finished");
db_set_intvar(topo->ld->wallet->db, "fixup_block_scan", 0);
return;
}

db_set_intvar(topo->ld->wallet->db, "fixup_block_scan", ++topo->old_block_scan);
bitcoind_getrawblockbyheight(topo, topo->bitcoind,
topo->old_block_scan,
fixup_scan_block, topo);
}

static void fixup_scan(struct chain_topology *topo)
{
log_info(topo->ld->log, "Scanning for missed UTXOs from block %u", topo->old_block_scan);
bitcoind_getrawblockbyheight(topo, topo->bitcoind,
topo->old_block_scan,
fixup_scan_block, topo);
}

void begin_topology(struct chain_topology *topo)
{
/* If we were not synced, start looping to check */
Expand All @@ -1494,6 +1537,9 @@ void begin_topology(struct chain_topology *topo)
start_fee_estimate(topo);
/* Regular block updates */
try_extend_tip(topo);

if (topo->old_block_scan)
fixup_scan(topo);
}

void stop_topology(struct chain_topology *topo)
Expand Down
3 changes: 3 additions & 0 deletions lightningd/chaintopology.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ struct chain_topology {
/* The number of headers known to the bitcoin backend at startup. Not
* updated after the initial check. */
u32 headercount;

/* Progress on routine to look for old missed transactions. 0 = not interested. */
u32 old_block_scan;
};

/* Information relevant to locating a TX in a blockchain. */
Expand Down
Binary file added tests/data/l3-missing-utxo.sqlite3.xz
Binary file not shown.
Loading
Loading