Skip to content

Instantly share code, notes, and snippets.

@justmoon
Last active February 13, 2017 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justmoon/a59fd43958ce421c8b4a88d5143c718b to your computer and use it in GitHub Desktop.
Save justmoon/a59fd43958ce421c8b4a88d5143c718b to your computer and use it in GitHub Desktop.
ILP Formats Rework

Interledger Protocol data format

Interledger packets are pieces of data that can be sent from one ledger user to another either as a message or attached to a transfer.

Header format

Each ILP packet consists of a series of headers. All headers start with a common eight byte preamble which looks as follows:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Type (16)          |           Length (16)         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Type:

    A 16-bit numeric ID identifying the type of header. The values are well-known IDs which map to a URI header type.

    The type field has bits with special meaning which are defined below.

  • Length:

    Length of the header in bytes. (Does not include the size of the Type and Length fields themselves.)

Special type bits

If the first bit of the type is zero, the header is called a required header. Required headers must be understood by all participants. If a participant encounters a required header that they do not understand, they MUST reject the entire transfer/message.

If the first bit of the header is one, the header is called an optional header. Optional headers may not be understood by all participants. If a participant encounters an optional header that they do not understand, they MUST ignore the header and process the rest of the transfer/message.

For optional headers, the second bit of the type is ignored. This bit is called the Partial bit. If a participant encounters an optional header that they do not understand and the Partial bit is unset, they MUST set the Partial bit before forwarding the packet.

Primary headers

Some header types can only appear as the first element in the message. All primary headers MUST also be required headers. When a participant encounters a primary header that appears after another header, it MUST reject/discard the entire message.

Type ranges

Range Used for
0...16383 Globally unique required types
16384...32767 Primary header-dependent required types
32768...40959 Globally unique optional types
40960...49151 Primary header-dependent optional types
49152...65535 Reserved for partial flag

Header Types

ILP header

Main header attached to ILP payments. Used for routing.

  • Primary header: Yes
  • Required header: Yes
  • Can appear on transfers: Yes
  • Can appear on messages: No
  • Multiple instances allowed: No
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Type (16)          |           Length (16)         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                     DestinationAmount (64)                    +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                     DestinationAccount (*)                    +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Type

    Always 0x0000; maps to "https://interledger.org/rel/ilp"

  • Length

    Length of the ILP header in bytes. (Does not include the size of the Type and Length fields.)

  • DestinationAmount

    Destination ILP amount. This is the amount that should be delivered to the destination account. Uses a 64-bit fixed-precision, floating-point decimal format (see Generic Data Types.) Implementations MUST reject negative values.

  • DestinationAccount

    Destination ILP account. Connectors should route the payment to this address. The length of this field equals the length of the ILP header minus 8 bytes.

ILP Source header

ILP senders can optionally specify their address by including this header. If they wish to include their address, but not the SourceAmount, they MUST set the SourceAmount to the special value of s = 0, e = -128.

  • Type: 0x4000 (Primary: 0x0000 / ILP Header)
  • Primary header: No
  • Required header: Yes
  • Can appear on transfers: Yes
  • Can appear on messages: No
  • Multiple instances allowed: No
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Type (16)          |           Length (16)         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                        SourceAmount (64)                      +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                        SourceAccount (*)                      +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Type

    Always 0x4000; maps to "https://interledger.org/rel/ilp/source"

  • Length

    Length of the ILP Source header in bytes. (Does not include the size of the Type and Length fields.)

  • SourceAmount

    Source ILP amount. Uses the Amount format (see Generic Data Types.)

  • SourceAccount

    Source ILP account. The length of this field equals the length of the ILP header minus 8 bytes.

ILP Trace

ILP senders may wish to know what path their payment is taking as it is being processed. This is important for debugging routing issues.

NOTE: More work is needed to evaluate the security and privacy implications of this feature. However, we recognize the need for good debug tools as a critical component of a successful routing architecture.

For more information about the contents of trace packets, please see: https://gist.github.com/justmoon/8e732663c53e39405cac379998e5c46c

  • Type: 0x4001 (Primary: 0x0000 / ILP Header)
  • Primary header: No
  • Required header: Yes
  • Can appear on transfers: Yes
  • Can appear on messages: No
  • Multiple instances allowed: Yes
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Type (16)          |           Length (16)         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                                                               +
|                                                               |
+                        UniqueUUID (128)                       +
|                                                               |
+                                                               +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                                                               +
|                                                               |
+                       TraceHostIP (128)                       +
|                                                               |
+                                                               +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       TraceHostPort (16)      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Type

    Always 0x4001; maps to "https://interledger.org/rel/ilp/trace"

  • Length

    Length of the ILP Trace header in bytes. (Does not include the size of the Type and Length fields.)

  • UniqueUUID

    Unique identifier to associate this trace request.

  • TraceHostIP

    Host IPv6 that trace packets should be sent to.

  • TraceHostPort

    UDP port number where trace packets should be delivered.

ILQP Quote Request header

Used by senders and connectors to request a quote from a connector.

  • Primary header: Yes
  • Required header: Yes
  • Can appear on transfers: Yes
  • Can appear on messages: Yes
  • Multiple instances allowed: No
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Type (16)          |           Length (16)         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                                                               +
|                                                               |
+                          QuoteId (128)                        +
|                                                               |
+                                                               +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                 DestinationExpiryDuration (32)                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    SourceExpiryDuration (32)                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                                                               +
|                                                               |
+                      DestinationAddress (*)                   +
|                                                               |
+                                                               +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Type

    Always 0x0020; maps to "https://interledger.org/rel/ilqp/quote_request"

  • Length

    Length of the ILQP Quote Request header in bytes. (Does not include the size of the Type and Length fields.)

  • QuoteId

    ID to identify the quote request.

  • DestinationExpiryDuration

    TODO

  • SourceExpiryDuration

    TODO

  • DestinationAddress

    ILP Address of the destination.

Note that the source address is always implied to be the address of the account that sent the quote_request message.

ILQP Quote Response header

Used by connectors to fulfill a quote request.

  • Primary header: Yes
  • Required header: Yes
  • Can appear on transfers: No
  • Can appear on messages: Yes
  • Multiple instances allowed: No
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Type (16)          |           Length (16)         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Type

    Always 0x0021; maps to "https://interledger.org/rel/ilqp/quote_response"

  • Length

    Length of the ILQP Quote Request header in bytes. (Does not include the size of the Type and Length fields.)

CCP Open header

This message is used by two peered connectors to perform an initial handshake before they start exchanging actual routing information.

  • Primary header: Yes
  • Required header: Yes
  • Can appear on transfers: No
  • Can appear on messages: Yes
  • Multiple instances allowed: No
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Type (16)          |           Length (16)         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         MLP Length (16)       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                     My Ledger Prefix (*)                      +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Type

    Always 0x0040; maps to "https://interledger.org/rel/ccp/open"

  • Length

    Length of the ILP Trace header in bytes. (Does not include the size of the Type and Length fields.)

CCP Update header

This message is used by a connector to update its peer with changes to its published routes.

  • Primary header: Yes
  • Required header: Yes
  • Can appear on transfers: Yes
  • Can appear on messages: Yes
  • Multiple instances allowed: No
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Type (16)          |           Length (16)         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
***TODO***
  • Type

    Always 0x0041; maps to "https://interledger.org/rel/ccp/update"

  • Length

    Length of the CCP Update header in bytes. (Does not include the size of the Type and Length fields.)

Generic Data Types

Amount

Simple decimal format consisting of two integers - significand and exponent - with a well-defined range.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Significand (56)                       |
+                                               +-+-+-+-+-+-+-+-+
|                                               |  Exponent (8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Exponent

    Signed (two's complement) 8-bit integer signifying the exponent e (base 10) of the amount. The amount is calculated as s * 10^e. The allowed range for e is -127 to 127. The special value e = -128 is reserved.

  • Significand

    Signed (two's complement) 56-bit integer representing the integer part of the amount aka the significand s. The amount is calculated as s * 10^e. The allowed range for s is -36,028,797,018,963,968 .. 36,028,797,018,963,967.

    There are 255 valid representations of zero. Implementations MUST accept all of them, but MUST produce only the value where s = 0, e = 0.

Generally, applications receiving amounts expressed in this format SHOULD convert them into a suitable arbitrary-precision decimal. This amount format is not intended to be used for calculations directly, however implementors MAY choose to do so for performance reasons if they take appropriate care.

Applications generating amounts in this format SHOULD choose the value closest to the actual value they are trying to represent and round as necessary. Higher-level protocols MAY specify the rounding behavior to be used in a given context.

The authors would have preferred to use an existing standard encoding and strongly considered using the decimal64 format from IEEE 754-2008. Unfortunately, it is significantly more complex to parse than the format presented here and not widely supported enough to make up for the complexity.

Liquidity Curve

Liquidity curves are used to represent the relationship between the input and output amounts of some connector or chain of connectors. It consists of a series of points where the x-axis is denominated in units of the input asset and the y-axis is denominated in units of the output asset. The y-coordinate of a point represents the output amount for a given x amount of input.

Each successive point's x and y values must be greater than the point before it. Coordinates must all be positive.

Between points the curve is thought to be linearly interpolated. Beyond the first and last points the curve is thought to be undefined and transactions in

JSON Representation

ILP Transfer Example

Local ledger transfer with an ILP header in JSON:

{
  "from": "connector",
  "to": "sharafian",
  "amount": "100",
  "data": [{
    "type": "https://interledger.org/rel/ilp",
    "destination_amount": "100",
    "destination_account": "us.nexus.sharafian"
  },{
    "type": "https://interledger.org/rel/ilp/source",
    "source_amount": "104.3",
    "source_account": "us.sharafian.justmoon"
  }]
}

Quoting Request Example

{
  "from": "lila",
  "to": "connector",
  "data": [{
    "type": "https://interledger.org/rel/ilqp/quote_request",
    "id": "721e4126-98a1-4974-b35a-8a8f4655f934",
    "destination_address": "example.usd-ledger.bob",
    "source_expiry_duration": "6000",
    "destination_expiry_duration": "5000"
  }]
}

Quoting Response Example

{
  "from": "connector",
  "to": "lila",
  "data": [{
    "type": "https://interledger.org/rel/ilqp/quote_response",
    "id": "721e4126-98a1-4974-b35a-8a8f4655f934",
    "source_connector_account": "mark",
    "source_ledger": "example.eur-ledger.",
    "source_amount": "100.25",
    "source_expiry_duration": "6000",
    "destination_ledger": "example.usd-ledger.",
    "destination_amount": "105.71",
    "destination_expiry_duration": "5000",
    "liquidity_curve": [
      [ 0, 0 ],
      [ 100000000, 99799999.99 ]
    ]
  }]
}

Route Broadcast Example

A connector wants to tell a peer about a new route.

{
  "ledger":"peer.sZapq.usd.",
  "from": "peer.sZapq.usd.bVHMFFYfda6f-_obQuqqW2Vo5W15o3ov5MeZldxWCWk",
  "to": "peer.sZapq.usd.hMhQUg-lLvVgb3z10jAsxfHw_h-ljkavH9Fxr8vyTQc",
  "data": [{
    "type": "https://interledger.org/rel/ccp/update",
    "new_routes": [{
      "source_ledger": "peer.sZapq.usd.",
      "destination_ledger": "us.usd.ilptestblah.",
      "points": [
        [ 0, 0 ],
        [ 100000000, 99799999.99 ]
      ],
      "min_message_window": 1,
      "source_account": "peer.sZapq.usd.bVHMFFYfda6f-_obQuqqW2Vo5W15o3ov5MeZldxWCWk"
    }],
    "withdrawn_routes": [
      "old.destination."
    ]
  }]
}
@michielbdejong
Copy link

  • Couldn't the ILP source header be tempered with at an intermediate hop?
  • Nodes that are not on the IPv6 internet will not be able to send trace information. This is OK as long as all nodes are on servers inside data centres, but not if we expect nodes to, one day, be behind home/shop/office/mobile carrier firewalls.
  • Shouldn't the ILQP Quote Response header repeat the quoteId from the corresponding ILQP Quote Request header, and how do these "headers" relate to the "body" of ILQP messages?
  • What's the use of the 'MLP length' field in the CCC Open header?
  • I like the data format for the binary representation of decimal significands/exponents! Remarks:
    • why use two's complement for the significand? Is there a use case for negative significands?
    • just like there are 255 ways to represent 0, there are 57-k ways to represent any k-figure integer number, for k>0.

@emschwartz
Copy link

Discussion -> interledger/rfcs#146

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