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

ILP Over HTTP #349

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions 0000-ilp-over-http.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
draft: 1
title: ILP Over HTTP
---
# ILP Over HTTP

This spec defines a minimal [Ledger Layer](./0001-interledger-architecture/0001-interledger-architecture.md#ledger-layer) protocol using the Hyper Text Transfer Protocol (HTTP). It includes the Interledger payment fields (such as destination address) alongside those that are local to a specific hop (such as the transfer amount).

**Note:** This protocol is not to be confused with [HTTP ILP](./0014-http-ilp/0014-http-ilp.md), which defines HTTP headers for communicating payment details on a normal HTTP request to an application server. The values defined in this protocol will be forwarded to the destination ILP address defined in the request.

## Overview

It's everything you need to do ILP with just a couple of HTTP headers on a POST request/response. What more do we need to say?

## Specification

This protocol SHOULD be used with HTTPS or HTTP/2. It SHOULD NOT be used with insecure HTTP except for testing purposes.

### Request

```http
POST / HTTP/1.1
ILP-Destination: g.crypto.bitcoin.1XPTgDRhN8RFnzniWCddobD9iKZatrvH4.~asdf1234
ILP-Condition: x73kz0AGyqYqhw/c5LqMhSgpcOLF3rBS8GdR52hLpB8=
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base64url encode the condition as x73kz0AGyqYqhw_c5LqMhSgpcOLF3rBS8GdR52hLpB8?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the motivation for using base64url (slightly obscure) vs base64?

Most standards I have come across use base64 unless they need to put the encoded data in a URL.

Also, as @michielbdejong points out, we should be consistent on padding

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we ever anticipate putting a condition into a URL? Given that this is specifying an HTTP binding for ILP-core, it seems like the answer would be, "probably."

If that answer is accurate, then we probably want to be consistent and allow for that (adding conditions to URLs) to happen easily without transformation (?).

For example, might some client (like an admin system or something) want to be able to query an ILP server for transfers, possibly identifying them by condition, like:

GET: /transfers?condition=x73kz0AGyqYqhw_c5LqMhSgpcOLF3rBS8GdR52hLpB8

While we're at it, is there an argument to use HEX encoding here? That way nobody will be confused about whether we used URL encoding or not? (There was some confusion about this in the crypto-conditions spec and @justmoon had a good rationale for when to use which encoding, but can't remember the details -- maybe it was just HEX for the DER?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My vote would either be for normal base64 or hex.

Using a module that supports base64url or rewriting the function that converts it all over the place (see the JS code for examples) is annoying enough that I'd prefer to avoid it. It's just a little bit less common and we're not actively using the condition in any URLs at the moment. A different protocol that has support for features like the one you describe could choose an entirely different encoding format or strategy, so I don't think this protocol needs to be designed with that in mind.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An advantage of hex is that it's more human-readable when comparing raw buffers in debug output:

> Buffer.from('0a101033', 'hex')
<Buffer 0a 10 10 33>
> Buffer.from('0a101033', 'base64')
<Buffer d1 ad 74 d7 4d f7>

Another advantage of hex would be that it would be less confusing to change to hex (obviously different from base64url) than to change from base64url to base64 (more subtle change, easier to confuse).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to all comments above from @emschwartz, @michielbdejong, and @adrianhopebailie .

I think we have consensus that we should not use Base64Url, and from my perspective I lean slightly towards HEX, but would be fine supporting Base64.

With that in mind, I propose that we use HEX (and if there's even one dissenter saying that we should use Base64, then let's just use that).

Any dissenters?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I would lean towards normal base64. Since this is specifically for encoding a hash or random 32-byte value, you don't need to do byte comparisons. I would agree with @michielbdejong's point if we were talking about a data field, but the hashes will always be completely different. Base64 saves 20 characters, and while this isn't really optimizing for bytes on the wire, I think we might as well save those characters because we're communicating the same information anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No objections from me.

Copy link

@sharafian sharafian Dec 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one thing we should specify for base64 is whether padding is optional or not. Many implementations of base64 (not node.js's version, but the openssl base64 command, for instance) won't accept it if it doesn't include the =s for padding.

ILP-Expiry: 2017-12-07T18:47:59.015Z
ILP-Amount: 1000

<body>
```

| Field | Type | Modified at Each Hop? | Description |
|---|---|---|---|
| `ILP-Destination` | [ILP Address](./0015-ilp-addresses/0015-ilp-addresses.md) | N | Destination address of the payment |
| `ILP-Condition` | Base64-Encoded String (With Padding), 32 Bytes | N | Execution condition of the payment, which is the Sha256 hash digest of the condition fulfillment |
| `ILP-Expiry` | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) Timestamp in UTC | Y | Expiry of the transfer |
| `ILP-Amount` | Unsigned 64-Bit Integer | Y | Transfer amount, denominated in the minimum divisible units of the ledger. Note that this is the local transfer amount, **not** the destination amount as in the original [ILP Payment Packet Format](https://github.com/interledger/rfcs/blob/master/0003-interledger-protocol/0003-interledger-protocol.md#ilp-payment-packet-format) |
| `<body>` | Binary, Maximum of 32767 Bytes | N | End-to-end data used by Transport Layer protocols |

### Response

#### Success

```http
HTTP/1.1 200 OK
ILP-Fulfillment: cz/9RGv1PVjhKIOoyPvWkAs8KrBpIJh8UrYsQ8j34CQ=
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, cz_9RGv1PVjhKIOoyPvWkAs8KrBpIJh8UrYsQ8j34CQ?


<body>
```

| Field | Type | Modified at Each Hop? | Description |
|---|---|---|---|
| `ILP-Fulfillment` | Base64-Encoded String (With Padding), 32 Bytes | N | Preimage of the `ILP-Condition` |
| `<body>` | Binary, Maximum of 32767 Bytes | N | End-to-end data used by Transport Layer protocols |

#### Error

HTTP Error Codes MAY be used to indicate certain types of failures, but [ILP Error Codes](./0003-interledger-protocol/0003-interledger-protocol.md#ilp-error-codes) MUST be used and relayed by connectors.

```http
HTTP/1.1 404 Not Found
ILP-Error-Code: F02
ILP-Error-Name: Unreachable
ILP-Error-Triggered-By: g.usd.acmebank.user12345.xclkv-909sdf
ILP-Error-Triggered-At: 2017-12-07T19:11:21.917Z
ILP-Error-Forwarded-By: g.usd.acmebank.connector,g.crypto.bitcoin.1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa

<body>
```

| Field | Type | Modified at Each Hop? | Description |
|---|---|---|---|
| `ILP-Error-Code` | [ILP Error Code](./0003-interledger-protocol/0003-interledger-protocol.md#ilp-error-codes) | N | 3-letter code identifying the error |
| `ILP-Error-Name` | String | N | Human-readable name corresponding to the `ILP-Error-Code` |
| `ILP-Error-Triggered-By` | ILP Address | N | Address of the party that initially emitted the error |
| `ILP-Error-Triggered-At` | ISO 8601 Timestamp in UTC | N | Time when the error was initially emitted |
| `ILP-Error-Forwarded-By` | Comma-Separated List of ILP Addresses | Y | List of connectors that relayed this error. Connectors SHOULD append their ILP addresses to the end of this list when relaying the error |
| `<body>` | Binary, Maximum of 32767 Bytes | N | End-to-end data used by Transport Layer Protocols |