Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement multi-hop routing of consensus messages #472

Merged
merged 44 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
cc46805
Add multi-hop routing implementation. This has some basic unit tests,…
swatanabe Jul 20, 2023
b5163db
Support local sockets for outgoing p2p connections
swatanabe Jul 25, 2023
40cd347
Handle absolute-form request targets
swatanabe Jul 25, 2023
9b131e1
Add unix socket support for psibase
swatanabe Jul 25, 2023
6f4f39e
Add queries to expose all the consensus state
swatanabe Jul 27, 2023
7a1941f
Make sure that match_index is set up when building a block that sets …
swatanabe Jul 27, 2023
4ed7da6
Use shortest_path_routing in psinode
swatanabe Jul 27, 2023
fae8455
Add initial psinode integration test
swatanabe Jul 27, 2023
eea3ae8
Add test for changing routes
swatanabe Jul 28, 2023
81fc74a
Fix test failures
swatanabe Jul 28, 2023
ea57fd5
Restrict routing to active producers. Prevents blowing up the routing…
swatanabe Jul 28, 2023
01591d4
Fix test program name
swatanabe Jul 31, 2023
3c5a50c
Update docker images
swatanabe Jul 31, 2023
4d7cc39
Temporarily switch to image-builder PR merge commit
swatanabe Jul 31, 2023
6099c9d
Fix typo
swatanabe Jul 31, 2023
d0eee6d
Update clang paths
swatanabe Jul 31, 2023
a896096
Ensure that log file is closed
swatanabe Jul 31, 2023
56f107c
Increase log level
swatanabe Jul 31, 2023
de742a2
Fix use-after-free when disconnect removes the last feasible route
swatanabe Jul 31, 2023
285e61c
Fix uninitialized variable
swatanabe Jul 31, 2023
6c6213b
Some refactoring of tests
swatanabe Aug 1, 2023
06675f8
Set --database-cache-size
swatanabe Aug 1, 2023
1944989
Add test for routing with BFT
swatanabe Aug 4, 2023
a211c34
When we rate-limit seqno requests, delay rather than dropping the mos…
swatanabe Aug 4, 2023
e17ada8
Delay consensus messages until we're sure that the peer has the block
swatanabe Aug 8, 2023
c68e957
Fix compile error
swatanabe Aug 8, 2023
5f828dc
Rework consensus to ensure convergence
swatanabe Aug 18, 2023
2e35749
Fix compilation
swatanabe Aug 18, 2023
6ecfd66
Restrict prepares and commits
swatanabe Aug 18, 2023
f688897
Improve log messages on consensus change
swatanabe Aug 18, 2023
2bc6815
Merge remote-tracking branch 'origin/main' into routing
swatanabe Aug 18, 2023
b0f26da
Fix compile error on old gcc
swatanabe Aug 18, 2023
5ed7ebf
Another instance of duration streaming
swatanabe Aug 21, 2023
1400ae3
Merge remote-tracking branch 'origin/main' into routing
swatanabe Aug 21, 2023
5c9b63a
Fix uninitialized variable
swatanabe Aug 21, 2023
d792e37
Include joint producers when searching for the best view change
swatanabe Aug 21, 2023
a19d25f
Fix another io_context halt
swatanabe Aug 21, 2023
436f2c9
Update consensus docs
swatanabe Aug 21, 2023
887003e
Bad timing can cause the tests to fail. Account for this by ignoring …
swatanabe Aug 22, 2023
21e810c
Fix close on timeout. We should not depend on the client closing thei…
swatanabe Aug 25, 2023
1eba2b2
Merge branch 'main' into routing
swatanabe Aug 25, 2023
76c3192
Add tests with stopping and restarting nodes
swatanabe Aug 29, 2023
55ed56f
Fix cmake
swatanabe Aug 29, 2023
91864be
Implement new conditions on prepare and commit
swatanabe Aug 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ubuntu-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ jobs:
fail-fast: false
matrix:
include:
- builder-image: "ghcr.io/${{ github.repository_owner }}/psibase-builder-ubuntu-2004:b2a46a609b12f645aaeb03245afd0e3d2bf75340"
- builder-image: "ghcr.io/${{ github.repository_owner }}/psibase-builder-ubuntu-2004:efa3d81568eb2d4cdc3b3d8a343dd26de0fcba6c"
ubuntu-version: "2004"
- builder-image: "ghcr.io/${{ github.repository_owner }}/psibase-builder-ubuntu-2204:7e3c6e5739df95ba33943789d2cdf5472f91111a"
- builder-image: "ghcr.io/${{ github.repository_owner }}/psibase-builder-ubuntu-2204:efa3d81568eb2d4cdc3b3d8a343dd26de0fcba6c"
ubuntu-version: "2204"
steps:
- name: Timestamp
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ vite.config.ts.timestamp-*.mjs
psibase.127.0.0.1.sslip.io*.pem
psinode_db
psinode_db_secure
__pycache__
60 changes: 53 additions & 7 deletions doc/psidk/src/consensus.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@
- [CFT](#cft)
- [BFT](#bft)
- [Joint Consensus](#joint-consensus)
- [Special Cases](#special-cases)

## Overview

The blockchain forms a replicated state machine. Each block contains a cryptographic hash identifying the previous block and a bundle of transactions that can be applied to the chain state to create a new state. Block execution is strictly deterministic. Applying the same sequence of blocks to the same initial state will always result in the same final state. The process of consensus ensures that nodes agree on the sequence of blocks to apply, and thus agree on the state of the chain.

New blocks are created by block producers designated in the chain state. After a block producer creates a block, the block is distributed to all other block producers which then agree to make the block irreversible. If there are conflicts, then the consensus algorithm will resolve them. Each consensus algorithm has its own constraints on the behavior of block producers. As long as these constraints are met, the consensus algorithm guarantees safety:
- Only one fork can ever become irreversible
- If two blocks are irreversible, one must be a descendant of the other
- An irreversible block cannot be forked out

All of these formulations are equivalent.

## CFT

Expand Down Expand Up @@ -57,24 +69,53 @@ BFT consensus has the following properties:

### Block Production

Blocks are produced by the leader. Leader selection is round-robin. The producer should build off a chain that includes the best block that has been prepared by 2f+1 producers.
Blocks are produced by the leader. Leader selection is round-robin.

### Irreversibility

- Blocks are ordered first by term, then by block height.
- Blocks go through two rounds of confirmation, prepare and commit. Each producer broadcasts its confirmations to all other producer nodes.
- A producer can only commit a block that has been prepared by 2f+1 producers.
- If a producer commits a block A, it can only prepare a conflicting block B that is better than A if at least 2f+1 nodes have already prepared an ancestor of B that is better than A.
- A block is considered irreversible if it has been committed by 2f+1 nodes.

Block producers must obey these restrictions:
1. A producer shall only commit a block that has been prepared by 2f+1 producers.
2. A producer shall not prepare or commit conflicting blocks in the same term
3. A view change for view N names a block from any prior view that has been prepared by 2f+1 producers. This block must not be worse than any block that the producer has committed in any view before N.
4. The first block of a term must be a descendant of a block which is the best block referenced by 2f+1 view changes from different producers, and is referenced by the leader's best view change. The leader MAY issue more than one view change and MUST issue a second view change if its original view change refers to a block that is too old.

### View Change

Each producer maintains a view change timer to detect failure in the leader. The view change timer is restarted whenever irreversibility advances. When the view change timer expires, a producer broadcasts a `view_change_message` to all other producers and increments the current term, moving to the next leader.

- After initiating a view change, a producer will not restart the view change timer until it sees 2f+1 view change messages.
- Consecutive view changes during which the chain does not make progress, cause the view change timeout to increase by a flat amount for each view change after the first.
- After initiating a view change, a producer will not restart the view change timer until it sees 2f+1 block producers are in the same term or later.
- Consecutive view changes during which the chain does not make progress, cause the view change timeout to increase.
- A view change will trigger immediately if the leader of the current term or at least f+1 other producers are in a later term. This view change is independent of the view change timer and may skip terms.

View change messages are broadcast network-wide. Every node retains the best view change from each active producer and broadcasts it to its peers whenever it receives a better one. When a node changes its view of active producers, it requests the current list of view change messages from all its peers.

The ordering of view change messages from a single node is defined as follows:
- A higher term is always better than a lower term
- The ordering of view changes with the same term depends on whether the node that issued the view change is the leader.
- If the source is not the leader, a view change is better if it refers to an older block
- If the source is the leader, a view change is better if it refers to a newer block

Note: Since the condition for activating a view requires the leader's view change to refer to a block which not older than other nodes' view changes, this ordering guarantees that as long as a valid set of view changes exist, all connected, honest nodes will converge to the same valid set.

### Safety

Let block X and block Y be two conflicting blocks which are both irreversible
- Without loss of generality, let X be better than Y
- Y has been committed by 2f+1 producers, because that is the requirement for it to be considered irreversible
- let Z be the earliest block that is an ancestor of X (inclusive of X), conflicts with Y, is better than Y, and is prepared by 2f+1 producers. Such a block is guaranteed to exist because X itself must be prepared by 2f+1 producers in order to be committed by any honest producer.

The existence of Z implies that at least f+1 producers have violated the protocol
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't the existence of X and Y already imply that at least f+1 producers have violated the protocol?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does. This list is the breakdown of exactly how they violated the protocol.

- If Z and Y have the same term then at least f+1 producers have violated rule 2
- Y does not have a higher term than Z because Z is better than Y
- If Z is in a higher term than Y, then there is a valid view change set for the term of Z
- Let W be the block named by the leader's view change
- If W is worse than Y, then at least f+1 producers have violated rule 3
- Otherwise, W is in a lower term than Z and is prepared by 2f+1 producers (by the definition of a view change) and conflicts with Y and is better than Y (otherwise X would be a descendant of Y), which contradicts the definition of Z.

### Messages

`BlockMessage`
Expand All @@ -92,12 +133,17 @@ The leader is selected from any of the old or new producers. Leader elections an

### CFT → BFT

The leader is selected by election from the old producers. Irreversibility requires a majority of the old producers and a quorum of the new producers. Leader election requires a majority of the old producers and a quorum of the new producers.
The leader is selected by election from the old producers. Irreversibility requires a majority of the old producers and a quorum of the new producers. Leader election requires a majority of the old producers and a quorum of the new producers. The new producers cannot advance the current term.

### BFT → CFT

The leader is selected from the old producers. The new producers commit, but do not prepare blocks. Commit require prepares by a quorum of the old producers. Irreversibility requires commits from a quorum of the old producers and a majority of the new producers.

### BFT → BFT

The leader is selected from the old producers. Committing a block and advancing irreversibility require quorums of both the old and the new producers. Switching forks after a commit is permitted if a quorum of either the old or the new producers have prepared the new fork.
The leader is selected from the old producers. Activating a view, committing a block, and advancing irreversibility all require quorums of both the old and the new producers. View change auto triggers if f+1 of the old producers are ahead of the current term.

## Special Cases

- Blocks with a single producer are immediately irreversible. This is a degenerate case for both algorithms and they behave identically.
- The genesis block is immediately irreversible. There is nothing to preserve pre-genesis.
Loading