Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implementation HTLC Endorsement to Mitigate Channel Jamming #6714

Closed
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
19 changes: 13 additions & 6 deletions channeld/channeld.c
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,8 @@ static void handle_peer_add_htlc(struct peer *peer, const u8 *msg)
add_err = channel_add_htlc(peer->channel, REMOTE, id, amount,
cltv_expiry, &payment_hash,
onion_routing_packet, tlvs->blinding_point, &htlc, NULL,
/* We just forward it :) smart ah? */
tlvs->endorsed,
/* We don't immediately fail incoming htlcs,
* instead we wait and fail them after
* they've been committed */
Expand Down Expand Up @@ -5622,9 +5624,12 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg)
billboard_update(peer);
}


/* Offer an HTLC to the remote side. */
static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
{
u8 *msg;
bool *endorsed;
u32 cltv_expiry;
struct amount_msat amount;
struct sha256 payment_hash;
Expand All @@ -5641,25 +5646,27 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
"funding not locked for offer_htlc");

if (!fromwire_channeld_offer_htlc(tmpctx, inmsg, &amount,
&cltv_expiry, &payment_hash,
onion_routing_packet, &blinding))
&cltv_expiry, &payment_hash,
onion_routing_packet, &blinding,
&endorsed))
master_badmsg(WIRE_CHANNELD_OFFER_HTLC, inmsg);

if (blinding) {
tlvs = tlv_update_add_htlc_tlvs_new(tmpctx);
tlvs->blinding_point = tal_dup(tlvs, struct pubkey, blinding);
tlvs->endorsed = (u8 *) endorsed;
} else
tlvs = NULL;

e = channel_add_htlc(peer->channel, LOCAL, peer->htlc_id,
amount, cltv_expiry, &payment_hash,
onion_routing_packet, take(blinding), NULL,
&htlc_fee, true);
status_debug("Adding HTLC %"PRIu64" amount=%s cltv=%u gave %s",
&htlc_fee, endorsed, true);
status_debug("Adding HTLC %"PRIu64" amount=%s cltv=%u gave %s endorsed=%u",
peer->htlc_id,
type_to_string(tmpctx, struct amount_msat, &amount),
cltv_expiry,
channel_add_err_name(e));
channel_add_err_name(e),
endorsed ? *endorsed : 0);

switch (e) {
case CHANNEL_ERR_ADD_OK:
Expand Down
1 change: 1 addition & 0 deletions channeld/channeld_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ msgdata,channeld_offer_htlc,cltv_expiry,u32,
msgdata,channeld_offer_htlc,payment_hash,sha256,
msgdata,channeld_offer_htlc,onion_routing_packet,u8,1366
msgdata,channeld_offer_htlc,blinding,?pubkey,
msgdata,channeld_offer_htlc,endorsed,?bool,

# Reply; synchronous since IDs have to increment.
msgtype,channeld_offer_htlc_reply,1104
Expand Down
1 change: 1 addition & 0 deletions channeld/full_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ enum channel_add_err channel_add_htlc(struct channel *channel,
const struct pubkey *blinding TAKES,
struct htlc **htlcp,
struct amount_sat *htlc_fee,
const bool endorsed,
bool err_immediate_failures)
{
enum htlc_state state;
Expand Down
1 change: 1 addition & 0 deletions channeld/full_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ enum channel_add_err channel_add_htlc(struct channel *channel,
const struct pubkey *blinding TAKES,
struct htlc **htlcp,
struct amount_sat *htlc_fee,
const bool endorsed,
bool err_immediate_failures);

/**
Expand Down
4 changes: 2 additions & 2 deletions channeld/test/run-full_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,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, true);
dummy_routing, NULL, NULL, NULL, false, true);
assert(e == CHANNEL_ERR_ADD_OK);
htlcs[i] = channel_get_htlc(channel, sender, i);
}
Expand Down Expand Up @@ -260,7 +260,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, true)
dummy_routing, NULL, NULL, NULL, false, true)
== CHANNEL_ERR_ADD_OK);
htlc = channel_get_htlc(channel, sender, 1337);
assert(htlc);
Expand Down
5 changes: 5 additions & 0 deletions doc/lightningd-config.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,11 @@ don't have to use a worst-case fee, but can bump the commitment transaction
if it's needed. Note that this means that we need to keep
some funds aside: see `min-emergency-msat`.

* **experimental-jamming-endorsement**

Specifying this option turn on part of the Channel Jamming mitigation
to forward the `endorsed` inside `update_add_htl` lightning message.

BUGS
----

Expand Down
3 changes: 3 additions & 0 deletions lightningd/lightningd.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ struct lightningd {
/* --invoices-onchain-fallback */
bool unified_invoices;

/* --experimental-jamming */
bool experimental_jamming_endorsement;

/* For anchors: how much do we keep for spending close txs? */
struct amount_sat emergency_sat;

Expand Down
4 changes: 4 additions & 0 deletions lightningd/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -1622,6 +1622,10 @@ static void register_opts(struct lightningd *ld)
opt_register_noarg("--invoices-onchain-fallback",
opt_set_bool, &ld->unified_invoices,
"Include an onchain address in invoices and mark them as paid if payment is received on-chain");
opt_register_noarg("--experimental-jamming-endorsement",
opt_set_bool, &ld->experimental_jamming_endorsement,
"experimental: allow htlc endorsement to mitigate channel jamming (incomplete)");

clnopt_witharg("--database-upgrade", OPT_SHOWBOOL,
opt_set_db_upgrade, NULL,
ld,
Expand Down
22 changes: 19 additions & 3 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <lightningd/pay.h>
#include <lightningd/peer_control.h>
#include <lightningd/peer_htlcs.h>
#include <stdbool.h>
#include <wallet/invoices.h>

/* Routing failure object */
Expand Down Expand Up @@ -730,7 +731,8 @@ static const u8 *send_onion(const tal_t *ctx, struct lightningd *ld,
u64 partid,
u64 groupid,
struct channel *channel,
struct htlc_out **hout)
struct htlc_out **hout,
const bool *endorsed)
{
const u8 *onion;
unsigned int base_expiry;
Expand All @@ -740,7 +742,8 @@ static const u8 *send_onion(const tal_t *ctx, struct lightningd *ld,
return send_htlc_out(ctx, channel, first_hop->amount,
base_expiry + first_hop->delay,
final_amount, payment_hash,
blinding, partid, groupid, onion, NULL, hout);
blinding, partid, groupid, onion, NULL, hout,
endorsed);
}

static struct command_result *check_invoice_request_usage(struct command *cmd,
Expand Down Expand Up @@ -1060,6 +1063,7 @@ send_payment_core(struct lightningd *ld,
struct secret *path_secrets,
const struct sha256 *local_invreq_id)
{
bool endorsed;
const struct wallet_payment *old_payment;
struct channel *channel;
const u8 *failmsg;
Expand Down Expand Up @@ -1105,9 +1109,21 @@ send_payment_core(struct lightningd *ld,
fmt_amount_msat(tmpctx, first_hop->amount),
fmt_amount_msat(tmpctx, msat));

/* BLIP-jamming #04:
* A sending node:
* - if it is the original source of the HTLC:
* - if it does not expect immediate fulfillment upon receipt by the
* final destination:
* - SHOULD set `endorsed` to `0`.
* - otherwise:
* - SHOULD set `endorsed` to `1`.
*
* We wait that someone else smarted than me will provide the way to
* calculate it for now it is just a placeholder. */
endorsed = false;
failmsg = send_onion(tmpctx, ld, packet, first_hop, msat,
rhash, NULL, partid,
group, channel, &hout);
group, channel, &hout, &endorsed);

if (failmsg) {
fail = immediate_routing_failure(
Expand Down
41 changes: 34 additions & 7 deletions lightningd/peer_htlcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,8 @@ const u8 *send_htlc_out(const tal_t *ctx,
u64 groupid,
const u8 *onion_routing_packet,
struct htlc_in *in,
struct htlc_out **houtp)
struct htlc_out **houtp,
const bool *endorsed)
{
u8 *msg;

Expand Down Expand Up @@ -652,7 +653,8 @@ const u8 *send_htlc_out(const tal_t *ctx,
}

msg = towire_channeld_offer_htlc(out, amount, cltv, payment_hash,
onion_routing_packet, blinding);
onion_routing_packet, blinding,
(bool *)endorsed);
subd_req(out->peer->ld, out->owner, take(msg), -1, 0, rcvd_htlc_reply,
*houtp);

Expand Down Expand Up @@ -705,7 +707,8 @@ static void forward_htlc(struct htlc_in *hin,
const struct short_channel_id *forward_scid,
const struct channel_id *forward_to,
const u8 next_onion[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)],
const struct pubkey *next_blinding)
const struct pubkey *next_blinding,
const bool *endorsed)
{
const u8 *failmsg;
struct lightningd *ld = hin->key.channel->peer->ld;
Expand Down Expand Up @@ -816,7 +819,7 @@ static void forward_htlc(struct htlc_in *hin,
outgoing_cltv_value, AMOUNT_MSAT(0),
&hin->payment_hash,
next_blinding, 0 /* partid */, 0 /* groupid */,
next_onion, hin, &hout);
next_onion, hin, &hout, endorsed);
if (!failmsg)
return;

Expand Down Expand Up @@ -844,6 +847,11 @@ struct htlc_accepted_hook_payload {
u8 *next_onion;
u64 failtlvtype;
size_t failtlvpos;
/* NULL if the jamming mitigation it is not
* supported */
bool *endorsed;
/* FIXME: add the possibility to encode
* and decode the raw tlvs */
};

/* We only handle the simplest cases here */
Expand Down Expand Up @@ -929,7 +937,8 @@ static bool htlc_accepted_hook_deserialize(struct htlc_accepted_hook_payload *re
struct htlc_in *hin = request->hin;
struct lightningd *ld = request->ld;
struct preimage payment_preimage;
const jsmntok_t *resulttok, *paykeytok, *payloadtok, *fwdtok;
const jsmntok_t *resulttok, *paykeytok,
*payloadtok, *fwdtok, *endorse_tok;
u8 *failonion;

if (!toks || !buffer)
Expand Down Expand Up @@ -981,6 +990,19 @@ static bool htlc_accepted_hook_deserialize(struct htlc_accepted_hook_payload *re
}
}

endorse_tok = json_get_member(buffer, toks, "endorsed");
if (endorse_tok) {
bool internal_endorsed;
tal_free(request->endorsed);
request->endorsed = tal(request, bool);
if (json_to_bool(buffer, endorse_tok, &internal_endorsed))
fatal("Bad endorsed for htlc_accepted"
" hook: %.*s",
endorse_tok->end - endorse_tok->start,
buffer + endorse_tok->start);
*request->endorsed = internal_endorsed ? 1 : 0;
}

if (json_tok_streq(buffer, resulttok, "continue")) {
return true;
}
Expand Down Expand Up @@ -1103,6 +1125,8 @@ static void htlc_accepted_hook_serialize(struct htlc_accepted_hook_payload *p,
}
json_add_hex_talarr(s, "next_onion", p->next_onion);
json_add_secret(s, "shared_secret", hin->shared_secret);
if (p->endorsed != NULL)
json_add_bool(s, "endorsed", *p->endorsed == 1);
json_object_end(s);

if (p->fwd_channel_id)
Expand Down Expand Up @@ -1151,7 +1175,7 @@ htlc_accepted_hook_final(struct htlc_accepted_hook_payload *request STEALS)
request->payload->forward_channel,
request->fwd_channel_id,
serialize_onionpacket(tmpctx, rs->next),
request->next_blinding);
request->next_blinding, request->endorsed);
} else
handle_localpay(hin,
request->payload->amt_to_forward,
Expand Down Expand Up @@ -1432,7 +1456,10 @@ static bool peer_accepted_htlc(const tal_t *ctx,
* we're in hook */
hook_payload->fwd_channel_id
= calc_forwarding_channel(ld, hook_payload);

// FIXME(vincenzopalazzo): ok this do not looks right, the value of
// hook_payload->endorsed should came from the prious pear of from us
// if we are the sender.
hook_payload->endorsed = ld->experimental_jamming_endorsement ? false : NULL;
plugin_hook_call_htlc_accepted(ld, NULL, hook_payload);

/* Falling through here is ok, after all the HTLC locked */
Expand Down
3 changes: 2 additions & 1 deletion lightningd/peer_htlcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const u8 *send_htlc_out(const tal_t *ctx,
u64 groupid,
const u8 *onion_routing_packet,
struct htlc_in *in,
struct htlc_out **houtp);
struct htlc_out **houtp,
const bool *endorsed);

void onchain_failed_our_htlc(const struct channel *channel,
const struct htlc_stub *htlc,
Expand Down
5 changes: 4 additions & 1 deletion wallet/test/run-wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,9 @@ struct json_stream *json_stream_fail(struct command *cmd UNNEEDED,
/* Generated stub for json_stream_success */
struct json_stream *json_stream_success(struct command *cmd UNNEEDED)
{ fprintf(stderr, "json_stream_success called!\n"); abort(); }
/* Generated stub for json_to_bool */
bool json_to_bool(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, bool *b UNNEEDED)
{ fprintf(stderr, "json_to_bool called!\n"); abort(); }
/* Generated stub for json_to_channel_id */
bool json_to_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct channel_id *cid UNNEEDED)
Expand Down Expand Up @@ -982,7 +985,7 @@ u8 *towire_channeld_got_commitsig_reply(const tal_t *ctx UNNEEDED)
u8 *towire_channeld_got_revoke_reply(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_channeld_got_revoke_reply called!\n"); abort(); }
/* Generated stub for towire_channeld_offer_htlc */
u8 *towire_channeld_offer_htlc(const tal_t *ctx UNNEEDED, struct amount_msat amount_msat UNNEEDED, u32 cltv_expiry UNNEEDED, const struct sha256 *payment_hash UNNEEDED, const u8 onion_routing_packet[1366] UNNEEDED, const struct pubkey *blinding UNNEEDED)
u8 *towire_channeld_offer_htlc(const tal_t *ctx UNNEEDED, struct amount_msat amount_msat UNNEEDED, u32 cltv_expiry UNNEEDED, const struct sha256 *payment_hash UNNEEDED, const u8 onion_routing_packet[1366] UNNEEDED, const struct pubkey *blinding UNNEEDED, bool *endorsed UNNEEDED)
{ fprintf(stderr, "towire_channeld_offer_htlc called!\n"); abort(); }
/* Generated stub for towire_channeld_sending_commitsig_reply */
u8 *towire_channeld_sending_commitsig_reply(const tal_t *ctx UNNEEDED)
Expand Down
13 changes: 13 additions & 0 deletions wire/extracted_peer_12_jamming.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv
index 063d8cf07..f4ddcfcb5 100644
--- a/wire/peer_wire.csv
+++ b/wire/peer_wire.csv
@@ -245,6 +245,8 @@ msgdata,update_add_htlc,cltv_expiry,u32,
msgdata,update_add_htlc,onion_routing_packet,byte,1366
tlvtype,update_add_htlc_tlvs,blinding_point,0
tlvdata,update_add_htlc_tlvs,blinding_point,blinding,point,
+tlvtype,update_add_htlc_tlvs,endorsed,1
+tlvdata,update_add_htlc_tlvs,endorsed,endorsed,byte,
msgtype,update_fulfill_htlc,130
msgdata,update_fulfill_htlc,channel_id,channel_id,
msgdata,update_fulfill_htlc,id,u64,
2 changes: 2 additions & 0 deletions wire/peer_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ msgdata,update_add_htlc,cltv_expiry,u32,
msgdata,update_add_htlc,onion_routing_packet,byte,1366
tlvtype,update_add_htlc_tlvs,blinding_point,0
tlvdata,update_add_htlc_tlvs,blinding_point,blinding,point,
tlvtype,update_add_htlc_tlvs,endorsed,1
tlvdata,update_add_htlc_tlvs,endorsed,endorsed,byte,
msgtype,update_fulfill_htlc,130
vincenzopalazzo marked this conversation as resolved.
Show resolved Hide resolved
msgdata,update_fulfill_htlc,channel_id,channel_id,
msgdata,update_fulfill_htlc,id,u64,
Expand Down
Loading