diff --git a/state.c b/state.c index cbacad492..f7ed14381 100644 --- a/state.c +++ b/state.c @@ -12,15 +12,6 @@ static inline bool high_priority(enum state state) #define toggle_prio(state, name) \ (!high_priority(state) ? name##_HIGHPRIO : name##_LOWPRIO) -#define add_effect(e, field, val) \ - do { \ - struct state_effect *_e = tal(ctx, struct state_effect); \ - _e->etype = STATE_EFFECT_##field; \ - _e->u.field = (val); \ - _e->next = (*e); \ - (*e) = _e; \ - } while(0) - /* STATE_CLOSE* can be treated as a bitset offset from STATE_CLOSED */ #define BITS_TO_STATE(bits) (STATE_CLOSED + (bits)) #define STATE_TO_BITS(state) ((state) - STATE_CLOSED) @@ -110,7 +101,6 @@ enum command_status state(const tal_t *ctx, Pkt *decline; struct bitcoin_tx *tx; Pkt *err; - struct htlc_watch *htlcs; enum command_status cstatus = CMD_NONE; *out = NULL; @@ -183,13 +173,12 @@ enum command_status state(const tal_t *ctx, } queue_pkt(out, pkt_open_commit_sig(ctx, peer)); - add_effect(effect, watch, - bitcoin_watch_anchor(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - BITCOIN_ANCHOR_TIMEOUT, - BITCOIN_ANCHOR_UNSPENT, - BITCOIN_ANCHOR_THEIRSPEND, - BITCOIN_ANCHOR_OTHERSPEND)); + peer_watch_anchor(peer, + BITCOIN_ANCHOR_DEPTHOK, + BITCOIN_ANCHOR_TIMEOUT, + BITCOIN_ANCHOR_UNSPENT, + BITCOIN_ANCHOR_THEIRSPEND, + BITCOIN_ANCHOR_OTHERSPEND); return next_state(peer, cstatus, STATE_OPEN_WAITING_THEIRANCHOR); @@ -210,13 +199,12 @@ enum command_status state(const tal_t *ctx, goto err_start_unilateral_close; } queue_tx_broadcast(broadcast, bitcoin_anchor(ctx, peer)); - add_effect(effect, watch, - bitcoin_watch_anchor(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - INPUT_NONE, - BITCOIN_ANCHOR_UNSPENT, - BITCOIN_ANCHOR_THEIRSPEND, - BITCOIN_ANCHOR_OTHERSPEND)); + peer_watch_anchor(peer, + BITCOIN_ANCHOR_DEPTHOK, + INPUT_NONE, + BITCOIN_ANCHOR_UNSPENT, + BITCOIN_ANCHOR_THEIRSPEND, + BITCOIN_ANCHOR_OTHERSPEND); return next_state(peer, cstatus, STATE_OPEN_WAITING_OURANCHOR); } else if (input_is(input, CMD_CLOSE)) { @@ -249,10 +237,9 @@ enum command_status state(const tal_t *ctx, goto anchor_unspent; } else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) { /* We no longer care about anchor depth. */ - add_effect(effect, unwatch, - bitcoin_unwatch_anchor_depth(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - INPUT_NONE)); + peer_unwatch_anchor_depth(peer, + BITCOIN_ANCHOR_DEPTHOK, + INPUT_NONE); complete_cmd(peer, &cstatus, CMD_FAIL); goto them_unilateral; } else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) { @@ -260,26 +247,23 @@ enum command_status state(const tal_t *ctx, return next_state(peer, cstatus, STATE_ERR_INFORMATION_LEAK); } else if (input_is(input, CMD_CLOSE)) { /* We no longer care about anchor depth. */ - add_effect(effect, unwatch, - bitcoin_unwatch_anchor_depth(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - INPUT_NONE)); + peer_unwatch_anchor_depth(peer, + BITCOIN_ANCHOR_DEPTHOK, + INPUT_NONE); complete_cmd(peer, &cstatus, CMD_FAIL); goto start_closing; } else if (input_is(input, PKT_CLOSE)) { /* We no longer care about anchor depth. */ - add_effect(effect, unwatch, - bitcoin_unwatch_anchor_depth(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - INPUT_NONE)); + peer_unwatch_anchor_depth(peer, + BITCOIN_ANCHOR_DEPTHOK, + INPUT_NONE); complete_cmd(peer, &cstatus, CMD_FAIL); goto accept_closing; } else if (input_is_pkt(input)) { /* We no longer care about anchor depth. */ - add_effect(effect, unwatch, - bitcoin_unwatch_anchor_depth(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - INPUT_NONE)); + peer_unwatch_anchor_depth(peer, + BITCOIN_ANCHOR_DEPTHOK, + INPUT_NONE); complete_cmd(peer, &cstatus, CMD_FAIL); goto unexpected_pkt_nocleanup; } @@ -315,34 +299,30 @@ enum command_status state(const tal_t *ctx, STATE_ERR_INFORMATION_LEAK); } else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) { /* We no longer care about anchor depth. */ - add_effect(effect, unwatch, - bitcoin_unwatch_anchor_depth(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - BITCOIN_ANCHOR_TIMEOUT)); + peer_unwatch_anchor_depth(peer, + BITCOIN_ANCHOR_DEPTHOK, + BITCOIN_ANCHOR_TIMEOUT); complete_cmd(peer, &cstatus, CMD_FAIL); goto them_unilateral; } else if (input_is(input, CMD_CLOSE)) { /* We no longer care about anchor depth. */ - add_effect(effect, unwatch, - bitcoin_unwatch_anchor_depth(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - BITCOIN_ANCHOR_TIMEOUT)); + peer_unwatch_anchor_depth(peer, + BITCOIN_ANCHOR_DEPTHOK, + BITCOIN_ANCHOR_TIMEOUT); complete_cmd(peer, &cstatus, CMD_FAIL); goto start_closing; } else if (input_is(input, PKT_CLOSE)) { /* We no longer care about anchor depth. */ - add_effect(effect, unwatch, - bitcoin_unwatch_anchor_depth(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - BITCOIN_ANCHOR_TIMEOUT)); + peer_unwatch_anchor_depth(peer, + BITCOIN_ANCHOR_DEPTHOK, + BITCOIN_ANCHOR_TIMEOUT); complete_cmd(peer, &cstatus, CMD_FAIL); goto accept_closing; } else if (input_is_pkt(input)) { /* We no longer care about anchor depth. */ - add_effect(effect, unwatch, - bitcoin_unwatch_anchor_depth(ctx, peer, - BITCOIN_ANCHOR_DEPTHOK, - BITCOIN_ANCHOR_TIMEOUT)); + peer_unwatch_anchor_depth(peer, + BITCOIN_ANCHOR_DEPTHOK, + BITCOIN_ANCHOR_TIMEOUT); complete_cmd(peer, &cstatus, CMD_FAIL); goto unexpected_pkt; } @@ -738,8 +718,7 @@ enum command_status state(const tal_t *ctx, /* One a steal is complete, we don't care about htlcs * (we stole them all) */ if (bits & STATE_CLOSE_HTLCS_BIT) - add_effect(effect, unwatch_htlc, - htlc_unwatch_all(ctx, peer)); + peer_unwatch_all_htlc_outputs(peer); return next_state(peer, cstatus, STATE_CLOSED); } @@ -764,9 +743,7 @@ enum command_status state(const tal_t *ctx, tx = bitcoin_spend_ours(ctx, peer); /* Now we need to wait for our commit to be done. */ queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch(ctx, tx, - BITCOIN_SPEND_OURS_DONE)); + peer_watch_tx(peer, tx, BITCOIN_SPEND_OURS_DONE); bits &= ~STATE_CLOSE_OURCOMMIT_BIT; bits |= STATE_CLOSE_SPENDOURS_BIT; return next_state(peer, cstatus, BITS_TO_STATE(bits)); @@ -791,9 +768,8 @@ enum command_status state(const tal_t *ctx, /* They revealed R value. */ peer_tx_revealed_r_value(peer, idata->btc); /* We don't care any more. */ - add_effect(effect, unwatch_htlc, - htlc_unwatch(ctx, idata->htlc, - INPUT_NO_MORE_HTLCS)); + peer_unwatch_htlc_output(peer, idata->htlc, + INPUT_NO_MORE_HTLCS); return unchanged_state(cstatus); } else if (input_is(input, BITCOIN_HTLC_TOTHEM_TIMEOUT)){ tx = bitcoin_htlc_timeout(ctx, @@ -805,11 +781,8 @@ enum command_status state(const tal_t *ctx, * try to spend, revealing rvalue. */ /* We're done when that gets buried. */ - add_effect(effect, watch_htlc_spend, - htlc_spend_watch(ctx, - tx, - idata->cmd, - BITCOIN_HTLC_RETURN_SPEND_DONE)); + peer_watch_htlc_spend(peer, tx, idata->htlc, + BITCOIN_HTLC_RETURN_SPEND_DONE); return unchanged_state(cstatus); } else if (input_is(input, INPUT_RVALUE)) { tx = bitcoin_htlc_spend(ctx, peer, @@ -818,44 +791,34 @@ enum command_status state(const tal_t *ctx, /* Spend it... */ queue_tx_broadcast(broadcast, tx); /* We're done when it gets buried. */ - add_effect(effect, watch_htlc_spend, - htlc_spend_watch(ctx, - tx, - idata->cmd, - BITCOIN_HTLC_FULFILL_SPEND_DONE)); + peer_watch_htlc_spend(peer, tx, idata->htlc, + BITCOIN_HTLC_FULFILL_SPEND_DONE); /* Don't care about this one any more. */ - add_effect(effect, unwatch_htlc, - htlc_unwatch(ctx, idata->htlc, - INPUT_NO_MORE_HTLCS)); + peer_unwatch_htlc_output(peer, idata->htlc, + INPUT_NO_MORE_HTLCS); return unchanged_state(cstatus); } else if (input_is(input, BITCOIN_HTLC_FULFILL_SPEND_DONE)) { /* Stop watching spend, send * INPUT_NO_MORE_HTLCS when done. */ - add_effect(effect, unwatch_htlc_spend, - htlc_spend_unwatch(ctx, - idata->htlc, - INPUT_NO_MORE_HTLCS)); + peer_unwatch_htlc_spend(peer, idata->htlc, + INPUT_NO_MORE_HTLCS); return unchanged_state(cstatus); } else if (input_is(input, BITCOIN_HTLC_RETURN_SPEND_DONE)) { /* Stop watching spend, send * INPUT_NO_MORE_HTLCS when done. */ - add_effect(effect, unwatch_htlc_spend, - htlc_spend_unwatch(ctx, - idata->htlc, - INPUT_NO_MORE_HTLCS)); + peer_unwatch_htlc_spend(peer, idata->htlc, + INPUT_NO_MORE_HTLCS); /* Don't need to watch the HTLC output any more, * either. */ - add_effect(effect, unwatch_htlc, - htlc_unwatch(ctx, idata->htlc, - INPUT_NO_MORE_HTLCS)); + peer_unwatch_htlc_output(peer, idata->htlc, + INPUT_NO_MORE_HTLCS); return unchanged_state(cstatus); } else if (input_is(input, BITCOIN_HTLC_TOUS_TIMEOUT)) { /* They can spend, we no longer care * about this HTLC. */ - add_effect(effect, unwatch_htlc, - htlc_unwatch(ctx, idata->htlc, - INPUT_NO_MORE_HTLCS)); + peer_unwatch_htlc_output(peer, idata->htlc, + INPUT_NO_MORE_HTLCS); return unchanged_state(cstatus); } } @@ -871,19 +834,14 @@ enum command_status state(const tal_t *ctx, if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) { tx = bitcoin_spend_theirs(ctx, peer, idata->btc); queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch(ctx, tx, - BITCOIN_SPEND_THEIRS_DONE)); - /* HTLC watches. */ - htlcs = htlc_outputs_their_commit(ctx, peer, - idata->btc, + peer_watch_tx(peer, tx, BITCOIN_SPEND_THEIRS_DONE); + /* HTLC watches: if any, set HTLCs bit. */ + if (peer_watch_their_htlc_outputs(peer, idata->btc, BITCOIN_HTLC_TOUS_TIMEOUT, BITCOIN_HTLC_TOTHEM_SPENT, - BITCOIN_HTLC_TOTHEM_TIMEOUT); - if (htlcs) { - add_effect(effect, watch_htlcs, htlcs); + BITCOIN_HTLC_TOTHEM_TIMEOUT)) bits |= STATE_CLOSE_HTLCS_BIT; - } + bits |= STATE_CLOSE_SPENDTHEM_BIT; return next_state_bits(peer, cstatus, bits); /* This can happen multiple times: need to steal ALL */ @@ -893,9 +851,7 @@ enum command_status state(const tal_t *ctx, return next_state(peer, cstatus, STATE_ERR_INFORMATION_LEAK); queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch(ctx, tx, - BITCOIN_STEAL_DONE)); + peer_watch_tx(peer, tx, BITCOIN_STEAL_DONE); bits |= STATE_CLOSE_STEAL_BIT; return next_state_bits(peer, cstatus, bits); } else if (input_is(input, BITCOIN_ANCHOR_UNSPENT)) @@ -981,20 +937,16 @@ start_unilateral_close: set_peer_cond(peer, PEER_CLOSED); tx = bitcoin_commit(ctx, peer); queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch_delayed(ctx, tx, - BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED)); + peer_watch_delayed(peer, tx, BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED); /* HTLC watches. */ - htlcs = htlc_outputs_our_commit(ctx, peer, tx, + if (peer_watch_our_htlc_outputs(peer, tx, BITCOIN_HTLC_TOUS_TIMEOUT, BITCOIN_HTLC_TOTHEM_SPENT, - BITCOIN_HTLC_TOTHEM_TIMEOUT); - if (htlcs) { - add_effect(effect, watch_htlcs, htlcs); + BITCOIN_HTLC_TOTHEM_TIMEOUT)) return next_state(peer, cstatus, STATE_CLOSE_WAIT_OURCOMMIT_WITH_HTLCS); - } + return next_state(peer, cstatus, STATE_CLOSE_WAIT_OURCOMMIT); err_start_unilateral_close_already_closing: @@ -1011,9 +963,7 @@ start_unilateral_close_already_closing: set_peer_cond(peer, PEER_CLOSED); tx = bitcoin_commit(ctx, peer); queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch_delayed(ctx, tx, - BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED)); + peer_watch_delayed(peer, tx, BITCOIN_ANCHOR_OURCOMMIT_DELAYPASSED); /* We agreed to close: shouldn't have any HTLCs */ if (committed_to_htlcs(peer)) @@ -1033,21 +983,17 @@ them_unilateral: set_peer_cond(peer, PEER_CLOSED); tx = bitcoin_spend_theirs(ctx, peer, idata->btc); queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch(ctx, tx, - BITCOIN_SPEND_THEIRS_DONE)); + peer_watch_tx(peer, tx, BITCOIN_SPEND_THEIRS_DONE); /* HTLC watches (based on what they broadcast, which *may* be out * of step with our current state by +/- 1 htlc. */ - htlcs = htlc_outputs_their_commit(ctx, peer, idata->btc, + if (peer_watch_their_htlc_outputs(peer, idata->btc, BITCOIN_HTLC_TOUS_TIMEOUT, BITCOIN_HTLC_TOTHEM_SPENT, - BITCOIN_HTLC_TOTHEM_TIMEOUT); - if (htlcs) { - add_effect(effect, watch_htlcs, htlcs); + BITCOIN_HTLC_TOTHEM_TIMEOUT)) return next_state(peer, cstatus, STATE_CLOSE_WAIT_SPENDTHEM_WITH_HTLCS); - } + return next_state(peer, cstatus, STATE_CLOSE_WAIT_SPENDTHEM); accept_htlc_update: @@ -1100,10 +1046,7 @@ start_closing: err = pkt_err(ctx, "Close forced due to HTLCs"); goto err_start_unilateral_close; } - add_effect(effect, close_timeout, INPUT_CLOSE_COMPLETE_TIMEOUT); - - add_effect(effect, watch, - bitcoin_watch_close(ctx, peer, BITCOIN_CLOSE_DONE)); + peer_watch_close(peer, BITCOIN_CLOSE_DONE, INPUT_CLOSE_COMPLETE_TIMEOUT); /* No more commands, we're already closing. */ set_peer_cond(peer, PEER_CLOSING); @@ -1116,9 +1059,9 @@ accept_closing: err = accept_pkt_close(ctx, peer, idata->pkt, effect); if (err) goto err_start_unilateral_close; - /* As soon as we send packet, they could close. */ - add_effect(effect, watch, - bitcoin_watch_close(ctx, peer, BITCOIN_CLOSE_DONE)); + peer_watch_close(peer, BITCOIN_CLOSE_DONE, INPUT_NONE); + /* Send close TX. */ + queue_tx_broadcast(broadcast, bitcoin_close(ctx, peer)); queue_pkt(out, pkt_close_complete(ctx, peer)); /* No more commands, we're already closing. */ set_peer_cond(peer, PEER_CLOSING); @@ -1151,18 +1094,14 @@ fail_during_close: /* A reorganization could make this happen. */ tx = bitcoin_spend_theirs(ctx, peer, idata->btc); queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch(ctx, tx, - BITCOIN_SPEND_THEIRS_DONE)); - htlcs = htlc_outputs_their_commit(ctx, peer, idata->btc, + peer_watch_tx(peer, tx, BITCOIN_SPEND_THEIRS_DONE); + if (peer_watch_their_htlc_outputs(peer, idata->btc, BITCOIN_HTLC_TOUS_TIMEOUT, BITCOIN_HTLC_TOTHEM_SPENT, - BITCOIN_HTLC_TOTHEM_TIMEOUT); - /* Expect either close or spendthem to complete */ - if (htlcs) { + BITCOIN_HTLC_TOTHEM_TIMEOUT)) { + /* Expect either close or spendthem to complete */ /* FIXME: Make sure caller uses INPUT_RVAL * if they were in the middle of FULFILL! */ - add_effect(effect, watch_htlcs, htlcs); return next_state(peer, cstatus, STATE_CLOSE_WAIT_SPENDTHEM_CLOSE_WITH_HTLCS); } @@ -1174,8 +1113,7 @@ fail_during_close: return next_state(peer, cstatus, STATE_ERR_INFORMATION_LEAK); queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch(ctx, tx, BITCOIN_STEAL_DONE)); + peer_watch_tx(peer, tx, BITCOIN_STEAL_DONE); /* Expect either close or steal to complete */ return next_state(peer, cstatus, STATE_CLOSE_WAIT_STEAL_CLOSE); @@ -1199,7 +1137,6 @@ old_commit_spotted: return next_state(peer, cstatus, STATE_ERR_INFORMATION_LEAK); queue_tx_broadcast(broadcast, tx); - add_effect(effect, watch, - bitcoin_watch(ctx, tx, BITCOIN_STEAL_DONE)); + peer_watch_tx(peer, tx, BITCOIN_STEAL_DONE); return next_state(peer, cstatus, STATE_CLOSE_WAIT_STEAL); } diff --git a/state.h b/state.h index 7d429a5cf..41037eb95 100644 --- a/state.h +++ b/state.h @@ -6,51 +6,13 @@ #include #include -enum state_effect_type { - STATE_EFFECT_watch, - STATE_EFFECT_unwatch, - /* FIXME: Use a watch for this?. */ - STATE_EFFECT_close_timeout, - /* FIXME: Combine into watches? */ - STATE_EFFECT_watch_htlcs, - STATE_EFFECT_unwatch_htlc, - STATE_EFFECT_watch_htlc_spend, - STATE_EFFECT_unwatch_htlc_spend -}; - /* * This is the core state machine. * - * Calling the state machine with an input simply returns the new state, - * and populates the "effect" struct with what it wants done. + * Calling the state machine updates updates peer->state, and may call + * various peer_ callbacks. It also returns the status of the current + * command. */ -struct state_effect { - struct state_effect *next; - - enum state_effect_type etype; - union { - /* Event to watch for. */ - struct watch *watch; - - /* Events to no longer watch for. */ - struct watch *unwatch; - - /* Set a timeout for close tx. */ - enum state_input close_timeout; - - /* HTLC outputs to watch. */ - const struct htlc_watch *watch_htlcs; - - /* HTLC output to unwatch. */ - const struct htlc_unwatch *unwatch_htlc; - - /* HTLC spends to watch/unwatch. */ - const struct htlc_spend_watch *watch_htlc_spend; - const struct htlc_spend_watch *unwatch_htlc_spend; - - /* FIXME: More to come (for accept_*) */ - } u; -}; static inline bool state_is_error(enum state s) { @@ -59,6 +21,7 @@ static inline bool state_is_error(enum state s) struct peer; struct bitcoin_tx; +struct state_effect; static inline bool input_is_pkt(enum state_input input) { @@ -226,8 +189,7 @@ Pkt *accept_pkt_close_ack(const tal_t *ctx, bool committed_to_htlcs(const struct peer *peer); /** - * bitcoin_watch_anchor: create a watch for the anchor. - * @ctx: context to tal the watch struct off. + * peer_watch_anchor: create a watch for the anchor transaction. * @peer: the state data for this peer. * @depthok: the input to give when anchor reaches expected depth. * @timeout: the input to give if anchor doesn't reach depth in time. @@ -238,136 +200,138 @@ bool committed_to_htlcs(const struct peer *peer); * @depthok can be INPUT_NONE if it's our anchor (we don't time * ourselves out). */ -struct watch *bitcoin_watch_anchor(const tal_t *ctx, - const struct peer *peer, - enum state_input depthok, - enum state_input timeout, - enum state_input unspent, - enum state_input theyspent, - enum state_input otherspent); +void peer_watch_anchor(struct peer *peer, + enum state_input depthok, + enum state_input timeout, + enum state_input unspent, + enum state_input theyspent, + enum state_input otherspent); /** - * bitcoin_unwatch_anchor_depth: remove depth watch for the anchor. - * @ctx: context to tal the watch struct off. + * peer_unwatch_anchor_depth: remove depth watch for the anchor. * @peer: the state data for this peer. * @depthok: the input to give when anchor reaches expected depth. * @timeout: the input to give if anchor doesn't reach depth in time. * * @depthok and @timeout must match bitcoin_watch_anchor() call. */ -struct watch *bitcoin_unwatch_anchor_depth(const tal_t *ctx, - const struct peer *peer, - enum state_input depthok, - enum state_input timeout); +void peer_unwatch_anchor_depth(struct peer *peer, + enum state_input depthok, + enum state_input timeout); /** - * bitcoin_watch_delayed: watch this (commit) tx, tell me when I can spend it - * @ctx: the context to tal the watch off + * peer_watch_delayed: watch this (commit) tx, tell me when I can spend it + * @peer: the state data for this peer. * @tx: the tx we're watching. * @canspend: the input to give when commit reaches spendable depth. * * Note that this tx may be malleated, as it's dual-signed. */ -struct watch *bitcoin_watch_delayed(const tal_t *ctx, - const struct bitcoin_tx *tx, - enum state_input canspend); +void peer_watch_delayed(struct peer *peer, + const struct bitcoin_tx *tx, + enum state_input canspend); /** - * bitcoin_watch: watch this tx until it's "irreversible" - * @ctx: the context to tal the watch off + * peer_watch_tx: watch this tx until it's "irreversible" + * @peer: the state data for this peer. * @tx: the tx we're watching. * @done: the input to give when tx is completely buried. * - * The tx should be immalleable by BIP62; once this fires we consider - * the channel completely closed and stop watching (eg 100 txs down). + * Once this fires we consider the channel completely closed and stop + * watching (eg 100 txs down). + * + * This is used for watching a transaction we sent (such as a steal, + * or spend of their close, etc). */ -struct watch *bitcoin_watch(const tal_t *ctx, - const struct bitcoin_tx *tx, - enum state_input done); +void peer_watch_tx(struct peer *peer, + const struct bitcoin_tx *tx, + enum state_input done); /** - * bitcoin_watch_close: watch close tx until it's "irreversible" - * @ctx: context to tal the watch struct off. + * peer_watch_close: watch for close tx until it's "irreversible" (or timedout) * @peer: the state data for this peer. * @done: the input to give when tx is completely buried. + * @timedout: the input to give if we time out. + * + * Once this fires we consider the channel completely closed and stop + * watching (eg 100 txs down). * - * This tx *is* malleable, since the other side can transmit theirs. + * This is used for watching a mutual close, or for a transaction we sent + * (such as a steal, or spend of their close, etc). */ -struct watch *bitcoin_watch_close(const tal_t *ctx, - const struct peer *peer, - enum state_input done); +void peer_watch_close(struct peer *peer, + enum state_input done, enum state_input timedout); /** - * htlc_outputs_our_commit: HTLC outputs from our commit tx to watch. - * @ctx: context to tal the watch struct off. + * peer_watch_our_htlc_outputs: HTLC outputs from our commit tx to watch. * @peer: the state data for this peer. * @tx: the commitment tx * @tous_timeout: input to give when a HTLC output to us times out. * @tothem_spent: input to give when a HTLC output to them is spent. * @tothem_timeout: input to give when a HTLC output to them times out. + * + * Returns true if there were any htlc outputs to watch. */ -struct htlc_watch *htlc_outputs_our_commit(const tal_t *ctx, - const struct peer *peer, - const struct bitcoin_tx *tx, - enum state_input tous_timeout, - enum state_input tothem_spent, - enum state_input tothem_timeout); +bool peer_watch_our_htlc_outputs(struct peer *peer, + const struct bitcoin_tx *tx, + enum state_input tous_timeout, + enum state_input tothem_spent, + enum state_input tothem_timeout); /** - * htlc_outputs_their_commit: HTLC outputs from their commit tx to watch. - * @ctx: context to tal the watch struct off. + * peer_watch_their_htlc_outputs: HTLC outputs from their commit tx to watch. * @peer: the state data for this peer. * @tx: the commitment tx * @tous_timeout: input to give when a HTLC output to us times out. * @tothem_spent: input to give when a HTLC output to them is spent. * @tothem_timeout: input to give when a HTLC output to them times out. + * + * Returns true if there were any htlc outputs to watch. */ -struct htlc_watch *htlc_outputs_their_commit(const tal_t *ctx, - const struct peer *peer, - const struct bitcoin_event *tx, - enum state_input tous_timeout, - enum state_input tothem_spent, - enum state_input tothem_timeout); +bool peer_watch_their_htlc_outputs(struct peer *peer, + const struct bitcoin_event *tx, + enum state_input tous_timeout, + enum state_input tothem_spent, + enum state_input tothem_timeout); /** - * htlc_unwatch: stop watching an HTLC - * @ctx: context to tal the watch struct off. + * peer_unwatch_htlc_output: stop watching an HTLC + * @peer: the state data for this peer. * @htlc: the htlc to stop watching - * @all_done: input to give if we're not watching any anymore. + * @all_done: input to give if we're not watching any outputs anymore. */ -struct htlc_unwatch *htlc_unwatch(const tal_t *ctx, - const struct htlc *htlc, - enum state_input all_done); +void peer_unwatch_htlc_output(struct peer *peer, + const struct htlc *htlc, + enum state_input all_done); /** - * htlc_unwatch_all: stop watching all HTLCs - * @ctx: context to tal the watch struct off. + * peer_unwatch_all_htlc_outputs: stop watching all HTLCs * @peer: the state data for this peer. */ -struct htlc_unwatch *htlc_unwatch_all(const tal_t *ctx, - const struct peer *peer); +void peer_unwatch_all_htlc_outputs(struct peer *peer); /** - * htlc_spend_watch: watch our spend of an HTLC - * @ctx: context to tal the watch struct off. + * peer_watch_htlc_spend: watch our spend of an HTLC output + * @peer: the state data for this peer. * @tx: the commitment tx - * @cmd: the command data. + * @htlc: the htlc the tx is spending an output of * @done: input to give when it's completely buried. */ -struct htlc_spend_watch *htlc_spend_watch(const tal_t *ctx, - const struct bitcoin_tx *tx, - const struct command *cmd, - enum state_input done); +void peer_watch_htlc_spend(struct peer *peer, + const struct bitcoin_tx *tx, + const struct htlc *htlc, + enum state_input done); /** - * htlc_spend_unwatch: stop watching an HTLC spend - * @ctx: context to tal the watch struct off. - * @htlc: the htlc to stop watching + * peer_unwatch_htlc_spend: stop watching our HTLC spend + * @peer: the state data for this peer. + * @htlc: the htlc to stop watching the spend for. * @all_done: input to give if we're not watching anything anymore. */ -struct htlc_spend_watch *htlc_spend_unwatch(const tal_t *ctx, - const struct htlc *htlc, - enum state_input all_done); +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); diff --git a/test/test_state_coverage.c b/test/test_state_coverage.c index bb565fe9d..8c122936a 100644 --- a/test/test_state_coverage.c +++ b/test/test_state_coverage.c @@ -871,134 +871,6 @@ struct bitcoin_tx *bitcoin_anchor(const tal_t *ctx, return bitcoin_tx("anchor"); } -static bool have_event(uint64_t events, enum state_input input) -{ - return events & (1ULL << input); -} - -static bool add_event_(uint64_t *events, enum state_input input) -{ - /* This is how they say "no event please" */ - if (input == INPUT_NONE) - return true; - - assert(input < 64); - if (have_event(*events, input)) - return false; - *events |= (1ULL << input); - return true; -} - -static bool remove_event_(uint64_t *events, enum state_input input) -{ - /* This is how they say "no event please" */ - if (input == INPUT_NONE) - return true; - - assert(input < 64); - if (!have_event(*events, input)) - return false; - *events &= ~(1ULL << input); - return true; -} - -static void remove_event(uint64_t *events, enum state_input input) -{ -#ifdef NDEBUG -#error "Don't run tests with NDEBUG" -#endif - assert(remove_event_(events, input)); -} - -static void add_event(uint64_t *events, enum state_input input) -{ -#ifdef NDEBUG -#error "Don't run tests with NDEBUG" -#endif - assert(add_event_(events, input)); -} - -struct watch { - uint64_t events; -}; - -struct watch *bitcoin_watch_anchor(const tal_t *ctx, - const struct peer *peer, - enum state_input depthok, - enum state_input timeout, - enum state_input unspent, - enum state_input theyspent, - enum state_input otherspent) -{ - struct watch *watch = talz(ctx, struct watch); - - add_event(&watch->events, depthok); - add_event(&watch->events, timeout); - add_event(&watch->events, unspent); - add_event(&watch->events, theyspent); - add_event(&watch->events, otherspent); - - /* We assume these values in activate_event. */ - assert(timeout == BITCOIN_ANCHOR_TIMEOUT - || timeout == INPUT_NONE); - assert(depthok == BITCOIN_ANCHOR_DEPTHOK); - return watch; -} - -struct watch *bitcoin_unwatch_anchor_depth(const tal_t *ctx, - const struct peer *peer, - enum state_input depthok, - enum state_input timeout) -{ - struct watch *watch = talz(ctx, struct watch); - - add_event(&watch->events, depthok); - add_event(&watch->events, timeout); - return watch; -} - -/* Wait for our commit to be spendable. */ -struct watch *bitcoin_watch_delayed(const tal_t *ctx, - const struct bitcoin_tx *tx, - enum state_input canspend) -{ - struct watch *watch = talz(ctx, struct watch); - - assert(bitcoin_tx_is(tx, "our commit")); - add_event(&watch->events, canspend); - return watch; -} - -/* Wait for commit to be very deeply buried (so we no longer need to - * even watch) */ -struct watch *bitcoin_watch(const tal_t *ctx, - const struct bitcoin_tx *tx, - enum state_input done) -{ - struct watch *watch = talz(ctx, struct watch); - - if (done == BITCOIN_STEAL_DONE) - assert(bitcoin_tx_is(tx, "steal")); - else if (done == BITCOIN_SPEND_THEIRS_DONE) - assert(bitcoin_tx_is(tx, "spend their commit")); - else if (done == BITCOIN_SPEND_OURS_DONE) - assert(bitcoin_tx_is(tx, "spend our commit")); - else - errx(1, "Unknown watch effect %s", input_name(done)); - add_event(&watch->events, done); - return watch; -} - -/* Other side should drop close tx; watch for it. */ -struct watch *bitcoin_watch_close(const tal_t *ctx, - const struct peer *peer, - enum state_input done) -{ - struct watch *watch = talz(ctx, struct watch); - add_event(&watch->events, done); - return watch; -} - struct bitcoin_tx *bitcoin_close(const tal_t *ctx, const struct peer *peer) { @@ -1054,143 +926,6 @@ bool committed_to_htlcs(const struct peer *peer) return peer->num_htlcs_to_them != 0 || peer->num_htlcs_to_us != 0; } -struct htlc_watch -{ - enum state_input tous_timeout; - enum state_input tothem_spent; - enum state_input tothem_timeout; - unsigned int num_htlcs_to_us, num_htlcs_to_them; - struct htlc htlcs_to_us[MAX_HTLCS], htlcs_to_them[MAX_HTLCS]; -}; - -struct htlc_unwatch -{ - unsigned int id; - enum state_input all_done; -}; - -struct htlc_watch *htlc_outputs_our_commit(const tal_t *ctx, - const struct peer *peer, - const struct bitcoin_tx *tx, - enum state_input tous_timeout, - enum state_input tothem_spent, - enum state_input tothem_timeout) -{ - struct htlc_watch *w = tal(ctx, struct htlc_watch); - - /* We assume these. */ - assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT); - assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT); - assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT); - - w->tous_timeout = tous_timeout; - w->tothem_spent = tothem_spent; - w->tothem_timeout = tothem_timeout; - - w->num_htlcs_to_us = peer->num_htlcs_to_us; - w->num_htlcs_to_them = peer->num_htlcs_to_them; - BUILD_ASSERT(sizeof(peer->htlcs_to_us) == sizeof(w->htlcs_to_us)); - BUILD_ASSERT(sizeof(peer->htlcs_to_them) == sizeof(w->htlcs_to_them)); - memcpy(w->htlcs_to_us, peer->htlcs_to_us, sizeof(peer->htlcs_to_us)); - memcpy(w->htlcs_to_them, peer->htlcs_to_them, - sizeof(peer->htlcs_to_them)); - - if (!w->num_htlcs_to_us && !w->num_htlcs_to_them) - return tal_free(w); - - return w; -} - -struct htlc_watch *htlc_outputs_their_commit(const tal_t *ctx, - const struct peer *peer, - const struct bitcoin_event *tx, - enum state_input tous_timeout, - enum state_input tothem_spent, - enum state_input tothem_timeout) -{ - struct htlc_watch *w = tal(ctx, struct htlc_watch); - unsigned int i; - - /* We assume these. */ - assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT); - assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT); - assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT); - - w->tous_timeout = tous_timeout; - w->tothem_spent = tothem_spent; - w->tothem_timeout = tothem_timeout; - - /* It's what our peer thinks is current... */ - w->num_htlcs_to_us = peer->other->num_htlcs_to_them; - w->num_htlcs_to_them = peer->other->num_htlcs_to_us; - BUILD_ASSERT(sizeof(peer->other->htlcs_to_them) == sizeof(w->htlcs_to_us)); - BUILD_ASSERT(sizeof(peer->other->htlcs_to_us) == sizeof(w->htlcs_to_them)); - memcpy(w->htlcs_to_us, peer->other->htlcs_to_them, sizeof(w->htlcs_to_us)); - memcpy(w->htlcs_to_them, peer->other->htlcs_to_us, - sizeof(w->htlcs_to_them)); - - if (!w->num_htlcs_to_us && !w->num_htlcs_to_them) - return tal_free(w); - - /* Reverse perspective, mark rvalue unknown */ - for (i = 0; i < w->num_htlcs_to_us; i++) { - assert(w->htlcs_to_us[i].to_them); - w->htlcs_to_us[i].to_them = false; - } - for (i = 0; i < w->num_htlcs_to_them; i++) { - assert(!w->htlcs_to_them[i].to_them); - w->htlcs_to_them[i].to_them = true; - } - return w; -} - -struct htlc_unwatch *htlc_unwatch(const tal_t *ctx, - const struct htlc *htlc, - enum state_input all_done) -{ - struct htlc_unwatch *w = tal(ctx, struct htlc_unwatch); - - w->id = htlc->id; - assert(w->id != -1U); - w->all_done = all_done; - return w; -} - -struct htlc_unwatch *htlc_unwatch_all(const tal_t *ctx, - const struct peer *peer) -{ - struct htlc_unwatch *w = tal(ctx, struct htlc_unwatch); - - w->id = -1U; - return w; -} - -struct htlc_spend_watch *htlc_spend_watch(const tal_t *ctx, - const struct bitcoin_tx *tx, - const struct command *cmd, - enum state_input done) -{ - struct htlc_spend_watch *w = tal(ctx, struct htlc_spend_watch); - w->id = htlc_id_from_tx(tx); - w->done = done; - return w; -} - -struct htlc_spend_watch *htlc_spend_unwatch(const tal_t *ctx, - const struct htlc *htlc, - enum state_input all_done) -{ - struct htlc_spend_watch *w = tal(ctx, struct htlc_spend_watch); - - w->id = htlc->id; - w->done = all_done; - return w; -} - -struct htlc_rval { - unsigned int id; -}; - #include "state.c" #include #include @@ -1401,6 +1136,282 @@ static bool outstanding_htlc_watches(const struct peer *peer) || peer->num_htlc_spends_to_them; } +static bool have_event(uint64_t events, enum state_input input) +{ + return events & (1ULL << input); +} + +static bool add_event_(struct peer *peer, enum state_input input) +{ + /* This is how they say "no event please" */ + if (input == INPUT_NONE) + return true; + + assert(input < 64); + if (have_event(peer->core.event_notifies, input)) + return false; + peer->core.event_notifies |= (1ULL << input); + return true; +} + +static bool remove_event_(uint64_t *events, enum state_input input) +{ + /* This is how they say "no event please" */ + if (input == INPUT_NONE) + return true; + + assert(input < 64); + if (!have_event(*events, input)) + return false; + *events &= ~(1ULL << input); + return true; +} + +static void remove_event(struct peer *peer, enum state_input input) +{ + if (!remove_event_(&peer->core.event_notifies, input)) + report_trail(peer->trail, "Removing event we don't have?"); +} + +static void add_event(struct peer *peer, enum state_input input) +{ + if (!add_event_(peer, input)) + report_trail(peer->trail, "Adding event we already have?"); +} + +void peer_watch_anchor(struct peer *peer, + enum state_input depthok, + enum state_input timeout, + enum state_input unspent, + enum state_input theyspent, + enum state_input otherspent) +{ + /* We assume these values in activate_event. */ + assert(timeout == BITCOIN_ANCHOR_TIMEOUT + || timeout == INPUT_NONE); + assert(depthok == BITCOIN_ANCHOR_DEPTHOK); + + add_event(peer, depthok); + add_event(peer, timeout); + add_event(peer, unspent); + add_event(peer, theyspent); + add_event(peer, otherspent); +} + +void peer_unwatch_anchor_depth(struct peer *peer, + enum state_input depthok, + enum state_input timeout) +{ + /* We assume these values in activate_event. */ + assert(timeout == BITCOIN_ANCHOR_TIMEOUT + || timeout == INPUT_NONE); + assert(depthok == BITCOIN_ANCHOR_DEPTHOK); + + remove_event(peer, depthok); + remove_event(peer, timeout); +} + +/* Wait for our commit to be spendable. */ +void peer_watch_delayed(struct peer *peer, + const struct bitcoin_tx *tx, enum state_input canspend) +{ + assert(bitcoin_tx_is(tx, "our commit")); + add_event(peer, canspend); +} + +/* Wait for commit to be very deeply buried (so we no longer need to + * even watch) */ +void peer_watch_tx(struct peer *peer, + const struct bitcoin_tx *tx, + enum state_input done) +{ + /* We can have multiple steals or spendtheirs in flight, so + * allow repeats for + * BITCOIN_STEAL_DONE/BITCOIN_SPEND_THEIRS_DONE */ + if (done == BITCOIN_STEAL_DONE) { + assert(bitcoin_tx_is(tx, "steal")); + add_event_(peer, done); + } else if (done == BITCOIN_SPEND_THEIRS_DONE) { + assert(bitcoin_tx_is(tx, "spend their commit")); + add_event_(peer, done); + } else if (done == BITCOIN_SPEND_OURS_DONE) { + assert(bitcoin_tx_is(tx, "spend our commit")); + add_event(peer, done); + } else + report_trail(peer->trail, "Unknown watch effect"); +} + +/* Other side should drop close tx; watch for it. */ +void peer_watch_close(struct peer *peer, + enum state_input done, enum state_input timedout) +{ + add_event(peer, done); + + /* We assume this. */ + assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT || timedout == INPUT_NONE); + add_event(peer, timedout); +} + +bool peer_watch_our_htlc_outputs(struct peer *peer, + const struct bitcoin_tx *tx, + enum state_input tous_timeout, + enum state_input tothem_spent, + enum state_input tothem_timeout) +{ + /* FIXME: We assume these. */ + assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT); + assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT); + assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT); + + if (!peer->num_htlcs_to_us && !peer->num_htlcs_to_them) + return false; + + assert(peer->num_live_htlcs_to_us + peer->num_htlcs_to_us + <= ARRAY_SIZE(peer->live_htlcs_to_us)); + assert(peer->num_live_htlcs_to_them + peer->num_htlcs_to_them + <= ARRAY_SIZE(peer->live_htlcs_to_them)); + memcpy(peer->live_htlcs_to_us + peer->num_live_htlcs_to_us, + peer->htlcs_to_us, + peer->num_htlcs_to_us * sizeof(peer->htlcs_to_us[0])); + memcpy(peer->live_htlcs_to_them + peer->num_live_htlcs_to_them, + peer->htlcs_to_them, + peer->num_htlcs_to_them * sizeof(peer->htlcs_to_them[0])); + peer->num_live_htlcs_to_us += peer->num_htlcs_to_us; + peer->num_live_htlcs_to_them += peer->num_htlcs_to_them; + /* Can happen if we were finished, then new commit tx */ + remove_event_(&peer->core.event_notifies, INPUT_NO_MORE_HTLCS); + + return true; +} + +bool peer_watch_their_htlc_outputs(struct peer *peer, + const struct bitcoin_event *tx, + enum state_input tous_timeout, + enum state_input tothem_spent, + enum state_input tothem_timeout) +{ + size_t i; + struct htlc *htlcs; + + /* We assume these. */ + assert(tous_timeout == BITCOIN_HTLC_TOUS_TIMEOUT); + assert(tothem_spent == BITCOIN_HTLC_TOTHEM_SPENT); + assert(tothem_timeout == BITCOIN_HTLC_TOTHEM_TIMEOUT); + + /* It's what our peer thinks is current... */ + if (!peer->other->num_htlcs_to_them && !peer->other->num_htlcs_to_us) + return false; + + assert(peer->num_live_htlcs_to_us + peer->other->num_htlcs_to_them + <= ARRAY_SIZE(peer->live_htlcs_to_us)); + assert(peer->num_live_htlcs_to_them + peer->other->num_htlcs_to_us + <= ARRAY_SIZE(peer->live_htlcs_to_them)); + + /* Copy from other peer, but reverse perspective */ + htlcs = peer->live_htlcs_to_us + peer->num_live_htlcs_to_us; + memcpy(htlcs, peer->other->htlcs_to_them, + peer->other->num_htlcs_to_them * sizeof(peer->htlcs_to_us[0])); + for (i = 0; i < peer->other->num_htlcs_to_them; i++) { + assert(htlcs[i].to_them); + htlcs[i].to_them = false; + } + + htlcs = peer->live_htlcs_to_them + peer->num_live_htlcs_to_them; + memcpy(htlcs, + peer->other->htlcs_to_us, + peer->other->num_htlcs_to_us * sizeof(peer->htlcs_to_them[0])); + for (i = 0; i < peer->other->num_htlcs_to_us; i++) { + assert(!htlcs[i].to_them); + htlcs[i].to_them = true; + } + + peer->num_live_htlcs_to_us += peer->other->num_htlcs_to_them; + peer->num_live_htlcs_to_them += peer->other->num_htlcs_to_us; + /* Can happen if we were finished, then new commit tx */ + remove_event_(&peer->core.event_notifies, INPUT_NO_MORE_HTLCS); + + return true; +} + +void peer_unwatch_htlc_output(struct peer *peer, + const struct htlc *htlc, + enum state_input all_done) +{ + const struct htlc *h; + + /* We assume this. */ + assert(all_done == INPUT_NO_MORE_HTLCS); + + h = find_live_htlc(peer, htlc->id); + + /* That can fail, when we see them spend (and thus stop + * watching) after we've timed out, then our return tx wins + * and gets buried. */ + if (h) { + remove_htlc(peer->live_htlcs_to_us, + &peer->num_live_htlcs_to_us, + peer->live_htlcs_to_them, + &peer->num_live_htlcs_to_them, + ARRAY_SIZE(peer->live_htlcs_to_us), + h); + + /* If that was last, fire INPUT_NO_MORE_HTLCS */ + if (!outstanding_htlc_watches(peer)) + add_event(peer, all_done); + } +} + +void peer_unwatch_all_htlc_outputs(struct peer *peer) +{ + /* This can happen if we get in front of INPUT_NO_MORE_HTLCS */ + if (!outstanding_htlc_watches(peer) + && !have_event(peer->core.event_notifies, INPUT_NO_MORE_HTLCS)) + report_trail(peer->trail, "unwatching all with no htlcs?"); + + peer->num_htlc_spends_to_us = 0; + peer->num_htlc_spends_to_them = 0; + peer->num_live_htlcs_to_us = 0; + peer->num_live_htlcs_to_them = 0; +} + +void peer_watch_htlc_spend(struct peer *peer, + const struct bitcoin_tx *tx, + const struct htlc *htlc, + enum state_input done) +{ + struct htlc *h = find_live_htlc(peer, htlc_id_from_tx(tx)); + + add_htlc(peer->htlc_spends_to_us, &peer->num_htlc_spends_to_us, + peer->htlc_spends_to_them, + &peer->num_htlc_spends_to_them, + ARRAY_SIZE(peer->htlc_spends_to_us), + h); + + /* We assume this */ + if (h->to_them) + assert(done == BITCOIN_HTLC_RETURN_SPEND_DONE); + else + assert(done == BITCOIN_HTLC_FULFILL_SPEND_DONE); +} + +void peer_unwatch_htlc_spend(struct peer *peer, + const struct htlc *htlc, + enum state_input all_done) +{ + struct htlc *h = find_htlc_spend(peer, htlc->id); + + assert(all_done == INPUT_NO_MORE_HTLCS); + remove_htlc(peer->htlc_spends_to_us, + &peer->num_htlc_spends_to_us, + peer->htlc_spends_to_them, + &peer->num_htlc_spends_to_them, + ARRAY_SIZE(peer->htlc_spends_to_us), + h); + + if (!outstanding_htlc_watches(peer)) + add_event(peer, all_done); +} + void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt) { const char *str = (const char *)pkt; @@ -1471,159 +1482,6 @@ void peer_tx_revealed_r_value(struct peer *peer, add_rval(peer, htlc->id); } -/* We apply them backwards, which helps our assertions. It's not actually - * required. */ -static const char *apply_effects(struct peer *peer, - const struct state_effect *effect, - uint64_t *effects) -{ - const struct htlc *h; - - if (!effect) - return NULL; - - if (effect->next) { - const char *problem = apply_effects(peer, effect->next, - effects); - if (problem) - return problem; - } - - if (*effects & (1ULL << effect->etype)) - return tal_fmt(NULL, "Effect %u twice", effect->etype); - *effects |= (1ULL << effect->etype); - - switch (effect->etype) { - case STATE_EFFECT_watch: - /* We can have multiple steals or spendtheirs - in flight, so make exceptions for - BITCOIN_STEAL_DONE/BITCOIN_SPEND_THEIRS_DONE */ - if (peer->core.event_notifies & (1ULL << BITCOIN_STEAL_DONE) - & effect->u.watch->events) - remove_event(&effect->u.watch->events, BITCOIN_STEAL_DONE); - - if (peer->core.event_notifies - & (1ULL << BITCOIN_SPEND_THEIRS_DONE) - & effect->u.watch->events) - remove_event(&effect->u.watch->events, - BITCOIN_SPEND_THEIRS_DONE); - - if (peer->core.event_notifies & effect->u.watch->events) - return "event set twice"; - peer->core.event_notifies |= effect->u.watch->events; - break; - case STATE_EFFECT_unwatch: - if ((peer->core.event_notifies & effect->u.unwatch->events) - != effect->u.unwatch->events) - return "unset event unwatched"; - peer->core.event_notifies &= ~effect->u.unwatch->events; - break; - case STATE_EFFECT_close_timeout: - add_event(&peer->core.event_notifies, - effect->u.close_timeout); - /* We assume this. */ - assert(effect->u.close_timeout - == INPUT_CLOSE_COMPLETE_TIMEOUT); - break; - case STATE_EFFECT_watch_htlcs: - assert(peer->num_live_htlcs_to_us - + effect->u.watch_htlcs->num_htlcs_to_us - <= ARRAY_SIZE(peer->live_htlcs_to_us)); - assert(peer->num_live_htlcs_to_them - + effect->u.watch_htlcs->num_htlcs_to_them - <= ARRAY_SIZE(peer->live_htlcs_to_them)); - memcpy(peer->live_htlcs_to_us + peer->num_live_htlcs_to_us, - effect->u.watch_htlcs->htlcs_to_us, - effect->u.watch_htlcs->num_htlcs_to_us - * sizeof(effect->u.watch_htlcs->htlcs_to_us[0])); - memcpy(peer->live_htlcs_to_them + peer->num_live_htlcs_to_them, - effect->u.watch_htlcs->htlcs_to_them, - effect->u.watch_htlcs->num_htlcs_to_them - * sizeof(effect->u.watch_htlcs->htlcs_to_them[0])); - peer->num_live_htlcs_to_us - += effect->u.watch_htlcs->num_htlcs_to_us; - peer->num_live_htlcs_to_them - += effect->u.watch_htlcs->num_htlcs_to_them; - /* Can happen if we were finished, then new commit tx */ - remove_event_(&peer->core.event_notifies, INPUT_NO_MORE_HTLCS); - break; - case STATE_EFFECT_unwatch_htlc: - /* Unwatch all? */ - if (effect->u.unwatch_htlc->id == -1) { - /* This can happen if we get in front of - * INPUT_NO_MORE_HTLCS */ - if (!outstanding_htlc_watches(peer) - && !have_event(peer->core.event_notifies, - INPUT_NO_MORE_HTLCS)) - return "unwatching all with no htlcs?"; - peer->num_htlc_spends_to_us = 0; - peer->num_htlc_spends_to_them = 0; - peer->num_live_htlcs_to_us = 0; - peer->num_live_htlcs_to_them = 0; - } else { - const struct htlc *h; - - h = find_live_htlc(peer, effect->u.unwatch_htlc->id); - - /* That can fail, when we see them spend (and - * thus stop watching) after we've timed out, - * then our return tx wins and gets buried. */ - if (h) { - remove_htlc(peer->live_htlcs_to_us, - &peer->num_live_htlcs_to_us, - peer->live_htlcs_to_them, - &peer->num_live_htlcs_to_them, - ARRAY_SIZE(peer->live_htlcs_to_us), - h); - - /* If that was last, fire INPUT_NO_MORE_HTLCS */ - if (!outstanding_htlc_watches(peer)) { - assert(effect->u.unwatch_htlc->all_done - == INPUT_NO_MORE_HTLCS); - add_event(&peer->core.event_notifies, - effect->u.unwatch_htlc->all_done); - } - } - } - break; - case STATE_EFFECT_watch_htlc_spend: - h = find_live_htlc(peer, effect->u.watch_htlc_spend->id); - add_htlc(peer->htlc_spends_to_us, &peer->num_htlc_spends_to_us, - peer->htlc_spends_to_them, - &peer->num_htlc_spends_to_them, - ARRAY_SIZE(peer->htlc_spends_to_us), - h); - - /* We assume this */ - if (h->to_them) - assert(effect->u.watch_htlc_spend->done - == BITCOIN_HTLC_RETURN_SPEND_DONE); - else - assert(effect->u.watch_htlc_spend->done - == BITCOIN_HTLC_FULFILL_SPEND_DONE); - break; - case STATE_EFFECT_unwatch_htlc_spend: - h = find_htlc_spend(peer, effect->u.unwatch_htlc_spend->id); - remove_htlc(peer->htlc_spends_to_us, - &peer->num_htlc_spends_to_us, - peer->htlc_spends_to_them, - &peer->num_htlc_spends_to_them, - ARRAY_SIZE(peer->htlc_spends_to_us), - h); - if (!outstanding_htlc_watches(peer)) { - assert(effect->u.unwatch_htlc_spend->done - == INPUT_NO_MORE_HTLCS); - add_event(&peer->core.event_notifies, - effect->u.unwatch_htlc_spend->done); - } - break; - default: - return tal_fmt(NULL, "Unknown effect %u", effect->etype); - } - - return NULL; -} - static const char *check_changes(const struct peer *old, struct peer *new, enum state_input input) { @@ -1661,16 +1519,12 @@ static const char *check_changes(const struct peer *old, struct peer *new, return NULL; } -static const char *apply_all_effects(const struct peer *old, +static const char *check_all_effects(const struct peer *old, enum command_status cstatus, enum state_input input, struct peer *peer, - const struct state_effect *effect, Pkt *output) { - const char *problem; - uint64_t effects = 0; - if (cstatus != CMD_NONE) { assert(peer->core.current_command != INPUT_NONE); /* We should only requeue HTLCs if we're lowprio */ @@ -1717,11 +1571,17 @@ static const char *apply_all_effects(const struct peer *old, peer->pkt_data[peer->core.num_outputs++] = htlc_id_from_pkt(output); } - - problem = apply_effects(peer, effect, &effects); - if (!problem) - problem = check_changes(old, peer, input); - return problem; + + if (peer->state >= STATE_CLOSE_WAIT_STEAL + && peer->state <= STATE_CLOSE_WAIT_STEAL_SPENDTHEM_CLOSE_SPENDOURS_WITH_HTLCS) { + if (STATE_TO_BITS(peer->state) & STATE_CLOSE_HTLCS_BIT) { + if (!outstanding_htlc_watches(peer) + && !have_event(peer->core.event_notifies, INPUT_NO_MORE_HTLCS)) + return "CLOSE_HTLCS with no outstanding watches?"; + } + } + + return check_changes(old, peer, input); } static void eliminate_input(enum state_input **inputs, enum state_input in) @@ -1958,7 +1818,7 @@ static void try_input(const struct peer *peer, add_dot(&hist->edges, oldstr, newstr, i, output); } - problem = apply_all_effects(peer, cstatus, i, ©, effect, output); + problem = check_all_effects(peer, cstatus, i, ©, output); update_trail(&t, ©, output); if (problem) report_trail(&t, problem); @@ -2069,7 +1929,7 @@ static void activate_event(struct peer *peer, enum state_input i) break; case BITCOIN_ANCHOR_TIMEOUT: /* Can't sent DEPTHOK */ - remove_event(&peer->core.event_notifies, BITCOIN_ANCHOR_DEPTHOK); + remove_event(peer, BITCOIN_ANCHOR_DEPTHOK); break; /* And of the "done" cases means we won't give the others. */ case BITCOIN_SPEND_THEIRS_DONE: @@ -2160,7 +2020,7 @@ static void run_peer(const struct peer *peer, /* Don't re-fire most events */ if (!can_refire(i)) - remove_event(©.core.event_notifies, i); + remove_event(©, i); activate_event(©, i); try_input(©, i, idata, normalpath, errorpath, prev_trail, hist);