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

A standard up for review as part of NIST's Cybersecurity Framework:  Only 3
commands are allowed to databases:  Load, Store, and Delete.

Proof of concept:  http://systemdotpersistence.blogspot.com.

Questions/comments welcome.

On Fri, Aug 18, 2017 at 4:10 PM, Andrew Bransford Brown <andrewbb@gmail.com>
wrote:

> If the human species survives, they'll say humans nearly went extinct,
> because some liked to keep secrets (top secret, secret, classified).
>
> On Thu, Aug 17, 2017 at 1:32 PM, Adrian Hope-Bailie <adrian@hopebailie.com
> > wrote:
>
>>
>>
>> On 16 August 2017 at 10:22, Ben Sharafian <sharafian@ripple.com> wrote:
>>
>>> OK, I think in that case we're mostly disagreeing over where the
>>> condition/fulfillment/expiry actually go in the data.
>>>
>>
>> That's one way to look at it but that's ultimately what the architecting
>> the layering is. Deciding at which layer (and therefor encapsulated in what
>> packet) certain data should be.
>>
>>
>>> The reason I don't agree with your position is based on which parties I
>>> think should be aware of ILP.
>>>
>>
>> I don't think that's the right way to look at it. The connector needs to
>> be able to understand at least the ILP layer data AND the lower layer data.
>> Normally the way the processing stack is implemented is that there is a
>> module for each layer that processes the data from that layer and then
>> passes the payload and any other important information up to the next layer.
>>
>>
>>> In order to track the balance between each other accurately, the two
>>> connectors have to keep track of conditions, fulfillments, and expiries on
>>> each of the transfers.
>>>
>>
>> This is where I disagree with you. Two connectors exchanging a transfer
>> only care about the data that is relevant to them for that transfer. It's
>> quite possible for two connectors to perform a transfer that has no
>> conditions or fulfillments or a transfer that has a different condition and
>> fulfillment (such as an atomic mode transfer where the condition is a
>> compound one that has multiple sub-conditions).
>>
>>
>>> That means the connectors' accounting logic that handles the conditions,
>>> fulfillments, and expiries is going to be using some information inside the
>>> ILP packet and some information outside of it in order to perform these
>>> transfers.
>>>
>>
>> It will only use info inside the packet if it uses conditional transfers
>> that use that same condition. This is the most likely scenario but that is
>> not a protocol requirement.
>>
>>
>>>
>>> I think it's cleaner to say everything required to make these local
>>> transfers should go in one protocol, so the accounting logic of these
>>> connectors doesn't have to deal with ILP directly.
>>>
>>
>> I strongly disagree with that. That's entirely the wrong reason to put
>> data into a specific layer. The data in the ILP layer is there because it's
>> "end-to-end" data.
>>
>> If a protocol at a lower layer wants to use that data then it must
>> replicate it. That seems inefficient but it's the correct way to do it.
>>
>> One could define a lower layer protocol that doesn't replicate the data
>> but the rules of the protocol are "Get the condition from the ILP packet".
>> In that case, that specific lower level protocol is forcing implementations
>> to understand the ILP packet format, that's an implementation detail.
>>
>> Another lower layer protocol might take the condition from the ILP packet
>> and re-encode it in a different form (like a base64ulr string or NI: uri)
>>
>>
>>> Then the connectors' ILP-packet-related behavior can all be routing
>>> related.
>>>
>>
>> Routing requires looking at the condition, expiry and amount. A
>> connector's routing logic shouldn't forward a packet if the expiry is too
>> low or if the condition is obviously corrupted.
>>
>> If the protocols were designed correctly as I am proposing then another
>> routing decision would be, is the condition that was used in the incoming
>> transfer the same as the one used in the ILP packet?
>>
>>
>>
>>> This would add a few benefits; two connectors could perform non-ILP
>>> conditional transfers between one another (which would be useful for
>>> reconciliation and settlement), and could also allow two connectors to use
>>> more complex condition types (i.e. signatures for atomic mode) without
>>> forcing us to support that in the ILP packet.
>>>
>>
>> You seem to have this backwards. Both of these things are supported if
>> the condition and expiry ARE in the ILP packet. Atomic mode is not
>> supported in the ILP protocol it is supported in the lower layer transfer
>> protocol. The ILP packet just contains the end-to-end condition (always a
>> SHA-256 hash) and then the local transfer can have a different condition
>> that is derived from the condition in the ILP packet.
>>
>>
>>> It also keeps the integrity of the ILP packet as something lower levels
>>> don't modify; the connector has to modify the expiry in order to pass along
>>> an ILP payment (they may not modify the expiry if they're using something
>>> like atomic mode, but then we have the issue with advanced condition types
>>> not being supported in the ILP packet).
>>>
>>
>> I think the expiry should always be the expiry set by the sender. It
>> won't be changed.
>>
>>>
>>> In the case where the ledger _does_ care about the condition and
>>> fulfillment, the argument in favor of separating
>>> condition/fulfillment/expiry from the rest of the packet is similar.
>>> Because we don't control the features of all ledgers, we'll need our
>>> plugins or ledger adapters to be aware of ILP. This makes it hard to
>>> interact with any events that don't involve ILP packets, and impossible to
>>> handle features that extend beyond what we support in the ILP packet. We
>>> could pass details about non-ILP ledger features (like a crypto condition)
>>> in the side data, but in the event of any redundancy we have to check the
>>> ledger-supplied info, not the info in the ILP packet.
>>>
>>
>> Comparing the condition in the local transfer and the one in the ILP
>> packet should be part of the routing logic.
>>
>>
>>>
>>> Basically, condition/fulfillment/expiry are used for accounting local
>>> transfers (even if they aren't being "ledger" enforced) in addition to
>>> their role as every-hop information. By putting them in the ILP packet, we
>>> limit the special features that ledgers can support and make our software
>>> abstractions harder to separate cleanly. By putting them in the local
>>> transfer alongside the ILP packet but not inside it, we do separate the
>>> data a little more, but we have more freedom in what the underlying
>>> accounting and ledger logic can do, and our software modules will have more
>>> clearly separated domains.
>>>
>>
>> They should be in both the local transfer AND the ILP packet if they are
>> needed by the local transfer protocol. This allows the flexibility you
>> desire because the local transfer protocol can do ANYTHING including using
>> the condition from the ILP packet as-is, not at all or enhanced for
>> something like atomic mode.
>>
>>
>>
>>>
>>> On Tue, Aug 15, 2017 at 10:24 AM, Adrian Hope-Bailie <
>>> adrian@hopebailie.com> wrote:
>>>
>>>> Exactly 👍
>>>>
>>>> On Tue, Aug 15, 2017 at 6:52 PM Ben Sharafian <sharafian@ripple.com>
>>>> wrote:
>>>>
>>>>> Ok, I think I have a better idea of what you're saying.
>>>>>
>>>>> It sounds like you're saying the ILP layer contains all information
>>>>> that is common between every hop (destination, destination amount, opaque
>>>>> data, condition, fulfillment, expiry). The lower level would then be used
>>>>> for all the transfer-local details (source amount, next connector account,
>>>>> custom/local data).
>>>>>
>>>>> If the lower level wanted to do anything related to the every-hop
>>>>> payment, i.e. escrow funds until the receipt has been produced, it would
>>>>> look into the ILP layer for that information. If the lower level didn't do
>>>>> any escrow or expiries that require every-hop details, it would simply
>>>>> function as a communication method.
>>>>>
>>>>> Is that right?
>>>>>
>>>>> On Tue, Aug 15, 2017 at 6:35 PM, Adrian Hope-Bailie <
>>>>> adrian@hopebailie.com> wrote:
>>>>>
>>>>>>
>>>>>>
>>>>>> 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.
>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>> --
>>>> Sent from a mobile device, please excuse any typos
>>>>
>>>
>>>
>>
>

Received on Friday, 18 August 2017 20:14:21 UTC