From c4c47685774d051637e56b31586ff28b9f4c9852 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jul 2023 11:19:43 +0930 Subject: [PATCH] lightningd: initialize runes way earlier, and add rune_is_ours helper. We want to access this in db migrations, which happen very early, but runes_init needs the db, creating a circular dependency which must be split. Signed-off-by: Rusty Russell --- lightningd/lightningd.c | 13 ++++++++---- lightningd/runes.c | 29 ++++++++++++++++++--------- lightningd/runes.h | 13 +++++++++++- lightningd/test/run-find_my_abspath.c | 9 ++++++--- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 5b4a63676..7f2527cb2 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -1059,6 +1059,13 @@ int main(int argc, char *argv[]) * Daemon Software Module. */ ld->bip32_base = hsm_init(ld); + /*~ We have bearer tokens called `runes` you can use to control access. They have + * a fascinating history which I shall not go into now, but they're derived from + * Macaroons which was a over-engineered Googlism. + * + * We need them minimally bootstrapped for our db migration code. */ + ld->runes = runes_early_init(ld); + /*~ Our "wallet" code really wraps the db, which is more than a simple * bitcoin wallet (though it's that too). It also stores channel * states, invoices, payments, blocks and bitcoin transactions. */ @@ -1120,10 +1127,8 @@ int main(int argc, char *argv[]) else if (max_blockheight != UINT32_MAX) max_blockheight -= ld->config.rescan; - /*~ We have bearer tokens called `runes` you can use to control access. They have - * a fascinating history which I shall not go into now, but they're derived from - * Macaroons which was a over-engineered Googlism. */ - ld->runes = runes_init(ld); + /*~ Finish our runes initialization (includes reading from db) */ + runes_finish_init(ld->runes); /*~ That's all of the wallet db operations for now. */ db_commit_transaction(ld->wallet->db); diff --git a/lightningd/runes.c b/lightningd/runes.c index 2dd27c438..6eaa5835d 100644 --- a/lightningd/runes.c +++ b/lightningd/runes.c @@ -59,6 +59,11 @@ struct runes { struct usage_table *usage_table; }; +const char *rune_is_ours(struct lightningd *ld, const struct rune *rune) +{ + return rune_is_derived(ld->runes->master, rune); +} + #if DEVELOPER static void memleak_help_usage_table(struct htable *memtable, struct usage_table *usage_table) @@ -111,30 +116,36 @@ static const char *rate_limit_check(const tal_t *ctx, return NULL; } -struct runes *runes_init(struct lightningd *ld) +/* We need to initialize master runes secret early, so db can use rune_is_ours */ +struct runes *runes_early_init(struct lightningd *ld) { const u8 *msg; struct runes *runes = tal(ld, struct runes); const u8 *data; struct secret secret; - runes->ld = ld; - runes->next_unique_id = db_get_intvar(ld->wallet->db, "runes_uniqueid", 0); - runes->blacklist = wallet_get_runes_blacklist(runes, ld->wallet); - /* Runes came out of commando, hence the derivation key is 'commando' */ data = tal_dup_arr(tmpctx, u8, (u8 *)"commando", strlen("commando"), 0); msg = hsm_sync_req(tmpctx, ld, towire_hsmd_derive_secret(tmpctx, data)); if (!fromwire_hsmd_derive_secret_reply(msg, &secret)) fatal("Bad reply from HSM: %s", tal_hex(tmpctx, msg)); + runes->ld = ld; runes->master = rune_new(runes, secret.data, ARRAY_SIZE(secret.data), NULL); + return runes; +} + +void runes_finish_init(struct runes *runes) +{ + struct lightningd *ld = runes->ld; + + runes->next_unique_id = db_get_intvar(ld->wallet->db, "runes_uniqueid", 0); + runes->blacklist = wallet_get_runes_blacklist(runes, ld->wallet); + /* Initialize usage table and start flush timer. */ runes->usage_table = NULL; flush_usage_table(runes); - - return runes; } struct rune_and_string { @@ -281,7 +292,7 @@ static struct command_result *json_add_rune(struct lightningd *ld, if (is_rune_blacklisted(ld->runes, rune)) { json_add_bool(js, "blacklisted", true); } - if (rune_is_derived(ld->runes->master, rune)) { + if (rune_is_ours(ld, rune) != NULL) { json_add_bool(js, "our_rune", false); } json_add_string(js, "unique_id", rune->unique_id); @@ -757,7 +768,7 @@ static struct command_result *json_checkrune(struct command *cmd, cinfo.usage = NULL; strmap_init(&cinfo.cached_params); - err = rune_is_derived(cmd->ld->runes->master, ras->rune); + err = rune_is_ours(cmd->ld, ras->rune); if (err) { return command_fail(cmd, RUNE_NOT_AUTHORIZED, "Not authorized: %s", err); } diff --git a/lightningd/runes.h b/lightningd/runes.h index d38052b44..e646021d4 100644 --- a/lightningd/runes.h +++ b/lightningd/runes.h @@ -2,6 +2,17 @@ #define LIGHTNING_LIGHTNINGD_RUNES_H #include "config.h" -struct runes *runes_init(struct lightningd *ld); +struct rune; + +/* Initialize ld->runes enough for rune_is_ours(): needs HSM. */ +struct runes *runes_early_init(struct lightningd *ld); + +/* Finish it: needs db. */ +void runes_finish_init(struct runes *runes); + +/* Is this rune one of ours? Needed for commando migration. + * Returns NULL if it is, or a string explaining (usually, "Not derived from master"). + */ +const char *rune_is_ours(struct lightningd *ld, const struct rune *rune); #endif /* LIGHTNING_LIGHTNINGD_RUNES_H */ diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index b33f3ce50..035ae3de2 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -187,9 +187,12 @@ void plugins_set_builtin_plugins_dir(struct plugins *plugins UNNEEDED, /* Generated stub for resend_closing_transactions */ void resend_closing_transactions(struct lightningd *ld UNNEEDED) { fprintf(stderr, "resend_closing_transactions called!\n"); abort(); } -/* Generated stub for runes_init */ -struct runes *runes_init(struct lightningd *ld UNNEEDED) -{ fprintf(stderr, "runes_init called!\n"); abort(); } +/* Generated stub for runes_early_init */ +struct runes *runes_early_init(struct lightningd *ld UNNEEDED) +{ fprintf(stderr, "runes_early_init called!\n"); abort(); } +/* Generated stub for runes_finish_init */ +void runes_finish_init(struct runes *runes UNNEEDED) +{ fprintf(stderr, "runes_finish_init called!\n"); abort(); } /* Generated stub for setup_color_and_alias */ void setup_color_and_alias(struct lightningd *ld UNNEEDED) { fprintf(stderr, "setup_color_and_alias called!\n"); abort(); }