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;