Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify which ILP v1 problems are solved by ILP v3 #12

Open
michielbdejong opened this issue Nov 28, 2017 · 8 comments
Open

Clarify which ILP v1 problems are solved by ILP v3 #12

michielbdejong opened this issue Nov 28, 2017 · 8 comments

Comments

@michielbdejong
Copy link

One thing I'm missing is a more explicit problem statement. What's wrong with ILP v1 that makes you propose to throw away a perfectly usable protocol stack and start almost from scratch? Is ILP v1 not as usable as we thought it was?

ILP v3 [...] aims to simplify the protocol stack and implementation even further and get the open Interledger started faster

That implicitly states that one reason that the open Interledger isn't starting as fast as we would wish is that the protocol stack and implementation aren't simple enough?

I personally think the three things that are stopping the open interledger from growing faster are uncertainty about legal risks, chicken-and-egg problem of "there are no apps -> there are no users -> there are no connectors", and the fact that we have not automated route switching yet. I wouldn't list protocol stack complexities as one of the main problems to solve today, so I think it's worth describing that argument in a bit more detail.

Is it your personal experience that there are complexities in the protocol stack that make adoption unattractive, or did you maybe meet people who told you that the reason they're not yet running a connector is that the protocol stack and/or its implementation is too complex for them? If so, can you be more specific about something that is currently complex and that desperately needs to be simplified?

connectors do not need to know the exact and up-to-date exchange rates of all other connectors.

That's something you can use - explain how in ILP v1, for instance the memory requirements are too high and that that's something that needs fixing.

restrictions on ILP addresses (not being able to use a ledger's address in another ledger's prefix unless the exchange rate is 1:1) that are unnecessary in a forwarding-only system

That's another one, but what problems did you run into due to these restrictions? Can you give an example of a downside of this restriction?

Simple Exchange Rates Instead of Liquidity Curves

That would be an advantage of chunked payments, regardless of whether you do them with ILP v1 or ILP v3.

@emschwartz
Copy link
Owner

Good question.

I see the biggest issues with ILPv1 and the current stack as:

  • Lack of Payment Size Limits - I think this is one of the most sensible ways to limit connectors' risk, especially in the early days of the software when we know there will be undiscovered bugs. However, limiting payment size would make for a very bad sender experience without also implementing transport protocols to deal with chunked payments.
  • Chunked Payments Cannot Be Implemented Well on ILPv1 - I started out trying to implement chunked payments with our normal stack and ran into all sorts of problems that made me realize that unless you are doing the exact behavior we've always done with ILPv1 -- get a quote with ILQP and then send a single payment -- you're likely to run into errors. If you don't know the rate up front, or the rate changes as you're sending, ILPv1 basically doesn't work for you. You could get a quote before sending every chunk but that seemed too clunky.
  • Large Connector Attack Surface - The ilp-connector forwards payments, does quoting, and routing. There is a large attack surface and we haven't really thought through how to protect against DoS attacks using the free methods. ILP3 tries to reduce the attack surface, so there's only one pipeline that needs to be defended.
  • No Support (Yet) for Multi-Payment Channel Plugins - @justmoon and @sharafian already ran into issues using escrow payments, because they are too slow for the use cases we want to focus on. This means we need to use payment channels if we're going to connect the public blockchains. We haven't implemented the plugins to support multiple payment channels yet, and I don't think the plugin factory is the best architecture to support this. I thought that switching to the middleware-based design would make it easier to implement support for these. (Note that payment size limits are also crucial for using unconditional payment channels)
  • Invent Less - I was excited and embarrassed when I realized we could just use a couple of headers on normal HTTP requests instead of BTP over websockets and all of the other methods we've spent loads of time on over the years. If we use a super well-supported protocol like HTTP without any modification, we get to take advantage of a ton of tooling that exists already, it's much easier to reimplement in other languages, and there's less code on our side that needs to be audited for bugs.

I agree with @justmoon that it's generally a bad idea to rewrite things from scratch. But in light of these considerations, I think it's easier to get real money ILP over unconditional payment channels going with a new implementation. Happy to discuss that further though!

@justmoon
Copy link
Collaborator

justmoon commented Nov 30, 2017

Chunked Payments Cannot Be Implemented Well on ILPv1

I believe with fulfillment data (done) and amount zero equals best-effort (in progress) it would work just fine.

What's wrong with ILP v1 that makes you propose to throw away a perfectly usable protocol stack and start almost from scratch?

Agree with @michielbdejong here, I think we can pretty easily take the lessons from ilp3 and transfer them to Interledger.js.

(Edit: I already chatted about this with @emschwartz, but thought it'd be worth recording some of this debate for anyone following along.)

@adrianhopebailie
Copy link
Collaborator

adrianhopebailie commented Nov 30, 2017

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

@justmoon
Copy link
Collaborator

justmoon commented Dec 1, 2017

👍

Just one thing:

From Account (ledger specific, can be omitted if implicit from the context)
To Account (ledger specific, can be omitted if implicit from the context)

You should never have a to/from. Since the Interledger Enlightenment, we view ledgers as connectors. If you have a to/from, you're essentially telling the next connector how to do its routing. It's not your concern.

@sappenin
Copy link
Collaborator

sappenin commented Dec 2, 2017

I am strongly in favour of the following changes to ILPv1

@adrianhopebailie Great comment, very well reasoned -- your proposal nicely merges the learnings of ILP3 with what we have in ILP1, IMHO.

Remove ILQP from the ILP layer...Drop the Destination Amount from the ILP Packet...Loosen up the transfer/ledger protocol

I agree with these proposed changes, though a common question I get from newcomers (and one I occasionally have for myself) is, "How do I do X while still being compatible with the Interledger Network"? (This is deeper than how I do X while still being compatible with the ILP-layer).

It's great that (if your proposal stands) we'll pull quoting out of the "ILP layer" and make what the sender/receiver have negotiated an opaque blob, but doesn't our community still need to specify some of the interactions between sender/receiver in order to have a functioning public network?

I'm somewhat unclear about what will and won't need to be normative at these "higher levels" in order for the Universal Mode network to work.

@michielbdejong
Copy link
Author

michielbdejong commented Dec 3, 2017

I think we should:

  • add fulfillment data (already done)
  • add forwarded payments in code and docs (PRs exist)
  • add a tutorial in which:
    • the shop allows paying for a Letter with a chunked payment
    • the shop reports how much arrived in the fulfillment data
    • the client sends (quoted!) chunks, adapting to the fulfillment data reports
    • once this chunked payment works with quoted payments, switch it to forwarded payments
    • explain the advantages and disadvantages of quoted vs forwarded payments in the tutorial
  • done.

Once we added these features, I think we should focus on adding signed test payments, because that's still the big missing ingredient for both quoted and forwarded payments.

I see the usefulness of forwarded payments in (rare?) situations where the exchange rate between source and destination is so volatile that it makes quote-then-pay impossible. This could for instance happen when dealing with a sparse order book. I wouldn't do it the "at any price" way Evan proposes though, I would set a target bandwidth, and only take the best offers, as I sort of vaguely described in interledger/rfcs#333.

In all other cases, I think that we should stick to the quoted payments which we already have working.

My reason to want to keep quoted payments would be because of the ilp-kit UI flow which I like: specify one of the two amounts, see the other amount, make a boolean decision, then pay with success or your money back.

And therefore, I think Yes, we should add support for forwarded payment to Interledger, but No, we should not deprecate quoted payments.

So I clearly disagree with Adrian and Stefan on that point.

@adrianhopebailie
Copy link
Collaborator

You should never have a to/from. Since the Interledger Enlightenment, we view ledgers as connectors. If you have a to/from, you're essentially telling the next connector how to do its routing. It's not your concern.

@BobWay and I discussed this at length a month or two ago. It's a great way to model these things but it's a little confusing when we talk about a ledger and mean a direct link between only two accounts.

I think that we've effectively proven to ourselves that our model works best with Payment Channels (both from the perspective of speed but also how we model the network).

A connector is a hub of payment channels and ILP is a protocol for connecting multiple channels using a common condition.

In fact looking at Lightning-like payment channels and µRaiden (so called "layer 2 protocols") it occurs to me that there is a subtle stratification of the ledger layer in many cases.

-------------------------------------------------------------------------------
| SPSP |             Other Application Layer Protocols                        |
-------------------------------------------------------------------------------
| PSK  |             Other Transport Layer Protocols                          |
===============================================================================
|                              Interledger Protocol                           |
===============================================================================
| Lightning |  µRaiden | XRP Payment Channels | Custom HTLA-based protocol    | <- Layer 2
|---------- |----------|----------------------|-------------------------------|
|  Bitcoin  | Ethereum |      XRP Ledger      |   Paypal/Bank/Other Legacy    | <- Ledger

The layer two protocols are more account <-> account than many <-> many which matches our model nicely.

Admittedly Lightning and Raiden network are attempting to also layer a full many <-> many network over their payment channel implementations but I expect that an ILP connector will follow our model of establishing a channel directly with another connector where the transfers over that connection will always be to/from the same pair of accounts so logically are a "payment channel" even if there is, for example, a multi-hop Lightning payment happening underneath.

@michielbdejong
Copy link
Author

As @emschwartz pointed out today, quote-then-pay is actually possible with forwarded payments, if the receiver supports end-to-end quoting and you combine with that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants