Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rustyrussell/pettycoin
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 531671cdf2b2
Choose a base ref
...
head repository: rustyrussell/pettycoin
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 90928e26553e
Choose a head ref
  • 4 commits
  • 12 files changed
  • 1 contributor

Commits on Oct 27, 2014

  1. block: consider a block "known" if we know sufficient previous blocks.

    We currently insist on knowing the contents of *all* previous blocks,
    but that's overkill.  Instead of a boolean, keep a counter, and compare
    it against the most we need to know to mine.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Oct 27, 2014
    Copy the full SHA
    f03e63c View commit details
  2. recv_block: don't get ancient transactions.

    Now we don't need all txs, don't get them.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Oct 27, 2014
    Copy the full SHA
    ccc5dd5 View commit details

Commits on Oct 28, 2014

  1. recv_block: Don't log UNKNOWN_PREV errors during sync.

    They're expected.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Oct 28, 2014
    Copy the full SHA
    d78668a View commit details
  2. generating: take care never to log { or } characters.

    The fast-path in pettycoin-query introduced in 994a7fa
    won't work if we do this.  So hex-ize the nonce.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    rustyrussell committed Oct 28, 2014
    Copy the full SHA
    90928e2 View commit details
Showing with 361 additions and 63 deletions.
  1. +5 −1 block.c
  2. +3 −2 block.h
  3. +3 −1 blockfile.c
  4. +41 −26 chain.c
  5. +3 −0 chain.h
  6. +5 −2 check_block.c
  7. +4 −3 generating.c
  8. +1 −1 mkgenesis.c
  9. +9 −8 recv_block.c
  10. +0 −1 test/run-01-difficulty.c
  11. +258 −0 test/run-09-chain-horizon-limit.c
  12. +29 −18 test/run-09-chain.c
6 changes: 5 additions & 1 deletion block.c
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ static struct block *new_block(const tal_t *ctx,
prev_work, &block->total_work);

block->bi = *bi;
block->all_known = false;
block->known_in_a_row = 0;
list_head_init(&block->children);
block->sha = *sha;
block->shard = tal_arr(block, struct block_shard *,
@@ -72,6 +72,10 @@ struct block *block_add(struct state *state,
block = new_block(state, &prev->total_work, sha, bi);
block->prev = prev;

/* Empty block case. */
if (block_all_known(block))
block->known_in_a_row = prev->known_in_a_row + 1;

/* Add to list for that generation. */
if (height >= tal_count(state->block_height)) {
/* We can only increment block heights. */
5 changes: 3 additions & 2 deletions block.h
Original file line number Diff line number Diff line change
@@ -25,8 +25,9 @@ struct block {
/* What features have been locked in for next fortnight? */
u8 pending_features;

/* Do we know all transactions for this and ancestors? */
bool all_known;
/* How many continuous predecessor blocks do we know completely?
* (Including this one). */
unsigned int known_in_a_row;

/* Total work to get to this block. */
BIGNUM total_work;
4 changes: 3 additions & 1 deletion blockfile.c
Original file line number Diff line number Diff line change
@@ -101,9 +101,11 @@ static void get_unknown_contents(struct state *state)
for (i = 0; i < tal_count(state->longest_chains); i++) {
for (b = state->longest_chains[i]; b; b = b->prev) {
/* Stop if we know from here down. */
if (b->all_known)
if (b->known_in_a_row == block_height(&b->bi))
break;
/* FIXME: Don't get over horizon */

/* A noop if we already know it. */
get_block_contents(state, b);
}
}
67 changes: 41 additions & 26 deletions chain.c
Original file line number Diff line number Diff line change
@@ -78,6 +78,21 @@ static bool find_connected_pair(const struct state *state,
return false;
}

/* This means we know the complete contents of enough predecessors to
* mine new blocks. */
bool predecessors_all_known(const struct block *b)
{
/* To build the next block, we need blocks b-0, b-1, b-2, b-4, b-8 ...
* b - 2^(PROTOCOL_PREV_BLOCK_TXHASHES-1) */
size_t prev_needed = 1U << (PROTOCOL_PREV_BLOCK_TXHASHES - 1);

/* +1 is for the genesis block, which is height 0 */
if (block_height(&b->bi) < prev_needed)
prev_needed = block_height(&b->bi) + 1;

return b->known_in_a_row >= prev_needed;
}

void check_chains(struct state *state, bool all)
{
const struct block *i;
@@ -99,7 +114,7 @@ void check_chains(struct state *state, bool all)
i != state->longest_knowns[0];
i = i->prev) {
assert(i != genesis_block(state));
assert(!i->all_known);
assert(!predecessors_all_known(i));
}

/*
@@ -146,7 +161,7 @@ void check_chains(struct state *state, bool all)
}
assert(i->complaint ||
cmp_work(i, state->longest_chains[0]) <= 0);
if (!i->complaint && i->all_known)
if (!i->complaint && predecessors_all_known(i))
assert(cmp_work(i, state->longest_knowns[0]) <= 0);

list_for_each(&i->children, b, sibling) {
@@ -240,39 +255,39 @@ static bool update_known_recursive(struct state *state, struct block *block)
struct block *b;
bool knowns_changed;

if (block->prev && !block->prev->all_known)
return false;

if (!block_all_known(block))
return false;

/* FIXME: Hack avoids writing to read-only genesis block. */
if (!block->all_known)
block->all_known = true;
/* We know one more than the previous block. */
if (block->prev)
block->known_in_a_row = block->prev->known_in_a_row + 1;

/* Blocks which are flawed are not useful */
if (block->complaint)
return false;

switch (cmp_work(block, state->longest_knowns[0])) {
case 1:
log_debug(state->log, "New known block work ");
log_add_struct(state->log, BIGNUM, &block->total_work);
log_add(state->log, " exceeds old known work ");
log_add_struct(state->log, BIGNUM,
&state->longest_knowns[0]->total_work);
/* They're no longer longest, we are. */
set_single(&state->longest_knowns, block);
knowns_changed = true;
break;
case 0:
tal_arr_append(&state->longest_knowns, block);
knowns_changed = true;
break;
case -1:
if (predecessors_all_known(block)) {
switch (cmp_work(block, state->longest_knowns[0])) {
case 1:
log_debug(state->log, "New known block work ");
log_add_struct(state->log, BIGNUM, &block->total_work);
log_add(state->log, " exceeds old known work ");
log_add_struct(state->log, BIGNUM,
&state->longest_knowns[0]->total_work);
/* They're no longer longest, we are. */
set_single(&state->longest_knowns, block);
knowns_changed = true;
break;
case 0:
tal_arr_append(&state->longest_knowns, block);
knowns_changed = true;
break;
case -1:
knowns_changed = false;
break;
}
} else
knowns_changed = false;
break;
}

/* Check descendents. */
list_for_each(&block->children, b, sibling) {
3 changes: 3 additions & 0 deletions chain.h
Original file line number Diff line number Diff line change
@@ -51,6 +51,9 @@ void update_block_ptrs_new_shard(struct state *state, struct block *block,
/* We've invalidated a block. */
void update_block_ptrs_invalidated(struct state *state, const struct block *block);

/* Are enough predecessors known that we can mine? */
bool predecessors_all_known(const struct block *b);

/* Debugging check */
void check_chains(struct state *state, bool all);
#endif /* PETTYCOIN_CHAIN_H */
7 changes: 5 additions & 2 deletions check_block.c
Original file line number Diff line number Diff line change
@@ -391,8 +391,11 @@ void check_block(struct state *state, const struct block *block, bool all)
assert(structeq(&sha, &block->sha));

if (block->prev) {
if (block->all_known)
assert(block->prev->all_known);
if (block_all_known(block))
assert(block->known_in_a_row
== block->prev->known_in_a_row + 1);
else
assert(block->known_in_a_row == 0);

if (block->prev->complaint)
assert(block->complaint);
7 changes: 4 additions & 3 deletions generating.c
Original file line number Diff line number Diff line change
@@ -241,7 +241,7 @@ static void exec_generator(struct generator *gen)
prev_merkle_str[STR_MAX_CHARS(u32)],
height[STR_MAX_CHARS(u32)],
shard_order[STR_MAX_CHARS(u8)];
char *prevstr;
char *prevstr, *hexnonce;
struct protocol_block_id prevs[PROTOCOL_NUM_PREV_IDS];
char fees_to[sizeof(struct protocol_address) * 2 + 1];
char nonce[14 + 1];
@@ -268,6 +268,7 @@ static void exec_generator(struct generator *gen)
for (i = 0; i < sizeof(nonce)-1; i++)
nonce[i] = 32 + isaac64_next_uint(isaac64, 224);
nonce[i] = '\0';
hexnonce = to_hex(gen, nonce, sizeof(nonce)-1);

if (pipe(outfd) != 0 || pipe(infd) != 0)
fatal(gen->state, "pipe: %s", strerror(errno));
@@ -296,11 +297,11 @@ static void exec_generator(struct generator *gen)

gen->log = new_log(gen, gen->state->lr, "%sGenerator %u:",
log_prefix(gen->state->log), gen->pid);
log_debug(gen->log, "Running '%s' '%s' '%s' '%s' %s' '%s' '%s' '%s'",
log_debug(gen->log, "Running '%s' '%s' '%s' '%s' %s' '%s' '%s' 0x%s",
gen->state->generator,
fees_to,
difficulty, prevstr, prev_merkle_str, height, shard_order,
nonce);
hexnonce);

close(outfd[1]);
close(infd[0]);
2 changes: 1 addition & 1 deletion mkgenesis.c
Original file line number Diff line number Diff line change
@@ -130,7 +130,7 @@ int main(int argc, char *argv[])
"},\n"
" .shard = genesis_shards,\n"
" .children = LIST_HEAD_INIT(genesis.children),\n"
" .all_known = true,\n"
" .known_in_a_row = 1,\n"
" .sha = { { ");

dump_array(sha.sha.sha, ARRAY_SIZE(sha.sha.sha));
17 changes: 9 additions & 8 deletions recv_block.c
Original file line number Diff line number Diff line change
@@ -139,9 +139,12 @@ recv_block(struct state *state, struct log *log, struct peer *peer,

e = check_block_header(state, bi, &prev, &sha.sha);
if (e != PROTOCOL_ECODE_NONE) {
log_unusual(log, "checking new block %u gave ",
block_height(bi));
log_add_enum(log, enum protocol_ecode, e);
/* Don't spam log during sync phase. */
if (!need_contents || e != PROTOCOL_ECODE_PRIV_UNKNOWN_PREV) {
log_unusual(log, "checking new block %u gave ",
block_height(bi));
log_add_enum(log, enum protocol_ecode, e);
}

/* If it was due to unknown prev, ask about that. */
if (peer) {
@@ -192,12 +195,10 @@ recv_block(struct state *state, struct log *log, struct peer *peer,

/* Don't bother about contents or extra
* children of expired blocks. */
if (!block_expired_by(expiry, current_time()))
if (!block_expired_by(expiry, current_time())) {
todo_add_get_children(state, &b->sha);

/* FIXME: We currently need *all* txs, for
* longest_known calculation */
get_block_contents(state, b);
get_block_contents(state, b);
}

} else {
/* Otherwise, tell peers about new block. */
1 change: 0 additions & 1 deletion test/run-01-difficulty.c
Original file line number Diff line number Diff line change
@@ -174,7 +174,6 @@ int main(int argc, char *argv[])
BN_init(&genesis.total_work);
if (!BN_zero(&genesis.total_work))
errx(1, "Failed to initialize genesis block");
genesis.all_known = true;
list_head_init(&genesis.children);
list_add_tail(state->block_height[0], &genesis.list);

258 changes: 258 additions & 0 deletions test/run-09-chain-horizon-limit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
#include "../chain.c"
#include "../state.c"
#include "../block.c"
#include "../pseudorand.c"
#include "../minimal_log.c"
#include "../difficulty.c"
#include "../block_shard.c"
#include "../prev_txhashes.c"
#include "../shadouble.c"
#include "easy_genesis.c"
#include <ccan/strmap/strmap.h>
#include <ccan/tal/str/str.h>

/* AUTOGENERATED MOCKS START */
/* Generated stub for check_proof */
bool check_proof(const struct protocol_proof *proof,
const struct block *b,
const union protocol_tx *tx,
const struct protocol_input_ref *refs)
{ fprintf(stderr, "check_proof called!\n"); abort(); }
/* Generated stub for check_tx */
enum protocol_ecode check_tx(struct state *state, const union protocol_tx *tx,
const struct block *inside_block)
{ fprintf(stderr, "check_tx called!\n"); abort(); }
/* Generated stub for check_tx_inputs */
enum input_ecode check_tx_inputs(struct state *state,
const struct block *block,
const struct txhash_elem *me,
const union protocol_tx *tx,
unsigned int *bad_input_num)
{ fprintf(stderr, "check_tx_inputs called!\n"); abort(); }
/* Generated stub for complain_bad_prev_txhashes */
void complain_bad_prev_txhashes(struct state *state,
struct block *block,
const struct block *bad_prev,
u16 bad_prev_shard)
{ fprintf(stderr, "complain_bad_prev_txhashes called!\n"); abort(); }
/* Generated stub for from_hex */
bool from_hex(const char *str, size_t slen, void *buf, size_t bufsize)
{ fprintf(stderr, "from_hex called!\n"); abort(); }
/* Generated stub for hash_tx */
void hash_tx(const union protocol_tx *tx, struct protocol_tx_id *txid)
{ fprintf(stderr, "hash_tx called!\n"); abort(); }
/* Generated stub for hash_tx_and_refs */
void hash_tx_and_refs(const union protocol_tx *tx,
const struct protocol_input_ref *refs,
struct protocol_txrefhash *txrefhash)
{ fprintf(stderr, "hash_tx_and_refs called!\n"); abort(); }
/* Generated stub for inputhash_hashfn */
size_t inputhash_hashfn(const struct inputhash_key *key)
{ fprintf(stderr, "inputhash_hashfn called!\n"); abort(); }
/* Generated stub for inputhash_keyof */
const struct inputhash_key *inputhash_keyof(const struct inputhash_elem *ie)
{ fprintf(stderr, "inputhash_keyof called!\n"); abort(); }
/* Generated stub for json_add_address */
void json_add_address(struct json_result *result, const char *fieldname,
bool test_net, const struct protocol_address *addr)
{ fprintf(stderr, "json_add_address called!\n"); abort(); }
/* Generated stub for json_add_block_id */
void json_add_block_id(struct json_result *result, const char *fieldname,
const struct protocol_block_id *id)
{ fprintf(stderr, "json_add_block_id called!\n"); abort(); }
/* Generated stub for json_add_double_sha */
void json_add_double_sha(struct json_result *result, const char *fieldname,
const struct protocol_double_sha *sha)
{ fprintf(stderr, "json_add_double_sha called!\n"); abort(); }
/* Generated stub for json_add_hex */
void json_add_hex(struct json_result *result, const char *fieldname,
const void *data, size_t len)
{ fprintf(stderr, "json_add_hex called!\n"); abort(); }
/* Generated stub for json_add_num */
void json_add_num(struct json_result *result, const char *fieldname,
unsigned int value)
{ fprintf(stderr, "json_add_num called!\n"); abort(); }
/* Generated stub for json_add_tx_id */
void json_add_tx_id(struct json_result *result, const char *fieldname,
const struct protocol_tx_id *id)
{ fprintf(stderr, "json_add_tx_id called!\n"); abort(); }
/* Generated stub for json_array_end */
void json_array_end(struct json_result *ptr)
{ fprintf(stderr, "json_array_end called!\n"); abort(); }
/* Generated stub for json_array_start */
void json_array_start(struct json_result *ptr, const char *fieldname)
{ fprintf(stderr, "json_array_start called!\n"); abort(); }
/* Generated stub for json_get_params */
void json_get_params(const char *buffer, const jsmntok_t param[], ...)
{ fprintf(stderr, "json_get_params called!\n"); abort(); }
/* Generated stub for json_object_end */
void json_object_end(struct json_result *ptr)
{ fprintf(stderr, "json_object_end called!\n"); abort(); }
/* Generated stub for json_object_start */
void json_object_start(struct json_result *ptr, const char *fieldname)
{ fprintf(stderr, "json_object_start called!\n"); abort(); }
/* Generated stub for json_tok_contents */
const char *json_tok_contents(const char *buffer, const jsmntok_t *t)
{ fprintf(stderr, "json_tok_contents called!\n"); abort(); }
/* Generated stub for json_tok_len */
int json_tok_len(const jsmntok_t *t)
{ fprintf(stderr, "json_tok_len called!\n"); abort(); }
/* Generated stub for json_tok_number */
bool json_tok_number(const char *buffer, const jsmntok_t *tok,
unsigned int *num)
{ fprintf(stderr, "json_tok_number called!\n"); abort(); }
/* Generated stub for log_to_file */
void log_to_file(int fd, const struct log_record *lr)
{ fprintf(stderr, "log_to_file called!\n"); abort(); }
/* Generated stub for logv */
void logv(struct log *log, enum log_level level, const char *fmt, va_list ap)
{ fprintf(stderr, "logv called!\n"); abort(); }
/* Generated stub for make_prev_blocks */
void make_prev_blocks(const struct block *prev,
struct protocol_block_id prevs[PROTOCOL_NUM_PREV_IDS])
{ fprintf(stderr, "make_prev_blocks called!\n"); abort(); }
/* Generated stub for marshal_input_ref_len */
size_t marshal_input_ref_len(const union protocol_tx *tx)
{ fprintf(stderr, "marshal_input_ref_len called!\n"); abort(); }
/* Generated stub for marshal_tx_len */
size_t marshal_tx_len(const union protocol_tx *tx)
{ fprintf(stderr, "marshal_tx_len called!\n"); abort(); }
/* Generated stub for merkle_txs */
void merkle_txs(const struct block_shard *shard,
struct protocol_double_sha *merkle)
{ fprintf(stderr, "merkle_txs called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */

void block_to_pending(struct state *state, const struct block *block)
{
}

void check_block(struct state *state, const struct block *block, bool all)
{
}

bool check_prev_txhashes(struct state *state, const struct block *block,
const struct block **bad_prev,
u16 *bad_shard)
{
return true;
}

void restart_generating(struct state *state)
{
}

void todo_forget_about_block(struct state *state,
const struct protocol_block_id *block)
{
}

void wake_peers(struct state *state)
{
}

void save_block(struct state *state, struct block *new)
{
}

struct pending_block *new_pending_block(struct state *state)
{
return talz(state, struct pending_block);
}

u8 pending_features(const struct block *block)
{
return 0;
}

void todo_add_get_shard(struct state *state,
const struct protocol_block_id *block,
u16 shardnum)
{
}

void seek_detached_blocks(struct state *state,
const struct block *block)
{
}

struct strmap_block {
STRMAP_MEMBERS(struct block *);
};
static struct strmap_block blockmap;

static struct block *add_next_block(struct state *state,
struct block *prev, const char *name,
unsigned int tx_count)
{
struct block *b;
struct block_info bi;
struct protocol_block_header *hdr;
struct protocol_block_tailer *tailer;
u8 *num_txs;
struct protocol_block_id dummy = { { { 0 } } };

hdr = tal(state, struct protocol_block_header);
hdr->shard_order = PROTOCOL_INITIAL_SHARD_ORDER;
hdr->height = cpu_to_le32(block_height(&prev->bi) + 1);
hdr->prevs[0] = prev->sha;

tailer = tal(state, struct protocol_block_tailer);
tailer->difficulty = cpu_to_le32(block_difficulty(&prev->bi));

num_txs = tal_arrz(state, u8, 1 << hdr->shard_order);
num_txs[0] = tx_count;

memcpy(&dummy, name,
strlen(name) < sizeof(dummy) ? strlen(name) : sizeof(dummy));

bi.hdr = hdr;
bi.tailer = tailer;
bi.num_txs = num_txs;
b = block_add(state, prev, &dummy, &bi);

strmap_add(&blockmap, name, b);
return b;
}

static void create_chain(struct state *state, struct block *base,
const char *prefix, unsigned int num, bool known)
{
unsigned int i;

for (i = 0; i < num; i++) {
char *name = tal_fmt(state, "%s-%u", prefix, i);
base = add_next_block(state, base, name, known ? 0 : 1);
known = true;
}
}

int main(void)
{
struct state *state;
static struct protocol_address zero_addr;

strmap_init(&blockmap);

pseudorand_init();
state = new_state(true);

/* Create a single unknown block, then many knowns. */
create_chain(state, &genesis, "unk", 1, false);
create_chain(state, strmap_get(&blockmap, "unk-0"), "known",
(1 << (PROTOCOL_PREV_BLOCK_TXHASHES-1)) + 1, true);

assert(!predecessors_all_known(strmap_get(&blockmap, "known-510")));
/* This is over the limit, so we don't care about old unknown. */
assert(predecessors_all_known(strmap_get(&blockmap, "known-511")));

/* make_prev_txhashes is *why* we need to know so far back. */
assert(!make_prev_txhashes(state, strmap_get(&blockmap, "known-510"),
&zero_addr));
assert(make_prev_txhashes(state, strmap_get(&blockmap, "known-511"),
&zero_addr));

strmap_clear(&blockmap);
tal_free(state);
return 0;
}
47 changes: 29 additions & 18 deletions test/run-09-chain.c
Original file line number Diff line number Diff line change
@@ -231,15 +231,24 @@ int main(void)
pseudorand_init();
state = new_state(true);

/* genesis -> block1-0 ... block1-10. */
/* genesis -> block1-0 ... block1-9. */
create_chain(state, &genesis, "block1", 10, true);
assert(strmap_get(&blockmap, "block1-0")->known_in_a_row == 2);
assert(strmap_get(&blockmap, "block1-1")->known_in_a_row == 3);
assert(strmap_get(&blockmap, "block1-2")->known_in_a_row == 4);
assert(strmap_get(&blockmap, "block1-3")->known_in_a_row == 5);
assert(strmap_get(&blockmap, "block1-4")->known_in_a_row == 6);
assert(strmap_get(&blockmap, "block1-5")->known_in_a_row == 7);
assert(strmap_get(&blockmap, "block1-6")->known_in_a_row == 8);
assert(strmap_get(&blockmap, "block1-7")->known_in_a_row == 9);
assert(strmap_get(&blockmap, "block1-8")->known_in_a_row == 10);
assert(strmap_get(&blockmap, "block1-9")->known_in_a_row == 11);

assert(tal_count(state->longest_knowns) == 1);
assert(state->longest_knowns[0] == strmap_get(&blockmap, "block1-9"));
assert(tal_count(state->longest_chains) == 1);
assert(state->longest_chains[0] == strmap_get(&blockmap, "block1-9"));
assert(state->preferred_chain == strmap_get(&blockmap, "block1-9"));
assert(strmap_get(&blockmap, "block1-9")->all_known);

/* Now add one we don't know all of. */
add_next_block(state, strmap_get(&blockmap, "block1-9"),
@@ -249,8 +258,9 @@ int main(void)
assert(tal_count(state->longest_chains) == 1);
assert(state->longest_chains[0] == strmap_get(&blockmap, "block1-10"));
assert(state->preferred_chain == strmap_get(&blockmap, "block1-10"));
assert(strmap_get(&blockmap, "block1-9")->all_known);
assert(!strmap_get(&blockmap, "block1-10")->all_known);
assert(strmap_get(&blockmap, "block1-9")->known_in_a_row == 11);
assert(strmap_get(&blockmap, "block1-10")->known_in_a_row == 0);
assert(!block_all_known(strmap_get(&blockmap, "block1-10")));

/* Now add another all-known one to that. */
add_next_block(state, strmap_get(&blockmap, "block1-10"),
@@ -260,9 +270,9 @@ int main(void)
assert(tal_count(state->longest_chains) == 1);
assert(state->longest_chains[0] == strmap_get(&blockmap, "block1-11"));
assert(state->preferred_chain == strmap_get(&blockmap, "block1-11"));
assert(strmap_get(&blockmap, "block1-9")->all_known);
assert(!strmap_get(&blockmap, "block1-10")->all_known);
assert(!strmap_get(&blockmap, "block1-11")->all_known);
assert(strmap_get(&blockmap, "block1-9")->known_in_a_row == 11);
assert(strmap_get(&blockmap, "block1-10")->known_in_a_row == 0);
assert(strmap_get(&blockmap, "block1-11")->known_in_a_row == 1);

/* Create a all-known competitor to block1-9. */
add_next_block(state, strmap_get(&blockmap, "block1-8"),
@@ -273,10 +283,10 @@ int main(void)
assert(tal_count(state->longest_chains) == 1);
assert(state->longest_chains[0] == strmap_get(&blockmap, "block1-11"));
assert(state->preferred_chain == strmap_get(&blockmap, "block1-11"));
assert(strmap_get(&blockmap, "block1-9")->all_known);
assert(!strmap_get(&blockmap, "block1-10")->all_known);
assert(!strmap_get(&blockmap, "block1-11")->all_known);
assert(strmap_get(&blockmap, "block2-9")->all_known);
assert(strmap_get(&blockmap, "block1-9")->known_in_a_row == 11);
assert(strmap_get(&blockmap, "block1-10")->known_in_a_row == 0);
assert(strmap_get(&blockmap, "block1-11")->known_in_a_row == 1);
assert(strmap_get(&blockmap, "block2-9")->known_in_a_row == 11);

/* Extend it by one more, and it will become preferred. */
add_next_block(state, strmap_get(&blockmap, "block2-9"),
@@ -286,10 +296,11 @@ int main(void)
assert(tal_count(state->longest_chains) == 1);
assert(state->longest_chains[0] == strmap_get(&blockmap, "block1-11"));
assert(state->preferred_chain == strmap_get(&blockmap, "block2-10"));
assert(strmap_get(&blockmap, "block1-9")->all_known);
assert(!strmap_get(&blockmap, "block1-10")->all_known);
assert(!strmap_get(&blockmap, "block1-11")->all_known);
assert(strmap_get(&blockmap, "block2-10")->all_known);
assert(strmap_get(&blockmap, "block1-9")->known_in_a_row == 11);
assert(strmap_get(&blockmap, "block1-10")->known_in_a_row == 0);
assert(strmap_get(&blockmap, "block1-11")->known_in_a_row == 1);
assert(strmap_get(&blockmap, "block2-9")->known_in_a_row == 11);
assert(strmap_get(&blockmap, "block2-10")->known_in_a_row == 12);

/* Add tx to shard to complete block1-10. */
strmap_get(&blockmap, "block1-10")->shard[0]->txcount++;
@@ -300,9 +311,9 @@ int main(void)
assert(tal_count(state->longest_chains) == 1);
assert(state->longest_chains[0] == strmap_get(&blockmap, "block1-11"));
assert(state->preferred_chain == strmap_get(&blockmap, "block1-11"));
assert(strmap_get(&blockmap, "block1-9")->all_known);
assert(strmap_get(&blockmap, "block1-10")->all_known);
assert(strmap_get(&blockmap, "block1-11")->all_known);
assert(strmap_get(&blockmap, "block1-9")->known_in_a_row == 11);
assert(strmap_get(&blockmap, "block1-10")->known_in_a_row == 12);
assert(strmap_get(&blockmap, "block1-11")->known_in_a_row == 13);

/* But, if block-1-10 is invalidated, we go back... */
strmap_get(&blockmap, "block1-10")->complaint = "foo";