Documentation ¶
Index ¶
- type ExecForkActor
- type ExecForkSuppressor
- func (s *ExecForkSuppressor) Add(newSeal *flow.IncorporatedResultSeal) (bool, error)
- func (s *ExecForkSuppressor) All() []*flow.IncorporatedResultSeal
- func (s *ExecForkSuppressor) ByID(identifier flow.Identifier) (*flow.IncorporatedResultSeal, bool)
- func (s *ExecForkSuppressor) Clear()
- func (s *ExecForkSuppressor) Limit() uint
- func (s *ExecForkSuppressor) RegisterEjectionCallbacks(callbacks ...mempool.OnEjection)
- func (s *ExecForkSuppressor) Rem(id flow.Identifier) bool
- func (s *ExecForkSuppressor) Size() uint
- type ExecutionTree
- func (et *ExecutionTree) AddReceipt(receipt *flow.ExecutionReceipt, block *flow.Header) (bool, error)
- func (et *ExecutionTree) AddResult(result *flow.ExecutionResult, block *flow.Header) error
- func (et *ExecutionTree) LowestHeight() uint64
- func (et *ExecutionTree) PruneUpToHeight(limit uint64) error
- func (et *ExecutionTree) ReachableReceipts(resultID flow.Identifier, blockFilter mempool.BlockFilter, ...) ([]*flow.ExecutionReceipt, error)
- func (et *ExecutionTree) Size() uint
- type ReceiptsOfSameResult
- func (rsr *ReceiptsOfSameResult) AddReceipt(receipt *flow.ExecutionReceipt) (uint, error)
- func (rsr *ReceiptsOfSameResult) AddReceipts(receipts ...*flow.ExecutionReceipt) (uint, error)
- func (rsr *ReceiptsOfSameResult) Has(receiptID flow.Identifier) bool
- func (rsr *ReceiptsOfSameResult) Level() uint64
- func (rsr *ReceiptsOfSameResult) Parent() (flow.Identifier, uint64)
- func (rsr *ReceiptsOfSameResult) Size() uint
- func (rsr *ReceiptsOfSameResult) VertexID() flow.Identifier
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ExecForkActor ¶
type ExecForkActor func([]*flow.IncorporatedResultSeal)
func LogForkAndCrash ¶
func LogForkAndCrash(log zerolog.Logger) ExecForkActor
type ExecForkSuppressor ¶
type ExecForkSuppressor struct {
// contains filtered or unexported fields
}
ExecForkSuppressor is a wrapper around a conventional mempool.IncorporatedResultSeals mempool. It implements the following mitigation strategy for execution forks:
- In case two conflicting results are considered sealable for the same block, sealing should halt. Specifically, two results are considered conflicting, if they differ in their start or end state.
- Even after a restart, the sealing should not resume.
- We rely on human intervention to resolve the conflict.
The ExecForkSuppressor implements this mitigation strategy as follows:
- For each candidate seal inserted into the mempool, inspect the state transition for the respective block.
- If this is the first seal for a block, store the seal as an archetype for the state transition into the internal map `sealsForBlock`.
- If the mempool already knows about a state transition for a block, and a second seal for the same block is inserted, check whether the seal has the same state transition.
- If conflicting state transitions for the same block are detected, ExecForkSuppressor sets an internal flag and thereafter reports the mempool as empty, which will lead to the respective consensus node not including any more seals.
- Evidence for an execution fork stored in a database (persisted across restarts).
Implementation is concurrency safe.
func NewExecStateForkSuppressor ¶
func NewExecStateForkSuppressor(onExecFork ExecForkActor, seals mempool.IncorporatedResultSeals, db *badger.DB, log zerolog.Logger) (*ExecForkSuppressor, error)
func (*ExecForkSuppressor) Add ¶
func (s *ExecForkSuppressor) Add(newSeal *flow.IncorporatedResultSeal) (bool, error)
Add adds the given seal to the mempool. Return value indicates whether or not seal was added to mempool. Error returns:
- engine.InvalidInputError (sentinel error) In case a seal fails one of the required consistency checks;
func (*ExecForkSuppressor) All ¶
func (s *ExecForkSuppressor) All() []*flow.IncorporatedResultSeal
All returns all the IncorporatedResultSeals in the mempool
func (*ExecForkSuppressor) ByID ¶
func (s *ExecForkSuppressor) ByID(identifier flow.Identifier) (*flow.IncorporatedResultSeal, bool)
ByID returns an IncorporatedResultSeal by its ID
func (*ExecForkSuppressor) Clear ¶
func (s *ExecForkSuppressor) Clear()
Clear removes all entities from the pool. The wrapper clears the internal state as well as its local (additional) state.
func (*ExecForkSuppressor) Limit ¶
func (s *ExecForkSuppressor) Limit() uint
Limit returns the size limit of the mempool
func (*ExecForkSuppressor) RegisterEjectionCallbacks ¶
func (s *ExecForkSuppressor) RegisterEjectionCallbacks(callbacks ...mempool.OnEjection)
RegisterEjectionCallbacks adds the provided OnEjection callbacks
func (*ExecForkSuppressor) Rem ¶
func (s *ExecForkSuppressor) Rem(id flow.Identifier) bool
Rem removes the IncorporatedResultSeal with id from the mempool
func (*ExecForkSuppressor) Size ¶
func (s *ExecForkSuppressor) Size() uint
Size returns the number of items in the mempool
type ExecutionTree ¶ added in v0.14.0
ExecutionTree is a mempool holding receipts, which is aware of the tree structure formed by the results. The mempool supports pruning by height: only results descending from the latest sealed and finalized result are relevant. Hence, we can prune all results for blocks _below_ the latest block with a finalized seal. Results of sufficient height for forks that conflict with the finalized fork are retained. However, such orphaned forks do not grow anymore and their results will be progressively flushed out with increasing sealed-finalized height.
Safe for concurrent access. Internally, the mempool utilizes the LevelledForrest. For an in-depth discussion of the core algorithm, see ./Fork-Aware_Mempools.md
func NewExecutionTree ¶ added in v0.14.0
func NewExecutionTree() *ExecutionTree
NewExecutionTree instantiates a ExecutionTree
func (*ExecutionTree) AddReceipt ¶ added in v0.14.0
func (et *ExecutionTree) AddReceipt(receipt *flow.ExecutionReceipt, block *flow.Header) (bool, error)
Add the given execution receipt to the memory pool. Requires height of the block the receipt is for. We enforce data consistency on an API level by using the block header as input.
func (*ExecutionTree) AddResult ¶ added in v0.14.0
func (et *ExecutionTree) AddResult(result *flow.ExecutionResult, block *flow.Header) error
AddResult adds an Execution Result to the Execution Tree (without any receipts), in case the result is not already stored in the tree. This is useful for crash recovery: After recovering from a crash, the mempools are wiped and the sealed results will not be stored in the Execution Tree anymore. Adding the result to the tree allows to create a vertex in the tree without attaching any Execution Receipts to it.
func (*ExecutionTree) LowestHeight ¶ added in v0.14.0
func (et *ExecutionTree) LowestHeight() uint64
LowestHeight returns the lowest height, where results are still stored in the mempool.
func (*ExecutionTree) PruneUpToHeight ¶ added in v0.14.0
func (et *ExecutionTree) PruneUpToHeight(limit uint64) error
PruneUpToHeight prunes all results for all blocks with height up to but NOT INCLUDING `newLowestHeight`. Errors if newLowestHeight is lower than the previous value (as we cannot recover previously pruned results).
func (*ExecutionTree) ReachableReceipts ¶ added in v0.14.0
func (et *ExecutionTree) ReachableReceipts(resultID flow.Identifier, blockFilter mempool.BlockFilter, receiptFilter mempool.ReceiptFilter) ([]*flow.ExecutionReceipt, error)
ReachableReceipts returns a slice of ExecutionReceipt, whose result is computationally reachable from resultID. Context:
- Conceptually, the Execution results form a tree, which we refer to as Execution Tree. A fork in the execution can be due to a fork in the main chain. Furthermore, the execution forks if ENs disagree about the result for the same block.
- As the ID of an execution result contains the BlockID, which the result for, all Execution Results with the same ID necessarily are for the same block. All Execution Receipts committing to the same result from an equivalence class and can be represented as one vertex in the Execution Tree.
- An execution result r1 points (field ExecutionResult.ParentResultID) to its parent result r0 , whose end state was used as the starting state to compute r1. Formally, we have an edge r0 -> r1 in the Execution Tree, if a result r1 is stored in the mempool, whose ParentResultID points to r0.
ReachableReceipts traverses the Execution Tree from the provided resultID. Execution Receipts are traversed in a parent-first manner, meaning that a receipt committing to the parent result is traversed first _before_ the receipt committing to the derived result. The algorithm only traverses to results, for which there exists a sequence of interim result in the mempool without any gaps.
func (*ExecutionTree) Size ¶ added in v0.14.0
func (et *ExecutionTree) Size() uint
Size returns the number of receipts stored in the mempool
type ReceiptsOfSameResult ¶ added in v0.14.0
type ReceiptsOfSameResult struct {
// contains filtered or unexported fields
}
ReceiptsOfSameResult represents a set of ExecutionReceipt all committing to the same ExecutionResult. As an ExecutionResult contains the Block ID, all results with the same ID must be for the same block. For optimized storage, we only store the result once. Mathematically, a ReceiptsOfSameResult struct represents an Equivalence Class of Execution Receipts. Implements LevelledForest's Vertex interface.
func NewReceiptsOfSameResult ¶ added in v0.14.0
func NewReceiptsOfSameResult(result *flow.ExecutionResult, block *flow.Header) (*ReceiptsOfSameResult, error)
NewReceiptsOfSameResult instantiates an empty Equivalence Class (without any receipts)
func (*ReceiptsOfSameResult) AddReceipt ¶ added in v0.14.0
func (rsr *ReceiptsOfSameResult) AddReceipt(receipt *flow.ExecutionReceipt) (uint, error)
AddReceipt adds the receipt to the ReceiptsOfSameResult (if not already stored). Returns:
- uint: number of receipts added (consistent API with AddReceipts()), Possible values: 0 or 1
- error in case of unforeseen problems
func (*ReceiptsOfSameResult) AddReceipts ¶ added in v0.14.0
func (rsr *ReceiptsOfSameResult) AddReceipts(receipts ...*flow.ExecutionReceipt) (uint, error)
AddReceipts adds the receipts to the ReceiptsOfSameResult (the ones not already stored). Returns:
- uint: number of receipts added
- error in case of unforeseen problems
func (*ReceiptsOfSameResult) Has ¶ added in v0.14.0
func (rsr *ReceiptsOfSameResult) Has(receiptID flow.Identifier) bool
func (*ReceiptsOfSameResult) Level ¶ added in v0.14.0
func (rsr *ReceiptsOfSameResult) Level() uint64
func (*ReceiptsOfSameResult) Parent ¶ added in v0.14.0
func (rsr *ReceiptsOfSameResult) Parent() (flow.Identifier, uint64)
func (*ReceiptsOfSameResult) Size ¶ added in v0.14.0
func (rsr *ReceiptsOfSameResult) Size() uint
Size returns the number of receipts in the equivalence class (i.e. the number of receipts known for that particular result)
func (*ReceiptsOfSameResult) VertexID ¶ added in v0.14.0
func (rsr *ReceiptsOfSameResult) VertexID() flow.Identifier