github.com/ethereum/go-ethereum@v1.16.1/core/state/reader.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 state 18 19 import ( 20 "errors" 21 "sync" 22 "sync/atomic" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/common/lru" 26 "github.com/ethereum/go-ethereum/core/rawdb" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/ethdb" 30 "github.com/ethereum/go-ethereum/rlp" 31 "github.com/ethereum/go-ethereum/trie" 32 "github.com/ethereum/go-ethereum/trie/utils" 33 "github.com/ethereum/go-ethereum/triedb" 34 "github.com/ethereum/go-ethereum/triedb/database" 35 ) 36 37 // ContractCodeReader defines the interface for accessing contract code. 38 type ContractCodeReader interface { 39 // Code retrieves a particular contract's code. 40 // 41 // - Returns nil code along with nil error if the requested contract code 42 // doesn't exist 43 // - Returns an error only if an unexpected issue occurs 44 Code(addr common.Address, codeHash common.Hash) ([]byte, error) 45 46 // CodeSize retrieves a particular contracts code's size. 47 // 48 // - Returns zero code size along with nil error if the requested contract code 49 // doesn't exist 50 // - Returns an error only if an unexpected issue occurs 51 CodeSize(addr common.Address, codeHash common.Hash) (int, error) 52 } 53 54 // StateReader defines the interface for accessing accounts and storage slots 55 // associated with a specific state. 56 // 57 // StateReader is assumed to be thread-safe and implementation must take care 58 // of the concurrency issue by themselves. 59 type StateReader interface { 60 // Account retrieves the account associated with a particular address. 61 // 62 // - Returns a nil account if it does not exist 63 // - Returns an error only if an unexpected issue occurs 64 // - The returned account is safe to modify after the call 65 Account(addr common.Address) (*types.StateAccount, error) 66 67 // Storage retrieves the storage slot associated with a particular account 68 // address and slot key. 69 // 70 // - Returns an empty slot if it does not exist 71 // - Returns an error only if an unexpected issue occurs 72 // - The returned storage slot is safe to modify after the call 73 Storage(addr common.Address, slot common.Hash) (common.Hash, error) 74 } 75 76 // Reader defines the interface for accessing accounts, storage slots and contract 77 // code associated with a specific state. 78 // 79 // Reader is assumed to be thread-safe and implementation must take care of the 80 // concurrency issue by themselves. 81 type Reader interface { 82 ContractCodeReader 83 StateReader 84 } 85 86 // ReaderStats wraps the statistics of reader. 87 type ReaderStats struct { 88 AccountHit int64 89 AccountMiss int64 90 StorageHit int64 91 StorageMiss int64 92 } 93 94 // ReaderWithStats wraps the additional method to retrieve the reader statistics from. 95 type ReaderWithStats interface { 96 Reader 97 GetStats() ReaderStats 98 } 99 100 // cachingCodeReader implements ContractCodeReader, accessing contract code either in 101 // local key-value store or the shared code cache. 102 // 103 // cachingCodeReader is safe for concurrent access. 104 type cachingCodeReader struct { 105 db ethdb.KeyValueReader 106 107 // These caches could be shared by multiple code reader instances, 108 // they are natively thread-safe. 109 codeCache *lru.SizeConstrainedCache[common.Hash, []byte] 110 codeSizeCache *lru.Cache[common.Hash, int] 111 } 112 113 // newCachingCodeReader constructs the code reader. 114 func newCachingCodeReader(db ethdb.KeyValueReader, codeCache *lru.SizeConstrainedCache[common.Hash, []byte], codeSizeCache *lru.Cache[common.Hash, int]) *cachingCodeReader { 115 return &cachingCodeReader{ 116 db: db, 117 codeCache: codeCache, 118 codeSizeCache: codeSizeCache, 119 } 120 } 121 122 // Code implements ContractCodeReader, retrieving a particular contract's code. 123 // If the contract code doesn't exist, no error will be returned. 124 func (r *cachingCodeReader) Code(addr common.Address, codeHash common.Hash) ([]byte, error) { 125 code, _ := r.codeCache.Get(codeHash) 126 if len(code) > 0 { 127 return code, nil 128 } 129 code = rawdb.ReadCode(r.db, codeHash) 130 if len(code) > 0 { 131 r.codeCache.Add(codeHash, code) 132 r.codeSizeCache.Add(codeHash, len(code)) 133 } 134 return code, nil 135 } 136 137 // CodeSize implements ContractCodeReader, retrieving a particular contracts code's size. 138 // If the contract code doesn't exist, no error will be returned. 139 func (r *cachingCodeReader) CodeSize(addr common.Address, codeHash common.Hash) (int, error) { 140 if cached, ok := r.codeSizeCache.Get(codeHash); ok { 141 return cached, nil 142 } 143 code, err := r.Code(addr, codeHash) 144 if err != nil { 145 return 0, err 146 } 147 return len(code), nil 148 } 149 150 // flatReader wraps a database state reader and is safe for concurrent access. 151 type flatReader struct { 152 reader database.StateReader 153 } 154 155 // newFlatReader constructs a state reader with on the given state root. 156 func newFlatReader(reader database.StateReader) *flatReader { 157 return &flatReader{reader: reader} 158 } 159 160 // Account implements StateReader, retrieving the account specified by the address. 161 // 162 // An error will be returned if the associated snapshot is already stale or 163 // the requested account is not yet covered by the snapshot. 164 // 165 // The returned account might be nil if it's not existent. 166 func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) { 167 account, err := r.reader.Account(crypto.Keccak256Hash(addr.Bytes())) 168 if err != nil { 169 return nil, err 170 } 171 if account == nil { 172 return nil, nil 173 } 174 acct := &types.StateAccount{ 175 Nonce: account.Nonce, 176 Balance: account.Balance, 177 CodeHash: account.CodeHash, 178 Root: common.BytesToHash(account.Root), 179 } 180 if len(acct.CodeHash) == 0 { 181 acct.CodeHash = types.EmptyCodeHash.Bytes() 182 } 183 if acct.Root == (common.Hash{}) { 184 acct.Root = types.EmptyRootHash 185 } 186 return acct, nil 187 } 188 189 // Storage implements StateReader, retrieving the storage slot specified by the 190 // address and slot key. 191 // 192 // An error will be returned if the associated snapshot is already stale or 193 // the requested storage slot is not yet covered by the snapshot. 194 // 195 // The returned storage slot might be empty if it's not existent. 196 func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { 197 addrHash := crypto.Keccak256Hash(addr.Bytes()) 198 slotHash := crypto.Keccak256Hash(key.Bytes()) 199 ret, err := r.reader.Storage(addrHash, slotHash) 200 if err != nil { 201 return common.Hash{}, err 202 } 203 if len(ret) == 0 { 204 return common.Hash{}, nil 205 } 206 // Perform the rlp-decode as the slot value is RLP-encoded in the state 207 // snapshot. 208 _, content, _, err := rlp.Split(ret) 209 if err != nil { 210 return common.Hash{}, err 211 } 212 var value common.Hash 213 value.SetBytes(content) 214 return value, nil 215 } 216 217 // trieReader implements the StateReader interface, providing functions to access 218 // state from the referenced trie. 219 // 220 // trieReader is safe for concurrent read. 221 type trieReader struct { 222 root common.Hash // State root which uniquely represent a state 223 db *triedb.Database // Database for loading trie 224 225 // Main trie, resolved in constructor. Note either the Merkle-Patricia-tree 226 // or Verkle-tree is not safe for concurrent read. 227 mainTrie Trie 228 229 subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved 230 subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved 231 lock sync.Mutex // Lock for protecting concurrent read 232 } 233 234 // trieReader constructs a trie reader of the specific state. An error will be 235 // returned if the associated trie specified by root is not existent. 236 func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCache) (*trieReader, error) { 237 var ( 238 tr Trie 239 err error 240 ) 241 if !db.IsVerkle() { 242 tr, err = trie.NewStateTrie(trie.StateTrieID(root), db) 243 } else { 244 tr, err = trie.NewVerkleTrie(root, db, cache) 245 } 246 if err != nil { 247 return nil, err 248 } 249 return &trieReader{ 250 root: root, 251 db: db, 252 mainTrie: tr, 253 subRoots: make(map[common.Address]common.Hash), 254 subTries: make(map[common.Address]Trie), 255 }, nil 256 } 257 258 // account is the inner version of Account and assumes the r.lock is already held. 259 func (r *trieReader) account(addr common.Address) (*types.StateAccount, error) { 260 account, err := r.mainTrie.GetAccount(addr) 261 if err != nil { 262 return nil, err 263 } 264 if account == nil { 265 r.subRoots[addr] = types.EmptyRootHash 266 } else { 267 r.subRoots[addr] = account.Root 268 } 269 return account, nil 270 } 271 272 // Account implements StateReader, retrieving the account specified by the address. 273 // 274 // An error will be returned if the trie state is corrupted. An nil account 275 // will be returned if it's not existent in the trie. 276 func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) { 277 r.lock.Lock() 278 defer r.lock.Unlock() 279 280 return r.account(addr) 281 } 282 283 // Storage implements StateReader, retrieving the storage slot specified by the 284 // address and slot key. 285 // 286 // An error will be returned if the trie state is corrupted. An empty storage 287 // slot will be returned if it's not existent in the trie. 288 func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { 289 r.lock.Lock() 290 defer r.lock.Unlock() 291 292 var ( 293 tr Trie 294 found bool 295 value common.Hash 296 ) 297 if r.db.IsVerkle() { 298 tr = r.mainTrie 299 } else { 300 tr, found = r.subTries[addr] 301 if !found { 302 root, ok := r.subRoots[addr] 303 304 // The storage slot is accessed without account caching. It's unexpected 305 // behavior but try to resolve the account first anyway. 306 if !ok { 307 _, err := r.account(addr) 308 if err != nil { 309 return common.Hash{}, err 310 } 311 root = r.subRoots[addr] 312 } 313 var err error 314 tr, err = trie.NewStateTrie(trie.StorageTrieID(r.root, crypto.Keccak256Hash(addr.Bytes()), root), r.db) 315 if err != nil { 316 return common.Hash{}, err 317 } 318 r.subTries[addr] = tr 319 } 320 } 321 ret, err := tr.GetStorage(addr, key.Bytes()) 322 if err != nil { 323 return common.Hash{}, err 324 } 325 value.SetBytes(ret) 326 return value, nil 327 } 328 329 // multiStateReader is the aggregation of a list of StateReader interface, 330 // providing state access by leveraging all readers. The checking priority 331 // is determined by the position in the reader list. 332 // 333 // multiStateReader is safe for concurrent read and assumes all underlying 334 // readers are thread-safe as well. 335 type multiStateReader struct { 336 readers []StateReader // List of state readers, sorted by checking priority 337 } 338 339 // newMultiStateReader constructs a multiStateReader instance with the given 340 // readers. The priority among readers is assumed to be sorted. Note, it must 341 // contain at least one reader for constructing a multiStateReader. 342 func newMultiStateReader(readers ...StateReader) (*multiStateReader, error) { 343 if len(readers) == 0 { 344 return nil, errors.New("empty reader set") 345 } 346 return &multiStateReader{ 347 readers: readers, 348 }, nil 349 } 350 351 // Account implementing StateReader interface, retrieving the account associated 352 // with a particular address. 353 // 354 // - Returns a nil account if it does not exist 355 // - Returns an error only if an unexpected issue occurs 356 // - The returned account is safe to modify after the call 357 func (r *multiStateReader) Account(addr common.Address) (*types.StateAccount, error) { 358 var errs []error 359 for _, reader := range r.readers { 360 acct, err := reader.Account(addr) 361 if err == nil { 362 return acct, nil 363 } 364 errs = append(errs, err) 365 } 366 return nil, errors.Join(errs...) 367 } 368 369 // Storage implementing StateReader interface, retrieving the storage slot 370 // associated with a particular account address and slot key. 371 // 372 // - Returns an empty slot if it does not exist 373 // - Returns an error only if an unexpected issue occurs 374 // - The returned storage slot is safe to modify after the call 375 func (r *multiStateReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { 376 var errs []error 377 for _, reader := range r.readers { 378 slot, err := reader.Storage(addr, slot) 379 if err == nil { 380 return slot, nil 381 } 382 errs = append(errs, err) 383 } 384 return common.Hash{}, errors.Join(errs...) 385 } 386 387 // reader is the wrapper of ContractCodeReader and StateReader interface. 388 type reader struct { 389 ContractCodeReader 390 StateReader 391 } 392 393 // newReader constructs a reader with the supplied code reader and state reader. 394 func newReader(codeReader ContractCodeReader, stateReader StateReader) *reader { 395 return &reader{ 396 ContractCodeReader: codeReader, 397 StateReader: stateReader, 398 } 399 } 400 401 // readerWithCache is a wrapper around Reader that maintains additional state caches 402 // to support concurrent state access. 403 type readerWithCache struct { 404 Reader // safe for concurrent read 405 406 // Previously resolved state entries. 407 accounts map[common.Address]*types.StateAccount 408 accountLock sync.RWMutex 409 410 // List of storage buckets, each of which is thread-safe. 411 // This reader is typically used in scenarios requiring concurrent 412 // access to storage. Using multiple buckets helps mitigate 413 // the overhead caused by locking. 414 storageBuckets [16]struct { 415 lock sync.RWMutex 416 storages map[common.Address]map[common.Hash]common.Hash 417 } 418 } 419 420 // newReaderWithCache constructs the reader with local cache. 421 func newReaderWithCache(reader Reader) *readerWithCache { 422 r := &readerWithCache{ 423 Reader: reader, 424 accounts: make(map[common.Address]*types.StateAccount), 425 } 426 for i := range r.storageBuckets { 427 r.storageBuckets[i].storages = make(map[common.Address]map[common.Hash]common.Hash) 428 } 429 return r 430 } 431 432 // account retrieves the account specified by the address along with a flag 433 // indicating whether it's found in the cache or not. The returned account 434 // might be nil if it's not existent. 435 // 436 // An error will be returned if the state is corrupted in the underlying reader. 437 func (r *readerWithCache) account(addr common.Address) (*types.StateAccount, bool, error) { 438 // Try to resolve the requested account in the local cache 439 r.accountLock.RLock() 440 acct, ok := r.accounts[addr] 441 r.accountLock.RUnlock() 442 if ok { 443 return acct, true, nil 444 } 445 // Try to resolve the requested account from the underlying reader 446 acct, err := r.Reader.Account(addr) 447 if err != nil { 448 return nil, false, err 449 } 450 r.accountLock.Lock() 451 r.accounts[addr] = acct 452 r.accountLock.Unlock() 453 return acct, false, nil 454 } 455 456 // Account implements StateReader, retrieving the account specified by the address. 457 // The returned account might be nil if it's not existent. 458 // 459 // An error will be returned if the state is corrupted in the underlying reader. 460 func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, error) { 461 account, _, err := r.account(addr) 462 return account, err 463 } 464 465 // storage retrieves the storage slot specified by the address and slot key, along 466 // with a flag indicating whether it's found in the cache or not. The returned 467 // storage slot might be empty if it's not existent. 468 func (r *readerWithCache) storage(addr common.Address, slot common.Hash) (common.Hash, bool, error) { 469 var ( 470 value common.Hash 471 ok bool 472 bucket = &r.storageBuckets[addr[0]&0x0f] 473 ) 474 // Try to resolve the requested storage slot in the local cache 475 bucket.lock.RLock() 476 slots, ok := bucket.storages[addr] 477 if ok { 478 value, ok = slots[slot] 479 } 480 bucket.lock.RUnlock() 481 if ok { 482 return value, true, nil 483 } 484 // Try to resolve the requested storage slot from the underlying reader 485 value, err := r.Reader.Storage(addr, slot) 486 if err != nil { 487 return common.Hash{}, false, err 488 } 489 bucket.lock.Lock() 490 slots, ok = bucket.storages[addr] 491 if !ok { 492 slots = make(map[common.Hash]common.Hash) 493 bucket.storages[addr] = slots 494 } 495 slots[slot] = value 496 bucket.lock.Unlock() 497 498 return value, false, nil 499 } 500 501 // Storage implements StateReader, retrieving the storage slot specified by the 502 // address and slot key. The returned storage slot might be empty if it's not 503 // existent. 504 // 505 // An error will be returned if the state is corrupted in the underlying reader. 506 func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { 507 value, _, err := r.storage(addr, slot) 508 return value, err 509 } 510 511 type readerWithCacheStats struct { 512 *readerWithCache 513 accountHit atomic.Int64 514 accountMiss atomic.Int64 515 storageHit atomic.Int64 516 storageMiss atomic.Int64 517 } 518 519 // newReaderWithCacheStats constructs the reader with additional statistics tracked. 520 func newReaderWithCacheStats(reader *readerWithCache) *readerWithCacheStats { 521 return &readerWithCacheStats{ 522 readerWithCache: reader, 523 } 524 } 525 526 // Account implements StateReader, retrieving the account specified by the address. 527 // The returned account might be nil if it's not existent. 528 // 529 // An error will be returned if the state is corrupted in the underlying reader. 530 func (r *readerWithCacheStats) Account(addr common.Address) (*types.StateAccount, error) { 531 account, incache, err := r.readerWithCache.account(addr) 532 if err != nil { 533 return nil, err 534 } 535 if incache { 536 r.accountHit.Add(1) 537 } else { 538 r.accountMiss.Add(1) 539 } 540 return account, nil 541 } 542 543 // Storage implements StateReader, retrieving the storage slot specified by the 544 // address and slot key. The returned storage slot might be empty if it's not 545 // existent. 546 // 547 // An error will be returned if the state is corrupted in the underlying reader. 548 func (r *readerWithCacheStats) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { 549 value, incache, err := r.readerWithCache.storage(addr, slot) 550 if err != nil { 551 return common.Hash{}, err 552 } 553 if incache { 554 r.storageHit.Add(1) 555 } else { 556 r.storageMiss.Add(1) 557 } 558 return value, nil 559 } 560 561 // GetStats implements ReaderWithStats, returning the statistics of state reader. 562 func (r *readerWithCacheStats) GetStats() ReaderStats { 563 return ReaderStats{ 564 AccountHit: r.accountHit.Load(), 565 AccountMiss: r.accountMiss.Load(), 566 StorageHit: r.storageHit.Load(), 567 StorageMiss: r.storageMiss.Load(), 568 } 569 }