diff --git a/README.md b/README.md index 03177de9..3142ab9f 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,10 @@ concerning dBFT's time depending behaviour. ## Usage A client of the library must implement its own event loop. -The library provides 4 callbacks: +The library provides 5 callbacks that change the state of the consensus +process: - `Start()` which initializes internal dBFT structures +- `Reset()` which reinitializes the consensus process - `OnTransaction()` which must be called everytime new transaction appears - `OnReceive()` which must be called everytime new payload is received - `OnTimer()` which must be called everytime timer fires @@ -59,7 +61,7 @@ callback which is called at the start of every epoch. In the simple case where v it can return the same value everytime it is called. 3. `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 until the `InitializeConsensus` +be initialized at the next height by itself to collect the next block until `Reset` 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 including diff --git a/check.go b/check.go index 14b2bb46..11822fd3 100644 --- a/check.go +++ b/check.go @@ -74,7 +74,7 @@ func (d *DBFT[H, A]) checkCommit() { d.ProcessBlock(d.block) // Do not initialize consensus process immediately. It's the caller's duty to - // start the new block acceptance process and call InitializeConsensus at the + // start the new block acceptance process and call Reset at the // new height. } @@ -102,5 +102,5 @@ func (d *DBFT[H, A]) checkChangeView(view byte) { } } - d.InitializeConsensus(view, d.lastBlockTimestamp) + d.initializeConsensus(view, d.lastBlockTimestamp) } diff --git a/context.go b/context.go index 83e0f99f..8bb97eaf 100644 --- a/context.go +++ b/context.go @@ -27,7 +27,7 @@ type Context[H crypto.Hash, A crypto.Address] struct { // blockProcessed denotes whether Config.ProcessBlock callback was called for the current // height. If so, then no second call must happen. After new block is received by the user, // dBFT stops any new transaction or messages processing as far as timeouts handling till - // the next call to InitializeConsensus. + // the next call to Reset. blockProcessed bool // BlockIndex is current block index. diff --git a/dbft.go b/dbft.go index 11f366d7..3271b09e 100644 --- a/dbft.go +++ b/dbft.go @@ -12,8 +12,10 @@ import ( ) type ( - // DBFT is a wrapper over Context containing service configuration and - // some other parameters not directly related to dBFT's state machine. + // DBFT is a dBFT implementation, it includes [Context] (main state) + // and [Config] (service configuration). Data exposed from these fields + // is supposed to be read-only, state is changed via methods of this + // structure. DBFT[H crypto.Hash, A crypto.Address] struct { Context[H, A] Config[H, A] @@ -22,13 +24,6 @@ type ( cache cache[H, A] recovering bool } - // Service is an interface for dBFT consensus. - Service[H crypto.Hash, A crypto.Address] interface { - Start(uint64) - OnTransaction(block.Transaction[H]) - OnReceive(payload.ConsensusPayload[H, A]) - OnTimeout(timer.HV) - } ) // New returns new DBFT instance with specified H and A generic parameters @@ -74,16 +69,25 @@ func (d *DBFT[H, A]) addTransaction(tx block.Transaction[H]) { } } -// Start initializes dBFT instance and starts protocol if node is primary. It -// accepts a timestamp of the previous block. +// Start initializes dBFT instance and starts the protocol if node is primary. +// It accepts the timestamp of the previous block. It should be called once +// per DBFT lifetime. func (d *DBFT[H, A]) Start(ts uint64) { d.cache = newCache[H, A]() - d.InitializeConsensus(0, ts) + d.initializeConsensus(0, ts) d.start() } -// InitializeConsensus initializes dBFT instance. -func (d *DBFT[H, A]) InitializeConsensus(view byte, ts uint64) { +// Reset reinitializes dBFT instance with the given timestamp of the previous +// block. It's used if the current consensus state is outdated which happens +// after new block is processed by ledger (the block can come from dBFT or be +// received by other means). The height is to be derived from the configured +// CurrentHeight callback and view will be set to 0. +func (d *DBFT[H, A]) Reset(ts uint64) { + d.initializeConsensus(0, ts) +} + +func (d *DBFT[H, A]) initializeConsensus(view byte, ts uint64) { d.reset(view, ts) var role string