diff --git a/channeld/channeld.c b/channeld/channeld.c index 798056562a24..d22490cb7cff 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -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 */ @@ -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; @@ -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: diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index 53590a2e6ee6..b43b7341d32f 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -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 diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 45639328ce26..d366f4ecc63a 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -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; diff --git a/channeld/full_channel.h b/channeld/full_channel.h index 05ebf8da0364..6cc7906a3dfb 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -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); /** diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index cfc1b213776e..6d3dafa12d3e 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -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); } @@ -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); diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index 177d6b624fd0..c0ab56a3fb2d 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -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 ---- diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index b2de15072810..166ea6496090 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -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; diff --git a/lightningd/options.c b/lightningd/options.c index 417e801e142d..26a8c1241923 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -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, diff --git a/lightningd/pay.c b/lightningd/pay.c index 1e759c7fdaa0..90c2ffa4e220 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -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 */ @@ -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; @@ -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, @@ -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; @@ -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( diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 36b81760915c..2019e881a11a 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -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; @@ -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); @@ -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; @@ -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; @@ -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 */ @@ -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) @@ -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; } @@ -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) @@ -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, @@ -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 */ diff --git a/lightningd/peer_htlcs.h b/lightningd/peer_htlcs.h index 688dd23ad7ed..a3ee73e4f978 100644 --- a/lightningd/peer_htlcs.h +++ b/lightningd/peer_htlcs.h @@ -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, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index a75112d205c4..328549359163 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -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) @@ -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) diff --git a/wire/extracted_peer_12_jamming.patch b/wire/extracted_peer_12_jamming.patch new file mode 100644 index 000000000000..e0185bfa5c7a --- /dev/null +++ b/wire/extracted_peer_12_jamming.patch @@ -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, diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv index 063d8cf07bd5..f4ddcfcb5d8c 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,