diff --git a/common/utxo.h b/common/utxo.h index a1ba5e4ee..c31d40641 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -26,6 +26,12 @@ struct utxo { /* Optional unilateral close information, NULL if this is just * a HD key */ struct unilateral_close_info *close_info; + + /* NULL if we haven't seen it in a block, otherwise the block it's in */ + const int *blockheight; + + /* NULL if not spent yet, otherwise, the block the spending transaction is in */ + const int *spendheight; }; void towire_utxo(u8 **pptr, const struct utxo *utxo); diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 4dbd05c38..ad5dbabbe 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -77,7 +77,7 @@ static void filter_block_txs(struct chain_topology *topo, struct block *b) satoshi_owned = 0; if (txfilter_match(topo->bitcoind->ld->owned_txfilter, tx)) { wallet_extract_owned_outputs(topo->bitcoind->ld->wallet, - tx, &satoshi_owned); + tx, b, &satoshi_owned); } /* We did spends first, in case that tells us to watch tx. */ @@ -350,17 +350,17 @@ static void updates_complete(struct chain_topology *topo) static void add_tip(struct chain_topology *topo, struct block *b) { - /* Only keep the transactions we care about. */ - filter_block_txs(topo, b); - - block_map_add(&topo->block_map, b); - /* Attach to tip; b is now the tip. */ assert(b->height == topo->tip->height + 1); b->prev = topo->tip; topo->tip->next = b; topo->tip = b; wallet_block_add(topo->wallet, b); + + /* Only keep the transactions we care about. */ + filter_block_txs(topo, b); + + block_map_add(&topo->block_map, b); } static struct block *new_block(struct chain_topology *topo, diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index e4d27180d..c2cbad270 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -226,6 +226,8 @@ static void onchain_add_utxo(struct channel *channel, const u8 *msg) u->status = output_state_available; u->close_info->channel_id = channel->dbid; u->close_info->peer_id = channel->peer->id; + u->blockheight = NULL; + u->spendheight = NULL; if (!fromwire_onchain_add_utxo(msg, &u->txid, &u->outnum, &u->close_info->commitment_point, @@ -457,4 +459,3 @@ enum watch_result funding_spent(struct channel *channel, /* We keep watching until peer finally deleted, for reorgs. */ return KEEP_WATCHING; } - diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index a750d901b..6b9f81d12 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -354,7 +354,7 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, tal_hex(msg, resp)); /* Extract the change output and add it to the DB */ - wallet_extract_owned_outputs(ld->wallet, fundingtx, &change_satoshi); + wallet_extract_owned_outputs(ld->wallet, fundingtx, NULL, &change_satoshi); /* Send it out and watch for confirms. */ broadcast_tx(ld->topology, channel, fundingtx, funding_broadcast_failed); diff --git a/wallet/wallet.c b/wallet/wallet.c index 8e35ee4ee..69d562d11 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -35,7 +35,18 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, { sqlite3_stmt *stmt; - stmt = db_prepare(w->db, "INSERT INTO outputs (prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"); + stmt = db_prepare(w->db, "INSERT INTO outputs (" + "prev_out_tx, " + "prev_out_index, " + "value, " + "type, " + "status, " + "keyindex, " + "channel_id, " + "peer_id, " + "commitment_point, " + "confirmation_height, " + "spend_height) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); sqlite3_bind_blob(stmt, 1, &utxo->txid, sizeof(utxo->txid), SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, utxo->outnum); sqlite3_bind_int64(stmt, 3, utxo->amount); @@ -51,6 +62,19 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, sqlite3_bind_null(stmt, 8); sqlite3_bind_null(stmt, 9); } + + if (utxo->blockheight) { + sqlite3_bind_int(stmt, 10, *utxo->blockheight); + } else + sqlite3_bind_null(stmt, 10); + + if (utxo->spendheight) + sqlite3_bind_int(stmt, 11, *utxo->spendheight); + else + sqlite3_bind_null(stmt, 11); + + /* May fail if we already know about the tx, e.g., because + * it's change or some internal tx. */ return db_exec_prepared_mayfail(w->db, stmt); } @@ -61,6 +85,7 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, */ static bool wallet_stmt2output(sqlite3_stmt *stmt, struct utxo *utxo) { + int *blockheight, *spendheight; sqlite3_column_sha256_double(stmt, 0, &utxo->txid.shad); utxo->outnum = sqlite3_column_int(stmt, 1); utxo->amount = sqlite3_column_int64(stmt, 2); @@ -76,6 +101,21 @@ static bool wallet_stmt2output(sqlite3_stmt *stmt, struct utxo *utxo) utxo->close_info = NULL; } + utxo->blockheight = NULL; + utxo->spendheight = NULL; + + if (sqlite3_column_type(stmt, 9) != SQLITE_NULL) { + blockheight = tal(utxo, int); + *blockheight = sqlite3_column_int(stmt, 9); + utxo->blockheight = blockheight; + } + + if (sqlite3_column_type(stmt, 10) != SQLITE_NULL) { + spendheight = tal(utxo, int); + *spendheight = sqlite3_column_int(stmt, 10); + utxo->spendheight = spendheight; + } + return true; } @@ -110,7 +150,7 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou sqlite3_stmt *stmt = db_prepare( w->db, "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, " - "channel_id, peer_id, commitment_point " + "channel_id, peer_id, commitment_point, confirmation_height, spend_height " "FROM outputs WHERE status=?1 OR ?1=255"); sqlite3_bind_int(stmt, 1, state); @@ -942,7 +982,7 @@ void wallet_peer_delete(struct wallet *w, u64 peer_dbid) } int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx, - u64 *total_satoshi) + const struct block *block, u64 *total_satoshi) { int num_utxos = 0; for (size_t output = 0; output < tal_count(tx->output); output++) { @@ -962,6 +1002,10 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx, bitcoin_txid(tx, &utxo->txid); utxo->outnum = output; utxo->close_info = NULL; + + utxo->blockheight = block?&block->height:NULL; + utxo->spendheight = NULL; + log_debug(w->log, "Owning output %zu %"PRIu64" (%s) txid %s", output, tx->output[output].amount, is_p2sh ? "P2SH" : "SEGWIT", diff --git a/wallet/wallet.h b/wallet/wallet.h index 3ce1fcb4d..514bcd2f4 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -279,7 +279,7 @@ u32 wallet_first_blocknum(struct wallet *w, u32 first_possible); * wallet_extract_owned_outputs - given a tx, extract all of our outputs */ int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx, - u64 *total_satoshi); + const struct block *block, u64 *total_satoshi); /** * wallet_htlc_save_in - store an htlc_in in the database diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index e3b231ba8..1ac3b19a1 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -58,7 +58,7 @@ static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind UNUSED, * generated the hex tx, so this should always work */ tx = bitcoin_tx_from_hex(withdraw, withdraw->hextx, strlen(withdraw->hextx)); assert(tx != NULL); - wallet_extract_owned_outputs(ld->wallet, tx, &change_satoshi); + wallet_extract_owned_outputs(ld->wallet, tx, NULL, &change_satoshi); /* Note normally, change_satoshi == withdraw->changesatoshi, but * not if we're actually making a payment to ourselves! */