github.com/dominant-strategies/go-quai@v0.28.2/core/state_processor.go (about) 1 // Copyright 2015 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 core 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "sync" 24 "time" 25 26 "github.com/dominant-strategies/go-quai/common" 27 "github.com/dominant-strategies/go-quai/common/prque" 28 "github.com/dominant-strategies/go-quai/consensus" 29 "github.com/dominant-strategies/go-quai/core/rawdb" 30 "github.com/dominant-strategies/go-quai/core/state" 31 "github.com/dominant-strategies/go-quai/core/state/snapshot" 32 "github.com/dominant-strategies/go-quai/core/types" 33 "github.com/dominant-strategies/go-quai/core/vm" 34 "github.com/dominant-strategies/go-quai/crypto" 35 "github.com/dominant-strategies/go-quai/ethdb" 36 "github.com/dominant-strategies/go-quai/event" 37 "github.com/dominant-strategies/go-quai/log" 38 "github.com/dominant-strategies/go-quai/metrics" 39 "github.com/dominant-strategies/go-quai/params" 40 "github.com/dominant-strategies/go-quai/trie" 41 lru "github.com/hashicorp/golang-lru" 42 ) 43 44 var ( 45 accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil) 46 accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil) 47 accountUpdateTimer = metrics.NewRegisteredTimer("chain/account/updates", nil) 48 accountCommitTimer = metrics.NewRegisteredTimer("chain/account/commits", nil) 49 50 storageReadTimer = metrics.NewRegisteredTimer("chain/storage/reads", nil) 51 storageHashTimer = metrics.NewRegisteredTimer("chain/storage/hashes", nil) 52 storageUpdateTimer = metrics.NewRegisteredTimer("chain/storage/updates", nil) 53 storageCommitTimer = metrics.NewRegisteredTimer("chain/storage/commits", nil) 54 55 snapshotAccountReadTimer = metrics.NewRegisteredTimer("chain/snapshot/account/reads", nil) 56 snapshotStorageReadTimer = metrics.NewRegisteredTimer("chain/snapshot/storage/reads", nil) 57 snapshotCommitTimer = metrics.NewRegisteredTimer("chain/snapshot/commits", nil) 58 ) 59 60 const ( 61 receiptsCacheLimit = 32 62 txLookupCacheLimit = 1024 63 TriesInMemory = 128 64 65 // BlockChainVersion ensures that an incompatible database forces a resync from scratch. 66 // 67 // Changelog: 68 // 69 // - Version 4 70 // The following incompatible database changes were added: 71 // * the `BlockNumber`, `TxHash`, `TxIndex`, `BlockHash` and `Index` fields of log are deleted 72 // * the `Bloom` field of receipt is deleted 73 // * the `BlockIndex` and `TxIndex` fields of txlookup are deleted 74 // - Version 5 75 // The following incompatible database changes were added: 76 // * the `TxHash`, `GasCost`, and `ContractAddress` fields are no longer stored for a receipt 77 // * the `TxHash`, `GasCost`, and `ContractAddress` fields are computed by looking up the 78 // receipts' corresponding block 79 // - Version 6 80 // The following incompatible database changes were added: 81 // * Transaction lookup information stores the corresponding block number instead of block hash 82 // - Version 7 83 // The following incompatible database changes were added: 84 // * Use freezer as the ancient database to maintain all ancient data 85 // - Version 8 86 // The following incompatible database changes were added: 87 // * New scheme for contract code in order to separate the codes and trie nodes 88 BlockChainVersion uint64 = 8 89 ) 90 91 // CacheConfig contains the configuration values for the trie caching/pruning 92 // that's resident in a blockchain. 93 type CacheConfig struct { 94 TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory 95 TrieCleanJournal string // Disk journal for saving clean cache entries. 96 TrieCleanRejournal time.Duration // Time interval to dump clean cache to disk periodically 97 TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks 98 TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk 99 TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk 100 SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory 101 Preimages bool // Whether to store preimage of trie key to the disk 102 } 103 104 // defaultCacheConfig are the default caching values if none are specified by the 105 // user (also used during testing). 106 var defaultCacheConfig = &CacheConfig{ 107 TrieCleanLimit: 256, 108 TrieDirtyLimit: 256, 109 TrieTimeLimit: 5 * time.Minute, 110 SnapshotLimit: 256, 111 } 112 113 // StateProcessor is a basic Processor, which takes care of transitioning 114 // state from one point to another. 115 // 116 // StateProcessor implements Processor. 117 type StateProcessor struct { 118 config *params.ChainConfig // Chain configuration options 119 hc *HeaderChain // Canonical block chain 120 engine consensus.Engine // Consensus engine used for block rewards 121 logsFeed event.Feed 122 rmLogsFeed event.Feed 123 cacheConfig *CacheConfig // CacheConfig for StateProcessor 124 stateCache state.Database // State database to reuse between imports (contains state cache) 125 receiptsCache *lru.Cache // Cache for the most recent receipts per block 126 txLookupCache *lru.Cache 127 validator Validator // Block and state validator interface 128 prefetcher Prefetcher 129 vmConfig vm.Config 130 131 scope event.SubscriptionScope 132 wg sync.WaitGroup // chain processing wait group for shutting down 133 quit chan struct{} // state processor quit channel 134 txLookupLimit uint64 135 136 snaps *snapshot.Tree 137 triegc *prque.Prque // Priority queue mapping block numbers to tries to gc 138 gcproc time.Duration // Accumulates canonical block processing for trie dumping 139 } 140 141 // NewStateProcessor initialises a new StateProcessor. 142 func NewStateProcessor(config *params.ChainConfig, hc *HeaderChain, engine consensus.Engine, vmConfig vm.Config, cacheConfig *CacheConfig, txLookupLimit *uint64) *StateProcessor { 143 receiptsCache, _ := lru.New(receiptsCacheLimit) 144 txLookupCache, _ := lru.New(txLookupCacheLimit) 145 146 if cacheConfig == nil { 147 cacheConfig = defaultCacheConfig 148 } 149 150 sp := &StateProcessor{ 151 config: config, 152 hc: hc, 153 receiptsCache: receiptsCache, 154 txLookupCache: txLookupCache, 155 vmConfig: vmConfig, 156 cacheConfig: cacheConfig, 157 stateCache: state.NewDatabaseWithConfig(hc.headerDb, &trie.Config{ 158 Cache: cacheConfig.TrieCleanLimit, 159 Journal: cacheConfig.TrieCleanJournal, 160 Preimages: cacheConfig.Preimages, 161 }), 162 engine: engine, 163 triegc: prque.New(nil), 164 quit: make(chan struct{}), 165 } 166 sp.validator = NewBlockValidator(config, hc, engine) 167 168 // Load any existing snapshot, regenerating it if loading failed 169 if sp.cacheConfig.SnapshotLimit > 0 { 170 // TODO: If the state is not available, enable snapshot recovery 171 head := hc.CurrentHeader() 172 sp.snaps, _ = snapshot.New(hc.headerDb, sp.stateCache.TrieDB(), sp.cacheConfig.SnapshotLimit, head.Root(), true, false) 173 } 174 if txLookupLimit != nil { 175 sp.txLookupLimit = *txLookupLimit 176 } 177 // If periodic cache journal is required, spin it up. 178 if sp.cacheConfig.TrieCleanRejournal > 0 { 179 if sp.cacheConfig.TrieCleanRejournal < time.Minute { 180 log.Warn("Sanitizing invalid trie cache journal time", "provided", sp.cacheConfig.TrieCleanRejournal, "updated", time.Minute) 181 sp.cacheConfig.TrieCleanRejournal = time.Minute 182 } 183 triedb := sp.stateCache.TrieDB() 184 sp.wg.Add(1) 185 go func() { 186 defer sp.wg.Done() 187 triedb.SaveCachePeriodically(sp.cacheConfig.TrieCleanJournal, sp.cacheConfig.TrieCleanRejournal, sp.quit) 188 }() 189 } 190 return sp 191 } 192 193 // Process processes the state changes according to the Quai rules by running 194 // the transaction messages using the statedb and applying any rewards to both 195 // the processor (coinbase) and any included uncles. 196 // 197 // Process returns the receipts and logs accumulated during the process and 198 // returns the amount of gas that was used in the process. If any of the 199 // transactions failed to execute due to insufficient gas it will return an error. 200 func (p *StateProcessor) Process(block *types.Block, etxSet types.EtxSet) (types.Receipts, []*types.Log, *state.StateDB, uint64, error) { 201 var ( 202 receipts types.Receipts 203 usedGas = new(uint64) 204 header = types.CopyHeader(block.Header()) 205 blockHash = block.Hash() 206 blockNumber = block.Number() 207 allLogs []*types.Log 208 gp = new(GasPool).AddGas(block.GasLimit()) 209 ) 210 211 start := time.Now() 212 parent := p.hc.GetBlock(block.Header().ParentHash(), block.NumberU64()-1) 213 if parent == nil { 214 return types.Receipts{}, []*types.Log{}, nil, 0, errors.New("parent block is nil for the block given to process") 215 } 216 time1 := common.PrettyDuration(time.Since(start)) 217 218 // Initialize a statedb 219 statedb, err := state.New(parent.Header().Root(), p.stateCache, p.snaps) 220 if err != nil { 221 return types.Receipts{}, []*types.Log{}, nil, 0, err 222 } 223 time2 := common.PrettyDuration(time.Since(start)) 224 225 var timeSenders, timeSign, timePrepare, timeEtx, timeTx time.Duration 226 startTimeSenders := time.Now() 227 senders := make(map[common.Hash]*common.InternalAddress) // temporary cache for senders of internal txs 228 numInternalTxs := 0 229 p.hc.pool.SendersMutex.RLock() 230 for _, tx := range block.Transactions() { // get all senders of internal txs from cache - easier on the SendersMutex to do it all at once here 231 if tx.Type() == types.InternalTxType || tx.Type() == types.InternalToExternalTxType { 232 numInternalTxs++ 233 if sender, ok := p.hc.pool.GetSenderThreadUnsafe(tx.Hash()); ok { 234 senders[tx.Hash()] = &sender // This pointer must never be modified 235 } else { 236 // TODO: calcuate the sender and add it to the pool senders cache in case of reorg (not necessary for now) 237 } 238 } 239 } 240 p.hc.pool.SendersMutex.RUnlock() 241 timeSenders = time.Since(startTimeSenders) 242 blockContext := NewEVMBlockContext(header, p.hc, nil) 243 vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, p.vmConfig) 244 time3 := common.PrettyDuration(time.Since(start)) 245 246 // Iterate over and process the individual transactions. 247 etxRLimit := len(parent.Transactions()) / params.ETXRegionMaxFraction 248 if etxRLimit < params.ETXRLimitMin { 249 etxRLimit = params.ETXRLimitMin 250 } 251 etxPLimit := len(parent.Transactions()) / params.ETXPrimeMaxFraction 252 if etxPLimit < params.ETXPLimitMin { 253 etxPLimit = params.ETXPLimitMin 254 } 255 256 for i, tx := range block.Transactions() { 257 startProcess := time.Now() 258 msg, err := tx.AsMessageWithSender(types.MakeSigner(p.config, header.Number()), header.BaseFee(), senders[tx.Hash()]) 259 if err != nil { 260 return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 261 } 262 timeSignDelta := time.Since(startProcess) 263 timeSign += timeSignDelta 264 265 startTimePrepare := time.Now() 266 statedb.Prepare(tx.Hash(), i) 267 timePrepareDelta := time.Since(startTimePrepare) 268 timePrepare += timePrepareDelta 269 270 var receipt *types.Receipt 271 if tx.Type() == types.ExternalTxType { 272 startTimeEtx := time.Now() 273 etxEntry, exists := etxSet[tx.Hash()] 274 if !exists { // Verify that the ETX exists in the set 275 return nil, nil, nil, 0, fmt.Errorf("invalid external transaction: etx %x not found in unspent etx set", tx.Hash()) 276 } 277 prevZeroBal := prepareApplyETX(statedb, &etxEntry.ETX) 278 receipt, err = applyTransaction(msg, p.config, p.hc, nil, gp, statedb, blockNumber, blockHash, &etxEntry.ETX, usedGas, vmenv, &etxRLimit, &etxPLimit) 279 statedb.SetBalance(common.ZeroInternal, prevZeroBal) // Reset the balance to what it previously was. Residual balance will be lost 280 281 if err != nil { 282 return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, etxEntry.ETX.Hash().Hex(), err) 283 } 284 285 delete(etxSet, etxEntry.ETX.Hash()) // This ETX has been spent so remove it from the unspent set 286 timeEtxDelta := time.Since(startTimeEtx) 287 timeEtx += timeEtxDelta 288 289 } else if tx.Type() == types.InternalTxType || tx.Type() == types.InternalToExternalTxType { 290 startTimeTx := time.Now() 291 292 receipt, err = applyTransaction(msg, p.config, p.hc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, &etxRLimit, &etxPLimit) 293 if err != nil { 294 return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 295 } 296 timeTxDelta := time.Since(startTimeTx) 297 timeTx += timeTxDelta 298 } else { 299 return nil, nil, nil, 0, ErrTxTypeNotSupported 300 } 301 receipts = append(receipts, receipt) 302 allLogs = append(allLogs, receipt.Logs...) 303 i++ 304 } 305 306 time4 := common.PrettyDuration(time.Since(start)) 307 // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) 308 p.engine.Finalize(p.hc, header, statedb, block.Transactions(), block.Uncles()) 309 time5 := common.PrettyDuration(time.Since(start)) 310 311 log.Debug("Total Tx Processing Time", "signing time", common.PrettyDuration(timeSign), "prepare state time", common.PrettyDuration(timePrepare), "etx time", common.PrettyDuration(timeEtx), "tx time", common.PrettyDuration(timeTx)) 312 log.Debug("Time taken in Process", "time1", time1, "time2", time2, "time3", time3, "time4", time4, "time5", time5) 313 314 log.Debug("Total Tx Processing Time", "signing time", common.PrettyDuration(timeSign), "senders cache time", common.PrettyDuration(timeSenders), "percent cached internal txs", fmt.Sprintf("%.2f", float64(len(senders))/float64(numInternalTxs)*100), "prepare state time", common.PrettyDuration(timePrepare), "etx time", common.PrettyDuration(timeEtx), "tx time", common.PrettyDuration(timeTx)) 315 316 return receipts, allLogs, statedb, *usedGas, nil 317 } 318 319 func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, etxRLimit, etxPLimit *int) (*types.Receipt, error) { 320 // Create a new context to be used in the EVM environment. 321 txContext := NewEVMTxContext(msg) 322 evm.Reset(txContext, statedb) 323 324 // Apply the transaction to the current state (included in the env). 325 result, err := ApplyMessage(evm, msg, gp) 326 if err != nil { 327 return nil, err 328 } 329 var ETXRCount int 330 var ETXPCount int 331 for _, tx := range result.Etxs { 332 // Count which ETXs are cross-region 333 if tx.To().Location().CommonDom(common.NodeLocation).Context() == common.REGION_CTX { 334 ETXRCount++ 335 } 336 // Count which ETXs are cross-prime 337 if tx.To().Location().CommonDom(common.NodeLocation).Context() == common.PRIME_CTX { 338 ETXPCount++ 339 } 340 } 341 if ETXRCount > *etxRLimit { 342 return nil, fmt.Errorf("tx %032x emits too many cross-region ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXRCount, *etxRLimit) 343 } 344 if ETXPCount > *etxPLimit { 345 return nil, fmt.Errorf("tx %032x emits too many cross-prime ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXPCount, *etxPLimit) 346 } 347 *etxRLimit -= ETXRCount 348 *etxPLimit -= ETXPCount 349 350 // Update the state with pending changes. 351 var root []byte 352 statedb.Finalise(true) 353 354 *usedGas += result.UsedGas 355 356 // Create a new receipt for the transaction, storing the intermediate root and gas used 357 // by the tx. 358 receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas, Etxs: result.Etxs} 359 if result.Failed() { 360 receipt.Status = types.ReceiptStatusFailed 361 log.Debug(result.Err.Error()) 362 } else { 363 receipt.Status = types.ReceiptStatusSuccessful 364 } 365 receipt.TxHash = tx.Hash() 366 receipt.GasUsed = result.UsedGas 367 368 // If the transaction created a contract, store the creation address in the receipt. 369 if msg.To() == nil { 370 receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce(), tx.Data()) 371 } 372 373 // Set the receipt logs and create the bloom filter. 374 receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash) 375 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 376 receipt.BlockHash = blockHash 377 receipt.BlockNumber = blockNumber 378 receipt.TransactionIndex = uint(statedb.TxIndex()) 379 return receipt, err 380 } 381 382 var lastWrite uint64 383 384 // Apply State 385 func (p *StateProcessor) Apply(batch ethdb.Batch, block *types.Block, newInboundEtxs types.Transactions) ([]*types.Log, error) { 386 // Update the set of inbound ETXs which may be mined. This adds new inbound 387 // ETXs to the set and removes expired ETXs so they are no longer available 388 start := time.Now() 389 blockHash := block.Hash() 390 header := types.CopyHeader(block.Header()) 391 etxSet := rawdb.ReadEtxSet(p.hc.bc.db, block.ParentHash(), block.NumberU64()-1) 392 time1 := common.PrettyDuration(time.Since(start)) 393 if etxSet == nil { 394 return nil, errors.New("failed to load etx set") 395 } 396 etxSet.Update(newInboundEtxs, block.NumberU64()) 397 time2 := common.PrettyDuration(time.Since(start)) 398 // Process our block 399 receipts, logs, statedb, usedGas, err := p.Process(block, etxSet) 400 if err != nil { 401 return nil, err 402 } 403 if block.Hash() != blockHash { 404 log.Warn("Block hash changed after Processing the block", "old hash", blockHash, "new hash", block.Hash()) 405 } 406 time3 := common.PrettyDuration(time.Since(start)) 407 err = p.validator.ValidateState(block, statedb, receipts, usedGas) 408 if err != nil { 409 return nil, err 410 } 411 time4 := common.PrettyDuration(time.Since(start)) 412 rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts) 413 time4_5 := common.PrettyDuration(time.Since(start)) 414 // Create bloom filter and write it to cache/db 415 bloom := types.CreateBloom(receipts) 416 p.hc.AddBloom(bloom, block.Hash()) 417 time5 := common.PrettyDuration(time.Since(start)) 418 rawdb.WritePreimages(batch, statedb.Preimages()) 419 time6 := common.PrettyDuration(time.Since(start)) 420 // Commit all cached state changes into underlying memory database. 421 root, err := statedb.Commit(true) 422 if err != nil { 423 return nil, err 424 } 425 triedb := p.stateCache.TrieDB() 426 time7 := common.PrettyDuration(time.Since(start)) 427 var time8 common.PrettyDuration 428 var time9 common.PrettyDuration 429 var time10 common.PrettyDuration 430 var time11 common.PrettyDuration 431 if err := triedb.Commit(root, false, nil); err != nil { 432 return nil, err 433 } 434 time8 = common.PrettyDuration(time.Since(start)) 435 rawdb.WriteEtxSet(batch, header.Hash(), header.NumberU64(), etxSet) 436 time12 := common.PrettyDuration(time.Since(start)) 437 438 log.Debug("times during state processor apply:", "t1:", time1, "t2:", time2, "t3:", time3, "t4:", time4, "t4.5:", time4_5, "t5:", time5, "t6:", time6, "t7:", time7, "t8:", time8, "t9:", time9, "t10:", time10, "t11:", time11, "t12:", time12) 439 return logs, nil 440 } 441 442 // ApplyTransaction attempts to apply a transaction to the given state database 443 // and uses the input parameters for its environment. It returns the receipt 444 // for the transaction, gas used and an error if the transaction failed, 445 // indicating the block was invalid. 446 func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, etxRLimit, etxPLimit *int) (*types.Receipt, error) { 447 msg, err := tx.AsMessage(types.MakeSigner(config, header.Number()), header.BaseFee()) 448 if err != nil { 449 return nil, err 450 } 451 // Create a new context to be used in the EVM environment 452 blockContext := NewEVMBlockContext(header, bc, author) 453 vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) 454 if tx.Type() == types.ExternalTxType { 455 prevZeroBal := prepareApplyETX(statedb, tx) 456 receipt, err := applyTransaction(msg, config, bc, author, gp, statedb, header.Number(), header.Hash(), tx, usedGas, vmenv, etxRLimit, etxPLimit) 457 statedb.SetBalance(common.ZeroInternal, prevZeroBal) // Reset the balance to what it previously was (currently a failed external transaction removes all the sent coins from the supply and any residual balance is gone as well) 458 return receipt, err 459 } 460 return applyTransaction(msg, config, bc, author, gp, statedb, header.Number(), header.Hash(), tx, usedGas, vmenv, etxRLimit, etxPLimit) 461 } 462 463 // GetVMConfig returns the block chain VM config. 464 func (p *StateProcessor) GetVMConfig() *vm.Config { 465 return &p.vmConfig 466 } 467 468 // State returns a new mutable state based on the current HEAD block. 469 func (p *StateProcessor) State() (*state.StateDB, error) { 470 return p.StateAt(p.hc.GetBlockByHash(p.hc.CurrentHeader().Hash()).Root()) 471 } 472 473 // StateAt returns a new mutable state based on a particular point in time. 474 func (p *StateProcessor) StateAt(root common.Hash) (*state.StateDB, error) { 475 return state.New(root, p.stateCache, p.snaps) 476 } 477 478 // StateCache returns the caching database underpinning the blockchain instance. 479 func (p *StateProcessor) StateCache() state.Database { 480 return p.stateCache 481 } 482 483 // HasState checks if state trie is fully present in the database or not. 484 func (p *StateProcessor) HasState(hash common.Hash) bool { 485 _, err := p.stateCache.OpenTrie(hash) 486 return err == nil 487 } 488 489 // HasBlockAndState checks if a block and associated state trie is fully present 490 // in the database or not, caching it if present. 491 func (p *StateProcessor) HasBlockAndState(hash common.Hash, number uint64) bool { 492 // Check first that the block itself is known 493 block := p.hc.GetBlock(hash, number) 494 if block == nil { 495 return false 496 } 497 return p.HasState(block.Root()) 498 } 499 500 // GetReceiptsByHash retrieves the receipts for all transactions in a given block. 501 func (p *StateProcessor) GetReceiptsByHash(hash common.Hash) types.Receipts { 502 if receipts, ok := p.receiptsCache.Get(hash); ok { 503 return receipts.(types.Receipts) 504 } 505 number := rawdb.ReadHeaderNumber(p.hc.headerDb, hash) 506 if number == nil { 507 return nil 508 } 509 receipts := rawdb.ReadReceipts(p.hc.headerDb, hash, *number, p.hc.config) 510 if receipts == nil { 511 return nil 512 } 513 p.receiptsCache.Add(hash, receipts) 514 return receipts 515 } 516 517 // GetTransactionLookup retrieves the lookup associate with the given transaction 518 // hash from the cache or database. 519 func (p *StateProcessor) GetTransactionLookup(hash common.Hash) *rawdb.LegacyTxLookupEntry { 520 // Short circuit if the txlookup already in the cache, retrieve otherwise 521 if lookup, exist := p.txLookupCache.Get(hash); exist { 522 return lookup.(*rawdb.LegacyTxLookupEntry) 523 } 524 tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(p.hc.headerDb, hash) 525 if tx == nil { 526 return nil 527 } 528 lookup := &rawdb.LegacyTxLookupEntry{BlockHash: blockHash, BlockIndex: blockNumber, Index: txIndex} 529 p.txLookupCache.Add(hash, lookup) 530 return lookup 531 } 532 533 // ContractCode retrieves a blob of data associated with a contract hash 534 // either from ephemeral in-memory cache, or from persistent storage. 535 func (p *StateProcessor) ContractCode(hash common.Hash) ([]byte, error) { 536 return p.stateCache.ContractCode(common.Hash{}, hash) 537 } 538 539 // either from ephemeral in-memory cache, or from persistent storage. 540 func (p *StateProcessor) TrieNode(hash common.Hash) ([]byte, error) { 541 return p.stateCache.TrieDB().Node(hash) 542 } 543 544 // ContractCodeWithPrefix retrieves a blob of data associated with a contract 545 // hash either from ephemeral in-memory cache, or from persistent storage. 546 // 547 // If the code doesn't exist in the in-memory cache, check the storage with 548 // new code scheme. 549 func (p *StateProcessor) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { 550 type codeReader interface { 551 ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) 552 } 553 return p.stateCache.(codeReader).ContractCodeWithPrefix(common.Hash{}, hash) 554 } 555 556 // StateAtBlock retrieves the state database associated with a certain block. 557 // If no state is locally available for the given block, a number of blocks 558 // are attempted to be reexecuted to generate the desired state. The optional 559 // base layer statedb can be passed then it's regarded as the statedb of the 560 // parent block. 561 // Parameters: 562 // - block: The block for which we want the state (== state at the stateRoot of the parent) 563 // - reexec: The maximum number of blocks to reprocess trying to obtain the desired state 564 // - base: If the caller is tracing multiple blocks, the caller can provide the parent state 565 // continuously from the callsite. 566 // - checklive: if true, then the live 'blockchain' state database is used. If the caller want to 567 // perform Commit or other 'save-to-disk' changes, this should be set to false to avoid 568 // storing trash persistently 569 func (p *StateProcessor) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (statedb *state.StateDB, err error) { 570 var ( 571 current *types.Header 572 database state.Database 573 report = true 574 origin = block.NumberU64() 575 ) 576 // Check the live database first if we have the state fully available, use that. 577 if checkLive { 578 statedb, err = p.StateAt(block.Root()) 579 if err == nil { 580 return statedb, nil 581 } 582 } 583 584 var newHeads []*types.Header 585 if base != nil { 586 // The optional base statedb is given, mark the start point as parent block 587 statedb, database, report = base, base.Database(), false 588 current = p.hc.GetHeaderOrCandidate(block.ParentHash(), block.NumberU64()-1) 589 } else { 590 // Otherwise try to reexec blocks until we find a state or reach our limit 591 current = types.CopyHeader(block.Header()) 592 593 // Create an ephemeral trie.Database for isolating the live one. Otherwise 594 // the internal junks created by tracing will be persisted into the disk. 595 database = state.NewDatabaseWithConfig(p.hc.headerDb, &trie.Config{Cache: 16}) 596 597 // If we didn't check the dirty database, do check the clean one, otherwise 598 // we would rewind past a persisted block (specific corner case is chain 599 // tracing from the genesis). 600 if !checkLive { 601 statedb, err = state.New(current.Root(), database, nil) 602 if err == nil { 603 return statedb, nil 604 } 605 } 606 newHeads = append(newHeads, current) 607 // Database does not have the state for the given block, try to regenerate 608 for i := uint64(0); i < reexec; i++ { 609 if current.NumberU64() == 0 { 610 return nil, errors.New("genesis state is missing") 611 } 612 parent := p.hc.GetHeaderOrCandidate(current.ParentHash(), current.NumberU64()-1) 613 if parent == nil { 614 return nil, fmt.Errorf("missing block %v %d", current.ParentHash(), current.NumberU64()-1) 615 } 616 current = types.CopyHeader(parent) 617 618 statedb, err = state.New(current.Root(), database, nil) 619 if err == nil { 620 break 621 } 622 newHeads = append(newHeads, current) 623 } 624 if err != nil { 625 switch err.(type) { 626 case *trie.MissingNodeError: 627 return nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec) 628 default: 629 return nil, err 630 } 631 } 632 } 633 // State was available at historical point, regenerate 634 var ( 635 start = time.Now() 636 logged time.Time 637 parent common.Hash 638 ) 639 for i := len(newHeads) - 1; i >= 0; i-- { 640 current := newHeads[i] 641 // Print progress logs if long enough time elapsed 642 if time.Since(logged) > 8*time.Second && report { 643 log.Info("Regenerating historical state", "block", current.NumberU64()+1, "target", origin, "remaining", origin-current.NumberU64()-1, "elapsed", time.Since(start)) 644 logged = time.Now() 645 } 646 647 etxSet := rawdb.ReadEtxSet(p.hc.bc.db, current.ParentHash(), current.NumberU64()-1) 648 if etxSet == nil { 649 return nil, errors.New("etxSet set is nil in StateProcessor") 650 } 651 inboundEtxs := rawdb.ReadInboundEtxs(p.hc.bc.db, current.Hash()) 652 etxSet.Update(inboundEtxs, current.NumberU64()) 653 654 currentBlock := rawdb.ReadBlock(p.hc.bc.db, current.Hash(), current.NumberU64()) 655 if currentBlock == nil { 656 return nil, errors.New("detached block found trying to regenerate state") 657 } 658 _, _, _, _, err := p.Process(currentBlock, etxSet) 659 if err != nil { 660 return nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) 661 } 662 // Finalize the state so any modifications are written to the trie 663 root, err := statedb.Commit(true) 664 if err != nil { 665 return nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", 666 current.NumberU64(), current.Root().Hex(), err) 667 } 668 statedb, err = state.New(root, database, nil) 669 if err != nil { 670 return nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(), err) 671 } 672 database.TrieDB().Reference(root, common.Hash{}) 673 if parent != (common.Hash{}) { 674 database.TrieDB().Dereference(parent) 675 } 676 parent = root 677 } 678 if report { 679 nodes, imgs := database.TrieDB().Size() 680 log.Info("Historical state regenerated", "block", current.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs) 681 } 682 return statedb, nil 683 } 684 685 // stateAtTransaction returns the execution environment of a certain transaction. 686 func (p *StateProcessor) StateAtTransaction(block *types.Block, txIndex int, reexec uint64) (Message, vm.BlockContext, *state.StateDB, error) { 687 // Short circuit if it's genesis block. 688 if block.NumberU64() == 0 { 689 return nil, vm.BlockContext{}, nil, errors.New("no transaction in genesis") 690 } 691 // Create the parent state database 692 parent := p.hc.GetBlock(block.ParentHash(), block.NumberU64()-1) 693 if parent == nil { 694 return nil, vm.BlockContext{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash()) 695 } 696 // Lookup the statedb of parent block from the live database, 697 // otherwise regenerate it on the flight. 698 statedb, err := p.StateAtBlock(parent, reexec, nil, true) 699 if err != nil { 700 return nil, vm.BlockContext{}, nil, err 701 } 702 if txIndex == 0 && len(block.Transactions()) == 0 { 703 return nil, vm.BlockContext{}, statedb, nil 704 } 705 // Recompute transactions up to the target index. 706 signer := types.MakeSigner(p.hc.Config(), block.Number()) 707 for idx, tx := range block.Transactions() { 708 // Assemble the transaction call message and return if the requested offset 709 msg, _ := tx.AsMessage(signer, block.BaseFee()) 710 txContext := NewEVMTxContext(msg) 711 context := NewEVMBlockContext(block.Header(), p.hc, nil) 712 if idx == txIndex { 713 return msg, context, statedb, nil 714 } 715 // Not yet the searched for transaction, execute on top of the current state 716 vmenv := vm.NewEVM(context, txContext, statedb, p.hc.Config(), vm.Config{}) 717 statedb.Prepare(tx.Hash(), idx) 718 if _, err := ApplyMessage(vmenv, msg, new(GasPool).AddGas(tx.Gas())); err != nil { 719 return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) 720 } 721 // Ensure any modifications are committed to the state 722 statedb.Finalise(true) 723 } 724 return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) 725 } 726 727 func (p *StateProcessor) Stop() { 728 // Ensure all live cached entries be saved into disk, so that we can skip 729 // cache warmup when node restarts. 730 if p.cacheConfig.TrieCleanJournal != "" { 731 triedb := p.stateCache.TrieDB() 732 triedb.SaveCache(p.cacheConfig.TrieCleanJournal) 733 } 734 close(p.quit) 735 log.Info("State Processor stopped") 736 } 737 738 func prepareApplyETX(statedb *state.StateDB, tx *types.Transaction) *big.Int { 739 prevZeroBal := statedb.GetBalance(common.ZeroInternal) // Get current zero address balance 740 fee := big.NewInt(0).Add(tx.GasFeeCap(), tx.GasTipCap()) // Add gas price cap to miner tip cap 741 fee.Mul(fee, big.NewInt(int64(tx.Gas()))) // Multiply gas price by gas limit (may need to check for int64 overflow) 742 total := big.NewInt(0).Add(fee, tx.Value()) // Add gas fee to value 743 statedb.SetBalance(common.ZeroInternal, total) // Use zero address at temp placeholder and set it to gas fee plus value 744 return prevZeroBal 745 }