Standards

Avalanche Network Protocol

The peer-to-peer messages that AvalancheGo nodes send to each other.

Overview

The Avalanche network protocol defines the messages that Avalanche nodes send to each other. Since v1.9.0 (Banff), nodes encode every message with Protocol Buffers (proto3). The schema is proto/p2p/p2p.proto in the AvalancheGo repository. The VM of each chain defines the bytes of the containers inside the messages. P-Chain and X-Chain containers use the primitive serialization format.

"Containers" are mentioned extensively in the description. A Container is simply a generic term for blocks.

This document describes the protocol for peer-to-peer communication using Protocol Buffers (proto3). The protocol defines a set of messages exchanged between peers in a peer-to-peer network. Each message is represented by the Message proto message, which can encapsulate various types of messages, including network messages, state-sync messages, bootstrapping messages, consensus messages, and application messages.

Message

The Message proto message is the main container for all peer-to-peer communication. It uses the oneof construct to represent different message types. The only supported compression algorithm is zstd. AvalancheGo v1.10.18 stopped gzip compression, and v1.11.3 removed the gzip field. Field 1 is now reserved.

message Message {
  reserved 1; // Until E upgrade is activated.
  reserved 37; // Next unused field number.
  oneof message {
    bytes compressed_zstd = 2;
    // Fields lower than 10 are reserved for other compression algorithms.

    // Network messages:
    Ping ping = 11;
    Pong pong = 12;
    Handshake handshake = 13;
    GetPeerList get_peer_list = 35;
    PeerList peer_list = 14;

    // State-sync messages:
    GetStateSummaryFrontier get_state_summary_frontier = 15;
    StateSummaryFrontier state_summary_frontier = 16;
    GetAcceptedStateSummary get_accepted_state_summary = 17;
    AcceptedStateSummary accepted_state_summary = 18;

    // Bootstrapping messages:
    GetAcceptedFrontier get_accepted_frontier = 19;
    AcceptedFrontier accepted_frontier = 20;
    GetAccepted get_accepted = 21;
    Accepted accepted = 22;
    GetAncestors get_ancestors = 23;
    Ancestors ancestors = 24;

    // Consensus messages:
    Get get = 25;
    Put put = 26;
    PushQuery push_query = 27;
    PullQuery pull_query = 28;
    Chits chits = 29;

    // App messages:
    AppRequest app_request = 30;
    AppResponse app_response = 31;
    AppGossip app_gossip = 32;
    AppError app_error = 34;

    // Simplex messages:
    Simplex simplex = 36;
  }
}

Compression

The compressed_zstd field holds the zstd-compressed bytes of a Message. The oneof field of that inner Message is one of the message types, not a compressed field. The sender sets this field only if the message type supports compression.

Network Messages

Ping

The Ping message reports a peer's perceived uptime percentage.

message Ping {
  uint32 uptime = 1;
  reserved 2; // Until Etna upgrade is activated.
}
  • uptime: Uptime percentage on the primary network [0, 100].

AvalancheGo v1.11.12 removed the L1 uptimes (field 2) from Ping.

Pong

The Pong message is sent in response to a Ping. It has no fields. AvalancheGo v1.11.5 removed its uptime fields, because Ping carries the uptime.

message Pong {
  reserved 1, 2; // Until E upgrade is activated.
}

Handshake

The Handshake message is the first outbound message sent to a peer when a connection is established. The peer must respond with a PeerList message. Peers drop connections to peers with incompatible versions. AvalancheGo v1.10.18 renamed this message from Version to Handshake.

message Handshake {
  uint32 network_id = 1;
  uint64 my_time = 2;
  bytes ip_addr = 3;
  uint32 ip_port = 4;
  uint64 upgrade_time = 5;
  uint64 ip_signing_time = 6;
  bytes ip_node_id_sig = 7;
  repeated bytes tracked_subnets = 8;
  Client client = 9;
  repeated uint32 supported_acps = 10;
  repeated uint32 objected_acps = 11;
  BloomFilter known_peers = 12;
  bytes ip_bls_sig = 13;
  bool all_subnets = 14;
}
  • network_id: Network identifier (for example local, testnet or Mainnet).
  • my_time: Unix timestamp when the Handshake message was created.
  • ip_addr: IP address of the peer.
  • ip_port: IP port of the peer.
  • upgrade_time: Unix timestamp (in seconds) of the most recently scheduled network upgrade. It can be a past upgrade or a future upgrade.
  • ip_signing_time: Timestamp of the IP.
  • ip_node_id_sig: Signature of the IP and port pair at ip_signing_time, made with the TLS key.
  • tracked_subnets: IDs of the L1s that the peer tracks.
  • client: Client name (for example avalanchego) and its major, minor and patch version.
  • supported_acps: ACPs that the peer supports.
  • objected_acps: ACPs that the peer objects to.
  • known_peers: Bloom filter, with a random salt, of the peers that the sender knows.
  • ip_bls_sig: Signature of the IP and port pair at ip_signing_time, made with the BLS key.
  • all_subnets: Confirms that the peer tracks all L1s. The other peer sends the IPs of validators that the peer does not track only when this value is true.

PeerList

The PeerList message contains network-level metadata for a set of validators.

message PeerList {
  repeated ClaimedIpPort claimed_ip_ports = 1;
}
  • claimed_ip_ports: List of claimed IP and port pairs.

GetPeerList

The GetPeerList message contains a bloom filter of the validator IPs that the sender knows. A peer responds to it only after the handshake is complete. The response is a PeerList message with the validators that are not in the bloom filter. AvalancheGo v1.10.18 replaced PeerListAck with GetPeerList.

message GetPeerList {
  BloomFilter known_peers = 1;
  bool all_subnets = 2;
}
  • known_peers: Bloom filter, with a random salt, of the validator IPs that the sender knows.
  • all_subnets: Confirms that the sender tracks all L1s.

State-Sync Messages

GetStateSummaryFrontier

The GetStateSummaryFrontier message requests a peer's most recently accepted state summary.

message GetStateSummaryFrontier {
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this request.
  • deadline: Timeout (ns) for this request.

StateSummaryFrontier

The StateSummaryFrontier message is sent in response to a GetStateSummaryFrontier request.

message StateSummaryFrontier {
  bytes chain_id = 1;
  uint32 request_id = 2;
  bytes summary = 3;
}
  • chain_id: Chain being responded from.
  • request_id: Request ID of the original GetStateSummaryFrontier request.
  • summary: The requested state summary.

GetAcceptedStateSummary

The GetAcceptedStateSummary message requests a set of state summaries at specified block heights.

message GetAcceptedStateSummary {
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
  repeated uint64 heights = 4;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this request.
  • deadline: Timeout (ns) for this request.
  • heights: Heights being requested.

AcceptedStateSummary

The AcceptedStateSummary message is sent in response to GetAcceptedStateSummary.

message AcceptedStateSummary {
  bytes chain_id = 1;
  uint32 request_id = 2;
  repeated bytes summary_ids = 3;
}
  • chain_id: Chain being responded from.
  • request_id: Request ID of the original GetAcceptedStateSummary request.
  • summary_ids: State summary IDs.

Bootstrapping Messages

GetAcceptedFrontier

The GetAcceptedFrontier message requests the accepted frontier from a peer.

message GetAcceptedFrontier {
  reserved 4;
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this request.
  • deadline: Timeout (ns) for this request.

AcceptedFrontier

The AcceptedFrontier message contains the remote peer's last accepted frontier.

message AcceptedFrontier {
  bytes chain_id = 1;
  uint32 request_id = 2;
  bytes container_id = 3;
}
  • chain_id: Chain being responded from.
  • request_id: Request ID of the original GetAcceptedFrontier request.
  • container_id: The ID of the last accepted frontier.

GetAccepted

The GetAccepted message sends a request with the sender's accepted frontier to a remote peer.

message GetAccepted {
  reserved 5;
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
  repeated bytes container_ids = 4;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this message.
  • deadline: Timeout (ns) for this request.
  • container_ids: The sender's accepted frontier.

Accepted

The Accepted message is sent in response to GetAccepted.

message Accepted {
  bytes chain_id = 1;
  uint32 request_id = 2;
  repeated bytes container_ids = 3;
}
  • chain_id: Chain being responded from.
  • request_id: Request ID of the original GetAccepted request.
  • container_ids: Subset of container IDs from the GetAccepted request that the sender has accepted.

GetAncestors

The GetAncestors message requests the ancestors for a given container.

message GetAncestors {
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
  bytes container_id = 4;
  EngineType engine_type = 5;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this request.
  • deadline: Timeout (ns) for this request.
  • container_id: Container for which ancestors are being requested.
  • engine_type: Consensus type to handle this message.

Ancestors

The Ancestors message is sent in response to GetAncestors.

message Ancestors {
  bytes chain_id = 1;
  uint32 request_id = 2;
  repeated bytes containers = 3;
}
  • chain_id: Chain being responded from.
  • request_id: Request ID of the original GetAncestors request.
  • containers: Ancestry for the requested container.

Consensus Messages

Get

The Get message requests a container from a remote peer.

message Get {
  reserved 5;
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
  bytes container_id = 4;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this request.
  • deadline: Timeout (ns) for this request.
  • container_id: Container being requested.

Put

The Put message is sent in response to Get with the requested block.

message Put {
  bytes chain_id = 1;
  uint32 request_id = 2;
  bytes container = 3;
}
  • chain_id: Chain being responded from.
  • request_id: Request ID of the original Get request.
  • container: Requested container.

PushQuery

The PushQuery message requests the preferences of a remote peer given a container.

message PushQuery {
  reserved 5;
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
  bytes container = 4;
  uint64 requested_height = 6;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this request.
  • deadline: Timeout (ns) for this request.
  • container: Container being gossiped.
  • requested_height: Requesting peer's last accepted height.

PullQuery

The PullQuery message requests the preferences of a remote peer given a container id.

message PullQuery {
  reserved 5;
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
  bytes container_id = 4;
  uint64 requested_height = 6;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this request.
  • deadline: Timeout (ns) for this request.
  • container_id: Container id being gossiped.
  • requested_height: Requesting peer's last accepted height.

Chits

The Chits message contains the preferences of a peer in response to a PushQuery or PullQuery message.

message Chits {
  bytes chain_id = 1;
  uint32 request_id = 2;
  bytes preferred_id = 3;
  bytes accepted_id = 4;
  bytes preferred_id_at_height = 5;
  uint64 accepted_height = 6;
}
  • chain_id: Chain being responded from.
  • request_id: Request ID of the original PushQuery/PullQuery request.
  • preferred_id: Currently preferred block.
  • accepted_id: Last accepted block.
  • preferred_id_at_height: Currently preferred block at the requested height.
  • accepted_height: Height of the last accepted block.

Application Messages

AppRequest

The AppRequest message is a VM-defined request.

message AppRequest {
  bytes chain_id = 1;
  uint32 request_id = 2;
  uint64 deadline = 3;
  bytes app_bytes = 4;
}
  • chain_id: Chain being requested from.
  • request_id: Unique identifier for this request.
  • deadline: Timeout (ns) for this request.
  • app_bytes: Request body.

AppResponse

The AppResponse message is a VM-defined response sent in response to AppRequest.

message AppResponse {
  bytes chain_id = 1;
  uint32 request_id = 2;
  bytes app_bytes = 3;
}
  • chain_id: Chain being responded from.
  • request_id: Request ID of the original AppRequest.
  • app_bytes: Response body.

AppError

The AppError message is a VM-defined error sent in response to AppRequest. A peer must respond to an AppRequest with an AppResponse or an AppError.

message AppError {
  bytes chain_id = 1;
  uint32 request_id = 2;
  sint32 error_code = 3;
  string error_message = 4;
}
  • chain_id: Chain the message is for.
  • request_id: Request ID of the original AppRequest.
  • error_code: VM-defined error code. VMs can define error codes greater than 0.
  • error_message: VM-defined error message.

AppGossip

The AppGossip message is a VM-defined message.

message AppGossip {
  bytes chain_id = 1;
  bytes app_bytes = 2;
}
  • chain_id: Chain the message is for.
  • app_bytes: Message body.

Is this guide helpful?