Giter Site home page Giter Site logo

interledger / rfcs Goto Github PK

View Code? Open in Web Editor NEW
423.0 71.0 106.0 1.45 MB

Specifications for Interledger and related protocols

Home Page: https://interledger.org

License: Other

JavaScript 55.73% HTML 4.44% Shell 33.47% Mermaid 6.35%
rfc ledger interledger ilp payments micropayments blockchain protocol interledger-protocol

rfcs's Introduction

Interledger RFCs gitter

This repository contains a collection of various specifications and documentation related to the Interledger Protocol (ILP). These documents or requests-for-comment (RFCs) are published by various authors and publication here does not imply official status unless otherwise specified in the document.

The process for submitting an RFC is documented in the RFC Process.

For the main reference implementation of the ILP stack, see Interledger.js.

ASN.1 and OER

A number of the protocols define data structures in ASN.1 notation. The collection of definitions is in asn1.

Changes to these files are automatically checked and compiled during CI using online ASN.1 tools from OSS Nokalva. If you need ASN.1 tools for any work you're doing on Interledger please contact them for assistance.

OSS Nokalva

You can also check your ASN.1 definitions online using OSS Nokalva's ASN.1 Playground available at http://asn1.io/

The default encoding rules for Interledger protocols are the Canonical Octet Encoding Rules as described in Notes on OER encoding.

Interledger Overview and Explanatory Docs

Core Interledger Protocol Specs

  • 27: Interledger Protocol V4 (ILPv4)

    Specifies the Interledger Protocol and Interledger Packet, which are used for sending payment instructions across different ledgers and connectors. This is the core protocol in the Interledger stack.

  • 15: ILP Addresses

    Specifies the Interledger Address format for ledgers and accounts.

Protocols Built Upon ILP

  • 9: Simple Payment Setup Protocol (SPSP)

    A basic Application Layer protocol that uses HTTPS to exchange details needed to set up an Interledger payment.

  • 29: STREAM

    The recommended Transport Layer protocol for most use cases, which handles quoting, individual payments, chunked payments, and streaming payments using a shared secret between the sender and receiver.

Ledger Layer

  • 38: Settlement Engines

    Specifies an interface to send and receive payments across different settlement systems and ledgers.

rfcs's People

Contributors

adrianhopebailie avatar davidnicol avatar dora-gt avatar emschwartz avatar gakonst avatar huijing avatar ivanseidel avatar jakeatdocforce avatar jasondavies avatar justmoon avatar kevinwmatthews avatar khoslaventures avatar kincaidoneil avatar mduo13 avatar michielbdejong avatar monsieurv avatar professorhantzen avatar ryangyoung avatar sabineschaller avatar sappenin avatar sbellem avatar sentientwaffle avatar sharon-wang avatar stakeylock avatar sublimator avatar tholop avatar traviscrist avatar unihedro avatar uroshercog avatar wilsonianb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rfcs's Issues

RFC-2: OER encoding of featureBitmask

Currently the RFC specifies the binary representation of a cryptocondition as follows:

Condition ::= SEQUENCE {
    type ConditionType,
    featureBitmask OCTET STRING,
    fingerprint OCTET STRING,
    maxFulfillmentLength INTEGER (0..MAX)
}

Notice that featureBitmask, which is an integer, is defined as an OCTET STRING. According to the OER spec (2.6, clause 2) variable-length octet strings are encoded as:

otherwise, the encoding of the octet string value consists of a length prefix as described in 2.11, followed by the octets of the string.

Notice that the endianess of an octet string is unspecified; with featureBitmask being an integer an implementation running on a little-endian architecture might, reasonably, encode the featureBitmask differently than one running on big-endian.

I suggest that we instead encode the field as an INTEGER of unknown length, under section 2.2, which explicitly specifies endianess ("All integer encodings are in big endian order."). So the featureBitmask would fall under clause 10:

otherwise, the integer value is encoded as a length prefix as described in 2.11, followed by a _signed_ binary integer occupying a variable number of octets; the length prefix contains the number of subsequent octets.

The emphasis on "signed" is mine: since the integer is represented as signed, if the high bit of the first encoded byte would be set, the encoder should add a leading 0 byte in the representation since the value is unsigned.

This is a change to the binary representation of cryptoconditions and the library itself will need to be updated.

All references to sections are based on this document: http://www.oss.com/asn1/resources/books-whitepapers-pubs/Overview%20of%20OER.pdf

RFC-4: add getAddress method

Ledger plugins should be able to tell you what your ILP address is (it can't be simply parsed from the auth because that is not standardized)

Proposal: "payments" -> "transfers"

Earlier when we actually had Payment objects, which contained multiple Transfer objects corresponding to different ledgers, it made sense to distinguish between local "transfers" and interledger "payments". Now that we do not have Payment objects anymore, we should stop using the term "payments". "Payments" are a loaded term for many people, and they also imply sending currency, which Interledger is not limited to.

I would propose that we talk about any sending of assets as a "transfer". If we need a distinction between local and interledger sends, I would propose that we say either "local transfer" or "interledger transfer".

RFC-[3,4]: Design error handling behavior

Currently, the retry/reject functionality mentioned in IL-RFC 4 is not actually being used. We should update the API with our latest thinking and figure out how error handling will work in ILP.

RFC-9: Combine Query and Quoting phases

The query phase should just include all information needed to locally calculate the behavior/cost for different amounts, to avoid a separate quoting call.

PROPOSAL: Refund local transfers immediately if connector returns error

Ledgers should allow a receiver (or receiving connector) to request that a transfer on hold for them be rolled back before it times out.

The ledger can notify the sender (or sending connector) who may then retry the transfer via a different connector, via a different ledger or by correcting an error in the transfer and resubmitting via the same connector again.

RFC-4: Make it clear that this document is JS specific

Some people were confused by IL-RFC 4, because it looks like a standard for all ledger plugins, but several design choices are in reality pretty specific to JavaScript.

Let's make it more clear that RFC-4 is specific to JavaScript.

RFC-4: Replace data field with ilpPacket

...or just packet

We don't care about passing arbitrary data along with transfers, we only care about passing the ILP packet. Plugins should figure out how to transfer the packet and extract it from an incoming transfer. Right now clients depend on accessing transfer.data.ilp_header, which seems odd and unnecessary.

I think @adrianhopebailie highlighted this in a thread somewhere.

RFC-4: Events `receive`, `fulfill_execution_condition`, `reject` -> `transfer_{prepare,execute,reject}`

Proposal: replace receive, fulfill_execution_condition, and reject with transfer_prepare, transfer_execute, transfer_reject.

Right now our event API leads to unnecessary complication on the part of the user of the plugin (client or connector).

Let's say you're a receiving client trying to check when you receive money. Right now you need to listen for both the receive and the fulfill_execution_condition events. You need to check whether a transfer you get from the receive event has an execution_condition. If not, you have actually received money. If the transfer does have a condition, you need to recognize that you have not received money but only a notification of funds being held. You only know a Universal payment (with holds) is completed when you get a fulfill_execution_condition event. You can't only check the fulfill_execution_condition event though because you might get money from a transfer with no condition.

Since any user of the plugin will immediately want to know the state of a transfer it gets, and since the plugin is in the best position to know what state it is in (depends on the details of the ledger), the plugin should provide explicit events for these different states.

RFC-3: Proposal especify Ilpamount with integers

Specifying amounts in floating point can be prone to error specially for protocols designed to be interoperable between different implementations in different languages and running on different hardware.

I think that it would be possible to use only integer amounts in the interledger protocol. Different ledger implementations already do this by specifying the amounts in the minimum divisible units. In bitcoin transactions, amounts are specified in satoshi and in ethereum transactions, amounts are specified in wei.

The same could be done in Ilp when requesting a quote from the connector the connector could provide information about the minimum divisible unit in the destination ledger. This way a client could specify integer Ilpamounts.

RFC-[1,3,5,6]: Combine "Transport protocols" back into ILP?

We have been calling Optimistic, Universal, and Atomic "transport protocols" based on the analogy with the Internet's layers, rather than Interledger Protocol "modes" as described in the original whitepaper. This has caused some confusion, in part because the analogy with the Internet's transport protocols is not a perfect one. This is a proposal to (re)include Optimistic and Universal -- not Atomic -- in the Interledger Protocol (RFC-3).

Transport protocols are host-to-host, Universal is not
The Internet's transport protocols (UDP, TCP) are completely ignored by the intermediary routers and only used by the hosts on either end of a connection. Universal is not "host-to-host" because it must be understood and supported by all intermediary ledgers and connectors. The partial analogy with the Internet makes the "transport protocol" terminology confusing.

Include Universal (and Optimistic) in ILP
Since Universal is not truly a transport protocol, we should include executionCondition and expiresAt in the ILP packet and call it part of the core Interledger Protocol. This makes "ILP" slightly more complicated, but the hold + crypto condition feature is already required for "full" and even "basic" Interledger support. Optimistic is already just the plain ILP packet with no condition or expiry.

What about Atomic?
Since writing the whitepaper we've started to see Atomic as a protocol that will be used within defined groups of connectors (and ledgers that support cancellationConditions). Finding commonly trusted parties is non-trivial and unlikely to work across distant groups. Atomic mode is one of a potentially large set of optimizations specific groups may use, for example to reduce their risk or increase efficiency. Thus, Atmoic should not be something that should be part of the core protocol implemented by everyone.

Issues / questions:

  • If the executionCondition is in the ILP packet as well as in the transfer, careless implementors may shoot themselves in the foot by failing to check that the two match.
  • If someone wanted to use "Interledger" and even the packet format, but didn't want to use the Crypto Conditions spec for the hold conditions, would that be "Interledger"?
  • It may be useful to have conditions in the ILP packet even if the ledgers don't support cryptographic holds. This way, senders could tell whether their payment made it to the recipient even though it's not secured by the ledgers. If this is a valid use case, is the crypto condition really an "execution condition"? Is it just a "condition"?

RFC-4: Flatten ledger plugin PluginOptions

Mentioned in #31 under "LedgerPlugin API Changes". The current PluginOptions object which is passed to the LedgerPlugin constructor has an auth field and a store field. However, the store may or may not be there depending on the plugin, and the contents of auth are plugin specific. The auth object can be flattened into the PluginOptions object, and special fields like store which cannot be represented in JSON are identified with a preceding underscore. The format would change from:

{
  auth: { /* plugin specific fields*/ }
  store: {get, put, del}
}

To:

{
  /* plugin specific fields */,
  _store: {get, put, del}
}

RFC-4: Include state in LedgerPlugin Transfers?

Clients and connectors need to be able to differentiate between incoming transfers that are prepared and awaiting fulfillment from those that are executed to determine how to react to the notification

RFC-11: Rename ITP to Payment Request Protocol (PRP)

Our analogy with IP Transport protocols is imprecise and calling ITP and other such protocols is confusing because they aren't actually "transporting" anything. Unless we can come up with a better name for this layer I would propose changing the name to something more descriptive of the actual functionality, like Payment Request Protocol.

RFC-4: Remove cancellation condition

Atomic mode will likely be used only between tightly-knit subgroups. We can simplify the general ILP implementation by removing cancellation conditions from the ledger plugin API.

This ticket is a strawman to see if anyone can come up with a compelling reason why we would want to keep cancellation conditions around.

Reasons to remove:

  • Simpler ledger plugins
  • Harder for connectors to shoot themselves in the foot

See also: #28

ILP Addresses per transaction?

In ITP we specify that the receiver can set a UUID for the transaction however it seems equally viable to simply append that to the receiver's address allowing the receiver to:

  1. Include the transaction identifier in the condition
  2. Easily reconcile the transaction later

RFC-4 - Allow RejectTransfer for any incoming transfer

The protocol currently allows for a transfer to be sent with no condition therefor it must define what a connector must do if it receives such a transfer and wants to reject it.

Right now the interface defines a rejectTransfer method for this but limits this to only transfers that are pending.

If a connector is able to use the same method to reject a transfer without a condition then this can be defined as the desired behaviour in the protocol.

RFC-3: add data header

Just like the IPv6 spec details some of the nextHeader possibilities (see here), we should explain how to attach arbitrary data (and maybe some of the other common headers we might need)

RFC-3: What does a connector do if they receive a transfer where the conditions in the transfer frame and the ILP packet are different?

The connector wants to get the money on hold for them so they want the transfer frame condition to be fulfilled therefor they would use that condition unless there is another way to get it fulfilled (perhaps the fulfillment in the ILP Packet is used to generate the fulfillment in the transfer frame).

BUT what really matters is which condition the receiver will fulfill (See #73) because that is the fulfillment they are most likely to receive. This means using the condition in the transfer frame too.

All of this implies that a connector will only put a different condition in the transfer frame to the one in the ILP Packet if they are certain that another connector down the line (or the receiver) will:
a) Fulfill that condition or do something that fulfills it
b) put the original ILP Packet condition back into the transfer frame for their next hop so that the receiver fulfills that condition

We should have language in the spec that details these scenarios and provides normative language for expected behavior.

We don't need to spell out atomic mode but should lay the foundations

RFC-3: What does a receiver do if they receive a transfer where the conditions in the transfer frame and the ILP packet are different?

Do they fulfill both if they can? They are only incentivized to fulfill the one that gets them paid which means the one in the transfer frame.

The implication is that if any connector changes the condition in the transfer frame to be different then it's unlikely any downstream connector will change it back because they are financially disincentivised to do so.

We should have language in the spec that details this scenario and provides normative language for expected behavior (which should align with incentives, i.e. fulfill the condition in the transfer frame).

PROPOSAL: Recommend that ILP Addresses are only encoded in Base64

The only requirement for ILP Addresses is that they are a binary string that can be used for prefix based matching at connectors.

Therefor RFC 3 does not need to specify an encoding but can recommend one that allows the binary string to be encoded into a human-readable form.

There is value in making this simple because it reduces the attack surface exposed by unusual addresses.

PROPOSAL: RFC 3 should say the following:

  • ILP Addresses are an octet string
  • It is not recommended for implementations to attempt to encode the address in any encoding but Base64URL
  • Human-readable addresses should be defined using only the Base64Url (RFC 4648) character set and then decoded. (This implies that they should then also be defined in multiples of 4 characters to avoid needing padding bits).
  • The - character (index 62) can be used as a delimiter in this case.
  • It would make sense for root addresses to use 4 or 8 chars so that subsequent segments can start with a - and then use 3, 7, 11, 15 etc. chars

Examples:
Bob's USD account at Well's Fargo in the USA
usa-bank-wfa-usd-bob = 0xba 0xc6 0xbe 0x6d 0xa9 0xe4 0xfb 0x07 0xda 0xfa 0xeb 0x1d 0xf9 0xba 0x1b
Adrian's ZAR account at Standard Bank in South Africa
rsa-bank-std-zar-adrian0 = 0xae 0xc6 0xbe 0x6d 0xa9 0xe4 0xfa 0xcb 0x5d 0xfb 0x36 0xab 0xf9 0xa7 0x6b 0x89 0xa9 0xf4
A Bitcoin account
bitcoin--145b3dEskk1a7U...

RFC-9: Questions about design + purpose of SPSP

I am looking over SPSP and have a number of questions about its design and purpose.

It seems like many of the options it was originally intended to bundle have since ceased to be options and are now fixed in other layers (e.g. sending "Universal" mode payments is now just sending ILP payments, and much of the request/response payment flow has been implemented in ITP).

As far as I can tell, this is what SPSP provides:

SPSP Features

  • Optional email-style identifiers for human readability
  • Handling end-to-end communication (which is explicitly left out of ITP) using HTTP
  • Standard API for peer-to-peer and invoice payments, two common use cases

Use Cases

Steps that are actually SPSP (versus a lower level protocol) are in bold (it's not that much)

Sending Peer-to-peer Payment, Fixed Destination Amount

0. (Optional) Discover - resolve human-readable identifier into URL
1. Setup - post payment params (amount, maybe sender id), get ILP Packet
2. Quote - check how much it would cost to delivery the packet
3. Execute

Paying Invoice

0. (Optional) Discover - resolve human-readable identifier into URL
1. Setup - get ILP Packet (no params)
2. Quote - check how much it would cost to delivery the packet
3. Execute

Sending Peer-to-peer Payment, Fixed Source Amount

0. (Optional) Discover - resolve human-readable identifier into URL
1. Query - get ILP address from receiver endpoint
2. Quote - find out how much receiver will receive
3. Setup - post payment params, get packet
4. Execute (create transfer based on original source amount, NOT based on packet)

Questions

  • Does the fixed destination amount use case make sense to include? How would the sender know how many units it would want the destination to receive if it doesn’t even know what ledger the destination is on?
  • If the only reason we need the Query step is to return the ILP address for fixed source amount payments so you can quote a payment to it, can we combine that endpoint with the Setup one? (#49 proposes combining Query and Quote, but Query goes to the receiver endpoint, whereas Quote goes through core ILP/ILQP to the connector)
  • Should the receiver endpoint return a binary packet or a JSON form that the client then turns into the packet to send? If it’s binary the receiver can include opaque routing headers that the sender won’t need to understand, but then we have a base64-encoded blob in an HTTP protocol. If it’s JSON then the SPSP client needs to reliably turn the JSON into the binary packet to send, and then the receiver needs to extract the same info from the packet to be able to regenerate the condition fulfillment.
  • Should the execution condition be based on the binary packet or an SPSP-specific representation of the fields to check? (Does it matter if SPSP uses ITP?)
  • If SPSP only needs one endpoint and that endpoint might even return a binary packet, should this be a protocol over HTTP? (Note it would probably be worth exploring combining ITP with IPFS’ libp2p for a transport-independent p2p application-layer protocol)
  • Could a receiver endpoint return different ILP addresses depending on params?

With @bensharaf

Proposal: Our transport layers deal with condition generation, memo encryption, ...

Issue #28 proposes the removal of Optimistic, Universal, Atomic as transport protocols.

@emschwartz suggested we could bring back conditions as a condition layer, because they are end-to-end and need to be standardized.

In addition to that, this layer could also deal with encrypting the memo to the recipient (we already have the recipient's public key in some of the layer types mentioned above.)

User-defined Transport

There is no condition and no expiry. The memo is unencrypted.

sender.getCondition(condition) 

Interactive Transport

Receiver generates the condition and provides a payment request (with a standard format) to the sender.

receiver.generateCondition(ilpPacket)
sender.getCondition(multiPaymentRequest | previousFulfillment)

As an additional feature, we could have a condition whose fulfillment is another payment request (including a condition), such that multiple (pre-planned) payments can be expressed by one original payment request. This is useful for repeated payments or other predictable payments between the same participants.

Passive Transport

Receiver has an Ed25519 public key. The sender generates the condition from this key and encrypts the memo with it. (Supercedes #30)

sender.getCondition(receiverPublicKey, ilpPacket:Buffer)
receiver.getFulfillment(receiverPrivateKey, finalTransfer)
// - Verify transfer has as much money as ilpPacket
// - Verify condition matches ilpPacket

// Alternative: sender-encrypted hashlock
sender.getCondition(receiverPublicKey, ilpPacket:Buffer)
receiver.getFulfillment(receiverPrivateKey, finalTransfer)
// - Verify transfer has as much money as ilpPacket claims
// - Verify condition matches ilpPacket

Open Questions:

  • How to decide ILP header expiry for Passive case?
  • How to decide source transfer expiry for Interactive & Passive cases?
  • Do we have an equivalent to UDP/TCP ports (i.e. an application ID or something)
  • Naming: Does it matter that we had a different meaning for UTP for a while? (Universal vs User-defined)

RFC-4: Remove canConnectToLedger

The canConnectToLedger call was supposed to be for a kind of ledger auto-detection, but we ended up just using an explicit type, which is simpler. So we should remove canConnectToLedger.

RFC-11: Add multi-payments to Interactive Transport

It is possible to remove a round trip for repeated payments between a sender and receiver if the receiver sets up their conditions such that the fulfillment for the first payment contains the payment request for the second payment.

We may want to add this feature once the use case is a bit better defined.

RFC-4: Ability to cancel incoming pending transfers

Idea from @adrianhopebailie.

If connectors can actively cancel incoming pending transfers, we can allow the previous connector/client to immediately retry. This can either result in much faster failures and therefore faster retries, or even retries without failing all the way back to the sender, because there is sufficient time to retry from the last successful connector.

Note that this could be done with cancellation conditions on the ledger level. But then the previous connector would need the public key of the next one. So it is preferable where possible to add a separate ledger feature to accomplish this.

Add a new method rejectIncomingTransfer which accepts a transferId:String and returns a Promise.<null>.

RFC-8: Send quote requests via Optimistic payments

A neat trick... Connectors broadcast rate curves and routes to one another but more well-known connectors don't have much of an incentive to store much information about the less well-known connectors and ledgers.

If ILQP is implemented such that quote requests are sent over the Interledger as Optimistic payments, more central connectors might actually have an incentive to store the routing info of smaller ledgers and connectors. The way it would work is each successive connector would take a little bit of the Optimistic payment's value until the packet reached a connector that could actually answer the quote request. Therefore, if a more central connector can answer the request without having to query further down the chain it would (legitimately) keep more of that payment's value.

Note that connectors could pretend to know the route info and keep the full value of the payment. However, when the sender went to actually send the payment it would likely fail so this would just show up to earlier connectors and the sender as an unreliable route and they would avoid it in the future.

It's also interesting to note that quote requests will often be followed by payments worth even more, so there may be an even more direct incentive to respond to the quote request honestly.

Proposal: Passive Payment Setup Protocol (alternative to SPSP)

We've gotten feedback from a number of people that SPSP doesn't seem simple because it relies on direct communication between the sender and recipient, which can't be guaranteed in every scenario.

An alternative proposal: Passive Payment Setup Protocol (PPSP)

Sender gets the following from a static source (use-case specific, some kind of central registry):

  • Ed25519 public key
  • ILP Address
  • Additional routing info needed by the sender (e.g. ledger precision)

PPSP would define how the sender should generate the condition from the transfer properties. The receiver would use the same method to check the incoming transfer against the condition before producing the fulfillment.

Open questions / issues:

  • For SPSP we've been assuming that the receiver can tell the sender what the rate curve looks like from some more well-known ledger to final ledger. If there's no direct communication and the sender is only querying a static source, we need to figure out another way for the sender to determine the last mile rate. The sender could potentially send a quote request using #29 before sending a payment.

RFC-4: meaning of `p`

In the method list like connect it is described as p.connect()

My understanding is that p refers to the LederPlugin object and it has to interface all the listed methods. Is this correct?

RFC-11 : Add key identifier to ITP Header

It's possible that a receiver may wish to maintain multiple secrets/keys for use in generating the pre-image for ITP payments.

This may be because the receiver wishes to have different keys per sender or just keep old keys alive for a short period after rotating to a new key.

It's common practice for entities like the receiver to store these keys securely index by some unique identifier (even just a numeric counter/index).

The receiver then uses this index to look up the key so it can recreate the the fulfillment after receiving a payment.

To do this, it must provide the key identifier to the sender in the original payment request (Interledger Packet) and the sender must send this in the subsequent payment.

PROPOSAL:

Add a new field to the ITP header

Field Type Short Description
keyIdentifer OCTET STRING Identifier used by the receiver to identify the HMAC key it used in generating this condition

RFC-4: Remove getConnectors method

We've more or less agreed that clients and connectors should figure out what connectors to connect to on a higher level. We should remove the getConnectors method from the Ledger Plugin Interface.

Proposal: Connector forwarding/delivery distinction

The current ILP connector implementation make a distinction between forwarding payments and delivering payments.

  • Forwarding occurs when the best matching (longest prefix) routing table entry names another connector. In other words, the connector has no direct access to the destination ledger.
  • Delivery occurs when the best matching routing table entry is a local ledger.

This mirrors closely a typical IP routing table:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.15.20.1      0.0.0.0         UG    600    0        0 wlan0
10.15.1.1       10.15.20.1      255.255.255.255 UGH   600    0        0 wlan0
10.15.20.0      0.0.0.0         255.255.254.0   U     600    0        0 wlan0
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 docker0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0

(Note the G flag. If set, it means to forward the packet through another gateway/router. If not set, it means to deliver the packet locally to the right host. The exception is subnetting, which is addressed later in this post.)

ILP Addresses

The ILP address space is divided into ledger prefixes. Here are some ILP addresses:

us.gov.fed.usd.ledger1.alice
cn.gov.pboc.cny.ledger2.bob.411dbf36-6180-4f3f-aa46-83092ebc8e36
btc.bitchannels.v1.1FfmbHfnpaZjKFvyi1okTjJJusN455paPH

The italicized portion is the ledger portion. The rest is the account portion. Every ILP address breaks down in this way.

This compares to IP addresses, which consist of a network and a host portion, which constitutes a similar breakdown.

Note that the ledger portion typically ends in a period (.) - this isn't mandatory, but strongly recommended practice, because otherwise the last segment of the ledger portion and the first part of the account portion will merge together with no visual separation at all. It also provides an easy way to distinguish between an ILP address (us.gov.fed.usd.ledger1.alice) and a ledger prefix (us.gov.fed.usd.ledger1.).

Common Prefixes

We believe that eventually, a very large number of ledger may be part of the Interledger. In order to plan for that, ledgers are encouraged to coordinate with each other in such a way that more closely related ledgers have longer common prefixes.

For instance, us.gov.fed.usd.ledger1. and us.gov.fed.usd.ledger2. might be very closely related, while us.gov.fed.usd.ledger1. and cn.gov.pboc.cny.ledger2. are not.

A connector operating in China may only have a generic us. route in its routing table, sending all US-directed payments through a single peer connector. This allows connectors to simplify and optimize their routing tables in order to reduce the amount of memory and bandwidth required for routing.

Note that there is no physical ledger with the address us.gov.fed.usd.. Common prefixes are merely informational.

Tagging

The account portion may include dots in order to indicate a further subdivision of the account space. Each ledger decides how it wants to handle address translation from the account portion of an ILP address to its local account address space. A typical behavior would be to discard all contents of the account portion from the first period onwards and deliver to an account by that identifier.

This gives account holders a large address space to tag their payments. For instance in the example given above, cn.gov.pboc.cny.ledger2.bob.411dbf36-6180-4f3f-aa46-83092ebc8e36, the account owner Bob has added a unique identifier to the address, presumably to associate the payment with some other prenegotiated data later.

Subledgering

Account holders may want to subdivide their funds and allocate them to different departments, devices, apps, etc. For instance, Bob might own a phone which has an app called "ACME App". This app can send and receive funds autonomously. In order to more easily keep track of its expenses, he might give it a unique ILP address like cn.gov.pboc.cny.ledger2.bob.phone.acme.

Bob might also want to restrict the amount of funds available for ACME App to spend. After all, the app could have a bug and Bob doesn't want it to be able to spend his entire life savings. So Bob sets up his own ledger and he operates an ILP connector between his account cn.gov.pboc.cny.ledger2.bob and the ledger he operates with the prefix cn.gov.pboc.cny.ledger2.bob.phone..

We call this a subledger. Bob has taken the account portion bob.phone.acme and subdivided it into a subledger portion bob.phone. and a subaccount portion acme.

The concept of a subledger is similar to subnets in IP.

Note that the connector on the cn.gov.pboc.cny.ledger2. still thinks it is the final hop and therefore delivering the payment. This is correct and expected. Creating a subledger is not the same as creating a new ledger. For instance, since the unit of the amount delivered is determined by the ledger portion of the ILP address, the subledger MUST use the same currency as the parent ledger. Bob also cannot charge himself any fees when relaying a payment to his subledger.

Tail Routing Table (TRT)

In some cases, users may wish to do something akin to subledgering, but without the limitations described in the previous section. In order to do this, we propose a new header type, called the Tail Routing Table (TRT) header.

In the most minimal design, this header would contain only a list of ledger prefixes and amounts:

Prefix Amount
ilpdemo.red. 221
ilpdemo.red.bob. 201
ilpdemo.red.bob.sub. 200
ilpdemo.red.bob.sub.doubledollars. 100

This would allow the last regular connector (the connector delivering on cn.gov.pboc.cny.ledger2.) to look up the amount that it is expected to deliver. Whenever a connector is delivering (as opposed to forwarding) a payment, it would look up the local ledger prefix in the TRT header to see if there is a different amount that has been requested. If not, it would default to the amount given in the ILP header.

The main limitation of this design is that the amount is fixed. We can use this for sending a payment, but it will not help a connector with quoting. (This might be fine, since the connector can ask the next connector for a quote.) If we wanted a slightly more sophisticated design, we could include not amounts, but rates. I.e. each entry in the table would show the exchange rate between a given ledger prefix and the final destination account.

However, this limits us to a fixed rate. To provide even more flexibility, we would have to include a rate curve, similar to the rate curves found in the Connector-to-Connector Protocol (CCP).

Finally, we may also wish to override the next hop from the default (first segment of the account portion) to some arbitrary account on the same ledger.

Here is an example of a more fully featured TRT:

Prefix Next Hop Curve
ilpdemo.red. ilpdemo.red.bobconnector [curve]
ilpdemo.red.bob. n/a [curve]
ilpdemo.red.bob.sub. n/a [curve]
ilpdemo.red.bob.sub.doubledollars. n/a [curve]

Tail Routing Tables can also be used for source routing. In source routing, we know the entire path. As a result, we know what the local prefix will be at each step. So we simply need to include a routing entry for each hop which will take precedence over the connector's default routing table.

Proposal: ILP Address Mapping

So far we haven't explained how ILP addresses would actually map to local ledger addresses. We need a scheme similar to the Address Resolution Protocol (ARP) in the IP stack.

Flow

  1. When an Interledger module wants to send a payment, it must first determine whether the payment is local for any of its ledger plugins. Local means that the address starts with the ledger plugin's address prefix.
  2. If yes, send through that plugin.
  3. If no, resolve using ILP routing table to a connector's ILP address and send to that address. (All next hop addresses in the routing table MUST be local.) Typically, clients' routing tables would contain a single entry with a catch-all (gateway).

Examples

We are us.fed.wf.alice.

Note: The send() API is simplified in this example.

core.isLocalAddress("us.fed.wf.bob") -> true
plugin.send("us.fed.wf.bob", "30.00")
  - Is local? Yes (otherwise throw exception)
  - My prefix is "us.fed.wf", so local identifier is "bob"

core.isLocalAddress("uk.gov.bofe.rbs.john") -> false
(not local, => look up in routing table - returns gateway ilp address)
plugin.send("us.fed.wf.connie", "30.00")
  - Is local? Yes (otherwise throw exception)
  - My prefix is "us.fed.wf", so local identifier is "connie"

core.isLocalAddress("us.fed.wf.nerd.frednoob") -> true
plugin.send("us.fed.wf.nerd.frednoob", "30.00")
  - Is local? Yes (otherwise throw exception)
  - My prefix is "us.fed.wf", so local identifier is "nerd"

Address Format Change

Before:

us.fed.wf/bob

After:

us.fed.wf.bob

Previously, we thought that being able to differentiate an account address from a ledger address was a useful feature. But as we investigated the details of the address resolution process, we discovered that this distinction makes it impossible for us.fed.wf/bob to be a ledger with subaccounts.

We were able to find the scheme outlined in this issue which properly allows for local address resolution without distinguishing between ledger addresses and account addresses.

Ledger Plugin API Changes

We want to add a new method to the ledger plugin:

getPrefix() -> Promise.<String>

getPrefix returns the ledger plugin's ILP address prefix (which may be configured, automatically detected, hard-coded, etc.)

If an ILP address begins with a ledger plugin's prefix, the address is considered local with respect to that plugin.

The call getAddress returns the ILP address. (Instead of the local account identifier.)

Ledger plugin configuration is custom per plugin (custom settings are no longer wrapped in an auth property.)

The account property in the send() call contains a ILP address (not a local address).

Some properties (such as _store) MAY be injected by the application hosting the plugin, however these are guaranteed to start with an underscore. (_)

Configuration Examples

new BellsPlugin({
  prefix: 'us.fed.wf', // defaults to the ledger's self-reported prefix
  account: 'https://red.ilpdemo.org/ledger/accounts/nerd',
  password: 'alice',
  _store: { ... }
})

// nerd
new VirtualPlugin({
  prefix: 'us.fed.wf.nerd.frednoob',
  token: '1234-1234',
  account: 'wootmeister',
  balance: '300',
  limit: '0',
  mqttHost: 'http://mqtt.example',
  secret: '245t',
  _store: { ... }
})

// noob
new VirtualPlugin({
  account: 'blahmeister',
  token: '1234-1234',
  mqttHost: 'http://mqtt.example'
})

with @bensharaf and @pedrorechez

RFC-2: Clarify that the binary encoding for conditions uses a variable-length encoding for fingerprints and why

The fingerprint in binary-encoded conditions is encoded as a standard variable-length octet string.

The reason is that different condition types may use different hashing functions and therefore have different length hashes. (You could tell from the type what the length should be, but we felt it was useful to be able to find the end of a condition in a binary stream even if you didn't recognize the type.)

This should be mentioned explicitly in the spec.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.