github.com/ethereum/go-ethereum@v1.16.1/triedb/pathdb/layertree.go (about)

     1  // Copyright 2023 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package pathdb
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"sync"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/trie/trienode"
    26  )
    27  
    28  // layerTree is a group of state layers identified by the state root.
    29  // This structure defines a few basic operations for manipulating
    30  // state layers linked with each other in a tree structure. It's
    31  // thread-safe to use. However, callers need to ensure the thread-safety
    32  // of the referenced layer by themselves.
    33  type layerTree struct {
    34  	base   *diskLayer
    35  	layers map[common.Hash]layer
    36  
    37  	// descendants is a two-dimensional map where the keys represent
    38  	// an ancestor state root, and the values are the state roots of
    39  	// all its descendants.
    40  	//
    41  	// For example: r -> [c1, c2, ..., cn], where c1 through cn are
    42  	// the descendants of state r.
    43  	//
    44  	// This map includes all the existing diff layers and the disk layer.
    45  	descendants map[common.Hash]map[common.Hash]struct{}
    46  	lookup      *lookup
    47  	lock        sync.RWMutex
    48  }
    49  
    50  // newLayerTree constructs the layerTree with the given head layer.
    51  func newLayerTree(head layer) *layerTree {
    52  	tree := new(layerTree)
    53  	tree.init(head)
    54  	return tree
    55  }
    56  
    57  // init initializes the layerTree by the given head layer.
    58  func (tree *layerTree) init(head layer) {
    59  	tree.lock.Lock()
    60  	defer tree.lock.Unlock()
    61  
    62  	current := head
    63  	tree.layers = make(map[common.Hash]layer)
    64  	tree.descendants = make(map[common.Hash]map[common.Hash]struct{})
    65  
    66  	for {
    67  		tree.layers[current.rootHash()] = current
    68  		tree.fillAncestors(current)
    69  
    70  		parent := current.parentLayer()
    71  		if parent == nil {
    72  			break
    73  		}
    74  		current = parent
    75  	}
    76  	tree.base = current.(*diskLayer) // panic if it's not a disk layer
    77  	tree.lookup = newLookup(head, tree.isDescendant)
    78  }
    79  
    80  // get retrieves a layer belonging to the given state root.
    81  func (tree *layerTree) get(root common.Hash) layer {
    82  	tree.lock.RLock()
    83  	defer tree.lock.RUnlock()
    84  
    85  	return tree.layers[root]
    86  }
    87  
    88  // isDescendant returns whether the specified layer with given root is a
    89  // descendant of a specific ancestor.
    90  //
    91  // This function assumes the read lock has been held.
    92  func (tree *layerTree) isDescendant(root common.Hash, ancestor common.Hash) bool {
    93  	subset := tree.descendants[ancestor]
    94  	if subset == nil {
    95  		return false
    96  	}
    97  	_, ok := subset[root]
    98  	return ok
    99  }
   100  
   101  // fillAncestors identifies the ancestors of the given layer and populates the
   102  // descendants set. The ancestors include the diff layers below the supplied
   103  // layer and also the disk layer.
   104  //
   105  // This function assumes the write lock has been held.
   106  func (tree *layerTree) fillAncestors(layer layer) {
   107  	hash := layer.rootHash()
   108  	for {
   109  		parent := layer.parentLayer()
   110  		if parent == nil {
   111  			break
   112  		}
   113  		layer = parent
   114  
   115  		phash := parent.rootHash()
   116  		subset := tree.descendants[phash]
   117  		if subset == nil {
   118  			subset = make(map[common.Hash]struct{})
   119  			tree.descendants[phash] = subset
   120  		}
   121  		subset[hash] = struct{}{}
   122  	}
   123  }
   124  
   125  // forEach iterates the stored layers inside and applies the
   126  // given callback on them.
   127  func (tree *layerTree) forEach(onLayer func(layer)) {
   128  	tree.lock.RLock()
   129  	defer tree.lock.RUnlock()
   130  
   131  	for _, layer := range tree.layers {
   132  		onLayer(layer)
   133  	}
   134  }
   135  
   136  // len returns the number of layers cached.
   137  func (tree *layerTree) len() int {
   138  	tree.lock.RLock()
   139  	defer tree.lock.RUnlock()
   140  
   141  	return len(tree.layers)
   142  }
   143  
   144  // add inserts a new layer into the tree if it can be linked to an existing old parent.
   145  func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *StateSetWithOrigin) error {
   146  	// Reject noop updates to avoid self-loops. This is a special case that can
   147  	// happen for clique networks and proof-of-stake networks where empty blocks
   148  	// don't modify the state (0 block subsidy).
   149  	//
   150  	// Although we could silently ignore this internally, it should be the caller's
   151  	// responsibility to avoid even attempting to insert such a layer.
   152  	if root == parentRoot {
   153  		return errors.New("layer cycle")
   154  	}
   155  	parent := tree.get(parentRoot)
   156  	if parent == nil {
   157  		return fmt.Errorf("triedb parent [%#x] layer missing", parentRoot)
   158  	}
   159  	l := parent.update(root, parent.stateID()+1, block, newNodeSet(nodes.Flatten()), states)
   160  
   161  	tree.lock.Lock()
   162  	defer tree.lock.Unlock()
   163  
   164  	// Link the given layer into the layer set
   165  	tree.layers[l.rootHash()] = l
   166  
   167  	// Link the given layer into its ancestors (up to the current disk layer)
   168  	tree.fillAncestors(l)
   169  
   170  	// Link the given layer into the state mutation history
   171  	tree.lookup.addLayer(l)
   172  	return nil
   173  }
   174  
   175  // cap traverses downwards the diff tree until the number of allowed diff layers
   176  // are crossed. All diffs beyond the permitted number are flattened downwards.
   177  func (tree *layerTree) cap(root common.Hash, layers int) error {
   178  	// Retrieve the head layer to cap from
   179  	l := tree.get(root)
   180  	if l == nil {
   181  		return fmt.Errorf("triedb layer [%#x] missing", root)
   182  	}
   183  	diff, ok := l.(*diffLayer)
   184  	if !ok {
   185  		return fmt.Errorf("triedb layer [%#x] is disk layer", root)
   186  	}
   187  	tree.lock.Lock()
   188  	defer tree.lock.Unlock()
   189  
   190  	// If full commit was requested, flatten the diffs and merge onto disk
   191  	if layers == 0 {
   192  		base, err := diff.persist(true)
   193  		if err != nil {
   194  			return err
   195  		}
   196  		tree.base = base
   197  
   198  		// Reset the layer tree with the single new disk layer
   199  		tree.layers = map[common.Hash]layer{
   200  			base.rootHash(): base,
   201  		}
   202  		// Resets the descendants map, since there's only a single disk layer
   203  		// with no descendants.
   204  		tree.descendants = make(map[common.Hash]map[common.Hash]struct{})
   205  		tree.lookup = newLookup(base, tree.isDescendant)
   206  		return nil
   207  	}
   208  	// Dive until we run out of layers or reach the persistent database
   209  	for i := 0; i < layers-1; i++ {
   210  		// If we still have diff layers below, continue down
   211  		if parent, ok := diff.parentLayer().(*diffLayer); ok {
   212  			diff = parent
   213  		} else {
   214  			// Diff stack too shallow, return without modifications
   215  			return nil
   216  		}
   217  	}
   218  	// We're out of layers, flatten anything below, stopping if it's the disk or if
   219  	// the memory limit is not yet exceeded.
   220  	var (
   221  		err      error
   222  		replaced layer
   223  		newBase  *diskLayer
   224  	)
   225  	switch parent := diff.parentLayer().(type) {
   226  	case *diskLayer:
   227  		return nil
   228  
   229  	case *diffLayer:
   230  		// Hold the lock to prevent any read operations until the new
   231  		// parent is linked correctly.
   232  		diff.lock.Lock()
   233  
   234  		// Hold the reference of the original layer being replaced
   235  		replaced = parent
   236  
   237  		// Replace the original parent layer with new disk layer. The procedure
   238  		// can be illustrated as below:
   239  		//
   240  		// Before change:
   241  		//     Chain:
   242  		//        C1->C2->C3->C4 (HEAD)
   243  		//          ->C2'->C3'->C4'
   244  		//
   245  		// After change:
   246  		//     Chain:
   247  		//        (a) C3->C4 (HEAD)
   248  		//		  (b) C1->C2
   249  		//		        ->C2'->C3'->C4'
   250  		// The original C3 is replaced by the new base (with root C3)
   251  		// Dangling layers in (b) will be removed later
   252  		newBase, err = parent.persist(false)
   253  		if err != nil {
   254  			diff.lock.Unlock()
   255  			return err
   256  		}
   257  		tree.layers[newBase.rootHash()] = newBase
   258  
   259  		// Link the new parent and release the lock
   260  		diff.parent = newBase
   261  		diff.lock.Unlock()
   262  
   263  	default:
   264  		panic(fmt.Sprintf("unknown data layer in triedb: %T", parent))
   265  	}
   266  	// Remove any layer that is stale or links into a stale layer
   267  	children := make(map[common.Hash][]common.Hash)
   268  	for root, layer := range tree.layers {
   269  		if dl, ok := layer.(*diffLayer); ok {
   270  			parent := dl.parentLayer().rootHash()
   271  			children[parent] = append(children[parent], root)
   272  		}
   273  	}
   274  	clearDiff := func(layer layer) {
   275  		diff, ok := layer.(*diffLayer)
   276  		if !ok {
   277  			return
   278  		}
   279  		tree.lookup.removeLayer(diff)
   280  	}
   281  	var remove func(root common.Hash)
   282  	remove = func(root common.Hash) {
   283  		clearDiff(tree.layers[root])
   284  
   285  		// Unlink the layer from the layer tree and cascade to its children
   286  		delete(tree.descendants, root)
   287  		delete(tree.layers, root)
   288  		for _, child := range children[root] {
   289  			remove(child)
   290  		}
   291  		delete(children, root)
   292  	}
   293  	remove(tree.base.rootHash()) // remove the old/stale disk layer
   294  	clearDiff(replaced)          // remove the lookup data of the stale parent being replaced
   295  	tree.base = newBase          // update the base layer with newly constructed one
   296  	return nil
   297  }
   298  
   299  // bottom returns the bottom-most disk layer in this tree.
   300  func (tree *layerTree) bottom() *diskLayer {
   301  	tree.lock.RLock()
   302  	defer tree.lock.RUnlock()
   303  
   304  	return tree.base
   305  }
   306  
   307  // lookupAccount returns the layer that is guaranteed to contain the account data
   308  // corresponding to the specified state root being queried.
   309  func (tree *layerTree) lookupAccount(accountHash common.Hash, state common.Hash) (layer, error) {
   310  	// Hold the read lock to prevent the unexpected layer changes
   311  	tree.lock.RLock()
   312  	defer tree.lock.RUnlock()
   313  
   314  	tip := tree.lookup.accountTip(accountHash, state, tree.base.root)
   315  	if tip == (common.Hash{}) {
   316  		return nil, fmt.Errorf("[%#x] %w", state, errSnapshotStale)
   317  	}
   318  	l := tree.layers[tip]
   319  	if l == nil {
   320  		return nil, fmt.Errorf("triedb layer [%#x] missing", tip)
   321  	}
   322  	return l, nil
   323  }
   324  
   325  // lookupStorage returns the layer that is guaranteed to contain the storage slot
   326  // data corresponding to the specified state root being queried.
   327  func (tree *layerTree) lookupStorage(accountHash common.Hash, slotHash common.Hash, state common.Hash) (layer, error) {
   328  	// Hold the read lock to prevent the unexpected layer changes
   329  	tree.lock.RLock()
   330  	defer tree.lock.RUnlock()
   331  
   332  	tip := tree.lookup.storageTip(accountHash, slotHash, state, tree.base.root)
   333  	if tip == (common.Hash{}) {
   334  		return nil, fmt.Errorf("[%#x] %w", state, errSnapshotStale)
   335  	}
   336  	l := tree.layers[tip]
   337  	if l == nil {
   338  		return nil, fmt.Errorf("triedb layer [%#x] missing", tip)
   339  	}
   340  	return l, nil
   341  }