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

From: Adrian Hope-Bailie <[email-masked]>
Date: Mon, 14 Aug 2017 18:57:55 +0200

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!

---

From: Evan Schwartz <[email-masked]>
Date: Mon, 14 Aug 2017 20:03:44 +0000

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 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 <[email-masked]>
wrote:

> 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.
>
> 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:
> - 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,
> - A payment packet should extend the request type and fulfillment and
> error should extend response.
> 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.
>
> 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).
>
> - 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.
> _______________________________________________
> Ledger mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/ledger
>
-- 

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

---

From: Adrian Hope-Bailie <[email-masked]>
Date: Tue, 15 Aug 2017 12:04:33 +0200

> 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.

> 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.

> 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.

> 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.
>
>    1. The "Ledger Layer" provides both messaging capabilities and some
>    type of HTLA

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.
>

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.

> 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.

> 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.

> 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.

---

From: Melvin Carvalho <[email-masked]>
Date: Tue, 15 Aug 2017 13:12:38 +0200

> packets follow exactly the same route as the request packets.

This is a great point.  IP and ILP do differ in this way.  This is
something that has always struck me.  As such it is easy for IP to
facilitate Turing complete infrastructures, of which HTTP and other
protocols provide open ended semantics, via specifications (e.g. JSON-LD).
ILP seems to be the solution to a specific pain point, which seems a
reasonable approach.

If at this point, changing the packet structure will cause too much
friction, why not work on ILP 1.0 and ILP 2.0?  Im sure some lessons will
be learnt from the first version.

ILP is quite high on my list to convert to a scale free architecture
closely aligned with the web.  Finding time is always a challenge, tho.
It's something I'd love to see developed further.

---

From: Ben Sharafian <[email-masked]>
Date: Tue, 15 Aug 2017 16:00:32 +0200

>>    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
>>
> 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. 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.

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.

> must provide and then leave it up to implementations to provide those

I don't agree with this point; the condition and fulfillment have actual
meaning to the ledger layer. 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. If the ledger layer has to look into the ILP
packet to do so, that is a blatant breaking of layering. 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.

I agree that Interledger defines how conditions, fulfillments, and expiries
should be chained together, but it makes no assertions about their data
format. ILP says you should send your outgoing transfer with the same
condition as the incoming one, and a lower expiry. But because ILP allows
for many different types of ledgers, it doesn't make sense to assert how
these are encoded.

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. 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 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. 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.

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.

On Tue, Aug 15, 2017 at 12:04 PM, Adrian Hope-Bailie <[email-masked]>
wrote:

>> 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.
>>
>
>>    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
>>
> My point above being that ILP expects ILP packets to be passed from peer
> to peer but has no expectations about transfers.
>
>> As a result, the original condition and the corresponding preimage MUST
>> be expressed in that layer.
>>
>
> "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.
>
>> 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.
>>
>

---

From: Adrian Hope-Bailie <[email-masked]>
Date: Tue, 15 Aug 2017 18:35:43 +0200

On 15 August 2017 at 16:00, Ben Sharafian <[email-masked]> wrote:

> 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.

> 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.

> 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.

> 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.
>
> 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?

> to keep the conditions and fulfillments in the layer where they're actually

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 <
> [email-masked]> wrote:
>
>>
>>
>>> 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).
>>>
>>
>> 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.
>>
>> 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
>> 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
>>> > - 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.
>>>
>>> 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.
>>>
>>
>> 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.
>>
>> 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
>>> 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.
>>>
>>
>> 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:
>> 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.
>>
>>
>>> 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.
>>>
>>
>> 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.
>>

---

From: Ben Sharafian <[email-masked]>
Date: Tue, 15 Aug 2017 18:52:40 +0200

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 <[email-masked]>
wrote:

>> 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.
>>
>
> *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.
>
> 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.
>
>>
>> ILP says you should send your outgoing transfer with the same condition
>> as the incoming one, and a lower expiry.
>>
>
> 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
>> 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.
>>
>
> 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
>> With ILP, we assume that there is a way to prepare a conditional
>> transfer, expire a conditional transfer, and fulfill a conditional
>> transfer.
>>
>
>>> 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 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.
>>>
>>>
>>> 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
>>>> 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
>>> As above, this is incorrect. There is no requirement for "all messages
>>> to go through an accounting system".
>>>
>>> 2. Transfer/ ledger: Layer on which financial positions between two
>>> peers are recorded
>>>
>>> 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 layer below ILP must be capable of doing conditional transfers
>>>> based on sha256 hashlocks with 32-byte preimages.
>>>>
>>>
>>> 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.
>>>
>>> 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.
>>>
>>>
>>>>

---

From: Adrian Hope-Bailie <[email-masked]>
Date: Tue, 15 Aug 2017 17:24:23 +0000

Exactly 👍

On Tue, Aug 15, 2017 at 6:52 PM Ben Sharafian <[email-masked]> wrote:

> It sounds like you're saying the ILP layer contains all information that
> is common between every hop (destination, destination amount, opaque data,
> On Tue, Aug 15, 2017 at 6:35 PM, Adrian Hope-Bailie <[email-masked]
> > wrote:
>
>>
>>
>>>>>    1. The "Ledger Layer" provides both messaging capabilities and
>>>>>    some type of HTLA
>> 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.
>>
>> 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
>>> 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.
>>>
>> NO THEY DON'T! They have meaning to SOME ledgers that implement SOME
>> lower layer protocols, IF they choose to 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
>> That's an implementation decision of the lower layer protocol used
>> between those two peers.
>>
>>
>>>
>> 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.
>>
>> 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 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.
>>
>>
>>>
>>>> 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
>>>> 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.
>>>>
>>>>
>>>>>
>>>>>    1. The "Ledger Layer" provides both messaging capabilities and
>>>>>    some type of HTLA
>>>> That said, you raise an interesting consideration about the layers
>>>> below ILP and actually I think it makes sense to split these.
>>>>
>>>> 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.
>>>>
>>>>> As a result, the original condition and the corresponding preimage
>>>>> MUST be expressed in that layer.
>>>>>
>>>>
>>>>> Also, the receiver will need to take out the condition in order to
>>>>> hash the packet for PSK or IPR.
>>>>>
>>>>
Sent from a mobile device, please excuse any typos

---

From: Michiel de Jong <[email-masked]>
Date: Tue, 15 Aug 2017 20:21:07 +0200

Thanks for writing this up Adrian, I finally get it now. :)

Yes, seen that way, it makes sense to say we want to have pure Interledger
requests and pure Interledger responses. Even if it's just so that we can
log them at that level.

I agree with you that the view of "the condition and timeout belong to the
ledger" is ledger centric or maybe even 5-bells-ledger centric, and it does
not make sense if you design the Interledger layer first, and then
afterwards look at what lower level systems you would need to implement it.

I think the fields I would log about an Interledger payment request (and
it's up to the lower layers to support these in whichever way), would be:

* source amount
* source timeout
* condition
* destination amount (aka higher-level value payload)
* destination address
* data (aka higher-level data payload)

When you forward such a request, you decrease the source amount (also
converting the source amount to the next currency, if necessary) and you
make the source timeout a bit earlier, but the other 4 fields stay the same.

The response probably needs, in case of success:
* fulfillment
* time at which the response was sent (< source timeout)

And in case of rejection:
* rejectionReason

QuoteRequests and QuoteResponses are probably already quite complete?

Then on the host-to-host level, two hosts would do accounting of which
payments were fulfilled correctly.

It's now interesting to look at the "condition lives on two layers" issue
from the opposite perspective:

The ledger (accounting system) should be very careful not to have a
separate way to represent the condition, because if that "ledger condition"
would be different from the condition in the Interledger packet, then the
ledger would be wrong. :)

I don't really want to change CLP now, but at the same time, Adrian does
have a point that the way CLP is proposed in
https://github.com/interledger/rfcs/pull/271 is a host-to-host API design,
and it would be better to design proper protocol layers into it.

So I would vote for, let's just get to work with CLP as we have it now, but
consider developing a v2 in which this layering is cleaned up?

Apart from the reshuffle of the nesting of fields, it would mean the
accounting/reconciliation system needs to reach into the Interledger
request and response, to see the amount, timeout, condition, and
fulfillment, compare them, and decide if the balance should change, so
that's a bit of a change form CLP's current design.

My 2ct,
Michiel.

On Tue, Aug 15, 2017 at 7:24 PM, Adrian Hope-Bailie <[email-masked]>
wrote:

>> 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 <
>>>>>>    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
>>>>>>
>>> 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.
>>>
>>> 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.
>>>
>>> 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.
>>>
>>>
>>>>
>>>> I don't agree with this point; the condition and fulfillment have
>>>> actual meaning to the ledger layer.
>>>>
>>>
>>> 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.
>>>
>>> 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
>>> 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
>>>
>>> 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.
>>>
>>>>>> 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
>>>>> 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.
>>>>>
>>>>>>    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
>>>>>>
>>>>> 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.
>>>>>
>>>>>> 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.
>>>>>>
>>>>>
>>>>> 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.
>>>>>
>>>>> 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.
>>>>>
>>>>>
>>>>>>
>>>>> 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:

---

From: David Nicol <[email-masked]>
Date: Tue, 15 Aug 2017 18:24:31 -0500

here's a fine referenice for the OSI reference model:
http://www.webopedia.com/quick_ref/OSI_Layers.asp

The ILP project lives entirely in layer 7. Specific implementations would
be constrained to specific choices in the lower levels, but I don't think
ILP should care if the data is in ASCII or EBCDIC -- which is contrived, as
all right-thinking protocols have demanded Unicode UTF8 for some years now.
But still it shouldn't matter. And likewise for if messages are JSON-LD or
Bencoded. Shouldn't matter.

All the communications are over reliable bi-directional streams. That might
fail at any time for any reason, but when they aren't failing they're
reliable bi-directional streams. if the failure is "NETWORK TIMEOUT" or
some other kind of failure, that doesn't matter, it's a failure of a
stream. Which is too detailed, a failure of a stream implies a failure of a
message, which as a semantic thing is composed of key/value or index/value
associations, regardless of encoding or wire-protocols.

In the language of that reference, ILP's internal layers (atop semantic
messages between peers) would be "tiers" in a "tiered application
architecture."

okay that's my two cents.

---

From: Ben Sharafian <[email-masked]>
Date: Wed, 16 Aug 2017 02:22:53 -0700

OK, I think in that case we're mostly disagreeing over where the
condition/fulfillment/expiry actually go in the data. The reason I don't
agree with your position is based on which parties I think should be aware
of ILP. I'll hold off on arguments about which current implementations this
would break.

There are a lot of cases where the ledger isn't going to care about the
condition and fulfillment of an individual interledger payment. In this
situation, transfers would be sent directly between two connectors. The
connectors would still keep track of the balance between them (you could
contrive a situation where this doesn't happen, but I think we can say
tracking the balance is going to be the norm). 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.
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.

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. Then the connectors'
ILP-packet-related behavior can all be routing related. 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. 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).

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.

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.

---

From: Adrian Hope-Bailie <[email-masked]>
Date: Thu, 17 Aug 2017 18:32:46 +0100

On 16 August 2017 at 10:22, Ben Sharafian <[email-masked]> wrote:

> 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).

> ILP packet and some information outside of it in order to perform these

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.

> 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.

> 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.

> 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 <
>>>>>>>    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
>>>>>>>
>>>>>>>
>>>> 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.
>>>>
>>>>
>>>> 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.
>>>>
>>>>> ILP says you should send your outgoing transfer with the same
>>>>> condition as the incoming one, and a lower expiry.
>>>>>
>>>>
>>>> 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?
>>>>
>>>>>
>>>>>
>>>>>> 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.
>>>>>>
>>>>>> 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.
>>>>>>
>>>>>>
>>>>>>>
>>>>>>> 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.
>>>>>>>
>>>>>>
>>>>>> As above, this is incorrect. There is no requirement for "all
>>>>>> messages to go through an accounting system".
>>>>>>
>>>>>>>    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
>>>>>> 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.
>>>>>>
>>>>>> This reflects the already emerging HTLA model and many of our
>>>>>> existing plugins and ledger integrations.
>>>>>> All connectors MUST inspect the condition in the ILP packet as part
>>>>>> of their decision to route the packet or not.
>>>>>> 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.
>>>>>>
>>>>>>

---

From: Ben Sharafian <[email-masked]>
Date: Fri, 18 Aug 2017 11:38:06 +0200

>
> 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).

Yes, two connectors could absolutely send an unconditional transfer on an
underlying ledger in order to settle an Interledger payment. But in order
to benefit from any of Interledger's guarantees (trustless connectors,
retry-ability, etc.), they MUST keep a conditional local transfer, at least
for clearing. If the local transfer cannot time out, it cannot be safely
retried. If the local transfer clears without a fulfillment, it loses the
"receipt or your money back" property. Yes, two parties in the chain could
eschew these benefits but that is no longer a correct implementation of
Interledger.

> replicate it. That seems inefficient but it's the correct way to do it.

What's the actual reasoning behind this, and why is it considered the
correct approach? If there's some IETF document that says this I'd like to
see it, because it intuitively feels wrong to have lower level abstractions
looking into higher levels.

> condition is obviously corrupted.

Those are validity checks and you're right that they are performed in the
connector, but the destination account, destination amount, and data are
enough to figure out what the best next hop is.

The ILP Packet's purpose is to describe where a payment is going. The data
it carries is only for the purpose of making sure the receiver can identify
that payment. In that context, the expiry has no bearing on where it will
be routed nor on how much to route, only on whether or not an individual
connector will take the risk of forwarding it.

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.

Fair enough; in your case you can transmit the condition twice and verify
the structure of the complex local condition, and in the
no-condition-in-ILP version you can verify the structure of the local
condition and extract the SHA256 condition to pass on.

> be changed.

That increases connector risk enormously, allowing anybody to cause a
connector to lose money by submitting a fulfillment at the last moment. If
an attacker knows enough about latency in the chain, they could even target
this attack at somebody many hops away. Staggering expiries (giving you a
minimum amount of time to fulfill a source transfer) is an easy mitigation
against this attack; we shouldn't take it out.

> should be part of the routing logic.

Sure, it can be done as an extra validity check, but it's just more code
and more attack surface. I still don't see any tangible benefit from doing
the layering in this way, aside from your assertion that it's the correct
way to do it. If you've read any documents that explain why this is the
correct way to do layering, I think I'd understand you better.

On Thu, Aug 17, 2017 at 7:32 PM, Adrian Hope-Bailie <[email-masked]>
wrote:

> 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.
> 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.
>
> 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.
>
> 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.
>
> Comparing the condition in the local transfer and the one in the ILP
> packet should be part of the routing logic.
>
>
>>
>>>> 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).
>>>>
>>>>> 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.
>>>>>
>>>>> 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.
>>>>>
>>>>>> 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.
>>>>>
>>>>> 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.
>>>>>
>>>>> 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.
>>>>>
>>>>> 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
>>>>> But, it will likely do something with that condition before sending
>>>>> the transfer to the ledger like encoding it differently or rehashing it
>>>>> 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..
>>>>>
>>>>>
>>>>>
>>>>> 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.
>>>>>>
>>>>>
>>>>> 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.
>>>>>
>>>>>
>>>>> 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
>>>>> 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,
>>>>>> 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.
>>>>>>
>>>>>>>> > - All interledger layer messages should be ILP packets
>>>>>>>> (including fulfillments) and be capable of carrying higher layer protocol
>>>>>>>> payloads.
>>>>>>>>
>>>>>>> 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.
>>>>>>> 1. Link layer: Layer upon which two peers that have a direct link,
>>>>>>> or participate in the same payment network, communicate
>>>>>>> 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.
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> 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.
>>>>>>>>
>>>>>>>
>>>>>>> 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
>>>>>>> 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
>>>>>>> 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.
>>>>>>>
>>>>>>>
>>>>>>> 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

---

From: Adrian Hope-Bailie <[email-masked]>
Date: Fri, 18 Aug 2017 14:21:59 +0100

> eschew these benefits but that is no longer a correct implementation of

Aha! That is where I disagree! Interledger is not implemented at the local
transfer layer, it is implemented at the Interledger layer. The whole point
is that it an Interledger payment can travel over payment networks that
know nothing about ILP but the greatest value comes from using ones that do.

What you're describing is an implementation of a local transfer service
that doesn't (or can't) take advantage of Interledger. In fact, this will
be the norm for most existing payment networks that we want to add to the
Interledger and this is where your work on payment channels and HTLAs comes
in to play.

If you have a local transfer channel that doesn't support conditions
natively or supports them in a way that requires some adaption you can
create an overlay network that does what's needed. Example: Bitcoin is not
a suitable network to use for ILP so we use a payment channel between the
peers that is underwritten by Bitcoin.

> looking into higher levels.

The data in the ILP layer is there for a specific reason. It's part of an
end-to-end exchange between the sender and receiver.

*Side note: It's unusual to be designing the whole stack at once so we keep
being tempted to move things around but in reality we should look at the
ILP layer in isolation and make sure it is complete. Alternatively we
should try to test our design against a number of lower and upper layer
protocols to make sure our thinking is sound.*
If we assume the ILP packet is well defined with all the ILP-required data
elements then when a lower layer wants to use that data it can but should
do it in a way that doesn't break the ILP layer for everyone else. How that
is implemented in practice will depend on the lower layer protocol.

> enough to figure out what the best next hop is.

Unless the next hop is backwards

>
> The ILP Packet's purpose is to describe where a payment is going.
>

Not only that. For comparison, an IP packet does a lot more than just
describe where a packet is going. All end-to-end concerns need to be in
there too.

> The data it carries is only for the purpose of making sure the receiver
> can identify that payment.
>

No, the condition is there so the receiver can ensure it is sending back
the correct fulfillment and the expiry to give the receiver some assurance
that the packet is still worth processing.

> In that context, the expiry has no bearing on where it will be routed nor
> on how much to route, only on whether or not an individual connector will
> take the risk of forwarding it.
>
> connector to lose money by submitting a fulfillment at the last moment.
>

Not at all. You're assuming that there is no expiry on the local transfer.
As a receiving node I have an incoming transfer with an expiry and it
carries an ILP packet that also has an expiry.

My routing logic should look at both and decide a) if this is safe to route
on (i.e. put some of my own capital at risk) and b) what expiry to set on
the next hop.

There is no incentive to change the expiry in the packet as this can only
be targeted at upstream connectors and the result will simply be that the
payment is declined and the upstream local transfer rolls back.

> If an attacker knows enough about latency in the chain, they could even
> target this attack at somebody many hops away. Staggering expiries (giving
> you a minimum amount of time to fulfill a source transfer) is an easy
> mitigation against this attack; we shouldn't take it out.
>

I agree. We would still have the local expiry.

> and more attack surface. I still don't see any tangible benefit from
> doing the layering in this way, aside from your assertion that it's the
> correct way to do it. If you've read any documents that explain why this is
> the correct way to do layering, I think I'd understand you better.
>
>
> On Thu, Aug 17, 2017 at 7:32 PM, Adrian Hope-Bailie <[email-masked]
> > wrote:
>
>>
>>
>> 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.
>>
>>
>> I think the expiry should always be the expiry set by the sender. It
>> won't be changed.
>>
>>>
>>>>>>>>>    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
>>>>>>>>>
>>>>>> There is a misconception that ILP requires the lower layers to
>>>>>> support conditional transfers, that is not true.
>>>>>>
>>>>>> 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.
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> If the ledger layer has to look into the ILP packet to do so, that
>>>>>>> is a blatant breaking of layering.
>>>>>>>
>>>>>>
>>>>>> 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.
>>>>>>>
>>>>>>
>>>>>>> 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.
>>>>>>>
>>>>>>
>>>>>> 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
>>>>>> 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.
>>>>>>
>>>>>>
>>>>>>>
>>>>>>>> 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 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.
>>>>>>>>
>>>>>>>>
>>>>>>>>>
>>>>>>>> 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
>>>>>>>>>    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
>>>>>>>>>
>>>>>>>> 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 agreement between any two peers is: "I will pay you X if you
>>>>>>>> can provide a receipt that Y was paid Z before T".
>>>>>>>>> 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

---

From: Ben Sharafian <[email-masked]>
Date: Fri, 18 Aug 2017 16:09:30 +0200

> peers that is underwritten by Bitcoin.

Exactly, when I say you need a to handle the condition and fulfillment via
a clearing layer, this "overlay network" is what I'm referring to. The
whole point of an HTLA is that from ILP's point of view it's just a
lower-level protocol that can commit conditional transfers and fulfill
them. ILP doesn't care how the ledger/HTLA works under the hood, whether
it's a clearing/overlay layer or a "real" ledger.

You're equating this "overlay network," which is a type of ledger, with the
ILP layer. If there is an overlay network that handles the condition and
fulfillment, that means you _are_ using a ledger, because the overlay
network _is_ a ledger. The ILP layer is a layer above this.

> is implemented in practice will depend on the lower layer protocol.

That's one way to see it, but what I'm wondering is why that's a better
model than saying there's a clearly defined interface that the ledger-layer
exposes, and then building the ILP layer on top of that.

There's no reason to send a backwards hop. If you don't want to forward a
payment you reject it.

> carries an ILP packet that also has an expiry.

If that's what you're talking about, the ILP packet already has an expiry.
It's implemented in the PSK details so the receiver knows whether the
packet it issued is still valid. But that's an application layer concern,
because it's only the receiver who looks at the ILP packet's expiry. The
connectors only need to know the expiries of the local transfers.

On Fri, Aug 18, 2017 at 3:21 PM, Adrian Hope-Bailie <[email-masked]>
wrote:

> *Side note: It's unusual to be designing the whole stack at once so we
> keep being tempted to move things around but in reality we should look at
> the ILP layer in isolation and make sure it is complete. Alternatively we
> My routing logic should look at both and decide a) if this is safe to
> route on (i.e. put some of my own capital at risk) and b) what expiry to
> set on the next hop.
>
>> On Thu, Aug 17, 2017 at 7:32 PM, Adrian Hope-Bailie <
>>>> 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.
>>>>
>>>
>>> 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)
>>>
>>>
>>>>>>>>>>    1. The "Ledger Layer" provides both messaging capabilities
>>>>>>>>>>    and some type of HTLA
>>>>>>> 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
>>>>>>> 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.
>>>>>>>>
>>>>>>>
>>>>>>>> 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.
>>>>>>>>
>>>>>>>
>>>>>>> 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?
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>>> 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
>>>>>>>>> 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.
>>>>>>>>>
>>>>>>>>>> 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.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 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.
>>>>>>>>>
>>>>>>>>>>    1. The "Ledger Layer" provides both messaging capabilities
>>>>>>>>>>    and some type of HTLA
>>>>>>>>> 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.
>>>>>>>>>
>>>>>>>>> 2. Transfer/ ledger: Layer on which financial positions between
>>>>>>>>> two peers are recorded
>>>>>>>>>
>>>>>>>>> My point above being that ILP expects ILP packets to be passed
>>>>>>>>> from peer to peer but has no expectations about transfers.
>>>>>>>>>
>>>>>>>>>> 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.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 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.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> All connectors MUST inspect the condition in the ILP packet as
>>>>>>>>> part of their decision to route the packet or not.
>>>>>>>>>> Also, the receiver will need to take out the condition in order
>>>>>>>>>> to hash the packet for PSK or IPR.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> "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.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>>

---

From: Adrian Hope-Bailie <[email-masked]>
Date: Fri, 18 Aug 2017 21:07:27 +0100

> it's a clearing/overlay layer or a "real" ledger.

My point is that it goes beyond that. ILP doesn't care if the layer below
even has a concept of HTLAs. I can do ILP over Bitcoin without the overlay
layer if I want to but I need to find a peer that is prepared to do that
with me.

In that case all I have to do is send them the ILP packet in a message that
says I owe them some Bitcoin. the "owe them some Bitcoin" isn't being
enforced anywhere using an HTLA.

>
>
> You're equating this "overlay network," which is a type of ledger, with
> the ILP layer.
>

Not at all. I agree with what you have below. It's a layer that exists
below ILP but above the actual ledger. But crucially it's not a requirement
for ILP to work so the protocol should depend on it existing.

> If there is an overlay network that handles the condition and fulfillment,
> that means you _are_ using a ledger, because the overlay network _is_ a
> ledger. The ILP layer is a layer above this.
>

Agreed.

> exposes, and then building the ILP layer on top of that.

Because that's not how you build a protocol stack. A protocol stack is not
defined through interfaces. It's defined through layers of data where each
layer has a standard packet format with headers carrying data for that
layer and encapsulates the data of layer(s) above in the payload.

The condition, fulfillment and expiry are part of ILP so they belong in the
ILP packet. If there are lower layers that want to use those things then
they can but ILP shouldn't depend on that.

> There's no reason to send a backwards hop. If you don't want to forward a

That's what I mean by a backwards hop. I was illustrating my point that
validating a packet is part of the routing decision.

> connectors only need to know the expiries of the local transfers.

There is a big misconception in your statement. The expiry is an end-to-end
concern, or as you put it the sender sets and "the receiver looks at the
ILP packet's expiry". That's why it's in the ILP packet.

The idea that anything to be exchanged end-to-end must be in higher layers
is completely wrong. The reason you'd put something in a higher layer
payload is because the endpoints have agreed to use a higher layer protocol
that requires it to be there.

> On Fri, Aug 18, 2017 at 3:21 PM, Adrian Hope-Bailie <[email-masked]
> > wrote:
>
>>
>>
>>> Yes, two connectors could absolutely send an unconditional transfer on
>>> an underlying ledger in order to settle an Interledger payment. But in
>>> order to benefit from any of Interledger's guarantees (trustless
>>> connectors, retry-ability, etc.), they MUST keep a conditional local
>>> transfer, at least for clearing. If the local transfer cannot time out, it
>>> cannot be safely retried. If the local transfer clears without a
>>> fulfillment, it loses the "receipt or your money back" property. Yes, two
>>> parties in the chain could eschew these benefits but that is no longer a
>>> correct implementation of Interledger.
>>>
>>
>> Aha! That is where I disagree! Interledger is not implemented at the
>> local transfer layer, it is implemented at the Interledger layer. The whole
>> point is that it an Interledger payment can travel over payment networks
>> that know nothing about ILP but the greatest value comes from using ones
>> that do.
>>
>> If we assume the ILP packet is well defined with all the ILP-required
>> data elements then when a lower layer wants to use that data it can but
>> should do it in a way that doesn't break the ILP layer for everyone else.
>> How that is implemented in practice will depend on the lower layer
>> protocol.
>>
>>
>>>
>>> Those are validity checks and you're right that they are performed in
>>> the connector, but the destination account, destination amount, and data
>>> are enough to figure out what the best next hop is.
>>>
>>
>>> In that context, the expiry has no bearing on where it will be routed
>>> nor on how much to route, only on whether or not an individual connector
>>> will take the risk of forwarding it.
>>>
>>> Fair enough; in your case you can transmit the condition twice and
>>> verify the structure of the complex local condition, and in the
>> Not at all. You're assuming that there is no expiry on the local
>> transfer. As a receiving node I have an incoming transfer with an expiry
>> and it carries an ILP packet that also has an expiry.
>>
>>>> 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
>>>> 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.
>>>>
>>>>
>>>>>
>>>>> 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).
>>>>>
>>>>
>>>> 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
>>>>>>>>>>>    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
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>> 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.
>>>>>>>>
>>>>>>>> *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
>>>>>>>>> In the current model, the CLP/trustline model and the direct
>>>>>>>>> ledger model both work without having to treat anything on the ILP layer
>>>>>>>> NO THEY DON'T! They have meaning to SOME ledgers that implement
>>>>>>>> SOME lower layer protocols, IF they choose to use them.
>>>>>>>>
>>>>>>>> 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 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.
>>>>>>>>>>>
>>>>>>>>>> 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.
>>>>>>>>>>
>>>>>>>>>>>    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
>>>>>>>>>> That said, you raise an interesting consideration about the
>>>>>>>>>> layers below ILP and actually I think it makes sense to split these.
>>>>>>>>>>
>>>>>>>>>> 1. Link layer: Layer upon which two peers that have a direct
>>>>>>>>>> link, or participate in the same payment network, communicate
>>>>>>>>>> What do you mean when you say "the protocol"? In my statement I
>>>>>>>>>> am referring to ILP.
>>>>>>>>>> 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 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.
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> 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.
>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>> --

---

From: Andrew Bransford Brown <[email-masked]>
Date: Fri, 18 Aug 2017 16:10:43 -0400

If the human species survives, they'll say humans nearly went extinct,
because some liked to keep secrets (top secret, secret, classified).

---

From: Andrew Bransford Brown <[email-masked]>
Date: Fri, 18 Aug 2017 16:13:55 -0400

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 <[email-masked]>
wrote:

> On Thu, Aug 17, 2017 at 1:32 PM, Adrian Hope-Bailie <[email-masked]
> > wrote:
>
>>
>>

---

From: Ben Sharafian <[email-masked]>
Date: Fri, 18 Aug 2017 23:39:10 +0200

> layer and encapsulates the data of layer(s) above in the payload.

I guess we're just using the term "doing ILP" differently. When I say it
I'm referring to the flow with prepare/fulfill/reject on a sha256
condition. If I'm understanding you correctly, you mean it to refer to the
data format; anything that gets the ILP packet to the destination via
peering or ledger connections counts as ILP.

On Fri, Aug 18, 2017 at 10:07 PM, Adrian Hope-Bailie <[email-masked]>
wrote:

>> Exactly, when I say you need a to handle the condition and fulfillment
>> via a clearing layer, this "overlay network" is what I'm referring to. The
> In that case all I have to do is send them the ILP packet in a message
> that says I owe them some Bitcoin. the "owe them some Bitcoin" isn't being
>> If there is an overlay network that handles the condition and
>>> How that is implemented in practice will depend on the lower layer protocol.
>>
>>
> The condition, fulfillment and expiry are part of ILP so they belong in
> the ILP packet. If there are lower layers that want to use those things
> then they can but ILP shouldn't depend on that.
>
>
>>
>> If that's what you're talking about, the ILP packet already has an
>> expiry. It's implemented in the PSK details so the receiver knows whether
>> the packet it issued is still valid. But that's an application layer
>> concern, because it's only the receiver who looks at the ILP packet's
>> expiry. The connectors only need to know the expiries of the local
>> transfers.
>>
>
> There is a big misconception in your statement. The expiry is an
> end-to-end concern, or as you put it the sender sets and "the receiver
> looks at the ILP packet's expiry". That's why it's in the ILP packet.
>
>> On Fri, Aug 18, 2017 at 3:21 PM, Adrian Hope-Bailie <
>>> The data in the ILP layer is there for a specific reason. It's part of
>>> an end-to-end exchange between the sender and receiver.
>>>
>>>
>>> There is no incentive to change the expiry in the packet as this can
>>> only be targeted at upstream connectors and the result will simply be that
>>> the payment is declined and the upstream local transfer rolls back.
>>>
>>>
>>>> Sure, it can be done as an extra validity check, but it's just more
>>>> code and more attack surface. I still don't see any tangible benefit
>>>> from doing the layering in this way, aside from your assertion that it's
>>>> the correct way to do it. If you've read any documents that explain why
>>>> this is the correct way to do layering, I think I'd understand you better.
>>>>
>>>>
>>>>> 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).
>>>>>
>>>>>
>>>>> 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.
>>>>>
>>>>> 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?
>>>>>
>>>>>
>>>>>
>>>>>>>>> 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.
>>>>>>>>>
>>>>>>>>>> With the ledger-level abstraction, we were able to switch from
>>>>>>>>>> our ledger-based mode of thinking to the CLP/trustline based way without
>>>>>>>>>> If the ledger layer has to look into the ILP packet to do so,
>>>>>>>>>> that is a blatant breaking of layering.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 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
>>>>>>>>> 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.
>>>>>>>>>
>>>>>>>>>> I agree that Interledger defines how conditions, fulfillments,
>>>>>>>>>> and expiries should be chained together, but it makes no assertions about
>>>>>>>>>> their data format.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 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.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 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.
>>>>>>>>>
>>>>>>>>> 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.
>>>>>>>>>>
>>>>>>>>>> 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.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>>> 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.
>>>>>>>>>>>
>>>>>>>>>>>> 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.
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> 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.
>>>>>>>>>>> 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.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>> 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.
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> 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.
>>>>>>>>>>>

---

From: David Nicol <[email-masked]>
Date: Fri, 18 Aug 2017 16:58:20 -0500

> layer and encapsulates the data of layer(s) above in the payload.

 Also: defining a protocol stack informs the design of more robust and
maintainable interfaces. That is, interfaces designed to an explicit
protocol stack are more maintainable and robust than interfaces designed
without one.

Hoping my generalities are useful

dln

---

From: Evan Schwartz <[email-masked]>
Date: Thu, 24 Aug 2017 19:26:24 +0000

I have to echo Ben's question about where this conception of layering comes
from.

In RFC 1122: Requirements for Internet Hosts -- Communication Layers
<https://tools.ietf.org/html/rfc1122#page-15>, it says:

> Protocol layering, which is generally used as an organizing principle in
implementing network software, has also been used to organize this
document...strict layering is an imperfect model, both for the protocol
suite and for recommended implementation approaches. Protocols in different
layers interact in complex and sometimes subtle ways, and particular
functions often involve multiple layers.  There are many design choices in
an implementation, many of which involve creative "breaking" of strict
layering...*This document describes the conceptual service interface
between layers using a functional ("procedure call") notation*, like that
used in the TCP specification [TCP:1]. A host implementation must support
the logical information flow. implied by these calls, but need not
literally implement the calls themselves.
> In general, each major section of this document is organized into the
following subsections:...*(4)  Interfaces -- discusses the service
interface to the next higher layer.*...

As far as I understand it, the idea is that each layer provides a set of
functionality or interface to the layer above. Each layer SHOULD NOT (in
the RFC sense, meaning it's wrong to do it but implementations may do it
anyway if they think they know better) inspect or try to understand the
data of higher-level protocols.

> From the perspective of the Interledger Protocol the implementation of
the lower layers is not important, that's the whole point of layering.

I'm pretty sure this is incorrect. Layers are defined by what functions
they provide to the layer above them. *How* they provide that functionality
is an implementation detail but not *what* functionality they provide.

> ILP doesn't care if the layer below even has a concept of HTLAs. I can do
ILP over Bitcoin without the overlay layer if I want to but I need to find
a peer that is prepared to do that with me.

I think you're missing the point of the HTLA idea. It is precisely the
functionality that Interledger requires. When you say you need to "find a
peer that is prepared to do that with me", the "that" means "use a pre or
post-funded trustline with Bitcoin settlement" (also using a specific
method and protocol for communication).

Interledger doesn't care how you implement HTLAs but that is the interface
it expects from the layer below it (+ request/response-based messaging).

We could have defined ILP differently to have lower requirements on the
layer below it. We could have said that all messaging goes over IP and is
thus part of the Interledger layer implemented by connectors. We also could
have said that we assume only that ledgers can do simple transfers so that
connectors are also the ones that implement the conditional transfer
semantic and always use simple ledger transfers for settlement. There is no
one right place to put this functionality. Where it should go depends on
the benefits it brings.

By abstracting both the messaging and the implementation of conditional
transfers we have allowed for implementations of the ledger layer to vary
from nothing being provided by a ledger to everything. If Interledger is
successful, I would expect future networks to be built with it in mind. I
think it's better to build for the assumption that ledgers will implement
whatever Interledger needs from them and create a way to overlay that on
existing ledgers that don't, rather than assuming ledgers will always be
built in the least useful way possible.

> *we should try to test our design against a number of lower and upper
layer protocols to make sure our thinking is sound.*

As Ben mentioned, we have. The current design has allowed Ledger Layer
implementations to change dramatically without affecting higher levels
(going from on-ledger transfers to trustlines and payment channels). It has
also allowed higher level protocols to change dramatically (going from IPR
to PSK).

On Fri, Aug 18, 2017 at 5:58 PM David Nicol <[email-masked]> wrote:

> On Fri, Aug 18, 2017 at 3:07 PM, Adrian Hope-Bailie <[email-masked]
> > wrote:
>>
>> Because that's not how you build a protocol stack. A protocol stack is
>> not defined through interfaces. It's defined through layers of data where
>> each layer has a standard packet format with headers carrying data for that

Evan Schwartz
Software Engineer