github.com/haliliceylan/bsc@v1.1.10-0.20220501224556-eb78d644ebcb/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 "bytes" 21 "errors" 22 "fmt" 23 "math/big" 24 "math/rand" 25 "sync" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/common/gopool" 30 "github.com/ethereum/go-ethereum/consensus" 31 "github.com/ethereum/go-ethereum/consensus/misc" 32 "github.com/ethereum/go-ethereum/core/rawdb" 33 "github.com/ethereum/go-ethereum/core/state" 34 "github.com/ethereum/go-ethereum/core/state/snapshot" 35 "github.com/ethereum/go-ethereum/core/systemcontracts" 36 "github.com/ethereum/go-ethereum/core/types" 37 "github.com/ethereum/go-ethereum/core/vm" 38 "github.com/ethereum/go-ethereum/crypto" 39 "github.com/ethereum/go-ethereum/log" 40 "github.com/ethereum/go-ethereum/params" 41 "github.com/ethereum/go-ethereum/rlp" 42 ) 43 44 const ( 45 fullProcessCheck = 21 // On diff sync mode, will do full process every fullProcessCheck randomly 46 recentTime = 1024 * 3 47 recentDiffLayerTimeout = 5 48 farDiffLayerTimeout = 2 49 ) 50 51 // StateProcessor is a basic Processor, which takes care of transitioning 52 // state from one point to another. 53 // 54 // StateProcessor implements Processor. 55 type StateProcessor struct { 56 config *params.ChainConfig // Chain configuration options 57 bc *BlockChain // Canonical block chain 58 engine consensus.Engine // Consensus engine used for block rewards 59 } 60 61 // NewStateProcessor initialises a new StateProcessor. 62 func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { 63 return &StateProcessor{ 64 config: config, 65 bc: bc, 66 engine: engine, 67 } 68 } 69 70 type LightStateProcessor struct { 71 check int64 72 StateProcessor 73 } 74 75 func NewLightStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *LightStateProcessor { 76 randomGenerator := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) 77 check := randomGenerator.Int63n(fullProcessCheck) 78 return &LightStateProcessor{ 79 check: check, 80 StateProcessor: *NewStateProcessor(config, bc, engine), 81 } 82 } 83 84 func (p *LightStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) { 85 allowLightProcess := true 86 if posa, ok := p.engine.(consensus.PoSA); ok { 87 allowLightProcess = posa.AllowLightProcess(p.bc, block.Header()) 88 } 89 // random fallback to full process 90 if allowLightProcess && block.NumberU64()%fullProcessCheck != uint64(p.check) && len(block.Transactions()) != 0 { 91 var pid string 92 if peer, ok := block.ReceivedFrom.(PeerIDer); ok { 93 pid = peer.ID() 94 } 95 var diffLayer *types.DiffLayer 96 var diffLayerTimeout = recentDiffLayerTimeout 97 if time.Now().Unix()-int64(block.Time()) > recentTime { 98 diffLayerTimeout = farDiffLayerTimeout 99 } 100 for tried := 0; tried < diffLayerTimeout; tried++ { 101 // wait a bit for the diff layer 102 diffLayer = p.bc.GetUnTrustedDiffLayer(block.Hash(), pid) 103 if diffLayer != nil { 104 break 105 } 106 time.Sleep(time.Millisecond) 107 } 108 if diffLayer != nil { 109 if err := diffLayer.Receipts.DeriveFields(p.bc.chainConfig, block.Hash(), block.NumberU64(), block.Transactions()); err != nil { 110 log.Error("Failed to derive block receipts fields", "hash", block.Hash(), "number", block.NumberU64(), "err", err) 111 // fallback to full process 112 return p.StateProcessor.Process(block, statedb, cfg) 113 } 114 115 receipts, logs, gasUsed, err := p.LightProcess(diffLayer, block, statedb) 116 if err == nil { 117 log.Info("do light process success at block", "num", block.NumberU64()) 118 return statedb, receipts, logs, gasUsed, nil 119 } 120 log.Error("do light process err at block", "num", block.NumberU64(), "err", err) 121 p.bc.removeDiffLayers(diffLayer.DiffHash) 122 // prepare new statedb 123 statedb.StopPrefetcher() 124 parent := p.bc.GetHeader(block.ParentHash(), block.NumberU64()-1) 125 statedb, err = state.New(parent.Root, p.bc.stateCache, p.bc.snaps) 126 if err != nil { 127 return statedb, nil, nil, 0, err 128 } 129 statedb.SetExpectedStateRoot(block.Root()) 130 if p.bc.pipeCommit { 131 statedb.EnablePipeCommit() 132 } 133 // Enable prefetching to pull in trie node paths while processing transactions 134 statedb.StartPrefetcher("chain") 135 } 136 } 137 // fallback to full process 138 return p.StateProcessor.Process(block, statedb, cfg) 139 } 140 141 func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *types.Block, statedb *state.StateDB) (types.Receipts, []*types.Log, uint64, error) { 142 statedb.MarkLightProcessed() 143 fullDiffCode := make(map[common.Hash][]byte, len(diffLayer.Codes)) 144 diffTries := make(map[common.Address]state.Trie) 145 diffCode := make(map[common.Hash][]byte) 146 147 snapDestructs, snapAccounts, snapStorage, err := statedb.DiffLayerToSnap(diffLayer) 148 if err != nil { 149 return nil, nil, 0, err 150 } 151 152 for _, c := range diffLayer.Codes { 153 fullDiffCode[c.Hash] = c.Code 154 } 155 stateTrie, err := statedb.Trie() 156 if err != nil { 157 return nil, nil, 0, err 158 } 159 for des := range snapDestructs { 160 stateTrie.TryDelete(des[:]) 161 } 162 threads := gopool.Threads(len(snapAccounts)) 163 164 iteAccounts := make([]common.Address, 0, len(snapAccounts)) 165 for diffAccount := range snapAccounts { 166 iteAccounts = append(iteAccounts, diffAccount) 167 } 168 169 errChan := make(chan error, threads) 170 exitChan := make(chan struct{}) 171 var snapMux sync.RWMutex 172 var stateMux, diffMux sync.Mutex 173 for i := 0; i < threads; i++ { 174 start := i * len(iteAccounts) / threads 175 end := (i + 1) * len(iteAccounts) / threads 176 if i+1 == threads { 177 end = len(iteAccounts) 178 } 179 go func(start, end int) { 180 for index := start; index < end; index++ { 181 select { 182 // fast fail 183 case <-exitChan: 184 return 185 default: 186 } 187 diffAccount := iteAccounts[index] 188 snapMux.RLock() 189 blob := snapAccounts[diffAccount] 190 snapMux.RUnlock() 191 addrHash := crypto.Keccak256Hash(diffAccount[:]) 192 latestAccount, err := snapshot.FullAccount(blob) 193 if err != nil { 194 errChan <- err 195 return 196 } 197 198 // fetch previous state 199 var previousAccount state.Account 200 stateMux.Lock() 201 enc, err := stateTrie.TryGet(diffAccount[:]) 202 stateMux.Unlock() 203 if err != nil { 204 errChan <- err 205 return 206 } 207 if len(enc) != 0 { 208 if err := rlp.DecodeBytes(enc, &previousAccount); err != nil { 209 errChan <- err 210 return 211 } 212 } 213 if latestAccount.Balance == nil { 214 latestAccount.Balance = new(big.Int) 215 } 216 if previousAccount.Balance == nil { 217 previousAccount.Balance = new(big.Int) 218 } 219 if previousAccount.Root == (common.Hash{}) { 220 previousAccount.Root = types.EmptyRootHash 221 } 222 if len(previousAccount.CodeHash) == 0 { 223 previousAccount.CodeHash = types.EmptyCodeHash 224 } 225 226 // skip no change account 227 if previousAccount.Nonce == latestAccount.Nonce && 228 bytes.Equal(previousAccount.CodeHash, latestAccount.CodeHash) && 229 previousAccount.Balance.Cmp(latestAccount.Balance) == 0 && 230 previousAccount.Root == common.BytesToHash(latestAccount.Root) { 231 // It is normal to receive redundant message since the collected message is redundant. 232 log.Debug("receive redundant account change in diff layer", "account", diffAccount, "num", block.NumberU64()) 233 snapMux.Lock() 234 delete(snapAccounts, diffAccount) 235 delete(snapStorage, diffAccount) 236 snapMux.Unlock() 237 continue 238 } 239 240 // update code 241 codeHash := common.BytesToHash(latestAccount.CodeHash) 242 if !bytes.Equal(latestAccount.CodeHash, previousAccount.CodeHash) && 243 !bytes.Equal(latestAccount.CodeHash, types.EmptyCodeHash) { 244 if code, exist := fullDiffCode[codeHash]; exist { 245 if crypto.Keccak256Hash(code) != codeHash { 246 errChan <- fmt.Errorf("code and code hash mismatch, account %s", diffAccount.String()) 247 return 248 } 249 diffMux.Lock() 250 diffCode[codeHash] = code 251 diffMux.Unlock() 252 } else { 253 rawCode := rawdb.ReadCode(p.bc.db, codeHash) 254 if len(rawCode) == 0 { 255 errChan <- fmt.Errorf("missing code, account %s", diffAccount.String()) 256 return 257 } 258 } 259 } 260 261 //update storage 262 latestRoot := common.BytesToHash(latestAccount.Root) 263 if latestRoot != previousAccount.Root { 264 accountTrie, err := statedb.Database().OpenStorageTrie(addrHash, previousAccount.Root) 265 if err != nil { 266 errChan <- err 267 return 268 } 269 snapMux.RLock() 270 storageChange, exist := snapStorage[diffAccount] 271 snapMux.RUnlock() 272 273 if !exist { 274 errChan <- errors.New("missing storage change in difflayer") 275 return 276 } 277 for k, v := range storageChange { 278 if len(v) != 0 { 279 accountTrie.TryUpdate([]byte(k), v) 280 } else { 281 accountTrie.TryDelete([]byte(k)) 282 } 283 } 284 285 // check storage root 286 accountRootHash := accountTrie.Hash() 287 if latestRoot != accountRootHash { 288 errChan <- errors.New("account storage root mismatch") 289 return 290 } 291 diffMux.Lock() 292 diffTries[diffAccount] = accountTrie 293 diffMux.Unlock() 294 } else { 295 snapMux.Lock() 296 delete(snapStorage, diffAccount) 297 snapMux.Unlock() 298 } 299 300 // can't trust the blob, need encode by our-self. 301 latestStateAccount := state.Account{ 302 Nonce: latestAccount.Nonce, 303 Balance: latestAccount.Balance, 304 Root: common.BytesToHash(latestAccount.Root), 305 CodeHash: latestAccount.CodeHash, 306 } 307 bz, err := rlp.EncodeToBytes(&latestStateAccount) 308 if err != nil { 309 errChan <- err 310 return 311 } 312 stateMux.Lock() 313 err = stateTrie.TryUpdate(diffAccount[:], bz) 314 stateMux.Unlock() 315 if err != nil { 316 errChan <- err 317 return 318 } 319 } 320 errChan <- nil 321 }(start, end) 322 } 323 324 for i := 0; i < threads; i++ { 325 err := <-errChan 326 if err != nil { 327 close(exitChan) 328 return nil, nil, 0, err 329 } 330 } 331 332 var allLogs []*types.Log 333 var gasUsed uint64 334 for _, receipt := range diffLayer.Receipts { 335 allLogs = append(allLogs, receipt.Logs...) 336 gasUsed += receipt.GasUsed 337 } 338 339 // Do validate in advance so that we can fall back to full process 340 if err := p.bc.validator.ValidateState(block, statedb, diffLayer.Receipts, gasUsed); err != nil { 341 log.Error("validate state failed during diff sync", "error", err) 342 return nil, nil, 0, err 343 } 344 345 // remove redundant storage change 346 for account := range snapStorage { 347 if _, exist := snapAccounts[account]; !exist { 348 log.Warn("receive redundant storage change in diff layer") 349 delete(snapStorage, account) 350 } 351 } 352 353 // remove redundant code 354 if len(fullDiffCode) != len(diffLayer.Codes) { 355 diffLayer.Codes = make([]types.DiffCode, 0, len(diffCode)) 356 for hash, code := range diffCode { 357 diffLayer.Codes = append(diffLayer.Codes, types.DiffCode{ 358 Hash: hash, 359 Code: code, 360 }) 361 } 362 } 363 364 statedb.SetSnapData(snapDestructs, snapAccounts, snapStorage) 365 if len(snapAccounts) != len(diffLayer.Accounts) || len(snapStorage) != len(diffLayer.Storages) { 366 diffLayer.Destructs, diffLayer.Accounts, diffLayer.Storages = statedb.SnapToDiffLayer() 367 } 368 statedb.SetDiff(diffLayer, diffTries, diffCode) 369 370 return diffLayer.Receipts, allLogs, gasUsed, nil 371 } 372 373 // Process processes the state changes according to the Ethereum rules by running 374 // the transaction messages using the statedb and applying any rewards to both 375 // the processor (coinbase) and any included uncles. 376 // 377 // Process returns the receipts and logs accumulated during the process and 378 // returns the amount of gas that was used in the process. If any of the 379 // transactions failed to execute due to insufficient gas it will return an error. 380 func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) { 381 var ( 382 usedGas = new(uint64) 383 header = block.Header() 384 allLogs []*types.Log 385 gp = new(GasPool).AddGas(block.GasLimit()) 386 ) 387 signer := types.MakeSigner(p.bc.chainConfig, block.Number()) 388 var receipts = make([]*types.Receipt, 0) 389 // Mutate the block and state according to any hard-fork specs 390 if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { 391 misc.ApplyDAOHardFork(statedb) 392 } 393 // Handle upgrade build-in system contract code 394 systemcontracts.UpgradeBuildInSystemContract(p.config, block.Number(), statedb) 395 396 blockContext := NewEVMBlockContext(header, p.bc, nil) 397 vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) 398 399 txNum := len(block.Transactions()) 400 // Iterate over and process the individual transactions 401 posa, isPoSA := p.engine.(consensus.PoSA) 402 commonTxs := make([]*types.Transaction, 0, txNum) 403 404 // initilise bloom processors 405 bloomProcessors := NewAsyncReceiptBloomGenerator(txNum) 406 statedb.MarkFullProcessed() 407 408 // usually do have two tx, one for validator set contract, another for system reward contract. 409 systemTxs := make([]*types.Transaction, 0, 2) 410 for i, tx := range block.Transactions() { 411 if isPoSA { 412 if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { 413 return statedb, nil, nil, 0, err 414 } else if isSystemTx { 415 systemTxs = append(systemTxs, tx) 416 continue 417 } 418 } 419 420 msg, err := tx.AsMessage(signer) 421 if err != nil { 422 return statedb, nil, nil, 0, err 423 } 424 statedb.Prepare(tx.Hash(), block.Hash(), i) 425 receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv, bloomProcessors) 426 if err != nil { 427 return statedb, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 428 } 429 430 commonTxs = append(commonTxs, tx) 431 receipts = append(receipts, receipt) 432 } 433 bloomProcessors.Close() 434 435 // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) 436 err := p.engine.Finalize(p.bc, header, statedb, &commonTxs, block.Uncles(), &receipts, &systemTxs, usedGas) 437 if err != nil { 438 return statedb, receipts, allLogs, *usedGas, err 439 } 440 for _, receipt := range receipts { 441 allLogs = append(allLogs, receipt.Logs...) 442 } 443 444 return statedb, receipts, allLogs, *usedGas, nil 445 } 446 447 func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, receiptProcessors ...ReceiptProcessor) (*types.Receipt, error) { 448 // Create a new context to be used in the EVM environment. 449 txContext := NewEVMTxContext(msg) 450 evm.Reset(txContext, statedb) 451 452 // Apply the transaction to the current state (included in the env). 453 result, err := ApplyMessage(evm, msg, gp) 454 if err != nil { 455 return nil, err 456 } 457 458 // Update the state with pending changes. 459 var root []byte 460 if config.IsByzantium(header.Number) { 461 statedb.Finalise(true) 462 } else { 463 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 464 } 465 *usedGas += result.UsedGas 466 467 // Create a new receipt for the transaction, storing the intermediate root and gas used 468 // by the tx. 469 receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas} 470 if result.Failed() { 471 receipt.Status = types.ReceiptStatusFailed 472 } else { 473 receipt.Status = types.ReceiptStatusSuccessful 474 } 475 receipt.TxHash = tx.Hash() 476 receipt.GasUsed = result.UsedGas 477 478 // If the transaction created a contract, store the creation address in the receipt. 479 if msg.To() == nil { 480 receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) 481 } 482 483 // Set the receipt logs and create the bloom filter. 484 receipt.Logs = statedb.GetLogs(tx.Hash()) 485 receipt.BlockHash = statedb.BlockHash() 486 receipt.BlockNumber = header.Number 487 receipt.TransactionIndex = uint(statedb.TxIndex()) 488 for _, receiptProcessor := range receiptProcessors { 489 receiptProcessor.Apply(receipt) 490 } 491 return receipt, err 492 } 493 494 // ApplyTransaction attempts to apply a transaction to the given state database 495 // and uses the input parameters for its environment. It returns the receipt 496 // for the transaction, gas used and an error if the transaction failed, 497 // indicating the block was invalid. 498 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, receiptProcessors ...ReceiptProcessor) (*types.Receipt, error) { 499 msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) 500 if err != nil { 501 return nil, err 502 } 503 // Create a new context to be used in the EVM environment 504 blockContext := NewEVMBlockContext(header, bc, author) 505 vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) 506 defer func() { 507 ite := vmenv.Interpreter() 508 vm.EVMInterpreterPool.Put(ite) 509 vm.EvmPool.Put(vmenv) 510 }() 511 return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv, receiptProcessors...) 512 }