test/test_state_coverage: Check that it terminates.

The state machine is infinite, but if we eliminate the normal inner
state loop, and a couple of other unusual cases where inputs can
repeat, we should be able to traverse it all.

This is slower than simply stopping when we hit a repeated state
though.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2015-09-25 11:51:18 +09:30
parent 786bef9002
commit 642c3e36e3

View File

@@ -533,6 +533,7 @@ static void copy_peers(struct state_data *dst, struct state_data *peer,
/* Recursion! */ /* Recursion! */
static struct trail *run_peer(const struct state_data *sdata, static struct trail *run_peer(const struct state_data *sdata,
bool normalpath, bool errorpath, bool normalpath, bool errorpath,
size_t depth,
struct hist *hist); struct hist *hist);
/* Returns false if we've been here before. */ /* Returns false if we've been here before. */
@@ -822,6 +823,7 @@ static const char *simplify_state(enum state s)
static struct trail *try_input(const struct state_data *sdata, static struct trail *try_input(const struct state_data *sdata,
enum state_input i, enum state_input i,
bool normalpath, bool errorpath, bool normalpath, bool errorpath,
size_t depth,
struct hist *hist) struct hist *hist)
{ {
struct state_data copy, peer; struct state_data copy, peer;
@@ -875,9 +877,21 @@ static struct trail *try_input(const struct state_data *sdata,
/* Have we been in this overall situation before? */ /* Have we been in this overall situation before? */
if (!sithash_update(&hist->sithash, &copy)) { if (!sithash_update(&hist->sithash, &copy)) {
/*
* We expect to loop if:
* 1) We deferred, OR
* 2) We get repeated BITCOIN_ANCHOR_OTHERSPEND, OR
* 3) We pass through NORMAL state.
*/
if (effect->defer != INPUT_NONE
|| newstate == STATE_NORMAL_LOWPRIO
|| i == BITCOIN_ANCHOR_OTHERSPEND) {
tal_free(effect); tal_free(effect);
return NULL; return NULL;
} }
if (depth > STATE_MAX * 10)
return new_trail(i, sdata, newstate, effect, "Loop");
}
/* Don't continue if we reached a different error state. */ /* Don't continue if we reached a different error state. */
if (state_is_error(newstate)) { if (state_is_error(newstate)) {
@@ -903,9 +917,9 @@ static struct trail *try_input(const struct state_data *sdata,
} }
/* Try inputs from here down. */ /* Try inputs from here down. */
t = run_peer(&copy, normalpath, errorpath, hist); t = run_peer(&copy, normalpath, errorpath, depth+1, hist);
if (!t) if (!t)
t = run_peer(&peer, normalpath, errorpath, hist); t = run_peer(&peer, normalpath, errorpath, depth+1, hist);
if (!t) { if (!t) {
tal_free(effect); tal_free(effect);
return NULL; return NULL;
@@ -943,6 +957,7 @@ static void activate_event(struct state_data *sdata, enum state_input i)
static struct trail *run_peer(const struct state_data *sdata, static struct trail *run_peer(const struct state_data *sdata,
bool normalpath, bool errorpath, bool normalpath, bool errorpath,
size_t depth,
struct hist *hist) struct hist *hist)
{ {
struct state_data copy, peer; struct state_data copy, peer;
@@ -965,7 +980,7 @@ static struct trail *run_peer(const struct state_data *sdata,
if (i != BITCOIN_ANCHOR_OTHERSPEND) if (i != BITCOIN_ANCHOR_OTHERSPEND)
copy.event_notifies &= ~(1ULL << i); copy.event_notifies &= ~(1ULL << i);
activate_event(&copy, i); activate_event(&copy, i);
t = try_input(&copy, i, normalpath, errorpath, hist); t = try_input(&copy, i, normalpath, errorpath, depth, hist);
if (t) if (t)
return t; return t;
copy.event_notifies = old_notifies; copy.event_notifies = old_notifies;
@@ -989,7 +1004,8 @@ static struct trail *run_peer(const struct state_data *sdata,
for (i = 0; i < sizeof(cmds) / sizeof(cmds[i]); i++) { for (i = 0; i < sizeof(cmds) / sizeof(cmds[i]); i++) {
copy.current_command = cmds[i]; copy.current_command = cmds[i];
t = try_input(&copy, cmds[i], t = try_input(&copy, cmds[i],
normalpath, errorpath, hist); normalpath, errorpath, depth,
hist);
if (t) if (t)
return t; return t;
} }
@@ -1007,7 +1023,8 @@ static struct trail *run_peer(const struct state_data *sdata,
i = copy.deferred_pkt; i = copy.deferred_pkt;
copy.deferred_pkt = INPUT_NONE; copy.deferred_pkt = INPUT_NONE;
return try_input(&copy, i, return try_input(&copy, i,
normalpath, errorpath, hist); normalpath, errorpath, depth,
hist);
} }
/* Can't send anything until that's done. */ /* Can't send anything until that's done. */
return NULL; return NULL;
@@ -1020,7 +1037,8 @@ static struct trail *run_peer(const struct state_data *sdata,
memmove(peer.outputs, peer.outputs + 1, memmove(peer.outputs, peer.outputs + 1,
sizeof(peer.outputs) - sizeof(peer.outputs[0])); sizeof(peer.outputs) - sizeof(peer.outputs[0]));
peer.num_outputs--; peer.num_outputs--;
return try_input(&copy, i, normalpath, errorpath, hist); return try_input(&copy, i, normalpath, errorpath, depth,
hist);
} }
} }
return NULL; return NULL;
@@ -1148,7 +1166,7 @@ int main(int argc, char *argv[])
abort(); abort();
/* Now, try each input in each state. */ /* Now, try each input in each state. */
t = run_peer(&a, true, false, &hist); t = run_peer(&a, true, false, 0, &hist);
if (t) { if (t) {
report_trail(t); report_trail(t);
exit(1); exit(1);
@@ -1158,7 +1176,7 @@ int main(int argc, char *argv[])
do_decline = true; do_decline = true;
sithash_init(&hist.sithash); sithash_init(&hist.sithash);
sithash_update(&hist.sithash, &a); sithash_update(&hist.sithash, &a);
t = run_peer(&a, true, false, &hist); t = run_peer(&a, true, false, 0, &hist);
if (t) { if (t) {
report_trail(t); report_trail(t);
exit(1); exit(1);