The snarkOS network protocol establishes a peer-to-peer network of nodes that maintains ledger liveness by actively exchanging transactions and blocks.
snarkOS uses TCP connections to facilitate data transfers over the network. Networking on snarkOS is built with asynchronous calls in Rust and tokio.rs. Tokio tasks are spawned to handle new connections and send messages to the main event loop.
snarkOS downloads, verifies, and stores the history of valid blocks and transactions prior to becoming an active node on the network.
When a node joins the network for the first time, it needs to populate a list of active peers in the network. In order to bootstrap peer discovery, snarkOS includes a set of optional bootnodes which provides an initial set of peers. To allow users flexibility, snarkOS provides allows users to configure the initial set of nodes in the configuration file, or as a input via a command-line flag.
Once a node is connected to one or more nodes, it may scan the network to discover more peers.
This processes starts by asking peers for more connected nodes in the network with a GetPeers
message,
followed by attempts to establish a connection with each newly discovered peer.
Upon success, snarkOS will store the new peer address to allow it to connect directly with this peer in the future, without needing to use bootnodes to startup in the future.
Bootnodes operate like other full nodes and serve as a public access point for all peers in the network. Bootnodes are run by community members and bolster the network by enabling new nodes to connect and participate in the network effortlessly.
Peer connections are established with an XX noise handshake.
Peer connections are maintained with a ping-pong protocol that periodically relays Ping
/ Pong
messages to
verify that peers are still connected. snarkOS will update its peer book to account for newly-connected peers,
and disconnected peers.
Before a node can participate in the network, it must sync itself to the latest state of the ledger. Whether a node is newly connecting to the network or simply has stale state, it must sync with its peers, and download its missing blocks and transactions.
snarkOS uses a "Header-First" approach to syncing blocks, where a node downloads and validates each block header before downloading the corresponding full block, in parallel.
When a node determines it needs to download state, it selects a peer as the sync-node and sends it a GetSync
message.
The GetSync
message contains information about the current block state of the node,
so the sync-node is able to determine which block headers are necessary to send as a response.
Upon receiving a GetSync
message, the sync-node sends back at most 100 block headers via a Sync
message.
The requester then validates these headers and downloads the blocks in parallel by sending out GetBlock
messages.
After these blocks have been downloaded, the requester sends another GetSync
message,
and repeats this process until its chain state is fully up to date.
Here is a basic iteration of the sync protocol:
Message | Sender | Receiver | Data |
---|---|---|---|
GetSync |
Node | Sync Node | 1 or more block hashes |
Sync |
Sync Node | Node | Up to 100 new block headers |
GetBlocks |
Node | Any Peer | Block headers of the requested blocks |
Block |
Any Peer | Node | A serialized block |
A node may broadcast a transaction to the network by sending a Transaction
message to its connected peers.
The peers receiving this transaction verify the transaction
and further propagate the transaction by broadcasting it to its connected peers.
This transaction continues through the network until it is propagated to every connected peer in the network.
A node may broadcast a block using a Block
message, in the same manner as broadcasting a transaction.
Send a block to a peer.
block
The serialized bytes of the block.
A request for blocks with the specified hashes.
getblocks
Parameter | Type | Description |
---|---|---|
block_hashes |
array | A list of hashes of blocks to request |
A request for a peer's memory pool transactions.
getmemorypool
None
A request for a list of the peer's connected peer addresses.
getpeers
None
A request for knowledge of specified block locator hashes.
getsync
Parameter | Type | Description |
---|---|---|
block_locator_hashes |
array | A list of block hashes describing the state of the requester's chain |
A response to a GetMemoryPool
request.
memorypool
Parameter | Type | Description |
---|---|---|
transactions |
array | A list of serialized memory pool transactions |
A response to a GetPeers
request.
peers
Parameter | Type | Description |
---|---|---|
addresses |
array | A list of listening addresses of connected peers |
A message used to check if a peer is active and calculate their RTT.
ping
Parameter | Type | Description |
---|---|---|
block_height |
number | The current height of the chain |
A response to a Ping
request.
pong
None
A response to a GetSync
message.
sync
Parameter | Type | Description |
---|---|---|
block_hashes |
array | A list of block hashes to share with the requester |
A response to a GetBlock
request.
syncblock
Parameter | Type | Description |
---|---|---|
data |
bytes | The serialized bytes of the requested block |
A transaction sent by a peer.
transaction
Parameter | Type | Description |
---|---|---|
data |
bytes | The serialized bytes of a transaction |
Sent during the handshake.
version
Parameter | Type | Description |
---|---|---|
version |
number | The version of the network protocol |
listening_port |
number | The node's listening port |
This README is auto-generated during continuous integration. To update this README, submit a pull request updating the appropriate Markdown file in documentation and the configuration file.