Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .msggen.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,24 @@
"perkb": 0,
"perkw": 1
},
"ForwardEventFailureReason": {
"channel_failed_permanent": 11,
"channel_shutting_down": 13,
"cltv_expiry_too_far": 8,
"cltv_expiry_too_soon": 7,
"cltv_incorrect": 6,
"dust_limit": 2,
"fee_insufficient": 5,
"htlc_above_maximum": 4,
"htlc_below_minimum": 3,
"insufficient_outgoing_liquidity": 0,
"invalid_onion": 12,
"max_htlc_value_in_flight": 14,
"outgoing_peer_offline": 10,
"peer_cannot_afford_fee": 15,
"too_many_htlcs": 1,
"unknown_next_peer": 9
},
"ForwardEventStatus": {
"failed": 3,
"local_failed": 2,
Expand Down Expand Up @@ -242,6 +260,24 @@
"ListconfigsConfigsConfSource": {
"cmdline": 0
},
"ListforwardsForwardsFailureReason": {
"channel_failed_permanent": 11,
"channel_shutting_down": 13,
"cltv_expiry_too_far": 8,
"cltv_expiry_too_soon": 7,
"cltv_incorrect": 6,
"dust_limit": 2,
"fee_insufficient": 5,
"htlc_above_maximum": 4,
"htlc_below_minimum": 3,
"insufficient_outgoing_liquidity": 0,
"invalid_onion": 12,
"max_htlc_value_in_flight": 14,
"outgoing_peer_offline": 10,
"peer_cannot_afford_fee": 15,
"too_many_htlcs": 1,
"unknown_next_peer": 9
},
"ListforwardsForwardsStatus": {
"failed": 3,
"local_failed": 2,
Expand Down Expand Up @@ -2015,6 +2051,7 @@
"ForwardEventNotification": {
"forward_event.failcode": 8,
"forward_event.failreason": 9,
"forward_event.failure_reason": 13,
"forward_event.fee_msat": 6,
"forward_event.in_channel": 2,
"forward_event.in_msat": 4,
Expand Down Expand Up @@ -3067,6 +3104,7 @@
"ListForwards.forwards[].created_index": 12,
"ListForwards.forwards[].failcode": 15,
"ListForwards.forwards[].failreason": 16,
"ListForwards.forwards[].failure_reason": 17,
"ListForwards.forwards[].fee_msat": 7,
"ListForwards.forwards[].in_channel": 1,
"ListForwards.forwards[].in_htlc_id": 10,
Expand Down Expand Up @@ -11161,6 +11199,10 @@
"added": "pre-v0.10.1",
"deprecated": null
},
"ListForwards.forwards[].failure_reason": {
"added": "v26.12",
"deprecated": null
},
"ListForwards.forwards[].fee_msat": {
"added": "pre-v0.10.1",
"deprecated": null
Expand Down Expand Up @@ -15745,6 +15787,10 @@
"added": "pre-v0.10.1",
"deprecated": null
},
"forward_event.failure_reason": {
"added": "v26.12",
"deprecated": null
},
"forward_event.fee_msat": {
"added": "pre-v0.10.1",
"deprecated": null
Expand Down
23 changes: 21 additions & 2 deletions channeld/channeld.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <channeld/watchtower.h>
#include <common/billboard.h>
#include <common/ecdh_hsmd.h>
#include <common/forward_failure_reason.h>
#include <common/interactivetx.h>
#include <common/key_derive.h>
#include <common/memleak.h>
Expand Down Expand Up @@ -6578,6 +6579,7 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
enum channel_add_err e;
const u8 *failwiremsg;
const char *failstr;
enum forward_failure_reason reason = FORWARD_FAIL_UNKNOWN;
struct amount_sat htlc_fee;
struct pubkey *path_key;
struct tlv_field *extra_tlvs;
Expand Down Expand Up @@ -6640,13 +6642,14 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
start_commit_timer(peer);
/* Tell the master. */
msg = towire_channeld_offer_htlc_reply(NULL, peer->htlc_id,
0, "");
0, "", FORWARD_FAIL_UNKNOWN);
wire_sync_write(MASTER_FD, take(msg));
peer->htlc_id++;
return;
case CHANNEL_ERR_INVALID_EXPIRY:
failwiremsg = towire_incorrect_cltv_expiry(inmsg, cltv_expiry, NULL);
failstr = tal_fmt(inmsg, "Invalid cltv_expiry %u", cltv_expiry);
reason = FORWARD_FAIL_CLTV_INCORRECT;
goto failed;
case CHANNEL_ERR_DUPLICATE:
case CHANNEL_ERR_DUPLICATE_ID_DIFFERENT:
Expand All @@ -6656,21 +6659,36 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
case CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED:
failwiremsg = towire_required_node_feature_missing(inmsg);
failstr = "Mini mode: maximum value exceeded";
reason = FORWARD_FAIL_HTLC_ABOVE_MAXIMUM;
goto failed;
case CHANNEL_ERR_MAX_HTLC_VALUE_IN_FLIGHT_EXCEEDED:
failwiremsg = towire_temporary_channel_failure(inmsg, NULL);
failstr = "Aggregate value of committed HTLCs would exceed max_htlc_value_in_flight_msat";
reason = FORWARD_FAIL_MAX_HTLC_VALUE_IN_FLIGHT;
goto failed;
Comment on lines +6664 to 6668

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splitting out CHANNEL_ERR_MAX_HTLC_VALUE_IN_FLIGHT_EXCEEDED also changes what we send on the wire when the in-flight limit is hit: required_node_feature_missing becomes temporary_channel_failure. I think that's the right change, because required_node_feature_missing is a permanent node-level error and makes payers avoid our whole node. But it's a behaviour change other implementations can see, so it shouldn't be hidden in a fixup.

Could you move it into its own commit (the new enum value, the return change in full_channel.c, and the cases here and in channeld_fakenet.c) with a changelog line, for example:

channeld: return temporary_channel_failure when max_htlc_value_in_flight is exceeded

We used to return required_node_feature_missing, a permanent node
failure, which makes payers exclude our whole node for what is a
temporary channel condition.

Changelog-Fixed: Protocol: forwarding an HTLC that would exceed the outgoing channel's `max_htlc_value_in_flight_msat` now fails with `temporary_channel_failure` instead of `required_node_feature_missing`.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!!

/* FIXME: Fuzz the boundaries a bit to avoid probing? */
case CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED:
failwiremsg = towire_temporary_channel_failure(inmsg, NULL);
failstr = tal_fmt(inmsg, "Capacity exceeded - HTLC fee: %s", fmt_amount_sat(inmsg, htlc_fee));
reason = FORWARD_FAIL_INSUFFICIENT_OUTGOING_LIQUIDITY;
goto failed;
case CHANNEL_ERR_OPENER_CANNOT_AFFORD_FEE:
failwiremsg = towire_temporary_channel_failure(inmsg, NULL);
failstr = tal_fmt(inmsg, "Peer (opener) cannot afford commitment fee - HTLC fee: %s",
fmt_amount_sat(inmsg, htlc_fee));
reason = FORWARD_FAIL_PEER_CANNOT_AFFORD_FEE;
goto failed;
case CHANNEL_ERR_HTLC_BELOW_MINIMUM:
failwiremsg = towire_amount_below_minimum(inmsg, amount, NULL);
failstr = tal_fmt(inmsg, "HTLC too small (%s minimum)",
fmt_amount_msat(tmpctx,
peer->channel->config[REMOTE].htlc_minimum));
reason = FORWARD_FAIL_HTLC_BELOW_MINIMUM;
goto failed;
case CHANNEL_ERR_TOO_MANY_HTLCS:
failwiremsg = towire_temporary_channel_failure(inmsg, NULL);
failstr = "Too many HTLCs";
reason = FORWARD_FAIL_TOO_MANY_HTLCS;
goto failed;
case CHANNEL_ERR_DUST_FAILURE:
/* BOLT-919 #2:
Expand All @@ -6681,14 +6699,15 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
*/
failwiremsg = towire_temporary_channel_failure(inmsg, NULL);
failstr = "HTLC too dusty, allowed dust limit reached";
reason = FORWARD_FAIL_DUST_LIMIT;
goto failed;
}
/* Shouldn't return anything else! */
abort();

failed:
/* lightningd appends update to this for us */
msg = towire_channeld_offer_htlc_reply(NULL, 0, failwiremsg, failstr);
msg = towire_channeld_offer_htlc_reply(NULL, 0, failwiremsg, failstr, reason);
wire_sync_write(MASTER_FD, take(msg));
}

Expand Down
3 changes: 3 additions & 0 deletions channeld/channeld_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ msgdata,channeld_offer_htlc_reply,id,u64,
msgdata,channeld_offer_htlc_reply,len,u16,
msgdata,channeld_offer_htlc_reply,failuremsg,u8,len
msgdata,channeld_offer_htlc_reply,failurestr,wirestring,
# enum forward_failure_reason (common/forward_failure_reason.h) - root cause
# of the failure, 0 (FORWARD_FAIL_UNKNOWN) on success or if unclassified
msgdata,channeld_offer_htlc_reply,reason,u8,

# Main daemon found out the preimage for an HTLC
#include <bitcoin/preimage.h>
Expand Down
17 changes: 12 additions & 5 deletions channeld/full_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ static enum channel_add_err add_htlc(struct channel *channel,
if (enforce_aggregate_limits
&& amount_msat_greater(msat_in_htlcs,
channel->config[recipient].max_htlc_value_in_flight)) {
return CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED;
return CHANNEL_ERR_MAX_HTLC_VALUE_IN_FLIGHT_EXCEEDED;
}

/* BOLT #2:
Expand Down Expand Up @@ -836,16 +836,23 @@ static enum channel_add_err add_htlc(struct channel *channel,
/* Try not to add a payment which will take opener into fees
* on either our side or theirs. */
if (sender == LOCAL) {
/* If they opened the channel, their balance pays for
* the extra output, so this isn't our liquidity */
enum channel_add_err fee_err
= channel->opener == sender
? CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED
: CHANNEL_ERR_OPENER_CANNOT_AFFORD_FEE;

if (!get_room_above_reserve(channel, view,
adding, removing,
channel->opener,
&remainder))
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED;
return fee_err;

if ((option_anchor_outputs || option_anchors_zero_fee_htlc_tx)
&& channel->opener != sender
&& !amount_msat_deduct_sat(&remainder, AMOUNT_SAT(660)))
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED;
return fee_err;

/* Should be able to afford both their own commit tx
* fee, and other's commit tx fee, which are subtly
Expand All @@ -862,7 +869,7 @@ static enum channel_add_err add_htlc(struct channel *channel,
status_debug("Funder could not afford own fee %s with %s above reserve",
fmt_amount_sat(tmpctx, fee),
fmt_amount_msat(tmpctx, remainder));
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED;
return fee_err;
}
fee = fee_for_htlcs(channel,
committed,
Expand All @@ -876,7 +883,7 @@ static enum channel_add_err add_htlc(struct channel *channel,
status_debug("Funder could not afford peer's fee `%s with %s above reserve",
fmt_amount_sat(tmpctx, fee),
fmt_amount_msat(tmpctx, remainder));
return CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED;
return fee_err;
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion channeld/full_channel_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ enum channel_add_err {
CHANNEL_ERR_DUPLICATE,
/* Same ID, but otherwise different. */
CHANNEL_ERR_DUPLICATE_ID_DIFFERENT,
/* Would exceed the specified max_htlc_value_in_flight_msat */
CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED,
/* Would exceed the specified max_htlc_value_in_flight_msat */
CHANNEL_ERR_MAX_HTLC_VALUE_IN_FLIGHT_EXCEEDED,
/* Can't afford it */
CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED,
/* The remote opener can't afford the commitment fee (or anchors)
* for one more HTLC output, although we can afford the HTLC */
CHANNEL_ERR_OPENER_CANNOT_AFFORD_FEE,
/* HTLC is below htlc_minimum_msat */
CHANNEL_ERR_HTLC_BELOW_MINIMUM,
/* HTLC would push past max_accepted_htlcs */
Expand Down
40 changes: 40 additions & 0 deletions cln-grpc/proto/node.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions cln-grpc/src/convert.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading