From cc16f4662109590daf9f42d6bde34a048775c4f9 Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Tue, 15 Mar 2016 17:07:31 +1030 Subject: [PATCH] daemon: introduce union htlc_staging for proposed changes to HTLCs. This encapsulates proposals more cleanly, and is important when we change the protocol to have more than one outstanding at a time. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- daemon/packets.c | 68 +++++++++++++++++++++++++++++------------------- daemon/peer.c | 41 ++++++++++++++++++----------- daemon/peer.h | 34 +++++++++++++++++++++--- 3 files changed, 97 insertions(+), 46 deletions(-) diff --git a/daemon/packets.c b/daemon/packets.c index 142fc406d..e259a088e 100644 --- a/daemon/packets.c +++ b/daemon/packets.c @@ -140,11 +140,12 @@ Pkt *pkt_htlc_add(const tal_t *ctx, const struct peer *peer, UpdateAddHtlc *u = tal(ctx, UpdateAddHtlc); update_add_htlc__init(u); + assert(htlc_prog->stage.type == HTLC_ADD); u->revocation_hash = sha256_to_proto(u, &htlc_prog->our_revocation_hash); - u->amount_msat = htlc_prog->htlc->msatoshis; - u->r_hash = sha256_to_proto(u, &htlc_prog->htlc->rhash); - u->expiry = abs_locktime_to_proto(u, &htlc_prog->htlc->expiry); + u->amount_msat = htlc_prog->stage.add.htlc.msatoshis; + u->r_hash = sha256_to_proto(u, &htlc_prog->stage.add.htlc.rhash); + u->expiry = abs_locktime_to_proto(u, &htlc_prog->stage.add.htlc.expiry); return make_pkt(ctx, PKT__PKT_UPDATE_ADD_HTLC, u); } @@ -155,9 +156,10 @@ Pkt *pkt_htlc_fulfill(const tal_t *ctx, const struct peer *peer, UpdateFulfillHtlc *f = tal(ctx, UpdateFulfillHtlc); update_fulfill_htlc__init(f); + assert(htlc_prog->stage.type == HTLC_FULFILL); f->revocation_hash = sha256_to_proto(f, &htlc_prog->our_revocation_hash); - f->r = sha256_to_proto(f, &htlc_prog->r); + f->r = sha256_to_proto(f, &htlc_prog->stage.fulfill.r); return make_pkt(ctx, PKT__PKT_UPDATE_FULFILL_HTLC, f); } @@ -166,11 +168,14 @@ Pkt *pkt_htlc_fail(const tal_t *ctx, const struct peer *peer, const struct htlc_progress *htlc_prog) { UpdateFailHtlc *f = tal(ctx, UpdateFailHtlc); + const struct channel_htlc *htlc; update_fail_htlc__init(f); + assert(htlc_prog->stage.type == HTLC_FAIL); + htlc = &peer->cstate->b.htlcs[htlc_prog->stage.fail.index]; f->revocation_hash = sha256_to_proto(f, &htlc_prog->our_revocation_hash); - f->r_hash = sha256_to_proto(f, &htlc_prog->htlc->rhash); + f->r_hash = sha256_to_proto(f, &htlc->rhash); return make_pkt(ctx, PKT__PKT_UPDATE_FAIL_HTLC, f); } @@ -419,29 +424,29 @@ Pkt *accept_pkt_htlc_add(const tal_t *ctx, struct htlc_progress *cur = tal(peer, struct htlc_progress); Pkt *err; - cur->htlc = tal(cur, struct channel_htlc); - cur->htlc->msatoshis = u->amount_msat; - proto_to_sha256(u->r_hash, &cur->htlc->rhash); + cur->stage.add.add = HTLC_ADD; + cur->stage.add.htlc.msatoshis = u->amount_msat; + proto_to_sha256(u->r_hash, &cur->stage.add.htlc.rhash); proto_to_sha256(u->revocation_hash, &cur->their_revocation_hash); - if (!proto_to_abs_locktime(u->expiry, &cur->htlc->expiry)) { + if (!proto_to_abs_locktime(u->expiry, &cur->stage.add.htlc.expiry)) { err = pkt_err(ctx, "Invalid HTLC expiry"); goto fail; } /* FIXME: Handle block-based expiry! */ - if (!abs_locktime_is_seconds(&cur->htlc->expiry)) { + if (!abs_locktime_is_seconds(&cur->stage.add.htlc.expiry)) { *decline = decline_htlc(ctx, "HTLC expiry in blocks not supported!"); goto decline; } - if (abs_locktime_to_seconds(&cur->htlc->expiry) < + if (abs_locktime_to_seconds(&cur->stage.add.htlc.expiry) < controlled_time().ts.tv_sec + peer->dstate->config.min_expiry) { *decline = decline_htlc(ctx, "HTLC expiry too soon!"); goto decline; } - if (abs_locktime_to_seconds(&cur->htlc->expiry) > + if (abs_locktime_to_seconds(&cur->stage.add.htlc.expiry) > controlled_time().ts.tv_sec + peer->dstate->config.max_expiry) { *decline = decline_htlc(ctx, "HTLC expiry too far!"); goto decline; @@ -449,16 +454,18 @@ Pkt *accept_pkt_htlc_add(const tal_t *ctx, cur->cstate = copy_funding(cur, peer->cstate); if (!funding_delta(peer->anchor.satoshis, - 0, cur->htlc->msatoshis, + 0, cur->stage.add.htlc.msatoshis, &cur->cstate->b, &cur->cstate->a)) { err = pkt_err(ctx, "Cannot afford %"PRIu64" milli-satoshis", - cur->htlc->msatoshis); + cur->stage.add.htlc.msatoshis); goto fail; } /* Add the htlc to their side of channel. */ - funding_add_htlc(&cur->cstate->b, cur->htlc->msatoshis, - &cur->htlc->expiry, &cur->htlc->rhash); - peer_add_htlc_expiry(peer, &cur->htlc->expiry); + funding_add_htlc(&cur->cstate->b, + cur->stage.add.htlc.msatoshis, + &cur->stage.add.htlc.expiry, + &cur->stage.add.htlc.rhash); + peer_add_htlc_expiry(peer, &cur->stage.add.htlc.expiry); peer_get_revocation_hash(peer, peer->commit_tx_counter+1, &cur->our_revocation_hash); @@ -495,6 +502,7 @@ Pkt *accept_pkt_htlc_fail(const tal_t *ctx, struct peer *peer, const Pkt *pkt) Pkt *err; size_t i; struct sha256 rhash; + struct channel_htlc *htlc; proto_to_sha256(f->revocation_hash, &cur->their_revocation_hash); proto_to_sha256(f->r_hash, &rhash); @@ -505,15 +513,17 @@ Pkt *accept_pkt_htlc_fail(const tal_t *ctx, struct peer *peer, const Pkt *pkt) goto fail; } - cur->htlc = tal_dup(cur, struct channel_htlc, &peer->cstate->a.htlcs[i]); + cur->stage.fail.fail = HTLC_FAIL; + cur->stage.fail.index = i; + htlc = &peer->cstate->a.htlcs[i]; /* Removing it should not fail: we regain HTLC amount */ cur->cstate = copy_funding(cur, peer->cstate); if (!funding_delta(peer->anchor.satoshis, - 0, -cur->htlc->msatoshis, + 0, -htlc->msatoshis, &cur->cstate->a, &cur->cstate->b)) { fatal("Unexpected failure fulfilling HTLC of %"PRIu64 - " milli-satoshis", cur->htlc->msatoshis); + " milli-satoshis", htlc->msatoshis); } funding_remove_htlc(&cur->cstate->a, i); /* FIXME: Remove timer. */ @@ -543,27 +553,31 @@ Pkt *accept_pkt_htlc_fulfill(const tal_t *ctx, struct htlc_progress *cur = tal(peer, struct htlc_progress); Pkt *err; size_t i; - struct sha256 rhash, r; + struct sha256 rhash; + struct channel_htlc *htlc; + + cur->stage.fulfill.fulfill = HTLC_FULFILL; + proto_to_sha256(f->r, &cur->stage.fulfill.r); - proto_to_sha256(f->r, &r); proto_to_sha256(f->revocation_hash, &cur->their_revocation_hash); - sha256(&rhash, &r, sizeof(r)); + sha256(&rhash, &cur->stage.fulfill.r, sizeof(cur->stage.fulfill.r)); i = funding_find_htlc(&peer->cstate->a, &rhash); if (i == tal_count(peer->cstate->a.htlcs)) { err = pkt_err(ctx, "Unknown HTLC"); goto fail; } + cur->stage.fulfill.index = i; - cur->htlc = tal_dup(cur, struct channel_htlc, &peer->cstate->a.htlcs[i]); + htlc = &peer->cstate->a.htlcs[i]; /* Removing it should not fail: they gain HTLC amount */ cur->cstate = copy_funding(cur, peer->cstate); if (!funding_delta(peer->anchor.satoshis, - -cur->htlc->msatoshis, - -cur->htlc->msatoshis, + -htlc->msatoshis, + -htlc->msatoshis, &cur->cstate->a, &cur->cstate->b)) { fatal("Unexpected failure fulfilling HTLC of %"PRIu64 - " milli-satoshis", cur->htlc->msatoshis); + " milli-satoshis", htlc->msatoshis); } funding_remove_htlc(&cur->cstate->a, i); diff --git a/daemon/peer.c b/daemon/peer.c index bc62e2ac2..e091c001b 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -1283,18 +1283,14 @@ const struct json_command getpeers_command = { static void set_htlc_command(struct peer *peer, struct channel_state *cstate, struct command *jsoncmd, - struct channel_htlc *htlc, enum state_input cmd, - const struct sha256 *r_fulfill) + const union htlc_staging *stage) { assert(!peer->current_htlc); peer->current_htlc = tal(peer, struct htlc_progress); peer->current_htlc->cstate = tal_steal(peer->current_htlc, cstate); - peer->current_htlc->htlc = tal_dup(peer->current_htlc, - struct channel_htlc, htlc); - if (r_fulfill) - peer->current_htlc->r = *r_fulfill; + peer->current_htlc->stage = *stage; peer_get_revocation_hash(peer, peer->commit_tx_counter+1, &peer->current_htlc->our_revocation_hash); @@ -1308,6 +1304,9 @@ static void set_htlc_command(struct peer *peer, static void check_htlc_expiry(struct peer *peer, void *unused) { size_t i; + union htlc_staging stage; + + stage.fail.fail = HTLC_FAIL; /* Check their htlcs for expiry. */ for (i = 0; i < tal_count(peer->cstate->b.htlcs); i++) { @@ -1334,9 +1333,9 @@ static void check_htlc_expiry(struct peer *peer, void *unused) " milli-satoshis", htlc->msatoshis); } funding_remove_htlc(&cstate->b, i); - - set_htlc_command(peer, cstate, NULL, htlc, - CMD_SEND_HTLC_FAIL, NULL); + stage.fail.index = i; + set_htlc_command(peer, cstate, NULL, CMD_SEND_HTLC_FAIL, + &stage); return; } } @@ -1369,6 +1368,10 @@ struct newhtlc { static void do_newhtlc(struct peer *peer, struct newhtlc *newhtlc) { struct channel_state *cstate; + union htlc_staging stage; + + stage.add.add = HTLC_ADD; + stage.add.htlc = newhtlc->htlc; /* Can we even offer this much? We check now, just before we * execute. */ @@ -1390,8 +1393,7 @@ static void do_newhtlc(struct peer *peer, struct newhtlc *newhtlc) peer_add_htlc_expiry(peer, &newhtlc->htlc.expiry); set_htlc_command(peer, cstate, newhtlc->jsoncmd, - &cstate->a.htlcs[tal_count(cstate->a.htlcs)-1], - CMD_SEND_HTLC_ADD, NULL); + CMD_SEND_HTLC_ADD, &stage); } static void json_newhtlc(struct command *cmd, @@ -1487,6 +1489,10 @@ static void do_fullfill(struct peer *peer, struct sha256 rhash; size_t i; struct channel_htlc *htlc; + union htlc_staging stage; + + stage.fulfill.fulfill = HTLC_FULFILL; + stage.fulfill.r = fulfillhtlc->r; sha256(&rhash, &fulfillhtlc->r, sizeof(fulfillhtlc->r)); @@ -1496,6 +1502,7 @@ static void do_fullfill(struct peer *peer, "preimage htlc not found"); return; } + stage.fulfill.index = i; /* Point at current one, since we remove from new cstate. */ htlc = &peer->cstate->b.htlcs[i]; @@ -1511,8 +1518,8 @@ static void do_fullfill(struct peer *peer, } funding_remove_htlc(&cstate->b, i); - set_htlc_command(peer, cstate, fulfillhtlc->jsoncmd, htlc, - CMD_SEND_HTLC_FULFILL, &fulfillhtlc->r); + set_htlc_command(peer, cstate, fulfillhtlc->jsoncmd, + CMD_SEND_HTLC_FULFILL, &stage); } static void json_fulfillhtlc(struct command *cmd, @@ -1570,12 +1577,16 @@ static void do_failhtlc(struct peer *peer, struct channel_state *cstate; size_t i; struct channel_htlc *htlc; + union htlc_staging stage; + + stage.fail.fail = HTLC_FAIL; i = funding_find_htlc(&peer->cstate->b, &failhtlc->rhash); if (i == tal_count(peer->cstate->b.htlcs)) { command_fail(failhtlc->jsoncmd, "htlc not found"); return; } + stage.fail.index = i; /* Point to current one, since we remove from new cstate. */ htlc = &peer->cstate->b.htlcs[i]; @@ -1592,8 +1603,8 @@ static void do_failhtlc(struct peer *peer, } funding_remove_htlc(&cstate->b, i); - set_htlc_command(peer, cstate, failhtlc->jsoncmd, htlc, - CMD_SEND_HTLC_FAIL, NULL); + set_htlc_command(peer, cstate, failhtlc->jsoncmd, + CMD_SEND_HTLC_FAIL, &stage); } static void json_failhtlc(struct command *cmd, diff --git a/daemon/peer.h b/daemon/peer.h index e525d1f91..95edec506 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -13,6 +13,35 @@ #include <ccan/list/list.h> #include <ccan/time/time.h> +enum htlc_stage_type { + HTLC_ADD, + HTLC_FULFILL, + HTLC_FAIL +}; + +struct htlc_add { + enum htlc_stage_type add; + struct channel_htlc htlc; +}; + +struct htlc_fulfill { + enum htlc_stage_type fulfill; + size_t index; + struct sha256 r; +}; + +struct htlc_fail { + enum htlc_stage_type fail; + size_t index; +}; + +union htlc_staging { + enum htlc_stage_type type; + struct htlc_add add; + struct htlc_fulfill fulfill; + struct htlc_fail fail; +}; + struct peer_visible_state { /* CMD_OPEN_WITH_ANCHOR or CMD_OPEN_WITHOUT_ANCHOR */ enum state_input offer_anchor; @@ -32,11 +61,8 @@ struct peer_visible_state { struct htlc_progress { /* The HTLC we're working on. */ - struct channel_htlc *htlc; + union htlc_staging stage; - /* Set if we're fulfilling. */ - struct sha256 r; - /* Our next state. */ /* Channel funding state, after we've completed htlc. */ struct channel_state *cstate;