mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-10 01:24:30 +01:00
lightningd/channel: support forcing HTLCs to restore channel state.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -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","
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user