Skip to main content

Peer Protocol

This protocol is a bidirectional protocol for communication between full nodes in the Chia system. The sender is the full node sending the message, and the recipient is the full node that is receiving the message.


Sent to peers whenever our node's peak weight advances (whenever the blockchain moves forward). The fork point allows peers to detect how deep of a reorg happened, and fetch the correct blocks. The unfinished reward block hash allows the receiving peer to use their cache for unfinished blocks, since they most likely already have the unfinished version of the same block, and therefore don't need to re-request the block transactions generator.

Usually, during normal operation, peers will ask for just the latest block, or ignore this message if they have already received it from another peer. If we are a few blocks behind, blocks are fetched one by one in reverse order up to the fork.

If we are far behind this peak, we will start a batch sync (download a few tens of blocks in batches) or a long sync, where we download a weight proof and then download many blocks in batches.

class NewPeak(Streamable):
header_hash: bytes32 # header_hash of new block
height: uint32 # height of new block
weight: uint128 # weight of new block
fork_point_with_previous_peak: uint32
unfinished_reward_block_hash: bytes32


Sent to peers when a new spend bundle has been added to the mempool. The receiving peer can then choose to ignore it, or request the whole transaction.

class NewTransaction(Streamable):
transaction_id: bytes32 # hash of the spend bundle
cost: uint64 # cost of the transaction, used to see if fees are sufficient for mempool inclusion
fees: uint64 # fees in mojo of transaction, used to see if fees are sufficient for mempool inclusion


Request for a full transaction (spend bundle) from a peer by its id. If a peer does not respond, other peers are contacted for the same transaction.

class RequestTransaction(Streamable):
transaction_id: bytes32 # hash of the spendbundle


Response for a request_transaction message. Sends a spend bundle to a peer. To see the contents of a SpendBundle, see the Spend Bundles page.

class RespondTransaction(Streamable):
transaction: SpendBundle


Request a weight proof from a peer. This is done right before starting a long sync. The weight proof allows our node to validate whether a new_peak that we received from a peer corresponds to an actual valid blockchain. It is proof that a certain amount of "weight", or space and time, has been used on that blockchain.

class RequestProofOfWeight(Streamable):
total_number_of_blocks: uint32 # Height of the peak block
tip: bytes32 # The header_hash of the peak block


Response to a request_proof_of_weight message. Note that weight proofs can be quite large, in the tens of MB range. If the chain VDFs are compressed (aka blueboxed), then they weight proofs will be smaller. This is the V1 version of weight proofs, more efficient versions might be added in the future.

class RespondProofOfWeight(Streamable):
wp: WeightProof
tip: bytes32


Request for a block at a certain height from a peer. Called after receiving a new_peak message.

class RequestBlock(Streamable):
height: uint32 # Height of the block to request
include_transaction_block: bool # Whether to include transaction data


Response to a request_block message.

class RespondBlock(Streamable):
block: FullBlock


Rejection to a request_block message.

class RejectBlock(Streamable):
height: uint32


Request multiple blocks at once from a peer.

class RequestBlocks(Streamable):
start_height: uint32
end_height: uint32 # Inclusive
include_transaction_block: bool # Whether to include transaction data


Response to a request_blocks message.

class RespondBlocks(Streamable):
start_height: uint32
end_height: uint32
blocks: List[FullBlock]


Rejection to a request_blocks message.

class RejectBlocks(Streamable):
start_height: uint32
end_height: uint32


Notification to another peer that a new unfinished block was added to the cache. These unfinished blocks are kept around temporarily, until the infusion point VDF is released, and the block can be "finished" and added to the blockchain.

class NewUnfinishedBlock(Streamable):
unfinished_reward_hash: bytes32


Request for an unfinished block from a peer.

class RequestUnfinishedBlock(Streamable):
unfinished_reward_hash: bytes32


Response to a request_unfinished_block message.

class RespondUnfinishedBlock(Streamable):
unfinished_block: UnfinishedBlock


Sent when the node adds a new signage point or a new end of sub slot to the full node store. The receiver can choose to request the object, or potentially request the previous sub slot, if they are far behind. For example, recently synced up to the peak of the blockchain.

class NewSignagePointOrEndOfSubSlot(Streamable):
prev_challenge_hash: Optional[bytes32] # Challenge hash at the start of the previous sub slot, if present
challenge_hash: bytes32 # Challenge hash at the start of the sub slot
index_from_challenge: uint8 # Index from the start, 0 for end of sub slot
last_rc_infusion: bytes32 # Last reward chain infusion hash


Request for a signage point or end of slot.

class RequestSignagePointOrEndOfSubSlot(Streamable):
challenge_hash: bytes32
index_from_challenge: uint8
last_rc_infusion: bytes32


Response for request_signage_point_or_end_of_sub_slot. After receiving this message, the recipient will check that all VDFs are correct, and forward it to other full nodes and potentially farmers.

class RespondSignagePoint(Streamable):
index_from_challenge: uint8 # Which index out of the 64 signage points, cannot be 0 since that is the EOS
challenge_chain_vdf: VDFInfo
challenge_chain_proof: VDFProof
reward_chain_vdf: VDFInfo
reward_chain_proof: VDFProof


Another response for request_signage_point_or_end_of_sub_slot in the case where index_from_challenge is zero. This is also verified and forwarded by the full node, similar to signage points.

class RespondEndOfSubSlot(Streamable):
end_of_slot_bundle: EndOfSubSlotBundle


This is a request for transactions in the mempool. The filter corresponds to a BIP158 Compact Block Filter, which allows the recipient to see what transactions the sender already has (with some small chance for false positives), without sending all transaction IDs. The recipient can then respond using respond_transction directly, but should not send a very large number of transactions, to not overwhelm the original sending peer.

class RequestMempoolTransactions(Streamable):
filter: bytes


A notification to a peer that a new compact VDF has been added to the blockchain. Compact VDFs are smaller versions of VDF proofs present in blocks. They do not change the block itself, they just compress the block data to keep the DB smaller and sync time lower. The actual proof

class NewCompactVDF(Streamable):
height: uint32 # Height of the block which has a new VDF
header_hash: bytes32 # Header hash of that block
field_vdf: uint8 # Which VDF in that block was updated (blocks have multiple VDFs)
vdf_info: VDFInfo # Info of the VDF that was updated


A request to a peer for a compact VDf.

class RequestCompactVDF(Streamable):
height: uint32
header_hash: bytes32
field_vdf: uint8
vdf_info: VDFInfo


A response to a peer that requested a compact VDF.

class RespondCompactVDF(Streamable):
height: uint32
header_hash: bytes32
field_vdf: uint8
vdf_info: VDFInfo
vdf_proof: VDFProof


Request a list of peers. There is no body in this message. This is usually sent when connecting to a peer.

class RequestPeers(Streamable):
Return full list of peers


A response to request_peers, containing a list of ip and port for each peer. Must be no larger than 1000. The timestamp corresponds to the last time this peer's record was updated, based on the peer DB update rules.

class RespondPeers(Streamable):
peer_list: List[TimestampedPeerInfo]