Skip to content

Instantly share code, notes, and snippets.

@sappenin
Created December 3, 2017 21:37
Show Gist options
  • Save sappenin/386900a769318eeda56c16d8a5a49e5e to your computer and use it in GitHub Desktop.
Save sappenin/386900a769318eeda56c16d8a5a49e5e to your computer and use it in GitHub Desktop.

Note: This snippet was taken from this issue #12 the Interledger project.

From Adrian:

I am trying to take a technology and architecture neutral perspective here so I have ignored some of the comments about plugins vs middle-ware approaches. I see those as implementation decisions as opposed to something that would be part of the ILP standard.

I am strongly in favour of the following changes to ILPv1 (but probably for very different reason to @emschwartz which I'll explain below).

Remove ILQP from the ILP layer

I have always maintained that quoting is not something that is required at the ILP layer so I am happy to see this being dropped. That said, I think there may still be a desire to support it between certain nodes. I.e. It should not be a requirement of every node on the network (in the same way that my home router isn't expected to implement BGP) but we shouldn't discard our work on it as some nodes (likely larger backbone connectors) may still use it/build on it.

Fundamentally, the amount that a sender uses in their first transfer can be determined in a variety of ways and shouldn't be tightly coupled to the protocol itself.

How the sender determines this amount is also very use case specific. I could use ILP to send via a single intermediary or a long chain of intermediaries. I could send in the same currency I expect the receiver to get or require implicit asset exchanges to happen as part of the payment. I could require a fixed send amount or a fixed receive amount. I also might have a requirement to send the whole payment in a single shot (i.e. explicitly not as a chunked payment). All of this impacts how the sender determines the initial transfer amount.

As such, we should design ILP on the assumption that the application layer protocol will:

  • assist the sender to select an appropriate amount to send in the first transfer
  • assist the receiver to decide if they should accept the payment or not

(NOTE: The application layer protocol may use a standard transport protocol that solves for this but as @justmoon pointed out in our recent presentations, a transport layer protocol is just a standardization of functions required by multiple application layer protocols)

ILP is simply about transferring the assets reliably across networks, inter-networking. "Quoting" (and by that I also mean, deciding to accept a payment because it matches the amount expected) is an application layer concern.

Drop the Destination Amount

Simplicity in the inter-networking layer is enhanced by providing intermediary nodes as little data as possible. In the end, data that is only important to the sender and receiver is best hidden from intermediaries as this makes connector behaviour the most predictable.

By default a connector should receive an opaque blob of end-to-end data attached to an incoming transfer along with an ILP Address, a condition and an expiry.

That is all the information the connector needs to make an outgoing transfer in the direction of the receiver.

Again, the behaviour of a specific connector will be very use case specific. Some connectors will require additional data in order to be compliant with regulations. In this case an appropriate application layer protocol will expose that data to the intermediaries, this is not the job of the ILP layer.

Loosen up the transfer/ledger protocol

I really like the idea of passing transfers over HTTP, not because they fit so elegantly but because it finally solves our debate around what data goes in what layers.

In reality the ILP layer is a "virtual" layer. There is actually no need for an ILP packet format that all nodes are able to encode and decode.

What we have instead is a standard logical data model for transfers, fulfillments and errors that specifies:

  1. The data that must be in an incoming transfer
  2. The data that must be in an outgoing transfer
  3. The data that must be in a fulfillment
  4. The data that must be in an error
  5. The expected behaviour of a connector in relaying these messages

In reality this data can be carried over any protocol (HTTP, gRPC etc). e.g. A connector can have an incoming transfer over BTP but make the outgoing transfer over HTTP and even receive the fulfillment or error via a WebHook. These decisions are all down to how a specific connector interfaces with another connector.

All that matters is:

  • The two nodes that are communicating with one another agree on a protocol
  • The protocol they use has a binding defined for exchanging ILP Transfers, ILP Fulfillments and ILP Errors

e.g. An ILP Transfers binding is a way to express a transfer request from the one node to the other including: the transfer amount, the destination ILP Address, Condition, Expiry and Data

Our work on BTP and the ILP packets is still useful as a basis for anyone looking to define bindings for a wire protocol like WebSockets but I'm reluctant to invest much more time on these.

Next Steps

We should define the generic ILP Transfer, ILP Fulfillment and ILP Error data models.

These are logical models, and don't even need to specify encodings. (E.g. I could send a Condition encoded as a Crypto-Condition using one protocol binding and this could be converted to a raw SHA-256 hash for the next hop using a different protocol binding. As long as the semantics are the same the encoding is irrelevant).

The definition for an ILP Transfer is:

  • From Account (ledger specific, can be omitted if implicit from the context)
  • To Account (ledger specific, can be omitted if implicit from the context)
  • Amount (ledger specific)
  • Condition (SHA-256 hash)
  • Expiry (Timezone neutral timestamp with millisecond precision)
  • Destination ILP Address
  • Data (Opaque BLOB)

The definition for an ILP Fulfillment is:

  • From Account (ledger specific, can be omitted if implicit from the context)
  • To Account (ledger specific, can be omitted if implicit from the context)
  • Fulfillment (SHA-256 hash preimage)
  • Data (Opaque BLOB)

The behavior of a connector is roughly:

  1. Determine if you accept the incoming transfer (risk assessment)
  2. Determine where to send the outgoing transfer (i.e. which outgoing channel)
  3. Calculate an appropriate amount and expiry for the outgoing transfer
  4. Send the outgoing transfer using:
    1. The appropriate to and from accounts for the channel
    2. The calculated amount and expiry
    3. The same condition and data
  5. Determine fulfillment is valid for outgoing transfer
  6. Pass fulfillment back along incoming transfer channel OR
  7. Pass error back along incoming transfer channel

Everything else is transport/application layer specific.

With this basic model in place the community is free to implement appropriate application layer protocols that solve for specific use cases. As these progress we will find there are transport layer behaviours we can standardize into new transport layer protocols (like PSK).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment