github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/chunk.go (about) 1 package flow 2 3 import ( 4 "log" 5 6 "github.com/ipfs/go-cid" 7 ) 8 9 var EmptyEventCollectionID Identifier 10 11 func init() { 12 // Convert hexadecimal string to a byte slice. 13 var err error 14 emptyEventCollectionHex := "0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8" 15 EmptyEventCollectionID, err = HexStringToIdentifier(emptyEventCollectionHex) 16 if err != nil { 17 log.Fatalf("Failed to decode hex: %v", err) 18 } 19 } 20 21 type ChunkBody struct { 22 CollectionIndex uint 23 24 // execution info 25 StartState StateCommitment // start state when starting executing this chunk 26 EventCollection Identifier // Events generated by executing results 27 BlockID Identifier // Block id of the execution result this chunk belongs to 28 29 // Computation consumption info 30 TotalComputationUsed uint64 // total amount of computation used by running all txs in this chunk 31 NumberOfTransactions uint64 // number of transactions inside the collection 32 } 33 34 type Chunk struct { 35 ChunkBody 36 37 Index uint64 // chunk index inside the ER (starts from zero) 38 // EndState inferred from next chunk or from the ER 39 EndState StateCommitment 40 } 41 42 func NewChunk( 43 blockID Identifier, 44 collectionIndex int, 45 startState StateCommitment, 46 numberOfTransactions int, 47 eventCollection Identifier, 48 endState StateCommitment, 49 totalComputationUsed uint64, 50 ) *Chunk { 51 return &Chunk{ 52 ChunkBody: ChunkBody{ 53 BlockID: blockID, 54 CollectionIndex: uint(collectionIndex), 55 StartState: startState, 56 NumberOfTransactions: uint64(numberOfTransactions), 57 EventCollection: eventCollection, 58 TotalComputationUsed: totalComputationUsed, 59 }, 60 Index: uint64(collectionIndex), 61 EndState: endState, 62 } 63 } 64 65 // ID returns a unique id for this entity 66 func (ch *Chunk) ID() Identifier { 67 return MakeID(ch.ChunkBody) 68 } 69 70 // Checksum provides a cryptographic commitment for a chunk content 71 func (ch *Chunk) Checksum() Identifier { 72 return MakeID(ch) 73 } 74 75 // ChunkDataPack holds all register touches (any read, or write). 76 // 77 // Note that we have to include merkle paths as storage proof for all registers touched (read or written) for 78 // the _starting_ state of the chunk (i.e. before the chunk computation updates the registers). 79 // For instance, if an execution state contains three registers: { A: 1, B: 2, C: 3}, and a certain 80 // chunk has a tx that assigns A = A + B, then its chunk data pack should include the merkle 81 // paths for { A: 1, B: 2 } as storage proof. 82 // C is not included because it's neither read or written by the chunk. 83 // B is included because it's read by the chunk. 84 // A is included because it's updated by the chunk, and its value 1 is included because it's 85 // the value before the chunk computation. 86 // This is necessary for Verification Nodes to (i) check that the read register values are 87 // consistent with the starting state's root hash and (ii) verify the correctness of the resulting 88 // state after the chunk computation. `Proof` includes merkle proofs for all touched registers 89 // during the execution of the chunk. 90 // Register proofs order must not be correlated to the order of register reads during 91 // the chunk execution in order to enforce the SPoCK secret high entropy. 92 type ChunkDataPack struct { 93 ChunkID Identifier // ID of the chunk this data pack is for 94 StartState StateCommitment // commitment for starting state 95 Proof StorageProof // proof for all registers touched (read or written) during the chunk execution 96 Collection *Collection // collection executed in this chunk 97 98 // ExecutionDataRoot is the root data structure of an execution_data.BlockExecutionData. 99 // It contains the necessary information for a verification node to validate that the 100 // BlockExecutionData produced is valid. 101 ExecutionDataRoot BlockExecutionDataRoot 102 } 103 104 // NewChunkDataPack returns an initialized chunk data pack. 105 func NewChunkDataPack( 106 chunkID Identifier, 107 startState StateCommitment, 108 proof StorageProof, 109 collection *Collection, 110 execDataRoot BlockExecutionDataRoot, 111 ) *ChunkDataPack { 112 return &ChunkDataPack{ 113 ChunkID: chunkID, 114 StartState: startState, 115 Proof: proof, 116 Collection: collection, 117 ExecutionDataRoot: execDataRoot, 118 } 119 } 120 121 // ID returns the unique identifier for the concrete view, which is the ID of 122 // the chunk the view is for. 123 func (c *ChunkDataPack) ID() Identifier { 124 return c.ChunkID 125 } 126 127 // Checksum returns the checksum of the chunk data pack. 128 func (c *ChunkDataPack) Checksum() Identifier { 129 return MakeID(c) 130 } 131 132 // TODO: This is the basic version of the list, we need to substitute it with something like Merkle tree at some point 133 type ChunkList []*Chunk 134 135 func (cl ChunkList) Fingerprint() Identifier { 136 return MerkleRoot(GetIDs(cl)...) 137 } 138 139 func (cl *ChunkList) Insert(ch *Chunk) { 140 *cl = append(*cl, ch) 141 } 142 143 func (cl ChunkList) Items() []*Chunk { 144 return cl 145 } 146 147 // Empty returns true if the chunk list is empty. Otherwise it returns false. 148 func (cl ChunkList) Empty() bool { 149 return len(cl) == 0 150 } 151 152 func (cl ChunkList) Indices() []uint64 { 153 indices := make([]uint64, len(cl)) 154 for i, chunk := range cl { 155 indices[i] = chunk.Index 156 } 157 158 return indices 159 } 160 161 // ByChecksum returns an entity from the list by entity fingerprint 162 func (cl ChunkList) ByChecksum(cs Identifier) (*Chunk, bool) { 163 for _, ch := range cl { 164 if ch.Checksum() == cs { 165 return ch, true 166 } 167 } 168 return nil, false 169 } 170 171 // ByIndex returns an entity from the list by index 172 // if requested chunk is within range of list, it returns chunk and true 173 // if requested chunk is out of the range, it returns nil and false 174 // boolean return value indicates whether requested chunk is within range 175 func (cl ChunkList) ByIndex(i uint64) (*Chunk, bool) { 176 if i >= uint64(len(cl)) { 177 // index out of range 178 return nil, false 179 } 180 return cl[i], true 181 } 182 183 // Len returns the number of Chunks in the list. It is also part of the sort 184 // interface that makes ChunkList sortable 185 func (cl ChunkList) Len() int { 186 return len(cl) 187 } 188 189 // BlockExecutionDataRoot represents the root of a serialized execution_data.BlockExecutionData. 190 // The hash of the serialized BlockExecutionDataRoot is the ExecutionDataID used within an 191 // flow.ExecutionResult. 192 // Context: 193 // - The trie updates in BlockExecutionDataRoot contain the _mutated_ registers only, which is 194 // helpful for clients to truslessly replicate the state. 195 // - In comparison, the chunk data packs contains all the register values at the chunk's starting 196 // state that were _touched_ (written and/or read). This is necessary for Verification Nodes to 197 // re-run the chunk the computation. 198 type BlockExecutionDataRoot struct { 199 // BlockID is the ID of the block, whose result this execution data is for. 200 BlockID Identifier 201 202 // ChunkExecutionDataIDs is a list of the root CIDs for each serialized execution_data.ChunkExecutionData 203 // associated with this block. 204 ChunkExecutionDataIDs []cid.Cid 205 }