Browse Source

utxos: add a 'reserved_til' marker for utxos

Allow a utxo to be reserved until explicitly unreserved or until a timer
runs out. Currently unused.

We explicitly do not unreserve these at startup.
release-0.9.0
niftynei 4 years ago
committed by Rusty Russell
parent
commit
7ebdc14397
  1. 3
      common/utxo.h
  2. 1
      wallet/db.c
  3. 31
      wallet/wallet.c
  4. 21
      wallet/walletrpc.c
  5. 3
      wallet/walletrpc.h

3
common/utxo.h

@ -39,6 +39,9 @@ struct utxo {
/* NULL if not spent yet, otherwise, the block the spending transaction is in */
const u32 *spendheight;
/* Block this utxo becomes unreserved, if applicable */
u32 *reserved_til;
/* The scriptPubkey if it is known */
u8 *scriptPubkey;

1
wallet/db.c

@ -617,6 +617,7 @@ static struct migration dbmigrations[] = {
/* We track the counter for coin_moves, as a convenience for notification consumers */
{SQL("INSERT INTO vars (name, intval) VALUES ('coin_moves_count', 0);"), NULL},
{NULL, migrate_last_tx_to_psbt},
{SQL("ALTER TABLE outputs ADD reserved_til INTEGER DEFAULT NULL;"), NULL},
};
/* Leak tracking. */

31
wallet/wallet.c

@ -158,7 +158,7 @@ static bool wallet_add_utxo(struct wallet *w, struct utxo *utxo,
static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt)
{
struct utxo *utxo = tal(ctx, struct utxo);
u32 *blockheight, *spendheight;
u32 *blockheight, *spendheight, *reserved_til;
db_column_txid(stmt, 0, &utxo->txid);
utxo->outnum = db_column_int(stmt, 1);
db_column_amount_sat(stmt, 2, &utxo->amount);
@ -184,6 +184,7 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt)
utxo->spendheight = NULL;
utxo->scriptPubkey = NULL;
utxo->scriptSig = NULL;
utxo->reserved_til = NULL;
if (!db_column_is_null(stmt, 9)) {
blockheight = tal(utxo, u32);
@ -202,6 +203,11 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt)
tal_dup_arr(utxo, u8, db_column_blob(stmt, 11),
db_column_bytes(stmt, 11), 0);
}
if (!db_column_is_null(stmt, 12)) {
reserved_til = tal(utxo, u32);
*reserved_til = db_column_int(stmt, 12);
utxo->reserved_til = reserved_til;
}
return utxo;
}
@ -255,6 +261,7 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou
", confirmation_height"
", spend_height"
", scriptpubkey "
", reserved_til "
"FROM outputs"));
} else {
stmt = db_prepare_v2(w->db, SQL("SELECT"
@ -270,6 +277,7 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou
", confirmation_height"
", spend_height"
", scriptpubkey "
", reserved_til "
"FROM outputs "
"WHERE status= ? "));
db_bind_int(stmt, 0, output_status_in_db(state));
@ -306,6 +314,7 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx,
", confirmation_height"
", spend_height"
", scriptpubkey"
", reserved_til"
" FROM outputs"
" WHERE channel_id IS NOT NULL AND "
"confirmation_height IS NULL"));
@ -341,6 +350,7 @@ struct utxo *wallet_utxo_get(const tal_t *ctx, struct wallet *w,
", confirmation_height"
", spend_height"
", scriptpubkey"
", reserved_til"
" FROM outputs"
" WHERE prev_out_tx = ?"
" AND prev_out_index = ?"));
@ -3799,14 +3809,17 @@ static void process_utxo_result(struct bitcoind *bitcoind,
enum output_status newstate =
txout == NULL ? output_state_spent : output_state_available;
log_unusual(bitcoind->ld->wallet->log,
"wallet: reserved output %s/%u reset to %s",
type_to_string(tmpctx, struct bitcoin_txid, &utxos[0]->txid),
utxos[0]->outnum,
newstate == output_state_spent ? "spent" : "available");
wallet_update_output_status(bitcoind->ld->wallet,
&utxos[0]->txid, utxos[0]->outnum,
utxos[0]->status, newstate);
/* Don't unreserve ones which are on timers */
if (!utxos[0]->reserved_til || newstate == output_state_spent) {
log_unusual(bitcoind->ld->wallet->log,
"wallet: reserved output %s/%u reset to %s",
type_to_string(tmpctx, struct bitcoin_txid, &utxos[0]->txid),
utxos[0]->outnum,
newstate == output_state_spent ? "spent" : "available");
wallet_update_output_status(bitcoind->ld->wallet,
&utxos[0]->txid, utxos[0]->outnum,
utxos[0]->status, newstate);
}
/* If we have more, resolve them too. */
tal_arr_remove(&utxos, 0);

21
wallet/walletrpc.c

@ -843,6 +843,19 @@ static const struct json_command listaddrs_command = {
};
AUTODATA(json_command, &listaddrs_command);
bool is_reserved(const struct utxo *utxo, u32 current_height)
{
if (utxo->status != output_state_reserved)
return false;
/* FIXME: Eventually this will always be set! */
if (!utxo->reserved_til)
return true;
return *utxo->reserved_til > current_height;
}
static void json_add_utxo(struct json_stream *response,
const char *fieldname,
struct wallet *wallet,
@ -899,7 +912,8 @@ static void json_add_utxo(struct json_stream *response,
json_add_string(response, "status", "unconfirmed");
json_add_bool(response, "reserved",
utxo->status == output_state_reserved);
is_reserved(utxo,
get_block_height(wallet->ld->topology)));
json_object_end(response);
}
@ -1315,9 +1329,8 @@ static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd,
if (!utxo)
continue;
/* Oops we haven't reserved this utxo yet.
* Let's just go ahead and reserve it now. */
if (utxo->status != output_state_reserved)
/* Oops we haven't reserved this utxo yet! */
if (!is_reserved(utxo, get_block_height(cmd->ld->topology)))
return command_fail(cmd, LIGHTNINGD,
"Aborting PSBT signing. UTXO %s:%u is not reserved",
type_to_string(tmpctx, struct bitcoin_txid,

3
wallet/walletrpc.h

@ -9,4 +9,7 @@ void json_add_utxos(struct json_stream *response,
struct wallet *wallet,
struct utxo **utxos);
/* We evaluate reserved timeouts lazily, so use this. */
bool is_reserved(const struct utxo *utxo, u32 current_height);
#endif /* LIGHTNING_WALLET_WALLETRPC_H */

Loading…
Cancel
Save