github.com/tacshi/go-ethereum@v0.0.0-20230616113857-84a434e20921/core/state_transition.go (about)

     1  // Copyright 2014 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"
    22  	"math/big"
    23  
    24  	"github.com/tacshi/go-ethereum/common"
    25  	cmath "github.com/tacshi/go-ethereum/common/math"
    26  	"github.com/tacshi/go-ethereum/core/types"
    27  	"github.com/tacshi/go-ethereum/core/vm"
    28  	"github.com/tacshi/go-ethereum/params"
    29  )
    30  
    31  // ExecutionResult includes all output after executing given evm
    32  // message no matter the execution itself is successful or not.
    33  type ExecutionResult struct {
    34  	UsedGas    uint64 // Total used gas but include the refunded gas
    35  	Err        error  // Any error encountered during the execution(listed in core/vm/errors.go)
    36  	ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
    37  
    38  	// Arbitrum: a tx may yield others that need to run afterward (see retryables)
    39  	ScheduledTxes types.Transactions
    40  	// Arbitrum: the contract deployed from the top-level transaction, or nil if not a contract creation tx
    41  	TopLevelDeployed *common.Address
    42  }
    43  
    44  // Unwrap returns the internal evm error which allows us for further
    45  // analysis outside.
    46  func (result *ExecutionResult) Unwrap() error {
    47  	return result.Err
    48  }
    49  
    50  // Failed returns the indicator whether the execution is successful or not
    51  func (result *ExecutionResult) Failed() bool { return result.Err != nil }
    52  
    53  // Return is a helper function to help caller distinguish between revert reason
    54  // and function return. Return returns the data after execution if no error occurs.
    55  func (result *ExecutionResult) Return() []byte {
    56  	if result.Err != nil {
    57  		return nil
    58  	}
    59  	return common.CopyBytes(result.ReturnData)
    60  }
    61  
    62  // Revert returns the concrete revert reason if the execution is aborted by `REVERT`
    63  // opcode. Note the reason can be nil if no data supplied with revert opcode.
    64  func (result *ExecutionResult) Revert() []byte {
    65  	if result.Err != vm.ErrExecutionReverted {
    66  		return nil
    67  	}
    68  	return common.CopyBytes(result.ReturnData)
    69  }
    70  
    71  // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
    72  func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool) (uint64, error) {
    73  	// Set the starting gas for the raw transaction
    74  	var gas uint64
    75  	if isContractCreation && isHomestead {
    76  		gas = params.TxGasContractCreation
    77  	} else {
    78  		gas = params.TxGas
    79  	}
    80  	dataLen := uint64(len(data))
    81  	// Bump the required gas by the amount of transactional data
    82  	if dataLen > 0 {
    83  		// Zero and non-zero bytes are priced differently
    84  		var nz uint64
    85  		for _, byt := range data {
    86  			if byt != 0 {
    87  				nz++
    88  			}
    89  		}
    90  		// Make sure we don't exceed uint64 for all data combinations
    91  		nonZeroGas := params.TxDataNonZeroGasFrontier
    92  		if isEIP2028 {
    93  			nonZeroGas = params.TxDataNonZeroGasEIP2028
    94  		}
    95  		if (math.MaxUint64-gas)/nonZeroGas < nz {
    96  			return 0, ErrGasUintOverflow
    97  		}
    98  		gas += nz * nonZeroGas
    99  
   100  		z := dataLen - nz
   101  		if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
   102  			return 0, ErrGasUintOverflow
   103  		}
   104  		gas += z * params.TxDataZeroGas
   105  
   106  		if isContractCreation && isEIP3860 {
   107  			lenWords := toWordSize(dataLen)
   108  			if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords {
   109  				return 0, ErrGasUintOverflow
   110  			}
   111  			gas += lenWords * params.InitCodeWordGas
   112  		}
   113  	}
   114  	if accessList != nil {
   115  		gas += uint64(len(accessList)) * params.TxAccessListAddressGas
   116  		gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
   117  	}
   118  	return gas, nil
   119  }
   120  
   121  // toWordSize returns the ceiled word size required for init code payment calculation.
   122  func toWordSize(size uint64) uint64 {
   123  	if size > math.MaxUint64-31 {
   124  		return math.MaxUint64/32 + 1
   125  	}
   126  
   127  	return (size + 31) / 32
   128  }
   129  
   130  // A Message contains the data derived from a single transaction that is relevant to state
   131  // processing.
   132  type Message struct {
   133  	// Arbitrum-specific
   134  	TxRunMode MessageRunMode
   135  	Tx        *types.Transaction
   136  
   137  	To         *common.Address
   138  	From       common.Address
   139  	Nonce      uint64
   140  	Value      *big.Int
   141  	GasLimit   uint64
   142  	GasPrice   *big.Int
   143  	GasFeeCap  *big.Int
   144  	GasTipCap  *big.Int
   145  	Data       []byte
   146  	AccessList types.AccessList
   147  
   148  	// When SkipAccountCheckss is true, the message nonce is not checked against the
   149  	// account nonce in state. It also disables checking that the sender is an EOA.
   150  	// This field will be set to true for operations like RPC eth_call.
   151  	SkipAccountChecks bool
   152  }
   153  
   154  type MessageRunMode uint8
   155  
   156  const (
   157  	MessageCommitMode MessageRunMode = iota
   158  	MessageGasEstimationMode
   159  	MessageEthcallMode
   160  )
   161  
   162  // TransactionToMessage converts a transaction into a Message.
   163  func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) {
   164  	msg := &Message{
   165  		Tx: tx,
   166  
   167  		Nonce:             tx.Nonce(),
   168  		GasLimit:          tx.Gas(),
   169  		GasPrice:          new(big.Int).Set(tx.GasPrice()),
   170  		GasFeeCap:         new(big.Int).Set(tx.GasFeeCap()),
   171  		GasTipCap:         new(big.Int).Set(tx.GasTipCap()),
   172  		To:                tx.To(),
   173  		Value:             tx.Value(),
   174  		Data:              tx.Data(),
   175  		AccessList:        tx.AccessList(),
   176  		SkipAccountChecks: tx.SkipAccountChecks(),
   177  	}
   178  	// If baseFee provided, set gasPrice to effectiveGasPrice.
   179  	if baseFee != nil {
   180  		msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap)
   181  	}
   182  	var err error
   183  	msg.From, err = types.Sender(s, tx)
   184  	return msg, err
   185  }
   186  
   187  // ApplyMessage computes the new state by applying the given message
   188  // against the old state within the environment.
   189  //
   190  // ApplyMessage returns the bytes returned by any EVM execution (if it took place),
   191  // the gas used (which includes gas refunds) and an error if it failed. An error always
   192  // indicates a core error meaning that the message would always fail for that particular
   193  // state and would never be accepted within a block.
   194  func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
   195  	return NewStateTransition(evm, msg, gp).TransitionDb()
   196  }
   197  
   198  // StateTransition represents a state transition.
   199  //
   200  // == The State Transitioning Model
   201  //
   202  // A state transition is a change made when a transaction is applied to the current world
   203  // state. The state transitioning model does all the necessary work to work out a valid new
   204  // state root.
   205  //
   206  //  1. Nonce handling
   207  //  2. Pre pay gas
   208  //  3. Create a new state object if the recipient is nil
   209  //  4. Value transfer
   210  //
   211  // == If contract creation ==
   212  //
   213  //	4a. Attempt to run transaction data
   214  //	4b. If valid, use result as code for the new state object
   215  //
   216  // == end ==
   217  //
   218  //  5. Run Script section
   219  //  6. Derive new state root
   220  type StateTransition struct {
   221  	gp           *GasPool
   222  	msg          *Message
   223  	gasRemaining uint64
   224  	initialGas   uint64
   225  	state        vm.StateDB
   226  	evm          *vm.EVM
   227  }
   228  
   229  // NewStateTransition initialises and returns a new state transition object.
   230  func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition {
   231  	if ReadyEVMForL2 != nil {
   232  		ReadyEVMForL2(evm, msg)
   233  	}
   234  
   235  	return &StateTransition{
   236  		gp:    gp,
   237  		evm:   evm,
   238  		msg:   msg,
   239  		state: evm.StateDB,
   240  	}
   241  }
   242  
   243  // to returns the recipient of the message.
   244  func (st *StateTransition) to() common.Address {
   245  	if st.msg == nil || st.msg.To == nil /* contract creation */ {
   246  		return common.Address{}
   247  	}
   248  	return *st.msg.To
   249  }
   250  
   251  func (st *StateTransition) buyGas() error {
   252  	mgval := new(big.Int).SetUint64(st.msg.GasLimit)
   253  	mgval = mgval.Mul(mgval, st.msg.GasPrice)
   254  	balanceCheck := mgval
   255  	if st.msg.GasFeeCap != nil {
   256  		balanceCheck = new(big.Int).SetUint64(st.msg.GasLimit)
   257  		balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap)
   258  		balanceCheck.Add(balanceCheck, st.msg.Value)
   259  	}
   260  	if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
   261  		return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
   262  	}
   263  	if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
   264  		return err
   265  	}
   266  	st.gasRemaining += st.msg.GasLimit
   267  
   268  	st.initialGas = st.msg.GasLimit
   269  	st.state.SubBalance(st.msg.From, mgval)
   270  
   271  	// Arbitrum: record fee payment
   272  	if st.evm.Config.Debug {
   273  		st.evm.Config.Tracer.CaptureArbitrumTransfer(st.evm, &st.msg.From, nil, mgval, true, "feePayment")
   274  	}
   275  
   276  	return nil
   277  }
   278  
   279  func (st *StateTransition) preCheck() error {
   280  	// Only check transactions that are not fake
   281  	msg := st.msg
   282  	if !msg.SkipAccountChecks {
   283  		// Make sure this transaction's nonce is correct.
   284  		stNonce := st.state.GetNonce(msg.From)
   285  		if msgNonce := msg.Nonce; stNonce < msgNonce {
   286  			return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
   287  				msg.From.Hex(), msgNonce, stNonce)
   288  		} else if stNonce > msgNonce {
   289  			return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
   290  				msg.From.Hex(), msgNonce, stNonce)
   291  		} else if stNonce+1 < stNonce {
   292  			return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
   293  				msg.From.Hex(), stNonce)
   294  		}
   295  		// Make sure the sender is an EOA
   296  		codeHash := st.state.GetCodeHash(msg.From)
   297  		if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
   298  			return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
   299  				msg.From.Hex(), codeHash)
   300  		}
   301  	}
   302  
   303  	// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
   304  	if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
   305  		// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
   306  		if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 {
   307  			if l := msg.GasFeeCap.BitLen(); l > 256 {
   308  				return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
   309  					msg.From.Hex(), l)
   310  			}
   311  			if l := msg.GasTipCap.BitLen(); l > 256 {
   312  				return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
   313  					msg.From.Hex(), l)
   314  			}
   315  			if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 {
   316  				return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
   317  					msg.From.Hex(), msg.GasTipCap, msg.GasFeeCap)
   318  			}
   319  			// This will panic if baseFee is nil, but basefee presence is verified
   320  			// as part of header validation.
   321  			if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
   322  				return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
   323  					msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
   324  			}
   325  		}
   326  	}
   327  	return st.buyGas()
   328  }
   329  
   330  // TransitionDb will transition the state by applying the current message and
   331  // returning the evm execution result with following fields.
   332  //
   333  //   - used gas: total gas used (including gas being refunded)
   334  //   - returndata: the returned data from evm
   335  //   - concrete execution error: various EVM errors which abort the execution, e.g.
   336  //     ErrOutOfGas, ErrExecutionReverted
   337  //
   338  // However if any consensus issue encountered, return the error directly with
   339  // nil evm execution result.
   340  func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
   341  	endTxNow, startHookUsedGas, err, returnData := st.evm.ProcessingHook.StartTxHook()
   342  	if endTxNow {
   343  		return &ExecutionResult{
   344  			UsedGas:       startHookUsedGas,
   345  			Err:           err,
   346  			ReturnData:    returnData,
   347  			ScheduledTxes: st.evm.ProcessingHook.ScheduledTxes(),
   348  		}, nil
   349  	}
   350  
   351  	// First check this message satisfies all consensus rules before
   352  	// applying the message. The rules include these clauses
   353  	//
   354  	// 1. the nonce of the message caller is correct
   355  	// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice)
   356  	// 3. the amount of gas required is available in the block
   357  	// 4. the purchased gas is enough to cover intrinsic usage
   358  	// 5. there is no overflow when calculating intrinsic gas
   359  	// 6. caller has enough balance to cover asset transfer for **topmost** call
   360  
   361  	// Arbitrum: drop tip for delayed (and old) messages
   362  	if st.evm.ProcessingHook.DropTip() && st.msg.GasPrice.Cmp(st.evm.Context.BaseFee) > 0 {
   363  		st.msg.GasPrice = st.evm.Context.BaseFee
   364  		st.msg.GasTipCap = common.Big0
   365  	}
   366  
   367  	// Check clauses 1-3, buy gas if everything is correct
   368  	if err := st.preCheck(); err != nil {
   369  		return nil, err
   370  	}
   371  
   372  	if st.evm.Config.Debug {
   373  		st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
   374  		defer func() {
   375  			st.evm.Config.Tracer.CaptureTxEnd(st.gasRemaining)
   376  		}()
   377  	}
   378  
   379  	var (
   380  		msg              = st.msg
   381  		sender           = vm.AccountRef(msg.From)
   382  		rules            = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time, st.evm.Context.ArbOSVersion)
   383  		contractCreation = msg.To == nil
   384  	)
   385  
   386  	// Check clauses 4-5, subtract intrinsic gas if everything is correct
   387  	gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
   388  	if err != nil {
   389  		return nil, err
   390  	}
   391  	if st.gasRemaining < gas {
   392  		return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
   393  	}
   394  	st.gasRemaining -= gas
   395  
   396  	tipAmount := big.NewInt(0)
   397  	tipReceipient, err := st.evm.ProcessingHook.GasChargingHook(&st.gasRemaining)
   398  	if err != nil {
   399  		return nil, err
   400  	}
   401  
   402  	// Check clause 6
   403  	if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) {
   404  		return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
   405  	}
   406  
   407  	// Check whether the init code size has been exceeded.
   408  	if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize {
   409  		return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize)
   410  	}
   411  
   412  	// Execute the preparatory steps for state transition which includes:
   413  	// - prepare accessList(post-berlin)
   414  	// - reset transient storage(eip 1153)
   415  	st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
   416  
   417  	var deployedContract *common.Address
   418  
   419  	var (
   420  		ret   []byte
   421  		vmerr error // vm errors do not effect consensus and are therefore not assigned to err
   422  	)
   423  	if contractCreation {
   424  		deployedContract = &common.Address{}
   425  		ret, *deployedContract, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, msg.Value)
   426  	} else {
   427  		// Increment the nonce for the next transaction
   428  		st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
   429  		ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
   430  	}
   431  
   432  	if !rules.IsLondon {
   433  		// Before EIP-3529: refunds were capped to gasUsed / 2
   434  		st.refundGas(params.RefundQuotient)
   435  	} else {
   436  		// After EIP-3529: refunds are capped to gasUsed / 5
   437  		st.refundGas(params.RefundQuotientEIP3529)
   438  	}
   439  	effectiveTip := msg.GasPrice
   440  	if rules.IsLondon {
   441  		effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee))
   442  	}
   443  
   444  	if st.evm.Config.NoBaseFee && msg.GasFeeCap.Sign() == 0 && msg.GasTipCap.Sign() == 0 {
   445  		// Skip fee payment when NoBaseFee is set and the fee fields
   446  		// are 0. This avoids a negative effectiveTip being applied to
   447  		// the coinbase when simulating calls.
   448  	} else {
   449  		fee := new(big.Int).SetUint64(st.gasUsed())
   450  		fee.Mul(fee, effectiveTip)
   451  		st.state.AddBalance(tipReceipient, fee)
   452  		tipAmount = fee
   453  	}
   454  
   455  	// Arbitrum: record the tip
   456  	if st.evm.Config.Debug && !st.evm.ProcessingHook.DropTip() {
   457  		st.evm.Config.Tracer.CaptureArbitrumTransfer(st.evm, nil, &tipReceipient, tipAmount, false, "tip")
   458  	}
   459  
   460  	st.evm.ProcessingHook.EndTxHook(st.gasRemaining, vmerr == nil)
   461  
   462  	// Arbitrum: record self destructs
   463  	if st.evm.Config.Debug {
   464  		suicides := st.evm.StateDB.GetSuicides()
   465  		for i, address := range suicides {
   466  			balance := st.evm.StateDB.GetBalance(address)
   467  			st.evm.Config.Tracer.CaptureArbitrumTransfer(st.evm, &suicides[i], nil, balance, false, "selfDestruct")
   468  		}
   469  	}
   470  
   471  	return &ExecutionResult{
   472  		UsedGas:          st.gasUsed(),
   473  		Err:              vmerr,
   474  		ReturnData:       ret,
   475  		ScheduledTxes:    st.evm.ProcessingHook.ScheduledTxes(),
   476  		TopLevelDeployed: deployedContract,
   477  	}, nil
   478  }
   479  
   480  func (st *StateTransition) refundGas(refundQuotient uint64) {
   481  	st.gasRemaining += st.evm.ProcessingHook.ForceRefundGas()
   482  
   483  	nonrefundable := st.evm.ProcessingHook.NonrefundableGas()
   484  	if nonrefundable < st.gasUsed() {
   485  		// Apply refund counter, capped to a refund quotient
   486  		refund := (st.gasUsed() - nonrefundable) / refundQuotient
   487  		if refund > st.state.GetRefund() {
   488  			refund = st.state.GetRefund()
   489  		}
   490  		st.gasRemaining += refund
   491  	}
   492  
   493  	// Return ETH for remaining gas, exchanged at the original rate.
   494  	remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
   495  	st.state.AddBalance(st.msg.From, remaining)
   496  
   497  	// Arbitrum: record the gas refund
   498  	if st.evm.Config.Debug {
   499  		st.evm.Config.Tracer.CaptureArbitrumTransfer(st.evm, nil, &st.msg.From, remaining, false, "gasRefund")
   500  	}
   501  
   502  	// Also return remaining gas to the block gas counter so it is
   503  	// available for the next transaction.
   504  	st.gp.AddGas(st.gasRemaining)
   505  }
   506  
   507  // gasUsed returns the amount of gas used up by the state transition.
   508  func (st *StateTransition) gasUsed() uint64 {
   509  	return st.initialGas - st.gasRemaining
   510  }