From e7b9a913a6d585572b8215851a2d8f4062a12650 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 24 Apr 2016 19:40:29 +0930 Subject: [PATCH] bitcoind: getrawblock helper. It turns out using the verbose=false parameter, you can get the raw block from getblock. Do that. Signed-off-by: Rusty Russell --- Makefile | 2 ++ bitcoin/block.c | 38 ++++++++++++++++++++++++++++++++++++++ bitcoin/block.h | 28 ++++++++++++++++++++++++++++ bitcoin/tx.c | 16 ++++++++++------ bitcoin/tx.h | 7 +++++++ daemon/bitcoind.c | 35 +++++++++++++++++++++++++++++++++++ daemon/bitcoind.h | 15 +++++++++++++++ 7 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 bitcoin/block.c create mode 100644 bitcoin/block.h diff --git a/Makefile b/Makefile index 7a444c0d0..e6f61d989 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ TEST_PROGRAMS := \ BITCOIN_SRC := \ bitcoin/base58.c \ + bitcoin/block.c \ bitcoin/locktime.c \ bitcoin/pubkey.c \ bitcoin/script.c \ @@ -129,6 +130,7 @@ CCAN_HEADERS := \ BITCOIN_HEADERS := bitcoin/address.h \ bitcoin/base58.h \ + bitcoin/block.h \ bitcoin/locktime.h \ bitcoin/privkey.h \ bitcoin/pubkey.h \ diff --git a/bitcoin/block.c b/bitcoin/block.c new file mode 100644 index 000000000..9b51cf903 --- /dev/null +++ b/bitcoin/block.c @@ -0,0 +1,38 @@ +#include "bitcoin/block.h" +#include "bitcoin/tx.h" +#include + +/* Encoding is ... */ +struct bitcoin_block *bitcoin_block_from_hex(const tal_t *ctx, + const char *hex, size_t hexlen) +{ + struct bitcoin_block *b; + u8 *linear_tx; + const u8 *p; + size_t len, i, num; + + if (hexlen && hex[hexlen-1] == '\n') + hexlen--; + + /* Set up the block for success. */ + b = tal(ctx, struct bitcoin_block); + + /* De-hex the array. */ + len = hex_data_size(hexlen); + p = linear_tx = tal_arr(ctx, u8, len); + if (!hex_decode(hex, hexlen, linear_tx, len)) + return tal_free(b); + + pull(&p, &len, &b->hdr, sizeof(b->hdr)); + num = pull_varint(&p, &len); + b->tx = tal_arr(b, struct bitcoin_tx *, num); + for (i = 0; i < num; i++) + b->tx[i] = pull_bitcoin_tx(b->tx, &p, &len); + + /* We should end up not overrunning, nor have extra */ + if (!p || len) + return tal_free(b); + + tal_free(linear_tx); + return b; +} diff --git a/bitcoin/block.h b/bitcoin/block.h new file mode 100644 index 000000000..b58c1215f --- /dev/null +++ b/bitcoin/block.h @@ -0,0 +1,28 @@ +#ifndef LIGHTNING_BITCOIN_BLOCK_H +#define LIGHTNING_BITCOIN_BLOCK_H +#include "config.h" +#include "bitcoin/shadouble.h" +#include +#include +#include +#include + +struct bitcoin_block_hdr { + le32 version; + struct sha256_double prev_hash; + struct sha256_double merkle_hash; + le32 timestamp; + le32 target; + le32 nonce; +}; + +struct bitcoin_block { + struct bitcoin_block_hdr hdr; + /* tal_count shows now many */ + struct bitcoin_tx **tx; +}; + +struct bitcoin_block *bitcoin_block_from_hex(const tal_t *ctx, + const char *hex, size_t hexlen); + +#endif /* LIGHTNING_BITCOIN_BLOCK_H */ diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 8bd8ef436..f49f1addb 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -1,3 +1,4 @@ +#include "bitcoin/block.h" #include "tx.h" #include #include @@ -343,7 +344,7 @@ struct bitcoin_tx *bitcoin_tx(const tal_t *ctx, varint_t input_count, } /* Sets *cursor to NULL and returns NULL when a pull fails. */ -static const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n) +const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n) { const u8 *p = *cursor; @@ -362,7 +363,7 @@ static const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n) return memcheck(p, n); } -static u64 pull_varint(const u8 **cursor, size_t *max) +u64 pull_varint(const u8 **cursor, size_t *max) { u64 ret; size_t len; @@ -470,8 +471,8 @@ static void pull_witness(struct bitcoin_tx_input *inputs, size_t i, } } -static struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, - const u8 **cursor, size_t *max) +struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, + const u8 **cursor, size_t *max) { struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx); size_t i; @@ -505,8 +506,8 @@ static struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, } tx->lock_time = pull_le32(cursor, max); - /* If we ran short, or have bytes left over, fail. */ - if (!*cursor || *max != 0) + /* If we ran short, fail. */ + if (!*cursor) tx = tal_free(tx); return tx; } @@ -533,6 +534,9 @@ struct bitcoin_tx *bitcoin_tx_from_hex(const tal_t *ctx, const char *hex, if (!tx) goto fail; + if (len) + goto fail_free_tx; + if (end != hex + hexlen && *end != '\n') goto fail_free_tx; diff --git a/bitcoin/tx.h b/bitcoin/tx.h index 5f6e8ff61..097ddb667 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -73,4 +73,11 @@ bool bitcoin_txid_from_hex(const char *hexstr, size_t hexstr_len, bool bitcoin_txid_to_hex(const struct sha256_double *txid, char *hexstr, size_t hexstr_len); + +/* Internal de-linearization functions. */ +struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, + const u8 **cursor, size_t *max); +u64 pull_varint(const u8 **cursor, size_t *max); +const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n); + #endif /* LIGHTNING_BITCOIN_TX_H */ diff --git a/daemon/bitcoind.c b/daemon/bitcoind.c index fdde3f375..d7c3d0697 100644 --- a/daemon/bitcoind.c +++ b/daemon/bitcoind.c @@ -1,5 +1,6 @@ /* Code for talking to bitcoind. We use bitcoin-cli. */ #include "bitcoin/base58.h" +#include "bitcoin/block.h" #include "bitcoin/shadouble.h" #include "bitcoin/tx.h" #include "bitcoind.h" @@ -724,6 +725,40 @@ void bitcoind_getblock_(struct lightningd_state *dstate, "getblock", hex, NULL); } +static void process_rawblock(struct bitcoin_cli *bcli) +{ + struct bitcoin_block *blk; + void (*cb)(struct lightningd_state *dstate, + struct bitcoin_block *blk, + void *arg) = bcli->cb; + + /* FIXME: Just get header if we can't get full block. */ + if (!bcli->output) + fatal("%s: unknown block?", bcli_args(bcli)); + + blk = bitcoin_block_from_hex(bcli, bcli->output, bcli->output_bytes); + if (!blk) + fatal("%s: bad block '%.*s'?", + bcli_args(bcli), + (int)bcli->output_bytes, (char *)bcli->output); + + cb(bcli->dstate, blk, bcli->cb_arg); +} + +void bitcoind_getrawblock_(struct lightningd_state *dstate, + const struct sha256_double *blockid, + void (*cb)(struct lightningd_state *dstate, + struct bitcoin_block *blk, + void *arg), + void *arg) +{ + char hex[hex_str_size(sizeof(*blockid))]; + + hex_encode(blockid, sizeof(*blockid), hex, sizeof(hex)); + start_bitcoin_cli(dstate, process_rawblock, cb, arg, + "getblock", hex, "false", NULL); +} + static void process_getblockcount(struct bitcoin_cli *bcli) { u32 blockcount; diff --git a/daemon/bitcoind.h b/daemon/bitcoind.h index ee8360e72..08cc01601 100644 --- a/daemon/bitcoind.h +++ b/daemon/bitcoind.h @@ -10,6 +10,7 @@ struct lightningd_state; struct ripemd160; struct bitcoin_tx; struct peer; +struct bitcoin_block; /* -datadir arg for bitcoin-cli. */ extern char *bitcoin_datadir; @@ -121,6 +122,20 @@ void bitcoind_getblockhash_(struct lightningd_state *dstate, const struct sha256_double *), \ (arg)) +void bitcoind_getrawblock_(struct lightningd_state *dstate, + const struct sha256_double *blockid, + void (*cb)(struct lightningd_state *dstate, + struct bitcoin_block *blk, + void *arg), + void *arg); +#define bitcoind_getrawblock(dstate, blkid, cb, arg) \ + bitcoind_getrawblock_((dstate), (blkid), \ + typesafe_cb_preargs(void, void *, \ + (cb), (arg), \ + struct lightningd_state *, \ + struct bitcoin_block *), \ + (arg)) + void normalized_txid(const struct bitcoin_tx *tx, struct sha256_double *txid); void check_bitcoind_config(struct lightningd_state *dstate);