From ebf2bc57d875e3f78a9313ca7acd1ac8c7cf1d3a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 22 Jan 2016 06:41:47 +1030 Subject: [PATCH] state: add async anchor creation. Actually generating the anchor transaction in my implementation requires interaction with bitcoind, which we want to be async. So add a callback and a new state to wait for it. Signed-off-by: Rusty Russell --- state.c | 18 ++++++++++++++++ state.h | 12 ++++++++--- state_types.h | 3 +++ test/test_state_coverage.c | 42 +++++++++++++++++++++++++++++++++----- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/state.c b/state.c index d2165ca48..a08cfb09a 100644 --- a/state.c +++ b/state.c @@ -149,13 +149,28 @@ enum command_status state(const tal_t *ctx, complete_cmd(peer, &cstatus, CMD_FAIL); goto err_close_nocleanup; } + bitcoin_create_anchor(peer, BITCOIN_ANCHOR_CREATED); + return next_state(peer, cstatus, + STATE_OPEN_WAIT_FOR_ANCHOR_CREATE); + } else if (input_is(input, CMD_CLOSE)) { + complete_cmd(peer, &cstatus, CMD_FAIL); + goto instant_close; + } else if (input_is_pkt(input)) { + complete_cmd(peer, &cstatus, CMD_FAIL); + goto unexpected_pkt_nocleanup; + } + break; + case STATE_OPEN_WAIT_FOR_ANCHOR_CREATE: + if (input_is(input, BITCOIN_ANCHOR_CREATED)) { queue_pkt(out, pkt_anchor(ctx, peer)); return next_state(peer, cstatus, STATE_OPEN_WAIT_FOR_COMMIT_SIG); } else if (input_is(input, CMD_CLOSE)) { + bitcoin_release_anchor(peer, BITCOIN_ANCHOR_CREATED); complete_cmd(peer, &cstatus, CMD_FAIL); goto instant_close; } else if (input_is_pkt(input)) { + bitcoin_release_anchor(peer, BITCOIN_ANCHOR_CREATED); complete_cmd(peer, &cstatus, CMD_FAIL); goto unexpected_pkt_nocleanup; } @@ -190,6 +205,7 @@ enum command_status state(const tal_t *ctx, if (input_is(input, PKT_OPEN_COMMIT_SIG)) { err = accept_pkt_open_commit_sig(ctx, peer, idata->pkt); if (err) { + bitcoin_release_anchor(peer, INPUT_NONE); complete_cmd(peer, &cstatus, CMD_FAIL); goto err_start_unilateral_close; } @@ -203,9 +219,11 @@ enum command_status state(const tal_t *ctx, return next_state(peer, cstatus, STATE_OPEN_WAITING_OURANCHOR); } else if (input_is(input, CMD_CLOSE)) { + bitcoin_release_anchor(peer, INPUT_NONE); complete_cmd(peer, &cstatus, CMD_FAIL); goto instant_close; } else if (input_is_pkt(input)) { + bitcoin_release_anchor(peer, INPUT_NONE); complete_cmd(peer, &cstatus, CMD_FAIL); goto unexpected_pkt_nocleanup; } diff --git a/state.h b/state.h index e10fe600e..dad8afa27 100644 --- a/state.h +++ b/state.h @@ -318,9 +318,15 @@ void peer_unwatch_htlc_spend(struct peer *peer, const struct htlc *htlc, enum state_input all_done); -/* Create a bitcoin anchor tx. */ -struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx, - const struct peer *peer); +/* Start creation of the bitcoin anchor tx. */ +void bitcoin_create_anchor(struct peer *peer, enum state_input done); + +/* We didn't end up broadcasting the anchor: release the utxos. + * If done != INPUT_NONE, remove existing create_anchor too. */ +void bitcoin_release_anchor(struct peer *peer, enum state_input done); + +/* Get the bitcoin anchor tx. */ +struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx, struct peer *peer); /* Create a bitcoin close tx. */ struct bitcoin_tx *bitcoin_close(const tal_t *ctx, diff --git a/state_types.h b/state_types.h index cf15f1e5c..7de7a53ef 100644 --- a/state_types.h +++ b/state_types.h @@ -19,6 +19,7 @@ enum state { */ STATE_OPEN_WAIT_FOR_OPEN_NOANCHOR, STATE_OPEN_WAIT_FOR_OPEN_WITHANCHOR, + STATE_OPEN_WAIT_FOR_ANCHOR_CREATE, STATE_OPEN_WAIT_FOR_ANCHOR, STATE_OPEN_WAIT_FOR_COMMIT_SIG, STATE_OPEN_WAITING_OURANCHOR, @@ -220,6 +221,8 @@ enum state_input { /* * Bitcoin events */ + /* Bitcoin anchor tx created. */ + BITCOIN_ANCHOR_CREATED, /* It reached the required depth. */ BITCOIN_ANCHOR_DEPTHOK, /* It didn't reach the required depth in time. */ diff --git a/test/test_state_coverage.c b/test/test_state_coverage.c index 3f11b2351..885bcc916 100644 --- a/test/test_state_coverage.c +++ b/test/test_state_coverage.c @@ -122,7 +122,10 @@ struct peer { /* Transitory: True if we just declined an HTLC. */ bool htlc_declined; - + + /* Have we created an anchor tx? */ + bool anchor; + unsigned int num_htlcs_to_them, num_htlcs_to_us; struct htlc htlcs_to_them[MAX_HTLCS], htlcs_to_us[MAX_HTLCS]; @@ -855,9 +858,11 @@ static bool bitcoin_tx_is(const struct bitcoin_tx *btx, const char *str) return streq((const char *)btx, str); } -struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx, - const struct peer *peer) +struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx, struct peer *peer) { + if (!peer->anchor) + report_trail(peer->trail, "Can't create anchor tx: no anchor!"); + peer->anchor = false; return bitcoin_tx("anchor"); } @@ -937,6 +942,7 @@ static void peer_init(struct peer *peer, peer->num_rvals_known = 0; peer->error = NULL; peer->htlc_declined = false; + peer->anchor = false; memset(peer->core.outputs, 0, sizeof(peer->core.outputs)); peer->pkt_data[0] = -1; peer->core.current_command = INPUT_NONE; @@ -1188,6 +1194,26 @@ void peer_watch_anchor(struct peer *peer, add_event(peer, otherspent); } +void bitcoin_create_anchor(struct peer *peer, enum state_input done) +{ + /* We assume this below */ + assert(done == BITCOIN_ANCHOR_CREATED); + if (peer->anchor) + report_trail(peer->trail, "Anchor already created?"); + + peer->anchor = true; + add_event(peer, done); +} + +void bitcoin_release_anchor(struct peer *peer, enum state_input done) +{ + if (!peer->anchor) + report_trail(peer->trail, "Anchor not created?"); + + peer->anchor = false; + remove_event(peer, done); +} + void peer_unwatch_anchor_depth(struct peer *peer, enum state_input depthok, enum state_input timeout) @@ -1492,6 +1518,9 @@ static const char *check_changes(const struct peer *old, struct peer *new, if (new->current_htlc.htlc.id != -1) return tal_fmt(NULL, "cond CLOSE with pending htlc"); + if (new->anchor) + return tal_fmt(NULL, + "cond CLOSE with anchor"); } if (new->cond == PEER_CLOSED) { /* FIXME: Move to state core */ @@ -1736,13 +1765,15 @@ static bool waiting_statepair(enum state a, enum state b) if (a == STATE_OPEN_WAITING_OURANCHOR || a == STATE_OPEN_WAITING_OURANCHOR_THEYCOMPLETED || a == STATE_OPEN_WAITING_THEIRANCHOR - || a == STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED) + || a == STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED + || a == STATE_OPEN_WAIT_FOR_ANCHOR_CREATE) return true; if (b == STATE_OPEN_WAITING_OURANCHOR || b == STATE_OPEN_WAITING_OURANCHOR_THEYCOMPLETED || b == STATE_OPEN_WAITING_THEIRANCHOR - || b == STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED) + || b == STATE_OPEN_WAITING_THEIRANCHOR_THEYCOMPLETED + || b == STATE_OPEN_WAIT_FOR_ANCHOR_CREATE) return true; /* We don't need inputs at start of main loop. */ @@ -2364,6 +2395,7 @@ int main(int argc, char *argv[]) || i == STATE_ERR_ANCHOR_TIMEOUT) a_expect = false; if (i == STATE_OPEN_WAIT_FOR_OPEN_WITHANCHOR + || i == STATE_OPEN_WAIT_FOR_ANCHOR_CREATE || i == STATE_OPEN_WAIT_FOR_COMMIT_SIG || i == STATE_OPEN_WAIT_FOR_COMPLETE_OURANCHOR || i == STATE_OPEN_WAITING_OURANCHOR