github.com/koko1123/flow-go-1@v0.29.6/module/forest/leveled_forrest.go (about) 1 package forest 2 3 import ( 4 "fmt" 5 6 "github.com/koko1123/flow-go-1/model/flow" 7 ) 8 9 // LevelledForest contains multiple trees (which is a potentially disconnected planar graph). 10 // Each vertexContainer in the graph has a level (view) and a hash. A vertexContainer can only have one parent 11 // with strictly smaller level (view). A vertexContainer can have multiple children, all with 12 // strictly larger level (view). 13 // A LevelledForest provides the ability to prune all vertices up to a specific level. 14 // A tree whose root is below the pruning threshold might decompose into multiple 15 // disconnected subtrees as a result of pruning. 16 type LevelledForest struct { 17 vertices VertexSet 18 verticesAtLevel map[uint64]VertexList 19 size uint64 20 LowestLevel uint64 21 } 22 23 type VertexList []*vertexContainer 24 type VertexSet map[flow.Identifier]*vertexContainer 25 26 // vertexContainer holds information about a tree vertex. Internally, we distinguish between 27 // - FULL container: has non-nil value for vertex. 28 // Used for vertices, which have been added to the tree. 29 // - EMPTY container: has NIL value for vertex. 30 // Used for vertices, which have NOT been added to the tree, but are 31 // referenced by vertices in the tree. An empty container is converted to a 32 // full container when the respective vertex is added to the tree 33 type vertexContainer struct { 34 id flow.Identifier 35 level uint64 36 children VertexList 37 38 // the following are only set if the block is actually known 39 vertex Vertex 40 } 41 42 // NewLevelledForest initializes a LevelledForest 43 func NewLevelledForest(lowestLevel uint64) *LevelledForest { 44 return &LevelledForest{ 45 vertices: make(VertexSet), 46 verticesAtLevel: make(map[uint64]VertexList), 47 LowestLevel: lowestLevel, 48 } 49 } 50 51 // PruneUpToLevel prunes all blocks UP TO but NOT INCLUDING `level` 52 func (f *LevelledForest) PruneUpToLevel(level uint64) error { 53 if level < f.LowestLevel { 54 return fmt.Errorf("new lowest level %d cannot be smaller than previous last retained level %d", level, f.LowestLevel) 55 } 56 if len(f.vertices) == 0 { 57 f.LowestLevel = level 58 return nil 59 } 60 61 elementsPruned := 0 62 63 // to optimize the pruning large level-ranges, we compare: 64 // * the number of levels for which we have stored vertex containers: len(f.verticesAtLevel) 65 // * the number of levels that need to be pruned: level-f.LowestLevel 66 // We iterate over the dimension which is smaller. 67 if uint64(len(f.verticesAtLevel)) < level-f.LowestLevel { 68 for l, vertices := range f.verticesAtLevel { 69 if l < level { 70 for _, v := range vertices { 71 if !f.isEmptyContainer(v) { 72 elementsPruned++ 73 } 74 delete(f.vertices, v.id) 75 } 76 delete(f.verticesAtLevel, l) 77 } 78 } 79 } else { 80 for l := f.LowestLevel; l < level; l++ { 81 verticesAtLevel := f.verticesAtLevel[l] 82 for _, v := range verticesAtLevel { // nil map behaves like empty map when iterating over it 83 if !f.isEmptyContainer(v) { 84 elementsPruned++ 85 } 86 delete(f.vertices, v.id) 87 } 88 delete(f.verticesAtLevel, l) 89 90 } 91 } 92 f.LowestLevel = level 93 f.size -= uint64(elementsPruned) 94 return nil 95 } 96 97 // HasVertex returns true iff full vertex exists 98 func (f *LevelledForest) HasVertex(id flow.Identifier) bool { 99 container, exists := f.vertices[id] 100 return exists && !f.isEmptyContainer(container) 101 } 102 103 // isEmptyContainer returns true iff vertexContainer container is empty, i.e. full vertex itself has not been added 104 func (f *LevelledForest) isEmptyContainer(vertexContainer *vertexContainer) bool { 105 return vertexContainer.vertex == nil 106 } 107 108 // GetVertex returns (<full vertex>, true) if the vertex with `id` and `level` was found 109 // (nil, false) if full vertex is unknown 110 func (f *LevelledForest) GetVertex(id flow.Identifier) (Vertex, bool) { 111 container, exists := f.vertices[id] 112 if !exists || f.isEmptyContainer(container) { 113 return nil, false 114 } 115 return container.vertex, true 116 } 117 118 // GetSize returns the total number of vertices above the pruned lowest level. 119 // Note this call is not concurrent-safe, caller is responsible to ensure concurrency safety. 120 func (f *LevelledForest) GetSize() uint64 { 121 return f.size 122 } 123 124 // GetChildren returns a VertexIterator to iterate over the children 125 // An empty VertexIterator is returned, if no vertices are known whose parent is `id` , `level` 126 func (f *LevelledForest) GetChildren(id flow.Identifier) VertexIterator { 127 container := f.vertices[id] 128 // if vertex does not exists, container is the default zero value for vertexContainer, which contains a nil-slice for its children 129 return newVertexIterator(container.children) // VertexIterator gracefully handles nil slices 130 } 131 132 // GetNumberOfChildren returns number of children of given vertex 133 func (f *LevelledForest) GetNumberOfChildren(id flow.Identifier) int { 134 container := f.vertices[id] // if vertex does not exists, container is the default zero value for vertexContainer, which contains a nil-slice for its children 135 num := 0 136 for _, child := range container.children { 137 if child.vertex != nil { 138 num++ 139 } 140 } 141 return num 142 } 143 144 // GetVerticesAtLevel returns a VertexIterator to iterate over the Vertices at the specified height 145 // An empty VertexIterator is returned, if no vertices are known at the specified `level` 146 func (f *LevelledForest) GetVerticesAtLevel(level uint64) VertexIterator { 147 return newVertexIterator(f.verticesAtLevel[level]) // go returns the zero value for a missing level. Here, a nil slice 148 } 149 150 // GetNumberOfVerticesAtLevel returns number of vertices at given level 151 func (f *LevelledForest) GetNumberOfVerticesAtLevel(level uint64) int { 152 num := 0 153 for _, container := range f.verticesAtLevel[level] { 154 if container.vertex != nil { 155 num++ 156 } 157 } 158 return num 159 } 160 161 // AddVertex adds vertex to forest if vertex is within non-pruned levels 162 // Handles repeated addition of same vertex (keeps first added vertex). 163 // If vertex is at or below pruning level: method is NoOp. 164 // UNVALIDATED: 165 // requires that vertex would pass validity check LevelledForest.VerifyVertex(vertex). 166 func (f *LevelledForest) AddVertex(vertex Vertex) { 167 if vertex.Level() < f.LowestLevel { 168 return 169 } 170 container := f.getOrCreateVertexContainer(vertex.VertexID(), vertex.Level()) 171 if !f.isEmptyContainer(container) { // the vertex was already stored 172 return 173 } 174 // container is empty, i.e. full vertex is new and should be stored in container 175 container.vertex = vertex // add vertex to container 176 f.registerWithParent(container) 177 f.size += 1 178 } 179 180 func (f *LevelledForest) registerWithParent(vertexContainer *vertexContainer) { 181 // caution: do not modify this combination of check (a) and (a) 182 // Deliberate handling of root vertex (genesis block) whose view is _exactly_ at LowestLevel 183 // For this block, we don't care about its parent and the exception is allowed where 184 // vertex.level = vertex.Parent().Level = LowestLevel = 0 185 if vertexContainer.level <= f.LowestLevel { // check (a) 186 return 187 } 188 189 _, parentView := vertexContainer.vertex.Parent() 190 if parentView < f.LowestLevel { 191 return 192 } 193 parentContainer := f.getOrCreateVertexContainer(vertexContainer.vertex.Parent()) 194 parentContainer.children = append(parentContainer.children, vertexContainer) // append works on nil slices: creates slice with capacity 2 195 } 196 197 // getOrCreateVertexContainer returns the vertexContainer if there exists one 198 // or creates a new vertexContainer and adds it to the internal data structures. 199 // It errors if a vertex with same id but different Level is already known 200 // (i.e. there exists an empty or full container with the same id but different level). 201 func (f *LevelledForest) getOrCreateVertexContainer(id flow.Identifier, level uint64) *vertexContainer { 202 container, exists := f.vertices[id] // try to find vertex container with same ID 203 if !exists { // if no vertex container found, create one and store it 204 container = &vertexContainer{ 205 id: id, 206 level: level, 207 } 208 f.vertices[container.id] = container 209 vtcs := f.verticesAtLevel[container.level] // returns nil slice if not yet present 210 f.verticesAtLevel[container.level] = append(vtcs, container) // append works on nil slices: creates slice with capacity 2 211 } 212 return container 213 } 214 215 // VerifyVertex verifies that vertex satisfies the following conditions 216 // (1) 217 func (f *LevelledForest) VerifyVertex(vertex Vertex) error { 218 if vertex.Level() < f.LowestLevel { 219 return nil 220 } 221 isKnownVertex, err := f.isEquivalentToStoredVertex(vertex) 222 if err != nil { 223 return fmt.Errorf("invalid Vertex: %w", err) 224 } 225 if isKnownVertex { 226 return nil 227 } 228 // vertex not found in storage => new vertex 229 230 // verify new vertex 231 if vertex.Level() == f.LowestLevel { 232 return nil 233 } 234 return f.verifyParent(vertex) 235 } 236 237 // isEquivalentToStoredVertex 238 // evaluates whether a vertex is equivalent to already stored vertex. 239 // for vertices at pruning level, parents are ignored 240 // 241 // (1) return value (false, nil) 242 // Two vertices are _not equivalent_ if they have different IDs (Hashes). 243 // 244 // (2) return value (true, nil) 245 // Two vertices _are equivalent_ if their respective fields are identical: 246 // ID, Level, and Parent (both parent ID and parent Level) 247 // 248 // (3) return value (false, error) 249 // errors if the vertices' IDs are identical but they differ 250 // in any of the _relevant_ fields (as defined in (2)). 251 func (f *LevelledForest) isEquivalentToStoredVertex(vertex Vertex) (bool, error) { 252 storedVertex, haveStoredVertex := f.GetVertex(vertex.VertexID()) 253 if !haveStoredVertex { 254 return false, nil //have no vertex with same id stored 255 } 256 257 // found vertex in storage with identical ID 258 // => we expect all other (relevant) fields to be identical 259 if vertex.Level() != storedVertex.Level() { // view number 260 return false, fmt.Errorf("conflicting vertices with ID %v", vertex.VertexID()) 261 } 262 if vertex.Level() <= f.LowestLevel { 263 return true, nil 264 } 265 newParentId, newParentView := vertex.Parent() 266 storedParentId, storedParentView := storedVertex.Parent() 267 if newParentId != storedParentId { // qc.blockID 268 return false, fmt.Errorf("conflicting vertices with ID %v", vertex.VertexID()) 269 } 270 if newParentView != storedParentView { // qc.view 271 return false, fmt.Errorf("conflicting vertices with ID %v", vertex.VertexID()) 272 } 273 // all _relevant_ fields identical 274 return true, nil 275 } 276 277 // verifyParent verifies whether vertex.Parent() is consistent with current forest. 278 // An error is raised if 279 // * there is a parent with the same id but different view; 280 // * the parent's level is _not_ smaller than the vertex's level 281 func (f *LevelledForest) verifyParent(vertex Vertex) error { 282 // verify parent 283 parentID, parentLevel := vertex.Parent() 284 if !(vertex.Level() > parentLevel) { 285 return fmt.Errorf("parent vertex's level (%d) must be smaller than the vertex's level (%d)", parentLevel, vertex.Level()) 286 } 287 parentVertex, haveParentStored := f.GetVertex(parentID) 288 if !haveParentStored { 289 return nil 290 } 291 if parentVertex.Level() != parentLevel { 292 return fmt.Errorf("parent vertex of %v has different level (%d) than the stored vertex (%d)", 293 vertex.VertexID(), parentLevel, parentVertex.Level(), 294 ) 295 } 296 return nil 297 }