-
Notifications
You must be signed in to change notification settings - Fork 33
Shared State Hash Protocol
This document describes the cross-module communication using the interfaces in ../shared/modules to compute a new state hash. See module specific documentation & implementation details inside each module respectively.
NOTE: The diagrams below use some Hotstuff specific terminology as described in the HotPOKT Consensus Specification but can be adapted to other BFT protocols as well.
The Utility
and Persistence
modules maintain a context (i.e. an ephemeral states) driven by the Consensus
module that can be released & reverted
(i.e. the block is invalid / no Validator Consensus reached) or can be committed & persisted
to disk (i.e. the block is finalized).
On every round of every height:
- The
Consensus
module handles aNEWROUND
message - A new
UtilityUnitOfWork
is initialized at the current height - A new
PersistenceRWContext
is initialized at the current height - The Block Application flow commences
sequenceDiagram
title Steps 1-4
participant B as Bus
participant C as Consensus
participant U as Utility
participant P as Persistence
%% Handle New Message
B-->>C: HandleMessage(NEWROUND)
%% NEWROUND
activate C
%% Create Contexts
C->>+U: NewContext(height)
U->>+P: NewRWContext(height)
P->>-U: PersistenceContext
U->>U: store context<br>locally
activate U
deactivate U
U->>-C: UtilityUnitOfWork
C->>C: store context<br>locally
deactivate C
%% Apply Block
Note over C, P: 'Block Application'
The Proposer drives the Validators to agreement via the Consensus Lifecycle (i.e. HotPOKT)
- The
Consensus
module handles theDECIDE
message - The
commitQC
is propagated to theUtilityUnitOfWork
&PersistenceContext
onCommit
- The persistence module's internal implementation for 'Store Block' must execute.
- Both the
UtilityUnitOfWork
andPersistenceContext
are released
sequenceDiagram
title Steps 5-8
participant B as Bus
participant C as Consensus
participant U as Utility
participant P as Persistence
%% Handle New Message
B-->>C: HandleMessage(DECIDE)
activate C
%% Commit Context
C->>+U: Context.Commit(proposer, quorumCert)
U->>+P: Context.Commit(proposer, quorumCert)
P->>P: Internal Implementation
Note over P: Store Block
P->>-U: err_code
U->>C: err_code
deactivate U
%% Release Context
C->>+U: Context.Release()
U->>+P: Context.Release()
P->>-U: err_code
U->>-C: err_code
deactivate C
When applying the block during the NEWROUND
message shown above, the majority of the flow is similar between the leader and the replica with one of the major differences being a call to the Utility
module as seen below.
-
ApplyBlock
- Uses the existing set of transactions to validate & propose -
CreateProposalBlock
- Reaps the mempool for a new set of transaction to validate and propose
graph TD
B[Should I prepare a new block?] --> |Wait for 2/3+ NEWROUND messages| C
C[Am I the leader?] --> |Yes| D
C[Am I the leader?] --> |No| Z
D[Did I get any prepareQCs?] --> |Find highest valid prepareQC| E
D[Did I get any prepareQCs?] --> |No| Z
E[Am I ahead of highPrepareQC?] --> |Yes| G
E[Am I ahead of highPrepareQC?] --> |No| Z
G[Do I have a lockedQC] --> |No| H
G[Do I have a lockedQC] --> |Yes| I
I[Is prepareQC.view > lockedQC.view] --> |"No<br>(lockedQC.block)"| Z
I[Is prepareQC.view > lockedQC.view] --> |"Yes<br>(prepareQC.block)"| Z
H[CreateProposalBlock]
Z[ApplyBlock]
As either the leader or replica, the following steps are followed to apply the proposal transactions in the block.
- Update the
UtilityUnitOfWork
with the proposed block - Call either
ApplyBlock
orCreateProposalBlock
based on the flow above
sequenceDiagram
title Steps 1-2
participant C as Consensus
participant U as Utility
%% Update the proposal in the utility unit of work
C->>+U: SetProposalBlock(hash, proposer, txs)
U->>-C: err_code
%% Apply the block to the local proposal state
C->>+U: ApplyBlock / CreateProposalBlock
U->>-C: err_code
- Loop over all transactions proposed
- Check if the transaction has already been applied to the local state
- Perform the CRUD operation(s) corresponding to each transaction
- The persistence module's internal implementation for 'Compute State Hash' must be triggered
- Validate that the local state hash computed is the same as that proposed
sequenceDiagram
title Steps 3-7
participant C as Consensus
participant U as Utility
participant P as Persistence
loop for each tx in txs
U->>+P: TransactionExists(txHash)
P->>-U: false (does not exist)
loop for each operation in tx
U->>+P: Get*/Set*/Update*/Insert*
P->>-U: err_code
U->>U: Validation logic
activate U
deactivate U
end
end
%% TODO: Consolidate AppHash and StateHash
U->>+P: ComputeStateHash()
P->>P: Internal Implementation
Note over P: Compute State Hash
P->>-U: stateHash
U->>C: stateHash
%% Validate the computed hash
C->>C: Compare local hash<br>against proposed hash
Contents
- Home
- Persistence
- Changelog
-
Persistence
- Indexer
- Rpc
- Runtime
- State_Machine
-
Guides
- Roadmap
-
Guides
- Learning
- Guides
-
Guides
- Contributing
- Devlog
-
Guides
- Dependencies
-
Guides
- Releases
- Guides
- P2P
-
Shared
- Crypto
- Shared
-
Shared
- Modules
-
Build
- Config
- Consensus
-
Guides
- Telemetry
- Utility
- Logger