2️⃣-Peer Protocol
The current protocol requires a direct connection between two nodes for performing updates, trades, and swaps. This section describes how the connection is set up.
Each node maintains a persistent secp256k1 private key with a corresponding public key, node key for short, which uniquely identifies the node in the network. We recommend only allowing manual resets of the private key, for example by deleting a file or database entry.
An initial handshake is required to establish a secure TCP-based session between two nodes. The default listening TCP port is 8885.
The communication session is established by creating a TCP connection and agreeing on ephemeral key material for further encrypted communication, in addition to utilizing the persistent key for authentication. The process of establishing this session is the “handshake” and is carried out between the “initiator” (the peer that opened the TCP connection) and the “recipient” (the peer that accepted it).
The handshake consists of each side sending the
SessionInit
message, and waiting to receive the SessionAck
message back. The first SessionInit
message is expected to be sent by the initiator.The initiator must know the recipient's identity (node key) in advance. The recipient learns the initiator's identity by receiving the
SessionInit
message.By the end of the handshake, two distinct shared keys are created, one for each side of the communication, to be used to encrypt all messages during the session's lifetime.
These messages are used in the initial handshake:
`string id = 1`
The message's globally unique identifier, generated by the sender
`string sign = 2`
secp256k1 signature over sha256 hash of a JSON-serialized msg containing fields 3-7
`string peer_pub_key = 3`
The target node secp256k1 public key (in hex)
`string ephemeral_pub_key = 4`
An ephemeral secp256k1 public key (in hex), generated by the sender, for ECDH key exchange
`NodeState node_state = 5`
General info regarding the sender's current node state
`string version = 6`
OpenDEX client version
`string node_pub_key = 7`
The sender's secp256k1 public key (in hex)
Once received by the destination node, the message is authenticated as follows:
peer_pub_key
should match the destination node's public keynode_pub_key
should match the sender node expected public key (relevant for the initiator node only since he already knows the recipient node's identity)sign
should be a valid secp256k1 signature over the sha256 hash of a JSON-serialized msg containing fields 3-7
If the fields of the
SessionInit
message are valid, the receiver replies with a SessionAck
message. If a SessionAck
message is not received within a reasonable time frame (10 seconds is recommended), the sender may disconnect.`string id = 1`
The message's globally unique identifier, generated by the sender
`string req_id = 2`
The id of the received SessionInit message
`string ephemeral_pub_key = 3`
An ephemeral secp256k1 public key (in hex), generated by the sender, for ECDH key exchange
Once the receiver of the
SessionInit
message (Bob) has generated his ECDH keys, he can calculate the shared key by using the ephemeral_pub_key
from the SessionInit
message. Once the SessionAck
message is received by the sender of the SessionInit
message (Alice), she can compute the shared key as well. All future communication from Alice to Bob must be encrypted with aes-256-cbc symmetric encryption using the shared key.These messages are used to maintain the P2P overlay after a session has been established via the initial handshake.
`string id = 1`
The message's globally unique identifier, generated by the sender
In order to allow long-lived TCP connections, both ends keep the TCP connection alive at the application level using
Ping
and Pong
messages.It is recommended to send a
Ping
message every 30 seconds.The sender of a
Ping
message may disconnect if a Pong
message is not received within 10 seconds.`string id = 1`
The message's globally unique identifier, generated by the sender
`string req_id = 2`
The id of the received Ping message
The
Pong
message is sent in response to the Ping
message. It serves to keep the connection alive by explicitly notifying the other end that the receiver is still active.`string id = 1`
The message's unique identifier, generated by the sender
`uint32 reason = 2`
The reason for the imminent disconnection
`string payload = 3`
Optional payload to specify the disconnection reason
The
Disconnecting
message is used to inform a connected peer that a disconnection is imminent and that the peer should disconnect immediately. A well-behaved host that sends a Disconnecting
message allows the peer at least 2 seconds to disconnect before disconnecting itself.reason
is an optional parameter for specifying one of the following reasons for the disconnection:Reason | Meaning |
---|---|
0x01 | Response stalling |
0x02 | Incompatible client protocol version |
0x03 | Unexpected identity |
0x04 | Forbidden identity update |
0x05 | Connected to self |
0x06 | Not accepting new connections |
0x07 | Banned |
0x08 | Already connected |
0x09 | Shutdown |
0x0a | Malformed version |
0x0b | Authentication failure: invalid target node |
0x0c | Authentication failure: invalid signature |
0x0d | Wire protocol error |
`string id = 1`
Message's globally unique identifier, generated by the sender
The
GetNodes
message is used to query a peer for its list of known, reachable OpenDEX nodes.`string id = 1`
Message's globally unique identifier, generated by the sender
`string req_id = 2`
Link to the id field from the received GetNodes message
`repeated Node nodes = 2`
The list of known nodes
The
Nodes
message is used to respond to the GetNodes
message.`string id = 1`
Message's globally unique identifier, generated by the sender
`NodeState node_state = 2`
The updated node state.
The
NodeStateUpdate
message is used to tell a peer about a change in the node state. An example of an update is the removal or addition of a supported trading pair.`repeated Address addresses = 1`
The sender's listening TCP addresses
`repeated string pairs = 2`
The sender's list of trading pair symbols, constructed with the base currency first, followed by a '/' separator and the quote currency (e.g., [“LTC/BTC”, “DAI/BTC”])
`string connext_identifier = 3`
The sender's Connext identifier (e.g. `indra123abc`)
`map<string, string> lnd_pub_keys = 4`
The sender's list of LND public keys
`map<string, string> token_identifiers = 5`
Mapping between currency symbols and chain identifiers or ETH-ERC20 token contract addresses (e.g., { BTC: 'bitcoin-mainnet', LTC: 'litecoin-mainnet', ETH:,'0x0000000000000000000000000000000000000000' })
`map<string, LndUris> lnd_uris = 6`
Mapping between currency symbols to LND listening URIs (should be reachable from the internet e.g., { BTC: ['2w526cyown43ovsvsojdowheqmukbykrexzyccp6v6j4pm5ve3hjzrid.onion:9735'], LTC: '['lndltc.kilrau.com:9735', 'qiyibtczmuhutusmygvc2injxl7v4yfcodwj3pft63edycud5gr3giad.onion:10735']' })
`string host = 1`
`uint32 port = 2`
`repeated string lnd_uri = 1`
`string node_pub_key = 1`
The node's public key upon which its identity should be verified
`repeated Address addresses = 2`
The node's listening TCP addresses
Last modified 1yr ago