Re: [Ledger] An attempt to clean up the protocol architecture

I think this thread is going to get extremely unwieldy but here goes:

> - All interledger layer messages should be ILP packets (including
fulfillments) and be capable of carrying higher layer protocol payloads.

Interledger has higher requirements than ILP for the lowest layer,
specifically because we are carrying money and not just data. One of the
requirements is being able to transmit a 32-byte fulfillment back along the
same path that carried the payment originally. If we expect this of the
lower layer, I don't see a point in putting the fulfillment into an ILP
packet and transmitting it as Interledger data along the same path. All
ledger-layer protocols will need to interpret the fulfillment passed in
their protocol, not the one passed through the Interledger layer.

> - While it may make sense to split the interledger payment and
interledger quoting protocols into new higher level protocols that seems
like an unnecessary abstraction. Instead the packet definitions should just
have some consistency and probably a common base/header.

The current protocols effectively have this header but it isn't separated
out. There are two fields in the request header: type and destination
address. There is one field in the response header: type. I don't think it
makes that much of a big difference to separate these fields if all of the
fields in that packet need to be interpreted together (for example, you
can't understand a quote request if you strip off the destination address).

> - We should define two base ILP packet types: request and response.

Unless this adds some substantive benefit or new fields I don't think it's
worth breaking all of the formats we have just to rearrange things.

> - ILP is not about ledgers, it is about trustlines between nodes/hosts.

A ledger is any system that tracks accounts and balances. When you use a
trustline all of your messages still need to go through an accounting
system (such as the plugin in the JS implementation) and then on to the
other program logic. In that case, the plugin or whatever is doing the
accounting is the ledger. Digital value is always tracked in ledgers, so I
think it does make sense to think of this as the base layer. The reason to
abstract the functionality you expect from the ledger layer is precisely so
you can handle it in different ways, depending on what the underlying
systems provide.

I see 3 ways to think of the layer(s) underpinning ILP:

   1. The "Ledger Layer" provides both messaging capabilities and some type
   of HTLA
   <https://github.com/interledger/rfcs/blob/master/0022-hashed-timelock-agreements/0022-hashed-timelock-agreements.md>
   2. There are separate plugins for messaging and for transfers and when
   you peer with someone you have to agree on a plugin for each
   3. We standardize the messaging part and say that all goes over IP and
   then just have more minimal plugins for the on-ledger settlements

Number 1 is what we have and I think that still makes the most sense.

> - The protocol should differentiate between the operation of preparing a
transfer on a ledger and the operation of passing an ILP packet from one
peer to another.

The protocol assumes your conditional transfer is underpinned by some HTLA
<https://github.com/interledger/rfcs/blob/master/0022-hashed-timelock-agreements/0022-hashed-timelock-agreements.md>.
It doesn't care whether that's on-ledger or not.

> - The condition and timeout should be included in the ILP payment packet.

I strongly disagree with this. We had this debate a year ago and I was on
your side but was convinced that this is not a good idea.

The layer below ILP must be capable of doing conditional transfers based on
sha256 hashlocks with 32-byte preimages. As a result, the original
condition and the corresponding preimage MUST be expressed in that layer.
Then the question is whether we should also include it in the packet that
is forwarded. What ultimately convinced me is the following: All connectors
MUST ignore the condition if it is in the packet, because they are only
guaranteed their money back if they use the same condition from the
incoming transfer they got. Also, the receiver will need to take out the
condition in order to hash the packet for PSK or IPR. So basically, no one
wants the condition in there. It feels like it ought to be in there, but
literally none of the parties want the extra 32 bytes in there.

The reason the timeout should not be in there is that there isn't a single
timeout for the payment. There are multiple separate timeouts for each of
the bilateral transfers. Those must go in the individual transfers and
there is no sensible value to put in the Interledger packet.

On Mon, Aug 14, 2017 at 12:58 PM Adrian Hope-Bailie <adrian@hopebailie.com>
wrote:

> I have had an ongoing debate with a number of people about the correct way
> to architect the protocol layering for Interledger. This has been an
> excellent discussion and I've made some valuable realizations (and conceded
> some mistakes on my part) along the way but I am still convinced that we
> have some errors in our architecture which are making the whole stack
> unwieldy and making it difficult to progress on designs for other layers.
>
> There is a sense that we should not be changing the core packet
> definitions any more but I'm not sure what justifies this. We have a
> limited number of implementations and the specifics of the packet formats
> and encapsulation are confined to a single library in both. Furthermore,
> the fundamentals of the protocol don't change, just the packet formats and
> layering to better reflect the protocol and not be influenced so strongly
> by the implementation.
>
> This is my attempt to explain my rationale and solicit feedback from the
> community. Hopefully we can come to consensus on the right design (ignoring
> concerns about X is frozen; or "we said we aren't going to change Y
> anymore" or this will break Z). Once we have a design we consider correct,
> let's count the cost and decide if it's a v2 or we can implement it now.
>
>
> *Protocol Layering: Request/Response at the core*
> Protocol layering is a mature pattern. The layering is achieved through
> encapsulation. A packet contains headers and a payload, and the payload is
> the packet of the next layer up.
>
> In the Internet stack the internetworking layer is the IP layer. Packets
> are addressed using IP addresses and layers above rely on these addresses
> to introduce messaging semantics. Layers below are host-to-host protocols
> that carry the IP packet from one host to another. *All data in the
> host-to-host protocol is discarded* when the packet is de-framed and
> re-framed for the next hop.
>
> The internetworking layer in the ILP stack is the Interledger layer. At
> this layer packets are used to carry payments, quotes and errors and are
> addressed using an Interledger Address. Similar to IP there are
> host-to-host protocols that exist below ILP and carry the ILP packets over
> each hop and higher layer protocols that carry end-to-end data encapsulated
> in the payload of the ILP packet.
>
> Currently, ILP requires that data outside the packet be passed along with
> the packet instead of inside the packet, requiring special treatment of
> specific hots-to-host data and making it very difficult to add/change this
> data in future.
>
> A critical difference between IP and ILP is in the messaging semantics. IP
> has none. A packet simply contains a source and destination address and
> higher layers use these (and introduce additional properties such as ports)
> to establish reliable connections, sessions etc. In contrast, ILP only
> works if ILP packets exist as request/response pairs and the response
> packets follow exactly the same route as the request packets.
>
> As such an ILP request packet has no source address, as this is useless. A
> response packet can't simply be addressed to the source of the request and
> sent. *A response packet must retrace the route of the request.*
>
> One may argue (as I did before) that a request/response pair should then
> have a unique end-to-end identifier that nodes can use to associate a
> request with it's original response, however there is a danger in relying
> on this identifier as it could be manipulated to cause responses to fail.
> If you can't rely on it, why have it at all?
>
> As such, a node at the Interledger layer MUST maintain state and be able
> to, not only match request/response pairs at the host-to-host layer but
> also,
> *match an incoming request/response pair to an outgoing request/response
> pair.*
>
> How a host does this not defined in the protocol but it means that at a
> minimum the host-to-host protocols must allow request/response pairs to be
> matched AND uniquely identified.
>
> Example:
>
> When Host B receives Response A from Host C it must pass that on as
> Response 1 to Host A. This would have to be recorded during the routing of
> Request 1 to Request A.
>
> Host A                    Host B                    Host C
>        --- Request 1 -->         --  Request A -->
>        <-- Response 1 --         <-- Response A --
>
> In protocol stacks like IP and ILP the internetworking layer is the glue
> between lower host-to-host layers and higher end-to-end layers. To avoid
> overloading the internetworking packets themselves it should be possible to
> encapsulate higher level protocol packets in the internetworking layer
> payload.
>
> Another unique feature of ILP (where it differs from IP) is that some
> Interledger packets carry value. You can look at this two ways:
> 1. The ILP payment packet carries value end-to-end.
> 2. The ILP payment packet carries data end-to-end but the sender pays for
> this.
>
> There are two basic request types in ILP, those that carry data and those
> that carry both data and value.
>
> For all request types there is a valid response type but the response
> could also be an error. Example: the response to a payment is a
> fulfillment, the response to a quote by source amount request is a quote by
> source amount response.
>
> In summary:
> - ILP depends on request/response semantics at it's core (these are a
> requirement of the internetworking layer itself, not just higher level
> protocols).
> - As such, the internetworking layer packets must be either a request or a
> response and the protocol should define which responses are valid for which
> requests and all requests should have a response.
> - There are two primary request packet types (a request carrying data and
> a request carrying data and value).
> - There are two primary response types, a success and failure response.
> The success responses are sub-typed to match the sub-type of the request,
> however the error response could be returned for any request.
>
> Proposal:
> - All interledger layer messages should be ILP packets (including
> fulfillments) and be capable of carrying higher layer protocol payloads.
> - While it may make sense to split the interledger payment and interledger
> quoting protocols into new higher level protocols that seems like an
> unnecessary abstraction. Instead the packet definitions should just have
> some consistency and probably a common base/header.
> - We should define two base ILP packet types: request and response.
> - A payment packet should extend the request type and fulfillment and
> error should extend response.
> - The ILQP packets already roughly follow this pattern but perhaps a
> generic message packet is also required.
>
> *Ledgers and Trustlines*
>
> For some time there has been a debate about what constitutes the nodes and
> what the edges in the Interledger graph. As we've begun to appreciate the
> various different forms a line of trust between two peers can take it's
> become clear that ledgers are not actually core to the protocol (despite
> the name). If you consider senders, receivers and connectors to be the
> nodes, then edges are simply lines of trust between any two nodes.
>
> In other words the Interledger is made of nodes that are connected via
> financial agreements of some form that allow for two nodes to transfer
> value between one another. This agreement may or may not be underwritten by
> a ledger that supports conditional transfers. Where there is a ledger that
> both parties trust to perform conditional transfers correctly the parties
> no longer need to trust one another (they trust the ledger).
>
> The Interledger works because not only does it define a universal address
> space for this network, it also defines a universal signature scheme for
> payment requests and receipts that can be leveraged by individual
> trustlines on the route of a payment, for conditional transfers between two
> peers.
>
> When two disconnected nodes wish to setup a payment they exchange data so
> that the sender has, at a minimum, the address of the receiver, a condition
> that the receiver can fulfill and the amount (in the receiver's currency)
> that the receiver must receive. Next the sender finds a peer to send a
> local transfer to, to initiate the end-to-end payment. They package all of
> the end-to-end data in an ILP packet and make the local transfer (attaching
> the packet or sending it to the peer separately).
>
> The terms of the local transfer are: "Show me the signature from the
> receiver that proves they were paid and you get the proceeds of the local
> transfer."
>
> These terms can be enforced in a variety of ways, one of which is by
> making the transfer on a ledger that understands the condition and
> fulfillment format and supports conditional payments. This protects the
> sender from their upstream peer in the case where they are unable to
> produce the fulfillment but still want to claim the proceeds of the
> transfer. i.e. It simply changes who the sender trusts (the ledger instead
> of the peer)
>
> How the ILP packet is transferred to the peer and how the transfer is
> setup on the ledger *are very different concerns*. It is a mistake to
> assume that the communication mechanism between peers is the creation of
> the transfer on the ledger itself. I believe that some of the confusion
> around this comes from the design of 5-bells ledger where these are the
> same thing.
>
> Consider the following setup where the ledger supports conditional
> transfers but does not support notifications as an example.
>
> Peer A
> Ledger                                              Peer B
>
>   | -- LocalTransfer(LocalAmount,Condition) -->
> |                                                   |
>   | <----------- Prepared --------------------- |
>                                              |
>   | -------------- ILP Payment Request (ILP Address, RemoteAmount,
> Condition) --------------------> |
>   |                                             | <--------- Check for
> pending transfer------------ |
>   | <----------------------------------------- Ack
> ------------------------------------------------ |
>   | - Poll for completed transfer (Optional) ->
> |                                                   |
>   |                                             |
>                                              | --> Transfer
>   |                                             |
>                                              | <-- Fulfillment
>   |                                             | <---------- Submit
> fulfillment------------------- |
>   | <------------------------- ILP Payment Response(Fulfillment)
> ---------------------------------- |
>   | - Confirm completed transfer (Optional) -->
> |                                                   |
>
> Note how the communication between peers, carrying the ILP packet, does
> not go through the ledger. Also, note how the ledger doesn't need to
> understand anything about ILP other than supporting the universal signature
> format (conditions and fulfillments). For simplicity this example excluded
> expiry but these could just as easily be included alongside the condition
> in the direct communication between the peers (i.e. in the ILP packet).
>
> The expiry in the packet is very similar to the TTL in an IP packet.
> Theoretically it can be modified at each hop to a value that the local
> sender considers safe for the outgoing local transfer and the trustline on
> which it is sent.
>
> Summary:
>
> - ILP is not about ledgers, it is about trustlines between nodes/hosts.
> - A trustline may be underwritten by a ledger to allow nodes to establish
> a trustline-by-proxy where they trust the ledger and not their peer. This
> is possible if the ledger supports conditional payments using ILP-style
> conditions.
> - The protocol should differentiate between the operation of preparing a
> transfer on a ledger and the operation of passing an ILP packet from one
> peer to another.
>
> Proposal:
> - The condition and timeout should be included in the ILP payment packet.
> - Where the fulfillment is a signature over the packet these can be zero'd
> out first as with the checksum in an IP packet.
>
> Look forward to your thoughts!
>
>
>
>
>
>
>
>
> _______________________________________________
> Ledger mailing list
> Ledger@ietf.org
> https://www.ietf.org/mailman/listinfo/ledger
>
-- 

Evan Schwartz
Software Engineer
Managing Director of Ripple Luxembourg
<http:> <http:>

Received on Monday, 14 August 2017 20:04:21 UTC