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  }