Catchain

**Catchain (catch-chain is a blockchain trap)** is an agreement type protocol that aims to intercept unwanted events that make it more difficult for network validators to reach consensus in the underlying TON blockchain.

The author of the protocol is Nikolai Durov. Was published in February 2020. The original can be found here.

## Introduction

The main idea of the Catchain agreement protocol is a special case of the consensus algorithm Proof-of-Stake (POS) from the solution algorithm called Byzantine Generals problem, which describes the issued problem of reaching out consensus in a distributed system where each one of participants in the network has no information about the entire network and does not trust none of its participants. None single block producer can always be trustworthy. Consensus underlies each block chain, and allows the launched network nodes to agree on the next block in the block chain without need of trusting each other.

There are usually two most common types of POS consensus algorithms. The first one is called (CBC Casper, Ouroboros, etc.) is when block generation is very simple, but forks are allowed too, followed by a process of complex negotiation between all network members. And the other kind (**Catchain**, PBFT, Tendermint, Algorand, etc.) is the opposite to the first onne, where agreement on block generation is complicated, but forks are rare or impossible to use.

The Catchain consensus involves the following steps:

* selecting a validator depending on the steak size;
* triggering a validation session;
* several rounds of block generation.

Each round of block generation is limited by the time and consists only of several attempts. If the validators can not reach an agreement using all available attempts, the round is being skipped and the new block is not added to this block chain. During the round, validators do exchange messages about candidate blocks, they do verify them, select them for a vote, next take a vote for them, and in the end finally place the selected block in the blockchain.

To decentralise this consensus, the algorithm uses a cyclical transfer of roles from validator to validator per round. In each round and each attempt, several validators are assigned to generate new blocks and one validator gets assigned to offer the block for voting. As the validators change their roles from one attempt to another attempt, the consensus mechanism can not be blocked by the inability no more to get a decision from a majority of the validators. The main general key idea is to make sure that 2/3 of the validators' votes for a particular block and are actually filled. The 2/3 cut-off threshold is set as theoretical value to ensure that a decision is totaly made by consensus.

To improve overall networks performance, a partial message synchronisation between nodes found it's way to be used. This means that each validator **communicates only with one randomly selected subset of all validators** and uses the data that was received from them to make a decision during the validation round. This gathered data also includes the final data received from all other validators as well.

## Comparison with other available solutions

The TON consensus protocol is very similar to PBFT schemes (PBFT, Tendermint, Algorand) - it uses the same three-step pattern (block approval, voting, pre-fixing) and can be found in all of them with slightly made variations.

### PBFT

Considered as the oldest protocol in this family. It was originated in 1999.

Features:

* The slot leader is only re-elected if it does not work as well as needed. By comparison, Catchain changes the leader every new round in a predetermined way.
* One round of block voting requires (n^2) messages (where n = number of needed nodes). Each node sends a message to all other users. Catchain uses more special protocol that greatly reduces the needed number of messages: outgoing messages are sent only to a small number of "neighbours" (set to 5 by default), who then resend them further.

### Tendermint

The most closest algorithm to Catchain.

* As in Catchain, the proposer node is chosen cyclically for each turn.
* For Tendermint, only **local time** info is needed to calculate timeouts. And this differs it from Catchain, for which time now must be synchronized **globally**. This scheme can make Catchain much more vulnerable to a kind of blackout attacks: by manipulating with NTP messages, a node can be ran completely out of sync (the block chain still will remain correct, but that particular node will not be able to vote no more and propose its blocks).

A gossip propagation protocol therefore has been implemented to reduce the number of needed messages to O (n log n) for each new vote. Catchain has overlay network protocol for such purpose messaging.

### Algorand

* At the each voting stage a small number of voters ("committee") is determined. The election follows for a specific but secretly taken procedure (only the user does knows that they have been chosen to sit on the committee, but they can still prove it to others). Then, only those committee members participate in this subsequent vote. Thanks to the cryptographic measures adopted, security is not compromised at this stage.
* No clock synchronisation is required no more, it has the same timeout delay for all nodes.
* Like Catchain, Algorand also uses a gossip propagation algorithm for processing. The authors claim that each node that is participating in the voting process sends exactly one message at every stage of voting process.

### Ouroboros, CBC Casper

Main differences are: they build multiple chains of the blocks, and then easily creates fork of them. There is a certain set of valid chains at any given time, and the algorithms do ensure that any valid transactions are present in any of these chains after generating needed R blocks (where R depends on the configuration set and can become quite large).

This type of algorithm does require far fewer amount of synchronization messages, but requires much more resources for processing these multiple concurrent chains. In addition to that, new transactions become publicly available by more later time.

## Catchain components

The consensus logic here is implemented in three main components and those are:

* **catchain** - responsible for communication and block delivery between all assigned validators;
* **validator-session** - responsible for the consensus by itself;
* **Validator Session**, responsible for communication between validator sessions and other needed TON components. In particular, this component validates new blocks, it interacts with picker nodes when forming block candidates and commits blocks in a block chain.

Components here are linked based on dependency inversion principle.

## Validator session component

### Overview of the consensus algorithm

To ensure that block validation is enabled, TON creates a list of validator nodes. The stage takes a concrete period of time to make it configured at blockchain zero state and it is called a validator session. A session is run in several round cycles, each one of them are aimed at creating signed blocks.

The needed list of validators for each validator session is governed by a specialy created smart contract that implements the election logic. Validation is set for a certain number of rounds, each of which ends with either a block commit or makes a round skip. The election results are collected in a list of nodes, where each one has a corresponding vote weight, which is directly proportional to the value of the node's steak. So, the greater the steak is, the greater its weight in the vote becomes. The nodes then makes a vote by signing the candidate for the block with their inique personal keys. If a block recieves more than 2/3 of all gathered weights - it automatically wins in that round of voting.

Each round does consists of several stages:

* creation of block candidates;
* confirmation;
* voting;
* signing.

The round ends when there is a new signed block made. To prevent validator conflicts over a newly created block, each round consists of a certain number of fixed attempts, pre-configured at blockchain zero state. In situation when consensus is not reached within the maximum number of attempts, the round is considered to be failed. A fixed block is now skipped and is not recorded in the whole block chain. If the validators do fail to reach consensus within a few upcoming rounds, choosing a new validator should help to resolve this situation.

Here each validator node stores the state of created validation session, and synchronises it with the other nodes after each newly made modification (it means that it creates a snapshot of its current status). Synchronization gets implemented using Catchain protocol by passing messages (it means that moving to the current status snapshot is done). Synchronization after modification process is not applied to all nodes, but only to neighbouring nodes. This subset is not permanent and is periodically updated. This minimizes used traffic amount between Catchain nodes and delivers node status info to all of them. The correctness of the status is managed and controlled through signature verification. His status consists of the current status info of a round and a list of statuses that were collected in the previous round (same as history of previous rounds).

The current status of a round, in turn, consists of a list containting attempts and signatures of the selected commit candidate block (it's called pre-committed block). Ultimately, each new round attempt involves these following steps:

* the validator nodes exchange block candidates for full approval;
* the main used node for the current attempt sends a block candidate straight to the other nodes for voting (based on current priority of the node that's calculated for that attempt);
* the validator nodes exchange votes.

To avoid chance of interblocking when voting and generating block candidates, the priority of a node is set according to the total number of nodes, round number, and number of needed attempts. Thus the validators priority is changed by each attempt:

* priority for providing block candidates (only by the first one `validatorSessionOptions::round_candidate` can propose a new candidate for approval);
* priority set as a ranking criteria for selecting candidates for whole approval process;
* priority for need to select an approved block for voting (this can be done only by one node).

Additionally for that priority is used to calculate delay timing in the approval process during each round (the lowest priority of corresponds is given to the lower approval delay).

Another really obvious and important point to mention is that each validator's decision always is checked by the other validators. A validator's unique node public key is used to verify his signature. At the start of each new validator session, each validator receives information about all other involved validators, including:

* the list of validators pre-created by this smart contract (and by their indices);
* the unique public keys of each validator;
* the weight (as priority) of the validator according to its stacks amount. Each time a validator receives new block candidates, approvals or votes from other nodes, it checks the signature correctnes (and in some cases the priority, as explained above) to ensure that:
* the sender is authorised to make its own decision;
* the decision was actually made by that particular message sender.

### Stages of consensus

The stages (called slots) of the round are set as follows:

1. **Block candidate generation**. Each selected node that has priority to create a block for the round generates a new block candidate, which now is requested from the picker itself (see `Validatorsession::ValidatorSession::Callback::on_generate_slot` for more details). Once a candidate appears here, it is sent to the rest validator nodes (`validatorSession.candidate > validatorSession.message.submittedBlock`).
2. **Approve candidate blocks**. The blocks from the previous step that are collected on each validator node and processed for new approval. The approval process is considered unrelated to the consensus by itself, and is intended now to verify that blocks don't seem to be corrupted in terms of related data (see `Validatorsession::ValidatorSession::Callback::on_candidate callback` for details). Once the block here isconsidered to be validated, it is signed by each of validators. Then a message `validatorSession.message.approvedBlock` appears with the round number and ID identifier of the approving node that is transmitted. This way, each one validator knows which node was approved by the sent block. The block is considered to be fully approved when it receives 2/3 of the approval messages.
3. **Voting Attempts.** Several attempts can be made to vote on the block. Each attempt has its time limit, and validators are assumed to be placed in a slot for that. Whatever votes for the current candidate are still being *accepted* after reaching the deadline of the attempt, this may cause a real situation where two attempts result in different votes for multiple candidates, a certain case being discussed can be found further below. The block candidate is now selected by the main validator node, and other nodes are notified with a specific `validatorSession.message.voteFor` message (see `ValidatorSessionRoundState::generate_vote_for` for more details; the main validator node that offers a block to try is given `ValidatorSessionDescriptionImpl::get_vote_for_author` this method). Block selection involves in it two aspects: a) the node ranks the approved blocks by the given priority of the nodes for the current coming attempt, so the list is getting reordered at each attempt, and b) the main validator node does randomly select a block to vote from this given list. Each validator node processes the above given message and selects a certain block to vote on. The validator for now does not have to vote for the proposed block and he may choose a different block. Thus, the proposed block now is more of a prompt, the purpose of which is to speed up the whole voting process. Voting involves two things to be marked: a) a signature block to note that a particular validator node got voted for it, and b) communicating this information using `validatorSession.message.vote` messages to the other validators. By the time as any approved block receives at least 2/3 of the needed total vote weight, it does become a candidate for signature (block before commit). Votes are more likely to be received after the end of this attempt. Late time votes are then processed at the same time as next new attempt. As a general rule to be taken, votes for each completed attempt may be taken even after the deadline; not becoming a logical error, this allows this curent round to be completed way more quickly. And if any one of previous attempts ends with 2/3 of the total needed votes or more, even after reaching deadline, it will still give a new pre-commitment candidate. In this case of a conflict, where two attempts do offer different blocks for pre-commitment, then it latter prevails. To be noted, for performance reasons, the vote that is received for a block in one attempt is automatically reused again in the remaining attempts.
4. **Commit (fixation) of a block**. As soon as a certain round attempt yields a pre-commit block, the signing process now begins. The validator who receives a pre-commit block first in the current round, signs it, and notifies the rest of validators with a `validatorSession_message_commit` message (see `ValidatorSessionImpl::check_sign_slot` and associated logic in `ValidatorSessionImpl::process_blocks` for more details). All other validators receive this messages, check senders signature and update their own state (see it in `ValidatorSessionRoundState::action (..., validatorSession_message_commit`). In a way a particular validator does get at least 2/3 of needed signatures from other validators.

If it does fail to get a signed block within a certain number of attempts being taken (`ValidatorSessionOptions::max_round_attempts`), a new round starts again, and the failed round is marked now as skipped (see at `Validatorsession::ValidatorSession::Callback::on_block_skipped`).

### Validator session protocol messages and structures

The validator session protocol does consists of:

* incoming events: **validatorSession.round.Message** (it can be one of the following subtypes: `validatorSession.message.submittedBlock`, `validatorSession.message.approvedBlock`, `validatorSession.message.rejectedBlock`, `validatorSession. message.voteFor`, `validatorSession.message.vote`, `validatorSession.message.precommit`, `validatorSession.message.commit`, `validatorSession.message.empty`), `validatorSession.blockUpdate`, `validatorSession.candidate`;
* mandatory as an outbound request `validatorSession.downloadCandidate` (with `validatorSession.candidate` set as two related events);
* internal structures that can be used in chosen events and requests above.

Main threads:

1. consensus stages

* a. Block candidate generation
	+ ². Proposal with highest priority for block candidate using `validatorSession.message.submittedBlock`.
	+ ². Each one validator with candidate block proposal priority can propose new block within a limited timing after the start of next round. Blocks offered outside the time slot will be ignored.
* b. Approval of block candidates
	+ I. After receiving `validatorSession.message.submittedBlock`, each one validator starts checking the block for the approval. If it's approved, the validator then generates `validatorSession.message.approvedBlock`, if it's rejected, uses `validatorSession.message.rejectedBlock`.
* c. Voting attempts
	+ I. Validator that is having block submission priority. Proposes a block for a vote, by selecting it randomly from the list of approved blocks and generates a message with `validatorSession.message.voteFor`.
	+ ². The validator that receives this `validatorSession.message.voteFor` does check if this message was created by the same validator who had priority to submit the block to vote. If it's true, it uses the proposed block as a priority for same voting.
	+ III. In his first attempt to vote, the validator votes for the block that was received in the `validatorSession.message.voteFor`. This is the most fastest way to make consensus decisions. The same vote on the block can be received in this `validatorSession.message.voteFor` message is executed after the maximum number of used attempts to vote. This creates a message `validatorSession.message.vote` with a vote on a specificly selected block.
	+ IV. If it is not his first attempt and the number of voting attempts is way less than the maximum alloed, the validator chooses a block to vote on and is offered by another validator with a bit lower priority for this current round. Situation like this creates a message `validatorSession.message.vote` with a vote on a particular block.
	+ V. If the validator did vote for a block in a previous round attempt, it now generates message `validatorSession.message.vote` with the same conainting vote.
	+ VI. When the validator receives this `validatorSession.message.vote`, it does check if at least 2/3 of the needed votes for the block are questioned and received. If it's true, the validator generates message `validatorSession.message.precommit` with the block selected as a candidate for commit.
* d. Block commit.
	+ I. When our validator receives the message `validatorSession.message.precommit` , it checks again if at least 2/3 of the needed votes for the block are proposed in the `validatorSession.message.precommit` are getting received. If it's true, a message`validatorSession.message.commit` is created with a block for the precommit and a corresponding validator signature.
	+ II. When the validator does receive message validatorSession.message.commit, it checks whether at least 2/3 of needed votes for the proposed block commit have been received. If it's true, the block is now committed and a new cycle round begins.
	+ III. If no block is geting committed within the maximum number of allowed attempts, the round is marked as skipped one and a new round is started.
* e. Candidate block upload.
	+ To speed up whole consensus processing, there is a request message `validatorSession.downloadCandidate` which can be sent by the validator to request a candidate block with its specific ID identifier. The validator then makes this request when it does not have any candidate block for further consensus processing.

2. Internal code structures:

* а. **validatorSession.config.** This structure is configured in state of null and contains consistent configuration of parameters common to all chosen validators.
	+ `catchain_idle_timeout`: `double` - timeout frame between calls to agreed iterations; each consensus that repeat can generate a new block;
	+ `catchain_max_deps: int` - maximum posible number of catchain blocks to merge during consensus repeat;
	+ `round_candidates`: `int` - number of candidate blocks per each round in which they are being generated;
	+ `next_candidate_delay`: `double` - delay time between block candidate offerings;
	+ `round_attempt_duration`: `int` - time duration of attempt in milliseconds;
	+ `max_round_attempts`: `int` - maximum number of attempts per each round;
	+ `max_block_size`: `int` - maximum block size;
	+ `max_collated_data_size`: `int` - maximum size of collated data per block.
* b. **validatorSession.candidateId**: is part of the `validatorSession.downloadCandidate` made query and contains candidate block hashes in it.
	+ `src`: `int256` - hash of the validator unique public key that generated by candidate block;
	+ `root_hash`: `int256` - block root hash;
	+ `file_hash`: `int256` - block file hash;
	+ `collated_data_file_hash`: `int256` - hash of mapped block data.

3. Events:

* а. **validatorSession.round.Message**
	+ '**validatorSession.message.submittedBlock** - the message does refer to the block candidate generation stage. It reports that our validator has generated a new candidate block and got it submitted to Catchain. Each validator has only a limited time frame for generating (and offering process) candidate blocks. It is calculated according to selected priority of the node, which does depend on the round and its current time. A new candidate block can be generated only when the current consensus round has not yet been completed fully (new block is not committed) during the `round_attempt_duration`. This message has the following structure:
		- `round`: `int` is number of the appearance round per new candidate block;
		- `root_hash`: `int256` - root hash code of the candidate block;
		- `file_hash`: `int256` - hash of certain candidate block file;
		- `collated_data_file_hash`: `int256` - data hash of candidate block data.
			* Actions: this message should be generated when validator generates a new block candidate
	+ '*validatorSession.message.approvedBlock* - the message refers to the block candidate approval stage. It reports that the validator has approved the block candidate in a particular round. Each validator chooses a list of blocks to approve, sorted by node priority. Only blocks that have not been previously approved are included in the list. The block is only approved from a certain time (`CandidateDecision::ok_from`) calculated by the validator. Block approval is initiated as soon as the block candidate is validated and signed off. The message has the following structure:
		- round: int - candidate block approval round number;
		- candidate: int256 - candidate block hash;
		- reason: bytes - validator signature.
			* Actions: For this message it should be generated when the validator approves one or more block candidates.
	+ '*validatorSession.message.rejectedBlock* - The message refers to the new block candidate approval stage. This indicates that the validator has validated our block candidate and somehow rejects it. This message can be ignored by the consensus itself (it does not have any other effect than logging if the message was received by our validator). The message has the following structure:
		- round: int - number of round in which our candidate block was rejected;
		- candidate: int256 - candidate block hash;
		- reason: bytes - his reason for rejection (is validator dependent).
			* action: this message is generated when the block check fails again and again. The message is not transitive one and should only be sent if our current validator rejects the candidate block.
	+ '*validatorSession.message.voteFor* - the message does refer to the stage of taken voting attempts. The message can only be sent by a validator with given priority to create a 'vote for' candidate block next attempt. The block on which is voted on gets selected randomly from the approved blocks by our validator with priority for the current attempt.
		- `round`: `int` - round # number;
		- `attempt`: `int` - the number of taken attempt in which our block candidate will be selected as the block gets voted for;
		- `candidate`: `int256` - hash of the candidate block.
			* Action: This message should be generated only if:
		- a) the node has bigger priority to generate the block it is voting for;
		- b) the node recieved at least one approved block;
		- c) the node does not have a pre-fixed block at all;
		- d) The node has not sent message `validatorSession.message.voteFor` during this curent attempt.
	+ `validatorSession.message.vote` - The message refers back to the voting attempts phase. It is sent to report a validator vote for a candidate block and has the following structure:
		- `round`: `int` - round # number;
		- `try`: `int` - the number of total attempts at which the validator voted for our block candidate;
		- `candidate`: `int256` - hash of the candidate block.
	+ The validator will vote for the block only in one of the selected cases:
		- a) the block has been blocked in a previous round cyle attempt;
		- b) the validator has been offered with a block of lowest priority for the round, if this current attempt is not the first attempt and the maximum number of available round attempts has not been reached yet;
		- c) a block has been offered in message `validatorSession.message.voteFormessage` by our validator with priority if the current attempt for now is the first or the maximum number of taken attempts has been already exceeded (unlike case (b) shown above).
			* Actions: this message must be generated if there are none pre-fixed block during the current attempt and one of our validator voting cases are still running.
	+ '*validatorSession.message.precommit* - this message refers to the stage of all voting attempts. This message is sent by each validator to notify that the validator has now been selected for a voted block as a precommit block. This pre-fixed block must be voted for and get by 2/3 of the total needed weight of the validators' votes. Please note that for some reason consensus ignores the case where a pre-fixed node block is not equal no more to the candidate block for that certain round, and only outputs a warning in the log about such a case type. The message then has the following structure:
		- `round`: `int` - round # number;
		- `try`: `int` - number of the taken attempts at which our validator selected the candidate block as the block for pre-commit;
		- `candidate`: `int256` - hash of the candidates block.
			* Action: This message must be generated only if all of the following conditions are reached:
		- a) The node itself did not send message `validatorSession.message.precommit` in this attempt;
		- b) there is a block with 2/3 of the total needed weight of validator votes.
	+ '*validatorSession.message.commit* - the message refers to the block commit stage. This message informs us that the validator has sucessfuly signed the block candidate as a block to be committed for the round. The message has the following structure:
		- `round`: `int` - round # number
		- `candidate`: `int256` - hash of our candidate block;
		- `signature`: `bytes` - validator signature.
	+ '*validatorSession.message.empty* is a special recieved message which is used as a token to stop message generation during synchronization process from internal validator state to a new list of additional messages which will be sent to all other validators. This message has the following structure:
		- `round`: `int` is round number in which the synchronisation did occur;
		- `attempt`: `int` - count nubmer of the attempted synchronization.
			* Actions: this message must be generated only to indicate that there are not any additional messages for sync status (in its attempt and round).
* b. '*validatorSession.blockUpdate* is the root message to update validator session blocks. It is getting packaged in catchain.block.data.vector. The message gets created after each consensus iteration period and has this following structure:
	+ `ts`: `long` - block gets update generation time stamp (unix time, global);
	+ `actions`: `vector validatorSession.round.Message` - list
	+ `validatorSession.round.Message` with essential incremental updates to synchronize this consensus state on other validators;
	+ `state`: `int` - status hash after each action is applied; used as checksum for status checks (being calculated recursively for status session; not trivial linear buffer hash with actions).
* c. '*validatorSession.candidate* - this message is sent to Catchain as a mailing when a new candidate block does appear (after validator making callback `on_generate_slot`). Secondly it can also be sent at the start of Catchain execution on each validator for all our blocks whenapproved by that validator as Catchain candidates (from validator side `get_blocks_approved_by` and `get_approved_candidate`). In this message initiates block approvals if they get received in a mailing and has this following structure:
	+ `src:` `int256` - the validator that had generated the block candidate;
	+ `round:` `int` - round number in which the block candidate did appear;
	+ `root_hash:` `int256` - The root hash of the candidate block;
	+ `data:` `bytes` - candidate block size data;
	+ `collated_data:` `bytes` - mapped candidate block size data.

4. Enquiries:

* а. '*validatorSession.downloadCandidate* - this message is used for to request a candidate block of a round with a specific ID identifier. If the validator does not have this candidate block for further consensus processing, it generates one by self.
	+ Request:
		- `round`: `int` is the round number in which the block candidate will appear;
		- `id`: `validatorSession.candidateId` - candidate block ID identifier.
	+ Other useful actions:
		- `validatorSession.candidate` - This candidate block is sent as an event when processing the request is taken.

## Catchain component

### Catchain Overview

Catchain is a communication protocol between all validators. It does not execute the consensus algorithm by itself, but it prepares for it all needed data to make decisions for the higher-level component: the *validator session*.

The main tasks of the catchain is to:

* setting up a network overlay on top of the ADNL helps to enable communication between all validators;
* setting up and updating a list of all neighboring nodes for direct communication within this overlay;
* receiving blocks from all of other validators and sending back as decisions from the current validator;
* dependencies of controlling block;
* managing the internal database containing data of the current catchain session results;
* restoring the catchain session state after a validator launches restart;
* detecting any forks and validators ID that created them;
* maintenance of the consensus algorithm.

Generaly speaking, the catchain component does provide a framework for needed consensus elements of a validator session.

### Catchain node initialization

The Catchain session does begin with creating message `CatchainImpl` and `CatChainReceiverImpl` objects. `CatChainReceiverImpl` helps to configure the ADNL overlay, communicating with all other validators.

The next step is taken to retrieve `CatChainReceiverImpl` previously retrieved blocks from our RocksDB database instance (check `CatChainReceiverImpl::read_db_from` and `CatChainReceiverImpl::read_block_from_db` for more details).

There is always a certan block with hash = 0 at the top, acting itself as a starter block for loading predecessor blocks and dependencies. These central processing cycles are getting triggered after the database read phase is fully complete (see this `CatChainImpl::on_receiver_started` and `CatChainImpl::send_process` for more details). This consensus algorithm initiates the generation of newly created block candidates for their further approval - a block is sent to the message chain when a new unknown candidate appears. If there are no blocks in system, the validator waits for new blocks from other validators in the chain.

### Scheduled actions

Each validator sends its output to only when a few neighbours (currently have 5) are minimizing traffic. Neighbours are changed randomly per every 60-120 seconds. Every 2-3 seconds the system does randomly select a validator from a common list of validators to synchronise. This synchronisation is bidirectional:

* Our initiating validator sends a list containing the height of the blocks that are delivered (including all vector timestamps, according to "Catchain Consensus: Outline"). The validator expects to receive back either missing blocks or at least notification of a fork event in response. If a fork is sucessfuly confirmed, the consensus blames the validator and rejects all messages. Only our current validator can verify the presence of the fork. The validator does compare its own list of block heights he owns with the received list and sends the difference, if there are any, to the requestor. This process does optimise network traffic and reduces the average block height delivery, limiting the number of outgoing reply messages to 100 symbols.
* The initiator validator requests delivery of all missing dependent blocks generated by our responder validator.
* Call iteration of the consensus algorithm (as described below). Each synchronisation adds new information about the states of the other validators, making the next consensus iteration of the validator more possible.

### Handling blocks

There are several types of blocks used in catchain:

* blocks written to our blockchain;
* catchain blocks with the status of a particular validator message (`CatchainReceivedBlock`). These are messages with validator id identification, agreed on algorithm iteration number (its height) and consensus increment messages used; `CatchainReceivedBlock` are temporary sources for creating consensus blocks (Catchain Blocks);
* `CatchainBlock` blocks are built from multiple `CatchainReceivedBlock` blocks (Catchain Block consists of plenty states of CatchainReceivedBlocks with a maximum known height for them by the validator).

The `CatchainReceivedBlock` consists of:

* catchain session ID identifier (to exclude chance to case of processing blocks from a previous catchain session);
* block origin validator # number;
* block height (equal to the consensus algorithm iteration number used for a particular validator);
* fork number (if there is more than one fork detected from the same validator, the block chain then becomes invalid)
* previous block that's sent to any other validators (called outgoing block);
* Dependent blocks received by any other validators (called incoming blocks); note that an incoming block can not depend on these two blocks from the same validator source; in general it is called DAG.

The dependent block graph allows us to:

* recursively load all of blocks needed to augment the status of the block being clearly processed;
* recursively mark block subgraphs as an invalid if forks from a particular source validator are being detected.

Each validator does contain a list of the states of the other connected validators. Each of them stores these blocks `CatchainReceivedBlock` that have come from them. Each new one that is incoming `CatchainReceivedBlock` is validated regardless of which data channel it did came from (directly from the validator or in transitive way, see message `CatChainReceiverImpl::validate_block_sync`). If the block signature still does not match the expected signature of the sender validator or if the block is invalid, the block then gets ignored.

The validator checks each catchain validator for any posible forks. Only one fork per validator here is allowed. In case the same validator sends two different blocks of the same height, it gets marked as accused and all `CatChainReceivedBlockImpl` corresponding to that validator now becomes invalid. The validator itself gets ignored until the end of the current catchain session cycle.

After receiving a block `CatChainReceivedBlockImpl`, then its processing begins fully (see here `CatChainReceiverImpl::receive_block`). It is then written to our database table. The processing procedure loads everything that is now needed for the block and then adds the block to the waiting queue of blocks so they are ready get ran. This loading procedure gets performed every upcoming next 2-3 seconds by synchronizing with other validators that are also getting quered for missing blocks `CatChainReceivedBlockImpl`.

When any data updates starts getting received (from its database at initialization, when new blocks are starting to get received and when new blocks are more likley added after consensus algorithm work (see `CatChainImpl::processing_block`) the block execution procedure then starts fully  `CatChainReceivedBlockImpl`.

Each validator does contain of state lists for all other validators. Each one now holds `CatchainReceivedBlock` blocks received from the other validators. Each new incoming one `CatchainReceivedBlock` is validated regardlesly of which data channel source it did come from (if it came directly from our validator or transitively, see `CatChainReceiverImpl::validate_block_sync`). Then validator ignores this certain block if the block signature is not matching the expected one signature of the message sender validator or if the block simply shows as invalid one.

The active validator checks for any posible forks. Only one fork per validator here can allowed too. If same validator does send two different blocks of the same height, it is now marked as invalid and all previous blocks `CatChainReceivedBlockImpl` matching same validator become invalid. The consensus mechanism then gets ignored by the validator by itself until the end of the current catchain session cycle.

Recieving block CatChainReceivedBlockImpl initiates processing (see CatChainReceiverImpl::receive\_block) and creates an new entry in the database. The processing procedure loads all its dependents for the block. In the next step, it does add the block to the queue of blocks for getting ready to run. The loading procedure gets performed in every 2-3 second cycle by synchronising with other validators that are required to provide missing blocks CatChainReceivedBlockImpl.

The whole `CatChainReceivedBlockImpl` calculation procedure is initiated whenever any data updates are getting received (from our database during initialization, when new blocks are geting received and when new blocks are added after the consensus algorithm is finaly running (see `CatChainImpl::processing_block`) and includes:

* creating a fork from an already existing previous block (in this case the authoring procedure can be initialised if the fork does already exist);
* preliminary block processing procedures (pre\_deliver);
* processing of our block.

Pre-processing does `CatChainReceivedBlockImpl` include checking all forks (see `CatChainReceivedBlockImpl::pre_deliver`).

Block processing (see `CatChainReceivedBlockImpl::deliver`) includes the following info:

* deliver\_block - notification that the block is now ready for his validator. This notification consists of:
	+ notifying rest of all neighbours of a new block `CatChainReceivedBlockImpl`;
	+ creating a new CatchainBlock and placing it right at the top of the chain from the validator that had sent the corresponding CatChainReceivedBlockImpl. The CatchainBlock used in the consensus algorithm is like a copy (snapshot) of the corresponding CatChainReceivedBlockImpl, except for the main data that is used for the dependency loading process;

dep\_delivered - notification of all CatChainReceivedBlockImpl dependencies (outgoing dependency). This places all dependents in the queue of blocks for waiting to be ready to run;

* block\_delivered - updating internal data about sent blocks info by the initiator validator (mark as sender of CatchainReceivedBlockImpl).

The `CatchainBlock` blocks that were received from the validator are the input to the consensus algorithm. Structurally, this block is realy similar to the `CatChainReceivedBlockImpl` mentioned block. However, it does contain all the data tthat is required for further processing (unlike CatChainReceivedBlockImpl, where some data may get lost and missing). Catchain stores a list of top blocks here `CatchainBlock` - one for each validator - and periodically runs them in the consensus algorithm on a timer - at start and by request (see `CatChainImpl::send_process)` for more details. This consensus iteration identification for each validator is the mesured height of the block created by the consensus algorithm. Thus like a pair (validator number, block height) uniquely identifies the block for our particular validator.

Processing for the consensus results from one validator to another validator can now result in two different blocks with the same set of height and validator numbers. This will surley result in a fork, and the identity ID key will expand to (`validator number, block height, its fork number`). No metter, since catchain does not allow any forks, the validator of the source from which the branched block has been created will be caught here. Thus, the fork number now can be skipped and the CatchainBlock from now can be identified using only this `validator number and block height`.

The consensus iteration here starts by selecting a random count of subset from the list of top blocks `CatchainBlock` (not more than max\_dept = 4) and passing them trough to the consensus algorithm thats described above (see message `ValidatorSessionImpl:: process_blocks`). Note that each type of such block is sent by a separate validator, and there can not be two same blocks from a single validator. These blocks are geting combined as part of the consensus algorithm, and then a new CatchainBlock appears based on them. Catchain reports the whole appearance of this block (see `CatchainImpl::loaded_block`). Adding a new block may cause it to be written to the database and a block `CatChainReceivedBlockImpl` that is created from it, which is then sent right away to its neighbours.

### Catchain protocol messages and its structures

The Catchain protocol consists of:

* an incoming event `catchain.blockUpdate`;
* mandatory outgoing requests `catchain.getBlock` and `catchain.getDifference`;
* optional outbound requests (is not used in the catchain component as itself, but can be sent from outside as message): `catchain.getBlocks`, `catchain.getBlockHistory`;
* query responses: `catchain.BlockResult`, `catchain.Sent`, `catchain.Difference`;
* internal structures - those can be used in all of the above mentioned events and queries.

* the validator periodically and randomly gets updates the list of all neighbouring validators (see for description above);
* the validator periodically selects one validator at random chance from the list of neighbouring validators (see for description above) and does send it:
	+ request `catchain.getDifference` with a full list of block heights that are already delivered to the validator-requirer;
	+ `catchain.getBlock` - request for top block dependencies (mesured by height) which are received but not geting fully resolved (not all dependencies are geting accepted by validator); validator can randomly select up to 16 dependencies for top block and sends a request message `catchain.getBlock` for each one of them.

2. the validator processes synchronisation of events:

* The validator accepts incoming message `catchain.blockUpdate` about events and updates the internal block data structures.

3. the validator processes the occurring list of forks:

* The validator receives an incoming message `catchain.differenceFork` about event, checks it for a fork and marks the validator of the counterparty that had sent the fork as its accused. All collected data from this validator will be discarded. In addition same happens to a block of the same height received from this validator (the fork block) will be marked as "bad" one, as will all blocks in future dependent on it.

4. iteration of matching

* Each one *catchain.blockUpdate* can lead it to a solution in which one or more catchain blocks over the opposite side of validators are fully resolved (this means that there will be colected enough data in those blocks, including dependencies, to use them in the consensus calculation)
* The validator randomly selects up to the top of CatChainOptions::max\_deps blocks (equals to 4 at this moment) from the various counterparty validators and sends them back to the validator session component for its further processing;
* the validator session component does merge such dependencies and receives in new kind of merged state;
* According to the new state form, the validator session component does generate incremental messages that later convert the pre-merge state (previous block) to the post-merge state (new kind of block). This message packet can be found in the Catchain structure `catchain.block.data.vector` and is mainly used as the data of the new Catchain block: the height size of the catchain block is equal to the iteration index, incrementing successively after each following iteration of the consensus;
* The new Catchain block is geting stored on the current validator without being immediately sent back to other validators, so that the third-party validators must query the current validator to manage to update the blocks using the `catchain.getDifference` query to get the right calculated blocks amount (pull-up model).

### Internal structures

1. `catchain.block.dep`
This structure provides all information about the dependent block. This dependent block is always derived from another validator and has the structure as described below. Note that all this structure does not contain any information about the block data, it can be seen only a description of it.

* `src` : `int` - The index of the validator who generated the block;
* `height` : `int` - height of the block of our validator with the src index;
* `data_hash` : `int256` - block data hash; it is used in block prefetching;
* `signature` : `bytes` - validator signature ID with block src index; it is needed for preliminary block validation.

2. `catchain.block.data`
This structure will describe the block with all references to the previous block on the validator and all of the dependent blocks that used to generate the current one. For its specified (`src`, `height`) there can only be set one previous block in the Catchain. If any forks are detected, the validator that did send the second candidate block for the specified (`src`, `height`) is now marked as accused and all its data will be discarded. The `catchain.block.data` structure is described as below:

* `prev` : `catchain.block.dep` - description of its previous block;
* `deps` : `vector of catchain.block.dep` - list of all dependent blocks that used to generate this block.

3. `catchain.block`.

This structure does describe a block with a payload.

* `incarnation` : `int256` - Catchain session ID identification, is equal to the hash of the first block used when starting new Catchain session;
* `src` : `int` - Index of the validator which did generate the block;
* `height` : `int` - The height set of the block on the validator with the src index in it;
* `data` : `catchain.block.data` - block header with all info about the previous block and dependent blocks that were used to generate the current block.

4. `catchain.block.inner.data`

This is a view of structure with one of the following subtypes: `catchain.block.data.badBlock`, `catchain.block.data.fork`, `catchain.block.data.nop`, `catchain.block.data.vector`. This structure gets placed immediately after the `catchain.block` structure and contains the corresponding useful data about block.

* `catchain.block.data.vector` - This message here contains the data of the internal validator session component, represented for it as a list of messages specific to it. The message for `catchain.block.data.vector` structure is used as placed container for distributing consensus algorithm data between all validators.
	+ `msgs` : `vector of bytes` - Internal validator session colected data (it is used as a byte buffer for its Catchain component).
* `catchain.block.data.fork` - this message does contain a fork proof for the specified chosen block pair. When there are two blocks with different hashes but the same height are received from a validator with `src`, then it means that a fork is detected. In this case, the validator now is in question for fault and all data quality coming from it, as well as all previous blocks depending on the detected fork, must be discarded for instance.
	+ `left` : `catchain.block.Dep` - is first known block;
	+ `right` : `catchain.block.Dep` - for detected fork block.
* `catchain.block.data.badBlock` - It is reserved and not currently in use.
* `catchain.block.data.nop` - It is rserved and not currently in use.

Events:

1. `catchain.blockUpdate`.

This event informs our validator that a particular block now has been updated. The validator must then add it to the processing queue list, check for forks and for all upstream and downstream block dependencies. Dependency checks may somehow result in one or more block status upcoming updates. The block can then be used as a source of info to calculate state in the next consensus iteration. A validator session iteration uses a totaly random subset of fully validated blocks (those are blocks whose dependencies are all received and geting pre-validated by the current validator). This subset contains only blocks from different validators to further merge them and create a new Catchain block according to the newly resulting merge state. `catchain.blockUpdate` it has the following structure:

* `block: catchain.block` - block full description with `catchain.block.inner.Data`.
* `signature` : `bytes` - block signature geting executed by validator (with validator index `block.src`); used for preliminary block validation process.

Queries:

1. `catchain.getBlock` (it is mandatory)

This query is used by the Catchain component to request a search to get missing block from another validator.

* query:
	+ `block` : `int256` - shows hash of the requested block;
* response - `catchain.BlockResult` (variant):
	+ `catchain.blockResult` - sent if block is found anywhere
		- `block` : catchain.block - description of requested block with its `catchain.block.inner.Data`
	+ `catchain.blockNotFound` - sent if block is not found

2. `catchain.getBlocks` (optional; it is not used by the Catchain component internally)

This request is used to make a request for multiple blocks from another validator.

* query:
	+ `block` : `int256` - it shows hash of the requested block;
* response - `catchain.sent` :
	+ `cnt` : `int` - gives a number of returned blocks.
* Side effect of it:
	+ multiple `catchain.blockUpdate` events will be sent back to the requestor validator before its responding.

3. `catchain.getDifference` (mandatory)

This is the initial type request sent from one of validators to another one to get the missing blocks back. The initiating validator sends a list of delivered blocks (its levels) and expects to receive in return the blocks that have not been delivered before (its difference). Initially, the requestor validator may send even a list of zero levels to initiate block synchronisation. In addition for it, the `catchain.getDifference` request should be regularly sent to its neighbouring validators to synchronise with them.

* query:
	+ `rt` : `vector int` - the list of block elevations is already delivered to the validator-requirer.
* response - catchain.difference:
	+ catchain.difference - sent when none forks are geting detected (normal case)
		- `sent_upto` : `vector int` - vector of levels known to the validator-reply; not currently being used in the Catchain component;
	+ `catchain.differenceFork` - sent when any fork is detected
		- `left` : `catchain.block.dep` - for first known block;
		- `right` : `catchain.block.dep` - if detected fork block.
* other effect:
	+ multiple `catchain.blockUpdate` events are geting sent back to the requestor validator before having `catchain.difference` response.

4. `catchain.getBlockHistory` (it is optional, and is not used by the Catchain component internally)

This request mostly is used to get the blocks that are used to create a block with the specified inverse height (find out the number of blocks inverse of the specified block).

* query:
	+ `block` : `int256` - stands for hash of the target block;
	+ `height` : `long` - shows number of predecessor blocks of our target block;
	+ `stop_if` : `vector int256` - hash list of blocks whose search must be stoped if one of them is found out during history processing.
* response - `catchain.sent` :
	+ `cnt` : `int` - number of blocks returned back.

## Links

1. Walk through the Catchain
2. Catchain Consensus: An Outline. By Nikolai Durov. 2020