# Consensus

To understand how the consensus smart contract works and how anonymous
staking and unstaking is achieved, read the following chapters:

* [Genesis stake](consensus/genesis_stake.md)
* [Stake](consensus/stake.md)
* [Proposal](consensus/proposal.md)
* [Unstake request](consensus/unstake_request.md)
* [Unstake](consensus/unstake.md)

This section of the book describes how nodes participating in the DarkFi
blockchain achieve consensus.

## Glossary

| Name                   | Description                                                                               |
|------------------------|-------------------------------------------------------------------------------------------|
| Consensus              | Algorithm for reaching blockchain consensus between participating nodes                   |
| Node                   | DarkFi daemon participating in the network                                                |
| Slot                   | Specified timeframe for block production, measured in seconds (default=90)                |
| Epoch                  | Specified timeframe for blockchain events, measured in slots (default=10)                 |
| Leader                 | Block producer                                                                            |
| Unproposed Transaction | Transaction that exists in the memory pool but has not yet been included in a block       |
| Block proposal         | Block that has not yet been appended onto the canonical blockchain                        |
| P2P network            | Peer-to-peer network on which Nodes communicate with each other                            |
| Finalization           | State achieved when a block and its contents are appended to the canonical blockchain     |
| Fork                   | Chain of block proposals that begins with the last block of the canonical blockchain      |

## Node main loop

As described in previous chapter, DarkFi is based on Ouroboros
Crypsinous. Therefore, block production involves the following steps:

At the start of every slot, each node runs the leader selection algorithm
to determine if they are the slot's leader. If successful, they can
produce a block containing unproposed transactions. This block is then
appended to the largest known fork and shared with rest of the nodes on
the P2P network as a block proposal.

Before the end of every slot each node triggers a _finalization check_,
to verify which block proposals can be finalized onto the canonical
blockchain. This is also known as the finalization sync period.

Pseudocode:
```
loop {
    wait_for_next_slot_start()

    if is_slot_leader() {
        block = propose_block()
        p2p.broadcast_block(block)
    }

    wait_for_slot_end()

    chain_finalization()
}
```

## Listening for blocks

Each node listens to new block proposals concurrently with the main
loop. Upon receiving block proposals, nodes try to extend the proposals
onto a fork that they hold in memory. This process is described in the
next section.

## Fork extension

Since there can be more than one slot leader, each node holds a set of
known forks in memory.  When a node becomes a leader, they extend the
longest fork they hold. 

Upon receiving a block, one of the following cases may occur:

| Description                               | Handling                                                            |
|-------------------------------------------|---------------------------------------------------------------------|
| Block extends a known fork at its end     | Append block to fork                                                |
| Block extends a known fork not at its end | Create a new fork up to the extended block and append the new block |
| Block extends canonical blockchain        | Create a new fork containing the new block                          |
| Block doesn't extend any known chain      | Ignore block                                                        |

### Visual Examples

| Symbol        | Description                            |
|---------------|----------------------------------------|
| [C]           | Canonical(finalized) blockchain block  |
| [C]--...--[C] | Sequence of canonical blocks           |
| [Ln]          | Proposal produced by Leader n          |
| Fn            | Fork name to identify them in examples |
| +--           | Appending a block to fork              |
| /--           | Dropped fork                           |

Starting state:

                   |--[L0] <-- F0
    [C]--...--[C]--|
                   |--[L1] <-- F1

#### Case 1

Extending F0 fork with a new block proposal:

                   |--[L0]+--[L2] <-- F0
    [C]--...--[C]--|
                   |--[L1]        <-- F1

#### Case 2

Extending F0 fork at [L0] slot with a new block proposal, creating a new fork chain:

                   |--[L0]--[L2]   <-- F0
    [C]--...--[C]--|
                   |--[L1]         <-- F1
                   |
                   |+--[L0]+--[L3] <-- F2

##### Case 3

Extending the canonical blockchain with a new block proposal:

                   |--[L0]--[L2] <-- F0
    [C]--...--[C]--|
                   |--[L1]       <-- F1
                   |
                   |--[L0]--[L3] <-- F2
                   |
                   |+--[L4]      <-- F3


## Finalization

When the finalization sync period kicks in, each node looks up the longest
fork chain it holds. There must be no other fork chain with same length.
If such a fork chain exists, nodes finalize all block proposals by appending them
to the canonical blockchain.

Once finalized, all fork chains are removed from the memory pool.
Practically this means that no finalization can occur while there are
competing fork chains of the same length. In such a case, finalization
can only occur when we have a slot with a single leader.

We continue Case 3 from the previous section to visualize this logic.
On slot 5, a node observes 2 proposals. One extends the F0 fork,
and the other extends the F2 fork:

                   |--[L0]--[L2]+--[L5a] <-- F0
    [C]--...--[C]--|
                   |--[L1]               <-- F1
                   |
                   |--[L0]--[L3]+--[L5b] <-- F2
                   |
                   |--[L4]               <-- F3

Since we have two competing fork chains finalization cannot occur.

On next slot, a node only observes 1 proposal. So it extends the
F2 fork:

                   |--[L0]--[L2]--[L5a]        <-- F0
    [C]--...--[C]--|
                   |--[L1]                     <-- F1
                   |
                   |--[L0]--[L3]--[L5b]+--[L6] <-- F2
                   |
                   |--[L4]                     <-- F3

When the finalization sync period starts, the node finalizes fork
F2 and all other forks get dropped:

                   |/--[L0]--[L2]--[L5a]      <-- F0
    [C]--...--[C]--|
                   |/--[L1]                   <-- F1
                   |
                   |--[L0]--[L3]--[L5b]--[L6] <-- F2
                   |
                   |/--[L4]                   <-- F3

The canonical blockchain now contains blocks L0, L3, L5b and L6 from fork F2.

