From 9d76481ccc402b6372923b4bfb566bcc27a76e64 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 18 Sep 2025 20:17:50 +0930 Subject: [PATCH 01/25] pytest: test for splicing while channel is not announced yet. ``` DEBUG lightningd: Got depth change 2->3 for e9e31956f77c3844ee2e6e4607dbfebdee95a9aa549668a7a429b8246a6a29de **BROKEN** lightningd: FATAL SIGNAL 6 (version v25.09-20-g003ba4a) **BROKEN** lightningd: backtrace: common/daemon.c:41 (send_backtrace) 0x619bef20e274 **BROKEN** lightningd: backtrace: common/daemon.c:78 (crashdump) 0x619bef20e408 **BROKEN** lightningd: backtrace: ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0 ((null)) 0x7a1ccf24532f **BROKEN** lightningd: backtrace: ./nptl/pthread_kill.c:44 (__pthread_kill_implementation) 0x7a1ccf29eb2c **BROKEN** lightningd: backtrace: ./nptl/pthread_kill.c:78 (__pthread_kill_internal) 0x7a1ccf29eb2c **BROKEN** lightningd: backtrace: ./nptl/pthread_kill.c:89 (__GI___pthread_kill) 0x7a1ccf29eb2c **BROKEN** lightningd: backtrace: ../sysdeps/posix/raise.c:26 (__GI_raise) 0x7a1ccf24527d **BROKEN** lightningd: backtrace: ./stdlib/abort.c:79 (__GI_abort) 0x7a1ccf2288fe **BROKEN** lightningd: backtrace: ./assert/assert.c:96 (__assert_fail_base) 0x7a1ccf22881a **BROKEN** lightningd: backtrace: ./assert/assert.c:105 (__assert_fail) 0x7a1ccf23b516 **BROKEN** lightningd: backtrace: lightningd/peer_control.c:2202 (funding_depth_cb) 0x619bef1ac497 **BROKEN** lightningd: backtrace: lightningd/watch.c:223 (txw_fire) 0x619bef1cfcbf **BROKEN** lightningd: backtrace: lightningd/watch.c:292 (watch_topology_changed) 0x619bef1cffa4 **BROKEN** lightningd: backtrace: lightningd/chaintopology.c:829 (updates_complete) 0x619bef144a8c **BROKEN** lightningd: backtrace: lightningd/chaintopology.c:1047 (get_new_block) 0x619bef14561e ``` Signed-off-by: Rusty Russell --- tests/test_splicing.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/test_splicing.py b/tests/test_splicing.py index 4974b91410af..f9eb6f05b741 100644 --- a/tests/test_splicing.py +++ b/tests/test_splicing.py @@ -551,3 +551,30 @@ def test_route_by_old_scid(node_factory, bitcoind): wait_for(lambda: only_one(l1.rpc.listpeers()['peers'])['connected'] is True) l1.rpc.sendpay(route, inv2['payment_hash'], payment_secret=inv2['payment_secret']) l1.rpc.waitsendpay(inv2['payment_hash']) + + +@pytest.mark.xfail(strict=True) +def test_splice_unannounced(node_factory, bitcoind): + l1, l2 = node_factory.line_graph(2, fundamount=1000000, wait_for_announce=False, opts={'experimental-splicing': None}) + + chan_id = l1.get_channel_id(l2) + + # add extra sats to pay fee + funds_result = l1.rpc.fundpsbt("109000sat", "slow", 166, excess_as_change=True) + result = l1.rpc.splice_init(chan_id, 100000, funds_result['psbt']) + result = l1.rpc.splice_update(chan_id, result['psbt']) + assert(result['commitments_secured'] is False) + result = l1.rpc.splice_update(chan_id, result['psbt']) + assert(result['commitments_secured'] is True) + result = l1.rpc.signpsbt(result['psbt']) + result = l1.rpc.splice_signed(chan_id, result['signed_psbt']) + + l2.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE') + l1.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE') + + bitcoind.generate_block(1, wait_for_mempool=1) + + l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + bitcoind.generate_block(1) + sync_blockheight(bitcoind, [l1, l2]) From 40675ffdf83e29219dd37802b83afce40b40f337 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 18 Sep 2025 20:17:52 +0930 Subject: [PATCH 02/25] lightningd: cancel watching original funding when we switch to the new one via splice. This happens if the channel is *not* announcable yet. Then we hit the assertion in funding_depth_cb that the txid is the same as the current funding.txid. Signed-off-by: Rusty Russell Changelog-EXPERIMENTAL: fixed crash when we splice a channel which hasn't been announced yet. --- lightningd/channel_control.c | 5 ++++- lightningd/peer_control.c | 8 ++++++++ lightningd/peer_control.h | 1 + lightningd/test/run-invoice-select-inchan.c | 10 ++++++++++ tests/test_splicing.py | 3 ++- wallet/test/run-wallet.c | 10 ++++++++++ 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index a72f959837ae..b291816f2cff 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -1134,7 +1134,8 @@ static void handle_peer_splice_locked(struct channel *channel, const u8 *msg) wallet_htlcsigs_confirm_inflight(channel->peer->ld->wallet, channel, &inflight->funding->outpoint); - update_channel_from_inflight(channel->peer->ld, channel, inflight, true); + /* Stop watching previous funding tx (could be, for announcement) */ + channel_unwatch_funding(channel->peer->ld, channel); /* Stash prev funding data so we can log it after scid is updated * (to get the blockheight) */ @@ -1142,6 +1143,8 @@ static void handle_peer_splice_locked(struct channel *channel, const u8 *msg) prev_funding_sats = channel->funding_sats; prev_funding_out = channel->funding; + update_channel_from_inflight(channel->peer->ld, channel, inflight, true); + channel->our_msat.millisatoshis += splice_amnt * 1000; /* Raw: splicing */ channel->msat_to_us_min.millisatoshis += splice_amnt * 1000; /* Raw: splicing */ channel->msat_to_us_max.millisatoshis += splice_amnt * 1000; /* Raw: splicing */ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 35b88089991f..72968efc1083 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -2351,6 +2351,14 @@ void channel_watch_wrong_funding(struct lightningd *ld, struct channel *channel) } } +/* We need to do this before we change channel funding (for splice), otherwise + * funding_depth_cb will fail the assertion that it's the current funding tx */ +void channel_unwatch_funding(struct lightningd *ld, struct channel *channel) +{ + tal_free(find_txwatch(ld->topology, + &channel->funding.txid, funding_depth_cb, channel)); +} + void channel_watch_funding(struct lightningd *ld, struct channel *channel) { log_debug(channel->log, "Watching for funding txid: %s", diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 2a28183fdace..a27dff9fbb11 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -131,6 +131,7 @@ void update_channel_from_inflight(struct lightningd *ld, const struct channel_inflight *inflight, bool is_splice); +void channel_unwatch_funding(struct lightningd *ld, struct channel *channel); void channel_watch_funding(struct lightningd *ld, struct channel *channel); /* If this channel has a "wrong funding" shutdown, watch that too. */ diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index fc7c642496ab..3262d9a5bafc 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -291,6 +291,16 @@ struct channel *find_channel_by_id(const struct peer *peer UNNEEDED, struct plugin *find_plugin_for_command(struct lightningd *ld UNNEEDED, const char *cmd_name UNNEEDED) { fprintf(stderr, "find_plugin_for_command called!\n"); abort(); } +/* Generated stub for find_txwatch_ */ +struct txwatch *find_txwatch_(struct chain_topology *topo UNNEEDED, + const struct bitcoin_txid *txid UNNEEDED, + enum watch_result (*cb)(struct lightningd *ld UNNEEDED, + const struct bitcoin_txid * UNNEEDED, + const struct bitcoin_tx * UNNEEDED, + unsigned int depth UNNEEDED, + void *arg) UNNEEDED, + void *arg UNNEEDED) +{ fprintf(stderr, "find_txwatch_ called!\n"); abort(); } /* Generated stub for fixup_htlcs_out */ void fixup_htlcs_out(struct lightningd *ld UNNEEDED) { fprintf(stderr, "fixup_htlcs_out called!\n"); abort(); } diff --git a/tests/test_splicing.py b/tests/test_splicing.py index f9eb6f05b741..a2b4c8f43f51 100644 --- a/tests/test_splicing.py +++ b/tests/test_splicing.py @@ -553,7 +553,8 @@ def test_route_by_old_scid(node_factory, bitcoind): l1.rpc.waitsendpay(inv2['payment_hash']) -@pytest.mark.xfail(strict=True) +@pytest.mark.openchannel('v1') +@pytest.mark.openchannel('v2') def test_splice_unannounced(node_factory, bitcoind): l1, l2 = node_factory.line_graph(2, fundamount=1000000, wait_for_announce=False, opts={'experimental-splicing': None}) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index c1cd3b066f25..a334808d1e15 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -264,6 +264,16 @@ void fatal(const char *fmt UNNEEDED, ...) /* Generated stub for fatal_vfmt */ void fatal_vfmt(const char *fmt UNNEEDED, va_list ap UNNEEDED) { fprintf(stderr, "fatal_vfmt called!\n"); abort(); } +/* Generated stub for find_txwatch_ */ +struct txwatch *find_txwatch_(struct chain_topology *topo UNNEEDED, + const struct bitcoin_txid *txid UNNEEDED, + enum watch_result (*cb)(struct lightningd *ld UNNEEDED, + const struct bitcoin_txid * UNNEEDED, + const struct bitcoin_tx * UNNEEDED, + unsigned int depth UNNEEDED, + void *arg) UNNEEDED, + void *arg UNNEEDED) +{ fprintf(stderr, "find_txwatch_ called!\n"); abort(); } /* Generated stub for force_peer_disconnect */ void force_peer_disconnect(struct lightningd *ld UNNEEDED, const struct peer *peer UNNEEDED, From 57e27bf7c72cc9389cc235468d9d482e54374d73 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 18 Sep 2025 20:20:11 +0930 Subject: [PATCH 03/25] lightningd: fix crash in channel_control. I got a NULL deref on `infcopy->remote_funding = *inflight->funding->splice_remote_funding` at once point in testing, so this should prevent that from happening. Signed-off-by: Rusty Russell --- lightningd/channel_control.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index b291816f2cff..d44e03323ba6 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -1827,6 +1827,9 @@ bool peer_start_channeld(struct channel *channel, if (inflight->splice_locked_memonly) continue; + if (!inflight->funding->splice_remote_funding) + continue; + infcopy = tal(inflights, struct inflight); infcopy->remote_funding = *inflight->funding->splice_remote_funding; From 4c54f5aef7a72e19eb9c895210178a4cba9f2b7c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:55:09 +0930 Subject: [PATCH 04/25] pytest: add test that we notice height change of sendpsbt with no change. Signed-off-by: Rusty Russell --- tests/test_wallet.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 63ddba2f1abe..a007b04ebcdc 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -1884,3 +1884,32 @@ def test_onchain_missing_no_p2tr_migrate(node_factory, bitcoind): # This can actually take a while for 100 blocks! l2.daemon.wait_for_log('Rescan finished! 1 outputs recovered') + + +@pytest.mark.xfail(strict=True) +@pytest.mark.parametrize("restart", [False, True]) +def test_sendpsbt_confirm(node_factory, bitcoind, restart): + """We should see our sendpsbt in wallet, and that it gets confirmed""" + l1, l2 = node_factory.get_nodes(2) + l1.fundwallet(100000) + + psbt = l1.rpc.fundpsbt(satoshi=10000, + feerate=7500, + startweight=42)['psbt'] + psbt = l2.rpc.addpsbtoutput(10000, psbt)['psbt'] + psbt = l1.rpc.signpsbt(psbt)['signed_psbt'] + sent = l1.rpc.sendpsbt(psbt) + + # Unconfirmed + lt = only_one([t for t in l1.rpc.listtransactions()['transactions'] if t['rawtx'] == sent['tx']]) + assert lt['blockheight'] == 0 + + if restart: + l1.restart() + + bitcoind.generate_block(1, wait_for_mempool=sent['txid']) + sync_blockheight(bitcoind, [l1]) + + # Should be confirmed now! + lt = only_one([t for t in l1.rpc.listtransactions()['transactions'] if t['rawtx'] == sent['tx']]) + assert lt['blockheight'] == bitcoind.rpc.getblockcount() From 349484964beb76b133eff6efa98eb9502bf2e08b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:55:17 +0930 Subject: [PATCH 05/25] wallet: make sure to watch all txids in transactions table. We watch if they are to do with a channel, or have outputs going to us, but otherwise we didn't, so we never updated the blockheight in the db. Signed-off-by: Rusty Russell Changelog-Fixed: JSON-RPC: `listtransactions` now correctly updates `blockheight` for txs created by `sendpsbt` which have no change outputs. --- lightningd/chaintopology.c | 37 +++++++++++++++++++++++++++++++++++++ lightningd/chaintopology.h | 8 ++++++++ tests/test_wallet.py | 1 - wallet/wallet.c | 13 ++++++++++--- wallet/walletrpc.c | 9 ++++++--- 5 files changed, 61 insertions(+), 7 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 59f004f732a7..7d02e9245395 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -356,6 +356,37 @@ static void watch_for_utxo_reconfirmation(struct chain_topology *topo, } } +static enum watch_result tx_confirmed(struct lightningd *ld, + const struct bitcoin_txid *txid, + const struct bitcoin_tx *tx, + unsigned int depth, + void *unused) +{ + /* We don't actually need to do anything here: the fact that we were + * watching the tx made chaintopology.c update the transaction depth */ + if (depth != 0) + return DELETE_WATCH; + return KEEP_WATCHING; +} + +void watch_unconfirmed_txid(struct lightningd *ld, + struct chain_topology *topo, + const struct bitcoin_txid *txid) +{ + watch_txid(ld->wallet, topo, txid, tx_confirmed, NULL); +} + +static void watch_for_unconfirmed_txs(struct lightningd *ld, + struct chain_topology *topo) +{ + struct bitcoin_txid *txids; + + txids = wallet_transactions_by_height(tmpctx, ld->wallet, 0); + log_debug(ld->log, "Got %zu unconfirmed transactions", tal_count(txids)); + for (size_t i = 0; i < tal_count(txids); i++) + watch_unconfirmed_txid(ld, topo, &txids[i]); +} + /* Mutual recursion via timer. */ static void next_updatefee_timer(struct chain_topology *topo); @@ -1028,6 +1059,7 @@ static void remove_tip(struct chain_topology *topo) /* This may have unconfirmed txs: reconfirm as we add blocks. */ watch_for_utxo_reconfirmation(topo, topo->ld->wallet); + block_map_del(topo->block_map, b); /* These no longer exist, so gossipd drops any reference to them just @@ -1478,6 +1510,11 @@ void setup_topology(struct chain_topology *topo) /* May have unconfirmed txs: reconfirm as we add blocks. */ watch_for_utxo_reconfirmation(topo, topo->ld->wallet); + + /* We usually watch txs because we have outputs coming to us, or they're + * related to a channel. But not if they're created by sendpsbt without any + * outputs to us. */ + watch_for_unconfirmed_txs(topo->ld, topo); db_commit_transaction(topo->ld->wallet->db); tal_free(local_ctx); diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index 4f80d21622a8..8a867b0e21f1 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -12,6 +12,7 @@ struct command; struct lightningd; struct peer; struct txwatch; +struct wallet; /* We keep the last three in case there are outliers (for min/max) */ #define FEE_HISTORY_NUM 3 @@ -280,4 +281,11 @@ void topology_add_sync_waiter_(const tal_t *ctx, /* In channel_control.c */ void notify_feerate_change(struct lightningd *ld); + +/* We want to update db when this txid is confirmed. We always do this + * if it's related to a channel or incoming funds, but sendpsbt without + * change would be otherwise untracked. */ +void watch_unconfirmed_txid(struct lightningd *ld, + struct chain_topology *topo, + const struct bitcoin_txid *txid); #endif /* LIGHTNING_LIGHTNINGD_CHAINTOPOLOGY_H */ diff --git a/tests/test_wallet.py b/tests/test_wallet.py index a007b04ebcdc..e00e3199cfac 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -1886,7 +1886,6 @@ def test_onchain_missing_no_p2tr_migrate(node_factory, bitcoind): l2.daemon.wait_for_log('Rescan finished! 1 outputs recovered') -@pytest.mark.xfail(strict=True) @pytest.mark.parametrize("restart", [False, True]) def test_sendpsbt_confirm(node_factory, bitcoind, restart): """We should see our sendpsbt in wallet, and that it gets confirmed""" diff --git a/wallet/wallet.c b/wallet/wallet.c index ddc933d70ced..4e18d453c336 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -5165,9 +5165,16 @@ struct bitcoin_txid *wallet_transactions_by_height(const tal_t *ctx, struct db_stmt *stmt; struct bitcoin_txid *txids = tal_arr(ctx, struct bitcoin_txid, 0); int count = 0; - stmt = db_prepare_v2( - w->db, SQL("SELECT id FROM transactions WHERE blockheight=?")); - db_bind_int(stmt, blockheight); + + /* Note: blockheight=NULL is not the same as is NULL! */ + if (blockheight == 0) { + stmt = db_prepare_v2( + w->db, SQL("SELECT id FROM transactions WHERE blockheight IS NULL")); + } else { + stmt = db_prepare_v2( + w->db, SQL("SELECT id FROM transactions WHERE blockheight=?")); + db_bind_int(stmt, blockheight); + } db_query_prepared(stmt); while (db_step(stmt)) { diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 677db8bab66f..ab011b553b4c 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -953,7 +953,6 @@ static void maybe_notify_new_external_send(struct lightningd *ld, wallet_save_chain_mvt(ld, take(mvt)); } - static void sendpsbt_done(struct bitcoind *bitcoind UNUSED, bool success, const char *msg, struct sending_psbt *sending) @@ -985,10 +984,14 @@ static void sendpsbt_done(struct bitcoind *bitcoind UNUSED, } wallet_transaction_add(ld->wallet, sending->wtx, 0, 0); + wally_txid(sending->wtx, &txid); /* Extract the change output and add it to the DB */ - wallet_extract_owned_outputs(ld->wallet, sending->wtx, false, NULL); - wally_txid(sending->wtx, &txid); + if (wallet_extract_owned_outputs(ld->wallet, sending->wtx, false, NULL) == 0) { + /* If we're not watching it for selfish reasons (i.e. pure send to + * others), make sure we're watching it so we can update depth in db */ + watch_unconfirmed_txid(ld, ld->topology, &txid); + } for (size_t i = 0; i < sending->psbt->num_outputs; i++) maybe_notify_new_external_send(ld, &txid, i, sending->psbt); From 20b79f7ca02a9318ab66c7491308c6a5c9fae6c6 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:55:42 +0930 Subject: [PATCH 06/25] memleak: make notleak() work even before memleak is initalized. It now simply renames tal names, so it's harmless to do even if we're not going to do memleak detection. Signed-off-by: Rusty Russell --- cli/Makefile | 1 + common/configdir.c | 4 ++-- common/memleak.c | 12 +++++------- common/trace.c | 6 +----- tools/Makefile | 2 +- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/cli/Makefile b/cli/Makefile index 82dea907ea61..05c07100d9d1 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -10,6 +10,7 @@ LIGHTNING_CLI_COMMON_OBJS := \ common/configdir.o \ common/configvar.o \ common/json_parse_simple.o \ + common/memleak.o \ common/status_levels.o \ common/utils.o \ common/version.o diff --git a/common/configdir.c b/common/configdir.c index 248c8e73e010..0926c44fd569 100644 --- a/common/configdir.c +++ b/common/configdir.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -36,8 +37,7 @@ static char *opt_set_abspath(const char *arg, char **p) /* Tal wrappers for opt. */ static void *opt_allocfn(size_t size) { - return tal_arr_label(NULL, char, size, - TAL_LABEL(opt_allocfn_notleak, "")); + return notleak(tal_arr(NULL, char, size)); } static void *tal_reallocfn(void *ptr, size_t size) diff --git a/common/memleak.c b/common/memleak.c index 7ac0da7c7bf3..de321a9a7c66 100644 --- a/common/memleak.c +++ b/common/memleak.c @@ -58,9 +58,6 @@ struct tal_backtrace { void *notleak_(void *ptr, bool plus_children) { const char *name; - /* If we're not tracking, don't do anything. */ - if (!memleak_track) - return cast_const(void *, ptr); /* We use special tal names to mark notleak */ name = tal_name(ptr); @@ -69,12 +66,14 @@ void *notleak_(void *ptr, bool plus_children) /* Don't mark more than once! */ if (!strstr(name, "**NOTLEAK")) { + /* Don't use tmpctx: it might not be set up yet! */ if (plus_children) - name = tal_fmt(tmpctx, "%s **NOTLEAK_IGNORE_CHILDREN**", + name = tal_fmt(NULL, "%s **NOTLEAK_IGNORE_CHILDREN**", name); else - name = tal_fmt(tmpctx, "%s **NOTLEAK**", name); + name = tal_fmt(NULL, "%s **NOTLEAK**", name); tal_set_name(ptr, name); + tal_free(name); } return cast_const(void *, ptr); @@ -331,8 +330,7 @@ static void call_memleak_helpers(struct htable *memtable, const tal_t *p) if (strends(name, "struct memleak_helper")) { const struct memleak_helper *mh = i; mh->cb(memtable, p); - } else if (strends(name, " **NOTLEAK**") - || strends(name, "_notleak")) { + } else if (strends(name, " **NOTLEAK**")) { memleak_ptr(memtable, i); memleak_scan_obj(memtable, i); } else if (strends(name, diff --git a/common/trace.c b/common/trace.c index eade3171f790..f64faa0ef440 100644 --- a/common/trace.c +++ b/common/trace.c @@ -184,15 +184,11 @@ static inline void trace_check_tree(void) {} static void trace_init(void) { const char *dev_trace_file; - const char notleak_name[] = "struct span **NOTLEAK**"; if (active_spans) return; - active_spans = tal_arrz(NULL, struct span, 1); - /* We're usually too early for memleak to be initialized, so mark - * this notleak manually! */ - tal_set_name(active_spans, notleak_name); + active_spans = notleak(tal_arrz(NULL, struct span, 1)); current = NULL; dev_trace_file = getenv("CLN_DEV_TRACE_FILE"); diff --git a/tools/Makefile b/tools/Makefile index 6b92ebdd5555..3922ce0c8566 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -18,7 +18,7 @@ tools/headerversions: $(FORCE) tools/headerversions.o libccan.a tools/headerversions.o: ccan/config.h tools/check-bolt: tools/check-bolt.o $(TOOLS_COMMON_OBJS) -tools/hsmtool: tools/hsmtool.o $(TOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/amount.o common/autodata.o common/bech32.o common/bech32_util.o common/bigsize.o common/codex32.o common/configdir.o common/configvar.o common/derive_basepoints.o common/descriptor_checksum.o common/hsm_encryption.o common/key_derive.o common/node_id.o common/version.o wire/fromwire.o wire/towire.o +tools/hsmtool: tools/hsmtool.o $(TOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/amount.o common/autodata.o common/bech32.o common/bech32_util.o common/bigsize.o common/codex32.o common/configdir.o common/configvar.o common/derive_basepoints.o common/descriptor_checksum.o common/hsm_encryption.o common/key_derive.o common/node_id.o common/version.o common/memleak.o wire/fromwire.o wire/towire.o tools/lightning-hsmtool: tools/hsmtool cp $< $@ From faa4b6fabf7fc8298175b6c43c19f3e96568723a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:55:43 +0930 Subject: [PATCH 07/25] common: add new_htable() macro to allocate, initialize and setup memleak coverage for any typed hash table. You can now simply add per-tal-object helpers for memleak, but our older pattern required calling memleak functions explicitly during memleak handling. Hash tables in particular need to be dynamically allocated (we override the allocators using htable_set_allocator and assume this), so it makes sense to have a helper macro that does all three. This eliminates a huge amount of code. Signed-off-by: Rusty Russell --- channeld/full_channel.c | 14 +++----------- common/memleak.h | 12 ++++++++++++ connectd/connectd.c | 27 +++++++-------------------- gossipd/gossipd.c | 4 +--- lightningd/chaintopology.c | 12 ++++-------- lightningd/lightningd.c | 24 ++++++++---------------- lightningd/memdump.c | 13 ------------- lightningd/onchain_control.c | 12 +----------- plugins/askrene/askrene.c | 8 -------- plugins/askrene/layer.c | 23 ++++------------------- plugins/askrene/layer.h | 2 -- plugins/askrene/reserve.c | 9 +-------- plugins/askrene/reserve.h | 2 -- plugins/chanbackup.c | 17 ++--------------- plugins/channel_hint.c | 10 +--------- wallet/test/run-db.c | 4 ---- wallet/test/run-wallet.c | 4 ---- wallet/txfilter.c | 8 +------- wallet/txfilter.h | 3 --- wallet/wallet.c | 10 +--------- wallet/wallet.h | 4 ---- 21 files changed, 46 insertions(+), 176 deletions(-) diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 699ccdf40ca4..cf27c69c11ad 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -17,12 +17,6 @@ /* Needs to be at end, since it doesn't include its own hdrs */ #include "full_channel_error_names_gen.h" -static void memleak_help_htlcmap(struct htable *memtable, - struct htlc_map *htlcs) -{ - memleak_scan_htable(memtable, &htlcs->raw); -} - /* This is a dangerous thing! Because we apply HTLCs in many places * in bulk, we can temporarily go negative. You must check balance_ok() * at the end! */ @@ -113,11 +107,9 @@ struct channel *new_full_channel(const tal_t *ctx, option_wumbo, opener); - if (channel) { - channel->htlcs = tal(channel, struct htlc_map); - htlc_map_init(channel->htlcs); - memleak_add_helper(channel->htlcs, memleak_help_htlcmap); - } + if (channel) + channel->htlcs = new_htable(channel, htlc_map); + return channel; } diff --git a/common/memleak.h b/common/memleak.h index a15413b23f34..b9782e651ceb 100644 --- a/common/memleak.h +++ b/common/memleak.h @@ -109,6 +109,18 @@ void memleak_scan_region(struct htable *memtable, const void *p, size_t len); /* Objects inside this htable (which is opaque to memleak) are not leaks. */ void memleak_scan_htable(struct htable *memtable, const struct htable *ht); +/* Allocate a htable, set up memleak scan automatically (assumes &p->raw == p) */ +#define new_htable(ctx, type) \ + ({ \ + const struct htable *raw; \ + struct type *p = tal(ctx, struct type); \ + type##_init(p); \ + raw = &p->raw; \ + assert((void *)raw == (void *)p); \ + memleak_add_helper(raw, memleak_scan_htable); \ + p; \ + }) + /* Objects inside this uintmap (which is opaque to memleak) are not leaks. */ #define memleak_scan_uintmap(memtable, umap) \ memleak_scan_intmap_(memtable, uintmap_unwrap_(umap)) diff --git a/connectd/connectd.c b/connectd/connectd.c index de841c3ff3c1..f0638eb887d7 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -2004,9 +2004,6 @@ static void dev_connect_memleak(struct daemon *daemon, const u8 *msg) /* Now delete daemon and those which it has pointers to. */ memleak_scan_obj(memtable, daemon); - memleak_scan_htable(memtable, &daemon->peers->raw); - memleak_scan_htable(memtable, &daemon->scid_htable->raw); - memleak_scan_htable(memtable, &daemon->important_ids->raw); found_leak = dump_memleak(memtable, memleak_status_broken, NULL); daemon_conn_send(daemon->master, @@ -2419,14 +2416,6 @@ static struct io_plan *recv_gossip(struct io_conn *conn, return daemon_conn_read_next(conn, daemon->gossipd); } -/*~ This is a hook used by the memleak code: it can't see pointers - * inside hash tables, so we give it a hint here. */ -static void memleak_daemon_cb(struct htable *memtable, struct daemon *daemon) -{ - memleak_scan_htable(memtable, &daemon->peers->raw); - memleak_scan_htable(memtable, &daemon->connecting->raw); -} - static void gossipd_failed(struct daemon_conn *gossipd) { status_failed(STATUS_FAIL_GOSSIP_IO, "gossipd exited?"); @@ -2446,14 +2435,13 @@ int main(int argc, char *argv[]) daemon = tal(NULL, struct daemon); daemon->developer = developer; daemon->connection_counter = 1; - daemon->peers = tal(daemon, struct peer_htable); + /* htable_new is our helper which allocates a htable, initializes it + * and set up the memleak callback so our memleak code can see objects + * inside it */ + daemon->peers = new_htable(daemon, peer_htable); daemon->listeners = tal_arr(daemon, struct io_listener *, 0); - peer_htable_init(daemon->peers); - memleak_add_helper(daemon, memleak_daemon_cb); - daemon->connecting = tal(daemon, struct connecting_htable); - connecting_htable_init(daemon->connecting); - daemon->important_ids = tal(daemon, struct important_id_htable); - important_id_htable_init(daemon->important_ids); + daemon->connecting = new_htable(daemon, connecting_htable); + daemon->important_ids = new_htable(daemon, important_id_htable); timers_init(&daemon->timers, time_mono()); daemon->gossmap_raw = NULL; daemon->shutting_down = false; @@ -2463,8 +2451,7 @@ int main(int argc, char *argv[]) daemon->dev_exhausted_fds = false; /* We generally allow 1MB per second per peer, except for dev testing */ daemon->gossip_stream_limit = 1000000; - daemon->scid_htable = tal(daemon, struct scid_htable); - scid_htable_init(daemon->scid_htable); + daemon->scid_htable = new_htable(daemon, scid_htable); /* stdin == control */ daemon->master = daemon_conn_new(daemon, STDIN_FILENO, recv_req, NULL, diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 41807050806f..40bfe551fa9e 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -479,7 +479,6 @@ static void dev_gossip_memleak(struct daemon *daemon, const u8 *msg) memleak_ptr(memtable, msg); /* Now delete daemon and those which it has pointers to. */ memleak_scan_obj(memtable, daemon); - memleak_scan_htable(memtable, &daemon->peers->raw); dev_seeker_memleak(memtable, daemon->seeker); gossmap_manage_memleak(memtable, daemon->gm); @@ -632,8 +631,7 @@ int main(int argc, char *argv[]) daemon = tal(NULL, struct daemon); daemon->developer = developer; daemon->dev_gossip_time = NULL; - daemon->peers = tal(daemon, struct peer_node_id_map); - peer_node_id_map_init(daemon->peers); + daemon->peers = new_htable(daemon, peer_node_id_map); daemon->deferred_txouts = tal_arr(daemon, struct short_channel_id, 0); daemon->current_blockheight = 0; /* i.e. unknown */ diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 7d02e9245395..5214b490ed0e 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -1229,14 +1229,10 @@ struct chain_topology *new_topology(struct lightningd *ld, struct logger *log) struct chain_topology *topo = tal(ld, struct chain_topology); topo->ld = ld; - topo->block_map = tal(topo, struct block_map); - block_map_init(topo->block_map); - topo->outgoing_txs = tal(topo, struct outgoing_tx_map); - outgoing_tx_map_init(topo->outgoing_txs); - topo->txwatches = tal(topo, struct txwatch_hash); - txwatch_hash_init(topo->txwatches); - topo->txowatches = tal(topo, struct txowatch_hash); - txowatch_hash_init(topo->txowatches); + topo->block_map = new_htable(topo, block_map); + topo->outgoing_txs = new_htable(topo, outgoing_tx_map); + topo->txwatches = new_htable(topo, txwatch_hash); + topo->txowatches = new_htable(topo, txowatch_hash); topo->log = log; topo->bitcoind = new_bitcoind(topo, ld, log); topo->poll_seconds = 30; diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 1c3fb7e4d77a..3ed15f9a6664 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -190,42 +190,34 @@ static struct lightningd *new_lightningd(const tal_t *ctx) * list attached to the channel structure itself, or even left them in * the database rather than making an in-memory version. Obviously * I was in a premature optimization mood when I wrote this: */ - ld->htlcs_in = tal(ld, struct htlc_in_map); - htlc_in_map_init(ld->htlcs_in); + ld->htlcs_in = new_htable(ld, htlc_in_map); /*~ Note also: we didn't need to use an allocation here! We could * have simply made the `struct htlc_out_map` a member. But we * override the htable allocation routines to use tal(), and they * want a tal parent, so we always make our hash table a tallocated * object. */ - ld->htlcs_out = tal(ld, struct htlc_out_map); - htlc_out_map_init(ld->htlcs_out); + ld->htlcs_out = new_htable(ld, htlc_out_map); /*~ This is the hash table of peers: converted from a * linked-list as part of the 100k-peers project! */ - ld->peers = tal(ld, struct peer_node_id_map); - peer_node_id_map_init(ld->peers); + ld->peers = new_htable(ld, peer_node_id_map); /*~ And this was done at the same time, for db lookups at startup */ - ld->peers_by_dbid = tal(ld, struct peer_dbid_map); - peer_dbid_map_init(ld->peers_by_dbid); + ld->peers_by_dbid = new_htable(ld, peer_dbid_map); /*~ This speeds lookups for short_channel_ids to their channels. */ - ld->channels_by_scid = tal(ld, struct channel_scid_map); - channel_scid_map_init(ld->channels_by_scid); + ld->channels_by_scid = new_htable(ld, channel_scid_map); /*~ Coin movements in db are indexed by the channel dbid. */ - ld->channels_by_dbid = tal(ld, struct channel_dbid_map); - channel_dbid_map_init(ld->channels_by_dbid); + ld->channels_by_dbid = new_htable(ld, channel_dbid_map); /*~ For multi-part payments, we need to keep some incoming payments * in limbo until we get all the parts, or we time them out. */ - ld->htlc_sets = tal(ld, struct htlc_set_map); - htlc_set_map_init(ld->htlc_sets); + ld->htlc_sets = new_htable(ld, htlc_set_map); /*~ We keep a map of closed channels. Mainly so we can respond to peers * who talk to us about long-closed channels. */ - ld->closed_channels = tal(ld, struct closed_channel_map); - closed_channel_map_init(ld->closed_channels); + ld->closed_channels = new_htable(ld, closed_channel_map); /*~ We have a multi-entry log-book infrastructure: we define a 10MB log * book to hold all the entries (and trims as necessary), and multiple diff --git a/lightningd/memdump.c b/lightningd/memdump.c index b2f32a10636f..31d84b0e057f 100644 --- a/lightningd/memdump.c +++ b/lightningd/memdump.c @@ -194,19 +194,6 @@ static bool lightningd_check_leaks(struct command *cmd) memleak_ptr(memtable, cmd); memleak_ignore_children(memtable, cmd); - /* First delete known false positives. */ - memleak_scan_htable(memtable, &ld->topology->txwatches->raw); - memleak_scan_htable(memtable, &ld->topology->txowatches->raw); - memleak_scan_htable(memtable, &ld->topology->outgoing_txs->raw); - memleak_scan_htable(memtable, &ld->htlcs_in->raw); - memleak_scan_htable(memtable, &ld->htlcs_out->raw); - memleak_scan_htable(memtable, &ld->htlc_sets->raw); - memleak_scan_htable(memtable, &ld->peers->raw); - memleak_scan_htable(memtable, &ld->peers_by_dbid->raw); - memleak_scan_htable(memtable, &ld->channels_by_scid->raw); - memleak_scan_htable(memtable, &ld->closed_channels->raw); - wallet_memleak_scan(memtable, ld->wallet); - /* Now delete ld and those which it has pointers to. */ memleak_scan_obj(memtable, ld); diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index b82523ab1b38..4d2723a5d1db 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -49,13 +49,6 @@ static bool replay_tx_eq_txid(const struct replay_tx *rtx, HTABLE_DEFINE_NODUPS_TYPE(struct replay_tx, replay_tx_keyof, txid_hash, replay_tx_eq_txid, replay_tx_hash); -/* Helper for memleak detection */ -static void memleak_replay_tx_hash(struct htable *memtable, - struct replay_tx_hash *replay_tx_hash) -{ - memleak_scan_htable(memtable, &replay_tx_hash->raw); -} - /* We dump all the known preimages when onchaind starts up. */ static void onchaind_tell_fulfill(struct channel *channel) { @@ -1904,11 +1897,8 @@ void onchaind_replay_channels(struct lightningd *ld) channel_state_name(channel), blockheight); /* We're in replay mode */ - channel->onchaind_replay_watches = tal(channel, struct replay_tx_hash); + channel->onchaind_replay_watches = new_htable(channel, replay_tx_hash); channel->onchaind_replay_height = blockheight; - replay_tx_hash_init(channel->onchaind_replay_watches); - memleak_add_helper(channel->onchaind_replay_watches, - memleak_replay_tx_hash); onchaind_funding_spent(channel, tx, blockheight); onchaind_replay(channel); diff --git a/plugins/askrene/askrene.c b/plugins/askrene/askrene.c index 9664d2487d7f..7f7f2d0d50c3 100644 --- a/plugins/askrene/askrene.c +++ b/plugins/askrene/askrene.c @@ -1290,13 +1290,6 @@ static const struct plugin_command commands[] = { }, }; -static void askrene_markmem(struct plugin *plugin, struct htable *memtable) -{ - struct askrene *askrene = get_askrene(plugin); - layer_memleak_mark(askrene, memtable); - reserve_memleak_mark(askrene, memtable); -} - static const char *init(struct command *init_cmd, const char *buf UNUSED, const jsmntok_t *config UNUSED) { @@ -1316,7 +1309,6 @@ static const char *init(struct command *init_cmd, "{id:%}", JSON_SCAN(json_to_node_id, &askrene->my_id)); plugin_set_data(plugin, askrene); - plugin_set_memleak_handler(plugin, askrene_markmem); load_layers(askrene, init_cmd); diff --git a/plugins/askrene/layer.c b/plugins/askrene/layer.c index 281e32a03c7b..4cbe657ac637 100644 --- a/plugins/askrene/layer.c +++ b/plugins/askrene/layer.c @@ -162,14 +162,10 @@ struct layer *new_temp_layer(const tal_t *ctx, struct askrene *askrene, const ch l->askrene = askrene; l->name = tal_strdup(l, name); l->persistent = false; - l->local_channels = tal(l, struct local_channel_hash); - local_channel_hash_init(l->local_channels); - l->local_updates = tal(l, struct local_update_hash); - local_update_hash_init(l->local_updates); - l->constraints = tal(l, struct constraint_hash); - constraint_hash_init(l->constraints); - l->biases = tal(l, struct bias_hash); - bias_hash_init(l->biases); + l->local_channels = new_htable(l, local_channel_hash); + l->local_updates = new_htable(l, local_update_hash); + l->constraints = new_htable(l, constraint_hash); + l->biases = new_htable(l, bias_hash); l->disabled_nodes = tal_arr(l, struct node_id, 0); return l; @@ -1162,14 +1158,3 @@ bool layer_disables_node(const struct layer *layer, } return false; } - -void layer_memleak_mark(struct askrene *askrene, struct htable *memtable) -{ - struct layer *l; - list_for_each(&askrene->layers, l, list) { - memleak_scan_htable(memtable, &l->constraints->raw); - memleak_scan_htable(memtable, &l->local_channels->raw); - memleak_scan_htable(memtable, &l->local_updates->raw); - memleak_scan_htable(memtable, &l->biases->raw); - } -} diff --git a/plugins/askrene/layer.h b/plugins/askrene/layer.h index e9b06fd5a4e6..b93f228ff05d 100644 --- a/plugins/askrene/layer.h +++ b/plugins/askrene/layer.h @@ -135,6 +135,4 @@ bool layer_disables_chan(const struct layer *layer, const struct short_channel_i /* For explain_failure: did this layer disable this node? */ bool layer_disables_node(const struct layer *layer, const struct node_id *node); -/* Scan for memleaks */ -void layer_memleak_mark(struct askrene *askrene, struct htable *memtable); #endif /* LIGHTNING_PLUGINS_ASKRENE_LAYER_H */ diff --git a/plugins/askrene/reserve.c b/plugins/askrene/reserve.c index abec9372dfc7..678ca248d667 100644 --- a/plugins/askrene/reserve.c +++ b/plugins/askrene/reserve.c @@ -36,9 +36,7 @@ HTABLE_DEFINE_DUPS_TYPE(struct reserve, reserve_scidd, hash_scidd, struct reserve_htable *new_reserve_htable(const tal_t *ctx) { - struct reserve_htable *reserved = tal(ctx, struct reserve_htable); - reserve_htable_init(reserved); - return reserved; + return new_htable(ctx, reserve_htable); } void reserve_add(struct reserve_htable *reserved, @@ -176,8 +174,3 @@ const char *fmt_reservations(const tal_t *ctx, } return ret; } - -void reserve_memleak_mark(struct askrene *askrene, struct htable *memtable) -{ - memleak_scan_htable(memtable, &askrene->reserved->raw); -} diff --git a/plugins/askrene/reserve.h b/plugins/askrene/reserve.h index 1c9e71eaaf60..868756ca0d9a 100644 --- a/plugins/askrene/reserve.h +++ b/plugins/askrene/reserve.h @@ -50,6 +50,4 @@ void json_add_reservations(struct json_stream *js, const struct reserve_htable *reserved, const char *fieldname); -/* Scan for memleaks */ -void reserve_memleak_mark(struct askrene *askrene, struct htable *memtable); #endif /* LIGHTNING_PLUGINS_ASKRENE_RESERVE_H */ diff --git a/plugins/chanbackup.c b/plugins/chanbackup.c index 11091edd92c4..16d6cb6189df 100644 --- a/plugins/chanbackup.c +++ b/plugins/chanbackup.c @@ -1040,10 +1040,8 @@ static void setup_backup_map(struct command *init_cmd, const jsmntok_t *datastore, *t; size_t i, total = 0; - cb->backups = tal(cb, struct backup_map); - backup_map_init(cb->backups); - cb->peers = tal(cb, struct peer_map); - peer_map_init(cb->peers); + cb->backups = new_htable(cb, backup_map); + cb->peers = new_htable(cb, peer_map); json_out_start(params, NULL, '{'); json_out_start(params, "key", '['); @@ -1084,14 +1082,6 @@ static void setup_backup_map(struct command *init_cmd, "Loaded %zu stored backups for peers", total); } -static void chanbackup_mark_mem(struct plugin *plugin, - struct htable *memtable) -{ - const struct chanbackup *cb = chanbackup(plugin); - memleak_scan_htable(memtable, &cb->backups->raw); - memleak_scan_htable(memtable, &cb->peers->raw); -} - static const char *init(struct command *init_cmd, const char *buf UNUSED, const jsmntok_t *config UNUSED) @@ -1132,9 +1122,6 @@ static const char *init(struct command *init_cmd, unlink_noerr("scb.tmp"); maybe_create_new_scb(init_cmd->plugin, scb_chan); - - plugin_set_memleak_handler(init_cmd->plugin, - chanbackup_mark_mem); return NULL; } diff --git a/plugins/channel_hint.c b/plugins/channel_hint.c index 1db37791ea0a..7a14f3992a44 100644 --- a/plugins/channel_hint.c +++ b/plugins/channel_hint.c @@ -23,12 +23,6 @@ bool channel_hint_eq(const struct channel_hint *a, a->scid.dir == b->dir; } -static void memleak_help_channel_hint_map(struct htable *memtable, - struct channel_hint_map *channel_hints) -{ - memleak_scan_htable(memtable, &channel_hints->raw); -} - void channel_hint_to_json(const char *name, const struct channel_hint *hint, struct json_stream *dest) { @@ -211,9 +205,7 @@ struct channel_hint *channel_hint_from_json(const tal_t *ctx, struct channel_hint_set *channel_hint_set_new(const tal_t *ctx) { struct channel_hint_set *set = tal(ctx, struct channel_hint_set); - set->hints = tal(set, struct channel_hint_map); - channel_hint_map_init(set->hints); - memleak_add_helper(set->hints, memleak_help_channel_hint_map); + set->hints = new_htable(set, channel_hint_map); return set; } diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index 106cd38026ae..86d6501463a3 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -170,10 +170,6 @@ struct invoices *invoices_new(const tal_t *ctx UNNEEDED, void logv(struct logger *logger UNNEEDED, enum log_level level UNNEEDED, const struct node_id *node_id UNNEEDED, bool call_notifier UNNEEDED, const char *fmt UNNEEDED, va_list ap UNNEEDED) { fprintf(stderr, "logv called!\n"); abort(); } -/* Generated stub for memleak_scan_outpointfilter */ -void memleak_scan_outpointfilter(struct htable *memtable UNNEEDED, - const struct outpointfilter *opf UNNEEDED) -{ fprintf(stderr, "memleak_scan_outpointfilter called!\n"); abort(); } /* Generated stub for mk_mvt_tags_ */ struct mvt_tags mk_mvt_tags_(enum mvt_tag tag UNNEEDED, ...) { fprintf(stderr, "mk_mvt_tags_ called!\n"); abort(); } diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index a334808d1e15..dce93f941d9d 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -661,10 +661,6 @@ void lockin_complete(struct channel *channel UNNEEDED, void logv(struct logger *logger UNNEEDED, enum log_level level UNNEEDED, const struct node_id *node_id UNNEEDED, bool call_notifier UNNEEDED, const char *fmt UNNEEDED, va_list ap UNNEEDED) { fprintf(stderr, "logv called!\n"); abort(); } -/* Generated stub for memleak_scan_outpointfilter */ -void memleak_scan_outpointfilter(struct htable *memtable UNNEEDED, - const struct outpointfilter *opf UNNEEDED) -{ fprintf(stderr, "memleak_scan_outpointfilter called!\n"); abort(); } /* Generated stub for mk_mvt_tags_ */ struct mvt_tags mk_mvt_tags_(enum mvt_tag tag UNNEEDED, ...) { fprintf(stderr, "mk_mvt_tags_ called!\n"); abort(); } diff --git a/wallet/txfilter.c b/wallet/txfilter.c index 10ef774e41b0..0ce6f46a7a2c 100644 --- a/wallet/txfilter.c +++ b/wallet/txfilter.c @@ -128,12 +128,6 @@ void outpointfilter_remove(struct outpointfilter *of, struct outpointfilter *outpointfilter_new(tal_t *ctx) { struct outpointfilter *opf = tal(ctx, struct outpointfilter); - opf->set = tal(opf, struct outpointset); - outpointset_init(opf->set); + opf->set = new_htable(opf, outpointset); return opf; } - -void memleak_scan_outpointfilter(struct htable *memtable, const struct outpointfilter *opf) -{ - memleak_scan_htable(memtable, &opf->set->raw); -} diff --git a/wallet/txfilter.h b/wallet/txfilter.h index c9152bffd390..2e72b68e1b93 100644 --- a/wallet/txfilter.h +++ b/wallet/txfilter.h @@ -64,9 +64,6 @@ bool outpointfilter_matches(struct outpointfilter *of, void outpointfilter_remove(struct outpointfilter *of, const struct bitcoin_outpoint *outpoint); -void memleak_scan_outpointfilter(struct htable *memtable, - const struct outpointfilter *opf); - /* Useful for other callers */ size_t scriptpubkey_hash(const u8 *out); diff --git a/wallet/wallet.c b/wallet/wallet.c index 4e18d453c336..2231c1f11198 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -181,8 +181,7 @@ static void our_addresses_add_for_index(struct wallet *w, u32 i) static void our_addresses_init(struct wallet *w) { w->our_addresses_maxindex = 0; - w->our_addresses = tal(w, struct wallet_address_htable); - wallet_address_htable_init(w->our_addresses); + w->our_addresses = new_htable(w, wallet_address_htable); our_addresses_add_for_index(w, w->our_addresses_maxindex); } @@ -6891,13 +6890,6 @@ struct local_anchor_info *wallet_get_local_anchors(const tal_t *ctx, return anchors; } -void wallet_memleak_scan(struct htable *memtable, const struct wallet *w) -{ - memleak_scan_outpointfilter(memtable, w->utxoset_outpoints); - memleak_scan_outpointfilter(memtable, w->owned_outpoints); - memleak_scan_htable(memtable, &w->our_addresses->raw); -} - struct issued_address_type *wallet_list_addresses(const tal_t *ctx, struct wallet *wallet, u64 liststart, const u32 *listlimit) { diff --git a/wallet/wallet.h b/wallet/wallet.h index 584f17b03076..512cac1ac57e 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -1920,8 +1920,4 @@ void wallet_datastore_save_payment_description(struct db *db, const char *desc); void migrate_setup_coinmoves(struct lightningd *ld, struct db *db); -/** - * wallet_memleak_scan - Check for memleaks in wallet. - */ -void wallet_memleak_scan(struct htable *memtable, const struct wallet *w); #endif /* LIGHTNING_WALLET_WALLET_H */ From 768835e1e4d0551c7b7eac2e92b8220f87995975 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:55:43 +0930 Subject: [PATCH 08/25] lightningd: try harder to ensure uniqueness in --dev-save-plugin-io names. Incorporate a time: this covers the restart case as well. And make it time_mono(), which doesn't get overridden when we override normal wall time. Signed-off-by: Rusty Russell --- lightningd/plugin.c | 10 +++++++++- tests/test_misc.py | 8 +------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lightningd/plugin.c b/lightningd/plugin.c index 1dba9a94dd87..e1c8130d3233 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -2688,16 +2688,24 @@ static void dev_save_plugin_io(struct plugins *plugins, const char *buf, size_t len) { static size_t counter; + static u64 starttime; const char *file; int fd; if (!plugins->dev_save_io) return; + /* If we reexec, we still want unique names */ + if (!starttime) { + struct timemono start = time_mono(); + starttime = start.ts.tv_sec * 1000000 + start.ts.tv_nsec / 1000; + } + file = path_join(tmpctx, plugins->dev_save_io, - take(tal_fmt(NULL, "%s-%s-%u-%zu", + take(tal_fmt(NULL, "%s-%s-%u-%"PRIu64"-%zu", type, name, (unsigned int)getpid(), + starttime, counter++))); fd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0600); if (fd < 0 || !write_all(fd, buf, len)) diff --git a/tests/test_misc.py b/tests/test_misc.py index 5832787aff20..afefce365472 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -3662,8 +3662,6 @@ def test_version_reexec(node_factory, bitcoind): # We use a file to tell our openingd wrapper where the real one is with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "openingd-real"), 'w') as f: f.write(os.path.abspath('lightningd/lightning_openingd')) - # Internal restart doesn't work well with --dev-save-plugin-io - del l1.daemon.opts['dev-save-plugin-io'] l1.start() # This is a "version" message verfile = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "openingd-version") @@ -4539,11 +4537,7 @@ def test_setconfig_changed(node_factory, bitcoind): @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "deletes database, which is assumed sqlite3") def test_recover_command(node_factory, bitcoind): - l1 = node_factory.get_node(start=False) - # Internal restart doesn't work well with --dev-save-plugin-io - del l1.daemon.opts['dev-save-plugin-io'] - l1.start() - l2 = node_factory.get_node() + l1, l2 = node_factory.get_nodes(2) l1oldid = l1.info['id'] From 3b4bea8a68b7da2a8a75b017de7b9a5f86a2cac2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:55:43 +0930 Subject: [PATCH 09/25] bitcoin: remove unused scriptpubkey_opreturn_padded. I noticed, because it pulled in randomness routines. Signed-off-by: Rusty Russell --- bitcoin/script.c | 11 ----------- bitcoin/script.h | 6 ------ 2 files changed, 17 deletions(-) diff --git a/bitcoin/script.c b/bitcoin/script.c index 63974644a34c..18461a8396b4 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -187,17 +187,6 @@ u8 *scriptpubkey_p2pkh(const tal_t *ctx, const struct bitcoin_address *addr) return script; } -u8 *scriptpubkey_opreturn_padded(const tal_t *ctx) -{ - u8 *script = tal_arr(ctx, u8, 0); - u8 random[20]; - randombytes_buf(random, sizeof(random)); - - add_op(&script, OP_RETURN); - script_push_bytes(&script, random, sizeof(random)); - return script; -} - /* Create an input script which spends p2pkh */ u8 *bitcoin_redeem_p2pkh(const tal_t *ctx, const struct pubkey *pubkey, const struct bitcoin_signature *sig) diff --git a/bitcoin/script.h b/bitcoin/script.h index 5b96d696ff15..c0a005c17d57 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -27,12 +27,6 @@ u8 *scriptpubkey_p2sh_hash(const tal_t *ctx, const struct ripemd160 *redeemhash) /* Create an output script using p2pkh */ u8 *scriptpubkey_p2pkh(const tal_t *ctx, const struct bitcoin_address *addr); -/* Create a prunable output script with 20 random bytes. - * This is needed since a spend from a p2wpkh to an `OP_RETURN` without - * any other outputs would result in a transaction smaller than the - * minimum size. */ -u8 *scriptpubkey_opreturn_padded(const tal_t *ctx); - /* Create an input script which spends p2pkh */ u8 *bitcoin_redeem_p2pkh(const tal_t *ctx, const struct pubkey *pubkey, const struct bitcoin_signature *sig); From 66cfba5c61aeae90e3dda045831bec326fef916e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:55:43 +0930 Subject: [PATCH 10/25] autogenerate-rpc-examples.py: add examples for listchainmoves and listchannelmoves. Signed-off-by: Rusty Russell --- contrib/msggen/msggen/schema.json | 589 +++++++++++++++++++++++++++++ doc/schemas/listchainmoves.json | 353 +++++++++++++++++ doc/schemas/listchannelmoves.json | 236 ++++++++++++ tests/autogenerate-rpc-examples.py | 14 + 4 files changed, 1192 insertions(+) diff --git a/contrib/msggen/msggen/schema.json b/contrib/msggen/msggen/schema.json index 69c33acf4aa8..0ead982d8a9a 100644 --- a/contrib/msggen/msggen/schema.json +++ b/contrib/msggen/msggen/schema.json @@ -16749,6 +16749,359 @@ ], "resources": [ "Main web site: " + ], + "examples": [ + { + "request": { + "id": "example:listchainmoves#1", + "method": "listchainmoves", + "params": {} + }, + "response": { + "chainmoves": [ + { + "created_index": 1, + "account_id": "wallet", + "credit_msat": 200000000000, + "debit_msat": 0, + "timestamp": 1758192762, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "994185cba7723715c0aa1d1859ce2781116776cea917035c90f8f04c9f4e095e:1", + "output_msat": 200000000000, + "blockheight": 104 + }, + { + "created_index": 2, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 0, + "debit_msat": 0, + "timestamp": 1758192777, + "primary_tag": "channel_open", + "extra_tags": [], + "utxo": "542906c8a9d90596592459a9484f4286a3200f6540599c83b43af2ac4166c6ca:1", + "peer_id": "nodeid010101010101010101010101010101010101010101010101010101010101", + "output_msat": 1000000000, + "blockheight": 109 + }, + { + "created_index": 3, + "account_id": "wallet", + "credit_msat": 2000000000, + "debit_msat": 0, + "timestamp": 1758192780, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "19e9e42f2f2097ea1dc18d7eb670bc53c90cbe31bb1daba8e94abf3c6b60d2dc:1", + "output_msat": 2000000000, + "blockheight": 110 + }, + { + "created_index": 4, + "account_id": "wallet", + "credit_msat": 0, + "debit_msat": 200000000000, + "timestamp": 1738530000, + "primary_tag": "withdrawal", + "extra_tags": [], + "utxo": "994185cba7723715c0aa1d1859ce2781116776cea917035c90f8f04c9f4e095e:1", + "spending_txid": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc", + "output_msat": 200000000000, + "blockheight": 111 + }, + { + "created_index": 5, + "account_id": "wallet", + "credit_msat": 198995073000, + "debit_msat": 0, + "timestamp": 1738530000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:1", + "output_msat": 198995073000, + "blockheight": 111 + }, + { + "created_index": 6, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1738530000, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:0", + "peer_id": "nodeid030303030303030303030303030303030303030303030303030303030303", + "output_msat": 1000000000, + "blockheight": 111 + }, + { + "created_index": 7, + "account_id": "wallet", + "credit_msat": 2000000000, + "debit_msat": 0, + "timestamp": 1758192792, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "b6d0090efbeb347fa59f90b321d6906cdf86779c15477582979fa427249f71f5:1", + "output_msat": 2000000000, + "blockheight": 114 + }, + { + "created_index": 8, + "account_id": "wallet", + "credit_msat": 0, + "debit_msat": 198995073000, + "timestamp": 1758192795, + "primary_tag": "withdrawal", + "extra_tags": [], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:1", + "spending_txid": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec", + "output_msat": 198995073000, + "blockheight": 115 + }, + { + "created_index": 9, + "account_id": "wallet", + "credit_msat": 197990453000, + "debit_msat": 0, + "timestamp": 1758192795, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:0", + "output_msat": 197990453000, + "blockheight": 115 + }, + { + "created_index": 10, + "account_id": "f8fc83a432cbfb2fffe222cc06727fdd977b5dd10ebd6707158e799e6f522d9f", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1758192795, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:1", + "peer_id": "nodeid050505050505050505050505050505050505050505050505050505050505", + "output_msat": 1000000000, + "blockheight": 115 + }, + { + "created_index": 11, + "account_id": "wallet", + "credit_msat": 486914000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "874b26d4c523a902fdc44b88ec000eb5c3fe8754c9d44190a140561e24e77781:0", + "output_msat": 486914000, + "blockheight": 121 + }, + { + "created_index": 12, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 489809898, + "timestamp": 1738520000, + "primary_tag": "channel_close", + "extra_tags": [], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:0", + "spending_txid": "txid010101010101010101010101010101010101010101010101010101010101", + "output_msat": 1000000000, + "output_count": 2, + "blockheight": 121 + }, + { + "created_index": 13, + "account_id": "external", + "credit_msat": 510190000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "to_them", + "extra_tags": [], + "utxo": "874b26d4c523a902fdc44b88ec000eb5c3fe8754c9d44190a140561e24e77781:1", + "originating_account": "channelid0230000230000230000230000230000230000230000230000230000", + "output_msat": 510190000, + "blockheight": 121 + }, + { + "created_index": 14, + "account_id": "wallet", + "credit_msat": 2000000000, + "debit_msat": 0, + "timestamp": 1758192808, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "c9c9bec064382b6a6fb2a30d8923949b3c9f732465542b96e9ad1b5eebda4c7d:0", + "output_msat": 2000000000, + "blockheight": 122 + }, + { + "created_index": 15, + "account_id": "wallet", + "credit_msat": 0, + "debit_msat": 197990453000, + "timestamp": 1738500000, + "primary_tag": "withdrawal", + "extra_tags": [], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:0", + "spending_txid": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682", + "output_msat": 197990453000, + "blockheight": 123 + }, + { + "created_index": 16, + "account_id": "wallet", + "credit_msat": 196985833000, + "debit_msat": 0, + "timestamp": 1738500000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682:1", + "output_msat": 196985833000, + "blockheight": 123 + }, + { + "created_index": 17, + "account_id": "channelid0230200230200230200230200230200230200230200230200230200", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1738500000, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682:0", + "peer_id": "nodeid030303030303030303030303030303030303030303030303030303030303", + "output_msat": 1000000000, + "blockheight": 123 + } + ] + } + }, + { + "request": { + "id": "example:listchainmoves#2", + "method": "listchainmoves", + "params": { + "index": "created", + "start": 10 + } + }, + "response": { + "chainmoves": [ + { + "created_index": 10, + "account_id": "f8fc83a432cbfb2fffe222cc06727fdd977b5dd10ebd6707158e799e6f522d9f", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1758192795, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:1", + "peer_id": "nodeid050505050505050505050505050505050505050505050505050505050505", + "output_msat": 1000000000, + "blockheight": 115 + }, + { + "created_index": 11, + "account_id": "wallet", + "credit_msat": 486914000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "874b26d4c523a902fdc44b88ec000eb5c3fe8754c9d44190a140561e24e77781:0", + "output_msat": 486914000, + "blockheight": 121 + }, + { + "created_index": 12, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 489809898, + "timestamp": 1738520000, + "primary_tag": "channel_close", + "extra_tags": [], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:0", + "spending_txid": "txid010101010101010101010101010101010101010101010101010101010101", + "output_msat": 1000000000, + "output_count": 2, + "blockheight": 121 + }, + { + "created_index": 13, + "account_id": "external", + "credit_msat": 510190000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "to_them", + "extra_tags": [], + "utxo": "874b26d4c523a902fdc44b88ec000eb5c3fe8754c9d44190a140561e24e77781:1", + "originating_account": "channelid0230000230000230000230000230000230000230000230000230000", + "output_msat": 510190000, + "blockheight": 121 + }, + { + "created_index": 14, + "account_id": "wallet", + "credit_msat": 2000000000, + "debit_msat": 0, + "timestamp": 1758192808, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "c9c9bec064382b6a6fb2a30d8923949b3c9f732465542b96e9ad1b5eebda4c7d:0", + "output_msat": 2000000000, + "blockheight": 122 + }, + { + "created_index": 15, + "account_id": "wallet", + "credit_msat": 0, + "debit_msat": 197990453000, + "timestamp": 1738500000, + "primary_tag": "withdrawal", + "extra_tags": [], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:0", + "spending_txid": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682", + "output_msat": 197990453000, + "blockheight": 123 + }, + { + "created_index": 16, + "account_id": "wallet", + "credit_msat": 196985833000, + "debit_msat": 0, + "timestamp": 1738500000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682:1", + "output_msat": 196985833000, + "blockheight": 123 + }, + { + "created_index": 17, + "account_id": "channelid0230200230200230200230200230200230200230200230200230200", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1738500000, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682:0", + "peer_id": "nodeid030303030303030303030303030303030303030303030303030303030303", + "output_msat": 1000000000, + "blockheight": 123 + } + ] + } + } ] }, "listchannelmoves.json": { @@ -16898,6 +17251,242 @@ ], "resources": [ "Main web site: " + ], + "examples": [ + { + "request": { + "id": "example:listchannelmoves#1", + "method": "listchannelmoves", + "params": {} + }, + "response": { + "channelmoves": [ + { + "created_index": 1, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 500000000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "invoice", + "payment_hash": "paymenthashdelpay10101010101010101010101010101010101010101010101", + "fees_msat": 0 + }, + { + "created_index": 2, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 500000000, + "timestamp": 1738520000, + "primary_tag": "invoice", + "payment_hash": "8a46ab91013146df39e98ad7c89505fbb5419f110e928f7a393e8304f3057df7", + "part_id": 0, + "group_id": 1, + "fees_msat": 0 + }, + { + "created_index": 3, + "account_id": "f8fc83a432cbfb2fffe222cc06727fdd977b5dd10ebd6707158e799e6f522d9f", + "credit_msat": 0, + "debit_msat": 500000000, + "timestamp": 1758192801, + "primary_tag": "invoice", + "payment_hash": "88969daaf02214a1928e6eb62a237a8ee557f3da93b2c44f3901432c88f4334b", + "part_id": 0, + "group_id": 1, + "fees_msat": 0 + }, + { + "created_index": 4, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000, + "timestamp": 1758192801, + "primary_tag": "routed", + "payment_hash": "paymenthashinvl0310031003100310031003100310031003100310031003100", + "fees_msat": 1 + }, + { + "created_index": 5, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10001, + "debit_msat": 0, + "timestamp": 1758192801, + "primary_tag": "routed", + "payment_hash": "paymenthashinvl0310031003100310031003100310031003100310031003100", + "fees_msat": 1 + }, + { + "created_index": 6, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000, + "timestamp": 1758192801, + "primary_tag": "routed", + "payment_hash": "paymenthashkey01k101k101k101k101k101k101k101k101k101k101k101k101", + "fees_msat": 1 + }, + { + "created_index": 7, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10001, + "debit_msat": 0, + "timestamp": 1758192801, + "primary_tag": "routed", + "payment_hash": "paymenthashkey01k101k101k101k101k101k101k101k101k101k101k101k101", + "fees_msat": 1 + }, + { + "created_index": 8, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000101, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey02k201k201k201k201k201k201k201k201k201k201k201k201", + "fees_msat": 101 + }, + { + "created_index": 9, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10000202, + "debit_msat": 0, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey02k201k201k201k201k201k201k201k201k201k201k201k201", + "fees_msat": 101 + }, + { + "created_index": 10, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey03k301k301k301k301k301k301k301k301k301k301k301k301", + "fees_msat": 1 + }, + { + "created_index": 11, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10001, + "debit_msat": 0, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey03k301k301k301k301k301k301k301k301k301k301k301k301", + "fees_msat": 1 + }, + { + "created_index": 12, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 50000, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashinvl0320032003200320032003200320032003200320032003200", + "fees_msat": 1 + }, + { + "created_index": 13, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 50001, + "debit_msat": 0, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashinvl0320032003200320032003200320032003200320032003200", + "fees_msat": 1 + }, + { + "created_index": 14, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 100000, + "timestamp": 1758192803, + "primary_tag": "invoice", + "payment_hash": "paymenthashinvl0330033003300330033003300330033003300330033003300", + "part_id": 0, + "group_id": 1, + "fees_msat": 0 + }, + { + "created_index": 15, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10001, + "timestamp": 1758192803, + "primary_tag": "routed", + "payment_hash": "61b929204f4db4f38e0412b2bd4c3c03668dad3575fb05f4e15a2214046c2bff", + "fees_msat": 1 + }, + { + "created_index": 16, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10002, + "debit_msat": 0, + "timestamp": 1758192803, + "primary_tag": "routed", + "payment_hash": "61b929204f4db4f38e0412b2bd4c3c03668dad3575fb05f4e15a2214046c2bff", + "fees_msat": 1 + }, + { + "created_index": 17, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 0, + "debit_msat": 1000000, + "timestamp": 1758192821, + "primary_tag": "invoice", + "payment_hash": "paymenthashsdinvsi10si10si10si10si10si10si10si10si10si10si10si10", + "part_id": 0, + "group_id": 1, + "fees_msat": 0 + }, + { + "created_index": 18, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 1000, + "debit_msat": 0, + "timestamp": 1758192821, + "primary_tag": "invoice", + "payment_hash": "paymenthashinvl0270027002700270027002700270027002700270027002700", + "fees_msat": 0 + } + ] + } + }, + { + "request": { + "id": "example:listchannelmoves#2", + "method": "listchannelmoves", + "params": { + "index": "created", + "start": 10, + "limit": 2 + } + }, + "response": { + "channelmoves": [ + { + "created_index": 10, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey03k301k301k301k301k301k301k301k301k301k301k301k301", + "fees_msat": 1 + }, + { + "created_index": 11, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10001, + "debit_msat": 0, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey03k301k301k301k301k301k301k301k301k301k301k301k301", + "fees_msat": 1 + } + ] + } + } ] }, "listchannels.json": { diff --git a/doc/schemas/listchainmoves.json b/doc/schemas/listchainmoves.json index 985105e93a55..eeec3e6b902e 100644 --- a/doc/schemas/listchainmoves.json +++ b/doc/schemas/listchainmoves.json @@ -197,5 +197,358 @@ ], "resources": [ "Main web site: " + ], + "examples": [ + { + "request": { + "id": "example:listchainmoves#1", + "method": "listchainmoves", + "params": {} + }, + "response": { + "chainmoves": [ + { + "created_index": 1, + "account_id": "wallet", + "credit_msat": 200000000000, + "debit_msat": 0, + "timestamp": 1758192762, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "994185cba7723715c0aa1d1859ce2781116776cea917035c90f8f04c9f4e095e:1", + "output_msat": 200000000000, + "blockheight": 104 + }, + { + "created_index": 2, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 0, + "debit_msat": 0, + "timestamp": 1758192777, + "primary_tag": "channel_open", + "extra_tags": [], + "utxo": "542906c8a9d90596592459a9484f4286a3200f6540599c83b43af2ac4166c6ca:1", + "peer_id": "nodeid010101010101010101010101010101010101010101010101010101010101", + "output_msat": 1000000000, + "blockheight": 109 + }, + { + "created_index": 3, + "account_id": "wallet", + "credit_msat": 2000000000, + "debit_msat": 0, + "timestamp": 1758192780, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "19e9e42f2f2097ea1dc18d7eb670bc53c90cbe31bb1daba8e94abf3c6b60d2dc:1", + "output_msat": 2000000000, + "blockheight": 110 + }, + { + "created_index": 4, + "account_id": "wallet", + "credit_msat": 0, + "debit_msat": 200000000000, + "timestamp": 1738530000, + "primary_tag": "withdrawal", + "extra_tags": [], + "utxo": "994185cba7723715c0aa1d1859ce2781116776cea917035c90f8f04c9f4e095e:1", + "spending_txid": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc", + "output_msat": 200000000000, + "blockheight": 111 + }, + { + "created_index": 5, + "account_id": "wallet", + "credit_msat": 198995073000, + "debit_msat": 0, + "timestamp": 1738530000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:1", + "output_msat": 198995073000, + "blockheight": 111 + }, + { + "created_index": 6, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1738530000, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:0", + "peer_id": "nodeid030303030303030303030303030303030303030303030303030303030303", + "output_msat": 1000000000, + "blockheight": 111 + }, + { + "created_index": 7, + "account_id": "wallet", + "credit_msat": 2000000000, + "debit_msat": 0, + "timestamp": 1758192792, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "b6d0090efbeb347fa59f90b321d6906cdf86779c15477582979fa427249f71f5:1", + "output_msat": 2000000000, + "blockheight": 114 + }, + { + "created_index": 8, + "account_id": "wallet", + "credit_msat": 0, + "debit_msat": 198995073000, + "timestamp": 1758192795, + "primary_tag": "withdrawal", + "extra_tags": [], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:1", + "spending_txid": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec", + "output_msat": 198995073000, + "blockheight": 115 + }, + { + "created_index": 9, + "account_id": "wallet", + "credit_msat": 197990453000, + "debit_msat": 0, + "timestamp": 1758192795, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:0", + "output_msat": 197990453000, + "blockheight": 115 + }, + { + "created_index": 10, + "account_id": "f8fc83a432cbfb2fffe222cc06727fdd977b5dd10ebd6707158e799e6f522d9f", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1758192795, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:1", + "peer_id": "nodeid050505050505050505050505050505050505050505050505050505050505", + "output_msat": 1000000000, + "blockheight": 115 + }, + { + "created_index": 11, + "account_id": "wallet", + "credit_msat": 486914000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "874b26d4c523a902fdc44b88ec000eb5c3fe8754c9d44190a140561e24e77781:0", + "output_msat": 486914000, + "blockheight": 121 + }, + { + "created_index": 12, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 489809898, + "timestamp": 1738520000, + "primary_tag": "channel_close", + "extra_tags": [], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:0", + "spending_txid": "txid010101010101010101010101010101010101010101010101010101010101", + "output_msat": 1000000000, + "output_count": 2, + "blockheight": 121 + }, + { + "created_index": 13, + "account_id": "external", + "credit_msat": 510190000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "to_them", + "extra_tags": [], + "utxo": "874b26d4c523a902fdc44b88ec000eb5c3fe8754c9d44190a140561e24e77781:1", + "originating_account": "channelid0230000230000230000230000230000230000230000230000230000", + "output_msat": 510190000, + "blockheight": 121 + }, + { + "created_index": 14, + "account_id": "wallet", + "credit_msat": 2000000000, + "debit_msat": 0, + "timestamp": 1758192808, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "c9c9bec064382b6a6fb2a30d8923949b3c9f732465542b96e9ad1b5eebda4c7d:0", + "output_msat": 2000000000, + "blockheight": 122 + }, + { + "created_index": 15, + "account_id": "wallet", + "credit_msat": 0, + "debit_msat": 197990453000, + "timestamp": 1738500000, + "primary_tag": "withdrawal", + "extra_tags": [], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:0", + "spending_txid": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682", + "output_msat": 197990453000, + "blockheight": 123 + }, + { + "created_index": 16, + "account_id": "wallet", + "credit_msat": 196985833000, + "debit_msat": 0, + "timestamp": 1738500000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682:1", + "output_msat": 196985833000, + "blockheight": 123 + }, + { + "created_index": 17, + "account_id": "channelid0230200230200230200230200230200230200230200230200230200", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1738500000, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682:0", + "peer_id": "nodeid030303030303030303030303030303030303030303030303030303030303", + "output_msat": 1000000000, + "blockheight": 123 + } + ] + } + }, + { + "request": { + "id": "example:listchainmoves#2", + "method": "listchainmoves", + "params": { + "index": "created", + "start": 10 + } + }, + "response": { + "chainmoves": [ + { + "created_index": 10, + "account_id": "f8fc83a432cbfb2fffe222cc06727fdd977b5dd10ebd6707158e799e6f522d9f", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1758192795, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:1", + "peer_id": "nodeid050505050505050505050505050505050505050505050505050505050505", + "output_msat": 1000000000, + "blockheight": 115 + }, + { + "created_index": 11, + "account_id": "wallet", + "credit_msat": 486914000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "874b26d4c523a902fdc44b88ec000eb5c3fe8754c9d44190a140561e24e77781:0", + "output_msat": 486914000, + "blockheight": 121 + }, + { + "created_index": 12, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 489809898, + "timestamp": 1738520000, + "primary_tag": "channel_close", + "extra_tags": [], + "utxo": "94418b652c9a0d79129552d317dcc37cb55afda1387257a22c7f16aa3981b7bc:0", + "spending_txid": "txid010101010101010101010101010101010101010101010101010101010101", + "output_msat": 1000000000, + "output_count": 2, + "blockheight": 121 + }, + { + "created_index": 13, + "account_id": "external", + "credit_msat": 510190000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "to_them", + "extra_tags": [], + "utxo": "874b26d4c523a902fdc44b88ec000eb5c3fe8754c9d44190a140561e24e77781:1", + "originating_account": "channelid0230000230000230000230000230000230000230000230000230000", + "output_msat": 510190000, + "blockheight": 121 + }, + { + "created_index": 14, + "account_id": "wallet", + "credit_msat": 2000000000, + "debit_msat": 0, + "timestamp": 1758192808, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "c9c9bec064382b6a6fb2a30d8923949b3c9f732465542b96e9ad1b5eebda4c7d:0", + "output_msat": 2000000000, + "blockheight": 122 + }, + { + "created_index": 15, + "account_id": "wallet", + "credit_msat": 0, + "debit_msat": 197990453000, + "timestamp": 1738500000, + "primary_tag": "withdrawal", + "extra_tags": [], + "utxo": "32de3d1592062670eb8630875a28705cc1988b7f83f8c712bf9d39be2152efec:0", + "spending_txid": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682", + "output_msat": 197990453000, + "blockheight": 123 + }, + { + "created_index": 16, + "account_id": "wallet", + "credit_msat": 196985833000, + "debit_msat": 0, + "timestamp": 1738500000, + "primary_tag": "deposit", + "extra_tags": [], + "utxo": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682:1", + "output_msat": 196985833000, + "blockheight": 123 + }, + { + "created_index": 17, + "account_id": "channelid0230200230200230200230200230200230200230200230200230200", + "credit_msat": 1000000000, + "debit_msat": 0, + "timestamp": 1738500000, + "primary_tag": "channel_open", + "extra_tags": [ + "opener" + ], + "utxo": "0137213d852e76d48f0270a78218d2f562ac0a8974f814cab66376537cfd1682:0", + "peer_id": "nodeid030303030303030303030303030303030303030303030303030303030303", + "output_msat": 1000000000, + "blockheight": 123 + } + ] + } + } ] } diff --git a/doc/schemas/listchannelmoves.json b/doc/schemas/listchannelmoves.json index d98a72b777a8..eba0f45a35db 100644 --- a/doc/schemas/listchannelmoves.json +++ b/doc/schemas/listchannelmoves.json @@ -145,5 +145,241 @@ ], "resources": [ "Main web site: " + ], + "examples": [ + { + "request": { + "id": "example:listchannelmoves#1", + "method": "listchannelmoves", + "params": {} + }, + "response": { + "channelmoves": [ + { + "created_index": 1, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 500000000, + "debit_msat": 0, + "timestamp": 1738520000, + "primary_tag": "invoice", + "payment_hash": "paymenthashdelpay10101010101010101010101010101010101010101010101", + "fees_msat": 0 + }, + { + "created_index": 2, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 500000000, + "timestamp": 1738520000, + "primary_tag": "invoice", + "payment_hash": "8a46ab91013146df39e98ad7c89505fbb5419f110e928f7a393e8304f3057df7", + "part_id": 0, + "group_id": 1, + "fees_msat": 0 + }, + { + "created_index": 3, + "account_id": "f8fc83a432cbfb2fffe222cc06727fdd977b5dd10ebd6707158e799e6f522d9f", + "credit_msat": 0, + "debit_msat": 500000000, + "timestamp": 1758192801, + "primary_tag": "invoice", + "payment_hash": "88969daaf02214a1928e6eb62a237a8ee557f3da93b2c44f3901432c88f4334b", + "part_id": 0, + "group_id": 1, + "fees_msat": 0 + }, + { + "created_index": 4, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000, + "timestamp": 1758192801, + "primary_tag": "routed", + "payment_hash": "paymenthashinvl0310031003100310031003100310031003100310031003100", + "fees_msat": 1 + }, + { + "created_index": 5, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10001, + "debit_msat": 0, + "timestamp": 1758192801, + "primary_tag": "routed", + "payment_hash": "paymenthashinvl0310031003100310031003100310031003100310031003100", + "fees_msat": 1 + }, + { + "created_index": 6, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000, + "timestamp": 1758192801, + "primary_tag": "routed", + "payment_hash": "paymenthashkey01k101k101k101k101k101k101k101k101k101k101k101k101", + "fees_msat": 1 + }, + { + "created_index": 7, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10001, + "debit_msat": 0, + "timestamp": 1758192801, + "primary_tag": "routed", + "payment_hash": "paymenthashkey01k101k101k101k101k101k101k101k101k101k101k101k101", + "fees_msat": 1 + }, + { + "created_index": 8, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000101, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey02k201k201k201k201k201k201k201k201k201k201k201k201", + "fees_msat": 101 + }, + { + "created_index": 9, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10000202, + "debit_msat": 0, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey02k201k201k201k201k201k201k201k201k201k201k201k201", + "fees_msat": 101 + }, + { + "created_index": 10, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey03k301k301k301k301k301k301k301k301k301k301k301k301", + "fees_msat": 1 + }, + { + "created_index": 11, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10001, + "debit_msat": 0, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey03k301k301k301k301k301k301k301k301k301k301k301k301", + "fees_msat": 1 + }, + { + "created_index": 12, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 50000, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashinvl0320032003200320032003200320032003200320032003200", + "fees_msat": 1 + }, + { + "created_index": 13, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 50001, + "debit_msat": 0, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashinvl0320032003200320032003200320032003200320032003200", + "fees_msat": 1 + }, + { + "created_index": 14, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 100000, + "timestamp": 1758192803, + "primary_tag": "invoice", + "payment_hash": "paymenthashinvl0330033003300330033003300330033003300330033003300", + "part_id": 0, + "group_id": 1, + "fees_msat": 0 + }, + { + "created_index": 15, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10001, + "timestamp": 1758192803, + "primary_tag": "routed", + "payment_hash": "61b929204f4db4f38e0412b2bd4c3c03668dad3575fb05f4e15a2214046c2bff", + "fees_msat": 1 + }, + { + "created_index": 16, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10002, + "debit_msat": 0, + "timestamp": 1758192803, + "primary_tag": "routed", + "payment_hash": "61b929204f4db4f38e0412b2bd4c3c03668dad3575fb05f4e15a2214046c2bff", + "fees_msat": 1 + }, + { + "created_index": 17, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 0, + "debit_msat": 1000000, + "timestamp": 1758192821, + "primary_tag": "invoice", + "payment_hash": "paymenthashsdinvsi10si10si10si10si10si10si10si10si10si10si10si10", + "part_id": 0, + "group_id": 1, + "fees_msat": 0 + }, + { + "created_index": 18, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 1000, + "debit_msat": 0, + "timestamp": 1758192821, + "primary_tag": "invoice", + "payment_hash": "paymenthashinvl0270027002700270027002700270027002700270027002700", + "fees_msat": 0 + } + ] + } + }, + { + "request": { + "id": "example:listchannelmoves#2", + "method": "listchannelmoves", + "params": { + "index": "created", + "start": 10, + "limit": 2 + } + }, + "response": { + "channelmoves": [ + { + "created_index": 10, + "account_id": "a397dd9b3e44afcb67f3f3ce1d649b74a8ade63e35505985e4cc1828634f69a2", + "credit_msat": 0, + "debit_msat": 10000, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey03k301k301k301k301k301k301k301k301k301k301k301k301", + "fees_msat": 1 + }, + { + "created_index": 11, + "account_id": "252d1b0a1e57895e84137f28cf19ab2c35847e284c112fefdecc7afeaa5c1de7", + "credit_msat": 10001, + "debit_msat": 0, + "timestamp": 1758192802, + "primary_tag": "routed", + "payment_hash": "paymenthashkey03k301k301k301k301k301k301k301k301k301k301k301k301", + "fees_msat": 1 + } + ] + } + } ] } diff --git a/tests/autogenerate-rpc-examples.py b/tests/autogenerate-rpc-examples.py index bfd564288c4f..1036adbd7a55 100644 --- a/tests/autogenerate-rpc-examples.py +++ b/tests/autogenerate-rpc-examples.py @@ -972,6 +972,19 @@ def generate_bookkeeper_examples(l2, l3, c23_2_chan_id): raise +def generate_coinmvt_examples(l2): + """Generates listchannelmoves and listchainmoves rpc examples""" + try: + logger.info('listcoinmoves Start...') + update_example(node=l2, method='listchainmoves', params={}) + update_example(node=l2, method='listchainmoves', params={'index': 'created', 'start': 10}) + update_example(node=l2, method='listchannelmoves', params={}) + update_example(node=l2, method='listchannelmoves', params={'index': 'created', 'start': 10, 'limit': 2}) + except Exception as e: + logger.error(f'Error in generating coinmoves examples: {e}') + raise + + def generate_offers_renepay_examples(l1, l2, inv_l21, inv_l34): """Covers all offers and renepay related examples""" try: @@ -2096,6 +2109,7 @@ def list_missing_examples(): c23_2, c23res2, c34_2, inv_l11, inv_l21, inv_l22, inv_l31, inv_l32, inv_l34 = generate_transactions_examples(l1, l2, l3, l4, l5, c25, bitcoind) rune_l21 = generate_runes_examples(l1, l2, l3) generate_datastore_examples(l2) + generate_coinmvt_examples(l2) generate_bookkeeper_examples(l2, l3, c23res2['channel_id']) offer_l23, inv_req_l1_l22 = generate_offers_renepay_examples(l1, l2, inv_l21, inv_l34) generate_askrene_examples(l1, l2, l3, c12, c23_2) From b587b44f04faccaca545cd0e9cf041605d0e4e80 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:56:43 +0930 Subject: [PATCH 11/25] lightningd: remove unused `start_time` field in bitcoind_getfilteredblock. Signed-off-by: Rusty Russell --- lightningd/bitcoind.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lightningd/bitcoind.c b/lightningd/bitcoind.c index 771ccf2f9f0a..879e2d87fe7c 100644 --- a/lightningd/bitcoind.c +++ b/lightningd/bitcoind.c @@ -703,7 +703,6 @@ struct filteredblock_call { struct filteredblock *result; struct filteredblock_outpoint **outpoints; size_t current_outpoint; - struct timeabs start_time; u32 height; }; @@ -858,7 +857,6 @@ void bitcoind_getfilteredblock_(const tal_t *ctx, call->arg = arg; call->height = height; assert(call->cb != NULL); - call->start_time = time_now(); call->result = NULL; call->current_outpoint = 0; From 5b920e53d456530fff22df2a0df9c9bc2a7701b6 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:57:43 +0930 Subject: [PATCH 12/25] tests: use timemono not time_now() for duration measurement. Signed-off-by: Rusty Russell --- bitcoin/test/run-secret_eq_consttime.c | 16 ++++++++-------- onchaind/test/run-grind_feerate.c | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bitcoin/test/run-secret_eq_consttime.c b/bitcoin/test/run-secret_eq_consttime.c index 4f21ee191f11..bfba7ceb5029 100644 --- a/bitcoin/test/run-secret_eq_consttime.c +++ b/bitcoin/test/run-secret_eq_consttime.c @@ -22,7 +22,7 @@ static struct timerel const_time_test(struct secret *s1, struct secret *s2, size_t off) { - struct timeabs start, end; + struct timemono start, end; int result = 0; memset(s1, 0, RUNS * sizeof(*s1)); @@ -31,16 +31,16 @@ static struct timerel const_time_test(struct secret *s1, for (size_t i = 0; i < RUNS; i++) s2[i].data[off] = i; - start = time_now(); + start = time_mono(); for (size_t i = 0; i < RUNS; i++) result += secret_eq_consttime(&s1[i], &s2[i]); - end = time_now(); + end = time_mono(); if (result != RUNS / 256) errx(1, "Expected %u successes at offset %zu, not %u!", RUNS / 256, off, result); - return time_between(end, start); + return timemono_between(end, start); } static inline bool secret_eq_nonconst(const struct secret *a, @@ -53,7 +53,7 @@ static struct timerel nonconst_time_test(struct secret *s1, struct secret *s2, size_t off) { - struct timeabs start, end; + struct timemono start, end; int result = 0; memset(s1, 0, RUNS * sizeof(*s1)); @@ -62,16 +62,16 @@ static struct timerel nonconst_time_test(struct secret *s1, for (size_t i = 0; i < RUNS; i++) s2[i].data[off] = i; - start = time_now(); + start = time_mono(); for (size_t i = 0; i < RUNS; i++) result += secret_eq_nonconst(&s1[i], &s2[i]); - end = time_now(); + end = time_mono(); if (result != RUNS / 256) errx(1, "Expected %u successes at offset %zu, not %u!", RUNS / 256, off, result); - return time_between(end, start); + return timemono_between(end, start); } static struct secret *s1, *s2; diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index e413f100d043..c9b1d4dd5368 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -356,7 +356,7 @@ int main(int argc, char *argv[]) struct amount_sat fee; struct pubkey htlc_key; struct keyset *keys; - struct timeabs start, end; + struct timemono start, end; int iterations = 1000; u8 *spk = tal_arr(tmpctx, u8, 1); spk[0] = 0x00; @@ -388,15 +388,15 @@ int main(int argc, char *argv[]) max_possible_feerate = 250000; min_possible_feerate = max_possible_feerate + 1 - iterations; - start = time_now(); + start = time_mono(); if (!grind_htlc_tx_fee(&fee, tx, &sig, wscript, 663)) abort(); - end = time_now(); + end = time_mono(); assert(amount_sat_eq(fee, AMOUNT_SAT(165750))); printf("%u iterations in %"PRIu64" msec = %"PRIu64" nsec each\n", iterations, - time_to_msec(time_between(end, start)), - time_to_nsec(time_divide(time_between(end, start), iterations))); + time_to_msec(timemono_between(end, start)), + time_to_nsec(time_divide(timemono_between(end, start), iterations))); common_shutdown(); return 0; From becfedf560e198e57cc958747941dfc2f7ac34dc Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:58:43 +0930 Subject: [PATCH 13/25] lightningd: fix scb remote_to_self_delay information. This was changing all the time when I tried to make autogenerate-rpc-examples.py reproducible. Turns out it was being corrupted (it does suspicious things with pointers); rather than try to diagnose it, I simply rewrote the code to create it only when we need it. Signed-off-by: Rusty Russell --- lightningd/channel.c | 25 -------------- lightningd/channel.h | 4 --- lightningd/dual_open_control.c | 19 ----------- lightningd/peer_control.c | 37 +++++++++++++++------ lightningd/test/run-invoice-select-inchan.c | 7 ++++ 5 files changed, 34 insertions(+), 58 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index 354249a4c24c..1390a4868713 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -343,7 +343,6 @@ struct channel *new_unsaved_channel(struct peer *peer, channel->openchannel_signed_cmd = NULL; channel->state = DUALOPEND_OPEN_INIT; channel->owner = NULL; - channel->scb = NULL; channel->reestablished = false; memset(&channel->billboard, 0, sizeof(channel->billboard)); channel->billboard.transient = tal_fmt(channel, "%s", @@ -578,30 +577,6 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->billboard.transient = tal_strdup(channel, transient_billboard); channel->channel_info = *channel_info; - /* If it's a unix domain socket connection, we don't save it */ - if (peer->addr.itype == ADDR_INTERNAL_WIREADDR) { - channel->scb = tal(channel, struct modern_scb_chan); - channel->scb->id = dbid; - /* More useful to have last_known_addr, if avail */ - if (peer->last_known_addr) - channel->scb->addr = *peer->last_known_addr; - channel->scb->addr = peer->addr.u.wireaddr.wireaddr; - channel->scb->node_id = peer->id; - channel->scb->funding = *funding; - channel->scb->cid = *cid; - channel->scb->funding_sats = funding_sats; - channel->scb->type = channel_type_dup(channel->scb, type); - - struct tlv_scb_tlvs *scb_tlvs = tlv_scb_tlvs_new(channel); - scb_tlvs->shachain = &channel->their_shachain.chain; - scb_tlvs->basepoints = &channel->channel_info.theirbase; - scb_tlvs->opener = &channel->opener; - scb_tlvs->remote_to_self_delay = &channel->channel_info.their_config.to_self_delay; - - channel->scb->tlvs = scb_tlvs; - } else - channel->scb = NULL; - if (!log) { channel->log = new_logger(channel, peer->ld->log_book, diff --git a/lightningd/channel.h b/lightningd/channel.h index af2f18a54b8a..fd8e031b0c39 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -343,10 +343,6 @@ struct channel { /* Lease commited max part per thousandth channel fee (ppm * 1000) */ u16 lease_chan_max_ppt; - /* `Channel-shell` of this channel - * (Minimum information required to backup this channel). */ - struct modern_scb_chan *scb; - /* Do we allow the peer to set any fee it wants? */ bool ignore_fee_limits; diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 3ad5cfb1dbb7..57c618ca452f 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1467,28 +1467,9 @@ wallet_commit_channel(struct lightningd *ld, &commitment_feerate); channel->min_possible_feerate = commitment_feerate; channel->max_possible_feerate = commitment_feerate; - if (channel->peer->addr.itype == ADDR_INTERNAL_WIREADDR) { - channel->scb = tal(channel, struct modern_scb_chan); - channel->scb->id = channel->dbid; - channel->scb->addr = channel->peer->addr.u.wireaddr.wireaddr; - channel->scb->node_id = channel->peer->id; - channel->scb->funding = *funding; - channel->scb->cid = channel->cid; - channel->scb->funding_sats = total_funding; - - struct tlv_scb_tlvs *scb_tlvs = tlv_scb_tlvs_new(channel); - scb_tlvs->shachain = &channel->their_shachain.chain; - scb_tlvs->basepoints = &channel_info->theirbase; - scb_tlvs->opener = &channel->opener; - scb_tlvs->remote_to_self_delay = &channel_info->their_config.to_self_delay; - - channel->scb->tlvs = scb_tlvs; - } else - channel->scb = NULL; tal_free(channel->type); channel->type = channel_type_dup(channel, type); - channel->scb->type = channel_type_dup(channel->scb, type); if (our_upfront_shutdown_script) channel->shutdown_scriptpubkey[LOCAL] diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 72968efc1083..132afbd0a6b8 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -2457,15 +2457,35 @@ static void json_add_scb(struct command *cmd, struct json_stream *response, struct channel *c) { - u8 *scb = tal_arr(cmd, u8, 0); + u8 *scb_wire = tal_arr(cmd, u8, 0); + struct modern_scb_chan *scb; - /* Update shachain & basepoints in SCB. */ - c->scb->tlvs->shachain = &c->their_shachain.chain; - c->scb->tlvs->basepoints = &c->channel_info.theirbase; - towire_modern_scb_chan(&scb, c->scb); + /* Don't do scb for unix domain sockets. */ + if (c->peer->addr.itype != ADDR_INTERNAL_WIREADDR) + return; + + scb = tal(tmpctx, struct modern_scb_chan); + scb->id = c->dbid; + /* More useful to have last_known_addr, if avail */ + if (c->peer->last_known_addr) + scb->addr = *c->peer->last_known_addr; + else + scb->addr = c->peer->addr.u.wireaddr.wireaddr; + scb->node_id = c->peer->id; + scb->funding = c->funding; + scb->cid = c->cid; + scb->funding_sats = c->funding_sats; + scb->type = channel_type_dup(scb, c->type); - json_add_hex_talarr(response, fieldname, - scb); + scb->tlvs = tlv_scb_tlvs_new(scb); + scb->tlvs->shachain = &c->their_shachain.chain; + scb->tlvs->basepoints = &c->channel_info.theirbase; + scb->tlvs->opener = &c->opener; + scb->tlvs->remote_to_self_delay = &c->channel_info.their_config.to_self_delay; + + towire_modern_scb_chan(&scb_wire, scb); + + json_add_hex_talarr(response, fieldname, scb_wire); } /* This will return a SCB for all the channels currently loaded @@ -2490,9 +2510,6 @@ static struct command_result *json_staticbackup(struct command *cmd, peer = peer_node_id_map_next(cmd->ld->peers, &it)) { struct channel *channel; list_for_each(&peer->channels, channel, list){ - /* cppcheck-suppress uninitvar - false positive on channel */ - if (!channel->scb) - continue; json_add_scb(cmd, NULL, response, channel); } } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 3262d9a5bafc..a89fd4e472d7 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -144,6 +144,10 @@ const char *channel_state_name(const struct channel *channel UNNEEDED) /* Generated stub for channel_state_str */ const char *channel_state_str(enum channel_state state UNNEEDED) { fprintf(stderr, "channel_state_str called!\n"); abort(); } +/* Generated stub for channel_type_dup */ +struct channel_type *channel_type_dup(const tal_t *ctx UNNEEDED, + const struct channel_type *t UNNEEDED) +{ fprintf(stderr, "channel_type_dup called!\n"); abort(); } /* Generated stub for channel_type_has */ bool channel_type_has(const struct channel_type *type UNNEEDED, int feature UNNEEDED) { fprintf(stderr, "channel_type_has called!\n"); abort(); } @@ -976,6 +980,9 @@ void subd_send_fd(struct subd *sd UNNEEDED, int fd UNNEEDED) /* Generated stub for subd_send_msg */ void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED) { fprintf(stderr, "subd_send_msg called!\n"); abort(); } +/* Generated stub for tlv_scb_tlvs_new */ +struct tlv_scb_tlvs *tlv_scb_tlvs_new(const tal_t *ctx UNNEEDED) +{ fprintf(stderr, "tlv_scb_tlvs_new called!\n"); abort(); } /* Generated stub for towire_bigsize */ void towire_bigsize(u8 **pptr UNNEEDED, const bigsize_t val UNNEEDED) { fprintf(stderr, "towire_bigsize called!\n"); abort(); } From 930e2ecd2d70bedcebbd69d37857274ef59cc819 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 09:59:43 +0930 Subject: [PATCH 14/25] common: add randbytes() wrapper to override cryptographic entropy: $CLN_DEV_ENTROPY_SEED Only in developer mode, ofc. Notes: 1. We have to move the initialization before the lightningd main trace_start, since that uses pseudorand(). 2. To make the results stable, we need to use per-caller values to randbytes(). Otherwise external timing changes the call order. Signed-off-by: Rusty Russell --- channeld/Makefile | 1 + channeld/test/Makefile | 1 + channeld/test/run-commit_tx.c | 10 +++ channeld/test/run-full_channel.c | 3 + cli/test/Makefile | 1 + closingd/Makefile | 1 + common/Makefile | 1 + common/daemon.c | 8 +++ common/randbytes.c | 64 +++++++++++++++++++ common/randbytes.h | 20 ++++++ common/test/Makefile | 4 ++ common/test/run-htable.c | 10 +++ common/test/run-json.c | 10 +++ common/test/run-param.c | 10 +++ common/test/run-route-infloop.c | 10 +++ common/test/run-route-specific.c | 10 +++ common/test/run-route.c | 10 +++ connectd/Makefile | 1 + connectd/test/Makefile | 1 + connectd/test/run-crc32_of_update.c | 10 +++ connectd/test/run-gossip_rcvd_filter.c | 6 ++ connectd/test/run-initiator-success.c | 9 +++ connectd/test/run-netaddress.c | 10 +++ connectd/test/run-responder-success.c | 9 +++ connectd/test/run-websocket.c | 10 +++ devtools/Makefile | 3 +- gossipd/Makefile | 1 + gossipd/test/Makefile | 1 + gossipd/test/run-check_channel_announcement.c | 10 +++ gossipd/test/run-extended-info.c | 10 +++ gossipd/test/run-next_block_range.c | 9 +++ gossipd/test/run-txout_failure.c | 10 +++ hsmd/Makefile | 1 + lightningd/Makefile | 1 + lightningd/lightningd.c | 6 +- lightningd/test/Makefile | 1 + onchaind/Makefile | 1 + onchaind/test/Makefile | 1 + onchaind/test/run-grind_feerate-bug.c | 6 ++ onchaind/test/run-grind_feerate.c | 6 ++ openingd/Makefile | 1 + plugins/Makefile | 1 + plugins/bkpr/test/Makefile | 1 + plugins/test/Makefile | 1 + plugins/test/run-funder_policy.c | 10 +++ tests/plugins/Makefile | 1 + tools/hsmtool.c | 6 ++ wallet/test/Makefile | 1 + wire/test/Makefile | 1 + wire/test/run-peer-wire.c | 10 +++ wire/test/run-tlvstream.c | 10 +++ 51 files changed, 337 insertions(+), 3 deletions(-) create mode 100644 common/randbytes.c create mode 100644 common/randbytes.h diff --git a/channeld/Makefile b/channeld/Makefile index 7edcd460ae4d..e6673a56326c 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -84,6 +84,7 @@ CHANNELD_COMMON_OBJS := \ common/psbt_open.o \ common/psbt_internal.o \ common/pseudorand.o \ + common/randbytes.o \ common/read_peer_msg.o \ common/setup.o \ common/status.o \ diff --git a/channeld/test/Makefile b/channeld/test/Makefile index 67bc5a79769f..7e447f598439 100644 --- a/channeld/test/Makefile +++ b/channeld/test/Makefile @@ -21,6 +21,7 @@ CHANNELD_TEST_COMMON_OBJS := \ common/msg_queue.o \ common/permute_tx.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/utils.o diff --git a/channeld/test/run-commit_tx.c b/channeld/test/run-commit_tx.c index 5f0a636bdd4b..89f2039eade9 100644 --- a/channeld/test/run-commit_tx.c +++ b/channeld/test/run-commit_tx.c @@ -15,6 +15,7 @@ static bool print_superverbose; #include #include #include +#include #include #include @@ -32,6 +33,15 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for pubkey_from_node_id */ bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); } diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index 69128019418e..95394b3a435a 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -25,6 +25,9 @@ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memt /* Generated stub for memleak_scan_htable */ void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) { fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for pubkey_from_node_id */ bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); } diff --git a/cli/test/Makefile b/cli/test/Makefile index 6f9c9bea6579..3f587e8c098b 100644 --- a/cli/test/Makefile +++ b/cli/test/Makefile @@ -15,6 +15,7 @@ CLI_TEST_COMMON_OBJS := \ common/htlc_state.o \ common/json_parse_simple.o \ common/pseudorand.o \ + common/randbytes.o \ common/memleak.o \ common/msg_queue.o \ common/setup.o \ diff --git a/closingd/Makefile b/closingd/Makefile index 1c3953c14f20..c3d055acbf68 100644 --- a/closingd/Makefile +++ b/closingd/Makefile @@ -47,6 +47,7 @@ CLOSINGD_COMMON_OBJS := \ common/psbt_keypath.o \ common/psbt_open.o \ common/pseudorand.o \ + common/randbytes.o \ common/status_wiregen.o \ common/read_peer_msg.o \ common/setup.o \ diff --git a/common/Makefile b/common/Makefile index dec98e099b26..18381e02859b 100644 --- a/common/Makefile +++ b/common/Makefile @@ -85,6 +85,7 @@ COMMON_SRC_NOGEN := \ common/psbt_keypath.c \ common/psbt_open.c \ common/pseudorand.c \ + common/randbytes.c \ common/random_select.c \ common/read_peer_msg.c \ common/route.c \ diff --git a/common/daemon.c b/common/daemon.c index c3adac2a0255..9d09b7c8b4d6 100644 --- a/common/daemon.c +++ b/common/daemon.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,7 @@ void daemon_shutdown(void) bool daemon_developer_mode(char *argv[]) { bool developer = false, debug = false; + const char *entropy_override; for (int i = 1; argv[i]; i++) { if (streq(argv[i], "--dev-debug-self")) @@ -222,6 +224,12 @@ bool daemon_developer_mode(char *argv[]) kill(getpid(), SIGSTOP); } + /* We can override cryptographic randomness with this var in development + * mode, for reproducible results */ + entropy_override = getenv("CLN_DEV_ENTROPY_SEED"); + if (entropy_override) + dev_override_randbytes(argv[0], atol(entropy_override)); + /* This checks for any tal_steal loops, but it's not free: * only use if we're already using the fairly heavy memleak * detection. */ diff --git a/common/randbytes.c b/common/randbytes.c new file mode 100644 index 000000000000..fd38cdf7009f --- /dev/null +++ b/common/randbytes.c @@ -0,0 +1,64 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool used = false; +static u64 dev_seed = 0; + +bool randbytes_overridden(void) +{ + return dev_seed != 0; +} + +void randbytes_(void *bytes, size_t num_bytes, u64 *offset) +{ + static u64 offset_init; + be64 pattern; + + used = true; + if (!randbytes_overridden()) { + randombytes_buf(bytes, num_bytes); /* discouraged: use randbytes() */ + return; + } + + /* First time, start callers at different offsets */ + if (*offset == 0) { + *offset = offset_init; + offset_init += 1000; + } + + /* Somewhat recognizable pattern */ + pattern = cpu_to_be64(dev_seed + (*offset)++); + for (size_t i = 0; i < num_bytes; i += sizeof(pattern)) { + size_t copy = num_bytes - i; + if (copy > sizeof(pattern)) + copy = sizeof(pattern); + + memcpy((u8 *)bytes + i, &pattern, copy); + } +} + +/* We want different seeds for each plugin (hence argv0), and for each + * lightmingd instance, (hence seed from environment) */ +void dev_override_randbytes(const char *argv0, long int seed) +{ + struct siphash_seed hashseed; + assert(!used); + + hashseed.u.u64[0] = seed; + hashseed.u.u64[1] = 0; + + dev_seed = siphash24(&hashseed, argv0, strlen(argv0)); + assert(randbytes_overridden()); +} diff --git a/common/randbytes.h b/common/randbytes.h new file mode 100644 index 000000000000..18aa485eecf3 --- /dev/null +++ b/common/randbytes.h @@ -0,0 +1,20 @@ +#ifndef LIGHTNING_COMMON_RANDBYTES_H +#define LIGHTNING_COMMON_RANDBYTES_H +#include "config.h" +#include +#include +#include + +/* Usually the libsodium routine randombytes_buf, but dev options can make this deterministic */ +#define randbytes(bytes, num_bytes) \ + do { \ + static u64 offset; \ + randbytes_((bytes), (num_bytes), &offset); \ + } while(0) + +void randbytes_(void *bytes, size_t num_bytes, u64 *offset); + +void dev_override_randbytes(const char *argv0, long int seed); + +bool randbytes_overridden(void); +#endif /* LIGHTNING_COMMON_RANDBYTES_H */ diff --git a/common/test/Makefile b/common/test/Makefile index 75331d62e6dc..78a3f0675820 100644 --- a/common/test/Makefile +++ b/common/test/Makefile @@ -31,6 +31,7 @@ common/test/run-json: \ common/lease_rates.o \ common/node_id.o \ common/pseudorand.o \ + common/randbytes.o \ common/wireaddr.o \ wire/fromwire.o \ wire/onion_wiregen.o \ @@ -44,6 +45,7 @@ common/test/run-route common/test/run-route-specific common/test/run-route-inflo common/gossmap.o \ common/node_id.o \ common/pseudorand.o \ + common/randbytes.o \ common/route.o \ gossipd/gossip_store_wiregen.o \ wire/fromwire.o \ @@ -119,11 +121,13 @@ common/test/run-trace: \ common/amount.o \ common/memleak.o \ common/pseudorand.o \ + common/randbytes.o \ common/trace.o \ wire/fromwire.o \ wire/towire.o common/test/run-htable: \ + common/randbytes.o \ common/pseudorand.o common/test/run-shutdown_scriptpubkey: wire/towire.o wire/fromwire.o diff --git a/common/test/run-htable.c b/common/test/run-htable.c index 64ac0b568555..32a2631c37af 100644 --- a/common/test/run-htable.c +++ b/common/test/run-htable.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,15 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/common/test/run-json.c b/common/test/run-json.c index b5fdecdb3c64..6702d68e97d1 100644 --- a/common/test/run-json.c +++ b/common/test/run-json.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,15 @@ bool json_filter_ok(const struct json_filter *filter UNNEEDED, const char *membe /* Generated stub for json_filter_up */ bool json_filter_up(struct json_filter **filter UNNEEDED) { fprintf(stderr, "json_filter_up called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire_sciddir_or_pubkey */ void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED, const struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/common/test/run-param.c b/common/test/run-param.c index 3cb94bf854c7..325539693d64 100644 --- a/common/test/run-param.c +++ b/common/test/run-param.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -86,6 +87,15 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for to_canonical_invstr */ const char *to_canonical_invstr(const tal_t *ctx UNNEEDED, const char *invstring UNNEEDED) { fprintf(stderr, "to_canonical_invstr called!\n"); abort(); } diff --git a/common/test/run-route-infloop.c b/common/test/run-route-infloop.c index c2e532fe5191..4e4ee302ff4a 100644 --- a/common/test/run-route-infloop.c +++ b/common/test/run-route-infloop.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,15 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for sciddir_or_pubkey_from_node_id */ bool sciddir_or_pubkey_from_node_id(struct sciddir_or_pubkey *sciddpk UNNEEDED, const struct node_id *node_id UNNEEDED) diff --git a/common/test/run-route-specific.c b/common/test/run-route-specific.c index d661d85b488a..921f4f9b75a0 100644 --- a/common/test/run-route-specific.c +++ b/common/test/run-route-specific.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,15 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for sciddir_or_pubkey_from_node_id */ bool sciddir_or_pubkey_from_node_id(struct sciddir_or_pubkey *sciddpk UNNEEDED, const struct node_id *node_id UNNEEDED) diff --git a/common/test/run-route.c b/common/test/run-route.c index 9175bbac760c..d8dccd51ed70 100644 --- a/common/test/run-route.c +++ b/common/test/run-route.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,15 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for sciddir_or_pubkey_from_node_id */ bool sciddir_or_pubkey_from_node_id(struct sciddir_or_pubkey *sciddpk UNNEEDED, const struct node_id *node_id UNNEEDED) diff --git a/connectd/Makefile b/connectd/Makefile index 781172e186de..78624204c417 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -72,6 +72,7 @@ CONNECTD_COMMON_OBJS := \ common/per_peer_state.o \ common/psbt_open.o \ common/pseudorand.o \ + common/randbytes.o \ common/sciddir_or_pubkey.o \ common/setup.o \ common/sphinx.o \ diff --git a/connectd/test/Makefile b/connectd/test/Makefile index c624f32190c2..2569e8c96c3a 100644 --- a/connectd/test/Makefile +++ b/connectd/test/Makefile @@ -8,6 +8,7 @@ CONNECTD_TEST_COMMON_OBJS := \ common/autodata.o \ common/features.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/utils.o diff --git a/connectd/test/run-crc32_of_update.c b/connectd/test/run-crc32_of_update.c index efcaaf4792d7..838505fc0a84 100644 --- a/connectd/test/run-crc32_of_update.c +++ b/connectd/test/run-crc32_of_update.c @@ -7,6 +7,7 @@ int unused_main(int argc, char *argv[]); #include #include #include +#include #include #include #include @@ -166,9 +167,18 @@ void inject_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } /* Generated stub for node_id_cmp */ int node_id_cmp(const struct node_id *a UNNEEDED, const struct node_id *b UNNEEDED) { fprintf(stderr, "node_id_cmp called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for status_fmt */ void status_fmt(enum log_level level UNNEEDED, const struct node_id *peer UNNEEDED, diff --git a/connectd/test/run-gossip_rcvd_filter.c b/connectd/test/run-gossip_rcvd_filter.c index ef20a1cd6839..fcaa06837f33 100644 --- a/connectd/test/run-gossip_rcvd_filter.c +++ b/connectd/test/run-gossip_rcvd_filter.c @@ -40,6 +40,12 @@ struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u /* Generated stub for amount_tx_fee */ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) { fprintf(stderr, "amount_tx_fee called!\n"); abort(); } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/connectd/test/run-initiator-success.c b/connectd/test/run-initiator-success.c index 26aeb40cceff..e90ebb693500 100644 --- a/connectd/test/run-initiator-success.c +++ b/connectd/test/run-initiator-success.c @@ -83,6 +83,15 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/connectd/test/run-netaddress.c b/connectd/test/run-netaddress.c index c69ed2510325..885e4d214d2a 100644 --- a/connectd/test/run-netaddress.c +++ b/connectd/test/run-netaddress.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -100,6 +101,15 @@ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr /* Generated stub for is_msg_for_gossipd */ bool is_msg_for_gossipd(const u8 *cursor UNNEEDED) { fprintf(stderr, "is_msg_for_gossipd called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for peer_wire_name */ const char *peer_wire_name(int e UNNEEDED) { fprintf(stderr, "peer_wire_name called!\n"); abort(); } diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c index ed1dfb175e35..53c63970619d 100644 --- a/connectd/test/run-responder-success.c +++ b/connectd/test/run-responder-success.c @@ -83,6 +83,15 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/connectd/test/run-websocket.c b/connectd/test/run-websocket.c index 25f126e927d2..69800798db09 100644 --- a/connectd/test/run-websocket.c +++ b/connectd/test/run-websocket.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -118,6 +119,15 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/devtools/Makefile b/devtools/Makefile index a80ebe4ab631..aa7cdd5c36bf 100644 --- a/devtools/Makefile +++ b/devtools/Makefile @@ -42,6 +42,7 @@ DEVTOOLS_COMMON_OBJS := \ common/per_peer_state.o \ common/psbt_open.o \ common/pseudorand.o \ + common/randbytes.o \ common/sciddir_or_pubkey.o \ common/setup.o \ common/utils.o \ @@ -83,7 +84,7 @@ devtools/gossipwith: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(BITCOIN_OBJS) wire/f $(DEVTOOLS_OBJS) $(DEVTOOLS_TOOL_OBJS): wire/wire.h -devtools/mkcommit: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/derive_basepoints.o common/channel_type.o common/keyset.o common/key_derive.o common/initial_commit_tx.o common/permute_tx.o wire/fromwire.o wire/towire.o devtools/mkcommit.o channeld/full_channel.o common/initial_channel.o common/htlc_state.o common/pseudorand.o common/htlc_tx.o channeld/commit_tx.o common/htlc_trim.o +devtools/mkcommit: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/derive_basepoints.o common/channel_type.o common/keyset.o common/key_derive.o common/initial_commit_tx.o common/permute_tx.o wire/fromwire.o wire/towire.o devtools/mkcommit.o channeld/full_channel.o common/initial_channel.o common/htlc_state.o common/pseudorand.o common/randbytes.o common/htlc_tx.o channeld/commit_tx.o common/htlc_trim.o devtools/mkfunding: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o common/key_derive.o devtools/mkfunding.o diff --git a/gossipd/Makefile b/gossipd/Makefile index c0732482d75f..a33a2c256553 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -56,6 +56,7 @@ GOSSIPD_COMMON_OBJS := \ common/ping.o \ common/psbt_open.o \ common/pseudorand.o \ + common/randbytes.o \ common/random_select.o \ common/setup.o \ common/status.o \ diff --git a/gossipd/test/Makefile b/gossipd/test/Makefile index 99cb7faafd3f..d87aa8a9a998 100644 --- a/gossipd/test/Makefile +++ b/gossipd/test/Makefile @@ -19,6 +19,7 @@ GOSSIPD_TEST_COMMON_OBJS := \ common/node_id.o \ common/lease_rates.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/utils.o \ common/wireaddr.o \ diff --git a/gossipd/test/run-check_channel_announcement.c b/gossipd/test/run-check_channel_announcement.c index 6c743d4d9871..b914bddda0a8 100644 --- a/gossipd/test/run-check_channel_announcement.c +++ b/gossipd/test/run-check_channel_announcement.c @@ -35,6 +35,7 @@ In particular, we set feature bit 19. The spec says we should set feature bit 1 #include #include #include +#include #include #include #include @@ -60,6 +61,15 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sciddir_or_pubkey *sciddpk UNNEEDED) { fprintf(stderr, "fromwire_sciddir_or_pubkey called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire_sciddir_or_pubkey */ void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED, const struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/gossipd/test/run-extended-info.c b/gossipd/test/run-extended-info.c index 45e19884d049..55715a49ea20 100644 --- a/gossipd/test/run-extended-info.c +++ b/gossipd/test/run-extended-info.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,15 @@ struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *e void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sciddir_or_pubkey *sciddpk UNNEEDED) { fprintf(stderr, "fromwire_sciddir_or_pubkey called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for peer_supplied_query_response */ void peer_supplied_query_response(struct daemon *daemon UNNEEDED, const struct node_id *source_peer UNNEEDED, diff --git a/gossipd/test/run-next_block_range.c b/gossipd/test/run-next_block_range.c index 49bd20f9eea7..9e75b502bae1 100644 --- a/gossipd/test/run-next_block_range.c +++ b/gossipd/test/run-next_block_range.c @@ -105,6 +105,12 @@ struct gossmap_node *gossmap_nth_node(const struct gossmap *map UNNEEDED, /* Generated stub for gossmap_random_node */ struct gossmap_node *gossmap_random_node(const struct gossmap *map UNNEEDED) { fprintf(stderr, "gossmap_random_node called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } /* Generated stub for memleak_scan_intmap_ */ void memleak_scan_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED) { fprintf(stderr, "memleak_scan_intmap_ called!\n"); abort(); } @@ -119,6 +125,9 @@ struct peer *next_random_peer(struct daemon *daemon UNNEEDED, const struct peer *first UNNEEDED, struct peer_node_id_map_iter *it UNNEEDED) { fprintf(stderr, "next_random_peer called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for query_channel_range */ bool query_channel_range(struct daemon *daemon UNNEEDED, struct peer *peer UNNEEDED, diff --git a/gossipd/test/run-txout_failure.c b/gossipd/test/run-txout_failure.c index ebb740ea77f4..919052b1b1bd 100644 --- a/gossipd/test/run-txout_failure.c +++ b/gossipd/test/run-txout_failure.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,15 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sciddir_or_pubkey *sciddpk UNNEEDED) { fprintf(stderr, "fromwire_sciddir_or_pubkey called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire_sciddir_or_pubkey */ void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED, const struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/hsmd/Makefile b/hsmd/Makefile index b4f51bef2ffd..bed5724ef194 100644 --- a/hsmd/Makefile +++ b/hsmd/Makefile @@ -46,6 +46,7 @@ HSMD_COMMON_OBJS := \ common/permute_tx.o \ common/psbt_open.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/status.o \ common/status_wire.o \ diff --git a/lightningd/Makefile b/lightningd/Makefile index fbf1d10f47a1..e5bd4e820638 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -139,6 +139,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/psbt_open.o \ common/pseudorand.o \ common/plugin.o \ + common/randbytes.o \ common/random_select.o \ common/setup.o \ common/shutdown_scriptpubkey.o \ diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 3ed15f9a6664..ed988d3069f7 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -1182,8 +1182,6 @@ int main(int argc, char *argv[]) bool try_reexec; size_t num_channels; - trace_span_start("lightningd/startup", argv); - /*~ What happens in strange locales should stay there. */ setup_locale(); @@ -1207,6 +1205,10 @@ int main(int argc, char *argv[]) * backtraces when we crash (if supported on this platform). */ daemon_setup(argv[0], log_backtrace_print, log_backtrace_exit); + /*~ We enable trace as early as possible, but it uses support functions + * (particularly if we're avoid entropy) so do it after daemon_setup. */ + trace_span_start("lightningd/startup", argv); + /*~ There's always a battle between what a constructor like this * should do, and what should be added later by the caller. In * general, because we use valgrind heavily for testing, we prefer not diff --git a/lightningd/test/Makefile b/lightningd/test/Makefile index a9aa3c12852b..776f963f69bd 100644 --- a/lightningd/test/Makefile +++ b/lightningd/test/Makefile @@ -21,6 +21,7 @@ LIGHTNINGD_TEST_COMMON_OBJS := \ common/json_parse_simple.o \ common/key_derive.o \ common/pseudorand.o \ + common/randbytes.o \ common/random_select.o \ common/memleak.o \ common/msg_queue.o \ diff --git a/onchaind/Makefile b/onchaind/Makefile index 8ef57d9ba6cd..32af13fa3b39 100644 --- a/onchaind/Makefile +++ b/onchaind/Makefile @@ -56,6 +56,7 @@ ONCHAIND_COMMON_OBJS := \ common/psbt_keypath.o \ common/psbt_open.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/status.o \ common/status_wire.o \ diff --git a/onchaind/test/Makefile b/onchaind/test/Makefile index 6777cb13905d..307a67e117ba 100644 --- a/onchaind/test/Makefile +++ b/onchaind/test/Makefile @@ -15,6 +15,7 @@ ONCHAIND_TEST_COMMON_OBJS := \ common/features.o \ common/psbt_keypath.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/utils.o diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index ff5ab45ef02a..cbc87029b013 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -89,9 +89,15 @@ struct bitcoin_tx *htlc_success_tx(const tal_t *ctx UNNEEDED, /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } /* Generated stub for memleak_ptr */ bool memleak_ptr(struct htable *memtable UNNEEDED, const void *p UNNEEDED) { fprintf(stderr, "memleak_ptr called!\n"); abort(); } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } /* Generated stub for memleak_scan_obj */ void memleak_scan_obj(struct htable *memtable UNNEEDED, const void *obj UNNEEDED) { fprintf(stderr, "memleak_scan_obj called!\n"); abort(); } diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index c9b1d4dd5368..453ea3e0e5f8 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -139,9 +139,15 @@ struct bitcoin_tx *htlc_timeout_tx(const tal_t *ctx UNNEEDED, /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } /* Generated stub for memleak_ptr */ bool memleak_ptr(struct htable *memtable UNNEEDED, const void *p UNNEEDED) { fprintf(stderr, "memleak_ptr called!\n"); abort(); } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } /* Generated stub for memleak_scan_obj */ void memleak_scan_obj(struct htable *memtable UNNEEDED, const void *obj UNNEEDED) { fprintf(stderr, "memleak_scan_obj called!\n"); abort(); } diff --git a/openingd/Makefile b/openingd/Makefile index 57dc84ee4177..29f4a4eba04c 100644 --- a/openingd/Makefile +++ b/openingd/Makefile @@ -70,6 +70,7 @@ OPENINGD_COMMON_OBJS := \ common/psbt_internal.o \ common/psbt_open.o \ common/pseudorand.o \ + common/randbytes.o \ common/read_peer_msg.o \ common/setup.o \ common/shutdown_scriptpubkey.o \ diff --git a/plugins/Makefile b/plugins/Makefile index 6efb6c2310f1..de10fd9171ef 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -197,6 +197,7 @@ PLUGIN_COMMON_OBJS := \ common/plugin.o \ common/psbt_open.o \ common/pseudorand.o \ + common/randbytes.o \ common/random_select.o \ common/splice_script.o \ common/setup.o \ diff --git a/plugins/bkpr/test/Makefile b/plugins/bkpr/test/Makefile index 80fed1875c0a..716190cae908 100644 --- a/plugins/bkpr/test/Makefile +++ b/plugins/bkpr/test/Makefile @@ -20,6 +20,7 @@ BOOKKEEPER_TEST_COMMON_OBJS := \ common/memleak.o \ common/node_id.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/trace.o \ common/timeout.o \ diff --git a/plugins/test/Makefile b/plugins/test/Makefile index 3b5712d5ac09..341616a0915a 100644 --- a/plugins/test/Makefile +++ b/plugins/test/Makefile @@ -11,6 +11,7 @@ PLUGIN_TEST_COMMON_OBJS := \ common/amount.o \ common/autodata.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/utils.o diff --git a/plugins/test/run-funder_policy.c b/plugins/test/run-funder_policy.c index 8880b905999a..5c9ec4931026 100644 --- a/plugins/test/run-funder_policy.c +++ b/plugins/test/run-funder_policy.c @@ -1,6 +1,7 @@ #include "config.h" #include "../funder_policy.c" #include +#include #include #include @@ -20,6 +21,15 @@ void json_add_string(struct json_stream *js UNNEEDED, const char *fieldname UNNEEDED, const char *str TAKES UNNEEDED) { fprintf(stderr, "json_add_string called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for pubkey_from_node_id */ bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); } diff --git a/tests/plugins/Makefile b/tests/plugins/Makefile index 826857db18a1..11d1d494132e 100644 --- a/tests/plugins/Makefile +++ b/tests/plugins/Makefile @@ -74,6 +74,7 @@ tests/plugins/channeld_fakenet: \ common/per_peer_state.o \ common/permute_tx.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/sphinx.o \ common/status.o \ diff --git a/tools/hsmtool.c b/tools/hsmtool.c index 7f2d30fb9d59..a6ba5435fcee 100644 --- a/tools/hsmtool.c +++ b/tools/hsmtool.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,11 @@ #define ERROR_LANG_NOT_SUPPORTED 6 #define ERROR_TERM 7 +void randbytes_(void *bytes, size_t num_bytes, u64 *offset) +{ + abort(); +} + static void show_usage(const char *progname) { printf("%s [arguments]\n", progname); diff --git a/wallet/test/Makefile b/wallet/test/Makefile index c986342dfbcf..9db6bcca3b33 100644 --- a/wallet/test/Makefile +++ b/wallet/test/Makefile @@ -24,6 +24,7 @@ WALLET_TEST_COMMON_OBJS := \ common/key_derive.o \ common/psbt_keypath.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/timeout.o \ common/trace.o \ diff --git a/wire/test/Makefile b/wire/test/Makefile index 997a72dae737..785fa5054293 100644 --- a/wire/test/Makefile +++ b/wire/test/Makefile @@ -13,6 +13,7 @@ WIRE_TEST_COMMON_OBJS := \ common/autodata.o \ common/base32.o \ common/pseudorand.o \ + common/randbytes.o \ common/setup.o \ common/utils.o \ common/wireaddr.o diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index 894920440a88..f9f5ab5c4d35 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,15 @@ extern secp256k1_context *secp256k1_ctx; /* AUTOGENERATED MOCKS START */ +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ /* memsetting pubkeys doesn't work */ diff --git a/wire/test/run-tlvstream.c b/wire/test/run-tlvstream.c index 68420fb900ed..b4f704fad17b 100644 --- a/wire/test/run-tlvstream.c +++ b/wire/test/run-tlvstream.c @@ -9,6 +9,7 @@ static const char *reason; #include #include #include +#include #include #include @@ -28,6 +29,15 @@ int chainparams_get_ln_port(const struct chainparams *params UNNEEDED) bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } +/* Generated stub for memleak_add_helper_ */ +void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, + const tal_t *)){ } +/* Generated stub for memleak_scan_htable */ +void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) +{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire_channel_id */ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "towire_channel_id called!\n"); abort(); } From c4a4a82396ffde39b50716b52562a279f43d530b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:00:43 +0930 Subject: [PATCH 15/25] global: replace randombytes_buf() with randbytes() wrapper. This allows us to override it for deterministic results. Signed-off-by: Rusty Russell --- Makefile | 2 +- bitcoin/short_channel_id.c | 4 ++-- channeld/test/run-commit_tx.c | 9 --------- channeld/test/run-full_channel.c | 3 --- common/blindedpath.h | 2 +- common/onion_message.c | 3 ++- common/pseudorand.c | 4 ++-- common/sphinx.c | 4 ++-- common/test/Makefile | 5 +++-- common/test/run-amount.c | 1 + common/test/run-base64.c | 1 + common/test/run-bigsize.c | 1 + common/test/run-blindedpath_enctlv.c | 1 + common/test/run-bolt11.c | 2 +- common/test/run-bolt12-encode-test.c | 1 + common/test/run-bolt12-format-string-test.c | 1 + common/test/run-bolt12-offer-decode.c | 1 + common/test/run-bolt12_decode.c | 1 + common/test/run-bolt12_merkle-json.c | 1 + common/test/run-bolt12_merkle.c | 1 + common/test/run-bolt12_period.c | 1 + common/test/run-channel_type.c | 1 + common/test/run-codex32.c | 1 + common/test/run-coin_mvt.c | 1 + common/test/run-cryptomsg.c | 1 + common/test/run-deprecation.c | 1 + common/test/run-derive_basepoints.c | 1 + common/test/run-features.c | 3 ++- common/test/run-gossmap-fp16.c | 1 + common/test/run-htable.c | 9 --------- common/test/run-ip_port_parsing.c | 1 + common/test/run-json.c | 9 --------- common/test/run-json_filter.c | 1 + common/test/run-json_remove.c | 1 + common/test/run-json_scan.c | 1 + common/test/run-json_stream-filter.c | 1 + common/test/run-key_derive.c | 1 + common/test/run-lease_rates.c | 1 + common/test/run-marginal_feerate.c | 1 + common/test/run-param.c | 9 --------- common/test/run-psbt_diff.c | 1 + common/test/run-route-infloop.c | 9 --------- common/test/run-route-specific.c | 9 --------- common/test/run-route.c | 9 --------- common/test/run-route_blinding_test.c | 1 + common/test/run-shutdown_scriptpubkey.c | 1 + common/test/run-splice_script.c | 1 + common/test/run-tlv_span.c | 1 + common/test/run-tlv_unknown.c | 1 + common/test/run-version.c | 4 ++++ common/test/run-wireaddr.c | 1 + connectd/connectd.c | 5 +++-- connectd/handshake.c | 4 ++-- connectd/test/run-crc32_of_update.c | 9 --------- connectd/test/run-gossip_rcvd_filter.c | 6 ------ connectd/test/run-initiator-success.c | 8 ++++---- connectd/test/run-netaddress.c | 9 --------- connectd/test/run-responder-success.c | 8 ++++---- connectd/test/run-websocket.c | 9 --------- gossipd/test/run-check_channel_announcement.c | 9 --------- gossipd/test/run-extended-info.c | 9 --------- gossipd/test/run-next_block_range.c | 9 --------- gossipd/test/run-txout_failure.c | 9 --------- hsmd/hsmd.c | 3 ++- lightningd/channel.c | 1 + lightningd/invoice.c | 8 ++++---- onchaind/test/run-grind_feerate-bug.c | 6 ------ onchaind/test/run-grind_feerate.c | 6 ------ plugins/fetchinvoice.c | 10 +++++----- plugins/keysend.c | 4 ++-- plugins/offers_invreq_hook.c | 3 ++- plugins/offers_offer.c | 6 +++--- plugins/renepay/test/run-bottleneck.c | 4 ++-- plugins/test/run-funder_policy.c | 9 --------- tests/fuzz/connectd_handshake.h | 4 ++-- wallet/db.c | 2 +- wire/test/run-peer-wire.c | 9 --------- wire/test/run-tlvstream.c | 9 --------- 78 files changed, 90 insertions(+), 220 deletions(-) diff --git a/Makefile b/Makefile index e67f0ca74d26..8fea6d098f32 100644 --- a/Makefile +++ b/Makefile @@ -569,7 +569,7 @@ check-tmpctx: @if git grep -n 'tal_free[(]tmpctx)' | grep -Ev '^ccan/|/test/|^common/setup.c:|^common/utils.c:'; then echo "Don't free tmpctx!">&2; exit 1; fi check-discouraged-functions: - @if git grep -E "[^a-z_/](fgets|fputs|gets|scanf|sprintf)\(" -- "*.c" "*.h" ":(exclude)ccan/" ":(exclude)contrib/"; then exit 1; fi + @if git grep -nE "[^a-z_/](fgets|fputs|gets|scanf|sprintf|randombytes_buf)\(" -- "*.c" "*.h" ":(exclude)ccan/" ":(exclude)contrib/" | grep -Fv '/* discouraged:'; then exit 1; fi # Don't access amount_msat and amount_sat members directly without a good reason # since it risks overflow. diff --git a/bitcoin/short_channel_id.c b/bitcoin/short_channel_id.c index cc1de68c4377..98fe4748b714 100644 --- a/bitcoin/short_channel_id.c +++ b/bitcoin/short_channel_id.c @@ -1,7 +1,7 @@ #include "config.h" #include #include -#include +#include #include #include @@ -104,6 +104,6 @@ struct short_channel_id fromwire_short_channel_id(const u8 **cursor, size_t *max struct short_channel_id random_scid(void) { struct short_channel_id scid; - randombytes_buf(&scid, sizeof(scid)); + randbytes(&scid, sizeof(scid)); return scid; } diff --git a/channeld/test/run-commit_tx.c b/channeld/test/run-commit_tx.c index 89f2039eade9..4df740c41ec4 100644 --- a/channeld/test/run-commit_tx.c +++ b/channeld/test/run-commit_tx.c @@ -33,15 +33,6 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for pubkey_from_node_id */ bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); } diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index 95394b3a435a..69128019418e 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -25,9 +25,6 @@ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memt /* Generated stub for memleak_scan_htable */ void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) { fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for pubkey_from_node_id */ bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); } diff --git a/common/blindedpath.h b/common/blindedpath.h index b84869351070..b0c96e0dd2cb 100644 --- a/common/blindedpath.h +++ b/common/blindedpath.h @@ -23,7 +23,7 @@ struct tlv_encrypted_data_tlv_payment_relay; * @next_path_privkey: (out) e(i+1), the next blinding secret (optional) * @node_alias: (out) the blinded pubkey of the node to tell the recipient. * - * You create a blinding secret using randombytes_buf(), then call this + * You create a blinding secret using randbytes(), then call this * iteratively for each node in the path. */ u8 *encrypt_tlv_encrypted_data(const tal_t *ctx, diff --git a/common/onion_message.c b/common/onion_message.c index c781866ee78c..e673538f5af6 100644 --- a/common/onion_message.c +++ b/common/onion_message.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -68,7 +69,7 @@ struct blinded_path *blinded_path_from_encdata_tlvs(const tal_t *ctx, assert(nhops > 0); assert(tal_count(ids) > 0); - randombytes_buf(&first_blinding, sizeof(first_blinding)); + randbytes(&first_blinding, sizeof(first_blinding)); if (!pubkey_from_privkey(&first_blinding, &path->first_path_key)) abort(); sciddir_or_pubkey_from_pubkey(&path->first_node_id, &ids[0]); diff --git a/common/pseudorand.c b/common/pseudorand.c index 831be2bb584b..4a6694fd645d 100644 --- a/common/pseudorand.c +++ b/common/pseudorand.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include static struct isaac64_ctx isaac64; @@ -19,7 +19,7 @@ static void init_if_needed(void) unsigned char seedbuf[16]; struct sha256 sha; - randombytes_buf(seedbuf, sizeof(seedbuf)); + randbytes(seedbuf, sizeof(seedbuf)); memcpy(&siphashseed, seedbuf, sizeof(siphashseed)); /* In case isaac is reversible, don't leak seed. */ diff --git a/common/sphinx.c b/common/sphinx.c index c254e63170bc..39a2c47bc598 100644 --- a/common/sphinx.c +++ b/common/sphinx.c @@ -6,13 +6,13 @@ #include #include #include +#include #include #include #include -#include #define BLINDING_FACTOR_SIZE 32 @@ -567,7 +567,7 @@ struct onionpacket *create_onionpacket( if (sp->session_key == NULL) { sp->session_key = tal(sp, struct secret); - randombytes_buf(sp->session_key, sizeof(struct secret)); + randbytes(sp->session_key, sizeof(struct secret)); } params = generate_hop_params(ctx, sp->session_key->data, sp); diff --git a/common/test/Makefile b/common/test/Makefile index 78a3f0675820..410ffde1270a 100644 --- a/common/test/Makefile +++ b/common/test/Makefile @@ -5,11 +5,13 @@ COMMON_TEST_PROGRAMS := $(COMMON_TEST_OBJS:.o=) COMMON_TEST_COMMON_OBJS := \ common/autodata.o \ + common/memleak.o \ + common/randbytes.o \ common/setup.o \ common/utils.o $(COMMON_TEST_PROGRAMS): $(COMMON_TEST_COMMON_OBJS) $(BITCOIN_OBJS) -$(COMMON_TEST_OBJS): $(COMMON_HEADERS) $(WIRE_HEADERS) $(COMMON_SRC) +$(COMMON_TEST_OBJS): $(COMMON_HEADERS) $(WIRE_HEADERS) $(COMMON_SRC) common/test/Makefile ALL_C_SOURCES += $(COMMON_TEST_SRC) ALL_TEST_PROGRAMS += $(COMMON_TEST_PROGRAMS) @@ -119,7 +121,6 @@ common/test/run-splice_script: \ common/test/run-trace: \ common/amount.o \ - common/memleak.o \ common/pseudorand.o \ common/randbytes.o \ common/trace.o \ diff --git a/common/test/run-amount.c b/common/test/run-amount.c index 0e9f295dc0c2..f76484ef3436 100644 --- a/common/test/run-amount.c +++ b/common/test/run-amount.c @@ -1,5 +1,6 @@ #include "config.h" #include "../amount.c" +#include #include #include diff --git a/common/test/run-base64.c b/common/test/run-base64.c index c36c08bb3fc3..e71371c9873b 100644 --- a/common/test/run-base64.c +++ b/common/test/run-base64.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-bigsize.c b/common/test/run-bigsize.c index 9b181261e6c6..d11ad50ab0c5 100644 --- a/common/test/run-bigsize.c +++ b/common/test/run-bigsize.c @@ -4,6 +4,7 @@ #include #include #include +#include #include static const char *reason; diff --git a/common/test/run-blindedpath_enctlv.c b/common/test/run-blindedpath_enctlv.c index c9408cba2dd5..d2552ad4e727 100644 --- a/common/test/run-blindedpath_enctlv.c +++ b/common/test/run-blindedpath_enctlv.c @@ -3,6 +3,7 @@ #include "../blinding.c" #include "../hmac.c" #include +#include #include #include diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index e4fbbd797cbd..3cc516a35a6a 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -6,10 +6,10 @@ #include "../features.c" #include "../node_id.c" #include "../hash_u5.c" -#include "../memleak.c" #include "../wire/fromwire.c" #include "../wire/towire.c" #include +#include #include /* AUTOGENERATED MOCKS START */ diff --git a/common/test/run-bolt12-encode-test.c b/common/test/run-bolt12-encode-test.c index e7de25fdd381..5ca641f93012 100644 --- a/common/test/run-bolt12-encode-test.c +++ b/common/test/run-bolt12-encode-test.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-bolt12-format-string-test.c b/common/test/run-bolt12-format-string-test.c index dc8384750a09..d38bd6ed6210 100644 --- a/common/test/run-bolt12-format-string-test.c +++ b/common/test/run-bolt12-format-string-test.c @@ -8,6 +8,7 @@ #include #include #include +#include #include /* AUTOGENERATED MOCKS START */ diff --git a/common/test/run-bolt12-offer-decode.c b/common/test/run-bolt12-offer-decode.c index 5296e8fd6c22..d15f24338ab5 100644 --- a/common/test/run-bolt12-offer-decode.c +++ b/common/test/run-bolt12-offer-decode.c @@ -14,6 +14,7 @@ #include #include #include +#include #include /* AUTOGENERATED MOCKS START */ diff --git a/common/test/run-bolt12_decode.c b/common/test/run-bolt12_decode.c index 4702d23f251c..ce80438f2c0a 100644 --- a/common/test/run-bolt12_decode.c +++ b/common/test/run-bolt12_decode.c @@ -7,6 +7,7 @@ #include #include #include +#include #include /* AUTOGENERATED MOCKS START */ diff --git a/common/test/run-bolt12_merkle-json.c b/common/test/run-bolt12_merkle-json.c index 4c0910d3f57f..1cd8e8bcdf93 100644 --- a/common/test/run-bolt12_merkle-json.c +++ b/common/test/run-bolt12_merkle-json.c @@ -11,6 +11,7 @@ #include #include #include +#include #include /* AUTOGENERATED MOCKS START */ diff --git a/common/test/run-bolt12_merkle.c b/common/test/run-bolt12_merkle.c index 43265ef4d74f..4d2f0bc6d639 100644 --- a/common/test/run-bolt12_merkle.c +++ b/common/test/run-bolt12_merkle.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/common/test/run-bolt12_period.c b/common/test/run-bolt12_period.c index 514e47fe734f..1fad5d142007 100644 --- a/common/test/run-bolt12_period.c +++ b/common/test/run-bolt12_period.c @@ -5,6 +5,7 @@ #include #include #include +#include #include /* AUTOGENERATED MOCKS START */ diff --git a/common/test/run-channel_type.c b/common/test/run-channel_type.c index 46edef12b3ee..2cac84ac8f41 100644 --- a/common/test/run-channel_type.c +++ b/common/test/run-channel_type.c @@ -2,6 +2,7 @@ #include "../channel_type.c" #include "../features.c" #include +#include #include #include #include diff --git a/common/test/run-codex32.c b/common/test/run-codex32.c index 2aed32315799..24929672c643 100644 --- a/common/test/run-codex32.c +++ b/common/test/run-codex32.c @@ -8,6 +8,7 @@ #include #include #include +#include #include /* AUTOGENERATED MOCKS START */ diff --git a/common/test/run-coin_mvt.c b/common/test/run-coin_mvt.c index e7512c089b55..99651ccbb54e 100644 --- a/common/test/run-coin_mvt.c +++ b/common/test/run-coin_mvt.c @@ -1,6 +1,7 @@ #include "config.h" #include "../coin_mvt.c" #include +#include #include #include diff --git a/common/test/run-cryptomsg.c b/common/test/run-cryptomsg.c index 42fa16e89c1b..e3218eb0b863 100644 --- a/common/test/run-cryptomsg.c +++ b/common/test/run-cryptomsg.c @@ -1,5 +1,6 @@ #include "config.h" #include +#include #include #include #include diff --git a/common/test/run-deprecation.c b/common/test/run-deprecation.c index fe1a4cd0579c..fa1378c8648b 100644 --- a/common/test/run-deprecation.c +++ b/common/test/run-deprecation.c @@ -6,6 +6,7 @@ static const char *test_next_version; #include "../deprecation.c" #include +#include #include #include #include diff --git a/common/test/run-derive_basepoints.c b/common/test/run-derive_basepoints.c index 861a65d63531..cb896ad7795a 100644 --- a/common/test/run-derive_basepoints.c +++ b/common/test/run-derive_basepoints.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-features.c b/common/test/run-features.c index e6936d5a8be8..ef38a0cfc353 100644 --- a/common/test/run-features.c +++ b/common/test/run-features.c @@ -1,8 +1,9 @@ #include "config.h" #include "../features.c" -#include "../memleak.c" #include +#include #include +#include /* AUTOGENERATED MOCKS START */ /* Generated stub for amount_asset_is_main */ diff --git a/common/test/run-gossmap-fp16.c b/common/test/run-gossmap-fp16.c index 274eccf3a3fd..539b129b5293 100644 --- a/common/test/run-gossmap-fp16.c +++ b/common/test/run-gossmap-fp16.c @@ -1,5 +1,6 @@ #include "config.h" #include "../fp16.c" +#include #include #include #include diff --git a/common/test/run-htable.c b/common/test/run-htable.c index 32a2631c37af..267ad8c03f10 100644 --- a/common/test/run-htable.c +++ b/common/test/run-htable.c @@ -81,15 +81,6 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/common/test/run-ip_port_parsing.c b/common/test/run-ip_port_parsing.c index 026a06f8f5d4..c7c5ba226530 100644 --- a/common/test/run-ip_port_parsing.c +++ b/common/test/run-ip_port_parsing.c @@ -4,6 +4,7 @@ #include #include +#include #include /* AUTOGENERATED MOCKS START */ diff --git a/common/test/run-json.c b/common/test/run-json.c index 6702d68e97d1..cbb3b42af1ce 100644 --- a/common/test/run-json.c +++ b/common/test/run-json.c @@ -36,15 +36,6 @@ bool json_filter_ok(const struct json_filter *filter UNNEEDED, const char *membe /* Generated stub for json_filter_up */ bool json_filter_up(struct json_filter **filter UNNEEDED) { fprintf(stderr, "json_filter_up called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire_sciddir_or_pubkey */ void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED, const struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/common/test/run-json_filter.c b/common/test/run-json_filter.c index 54138cbe6999..d682b82130b3 100644 --- a/common/test/run-json_filter.c +++ b/common/test/run-json_filter.c @@ -6,6 +6,7 @@ #include "../json_stream.c" #include #include +#include #include #include diff --git a/common/test/run-json_remove.c b/common/test/run-json_remove.c index f1c16a28cbe4..8a15653ebfae 100644 --- a/common/test/run-json_remove.c +++ b/common/test/run-json_remove.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-json_scan.c b/common/test/run-json_scan.c index a80dad990606..40ddb9bd4541 100644 --- a/common/test/run-json_scan.c +++ b/common/test/run-json_scan.c @@ -2,6 +2,7 @@ #include "../json_parse.c" #include "../json_parse_simple.c" #include +#include #include #include diff --git a/common/test/run-json_stream-filter.c b/common/test/run-json_stream-filter.c index 1e484b475868..6f6fe060f834 100644 --- a/common/test/run-json_stream-filter.c +++ b/common/test/run-json_stream-filter.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-key_derive.c b/common/test/run-key_derive.c index f30fcdfb2e18..6b158f74413d 100644 --- a/common/test/run-key_derive.c +++ b/common/test/run-key_derive.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-lease_rates.c b/common/test/run-lease_rates.c index 31da81c7d317..f995eb88c2f6 100644 --- a/common/test/run-lease_rates.c +++ b/common/test/run-lease_rates.c @@ -1,6 +1,7 @@ #include "config.h" #include "../amount.c" #include "../lease_rates.c" +#include #include #include diff --git a/common/test/run-marginal_feerate.c b/common/test/run-marginal_feerate.c index e0514cfdd83f..097852ceabc8 100644 --- a/common/test/run-marginal_feerate.c +++ b/common/test/run-marginal_feerate.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include "../fee_states.c" diff --git a/common/test/run-param.c b/common/test/run-param.c index 325539693d64..749f6a4946a2 100644 --- a/common/test/run-param.c +++ b/common/test/run-param.c @@ -87,15 +87,6 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for to_canonical_invstr */ const char *to_canonical_invstr(const tal_t *ctx UNNEEDED, const char *invstring UNNEEDED) { fprintf(stderr, "to_canonical_invstr called!\n"); abort(); } diff --git a/common/test/run-psbt_diff.c b/common/test/run-psbt_diff.c index 6d355697792d..235163fe0848 100644 --- a/common/test/run-psbt_diff.c +++ b/common/test/run-psbt_diff.c @@ -1,4 +1,5 @@ #include "config.h" +#include #include #include #include "../amount.c" diff --git a/common/test/run-route-infloop.c b/common/test/run-route-infloop.c index 4e4ee302ff4a..7556fd2f93af 100644 --- a/common/test/run-route-infloop.c +++ b/common/test/run-route-infloop.c @@ -32,15 +32,6 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for sciddir_or_pubkey_from_node_id */ bool sciddir_or_pubkey_from_node_id(struct sciddir_or_pubkey *sciddpk UNNEEDED, const struct node_id *node_id UNNEEDED) diff --git a/common/test/run-route-specific.c b/common/test/run-route-specific.c index 921f4f9b75a0..fef067c7cc13 100644 --- a/common/test/run-route-specific.c +++ b/common/test/run-route-specific.c @@ -37,15 +37,6 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for sciddir_or_pubkey_from_node_id */ bool sciddir_or_pubkey_from_node_id(struct sciddir_or_pubkey *sciddpk UNNEEDED, const struct node_id *node_id UNNEEDED) diff --git a/common/test/run-route.c b/common/test/run-route.c index d8dccd51ed70..0c63a8f50c33 100644 --- a/common/test/run-route.c +++ b/common/test/run-route.c @@ -30,15 +30,6 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for sciddir_or_pubkey_from_node_id */ bool sciddir_or_pubkey_from_node_id(struct sciddir_or_pubkey *sciddpk UNNEEDED, const struct node_id *node_id UNNEEDED) diff --git a/common/test/run-route_blinding_test.c b/common/test/run-route_blinding_test.c index 3358319dfae3..31a83a28caa4 100644 --- a/common/test/run-route_blinding_test.c +++ b/common/test/run-route_blinding_test.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-shutdown_scriptpubkey.c b/common/test/run-shutdown_scriptpubkey.c index db543a9d8d60..c98610d28277 100644 --- a/common/test/run-shutdown_scriptpubkey.c +++ b/common/test/run-shutdown_scriptpubkey.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-splice_script.c b/common/test/run-splice_script.c index c3bd63fcb2fc..082f46ceab49 100644 --- a/common/test/run-splice_script.c +++ b/common/test/run-splice_script.c @@ -6,6 +6,7 @@ #include "../json_stream.c" #include "../json_parse_simple.c" #include +#include #include #include #include diff --git a/common/test/run-tlv_span.c b/common/test/run-tlv_span.c index 4055ec9bcaae..eb3ede4b6cb4 100644 --- a/common/test/run-tlv_span.c +++ b/common/test/run-tlv_span.c @@ -2,6 +2,7 @@ #include "../bolt12.c" #include "../bigsize.c" #include "../../wire/fromwire.c" +#include #include #include diff --git a/common/test/run-tlv_unknown.c b/common/test/run-tlv_unknown.c index fdecc469965d..071b10432e1d 100644 --- a/common/test/run-tlv_unknown.c +++ b/common/test/run-tlv_unknown.c @@ -5,6 +5,7 @@ #include "../../wire/towire.c" #include "../bigsize.c" #include "../bolt12.c" +#include #include #include diff --git a/common/test/run-version.c b/common/test/run-version.c index 0e04b4cb061a..3b46f56e2289 100644 --- a/common/test/run-version.c +++ b/common/test/run-version.c @@ -1,9 +1,13 @@ #include "config.h" #include "../version.c" +#include #include #include #include +/* AUTOGENERATED MOCKS START */ +/* AUTOGENERATED MOCKS END */ + int main(int argc, char *argv[]) { common_setup(argv[0]); diff --git a/common/test/run-wireaddr.c b/common/test/run-wireaddr.c index 6d3bd76f232c..3ca99163d718 100644 --- a/common/test/run-wireaddr.c +++ b/common/test/run-wireaddr.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include diff --git a/connectd/connectd.c b/connectd/connectd.c index f0638eb887d7..26e1fa1d9b61 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1498,7 +1499,7 @@ setup_listeners(const tal_t *ctx, if (sodium_mlock(&random, sizeof(random)) != 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Could not lock the random prf key memory."); - randombytes_buf((void * const)&random, 32); + randbytes((void * const)&random, 32); /* generate static tor node address, take first 32 bytes from secret of node_id plus 32 random bytes from sodiom */ struct sha256 sha; struct secret ss; @@ -1523,7 +1524,7 @@ setup_listeners(const tal_t *ctx, localaddr, 0); /* get rid of blob data on our side of tor and add jitter */ - randombytes_buf((void * const)proposed_wireaddr[i].u.torservice.blob, TOR_V3_BLOBLEN); + randbytes((void * const)proposed_wireaddr[i].u.torservice.blob, TOR_V3_BLOBLEN); if (!(proposed_listen_announce[i] & ADDR_ANNOUNCE)) { continue; diff --git a/connectd/handshake.c b/connectd/handshake.c index 3a11dead0ec0..ad388a62182c 100644 --- a/connectd/handshake.c +++ b/connectd/handshake.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,7 +15,6 @@ #include #include #include -#include #ifndef SUPERVERBOSE #define SUPERVERBOSE(...) @@ -194,7 +194,7 @@ static struct keypair generate_key(void) struct keypair k; do { - randombytes_buf(k.priv.secret.data, sizeof(k.priv.secret.data)); + randbytes(k.priv.secret.data, sizeof(k.priv.secret.data)); } while (!secp256k1_ec_pubkey_create(secp256k1_ctx, &k.pub.pubkey, k.priv.secret.data)); return k; diff --git a/connectd/test/run-crc32_of_update.c b/connectd/test/run-crc32_of_update.c index 838505fc0a84..ca5cd84df387 100644 --- a/connectd/test/run-crc32_of_update.c +++ b/connectd/test/run-crc32_of_update.c @@ -167,18 +167,9 @@ void inject_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } /* Generated stub for node_id_cmp */ int node_id_cmp(const struct node_id *a UNNEEDED, const struct node_id *b UNNEEDED) { fprintf(stderr, "node_id_cmp called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for status_fmt */ void status_fmt(enum log_level level UNNEEDED, const struct node_id *peer UNNEEDED, diff --git a/connectd/test/run-gossip_rcvd_filter.c b/connectd/test/run-gossip_rcvd_filter.c index fcaa06837f33..ef20a1cd6839 100644 --- a/connectd/test/run-gossip_rcvd_filter.c +++ b/connectd/test/run-gossip_rcvd_filter.c @@ -40,12 +40,6 @@ struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u /* Generated stub for amount_tx_fee */ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) { fprintf(stderr, "amount_tx_fee called!\n"); abort(); } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/connectd/test/run-initiator-success.c b/connectd/test/run-initiator-success.c index e90ebb693500..ab95d25df5e9 100644 --- a/connectd/test/run-initiator-success.c +++ b/connectd/test/run-initiator-success.c @@ -123,10 +123,10 @@ void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNE /* AUTOGENERATED MOCKS END */ /* No randomness please, we want to replicate test vectors. */ -#include +#include -static void seed_randomness(u8 *secret, size_t len); -#define randombytes_buf(secret, len) seed_randomness((secret), (len)) +static void seed_randomness(u8 *secret, size_t len, u64 *offset); +#define randbytes_(secret, len, offset) seed_randomness((secret), (len), (offset)) struct handshake; static struct io_plan *test_write(struct io_conn *conn, @@ -197,7 +197,7 @@ const void *trc; static struct pubkey rs_pub, ls_pub, e_pub; static struct privkey ls_priv, e_priv; -static void seed_randomness(u8 *secret, size_t len) +static void seed_randomness(u8 *secret, size_t len, u64 *offset) { assert(len == sizeof(e_priv)); memcpy(secret, &e_priv, len); diff --git a/connectd/test/run-netaddress.c b/connectd/test/run-netaddress.c index 885e4d214d2a..4fee8f6a3f75 100644 --- a/connectd/test/run-netaddress.c +++ b/connectd/test/run-netaddress.c @@ -101,15 +101,6 @@ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr /* Generated stub for is_msg_for_gossipd */ bool is_msg_for_gossipd(const u8 *cursor UNNEEDED) { fprintf(stderr, "is_msg_for_gossipd called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for peer_wire_name */ const char *peer_wire_name(int e UNNEEDED) { fprintf(stderr, "peer_wire_name called!\n"); abort(); } diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c index 53c63970619d..7ddb68cad3f9 100644 --- a/connectd/test/run-responder-success.c +++ b/connectd/test/run-responder-success.c @@ -123,10 +123,10 @@ void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNE /* AUTOGENERATED MOCKS END */ /* No randomness please, we want to replicate test vectors. */ -#include +#include -static void seed_randomness(u8 *secret, size_t len); -#define randombytes_buf(secret, len) seed_randomness((secret), (len)) +static void seed_randomness(u8 *secret, size_t len, u64 *offset); +#define randbytes_(secret, len, offset) seed_randomness((secret), (len), (offset)) struct handshake; static struct io_plan *test_write(struct io_conn *conn, @@ -196,7 +196,7 @@ extern secp256k1_context *secp256k1_ctx; static struct pubkey ls_pub, e_pub; static struct privkey ls_priv, e_priv; -static void seed_randomness(u8 *secret, size_t len) +static void seed_randomness(u8 *secret, size_t len, u64 *offset) { assert(len == sizeof(e_priv)); memcpy(secret, &e_priv, len); diff --git a/connectd/test/run-websocket.c b/connectd/test/run-websocket.c index 69800798db09..393534b036a1 100644 --- a/connectd/test/run-websocket.c +++ b/connectd/test/run-websocket.c @@ -119,15 +119,6 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/gossipd/test/run-check_channel_announcement.c b/gossipd/test/run-check_channel_announcement.c index b914bddda0a8..7e3fe9517c7d 100644 --- a/gossipd/test/run-check_channel_announcement.c +++ b/gossipd/test/run-check_channel_announcement.c @@ -61,15 +61,6 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sciddir_or_pubkey *sciddpk UNNEEDED) { fprintf(stderr, "fromwire_sciddir_or_pubkey called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire_sciddir_or_pubkey */ void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED, const struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/gossipd/test/run-extended-info.c b/gossipd/test/run-extended-info.c index 55715a49ea20..a2f3755f9685 100644 --- a/gossipd/test/run-extended-info.c +++ b/gossipd/test/run-extended-info.c @@ -43,15 +43,6 @@ struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *e void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sciddir_or_pubkey *sciddpk UNNEEDED) { fprintf(stderr, "fromwire_sciddir_or_pubkey called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for peer_supplied_query_response */ void peer_supplied_query_response(struct daemon *daemon UNNEEDED, const struct node_id *source_peer UNNEEDED, diff --git a/gossipd/test/run-next_block_range.c b/gossipd/test/run-next_block_range.c index 9e75b502bae1..49bd20f9eea7 100644 --- a/gossipd/test/run-next_block_range.c +++ b/gossipd/test/run-next_block_range.c @@ -105,12 +105,6 @@ struct gossmap_node *gossmap_nth_node(const struct gossmap *map UNNEEDED, /* Generated stub for gossmap_random_node */ struct gossmap_node *gossmap_random_node(const struct gossmap *map UNNEEDED) { fprintf(stderr, "gossmap_random_node called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } /* Generated stub for memleak_scan_intmap_ */ void memleak_scan_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED) { fprintf(stderr, "memleak_scan_intmap_ called!\n"); abort(); } @@ -125,9 +119,6 @@ struct peer *next_random_peer(struct daemon *daemon UNNEEDED, const struct peer *first UNNEEDED, struct peer_node_id_map_iter *it UNNEEDED) { fprintf(stderr, "next_random_peer called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for query_channel_range */ bool query_channel_range(struct daemon *daemon UNNEEDED, struct peer *peer UNNEEDED, diff --git a/gossipd/test/run-txout_failure.c b/gossipd/test/run-txout_failure.c index 919052b1b1bd..f9c2462d69c1 100644 --- a/gossipd/test/run-txout_failure.c +++ b/gossipd/test/run-txout_failure.c @@ -34,15 +34,6 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sciddir_or_pubkey *sciddpk UNNEEDED) { fprintf(stderr, "fromwire_sciddir_or_pubkey called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire_sciddir_or_pubkey */ void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED, const struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index ff6d1e7b2c91..eaa8a5fc4f61 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -322,7 +323,7 @@ static void maybe_create_new_hsm(const struct secret *encryption_key, /*~ This is libsodium's cryptographic randomness routine: we assume * it's doing a good job. */ if (random_hsm) - randombytes_buf(&hsm_secret, sizeof(hsm_secret)); + randbytes(&hsm_secret, sizeof(hsm_secret)); /*~ If an encryption_key was provided, store an encrypted seed. */ if (encryption_key) diff --git a/lightningd/channel.c b/lightningd/channel.c index 1390a4868713..0db16d1b88a2 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 31362ab6c7ef..8c3c05663dd0 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -1183,8 +1183,8 @@ static struct command_result *json_invoice(struct command *cmd, info->payment_preimage = *preimage; else /* Generate random secret preimage. */ - randombytes_buf(&info->payment_preimage, - sizeof(info->payment_preimage)); + randbytes(&info->payment_preimage, + sizeof(info->payment_preimage)); /* Generate preimage hash. */ sha256(&rhash, &info->payment_preimage, sizeof(info->payment_preimage)); /* Generate payment secret. */ @@ -1623,7 +1623,7 @@ static void add_stub_blindedpath(const tal_t *ctx, path = tal(NULL, struct blinded_path); sciddir_or_pubkey_from_pubkey(&path->first_node_id, &ld->our_pubkey); - randombytes_buf(&path_key, sizeof(path_key)); + randbytes(&path_key, sizeof(path_key)); if (!pubkey_from_privkey(&path_key, &path->first_path_key)) abort(); path->path = tal_arr(path, struct blinded_path_hop *, 1); diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index cbc87029b013..ff5ab45ef02a 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -89,15 +89,9 @@ struct bitcoin_tx *htlc_success_tx(const tal_t *ctx UNNEEDED, /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } /* Generated stub for memleak_ptr */ bool memleak_ptr(struct htable *memtable UNNEEDED, const void *p UNNEEDED) { fprintf(stderr, "memleak_ptr called!\n"); abort(); } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } /* Generated stub for memleak_scan_obj */ void memleak_scan_obj(struct htable *memtable UNNEEDED, const void *obj UNNEEDED) { fprintf(stderr, "memleak_scan_obj called!\n"); abort(); } diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index 453ea3e0e5f8..c9b1d4dd5368 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -139,15 +139,9 @@ struct bitcoin_tx *htlc_timeout_tx(const tal_t *ctx UNNEEDED, /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } /* Generated stub for memleak_ptr */ bool memleak_ptr(struct htable *memtable UNNEEDED, const void *p UNNEEDED) { fprintf(stderr, "memleak_ptr called!\n"); abort(); } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } /* Generated stub for memleak_scan_obj */ void memleak_scan_obj(struct htable *memtable UNNEEDED, const void *obj UNNEEDED) { fprintf(stderr, "memleak_scan_obj called!\n"); abort(); } diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index c40889763d95..a809e30b8648 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,6 @@ #include #include #include -#include static LIST_HEAD(sent_list); @@ -448,7 +448,7 @@ static struct blinded_path *make_reply_path(const tal_t *ctx, assert(tal_count(path) > 0); - randombytes_buf(reply_secret, sizeof(struct secret)); + randbytes(reply_secret, sizeof(struct secret)); if (sent->dev_reply_path) { ids = sent->dev_reply_path; @@ -1016,8 +1016,8 @@ struct command_result *json_fetchinvoice(struct command *cmd, * bytes. */ invreq->invreq_metadata = tal_arr(invreq, u8, 16); - randombytes_buf(invreq->invreq_metadata, - tal_bytelen(invreq->invreq_metadata)); + randbytes(invreq->invreq_metadata, + tal_bytelen(invreq->invreq_metadata)); } } @@ -1405,7 +1405,7 @@ struct command_result *json_sendinvoice(struct command *cmd, * - MUST set `invoice_payment_hash` to the SHA256 hash of the * `payment_preimage` that will be given in return for payment. */ - randombytes_buf(&sent->inv_preimage, sizeof(sent->inv_preimage)); + randbytes(&sent->inv_preimage, sizeof(sent->inv_preimage)); sent->inv->invoice_payment_hash = tal(sent->inv, struct sha256); sha256(sent->inv->invoice_payment_hash, &sent->inv_preimage, sizeof(sent->inv_preimage)); diff --git a/plugins/keysend.c b/plugins/keysend.c index 6104bf607ccd..78a0c823258e 100644 --- a/plugins/keysend.c +++ b/plugins/keysend.c @@ -8,9 +8,9 @@ #include #include #include +#include #include #include -#include #define PREIMAGE_TLV_TYPE 5482373484 #define KEYSEND_FEATUREBIT 55 @@ -49,7 +49,7 @@ static struct keysend_data *keysend_init(struct payment *p) * and populate the preimage field in the keysend_data and the * payment_hash in the payment. */ d = tal(p, struct keysend_data); - randombytes_buf(&d->preimage, sizeof(d->preimage)); + randbytes(&d->preimage, sizeof(d->preimage)); ccan_sha256(&payment_hash, &d->preimage, sizeof(d->preimage)); p->payment_hash = tal_dup(p, struct sha256, &payment_hash); d->extra_tlvs = NULL; diff --git a/plugins/offers_invreq_hook.c b/plugins/offers_invreq_hook.c index c8fe8d6e5ed4..77d5e543fa1b 100644 --- a/plugins/offers_invreq_hook.c +++ b/plugins/offers_invreq_hook.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -961,7 +962,7 @@ static struct command_result *listoffers_done(struct command *cmd, * - MUST set `invoice_payment_hash` to the SHA256 hash of the * `payment_preimage` that will be given in return for payment. */ - randombytes_buf(&ir->preimage, sizeof(ir->preimage)); + randbytes(&ir->preimage, sizeof(ir->preimage)); ir->inv->invoice_payment_hash = tal(ir->inv, struct sha256); sha256(ir->inv->invoice_payment_hash, &ir->preimage, sizeof(ir->preimage)); diff --git a/plugins/offers_offer.c b/plugins/offers_offer.c index a50052cb13b1..82f9dd19aba3 100644 --- a/plugins/offers_offer.c +++ b/plugins/offers_offer.c @@ -10,9 +10,9 @@ #include #include #include +#include #include #include -#include static bool msat_or_any(const char *buffer, const jsmntok_t *tok, @@ -710,8 +710,8 @@ struct command_result *json_invoicerequest(struct command *cmd, * - MUST set `invreq_metadata` to an unpredictable series of bytes. */ invreq->invreq_metadata = tal_arr(invreq, u8, 16); - randombytes_buf(invreq->invreq_metadata, - tal_bytelen(invreq->invreq_metadata)); + randbytes(invreq->invreq_metadata, + tal_bytelen(invreq->invreq_metadata)); /* BOLT #12: * - otherwise (not responding to an offer): diff --git a/plugins/renepay/test/run-bottleneck.c b/plugins/renepay/test/run-bottleneck.c index f22d45fbbf6e..67708a404811 100644 --- a/plugins/renepay/test/run-bottleneck.c +++ b/plugins/renepay/test/run-bottleneck.c @@ -14,9 +14,9 @@ #include #include #include +#include #include #include -#include /* AUTOGENERATED MOCKS START */ /* Generated stub for sciddir_or_pubkey_from_node_id */ @@ -235,7 +235,7 @@ int main(int argc, char *argv[]) pinfo.base_prob_success = 1.0; pinfo.use_shadow = false; - randombytes_buf(&preimage, sizeof(preimage)); + randbytes(&preimage, sizeof(preimage)); sha256(&pinfo.payment_hash, &preimage, sizeof(preimage)); // char hex_preimage[600], hex_sha256[600]; diff --git a/plugins/test/run-funder_policy.c b/plugins/test/run-funder_policy.c index 5c9ec4931026..89e5840c5340 100644 --- a/plugins/test/run-funder_policy.c +++ b/plugins/test/run-funder_policy.c @@ -21,15 +21,6 @@ void json_add_string(struct json_stream *js UNNEEDED, const char *fieldname UNNEEDED, const char *str TAKES UNNEEDED) { fprintf(stderr, "json_add_string called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for pubkey_from_node_id */ bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); } diff --git a/tests/fuzz/connectd_handshake.h b/tests/fuzz/connectd_handshake.h index 6412db8a95c8..da4be733585e 100644 --- a/tests/fuzz/connectd_handshake.h +++ b/tests/fuzz/connectd_handshake.h @@ -1,6 +1,6 @@ /* This header contains globals and helper functions used by all the * fuzz-connectd-handshake-act* fuzz targets. It also takes care of intercepting - * io_read(), io_write(), and randombytes_buf(), so that the actual fuzz targets + * io_read(), io_write(), and randbytes(), so that the actual fuzz targets * only need to implement the test_read() and test_write() interceptors and the * run() function. */ @@ -21,7 +21,7 @@ #include static void seeded_randombytes_buf(u8 *secret, size_t len); -#define randombytes_buf(secret, len) seeded_randombytes_buf((secret), (len)) +#define randbytes(secret, len) seeded_randombytes_buf((secret), (len)) struct handshake; diff --git a/wallet/db.c b/wallet/db.c index 6057952dd9c1..d15f1ee8dd17 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index f9f5ab5c4d35..f8b17c32e60b 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -21,15 +21,6 @@ extern secp256k1_context *secp256k1_ctx; /* AUTOGENERATED MOCKS START */ -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ /* memsetting pubkeys doesn't work */ diff --git a/wire/test/run-tlvstream.c b/wire/test/run-tlvstream.c index b4f704fad17b..2cb0c8ceb567 100644 --- a/wire/test/run-tlvstream.c +++ b/wire/test/run-tlvstream.c @@ -29,15 +29,6 @@ int chainparams_get_ln_port(const struct chainparams *params UNNEEDED) bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire_channel_id */ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "towire_channel_id called!\n"); abort(); } From e11958454352449613a7a9e451661b3d1a0758fa Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:01 +0930 Subject: [PATCH 16/25] pseudorand: make the results in deterministic mode per-caller. Signed-off-by: Rusty Russell --- common/pseudorand.c | 23 ++++++++++++++++++++--- common/pseudorand.h | 11 +++++++---- common/test/run-psbt_diff.c | 6 +++--- connectd/test/run-initiator-success.c | 9 --------- connectd/test/run-responder-success.c | 9 --------- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/common/pseudorand.c b/common/pseudorand.c index 4a6694fd645d..050906605225 100644 --- a/common/pseudorand.c +++ b/common/pseudorand.c @@ -29,25 +29,42 @@ static void init_if_needed(void) } } -uint64_t pseudorand(uint64_t max) +uint64_t pseudorand_(uint64_t max, uint64_t *offset) { init_if_needed(); assert(max); + + /* We try to avoid being order-dependent here. */ + if (randbytes_overridden()) { + uint64_t rand; + randbytes_(&rand, sizeof(rand), offset); + return rand % max; + } return isaac64_next_uint(&isaac64, max); } -uint64_t pseudorand_u64(void) +uint64_t pseudorand_u64_(uint64_t *offset) { init_if_needed(); + if (randbytes_overridden()) { + uint64_t rand; + randbytes_(&rand, sizeof(rand), offset); + return rand; + } return isaac64_next_uint64(&isaac64); } -double pseudorand_double(void) +double pseudorand_double_(uint64_t *offset) { init_if_needed(); + if (randbytes_overridden()) { + uint64_t rand; + randbytes_(&rand, sizeof(rand), offset); + return rand / (double)UINT64_MAX; + } return isaac64_next_double(&isaac64); } diff --git a/common/pseudorand.h b/common/pseudorand.h index a34220055560..e0303eaf094b 100644 --- a/common/pseudorand.h +++ b/common/pseudorand.h @@ -7,18 +7,21 @@ /** * pseudorand - pseudo (guessable!) random number between 0 and max-1. */ -uint64_t pseudorand(uint64_t max); +#define pseudorand(max) ({static uint64_t offset; pseudorand_((max), &offset);}) +uint64_t pseudorand_(uint64_t max, uint64_t *offset); /** - * pseudorand - pseudo (guessable!) random number between 0 and UINT64_MAX. + * pseudorand_u64 - pseudo (guessable!) random number between 0 and UINT64_MAX. */ -uint64_t pseudorand_u64(void); +#define pseudorand_u64() ({static uint64_t offset; pseudorand_u64_(&offset);}) +uint64_t pseudorand_u64_(uint64_t *offset); /** * pseudorand - pseudo (guessable!) random number between 0 (inclusive) and 1 * (exclusive). */ -double pseudorand_double(void); +#define pseudorand_double() ({static uint64_t offset; pseudorand_double_(&offset);}) +double pseudorand_double_(uint64_t *offset); /** * Get the siphash seed for hash tables. diff --git a/common/test/run-psbt_diff.c b/common/test/run-psbt_diff.c index 235163fe0848..1c107851ac66 100644 --- a/common/test/run-psbt_diff.c +++ b/common/test/run-psbt_diff.c @@ -38,9 +38,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for pseudorand_u64 */ -uint64_t pseudorand_u64(void) -{ fprintf(stderr, "pseudorand_u64 called!\n"); abort(); } +/* Generated stub for pseudorand_u64_ */ +uint64_t pseudorand_u64_(uint64_t *offset UNNEEDED) +{ fprintf(stderr, "pseudorand_u64_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/connectd/test/run-initiator-success.c b/connectd/test/run-initiator-success.c index ab95d25df5e9..f9a45fc73847 100644 --- a/connectd/test/run-initiator-success.c +++ b/connectd/test/run-initiator-success.c @@ -83,15 +83,6 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c index 7ddb68cad3f9..e349a9a5ae6e 100644 --- a/connectd/test/run-responder-success.c +++ b/connectd/test/run-responder-success.c @@ -83,15 +83,6 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for memleak_add_helper_ */ -void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED, - const tal_t *)){ } -/* Generated stub for memleak_scan_htable */ -void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED) -{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } From 030cfcaa35c783264fab23a8344269a1075b70d2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:01 +0930 Subject: [PATCH 17/25] gossipd: remove --dev-gossip-time setting, we'll use CLN_DEV_SET_TIME. Signed-off-by: Rusty Russell --- gossipd/gossipd.c | 40 +------------------------------------ gossipd/gossipd.h | 10 ---------- gossipd/gossipd_wire.csv | 5 ----- gossipd/gossmap_manage.c | 2 +- lightningd/gossip_control.c | 28 -------------------------- lightningd/lightningd.c | 1 - lightningd/lightningd.h | 3 --- lightningd/options.c | 4 ---- 8 files changed, 2 insertions(+), 91 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 40bfe551fa9e..f472bf0d01bf 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -374,19 +374,11 @@ static void master_or_connectd_gone(struct daemon_conn *dc UNUSED) exit(2); } -struct timeabs gossip_time_now(const struct daemon *daemon) -{ - if (daemon->dev_gossip_time) - return *daemon->dev_gossip_time; - - return time_now(); -} - /* We don't check this when loading from the gossip_store: that would break * our canned tests, and usually old gossip is better than no gossip */ bool timestamp_reasonable(const struct daemon *daemon, u32 timestamp) { - u64 now = gossip_time_now(daemon).ts.tv_sec; + u64 now = time_now().ts.tv_sec; /* More than one day ahead? */ if (timestamp > now + 24*60*60) @@ -400,27 +392,16 @@ bool timestamp_reasonable(const struct daemon *daemon, u32 timestamp) /*~ Parse init message from lightningd: starts the daemon properly. */ static void gossip_init(struct daemon *daemon, const u8 *msg) { - u32 *dev_gossip_time; - if (!fromwire_gossipd_init(daemon, msg, &chainparams, &daemon->our_features, &daemon->id, - &dev_gossip_time, &daemon->dev_fast_gossip, &daemon->dev_fast_gossip_prune, &daemon->autoconnect_seeker_peers)) { master_badmsg(WIRE_GOSSIPD_INIT, msg); } - if (dev_gossip_time) { - assert(daemon->developer); - daemon->dev_gossip_time = tal(daemon, struct timeabs); - daemon->dev_gossip_time->ts.tv_sec = *dev_gossip_time; - daemon->dev_gossip_time->ts.tv_nsec = 0; - tal_free(dev_gossip_time); - } - /* Gossmap manager starts up */ daemon->gm = gossmap_manage_new(daemon, daemon); @@ -488,18 +469,6 @@ static void dev_gossip_memleak(struct daemon *daemon, const u8 *msg) found_leak))); } -static void dev_gossip_set_time(struct daemon *daemon, const u8 *msg) -{ - u32 time; - - if (!fromwire_gossipd_dev_set_time(msg, &time)) - master_badmsg(WIRE_GOSSIPD_DEV_SET_TIME, msg); - if (!daemon->dev_gossip_time) - daemon->dev_gossip_time = tal(daemon, struct timeabs); - daemon->dev_gossip_time->ts.tv_sec = time; - daemon->dev_gossip_time->ts.tv_nsec = 0; -} - /*~ lightningd tells us when about a gossip message directly, when told to by * the addgossip RPC call. That's usually used when a plugin gets an update * returned in an payment error. */ @@ -591,12 +560,6 @@ static struct io_plan *recv_req(struct io_conn *conn, goto done; } /* fall thru */ - case WIRE_GOSSIPD_DEV_SET_TIME: - if (daemon->developer) { - dev_gossip_set_time(daemon, msg); - goto done; - } - /* fall thru */ /* We send these, we don't receive them */ case WIRE_GOSSIPD_INIT_CUPDATE: @@ -630,7 +593,6 @@ int main(int argc, char *argv[]) daemon = tal(NULL, struct daemon); daemon->developer = developer; - daemon->dev_gossip_time = NULL; daemon->peers = new_htable(daemon, peer_node_id_map); daemon->deferred_txouts = tal_arr(daemon, struct short_channel_id, 0); daemon->current_blockheight = 0; /* i.e. unknown */ diff --git a/gossipd/gossipd.h b/gossipd/gossipd.h index 8318156348dc..6a347e61b251 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -65,9 +65,6 @@ struct daemon { /* Features lightningd told us to set. */ struct feature_set *our_features; - /* Override local time for gossip messages */ - struct timeabs *dev_gossip_time; - /* Speed up gossip. */ bool dev_fast_gossip; @@ -163,13 +160,6 @@ void tell_lightningd_peer_update(struct daemon *daemon, struct amount_msat htlc_minimum, struct amount_msat htlc_maximum); -/** - * Get the local time. - * - * This gets overridden in dev mode so we can use canned (stale) gossip. - */ -struct timeabs gossip_time_now(const struct daemon *daemon); - /** * Is this gossip timestamp reasonable? */ diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index d8bee4b298bb..10ba124da4a7 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -9,7 +9,6 @@ msgtype,gossipd_init,3000 msgdata,gossipd_init,chainparams,chainparams, msgdata,gossipd_init,our_features,feature_set, msgdata,gossipd_init,id,node_id, -msgdata,gossipd_init,dev_gossip_time,?u32, msgdata,gossipd_init,dev_fast_gossip,bool, msgdata,gossipd_init,dev_fast_gossip_prune,bool, msgdata,gossipd_init,autoconnect_seeker_peers,u32, @@ -27,10 +26,6 @@ msgdata,gossipd_init_nannounce,nannounce,u8,len msgtype,gossipd_init_reply,3100 -# In developer mode, we can mess with time. -msgtype,gossipd_dev_set_time,3001 -msgdata,gossipd_dev_set_time,dev_gossip_time,u32, - # Gossipd->master get this tx output please. msgtype,gossipd_get_txout,3018 msgdata,gossipd_get_txout,short_channel_id,short_channel_id, diff --git a/gossipd/gossmap_manage.c b/gossipd/gossmap_manage.c index 29b0a8db1d83..535682003cd0 100644 --- a/gossipd/gossmap_manage.c +++ b/gossipd/gossmap_manage.c @@ -356,7 +356,7 @@ static bool channel_already_dying(const struct chan_dying dying_channels[], /* Every half a week we look for dead channels (faster in dev) */ static void prune_network(struct gossmap_manage *gm) { - u64 now = gossip_time_now(gm->daemon).ts.tv_sec; + u64 now = time_now().ts.tv_sec; /* Anything below this highwater mark ought to be pruned */ const s64 highwater = now - GOSSIP_PRUNE_INTERVAL(gm->daemon->dev_fast_gossip_prune); const struct gossmap_node *me; diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 4e931a7844cf..8bc5f86d6d0d 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -202,7 +202,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_GET_TXOUT_REPLY: case WIRE_GOSSIPD_OUTPOINTS_SPENT: case WIRE_GOSSIPD_DEV_MEMLEAK: - case WIRE_GOSSIPD_DEV_SET_TIME: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: case WIRE_GOSSIPD_ADDGOSSIP: /* This is a reply, so never gets through to here. */ @@ -329,7 +328,6 @@ void gossip_init(struct lightningd *ld, int connectd_fd) chainparams, ld->our_features, &ld->our_nodeid, - ld->dev_gossip_time ? &ld->dev_gossip_time: NULL, ld->dev_fast_gossip, ld->dev_fast_gossip_prune, ld->autoconnect_seeker_peers); @@ -498,29 +496,3 @@ static const struct json_command dev_set_max_scids_encode_size = { .dev_only = true, }; AUTODATA(json_command, &dev_set_max_scids_encode_size); - -static struct command_result *json_dev_gossip_set_time(struct command *cmd, - const char *buffer, - const jsmntok_t *obj UNNEEDED, - const jsmntok_t *params) -{ - u8 *msg; - u32 *time; - - if (!param(cmd, buffer, params, - p_req("time", param_number, &time), - NULL)) - return command_param_failed(); - - msg = towire_gossipd_dev_set_time(NULL, *time); - subd_send_msg(cmd->ld->gossip, take(msg)); - - return command_success(cmd, json_stream_success(cmd)); -} - -static const struct json_command dev_gossip_set_time = { - "dev-gossip-set-time", - json_dev_gossip_set_time, - .dev_only = true, -}; -AUTODATA(json_command, &dev_gossip_set_time); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index ed988d3069f7..41d4608f77f8 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -130,7 +130,6 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->dev_disconnect_fd = -1; ld->dev_subdaemon_fail = false; ld->dev_allow_localhost = false; - ld->dev_gossip_time = 0; ld->dev_fast_gossip = false; ld->dev_fast_gossip_prune = false; ld->dev_throttle_gossip = false; diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index ce8b62b017a6..6d8eac7197d1 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -306,9 +306,6 @@ struct lightningd { /* Allow and accept localhost node_announcement addresses */ bool dev_allow_localhost; - /* Timestamp to use for gossipd, iff non-zero */ - u32 dev_gossip_time; - /* Speedup gossip propagation, for testing. */ bool dev_fast_gossip; bool dev_fast_gossip_prune; diff --git a/lightningd/options.c b/lightningd/options.c index d746c0476e71..4b1dc99dfb9d 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -807,10 +807,6 @@ static void dev_register_opts(struct lightningd *ld) opt_set_bool, &ld->dev_fast_gossip_prune, "Make gossip pruning 120 seconds"); - clnopt_witharg("--dev-gossip-time", OPT_DEV|OPT_SHOWINT, - opt_set_u32, opt_show_u32, - &ld->dev_gossip_time, - "UNIX time to override gossipd to use."); clnopt_witharg("--dev-force-privkey", OPT_DEV, opt_force_privkey, NULL, ld, "Force HSM to use this as node private key"); From 9f874a6ebbe951feb1d1d04e3a52007914fba526 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:01 +0930 Subject: [PATCH 18/25] connectd, gossipd, pay, bcli: use timemono when solely measuring duration for timeouts. This is immune to things like clock changes, and has the convenient side-effect that it will *not* be overridden when we override time for developer purposes. Signed-off-by: Rusty Russell --- connectd/connectd.c | 2 +- connectd/connectd.h | 2 +- connectd/multiplex.c | 6 +++--- gossipd/gossip_store.c | 4 ++-- lightningd/channel.h | 2 +- lightningd/pay.c | 2 +- lightningd/peer_control.c | 2 +- lightningd/peer_htlcs.c | 4 ++-- plugins/bcli.c | 6 +++--- plugins/keysend.c | 2 +- plugins/libplugin-pay.c | 4 ++-- plugins/libplugin-pay.h | 2 +- plugins/pay.c | 2 +- 13 files changed, 20 insertions(+), 20 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 26e1fa1d9b61..a7df66e7273d 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -150,7 +150,7 @@ static struct peer *new_peer(struct daemon *daemon, peer->draining = false; peer->peer_in_lastmsg = -1; peer->peer_outq = msg_queue_new(peer, false); - peer->last_recv_time = time_now(); + peer->last_recv_time = time_mono(); peer->is_websocket = is_websocket; peer->dev_writes_enabled = NULL; peer->dev_read_enabled = true; diff --git a/connectd/connectd.h b/connectd/connectd.h index d3fb0c33abf7..752443f7f591 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -95,7 +95,7 @@ struct peer { struct oneshot *ping_timer; /* Last time we received traffic */ - struct timeabs last_recv_time; + struct timemono last_recv_time; /* How long have we been ignoring peer input? */ struct timemono peer_in_lasttime; diff --git a/connectd/multiplex.c b/connectd/multiplex.c index d7cbf80e2b59..643c34fbfdf1 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -646,8 +646,8 @@ static void send_ping(struct peer *peer) /* If it's still sending us traffic, maybe ping reply is backed up? * That's OK, ping is just to make sure it's still alive, and clearly * it is. */ - if (time_before(peer->last_recv_time, - timeabs_sub(time_now(), time_from_sec(60)))) { + if (timemono_before(peer->last_recv_time, + timemono_sub(time_mono(), time_from_sec(60)))) { /* Already have a ping in flight? */ if (peer->expecting_pong != PONG_UNEXPECTED) { status_peer_debug(&peer->id, "Last ping unreturned: hanging up"); @@ -1260,7 +1260,7 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, } /* We got something! */ - peer->last_recv_time = time_now(); + peer->last_recv_time = time_mono(); /* Don't process packets while we're closing */ if (peer->draining) diff --git a/gossipd/gossip_store.c b/gossipd/gossip_store.c index 906b6c10f22e..ca4d62a36209 100644 --- a/gossipd/gossip_store.c +++ b/gossipd/gossip_store.c @@ -204,7 +204,7 @@ static int gossip_store_compact(struct daemon *daemon, struct gossip_hdr hdr; u8 oldversion, version = GOSSIP_STORE_VER; struct stat st; - struct timeabs start = time_now(); + struct timemono start = time_mono(); const char *bad; *populated = false; @@ -370,7 +370,7 @@ static int gossip_store_compact(struct daemon *daemon, } status_debug("Store compact time: %"PRIu64" msec", - time_to_msec(time_between(time_now(), start))); + time_to_msec(timemono_between(time_mono(), start))); status_debug("gossip_store: Read %zu/%zu/%zu/%zu cannounce/cupdate/nannounce/delete from store in %"PRIu64" bytes, now %"PRIu64" bytes (populated=%s)", cannounces, cupdates, nannounces, deleted, old_len, *total_len, diff --git a/lightningd/channel.h b/lightningd/channel.h index fd8e031b0c39..94960601b434 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -294,7 +294,7 @@ struct channel { u32 feerate_base, feerate_ppm; /* But allow these feerates/htlcs up until this time. */ - struct timeabs old_feerate_timeout; + struct timemono old_feerate_timeout; u32 old_feerate_base, old_feerate_ppm; struct amount_msat old_htlc_minimum_msat, old_htlc_maximum_msat; diff --git a/lightningd/pay.c b/lightningd/pay.c index 44931d700ea3..2111e5b4091a 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -2021,7 +2021,7 @@ static struct command_result *json_injectpaymentonion(struct command *cmd, if (amount_msat_greater(*msat, next->htlc_maximum_msat) || amount_msat_less(*msat, next->htlc_minimum_msat)) { /* Are we in old-range grace-period? */ - if (!time_before(time_now(), next->old_feerate_timeout) + if (!timemono_before(time_mono(), next->old_feerate_timeout) || amount_msat_less(*msat, next->old_htlc_minimum_msat) || amount_msat_greater(*msat, next->old_htlc_maximum_msat)) { return command_fail(cmd, JSONRPC2_INVALID_PARAMS, diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 132afbd0a6b8..b4f1c04f7df6 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -3178,7 +3178,7 @@ static void set_channel_config(struct command *cmd, struct channel *channel, || (htlc_max && amount_msat_less(*htlc_max, channel->htlc_maximum_msat))) { channel->old_feerate_timeout - = timeabs_add(time_now(), time_from_sec(delaysecs)); + = timemono_add(time_mono(), time_from_sec(delaysecs)); channel->old_feerate_base = channel->feerate_base; channel->old_feerate_ppm = channel->feerate_ppm; channel->old_htlc_minimum_msat = channel->htlc_minimum_msat; diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 27c3a4757674..e776bde0fc5d 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -856,7 +856,7 @@ static void forward_htlc(struct htlc_in *hin, * - If it creates a new `channel_update` with updated channel parameters: * - SHOULD keep accepting the previous channel parameters for 10 minutes */ - if (!time_before(time_now(), next->old_feerate_timeout) + if (!timemono_before(time_mono(), next->old_feerate_timeout) || !check_fwd_amount(hin, amt_to_forward, hin->msat, next->old_feerate_base, next->old_feerate_ppm)) { @@ -872,7 +872,7 @@ static void forward_htlc(struct htlc_in *hin, if (amount_msat_greater(amt_to_forward, next->htlc_maximum_msat) || amount_msat_less(amt_to_forward, next->htlc_minimum_msat)) { /* Are we in old-range grace-period? */ - if (!time_before(time_now(), next->old_feerate_timeout) + if (!timemono_before(time_mono(), next->old_feerate_timeout) || amount_msat_less(amt_to_forward, next->old_htlc_minimum_msat) || amount_msat_greater(amt_to_forward, next->old_htlc_maximum_msat)) { failmsg = towire_temporary_channel_failure(tmpctx, diff --git a/plugins/bcli.c b/plugins/bcli.c index fdd5a7c6e228..198edcf70166 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -76,7 +76,7 @@ struct bitcoin_cli { int *exitstatus; pid_t pid; const char **args; - struct timeabs start; + struct timemono start; enum bitcoind_prio prio; char *output; size_t output_bytes; @@ -247,7 +247,7 @@ static void bcli_finished(struct io_conn *conn UNUSED, struct bitcoin_cli *bcli) int ret, status; struct command_result *res; enum bitcoind_prio prio = bcli->prio; - u64 msec = time_to_msec(time_between(time_now(), bcli->start)); + u64 msec = time_to_msec(timemono_between(time_mono(), bcli->start)); /* If it took over 10 seconds, that's rather strange. */ if (msec > 10000) @@ -318,7 +318,7 @@ static void next_bcli(enum bitcoind_prio prio) close(in); - bcli->start = time_now(); + bcli->start = time_mono(); bitcoind->num_requests[prio]++; diff --git a/plugins/keysend.c b/plugins/keysend.c index 78a0c823258e..b1b51a5f6f47 100644 --- a/plugins/keysend.c +++ b/plugins/keysend.c @@ -241,7 +241,7 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf, p->invstring_used = true; p->why = "Initial attempt"; p->constraints.cltv_budget = *maxdelay; - p->deadline = timeabs_add(time_now(), time_from_sec(*retryfor)); + p->deadline = timemono_add(time_mono(), time_from_sec(*retryfor)); p->getroute->riskfactorppm = 10000000; if (node_id_eq(&my_id, p->route_destination)) { diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index b296b87d7a97..adaf9bdfcb6c 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -2525,12 +2525,12 @@ static struct command_result *retry_step_cb(struct retry_mod_data *rd, { struct payment *subpayment, *root = payment_root(p); struct retry_mod_data *rdata = payment_mod_retry_get_data(p); - struct timeabs now = time_now(); + struct timemono now = time_mono(); if (p->step != PAYMENT_STEP_FAILED) return payment_continue(p); - if (time_after(now, p->deadline)) { + if (timemono_after(now, p->deadline)) { paymod_log( p, LOG_INFORM, "Payment deadline expired, not retrying (partial-)payment " diff --git a/plugins/libplugin-pay.h b/plugins/libplugin-pay.h index bc1ec51b5dc9..20b6fae6f355 100644 --- a/plugins/libplugin-pay.h +++ b/plugins/libplugin-pay.h @@ -206,7 +206,7 @@ struct payment { u32 start_block; struct timeabs start_time, end_time; - struct timeabs deadline; + struct timemono deadline; /* Constraints the state machine and modifiers needs to maintain. */ struct payment_constraints constraints; diff --git a/plugins/pay.c b/plugins/pay.c index 7deaf85bc518..87ad826f1bec 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -1480,7 +1480,7 @@ static struct command_result *json_pay(struct command *cmd, p->why = "Initial attempt"; p->constraints.cltv_budget = *maxdelay; tal_free(maxdelay); - p->deadline = timeabs_add(time_now(), time_from_sec(*retryfor)); + p->deadline = timemono_add(time_mono(), time_from_sec(*retryfor)); tal_free(retryfor); p->getroute->riskfactorppm = *riskfactor_millionths; tal_free(riskfactor_millionths); From 492f13bbce92b25f0ad179fe6c3937a8e5d50fc7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:01 +0930 Subject: [PATCH 19/25] common/clock_time: wrapper for time_now() so we can override it. Signed-off-by: Rusty Russell --- channeld/Makefile | 1 + closingd/Makefile | 1 + common/Makefile | 1 + common/clock_time.c | 36 ++++++++++++++++++++++++++++++++++++ common/clock_time.h | 19 +++++++++++++++++++ common/daemon.c | 12 +++++++++++- connectd/Makefile | 1 + devtools/Makefile | 1 + gossipd/Makefile | 1 + hsmd/Makefile | 1 + lightningd/Makefile | 1 + onchaind/Makefile | 1 + onchaind/test/Makefile | 1 + openingd/Makefile | 1 + plugins/Makefile | 1 + tests/plugins/Makefile | 1 + 16 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 common/clock_time.c create mode 100644 common/clock_time.h diff --git a/channeld/Makefile b/channeld/Makefile index e6673a56326c..cd7aae387548 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -48,6 +48,7 @@ CHANNELD_COMMON_OBJS := \ common/channel_config.o \ common/channel_id.o \ common/channel_type.o \ + common/clock_time.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/closingd/Makefile b/closingd/Makefile index c3d055acbf68..c48d4db0f392 100644 --- a/closingd/Makefile +++ b/closingd/Makefile @@ -25,6 +25,7 @@ CLOSINGD_COMMON_OBJS := \ common/bigsize.o \ common/bip32.o \ common/channel_id.o \ + common/clock_time.o \ common/close_tx.o \ common/cryptomsg.o \ common/daemon.o \ diff --git a/common/Makefile b/common/Makefile index 18381e02859b..b8b50eff7b0a 100644 --- a/common/Makefile +++ b/common/Makefile @@ -21,6 +21,7 @@ COMMON_SRC_NOGEN := \ common/channel_config.c \ common/channel_id.c \ common/channel_type.c \ + common/clock_time.c \ common/close_tx.c \ common/codex32.c \ common/coin_mvt.c \ diff --git a/common/clock_time.c b/common/clock_time.c new file mode 100644 index 000000000000..e3a982d77e4f --- /dev/null +++ b/common/clock_time.c @@ -0,0 +1,36 @@ +#include "config.h" +#include +#include + +static bool used = false; +static struct timeabs dev_override; + +bool clock_time_overridden(void) +{ + return dev_override.ts.tv_sec != 0; +} + +struct timeabs clock_time(void) +{ + used = true; + if (!clock_time_overridden()) + return time_now(); /* discouraged: use clock_time so we can override */ + + return dev_override; +} + +struct timeabs clock_time_progresses_(u64 *progress) +{ + if (!clock_time_overridden()) + return clock_time(); + + return timeabs_add(dev_override, time_from_sec((*progress)++)); +} + +void dev_override_clock_time(struct timeabs now) +{ + assert(!used); + + dev_override = now; + assert(clock_time_overridden()); +} diff --git a/common/clock_time.h b/common/clock_time.h new file mode 100644 index 000000000000..a267abf461d9 --- /dev/null +++ b/common/clock_time.h @@ -0,0 +1,19 @@ +#ifndef LIGHTNING_COMMON_CLOCK_TIME_H +#define LIGHTNING_COMMON_CLOCK_TIME_H +#include "config.h" +#include +#include + +/* We use this instead of time_now, for overriding when we want reproducibility */ +struct timeabs clock_time(void); + +/* If you need a clock that progresses even when reproducible, use this. */ +#define clock_time_progresses() ({static u64 progress; clock_time_progresses_(&progress);}) +struct timeabs clock_time_progresses_(u64 *progress); + +/* dev setting to override time */ +void dev_override_clock_time(struct timeabs now); + +/* Did someone override time? */ +bool clock_time_overridden(void); +#endif /* LIGHTNING_COMMON_CLOCK_TIME_H */ diff --git a/common/daemon.c b/common/daemon.c index 9d09b7c8b4d6..dc0a7b829398 100644 --- a/common/daemon.c +++ b/common/daemon.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -199,7 +200,7 @@ void daemon_shutdown(void) bool daemon_developer_mode(char *argv[]) { bool developer = false, debug = false; - const char *entropy_override; + const char *entropy_override, *time_override; for (int i = 1; argv[i]; i++) { if (streq(argv[i], "--dev-debug-self")) @@ -230,6 +231,15 @@ bool daemon_developer_mode(char *argv[]) if (entropy_override) dev_override_randbytes(argv[0], atol(entropy_override)); + /* We can also control TIME ITSELF! */ + time_override = getenv("CLN_DEV_SET_TIME"); + if (time_override) { + struct timeabs t; + t.ts.tv_nsec = 0; + t.ts.tv_sec = atol(time_override); + dev_override_clock_time(t); + } + /* This checks for any tal_steal loops, but it's not free: * only use if we're already using the fairly heavy memleak * detection. */ diff --git a/connectd/Makefile b/connectd/Makefile index 78624204c417..0300e27623ee 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -48,6 +48,7 @@ CONNECTD_COMMON_OBJS := \ common/blinding.o \ common/blindedpath.o \ common/channel_id.o \ + common/clock_time.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/devtools/Makefile b/devtools/Makefile index aa7cdd5c36bf..be005a77357b 100644 --- a/devtools/Makefile +++ b/devtools/Makefile @@ -29,6 +29,7 @@ DEVTOOLS_COMMON_OBJS := \ common/bolt11.o \ common/blockheight_states.o \ common/channel_id.o \ + common/clock_time.o \ common/decode_array.o \ common/features.o \ common/fee_states.o \ diff --git a/gossipd/Makefile b/gossipd/Makefile index a33a2c256553..76999cf93f67 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -35,6 +35,7 @@ GOSSIPD_COMMON_OBJS := \ common/bigsize.o \ common/bip32.o \ common/channel_id.o \ + common/clock_time.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/hsmd/Makefile b/hsmd/Makefile index bed5724ef194..fc3aa3826d00 100644 --- a/hsmd/Makefile +++ b/hsmd/Makefile @@ -31,6 +31,7 @@ HSMD_COMMON_OBJS := \ common/bolt12_id.o \ common/bolt12_merkle.o \ common/channel_id.o \ + common/clock_time.o \ common/daemon.o \ common/daemon_conn.o \ common/derive_basepoints.o \ diff --git a/lightningd/Makefile b/lightningd/Makefile index e5bd4e820638..250835584629 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -95,6 +95,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/channel_config.o \ common/channel_id.o \ common/channel_type.o \ + common/clock_time.o \ common/coin_mvt.o \ common/configdir.o \ common/configvar.o \ diff --git a/onchaind/Makefile b/onchaind/Makefile index 32af13fa3b39..fdccc7ee39dd 100644 --- a/onchaind/Makefile +++ b/onchaind/Makefile @@ -36,6 +36,7 @@ ONCHAIND_COMMON_OBJS := \ common/base32.o \ common/bigsize.o \ common/bip32.o \ + common/clock_time.o \ common/coin_mvt.o \ common/channel_id.o \ common/daemon.o \ diff --git a/onchaind/test/Makefile b/onchaind/test/Makefile index 307a67e117ba..717b6d999083 100644 --- a/onchaind/test/Makefile +++ b/onchaind/test/Makefile @@ -25,6 +25,7 @@ $(ONCHAIND_TEST_PROGRAMS): $(ONCHAIND_TEST_COMMON_OBJS) $(BITCOIN_OBJS) onchaind/test/run-onchainstress: \ common/htlc_tx.o \ common/derive_basepoints.o \ + common/clock_time.o \ common/daemon.o \ common/htlc_wire.o \ common/initial_commit_tx.o \ diff --git a/openingd/Makefile b/openingd/Makefile index 29f4a4eba04c..e5a37438e1b0 100644 --- a/openingd/Makefile +++ b/openingd/Makefile @@ -41,6 +41,7 @@ OPENINGD_COMMON_OBJS := \ common/channel_config.o \ common/channel_id.o \ common/channel_type.o \ + common/clock_time.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/plugins/Makefile b/plugins/Makefile index de10fd9171ef..d5c94e085aec 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -181,6 +181,7 @@ PLUGIN_COMMON_OBJS := \ common/bigsize.o \ common/bolt11.o \ common/channel_id.o \ + common/clock_time.o \ common/daemon.o \ common/deprecation.o \ common/features.o \ diff --git a/tests/plugins/Makefile b/tests/plugins/Makefile index 11d1d494132e..ed9f4ee0ab3d 100644 --- a/tests/plugins/Makefile +++ b/tests/plugins/Makefile @@ -44,6 +44,7 @@ tests/plugins/channeld_fakenet: \ common/channel_config.o \ common/channel_id.o \ common/channel_type.o \ + common/clock_time.o \ common/daemon.o \ common/daemon_conn.o \ common/derive_basepoints.o \ From 286de30b301aff83c6b728e60795f3d49bf286a5 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:01 +0930 Subject: [PATCH 20/25] global: use clock_time in place of time_now(). Except for tracing, that sticks with time_now(). Signed-off-by: Rusty Russell --- Makefile | 2 +- bitcoin/test/Makefile | 2 +- common/coin_mvt.c | 24 +++++++++++++------ common/coin_mvt.h | 3 +++ common/test/Makefile | 1 + common/test/run-json.c | 1 + common/test/run-param.c | 1 + common/test/run-route_blinding_test.c | 1 + common/trace.c | 4 ++-- connectd/connectd.c | 3 ++- devtools/bolt11-cli.c | 3 ++- devtools/gossipwith.c | 3 ++- gossipd/gossip_store.c | 3 ++- gossipd/gossipd.c | 5 ++-- gossipd/gossmap_manage.c | 3 ++- gossipd/seeker.c | 3 ++- gossipd/test/run-check_channel_announcement.c | 7 ++++++ gossipd/test/run-extended-info.c | 7 ++++++ gossipd/test/run-next_block_range.c | 9 +++++++ gossipd/test/run-txout_failure.c | 7 ++++++ lightningd/channel.c | 3 ++- lightningd/channel_gossip.c | 5 ++-- lightningd/coin_mvts.c | 13 +++++----- lightningd/dual_open_control.c | 5 ++-- lightningd/gossip_generation.c | 5 ++-- lightningd/htlc_end.c | 3 ++- lightningd/invoice.c | 3 ++- lightningd/log.c | 7 +++--- lightningd/opening_control.c | 3 ++- lightningd/pay.c | 7 +++--- lightningd/runes.c | 3 ++- lightningd/test/Makefile | 1 + plugins/askrene/askrene.c | 6 ++--- plugins/autoclean.c | 3 ++- plugins/bkpr/bookkeeper.c | 1 + plugins/bkpr/incomestmt.c | 3 ++- plugins/bkpr/test/run-recorder.c | 7 ++++++ plugins/bkpr/test/run-sql.c | 7 ++++++ plugins/chanbackup.c | 3 ++- plugins/fetchinvoice.c | 7 +++--- plugins/keysend.c | 4 +++- plugins/libplugin-pay.c | 15 ++++++------ plugins/offers.c | 3 ++- plugins/offers_inv_hook.c | 3 ++- plugins/offers_invreq_hook.c | 5 ++-- plugins/pay.c | 7 +++--- plugins/renepay/main.c | 3 ++- plugins/renepay/mods.c | 5 ++-- plugins/renepay/payment.c | 3 ++- plugins/renepay/test/run-bottleneck.c | 3 ++- plugins/test/Makefile | 1 + plugins/xpay/xpay.c | 7 +++--- tests/fuzz/Makefile | 1 + tools/bench-gossipd.sh | 2 +- wallet/invoices.c | 9 +++---- wallet/test/Makefile | 1 + wallet/wallet.c | 5 ++-- 57 files changed, 183 insertions(+), 81 deletions(-) diff --git a/Makefile b/Makefile index 8fea6d098f32..324f86cc158f 100644 --- a/Makefile +++ b/Makefile @@ -569,7 +569,7 @@ check-tmpctx: @if git grep -n 'tal_free[(]tmpctx)' | grep -Ev '^ccan/|/test/|^common/setup.c:|^common/utils.c:'; then echo "Don't free tmpctx!">&2; exit 1; fi check-discouraged-functions: - @if git grep -nE "[^a-z_/](fgets|fputs|gets|scanf|sprintf|randombytes_buf)\(" -- "*.c" "*.h" ":(exclude)ccan/" ":(exclude)contrib/" | grep -Fv '/* discouraged:'; then exit 1; fi + @if git grep -nE "[^a-z_/](fgets|fputs|gets|scanf|sprintf|randombytes_buf|time_now)\(" -- "*.c" "*.h" ":(exclude)ccan/" ":(exclude)contrib/" | grep -Fv '/* discouraged:'; then exit 1; fi # Don't access amount_msat and amount_sat members directly without a good reason # since it risks overflow. diff --git a/bitcoin/test/Makefile b/bitcoin/test/Makefile index 7b15ab9ae07f..fd29ff5907ce 100644 --- a/bitcoin/test/Makefile +++ b/bitcoin/test/Makefile @@ -2,7 +2,7 @@ BITCOIN_TEST_SRC := $(wildcard bitcoin/test/run-*.c) BITCOIN_TEST_OBJS := $(BITCOIN_TEST_SRC:.c=.o) BITCOIN_TEST_PROGRAMS := $(BITCOIN_TEST_OBJS:.o=) -BITCOIN_TEST_COMMON_OBJS := common/utils.o common/setup.o common/autodata.o +BITCOIN_TEST_COMMON_OBJS := common/utils.o common/setup.o common/autodata.o common/clock_time.o $(BITCOIN_TEST_PROGRAMS): $(BITCOIN_TEST_COMMON_OBJS) bitcoin/chainparams.o $(BITCOIN_TEST_OBJS): $(CCAN_HEADERS) $(BITCOIN_HEADERS) $(BITCOIN_SRC) diff --git a/common/coin_mvt.c b/common/coin_mvt.c index 4e9ec871e0a6..b15663aaaf17 100644 --- a/common/coin_mvt.c +++ b/common/coin_mvt.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -154,6 +154,12 @@ static enum mvt_tag mvt_tag_in_db(enum mvt_tag mvt_tag) abort(); } +/* This puts the coin movements in order */ +u64 coinmvt_current_time(void) +{ + return clock_time_progresses().ts.tv_sec; +} + const char *mvt_tag_str(enum mvt_tag tag) { assert((unsigned)tag < NUM_MVT_TAGS); @@ -337,7 +343,7 @@ static struct chain_coin_mvt *new_chain_coin_mvt_sat(const tal_t *ctx, assert(ok); return new_chain_coin_mvt(ctx, channel, account_name, - time_now().ts.tv_sec, tx_txid, + coinmvt_current_time(), tx_txid, outpoint, payment_hash, blockheight, tags, direction, amt_msat, /* All amounts that are sat are @@ -392,7 +398,7 @@ struct chain_coin_mvt *new_coin_channel_close(const tal_t *ctx, tags = mk_mvt_tags(MVT_CHANNEL_CLOSE); mvt = new_chain_coin_mvt(ctx, channel, alt_account, - time_now().ts.tv_sec, txid, + coinmvt_current_time(), txid, out, NULL, blockheight, tags, COIN_DEBIT, amount, @@ -420,7 +426,7 @@ struct chain_coin_mvt *new_coin_channel_open_proposed(const tal_t *ctx, if (is_leased) mvt_tag_set(&tags, MVT_LEASED); - mvt = new_chain_coin_mvt(ctx, channel, NULL, time_now().ts.tv_sec, + mvt = new_chain_coin_mvt(ctx, channel, NULL, coinmvt_current_time(), NULL, out, NULL, 0, tags, COIN_CREDIT, amount, output_val, 0); @@ -473,7 +479,7 @@ struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx, bool is_leased) { return new_coin_channel_open_general(ctx, channel, NULL, - time_now().ts.tv_sec, + coinmvt_current_time(), out, peer_id, blockheight, amount, output_val, is_opener, is_leased); } @@ -515,7 +521,7 @@ struct chain_coin_mvt *new_coin_external_spend(const tal_t *ctx, struct mvt_tags tags) { return new_chain_coin_mvt(ctx, NULL, ACCOUNT_NAME_EXTERNAL, - time_now().ts.tv_sec, txid, + coinmvt_current_time(), txid, outpoint, NULL, blockheight, tags, COIN_CREDIT, AMOUNT_MSAT(0), amount, 0); @@ -583,7 +589,7 @@ struct channel_coin_mvt *new_coin_channel_push(const tal_t *ctx, struct mvt_tags tags) { return new_coin_channel_push_general(ctx, channel, NULL, - time_now().ts.tv_sec, + coinmvt_current_time(), direction, amount, tags); } @@ -730,6 +736,10 @@ void fromwire_chain_coin_mvt(const u8 **cursor, size_t *max, struct chain_coin_m } else mvt->peer_id = NULL; mvt->timestamp = fromwire_u64(cursor, max); + + /* Align onchaind's timestamps with ours if we're deterministic */ + if (clock_time_overridden()) + mvt->timestamp = coinmvt_current_time(); } struct mvt_tags mk_mvt_tags_(enum mvt_tag tag, ...) diff --git a/common/coin_mvt.h b/common/coin_mvt.h index e9a41b3251cd..fb20f5aaaebe 100644 --- a/common/coin_mvt.h +++ b/common/coin_mvt.h @@ -348,4 +348,7 @@ bool mvt_tag_parse(const char *buf, size_t len, enum mvt_tag *tag); void towire_chain_coin_mvt(u8 **pptr, const struct chain_coin_mvt *mvt); void fromwire_chain_coin_mvt(const u8 **cursor, size_t *max, struct chain_coin_mvt *mvt); +/* Time helper for deterministic timestamps: always moves forwards */ +u64 coinmvt_current_time(void); + #endif /* LIGHTNING_COMMON_COIN_MVT_H */ diff --git a/common/test/Makefile b/common/test/Makefile index 410ffde1270a..8c26954a206b 100644 --- a/common/test/Makefile +++ b/common/test/Makefile @@ -7,6 +7,7 @@ COMMON_TEST_COMMON_OBJS := \ common/autodata.o \ common/memleak.o \ common/randbytes.o \ + common/clock_time.o \ common/setup.o \ common/utils.o diff --git a/common/test/run-json.c b/common/test/run-json.c index cbb3b42af1ce..10733adaedbb 100644 --- a/common/test/run-json.c +++ b/common/test/run-json.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-param.c b/common/test/run-param.c index 749f6a4946a2..ddb5cab1e6a2 100644 --- a/common/test/run-param.c +++ b/common/test/run-param.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/common/test/run-route_blinding_test.c b/common/test/run-route_blinding_test.c index 31a83a28caa4..2b3ef812f77e 100644 --- a/common/test/run-route_blinding_test.c +++ b/common/test/run-route_blinding_test.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/common/trace.c b/common/trace.c index f64faa0ef440..1be745bed474 100644 --- a/common/trace.c +++ b/common/trace.c @@ -77,7 +77,7 @@ static void init_span(struct span *s, const char *name, struct span *parent) { - struct timeabs now = time_now(); + struct timeabs now = time_now(); /* discouraged: but tracing wants non-dev time */ s->key = key; s->id = pseudorand_u64(); @@ -368,7 +368,7 @@ void trace_span_end(const void *key) trace_check_tree(); - struct timeabs now = time_now(); + struct timeabs now = time_now(); /* discouraged: but tracing wants non-dev time */ s->end_time = (now.ts.tv_sec * 1000000) + now.ts.tv_nsec / 1000; DTRACE_PROBE1(lightningd, span_end, s->id); if (trace_to_file) { diff --git a/connectd/connectd.c b/connectd/connectd.c index a7df66e7273d..15224912419d 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -2192,7 +2193,7 @@ static void dev_report_fds(struct daemon *daemon, const u8 *msg) void update_recent_timestamp(struct daemon *daemon, struct gossmap *gossmap) { /* 2 hours allows for some clock drift, not too much gossip */ - u32 recent = time_now().ts.tv_sec - 7200; + u32 recent = clock_time().ts.tv_sec - 7200; /* Only update every minute */ if (daemon->gossip_recent_time + 60 > recent) diff --git a/devtools/bolt11-cli.c b/devtools/bolt11-cli.c index 5553822c6738..cc11e9dbe08b 100644 --- a/devtools/bolt11-cli.c +++ b/devtools/bolt11-cli.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -108,7 +109,7 @@ static void encode(const tal_t *ctx, struct pubkey me; bool explicit_n = false; - b11->timestamp = time_now().ts.tv_sec; + b11->timestamp = clock_time().ts.tv_sec; b11->chain = chainparams_for_network("regtest"); b11->expiry = 3600; b11->min_final_cltv_expiry = DEFAULT_FINAL_CLTV_DELTA; diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index f506787cd4e3..316787e5127d 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -214,7 +215,7 @@ static struct io_plan *handshake_success(struct io_conn *conn, msg = towire_gossip_timestamp_filter(NULL, &chainparams->genesis_blockhash, all_gossip ? 0 - : no_gossip ? 0xFFFFFFFF : time_now().ts.tv_sec, + : no_gossip ? 0xFFFFFFFF : clock_time().ts.tv_sec, 0xFFFFFFFF); sync_crypto_write(peer_fd, cs, take(msg)); } diff --git a/gossipd/gossip_store.c b/gossipd/gossip_store.c index ca4d62a36209..120b265b80f1 100644 --- a/gossipd/gossip_store.c +++ b/gossipd/gossip_store.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -351,7 +352,7 @@ static int gossip_store_compact(struct daemon *daemon, /* If we have any contents, and the file is less than 1 hour * old, say "seems good" */ - if (st.st_mtime > time_now().ts.tv_sec - 3600 && *total_len > 1) { + if (st.st_mtime > clock_time().ts.tv_sec - 3600 && *total_len > 1) { *populated = true; } diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index f472bf0d01bf..de420fd485a0 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -13,6 +13,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -378,7 +379,7 @@ static void master_or_connectd_gone(struct daemon_conn *dc UNUSED) * our canned tests, and usually old gossip is better than no gossip */ bool timestamp_reasonable(const struct daemon *daemon, u32 timestamp) { - u64 now = time_now().ts.tv_sec; + u64 now = clock_time().ts.tv_sec; /* More than one day ahead? */ if (timestamp > now + 24*60*60) @@ -603,7 +604,7 @@ int main(int argc, char *argv[]) /* Note the use of time_mono() here. That's a monotonic clock, which * is really useful: it can only be used to measure relative events * (there's no correspondence to time-since-Ken-grew-a-beard or - * anything), but unlike time_now(), this will never jump backwards by + * anything), but unlike time_now, this will never jump backwards by * half a second and leave me wondering how my tests failed CI! */ timers_init(&daemon->timers, time_mono()); diff --git a/gossipd/gossmap_manage.c b/gossipd/gossmap_manage.c index 535682003cd0..c75f8a19b94f 100644 --- a/gossipd/gossmap_manage.c +++ b/gossipd/gossmap_manage.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -356,7 +357,7 @@ static bool channel_already_dying(const struct chan_dying dying_channels[], /* Every half a week we look for dead channels (faster in dev) */ static void prune_network(struct gossmap_manage *gm) { - u64 now = time_now().ts.tv_sec; + u64 now = clock_time().ts.tv_sec; /* Anything below this highwater mark ought to be pruned */ const s64 highwater = now - GOSSIP_PRUNE_INTERVAL(gm->daemon->dev_fast_gossip_prune); const struct gossmap_node *me; diff --git a/gossipd/seeker.c b/gossipd/seeker.c index 414aa3e73626..7a8a7e76f849 100644 --- a/gossipd/seeker.c +++ b/gossipd/seeker.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -245,7 +246,7 @@ static void enable_gossip_stream(struct seeker *seeker, struct peer *peer, start = 0; } else { /* Just in case they care */ - start = time_now().ts.tv_sec - GOSSIP_SEEKER_INTERVAL(seeker) * 10; + start = clock_time().ts.tv_sec - GOSSIP_SEEKER_INTERVAL(seeker) * 10; } status_peer_debug(&peer->id, "seeker: starting gossip (%s)", diff --git a/gossipd/test/run-check_channel_announcement.c b/gossipd/test/run-check_channel_announcement.c index 7e3fe9517c7d..a55ca5dca6ab 100644 --- a/gossipd/test/run-check_channel_announcement.c +++ b/gossipd/test/run-check_channel_announcement.c @@ -33,6 +33,7 @@ In particular, we set feature bit 19. The spec says we should set feature bit 1 #include #include #include +#include #include #include #include @@ -57,6 +58,12 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, const struct sha256 *h UNNEEDED, struct privkey *next UNNEEDED) { fprintf(stderr, "blinding_next_path_privkey called!\n"); abort(); } +/* Generated stub for clock_time_overridden */ +bool clock_time_overridden(void) +{ fprintf(stderr, "clock_time_overridden called!\n"); abort(); } +/* Generated stub for clock_time_progresses_ */ +struct timeabs clock_time_progresses_(u64 *progress UNNEEDED) +{ fprintf(stderr, "clock_time_progresses_ called!\n"); abort(); } /* Generated stub for fromwire_sciddir_or_pubkey */ void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/gossipd/test/run-extended-info.c b/gossipd/test/run-extended-info.c index a2f3755f9685..5dfe23ae8813 100644 --- a/gossipd/test/run-extended-info.c +++ b/gossipd/test/run-extended-info.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,12 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, const struct sha256 *h UNNEEDED, struct privkey *next UNNEEDED) { fprintf(stderr, "blinding_next_path_privkey called!\n"); abort(); } +/* Generated stub for clock_time_overridden */ +bool clock_time_overridden(void) +{ fprintf(stderr, "clock_time_overridden called!\n"); abort(); } +/* Generated stub for clock_time_progresses_ */ +struct timeabs clock_time_progresses_(u64 *progress UNNEEDED) +{ fprintf(stderr, "clock_time_progresses_ called!\n"); abort(); } /* Generated stub for decode_channel_update_timestamps */ struct channel_update_timestamps *decode_channel_update_timestamps(const tal_t *ctx UNNEEDED, const struct tlv_reply_channel_range_tlvs_timestamps_tlv *timestamps_tlv UNNEEDED) diff --git a/gossipd/test/run-next_block_range.c b/gossipd/test/run-next_block_range.c index 49bd20f9eea7..a7178390152f 100644 --- a/gossipd/test/run-next_block_range.c +++ b/gossipd/test/run-next_block_range.c @@ -27,6 +27,15 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, const struct sha256 *h UNNEEDED, struct privkey *next UNNEEDED) { fprintf(stderr, "blinding_next_path_privkey called!\n"); abort(); } +/* Generated stub for clock_time */ +struct timeabs clock_time(void) +{ fprintf(stderr, "clock_time called!\n"); abort(); } +/* Generated stub for clock_time_overridden */ +bool clock_time_overridden(void) +{ fprintf(stderr, "clock_time_overridden called!\n"); abort(); } +/* Generated stub for clock_time_progresses_ */ +struct timeabs clock_time_progresses_(u64 *progress UNNEEDED) +{ fprintf(stderr, "clock_time_progresses_ called!\n"); abort(); } /* Generated stub for daemon_conn_send */ void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "daemon_conn_send called!\n"); abort(); } diff --git a/gossipd/test/run-txout_failure.c b/gossipd/test/run-txout_failure.c index f9c2462d69c1..0985c5f49096 100644 --- a/gossipd/test/run-txout_failure.c +++ b/gossipd/test/run-txout_failure.c @@ -3,6 +3,7 @@ #include "../common/timeout.c" #include #include +#include #include #include #include @@ -30,6 +31,12 @@ bool blinding_next_path_privkey(const struct privkey *e UNNEEDED, const struct sha256 *h UNNEEDED, struct privkey *next UNNEEDED) { fprintf(stderr, "blinding_next_path_privkey called!\n"); abort(); } +/* Generated stub for clock_time_overridden */ +bool clock_time_overridden(void) +{ fprintf(stderr, "clock_time_overridden called!\n"); abort(); } +/* Generated stub for clock_time_progresses_ */ +struct timeabs clock_time_progresses_(u64 *progress UNNEEDED) +{ fprintf(stderr, "clock_time_progresses_ called!\n"); abort(); } /* Generated stub for fromwire_sciddir_or_pubkey */ void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sciddir_or_pubkey *sciddpk UNNEEDED) diff --git a/lightningd/channel.c b/lightningd/channel.c index 0db16d1b88a2..9a84b799a388 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -1010,7 +1011,7 @@ void channel_set_state(struct channel *channel, struct channel_state_change *change; change = new_channel_state_change(channel->state_changes, - time_now(), + clock_time(), old_state, state, reason, diff --git a/lightningd/channel_gossip.c b/lightningd/channel_gossip.c index d4153b207ad4..04da4555eeda 100644 --- a/lightningd/channel_gossip.c +++ b/lightningd/channel_gossip.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -582,7 +583,7 @@ static void arm_refresh_timer(struct channel *channel) { struct lightningd *ld = channel->peer->ld; struct channel_gossip *cg = channel->channel_gossip; - struct timeabs now = time_now(), due; + struct timeabs now = clock_time(), due; u32 timestamp; if (!channel_update_details(cg->cupdate, ×tamp, NULL)) { @@ -1188,7 +1189,7 @@ void channel_gossip_init_done(struct lightningd *ld) static void channel_reestablished_stable(struct channel *channel) { channel->stable_conn_timer = NULL; - channel->last_stable_connection = time_now().ts.tv_sec; + channel->last_stable_connection = clock_time().ts.tv_sec; wallet_channel_save(channel->peer->ld->wallet, channel); } diff --git a/lightningd/coin_mvts.c b/lightningd/coin_mvts.c index cc206b62b1bb..f1195aff7e2a 100644 --- a/lightningd/coin_mvts.c +++ b/lightningd/coin_mvts.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -12,7 +13,7 @@ struct channel_coin_mvt *new_channel_mvt_invoice_hin(const tal_t *ctx, const struct htlc_in *hin, const struct channel *channel) { - return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec, + return new_channel_coin_mvt(ctx, channel, coinmvt_current_time(), &hin->payment_hash, NULL, NULL, COIN_CREDIT, hin->msat, mk_mvt_tags(MVT_INVOICE), @@ -32,7 +33,7 @@ struct channel_coin_mvt *new_channel_mvt_routed_hin(const tal_t *ctx, hin->payload->amt_to_forward)) return NULL; - return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec, + return new_channel_coin_mvt(ctx, channel, coinmvt_current_time(), &hin->payment_hash, NULL, NULL, COIN_CREDIT, hin->msat, mk_mvt_tags(MVT_ROUTED), @@ -43,7 +44,7 @@ struct channel_coin_mvt *new_channel_mvt_invoice_hout(const tal_t *ctx, const struct htlc_out *hout, const struct channel *channel) { - return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec, + return new_channel_coin_mvt(ctx, channel, coinmvt_current_time(), &hout->payment_hash, &hout->partid, &hout->groupid, @@ -56,7 +57,7 @@ struct channel_coin_mvt *new_channel_mvt_routed_hout(const tal_t *ctx, const struct htlc_out *hout, const struct channel *channel) { - return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec, + return new_channel_coin_mvt(ctx, channel, coinmvt_current_time(), &hout->payment_hash, NULL, NULL, COIN_DEBIT, hout->msat, mk_mvt_tags(MVT_ROUTED), @@ -68,7 +69,7 @@ struct channel_coin_mvt *new_channel_mvt_penalty_adj(const tal_t *ctx, struct amount_msat amount, enum coin_mvt_dir direction) { - return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec, + return new_channel_coin_mvt(ctx, channel, coinmvt_current_time(), NULL, NULL, NULL, direction, amount, mk_mvt_tags(MVT_PENALTY_ADJ), @@ -109,7 +110,7 @@ void send_account_balance_snapshot(struct lightningd *ld) struct peer_node_id_map_iter it; snap->blockheight = get_block_height(ld->topology); - snap->timestamp = time_now().ts.tv_sec; + snap->timestamp = coinmvt_current_time(); snap->node_id = &ld->our_nodeid; /* Add the 'wallet' account balance */ diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 57c618ca452f..ae1191122574 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1336,7 +1337,7 @@ wallet_update_channel_commit(struct lightningd *ld, &channel->peer->id, &channel->cid, channel->scid, - time_now(), + clock_time(), DUALOPEND_OPEN_COMMIT_READY, DUALOPEND_OPEN_COMMITTED, REASON_REMOTE, @@ -1434,7 +1435,7 @@ wallet_commit_channel(struct lightningd *ld, &channel->peer->id, &channel->cid, channel->scid, - time_now(), + clock_time(), DUALOPEND_OPEN_INIT, DUALOPEND_OPEN_COMMIT_READY, REASON_REMOTE, diff --git a/lightningd/gossip_generation.c b/lightningd/gossip_generation.c index 22877c9c0596..b4dffe5ac97d 100644 --- a/lightningd/gossip_generation.c +++ b/lightningd/gossip_generation.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -124,7 +125,7 @@ u8 *unsigned_channel_update(const tal_t *ctx, message_flags |= ROUTING_OPT_DONT_FORWARD; /* Make sure timestamp changes! */ - timestamp = time_now().ts.tv_sec; + timestamp = clock_time().ts.tv_sec; /* FIXME: @endothermicdev points out that our clock could be * wrong once, and now we'll keep producing future timestamps. * We could sanity check that old_timestamp is within 2 weeks and @@ -417,7 +418,7 @@ u8 *unsigned_node_announcement(const tal_t *ctx, { secp256k1_ecdsa_signature sig; const struct wireaddr *addrs; - u32 timestamp = time_now().ts.tv_sec; + u32 timestamp = clock_time().ts.tv_sec; addrs = gather_addresses(tmpctx, ld); /* Even if we're quick, don't duplicate timestamps! */ diff --git a/lightningd/htlc_end.c b/lightningd/htlc_end.c index 91d66b0c3357..77fe3074b5bb 100644 --- a/lightningd/htlc_end.c +++ b/lightningd/htlc_end.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -161,7 +162,7 @@ struct htlc_in *new_htlc_in(const tal_t *ctx, hin->we_filled = NULL; hin->payload = NULL; - hin->received_time = time_now(); + hin->received_time = clock_time(); return htlc_in_check(hin, "new_htlc_in"); } diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 8c3c05663dd0..6060b6fe3a74 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1192,7 +1193,7 @@ static struct command_result *json_invoice(struct command *cmd, info->b11 = new_bolt11(info, msatoshi_val); info->b11->chain = chainparams; - info->b11->timestamp = time_now().ts.tv_sec; + info->b11->timestamp = clock_time().ts.tv_sec; info->b11->payment_hash = rhash; info->b11->receiver_id = cmd->ld->our_nodeid; info->b11->min_final_cltv_expiry = *cltv; diff --git a/lightningd/log.c b/lightningd/log.c index 9775e79f44b1..1827b202e97d 100644 --- a/lightningd/log.c +++ b/lightningd/log.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -400,7 +401,7 @@ struct log_book *new_log_book(struct lightningd *ld, size_t max_mem) log_book->prefix = tal_strdup(log_book, ""); list_head_init(&log_book->print_filters); list_head_init(&log_book->loggers); - log_book->init_time = time_now(); + log_book->init_time = clock_time(); log_book->ld = ld; log_book->cache = tal(log_book, struct node_id_map); node_id_map_init(log_book->cache); @@ -525,7 +526,7 @@ static struct log_entry *new_log_entry(struct logger *log, enum log_level level, tal_resize(&log->log_book->log, tal_count(log->log_book->log) * 2); l = &log->log_book->log[log->log_book->num_entries]; - l->time = time_now(); + l->time = clock_time(); l->level = level; l->skipped = 0; l->prefix = log_prefix_get(log->prefix); @@ -1014,7 +1015,7 @@ void log_backtrace_exit(void) int fd; char timebuf[sizeof("YYYYmmddHHMMSS")]; char logfile[sizeof("/tmp/lightning-crash.log.") + sizeof(timebuf)]; - struct timeabs time = time_now(); + struct timeabs time = clock_time(); strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%S", gmtime(&time.ts.tv_sec)); diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 7c12a0ffd551..c914e51dadbd 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -243,7 +244,7 @@ wallet_commit_channel(struct lightningd *ld, wallet_channel_insert(ld->wallet, channel); /* Notify that channel state changed (from non existant to existant) */ - timestamp = time_now(); + timestamp = clock_time(); notify_channel_state_changed(ld, &channel->peer->id, &channel->cid, channel->scid, /* NULL */ diff --git a/lightningd/pay.c b/lightningd/pay.c index 2111e5b4091a..2a4e0c175e43 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -1150,7 +1151,7 @@ send_payment_core(struct lightningd *ld, payment = wallet_add_payment(cmd, ld->wallet, - time_now().ts.tv_sec, + clock_time().ts.tv_sec, NULL, rhash, partid, @@ -1464,7 +1465,7 @@ static struct command_result *self_payment(struct lightningd *ld, payment = wallet_add_payment(tmpctx, ld->wallet, - time_now().ts.tv_sec, + clock_time().ts.tv_sec, NULL, rhash, partid, @@ -1794,7 +1795,7 @@ static void register_payment_and_waiter(struct command *cmd, { wallet_add_payment(cmd, cmd->ld->wallet, - time_now().ts.tv_sec, + clock_time().ts.tv_sec, NULL, payment_hash, partid, diff --git a/lightningd/runes.c b/lightningd/runes.c index 77be7a30a0ad..e3285b06100b 100644 --- a/lightningd/runes.c +++ b/lightningd/runes.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -946,7 +947,7 @@ static struct command_result *json_checkrune(struct command *cmd, cinfo.buf = buffer; cinfo.method = method; cinfo.params = methodparams; - cinfo.now = time_now(); + cinfo.now = clock_time(); strmap_init(&cinfo.cached_params); err = rune_is_ours(cmd->ld, ras->rune); diff --git a/lightningd/test/Makefile b/lightningd/test/Makefile index 776f963f69bd..694d1a6b6ead 100644 --- a/lightningd/test/Makefile +++ b/lightningd/test/Makefile @@ -15,6 +15,7 @@ LIGHTNINGD_TEST_COMMON_OBJS := \ common/autodata.o \ common/base32.o \ common/bech32.o \ + common/clock_time.o \ common/daemon_conn.o \ common/htlc_state.o \ common/htlc_wire.o \ diff --git a/plugins/askrene/askrene.c b/plugins/askrene/askrene.c index 7f7f2d0d50c3..de659b5d9b89 100644 --- a/plugins/askrene/askrene.c +++ b/plugins/askrene/askrene.c @@ -9,7 +9,7 @@ #include "config.h" #include #include -#include +#include #include #include #include @@ -1029,7 +1029,7 @@ static struct command_result *json_askrene_inform_channel(struct command *cmd, *amount = AMOUNT_MSAT(0); if (command_check_only(cmd)) return command_check_done(cmd); - c = layer_add_constraint(layer, scidd, time_now().ts.tv_sec, + c = layer_add_constraint(layer, scidd, clock_time().ts.tv_sec, NULL, amount); goto output; case INFORM_UNCONSTRAINED: @@ -1037,7 +1037,7 @@ static struct command_result *json_askrene_inform_channel(struct command *cmd, * that no reserves were used) */ if (command_check_only(cmd)) return command_check_done(cmd); - c = layer_add_constraint(layer, scidd, time_now().ts.tv_sec, + c = layer_add_constraint(layer, scidd, clock_time().ts.tv_sec, amount, NULL); goto output; case INFORM_SUCCEEDED: diff --git a/plugins/autoclean.c b/plugins/autoclean.c index bfd358c988c6..65a49693fc55 100644 --- a/plugins/autoclean.c +++ b/plugins/autoclean.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -502,7 +503,7 @@ static struct command_result *list_done(struct command *cmd, const struct subsystem_ops *ops = get_subsystem_ops(subsystem); const jsmntok_t *t, *inv = json_get_member(buf, result, ops->arr_name); size_t i; - u64 now = time_now().ts.tv_sec; + u64 now = clock_time().ts.tv_sec; json_for_each_arr(i, t, inv) { struct per_variant *variant; diff --git a/plugins/bkpr/bookkeeper.c b/plugins/bkpr/bookkeeper.c index 1312924de600..b84e876f48b5 100644 --- a/plugins/bkpr/bookkeeper.c +++ b/plugins/bkpr/bookkeeper.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/plugins/bkpr/incomestmt.c b/plugins/bkpr/incomestmt.c index fd3a7e452c08..f35a0e96daa4 100644 --- a/plugins/bkpr/incomestmt.c +++ b/plugins/bkpr/incomestmt.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -442,7 +443,7 @@ const char *csv_filename(const tal_t *ctx, const struct csv_fmt *fmt) { return tal_fmt(ctx, "cln_incomestmt_%s_%lu.csv", fmt->fmt_name, - (unsigned long)time_now().ts.tv_sec); + (unsigned long)clock_time().ts.tv_sec); } static void cointrack_header(FILE *csvf) diff --git a/plugins/bkpr/test/run-recorder.c b/plugins/bkpr/test/run-recorder.c index af8802e618bc..4aa188763cfe 100644 --- a/plugins/bkpr/test/run-recorder.c +++ b/plugins/bkpr/test/run-recorder.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -50,6 +51,12 @@ const char *chain_event_description(const struct bkpr *bkpr UNNEEDED, const char *channel_event_description(const struct bkpr *bkpr UNNEEDED, const struct channel_event *ce UNNEEDED) { fprintf(stderr, "channel_event_description called!\n"); abort(); } +/* Generated stub for clock_time_overridden */ +bool clock_time_overridden(void) +{ fprintf(stderr, "clock_time_overridden called!\n"); abort(); } +/* Generated stub for clock_time_progresses_ */ +struct timeabs clock_time_progresses_(u64 *progress UNNEEDED) +{ fprintf(stderr, "clock_time_progresses_ called!\n"); abort(); } /* Generated stub for command_fail_badparam */ struct command_result *command_fail_badparam(struct command *cmd UNNEEDED, const char *paramname UNNEEDED, diff --git a/plugins/bkpr/test/run-sql.c b/plugins/bkpr/test/run-sql.c index 8be5859adad7..dc3604d0f8f8 100644 --- a/plugins/bkpr/test/run-sql.c +++ b/plugins/bkpr/test/run-sql.c @@ -3,6 +3,7 @@ #include "plugins/bkpr/sql.c" #include "plugins/libplugin.c" +#include #include #include #include @@ -12,6 +13,12 @@ #include /* AUTOGENERATED MOCKS START */ +/* Generated stub for clock_time_overridden */ +bool clock_time_overridden(void) +{ fprintf(stderr, "clock_time_overridden called!\n"); abort(); } +/* Generated stub for clock_time_progresses_ */ +struct timeabs clock_time_progresses_(u64 *progress UNNEEDED) +{ fprintf(stderr, "clock_time_progresses_ called!\n"); abort(); } /* Generated stub for daemon_developer_mode */ bool daemon_developer_mode(char *argv[]) { fprintf(stderr, "daemon_developer_mode called!\n"); abort(); } diff --git a/plugins/chanbackup.c b/plugins/chanbackup.c index 16d6cb6189df..3e51b1436200 100644 --- a/plugins/chanbackup.c +++ b/plugins/chanbackup.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -140,7 +141,7 @@ static void write_scb(struct plugin *p, struct modern_scb_chan **scb_chan_arr) { const struct chanbackup *cb = chanbackup(p); - u32 timestamp = time_now().ts.tv_sec; + u32 timestamp = clock_time().ts.tv_sec; u8 *decrypted_scb = towire_static_chan_backup_with_tlvs(tmpctx, VERSION, diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index a809e30b8648..9b1e68e42cf6 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -732,7 +733,7 @@ static struct command_result *invreq_done(struct command *cmd, } if (base) { - u64 period_start, period_end, now = time_now().ts.tv_sec; + u64 period_start, period_end, now = clock_time().ts.tv_sec; offer_period_paywindow(sent->invreq->offer_recurrence, sent->invreq->offer_recurrence_paywindow, sent->invreq->offer_recurrence_base, @@ -859,7 +860,7 @@ struct command_result *json_fetchinvoice(struct command *cmd, * - MUST NOT respond to the offer. */ if (sent->offer->offer_absolute_expiry - && time_now().ts.tv_sec > *sent->offer->offer_absolute_expiry) + && clock_time().ts.tv_sec > *sent->offer->offer_absolute_expiry) return command_fail(cmd, OFFER_EXPIRED, "Offer expired"); /* BOLT #12: @@ -1397,7 +1398,7 @@ struct command_result *json_sendinvoice(struct command *cmd, * `invreq_chain`. */ sent->inv->invoice_created_at = tal(sent->inv, u64); - *sent->inv->invoice_created_at = time_now().ts.tv_sec; + *sent->inv->invoice_created_at = clock_time().ts.tv_sec; /* FIXME: Support blinded paths, in which case use fake nodeid */ diff --git a/plugins/keysend.c b/plugins/keysend.c index b1b51a5f6f47..58e42e4f0ced 100644 --- a/plugins/keysend.c +++ b/plugins/keysend.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -448,7 +449,8 @@ static struct command_result *htlc_accepted_call(struct command *cmd, bigsize_t s; struct keysend_in *ki; struct out_req *req; - struct timeabs now = time_now(); + /* Even with CLN_DEV_SET_TIME, we need this to change */ + struct timeabs now = clock_time_progresses(); const char *err; u64 *allowed; size_t err_off; diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index adaf9bdfcb6c..5b7330af2ec3 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -87,7 +88,7 @@ struct payment *payment_new(tal_t *ctx, struct command *cmd, p->modifiers = mods; p->cmd = cmd; p->finished = false; - p->start_time = time_now(); + p->start_time = clock_time(); p->result = NULL; p->why = NULL; p->getroute = tal(p, struct getroute_request); @@ -428,7 +429,7 @@ static void channel_hints_update(struct payment *p, /* Local channels must have an HTLC budget */ assert(!local || htlc_budget != NULL); - channel_hint_set_add(root->hints, time_now().ts.tv_sec, scidd, enabled, + channel_hint_set_add(root->hints, clock_time().ts.tv_sec, scidd, enabled, estimated_capacity, overall_capacity, htlc_budget); hint = channel_hint_set_find(root->hints, scidd); @@ -1637,7 +1638,7 @@ payment_waitsendpay_finished(struct command *cmd, assert(p->route != NULL); - p->end_time = time_now(); + p->end_time = clock_time(); p->result = tal_sendpay_result_from_json(p, buffer, toks); if (p->result == NULL) { @@ -2332,7 +2333,7 @@ void payment_set_step(struct payment *p, enum payment_step newstep) /* Any final state needs an end_time */ if (p->step >= PAYMENT_STEP_SPLIT) - p->end_time = time_now(); + p->end_time = clock_time(); } struct command_result *payment_continue(struct payment *p) @@ -2391,7 +2392,7 @@ struct command_result *payment_abort(struct payment *p, enum jsonrpc_errcode cod va_list ap; struct payment *root = payment_root(p); payment_set_step(p, PAYMENT_STEP_FAILED); - p->end_time = time_now(); + p->end_time = clock_time(); /* We can fail twice, it seems. */ tal_free(p->failreason); @@ -2418,7 +2419,7 @@ struct command_result *payment_abort(struct payment *p, enum jsonrpc_errcode cod struct command_result *payment_fail(struct payment *p, const char *fmt, ...) { va_list ap; - p->end_time = time_now(); + p->end_time = clock_time(); payment_set_step(p, PAYMENT_STEP_FAILED); /* We can fail twice, it seems. */ tal_free(p->failreason); @@ -2644,7 +2645,7 @@ local_channel_hints_listpeerchannels(struct command *cmd, * observations, and should re-enable some channels that would * otherwise start out as excluded and remain so until * forever. */ - channel_hint_set_update(payment_root(p)->hints, time_now()); + channel_hint_set_update(payment_root(p)->hints, clock_time()); p->mods = gossmods_from_listpeerchannels( p, p->local_id, buffer, toks, true, gossmod_add_localchan, NULL); diff --git a/plugins/offers.c b/plugins/offers.c index 48ecff4f4fdb..d9659ccee15a 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1320,7 +1321,7 @@ static void json_add_rune(struct command *cmd, struct json_stream *js, const str u64 t = atol(alt->value); if (t) { - u64 diff, now = time_now().ts.tv_sec; + u64 diff, now = clock_time().ts.tv_sec; /* Need a non-const during construction */ char *v; diff --git a/plugins/offers_inv_hook.c b/plugins/offers_inv_hook.c index 07bc1a7ed6b6..01a4fe1a49e5 100644 --- a/plugins/offers_inv_hook.c +++ b/plugins/offers_inv_hook.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -312,7 +313,7 @@ struct command_result *handle_invoice(struct command *cmd, invexpiry = *inv->inv->invoice_created_at + *inv->inv->invoice_relative_expiry; else invexpiry = *inv->inv->invoice_created_at + BOLT12_DEFAULT_REL_EXPIRY; - if (time_now().ts.tv_sec > invexpiry) + if (clock_time().ts.tv_sec > invexpiry) return fail_inv(cmd, inv, "Expired invoice"); /* BOLT #12: diff --git a/plugins/offers_invreq_hook.c b/plugins/offers_invreq_hook.c index 77d5e543fa1b..7a51e4525b2f 100644 --- a/plugins/offers_invreq_hook.c +++ b/plugins/offers_invreq_hook.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -858,7 +859,7 @@ static struct command_result *listoffers_done(struct command *cmd, } if (ir->invreq->offer_absolute_expiry - && time_now().ts.tv_sec >= *ir->invreq->offer_absolute_expiry) { + && clock_time().ts.tv_sec >= *ir->invreq->offer_absolute_expiry) { /* FIXME: do deloffer to disable it */ return fail_invreq(cmd, ir, "Offer expired"); } @@ -956,7 +957,7 @@ static struct command_result *listoffers_done(struct command *cmd, * Midnight 1 January 1970, UTC when the invoice was created. */ ir->inv->invoice_created_at = tal(ir->inv, u64); - *ir->inv->invoice_created_at = time_now().ts.tv_sec; + *ir->inv->invoice_created_at = clock_time().ts.tv_sec; /* BOLT #12: * - MUST set `invoice_payment_hash` to the SHA256 hash of the diff --git a/plugins/pay.c b/plugins/pay.c index 87ad826f1bec..087b33ccdb87 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -150,7 +151,7 @@ static void paystatus_add_payment(struct json_stream *s, const struct payment *p json_add_string(s, "strategy", p->why); json_add_string(s, "start_time", timestr); json_add_u64(s, "age_in_seconds", - time_to_sec(time_between(time_now(), p->start_time))); + time_to_sec(time_between(clock_time(), p->start_time))); /* Any final state will have an end time. */ if (p->step >= PAYMENT_STEP_SPLIT) { @@ -1424,7 +1425,7 @@ static struct command_result *json_pay(struct command *cmd, p->payment_secret = NULL; } - if (time_now().ts.tv_sec > invexpiry) + if (clock_time().ts.tv_sec > invexpiry) return command_fail(cmd, PAY_INVOICE_EXPIRED, "Invoice expired"); if (invmsat) { @@ -1549,7 +1550,7 @@ static struct command_result *handle_channel_hint_update(struct command *cmd, fmt_amount_msat(tmpctx, hint->estimated_capacity), fmt_amount_msat(tmpctx, hint->capacity) ); - channel_hint_set_add(global_hints, time_now().ts.tv_sec, &hint->scid, + channel_hint_set_add(global_hints, clock_time().ts.tv_sec, &hint->scid, hint->enabled, &hint->estimated_capacity, hint->capacity, NULL); tal_free(hint); diff --git a/plugins/renepay/main.c b/plugins/renepay/main.c index 01b4d13be34c..18872c1936fe 100644 --- a/plugins/renepay/main.c +++ b/plugins/renepay/main.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -311,7 +312,7 @@ static struct command_result *json_renepay(struct command *cmd, const char *buf, /* === Is it expired? === */ - const u64 now_sec = time_now().ts.tv_sec; + const u64 now_sec = clock_time().ts.tv_sec; if (now_sec > invexpiry) return command_fail(cmd, PAY_INVOICE_EXPIRED, "Invoice expired"); diff --git a/plugins/renepay/mods.c b/plugins/renepay/mods.c index 34e505816538..30d6314a2e6c 100644 --- a/plugins/renepay/mods.c +++ b/plugins/renepay/mods.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -917,7 +918,7 @@ REGISTER_PAYMENT_MODIFIER(end, end_cb); static struct command_result *checktimeout_cb(struct payment *payment) { - if (time_after(time_now(), payment->payment_info.stop_time)) { + if (time_after(clock_time(), payment->payment_info.stop_time)) { return payment_fail(payment, PAY_STOPPED_RETRYING, "Timed out"); } return payment_continue(payment); @@ -1129,7 +1130,7 @@ REGISTER_PAYMENT_MODIFIER(pendingsendpays, pendingsendpays_cb); static struct command_result *knowledgerelax_cb(struct payment *payment) { - const u64 now_sec = time_now().ts.tv_sec; + const u64 now_sec = clock_time().ts.tv_sec; enum renepay_errorcode err = uncertainty_relax( pay_plugin->uncertainty, now_sec - pay_plugin->last_time); if (err) diff --git a/plugins/renepay/payment.c b/plugins/renepay/payment.c index 02566b01cdff..c732ecca0ae4 100644 --- a/plugins/renepay/payment.c +++ b/plugins/renepay/payment.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -96,7 +97,7 @@ bool payment_refresh(struct payment *p){ p->retry = false; p->waitresult_timer = tal_free(p->waitresult_timer); - pinfo->start_time = time_now(); + pinfo->start_time = clock_time(); pinfo->stop_time = timeabs_add(pinfo->start_time, time_from_sec(pinfo->retryfor)); diff --git a/plugins/renepay/test/run-bottleneck.c b/plugins/renepay/test/run-bottleneck.c index 67708a404811..5111892e5911 100644 --- a/plugins/renepay/test/run-bottleneck.c +++ b/plugins/renepay/test/run-bottleneck.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -225,7 +226,7 @@ int main(int argc, char *argv[]) pinfo.maxdelay = 100; pinfo.final_cltv = 5; - pinfo.start_time = time_now(); + pinfo.start_time = clock_time(); pinfo.stop_time = timeabs_add(pinfo.start_time, time_from_sec(10000)); pinfo.base_fee_penalty = 1e-5; diff --git a/plugins/test/Makefile b/plugins/test/Makefile index 341616a0915a..c7744825295e 100644 --- a/plugins/test/Makefile +++ b/plugins/test/Makefile @@ -10,6 +10,7 @@ ALL_TEST_PROGRAMS += $(PLUGIN_TEST_PROGRAMS) PLUGIN_TEST_COMMON_OBJS := \ common/amount.o \ common/autodata.o \ + common/clock_time.o \ common/pseudorand.o \ common/randbytes.o \ common/setup.o \ diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index 16717ce3d045..078ee747c382 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1867,7 +1868,7 @@ static struct command_result *xpay_core(struct command *cmd, payment->requests = tal_arr(payment, struct out_req *, 0); payment->prior_results = tal_strdup(payment, ""); payment->deadline = timemono_add(time_mono(), time_from_sec(retryfor)); - payment->start_time = time_now(); + payment->start_time = clock_time(); payment->pay_compat = as_pay; payment->invstring = tal_strdup(payment, invstring); if (layers) @@ -1975,7 +1976,7 @@ static struct command_result *xpay_core(struct command *cmd, invexpiry = b11->timestamp + b11->expiry; } - now = time_now().ts.tv_sec; + now = clock_time().ts.tv_sec; if (now > invexpiry) return command_fail(cmd, PAY_INVOICE_EXPIRED, "Invoice expired %"PRIu64" seconds ago", @@ -2092,7 +2093,7 @@ static struct command_result *age_layer(struct command *timer_cmd, void *unused) plugin_broken_cb, NULL); json_add_string(req->js, "layer", "xpay"); - json_add_u64(req->js, "cutoff", time_now().ts.tv_sec - 3600); + json_add_u64(req->js, "cutoff", clock_time().ts.tv_sec - 3600); return send_outreq(req); } diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile index 6b36b1e941a3..1561f2d25da4 100644 --- a/tests/fuzz/Makefile +++ b/tests/fuzz/Makefile @@ -32,6 +32,7 @@ FUZZ_COMMON_OBJS := \ common/configvar.o \ common/channel_id.o \ common/channel_type.o \ + common/clock_time.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/tools/bench-gossipd.sh b/tools/bench-gossipd.sh index 9b4ff5269b44..4bea1552ce22 100755 --- a/tools/bench-gossipd.sh +++ b/tools/bench-gossipd.sh @@ -78,7 +78,7 @@ if ! bitcoin-cli -regtest ping >/dev/null 2>&1; then while ! bitcoin-cli -regtest ping >/dev/null 2>&1; do sleep 1; done fi -LIGHTNINGD="./lightningd/lightningd --developer --network=regtest --dev-gossip-time=1550513768" +LIGHTNINGD="CLN_DEV_SET_TIME=1550513768 ./lightningd/lightningd --developer --network=regtest" LCLI1="./cli/lightning-cli --lightning-dir=$DIR -R" if [ -z "$DIR" ]; then diff --git a/wallet/invoices.c b/wallet/invoices.c index 1655c8f96f85..ddbff6515146 100644 --- a/wallet/invoices.c +++ b/wallet/invoices.c @@ -1,5 +1,6 @@ #include "config.h" #include +#include #include #include #include @@ -179,7 +180,7 @@ static u64 *expired_ids(const tal_t *ctx, static void trigger_expiration(struct invoices *invoices) { u64 *inv_dbids; - u64 now = time_now().ts.tv_sec; + u64 now = clock_time().ts.tv_sec; struct db_stmt *stmt; /* Free current expiration timer */ @@ -214,7 +215,7 @@ static void install_expiration_timer(struct invoices *invoices) struct db_stmt *stmt; struct timerel rel; struct timeabs expiry; - struct timeabs now = time_now(); + struct timeabs now = clock_time(); assert(!invoices->expiration_timer); @@ -275,7 +276,7 @@ bool invoices_create(struct invoices *invoices, { struct db_stmt *stmt; u64 expiry_time; - u64 now = time_now().ts.tv_sec; + u64 now = clock_time().ts.tv_sec; if (invoices_find_by_label(invoices, inv_dbid, label)) { if (taken(msat)) @@ -609,7 +610,7 @@ bool invoices_resolve(struct invoices *invoices, /* Assign a pay-index. */ pay_index = get_next_pay_index(invoices->wallet->db); - paid_timestamp = time_now().ts.tv_sec; + paid_timestamp = clock_time().ts.tv_sec; /* Update database. */ stmt = db_prepare_v2(invoices->wallet->db, SQL("UPDATE invoices" diff --git a/wallet/test/Makefile b/wallet/test/Makefile index 9db6bcca3b33..5d2e6e598bc5 100644 --- a/wallet/test/Makefile +++ b/wallet/test/Makefile @@ -12,6 +12,7 @@ WALLET_TEST_COMMON_OBJS := \ common/blockheight_states.o \ common/channel_id.o \ common/channel_type.o \ + common/clock_time.o \ common/derive_basepoints.o \ common/features.o \ common/htlc_state.o \ diff --git a/wallet/wallet.c b/wallet/wallet.c index 2231c1f11198..4f45b7027e72 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -4161,7 +4162,7 @@ void wallet_payment_set_status(struct wallet *wallet, u32 completed_at = 0; if (newstatus != PAYMENT_PENDING) - completed_at = time_now().ts.tv_sec; + completed_at = clock_time().ts.tv_sec; stmt = db_prepare_v2(wallet->db, SQL("UPDATE payments SET status=?, completed_at=?, updated_index=? " @@ -5316,7 +5317,7 @@ void wallet_forwarded_payment_add(struct wallet *w, const struct htlc_in *in, if (state == FORWARD_SETTLED || state == FORWARD_FAILED) { resolved_time = tal(tmpctx, struct timeabs); - *resolved_time = time_now(); + *resolved_time = clock_time(); } else { resolved_time = NULL; } From 5e8c7f26d55bda8a2e09e0cef7e582f8300fd57b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:01 +0930 Subject: [PATCH 21/25] lightningd: introduce some changes for dual open id randomness even with CLN_DEV_ENTROPY_SEED. Signed-off-by: Rusty Russell --- lightningd/dual_open_control.c | 37 ++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index ae1191122574..185450d0459f 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -34,6 +34,7 @@ #include #include #include +#include struct commit_rcvd { struct channel *channel; @@ -4065,6 +4066,35 @@ static void dualopen_errmsg(struct channel *channel, err_for_them ? "sent" : "received", desc); } +/* This is a hack for CLN_DEV_ENTROPY_SEED. We cannot actually use + * the same seed for each dualopend, or they choose the same ids, and we + * clash when combining the PSBTs (this is phenomenally unlikey normally). + * So we set it (for the child) to an incrementing value. */ +static const char *dev_setup_dualopend_seed(const tal_t *ctx, struct lightningd *ld) +{ + static u64 seed_incr = 0; + char seedstr[STR_MAX_CHARS(u64)]; + const char *old_seed; + + if (!ld->developer) + return NULL; + + old_seed = getenv("CLN_DEV_ENTROPY_SEED"); + if (!old_seed) + return NULL; + + old_seed = tal_strdup(tmpctx, old_seed); + seed_incr++; + snprintf(seedstr, sizeof(seedstr), "%"PRIu64, atol(old_seed) + seed_incr); + setenv("CLN_DEV_ENTROPY_SEED", seedstr, 1); + return old_seed; +} + +static void dev_restore_seed(const char *old_seed) +{ + if (old_seed) + setenv("CLN_DEV_ENTROPY_SEED", old_seed, 1); +} bool peer_start_dualopend(struct peer *peer, struct peer_fd *peer_fd, @@ -4074,6 +4104,7 @@ bool peer_start_dualopend(struct peer *peer, u32 max_to_self_delay; struct amount_msat min_effective_htlc_capacity; const u8 *msg; + const char *dev_old_seed; hsmfd = hsm_get_client_fd(peer->ld, &peer->id, channel->unsaved_dbid, HSM_PERM_COMMITMENT_POINT @@ -4087,6 +4118,7 @@ bool peer_start_dualopend(struct peer *peer, return false; } + dev_old_seed = dev_setup_dualopend_seed(tmpctx, peer->ld); channel->owner = new_channel_subd(channel, peer->ld, "lightning_dualopend", @@ -4099,6 +4131,7 @@ bool peer_start_dualopend(struct peer *peer, channel_set_billboard, take(&peer_fd->fd), take(&hsmfd), NULL); + dev_restore_seed(dev_old_seed); if (!channel->owner) { channel_internal_error(channel, @@ -4152,6 +4185,7 @@ bool peer_restart_dualopend(struct peer *peer, int hsmfd; u32 *local_shutdown_script_wallet_index; u8 *msg; + const char *dev_old_seed; if (channel_state_uncommitted(channel->state)) return peer_start_dualopend(peer, peer_fd, channel); @@ -4171,6 +4205,7 @@ bool peer_restart_dualopend(struct peer *peer, return false; } + dev_old_seed = dev_setup_dualopend_seed(tmpctx, peer->ld); channel_set_owner(channel, new_channel_subd(channel, peer->ld, "lightning_dualopend", @@ -4183,6 +4218,8 @@ bool peer_restart_dualopend(struct peer *peer, channel_set_billboard, take(&peer_fd->fd), take(&hsmfd), NULL)); + dev_restore_seed(dev_old_seed); + if (!channel->owner) { log_broken(channel->log, "Could not subdaemon channel: %s", strerror(errno)); From be00be5e36c250f5ff679eaa4ed9abaa4aadfe5c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:01 +0930 Subject: [PATCH 22/25] wallet: make utxo order deterministic if CLN_DEV_ENTROPY_SEED set. Signed-off-by: Rusty Russell --- wallet/wallet.c | 92 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 22 deletions(-) diff --git a/wallet/wallet.c b/wallet/wallet.c index 4f45b7027e72..4a4e20e4923e 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -459,7 +461,23 @@ bool wallet_update_output_status(struct wallet *w, return changes > 0; } -static struct utxo **gather_utxos(const tal_t *ctx, struct db_stmt *stmt STEALS) +static int cmp_utxo(struct utxo *const *a, + struct utxo *const *b, + void *unused) +{ + int ret = memcmp(&(*a)->outpoint.txid, &(*b)->outpoint.txid, + sizeof((*a)->outpoint.txid)); + if (ret) + return ret; + if ((*a)->outpoint.n < (*b)->outpoint.n) + return -1; + else if ((*a)->outpoint.n > (*b)->outpoint.n) + return 1; + return 0; +} + +static struct utxo **gather_utxos(const tal_t *ctx, + struct db_stmt *stmt STEALS) { struct utxo **results; @@ -471,6 +489,10 @@ static struct utxo **gather_utxos(const tal_t *ctx, struct db_stmt *stmt STEALS) } tal_free(stmt); + /* Make sure these are in order if we're trying to remove entropy */ + if (randbytes_overridden()) + asort(results, tal_count(results), cmp_utxo, NULL); + return results; } @@ -817,27 +839,53 @@ struct utxo *wallet_find_utxo(const tal_t *ctx, struct wallet *w, struct db_stmt *stmt; struct utxo *utxo; - stmt = db_prepare_v2(w->db, SQL("SELECT" - " prev_out_tx" - ", prev_out_index" - ", value" - ", type" - ", status" - ", keyindex" - ", channel_id" - ", peer_id" - ", commitment_point" - ", option_anchor_outputs" - ", confirmation_height" - ", spend_height" - ", scriptpubkey " - ", reserved_til" - ", csv_lock" - ", is_in_coinbase" - " FROM outputs" - " WHERE status = ?" - " OR (status = ? AND reserved_til <= ?)" - "ORDER BY RANDOM();")); + /* Make sure these are in order if we're trying to remove entropy! */ + if (w->ld->developer && getenv("CLN_DEV_ENTROPY_SEED")) { + stmt = db_prepare_v2(w->db, SQL("SELECT" + " prev_out_tx" + ", prev_out_index" + ", value" + ", type" + ", status" + ", keyindex" + ", channel_id" + ", peer_id" + ", commitment_point" + ", option_anchor_outputs" + ", confirmation_height" + ", spend_height" + ", scriptpubkey " + ", reserved_til" + ", csv_lock" + ", is_in_coinbase" + " FROM outputs" + " WHERE status = ?" + " OR (status = ? AND reserved_til <= ?)" + "ORDER BY prev_out_tx, prev_out_index;")); + } else { + stmt = db_prepare_v2(w->db, SQL("SELECT" + " prev_out_tx" + ", prev_out_index" + ", value" + ", type" + ", status" + ", keyindex" + ", channel_id" + ", peer_id" + ", commitment_point" + ", option_anchor_outputs" + ", confirmation_height" + ", spend_height" + ", scriptpubkey " + ", reserved_til" + ", csv_lock" + ", is_in_coinbase" + " FROM outputs" + " WHERE status = ?" + " OR (status = ? AND reserved_til <= ?)" + "ORDER BY RANDOM();")); + } + db_bind_int(stmt, output_status_in_db(OUTPUT_STATE_AVAILABLE)); db_bind_int(stmt, output_status_in_db(OUTPUT_STATE_RESERVED)); db_bind_u64(stmt, current_blockheight); From f04924010a0531f4ade095f9174bc9fb31ad60a9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:02 +0930 Subject: [PATCH 23/25] topology: in deterministic mode, only return one best candidate for listincoming. This ensures that bolt11/bolt12 selection of routehints/blinded paths is always the same. Signed-off-by: Rusty Russell --- plugins/topology.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/plugins/topology.c b/plugins/topology.c index 4c84d02b92c2..5447303efdc5 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -462,6 +463,33 @@ static struct amount_msat peer_capacity(const struct gossmap *gossmap, return capacity; } +/* For deterministic results with bolt12/11 routes, we only return a + * single candidate: choose the one with most capacity */ +static size_t best_candidate(const struct gossmap *gossmap, + const struct gossmap_node *me) +{ + struct amount_msat best_cap = AMOUNT_MSAT(0); + size_t best_num = 0; + for (size_t i = 0; i < me->num_chans; i++) { + int dir; + struct gossmap_chan *ourchan; + struct amount_msat cap; + struct gossmap_node *peer; + + ourchan = gossmap_nth_chan(gossmap, me, i, &dir); + if (ourchan->cupdate_off[!dir] == 0) + continue; + + peer = gossmap_nth_node(gossmap, ourchan, !dir); + cap = peer_capacity(gossmap, me, peer, ourchan); + if (amount_msat_greater(cap, best_cap)) { + best_num = i; + best_cap = cap; + } + } + return best_num; +} + static struct command_result * listpeerchannels_listincoming_done(struct command *cmd, const char *method, @@ -473,6 +501,7 @@ listpeerchannels_listincoming_done(struct command *cmd, struct gossmap_node *me; struct gossmap *gossmap; struct gossmap_localmods *mods; + size_t deterministic_candidate = 0; /* Get local knowledge */ mods = gossmods_from_listpeerchannels(tmpctx, &local_id, @@ -490,6 +519,9 @@ listpeerchannels_listincoming_done(struct command *cmd, if (!me) goto done; + if (randbytes_overridden()) + deterministic_candidate = best_candidate(gossmap, me); + for (size_t i = 0; i < me->num_chans; i++) { struct node_id peer_id; int dir; @@ -502,6 +534,10 @@ listpeerchannels_listincoming_done(struct command *cmd, /* Entirely missing? Ignore. */ if (ourchan->cupdate_off[!dir] == 0) continue; + + if (randbytes_overridden() && i != deterministic_candidate) + continue; + /* We used to ignore if the peer said it was disabled, * but we have a report of LND telling us our unannounced * channel is disabled, so we still use them. */ From af8cbc036abc62e5779acd670c52e44f761ba6c8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:02 +0930 Subject: [PATCH 24/25] lightningd: add --dev-ignore-idb to not complain about bitcoind in initialblockdownload. Signed-off-by: Rusty Russell --- plugins/bcli.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/bcli.c b/plugins/bcli.c index 198edcf70166..af232da24eae 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -66,6 +66,9 @@ struct bitcoind { /* Override in case we're developer mode for testing*/ bool dev_no_fake_fees; + + /* Override initialblockdownload (using canned blocks sets this) */ + bool dev_ignore_ibd; }; static struct bitcoind *bitcoind; @@ -458,6 +461,9 @@ static struct command_result *process_getblockchaininfo(struct bitcoin_cli *bcli if (err) return command_err_bcli_badjson(bcli, err); + if (bitcoind->dev_ignore_ibd) + ibd = false; + response = jsonrpc_stream_success(bcli->cmd); json_add_string(response, "chain", chain); json_add_u32(response, "headercount", headers); @@ -1157,6 +1163,7 @@ static struct bitcoind *new_bitcoind(const tal_t *ctx) although normal rpcclienttimeout default value is 900. */ bitcoind->rpcclienttimeout = 60; bitcoind->dev_no_fake_fees = false; + bitcoind->dev_ignore_ibd = false; return bitcoind; } @@ -1208,5 +1215,9 @@ int main(int argc, char *argv[]) "bool", "Suppress fee faking for regtest", bool_option, NULL, &bitcoind->dev_no_fake_fees), + plugin_option_dev("dev-ignore-ibd", + "bool", + "Never tell lightningd we're doing initial block download", + bool_option, NULL, &bitcoind->dev_ignore_ibd), NULL); } From 49c4b0f18668194c58fe8f4f67ef4673743e9506 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 19 Sep 2025 10:01:02 +0930 Subject: [PATCH 25/25] pyln-testing: introduce canned blocks support to bitcoind fixture. We have to add a send_and_mine_block() for cases where we want to get a txid and then mine it (for canned blocks, we mine it then figure out which tx it was!). And fix up out-by-one in saving blocks. Signed-off-by: Rusty Russell --- contrib/pyln-testing/pyln/testing/fixtures.py | 58 ++++++++-------- contrib/pyln-testing/pyln/testing/utils.py | 67 ++++++++++++++++--- 2 files changed, 88 insertions(+), 37 deletions(-) diff --git a/contrib/pyln-testing/pyln/testing/fixtures.py b/contrib/pyln-testing/pyln/testing/fixtures.py index 215c54022325..7db4b66e8057 100644 --- a/contrib/pyln-testing/pyln/testing/fixtures.py +++ b/contrib/pyln-testing/pyln/testing/fixtures.py @@ -125,36 +125,40 @@ def node_cls(): @pytest.fixture -def bitcoind(directory, teardown_checks): +def bitcoind(request, directory, teardown_checks): chaind = network_daemons[env('TEST_NETWORK', 'regtest')] bitcoind = chaind(bitcoin_dir=directory) - try: - bitcoind.start() - except Exception: - bitcoind.stop() - raise - - info = bitcoind.rpc.getnetworkinfo() - - # FIXME: include liquid-regtest in this check after elementsd has been - # updated - if info['version'] < 200100 and env('TEST_NETWORK') != 'liquid-regtest': - bitcoind.rpc.stop() - raise ValueError("bitcoind is too old. At least version 20100 (v0.20.1)" - " is needed, current version is {}".format(info['version'])) - elif info['version'] < 160000: - bitcoind.rpc.stop() - raise ValueError("elementsd is too old. At least version 160000 (v0.16.0)" - " is needed, current version is {}".format(info['version'])) - - info = bitcoind.rpc.getblockchaininfo() - # Make sure we have some spendable funds - if info['blocks'] < 101: - bitcoind.generate_block(101 - info['blocks']) - elif bitcoind.rpc.getwalletinfo()['balance'] < 1: - logging.debug("Insufficient balance, generating 1 block") - bitcoind.generate_block(1) + # @pytest.mark.parametrize('bitcoind', [False], indirect=True) if you don't + # want bitcoind started! + if getattr(request, 'param', True): + try: + bitcoind.start() + except Exception: + bitcoind.stop() + raise + + info = bitcoind.rpc.getnetworkinfo() + + # FIXME: include liquid-regtest in this check after elementsd has been + # updated + if info['version'] < 200100 and env('TEST_NETWORK') != 'liquid-regtest': + bitcoind.rpc.stop() + raise ValueError("bitcoind is too old. At least version 20100 (v0.20.1)" + " is needed, current version is {}".format(info['version'])) + elif info['version'] < 160000: + bitcoind.rpc.stop() + raise ValueError("elementsd is too old. At least version 160000 (v0.16.0)" + " is needed, current version is {}".format(info['version'])) + + info = bitcoind.rpc.getblockchaininfo() + + # Make sure we have some spendable funds + if info['blocks'] < 101: + bitcoind.generate_block(101 - info['blocks']) + elif bitcoind.rpc.getwalletinfo()['balance'] < 1: + logging.debug("Insufficient balance, generating 1 block") + bitcoind.generate_block(1) yield bitcoind diff --git a/contrib/pyln-testing/pyln/testing/utils.py b/contrib/pyln-testing/pyln/testing/utils.py index 2317c96c315f..0ecd81bcff93 100644 --- a/contrib/pyln-testing/pyln/testing/utils.py +++ b/contrib/pyln-testing/pyln/testing/utils.py @@ -407,6 +407,7 @@ def __init__(self, bitcoin_dir="/tmp/bitcoind-test", rpcport=None): self.bitcoin_dir = bitcoin_dir self.rpcport = rpcport self.prefix = 'bitcoind' + self.canned_blocks = None regtestdir = os.path.join(bitcoin_dir, 'regtest') if not os.path.exists(regtestdir): @@ -442,15 +443,18 @@ def __del__(self): if self.reserved_rpcport is not None: drop_unused_port(self.reserved_rpcport) - def start(self): + def start(self, wallet_file=None): TailableProc.start(self) self.wait_for_log("Done loading", timeout=TIMEOUT) logging.info("BitcoinD started") - try: - self.rpc.createwallet("lightningd-tests") - except JSONRPCError: - self.rpc.loadwallet("lightningd-tests") + if wallet_file: + self.rpc.restorewallet("lightningd-tests", wallet_file) + else: + try: + self.rpc.createwallet("lightningd-tests") + except JSONRPCError: + self.rpc.loadwallet("lightningd-tests") def stop(self): for p in self.proxies: @@ -464,6 +468,10 @@ def get_proxy(self): proxy.start() return proxy + def set_canned_blocks(self, blocks): + """Set blocks as an array of blocks to "generate", or None to reset""" + self.canned_blocks = blocks + # wait_for_mempool can be used to wait for the mempool before generating blocks: # True := wait for at least 1 transation # int > 0 := wait for at least N transactions @@ -478,6 +486,16 @@ def generate_block(self, numblocks=1, wait_for_mempool=0, to_addr=None, needfeer else: wait_for(lambda: len(self.rpc.getrawmempool()) >= wait_for_mempool) + # Use canned blocks if we have them (fails if we run out!). + if self.canned_blocks is not None: + ret = [] + while numblocks > 0: + self.rpc.submitblock(self.canned_blocks[0]) + ret.append(self.rpc.getbestblockhash()) + numblocks -= 1 + del self.canned_blocks[0] + return ret + mempool = self.rpc.getrawmempool(True) logging.debug("Generating {numblocks}, confirming {lenmempool} transactions: {mempool}".format( numblocks=numblocks, @@ -505,6 +523,21 @@ def generate_block(self, numblocks=1, wait_for_mempool=0, to_addr=None, needfeer return self.rpc.generatetoaddress(numblocks, to_addr) + def send_and_mine_block(self, addr, sats): + """Sometimes we want the txid. We assume it's the first tx for canned blocks""" + if self.canned_blocks: + self.generate_block(1) + # Find which non-coinbase txs sent to this address: return txid + for txid in self.rpc.getblock(self.rpc.getbestblockhash())['tx'][1:]: + for out in self.rpc.getrawtransaction(txid, 1)['vout']: + if out['scriptPubKey'].get('address') == addr: + return txid + assert False, f"No address {addr} in block {self.rpc.getblock(self.rpc.getbestblockhash())}" + + txid = self.rpc.sendtoaddress(addr, sats / 10**8) + self.generate_block(1) + return txid + def simple_reorg(self, height, shift=0): """ Reorganize chain by creating a fork at height=[height] and re-mine all mempool @@ -522,6 +555,7 @@ def simple_reorg(self, height, shift=0): forward to h1. 2. Set [height]=h2 and [shift]= h1-h2 """ + assert self.canned_blocks is None hashes = [] fee_delta = 1000000 orig_len = self.rpc.getblockcount() @@ -555,7 +589,7 @@ def save_blocks(self): """Bundle up blocks into an array, for restore_blocks""" blocks = [] numblocks = self.rpc.getblockcount() - for bnum in range(1, numblocks): + for bnum in range(1, numblocks + 1): bhash = self.rpc.getblockhash(bnum) blocks.append(self.rpc.getblock(bhash, False)) return blocks @@ -887,6 +921,10 @@ def __init__(self, node_id, lightning_dir, bitcoind, executor, valgrind, may_fai self.daemon.opts['grpc-port'] = grpc_port self.grpc_port = grpc_port or 9736 + # If bitcoind is serving canned blocks, it will keep initialblockdownload on true! + if self.bitcoin.canned_blocks is not None: + self.daemon.opts['dev-ignore-ibd'] = True + def _create_rpc(self, jsonschemas): """Prepares anything related to the RPC. """ @@ -982,10 +1020,12 @@ def openchannel(self, remote_node, capacity=FUNDAMOUNT, addrtype="bech32", confi def fundwallet(self, sats, addrtype="bech32", mine_block=True): addr = self.rpc.newaddr(addrtype)[addrtype] - txid = self.bitcoin.rpc.sendtoaddress(addr, sats / 10**8) if mine_block: - self.bitcoin.generate_block(1) + txid = self.bitcoin.send_and_mine_block(addr, sats) self.daemon.wait_for_log('Owning output .* txid {} CONFIRMED'.format(txid)) + else: + txid = self.bitcoin.rpc.sendtoaddress(addr, sats / 10**8) + return addr, txid def fundbalancedchannel(self, remote_node, total_capacity=FUNDAMOUNT, announce=True): @@ -1113,8 +1153,7 @@ def has_funds_on_addr(addr): # We should not have funds on that address yet, we just generated it. assert not has_funds_on_addr(addr) - self.bitcoin.rpc.sendtoaddress(addr, (amount + 1000000) / 10**8) - self.bitcoin.generate_block(1) + self.bitcoin.send_and_mine_block(addr, amount + 1000000) # Now we should. wait_for(lambda: has_funds_on_addr(addr)) @@ -1129,10 +1168,18 @@ def has_funds_on_addr(addr): **kwargs) blockid = self.bitcoin.generate_block(1, wait_for_mempool=res['txid'])[0] + txnum = None for i, txid in enumerate(self.bitcoin.rpc.getblock(blockid)['tx']): if txid == res['txid']: txnum = i + if txnum is None: + print(f"mempool = {self.bitcoin.rpc.getrawmempool()}") + print(f"txs:") + for txid in self.bitcoin.rpc.getblock(blockid)['tx'][1:]: + print(f"txid {txid}: {self.bitcoin.rpc.getrawtransaction(txid)} {self.bitcoin.rpc.getrawtransaction(txid, 1)}") + assert False, f"txid {res['txid']} not found" + scid = "{}x{}x{}".format(self.bitcoin.rpc.getblockcount(), txnum, res['outnum'])