Synchronization
This chapter describes how synchronization is achieved in the Blade system.
The fundamental objective of each participant, i.e. node, in a blockchain network is to find a sequence of cryptographically linked blocks that, according to a specific parameter (usually the number of blocks), is considered the currently accepted history at a given point in time. This chain is commonly referred to as the canonical chain. Various optimization and protection challenges arise in this context.
It is necessary to devise such a mechanism that, alongside an efficient defense against DoS (i.e., denial of service) and Eclipse attacks, will allow a node, regardless of how far behind it is, to align relatively quickly with all other (honest) participants in the network. The implementation is significantly influenced by the way new blocks are generated. Since the Blade system is based on the IBFT 2.0 consensus protocol and immediate finality, there is no need to take into account potential forks and reorganizations. Synchronization, alongside correctly implemented consensus rules, is of essential importance for the meaningful operation of every node.

The entire synchronization process is encapsulated within the Syncer object and the execution of its methods. As depicted in the class diagram, this object is a component of Polybft, initialized by invoking the newSyncer() method during node startup. Upon calling it, various fields of the Syncer object are set, including the most important ones: peerMap, syncPeerService, and syncPeerClient. In the context of synchronization, communication between nodes is organized so that each node establishes gRPC service through which other peers can send requests, made by syncPeerService. On the other hand, the core of the synchronization logic is implemented inside the syncPeerClient. It establishes the foundation for successful synchronization. Finally, as the name suggests, peerMap provides insight into the states of peers currently connected to the node. With the state of the node we denote the sequence number of the last block that a peer node has.
After completion of the initialization process, the Syncer starts up. This is done as the first step during the start of Polybft by calling the Syncer's Start() method. Its role is to launch all previously initialized components, as well as collect the current states of all connected peers. The first to be started is syncPeerClient.
As mentioned earlier, the syncPeerClient provides the foundation for successful synchronization. The first thing that starts within it is the gossip algorithm by calling the StartGossip method (this algorithm is exclusively related to blocks, not to transactions). When the method is called, a new topic is registered within the network layer with an appropriate message of the SyncPeerStatus type assigned, and then a subscription is made. A node determines which messages to send to each of its connected peers based on their subscriptions. During the subscription, a handler function is defined. It is called on the arrival of a message for the specified topic. In the case of synchronization, the function is checking the validity of the message and its origin, and if everything is fine, it forwards information to the peerStatusUpdateCh channel, indicating that a particular node has changed its status. This information includes the ID of the nodes, its new status (the new sequence number of the last block), and the distance to that peer.
In addition to running the gossip algorithm, two other things are started within the client. The first refers to the processing of a new block in the blockchain (startNewBlockProcess method). Specifically, if the state of the node's blockchain changes, within this method, a new SyncPeerStatus message will be sent to all peers who have subscribed to the topic for synchronization. The second thing that starts is the mechanism for monitoring the connection status of the peers (startPeerEventProcess method). Within the given method, upon the appearance or departure of a peer, certain information about it is sent to the peerConnectionUpdateCh channel.
Once the client-side synchronization of the node (syncPeerClient) is initiated, it is necessary to also activate the server-side (syncPeerService). As previously mentioned, this is a gRPC server that facilitates seamless and rapid communication between peers. We will not go into the details of the starting and processing of the gRPC server.
Upon successful completion of the aforementioned steps, the next phase of starting Syncer involves initializing the peer map through the initializePeerMap() method. It is important to note that this initialization is a one-time action during the node startup. Once the initialization of the map is complete, it is only updated dynamically based on the signals received from the peerStatusUpdateCh and peerConnectionUpdateCh channels. The peer map initialization process itself is relatively straightforward, entailing the dispatch of queries to each peer requesting their current state in terms of the sequence number of the last block. Subsequently, the peer map is populated, utilizing the peer's ID as the key and its corresponding state as the assigned value.
The final two things that are realized when starting Syncer, that is, in its Start() method, are related to activation of the mechanism for updating the previously mentioned map. This is carried out through the startPeerStatusUpdateProcess and startPeerConnectionEventProcess methods of the Syncer object. The first has a role to listen on the peerStatusUpdateCh channel and, upon the signal's appearance, update the existing map with the new state of the corresponding peer. Additionally, a signal is sent to the newStatusCh channel (the role of this channel will be explained further). The second method is responsible for listening on the peerConnectionUpdateCh channel. Upon the emergence of a new peer, it sends a request for the peer’s status and adds the new peer to the map (the signal is also sent to the newStatusCh channel). In a case of disconnection, the method removes the corresponding peer from the map.
After the successful startup of the Syncer synchronization begins. This is achieved by invoking its Sync method, again from within Polybft. The synchronization process itself is relatively straightforward. It revolves around waiting on the newStatusCh channel and upon the signal's appearance, searching for the best peer from the peer map. The best peer is the one with the best status, that is, the one with the highest last block. In a case where two peers share the same status, the distances are considered, and the closer peer is selected. If the best peer has a lower block height than the current node, the process is halted, and the node awaits the next signal on the newStatusCh channel. Otherwise, the process proceeds to retrieve blocks from the chosen peer. This is accomplished by invoking the bulkSyncWithPeer() method. Within this method, a connection stream is established between the node and the peer, where blocks arrive one after another. As each block arrives, it undergoes validation, and if successful, it is recorded in the blockchain. If any block fails validation, the process halts, the peer is marked as one to avoid further synchronization, and the node returns to waiting on the newStatusCh channel.
The entire synchronization process is illustrated through a sequential diagram below.

Last updated