/* Encoding is <blockhdr> <varint-num-txs> <tx>... */ 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; }
static void read_output(struct space *space, struct file *f, off_t *poff, struct bitcoin_transaction_output *output) { output->amount = pull_u64(f, poff); output->script_length = pull_varint(f, poff); output->script = space_alloc(space, output->script_length); pull_bytes(f, poff, output->script, output->script_length); }
/* Pulls a varint which specifies a data length: ensures basic sanity to * avoid trivial OOM */ static u64 pull_length(const u8 **cursor, size_t *max) { u64 v = pull_varint(cursor, max); if (v > *max) { *cursor = NULL; *max = 0; return 0; } return v; }
static void read_input(struct space *space, struct file *f, off_t *poff, struct bitcoin_transaction_input *input) { pull_hash(f, poff, input->hash); input->index = pull_u32(f, poff); input->script_length = pull_varint(f, poff); input->script = space_alloc(space, input->script_length); pull_bytes(f, poff, input->script, input->script_length); input->sequence_number = pull_u32(f, poff); }
void read_bitcoin_transaction(struct space *space, struct bitcoin_transaction *trans, struct file *f, off_t *poff) { size_t i; off_t start = *poff; SHA256_CTX sha256; trans->version = pull_u32(f, poff); trans->input_count = pull_varint(f, poff); trans->input = space_alloc_arr(space, struct bitcoin_transaction_input, trans->input_count); for (i = 0; i < trans->input_count; i++) read_input(space, f, poff, trans->input + i); trans->output_count = pull_varint(f, poff); trans->output = space_alloc_arr(space, struct bitcoin_transaction_output, trans->output_count); for (i = 0; i < trans->output_count; i++) read_output(space, f, poff, trans->output + i); trans->lock_time = pull_u32(f, poff); /* Bitcoin uses double sha (it's not quite known why...) */ SHA256_Init(&sha256); if (likely(f->mmap)) { SHA256_Update(&sha256, f->mmap + start, *poff - start); } else { u8 *buf = tal_arr(NULL, u8, *poff - start); file_read(f, start, *poff - start, buf); SHA256_Update(&sha256, buf, *poff - start); tal_free(buf); } SHA256_Final(trans->sha256, &sha256); SHA256_Init(&sha256); SHA256_Update(&sha256, trans->sha256, sizeof(trans->sha256)); SHA256_Final(trans->sha256, &sha256); trans->len = *poff - start; }
bool read_bitcoin_block_header(struct bitcoin_block *block, struct file *f, off_t *off, u8 block_md[SHA256_DIGEST_LENGTH], const u32 marker) { SHA256_CTX sha256; off_t start; block->D9B4BEF9 = pull_u32(f, off); assert(block->D9B4BEF9 == marker); block->len = pull_u32(f, off); /* Hash only covers version to nonce, inclusive. */ start = *off; block->version = pull_u32(f, off); pull_hash(f, off, block->prev_hash); pull_hash(f, off, block->merkle_hash); block->timestamp = pull_u32(f, off); block->target = pull_u32(f, off); block->nonce = pull_u32(f, off); /* Bitcoin uses double sha (it's not quite known why...) */ SHA256_Init(&sha256); if (likely(f->mmap)) { SHA256_Update(&sha256, f->mmap + start, *off - start); } else { u8 *buf = tal_arr(NULL, u8, *off - start); file_read(f, start, *off - start, buf); SHA256_Update(&sha256, buf, *off - start); tal_free(buf); } SHA256_Final(block_md, &sha256); SHA256_Init(&sha256); SHA256_Update(&sha256, block_md, SHA256_DIGEST_LENGTH); SHA256_Final(block_md, &sha256); block->transaction_count = pull_varint(f, off); return block; }
static raw_iblt *read_iblt(std::istream &in, size_t *ibltslices, u64 *seed) { std::string ibltstr; // If they choose not to IBLT encode. if (in.peek() != 'i') return NULL; std::getline(in, ibltstr, ','); if (ibltstr != "iblt") throw std::runtime_error("Bad iblt line"); std::string iblthex; std::getline(in, iblthex); if (!in) throw std::runtime_error("Bad iblt hex line"); size_t ibltsize = hex_data_size(iblthex.size()); u8 data[ibltsize]; if (!hex_decode(iblthex.c_str(), iblthex.size(), data, sizeof(data))) throw std::runtime_error("Bad iblt hex"); const u8 *p = data; size_t len = sizeof(data); *ibltslices = pull_varint(&p, &len); if (!p) throw std::runtime_error("Bad iblt size"); if (len < 16) throw std::runtime_error("Bad iblt seed"); memcpy(seed, p, sizeof(*seed)); p += 16; len -= 16; raw_iblt *riblt = new raw_iblt(*ibltslices); if (!riblt->read(p, len)) throw std::runtime_error("Bad iblt"); return riblt; }