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