mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
bitcoind: Add a multi-step getfilteredblock method
This will eventually replace the multi-step `getblockhash` + `getblock` + `gettxout` mechanism, and return entire filtered blocks which can be added to the DB, and represent the full set of P2WSH UTXOs. Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
parent
5bb411b572
commit
f4e434d8e1
@ -2,6 +2,7 @@
|
||||
#include "bitcoin/base58.h"
|
||||
#include "bitcoin/block.h"
|
||||
#include "bitcoin/feerate.h"
|
||||
#include "bitcoin/script.h"
|
||||
#include "bitcoin/shadouble.h"
|
||||
#include "bitcoind.h"
|
||||
#include "lightningd.h"
|
||||
@ -784,6 +785,124 @@ void bitcoind_gettxout(struct bitcoind *bitcoind,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Context for the getfilteredblock call. Wraps the actual arguments while we
|
||||
* process the various steps. */
|
||||
struct filteredblock_call {
|
||||
void (*cb)(struct bitcoind *bitcoind, struct filteredblock *fb,
|
||||
void *arg);
|
||||
void *arg;
|
||||
|
||||
struct filteredblock *result;
|
||||
struct filteredblock_outpoint **outpoints;
|
||||
size_t current_outpoint;
|
||||
struct timeabs start_time;
|
||||
};
|
||||
|
||||
static void
|
||||
process_getfilteredblock_step3(struct bitcoind *bitcoind,
|
||||
const struct bitcoin_tx_output *output,
|
||||
void *arg)
|
||||
{
|
||||
struct filteredblock_call *call = (struct filteredblock_call *)arg;
|
||||
struct filteredblock_outpoint *o = call->outpoints[call->current_outpoint];
|
||||
|
||||
/* If this output is unspent, add it to the filteredblock result. */
|
||||
if (output)
|
||||
tal_arr_expand(&call->result->outpoints, tal_steal(call->result, o));
|
||||
|
||||
call->current_outpoint++;
|
||||
if (call->current_outpoint < tal_count(call->outpoints)) {
|
||||
o = call->outpoints[call->current_outpoint];
|
||||
bitcoind_gettxout(bitcoind, &o->txid, o->outnum,
|
||||
process_getfilteredblock_step3, call);
|
||||
} else {
|
||||
/* If there were no more outpoints to check, we call the callback. */
|
||||
call->cb(bitcoind, call->result, call->arg);
|
||||
tal_free(call);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_getfilteredblock_step2(struct bitcoind *bitcoind,
|
||||
struct bitcoin_block *block,
|
||||
struct filteredblock_call *call)
|
||||
{
|
||||
struct filteredblock_outpoint *o;
|
||||
struct bitcoin_tx *tx;
|
||||
call->result->prev_hash = block->hdr.prev_hash;
|
||||
|
||||
/* Allocate an array containing all the potentially interesting
|
||||
* outpoints. We will later copy the ones we're interested in into the
|
||||
* call->result if they are unspent. */
|
||||
|
||||
call->outpoints = tal_arr(call, struct filteredblock_outpoint *, 0);
|
||||
for (size_t i = 0; i < tal_count(block->tx); i++) {
|
||||
tx = block->tx[i];
|
||||
for (size_t j = 0; j < tx->wtx->num_outputs; j++) {
|
||||
const u8 *script = bitcoin_tx_output_get_script(NULL, tx, j);
|
||||
if (is_p2wsh(script, NULL)) {
|
||||
/* This is an interesting output, remember it. */
|
||||
o = tal(call->outpoints, struct filteredblock_outpoint);
|
||||
bitcoin_txid(tx, &o->txid);
|
||||
o->satoshis = bitcoin_tx_output_get_amount(tx, j);
|
||||
o->txindex = i;
|
||||
o->outnum = j;
|
||||
o->scriptPubKey = tal_steal(o, script);
|
||||
tal_arr_expand(&call->outpoints, o);
|
||||
} else {
|
||||
tal_free(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call->result->outpoints = tal_arr(call->result, struct filteredblock_outpoint *, 0);
|
||||
call->current_outpoint = 0;
|
||||
if (tal_count(call->outpoints) == 0) {
|
||||
/* If there were no outpoints to check, we can short-circuit
|
||||
* and just call the callback. */
|
||||
call->cb(bitcoind, call->result, call->arg);
|
||||
tal_free(call);
|
||||
} else {
|
||||
|
||||
/* Otherwise we start iterating through call->outpoints and
|
||||
* store the one's that are unspent in
|
||||
* call->result->outpoints. */
|
||||
o = call->outpoints[call->current_outpoint];
|
||||
bitcoind_gettxout(bitcoind, &o->txid, o->outnum,
|
||||
process_getfilteredblock_step3, call);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_getfilteredblock_step1(struct bitcoind *bitcoind,
|
||||
const struct bitcoin_blkid *blkid,
|
||||
struct filteredblock_call *call)
|
||||
{
|
||||
/* So we have the first piece of the puzzle, the block hash */
|
||||
call->result->id = *blkid;
|
||||
|
||||
/* Now get the raw block to get all outpoints that were created in
|
||||
* this block. */
|
||||
bitcoind_getrawblock(bitcoind, blkid, process_getfilteredblock_step2, call);
|
||||
}
|
||||
|
||||
void bitcoind_getfilteredblock_(struct bitcoind *bitcoind, u32 height,
|
||||
void (*cb)(struct bitcoind *bitcoind,
|
||||
struct filteredblock *fb,
|
||||
void *arg),
|
||||
void *arg)
|
||||
{
|
||||
/* Stash the call context for when we need to call the callback after
|
||||
* all the bitcoind calls we need to perform. */
|
||||
struct filteredblock_call *call = tal(bitcoind, struct filteredblock_call);
|
||||
call->cb = cb;
|
||||
call->arg = arg;
|
||||
call->result = tal(call, struct filteredblock);
|
||||
assert(call->cb != NULL);
|
||||
call->start_time = time_now();
|
||||
call->result->height = height;
|
||||
|
||||
bitcoind_getblockhash(bitcoind, height, process_getfilteredblock_step1, call);
|
||||
}
|
||||
|
||||
static bool extract_numeric_version(struct bitcoin_cli *bcli,
|
||||
const char *output, size_t output_bytes,
|
||||
u64 *version)
|
||||
|
@ -67,6 +67,23 @@ struct bitcoind {
|
||||
char *rpcuser, *rpcpass, *rpcconnect, *rpcport;
|
||||
};
|
||||
|
||||
/* A single outpoint in a filtered block */
|
||||
struct filteredblock_outpoint {
|
||||
struct bitcoin_txid txid;
|
||||
u32 outnum;
|
||||
u32 txindex;
|
||||
const u8 *scriptPubKey;
|
||||
struct amount_sat satoshis;
|
||||
};
|
||||
|
||||
/* A struct representing a block with most of the parts filtered out. */
|
||||
struct filteredblock {
|
||||
struct bitcoin_blkid id;
|
||||
u32 height;
|
||||
struct bitcoin_blkid prev_hash;
|
||||
struct filteredblock_outpoint **outpoints;
|
||||
};
|
||||
|
||||
struct bitcoind *new_bitcoind(const tal_t *ctx,
|
||||
struct lightningd *ld,
|
||||
struct log *log);
|
||||
@ -132,6 +149,20 @@ void bitcoind_getblockhash_(struct bitcoind *bitcoind,
|
||||
const struct bitcoin_blkid *), \
|
||||
(arg))
|
||||
|
||||
void bitcoind_getfilteredblock_(struct bitcoind *bitcoind, u32 height,
|
||||
void (*cb)(struct bitcoind *bitcoind,
|
||||
struct filteredblock *fb,
|
||||
void *arg),
|
||||
void *arg);
|
||||
#define bitcoind_getfilteredblock(bitcoind_, height, cb, arg) \
|
||||
bitcoind_getfilteredblock_((bitcoind_), \
|
||||
(height), \
|
||||
typesafe_cb_preargs(void, void *, \
|
||||
(cb), (arg), \
|
||||
struct bitcoind *, \
|
||||
const struct filteredblock *), \
|
||||
(arg))
|
||||
|
||||
void bitcoind_getrawblock_(struct bitcoind *bitcoind,
|
||||
const struct bitcoin_blkid *blockid,
|
||||
void (*cb)(struct bitcoind *bitcoind,
|
||||
|
Loading…
Reference in New Issue
Block a user