diff --git a/lightningd/channel.c b/lightningd/channel.c index e3191248f..8aa420759 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -341,13 +342,13 @@ struct channel *copy_channel(const tal_t *ctx, const struct channel *old) return new; } -enum channel_add_err channel_add_htlc(struct channel *channel, - enum side sender, - u64 id, - u64 msatoshi, - u32 cltv_expiry, - const struct sha256 *payment_hash, - const u8 routing[TOTAL_PACKET_SIZE]) +static enum channel_add_err add_htlc(struct channel *channel, + enum side sender, + u64 id, u64 msatoshi, u32 cltv_expiry, + const struct sha256 *payment_hash, + const u8 routing[TOTAL_PACKET_SIZE], + struct htlc **htlcp, + bool enforce_aggregate_limits) { const tal_t *tmpctx = tal_tmpctx(channel); struct htlc *htlc, *old; @@ -360,39 +361,32 @@ enum channel_add_err channel_add_htlc(struct channel *channel, htlc = tal(tmpctx, struct htlc); + /* FIXME: Don't need fields: peer, deadline, src. */ + if (sender == LOCAL) htlc->state = SENT_ADD_HTLC; else htlc->state = RCVD_ADD_HTLC; + htlc->id = id; htlc->msatoshi = msatoshi; + /* FIXME: Change expiry to simple u32 */ + /* BOLT #2: * * A receiving node SHOULD fail the channel if a sending node... sets * `cltv_expiry` to greater or equal to 500000000. */ - if (!blocks_to_abs_locktime(cltv_expiry, &htlc->expiry)) - return CHANNEL_ERR_INVALID_EXPIRY; + if (!blocks_to_abs_locktime(cltv_expiry, &htlc->expiry)) { + e = CHANNEL_ERR_INVALID_EXPIRY; + goto out; + } + htlc->rhash = *payment_hash; htlc->fail = NULL; htlc->r = NULL; - - /* BOLT #2: - * - * 1. type: 128 (`update_add_htlc`) - * 2. data: - * * [`32`:`channel_id`] - * * [`8`:`id`] - * * [`8`:`amount_msat`] - * * [`32`:`payment_hash`] - * * [`4`:`cltv_expiry`] - * * [`1366`:`onion_routing_packet`] - */ htlc->routing = tal_dup_arr(htlc, u8, routing, TOTAL_PACKET_SIZE, 0); - /* FIXME: check expiry etc. against config. */ - /* FIXME: set deadline */ - old = htlc_get(&channel->htlcs, htlc->id, htlc_owner(htlc)); if (old) { if (old->state != htlc->state @@ -443,7 +437,8 @@ enum channel_add_err channel_add_htlc(struct channel *channel, * A receiving node SHOULD fail the channel if a sending node * adds more than its `max_accepted_htlcs` HTLCs to its local * commitment transaction */ - if (tal_count(committed) - tal_count(removing) + tal_count(adding) + if (enforce_aggregate_limits + && tal_count(committed) - tal_count(removing) + tal_count(adding) > max_accepted_htlcs(channel, recipient)) { e = CHANNEL_ERR_TOO_MANY_HTLCS; goto out; @@ -458,7 +453,8 @@ enum channel_add_err channel_add_htlc(struct channel *channel, * A receiving node SHOULD fail the channel if a sending node ... or * adds more than its `max_htlc_value_in_flight_msat` worth of offered * HTLCs to its local commitment transaction */ - if (msat_in_htlcs > max_htlc_value_in_flight_msat(channel, recipient)) { + if (enforce_aggregate_limits + && msat_in_htlcs > max_htlc_value_in_flight_msat(channel, recipient)) { e = CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED; goto out; } @@ -505,7 +501,8 @@ enum channel_add_err channel_add_htlc(struct channel *channel, * come back to the sender after revoke_and_ack. So the check * here is that the balance to the sender doesn't go below the * sender's reserve. */ - if (balance_msat - fee_msat < (s64)channel_reserve_msat(channel, sender)) { + if (enforce_aggregate_limits + && balance_msat - fee_msat < (s64)channel_reserve_msat(channel, sender)) { e = CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED; goto out; } @@ -513,12 +510,27 @@ enum channel_add_err channel_add_htlc(struct channel *channel, dump_htlc(htlc, "NEW:"); htlc_map_add(&channel->htlcs, tal_steal(channel, htlc)); e = CHANNEL_ERR_ADD_OK; + if (htlcp) + *htlcp = htlc; out: tal_free(tmpctx); return e; } +enum channel_add_err channel_add_htlc(struct channel *channel, + enum side sender, + u64 id, + u64 msatoshi, + u32 cltv_expiry, + const struct sha256 *payment_hash, + const u8 routing[TOTAL_PACKET_SIZE]) +{ + /* FIXME: check expiry etc. against config. */ + return add_htlc(channel, sender, id, msatoshi, cltv_expiry, payment_hash, + routing, NULL, true); +} + struct htlc *channel_get_htlc(struct channel *channel, enum side sender, u64 id) { return htlc_get(&channel->htlcs, id, sender); @@ -783,6 +795,178 @@ bool channel_awaiting_revoke_and_ack(const struct channel *channel) return false; } +static bool adjust_balance(struct channel *channel, struct htlc *htlc) +{ + enum side side; + + for (side = 0; side < NUM_SIDES; side++) { + /* Did it ever add it? */ + if (!htlc_has(htlc, HTLC_FLAG(side, HTLC_F_WAS_COMMITTED))) + continue; + + /* Add it. */ + channel->view[side].owed_msat[LOCAL] + += balance_adding_htlc(htlc, LOCAL); + channel->view[side].owed_msat[REMOTE] + += balance_adding_htlc(htlc, REMOTE); + + /* If it is no longer committed, remove it (depending + * on fail || fulfill). */ + if (htlc_has(htlc, HTLC_FLAG(side, HTLC_F_COMMITTED))) + continue; + + if (!htlc->fail && !htlc->r) { + status_trace("%s HTLC %"PRIu64 + " %s neither fail nor fulfull?", + htlc_state_owner(htlc->state) == LOCAL + ? "out" : "in", + htlc->id, + htlc_state_name(htlc->state)); + return false; + } + channel->view[side].owed_msat[LOCAL] + += balance_removing_htlc(htlc, LOCAL); + channel->view[side].owed_msat[REMOTE] + += balance_removing_htlc(htlc, REMOTE); + } + return true; +} + +bool channel_force_htlcs(struct channel *channel, + const struct added_htlc *htlcs, + const enum htlc_state *hstates, + const struct fulfilled_htlc *fulfilled, + const enum side *fulfilled_sides, + const struct failed_htlc *failed, + const enum side *failed_sides) +{ + size_t i; + + if (tal_count(hstates) != tal_count(htlcs)) { + status_trace("#hstates %zu != #htlcs %zu", + tal_count(hstates), tal_count(htlcs)); + return false; + } + + if (tal_count(fulfilled) != tal_count(fulfilled_sides)) { + status_trace("#fulfilled sides %zu != #fulfilled %zu", + tal_count(fulfilled_sides), tal_count(fulfilled)); + return false; + } + + if (tal_count(failed) != tal_count(failed_sides)) { + status_trace("#failed sides %zu != #failed %zu", + tal_count(failed_sides), tal_count(failed)); + return false; + } + for (i = 0; i < tal_count(htlcs); i++) { + enum channel_add_err e; + struct htlc *htlc; + + status_trace("Restoring HTLC %zu/%zu:" + " id=%"PRIu64" msat=%"PRIu64" ctlv=%u" + " payment_hash=%s", + i, tal_count(htlcs), + htlcs[i].id, htlcs[i].amount_msat, + htlcs[i].cltv_expiry, + type_to_string(trc, struct sha256, + &htlcs[i].payment_hash)); + + e = add_htlc(channel, htlc_state_owner(hstates[i]), + htlcs[i].id, htlcs[i].amount_msat, + htlcs[i].cltv_expiry, + &htlcs[i].payment_hash, + htlcs[i].onion_routing_packet, &htlc, false); + if (e != CHANNEL_ERR_ADD_OK) { + status_trace("%s HTLC %"PRIu64" failed error %u", + htlc_state_owner(hstates[i]) == LOCAL + ? "out" : "in", htlcs[i].id, e); + return false; + } + + /* Override state. */ + htlc->state = hstates[i]; + } + + for (i = 0; i < tal_count(fulfilled); i++) { + struct htlc *htlc = channel_get_htlc(channel, + fulfilled_sides[i], + fulfilled[i].id); + if (!htlc) { + status_trace("Fulfill %s HTLC %"PRIu64" not found", + fulfilled_sides[i] == LOCAL ? "out" : "in", + fulfilled[i].id); + return false; + } + if (htlc->r) { + status_trace("Fulfill %s HTLC %"PRIu64" already fulfilled", + fulfilled_sides[i] == LOCAL ? "out" : "in", + fulfilled[i].id); + return false; + } + if (htlc->fail) { + status_trace("Fulfill %s HTLC %"PRIu64" already failed", + fulfilled_sides[i] == LOCAL ? "out" : "in", + fulfilled[i].id); + return false; + } + if (!htlc_has(htlc, HTLC_REMOVING)) { + status_trace("Fulfill %s HTLC %"PRIu64" state %s", + fulfilled_sides[i] == LOCAL ? "out" : "in", + fulfilled[i].id, + htlc_state_name(htlc->state)); + return false; + } + htlc->r = tal_dup(htlc, struct preimage, + &fulfilled[i].payment_preimage); + } + + for (i = 0; i < tal_count(failed); i++) { + struct htlc *htlc; + htlc = channel_get_htlc(channel, failed_sides[i], + failed[i].id); + if (!htlc) { + status_trace("Fail %s HTLC %"PRIu64" not found", + failed_sides[i] == LOCAL ? "out" : "in", + failed[i].id); + return false; + } + if (htlc->r) { + status_trace("Fail %s HTLC %"PRIu64" already fulfilled", + failed_sides[i] == LOCAL ? "out" : "in", + failed[i].id); + return false; + } + if (htlc->fail) { + status_trace("Fail %s HTLC %"PRIu64" already failed", + failed_sides[i] == LOCAL ? "out" : "in", + failed[i].id); + return false; + } + if (!htlc_has(htlc, HTLC_REMOVING)) { + status_trace("Fail %s HTLC %"PRIu64" state %s", + failed_sides[i] == LOCAL ? "out" : "in", + fulfilled[i].id, + htlc_state_name(htlc->state)); + return false; + } + htlc->fail = tal_dup_arr(htlc, u8, failed[i].failreason, + tal_len(failed[i].failreason), 0); + } + + for (i = 0; i < tal_count(htlcs); i++) { + struct htlc *htlc; + htlc = channel_get_htlc(channel, + htlc_state_owner(hstates[i]), + htlcs[i].id); + + if (!adjust_balance(channel, htlc)) + return false; + } + + return true; +} + static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view) { return tal_fmt(ctx, "{ feerate_per_kw=%"PRIu64"," diff --git a/lightningd/channel.h b/lightningd/channel.h index cf5965107..127c10e91 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -12,6 +12,9 @@ #include struct signature; +struct added_htlc; +struct failed_htlc; +struct fulfilled_htlc; /* View from each side */ struct channel_view { @@ -372,6 +375,26 @@ bool channel_sending_revoke_and_ack(struct channel *channel); */ bool channel_awaiting_revoke_and_ack(const struct channel *channel); +/** + * channel_force_htlcs: force these htlcs into the (new) channel + * @channel: the channel + * @htlcs: the htlcs to add (tal_arr) + * @hstates: the states for the htlcs (tal_arr of same size) + * @fulfilled: htlcs of those which are fulfilled + * @fulfilled_sides: sides for ids in @fulfilled + * @failed: htlcs of those which are failed + * @failed_sides: sides for ids in @failed + * + * This is used for restoring a channel state. + */ +bool channel_force_htlcs(struct channel *channel, + const struct added_htlc *htlcs, + const enum htlc_state *hstates, + const struct fulfilled_htlc *fulfilled, + const enum side *fulfilled_sides, + const struct failed_htlc *failed, + const enum side *failed_sides); + /** * dump_htlcs: debugging dump of all HTLCs * @channel: the channel diff --git a/lightningd/test/run-channel.c b/lightningd/test/run-channel.c index 4f32414bd..d18ac63bd 100644 --- a/lightningd/test/run-channel.c +++ b/lightningd/test/run-channel.c @@ -15,6 +15,8 @@ #include #include +const void *trc; + static struct sha256 sha256_from_hex(const char *hex) { struct sha256 sha256; @@ -319,6 +321,8 @@ int main(void) secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); + trc = tmpctx; + /* BOLT #3: * * # Appendix C: Commitment and HTLC Transaction Test Vectors