wallet: Retrieve transaction annotations when listing transactions

This triple join should be efficient to read, and to process. We have a
one-to-many (tx-to-annotations), followed by a
one-to-one (annotation-to-channel) join, so we are limited to annotations x
transactions results.
This commit is contained in:
Christian Decker 2019-10-02 19:36:28 +02:00 committed by neil saitug
parent ddae604f3d
commit d981b58234
3 changed files with 93 additions and 21 deletions

View File

@ -3410,24 +3410,88 @@ struct wallet_transaction *wallet_transactions_get(struct wallet *w, const tal_t
{
struct db_stmt *stmt;
size_t count;
struct wallet_transaction *cur, *txs = tal_arr(ctx, struct wallet_transaction, 0);
struct wallet_transaction *cur = NULL, *txs = tal_arr(ctx, struct wallet_transaction, 0);
struct bitcoin_txid last;
/* Make sure we can check for changing txids */
memset(&last, 0, sizeof(last));
stmt = db_prepare_v2(
w->db,
SQL("SELECT id, id, rawtx, blockheight, txindex, type, channel_id "
"FROM transactions"));
SQL("SELECT"
" t.id"
", t.rawtx"
", t.blockheight"
", t.txindex"
", t.type as txtype"
", c2.short_channel_id as txchan"
", a.location"
", a.idx as ann_idx"
", a.type as annotation_type"
", c.short_channel_id"
" FROM"
" transactions t LEFT JOIN"
" transaction_annotations a ON (a.txid = t.id) LEFT JOIN"
" channels c ON (a.channel = c.id) LEFT JOIN"
" channels c2 ON (t.channel_id = c2.id) "
"ORDER BY blockheight, txindex ASC"));
db_query_prepared(stmt);
for (count = 0; db_step(stmt); count++) {
tal_resize(&txs, count + 1);
cur = &txs[count];
db_column_txid(stmt, 1, &cur->id);
cur->rawtx = tal_dup_arr(txs, u8, db_column_blob(stmt, 2),
db_column_bytes(stmt, 2), 0);
cur->blockheight = db_column_int(stmt, 3);
cur->txindex = db_column_int(stmt, 4);
cur->type = db_column_int(stmt, 5);
cur->channel_id = db_column_int(stmt, 6);
struct bitcoin_txid curtxid;
db_column_txid(stmt, 0, &curtxid);
/* If this is a new entry, allocate it in the array and set
* the common fields (all fields from the transactions
* table. */
if (!bitcoin_txid_eq(&last, &curtxid)) {
last = curtxid;
tal_resize(&txs, count + 1);
cur = &txs[count];
db_column_txid(stmt, 0, &cur->id);
cur->tx = db_column_tx(txs, stmt, 1);
cur->rawtx = tal_dup_arr(txs, u8, db_column_blob(stmt, 1),
db_column_bytes(stmt, 1), 0);
cur->blockheight = db_column_int(stmt, 2);
cur->txindex = db_column_int(stmt, 3);
if (!db_column_is_null(stmt, 4))
cur->annotation.type = db_column_u64(stmt, 4);
else
cur->annotation.type = 0;
if (!db_column_is_null(stmt, 5))
db_column_short_channel_id(stmt, 5, &cur->annotation.channel);
else
cur->annotation.channel.u64 = 0;
cur->output_annotations = tal_arrz(txs, struct tx_annotation, cur->tx->wtx->num_outputs);
cur->input_annotations = tal_arrz(txs, struct tx_annotation, cur->tx->wtx->num_inputs);
}
/* This should always be set by the above if-statement,
* otherwise we have a txid of all 0x00 bytes... */
assert(cur != NULL);
/* Check if we have any annotations. If there are none the
* fields are all set to null */
if (!db_column_is_null(stmt, 6)) {
enum wallet_tx_annotation_type loc = db_column_int(stmt, 6);
int idx = db_column_int(stmt, 7);
struct tx_annotation *ann;
/* Select annotation from array to fill in. */
if (loc == OUTPUT_ANNOTATION)
ann = &cur->output_annotations[idx];
else if (loc == INPUT_ANNOTATION)
ann = &cur->input_annotations[idx];
else
fatal("Transaction annotations are only available for inputs and outputs. Value %d", loc);
ann->type = db_column_int(stmt, 8);
if (!db_column_is_null(stmt, 9))
db_column_short_channel_id(stmt, 9, &ann->channel);
else
ann->channel.u64 = 0;
}
}
tal_free(stmt);
return txs;

View File

@ -219,6 +219,11 @@ enum wallet_payment_status {
PAYMENT_FAILED = 2
};
struct tx_annotation {
enum wallet_tx_type type;
struct short_channel_id channel;
};
static inline enum wallet_payment_status wallet_payment_status_in_db(enum wallet_payment_status w)
{
switch (w) {
@ -295,8 +300,17 @@ struct wallet_transaction {
u32 blockheight;
u32 txindex;
u8 *rawtx;
enum wallet_tx_type type;
u64 channel_id;
/* Fully parsed transaction */
const struct bitcoin_tx *tx;
struct tx_annotation annotation;
/* tal_arr containing the annotation types, if any, for the respective
* inputs and outputs. 0 if there are no annotations for the
* element. */
struct tx_annotation *input_annotations;
struct tx_annotation *output_annotations;
};
/**
@ -1179,7 +1193,7 @@ void free_unreleased_txs(struct wallet *w);
*
* @param ctx: allocation context for the returned list
* @param wallet: Wallet to load from.
* @return A tal_arr of wallet transactions
* @return A tal_arr of wallet annotated transactions
*/
struct wallet_transaction *wallet_transactions_get(struct wallet *w, const tal_t *ctx);

View File

@ -936,12 +936,6 @@ static struct command_result *json_listtransactions(struct command *cmd,
json_add_hex_talarr(response, "rawtx", txs[i].rawtx);
json_add_u64(response, "blockheight", txs[i].blockheight);
json_add_num(response, "txindex", txs[i].txindex);
json_add_txtypes(response, "type", txs[i].type);
if (txs[i].channel_id != 0) {
json_add_num(response, "channel_id", txs[i].channel_id);
} else {
json_add_null(response, "channel_id");
}
json_object_end(response);
}
json_array_end(response);