Skip to content

Network

Timur Ramazanov edited this page Aug 14, 2019 · 9 revisions

Communication Protocol

All nodes communicate over TCP. Messages are encoded with XDR(RFC 4506). XDR uses the similar approach to Protocol Buffers or Thrift. All data declarations can be found in the reference stellar-core repo.

Peer Discovery

When started for the first time, programs don't know the IP addresses of any active nodes. Initial trusted nodes(maintained by stellar.org) should be added at first startup. Once a program has connected to the other nodes, its can begin to request GET_PEERS messages and receive in response PEERS message with the IP addresses and port numbers of other peers on the network, providing a fully decentralized method of peer discovery.

Node Identity

Each node must maintain a secret seed, public and private keys, derived from the seed, and the hashed network passphrase, which determines, in what network node operates.

Official Stellar networks passphrases are:

  1. Test SDF Network ; September 2015 – the testnet
  2. Public Global Stellar Network ; September 2015 – the public network

Use any other string as the network passphrase to build private network.

Sha256 of network passphrase is called "network id".

All cryptographic operations are based on the Ed25519 (for signatures) and Curve25519 (for keypair generation).

Messages

Stellar-core node supports the next messages:

union StellarMessage switch (MessageType type)
{
case ERROR_MSG:
    Error error;
case HELLO: // initiate handshake. Precedes `AUTH` message
    Hello hello;
case AUTH: //  authenticate the node. Used in the handshake, follows `HELLO` message
    Auth auth;
case DONT_HAVE:
    DontHave dontHave;
case GET_PEERS: // get a list of peers this node knows about
    void;
case PEERS:
    PeerAddress peers<100>;

case GET_TX_SET: // get a particular `txset` by its hash
    uint256 txSetHash;
case TX_SET:
    TransactionSet txSet;

case TRANSACTION: // pass on a tx you have heard about
    TransactionEnvelope transaction;

// SCP
case GET_SCP_QUORUMSET:
    uint256 qSetHash;
case SCP_QUORUMSET:
    SCPQuorumSet qSet;
case SCP_MESSAGE:
    SCPEnvelope envelope;
case GET_SCP_STATE:
    uint32 getSCPLedgerSeq; // ledger seq requested ; if 0, requests the latest
};

The StellarMessage union contains 3 logically distinct kinds of message:

  • Messages directed to or from a specific peer, with or without a response: HELLO, GET_PEERS, PEERS, DONT_HAVE, ERROR_MSG
  • One-way broadcast messages informing other peers of an event: TRANSACTION and SCP_MESSAGE
  • Two-way anycast messages requesting a value (by hash) or providing it: GET_TX_SET, TX_SET, GET_SCP_QUORUMSET, SCP_QUORUMSET, GET_SCP_STATE

Every message, except for HELLO and ERROR, goes with HMAC and the sequence number. All these pieces form AuthenticatedMessage structure:

union AuthenticatedMessage switch (uint32 v)
{
  case 0:
    struct
    {
      uint64 sequence; // incremental counter of all messages node sent
      StellarMessage message; // one of the messages listed above
      HmacSha256Mac mac; // calculated on the handshake
    } v0;
};

Frames

Messages are minimally framed using the Record Marking (RM) standard of RFC 5531 and the RM-framed messages are transmitted over TCP/IP sockets, between peers.

| 4 bytes header | XDR message |

Handshake

For every new connection, we need to build an AuthCert and HELLO XDR structs. (link).

Connection process:

  1. A wants to connect to B
  2. A starts a TCP connection to B
  3. connection is established
  4. A builds HELLO message and sends it to B
  5. B now has IP and port of A, B builds HELLO message and sends it back to A
  6. A builds MAC key
    1. get a shared secret, using Elliptic-Curve Diffie-Hellman (ECDH) key agreement on A and B public keys
    2. feed this shared secret as a salt, and use concatenation of 0, A nonce and B nonce as an input to HKDF (use Sha256 for hashing)
    3. extract MAC key from the HKDF
  7. A builds AUTH message, which is an empty message with the MAC, and sends it to B
  8. B verifies AUTH message from A
  9. B builds MAC key its AUTH message and sends it back to A
    1. get a shared secret, using Elliptic-Curve Diffie-Hellman (ECDH) key agreement on A and B public keys
    2. feed this shared secret as a salt, and use concatenation of 1, B nonce and A nonce as an input to HKDF (use Sha256 for hashing)
    3. extract MAC key from the HKDF
  10. B builds AUTH message, which is an empty message with the MAC, and sends it back to A
  11. A verifies the AUTH message from B

If any verification step fails, the peer disconnects immediately.

AuthCert XDR struct

HELLO message contains AuthCert struct:

struct AuthCert
{
    Curve25519Public pubkey; // the node's public key
    uint64 expiration; // unix time
    Signature sig;
};

sig is built this way:

  • concatenate network id, ENVELOPE_TYPE_AUTH XDR constant, expiration and pubkey to form a binary buffer
  • hash this buffer with sha256
  • sign this hash with node's private key
  • wrap the signature with Signature XDR data type

Hello XDR struct

struct Hello
{
    uint32 ledgerVersion; //current ledger protocol version. Used for know how upgrade frames to latest versions from legacy nodes. Related to stellar-core version.
    uint32 overlayVersion; // max overlay version supported by the node
    uint32 overlayMinVersion; // min overlay version understood by the node
    Hash networkID; // sha256(network passphrase)
    string versionStr<100>; // node version as a string (for information only)
    int listeningPort; // the port node is listening to
    NodeID peerID; // the node's public key
    AuthCert cert; // see paragraph above for details
    uint256 nonce; // some random number
};

Broadcast

Local node keeps track of which peers have sent us which broadcast messages, in order to ensure that for each broadcast message M and for each peer P, we either send M to P once (and only once), or receive M from P (thereby inhibit sending M to P at all).

The broadcast message types are TRANSACTION and SCP_MESSAGE.

All messages are marked with the ledger sequence number to which they relate, and all broadcast-management information for a given ledger number is purged when the ledger closes.

Clone this wiki locally