This repo contains Go implementation of the dBFT 2.0 consensus algorithm and its models written in TLA⁺ language.
- All control flow is done in main
dbft
package. Most of the code which communicates with external world (event time events) is hidden behind interfaces, callbacks and generic parameters. As a consequence it is highly flexible and extendable. Description of config options can be found inconfig.go
. dbft
package containsPrivateKey
/PublicKey
interfaces which permits usage of one's own cryptography for signing blocks onCommit
stage. Refer toidentity.go
forPrivateKey
/PublicKey
description. No default implementation is provided.dbft
package containsHash
interface which permits usage of one's own hash implementation without additional overhead on conversions. Instantiate dBFT with custom hash implementation that matches requirements specified in the corresponding documentation. Refer toidentity.go
forHash
description. No default implementation is provided.dbft
package containsBlock
andTransaction
abstractions located at theblock.go
andtransaction.go
files. Every block must be able to be signed and verified as well as implement getters for main fields.Transaction
is an entity which can be hashed. Two entities having equal hashes are considered equal. No default implementation is provided.dbft
contains generic interfaces for payloads. No default implementation is provided.dbft
contains genericTimer
interface for time-related operations.timer
package contains defaultTimer
provider that can safely be used in production code. The interface itself is mostly created for tests dealing with dBFT's time-dependant behaviour.internal
contains an example of custom identity types and payloads implementation used to implement an example of dBFT's usage with 6-node consensus. Refer tointernal
subpackages for type-specific dBFT implementation and tests. Refer tointernal/simulation
for an example of dBFT library usage.formal-models
contains the set of dBFT's models written in TLA⁺ language and instructions on how to run and check them. Please, refer to the README for more details.
A client of the library must implement its own event loop. The library provides 5 callbacks that change the state of the consensus process:
Start()
which initializes internal dBFT structuresReset()
which reinitializes the consensus processOnTransaction()
which must be called everytime new transaction appearsOnReceive()
which must be called everytime new payload is receivedOnTimer()
which must be called everytime timer fires
A minimal example can be found in internal/simulation/main.go
.
- dBFT high-level description on NEO website https://docs.neo.org/docs/en-us/basic/consensus/dbft.html
- dBFT research paper https://github.com/NeoResearch/yellowpaper/blob/master/releases/08_dBFT.pdf
- C# NEO node implementation works with the memory pool model, where only transaction hashes
are proposed in the first step of the consensus and
transactions are synchronized in the background.
Some of the callbacks are in config with sole purpose to support this usecase. However it is
very easy to extend
PrepareRequest
to also include proposed transactions. - NEO has the ability to change the list nodes which verify the block (they are called Validators). This is done through
GetValidators
callback which is called at the start of every epoch. In the simple case where validators are constant it can return the same value everytime it is called. ProcessBlock
is a callback which is called synchronously every time new block is accepted. It can or can not persist block; it also may keep the blockchain state unchanged. dBFT will NOT be initialized at the next height by itself to collect the next block untilReset
is called. In other words, it's the caller's responsibility to initialize dBFT at the next height even after block collection at the current height. It's also the caller's responsibility to update the blockchain state before the next height initialization so that other callbacks includingCurrentHeight
andCurrentHash
return new values.