Core

Ripple Core Protocol

Core Work Page

The following is common to all Ripple subprotocols.

Messaging

The Ripple network consists of software agents called nodes connected together pairwise where one or both accept the other's obligations as valuable. These abstract connections are manifested over messaging connections between hosts, each of which may host multiple nodes.

Messaging Semantics

A message transport layer must distinguish between three message types: message, reply, and error. Each Ripple message has a unique ID within the host-level connection, and must be immediately responded to by either a reply or an error with the same ID upon receipt. This serves to establish that the message was received and was either understood (reply), or deemed somehow malformed or otherwise inappropriate as detailed by an error code and message (error). The ID may consist of one or more fields.

Replies and errors may carry any data that a regular message may carry. In addition, error messages must carry an error code.

In general, nodes need not wait for the reply or error to send another message.

Message Syntax

Ripple messages carried within the transport layer are in JSON textual format. For example:

{
    "type": "account-request",
    "from": "rfugger@ripplepay.com",
    "to": "otheruser@otherhost.com:2338",
    ("request-id": (integer),)
    ("time": "2007-03-30 14:10:03.112000",)
    ("body": (message body goes here))
}

The indentation and line breaks are for readability in this document only. The actual messages themselves do not have significant whitespace other than described in the JSON specification.

The from and to fields contain node names on the sending and receiving host, respectively. For host-to-host messages, these fields contain hostnames (with optional ports), without node IDs. This allows hosts to know each other's hostnames, and also provides, for signed messages, a record of sender and recipient.

The request-id field is used to pair up requests and replies. Request IDs must be unique among open requests between two hosts. The time field contains the UTC time according to the sending host's clock. It is only used in certain subprotocols, particularly Payments and Accounts. The body field is not used for every message type.

Host Messages

Certain messages are sent to a host, rather than to an individual node on a host.

Keeping Time

The timestamp put on a Ripple message by the sending host is interpreted by the receiving host as the time the corresponding event occurred, so it is important that:

  • the two hosts' clocks are reasonably in sync
  • the network latency is reasonable

To allow two hosts to verify these two conditions at the beginning of a connection, and at any other time there is uncertainty (such as a long delay between timestamped messages), they may use a time message:

{
    "type": "time",
    (request-id: 24223,)
    "time": "2007-03-30 14:10:03.112000"
}

request-id is only used if the message is in reply to a time-request. An affirmative reply to this message indicates the receiving host's approval of the sending host's local clock and network latency of the connection. An error reply containing a time-request message indicates that the another time message should be sent. After three consecutive time errors, the connection should be closed after all open transactions are completed.

To request a time message from another host, for example, when timestamped non-time messages are arriving at off-times, send a time-request:

{
    "type": "time-request",
    "request-id": (4485093)
}

The host receiving a time-request must give an affirmative reply followed immediately by a time message with the same request-id as the request. This may trigger a time error and subsequent time messages and possibly a closed connection.

Ping may also be used to detect network latency. Ripple hosts should accept pings.

This section presumes both hosts are making every effort to be honest about their timekeeping. Cheating is addressed elsewhere. Timekeeping issues such as clock differences between hosts, network latency, and cheating may be addressed in the future by allowing hosts to negotiate a third-party timestamping authority as an intermediary for their Ripple messaging.

Host Status

At any time they are connected, a host may request another for the status of its protocol support by sending a host-status-request message with no body:

{
    "type": "host-status-request"
}

The host receiving such a message must reply immediately with a host-status message containing a list of protocol versions and subprotocols of each that it understands.

{
    "type": "host-status",
    "body": [
        {
            "version": "1",
            "subprotocols": [
                "ripple-payment",
                "ripple-routing",
                "ripple-channel",
                "ripple-account",
            ]
        }
    ]
}

Transport

Host Connections

Ripple hosts connect to each other by TCP. (Need to specify a standard port for hosts to listen on.) TCP connections are meant to be persistent, but may be closed by either host at any time.

Hosts may open multiple connections with each other.

Connection Security

After time and possibly host-status messages have been exchanged, the initiating host starts TLS on the connection.

Node Identification

Nodes are identified in standard node@host.com email-address style. For nonstandard ports, use node@host.com:xxxx, where xxxx is the port the host is listening on for Ripple connections.

Host Messages

Host messages are sent in BEEP-style frames as follows:

(type) (version) (msgno) (more) (size)(CRLF)
(content)
END(CRLF)

where

(type)    = MSG | RPY | ERR
(version) = (string)
(msgno)   = 0..2147483647
(more)    = . | *
(size)    = (integer)

Message types MSG, RPY, and ERR correspond to the Ripple message types message, reply, and error.

The version indicates the Ripple protocol version.

The msgno must be unique among MSG-type messages in the connection that have not yet received a complete response. For RPY and ERR types, msgno must be identical to the original MSG. The host that initiated the connection must use only even-numbered msgnos and the host that received the connection must use only odd-numbered msgnos.

If more is "*", it signifies there are more frames in the message; if it is ".", this is the final frame. This allows a host to chunk messages into discrete bits in order to interleave messages on the same connection. If the connection is dropped before the final frame is received and acknowledged, the message must be disregarded.

size is the number of content bytes between, but not including, the CRLF at the end of the header line, and the END at the end of the frame.

Channels from the BEEP specification are omitted because Ripple interleaving message frames seems to accomplish much the same thing. The seqno field from BEEP is omitted here because TCP already does its own byte-counting at a lower level.

Errors

If a received frame is not in the correct format, the association must be immediately closed.

Core Work Page