From e09795d24ee1b319151d8fe3bfc62d0fc02b8bb1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 24 Apr 2016 19:42:18 +0930 Subject: [PATCH] chaintopology: get full tx information for each block. Signed-off-by: Rusty Russell --- daemon/chaintopology.c | 139 +++++++++++++++++++++++++++-------------- daemon/chaintopology.h | 3 +- 2 files changed, 93 insertions(+), 49 deletions(-) diff --git a/daemon/chaintopology.c b/daemon/chaintopology.c index 9e662e824..3a4973ad2 100644 --- a/daemon/chaintopology.c +++ b/daemon/chaintopology.c @@ -1,9 +1,13 @@ +#include "bitcoin/block.h" +#include "bitcoin/tx.h" #include "bitcoind.h" #include "chaintopology.h" #include "lightningd.h" #include "log.h" #include "timeout.h" #include "watch.h" +#include +#include #include #include @@ -18,13 +22,19 @@ struct tx_in_block { struct block { int height; - /* We can have a single parent */ - struct sha256_double prevblkid; - /* ... but multiple children. */ + /* Actual header. */ + struct bitcoin_block_hdr hdr; + + /* Previous block (if any). */ + struct block *prev; + + /* We can have multiple children. */ struct block **nexts; /* Key for hash table */ struct sha256_double blkid; + + /* 0 if not enough predecessors. */ u32 mediantime; /* Transactions in this block we care about */ @@ -57,24 +67,49 @@ struct topology { struct block_map block_map; }; -static struct block *connect_blocks(struct topology *topo, - const struct sha256_double *blkid) +static int cmp_times(const u32 *a, const u32 *b, void *unused) +{ + if (*a > *b) + return -1; + else if (*b > * a) + return 1; + return 0; +} + +/* Mediantime is median of previous 11 blocks. */ +static u32 get_mediantime(const struct topology *topo, const struct block *b) +{ + unsigned int i; + u32 times[11]; + + for (i = 0; i < ARRAY_SIZE(times); i++) { + if (!b) + return 0; + times[i] = le32_to_cpu(b->hdr.timestamp); + b = b->prev; + } + asort(times, ARRAY_SIZE(times), cmp_times, NULL); + return times[ARRAY_SIZE(times) / 2]; +} + +/* Fills in prev, height, mediantime. */ +static void connect_blocks(struct topology *topo, struct block *b) { - struct block *b = block_map_get(&topo->block_map, blkid); - struct block *prev; size_t n; /* Hooked in already? */ if (b->height != -1) - return b; + return; - prev = connect_blocks(topo, &b->prevblkid); - b->height = prev->height + 1; - n = tal_count(prev->nexts); - tal_resize(&prev->nexts, n+1); - prev->nexts[n] = b; + b->prev = block_map_get(&topo->block_map, &b->hdr.prev_hash); + connect_blocks(topo, b->prev); - return b; + b->height = b->prev->height + 1; + n = tal_count(b->prev->nexts); + tal_resize(&b->prev->nexts, n+1); + b->prev->nexts[n] = b; + + b->mediantime = get_mediantime(topo, b->prev); } /* This is expensive, but reorgs are usually short and txs are few. @@ -128,13 +163,16 @@ static bool tx_in_block(const struct block *b, const struct txwatch *w) static size_t get_tx_branch_height(const struct topology *topo, const struct block *tip, const struct txwatch *w, + struct sha256_double *blkid, size_t max) { const struct block *b; - for (b = tip; b; b = block_map_get(&topo->block_map, &b->prevblkid)) { - if (tx_in_block(b, w)) + for (b = tip; b; b = b->prev) { + if (tx_in_block(b, w)) { + *blkid = b->blkid; return b->height; + } /* Don't bother returning less than max */ if (b->height < max) return max; @@ -143,14 +181,16 @@ static size_t get_tx_branch_height(const struct topology *topo, return tip->height + 1; } -size_t get_tx_depth(struct lightningd_state *dstate, const struct txwatch *w) +size_t get_tx_depth(struct lightningd_state *dstate, const struct txwatch *w, + struct sha256_double *blkid) { const struct topology *topo = dstate->topology; size_t i, max = 0, longest = 0; /* Calculate tx height. */ for (i = 0; i < tal_count(topo->tips); i++) { - size_t h = get_tx_branch_height(topo, topo->tips[i], w, max); + size_t h = get_tx_branch_height(topo, topo->tips[i], w, blkid, + max); if (h > max) max = h; @@ -235,8 +275,11 @@ static void topology_changed(struct lightningd_state *dstate) tal_free(topo->tips); topo->tips = tal_arr(topo, struct block *, tal_count(topo->newtips)); - for (i = 0; i < tal_count(topo->newtips); i++) - topo->tips[i] = connect_blocks(topo, &topo->newtips[i]); + for (i = 0; i < tal_count(topo->newtips); i++) { + topo->tips[i] = block_map_get(&topo->block_map, + &topo->newtips[i]); + connect_blocks(topo, topo->tips[i]); + } /* FIXME: Tell watch code to re-evaluate all txs. */ } @@ -258,31 +301,36 @@ static void add_tx_to_block(struct block *b, struct txwatch *w) } static struct block *add_block(struct lightningd_state *dstate, - struct sha256_double *blkid, - struct sha256_double *prevblock, - struct sha256_double *txids, - u32 mediantime) + struct bitcoin_block *blk) { size_t i; struct topology *topo = dstate->topology; struct block *b = tal(topo, struct block); - assert(!block_map_get(&topo->block_map, blkid)); + sha256_double(&b->blkid, &blk->hdr, sizeof(blk->hdr)); + log_debug(dstate->base_log, "Adding block %02x%02x%02x%02x...\n", + b->blkid.sha.u.u8[0], + b->blkid.sha.u.u8[1], + b->blkid.sha.u.u8[2], + b->blkid.sha.u.u8[3]); + assert(!block_map_get(&topo->block_map, &b->blkid)); /* We fill these out in topology_changed */ b->height = -1; b->nexts = tal_arr(b, struct block *, 0); + b->mediantime = 0; + b->prev = NULL; - b->mediantime = mediantime; - b->blkid = *blkid; - b->prevblkid = *prevblock; + b->hdr = blk->hdr; - /* See if any of those txids are interesting. */ + /* See if any of those txs are interesting. */ list_head_init(&b->txs); - for (i = 1; i < tal_count(txids); i++) { + for (i = 0; i < tal_count(blk->tx); i++) { struct txwatch *w; + struct sha256_double txid; - w = txwatch_hash_get(&dstate->txwatches, &txids[i]); + bitcoin_txid(blk->tx[i], &txid); + w = txwatch_hash_get(&dstate->txwatches, &txid); if (w) add_tx_to_block(b, w); } @@ -292,28 +340,26 @@ static struct block *add_block(struct lightningd_state *dstate, } static void gather_blocks(struct lightningd_state *dstate, - struct sha256_double *blkid, - struct sha256_double *prevblock, - struct sha256_double *txids, - u32 mediantime, + struct bitcoin_block *blk, ptrint_t *p) { struct topology *topo = dstate->topology; ptrdiff_t i; - add_block(dstate, blkid, prevblock, txids, mediantime); + add_block(dstate, blk); /* Recurse if we need prev. */ - if (!block_map_get(&topo->block_map, prevblock)) { - bitcoind_getblock(dstate, prevblock, gather_blocks, p); + if (!block_map_get(&topo->block_map, &blk->hdr.prev_hash)) { + bitcoind_getrawblock(dstate, &blk->hdr.prev_hash, + gather_blocks, p); return; } /* Recurse if more tips to map. */ for (i = ptr2int(p) + 1; i < tal_count(topo->newtips); i++) { if (!block_map_get(&topo->block_map, &topo->newtips[i])) { - bitcoind_getblock(dstate, &topo->newtips[i], - gather_blocks, int2ptr(i)); + bitcoind_getrawblock(dstate, &topo->newtips[i], + gather_blocks, int2ptr(i)); return; } } @@ -357,8 +403,8 @@ static void check_chaintips(struct lightningd_state *dstate, for (i = 0; i < tal_count(topo->newtips); i++) { if (block_map_get(&topo->block_map, &topo->newtips[i])) continue; - bitcoind_getblock(dstate, &topo->newtips[i], gather_blocks, - int2ptr(i)); + bitcoind_getrawblock(dstate, &topo->newtips[i], gather_blocks, + int2ptr(i)); return; } @@ -380,15 +426,12 @@ static void start_poll_chaintips(struct lightningd_state *dstate) } static void init_topo(struct lightningd_state *dstate, - struct sha256_double *blkid, - struct sha256_double *prevblock, - struct sha256_double *txids, - u32 mediantime, + struct bitcoin_block *blk, ptrint_t *p) { struct block *b; - b = add_block(dstate, blkid, prevblock, txids, mediantime); + b = add_block(dstate, blk); b->height = ptr2int(p); /* Now grab chaintips immediately. */ @@ -399,7 +442,7 @@ static void get_init_block(struct lightningd_state *dstate, const struct sha256_double *blkid, ptrint_t *blknum) { - bitcoind_getblock(dstate, blkid, init_topo, blknum); + bitcoind_getrawblock(dstate, blkid, init_topo, blknum); } static void get_init_blockhash(struct lightningd_state *dstate, u32 blockcount, diff --git a/daemon/chaintopology.h b/daemon/chaintopology.h index f99ce7769..d74b6cbfb 100644 --- a/daemon/chaintopology.h +++ b/daemon/chaintopology.h @@ -6,7 +6,8 @@ struct lightningd_state; struct txwatch; -size_t get_tx_depth(struct lightningd_state *dstate, const struct txwatch *w); +size_t get_tx_depth(struct lightningd_state *dstate, const struct txwatch *w, + struct sha256_double *blkid); void setup_topology(struct lightningd_state *dstate); #endif /* LIGHTNING_DAEMON_CRYPTOPKT_H */