mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-03 10:46:58 +01:00
utxo: Add blockheight and spendheight to outputs to track state
Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
parent
7f00230657
commit
227dc36146
7 changed files with 64 additions and 13 deletions
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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! */
|
||||||
|
|
Loading…
Add table
Reference in a new issue