diff --git a/state.c b/state.c index 43049c14f..a79089895 100644 --- a/state.c +++ b/state.c @@ -94,7 +94,6 @@ enum command_status state(const tal_t *ctx, struct bitcoin_tx *tx; Pkt *err; struct htlc_watch *htlcs; - struct htlc_progress *htlcprog; enum command_status cstatus = CMD_NONE; /* NULL-terminated linked list. */ @@ -376,19 +375,14 @@ enum command_status state(const tal_t *ctx, add_effect(effect, send_pkt, pkt_htlc_update(ctx, peer, idata->htlc_prog)); - add_effect(effect, htlc_in_progress, idata->htlc_prog); change_peer_cond(peer, PEER_CMD_OK, PEER_BUSY); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_HTLC_ACCEPT)); } else if (input_is(input, CMD_SEND_HTLC_FULFILL)) { /* We are to send an HTLC fulfill. */ - /* This gives us the r value (FIXME: type!) */ - add_effect(effect, r_value, - r_value_from_cmd(ctx, peer, idata->htlc)); add_effect(effect, send_pkt, pkt_htlc_fulfill(ctx, peer, idata->htlc_prog)); - add_effect(effect, htlc_in_progress, idata->htlc_prog); change_peer_cond(peer, PEER_CMD_OK, PEER_BUSY); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_UPDATE_ACCEPT)); @@ -397,7 +391,6 @@ enum command_status state(const tal_t *ctx, add_effect(effect, send_pkt, pkt_htlc_timedout(ctx, peer, idata->htlc_prog)); - add_effect(effect, htlc_in_progress, idata->htlc_prog); change_peer_cond(peer, PEER_CMD_OK, PEER_BUSY); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_UPDATE_ACCEPT)); @@ -406,7 +399,6 @@ enum command_status state(const tal_t *ctx, add_effect(effect, send_pkt, pkt_htlc_routefail(ctx, peer, idata->htlc_prog)); - add_effect(effect, htlc_in_progress, idata->htlc_prog); change_peer_cond(peer, PEER_CMD_OK, PEER_BUSY); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_UPDATE_ACCEPT)); @@ -440,16 +432,11 @@ enum command_status state(const tal_t *ctx, case STATE_WAIT_FOR_HTLC_ACCEPT_HIGHPRIO: /* HTLCs can also evoke a refusal. */ if (input_is(input, PKT_UPDATE_DECLINE_HTLC)) { - add_effect(effect, htlc_abandon, true); + peer_htlc_declined(peer, idata->pkt); complete_cmd(peer, &cstatus, CMD_FAIL); /* No update means no priority change. */ return next_state(peer, cstatus, prio(peer->state, STATE_NORMAL)); - /* They can't close with an HTLC, so only possible here */ - } else if (input_is(input, PKT_CLOSE)) { - complete_cmd(peer, &cstatus, CMD_FAIL); - add_effect(effect, htlc_abandon, true); - goto accept_closing; } /* Fall thru */ case STATE_WAIT_FOR_UPDATE_ACCEPT_LOWPRIO: @@ -460,8 +447,8 @@ enum command_status state(const tal_t *ctx, return cstatus; /* Otherwise, process their request first: defer ours */ + peer_htlc_ours_deferred(peer); complete_cmd(peer, &cstatus, CMD_REQUEUE); - add_effect(effect, htlc_abandon, true); /* Stay busy, since we're processing theirs. */ change_peer_cond(peer, PEER_CMD_OK, PEER_BUSY); goto accept_htlc_update; @@ -471,8 +458,8 @@ enum command_status state(const tal_t *ctx, return cstatus; /* Otherwise, process their request first: defer ours */ + peer_htlc_ours_deferred(peer); complete_cmd(peer, &cstatus, CMD_REQUEUE); - add_effect(effect, htlc_abandon, true); /* Stay busy, since we're processing theirs. */ change_peer_cond(peer, PEER_CMD_OK, PEER_BUSY); goto accept_htlc_fulfill; @@ -482,8 +469,8 @@ enum command_status state(const tal_t *ctx, return cstatus; /* Otherwise, process their request first: defer ours */ + peer_htlc_ours_deferred(peer); complete_cmd(peer, &cstatus, CMD_REQUEUE); - add_effect(effect, htlc_abandon, true); /* Stay busy, since we're processing theirs. */ change_peer_cond(peer, PEER_CMD_OK, PEER_BUSY); goto accept_htlc_timedout; @@ -493,77 +480,87 @@ enum command_status state(const tal_t *ctx, return cstatus; /* Otherwise, process their request first: defer ours */ + peer_htlc_ours_deferred(peer); complete_cmd(peer, &cstatus, CMD_REQUEUE); - add_effect(effect, htlc_abandon, true); /* Stay busy, since we're processing theirs. */ change_peer_cond(peer, PEER_CMD_OK, PEER_BUSY); goto accept_htlc_routefail; } else if (input_is(input, PKT_UPDATE_ACCEPT)) { struct signature *sig; err = accept_pkt_update_accept(ctx, peer, idata->pkt, - &sig, effect); + &sig); if (err) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); - add_effect(effect, htlc_abandon, true); goto err_start_unilateral_close; } add_effect(effect, update_theirsig, sig); add_effect(effect, send_pkt, pkt_update_signature(ctx, peer)); /* HTLC is signed (though old tx not revoked yet!) */ - add_effect(effect, htlc_fulfill, true); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_UPDATE_COMPLETE)); } else if (input_is(input, BITCOIN_ANCHOR_UNSPENT)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); - add_effect(effect, htlc_abandon, true); goto anchor_unspent; } else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); - add_effect(effect, htlc_abandon, true); goto them_unilateral; } else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); - add_effect(effect, htlc_abandon, true); goto old_commit_spotted; } else if (input_is(input, CMD_CLOSE)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); - add_effect(effect, htlc_abandon, true); goto start_closing; - } else if (input_is_pkt(input)) { + } else if (input_is(input, PKT_CLOSE)) { + peer_htlc_aborted(peer); + complete_cmd(peer, &cstatus, CMD_FAIL); + goto accept_closing; + } else if (input_is_pkt(input)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); - add_effect(effect, htlc_abandon, true); goto unexpected_pkt; } break; case STATE_WAIT_FOR_UPDATE_COMPLETE_LOWPRIO: case STATE_WAIT_FOR_UPDATE_COMPLETE_HIGHPRIO: if (input_is(input, PKT_UPDATE_COMPLETE)) { - err = accept_pkt_update_complete(ctx, peer, idata->pkt, - effect); + err = accept_pkt_update_complete(ctx, peer, idata->pkt); if (err) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); goto err_start_unilateral_close; } + peer_htlc_done(peer); complete_cmd(peer, &cstatus, CMD_SUCCESS); return next_state(peer, cstatus, toggle_prio(peer->state, STATE_NORMAL)); } else if (input_is(input, BITCOIN_ANCHOR_UNSPENT)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); goto anchor_unspent; } else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); goto them_unilateral; } else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); goto old_commit_spotted; } else if (input_is(input, PKT_CLOSE)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); goto accept_closing; } else if (input_is(input, CMD_CLOSE)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); goto start_closing; } else if (input_is_pkt(input)) { + peer_htlc_aborted(peer); complete_cmd(peer, &cstatus, CMD_FAIL); goto unexpected_pkt; } @@ -573,36 +570,37 @@ enum command_status state(const tal_t *ctx, if (input_is(input, PKT_UPDATE_SIGNATURE)) { struct signature *sig; err = accept_pkt_update_signature(ctx, peer, idata->pkt, - &sig, effect); + &sig); if (err) { - add_effect(effect, htlc_abandon, true); + peer_htlc_aborted(peer); goto err_start_unilateral_close; } add_effect(effect, update_theirsig, sig); add_effect(effect, send_pkt, pkt_update_complete(ctx, peer)); - add_effect(effect, htlc_fulfill, true); + + peer_htlc_done(peer); change_peer_cond(peer, PEER_BUSY, PEER_CMD_OK); /* Toggle between high and low priority states. */ return next_state(peer, cstatus, toggle_prio(peer->state, STATE_NORMAL)); } else if (input_is(input, BITCOIN_ANCHOR_UNSPENT)) { - add_effect(effect, htlc_abandon, true); + peer_htlc_aborted(peer); goto anchor_unspent; } else if (input_is(input, BITCOIN_ANCHOR_THEIRSPEND)) { - add_effect(effect, htlc_abandon, true); + peer_htlc_aborted(peer); goto them_unilateral; } else if (input_is(input, BITCOIN_ANCHOR_OTHERSPEND)) { - add_effect(effect, htlc_abandon, true); + peer_htlc_aborted(peer); goto old_commit_spotted; } else if (input_is(input, CMD_CLOSE)) { - add_effect(effect, htlc_abandon, true); + peer_htlc_aborted(peer); goto start_closing; } else if (input_is(input, PKT_CLOSE)) { - add_effect(effect, htlc_abandon, true); + peer_htlc_aborted(peer); goto accept_closing; } else if (input_is_pkt(input)) { - add_effect(effect, htlc_abandon, true); + peer_htlc_aborted(peer); goto unexpected_pkt; } break; @@ -780,8 +778,7 @@ enum command_status state(const tal_t *ctx, BITS_TO_STATE(bits)); } else if (input_is(input, BITCOIN_HTLC_TOTHEM_SPENT)) { /* They revealed R value. */ - add_effect(effect, r_value, - bitcoin_r_value(ctx, idata->htlc)); + peer_tx_revealed_r_value(peer, idata->btc); /* We don't care any more. */ add_effect(effect, unwatch_htlc, htlc_unwatch(ctx, idata->htlc, @@ -807,10 +804,6 @@ enum command_status state(const tal_t *ctx, tx = bitcoin_htlc_spend(ctx, peer, idata->htlc); - /* This gives us the r value. */ - add_effect(effect, r_value, - r_value_from_cmd(ctx, peer, - idata->htlc)); /* Spend it... */ add_effect(effect, broadcast_tx, tx); /* We're done when it gets buried. */ @@ -1047,51 +1040,43 @@ them_unilateral: return next_state(peer, cstatus, STATE_CLOSE_WAIT_SPENDTHEM); accept_htlc_update: - err = accept_pkt_htlc_update(ctx, peer, idata->pkt, &decline, &htlcprog, - effect); + err = accept_pkt_htlc_update(ctx, peer, idata->pkt, &decline, effect); if (err) goto err_start_unilateral_close; if (decline) { add_effect(effect, send_pkt, decline); + peer_htlc_declined(peer, decline); /* No update means no priority change. */ change_peer_cond(peer, PEER_BUSY, PEER_CMD_OK); /* We may already be in STATE_NORMAL */ return next_state_nocheck(peer, cstatus, prio(peer->state, STATE_NORMAL)); } - add_effect(effect, htlc_in_progress, htlcprog); add_effect(effect, send_pkt, pkt_update_accept(ctx, peer)); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_UPDATE_SIG)); accept_htlc_routefail: - err = accept_pkt_htlc_routefail(ctx, peer, idata->pkt, &htlcprog, - effect); + err = accept_pkt_htlc_routefail(ctx, peer, idata->pkt, effect); if (err) goto err_start_unilateral_close; - add_effect(effect, htlc_in_progress, htlcprog); add_effect(effect, send_pkt, pkt_update_accept(ctx, peer)); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_UPDATE_SIG)); accept_htlc_timedout: - err = accept_pkt_htlc_timedout(ctx, peer, idata->pkt, &htlcprog, - effect); + err = accept_pkt_htlc_timedout(ctx, peer, idata->pkt, effect); if (err) goto err_start_unilateral_close; - add_effect(effect, htlc_in_progress, htlcprog); add_effect(effect, send_pkt, pkt_update_accept(ctx, peer)); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_UPDATE_SIG)); accept_htlc_fulfill: - err = accept_pkt_htlc_fulfill(ctx, peer, idata->pkt, &htlcprog, - effect); + err = accept_pkt_htlc_fulfill(ctx, peer, idata->pkt); if (err) goto err_start_unilateral_close; - add_effect(effect, htlc_in_progress, htlcprog); add_effect(effect, send_pkt, pkt_update_accept(ctx, peer)); - add_effect(effect, r_value, r_value_from_pkt(ctx, idata->pkt)); return next_state(peer, cstatus, prio(peer->state, STATE_WAIT_FOR_UPDATE_SIG)); diff --git a/state.h b/state.h index 7682f63d2..660fed890 100644 --- a/state.h +++ b/state.h @@ -13,11 +13,7 @@ enum state_effect_type { STATE_EFFECT_unwatch, /* FIXME: Use a watch for this?. */ STATE_EFFECT_close_timeout, - STATE_EFFECT_htlc_in_progress, STATE_EFFECT_update_theirsig, - STATE_EFFECT_htlc_abandon, - STATE_EFFECT_htlc_fulfill, - STATE_EFFECT_r_value, /* FIXME: Combine into watches? */ STATE_EFFECT_watch_htlcs, STATE_EFFECT_unwatch_htlc, @@ -51,21 +47,9 @@ struct state_effect { /* Set a timeout for close tx. */ enum state_input close_timeout; - /* HTLC we're working on. */ - struct htlc_progress *htlc_in_progress; - /* Their signature for the new commit tx. */ struct signature *update_theirsig; - /* Stop working on HTLC. */ - bool htlc_abandon; - - /* Finished working on HTLC. */ - bool htlc_fulfill; - - /* R value. */ - const struct htlc_rval *r_value; - /* HTLC outputs to watch. */ const struct htlc_watch *watch_htlcs; @@ -132,6 +116,35 @@ struct signature; /* Inform peer have an unexpected packet. */ void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt); +/* Current HTLC management. + * The "current" htlc is set before sending CMD_SEND_HTLC_*, or by + * accept_pkt_htlc_*. + * + * After that the state machine manages the current htlc, eventually giving one + * of the following calls (which should reset the current HTLC): + * + * - peer_htlc_declined: sent PKT_UPDATE_DECLINE_HTLC. + * - peer_htlc_ours_deferred: their update was higher priority, retry later. + * - peer_htlc_added: a new HTLC was added successfully. + * - peer_htlc_fulfilled: an existing HTLC was fulfilled successfully. + * - peer_htlc_timedout: an existing HTLC was timed out successfully. + * - peer_htlc_routefail: an existing HTLC failed to route. + * - peer_htlc_aborted: eg. comms error + */ + +/* Someone declined our HTLC: details in pkt (we will also get CMD_FAIL) */ +void peer_htlc_declined(struct peer *peer, const Pkt *pkt); +/* Called when their update overrides our update cmd. */ +void peer_htlc_ours_deferred(struct peer *peer); +/* Successfully added/fulfilled/timedout/routefail an HTLC. */ +void peer_htlc_done(struct peer *peer); +/* Someone aborted an existing HTLC. */ +void peer_htlc_aborted(struct peer *peer); + +/* An on-chain transaction revealed an R value. */ +void peer_tx_revealed_r_value(struct peer *peer, + const struct bitcoin_event *btc); + /* Create various kinds of packets, allocated off @ctx */ Pkt *pkt_open(const tal_t *ctx, const struct peer *peer, OpenChannel__AnchorOffer anchor); @@ -171,40 +184,32 @@ Pkt *accept_pkt_open_commit_sig(const tal_t *ctx, struct state_effect **effect); Pkt *accept_pkt_htlc_update(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, + struct peer *peer, const Pkt *pkt, Pkt **decline, - struct htlc_progress **htlcprog, struct state_effect **effect); Pkt *accept_pkt_htlc_routefail(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct htlc_progress **htlcprog, + struct peer *peer, const Pkt *pkt, struct state_effect **effect); Pkt *accept_pkt_htlc_timedout(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct htlc_progress **htlcprog, + struct peer *peer, const Pkt *pkt, struct state_effect **effect); Pkt *accept_pkt_htlc_fulfill(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct htlc_progress **htlcprog, - struct state_effect **effect); + struct peer *peer, const Pkt *pkt); Pkt *accept_pkt_update_accept(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct signature **sig, - struct state_effect **effect); + struct peer *peer, const Pkt *pkt, + struct signature **sig); Pkt *accept_pkt_update_complete(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct state_effect **effect); + struct peer *peer, const Pkt *pkt); Pkt *accept_pkt_update_signature(const tal_t *ctx, - const struct peer *peer, + struct peer *peer, const Pkt *pkt, - struct signature **sig, - struct state_effect **effect); + struct signature **sig); Pkt *accept_pkt_close(const tal_t *ctx, const struct peer *peer, const Pkt *pkt, @@ -410,10 +415,4 @@ struct bitcoin_tx *bitcoin_htlc_spend(const tal_t *ctx, const struct peer *peer, const struct htlc *htlc); -struct htlc_rval *r_value_from_cmd(const tal_t *ctx, - const struct peer *peer, - const struct htlc *htlc); -struct htlc_rval *bitcoin_r_value(const tal_t *ctx, const struct htlc *htlc); -struct htlc_rval *r_value_from_pkt(const tal_t *ctx, const Pkt *pkt); - #endif /* LIGHTNING_STATE_H */ diff --git a/test/test_state_coverage.c b/test/test_state_coverage.c index b99679bb0..cd35f972e 100644 --- a/test/test_state_coverage.c +++ b/test/test_state_coverage.c @@ -119,6 +119,9 @@ struct peer { /* id == -1 if none currently. */ struct htlc_progress current_htlc; + + /* Transitory: True if we just declined an HTLC. */ + bool htlc_declined; unsigned int num_htlcs_to_them, num_htlcs_to_us; struct htlc htlcs_to_them[MAX_HTLCS], htlcs_to_us[MAX_HTLCS]; @@ -479,6 +482,7 @@ static unsigned int htlc_id_from_pkt(const Pkt *pkt) static Pkt *htlc_pkt(const tal_t *ctx, const char *prefix, unsigned int id) { + assert(id != -1); return (Pkt *)tal_fmt(ctx, "%s: HTLC #%u", prefix, id); } @@ -543,6 +547,48 @@ static struct htlc *find_htlc_spend(const struct peer *peer, return (struct htlc *)h; } +/* FIXME: order functions correctly. */ +static void report_trail(const struct trail *t, const char *problem); + +static void set_current_htlc(struct peer *peer, + unsigned int id, + bool to_them, bool adding) +{ + if (peer->current_htlc.htlc.id != -1) + report_trail(peer->trail, "Already have current htlc"); + + assert(id != -1); + peer->current_htlc.htlc.id = id; + peer->current_htlc.htlc.to_them = to_them; + peer->current_htlc.adding = adding; +} + +static void clear_current_htlc(struct peer *peer) +{ + if (peer->current_htlc.htlc.id == -1) + report_trail(peer->trail, "No current htlc"); + + peer->current_htlc.htlc.id = -1; +} + +static bool rval_known(const struct peer *peer, unsigned int id) +{ + unsigned int i; + + for (i = 0; i < peer->num_rvals_known; i++) + if (peer->rvals_known[i] == id) + return true; + return false; +} + +static void add_rval(struct peer *peer, unsigned int id) +{ + if (!rval_known(peer, id)) { + assert(peer->num_rvals_known < ARRAY_SIZE(peer->rvals_known)); + peer->rvals_known[peer->num_rvals_known++] = id; + } +} + Pkt *pkt_open(const tal_t *ctx, const struct peer *peer, OpenChannel__AnchorOffer anchor) { @@ -590,17 +636,19 @@ Pkt *pkt_htlc_routefail(const tal_t *ctx, const struct peer *peer, Pkt *pkt_update_accept(const tal_t *ctx, const struct peer *peer) { - return new_pkt(ctx, PKT_UPDATE_ACCEPT); + return htlc_pkt(ctx, "PKT_UPDATE_ACCEPT", peer->current_htlc.htlc.id); } Pkt *pkt_update_signature(const tal_t *ctx, const struct peer *peer) { - return new_pkt(ctx, PKT_UPDATE_SIGNATURE); + return htlc_pkt(ctx, "PKT_UPDATE_SIGNATURE", + peer->current_htlc.htlc.id); } Pkt *pkt_update_complete(const tal_t *ctx, const struct peer *peer) { - return new_pkt(ctx, PKT_UPDATE_COMPLETE); + return htlc_pkt(ctx, "PKT_UPDATE_COMPLETE", + peer->current_htlc.htlc.id); } Pkt *pkt_err(const tal_t *ctx, const char *msg) @@ -657,30 +705,26 @@ Pkt *accept_pkt_open_commit_sig(const tal_t *ctx, } Pkt *accept_pkt_htlc_update(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, + struct peer *peer, const Pkt *pkt, Pkt **decline, - struct htlc_progress **htlcprog, struct state_effect **effect) { if (fail(peer, FAIL_ACCEPT_HTLC_UPDATE)) return pkt_err(ctx, "Error inject"); + /* This is the current htlc: If they propose it, it's to us. */ + set_current_htlc(peer, htlc_id_from_pkt(pkt), false, true); + if (fail(peer, FAIL_DECLINE_HTLC)) *decline = new_pkt(ctx, PKT_UPDATE_DECLINE_HTLC); - else { + else *decline = NULL; - *htlcprog = tal(ctx, struct htlc_progress); - /* If they propose it, it's to us. */ - (*htlcprog)->htlc.to_them = false; - (*htlcprog)->htlc.id = htlc_id_from_pkt(pkt); - (*htlcprog)->adding = true; - } + return NULL; } Pkt *accept_pkt_htlc_routefail(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct htlc_progress **htlcprog, + struct peer *peer, const Pkt *pkt, struct state_effect **effect) { unsigned int id = htlc_id_from_pkt(pkt); @@ -692,15 +736,13 @@ Pkt *accept_pkt_htlc_routefail(const tal_t *ctx, /* The shouldn't fail unless it's to them */ assert(h->to_them); - *htlcprog = tal(ctx, struct htlc_progress); - (*htlcprog)->htlc = *h; - (*htlcprog)->adding = false; + /* This is the current htlc */ + set_current_htlc(peer, h->id, h->to_them, false); return NULL; } Pkt *accept_pkt_htlc_timedout(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct htlc_progress **htlcprog, + struct peer *peer, const Pkt *pkt, struct state_effect **effect) { unsigned int id = htlc_id_from_pkt(pkt); @@ -711,17 +753,14 @@ Pkt *accept_pkt_htlc_timedout(const tal_t *ctx, /* The shouldn't timeout unless it's to us */ assert(!h->to_them); - - *htlcprog = tal(ctx, struct htlc_progress); - (*htlcprog)->htlc = *h; - (*htlcprog)->adding = false; + + /* This is the current htlc */ + set_current_htlc(peer, h->id, h->to_them, false); return NULL; } Pkt *accept_pkt_htlc_fulfill(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct htlc_progress **htlcprog, - struct state_effect **effect) + struct peer *peer, const Pkt *pkt) { unsigned int id = htlc_id_from_pkt(pkt); const struct htlc *h = find_htlc(peer, id); @@ -732,17 +771,22 @@ Pkt *accept_pkt_htlc_fulfill(const tal_t *ctx, /* The shouldn't complete unless it's to them */ assert(h->to_them); - *htlcprog = tal(ctx, struct htlc_progress); - (*htlcprog)->htlc = *h; - (*htlcprog)->adding = false; + /* This gives us the r value. */ + add_rval(peer, htlc_id_from_pkt(pkt)); + + /* This is the current htlc */ + set_current_htlc(peer, h->id, h->to_them, false); return NULL; } Pkt *accept_pkt_update_accept(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct signature **sig, - struct state_effect **effect) + struct peer *peer, const Pkt *pkt, + struct signature **sig) { + unsigned int id = htlc_id_from_pkt(pkt); + + assert(id == peer->current_htlc.htlc.id); + if (fail(peer, FAIL_ACCEPT_UPDATE_ACCEPT)) return pkt_err(ctx, "Error inject"); @@ -751,22 +795,30 @@ Pkt *accept_pkt_update_accept(const tal_t *ctx, } Pkt *accept_pkt_update_complete(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct state_effect **effect) + struct peer *peer, const Pkt *pkt) { + unsigned int id = htlc_id_from_pkt(pkt); + + assert(id == peer->current_htlc.htlc.id); + if (fail(peer, FAIL_ACCEPT_UPDATE_COMPLETE)) return pkt_err(ctx, "Error inject"); + return NULL; } Pkt *accept_pkt_update_signature(const tal_t *ctx, - const struct peer *peer, const Pkt *pkt, - struct signature **sig, - struct state_effect **effect) + struct peer *peer, const Pkt *pkt, + struct signature **sig) { + unsigned int id = htlc_id_from_pkt(pkt); + + assert(id == peer->current_htlc.htlc.id); + if (fail(peer, FAIL_ACCEPT_UPDATE_SIGNATURE)) return pkt_err(ctx, "Error inject"); *sig = (struct signature *)tal_strdup(ctx, "from PKT_UPDATE_SIGNATURE"); + return NULL; } @@ -1143,29 +1195,6 @@ struct htlc_rval { unsigned int id; }; -struct htlc_rval *r_value_from_cmd(const tal_t *ctx, - const struct peer *peer, - const struct htlc *htlc) -{ - struct htlc_rval *r = tal(ctx, struct htlc_rval); - r->id = htlc->id; - return r; -} - -struct htlc_rval *bitcoin_r_value(const tal_t *ctx, const struct htlc *htlc) -{ - struct htlc_rval *r = tal(ctx, struct htlc_rval); - r->id = htlc->id; - return r; -} - -struct htlc_rval *r_value_from_pkt(const tal_t *ctx, const Pkt *pkt) -{ - struct htlc_rval *r = tal(ctx, struct htlc_rval); - r->id = htlc_id_from_pkt(pkt); - return r; -} - #include "state.c" #include #include @@ -1186,6 +1215,7 @@ static void peer_init(struct peer *peer, peer->num_htlc_spends_to_them = 0; peer->num_rvals_known = 0; peer->error = NULL; + peer->htlc_declined = false; memset(peer->core.outputs, 0, sizeof(peer->core.outputs)); peer->pkt_data[0] = -1; peer->core.current_command = INPUT_NONE; @@ -1352,6 +1382,21 @@ static void remove_htlc(struct htlc *to_us, unsigned int *num_to_us, (*n)--; } +static void remove_htlc_id(struct peer *peer, unsigned int id) +{ + const struct htlc *h = find_htlc(peer, id); + + if (!h) + report_trail(peer->trail, "Removing nonexistent HTLC?"); + if (h->to_them != peer->current_htlc.htlc.to_them) + report_trail(peer->trail, + "Removing disagreed about to_them"); + remove_htlc(peer->htlcs_to_us, &peer->num_htlcs_to_us, + peer->htlcs_to_them, &peer->num_htlcs_to_them, + ARRAY_SIZE(peer->htlcs_to_us), h); +} + + static bool outstanding_htlc_watches(const struct peer *peer) { return peer->num_live_htlcs_to_us @@ -1360,16 +1405,6 @@ static bool outstanding_htlc_watches(const struct peer *peer) || peer->num_htlc_spends_to_them; } -static bool rval_known(const struct peer *peer, unsigned int id) -{ - unsigned int i; - - for (i = 0; i < peer->num_rvals_known; i++) - if (peer->rvals_known[i] == id) - return true; - return false; -} - void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt) { const char *str = (const char *)pkt; @@ -1382,6 +1417,64 @@ void peer_unexpected_pkt(struct peer *peer, const Pkt *pkt) report_trail(peer->trail, "Unexpected packet"); } +/* Called when their update overrides our update cmd. */ +void peer_htlc_ours_deferred(struct peer *peer) +{ + /* Only happens for HTLC commands of low priority. */ + if (high_priority(peer->state)) + report_trail(peer->trail, "Defer while high priority"); + + if (peer->current_htlc.htlc.id == -1) + report_trail(peer->trail, "Deferred with no current HTLC"); + if (!input_is(peer->core.current_command, CMD_SEND_UPDATE_ANY)) + report_trail(peer->trail, "Deferred their HTLC?"); + + /* FIXME: Expect CMD_REQUEUE */ + clear_current_htlc(peer); +} + +/* Successfully added/fulfilled/timedout/routefail an HTLC. */ +void peer_htlc_done(struct peer *peer) +{ + if (peer->current_htlc.htlc.id == -1) + report_trail(peer->trail, "Adding with no current HTLC"); + + if (peer->current_htlc.adding) { + add_htlc(peer->htlcs_to_us, &peer->num_htlcs_to_us, + peer->htlcs_to_them, &peer->num_htlcs_to_them, + ARRAY_SIZE(peer->htlcs_to_us), + &peer->current_htlc.htlc); + } else { + remove_htlc_id(peer, peer->current_htlc.htlc.id); + } + clear_current_htlc(peer); +} + +/* Someone aborted an existing HTLC update. */ +void peer_htlc_aborted(struct peer *peer) +{ + if (peer->current_htlc.htlc.id == -1) + report_trail(peer->trail, "Abort with no current HTLC"); + clear_current_htlc(peer); +} + +void peer_htlc_declined(struct peer *peer, const Pkt *pkt) +{ + if (peer->current_htlc.htlc.id == -1) + report_trail(peer->trail, "Decline with no current HTLC"); + if (!peer->current_htlc.adding) + report_trail(peer->trail, "Decline but HTLC not marked for add"); + clear_current_htlc(peer); + peer->htlc_declined = true; +} + +void peer_tx_revealed_r_value(struct peer *peer, + const struct bitcoin_event *btc) +{ + const struct htlc *htlc = (struct htlc *)btc; + 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, @@ -1463,60 +1556,8 @@ static const char *apply_effects(struct peer *peer, assert(effect->u.close_timeout == INPUT_CLOSE_COMPLETE_TIMEOUT); break; - case STATE_EFFECT_htlc_in_progress: - if (peer->current_htlc.htlc.id != -1) - return "HTLC already in progress"; - peer->current_htlc = *effect->u.htlc_in_progress; - break; case STATE_EFFECT_update_theirsig: break; - case STATE_EFFECT_htlc_abandon: - if (peer->current_htlc.htlc.id == -1) - return "HTLC not in progress, can't abandon"; - peer->current_htlc.htlc.id = -1; - break; - case STATE_EFFECT_htlc_fulfill: - if (peer->current_htlc.htlc.id == -1) - return "HTLC not in progress, can't complete"; - - if (peer->current_htlc.adding) { - add_htlc(peer->htlcs_to_us, - &peer->num_htlcs_to_us, - peer->htlcs_to_them, - &peer->num_htlcs_to_them, - ARRAY_SIZE(peer->htlcs_to_us), - &peer->current_htlc.htlc); - } else { - const struct htlc *h; - h = find_htlc(peer, - peer->current_htlc.htlc.id); - if (!h) - return "Removing nonexistent HTLC?"; - if (h->to_them != - peer->current_htlc.htlc.to_them) - return "Removing disagreed about to_them"; - remove_htlc(peer->htlcs_to_us, &peer->num_htlcs_to_us, - peer->htlcs_to_them, - &peer->num_htlcs_to_them, - ARRAY_SIZE(peer->htlcs_to_us), - h); - } - peer->current_htlc.htlc.id = -1; - break; - case STATE_EFFECT_r_value: - /* We set r_value when they spend an HTLC, so - * we can set this multiple times (multiple commit - * txs) */ - if (!rval_known(peer, effect->u.r_value->id)) { - if (peer->num_rvals_known - == ARRAY_SIZE(peer->rvals_known)) - return "Too many rvals"; - - peer->rvals_known[peer->num_rvals_known++] - = effect->u.r_value->id; - } - break; - case STATE_EFFECT_watch_htlcs: assert(peer->num_live_htlcs_to_us + effect->u.watch_htlcs->num_htlcs_to_us @@ -1632,6 +1673,9 @@ static const char *check_changes(const struct peer *old, struct peer *new, return tal_fmt(NULL, "cond CLOSE with pending command %s", input_name(new->core.current_command)); + if (new->current_htlc.htlc.id != -1) + return tal_fmt(NULL, + "cond CLOSE with pending htlc"); } if (new->cond == PEER_CLOSED) { /* FIXME: Move to state core */ @@ -1646,6 +1690,7 @@ static const char *check_changes(const struct peer *old, struct peer *new, && new->cond != PEER_CLOSED) return "packets still open after error pkt"; } + return NULL; } @@ -1663,10 +1708,25 @@ static const char *apply_all_effects(const struct peer *old, if (cstatus != CMD_NONE) { assert(peer->core.current_command != INPUT_NONE); /* We should only requeue HTLCs if we're lowprio */ - if (cstatus == CMD_REQUEUE) - assert(!high_priority(old->state) - && input_is(peer->core.current_command, - CMD_SEND_UPDATE_ANY)); + if (cstatus == CMD_REQUEUE) { + if (high_priority(old->state)) + return "CMD_REQUEUE despite high prio state"; + else if (!input_is(peer->core.current_command, + CMD_SEND_UPDATE_ANY)) + return tal_fmt(NULL, "CMD_REQUEUE on cmd %s", + input_name(peer->core.current_command)); + /* We expect to be replaced by their HTLC + * (unless we inject an error!). */ + if (peer->current_htlc.htlc.id == -1 + && peer->cond != PEER_CLOSED + && !peer->htlc_declined) + return tal_fmt(NULL, "CMD_REQUEUE but no new htlc?"); + } else { + /* Expect no HTLCs in other cases. */ + if (peer->current_htlc.htlc.id != -1) + return tal_fmt(NULL, "%s but still have htlc?", + cstatus_name(cstatus)); + } peer->core.current_command = INPUT_NONE; } @@ -1939,6 +1999,8 @@ static void try_input(const struct peer *peer, if (strstarts(state_name(copy.state), "STATE_UNUSED")) report_trail(&t, "Unused state"); + /* Re-set htlc_declined */ + copy.htlc_declined = false; /* Record any output. */ if (output) { @@ -2149,6 +2211,9 @@ static void run_peer(const struct peer *peer, if (peer->cond == PEER_CMD_OK) { unsigned int i; + /* Shouldn't be currently doing an HTLC. */ + assert(copy.current_htlc.htlc.id == -1); + /* Add a new HTLC if not at max. */ if (copy.num_htlcs_to_them < MAX_HTLCS) { copy.core.current_command = CMD_SEND_HTLC_UPDATE; @@ -2156,11 +2221,17 @@ static void run_peer(const struct peer *peer, idata->htlc_prog->adding = true; idata->htlc_prog->htlc.to_them = true; idata->htlc_prog->htlc.id = next_htlc_id(); - + + set_current_htlc(©, + idata->htlc_prog->htlc.id, + idata->htlc_prog->htlc.to_them, + idata->htlc_prog->adding); try_input(©, copy.core.current_command, idata, normalpath, errorpath, prev_trail, hist); idata->htlc_prog = tal_free(idata->htlc_prog); + /* If it was requeued, may already be reset. */ + copy.current_htlc.htlc.id = -1; } /* We can complete or routefail an HTLC they offered */ @@ -2169,6 +2240,11 @@ static void run_peer(const struct peer *peer, idata->htlc_prog->htlc = peer->htlcs_to_us[i]; idata->htlc_prog->adding = false; + set_current_htlc(©, + idata->htlc_prog->htlc.id, + idata->htlc_prog->htlc.to_them, + idata->htlc_prog->adding); + /* Only send this once. */ if (!rval_known(peer, idata->htlc_prog->htlc.id)) { copy.core.current_command @@ -2181,6 +2257,8 @@ static void run_peer(const struct peer *peer, try_input(©, copy.core.current_command, idata, normalpath, errorpath, prev_trail, hist); + /* If it was requeued, may already be reset. */ + copy.current_htlc.htlc.id = -1; } /* We can timeout an HTLC we offered. */ @@ -2189,10 +2267,16 @@ static void run_peer(const struct peer *peer, idata->htlc_prog->htlc = peer->htlcs_to_them[i]; idata->htlc_prog->adding = false; + set_current_htlc(©, + idata->htlc_prog->htlc.id, + idata->htlc_prog->htlc.to_them, + idata->htlc_prog->adding); copy.core.current_command = CMD_SEND_HTLC_TIMEDOUT; try_input(©, copy.core.current_command, idata, normalpath, errorpath, prev_trail, hist); + /* If it was requeued, may already be reset. */ + copy.current_htlc.htlc.id = -1; } /* Restore current_command */ @@ -2214,10 +2298,11 @@ static void run_peer(const struct peer *peer, } for (i = 0; i < peer->num_live_htlcs_to_them; i++) { - idata->htlc = (struct htlc *)©.live_htlcs_to_them[i]; + idata->btc = (struct bitcoin_event *)©.live_htlcs_to_them[i]; try_input(©, BITCOIN_HTLC_TOTHEM_SPENT, idata, normalpath, errorpath, prev_trail, hist); + idata->htlc = (struct htlc *)©.live_htlcs_to_them[i]; try_input(©, BITCOIN_HTLC_TOTHEM_TIMEOUT, idata, normalpath, errorpath, prev_trail, hist);