From cc4fc4b668bc7b228f0de3c02c71eddfaff9d518 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 30 Jun 2016 09:08:11 +0930 Subject: [PATCH] daemon: use htlc pointers everywhere. No more copies! I tried changing the cstate->side[].htlcs to htlc_map rather than a simple pointer array, but we rely on those array indices heavily for permutation mapping, and it turned into a major rewrite (especially for the steal case). Eventually, we're going to want to reconstruct the commit info for older commit txs rather than keeping all the permutation and per-commit-info HTLC information in memory, so we can do the work then. Signed-off-by: Rusty Russell --- commit_tx.c | 6 +- daemon/channel.c | 111 ++++++++++++++------------------ daemon/channel.h | 57 ++++++----------- daemon/packets.c | 122 +++++++++++++++-------------------- daemon/peer.c | 163 ++++++++++++++++++++++++++++------------------- daemon/peer.h | 20 +++++- state.h | 12 ++-- 7 files changed, 240 insertions(+), 251 deletions(-) diff --git a/commit_tx.c b/commit_tx.c index 6eff9d96e..2b91f1a74 100644 --- a/commit_tx.c +++ b/commit_tx.c @@ -11,7 +11,7 @@ #include static bool add_htlc(struct bitcoin_tx *tx, size_t n, - const struct channel_htlc *h, + const struct htlc *h, const struct pubkey *ourkey, const struct pubkey *theirkey, const struct sha256 *rhash, @@ -96,7 +96,7 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx, /* HTLCs this side sent. */ for (i = 0; i < tal_count(cstate->side[side].htlcs); i++) { - if (!add_htlc(tx, num, &cstate->side[side].htlcs[i], + if (!add_htlc(tx, num, cstate->side[side].htlcs[i], self, other, rhash, locktime, bitcoin_redeem_htlc_send)) return tal_free(tx); @@ -104,7 +104,7 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx, } /* HTLCs this side has received. */ for (i = 0; i < tal_count(cstate->side[!side].htlcs); i++) { - if (!add_htlc(tx, num, &cstate->side[!side].htlcs[i], + if (!add_htlc(tx, num, cstate->side[!side].htlcs[i], self, other, rhash, locktime, bitcoin_redeem_htlc_recv)) return tal_free(tx); diff --git a/daemon/channel.c b/daemon/channel.c index 466516a01..6ecfa4940 100644 --- a/daemon/channel.c +++ b/daemon/channel.c @@ -36,13 +36,13 @@ static uint64_t calculate_fee_msat(size_t num_nondust_htlcs, } /* Total, in millisatoshi. */ -static uint64_t htlcs_total(const struct channel_htlc *htlcs) +static uint64_t htlcs_total(struct htlc **htlcs) { size_t i, n = tal_count(htlcs); uint64_t total = 0; for (i = 0; i < n; i++) - total += htlcs[i].msatoshis; + total += htlcs[i]->msatoshis; return total; } @@ -152,8 +152,8 @@ struct channel_state *initial_cstate(const tal_t *ctx, fundee = &cstate->side[!funding]; /* Neither side has HTLCs. */ - funder->htlcs = tal_arr(cstate, struct channel_htlc, 0); - fundee->htlcs = tal_arr(cstate, struct channel_htlc, 0); + funder->htlcs = tal_arr(cstate, struct htlc *, 0); + fundee->htlcs = tal_arr(cstate, struct htlc *, 0); /* Initially, all goes back to funder. */ funder->pay_msat = anchor_satoshis * 1000 - fee_msat; @@ -174,12 +174,12 @@ bool is_dust_amount(uint64_t satoshis) return satoshis < 546; } -static size_t count_nondust_htlcs(const struct channel_htlc *htlcs) +static size_t count_nondust_htlcs(struct htlc **htlcs) { size_t i, n = tal_count(htlcs), nondust = 0; for (i = 0; i < n; i++) - if (!is_dust_amount(htlcs[i].msatoshis / 1000)) + if (!is_dust_amount(htlcs[i]->msatoshis / 1000)) nondust++; return nondust; } @@ -211,14 +211,9 @@ bool force_fee(struct channel_state *cstate, uint64_t fee) } /* Add a HTLC to @creator if it can afford it. */ -struct channel_htlc *cstate_add_htlc(struct channel_state *cstate, - u32 msatoshis, - const struct abs_locktime *expiry, - const struct sha256 *rhash, - uint64_t id, - const u8 *routing, - size_t routing_len, - enum channel_side side) +bool cstate_add_htlc(struct channel_state *cstate, + struct htlc *htlc, + enum channel_side side) { size_t n, nondust; struct channel_oneside *creator, *recipient; @@ -228,42 +223,32 @@ struct channel_htlc *cstate_add_htlc(struct channel_state *cstate, /* Remember to count the new one in total txsize if not dust! */ nondust = total_nondust_htlcs(cstate); - if (!is_dust_amount(msatoshis / 1000)) + if (!is_dust_amount(htlc->msatoshis / 1000)) nondust++; if (!change_funding(cstate->anchor, cstate->fee_rate, - msatoshis, creator, recipient, nondust)) - return NULL; + htlc->msatoshis, creator, recipient, nondust)) + return false; n = tal_count(creator->htlcs); tal_resize(&creator->htlcs, n+1); - creator->htlcs[n].msatoshis = msatoshis; - creator->htlcs[n].expiry = *expiry; - creator->htlcs[n].rhash = *rhash; - creator->htlcs[n].id = id; - creator->htlcs[n].routing = tal_dup_arr(cstate, u8, routing, - routing_len, 0); - memcheck(&creator->htlcs[n].msatoshis, - sizeof(creator->htlcs[n].msatoshis)); - memcheck(&creator->htlcs[n].rhash, sizeof(creator->htlcs[n].rhash)); + creator->htlcs[n] = htlc; + memcheck(&creator->htlcs[n]->msatoshis, + sizeof(creator->htlcs[n]->msatoshis)); + memcheck(&creator->htlcs[n]->rhash, sizeof(creator->htlcs[n]->rhash)); cstate->changes++; - return &creator->htlcs[n]; + return true; } /* Remove htlc from creator, credit it to beneficiary. */ static void remove_htlc(struct channel_state *cstate, enum channel_side creator, enum channel_side beneficiary, - struct channel_htlc *htlc) + struct htlc *htlc) { size_t nondust; - size_t n = tal_count(cstate->side[creator].htlcs); - const struct channel_htlc *end; - - end = cstate->side[creator].htlcs + n; - - assert(htlc >= cstate->side[creator].htlcs && htlc < end); + size_t i, n = tal_count(cstate->side[creator].htlcs); /* Remember to remove this one in total txsize if not dust! */ nondust = total_nondust_htlcs(cstate); @@ -280,69 +265,69 @@ static void remove_htlc(struct channel_state *cstate, abort(); /* Actually remove the HTLC. */ - tal_free(htlc->routing); - memmove(htlc, htlc + 1, (end - htlc - 1) * sizeof(*htlc)); - tal_resize(&cstate->side[creator].htlcs, n-1); - cstate->changes++; + for (i = 0; i < tal_count(cstate->side[creator].htlcs); i++) { + if (cstate->side[creator].htlcs[i] == htlc) { + memmove(cstate->side[creator].htlcs + i, + cstate->side[creator].htlcs + i + 1, + (n - i - 1) * sizeof(htlc)); + tal_resize(&cstate->side[creator].htlcs, n-1); + cstate->changes++; + return; + } + } + abort(); } void cstate_fail_htlc(struct channel_state *cstate, - struct channel_htlc *htlc, - enum channel_side side) + struct htlc *htlc, + enum channel_side side) { remove_htlc(cstate, side, side, htlc); } void cstate_fulfill_htlc(struct channel_state *cstate, - struct channel_htlc *htlc, - enum channel_side side) + struct htlc *htlc, + enum channel_side side) { remove_htlc(cstate, side, !side, htlc); } -size_t cstate_find_htlc(const struct channel_state *cstate, - const struct sha256 *rhash, - enum channel_side side) +struct htlc *cstate_find_htlc(const struct channel_state *cstate, + const struct sha256 *rhash, + enum channel_side side) { size_t i; for (i = 0; i < tal_count(cstate->side[side].htlcs); i++) { - if (structeq(&cstate->side[side].htlcs[i].rhash, rhash)) - return i; + if (structeq(&cstate->side[side].htlcs[i]->rhash, rhash)) + return cstate->side[side].htlcs[i]; } - return -1; + return NULL; } -struct channel_htlc *cstate_htlc_by_id(const struct channel_state *cstate, - uint64_t id, - enum channel_side side) +struct htlc *cstate_htlc_by_id(const struct channel_state *cstate, + uint64_t id, + enum channel_side side) { size_t i; for (i = 0; i < tal_count(cstate->side[side].htlcs); i++) { - if (cstate->side[side].htlcs[i].id == id) - return &cstate->side[side].htlcs[i]; + if (cstate->side[side].htlcs[i]->id == id) + return cstate->side[side].htlcs[i]; } return NULL; } struct channel_state *copy_cstate(const tal_t *ctx, - const struct channel_state *cstate) + const struct channel_state *cstate) { struct channel_state *cs = tal_dup(ctx, struct channel_state, cstate); - size_t i, j; + size_t i; for (i = 0; i < ARRAY_SIZE(cs->side); i++) { - cs->side[i].htlcs = tal_dup_arr(cs, struct channel_htlc, + cs->side[i].htlcs = tal_dup_arr(cs, struct htlc *, cs->side[i].htlcs, tal_count(cs->side[i].htlcs), 0); - for (j = 0; j < tal_count(cs->side[i].htlcs); j++) { - struct channel_htlc *h = &cs->side[i].htlcs[j]; - h->routing = tal_dup_arr(cs, u8, - h->routing, - tal_count(h->routing), - 0); - } } return cs; } diff --git a/daemon/channel.h b/daemon/channel.h index e1909350a..f146172a8 100644 --- a/daemon/channel.h +++ b/daemon/channel.h @@ -2,23 +2,17 @@ #define LIGHTNING_DAEMON_CHANNEL_H #include "config.h" #include "bitcoin/locktime.h" +#include "htlc.h" #include #include #include -struct channel_htlc { - u64 id; - u64 msatoshis; - struct abs_locktime expiry; - struct sha256 rhash; - const u8 *routing; -}; - struct channel_oneside { /* Payment and fee is in millisatoshi. */ uint32_t pay_msat, fee_msat; /* Use tal_count to get the number */ - struct channel_htlc *htlcs; + /* FIXME: Use htlc_map, but needs permute changes. */ + struct htlc **htlcs; }; enum channel_side { @@ -63,28 +57,17 @@ struct channel_state *copy_cstate(const tal_t *ctx, /** * cstate_add_htlc: append an HTLC to cstate if it can afford it * @cstate: The channel state - * @msatoshis: Millisatoshi going into a HTLC - * @expiry: time it expires - * @rhash: hash of redeem secret - * @id: 64-bit ID for htlc - * @routing: onion routing blob - * @routing_len: onion routing blob length + * @htlc: the htlc pointer. * @side: OURS or THEIRS * * If that direction can't afford the HTLC (or still owes its half of the fees), - * this will return NULL and leave @cstate unchanged. Otherwise + * this will return false and leave @cstate unchanged. Otherwise * cstate->side[dir].htlcs will have the HTLC appended, and pay_msat and - * fee_msat are adjusted accordingly; &cstate->side[dir].htlcs[] - * is returned. + * fee_msat are adjusted accordingly; true is returned. */ -struct channel_htlc *cstate_add_htlc(struct channel_state *cstate, - u32 msatoshis, - const struct abs_locktime *expiry, - const struct sha256 *rhash, - uint64_t id, - const u8 *routing, - size_t routing_len, - enum channel_side side); +bool cstate_add_htlc(struct channel_state *cstate, + struct htlc *htlc, + enum channel_side side); /** * cstate_fail_htlc: remove an HTLC, funds to the side which offered it. * @cstate: The channel state @@ -95,8 +78,8 @@ struct channel_htlc *cstate_add_htlc(struct channel_state *cstate, * the value of the HTLC (back) to cstate->side[dir]. */ void cstate_fail_htlc(struct channel_state *cstate, - struct channel_htlc *htlc, - enum channel_side side); + struct htlc *htlc, + enum channel_side side); /** * cstate_fulfill_htlc: remove an HTLC, funds to side which accepted it. @@ -108,8 +91,8 @@ void cstate_fail_htlc(struct channel_state *cstate, * the value of the HTLC to cstate->side[!dir]. */ void cstate_fulfill_htlc(struct channel_state *cstate, - struct channel_htlc *htlc, - enum channel_side side); + struct htlc *htlc, + enum channel_side side); /** * adjust_fee: Change fee rate. @@ -135,11 +118,11 @@ bool force_fee(struct channel_state *cstate, uint64_t fee); * @rhash: hash of redeem secret * @side: OURS or THEIRS * - * Returns a number < tal_count(cstate->side[dir].htlcs), or -1 on fail. + * Returns the HTLC, or NULL on fail. */ -size_t cstate_find_htlc(const struct channel_state *cstate, - const struct sha256 *rhash, - enum channel_side side); +struct htlc *cstate_find_htlc(const struct channel_state *cstate, + const struct sha256 *rhash, + enum channel_side side); /** * cstate_htlc_by_id: find an HTLC on this side of the channel by ID. @@ -149,9 +132,9 @@ size_t cstate_find_htlc(const struct channel_state *cstate, * * Returns a pointer into cstate->side[@side].htlcs, or NULL. */ -struct channel_htlc *cstate_htlc_by_id(const struct channel_state *cstate, - uint64_t id, - enum channel_side side); +struct htlc *cstate_htlc_by_id(const struct channel_state *cstate, + uint64_t id, + enum channel_side side); /** * fee_for_feerate: calculate the fee (in satoshi) for a given fee_rate. diff --git a/daemon/packets.c b/daemon/packets.c index 9a915ad23..6d623b2a4 100644 --- a/daemon/packets.c +++ b/daemon/packets.c @@ -4,6 +4,7 @@ #include "commit_tx.h" #include "controlled_time.h" #include "cryptopkt.h" +#include "htlc.h" #include "lightningd.h" #include "log.h" #include "names.h" @@ -168,29 +169,23 @@ void queue_pkt_open_complete(struct peer *peer) queue_pkt(peer, PKT__PKT_OPEN_COMPLETE, o); } -void queue_pkt_htlc_add(struct peer *peer, - u64 id, - u64 msatoshis, - const struct sha256 *rhash, - u32 expiry, - const u8 *route) +void queue_pkt_htlc_add(struct peer *peer, struct htlc *htlc) { UpdateAddHtlc *u = tal(peer, UpdateAddHtlc); union htlc_staging stage; - struct abs_locktime locktime; - struct channel_htlc *htlc; update_add_htlc__init(u); - u->id = id; - u->amount_msat = msatoshis; - u->r_hash = sha256_to_proto(u, rhash); - if (!blocks_to_abs_locktime(expiry, &locktime)) - fatal("Invalid locktime?"); - u->expiry = abs_locktime_to_proto(u, &locktime); + u->id = htlc->id; + u->amount_msat = htlc->msatoshis; + u->r_hash = sha256_to_proto(u, &htlc->rhash); + u->expiry = abs_locktime_to_proto(u, &htlc->expiry); u->route = tal(u, Routing); routing__init(u->route); - u->route->info.data = tal_dup_arr(u, u8, route, tal_count(route), 0); + u->route->info.data = tal_dup_arr(u, u8, + htlc->routing, + tal_count(htlc->routing), + 0); u->route->info.len = tal_count(u->route->info.data); /* BOLT #2: @@ -198,16 +193,11 @@ void queue_pkt_htlc_add(struct peer *peer, * The sending node MUST add the HTLC addition to the unacked * changeset for its remote commitment */ - htlc = cstate_add_htlc(peer->remote.staging_cstate, - msatoshis, &locktime, rhash, id, - route, tal_count(route), OURS); - if (!htlc) + if (!cstate_add_htlc(peer->remote.staging_cstate, htlc, OURS)) fatal("Could not add HTLC?"); stage.add.add = HTLC_ADD; - /* FIXME: This assumes stage's lifetime >= htlc, since we copy - * htlc.route pointer. Why not just make stage.add.htlc a ptr? */ - stage.add.htlc = *htlc; + stage.add.htlc = htlc; add_unacked(&peer->remote, &stage); remote_changes_pending(peer); @@ -215,14 +205,14 @@ void queue_pkt_htlc_add(struct peer *peer, queue_pkt(peer, PKT__PKT_UPDATE_ADD_HTLC, u); } -void queue_pkt_htlc_fulfill(struct peer *peer, u64 id, const struct rval *r) +void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc, + const struct rval *r) { UpdateFulfillHtlc *f = tal(peer, UpdateFulfillHtlc); - struct channel_htlc *htlc; union htlc_staging stage; update_fulfill_htlc__init(f); - f->id = id; + f->id = htlc->id; f->r = rval_to_proto(f, r); /* BOLT #2: @@ -230,12 +220,12 @@ void queue_pkt_htlc_fulfill(struct peer *peer, u64 id, const struct rval *r) * The sending node MUST add the HTLC fulfill/fail to the * unacked changeset for its remote commitment */ - htlc = cstate_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS); - assert(htlc); + assert(cstate_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS) + == htlc); cstate_fulfill_htlc(peer->remote.staging_cstate, htlc, THEIRS); stage.fulfill.fulfill = HTLC_FULFILL; - stage.fulfill.id = f->id; + stage.fulfill.htlc = htlc; stage.fulfill.r = *r; add_unacked(&peer->remote, &stage); @@ -244,14 +234,13 @@ void queue_pkt_htlc_fulfill(struct peer *peer, u64 id, const struct rval *r) queue_pkt(peer, PKT__PKT_UPDATE_FULFILL_HTLC, f); } -void queue_pkt_htlc_fail(struct peer *peer, u64 id) +void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc) { UpdateFailHtlc *f = tal(peer, UpdateFailHtlc); - struct channel_htlc *htlc; union htlc_staging stage; update_fail_htlc__init(f); - f->id = id; + f->id = htlc->id; /* FIXME: reason! */ f->reason = tal(f, FailReason); @@ -262,12 +251,12 @@ void queue_pkt_htlc_fail(struct peer *peer, u64 id) * The sending node MUST add the HTLC fulfill/fail to the * unacked changeset for its remote commitment */ - htlc = cstate_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS); - assert(htlc); + assert(cstate_htlc_by_id(peer->remote.staging_cstate, f->id, THEIRS) + == htlc); cstate_fail_htlc(peer->remote.staging_cstate, htlc, THEIRS); stage.fail.fail = HTLC_FAIL; - stage.fail.id = f->id; + stage.fail.htlc = htlc; add_unacked(&peer->remote, &stage); remote_changes_pending(peer); @@ -338,41 +327,38 @@ static void apply_changeset(struct peer *peer, size_t num_changes) { size_t i; - struct channel_htlc *htlc; + struct htlc *htlc; for (i = 0; i < num_changes; i++) { switch (changes[i].type) { case HTLC_ADD: htlc = cstate_htlc_by_id(which->staging_cstate, - changes[i].add.htlc.id, side); + changes[i].add.htlc->id, side); if (htlc) fatal("Can't add duplicate HTLC id %"PRIu64, - changes[i].add.htlc.id); + changes[i].add.htlc->id); if (!cstate_add_htlc(which->staging_cstate, - changes[i].add.htlc.msatoshis, - &changes[i].add.htlc.expiry, - &changes[i].add.htlc.rhash, - changes[i].add.htlc.id, - changes[i].add.htlc.routing, - tal_count(changes[i].add.htlc.routing), - side)) + changes[i].add.htlc, + side)) fatal("Adding HTLC to %s failed", side == OURS ? "ours" : "theirs"); continue; case HTLC_FAIL: htlc = cstate_htlc_by_id(which->staging_cstate, - changes[i].fail.id, !side); + changes[i].fail.htlc->id, + !side); if (!htlc) fatal("Can't fail non-exisent HTLC id %"PRIu64, - changes[i].fail.id); + changes[i].fail.htlc->id); cstate_fail_htlc(which->staging_cstate, htlc, !side); continue; case HTLC_FULFILL: htlc = cstate_htlc_by_id(which->staging_cstate, - changes[i].fulfill.id, !side); + changes[i].fulfill.htlc->id, + !side); if (!htlc) fatal("Can't fulfill non-exisent HTLC id %"PRIu64, - changes[i].fulfill.id); + changes[i].fulfill.htlc->id); cstate_fulfill_htlc(which->staging_cstate, htlc, !side); continue; } @@ -613,7 +599,7 @@ Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt) const UpdateAddHtlc *u = pkt->update_add_htlc; struct sha256 rhash; struct abs_locktime expiry; - struct channel_htlc *htlc; + struct htlc *htlc; union htlc_staging stage; /* BOLT #2: @@ -647,24 +633,17 @@ Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt) /* Note that it's not *our* problem if they do this, it's * theirs (future confusion). Nonetheless, we detect and * error for them. */ - if (cstate_htlc_by_id(peer->remote.staging_cstate, u->id, THEIRS) - || cstate_htlc_by_id(peer->remote.commit->cstate, u->id, THEIRS)) { + if (htlc_map_get(&peer->remote.htlcs, u->id)) return pkt_err(peer, "HTLC id %"PRIu64" clashes for you", u->id); - } - - if (cstate_htlc_by_id(peer->local.staging_cstate, u->id, THEIRS) - || cstate_htlc_by_id(peer->local.commit->cstate, u->id, THEIRS)) { - return pkt_err(peer, "HTLC id %"PRIu64" clashes for you", u->id); - } /* BOLT #2: * * ...and the receiving node MUST add the HTLC addition to the * unacked changeset for its local commitment. */ - htlc = cstate_add_htlc(peer->local.staging_cstate, - u->amount_msat, &expiry, &rhash, u->id, - u->route->info.data, u->route->info.len, - THEIRS); + htlc = peer_new_htlc(peer, u->id, u->amount_msat, &rhash, + abs_locktime_to_blocks(&expiry), + u->route->info.data, u->route->info.len, + THEIRS); /* BOLT #2: * @@ -677,13 +656,15 @@ Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt) /* FIXME: This is wrong! We may have already added more txs to * them.staging_cstate, driving that fee up. * We should check against the last version they acknowledged. */ - if (!htlc) + if (!cstate_add_htlc(peer->local.staging_cstate, htlc, THEIRS)) { + tal_free(htlc); return pkt_err(peer, "Cannot afford %"PRIu64" milli-satoshis" " in your commitment tx", u->amount_msat); + } stage.add.add = HTLC_ADD; - stage.add.htlc = *htlc; + stage.add.htlc = htlc; add_unacked(&peer->local, &stage); /* FIXME: Fees must be sufficient. */ @@ -691,18 +672,15 @@ Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt) } static Pkt *find_commited_htlc(struct peer *peer, uint64_t id, - struct channel_htlc **local_htlc) + struct htlc **local_htlc) { - struct channel_htlc *htlc; - /* BOLT #2: * * A node MUST check that `id` corresponds to an HTLC in its * current commitment transaction, and MUST fail the * connection if it does not. */ - htlc = cstate_htlc_by_id(peer->local.commit->cstate, id, OURS); - if (!htlc) + if (!cstate_htlc_by_id(peer->local.commit->cstate, id, OURS)) return pkt_err(peer, "Did not find HTLC %"PRIu64, id); /* They must not fail/fulfill twice, so it should be in staging, too. */ @@ -716,7 +694,7 @@ static Pkt *find_commited_htlc(struct peer *peer, uint64_t id, Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt) { const UpdateFailHtlc *f = pkt->update_fail_htlc; - struct channel_htlc *htlc; + struct htlc *htlc; Pkt *err; union htlc_staging stage; @@ -734,7 +712,7 @@ Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt) * to the unacked changeset for its local commitment. */ stage.fail.fail = HTLC_FAIL; - stage.fail.id = f->id; + stage.fail.htlc = htlc; add_unacked(&peer->local, &stage); return NULL; } @@ -742,7 +720,7 @@ Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt) Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt) { const UpdateFulfillHtlc *f = pkt->update_fulfill_htlc; - struct channel_htlc *htlc; + struct htlc *htlc; struct sha256 rhash; struct rval r; Pkt *err; @@ -767,7 +745,7 @@ Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt) cstate_fulfill_htlc(peer->local.staging_cstate, htlc, OURS); stage.fulfill.fulfill = HTLC_FULFILL; - stage.fulfill.id = f->id; + stage.fulfill.htlc = htlc; stage.fulfill.r = r; add_unacked(&peer->local, &stage); return NULL; diff --git a/daemon/peer.c b/daemon/peer.c index 698651af6..69b769e1e 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -535,23 +535,23 @@ static void state_event(struct peer *peer, } /* FIXME: Reason! */ -static bool command_htlc_fail(struct peer *peer, u64 id) +static bool command_htlc_fail(struct peer *peer, struct htlc *htlc) { if (!state_can_remove_htlc(peer->state)) return false; - queue_pkt_htlc_fail(peer, id); + queue_pkt_htlc_fail(peer, htlc); return true; } static bool command_htlc_fulfill(struct peer *peer, - u64 id, + struct htlc *htlc, const struct rval *r) { if (!state_can_remove_htlc(peer->state)) return false; - queue_pkt_htlc_fulfill(peer, id, r); + queue_pkt_htlc_fulfill(peer, htlc, r); return true; } @@ -562,6 +562,7 @@ static bool command_htlc_add(struct peer *peer, u64 msatoshis, { struct channel_state *cstate; struct abs_locktime locktime; + struct htlc *htlc; if (!blocks_to_abs_locktime(expiry, &locktime)) { log_unusual(peer->log, "add_htlc: fail: bad expiry %u", expiry); @@ -580,6 +581,7 @@ static bool command_htlc_add(struct peer *peer, u64 msatoshis, return false; } + /* FIXME: This is wrong: constraint on remote is sufficient. */ /* BOLT #2: * * A node MUST NOT add a HTLC if it would result in it @@ -597,37 +599,38 @@ static bool command_htlc_add(struct peer *peer, u64 msatoshis, return false; } + htlc = peer_new_htlc(peer, peer->htlc_id_counter, + msatoshis, rhash, expiry, route, tal_count(route), + OURS); + + /* FIXME: BOLT is not correct here: we should say IFF we cannot + * afford it in remote at its own current proposed fee-rate. */ /* BOLT #2: * * A node MUST NOT offer `amount_msat` it cannot pay for in * both commitment transactions at the current `fee_rate` */ cstate = copy_cstate(peer, peer->remote.staging_cstate); - if (!cstate_add_htlc(cstate, msatoshis, - &locktime, rhash, peer->htlc_id_counter, - route, tal_count(route), - OURS)) { + if (!cstate_add_htlc(cstate, htlc, OURS)) { log_unusual(peer->log, "add_htlc: fail: Cannot afford %"PRIu64 " milli-satoshis in their commit tx", msatoshis); + tal_free(htlc); return false; } tal_free(cstate); cstate = copy_cstate(peer, peer->local.staging_cstate); - if (!cstate_add_htlc(cstate, msatoshis, - &locktime, rhash, peer->htlc_id_counter, - route, tal_count(route), - OURS)) { + if (!cstate_add_htlc(cstate, htlc, OURS)) { log_unusual(peer->log, "add_htlc: fail: Cannot afford %"PRIu64 " milli-satoshis in our commit tx", msatoshis); + tal_free(htlc); return false; } tal_free(cstate); - queue_pkt_htlc_add(peer, peer->htlc_id_counter, - msatoshis, rhash, expiry, route); + queue_pkt_htlc_add(peer, htlc); /* Make sure we never offer the same one twice. */ peer->htlc_id_counter++; @@ -840,7 +843,10 @@ static struct peer *new_peer(struct lightningd_state *dstate, peer->local.commit = peer->remote.commit = NULL; peer->local.staging_cstate = peer->remote.staging_cstate = NULL; - + + htlc_map_init(&peer->local.htlcs); + htlc_map_init(&peer->remote.htlcs); + /* FIXME: Attach IO logging for this peer. */ tal_add_destructor(peer, destroy_peer); @@ -860,6 +866,41 @@ static struct peer *new_peer(struct lightningd_state *dstate, return peer; } +static void htlc_destroy(struct htlc *htlc) +{ + if (!htlc_map_del(&htlc->peer->local.htlcs, htlc) + && !htlc_map_del(&htlc->peer->remote.htlcs, htlc)) + fatal("Could not find htlc to destroy"); +} + +struct htlc *peer_new_htlc(struct peer *peer, + u64 id, + u64 msatoshis, + const struct sha256 *rhash, + u32 expiry, + const u8 *route, + size_t routelen, + enum channel_side side) +{ + struct htlc *h = tal(peer, struct htlc); + h->peer = peer; + h->id = id; + h->msatoshis = msatoshis; + h->rhash = *rhash; + if (!blocks_to_abs_locktime(expiry, &h->expiry)) + fatal("Invalid HTLC expiry %u", expiry); + h->routing = tal_dup_arr(h, u8, route, routelen, 0); + if (side == OURS) + htlc_map_add(&peer->local.htlcs, h); + else { + assert(side == THEIRS); + htlc_map_add(&peer->remote.htlcs, h); + } + tal_add_destructor(h, htlc_destroy); + + return h; +} + static struct io_plan *peer_connected_out(struct io_conn *conn, struct lightningd_state *dstate, struct json_connecting *connect) @@ -1066,7 +1107,7 @@ again: /* Check their currently still-existing htlcs for expiry: * We eliminate them from staging as we go. */ for (i = 0; i < tal_count(peer->remote.staging_cstate->side[THEIRS].htlcs); i++) { - struct channel_htlc *htlc = &peer->remote.staging_cstate->side[THEIRS].htlcs[i]; + struct htlc *htlc = peer->remote.staging_cstate->side[THEIRS].htlcs[i]; assert(!abs_locktime_is_seconds(&htlc->expiry)); @@ -1076,7 +1117,7 @@ again: continue; /* This can fail only if we're in an error state. */ - if (!command_htlc_fail(peer, htlc->id)) + if (!command_htlc_fail(peer, htlc)) return; goto again; } @@ -1166,8 +1207,7 @@ static bool is_mutual_close(const struct peer *peer, return false; } -static struct channel_htlc *htlc_by_index(const struct commit_info *ci, - size_t index) +static struct htlc *htlc_by_index(const struct commit_info *ci, size_t index) { if (ci->map[index] == -1) return NULL; @@ -1177,13 +1217,10 @@ static struct channel_htlc *htlc_by_index(const struct commit_info *ci, index -= 2; if (index < tal_count(ci->cstate->side[OURS].htlcs)) - return cast_const(struct channel_htlc *, - ci->cstate->side[OURS].htlcs) - + index; + return ci->cstate->side[OURS].htlcs[index]; index -= tal_count(ci->cstate->side[OURS].htlcs); assert(index < tal_count(ci->cstate->side[THEIRS].htlcs)); - return cast_const(struct channel_htlc *, ci->cstate->side[THEIRS].htlcs) - + index; + return ci->cstate->side[THEIRS].htlcs[index]; } static bool htlc_is_ours(const struct commit_info *ci, size_t index) @@ -1200,7 +1237,7 @@ static const struct bitcoin_tx *htlc_timeout_tx(const struct peer *peer, unsigned int i) { u8 *wscript; - struct channel_htlc *htlc; + struct htlc *htlc; struct bitcoin_tx *tx = bitcoin_tx(peer, 1, 1); struct bitcoin_signature sig; u64 fee, satoshis; @@ -1360,7 +1397,7 @@ static void resolve_cheating(struct peer *peer) } for (i = 2; i < tal_count(ci->map); i++) { - struct channel_htlc *h; + struct htlc *h; if (ci->map[i] == -1) continue; @@ -1420,7 +1457,7 @@ static void our_htlc_spent(struct peer *peer, size_t input_num, ptrint_t *pi) { - struct channel_htlc *h; + struct htlc *h; struct sha256 sha; struct rval preimage; size_t i = ptr2int(pi); @@ -1475,7 +1512,7 @@ static void our_htlc_depth(struct peer *peer, bool our_commit, size_t i) { - struct channel_htlc *h; + struct htlc *h; u32 height; /* Must be in a block. */ @@ -1584,7 +1621,7 @@ static void their_htlc_depth(struct peer *peer, ptrint_t *pi) { u32 height; - struct channel_htlc *h; + struct htlc *h; size_t i = ptr2int(pi); /* Must be in a block. */ @@ -2253,7 +2290,7 @@ static const char *owner_name(enum channel_side side) } static void route_htlc_onwards(struct peer *peer, - const struct channel_htlc *htlc, + const struct htlc *htlc, u64 msatoshis, const BitcoinPubkey *pb_id, const u8 *rest_of_route) @@ -2261,7 +2298,7 @@ static void route_htlc_onwards(struct peer *peer, /* FIXME: implement */ } -static void their_htlc_added(struct peer *peer, const struct channel_htlc *htlc) +static void their_htlc_added(struct peer *peer, struct htlc *htlc) { RouteStep *step; const u8 *rest_of_route; @@ -2269,7 +2306,7 @@ static void their_htlc_added(struct peer *peer, const struct channel_htlc *htlc) if (abs_locktime_is_seconds(&htlc->expiry)) { log_unusual(peer->log, "HTLC %"PRIu64" is in seconds", htlc->id); - command_htlc_fail(peer, htlc->id); + command_htlc_fail(peer, htlc); return; } @@ -2278,7 +2315,7 @@ static void their_htlc_added(struct peer *peer, const struct channel_htlc *htlc) log_unusual(peer->log, "HTLC %"PRIu64" expires too soon:" " block %u", htlc->id, abs_locktime_to_blocks(&htlc->expiry)); - command_htlc_fail(peer, htlc->id); + command_htlc_fail(peer, htlc); return; } @@ -2287,7 +2324,7 @@ static void their_htlc_added(struct peer *peer, const struct channel_htlc *htlc) log_unusual(peer->log, "HTLC %"PRIu64" expires too far:" " block %u", htlc->id, abs_locktime_to_blocks(&htlc->expiry)); - command_htlc_fail(peer, htlc->id); + command_htlc_fail(peer, htlc); return; } @@ -2296,7 +2333,7 @@ static void their_htlc_added(struct peer *peer, const struct channel_htlc *htlc) if (!step) { log_unusual(peer->log, "Bad onion, failing HTLC %"PRIu64, htlc->id); - command_htlc_fail(peer, htlc->id); + command_htlc_fail(peer, htlc); return; } @@ -2309,7 +2346,7 @@ static void their_htlc_added(struct peer *peer, const struct channel_htlc *htlc) log_add_struct(peer->log, " rhash=%s", struct sha256, &htlc->rhash); if (unlikely(!peer->dstate->dev_never_routefail)) - command_htlc_fail(peer, htlc->id); + command_htlc_fail(peer, htlc); goto free_rest; } @@ -2319,13 +2356,13 @@ static void their_htlc_added(struct peer *peer, const struct channel_htlc *htlc) htlc->id, htlc->msatoshis, payment->msatoshis); - command_htlc_fail(peer, htlc->id); + command_htlc_fail(peer, htlc); return; } log_info(peer->log, "Immediately resolving HTLC %"PRIu64, htlc->id); - command_htlc_fulfill(peer, htlc->id, &payment->r); + command_htlc_fulfill(peer, htlc, &payment->r); goto free_rest; case ROUTE_STEP__NEXT_BITCOIN: @@ -2334,7 +2371,7 @@ static void their_htlc_added(struct peer *peer, const struct channel_htlc *htlc) goto free_rest; default: log_info(peer->log, "Unknown step type %u", step->next_case); - command_htlc_fail(peer, htlc->id); + command_htlc_fail(peer, htlc); goto free_rest; } @@ -2357,7 +2394,7 @@ void peer_both_committed_to(struct peer *peer, switch (changes[i].type) { case HTLC_ADD: type = "ADD"; - htlc_id = changes[i].add.htlc.id; + htlc_id = changes[i].add.htlc->id; owner = owner_name(side); assert(cstate_htlc_by_id(peer->remote.commit->cstate, htlc_id, side)); @@ -2366,7 +2403,7 @@ void peer_both_committed_to(struct peer *peer, goto print; case HTLC_FAIL: type = "FAIL"; - htlc_id = changes[i].fail.id; + htlc_id = changes[i].fail.htlc->id; owner = owner_name(!side); assert(!cstate_htlc_by_id(peer->remote.commit->cstate, htlc_id, !side)); @@ -2379,7 +2416,7 @@ void peer_both_committed_to(struct peer *peer, goto print; case HTLC_FULFILL: type = "FULFILL"; - htlc_id = changes[i].fulfill.id; + htlc_id = changes[i].fulfill.htlc->id; owner = owner_name(!side); assert(!cstate_htlc_by_id(peer->remote.commit->cstate, htlc_id, !side)); @@ -2404,7 +2441,7 @@ void peer_both_committed_to(struct peer *peer, for (i = 0; i < n; i++) { switch (changes[i].type) { case HTLC_ADD: - their_htlc_added(peer, &changes[i].add.htlc); + their_htlc_added(peer, changes[i].add.htlc); break; case HTLC_FULFILL: /* FIXME: resolve_one_htlc(peer, id, preimage); */ @@ -2495,11 +2532,11 @@ static void json_add_htlcs(struct json_result *response, json_array_start(response, id); for (i = 0; i < tal_count(side->htlcs); i++) { json_object_start(response, NULL); - json_add_u64(response, "msatoshis", side->htlcs[i].msatoshis); - json_add_abstime(response, "expiry", &side->htlcs[i].expiry); + json_add_u64(response, "msatoshis", side->htlcs[i]->msatoshis); + json_add_abstime(response, "expiry", &side->htlcs[i]->expiry); json_add_hex(response, "rhash", - &side->htlcs[i].rhash, - sizeof(side->htlcs[i].rhash)); + &side->htlcs[i]->rhash, + sizeof(side->htlcs[i]->rhash)); json_object_end(response); } json_array_end(response); @@ -2648,12 +2685,12 @@ const struct json_command newhtlc_command = { }; /* Looks for their HTLC, but must be committed. */ -static size_t find_their_committed_htlc(struct peer *peer, - const struct sha256 *rhash) +static struct htlc *find_their_committed_htlc(struct peer *peer, + const struct sha256 *rhash) { /* Must be in last committed cstate. */ - if (cstate_find_htlc(peer->remote.commit->cstate, rhash, THEIRS) == -1) - return -1; + if (!cstate_find_htlc(peer->remote.commit->cstate, rhash, THEIRS)) + return NULL; return cstate_find_htlc(peer->remote.staging_cstate, rhash, THEIRS); } @@ -2665,8 +2702,7 @@ static void json_fulfillhtlc(struct command *cmd, jsmntok_t *peeridtok, *rtok; struct rval r; struct sha256 rhash; - size_t i; - u64 id; + struct htlc *htlc; if (!json_get_params(buffer, params, "peerid", &peeridtok, @@ -2698,21 +2734,20 @@ static void json_fulfillhtlc(struct command *cmd, sha256(&rhash, &r, sizeof(r)); - i = find_their_committed_htlc(peer, &rhash); - if (i == -1) { + htlc = find_their_committed_htlc(peer, &rhash); + if (!htlc) { command_fail(cmd, "preimage htlc not found"); return; } - id = peer->remote.staging_cstate->side[THEIRS].htlcs[i].id; - if (command_htlc_fulfill(peer, id, &r)) + if (command_htlc_fulfill(peer, htlc, &r)) command_success(cmd, null_response(cmd)); else command_fail(cmd, "htlc_fulfill not possible in state %s", state_name(peer->state)); } - + const struct json_command fulfillhtlc_command = { "fulfillhtlc", json_fulfillhtlc, @@ -2726,8 +2761,7 @@ static void json_failhtlc(struct command *cmd, struct peer *peer; jsmntok_t *peeridtok, *rhashtok; struct sha256 rhash; - size_t i; - u64 id; + struct htlc *htlc; if (!json_get_params(buffer, params, "peerid", &peeridtok, @@ -2759,20 +2793,19 @@ static void json_failhtlc(struct command *cmd, /* Look in peer->remote.staging_cstate->a, as that's where we'll * immediately remove it from: avoids double-handling. */ - i = find_their_committed_htlc(peer, &rhash); - if (i == -1) { + htlc = find_their_committed_htlc(peer, &rhash); + if (!htlc) { command_fail(cmd, "htlc not found"); return; } - id = peer->remote.staging_cstate->side[THEIRS].htlcs[i].id; - if (command_htlc_fail(peer, id)) + if (command_htlc_fail(peer, htlc)) command_success(cmd, null_response(cmd)); else command_fail(cmd, "htlc_fail not possible in state %s", state_name(peer->state)); } - + const struct json_command failhtlc_command = { "failhtlc", json_failhtlc, diff --git a/daemon/peer.h b/daemon/peer.h index 3aee2528a..e8abc0814 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -7,6 +7,7 @@ #include "bitcoin/script.h" #include "bitcoin/shadouble.h" #include "channel.h" +#include "htlc.h" #include "lightning.pb-c.h" #include "netaddr.h" #include "protobuf_convert.h" @@ -24,18 +25,18 @@ enum htlc_stage_type { struct htlc_add { enum htlc_stage_type add; - struct channel_htlc htlc; + struct htlc *htlc; }; struct htlc_fulfill { enum htlc_stage_type fulfill; - u64 id; + struct htlc *htlc; struct rval r; }; struct htlc_fail { enum htlc_stage_type fail; - u64 id; + struct htlc *htlc; }; union htlc_staging { @@ -95,6 +96,9 @@ struct peer_visible_state { /* cstate to generate next commitment tx. */ struct channel_state *staging_cstate; + + /* HTLCs offered by this side */ + struct htlc_map htlcs; }; struct out_pkt { @@ -240,6 +244,16 @@ void add_acked_changes(union htlc_staging **acked, void peer_both_committed_to(struct peer *peer, const union htlc_staging *changes, enum channel_side side); +/* Freeing removes from map, too */ +struct htlc *peer_new_htlc(struct peer *peer, + u64 id, + u64 msatoshis, + const struct sha256 *rhash, + u32 expiry, + const u8 *route, + size_t route_len, + enum channel_side side); + /* Peer has recieved revocation. */ void peer_update_complete(struct peer *peer); diff --git a/state.h b/state.h index 39ec448a8..031603b32 100644 --- a/state.h +++ b/state.h @@ -100,14 +100,10 @@ void queue_pkt_open(struct peer *peer, OpenChannel__AnchorOffer anchor); void queue_pkt_anchor(struct peer *peer); void queue_pkt_open_commit_sig(struct peer *peer); void queue_pkt_open_complete(struct peer *peer); -void queue_pkt_htlc_add(struct peer *peer, - u64 id, - u64 msatoshis, - const struct sha256 *rhash, - u32 expiry, - const u8 *route); -void queue_pkt_htlc_fulfill(struct peer *peer, u64 id, const struct rval *r); -void queue_pkt_htlc_fail(struct peer *peer, u64 id); +void queue_pkt_htlc_add(struct peer *peer, struct htlc *htlc); +void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc, + const struct rval *r); +void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc); void queue_pkt_commit(struct peer *peer); void queue_pkt_revocation(struct peer *peer); void queue_pkt_close_clearing(struct peer *peer);