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

     1  // Copyright 2024 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  	"bytes"
    21  
    22  	"github.com/VictoriaMetrics/fastcache"
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/core/rawdb"
    25  	"github.com/ethereum/go-ethereum/ethdb"
    26  	"github.com/ethereum/go-ethereum/trie/trienode"
    27  )
    28  
    29  // nodeCacheKey constructs the unique key of clean cache. The assumption is held
    30  // that zero address does not have any associated storage slots.
    31  func nodeCacheKey(owner common.Hash, path []byte) []byte {
    32  	if owner == (common.Hash{}) {
    33  		return path
    34  	}
    35  	return append(owner.Bytes(), path...)
    36  }
    37  
    38  // writeNodes writes the trie nodes into the provided database batch.
    39  // Note this function will also inject all the newly written nodes
    40  // into clean cache.
    41  func writeNodes(batch ethdb.Batch, nodes map[common.Hash]map[string]*trienode.Node, clean *fastcache.Cache) (total int) {
    42  	for owner, subset := range nodes {
    43  		for path, n := range subset {
    44  			if n.IsDeleted() {
    45  				if owner == (common.Hash{}) {
    46  					rawdb.DeleteAccountTrieNode(batch, []byte(path))
    47  				} else {
    48  					rawdb.DeleteStorageTrieNode(batch, owner, []byte(path))
    49  				}
    50  				if clean != nil {
    51  					clean.Del(nodeCacheKey(owner, []byte(path)))
    52  				}
    53  			} else {
    54  				if owner == (common.Hash{}) {
    55  					rawdb.WriteAccountTrieNode(batch, []byte(path), n.Blob)
    56  				} else {
    57  					rawdb.WriteStorageTrieNode(batch, owner, []byte(path), n.Blob)
    58  				}
    59  				if clean != nil {
    60  					clean.Set(nodeCacheKey(owner, []byte(path)), n.Blob)
    61  				}
    62  			}
    63  		}
    64  		total += len(subset)
    65  	}
    66  	return total
    67  }
    68  
    69  // writeStates flushes state mutations into the provided database batch as a whole.
    70  //
    71  // This function assumes the background generator is already terminated and states
    72  // before the supplied marker has been correctly generated.
    73  //
    74  // TODO(rjl493456442) do we really need this generation marker? The state updates
    75  // after the marker can also be written and will be fixed by generator later if
    76  // it's outdated.
    77  func writeStates(batch ethdb.Batch, genMarker []byte, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte, clean *fastcache.Cache) (int, int) {
    78  	var (
    79  		accounts int
    80  		slots    int
    81  	)
    82  	for addrHash, blob := range accountData {
    83  		// Skip any account not yet covered by the snapshot. The account
    84  		// at the generation marker position (addrHash == genMarker[:common.HashLength])
    85  		// should still be updated, as it would be skipped in the next
    86  		// generation cycle.
    87  		if genMarker != nil && bytes.Compare(addrHash[:], genMarker) > 0 {
    88  			continue
    89  		}
    90  		accounts += 1
    91  		if len(blob) == 0 {
    92  			rawdb.DeleteAccountSnapshot(batch, addrHash)
    93  			if clean != nil {
    94  				clean.Set(addrHash[:], nil)
    95  			}
    96  		} else {
    97  			rawdb.WriteAccountSnapshot(batch, addrHash, blob)
    98  			if clean != nil {
    99  				clean.Set(addrHash[:], blob)
   100  			}
   101  		}
   102  	}
   103  	for addrHash, storages := range storageData {
   104  		// Skip any account not covered yet by the snapshot
   105  		if genMarker != nil && bytes.Compare(addrHash[:], genMarker) > 0 {
   106  			continue
   107  		}
   108  		midAccount := genMarker != nil && bytes.Equal(addrHash[:], genMarker[:common.HashLength])
   109  
   110  		for storageHash, blob := range storages {
   111  			// Skip any storage slot not yet covered by the snapshot. The storage slot
   112  			// at the generation marker position (addrHash == genMarker[:common.HashLength]
   113  			// and storageHash == genMarker[common.HashLength:]) should still be updated,
   114  			// as it would be skipped in the next generation cycle.
   115  			if midAccount && bytes.Compare(storageHash[:], genMarker[common.HashLength:]) > 0 {
   116  				continue
   117  			}
   118  			slots += 1
   119  			if len(blob) == 0 {
   120  				rawdb.DeleteStorageSnapshot(batch, addrHash, storageHash)
   121  				if clean != nil {
   122  					clean.Set(append(addrHash[:], storageHash[:]...), nil)
   123  				}
   124  			} else {
   125  				rawdb.WriteStorageSnapshot(batch, addrHash, storageHash, blob)
   126  				if clean != nil {
   127  					clean.Set(append(addrHash[:], storageHash[:]...), blob)
   128  				}
   129  			}
   130  		}
   131  	}
   132  	return accounts, slots
   133  }