From a759fa9e8d7796e2c6e32fbfea804df54ec7e79b Mon Sep 17 00:00:00 2001 From: ZmnSCPxj jxPCSnmZ Date: Fri, 21 Apr 2023 05:25:49 +0800 Subject: [PATCH] LSPS4: Continuous JIT Channels. --- LSPS4/README.md | 968 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 3 +- 2 files changed, 970 insertions(+), 1 deletion(-) create mode 100644 LSPS4/README.md diff --git a/LSPS4/README.md b/LSPS4/README.md new file mode 100644 index 0000000..9d60926 --- /dev/null +++ b/LSPS4/README.md @@ -0,0 +1,968 @@ +# LSPS4 Continuous JIT Channel + +| Name | `continuous_jit_channels` | +| ------- | -------------------------- | +| Version | 1 | +| Status | For Implementation | + +## Motivation + +It is logical to users that before they can pay using some +currency, they must first receive that currency. + +However, by default, Lightning Network users cannot receive +unless somebody first creates a channel to them. +And whoever creates that channel needs to pay mining fees, +as well as possibly get revenue for this service. + +Generally, this means that a channel must first be bought, +often using Bitcoin, before a user can actually receive +Bitcoins over Lightning. +This means the user must first possess onchain Bitcoins +before they can receive Lightning Bitcoins; they cannot +simply "jump into" Lightning and receive their first +ever Bitcoins on Lightning. + +JIT Channels allows the channel opening fee to be paid from +the first payment to the user. +This allows users to "jump into" Lightning easily. + +Continuous JIT Channels is a logical extension of the JIT +Channels concept. +Whenever the user has insufficient inbound liquidity and +receives a payment, the user can use part of the payment +to pay for the channel open. +The LSP holds onto such payments until both the user and +the LSP can agree on the channel opening fee, then opens +the channel and deducts from incoming payments. + +### Trust Models + +As of this version, the trust model is that the LSP trusts clients to actually +claim their payment once the channel is opened and the payment is forwarded. + +If the client does not claim the payment, and the funding transaction confirms, +then the LSP will have its funds locked in a channel that was not paid for. +Even if the LSP disables all other use of the channel until the payment paying +for the channel is claimed, the client may then refuse all mutual close attempts +in retaliation (by disconnecting), and force the LSP to unilaterally close, +which locks the funds until the `to_self_delay` (indicated by the client, and +imposed on the LSP) has passed. + +LSPs that implement this API SHOULD include mitigations to allow them to +determine if clients can be trusted, or to detect and protect against attacks +on the LSP. +How those mitigations are performed is beyond the scope of this specification. + +### Actors + +The 'LSP' is the API provider, and is selling inbound +liquidity to clients. +The 'client' is the API consumer, and continuously +purchases inbound liquidity as incoming payments arrive +that overload its existing inbound liquidity. + +The 'payer' is an entity that pays to the client. + +## Flow + +Overview: + +* The client requests for an SCID it can use in an invoice via + `lsps4.reservescid`. + The client generates the invoice using the given SCID, and issues + the invoice to the payer. +* Payer pays, forwarding towards the LSP with the given SCID as the + next hop. + When payment arrives at the LSP, it creates pending payment parts + (PPPs, a fancy invented term for HODL HTLCs) for it. +* LSP notifies the client with `lsps4.youhavenewppp`, indicating that + the client has a new pending payment part, so that the client can + read them and process them. +* Client attempts to have the LSP directly forward the PPP(s) of a + single payment via the `lsps4.forwardppps` API call. + If this succeeds and all the HEDL HTLCs arrive at the client, the + client can claim them using normal BOLT operations and this flow + ends. + However, if it fails due to lack of inbound liquidity towards the + client, the client proceeds below. +* Client determines the current LSP fees for opening a new channel + via `lsps4.getopeningfee`. +* Client accepts the opening fee, and determines a set of PPPs that + are sufficient to pay for it. + Client provides this set to the LSP via `lsps4.openwithppps`. +* The LSP opens a channel with the client, and deducts the opening + fee from the given set of PPPs. + +> **Rationale** An alternative flow would be for the client to provide a +> payment hash for the LSP to recognize, instead of the LSP providing a +> SCID for the client to use in its invoice. +> However, this has drawbacks for some future modifications of the Lightning +> protocol: +> +> - Protocols where the payer generates the payment preimage and gives +> the preimage to the payee inside the encrypted onion are incompatible +> with having the client (the payee) provide the payment hash to the +> LSP beforehand. +> - Current plans for asynchronous receive uses such a scheme. +> - PTLCs are supposed to improve privacy by having each hop have a +> different blinding factor, but for the LSP to recognize the payment +> point, it would have to know the blinding factor towards the client, +> which reduces the privacy of the client in a multipath payment. +> - PTLCs would allow a payer to buy a private key from a payee +> (client in this context); normally the per-hop blinding factors +> would hide the sold private key from forwarding nodes, but due to +> the LSP having to know the exact payment point and the blinding +> factor towards the client / payee, it would also learn the sold +> private key. + +### 0. API Version Negotiation + +The client queries the versions supported by the LSP via the +`lsps4.getversions` call. +This call takes no parameters `{}` and has no defined errors. + +The LSP MUST store a "current client version" while a client is +connected. +This is an API version that the client specified as the version it +wants to use on the current connection. +If the client disconnects, the LSP forgets the current client +version for that client. +On connection, the LSP sets the current client version to 0. + +The result of the `lsps4.getversions` call is this: + +```JSON +{ + "versions": [1], + "current_version": 0 +} +``` + +`versions` is the set of LSPS4 versions the LSP supports. + +`current_version` is the current client version the LSP knows +about the client. + +To change the current client version, the client calls +`lsps4.setversion`. +It has no errors defined, and accepts the parameters: + +```JSON +{ + "current_version": 1 +} +``` + +`current_version` is what the client wants to set the current +client version to. +It is a required integer. + +`lsps4.setversion` always results in an empty object `{}`. + +On connection establishment, the client SHOULD call `lsps4.getversions` +to determine what versions the LSP supports. +Then it MUST call `lsps4.setversion` to indicate which version it +wants to use. + +All APIs other than `lsps4.getversions` and `lsps4.setversion` have +the following error code defined (error `code` is the number in +parenthesis): + +* `unsupported_version` (1) - the current client version is not among + the versions the LSP supports. + +Until the client selects a current client version that is among the +set of versions the LSP supports, all other APIs in this specification +are unuseable and will always return the `unsupported_version` error. + +### 1. Request SCID + +The client can request two types of SCIDs: + +* Permanent. + The client can have at most one permanent SCID. +* Ephemeral. + The client can have any number of ephemeral SCIDs, up to some LSP-defined + limit. + +A permanent SCID is actually only permanent as long as the LSP and client +have a channel in "normal operation" state (after both peers have sent +`channel_ready`, and before either has sent `shutdown`, and no commitment +transaction has confirmed). +If the LSP thinks there are no more "normal operation" channels, the +permanent SCID has a defined "expiry time"; if the current time has +exceeded the expiry time then the LSP forgets the permanent SCID. + +An ephemeral SCID also has an "expiry time", and is forgotten by the +LSP as soon as the expiry time has passed, regardless of the existence +or non-existence of a channel between the LSP and the client. +It is also forgotten if at least one forwarded payment using that SCID +has been successfully claimed (`update_fulfill_htlc`) by the client +(but not if the client fails the HTLC). + +* Permanent: Forget if past expiry time AND no channel. +* Ephemeral: Forget if past expiry time OR payment succeeded. + +Ephemeral SCIDs are provided to give privacy to clients. +For each invoice, the client requests an ephemeral SCID and generates +a fresh keypair as the node ID; separate invoices thus have a +different final node ID and final hop SCID. +On receiving a payment, the client iterates over its known invoice +keypairs until it is able to decode the onion, then can claim the +funds. + +Permanent SCIDs are provided to give a stable path to clients. +For example, the upcoming BOLT12 offers will need a stable permanent +SCID to be embedded in a blinded route. +This still provides privacy as the client can generate multiple +different BOLT12 offers with different ciphertexts of the same +blinded route. + +> **Rationale** All SCIDs, including the "permanent" one, have an +> expiry time in order to time-bound any extra information the +> LSP has to store for clients that request SCIDs (which are shared +> among all clients of the same LSP) and then never actually use +> them. +> The permanent SCID needs an expiry time so that the client has +> an opportunity to have a channel opened (either by opening one +> itself, or otherwise purchasing a channel from the LSP via this +> LSPS or via [LSPS1][] or [LSPS2][]) during this expiry time +> period. + +[LSPS1]: ../LSPS1/README.md +[LSPS2]: ../LSPS2/README.md + +The client MAY use a permanent SCID and its stable node ID for BOLT11 +invoices, though this leaks the privacy of the client. + +The client requests for an SCID via the `lsps4.reservescid` API, +which accepts the following parameters: + +```JSON +{ + "type": "p", + "expiry_time": "2023-04-20T10:08:41.222Z", + "min_final_cltv_expiry_delta": 18 +} +``` + +All parameters are required. + +`type` is a string, either `"p"` to request for a permanent SCID, +or `"e"` to request for an ephemeral SCID. + +`expiry_time` is the time to request. +Expiry times have granularity up to the millisecond. + +The client MUST set an expiry time that is at most 7 days (7 times +24 hours) from the current time. +The LSP MUST check the requested expiry time is at most 7 days +from the current time. + +`min_final_cltv_expiry_delta` is the final CLTV delta for the +recipient, i.e. the `c` field in BOLT11 invoices. +The LSP MUST persist this together with the generated SCID if +this call succeeds. + +On success, the result looks like: + +```JSON +{ + "lsps4_scid": "835932x85942x65443", + "expiry_time": "2023-04-19T11:02:11.841Z", + "min_final_cltv_expiry_delta": 24, + "ln_base_fee": "1000", + "ln_prop_fee": 1000, + "cltv_expiry_delta": 144 +} +``` + +`lsps4_scid` is the SCID reserved. + +`expiry_time` is the expiry time for the SCID. + +If the client asked for a `"p"`ermanent SCID, and the LSP currently +remembers a permanent SCID for thet client, the LSP MUST return +the current permanent SCID and its current `expiry_time` and +`min_final_cltv_expiry_delta`, which may be different from those +in the request parameters. +In this case, the `expiry_time` can be in the past, for example if +there is currently a channel between the LSP and the client. + +> **Rationale** There is a race condition where the client reserves +> a permanent SCID, but crashes before it can persist the returned +> permanent SCID. +> In that case, the LSP has already reserved the SCID but the client +> has forgotten it by accident. +> Thus, repeating that request should be idempotent until the LSP +> has also forgotten the permanent SCID. +> +> The LSP should not change the expiry time for the permanent SCID +> just because the request was repeated, and thus should return +> the original expiry time for the permanent SCID. +> +> `expiry_time` is set by the client instead of being determined +> and set by the LSP as the `expiry_time` would be determined from +> the `expiry`/`x` field of the BOLT11 invoice the client intends +> to issue. + +Otherwise, if a fresh SCID was created, then the `expiry_time` +MUST be the same as the request parameter. + +`ln_base_fee` is the base fee that the client MUST indicate as the +base fee for the given SCID. +`ln_prop_fee` is the proportional fee the client MUST indicate as +the proportional / parts-per-million fee for the given SCID. + +`cltv_expiry_delta` is the CLTV difference between the LSP-inbound +timelock and the to-client timelock. + +`lsps4.reservescid` has the following defined errors (error `code` +in parenthesis): + +* `expiry_too_long` (2) - The `expiry_time` requested by the client + exceeds 7 days from now. + The `data` object contains a field `current_time` which is a + datetime indicating what the LSP believes is the current time. +* `too_many_scids` (3) - The client requested for an ephemeral SCID + but the LSP has hit some internal limit on the number of ephemeral + SCIDs for the client. + +#### Invoice Generation + +TODO, basically `lsps4_scid` is put in the invoice. + +#### Forward Compatibility + +TODO, essentially the same as current LSPS2 proposal. + +### 2. Payment + +The payer now attempts to send money to the client. +The payer will now send out HTLC(s) going towards the LSP, with +the next hop being some LSPS4-reserved SCID. + +#### Pending Payment Parts (PPPs) + +When the LSP receives an HTLC that points to an SCID reserved for +LSPS4, the LSP MUST hold the incoming HTLC +and put its details into a structure called a "pending payment +part" or "PPP". +A pending payment part is a generalized term for some payment, +or *part* of a *payment*, that is *pending* --- i.e. it is +waiting for more inbound liquidity to become available to the +client before it is forwarded. + +We use the name "pending payment part" instead of "pending HTLC" +since in the future, pending payment parts might be pending PTLCs, +or pending asynchronous receives. +The same general mechanism is still applicable --- the LSP must +still "hold on" to the HTLC/PTLC/asyncpay (i.e. not respond to +the it, just wait for the client) until the client can either +arrange to pay for a new channel open, or the client decides to +refuse the payment in order to avoid paying for new channels with +this LSP (and presumably picks a different LSP with lower channel +opening fees). + +Once an HTLC (or in the future, PTLC or asynchronous receive) +has been placed into a PPP stored at the LSP, the client can +then learn its details and decide on what to do with the PPP. + +Each PPP has a type. +Currently, the only defined PPP type is HTLC-type PPP, also +known as `"type": "h"` PPPs. + +LSPs MUST impose a reasonably short time frame to hold onto +PPPs, after which it should just fail the PPP regardles of +whether the client has gotten around to processing it or not. + +* For HTLC-type PPPs, the hold time SHOULD be 90 to 120 seconds. + +> **Rationele** The LSP needs to hold onto the PPP so that the +> client can process it, and for the messages involved to +> traverse the network towards the client. +> +> The hold time can be larger for other future PPP types; for +> example, it would be reasonable to hold onto an asynchronous +> receive request for 24 hours or more, as no actual resources +> are held on the rest of the network; thus we specify the +> required hold time based on type. +> +> Multipath payments already mandate a hold time of up to 60 +> seconds at the payee; +> the additional 30 seconds in the 90-second minimum is to +> allow for client and LSP intercommunications. + +If the LSP decides to fail an HTLC-type PPP due to hold +timeout, the LSP MUST fail it with a +`temporary_channel_failure` error. + +An HTLC-type PPP is a hold on an incoming HTLC that is to be +forwarded to the client, as indicated by an LSPS4-reserved +SCID. +The onion for the outbound HTLC (the one that would go to +the client) can be read by the client, so that the client +can read any information in the onion, such as a +`keysend`-style preimage, or how large the total payment +would be for a multipart payment. + +> **Rationale** As their name implies, the PPP system is +> designed to handle multipart payments. +> The LSP cannot decode the onion to determine how much +> the total payment would be, but the client can. +> The problem is that it is possible that only some parts +> of a multipart payment reached the LSP, and then the +> payer gices up on trying to get the remaining parts to +> the destination. +> If so, if the LSP then opens a channel to the client and +> forwards the incomplete set of parts, the client is forced +> to fail the payment (since it did not receive the +> entire payment) but now has a channel opened by the LSP, +> which the LSP should now close (additional onchain +> activity that requires mining fees) to prevent use of a +> channel that was not paid for. +> +> If the client knows beforehand what the payment size +> would be, it could simply outright inform the LSP of +> the payment size, but this would prevent MPP from +> working with variable-amount invoices ("0-amount +> invoices") where the client does not know the +> payment size beforehand. +> +> A side benefit of the PPP mechanism is that it can also +> be used to aggregate multiple small separate payments +> and use their total to pay for a channel open. +> Even if no single payment is large enough for a channel +> open, if enough payments arrive in a short enough time +> frame, the aggregate may be large enough to pay for a +> channel open. + +### 3. Pending Payment Part Notification + +A "pending payment part" or "PPP" is an abstraction. +As of this specification version, all PPPs are HTLCs, but in the +future, a PPP may be a pending asynchronous receive, or a PTLC. + +Every PPP has a unique string identifier, the "PPP identifier". +The format of this identifier is defined by the LSP, but MUST be a +high-entropy identifier, with at least 80 bits of entropy. +The PPP identifier: + +* MUST be generated with at least 80 bits of entropy. +* MAY have any format, provided: + * MUST be encodable in an ASCII encoded JSON string without any + string escapes needed. + * MUST not be longer than 24 bytes (not including the `"` + delimiters) when encoded as an ASCII-encoded JSON string. + +Whenever the LSP receives an incoming payment that goes to a reserved +SCID, it: + +* Generates a fresh PPP identifier for it. +* Starts a hold timer for that incoming payment, duration depending on + its PPP type. + * Does not respond to the inbound until after the hold timer expires, + or the client has handled the payment fully. +* Adds the PPP to a disk-persisted structure called the "PPP Map", which + maps the PPP identifier to the information the LSP needs to forward, + handle, or fail the underlying payment, as well as the information + that the client needs to process for that PPP. + * If the hold timer expires before the client has decided to forward, + fail, or use the PPP for opening a new channel, should also remove + it from the PPP Map. +* Sends the `lsps4.youhavenewppp` notification to the client, containing + the PPP identifier and the details the client needs to process the + PPP. + +If the client has previously called `lsps4.reservescid`, this also +enables the LSP sending the notification `lsps4.youhavenewppp`. + +This notification contains the detail of one PPP that the LSP +wants to inform to the client. + +The notification contains these parameters: + +```JSON +{ + "ppp": "id#0123456789abcdef", + "details": { + "type": "h", + "amount": "21000", + "hash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "cltv": 599999 + "onion": "abcdefghijklmnopqrstuvwxyz+/" + } +} +``` + +`ppp` is the PPP identifier, and is required. + +`details` is an object, and is required. +`details` always has the keys: + +* `amount` - a monetary amount that is the pending outgoing amount + of this PPP (i.e. the amount that the client would receive if + it is able to claim the PPP). +* `type` - a single-character string denoting the type of this + PPP. + +The PPP `type` may be one of the following, which defines the +additional keys the `details` object has: + +* `"type": "h"` - HTLC-type PPP. + Additional keys (all required): + * `hash` - the 32-byte hash of the HTLC, as a hex-encoded JSON string. + * `cltv` - the timeout of the HTLC, a blockheight JSON integral number. + * `onion` - the onion for the client, as a binary blob. + The binary blob format is the [BOLT 4 Packet Structure][]. + +[BOLT 4 Packet Structure]: https://github.com/lightning/bolts/blob/master/04-onion-routing.md#packet-structure + +On connection establishment, the LSP MUST send `lsps4.youhavenewppp` +notifications, one for each PPP still being held in its persisted +PPP Map. + +The client MUST ignore duplicated `lsps4.youhavenewppp`; if it +already knows the given PPP identifier, it can completely ignore +the notification. + +> **Rationale** By having the LSP always replay the PPP Map on +> reconnection, the client can keep its copy of the PPP Map +> in-memory only; if the client crashes and restarts, the LSP +> simply resends the same PPP Map to the client. +> In addition, a disconnection may mean that the last few +> messages sent by the LSP might not have reached the client; +> thus, it is best and simplest to just send the entire PPP Map, +> as previous notifications might not have reached the client. +> +> A reconnection may occur if the client does not crash, but +> instead loses connectivity (e.g. it is a mobile app and the +> mobile unit entered a street tunnel and loses carrier signal). +> In that case the client may receive multiple copies of the +> same `lsps4.youhavenewppp`, and can ignore the additional one. + +On receiving the `lsps4.youhavenewppp` notification, the client +SHOULD: + +* Update its own copy of the PPP Map with the new PPP, together + with any decoded information in the PPP, such as the onion of + an HTLC-type PPP. +* Evaluate if its own copy of the PPP Map now has a complete + set of PPPs for a multipath payment, and if so, should continue + to attempt normal forwarding of the payment. + +### 4. Attempting Normal Forwarding + +For HTLC-type PPPs, the client decodes the onion using any of the +invoice node IDs it has used. +If the onion cannot be decoded by any of the invoice node IDs the client +knows about, the client MUST fail the PPP with an `invalid_onion_hmac` +error. +The client may fail a PPP via `lsps4.failppp`. + +The client can then determine if enough MPP payment parts have reached +the the client as actual HTLCs or PTLCs, and as LSP-held PPPs, and +can then attempt to have the LSP forward all those parts to the client. +This attempt to normally forward is done via `lsps4.forwardppps`. + +The client can always **attempt** to forward --- if there is +insufficient liquidity, `lsps4.forwardppps` will fail with a specific +error code and the client can proceed to steps 5 and 6. +This simplifies the client design as it can delegate checking for +liquidity to the LSP. + +> **Rationale** Even if the client does pre-checking if it has +> sufficient inbound liquidity before attempting to forward +> normally, the LSP can always refuse to forward even if there is +> enough inbound liquidity. +> Presumably, if the LSP did indeed hold onto incoming HTLCs, +> it has a stake in getting the payment resolved, and will +> forward immediately if possible. + +#### Forwarding Pending Payment Parts + +The client can use the `lsps4.forwardppps` API, which accepts +the parameters: + +```JSON +{ + "ppps": ["id#abcdefghijklmnop"] +} +``` + +`ppp` is a required non-empty array of PPP string identifiers, +for the PPPs to be forwarded or otherwise "normally handled". + +> **Rationale** The "normal handling" of an HTLC would be to +> just forward it to the client, but the "normal handling" +> of an asynchronous receive would be to respond to the +> sender or sender LSP with the notification that the client +> is online. + +If the client indicates multiple PPPs, the client MUST ensure +that all PPPs form a single complete multipath payment. + +On receiving this request, the LSP MUST **atomically** +perform the following: + +* Look up all `ppps` in the PPP Map. + * If any PPP is not found, fail with `nonexistent_ppp` + described below. +* Do a spot check of whether the client has enough + inbound liquidity to actually fulfill all the `ppps`. + * For HTLC-type PPPs, there must be enough inbound + liquidity in one channel to send the HTLC amount, + as well as to actually pay for the onchain fees of + the HTLC for the current onchain feerate of the + channel. + * If this check fails, fail with + `insufficient_liquidity` described below. +* Suppress the hold timers of the `ppps`. + * Hold timeout handling code must be atomic to this + call, if this API call is sent near the timeout; + either the timeout handler is called before this + entire atomic section (and the PPP is no longer + in the PPP Map and the section fails in the first + step above) or the timeout handler is called + after this entire atomic section (and does not + remove this PPP and release the incoming HTLC or + underlying payment, just notes that it would have + timed out). +* Remove the `ppps` from the PPP Map and arranges + them to be handled normally. + * For HTLC-type PPPs, arrange to have the HTLC be + forwarded to the client via any available + inbound liquidity to the client. + +The above atomic section ends before normal handling of +the PPPs is completed; it is enough for the LSP to +arrange to have the payment handled without actually +forwarding the HTLCs (or appropriate handling for its +type) yet, just arranging them to occur after the call. + +The `lsps4.forwardppps` call has the following errors +defined (error `code`s in parenthesis): + +* `nonexistent_ppp` (2) - One or more of the listed `ppps` is + not in the PPP Map; the expected case is that the hold + timer for the PPP has passed and the LSP has failed the + underlying PPP. + The error `data` object contains the required field + `unknown_ppps`, which is an array of PPP identifiers + containing the PPPs which were not found (and were + presumably timed out). + * The client SHOULD remove the indicated PPPs from its + own copy of the PPP Map, and should then re-evaluate + if it can accept the PPPs (for instance, it might + have received a `lsps4.youhavenewppp` while this + call was being handled by the LSP) in the PPP Map. +* `insufficient_liquidity` (3) - The client has insufficient + inbound liquidity to actually receive the entire set of + `ppps`. + * The client SHOULD continue to the next step (5 and 6) of + the flow. + +The LSP SHOULD make a best-effort attempt to deliver all +the PPPs in the `lsps4.forwardppps` call. +However, race conditions can cause the actual inbound +liquidity to change from when it was checked in the atomic +section, to when the LSP is now sending `update_add_htlc`s +to the client: + +* The channel initiator might send an `update_fees` which + increases the onchain feerate, such that an HTLC that would + have barely fit in the channel, no longer fits since the + increased onchain feerate prices it out of the channel. +* Some automated system in the client or LSP (such as the + one checking that the `update_fees` from the remote are + reasonable) might close a channel that the LSP was planning + to send an HTLC through. +* The client might be trying to mess with the LSP and + broadcasts a currently-unrevoked commitment transaction, + closing the channel before the LSP can deliver an HTLC it + was planning to send via that channel. +* The LSP might allow specific channels to be indicated via + their SCID, and an unrelated payment might go through a + channel that the LSP was intending to send one of the + `lsps4.forwardppps` HTLCs through. + +In such a case the LSP, for each PPP it was unable to handle +normally due to a race condition that changes the liquidity +towards the client: + +* MUST do one of the following: + * (preferred) add the PPP back to the PPP Map under a + new PPP identifier and resumes its hold timer. + It re-sends `lsps4.youhavenewppp` under the new PPP + identifiers. + If its hold timer has already expired at this point, the + LSP MUST NOT do this, but MUST do the alternative below + instead. + * (unpreferred) NOT add the PPP back to the PPP Map and + fail the payment with `temporary_channel_failure`. + +> **Rationale** Most node implementations, once you have +> indicated that the HTLC is to be forwarded "normally", will +> take over processing, and if it then turns out that there +> is insufficient liquidity, will automatically fail the +> HTLC with no way to re-handle the HTLC. +> Thus, the "unpreferred" branch is allowed (it is the only +> behavior such node implementations can do), but is still +> marked as unpreferred as it increases payment failure (the +> payer might give up retrying). +> The hope is that node implementations will eventually be +> modified so that the preferred branch can be taken instead. + +Regardless, normal BOLT-specified handling on the client +would still work despite this issue: + +* If the payment is a single part: + * If the preferred branch is taken by the LSP, the + client gets notified and can retry the + `lsps4.forwardppps` call, hopefully now with the updated + information on available liquidity and onchain fees + allowing the call to correctly report + `insufficient_liquidity`. + * If the unprefrred branch is taken by the LSP, the + payer may still retry, and the client would again be + notified of the new PPP, with the same result as above. +* If the payment is multipart: + * Any parts that were successfully forwarded will eventually + time out with the remaining parts undelivered, and a + BOLT-compliant client will `mpp_timeout` the delivered + parts. + * Any parts that were not successfully forwarded will be + re-added to the client copy of the PPP Map (if the LSP + takes the preferred branch) for re-evaluation by the + client, or might eventually be retried by the payer + (if the LSP takes the unpreferred branch). + +#### Failing Pending Payment Parts + +A pending payment part can be failed by the client using the +`lsps4.failppp` API. + +For example, suppose that the payer attempts a multipath +payment to the client via the LSP. +Some of the parts arrive at the LSP and are converted to PPPs. +However, other parts fail to reach the LSP, and eventually +the payer gives up. + +The client, as a "good citizen", SHOULD fail the multipath +parts that reached the LSP using an `mpp_timeout` error, in +order to free up network resources. + +`lsps4.failppp` accepts the parameters: + +```JSON +{ + "ppp": "id#abcdefghijklmnop", + "details": { + "type": "h", + "error_onion": "AbCdEfGhIjKlMnOpQrStUvWxYz+/" + } +} +``` + +`ppp` and `details` are required. + +`ppp` is the PPP string identifier for the PPP to be failed. + +`details` is an object whose keys are dependent on the type of +the PPP. +It always has the field `type`, which indicates the type of the +PPP. + +Depending on the PPP `type`, the additional fields of `details` +are: + +* `"h"` - HTLC-type PPP. + Additional fields: + * `error_onion` - a binary blob containing the error onion. + The binary blob format is described in + [BOLT 4 Returning Errors][], with the client as the *erring + node*. + +[BOLT 4 Returning Errors]: https://github.com/lightning/bolts/blob/master/04-onion-routing.md#returning-errors + +The LSP MUST look up the `ppp` in the PPP Map, and check that +the PPP type matches the `details.type` field. +The LSP MUST then check that the `details` field object +contains the fields necessary for that type. + +If the above checks succeed, the LSP removes the PPP from the +PPP Map and fails the PPP based on its type. + +* For HTLC-type PPPs, the LSP adds its own encryption layer + to the client `error_onion` and propagates the error onion + back to the payer via `update_fail_htlc`. + +On success, `lsps4.failppp` returns no results `{}`. + +In addition to `unsupported_version`, `lsps4.failppp` may +error with the below error codes: + +* `nonexistent_ppp` (2) - the PPP is not in the PPP Map + (it never existed, or was removed due to timing out its + hold time). +* `invalid_details` (3) - the `details.type` does not + match the PPP type, or the `details` object does not + contain the fields expected of its type. + +### 5. Determining Opening Fee + +The client can query for the cost of opening a new inbound +channel via the `lsps4.getopeningfee` call. + +TODO: copy LSPS2 `getinfo`, `opening_fee` computation, +`opening_fee_params` blah. + +Add `minimum_htlc_msat` to the `opening_fee_params`. + +### 6. Buying Inbound Liquidity + +The client selects a set of PPPs it wants to have forwarded +to it. + +The total amounts of the PPPs would now be the `payment_size`. +The client then computes the `opening_fee`. + +A portion of the PPPs will be used to pay the `opening_fee`, +while the total of the PPPs determines how large the `opening_fee` +would be. +The larger the total amount of the PPPs selected, the higher +the `opening_Fee` due to the proportional part, but the PPPs +selected must pay for both the proportional and base parts of +the opening fee. + +The client MUST check if the `opening_fee` is strictly less +than `payment_size - number_of_ppps * minimum_htlc_msat`, +where `number_of_ppps` is the number of PPPs in the set. +The client MUST check that `minimum_htlc_msat` is strictly +less than or equal to the smallest PPP amount in the selected +PPP set. + +Once the client has selected the set of PPPs it will use to +pay for the channel open, the client calls `lsps4.openwithppps` +call, which accepts the parameters: + +```JSON +{ + "ppps": ["id#abcdefghijklmnop"], + "opening_fee_params": { + "base": "546000", + "proportional": 1000, + "valid_until": "2023-04-19T16:55:21.295Z", + "max_idle_time": 4032, + "max_client_to_self_delay": 1008, + "minimum_htlc_msat": "1", + "promise": "abcdefghijklmnopqrstuvwxyz+/" + } +} +``` + +All parameters are required. + +`ppps` is a set of PPP string identifiers that the client wants +to use to open the channel. +It MUST NOT be empty. + +`opening_fee_params` is an object selected from the result of +the `lsps4.getopeningfee` call, copied verbatim. + +The entire `lsps4.openwithppps` call MUST be atomic, including +the checks below. + +The LSP: + +* MUST check that there is currently no pending LSPS4-bought + channel currently being opened (i.e. has not completed up to + `channel_ready` from both parties). +* MUST check that the given `opening_fee_params.promise` validates + the given `opening_fee_params`, and that + `opening_fee_params.valid_until` is a future datetime. +* MUST check that all the PPPs listed in `ppps` are still in the + PPP Map. +* MUST sum up the amounts of all PPPs listed and set `payment_size` + to that sum. +* MUST compute the `opening_fee` based on the `payment_size` and + the given `opening_fee_params`, and MUST check that the + `opening_fee` is strictly less than + `payment_size - number_of_ppps * minimum_htlc_msat`. + +If all above checks pass, the call succeeds. +Before responding, the LSP, still in the same atomic section: + +* Removes the PPPs listed in `ppps` from the PPP Map and puts + them into a PPP Opening Set. + * The existence of the PPP Opening Set is what is checked to + determine if a pending LSPS4-bought channel is being opened. + +Once the above operations complete, the call succeeds and the +atomic section ends, and the LSP responds with an empty object +`{}` and proceeds to the next step. + +If the checks fail, the atomic section ends and the LSP responds +with an error code: + +* `operation_pending` (2) - An LSPS4-bought channel is not yet + completed opening and sending the PPPs being used to pay for + it. + * The client SHOULD retry later once the channel has opened and + the existing payments resolved. +* `invalid_opening_fee_params` (3) - The `opening_fee_params.promise` + failed validation, or the `opening_fee_params.valid_until` is + already a past datetime. +* `nonexistent_ppp` (4) - One or more of the `ppps` is not in the PPP + Map. + The error `data` object contains the required field + `unknown_ppps`, which is an array of PPP identifiers + containing the PPPs which were not found. +* `insufficient_funds` (5) - The total `payment_size` is not + enough to pay for the `opening_fee`. + +> **Non-normative** The intent is that once asynchronous receives +> are possible, asyncpay-type PPPs will NOT be accepted in the +> `lsps4.openwithppps` call. +> Instead, those PPPs can only be passed to `lsps4.forwardppps` +> call, which will cause the LSP to respond to the senders of those +> asynchronous receives. +> The senders would then deliver actual HTLCs/PTLCs that the LSP +> will convert again to PPPs. +> +> This will help with the multiple-small-separate-payments +> case; asyncpay-type PPPs are expected to be holdable by the +> LSP longer, and once enough asyncpay-type PPPs are available, +> the client can then request the senders to try sending the +> actual payments in the hope that the LSP can gather enough +> to pay for a new channel. + +### 7. Opening Channel And Forwarding Selected Pending Payment Parts + +The LSP opens a channel to the client. + +TODO: copy from existing LSPS2. + +The client MUST NOT use the `alias` SCID sent in the 0-conf +channel open, or the "real" SCID of the channel once confirmed. +The client MUST use only the SCIDs issued via `lsps4.reservescid` +for all invoices and offers. + +The LSP SHOULD fail an incoming HTLC if it uses the `alias` or +"real" SCID of the channel as the next hop, with the failure +`unknown_next_peer`. + +Once both peers have exchanged `channel_ready`, the LSP iterates +over the PPP Opening Set and forwards the HTLCs in it to the +client. +The LSP MUST deduct amounts from the HTLCs in the PPP Opening +Set until it has claimed `opening_fee`. +The client MUST accept these non-standard HTLCs, and MUST +validate that the LSP claims `opening_fee` or less. + +The LSP MUST NOT forward other HTLCs to the new channel until +the PPP Opening Set is empty. + +Once the PPP Opening Set is empty, the LSP removes the set, +and the `lsps4.openwithppps` API can be invoked again. diff --git a/README.md b/README.md index 43d4821..33e393e 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ Describes the basics of how clients and LSPs communicate to each other. ### **LSPS.1** [Channel Request](channel-request.md) A unified channel request API standard for services to buy channels from LSP. This spec supports both just in time channel openings and pre paid channels - +### **LSPS4** [Continuous JIT Channels](LSPS4/README.md) +Describes how a client can buy channels from the LSP, by paying via a deduction from their incoming payments, creating a channel just-in-time to receive the incoming payment, but more awesome because it lets you buy using multiple separate tiny payments and with better privacy in BOLT11 invoices. ## Services List of Lightning Service Providers in alphabetic order that currently or will support LSP specs in future.