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