Skip to content

Commit

Permalink
BTP/2.0 (#383)
Browse files Browse the repository at this point in the history
* docs: BTP/2.0

* address review comments from @justmoon

* Comments from @adrianhopebailie
  • Loading branch information
michielbdejong committed Mar 7, 2018
1 parent df3e413 commit af1acf2
Showing 1 changed file with 31 additions and 190 deletions.
221 changes: 31 additions & 190 deletions 0023-bilateral-transfer-protocol/0023-bilateral-transfer-protocol.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,28 @@
---
title: Bilateral Transfer Protocol (BTP)
draft: 5
title: Bilateral Transfer Protocol 2.0 (BTP/2.0)
draft: 6
---
# Bilateral Transfer Protocol (BTP)
# Bilateral Transfer Protocol 2.0 (BTP/2.0)

## Preface

This document describes the Bilateral Transfer Protocol (BTP), a ledger
protocol for bilateral transfers of value. It the successor to [Plugin
RPC](https://github.com/interledger/rfcs/blob/master/0021-plugin-rpc-api/0021-plugin-rpc-api.md#plugin-rpc-api),
and has been written to use OER instead of JSON.
This document describes version 2.0 of the Bilateral Transfer Protocol (BTP), a request/response
protocol for bilateral WebSocket links between Interledger connectors.

## Introduction

### Motivation

There are many different types of ledgers, and Interledger aims to interoperate
all of them. For fast ledgers that support hash time locks, memos, and
messaging, it is enough to wrap the ledger's API in a [Ledger
Plugin](https://github.com/interledger/rfcs/blob/master/0004-ledger-plugin-interface/0004-ledger-plugin-interface.md).
These allow you to send interledger payments through anyone else on that ledger
who is running your plugin.
When two Interledger connectors send ILPv4 packets over HTTP POST,
they each need to act as an HTTP server at times. If one of the connectors runs behind a firewall,
this may be impossible. Therefore, BTP uses WebSockets instead of HTTP. With
WebSockets, only one of the connectors needs to be publicly addressable.

In lots of scenarios, we don't have an underlying ledger that's fast enough to
do every ILP payment on-ledger. If two parties want to transact, they can send
transfers directly to one another with BTP. BTP requires that the two parties
trust one another (up to a limit) for funds that have not yet been settled on
the underlying ledger. If their trust limit is high enough, the two parties can
transact without settling on an underlying ledger at all.

Because we believe the use case for a bilateral ledger protocols is so
ubiquitous, the BTP has been designed to be efficient to transmit and friendly
to re-implement.
However, WebSockets don't provide a mechanism for relating responses to requests. BTP adds this missing
request/response layer, between WebSockets and the request/response pairs exchanged by the connectors.

### Scope

BTP manages conditional and unconditional transfers, messaging requests,
result/error reporting, and carries sub-protocols (sometimes called
side-protocols) for extensibility. You can use ILP without using BTP. BTP is
not a ledger in itself, but it is a ledger-layer protocol in the [ILP
architecture](https://github.com/interledger/rfcs/blob/master/0001-interledger-architecture/0001-interledger-architecture.md)
because it handles local transfers of money and data.

BTP is intended to be a well-suited solution so that a new bilateral ledger
protocol doesn't need to exist for every new use case. It also includes
functionality which is common between many different ledger types, making it a
good place to start from when creating a new bilateral protocol for transfering
value.

This document describes the flow and data format that BTP uses, but not
sub-protocols. Sub-protocols include optional functionality like ledger
metadata, balance, automated settlement, and dispute resolution. Some protocols
Expand Down Expand Up @@ -90,17 +65,11 @@ causes the peers to disagree about expiries. If one party keeps authoritative
state, the other party must trust them not to tamper with it.

- A request is **In-Flight** if the request has been sent out, but no response
has been sent yet. A transfer is **In-Flight** if it has been prepared but
not yet fulfilled nor rejected.

- An **Underlying Ledger** moves value between the two peers when they settle
their balance. If Peer 1 owes Peer 2 100 XRP, Peer 1 could send Peer 2 100
XRP on Ripple in order to make their balance 0. In that scenario, XRP ledger is
the underlying ledger.
has been received yet.

## Overview

BTP is broken up into 4 different RPC requests, which can get 2 different
BTP is broken up into one different RPC requests, which can get two different
responses. Every BTP packet follows a common structure:

```
Expand Down Expand Up @@ -159,9 +128,9 @@ sub-protocols carried by this packet.
|:--|:--|:--|
| 1 | `Response` | Response |
| 2 | `Error` | Response |
| 3 | `Prepare` | Request |
| 4 | `Fulfill` | Request |
| 5 | `Reject` | Request |
| 3 | (not used) | |
| 4 | (not used) | |
| 5 | (not used) | |
| 6 | `Message` | Request |
| 7 | `Transfer` | Request |

Expand All @@ -187,6 +156,7 @@ Before anything else, when a client connects to a server, it sends a special
`Message` request. Its primary `protocolData` entry MUST have name `'auth'`,
content type `MIME_APPLICATION_OCTET_STREAM`,
and empty data, and among the secondary entries, there MUST be a UTF-8
<<<<<<< HEAD
`'auth_token'` entry, and there MAY be a UTF-8 `'auth_username'` entry. The further secondary
protocol data entries of this `Message` request MAY also be used to send
additional information to the server. In situations where no authentication
Expand All @@ -195,6 +165,13 @@ empty string, but it cannot be omitted. In situations where the `'auth_token'`
acts as a bearer token, and the value of `'auth_username'` can be derived from
the value of `'auth_token'` deterministically, the `'auth_username'` entry can either
be omitted, or set to the empty string.
=======
`'auth_token'` entry. The further secondary
protocol data entries of this `Message` request MAY also be used to send
additional information to the server. In situations where no authentication
is needed, the `'auth_token'` data can be set to the
empty string, but it cannot be omitted.
>>>>>>> 35e6dd7... docs: BTP/2.0
If the client sends any BTP call that is not a Message, or sends a Message call
whose primary sub-protocol is not `auth`, the server should respond with an `Error`
Expand Down Expand Up @@ -232,13 +209,13 @@ For example, the primary sub-protocol entry of a Message might represent a quote

Likewise, only the primary sub-protocol data in a Response indicates whether result of the request from the Message being responded to actually succeeded or not.

In Error, Prepare, Fulfill, and Reject calls, the distinction between primary and secondary sub-protocol entries is less strict.
In Error calls, the distinction between primary and secondary sub-protocol entries is less strict.

## Flow

BTP uses a simple RPC flow. A request-type BTP packet is sent, and a
response-type BTP packet is sent in response with the same request ID. The
request types are `Message`, `Prepare`, `Fulfill` and `Reject`, and the
request types are `Message` and `Transfer`, and the
response types are `Response` and [`Error`](#error).

Because it would be too slow to atomically save all requestIds that are
Expand Down Expand Up @@ -270,7 +247,7 @@ Message ::= SEQUENCE {
```

`Message` is used for sending information to the peer. It contains no
packet-specific data, only protocol data. [ILQP](https://github.com/interledger/rfcs/blob/master/0008-interledger-quoting-protocol/0008-interledger-quoting-protocol.md) packets are attached under the
packet-specific data, only protocol data. [ILP](https://github.com/interledger/rfcs/blob/master/0003-interledger-protocol/0003-interledger-protocol.md#ilp-payment-packet-format) packets are attached under the
protocol name `ilp` with content-type `application/octet-stream`.

- `Response` is returned if the peer acknowledges the `Message`. If the peer
Expand All @@ -282,140 +259,6 @@ protocol data.
not include ILP errors such as "No quote found", only the cases in which the
`Message` cannot be sent/processed at all.

### Prepare

```asn1
Prepare ::= SEQUENCE {
transferId UInt128,
amount UInt64,
executionCondition UInt256,
expiresAt GeneralizedTime,
--
protocolData ProtocolData
}
```

`Prepare` is used to create a transfer on the bilateral ledger. The packet
data contains `transferId`, `amount`, `executionCondition`, and `expiresAt`.
`Prepare` is a request with side effects, because it creates a transfer with
the given details. This transfer begins in the `prepared` state.

`transferId` is a securely random 128-bit unique ID that references the
transfer. `amount` is a 64-bit integer denominated in ledger base units. The
ledger base units can be anything, so long as both parties on the bilateral
ledger agree on their meaning. Examples of base units are "micro-XRP,"
"satoshi," or "nano-dollars settled over paypal." `executionCondition` is a
256-bit integer containing the SHA-256 hash of this conditional transfer's
fulfillment. `expiresAt` is a ASN.1 UTC GeneralizedTime containing the expiry
of this transfer. The GeneralizedTime MUST be in UTC (i.e. no timezone info).

ILP payment packets are attached to the protocol data under the protocol
name `ilp` and the MIME type `application/octet-stream`.

- `Response` is returned if the peer acknowledges the `Prepare`. This means the
transfer is now `prepared` and has been applied to the balance. It may carry
sub-protocol data, for example a payment channel claim.

- `Error` is returned if the peer does not accept the transfer. This could be
because it is incompatible with an existing transfer with the same ID (see
Idempotency below), or because it exceeds some constraint your peer has placed.
The amount could be too high, or could exceeds the balance. If the transfer ever enters the `prepared` state, an `Error` should not be returned. Instead, a `Reject` call should be made.

#### Idempotency

If a transfer with the given ID already exists in any state, a new transfer
should not be created. If the packet (including protocol data) matches an
existing transfer exactly and that transfer is in the `prepared` state, a
`Response` should be returned. If the packet (including protocol data) shares
the ID of an existing transfer but other details do not match, an `Error`
should be returned. If the packet (including protocol data) exactly
matches an existing transfer but that transfer is in the `fulfilled` state or
the `rejected` state, an `Error` should be returned.

#### Expiry

After the `expiresAt` date is reached, the transfer can no longer be fulfilled.
If one party on the BTP connection is keeping authoritative state, they MUST
send a `Reject` request to the other party. If both parties are keeping
authoritative state, they MAY independently expire the transfer (set the state
to `rejected` and roll it back) automatically.

### Fulfill

```asn1
Fulfill ::= SEQUENCE {
transferId UInt128,
fulfillment UInt256,
--
protocolData ProtocolData
}
```

`Fulfill` is used to change an existing transfer from the `prepared` state to
the `fulfilled` state. The packet-specific data of `Fulfill` is made up of `transferId`
and `fulfillment`. `Fulfill` is a request with side effects: it changes the
state of the transfer and finalizes the transfer's balance update. If the
transfer is already fulfilled, no changes are applied.

`transferId` is a 128-bit unique ID, which references an existing transfer.
`fulfillment` is a 256-bit integer, containing the preimage of the
`executionCondition` of the referenced transfer.

A `Fulfill` request must be sent from the receiver of the referenced transfer,
not the sender.

A `Fulfill` request is successful if `transferId` references an existing
transfer in the `prepared` state, the `fulfillment` is the SHA-256 preimage of
the referenced transfer's `executionCondition`, and the current time (when the
request is being processed) is before the referenced transfer's `expiresAt`.

A `Fulfill` request is also successful if the transfer is in the `fulfilled`
state, and this packet matches the one that fulfilled the transfer,
including protocols but not including requestId.

- `Response` is returned if the request is successful. This means the
transfer's state is now `fulfilled`, and its balance change has been
finalized.

- `Error` is returned if there is no transfer with the given ID, the
fulfillment does not match the condition, the expiresAt has already passed,
or the transfer has been `rejected`.

### Reject

```
Reject ::= SEQUENCE {
transferId UInt128,
--
protocolData ProtocolData
}
```

`Reject` is used to change an existing transfer from the `prepared`
state to the `rejected` state. The packet-specific data of `Reject` is made up
only of `transferId`.

`transferId` is a 128-bit unique ID, which references an existing transfer.
The reason that the transfer was rejected should go in the protocol data. For
example, if this is an ILP Payment being rejected, the `ilp` protocol will
contain an [ILP
Error](https://github.com/interledger/rfcs/blob/master/0003-interledger-protocol/0003-interledger-protocol.md#ilp-error-format).

A `Reject` request must come from the receiver of the referenced transfer,
not the sender.

A `Reject` request is successful if `transferId` references an existing
transfer in the `prepared` state.

A `Reject` request is also successful if `transferId` references an existing
transfer in the `rejected` state, and this packet matches the one that
rejected this transfer, including protocols but not including requestId.

- A `Response` is returned if the request is successful. This indicates that
the balance changes of the referenced transfer have been rolled back.

- An `Error` is returned if the request was not successful.

### Error

```
Expand Down Expand Up @@ -468,12 +311,10 @@ Transfer ::= SEQUENCE {
}
```

`Transfer` is used to send money unconditionally on the bilateral ledger.
Unlike a `Prepare`, `Transfer` is assumed to move funds immediately, without
requiring a subsequent `Fulfill` call.

Data to secure this payment (such as payment channel claims), can be attached
under the protocol data.
`Transfer` is used to send proof of payment, payment channel claims, or other
settlement information to the other connector.
The amount should indicate the additional value of this settlement state (compared to the
previous settlement state), in a unit that was agreed out-of-band.

- `Response` is returned if the peer acknowledges the `Transfer`. This means
the transfer is now completed and has been applied to the balance. If a
Expand Down

0 comments on commit af1acf2

Please sign in to comment.