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 }