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

Conditions are NOT a ledger layer concern #359

Closed
justmoon opened this issue Dec 22, 2017 · 31 comments
Closed

Conditions are NOT a ledger layer concern #359

justmoon opened this issue Dec 22, 2017 · 31 comments
Labels
history ilp Related to the core protocol specs wontfix

Comments

@justmoon
Copy link
Member

Brought to you from our sponsors at holy ****, there are still ways to simplify ILP...

This is a follow-on to @adrianhopebailie's famous ticket #270. He was the first to recognize that executionConditions awkwardly straddle two layers: Interledger and ledger. This dissonance stuck with me until it lead me to the realization described in this ticket, which finally resolves it.


We recently started seriously implementing an earlier realization we dubbed the Interledger enlightenment. Before the enlightenment, we thought that ledgers were the nodes and connectors were the edges of the financial graph. But we realized that a simpler and more general model is that the nodes in the Interledger graph are senders, connectors and receivers and the edges are accounts they have with one another. A ledger then is just another type of connector.

Interestingly, there aren't a lot of different types of account you can have. You can have a credit relationship, which we sometimes call a trustline. Or you can have a payment channel, which essentially the crypto-equivalent of a check: One party signs something called a claim that the other party can take to someone else (such as a blockchain) to get paid. Checks reduce the trust needed between the parties because the settlement is enforceable.

In ILP, we use unsecured payment channels. What we do is we transfer a claim after receiving a fulfillment. In other words, for us, a payment channel is just a very efficient way to send some money. Note that there is no condition involved.

We believe that such unsecured payment channels are fine, because each payment is very small, so it is not worth worrying about losing a payment, as long as the cumulative loss is limited.

If we use unconditional transfers between each pair of nodes, then how come we haven't gotten rid of conditions entirely? (We call this "optimistic mode" in ILP speak.)

The reason we still have conditions is to isolate risk to a specific hop. I.e. if someone along the chain fails, we want to be able to assign blame correctly. That's why the two phase execution still makes sense.

But if conditions are only evaluated by connectors and ledger plugins only do unconditional transfers, then conditions are an Interledger concern, not a ledger layer concern.

In other words, the LPI sendTransfer should be changed from:

interface Transfer {
  amount: string,
  executionCondition: Buffer,
  expiresAt: string,
  ilp: Buffer
}

interface FulfillmentInfo {
  fulfillment: Buffer,
  ilp: Buffer
}

class Plugin {
  sendTransfer(transfer: Transfer): FulfillmentInfo
}
const { fulfillment, data: ilpFulfillmentPacket } = await plugin.sendTransfer({
  amount: '10',
  executionCondition: Buffer.from('47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU', 'base64'),
  expiresAt: '2016-05-18T12:00:00.000Z',
  ilp: ilpPaymentPacket
})

to

class Plugin {
  async sendData(data: Buffer): Buffer
  async sendMoney(amount: string): void
}
const ilpFulfillmentPacket = await plugin.sendData(ilpPaymentPacket)
await plugin.sendMoney('10')

If your head just exploded, please do not be concerned. This is normal.

The best way I can explain the above is that this is exactly what ilp-plugin-xrp-paychan already does. It first sends a prepare which is basically just sending a bunch of data to the next connector with no money attached at all. If it gets back a fulfillment, it now owes the connector, so before it can send more payments, it needs to send some money by sending a claim against the underlying payment channel.

The important thing to understand is that the sendData call is triggering both the next sendData call as well as the next sendMoney call at each hop. This is what creates the Interledger two-phase semantics, i.e. as the receiver I only need to trust connector 2 to send the money, not the sender and the whole chain in between.

Sender --sendData-> Connector 1 --sendData-> Connector 2 --sendData-> Receiver
   |                        |                        |
   `----sendMoney->         `----sendMoney->         `----sendMoney->

The sendData call can also throw an InterledgerRejectionError just as before, in which case the sendMoney call is never reached.

So where did the executionCondition go? It moved inside the ILP payment packet. So did the expiry. The fulfillment moved inside the ILP fulfillment packet. Note that that does mean that the ILP packet changes at each hop, but that's no different than the IP hop limit changing at each hop.

Certain logic that needed to be reimplemented in every plugin before, such as verifying the fulfillment etc. is now part of the connector / sender.

If the hashing function we use needed to be updated in a future version of ILP, we would no longer need to also change all of the ledger protocols. In fact, the ledger plugin interface is now arguably timeless - it can send integers of information (bytes) and it can send integers of value.

It makes sense that the escrow would go away under the enlightenment. Escrow is just transferring money from one account to another. It is still possible to implement the escrow pattern using this new LPI. Ledgers are connectors now, so the escrowing ledger is a connector. Let's call her Ellie.

  • Alice first sends money to Ellie, then sends her the prepare packet.
  • Ellie then sends the prepare packet to Bob.
  • Bob responds to Ellie's request with the fulfillment packet.
  • Ellie then sends money to Bob.
  • Ellie then responds to Alice's request with the fulfillment packet.

If Bob hadn't responded with the fulfillment in time, Ellie would have responded to Alice's request with a rejection packet and sent the money back to Alice.

As with routing, escrow functionality can also be implemented in the ledger plugin if there is a ledger that is fast and permissive enough and can do escrow, but doesn't understand ILP. Since no such ledgers exist (at least none that are fast enough for actually doing ILP on them) this is a theoretical exercise. Any future ledgers that may be built specifically for ILP that wish to implement the escrow pattern should think of themselves as connectors.

@justmoon
Copy link
Member Author

(Note that there is a ton of stuff that I left out of the ticket description, for example how balances are handled under this new view. But the length of the text was already getting ridiculous, so please feel free to ask questions.)

@emschwartz
Copy link
Member

Well there goes ILPv2. And the name ILPv3 is already taken.

So I guess we're landing on ILPv4 😉

@dappelt
Copy link

dappelt commented Dec 22, 2017

If your head just exploded, please do not be concerned. This is normal.

😂

@sappenin
Copy link
Contributor

So I guess we're landing on ILPv4 😉

I actually think that when we "go live", we should use ILPv4, and then, in 15 years when we realize the size of the ILP address is too small or something, we purposefully skip v5 and come out with ILPv6.

😉

@emschwartz
Copy link
Member

Famous last words: "there's no way we'll need more than 1023 characters in the address." (Speaking of which...)

I would bet on the hash function being broken as the motivation for going to the next version once things settle down in the short term.

@adrianhopebailie
Copy link
Collaborator

/me is so happy he decides to take a 2 week holiday

@sharafian
Copy link

I sure am glad that I didn't update every plugin to LPI 2. I think this makes a lot of sense though, because now the architecture can be described as:

"You ask your peer for the fulfillment to a packet; if they give you the fulfillment, you pay them the money. The payment for each packet could be defaulted upon, so amounts are kept low. In order to make a payment, you split it into many packets of money."

One thing I notice is that this obsoletes BTP; Now it's a message followed by an unconditional transfer. Additionally, it's not immediately clear how a completely unconditional trustline should work. Under this architecture it might look like:

1. Sender ---data---> Receiver
2. Sender <---data--- Receiver
3. Sender ---money--> Receiver

But if the balance is unsecured, this is redundant. 3 is not actually passing any meaningful data unless the balance is secured by claims. The smart thing to do would be to update balances automatically after 2 completes, but if the data transfer is independent of the money transfer, that's not allowed by the separation of concerns.

We may just say that's ok, and eat the efficiency loss in that case (BTP already contains this extra message, so it would really only affect protocols like ILP-over-HTTP). But it still seems like intuitively that there are a few things the ledger layer knows how to do right.

One other thing is that modification of the ILP packet doesn't sit so well with me. Although it does seem more elegant than the current version of things, which is to pass all the non-ILP fields separately.

Also congratulations @adrianhopebailie for your vision finally being realized :)

@BobWay
Copy link

BobWay commented Dec 22, 2017

Woot! I’m liking this idea. /me decides to take Adrian’s vacation as well. :-)

@michielbdejong
Copy link
Contributor

Data is Money if the Medium is a Ledger.

screen shot 2017-12-23 at 07 30 11

This proposal changes what we call the ledger. We used to say the trustline of PluginVirtual, with its Prepare and Fulfill messages, was a ledger. That confused everybody. Now we can say the mediums interconnected by Interledger are Data, and the mediums that back their liquidity are ledgers.

@emschwartz
Copy link
Member

There are a number of things I really like about this proposal, but there's one thing that isn't sitting right with me.


This change is very close to the one proposed in ILP3. I proposed merging the fields from the ILP packet into the transfer, this merges the transfer fields into the ILP packet.

The substantive differences between these approaches are that having a standard packet encoding:

  1. Saves the overhead of re-encoding the packet at each hop
  2. Makes it easier to ensure that connectors pass on extensions they don't understand

I don't think the packet encoding is super difficult to implement (as long as you write only the functions for encoding/decoding a variable-length octet string, rather than a full OER parser), so I think these are good enough reasons to have a standard format.


It feels like we're on one of these:
image

We're getting closer to the end and things are moving/changing faster but the differences are getting smaller and smaller. (For example, updating the PSK2 implementation to use this format would be super quick because it would be using all the same fields but pulling them from a different place)


The thing that's not sitting quite right with me is thinking about how we would actually implement different HTLAs under this new architecture -- specifically the part about when we pay.

there aren't a lot of different types of account you can have...We believe that such unsecured payment channels are fine

But we could set up the agreement in a number of different ways. We could send money with every prepare, after every fulfill, after the balance hits a certain limit, or at a pre-defined time (and of course with escrow, but you spoke to that above).

The argument for keeping the HTLAs in the "layer" below ILP, like what's proposed in #358, is that the important part is not just the hashlock but the agreement around what action the hashlock means you should take, and that varies.

Would we build the connector such that you could configure when it should send money for each of its peers? Or would it make more sense for that type of logic to live in plugins, each of which would have a predefined agreement/protocol? If you wanted to implement another HTLA, wouldn't you just end up writing a ledger plugin that looks at the ILP packet it's being passed to know what it should do (which would break the layering)?


As @justmoon mentioned the other day in #356 (comment) though, it does seem like getting rid of the separation between the IP and ethernet layers would be a good idea...

@michielbdejong
Copy link
Contributor

But we could set up the agreement in a number of different ways. We could send money with every prepare, after every fulfill, after the balance hits a certain limit, or at a pre-defined time

Isn't that decision out of scope now, sort of? Two peers need to agree on a minimum and maximum balance, and then the sending connector can have its own strategy for making sure they stay within those limits, and this strategy doesn't necessarily need to be announced or agreed on, right?

In a way, the specific ledger used to settle the balance of the transfer layer is even irrelevant if you just look at the transfer layer, except maybe that the transfer layer needs to pick a unit of value, and you would usually pick the one in which you plan to settle. For instance, if settlement happens on xrp paychan, then it makes sense if amounts on the transfer layer are expressed in XRP.

(and of course with escrow, but you spoke to that above).

Yes, I liked how one-to-one escrow can be modeled as one pre-funded transfer to Ellie and one post-funded transfer from Ellie. And one-to-many escrow like e.g. five-bells-ledger, will now be temporarily deprecated by strong enlightenment, so that's also a nice simplification.

@sappenin
Copy link
Contributor

The substantive differences between these approaches [ILP3 and this issue] are that having a standard packet encoding:

  1. Saves the overhead of re-encoding the packet at each hop
  2. Makes it easier to ensure that connectors pass on extensions they don't understand

I’m not sure I agree. While point number 2 seems valid, the new packet design forces each hop to re-encode a new packet with a new amount and expiry for each next hop, no?

Personally, I'm "on the fence" about the current ILPv4 packet changes: Primarily, I don’t like the idea of each Connector having to modify the ILP packet at each hop (though maybe I should just embrace that). However, I do like the idea of a timeless lLP-Layer-2 interface (a.k.a. LPI2), and the #356 comment is giving me pause about what I'm about to write.

But, setting aside the #356 comment for a second...would it not make sense to break the ILPv4 packet into 2 separate payloads (one for Layer3 Interledger data and one for Layer2 LPI data), like this:

// Not mutated at each hop...
InterledgerPrepare ::= SEQUENCE {
  -- Execution condition
  executionCondition Uint256,
   Destination ILP Address.
  destination Address,
  -- Information for recipient (Layer4 transport layer information)
  data OCTET STRING (SIZE (0..32767))
}

//different at each hop
LocalLedgerPrepare ::= SEQUENCE {
  -- Local amount
  amount UInt64,
   -- Expiry date
   expiresAt Timestamp,
   -- Extra info for local ledger.
  data OCTET STRING (SIZE (0..32767))
}

If the above were the structure of the payload at each layer, then the LPI could look like this:

  async sendData(ilpData:Buffer, localLedgerData:Buffer):Buffer
  async sendMoney(amount: string): void

If we were to clearly separate the two packets according to Interledger Layer3/Layer2 , then it becomes obvious what parts of the payloads change and what parts do not change at each hop. Also, if two peers want to use a different LocalLedgerPrepare encoding, then they would be free to do so without breaking the Interledger layer (Layer 3). Finally, this design is very close to ILPv3 except that the condition has been moved to the ILP layer, thanks to the new ILPv4 protocol flow.

I suppose the outstanding question in all of this still relates to the #353 comment - is it actually better to conflate the layer 2 and 3 data??

@justmoon
Copy link
Member Author

As @justmoon mentioned the other day in #356 (comment) though, it does seem like getting rid of the separation between the IP and ethernet layers would be a good idea...

Who said anything about getting rid of the separation between the IP and ethernet layers? (I'm guessing you mean internetwork and network layers.) That would be a bad idea. What I'm talking about in that comment is to make sure only the internetwork layer does routing. The key insight here is that an Ethernet switch is basically doing the same thing an IP router does. So you can get rid of Ethernet switches and turn them into routers. And suddenly you don't need Ethernet addresses anymore, so you don't need address translation, etc. You can make the network layer a pure link layer, i.e. physical (bilateral) connections only.

The same thing applies to ILP. Once we realize that a ledger is just another connector, we can get rid of everything in the ledger layer that deals with multiparty (i.e. more than bilateral) functionality and handle that on the Interledger layer where we already have to handle it. The realization in this ticket is that escrow falls into the category of multi-lateral functionality and therefore should be on the interledger layer, not the ledger layer. (Note that the ledger should really be called the "account" layer if it's only bilateral, but I don't think it's a good idea to try such a massive rename at this point, we'd never quite get rid of the old name.)

The thing that's not sitting quite right with me is thinking about how we would actually implement different HTLAs under this new architecture -- specifically the part about when we pay.

Let's actually categorize HTLAs into a useful framework. I would say that there are only three cases:

  1. You can pay first.
  2. You can pay later.
  3. You involve a third party as an intermediary.

Note that in case 3 you still have to pay the intermediary and they have to pay the recipient, so case 3 can be transformed into case 1/2 by making the intermediary a connector. In the escrow case, you pay-first the escrow provider, then they pay-later the recipient.

Looking at the HTLA types:

  • Trustlines: A trustline (with settlement) is case 1/2, usually with a very rare settlement.
  • Simple Payment Channels: Also case 1/2, except we can settle more cheaply and therefore frequently.
  • On-Ledger Holds/Escrow (using HTLCs): Case 3 (escrow). Can be implemented with a virtual connector or by natively supporting ILP in the escrow system.
  • Conditional Payment Channels (with HTLCs): Case 3, but now the escrowing connector is not in the flow, so it has to be implemented as a virtual connector in the plugin. Not an option I would recommend, but it can be done.

With payment channels, pay first or pay later doesn't make much of a difference. If you looked on the wire, you could barely tell which mode a set of connectors are using:

  • ...
  • Pay
  • Packet
  • Pay
  • Packet
  • Pay
  • Packet
  • Pay
  • ...

Is this pay first? Pay later? You can't tell and it doesn't much matter.

I'd say we should add configuration to the connector that lets us select:

  1. Your max exposure for any given counterparty. I.e. how much you're willing to let them owe you at any given time.
  2. How often you want to settle.

The max exposure setting decides whether to use pay-first or pay-later. You'll always want to use pay-later. It's better for your liquidity and doesn't require complex refunds in case of a rejection. The only exception is if the other side doesn't trust you, but you trust them. In that case, you have to use pay-first.

How often you settle depends on the cost/speed of the underlying settlement system and how much trust you have in your counterparty.

@justmoon
Copy link
Member Author

justmoon commented Dec 27, 2017

I’m not sure I agree. While point number 2 seems valid, the new packet design forces each hop to re-encode a new packet with a new amount and expiry for each next hop, no?

No, you can update the packet in-place, you don't have to copy it.

The amount is fixed-length, so that's easy.

The expiry date is variable-length (although it only varies if the milliseconds have different amounts of trailing zeros.) So we should think about changing the expiry date to a fixed length format even if it means not using OER's GeneralizedTime, which is otherwise a perfect fit for our needs.

If the connector's minMessageWindow is a multiple of 1000 ms (which it currently is in ilp-connector), then this is not an issue, the new expiry date will always have the same length as the previous one. If connectors in the future use minMessageWindow values that aren't divisible by 1000ms, perhaps a convention might emerge to add 1ms to your expiry if the last digit is zero. Not super-elegant, but whatever. You can always fall back to re-encoding the packet. In other words, sticking with the variable-length encoding is a defensible choice imo.

Anybody have an opinion on whether expiresAt should be changed to a fixed length layout and if so, what it should be? Here are some options:

# ASN.1 Type String Example Pro/con
1 GeneralizedTime YYYYMMDDHHmmss.oooZ Pro: Standard C-OER Con: variable length
2 PrintableString (SIZE(24)) YYYY-MM-DDTHH:mm:ss.oooZ Pro: compatible with ISO 8601 Con: Wastes bytes
3 PrintableString (SIZE(19)) YYYYMMDDHHmmss.oooZ Pro: compatible with OER GeneralizedTime parsers Con: Annoying to convert between ISO 8601 and this
4 PrintableString (SIZE(17)) YYYYMMDDHHmmssooo Pro: Removes the two bytes that were still needed in OER, but are unnecessary in a fully fixed length encoding Con: hard to read

I kinda like option 2. Probably easiest to parse. Otherwise, option 4. If ILP is successful, those saved bytes might add up to trillions of dollars or whatever. Or option 1, which is sticking with "proper" OER... choices, choices.

@justmoon
Copy link
Member Author

Ok, seems like nobody cares. Chatted with @sharafian and we settled on option no 4 as the most defensible. No cruft bytes and even though it's not the most "OER-y" option (that would be option 1), it can still be serialized/parsed as a string by a standard OER implementation.

@michielbdejong
Copy link
Contributor

michielbdejong commented Dec 28, 2017

I wonder why the authors of OER decided that being fixed-length was not a design goal for the GeneralizedTime type. Does it explicitly prohibit trailing zeroes? If not, then we could just say we use the subset of OER GeneralizedTime where all trailing zeroes are present?

And what is it that makes our use case incompatible with what the authors of OER had expected people to need?

I guess a PrintableString is not an incorrect use of OER, so I'm fine with option 4, too.

@michielbdejong
Copy link
Contributor

michielbdejong commented Dec 28, 2017

Data is Money if the Medium is a Ledger.

Apart from how we encode things and nest encoded objects into other data structures, the important part of this proposal is that it means that by the time everyone's back from their christmas holidays, we already implemented this, and conditional transfers will suddenly no longer be what puts the ledger in interledger. It feels like a really big change, right?

screen shot 2017-12-23 at 07 30 11

This proposal changes what we call the ledger. We used to say the trustline of PluginVirtual, with its Prepare and Fulfill messages, was a ledger. That confused everybody. Now we can say the mediums interconnected by Interledger are Data, and the mediums that back their liquidity are ledgers.

And wouldn't the next logical step be to decouple the sendMoney ledger from the trustline ledger altogether, saying it might be paypal or whatever out-of-band channels exist?

@sharafian
Copy link

Yeah; Currently having the BTP channel also available to send claims is useful, which is why the plugin bundles the money connection together with the data connection. If we do find in the future that it's useful to have them as two separate plugins, it would be trivial to implement in our current architecture:

connect () {
   moneyPlugin.connect()
   dataPlugin.connect()
}

sendMoney (amount) {
  return moneyPlugin.send(amount)
}

sendData (data) {
  return dataPlugin.send(data)
}

@michielbdejong
Copy link
Contributor

And which one of the two would you call the ledger plugin?

@michielbdejong
Copy link
Contributor

I mean, would you agree with my point that this proposal would change what we call the ledger?

@sharafian
Copy link

Are you saying that the sendData function isn't part of the ledger layer because it doesn't have bearing on the ledger itself?

@michielbdejong
Copy link
Contributor

Old view: the trustline ledger with the conditional transfers of PluginVirtual is the real interledgery ledger to which the L in LPI refers, the PayPal ledger may also be a ledger, but it's out-of-scope for interledger.

New view: the data sent for prepare and fulfill is just data, not money. The unconditional transfers that rebalance the liquidity afterwards, are now the real interledgery ledger to which the L in LPI refers.

@emschwartz
Copy link
Member

It feels like a really big change, right?

This definitely feels like a big change to how we talk about Interledger, and specifically what it requires from ledgers. But it isn't a super substantive change from how we were already using ILP with trustlines and payment channels.

my point that this proposal would change what we call the ledger

I don't think it changes what entity we call the ledger, only what functionality we expect from ledgers.

The old view was that Interledger required ledgers to be fast, cheap, and support conditional transfers or we'd need to add an extra layer on top of them. The new view is that ledgers just do simple transfers of value and the Interledger layer implements the conditional part.

@michielbdejong
Copy link
Contributor

ledgers just do simple transfers of value and the Interledger layer implements the conditional part

yes, so in the example from the screenshot, we will now say Paypal is the ledger, and PluginVirtual's trustline no longer is.

@earizon
Copy link

earizon commented Jan 5, 2018

@sappenin

would it not make sense to break the ILPv4 packet into 2 separate payloads (one for Layer3 Interledger data and one for Layer2 LPI data),

My intuition tells me that having something that keeps constant during the payment process can be a good thing. That would represent the initial contract between the sender and receiver, the "intention to make a payment" that both parties have agreed, for example during the SPSP phase. In the InterledgerPrepare packet that you mention it could also be useful to add the intended initial amount. In case of trouble this could really help in tracing the source of the problem and taking sensible decisions. It adds a few extra bytes but this is not really a concern in terms of performance. A wrong network setup forcing for example continuous tcp re-connections will have a much bigger impact in terms of slowdowns.

Also the payment related data would go into the InterledgerPrepare (constant) packet while any data in the LocalLedgerPrepare could be used at will by peers's plugins. (private data within peers).

@adrianhopebailie
Copy link
Collaborator

It's taken me a while to catch up on everything but my general feeling is that:

  1. This is a great improvement BUT
  2. We may have swung the pendulum too far the other way this time by putting the transfer amount and expiry in the packet.

I agree with @sappenin (I think). An ILP prepare packet should contain an ILP Address, a Condition and Data (only expected to be consumed by the entity identified by the address). The response packet should contain either an Error plus Data or a Fulfillment plus Data.

In this way the ILP layer is a clean inter-networking layer that is purely for the purpose of routing a condition and request data in one direction and routing the fulfillment and response data in the other direction.

The understanding between the payer and payee is that the payee will only respond with a valid fulfillment if they get paid to do so. Since the payer has no direct relationship with the payee they make a request to a local peer, committing to pay them if they are able to get the fulfillment from the payee. This propagates all the way to the payee who ultimately gets paid for the fulfillment and response data which are passed all the way back to the payer.

How much is paid (if anything) is out of scope of the Interledger layer. In fact a payer may not pay their local peer anything if they think the ILP Packet will still be delivered. The Condition, Fulfillment and Data exchanged may be valuable enough in their own right.

@justmoon said:

you can update the packet in-place, you don't have to copy it.

I'm not sure I agree with that. Sure, it's possible, but why force implementations to do this if we can design the protocol to avoid it? Instead we are using a non-standard fixed-length date format just to make this easier. I think we should discuss this further.

In #363 @emschwartz asked the same question and @justmoon made the point:

we should keep this information in the standard packet. The whole point of having a packet is to minimize the surface area between the ledger and interledger layers and what we have now is pretty close to minimal.

Again, I don't agree completely. I think forcing all layers below the ledger layer to standardize on UInt64 with no currency for amounts adds complexity rather than reducing it.

IMO the interface from the ledger layer up to the interledger layer should look as follows:

routePayment(incomingRoute, incomingTransferAmount, expiry, ilpPacket)

i.e. The ledger layer has dealt with preparing for an incoming transfer which will be made in exchange for routing the attached ILP Packet. Based on the amount it is being paid and the time remaining before the offer expires the ILP layer routes the packet to an outgoing ledger layer route.

The current proposal makes the interface:

routePayment(incomingRoute, ilpPacket)

I'm not convinced that makes this simpler since the connector now has to decode and recode the ILP packet but I need to spend some time looking at the implementations to be sure.

I do like @emschwartz characterization of the layers below this being split further and, despite my gut telling me we'll encounter a lot of debate around the "true" meaning of these terms, also agree with calling them the clearing and settlement layers.

The clearing layer is responsible for the transfer of value between peers on the route of a payment. The ILP layer is unaffected by the semantics of this relationship BUT by having a well-defined standard for the condition and fulfillment the participants at the clearing layer can leverage this and use the condition and fulfillment in the rules they enforce for transfers between the nodes.

Where two peers don't trust one-another they can insert an intermediary between then that they mutually trust. This could be a mutually trusted "ledger" (as described by @justmoon above) where the system is just responsible for same-currency transfers between two accounts. This system could also be a decentralized system like XRP Ledger so the two connecting parties don't need to trust a third-party but just trust the decentralized system.

So perhaps a good way to start thinking about ledgers is simply as a specialization of a connector where all accounts are the same currency.

@adrianhopebailie
Copy link
Collaborator

An observation that I wonder if everyone agrees with:

The interface from interledger -> ledger component in ILPv4 is:

sendData(ilpPacket)
sendMoney(amount)

This can be executed either as:

-- sendData(preparePacket) -->
<-- sendData(fufillPacket) --
-- sendMoney(amount) -->

OR

-- sendMoney(amount) -->
-- sendData(preparePacket) -->
<-- sendData(fufillPacket) --

It's possible that the protocol used between two peers supports passing the ilpPacket with the sendMoney (as a memo for example). E.g. in the case where there is an ILP-enabled "ledger" system and the financial effect of sending the ILP prepare packet is the same as sending a sendMoney (funds are moved from the peers account to a hold account of the "ledger")

In this case I'd expect the plugin for that protocol to only support the latter sequence (pay first) but to queue the sendMoney until it gets the sendData and then use the protocol's version of

sendMoney(preparePacket)

On the receiving side the plugin will parse the incoming sendMoney(preparePacket) into first a sendMoney(amount) call to the Interledger component (where the amount is extracted from the packet) and then a 'sendData(preparePacket)`.

@justmoon @emschwartz @sharafian @michielbdejong @dappelt does that sound right?

@adrianhopebailie
Copy link
Collaborator

Follow up question: who initiates the reversal of the sendMoney(amount) on a pay-first account if the sendData(ilpPacket) never arrives?

Similarly, how does the receiver on the account request a sendMoney if it never arrives following the fulfillment on a pay-after account?

i.e. Who is responsible for reconciling sendMoney and sendData calls in the two account scenarios?

@michielbdejong
Copy link
Contributor

Who is responsible for reconciling sendMoney and sendData calls in the two account scenarios?

With ILP v1, the plugin (even if it was a virtual / BTP plugin) was expected to keep that balance. Now we no longer call it a balance that needs to be reconciled if it gets too low, but an "unsecuredAmount" that needs to be reconciled if it gets too high, see #360 (comment)

@emschwartz
Copy link
Member

who initiates the reversal of the sendMoney(amount) on a pay-first account if the sendData(ilpPacket) never arrives?

You probably wouldn't reverse it. Instead, the sender's account would just have a small positive balance. (Don't think of sendMoney as necessarily corresponding to an individual ILP payment)

Similarly, how does the receiver on the account request a sendMoney if it never arrives following the fulfillment on a pay-after account?

They don't, they just wouldn't forward any more ILP payments for that sender if they don't pay up.

On the receiving side the plugin will parse the incoming sendMoney(preparePacket)...does that sound right?

Not really, because the whole point of this change was to remove conditional transfers from the ledger and you're talking about how to support putting them back in...

@adrianhopebailie adrianhopebailie added the ilp Related to the core protocol specs label Mar 16, 2018
@stale
Copy link

stale bot commented May 10, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. \n\n If this issue is important, please feel free to bring it up on the next Interledger Community Group Call or in the Gitter chat.

@stale stale bot added the wontfix label May 10, 2018
@stale stale bot closed this as completed May 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
history ilp Related to the core protocol specs wontfix
Projects
None yet
Development

No branches or pull requests

9 participants