Browse Source

lightningd/channel: support forcing HTLCs to restore channel state.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
dc160110a6
  1. 238
      lightningd/channel.c
  2. 23
      lightningd/channel.h
  3. 4
      lightningd/test/run-channel.c

238
lightningd/channel.c

@ -13,6 +13,7 @@
#include <inttypes.h>
#include <lightningd/channel_config.h>
#include <lightningd/htlc_tx.h>
#include <lightningd/htlc_wire.h>
#include <lightningd/key_derive.h>
#include <lightningd/status.h>
#include <string.h>
@ -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","

23
lightningd/channel.h

@ -12,6 +12,9 @@
#include <stdbool.h>
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

4
lightningd/test/run-channel.c

@ -15,6 +15,8 @@
#include <lightningd/sphinx.h>
#include <type_to_string.h>
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

Loading…
Cancel
Save