github.com/fff-chain/go-fff@v0.0.0-20220726032732-1c84420b8a99/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/fff-chain/go-fff/common" 29 "github.com/fff-chain/go-fff/common/gopool" 30 "github.com/fff-chain/go-fff/consensus" 31 "github.com/fff-chain/go-fff/consensus/misc" 32 "github.com/fff-chain/go-fff/core/rawdb" 33 "github.com/fff-chain/go-fff/core/state" 34 "github.com/fff-chain/go-fff/core/state/snapshot" 35 "github.com/fff-chain/go-fff/core/systemcontracts" 36 "github.com/fff-chain/go-fff/core/types" 37 "github.com/fff-chain/go-fff/core/vm" 38 "github.com/fff-chain/go-fff/crypto" 39 "github.com/fff-chain/go-fff/log" 40 "github.com/fff-chain/go-fff/params" 41 "github.com/fff-chain/go-fff/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 statedb.SetExpectedStateRoot(block.Root()) 127 if p.bc.pipeCommit { 128 statedb.EnablePipeCommit() 129 } 130 if err != nil { 131 return statedb, nil, nil, 0, err 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, false); 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 statedb.TryPreload(block, signer) 389 var receipts = make([]*types.Receipt, 0) 390 // Mutate the block and state according to any hard-fork specs 391 if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { 392 misc.ApplyDAOHardFork(statedb) 393 } 394 // Handle upgrade build-in system contract code 395 systemcontracts.UpgradeBuildInSystemContract(p.config, block.Number(), statedb) 396 397 blockContext := NewEVMBlockContext(header, p.bc, nil) 398 vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) 399 400 txNum := len(block.Transactions()) 401 // Iterate over and process the individual transactions 402 posa, isPoSA := p.engine.(consensus.PoSA) 403 commonTxs := make([]*types.Transaction, 0, txNum) 404 405 // initilise bloom processors 406 bloomProcessors := NewAsyncReceiptBloomGenerator(txNum) 407 statedb.MarkFullProcessed() 408 409 // usually do have two tx, one for validator set contract, another for system reward contract. 410 systemTxs := make([]*types.Transaction, 0, 2) 411 for i, tx := range block.Transactions() { 412 if isPoSA { 413 if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { 414 return statedb, nil, nil, 0, err 415 } else if isSystemTx { 416 systemTxs = append(systemTxs, tx) 417 continue 418 } 419 } 420 421 msg, err := tx.AsMessage(signer) 422 if err != nil { 423 return statedb, nil, nil, 0, err 424 } 425 statedb.Prepare(tx.Hash(), block.Hash(), i) 426 receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv, bloomProcessors) 427 if err != nil { 428 return statedb, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 429 } 430 431 commonTxs = append(commonTxs, tx) 432 receipts = append(receipts, receipt) 433 } 434 bloomProcessors.Close() 435 436 // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) 437 err := p.engine.Finalize(p.bc, header, statedb, &commonTxs, block.Uncles(), &receipts, &systemTxs, usedGas) 438 if err != nil { 439 return statedb, receipts, allLogs, *usedGas, err 440 } 441 for _, receipt := range receipts { 442 allLogs = append(allLogs, receipt.Logs...) 443 } 444 445 return statedb, receipts, allLogs, *usedGas, nil 446 } 447 448 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) { 449 // Create a new context to be used in the EVM environment. 450 txContext := NewEVMTxContext(msg) 451 evm.Reset(txContext, statedb) 452 453 // Apply the transaction to the current state (included in the env). 454 result, err := ApplyMessage(evm, msg, gp) 455 if err != nil { 456 return nil, err 457 } 458 459 // Update the state with pending changes. 460 var root []byte 461 if config.IsByzantium(header.Number) { 462 statedb.Finalise(true) 463 } else { 464 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 465 } 466 *usedGas += result.UsedGas 467 468 // Create a new receipt for the transaction, storing the intermediate root and gas used 469 // by the tx. 470 receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas} 471 if result.Failed() { 472 receipt.Status = types.ReceiptStatusFailed 473 } else { 474 receipt.Status = types.ReceiptStatusSuccessful 475 } 476 receipt.TxHash = tx.Hash() 477 receipt.GasUsed = result.UsedGas 478 479 // If the transaction created a contract, store the creation address in the receipt. 480 if msg.To() == nil { 481 receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) 482 } 483 484 // Set the receipt logs and create the bloom filter. 485 receipt.Logs = statedb.GetLogs(tx.Hash()) 486 receipt.BlockHash = statedb.BlockHash() 487 receipt.BlockNumber = header.Number 488 receipt.TransactionIndex = uint(statedb.TxIndex()) 489 for _, receiptProcessor := range receiptProcessors { 490 receiptProcessor.Apply(receipt) 491 } 492 return receipt, err 493 } 494 495 // ApplyTransaction attempts to apply a transaction to the given state database 496 // and uses the input parameters for its environment. It returns the receipt 497 // for the transaction, gas used and an error if the transaction failed, 498 // indicating the block was invalid. 499 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) { 500 msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) 501 if err != nil { 502 return nil, err 503 } 504 // Create a new context to be used in the EVM environment 505 blockContext := NewEVMBlockContext(header, bc, author) 506 vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) 507 defer func() { 508 ite := vmenv.Interpreter() 509 vm.EVMInterpreterPool.Put(ite) 510 vm.EvmPool.Put(vmenv) 511 }() 512 return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv, receiptProcessors...) 513 }