github.com/koko1123/flow-go-1@v0.29.6/module/mempool/execution_tree.go (about) 1 // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED 2 3 package mempool 4 5 import ( 6 "github.com/koko1123/flow-go-1/model/flow" 7 ) 8 9 // ExecutionTree represents a concurrency-safe memory pool for execution 10 // Receipts. Its is aware of the tree structure formed by execution results. 11 // All execution receipts for the _same result_ form an equivalence class and 12 // are represented by _one_ vertex in the execution tree. The mempool utilizes 13 // knowledge about the height of the block the result is for. Hence, the 14 // Mempool can only store and process Receipts whose block is known. 15 // 16 // Implementations are concurrency safe. 17 type ExecutionTree interface { 18 19 // AddResult adds an Execution Result to the Execution Tree (without any receipts), in 20 // case the result is not already stored in the tree. 21 // This is useful for crash recovery: 22 // After recovering from a crash, the mempools are wiped and the sealed results will not 23 // be stored in the Execution Tree anymore. Adding the result to the tree allows to create 24 // a vertex in the tree without attaching any Execution Receipts to it. 25 AddResult(result *flow.ExecutionResult, block *flow.Header) error 26 27 // AddReceipt adds the given execution receipt to the memory pool. Requires height 28 // of the block the receipt is for. We enforce data consistency on an API 29 // level by using the block header as input. 30 AddReceipt(receipt *flow.ExecutionReceipt, block *flow.Header) (bool, error) 31 32 // HasReceipt returns true if the given receipt is already present in the mempool. 33 HasReceipt(receipt *flow.ExecutionReceipt) bool 34 35 // ReachableReceipts returns a slice of ExecutionReceipt, whose result 36 // is computationally reachable from resultID. Context: 37 // * Conceptually, the Execution results form a tree, which we refer to as 38 // Execution Tree. A branch in the execution can be due to a fork in the main 39 // chain. Furthermore, the execution branches if ENs disagree about the result 40 // for the same block. 41 // * As the ID of an execution result contains the BlockID, which the result 42 // for, all Execution Results with the same ID necessarily are for the same 43 // block. All Execution Receipts committing to the same result from an 44 // equivalence class and can be represented as one vertex in the Execution 45 // Tree. 46 // * An execution result r1 points (field ExecutionResult.ParentResultID) to 47 // its parent result r0 , whose end state was used as the starting state 48 // to compute r1. Formally, we have an edge r0 -> r1 in the Execution Tree, 49 // if a result r1 is stored in the mempool, whose ParentResultID points to 50 // r0. 51 // ReachableReceipts implements a tree search on the Execution Tree starting 52 // from the provided resultID. Execution Receipts are traversed in a 53 // parent-first manner, meaning that a the parent result is traversed 54 // _before_ any of its derived results. The algorithm only traverses to 55 // results, for which there exists a sequence of interim result in the 56 // mempool without any gaps. 57 // 58 // Two filters are supplied: 59 // * blockFilter: the tree search will only travers to results for 60 // blocks which pass the filter. Often higher-level logic is only 61 // interested in results for blocks in a specific fork. Such can be 62 // implemented by a suitable blockFilter. 63 // * receiptFilter: for a reachable result (subject to the restrictions 64 // imposed by blockFilter, all known receipts are returned. 65 // While _all_ Receipts for the parent result are guaranteed to be 66 // listed before the receipts for the derived results, there is no 67 // specific ordering for the receipts committing to the same result 68 // (random order). If only a subset of receipts for a result is desired 69 // (e.g. for de-duplication with parent blocks), receiptFilter should 70 // be used. 71 // Note the important difference between the two filters: 72 // * The blockFilter suppresses traversal to derived results. 73 // * The receiptFilter does _not_ suppresses traversal to derived results. 74 // Only individual receipts are dropped. 75 // 76 // Error returns: 77 // * UnknownExecutionResultError (sentinel) if resultID is unknown 78 // * all other error are unexpected and potential indicators of corrupted internal state 79 ReachableReceipts(resultID flow.Identifier, blockFilter BlockFilter, receiptFilter ReceiptFilter) ([]*flow.ExecutionReceipt, error) 80 81 // Size returns the number of receipts stored in the mempool 82 Size() uint 83 84 // PruneUpToHeight prunes all results for all blocks with height up to but 85 // NOT INCLUDING `newLowestHeight`. Errors if newLowestHeight is smaller than 86 // the previous value (as we cannot recover previously pruned results). 87 PruneUpToHeight(newLowestHeight uint64) error 88 89 // LowestHeight returns the lowest height, where results are still 90 // stored in the mempool. 91 LowestHeight() uint64 92 } 93 94 // BlockFilter is used for controlling the ExecutionTree's Execution Tree search. 95 // The search only traverses to results for blocks which pass the filter. 96 // If an the block for an execution result does not pass the filter, the entire 97 // sub-tree of derived results is not traversed. 98 type BlockFilter func(header *flow.Header) bool 99 100 // ReceiptFilter is used to drop specific receipts from. It does NOT 101 // affect the ExecutionTree's Execution Tree search. 102 type ReceiptFilter func(receipt *flow.ExecutionReceipt) bool