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