From 42e40c1ced7bb81630bef5716357f17b319f3d13 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 28 Sep 2021 14:08:11 -0500 Subject: [PATCH] htlcs: add flag to 'fail immediately' If we're over the dust limit, we fail it immediatey *after* commiting it, but we need a way to signal this throughout the lifecycle, so we add it to htlc_in struct and persist it through to the database. If it's supposed to be failed, we fail after the commit cycle is completed. --- channeld/channeld.c | 10 ++++++++-- channeld/channeld_htlc.h | 3 +++ channeld/full_channel.c | 11 +++++++---- channeld/full_channel.h | 7 ++++++- channeld/test/run-full_channel.c | 4 ++-- common/htlc_wire.c | 2 ++ common/htlc_wire.h | 1 + lightningd/htlc_end.c | 4 +++- lightningd/htlc_end.h | 5 ++++- lightningd/peer_htlcs.c | 10 +++++++++- wallet/wallet.c | 10 ++++++++-- 11 files changed, 53 insertions(+), 14 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 8a3b56e8e..5eb0fb26c 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -738,7 +738,11 @@ static void handle_peer_add_htlc(struct peer *peer, const u8 *msg) #endif add_err = channel_add_htlc(peer->channel, REMOTE, id, amount, cltv_expiry, &payment_hash, - onion_routing_packet, blinding, &htlc, NULL); + onion_routing_packet, blinding, &htlc, NULL, + /* We don't immediately fail incoming htlcs, + * instead we wait and fail them after + * they've been committed */ + false); if (add_err != CHANNEL_ERR_ADD_OK) peer_failed_warn(peer->pps, &peer->channel_id, "Bad peer_add_htlc: %s", @@ -1468,6 +1472,7 @@ static void marshall_htlc_info(const tal_t *ctx, ecdh(a.blinding, &a.blinding_ss); } else a.blinding = NULL; + a.fail_immediate = htlc->fail_immediate; tal_arr_expand(added, a); } else if (htlc->state == RCVD_REMOVE_COMMIT) { if (htlc->r) { @@ -3299,7 +3304,8 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) e = channel_add_htlc(peer->channel, LOCAL, peer->htlc_id, amount, cltv_expiry, &payment_hash, - onion_routing_packet, take(blinding), NULL, &htlc_fee); + onion_routing_packet, take(blinding), NULL, + &htlc_fee, true); status_debug("Adding HTLC %"PRIu64" amount=%s cltv=%u gave %s", peer->htlc_id, type_to_string(tmpctx, struct amount_msat, &amount), diff --git a/channeld/channeld_htlc.h b/channeld/channeld_htlc.h index fcb4e0841..3a40416f6 100644 --- a/channeld/channeld_htlc.h +++ b/channeld/channeld_htlc.h @@ -28,6 +28,9 @@ struct htlc { /* Blinding (optional). */ struct pubkey *blinding; + + /* Should we immediately fail this htlc? */ + bool fail_immediate; }; static inline bool htlc_has(const struct htlc *h, int flag) diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 1ae08ec79..59eb23acd 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -493,7 +493,8 @@ static enum channel_add_err add_htlc(struct channel *channel, const struct pubkey *blinding TAKES, struct htlc **htlcp, bool enforce_aggregate_limits, - struct amount_sat *htlc_fee) + struct amount_sat *htlc_fee, + bool err_immediate_failures) { struct htlc *htlc, *old; struct amount_msat msat_in_htlcs, committed_msat, adding_msat, removing_msat; @@ -508,6 +509,7 @@ static enum channel_add_err add_htlc(struct channel *channel, htlc->id = id; htlc->amount = amount; htlc->state = state; + htlc->fail_immediate = false; htlc->rhash = *payment_hash; if (blinding) @@ -768,7 +770,8 @@ enum channel_add_err channel_add_htlc(struct channel *channel, const u8 routing[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)], const struct pubkey *blinding TAKES, struct htlc **htlcp, - struct amount_sat *htlc_fee) + struct amount_sat *htlc_fee, + bool err_immediate_failures) { enum htlc_state state; @@ -786,7 +789,7 @@ enum channel_add_err channel_add_htlc(struct channel *channel, return add_htlc(channel, state, id, amount, cltv_expiry, payment_hash, routing, blinding, - htlcp, true, htlc_fee); + htlcp, true, htlc_fee, err_immediate_failures); } struct htlc *channel_get_htlc(struct channel *channel, enum side sender, u64 id) @@ -1392,7 +1395,7 @@ bool channel_force_htlcs(struct channel *channel, &htlcs[i]->payment_hash, htlcs[i]->onion_routing_packet, htlcs[i]->blinding, - &htlc, false, NULL); + &htlc, false, NULL, false); if (e != CHANNEL_ERR_ADD_OK) { status_broken("%s HTLC %"PRIu64" failed error %u", htlc_state_owner(htlcs[i]->state) == LOCAL diff --git a/channeld/full_channel.h b/channeld/full_channel.h index b9f59e9c1..ebfb4f856 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -103,6 +103,10 @@ u32 actual_feerate(const struct channel *channel, * @routing: routing information (copied) * @blinding: optional blinding information for this HTLC. * @htlcp: optional pointer for resulting htlc: filled in if and only if CHANNEL_ERR_NONE. + * @err_immediate_failures: in some cases (dusty htlcs) we want to immediately + * fail the htlc; for peer incoming don't want to + * error, but rather mark it as failed and fail after + * it's been committed to (so set this to false) * * If this returns CHANNEL_ERR_NONE, the fee htlc was added and * the output amounts adjusted accordingly. Otherwise nothing @@ -117,7 +121,8 @@ enum channel_add_err channel_add_htlc(struct channel *channel, const u8 routing[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)], const struct pubkey *blinding TAKES, struct htlc **htlcp, - struct amount_sat *htlc_fee); + struct amount_sat *htlc_fee, + bool err_immediate_failures); /** * channel_get_htlc: find an HTLC diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index addd5f564..1212f596f 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -165,7 +165,7 @@ static const struct htlc **include_htlcs(struct channel *channel, enum side side memset(&preimage, i, sizeof(preimage)); sha256(&hash, &preimage, sizeof(preimage)); e = channel_add_htlc(channel, sender, i, msatoshi, 500+i, &hash, - dummy_routing, NULL, NULL, NULL); + dummy_routing, NULL, NULL, NULL, true); assert(e == CHANNEL_ERR_ADD_OK); htlcs[i] = channel_get_htlc(channel, sender, i); } @@ -257,7 +257,7 @@ static void send_and_fulfill_htlc(struct channel *channel, sha256(&rhash, &r, sizeof(r)); assert(channel_add_htlc(channel, sender, 1337, msatoshi, 900, &rhash, - dummy_routing, NULL, NULL, NULL) + dummy_routing, NULL, NULL, NULL, true) == CHANNEL_ERR_ADD_OK); changed_htlcs = tal_arr(channel, const struct htlc *, 0); diff --git a/common/htlc_wire.c b/common/htlc_wire.c index e82f27ed4..801c8124b 100644 --- a/common/htlc_wire.c +++ b/common/htlc_wire.c @@ -78,6 +78,7 @@ void towire_added_htlc(u8 **pptr, const struct added_htlc *added) towire_secret(pptr, &added->blinding_ss); } else towire_bool(pptr, false); + towire_bool(pptr, added->fail_immediate); } void towire_existing_htlc(u8 **pptr, const struct existing_htlc *existing) @@ -171,6 +172,7 @@ void fromwire_added_htlc(const u8 **cursor, size_t *max, fromwire_secret(cursor, max, &added->blinding_ss); } else added->blinding = NULL; + added->fail_immediate = fromwire_bool(cursor, max); } struct existing_htlc *fromwire_existing_htlc(const tal_t *ctx, diff --git a/common/htlc_wire.h b/common/htlc_wire.h index 73a1236f8..0779dbfec 100644 --- a/common/htlc_wire.h +++ b/common/htlc_wire.h @@ -15,6 +15,7 @@ struct added_htlc { struct sha256 payment_hash; u32 cltv_expiry; u8 onion_routing_packet[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)]; + bool fail_immediate; /* If this is non-NULL, secret is the resulting shared secret */ struct pubkey *blinding; diff --git a/lightningd/htlc_end.c b/lightningd/htlc_end.c index b5589c2e5..461d77d17 100644 --- a/lightningd/htlc_end.c +++ b/lightningd/htlc_end.c @@ -130,7 +130,8 @@ struct htlc_in *new_htlc_in(const tal_t *ctx, const struct secret *shared_secret TAKES, const struct pubkey *blinding TAKES, const struct secret *blinding_ss, - const u8 *onion_routing_packet) + const u8 *onion_routing_packet, + bool fail_immediate) { struct htlc_in *hin = tal(ctx, struct htlc_in); @@ -141,6 +142,7 @@ struct htlc_in *new_htlc_in(const tal_t *ctx, hin->cltv_expiry = cltv_expiry; hin->payment_hash = *payment_hash; hin->status = NULL; + hin->fail_immediate = fail_immediate; if (shared_secret) hin->shared_secret = tal_dup(hin, struct secret, shared_secret); else diff --git a/lightningd/htlc_end.h b/lightningd/htlc_end.h index f6a4fd9fc..91bd6315b 100644 --- a/lightningd/htlc_end.h +++ b/lightningd/htlc_end.h @@ -52,6 +52,8 @@ struct htlc_in { struct secret blinding_ss; /* true if we supplied the preimage */ bool *we_filled; + /* true if we immediately fail the htlc (too much dust) */ + bool fail_immediate; /* A simple text annotation shown in `listpeers` */ char *status; @@ -154,7 +156,8 @@ struct htlc_in *new_htlc_in(const tal_t *ctx, const struct secret *shared_secret TAKES, const struct pubkey *blinding TAKES, const struct secret *blinding_ss, - const u8 *onion_routing_packet); + const u8 *onion_routing_packet, + bool fail_immediate); /* You need to set the ID, then connect_htlc_out this! */ struct htlc_out *new_htlc_out(const tal_t *ctx, diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index e937b8105..9e9456595 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1171,6 +1171,13 @@ static bool peer_accepted_htlc(const tal_t *ctx, goto fail; } + if (hin->fail_immediate && htlc_in_update_state(channel, hin, RCVD_ADD_ACK_REVOCATION)) { + log_debug(channel->log, "failing immediately, as requested"); + /* Failing the htlc, typically done because of htlc dust */ + *failmsg = towire_temporary_node_failure(ctx); + goto fail; + } + if (!replay && !htlc_in_update_state(channel, hin, RCVD_ADD_ACK_REVOCATION)) { *failmsg = towire_temporary_node_failure(ctx); goto fail; @@ -1863,7 +1870,8 @@ static bool channel_added_their_htlc(struct channel *channel, added->cltv_expiry, &added->payment_hash, op ? &shared_secret : NULL, added->blinding, &added->blinding_ss, - added->onion_routing_packet); + added->onion_routing_packet, + added->fail_immediate); /* Save an incoming htlc to the wallet */ wallet_htlc_save_in(ld->wallet, channel, hin); diff --git a/wallet/wallet.c b/wallet/wallet.c index 56180e166..1492f358a 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -2317,8 +2317,9 @@ void wallet_htlc_save_in(struct wallet *wallet, " shared_secret," " routing_onion," " received_time," - " min_commit_num) VALUES " - "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); + " min_commit_num, " + " fail_immediate) VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); db_bind_u64(stmt, 0, chan->dbid); db_bind_u64(stmt, 1, in->key.id); @@ -2345,6 +2346,8 @@ void wallet_htlc_save_in(struct wallet *wallet, db_bind_u64(stmt, 11, min_unsigned(chan->next_index[LOCAL]-1, chan->next_index[REMOTE]-1)); + db_bind_int(stmt, 12, in->fail_immediate); + db_exec_prepared_v2(stmt); in->dbid = db_last_insert_id_v2(take(stmt)); } @@ -2555,6 +2558,8 @@ static bool wallet_stmt2htlc_in(struct channel *channel, } else in->we_filled = NULL; + in->fail_immediate = db_column_int(stmt, 14); + return ok; } @@ -2683,6 +2688,7 @@ bool wallet_htlcs_load_in_for_channel(struct wallet *wallet, ", shared_secret" ", received_time" ", we_filled" + ", fail_immediate" " FROM channel_htlcs" " WHERE direction= ?" " AND channel_id= ?"