W3C home > Mailing lists > Public > public-interledger@w3.org > August 2017

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

From: Adrian Hope-Bailie <adrian@hopebailie.com>
Date: Tue, 15 Aug 2017 18:35:43 +0200
Message-ID: <CA+eFz_J=YtT=coni9qy-gvveJKJGejCNmvFOHGxFMfGFUoKCYQ@mail.gmail.com>
To: Ben Sharafian <sharafian@ripple.com>
Cc: Evan Schwartz <evan@ripple.com>, Interledger Community Group <public-interledger@w3.org>, Interledger Mailing List - IETF <ledger@ietf.org>
On 15 August 2017 at 16:00, Ben Sharafian <sharafian@ripple.com> wrote:

> 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>
>>>
>>>
>>>    1. There are separate plugins for messaging and for transfers and
>>>    when you peer with someone you have to agree on a plugin for each
>>>
>>>
>>>    1. 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.
>>
>>
> I think you're confusing implementation details and defining of interfaces
>> with definition of a protocol stack. The only differences between the tree
>> examples you have above is in implementation.
>
>
> I had to scroll up after reading this to make sure it was @adrian talking,
> because that seems like the opposite of what you were arguing for.
>

I don't think so. But I think that is part of the problem. We are not all
focused on the same thing. I am actually not very interested in CLP at all.
It is one of potentially many protocols that may exist below the ILP layer.
All we're doing by defining CLP is bootstrapping the network by defining a
protocol for everyone to use to get started.

In designing the ILP layer properly we should try and forget everything we
know about the lower layers other than what features we require of them.

There is a misconception that ILP requires the lower layers to support
conditional transfers, that is not true.

All we actually need from a lower layer protocol is to transfer data back
and forth and provide a way to reliably map requests to responses.

What ILP provides lower layers is a way to reward your peer for passing on
the packet. The Internetworking layer defines a condition, a reward that
must be paid to the receiver for the fulfillment and the time allowed to
claim this reward.

Because of this, within lower-layer protocols that offer the basic
request/response features we need, we could add conditional payment
semantics that use the condition, expiry and fulfillment provided by ILP.
This would allow a node to offer a reward to  their next peer to for
delivering the packet they send them and to make the local financial
transaction contingent on the end-to-end transaction.

But crucially, adding that semantic to the lower layer protocol provides
nothing extra to the ILP layer. The value is purely derived from the two
peers who use that protocol and can now use conditional payments to protect
themselves from their peers.


> The proposal that you're arguing for is basically asserting that we're
> going to be using CLP, because it makes the assumption that the connectors
> (who understand ILP) are managing the HTLA logic.
>

Not at all. I am asserting that it doesn't matter what protocol you use
below the ILP layer because it shouldn't matter. All of this talk about ILP
being different because money is more important than data is nonsense.

The difference between ILP and IP that makes ILP suitable for value
transfer and IP not is at the internetworking layer. ILP requires that all
packets are either a request or response and that the responses follow the
same path as the requests. Further ILP defines a signature scheme that
gives the sender a way to be certain the request was received by the
receiver.

*This could be done entirely without money* but then there would be little
incentive to sign the receipt or deliver the signature back to the original
sender.

So, if you add money then you add economic incentives to the mix. At each
hop the sender promises the next upstream peer a payment if they can return
the receipt. The net effect is that this can be used to transfer money from
the sender to the receiver by simply defining up front the amount that the
receiver must get to produce the signature.


>
> In the current model, the CLP/trustline model and the direct ledger model
> both work without having to treat anything on the ILP layer differently.
> We're favoring on-ledger messaging because of our implementation, yes, but
> we've been able to switch most all of our plugins from on-ledger messaging
> to RPC-based messaging without changing the ILP layer at all.
>
> With the ledger-level abstraction, we were able to switch from our
> ledger-based mode of thinking to the CLP/trustline based way without
> changing anything other than the plugin. Your argument comes from an
> assumption of a CLP-style ledger protocol with some underlying ledger,
> which we can't assume is always the case.
>

I'm not sure what any of that proves tbh. These are all implementation
concerns. They don't change the fact that the condition, expiry and
fulfillment are part of ILP not the lower layer protocols.

>
>
> From the perspective of the Interledger Protocol the implementation of the
>> lower layers is not important, that's the whole point of layering. By
>> forcing important aspects of ILP like the condition, fulfillment and expiry
>> down into those layers you muddy the waters and we now have to standardize
>> those protocols too. Instead we should just be defining the functions they
>> must provide and then leave it up to implementations to provide those
>> functions.
>
>
> I don't agree with this point; the condition and fulfillment have actual
> meaning to the ledger layer.
>

NO THEY DON'T! They have meaning to SOME ledgers that implement SOME lower
layer protocols, IF they choose to use them.

Excuse the shouting but this is the crux of the issue. We need to all agree
that it is entirely possible for a transfer to be done that doesn't use the
condition and fulfillment and that if this was in the middle of a 10-hop
ILP payment it would have no effect on the sender and receiver.

>
> You've said that the ledger often doesn't care about fulfillment and
> condition, but the ledger _layer_'s (where transfers are done) role is to
> take in condition and fulfillment and make a transfer which satisfies its
> HTLA.
>

No, the ledger's role is to keep a tab of net financial positions between
two peers. It MAY use conditions and fulfillments that it pulls from the
ILP layer to help it do that in a way both peers agree on.

Note that a "layer" doesn't have a role. I think there is some confusion
about the difference between layering the protocol and abstracting
functionality into different components.


> If the ledger layer has to look into the ILP packet to do so, that is a
> blatant breaking of layering.
>

Not at all! The module acting at the layers *below* the internetworking
layer shouldn't modify anything inside the packets of the higher layers but
they can definitely inspect them and adjust their behavior based on what
they to find.

In fact the prevalence of this is the subject of a lot of debate at the
IETF currently because endpoints are often encrypting their payloads and in
some cases this makes it difficult for middle-boxes to be effective at
their jobs.

By putting the condition, fulfillment, and expiry on the ledger layer, we
> leave it open for any ledger type to work, rather than forcing all
> ledger-layer software to understand ILP.
>

Actually you do the opposite. You make it a requirement of every protocol
below the ILP layer to define a way to carry these data elements and encode
and decode them, even if they don't use them

Ledger layer components don't have to understand ILP unless they choose to
re-use the condition for their own local transfer. Ledgers themselves
*never* have to understand ILP.

Remember a ledger layer protocol could use a completely different
conditional payments scheme, like atomic mode ILP, where it takes the
end-to-end condition and creates a new compound condition that depends on
the fulfillment and some notary signature.

There will be a component in a connector's stack that must pass the ILP
packet to the next peer. If it does this using a transfer protocol that
uses conditional transfers and wants to use the same condition as the ILP
packet then it must decode the packet.

But, it will likely do something with that condition before sending the
transfer to the ledger like encoding it differently or rehashing it
(lightning?) so that it's in the form expected by the ledger.

That's an implementation decision of the lower layer protocol used between
those two peers.


>
> I agree that Interledger defines how conditions, fulfillments, and
> expiries should be chained together, but it makes no assertions about their
> data format.
>

ILP doesn't define how anything is chained together. From the perspective
of ILP the condition and fulfillment are end-to-end data. They are agreed
by the two endpoints who don't care how they get from Alice to Bob and back.

The design of ILP is such that it facilitates the design of lower level
protocols that can be used to carry the ILP packets across multiple hops
(networks) using economic incentives such that the sender pays enough for
the first hop to ensure that all nodes in between can extract the fee they
want and the receiver will still get the amount they expected..



> ILP says you should send your outgoing transfer with the same condition as
> the incoming one, and a lower expiry.
>

No it doesn't. An internetworking protocol can't prescribe that kind of
thing to lower level protocols. An incoming and outgoing transfer could be
sent using completely different protocols and the financial agreement with
the peers on those two routes could be vastly different too.

The only service ILP requires of lower level protocols is that they can map
a response to an original request. This requirement is okay because it is
isolated to a single route/link at a time not a requirement that crosses
the inter-network boundary that ILP crosses.


> But because ILP allows for many different types of ledgers, it doesn't
> make sense to assert how these are encoded.
>

By putting them in the ILP packet you do the opposite. You make no
assertions about how they are encoded if they are used at lower layers, or
how they may be combined with other conditions or even used to derive new
conditions.

>
> IP doesn't tell you how to encode an ethernet packet. It doesn't even know
> whether it's going over a computer or a hand-written letter carried by a
> pigeon. IP takes for granted that you can send data over one connection by
> putting it in a lower level.
>

Correct, but if a link layer protocol wanted to look into the IP packet
headers of a packet it wants to transfer and use some data from there in
its internal logic (or even reuse data in it's own frame) that would be
totally fine.


> Even though IP tells you how to chain these connections together, it
> doesn't have to put the things it's chaining on the internetworking level.
>

IP doesn't tell you how to chain things together. IP simply defines the
end-to end data envelope and address space. Because of this nodes that
implement the multiple lower layer protocols are able to push IP packets
down a link and expect the node on the other side to understand the headers
and route it onward on another link.

Everything needed by the IP module to decide what to do with the packet is
in the IP packet headers. i.e. Has it exceeded a TTL? Is there a route for
this destination? Is it corrupted (checksum fails)? But also, everything
that is needed by the endpoint (like the source address) is also in there.

There is no dependency on nodes to be good citizens and always pass certain
other data from the lower layers into the next link. That would be breaking
the layering.


> IP also assumes that if you get some incoming data on a connection you can
> copy it and send it out on the next connection. Because you can already
> send data over a connection, all IP adds is the missing piece: a packet
> that tells you where to go.
>
> With ILP, we assume that there is a way to prepare a conditional transfer,
> expire a conditional transfer, and fulfill a conditional transfer.
>

No we don't! We assume that if we deliver the packet as intended we'll get
back a response packet with a signature that matches the condition in the
packet. So, if we have an agreement with someone that they will pay us when
we present that signature then we are prepared to enter a similar agreement
with the next peer because we expect that signature to come all the way
back along the interledger layer route..


> We also assume that if you get an incoming transfer you can create an
> outgoing transfer with the same condition. The abstraction we made means
> that conditions and fulfillments are already carried in the lower levels.
>

That is a bad assumption that comes from the broken layering. What if my
outgoing link doesn't support conditional transfers? So now where do I put
the condition?

>
>
> We could have assumed that no ledgers ever support conditional transfers,
> and said the only thing ILP gets from lower levels is the ability to send a
> transfer. But if we want to support the case where any of them do, we have
> to keep the conditions and fulfillments in the layer where they're actually
> used.
>

I don't follow that logic at all. If we want to support the case where any
of them do then we must ensure the condition and expiry are always carried
in a consistent place at the internetworking layer so that if they do want
to use them they know where to find them.


>
> On Tue, Aug 15, 2017 at 12:04 PM, Adrian Hope-Bailie <
> adrian@hopebailie.com> wrote:
>
>>
>>
>> On 14 August 2017 at 22:03, Evan Schwartz <evan@ripple.com> wrote:
>>
>>> 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.
>>>
>>
>> This is not correct. There is no requirement on ledger layer protocols to
>> transmit or understand the fulfillment. You are looking at this through the
>> lens of existing implementations from the bottom up instead of starting at
>> the interledger layer.
>>
>> The primary function of the condition and fulfillment is as a signed
>> end-to-end receipt. If the sender agrees a condition with a receiver and
>> then gets back the valid fulfillment they don't care what happened in the
>> middle. The receiver has signed a receipt saying they have their money.
>>
>> The value of using a standard for the receipt and signature is that each
>> transfer along the way CAN re-use it. One the one hand you can have a
>> transfer between two peers that have zero trust and the ledger they use
>> supports conditional payments completely. On the other extreme you can have
>> two peers that have a full trust and ignore the condition and fulfillment
>> completely.
>>
>> The ledger layer protocols carry ILP packets. Payment requests and either
>> fulfillment or error responses. If a ledger layer protocol wants to use the
>> condition and fulfillment for their own operations they can extract these
>> from the ILP packets and use them.
>>
>>
>>> > - 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).
>>>
>>
>> I agree that we don't HAVE to explicitly separate them out but I think ti
>> would make it clearer how the stack is architected if there was a header
>> that was consistent across all packets. Currently the only thing that is
>> consitent across all ILP packets is that they are defined int he same file.
>>
>>
>>>
>>> > - 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.
>>>
>>
>> The goal of this exercise is to tease out the best design and ignore the
>> cost of change until we can compare the results with the current design.
>>
>>
>>>
>>> > - 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.
>>>
>>
>> As above, this is incorrect. There is no requirement for "all messages to
>> go through an accounting system".
>>
>> Since designing the first implementation of 5-bells ledger we have
>> assumed that passing the ILP packet MUST be done by the ledger because that
>> is how we implemented it. But that is not true. It is perfectly valid for
>> the passing of an ILP packet from one peer to another to be simply an
>> exchange of data.
>>
>> The receiving peer makes a decision about whether or not to forward the
>> packet based on the current financial position they have with the sending
>> peer.
>>
>> It is convenient if the ledger that records the net positions of the
>> peers also forwards the messaging and even better if it natively supports
>> conditional payments and can use the condition and the fulfillment from the
>> ILP packet for those but that's all it is, convenient.
>>
>>
>>
>>> 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.
>>>
>>
>> I think you're confusing implementation details and defining of
>> interfaces with definition of a protocol stack. The only differences
>> between the tree examples you have above is in implementation.
>>
>> From the perspective of the Interledger Protocol the implementation of
>> the lower layers is not important, that's the whole point of layering. By
>> forcing important aspects of ILP like the condition, fulfillment and expiry
>> down into those layers you muddy the waters and we now have to standardize
>> those protocols too. Instead we should just be defining the functions they
>> must provide and then leave it up to implementations to provide those
>> functions.
>>
>> I know we want to define a standard to bootstrap the system (CLP) but
>> that's misleading us into thinking it's an essential part of the stack.
>> It's perfectly valid for two peers to not use CLP and still be part of the
>> Interledger.
>>
>> That said, you raise an interesting consideration about the layers below
>> ILP and actually I think it makes sense to split these.
>>
>> We keep trying to force messaging through the ledger layer and actually
>> that's the wrong place to put it if we can split the ledger layer into a
>> messaging layer and a ledger layer. That way we can stop trying to think of
>> all HLTAs as ledgers.
>>
>> A thought, why not use sub-layers as is common in other stacks:
>>
>> 1. Link layer: Layer upon which two peers that have a direct link, or
>> participate in the same payment network, communicate
>> 2. Transfer/ ledger: Layer on which financial positions between two peers
>> are recorded
>>
>> This reflects the already emerging HTLA model and many of our existing
>> plugins and ledger integrations.
>> Link Layer: XRP Paychan, Lightning
>> Ledger Layer: XRP Ledger, Bitcoin
>>
>> This doesn't prevent us from defining a standard binary protocol that
>> defines all of the operations for both layers (like CLP) but I see value in
>> distinguishing between these two.
>>
>>
>>>
>>> > - 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.
>>>
>>
>> What do you mean when you say "the protocol"? In my statement I am
>> referring to ILP.
>> My point above being that ILP expects ILP packets to be passed from peer
>> to peer but has no expectations about transfers.
>>
>> It's perfectly legal (from an ILP perspective) for two peers to exchange
>> ILP packets with no transfers. Clearly if a node routes a packet on and has
>> no incoming transfer it's going to lose money but that's a consideration
>> for that node. It doesn't affect anyone else in the chain.
>>
>> ILP doesn't assume anything about transfers at all, let alone conditional
>> transfers. It provides useful semantics for conditional transfers to be
>> used by two peers to transact as part of a larger ILP payment.
>>
>>
>>>
>>> > - 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.
>>>
>>
>> Yes, I recall this and I'm sorry I didn't push harder on this point.
>> Unfortunately I think the decision to pull it out of the packet is mostly
>> driven by how our prototypes were implemented rather than good architecture.
>>
>>>
>>> The layer below ILP must be capable of doing conditional transfers based
>>> on sha256 hashlocks with 32-byte preimages.
>>>
>>
>> This is not true and I think it would be useful for us to agree on this
>> as this seems to be the argument I am coming up against most often. The
>> peers participating in a transfer that is part of an ILP payment may wish
>> to use conditional transfers as a way to enforce their agreement but this
>> is not a requirement of the protocol.
>>
>> The agreement between any two peers is: "I will pay you X if you can
>> provide a receipt that Y was paid Z before T".
>> ILP provides a standard for expressing this agreement so that these can
>> be chained together BUT it is not a requirement that every agreement in the
>> chain uses the condition, and fulfillment provided at the ILP layer.
>>
>>
>>>
>>> As a result, the original condition and the corresponding preimage MUST
>>> be expressed in that layer.
>>>
>>
>> As I have shown above, this is not true.
>>
>>
>>> 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.
>>>
>>
>> Here is where the layering is being corrupted.
>>
>> All connectors MUST inspect the condition in the ILP packet as part of
>> their decision to route the packet or not.
>> When the local transfer module of the connectors stack passes the ILP
>> packet up to the ILP module it should indicate the properties of the
>> incoming transfer that carried the packet.
>> This is essential firstly so that the routing logic in the ILP module can
>> record the incoming transfer identifier so it is able to use the correct
>> response id when it passes back the fulfillment or error.
>> The other properties that the ILP module should look at are the condition
>> and expiry on the incoming transfer.
>>
>> If the incoming route uses conditional transfers and these are supposed
>> to match the condition and expiry in the ILP packet then the ILP module
>> should compare them and reject the packet if:
>> a) the conditions don't match OR
>> b) the expiry is too short
>>
>> We should still discuss if the expiry should be set by the sender and
>> left unchanged or used like a TTL and decremented by each node.
>>
>>
>>> Also, the receiver will need to take out the condition in order to hash
>>> the packet for PSK or IPR.
>>>
>>
>> This is completely normal. Zeroing a checksum field in a header before
>> calculating the checksum is VERY common precisely because it's long been
>> accepted that the right place to put that data is in the headers and the
>> work of zero'ing it out to calculate the checksum (or signature in our
>> case) is not material.
>>
>>
>>> 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.
>>>
>>
>> "Nobody wants it there" is a terrible reason to abandon the correct
>> design. The whole purpose of a good architecture is you accept that there
>> may be cases in future that haven't been considered now so designing just
>> for the known cases is a bad idea.
>>
>> Good architecture is not the same as optimization. Taking stuff out (even
>> when it feels wrong) to save a few bytes is a good sign that it's a bad
>> idea.
>>
>>
>>>
>>> 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.
>>>
>>
>> As above, this is somewhat equivalent to the TTL in an IP packet. I'm
>> open to discussing if it should be a fixed value set by the sender where
>> each node uses their own value but has the sender-defined value as a
>> reference or it is actually decremented at each hop.
>>
>> Either way, this is part of ILP not the ledger layer just like the
>> condition and fulfillment. It may be used by the ledger layer but that's
>> implementation specific. It belongs in the ILP packet.
>>
>>>
>>>
>>>
>>
>
Received on Tuesday, 15 August 2017 16:36:09 UTC

This archive was generated by hypermail 2.3.1 : Tuesday, 15 August 2017 16:36:09 UTC