wallet: save keytype when issuing new address.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-11-10 13:34:47 +10:30
parent 13af9bcfe7
commit 6da97e6461
9 changed files with 107 additions and 18 deletions

View File

@ -1212,9 +1212,9 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg)
u8 *scriptpubkey; u8 *scriptpubkey;
struct lightningd *ld = channel->peer->ld; struct lightningd *ld = channel->peer->ld;
struct bitcoin_outpoint *wrong_funding; struct bitcoin_outpoint *wrong_funding;
bool anysegwit = feature_negotiated(ld->our_features, bool anysegwit = !chainparams->is_elements && feature_negotiated(ld->our_features,
channel->peer->their_features, channel->peer->their_features,
OPT_SHUTDOWN_ANYSEGWIT); OPT_SHUTDOWN_ANYSEGWIT);
bool anchors = feature_negotiated(ld->our_features, bool anchors = feature_negotiated(ld->our_features,
channel->peer->their_features, channel->peer->their_features,
OPT_ANCHOR_OUTPUTS_DEPRECATED) OPT_ANCHOR_OUTPUTS_DEPRECATED)

View File

@ -1383,6 +1383,9 @@ wallet_commit_channel(struct lightningd *ld,
{ {
struct amount_msat our_msat, lease_fee_msat; struct amount_msat our_msat, lease_fee_msat;
struct channel_inflight *inflight; struct channel_inflight *inflight;
bool anysegwit = !chainparams->is_elements && feature_negotiated(channel->peer->ld->our_features,
channel->peer->their_features,
OPT_SHUTDOWN_ANYSEGWIT);
bool any_active = peer_any_channel(channel->peer, channel_state_wants_peercomms, NULL); bool any_active = peer_any_channel(channel->peer, channel_state_wants_peercomms, NULL);
if (!amount_sat_to_msat(&our_msat, our_funding)) { if (!amount_sat_to_msat(&our_msat, our_funding)) {
@ -1395,8 +1398,11 @@ wallet_commit_channel(struct lightningd *ld,
return NULL; return NULL;
} }
/* Get a key to use for closing outputs from this tx */ /* Get a key to use for closing outputs from this tx. Prefer
channel->final_key_idx = wallet_get_newindex(ld); * P2TR, but we'll use BECH32 for older peers (but always P2TR
* for our own onchian spends, if any). */
channel->final_key_idx = wallet_get_newindex(ld, anysegwit ? ADDR_P2TR : (ADDR_BECH32|ADDR_P2TR));
if (channel->final_key_idx == -1) { if (channel->final_key_idx == -1) {
log_broken(channel->log, "Can't get final key index"); log_broken(channel->log, "Can't get final key index");
return NULL; return NULL;

View File

@ -110,6 +110,7 @@ wallet_commit_channel(struct lightningd *ld,
struct timeabs timestamp; struct timeabs timestamp;
bool any_active = peer_any_channel(uc->peer, channel_state_wants_peercomms, NULL); bool any_active = peer_any_channel(uc->peer, channel_state_wants_peercomms, NULL);
struct channel_stats zero_channel_stats; struct channel_stats zero_channel_stats;
enum addrtype addrtype;
/* We can't have any payments yet */ /* We can't have any payments yet */
memset(&zero_channel_stats, 0, sizeof(zero_channel_stats)); memset(&zero_channel_stats, 0, sizeof(zero_channel_stats));
@ -119,8 +120,14 @@ wallet_commit_channel(struct lightningd *ld,
*/ */
assert(!(uc->got_offer && uc->fc)); assert(!(uc->got_offer && uc->fc));
/* FIXME: P2TR for elements! */
if (chainparams->is_elements)
addrtype = ADDR_BECH32;
else
addrtype = ADDR_P2TR;
/* Get a key to use for closing outputs from this tx */ /* Get a key to use for closing outputs from this tx */
final_key_idx = wallet_get_newindex(ld); final_key_idx = wallet_get_newindex(ld, addrtype);
if (final_key_idx == -1) { if (final_key_idx == -1) {
log_broken(uc->log, "Can't get final key index"); log_broken(uc->log, "Can't get final key index");
return NULL; return NULL;

View File

@ -1021,7 +1021,9 @@ static struct migration dbmigrations[] = {
{SQL("ALTER TABLE channels ADD remote_htlc_minimum_msat BIGINT DEFAULT NULL;"), NULL}, {SQL("ALTER TABLE channels ADD remote_htlc_minimum_msat BIGINT DEFAULT NULL;"), NULL},
{SQL("ALTER TABLE channels ADD last_stable_connection BIGINT DEFAULT 0;"), NULL}, {SQL("ALTER TABLE channels ADD last_stable_connection BIGINT DEFAULT 0;"), NULL},
{NULL, migrate_initialize_alias_local}, {NULL, migrate_initialize_alias_local},
/* FIXME: Remove now-unused type column from channeltxs */ {SQL("CREATE TABLE addresses ("
" keyidx BIGINT,"
" addrtype INTEGER)"), NULL},
}; };
/** /**

View File

@ -366,9 +366,16 @@ static struct command_result *finish_psbt(struct command *cmd,
struct pubkey pubkey; struct pubkey pubkey;
s64 keyidx; s64 keyidx;
u8 *b32script; u8 *b32script;
enum addrtype type;
/* FIXME: P2TR for elements! */
if (chainparams->is_elements)
type = ADDR_BECH32;
else
type = ADDR_P2TR;
/* Get a change adddress */ /* Get a change adddress */
keyidx = wallet_get_newindex(cmd->ld); keyidx = wallet_get_newindex(cmd->ld, type);
if (keyidx < 0) if (keyidx < 0)
return command_fail(cmd, LIGHTNINGD, return command_fail(cmd, LIGHTNINGD,
"Failed to generate change address." "Failed to generate change address."
@ -700,7 +707,15 @@ static struct command_result *json_addpsbtoutput(struct command *cmd,
/* Get a change adddress */ /* Get a change adddress */
if (!b32script) { if (!b32script) {
keyidx = wallet_get_newindex(cmd->ld); enum addrtype type;
/* FIXME: P2TR for elements! */
if (chainparams->is_elements)
type = ADDR_BECH32;
else
type = ADDR_P2TR;
keyidx = wallet_get_newindex(cmd->ld, type);
if (keyidx < 0) if (keyidx < 0)
return command_fail(cmd, LIGHTNINGD, return command_fail(cmd, LIGHTNINGD,
"Failed to generate change address." "Failed to generate change address."

View File

@ -836,17 +836,50 @@ bool wallet_can_spend(struct wallet *w, const u8 *script,
return false; return false;
} }
s64 wallet_get_newindex(struct lightningd *ld) s64 wallet_get_newindex(struct lightningd *ld, enum addrtype addrtype)
{ {
struct db_stmt *stmt;
u64 newidx = db_get_intvar(ld->wallet->db, "bip32_max_index", 0) + 1; u64 newidx = db_get_intvar(ld->wallet->db, "bip32_max_index", 0) + 1;
if (newidx == BIP32_INITIAL_HARDENED_CHILD) if (newidx == BIP32_INITIAL_HARDENED_CHILD)
return -1; return -1;
db_set_intvar(ld->wallet->db, "bip32_max_index", newidx); db_set_intvar(ld->wallet->db, "bip32_max_index", newidx);
stmt = db_prepare_v2(ld->wallet->db,
SQL("INSERT INTO addresses ("
" keyidx"
", addrtype"
") VALUES (?, ?);"));
db_bind_u64(stmt, newidx);
db_bind_int(stmt, wallet_addrtype_in_db(addrtype));
db_exec_prepared_v2(take(stmt));
return newidx; return newidx;
} }
enum addrtype wallet_get_addrtype(struct wallet *wallet, u64 idx)
{
struct db_stmt *stmt;
enum addrtype type;
stmt = db_prepare_v2(wallet->db,
SQL("SELECT addrtype"
" FROM addresses"
" WHERE keyidx=?"));
db_bind_u64(stmt, idx);
db_query_prepared(stmt);
/* Unknown means prior to v24.11 */
if (!db_step(stmt)) {
tal_free(stmt);
return ADDR_P2TR|ADDR_BECH32;
}
type = wallet_addrtype_in_db(db_col_int(stmt, "addrtype"));
tal_free(stmt);
return type;
}
static void wallet_shachain_init(struct wallet *wallet, static void wallet_shachain_init(struct wallet *wallet,
struct wallet_shachain *chain) struct wallet_shachain *chain)
{ {

View File

@ -271,6 +271,30 @@ static inline enum channel_state channel_state_in_db(enum channel_state s)
fatal("%s: %u is invalid", __func__, s); fatal("%s: %u is invalid", __func__, s);
} }
/* /!\ This is a DB ENUM, please do not change the numbering of any
* already defined elements (adding is ok) /!\ */
enum addrtype {
ADDR_BECH32 = 2,
ADDR_P2TR = 4,
ADDR_ALL = (ADDR_BECH32 + ADDR_P2TR)
};
static inline enum addrtype wallet_addrtype_in_db(enum addrtype t)
{
switch (t) {
case ADDR_BECH32:
BUILD_ASSERT(ADDR_BECH32 == 2);
return t;
case ADDR_P2TR:
BUILD_ASSERT(ADDR_P2TR == 4);
return t;
case ADDR_ALL:
BUILD_ASSERT(ADDR_ALL == 6);
return t;
}
fatal("%s: %u is invalid", __func__, t);
}
/* A database backed shachain struct. The datastructure is /* A database backed shachain struct. The datastructure is
* writethrough, reads are performed from an in-memory version, all * writethrough, reads are performed from an in-memory version, all
* writes are passed through to the DB. */ * writes are passed through to the DB. */
@ -567,10 +591,18 @@ bool wallet_can_spend(struct wallet *w,
/** /**
* wallet_get_newindex - get a new index from the wallet. * wallet_get_newindex - get a new index from the wallet.
* @ld: (in) lightning daemon * @ld: (in) lightning daemon
* @addrtype: (in) addess types we will publish for this
* *
* Returns -1 on error (key exhaustion). * Returns -1 on error (key exhaustion).
*/ */
s64 wallet_get_newindex(struct lightningd *ld); s64 wallet_get_newindex(struct lightningd *ld, enum addrtype addrtype);
/**
* wallet_get_addrtype - get the address types for this key.
* @wallet: (in) wallet
* @keyidx: what address types we've published.
*/
enum addrtype wallet_get_addrtype(struct wallet *w, u64 keyidx);
/** /**
* wallet_shachain_add_hash -- wallet wrapper around shachain_add_hash * wallet_shachain_add_hash -- wallet wrapper around shachain_add_hash

View File

@ -119,7 +119,7 @@ bool WARN_UNUSED_RESULT newaddr_inner(struct command *cmd, struct pubkey *pubkey
u8 *b32script; u8 *b32script;
u8 *p2tr_script; u8 *p2tr_script;
keyidx = wallet_get_newindex(cmd->ld); keyidx = wallet_get_newindex(cmd->ld, addrtype);
if (keyidx < 0) { if (keyidx < 0) {
// return command_fail(cmd, LIGHTNINGD, "Keys exhausted "); // return command_fail(cmd, LIGHTNINGD, "Keys exhausted ");
return false; return false;

View File

@ -2,12 +2,6 @@
#define LIGHTNING_WALLET_WALLETRPC_H #define LIGHTNING_WALLET_WALLETRPC_H
#include "config.h" #include "config.h"
enum addrtype {
ADDR_BECH32 = 2,
ADDR_P2TR = 4,
ADDR_ALL = (ADDR_BECH32 + ADDR_P2TR)
};
struct utxo; struct utxo;
/* We evaluate reserved timeouts lazily, so use this. */ /* We evaluate reserved timeouts lazily, so use this. */