utxo: Add blockheight and spendheight to outputs to track state

Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
Christian Decker 2018-02-26 11:36:48 +01:00
parent 7f00230657
commit 227dc36146
7 changed files with 64 additions and 13 deletions

View file

@ -26,6 +26,12 @@ struct utxo {
/* Optional unilateral close information, NULL if this is just /* Optional unilateral close information, NULL if this is just
* a HD key */ * a HD key */
struct unilateral_close_info *close_info; 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); void towire_utxo(u8 **pptr, const struct utxo *utxo);

View file

@ -77,7 +77,7 @@ static void filter_block_txs(struct chain_topology *topo, struct block *b)
satoshi_owned = 0; satoshi_owned = 0;
if (txfilter_match(topo->bitcoind->ld->owned_txfilter, tx)) { if (txfilter_match(topo->bitcoind->ld->owned_txfilter, tx)) {
wallet_extract_owned_outputs(topo->bitcoind->ld->wallet, 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. */ /* 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) 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. */ /* Attach to tip; b is now the tip. */
assert(b->height == topo->tip->height + 1); assert(b->height == topo->tip->height + 1);
b->prev = topo->tip; b->prev = topo->tip;
topo->tip->next = b; topo->tip->next = b;
topo->tip = b; topo->tip = b;
wallet_block_add(topo->wallet, 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, static struct block *new_block(struct chain_topology *topo,

View file

@ -226,6 +226,8 @@ static void onchain_add_utxo(struct channel *channel, const u8 *msg)
u->status = output_state_available; u->status = output_state_available;
u->close_info->channel_id = channel->dbid; u->close_info->channel_id = channel->dbid;
u->close_info->peer_id = channel->peer->id; u->close_info->peer_id = channel->peer->id;
u->blockheight = NULL;
u->spendheight = NULL;
if (!fromwire_onchain_add_utxo(msg, &u->txid, &u->outnum, if (!fromwire_onchain_add_utxo(msg, &u->txid, &u->outnum,
&u->close_info->commitment_point, &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. */ /* We keep watching until peer finally deleted, for reorgs. */
return KEEP_WATCHING; return KEEP_WATCHING;
} }

View file

@ -354,7 +354,7 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp,
tal_hex(msg, resp)); tal_hex(msg, resp));
/* Extract the change output and add it to the DB */ /* 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. */ /* Send it out and watch for confirms. */
broadcast_tx(ld->topology, channel, fundingtx, funding_broadcast_failed); broadcast_tx(ld->topology, channel, fundingtx, funding_broadcast_failed);

View file

@ -35,7 +35,18 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo,
{ {
sqlite3_stmt *stmt; 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_blob(stmt, 1, &utxo->txid, sizeof(utxo->txid), SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 2, utxo->outnum); sqlite3_bind_int(stmt, 2, utxo->outnum);
sqlite3_bind_int64(stmt, 3, utxo->amount); 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, 8);
sqlite3_bind_null(stmt, 9); 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); 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) static bool wallet_stmt2output(sqlite3_stmt *stmt, struct utxo *utxo)
{ {
int *blockheight, *spendheight;
sqlite3_column_sha256_double(stmt, 0, &utxo->txid.shad); sqlite3_column_sha256_double(stmt, 0, &utxo->txid.shad);
utxo->outnum = sqlite3_column_int(stmt, 1); utxo->outnum = sqlite3_column_int(stmt, 1);
utxo->amount = sqlite3_column_int64(stmt, 2); 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->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; 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( sqlite3_stmt *stmt = db_prepare(
w->db, "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, " 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"); "FROM outputs WHERE status=?1 OR ?1=255");
sqlite3_bind_int(stmt, 1, state); 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, 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; int num_utxos = 0;
for (size_t output = 0; output < tal_count(tx->output); output++) { 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); bitcoin_txid(tx, &utxo->txid);
utxo->outnum = output; utxo->outnum = output;
utxo->close_info = NULL; utxo->close_info = NULL;
utxo->blockheight = block?&block->height:NULL;
utxo->spendheight = NULL;
log_debug(w->log, "Owning output %zu %"PRIu64" (%s) txid %s", log_debug(w->log, "Owning output %zu %"PRIu64" (%s) txid %s",
output, tx->output[output].amount, output, tx->output[output].amount,
is_p2sh ? "P2SH" : "SEGWIT", is_p2sh ? "P2SH" : "SEGWIT",

View file

@ -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 * 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, 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 * wallet_htlc_save_in - store an htlc_in in the database

View file

@ -58,7 +58,7 @@ static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind UNUSED,
* generated the hex tx, so this should always work */ * generated the hex tx, so this should always work */
tx = bitcoin_tx_from_hex(withdraw, withdraw->hextx, strlen(withdraw->hextx)); tx = bitcoin_tx_from_hex(withdraw, withdraw->hextx, strlen(withdraw->hextx));
assert(tx != NULL); 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 /* Note normally, change_satoshi == withdraw->changesatoshi, but
* not if we're actually making a payment to ourselves! */ * not if we're actually making a payment to ourselves! */