github.com/ethereum/go-ethereum@v1.16.1/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  	"fmt"
    21  	"math/big"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/consensus/misc"
    25  	"github.com/ethereum/go-ethereum/core/state"
    26  	"github.com/ethereum/go-ethereum/core/tracing"
    27  	"github.com/ethereum/go-ethereum/core/types"
    28  	"github.com/ethereum/go-ethereum/core/vm"
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/params"
    31  )
    32  
    33  // StateProcessor is a basic Processor, which takes care of transitioning
    34  // state from one point to another.
    35  //
    36  // StateProcessor implements Processor.
    37  type StateProcessor struct {
    38  	config *params.ChainConfig // Chain configuration options
    39  	chain  *HeaderChain        // Canonical header chain
    40  }
    41  
    42  // NewStateProcessor initialises a new StateProcessor.
    43  func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StateProcessor {
    44  	return &StateProcessor{
    45  		config: config,
    46  		chain:  chain,
    47  	}
    48  }
    49  
    50  // Process processes the state changes according to the Ethereum rules by running
    51  // the transaction messages using the statedb and applying any rewards to both
    52  // the processor (coinbase) and any included uncles.
    53  //
    54  // Process returns the receipts and logs accumulated during the process and
    55  // returns the amount of gas that was used in the process. If any of the
    56  // transactions failed to execute due to insufficient gas it will return an error.
    57  func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
    58  	var (
    59  		receipts    types.Receipts
    60  		usedGas     = new(uint64)
    61  		header      = block.Header()
    62  		blockHash   = block.Hash()
    63  		blockNumber = block.Number()
    64  		allLogs     []*types.Log
    65  		gp          = new(GasPool).AddGas(block.GasLimit())
    66  	)
    67  
    68  	// Mutate the block and state according to any hard-fork specs
    69  	if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
    70  		misc.ApplyDAOHardFork(statedb)
    71  	}
    72  	var (
    73  		context vm.BlockContext
    74  		signer  = types.MakeSigner(p.config, header.Number, header.Time)
    75  	)
    76  
    77  	// Apply pre-execution system calls.
    78  	var tracingStateDB = vm.StateDB(statedb)
    79  	if hooks := cfg.Tracer; hooks != nil {
    80  		tracingStateDB = state.NewHookedState(statedb, hooks)
    81  	}
    82  	context = NewEVMBlockContext(header, p.chain, nil)
    83  	evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
    84  
    85  	if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
    86  		ProcessBeaconBlockRoot(*beaconRoot, evm)
    87  	}
    88  	if p.config.IsPrague(block.Number(), block.Time()) || p.config.IsVerkle(block.Number(), block.Time()) {
    89  		ProcessParentBlockHash(block.ParentHash(), evm)
    90  	}
    91  
    92  	// Iterate over and process the individual transactions
    93  	for i, tx := range block.Transactions() {
    94  		msg, err := TransactionToMessage(tx, signer, header.BaseFee)
    95  		if err != nil {
    96  			return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
    97  		}
    98  		statedb.SetTxContext(tx.Hash(), i)
    99  
   100  		receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, usedGas, evm)
   101  		if err != nil {
   102  			return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
   103  		}
   104  		receipts = append(receipts, receipt)
   105  		allLogs = append(allLogs, receipt.Logs...)
   106  	}
   107  	// Read requests if Prague is enabled.
   108  	var requests [][]byte
   109  	if p.config.IsPrague(block.Number(), block.Time()) {
   110  		requests = [][]byte{}
   111  		// EIP-6110
   112  		if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil {
   113  			return nil, err
   114  		}
   115  		// EIP-7002
   116  		if err := ProcessWithdrawalQueue(&requests, evm); err != nil {
   117  			return nil, err
   118  		}
   119  		// EIP-7251
   120  		if err := ProcessConsolidationQueue(&requests, evm); err != nil {
   121  			return nil, err
   122  		}
   123  	}
   124  
   125  	// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
   126  	p.chain.engine.Finalize(p.chain, header, tracingStateDB, block.Body())
   127  
   128  	return &ProcessResult{
   129  		Receipts: receipts,
   130  		Requests: requests,
   131  		Logs:     allLogs,
   132  		GasUsed:  *usedGas,
   133  	}, nil
   134  }
   135  
   136  // ApplyTransactionWithEVM attempts to apply a transaction to the given state database
   137  // and uses the input parameters for its environment similar to ApplyTransaction. However,
   138  // this method takes an already created EVM instance as input.
   139  func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
   140  	if hooks := evm.Config.Tracer; hooks != nil {
   141  		if hooks.OnTxStart != nil {
   142  			hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
   143  		}
   144  		if hooks.OnTxEnd != nil {
   145  			defer func() { hooks.OnTxEnd(receipt, err) }()
   146  		}
   147  	}
   148  	// Apply the transaction to the current state (included in the env).
   149  	result, err := ApplyMessage(evm, msg, gp)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	// Update the state with pending changes.
   154  	var root []byte
   155  	if evm.ChainConfig().IsByzantium(blockNumber) {
   156  		evm.StateDB.Finalise(true)
   157  	} else {
   158  		root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes()
   159  	}
   160  	*usedGas += result.UsedGas
   161  
   162  	// Merge the tx-local access event into the "block-local" one, in order to collect
   163  	// all values, so that the witness can be built.
   164  	if statedb.Database().TrieDB().IsVerkle() {
   165  		statedb.AccessEvents().Merge(evm.AccessEvents)
   166  	}
   167  	return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, *usedGas, root), nil
   168  }
   169  
   170  // MakeReceipt generates the receipt object for a transaction given its execution result.
   171  func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt {
   172  	// Create a new receipt for the transaction, storing the intermediate root and gas used
   173  	// by the tx.
   174  	receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas}
   175  	if result.Failed() {
   176  		receipt.Status = types.ReceiptStatusFailed
   177  	} else {
   178  		receipt.Status = types.ReceiptStatusSuccessful
   179  	}
   180  	receipt.TxHash = tx.Hash()
   181  	receipt.GasUsed = result.UsedGas
   182  
   183  	if tx.Type() == types.BlobTxType {
   184  		receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob)
   185  		receipt.BlobGasPrice = evm.Context.BlobBaseFee
   186  	}
   187  
   188  	// If the transaction created a contract, store the creation address in the receipt.
   189  	if tx.To() == nil {
   190  		receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
   191  	}
   192  
   193  	// Set the receipt logs and create the bloom filter.
   194  	receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash, blockTime)
   195  	receipt.Bloom = types.CreateBloom(receipt)
   196  	receipt.BlockHash = blockHash
   197  	receipt.BlockNumber = blockNumber
   198  	receipt.TransactionIndex = uint(statedb.TxIndex())
   199  	return receipt
   200  }
   201  
   202  // ApplyTransaction attempts to apply a transaction to the given state database
   203  // and uses the input parameters for its environment. It returns the receipt
   204  // for the transaction, gas used and an error if the transaction failed,
   205  // indicating the block was invalid.
   206  func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) {
   207  	msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	// Create a new context to be used in the EVM environment
   212  	return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), header.Time, tx, usedGas, evm)
   213  }
   214  
   215  // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
   216  // contract. This method is exported to be used in tests.
   217  func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
   218  	if tracer := evm.Config.Tracer; tracer != nil {
   219  		onSystemCallStart(tracer, evm.GetVMContext())
   220  		if tracer.OnSystemCallEnd != nil {
   221  			defer tracer.OnSystemCallEnd()
   222  		}
   223  	}
   224  	msg := &Message{
   225  		From:      params.SystemAddress,
   226  		GasLimit:  30_000_000,
   227  		GasPrice:  common.Big0,
   228  		GasFeeCap: common.Big0,
   229  		GasTipCap: common.Big0,
   230  		To:        &params.BeaconRootsAddress,
   231  		Data:      beaconRoot[:],
   232  	}
   233  	evm.SetTxContext(NewEVMTxContext(msg))
   234  	evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress)
   235  	_, _, _ = evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
   236  	evm.StateDB.Finalise(true)
   237  }
   238  
   239  // ProcessParentBlockHash stores the parent block hash in the history storage contract
   240  // as per EIP-2935/7709.
   241  func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
   242  	if tracer := evm.Config.Tracer; tracer != nil {
   243  		onSystemCallStart(tracer, evm.GetVMContext())
   244  		if tracer.OnSystemCallEnd != nil {
   245  			defer tracer.OnSystemCallEnd()
   246  		}
   247  	}
   248  	msg := &Message{
   249  		From:      params.SystemAddress,
   250  		GasLimit:  30_000_000,
   251  		GasPrice:  common.Big0,
   252  		GasFeeCap: common.Big0,
   253  		GasTipCap: common.Big0,
   254  		To:        &params.HistoryStorageAddress,
   255  		Data:      prevHash.Bytes(),
   256  	}
   257  	evm.SetTxContext(NewEVMTxContext(msg))
   258  	evm.StateDB.AddAddressToAccessList(params.HistoryStorageAddress)
   259  	_, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
   260  	if err != nil {
   261  		panic(err)
   262  	}
   263  	if evm.StateDB.AccessEvents() != nil {
   264  		evm.StateDB.AccessEvents().Merge(evm.AccessEvents)
   265  	}
   266  	evm.StateDB.Finalise(true)
   267  }
   268  
   269  // ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
   270  // It returns the opaque request data returned by the contract.
   271  func ProcessWithdrawalQueue(requests *[][]byte, evm *vm.EVM) error {
   272  	return processRequestsSystemCall(requests, evm, 0x01, params.WithdrawalQueueAddress)
   273  }
   274  
   275  // ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract.
   276  // It returns the opaque request data returned by the contract.
   277  func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) error {
   278  	return processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress)
   279  }
   280  
   281  func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) error {
   282  	if tracer := evm.Config.Tracer; tracer != nil {
   283  		onSystemCallStart(tracer, evm.GetVMContext())
   284  		if tracer.OnSystemCallEnd != nil {
   285  			defer tracer.OnSystemCallEnd()
   286  		}
   287  	}
   288  	msg := &Message{
   289  		From:      params.SystemAddress,
   290  		GasLimit:  30_000_000,
   291  		GasPrice:  common.Big0,
   292  		GasFeeCap: common.Big0,
   293  		GasTipCap: common.Big0,
   294  		To:        &addr,
   295  	}
   296  	evm.SetTxContext(NewEVMTxContext(msg))
   297  	evm.StateDB.AddAddressToAccessList(addr)
   298  	ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
   299  	evm.StateDB.Finalise(true)
   300  	if err != nil {
   301  		return fmt.Errorf("system call failed to execute: %v", err)
   302  	}
   303  	if len(ret) == 0 {
   304  		return nil // skip empty output
   305  	}
   306  	// Append prefixed requestsData to the requests list.
   307  	requestsData := make([]byte, len(ret)+1)
   308  	requestsData[0] = requestType
   309  	copy(requestsData[1:], ret)
   310  	*requests = append(*requests, requestsData)
   311  	return nil
   312  }
   313  
   314  var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5")
   315  
   316  // ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
   317  // BeaconDepositContract.
   318  func ParseDepositLogs(requests *[][]byte, logs []*types.Log, config *params.ChainConfig) error {
   319  	deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type)
   320  	for _, log := range logs {
   321  		if log.Address == config.DepositContractAddress && len(log.Topics) > 0 && log.Topics[0] == depositTopic {
   322  			request, err := types.DepositLogToRequest(log.Data)
   323  			if err != nil {
   324  				return fmt.Errorf("unable to parse deposit data: %v", err)
   325  			}
   326  			deposits = append(deposits, request...)
   327  		}
   328  	}
   329  	if len(deposits) > 1 {
   330  		*requests = append(*requests, deposits)
   331  	}
   332  	return nil
   333  }
   334  
   335  func onSystemCallStart(tracer *tracing.Hooks, ctx *tracing.VMContext) {
   336  	if tracer.OnSystemCallStartV2 != nil {
   337  		tracer.OnSystemCallStartV2(ctx)
   338  	} else if tracer.OnSystemCallStart != nil {
   339  		tracer.OnSystemCallStart()
   340  	}
   341  }