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  }