Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 30 additions & 24 deletions bitcoin/block.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "config.h"
#include <assert.h>
#include <bitcoin/block.h>
#include <bitcoin/tx.h>
#include <ccan/mem/mem.h>
Expand All @@ -11,7 +10,9 @@ static const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n)
{
const u8 *p = *cursor;

if (*max < n) {
/* Once a pull has overrun, the cursor stays NULL: a later zero-length
* pull must not resume from it. */
if (!p || *max < n) {
*cursor = NULL;
*max = 0;
/* Just make sure we don't leak uninitialized mem! */
Expand All @@ -21,7 +22,6 @@ static const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n)
}
*cursor += n;
*max -= n;
assert(p);
if (copy)
memcpy(copy, p, n);
return memcheck(p, n);
Expand Down Expand Up @@ -60,6 +60,16 @@ static void sha256_varint(struct sha256_ctx *ctx, u64 val)
sha256_update(ctx, vt, vtlen);
}

/* Hashing before the pull reads past the end of a truncated block, so let
* pull() say whether the bytes are there. */
static void pull_and_hash(const u8 **cursor, size_t *len,
struct sha256_ctx *shactx, size_t n)
{
const u8 *p = pull(cursor, len, NULL, n);
if (p)
sha256_update(shactx, p, n);
}

static void bitcoin_block_pull_dynafed_params(const u8 **cursor, size_t *len, struct sha256_ctx *shactx)
{
u8 type;
Expand All @@ -73,49 +83,41 @@ static void bitcoin_block_pull_dynafed_params(const u8 **cursor, size_t *len, st
/* "scriptPubKey" used for block signing */
l1 = pull_varint(cursor, len);
sha256_varint(shactx, l1);
sha256_update(shactx, *cursor, l1);
pull(cursor, len, NULL, l1);
pull_and_hash(cursor, len, shactx, l1);

/* signblock_witness_limit */
sha256_update(shactx, *cursor, 4);
pull(cursor, len, NULL, 4);
pull_and_hash(cursor, len, shactx, 4);

/* Skip elided_root */
sha256_update(shactx, *cursor, 32);
pull(cursor, len, NULL, 32);
pull_and_hash(cursor, len, shactx, 32);
break;

case DYNAFED_PARAMS_FULL:
/* "scriptPubKey" used for block signing */
l1 = pull_varint(cursor, len);
sha256_varint(shactx, l1);
sha256_update(shactx, *cursor, l1);
pull(cursor, len, NULL, l1);
pull_and_hash(cursor, len, shactx, l1);

/* signblock_witness_limit */
sha256_update(shactx, *cursor, 4);
pull(cursor, len, NULL, 4);
pull_and_hash(cursor, len, shactx, 4);

/* fedpeg_program */
l1 = pull_varint(cursor, len);
sha256_varint(shactx, l1);
sha256_update(shactx, *cursor, l1);
pull(cursor, len, NULL, l1);
pull_and_hash(cursor, len, shactx, l1);

/* fedpegscript */
l1 = pull_varint(cursor, len);
sha256_varint(shactx, l1);
sha256_update(shactx, *cursor, l1);
pull(cursor, len, NULL, l1);
pull_and_hash(cursor, len, shactx, l1);

/* extension space */
l2 = pull_varint(cursor, len);
sha256_varint(shactx, l2);
for (size_t i = 0; i < l2; i++) {
for (size_t i = 0; i < l2 && *cursor; i++) {
l1 = pull_varint(cursor, len);
sha256_varint(shactx, l1);
sha256_update(shactx, *cursor, l1);
pull(cursor, len, NULL, l1);
pull_and_hash(cursor, len, shactx, l1);
}
break;
}
Expand All @@ -128,7 +130,7 @@ static void bitcoin_block_pull_dynafed_details(const u8 **cursor, size_t *len, s

/* Consume the signblock_witness */
u64 numwitnesses = pull_varint(cursor, len);
for (size_t i=0; i<numwitnesses; i++) {
for (size_t i=0; i<numwitnesses && *cursor; i++) {
u64 witsize = pull_varint(cursor, len);
pull(cursor, len, NULL, witsize);
}
Expand All @@ -155,7 +157,7 @@ bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams,

/* De-hex the array. */
len = hex_data_size(hexlen);
p = linear_tx = tal_arr(ctx, u8, len);
p = linear_tx = tal_arr(b, u8, len);
if (!hex_decode(hex, hexlen, linear_tx, len))
return tal_free(b);

Expand Down Expand Up @@ -187,8 +189,7 @@ bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams,
/* elemens_header.challenge */
templen = pull_varint(&p, &len);
sha256_varint(&shactx, templen);
sha256_update(&shactx, p, templen);
pull(&p, &len, NULL, templen);
pull_and_hash(&p, &len, &shactx, templen);

/* elements_header.solution. Not hashed since it'd be
* a circular dependency. */
Expand All @@ -206,10 +207,15 @@ bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams,
sha256_double_done(&shactx, &b->hdr.hash.shad);

num = pull_varint(&p, &len);
/* Every transaction takes at least one byte */
if (num > len)
return tal_free(b);
b->tx = tal_arr(b, struct bitcoin_tx *, num);
b->txids = tal_arr(b, struct bitcoin_txid, num);
for (i = 0; i < num; i++) {
b->tx[i] = pull_bitcoin_tx_only(b->tx, &p, &len);
if (!b->tx[i])
return tal_free(b);
b->tx[i]->chainparams = chainparams;
bitcoin_txid(b->tx[i], &b->txids[i]);
}
Expand Down
39 changes: 39 additions & 0 deletions bitcoin/test/run-bitcoin_block_from_hex.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ static const char block[] =
"ac0eb82500000000001976a914e05655a7d90b01ba874d81beff57ee09610ca"
"3ce88ac00000000";

/* Elements header whose challenge varint promises 80 bytes with none
* left in the block. */
static const char elements_short_challenge[] =
"0000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000afdc6a5c6400000050";

/* Dynafed header whose scriptPubKey varint promises 80 bytes with none
* left in the block. */
static const char elements_short_dynafed[] =
"000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000afdc6a5c640000000150";

/* Block whose only transaction does not parse. */
static const char bad_tx[] =
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ff";

/* Block claiming far more transactions than it has bytes. */
static const char huge_tx_count[] =
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff7f";

/* Dynafed header whose extension space claims far more entries than it
* has bytes. */
static const char elements_huge_extension[] =
"000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000ffffffffffffffff7f";

STRUCTEQ_DEF(sha256_double, 0, sha);

int main(int argc, const char *argv[])
Expand All @@ -70,7 +93,23 @@ int main(int argc, const char *argv[])
struct bitcoin_block *b;

common_setup(argv[0]);
chainparams = chainparams_for_network("liquid-regtest");
assert(!bitcoin_block_from_hex(NULL, chainparams,
elements_short_challenge,
strlen(elements_short_challenge)));
assert(!bitcoin_block_from_hex(NULL, chainparams,
elements_short_dynafed,
strlen(elements_short_dynafed)));
assert(!bitcoin_block_from_hex(NULL, chainparams,
elements_huge_extension,
strlen(elements_huge_extension)));

chainparams = chainparams_for_network("bitcoin");
assert(!bitcoin_block_from_hex(NULL, chainparams,
bad_tx, strlen(bad_tx)));
assert(!bitcoin_block_from_hex(NULL, chainparams,
huge_tx_count, strlen(huge_tx_count)));

b = bitcoin_block_from_hex(NULL, chainparams,
block, strlen(block));

Expand Down