gitlab.com/flarenetwork/coreth@v0.1.1/core/state_transition.go (about)

     1  // (c) 2021, Flare Networks Limited. All rights reserved.
     2  //
     3  // This file is a derived work, based on the avalanchego library whose original
     4  // notices appear below. It is distributed under a license compatible with the
     5  // licensing terms of the original code from which it is derived.
     6  // Please see the file LICENSE_AVALABS for licensing terms of the original work.
     7  // Please see the file LICENSE for licensing terms.
     8  //
     9  // (c) 2019-2020, Ava Labs, Inc.
    10  //
    11  // This file is a derived work, based on the go-ethereum library whose original
    12  // notices appear below.
    13  //
    14  // It is distributed under a license compatible with the licensing terms of the
    15  // original code from which it is derived.
    16  //
    17  // Much love to the original authors for their work.
    18  // **********
    19  // Copyright 2014 The go-ethereum Authors
    20  // This file is part of the go-ethereum library.
    21  //
    22  // The go-ethereum library is free software: you can redistribute it and/or modify
    23  // it under the terms of the GNU Lesser General Public License as published by
    24  // the Free Software Foundation, either version 3 of the License, or
    25  // (at your option) any later version.
    26  //
    27  // The go-ethereum library is distributed in the hope that it will be useful,
    28  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    29  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    30  // GNU Lesser General Public License for more details.
    31  //
    32  // You should have received a copy of the GNU Lesser General Public License
    33  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    34  
    35  package core
    36  
    37  import (
    38  	"bytes"
    39  	"encoding/binary"
    40  	"fmt"
    41  	"math"
    42  	"math/big"
    43  
    44  	"github.com/ethereum/go-ethereum/common"
    45  	"github.com/ethereum/go-ethereum/crypto"
    46  	"github.com/ethereum/go-ethereum/log"
    47  
    48  	"gitlab.com/flarenetwork/coreth/core/types"
    49  	"gitlab.com/flarenetwork/coreth/core/vm"
    50  	"gitlab.com/flarenetwork/coreth/params"
    51  )
    52  
    53  var emptyCodeHash = crypto.Keccak256Hash(nil)
    54  
    55  /*
    56  The State Transitioning Model
    57  
    58  A state transition is a change made when a transaction is applied to the current world state
    59  The state transitioning model does all the necessary work to work out a valid new state root.
    60  
    61  1) Nonce handling
    62  2) Pre pay gas
    63  3) Create a new state object if the recipient is \0*32
    64  4) Value transfer
    65  == If contract creation ==
    66    4a) Attempt to run transaction data
    67    4b) If valid, use result as code for the new state object
    68  == end ==
    69  5) Run Script section
    70  6) Derive new state root
    71  */
    72  type StateTransition struct {
    73  	gp         *GasPool
    74  	msg        Message
    75  	gas        uint64
    76  	gasPrice   *big.Int
    77  	gasFeeCap  *big.Int
    78  	gasTipCap  *big.Int
    79  	initialGas uint64
    80  	value      *big.Int
    81  	data       []byte
    82  	state      vm.StateDB
    83  	evm        *vm.EVM
    84  }
    85  
    86  // Message represents a message sent to a contract.
    87  type Message interface {
    88  	From() common.Address
    89  	To() *common.Address
    90  
    91  	GasPrice() *big.Int
    92  	GasFeeCap() *big.Int
    93  	GasTipCap() *big.Int
    94  	Gas() uint64
    95  	Value() *big.Int
    96  
    97  	Nonce() uint64
    98  	IsFake() bool
    99  	Data() []byte
   100  	AccessList() types.AccessList
   101  }
   102  
   103  // ExecutionResult includes all output after executing given evm
   104  // message no matter the execution itself is successful or not.
   105  type ExecutionResult struct {
   106  	UsedGas    uint64 // Total used gas but include the refunded gas
   107  	Err        error  // Any error encountered during the execution(listed in core/vm/errors.go)
   108  	ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
   109  }
   110  
   111  // Unwrap returns the internal evm error which allows us for further
   112  // analysis outside.
   113  func (result *ExecutionResult) Unwrap() error {
   114  	return result.Err
   115  }
   116  
   117  // Failed returns the indicator whether the execution is successful or not
   118  func (result *ExecutionResult) Failed() bool { return result.Err != nil }
   119  
   120  // Return is a helper function to help caller distinguish between revert reason
   121  // and function return. Return returns the data after execution if no error occurs.
   122  func (result *ExecutionResult) Return() []byte {
   123  	if result.Err != nil {
   124  		return nil
   125  	}
   126  	return common.CopyBytes(result.ReturnData)
   127  }
   128  
   129  // Implement the EVMCaller interface on the state transition structure; simply delegate the calls
   130  func (st *StateTransition) Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
   131  	return st.evm.Call(caller, addr, input, gas, value)
   132  }
   133  
   134  func (st *StateTransition) GetBlockNumber() *big.Int {
   135  	return st.evm.Context.BlockNumber
   136  }
   137  
   138  func (st *StateTransition) GetGasLimit() uint64 {
   139  	return st.evm.Context.GasLimit
   140  }
   141  
   142  func (st *StateTransition) AddBalance(addr common.Address, amount *big.Int) {
   143  	st.state.AddBalance(addr, amount)
   144  }
   145  
   146  // Revert returns the concrete revert reason if the execution is aborted by `REVERT`
   147  // opcode. Note the reason can be nil if no data supplied with revert opcode.
   148  func (result *ExecutionResult) Revert() []byte {
   149  	if result.Err != vm.ErrExecutionReverted {
   150  		return nil
   151  	}
   152  	return common.CopyBytes(result.ReturnData)
   153  }
   154  
   155  // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
   156  func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) {
   157  	// Set the starting gas for the raw transaction
   158  	var gas uint64
   159  	if isContractCreation && isHomestead {
   160  		gas = params.TxGasContractCreation
   161  	} else {
   162  		gas = params.TxGas
   163  	}
   164  	// Bump the required gas by the amount of transactional data
   165  	if len(data) > 0 {
   166  		// Zero and non-zero bytes are priced differently
   167  		var nz uint64
   168  		for _, byt := range data {
   169  			if byt != 0 {
   170  				nz++
   171  			}
   172  		}
   173  		// Make sure we don't exceed uint64 for all data combinations
   174  		nonZeroGas := params.TxDataNonZeroGasFrontier
   175  		if isEIP2028 {
   176  			nonZeroGas = params.TxDataNonZeroGasEIP2028
   177  		}
   178  		if (math.MaxUint64-gas)/nonZeroGas < nz {
   179  			return 0, ErrGasUintOverflow
   180  		}
   181  		gas += nz * nonZeroGas
   182  
   183  		z := uint64(len(data)) - nz
   184  		if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
   185  			return 0, ErrGasUintOverflow
   186  		}
   187  		gas += z * params.TxDataZeroGas
   188  	}
   189  	if accessList != nil {
   190  		gas += uint64(len(accessList)) * params.TxAccessListAddressGas
   191  		gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
   192  	}
   193  	return gas, nil
   194  }
   195  
   196  // NewStateTransition initialises and returns a new state transition object.
   197  func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
   198  	return &StateTransition{
   199  		gp:        gp,
   200  		evm:       evm,
   201  		msg:       msg,
   202  		gasPrice:  msg.GasPrice(),
   203  		gasFeeCap: msg.GasFeeCap(),
   204  		gasTipCap: msg.GasTipCap(),
   205  		value:     msg.Value(),
   206  		data:      msg.Data(),
   207  		state:     evm.StateDB,
   208  	}
   209  }
   210  
   211  // ApplyMessage computes the new state by applying the given message
   212  // against the old state within the environment.
   213  //
   214  // ApplyMessage returns the bytes returned by any EVM execution (if it took place),
   215  // the gas used (which includes gas refunds) and an error if it failed. An error always
   216  // indicates a core error meaning that the message would always fail for that particular
   217  // state and would never be accepted within a block.
   218  func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
   219  	return NewStateTransition(evm, msg, gp).TransitionDb()
   220  }
   221  
   222  // to returns the recipient of the message.
   223  func (st *StateTransition) to() common.Address {
   224  	if st.msg == nil || st.msg.To() == nil /* contract creation */ {
   225  		return common.Address{}
   226  	}
   227  	return *st.msg.To()
   228  }
   229  
   230  func (st *StateTransition) buyGas() error {
   231  	mgval := new(big.Int).SetUint64(st.msg.Gas())
   232  	mgval = mgval.Mul(mgval, st.gasPrice)
   233  	balanceCheck := mgval
   234  	if st.gasFeeCap != nil {
   235  		balanceCheck = new(big.Int).SetUint64(st.msg.Gas())
   236  		balanceCheck.Mul(balanceCheck, st.gasFeeCap)
   237  		balanceCheck.Add(balanceCheck, st.value)
   238  	}
   239  	if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
   240  		return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want)
   241  	}
   242  	if err := st.gp.SubGas(st.msg.Gas()); err != nil {
   243  		return err
   244  	}
   245  	st.gas += st.msg.Gas()
   246  
   247  	st.initialGas = st.msg.Gas()
   248  	st.state.SubBalance(st.msg.From(), mgval)
   249  	return nil
   250  }
   251  
   252  func (st *StateTransition) preCheck() error {
   253  	// Only check transactions that are not fake
   254  	if !st.msg.IsFake() {
   255  		// Make sure this transaction's nonce is correct.
   256  		stNonce := st.state.GetNonce(st.msg.From())
   257  		if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
   258  			return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
   259  				st.msg.From().Hex(), msgNonce, stNonce)
   260  		} else if stNonce > msgNonce {
   261  			return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
   262  				st.msg.From().Hex(), msgNonce, stNonce)
   263  		}
   264  		// Make sure the sender is an EOA
   265  		if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
   266  			return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
   267  				st.msg.From().Hex(), codeHash)
   268  		}
   269  	}
   270  	// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
   271  	if st.evm.ChainConfig().IsApricotPhase3(st.evm.Context.Time) {
   272  		// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
   273  		if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 {
   274  			if l := st.gasFeeCap.BitLen(); l > 256 {
   275  				return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
   276  					st.msg.From().Hex(), l)
   277  			}
   278  			if l := st.gasTipCap.BitLen(); l > 256 {
   279  				return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
   280  					st.msg.From().Hex(), l)
   281  			}
   282  			if st.gasFeeCap.Cmp(st.gasTipCap) < 0 {
   283  				return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
   284  					st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
   285  			}
   286  			// This will panic if baseFee is nil, but basefee presence is verified
   287  			// as part of header validation.
   288  			if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
   289  				return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
   290  					st.msg.From().Hex(), st.gasFeeCap, st.evm.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 evm execution result with following fields.
   299  //
   300  // - used gas:
   301  //      total gas used (including gas being refunded)
   302  // - returndata:
   303  //      the returned data from evm
   304  // - concrete execution error:
   305  //      various **EVM** error which aborts the execution,
   306  //      e.g. ErrOutOfGas, ErrExecutionReverted
   307  //
   308  // However if any consensus issue encountered, return the error directly with
   309  // nil evm execution result.
   310  func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
   311  	// First check this message satisfies all consensus rules before
   312  	// applying the message. The rules include these clauses
   313  	//
   314  	// 1. the nonce of the message caller is correct
   315  	// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice)
   316  	// 3. the amount of gas required is available in the block
   317  	// 4. the purchased gas is enough to cover intrinsic usage
   318  	// 5. there is no overflow when calculating intrinsic gas
   319  	// 6. caller has enough balance to cover asset transfer for **topmost** call
   320  
   321  	// Check clauses 1-3, buy gas if everything is correct
   322  	if err := st.preCheck(); err != nil {
   323  		return nil, err
   324  	}
   325  	msg := st.msg
   326  	sender := vm.AccountRef(msg.From())
   327  	homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber)
   328  	istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber)
   329  	apricotPhase1 := st.evm.ChainConfig().IsApricotPhase1(st.evm.Context.Time)
   330  
   331  	contractCreation := msg.To() == nil
   332  
   333  	// Check clauses 4-5, subtract intrinsic gas if everything is correct
   334  	gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  	if st.gas < gas {
   339  		return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
   340  	}
   341  	st.gas -= gas
   342  
   343  	// Check clause 6
   344  	if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
   345  		return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
   346  	}
   347  
   348  	// Set up the initial access list.
   349  	if rules := st.evm.ChainConfig().AvalancheRules(st.evm.Context.BlockNumber, st.evm.Context.Time); rules.IsApricotPhase2 {
   350  		st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
   351  	}
   352  
   353  	var (
   354  		ret                                       []byte
   355  		vmerr                                     error // vm errors do not affect consensus and are therefore not assigned to err
   356  		selectProveDataAvailabilityPeriodFinality bool
   357  		selectProvePaymentFinality                bool
   358  		selectDisprovePaymentFinality             bool
   359  		prioritisedFTSOContract                   bool
   360  	)
   361  
   362  	if st.evm.Context.Coinbase != common.HexToAddress("0x0100000000000000000000000000000000000000") {
   363  		return nil, fmt.Errorf("Invalid value for block.coinbase")
   364  	}
   365  	if st.msg.From() == common.HexToAddress("0x0100000000000000000000000000000000000000") ||
   366  		st.msg.From() == common.HexToAddress(GetStateConnectorContractAddr(st.evm.Context.Time)) ||
   367  		st.msg.From() == common.HexToAddress(GetSystemTriggerContractAddr(st.evm.Context.Time)) {
   368  		return nil, fmt.Errorf("Invalid sender")
   369  	}
   370  	burnAddress := st.evm.Context.Coinbase
   371  	if !contractCreation {
   372  		if *msg.To() == common.HexToAddress(GetStateConnectorContractAddr(st.evm.Context.Time)) && len(st.data) >= 4 {
   373  			selectProveDataAvailabilityPeriodFinality = bytes.Equal(st.data[0:4], GetProveDataAvailabilityPeriodFinalitySelector(st.evm.Context.Time))
   374  			selectProvePaymentFinality = bytes.Equal(st.data[0:4], GetProvePaymentFinalitySelector(st.evm.Context.Time))
   375  			selectDisprovePaymentFinality = bytes.Equal(st.data[0:4], GetDisprovePaymentFinalitySelector(st.evm.Context.Time))
   376  		} else {
   377  			prioritisedFTSOContract = *msg.To() == common.HexToAddress(GetPrioritisedFTSOContract(st.evm.Context.Time))
   378  		}
   379  	}
   380  
   381  	if selectProveDataAvailabilityPeriodFinality || selectProvePaymentFinality || selectDisprovePaymentFinality {
   382  		// Increment the nonce for the next transaction
   383  		st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
   384  		stateConnectorGas := st.gas / GetStateConnectorGasDivisor(st.evm.Context.Time)
   385  		checkRet, _, checkVmerr := st.evm.Call(sender, st.to(), st.data, stateConnectorGas, st.value)
   386  		if checkVmerr == nil {
   387  			chainConfig := st.evm.ChainConfig()
   388  			if GetStateConnectorActivated(chainConfig.ChainID, st.evm.Context.Time) && binary.BigEndian.Uint32(checkRet[28:32]) < GetMaxAllowedChains(st.evm.Context.Time) {
   389  				if StateConnectorCall(msg.From(), st.evm.Context.Time, st.data[0:4], checkRet) {
   390  					originalCoinbase := st.evm.Context.Coinbase
   391  					defer func() {
   392  						st.evm.Context.Coinbase = originalCoinbase
   393  					}()
   394  					st.evm.Context.Coinbase = st.msg.From()
   395  				}
   396  			}
   397  		}
   398  		ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, stateConnectorGas, st.value)
   399  	} else {
   400  		if contractCreation {
   401  			ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value)
   402  		} else {
   403  			// Increment the nonce for the next transaction
   404  			st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
   405  			ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
   406  		}
   407  	}
   408  	st.refundGas(apricotPhase1)
   409  	if vmerr == nil && prioritisedFTSOContract {
   410  		nominalGasUsed := uint64(21000)
   411  		nominalGasPrice := uint64(225_000_000_000)
   412  		nominalFee := new(big.Int).Mul(new(big.Int).SetUint64(nominalGasUsed), new(big.Int).SetUint64(nominalGasPrice))
   413  		actualGasUsed := st.gasUsed()
   414  		actualGasPrice := st.gasPrice
   415  		actualFee := new(big.Int).Mul(new(big.Int).SetUint64(actualGasUsed), actualGasPrice)
   416  		if actualFee.Cmp(nominalFee) > 0 {
   417  			feeRefund := new(big.Int).Sub(actualFee, nominalFee)
   418  			st.state.AddBalance(st.msg.From(), feeRefund)
   419  			st.state.AddBalance(burnAddress, nominalFee)
   420  		} else {
   421  			st.state.AddBalance(burnAddress, actualFee)
   422  		}
   423  	} else {
   424  		st.state.AddBalance(burnAddress, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
   425  	}
   426  
   427  	// Call the keeper contract trigger method if there is no vm error
   428  	if vmerr == nil {
   429  		// Temporarily disable EVM debugging
   430  		oldDebug := st.evm.Config.Debug
   431  		st.evm.Config.Debug = false
   432  		// Call the keeper contract trigger
   433  		log := log.Root()
   434  		triggerKeeperAndMint(st, log)
   435  		st.evm.Config.Debug = oldDebug
   436  	}
   437  
   438  	return &ExecutionResult{
   439  		UsedGas:    st.gasUsed(),
   440  		Err:        vmerr,
   441  		ReturnData: ret,
   442  	}, nil
   443  }
   444  
   445  func (st *StateTransition) refundGas(apricotPhase1 bool) {
   446  	// Inspired by: https://gist.github.com/holiman/460f952716a74eeb9ab358bb1836d821#gistcomment-3642048
   447  	if !apricotPhase1 {
   448  		// Apply refund counter, capped to half of the used gas.
   449  		refund := st.gasUsed() / 2
   450  		if refund > st.state.GetRefund() {
   451  			refund = st.state.GetRefund()
   452  		}
   453  		st.gas += refund
   454  	}
   455  
   456  	// Return ETH for remaining gas, exchanged at the original rate.
   457  	remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.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.gas)
   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.gas
   468  }