# Gossamer sync: an overview - Synchronization is important for validators nodes since they must achieve a valid tip state to produce/finalize new blocks. The spec describe 3 different types of synchronization: `Full`, `Fast`, `Warp` - We can resume the sync it in 3 steps: request blocks from connected peers, validate and execute them in order to achieve the tip with a complete and valid history - Let's go through the different kinds of sync: - Full sync: works by listening to announced blocks and requesting blocks from the announcing peers, or just block headers in case of light clients. - Fast Sync: works by downloading the block header history and validating the authority set changes in order to arrive at a specif (and most recent) header. After achieving the tip the state can be downloaded and imported, once this proccess has been completed the node can proceed with a full sync. - Warp sync only downloads the block headers where authority set changes occurred, so called fragments, and by verifying the GRANDPA justifications. This method allows nodes to arrive at the desired state much faster than fast sync, once we reach the tip of the chain we can download the blocks in the gaps --- ### Gossamer Currently Gossamer contains the `sync` package located at `./dot/sync` and it is an service as `babe` and as `grandpa`. The `sync` service handles two internal services - chain sync - Takes care of the workers that request blocks from other peers (the workers queue, result queue and workers state), tracks the state of connected peers as their best block hash and number - It handles the readyBlocks queue which is a set of blocks which their parents is known - It handles pending blocks also known as disjoint set, they are blocks that are not ready to proccess, that means: blocks that we know only the hash, or the parent block is unknown or the body is unknown - It already has the concept of handler which, currently is splited in two, `bootstrap` and `tip` - chain processor - Process ready blocks, and also handles the disjoint block set. #### Chain Sync in details When we start the chain sync service we start the actual `sync` proccess and the `pending blocks` process (disjoint set of blocks). - The `pending block` proccess is a goroutine that executes the `clearBlocks` method every 1min. But every pending block added to this set contains an expiration value, and when that expiration value is reached the block is removed from the set, this clear avoids Gossamer to holds disjoint blocks for so long time. Also is not a problem to clear a disjoint block since it can be retrieved in the future by any active worker. - The `sync` proccess spwans a goroutine as well, but this time we do more than just calling one method. - inside the `sync` method we have a select that watches for 4 channels: `work queue`, `result queue`, `ticker`, `finalised channel`. - `Finalized Channel`: whenever a new blocks is finalized we got its information through this channel which means that we should clear all disjoint blocks lower than the new finalized block. - `Result queue`: Every time we dispatch a worker and it finishes we should handle the result (or error) from it - `Work queue`: every time we identify a block announcement from a connected peer we setup a `peerState` struct that contains its `peer id`, `best block hash` and `best block number` and send it through the `workQueue` channel, so we will setup a potential worker for that peer. As you notice in some of that cases we call the method `maybeSwitchMode`. This method basically changes the handler from `bootstrap` to `tip` if we are already in the tip of the chain, or the other way around if we are behind the tip. This is important to know, `bootstrap sync` mode always request blocks using the `Ascending` direction, while `tip sync` mode can request blocks use `Descending` direction. ### Requesting a block As we know, the blocks are requested via workers and those workers contains the peer ID and some informations to execute the request, so let's take a look in the format of the request: https://spec.polkadot.network/#sect-msg-block-request The block request is made out of 4 fields: - Block to start (hash or number) - Direction (Ascending or Descending) - Maximun amount (0-128) - Bits of data to request - HEADER: 00001 - BODY: 00010 - JUSTIFICATION: 10000 So for example if you want to a request 50 full blocks ahead starting from block hash `0x89...` the request will look like this: ``` { start: 0x89... direction: 0 max: 50, requesteData: 10011 } ```