github.com/klaytn/klaytn@v1.10.2/blockchain/state_transition.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2014 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from core/state_transition.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package blockchain
    22  
    23  import (
    24  	"errors"
    25  	"math/big"
    26  
    27  	"github.com/klaytn/klaytn/blockchain/types"
    28  	"github.com/klaytn/klaytn/blockchain/vm"
    29  	"github.com/klaytn/klaytn/common"
    30  	"github.com/klaytn/klaytn/kerrors"
    31  	"github.com/klaytn/klaytn/params"
    32  )
    33  
    34  var (
    35  	errInsufficientBalanceForGas         = errors.New("insufficient balance of the sender to pay for gas")
    36  	errInsufficientBalanceForGasFeePayer = errors.New("insufficient balance of the fee payer to pay for gas")
    37  	errNotProgramAccount                 = errors.New("not a program account")
    38  	errAccountAlreadyExists              = errors.New("account already exists")
    39  	errMsgToNil                          = errors.New("msg.To() is nil")
    40  	errInvalidCodeFormat                 = errors.New("smart contract code format is invalid")
    41  )
    42  
    43  /*
    44  The State Transitioning Model
    45  
    46  A state transition is a change made when a transaction is applied to the current world state
    47  The state transitioning model does all the necessary work to work out a valid new state root.
    48  
    49  1) Nonce handling
    50  2) Pre pay gas
    51  3) Create a new state object if the recipient is \0*32
    52  4) Value transfer
    53  == If contract creation ==
    54    4a) Attempt to run transaction data
    55    4b) If valid, use result as code for the new state object
    56  == end ==
    57  5) Run Script section
    58  6) Derive new state root
    59  */
    60  type StateTransition struct {
    61  	msg        Message
    62  	gas        uint64
    63  	gasPrice   *big.Int
    64  	gasTipCap  *big.Int
    65  	gasFeeCap  *big.Int
    66  	initialGas uint64
    67  	value      *big.Int
    68  	data       []byte
    69  	state      vm.StateDB
    70  	evm        *vm.EVM
    71  }
    72  
    73  // Message represents a message sent to a contract.
    74  type Message interface {
    75  	// ValidatedSender returns the sender of the transaction.
    76  	// The returned sender should be derived by calling AsMessageAccountKeyPicker().
    77  	ValidatedSender() common.Address
    78  
    79  	// ValidatedFeePayer returns the fee payer of the transaction.
    80  	// The returned fee payer should be derived by calling AsMessageAccountKeyPicker().
    81  	ValidatedFeePayer() common.Address
    82  
    83  	// ValidatedIntrinsicGas returns the intrinsic gas of the transaction.
    84  	// The returned intrinsic gas should be derived by calling AsMessageAccountKeyPicker().
    85  	ValidatedIntrinsicGas() uint64
    86  
    87  	// FeeRatio returns a ratio of tx fee paid by the fee payer in percentage.
    88  	// For example, if it is 30, 30% of tx fee will be paid by the fee payer.
    89  	// 70% will be paid by the sender.
    90  	FeeRatio() (types.FeeRatio, bool)
    91  
    92  	// FromFrontier() (common.Address, error)
    93  	To() *common.Address
    94  
    95  	Hash() common.Hash
    96  
    97  	GasPrice() *big.Int
    98  
    99  	// For TxTypeEthereumDynamicFee
   100  	GasTipCap() *big.Int
   101  	GasFeeCap() *big.Int
   102  	EffectiveGasTip(baseFee *big.Int) *big.Int
   103  	EffectiveGasPrice(header *types.Header) *big.Int
   104  
   105  	Gas() uint64
   106  	Value() *big.Int
   107  
   108  	Nonce() uint64
   109  	CheckNonce() bool
   110  	Data() []byte
   111  
   112  	// IntrinsicGas returns `intrinsic gas` based on the tx type.
   113  	// This value is used to differentiate tx fee based on the tx type.
   114  	IntrinsicGas(currentBlockNumber uint64) (uint64, error)
   115  
   116  	// Type returns the transaction type of the message.
   117  	Type() types.TxType
   118  
   119  	// Validate performs additional validation for each transaction type
   120  	Validate(stateDB types.StateDB, currentBlockNumber uint64) error
   121  
   122  	// Execute performs execution of the transaction according to the transaction type.
   123  	Execute(vm types.VM, stateDB types.StateDB, currentBlockNumber uint64, gas uint64, value *big.Int) ([]byte, uint64, error)
   124  }
   125  
   126  // TODO-Klaytn Later we can merge Err and Status into one uniform error.
   127  //         This might require changing overall error handling mechanism in Klaytn.
   128  // Klaytn error type
   129  // - Status: Indicate status of transaction after execution.
   130  //           This value will be stored in Receipt if Receipt is available.
   131  //           Please see getReceiptStatusFromErrTxFailed() how this value is calculated.
   132  type kerror struct {
   133  	ErrTxInvalid error
   134  	Status       uint
   135  }
   136  
   137  // NewStateTransition initialises and returns a new state transition object.
   138  func NewStateTransition(evm *vm.EVM, msg Message) *StateTransition {
   139  	// before magma hardfork, effectiveGasPrice is  GasPrice of tx
   140  	// after magma hardfork, effectiveGasPrice is BaseFee
   141  	effectiveGasPrice := evm.Context.GasPrice
   142  
   143  	return &StateTransition{
   144  		evm:       evm,
   145  		msg:       msg,
   146  		gasPrice:  effectiveGasPrice,
   147  		gasFeeCap: msg.GasFeeCap(),
   148  		gasTipCap: msg.GasTipCap(),
   149  		value:     msg.Value(),
   150  		data:      msg.Data(),
   151  		state:     evm.StateDB,
   152  	}
   153  }
   154  
   155  // ApplyMessage computes the new state by applying the given message
   156  // against the old state within the environment.
   157  //
   158  // ApplyMessage returns the bytes returned by any EVM execution (if it took place),
   159  // the gas used (which includes gas refunds) and an error if it failed. An error always
   160  // indicates a core error meaning that the message would always fail for that particular
   161  // state and would never be accepted within a block.
   162  func ApplyMessage(evm *vm.EVM, msg Message) ([]byte, uint64, kerror) {
   163  	return NewStateTransition(evm, msg).TransitionDb()
   164  }
   165  
   166  // to returns the recipient of the message.
   167  func (st *StateTransition) to() common.Address {
   168  	if st.msg == nil || st.msg.To() == nil /* contract creation */ {
   169  		return common.Address{}
   170  	}
   171  	return *st.msg.To()
   172  }
   173  
   174  func (st *StateTransition) useGas(amount uint64) error {
   175  	if st.gas < amount {
   176  		return kerrors.ErrOutOfGas
   177  	}
   178  	st.gas -= amount
   179  
   180  	return nil
   181  }
   182  
   183  func (st *StateTransition) buyGas() error {
   184  	// st.gasPrice : gasPrice user set before magma hardfork
   185  	// st.gasPrice : BaseFee after magma hardfork
   186  	mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice)
   187  
   188  	validatedFeePayer := st.msg.ValidatedFeePayer()
   189  	validatedSender := st.msg.ValidatedSender()
   190  	feeRatio, isRatioTx := st.msg.FeeRatio()
   191  	if isRatioTx {
   192  		feePayerFee, senderFee := types.CalcFeeWithRatio(feeRatio, mgval)
   193  
   194  		if st.state.GetBalance(validatedFeePayer).Cmp(feePayerFee) < 0 {
   195  			logger.Debug(errInsufficientBalanceForGasFeePayer.Error(), "feePayer", validatedFeePayer.String(),
   196  				"feePayerBalance", st.state.GetBalance(validatedFeePayer).Uint64(), "feePayerFee", feePayerFee.Uint64(),
   197  				"txHash", st.msg.Hash().String())
   198  			return errInsufficientBalanceForGasFeePayer
   199  		}
   200  
   201  		if st.state.GetBalance(validatedSender).Cmp(senderFee) < 0 {
   202  			logger.Debug(errInsufficientBalanceForGas.Error(), "sender", validatedSender.String(),
   203  				"senderBalance", st.state.GetBalance(validatedSender).Uint64(), "senderFee", senderFee.Uint64(),
   204  				"txHash", st.msg.Hash().String())
   205  			return errInsufficientBalanceForGas
   206  		}
   207  
   208  		st.state.SubBalance(validatedFeePayer, feePayerFee)
   209  		st.state.SubBalance(validatedSender, senderFee)
   210  	} else {
   211  		// to make a short circuit, process the special case feeRatio == MaxFeeRatio
   212  		if st.state.GetBalance(validatedFeePayer).Cmp(mgval) < 0 {
   213  			logger.Debug(errInsufficientBalanceForGasFeePayer.Error(), "feePayer", validatedFeePayer.String(),
   214  				"feePayerBalance", st.state.GetBalance(validatedFeePayer).Uint64(), "feePayerFee", mgval.Uint64(),
   215  				"txHash", st.msg.Hash().String())
   216  			return errInsufficientBalanceForGasFeePayer
   217  		}
   218  
   219  		st.state.SubBalance(validatedFeePayer, mgval)
   220  	}
   221  
   222  	st.gas += st.msg.Gas()
   223  
   224  	st.initialGas = st.msg.Gas()
   225  	return nil
   226  }
   227  
   228  func (st *StateTransition) preCheck() error {
   229  	// Make sure this transaction's nonce is correct.
   230  	if st.msg.CheckNonce() {
   231  		nonce := st.state.GetNonce(st.msg.ValidatedSender())
   232  		if nonce < st.msg.Nonce() {
   233  			logger.Debug(ErrNonceTooHigh.Error(), "account", st.msg.ValidatedSender().String(),
   234  				"accountNonce", nonce, "txNonce", st.msg.Nonce(), "txHash", st.msg.Hash().String())
   235  			return ErrNonceTooHigh
   236  		} else if nonce > st.msg.Nonce() {
   237  			logger.Debug(ErrNonceTooLow.Error(), "account", st.msg.ValidatedSender().String(),
   238  				"accountNonce", nonce, "txNonce", st.msg.Nonce(), "txHash", st.msg.Hash().String())
   239  			return ErrNonceTooLow
   240  		}
   241  	}
   242  	return st.buyGas()
   243  }
   244  
   245  // TransitionDb will transition the state by applying the current message and
   246  // returning the result including the used gas. It returns an error if failed.
   247  // An error indicates a consensus issue.
   248  func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, kerr kerror) {
   249  	if st.evm.IsPrefetching() {
   250  		st.gas = st.msg.Gas()
   251  	} else {
   252  		if kerr.ErrTxInvalid = st.preCheck(); kerr.ErrTxInvalid != nil {
   253  			return
   254  		}
   255  	}
   256  
   257  	msg := st.msg
   258  
   259  	// Pay intrinsic gas.
   260  	if kerr.ErrTxInvalid = st.useGas(msg.ValidatedIntrinsicGas()); kerr.ErrTxInvalid != nil {
   261  		kerr.Status = getReceiptStatusFromErrTxFailed(nil)
   262  		return nil, 0, kerr
   263  	}
   264  
   265  	rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber)
   266  	if rules.IsKore {
   267  		st.state.PrepareAccessList(msg.ValidatedSender(), msg.ValidatedFeePayer(), msg.To(), vm.ActivePrecompiles(rules))
   268  	}
   269  	// vm errors do not effect consensus and are therefor
   270  	// not assigned to err, except for insufficient balance
   271  	// error and total time limit reached error.
   272  	var errTxFailed error
   273  
   274  	ret, st.gas, errTxFailed = msg.Execute(st.evm, st.state, st.evm.BlockNumber.Uint64(), st.gas, st.value)
   275  
   276  	if errTxFailed != nil {
   277  		logger.Debug("VM returned with error", "err", errTxFailed, "txHash", st.msg.Hash().String())
   278  		// The only possible consensus-error would be if there wasn't
   279  		// sufficient balance to make the transfer happen. The first
   280  		// balance transfer may never fail.
   281  		// Another possible errTxFailed could be a time-limit error that happens
   282  		// when the EVM is still running while the block proposer's total
   283  		// execution time of txs for a candidate block reached the predefined
   284  		// limit.
   285  		if errTxFailed == vm.ErrInsufficientBalance || errTxFailed == vm.ErrTotalTimeLimitReached {
   286  			kerr.ErrTxInvalid = errTxFailed
   287  			kerr.Status = getReceiptStatusFromErrTxFailed(nil)
   288  			return nil, 0, kerr
   289  		}
   290  	}
   291  
   292  	if rules.IsKore {
   293  		// After EIP-3529: refunds are capped to gasUsed / 5
   294  		st.refundGas(params.RefundQuotientEIP3529)
   295  	} else {
   296  		// Before EIP-3529: refunds were capped to gasUsed / 2
   297  		st.refundGas(params.RefundQuotient)
   298  	}
   299  
   300  	// Defer transferring Tx fee when DeferredTxFee is true
   301  	if st.evm.ChainConfig().Governance == nil || !st.evm.ChainConfig().Governance.DeferredTxFee() {
   302  		effectiveGasPrice := msg.EffectiveGasPrice(nil)
   303  		st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveGasPrice))
   304  	}
   305  
   306  	kerr.ErrTxInvalid = nil
   307  	kerr.Status = getReceiptStatusFromErrTxFailed(errTxFailed)
   308  	return ret, st.gasUsed(), kerr
   309  }
   310  
   311  var errTxFailed2receiptstatus = map[error]uint{
   312  	nil:                                             types.ReceiptStatusSuccessful,
   313  	vm.ErrDepth:                                     types.ReceiptStatusErrDepth,
   314  	vm.ErrContractAddressCollision:                  types.ReceiptStatusErrContractAddressCollision,
   315  	vm.ErrCodeStoreOutOfGas:                         types.ReceiptStatusErrCodeStoreOutOfGas,
   316  	vm.ErrMaxCodeSizeExceeded:                       types.ReceiptStatuserrMaxCodeSizeExceed,
   317  	kerrors.ErrOutOfGas:                             types.ReceiptStatusErrOutOfGas,
   318  	vm.ErrWriteProtection:                           types.ReceiptStatusErrWriteProtection,
   319  	vm.ErrExecutionReverted:                         types.ReceiptStatusErrExecutionReverted,
   320  	vm.ErrOpcodeComputationCostLimitReached:         types.ReceiptStatusErrOpcodeComputationCostLimitReached,
   321  	kerrors.ErrAccountAlreadyExists:                 types.ReceiptStatusErrAddressAlreadyExists,
   322  	kerrors.ErrNotProgramAccount:                    types.ReceiptStatusErrNotAProgramAccount,
   323  	kerrors.ErrNotHumanReadableAddress:              types.ReceiptStatusErrNotHumanReadableAddress,
   324  	kerrors.ErrFeeRatioOutOfRange:                   types.ReceiptStatusErrFeeRatioOutOfRange,
   325  	kerrors.ErrAccountKeyFailNotUpdatable:           types.ReceiptStatusErrAccountKeyFailNotUpdatable,
   326  	kerrors.ErrDifferentAccountKeyType:              types.ReceiptStatusErrDifferentAccountKeyType,
   327  	kerrors.ErrAccountKeyNilUninitializable:         types.ReceiptStatusErrAccountKeyNilUninitializable,
   328  	kerrors.ErrNotOnCurve:                           types.ReceiptStatusErrNotOnCurve,
   329  	kerrors.ErrZeroKeyWeight:                        types.ReceiptStatusErrZeroKeyWeight,
   330  	kerrors.ErrUnserializableKey:                    types.ReceiptStatusErrUnserializableKey,
   331  	kerrors.ErrDuplicatedKey:                        types.ReceiptStatusErrDuplicatedKey,
   332  	kerrors.ErrWeightedSumOverflow:                  types.ReceiptStatusErrWeightedSumOverflow,
   333  	kerrors.ErrUnsatisfiableThreshold:               types.ReceiptStatusErrUnsatisfiableThreshold,
   334  	kerrors.ErrZeroLength:                           types.ReceiptStatusErrZeroLength,
   335  	kerrors.ErrLengthTooLong:                        types.ReceiptStatusErrLengthTooLong,
   336  	kerrors.ErrNestedCompositeType:                  types.ReceiptStatusErrNestedRoleBasedKey,
   337  	kerrors.ErrLegacyTransactionMustBeWithLegacyKey: types.ReceiptStatusErrLegacyTransactionMustBeWithLegacyKey,
   338  	kerrors.ErrDeprecated:                           types.ReceiptStatusErrDeprecated,
   339  	kerrors.ErrNotSupported:                         types.ReceiptStatusErrNotSupported,
   340  	kerrors.ErrInvalidCodeFormat:                    types.ReceiptStatusErrInvalidCodeFormat,
   341  }
   342  
   343  var receiptstatus2errTxFailed = map[uint]error{
   344  	types.ReceiptStatusSuccessful:                              nil,
   345  	types.ReceiptStatusErrDefault:                              ErrVMDefault,
   346  	types.ReceiptStatusErrDepth:                                vm.ErrDepth,
   347  	types.ReceiptStatusErrContractAddressCollision:             vm.ErrContractAddressCollision,
   348  	types.ReceiptStatusErrCodeStoreOutOfGas:                    vm.ErrCodeStoreOutOfGas,
   349  	types.ReceiptStatuserrMaxCodeSizeExceed:                    vm.ErrMaxCodeSizeExceeded,
   350  	types.ReceiptStatusErrOutOfGas:                             kerrors.ErrOutOfGas,
   351  	types.ReceiptStatusErrWriteProtection:                      vm.ErrWriteProtection,
   352  	types.ReceiptStatusErrExecutionReverted:                    vm.ErrExecutionReverted,
   353  	types.ReceiptStatusErrOpcodeComputationCostLimitReached:    vm.ErrOpcodeComputationCostLimitReached,
   354  	types.ReceiptStatusErrAddressAlreadyExists:                 kerrors.ErrAccountAlreadyExists,
   355  	types.ReceiptStatusErrNotAProgramAccount:                   kerrors.ErrNotProgramAccount,
   356  	types.ReceiptStatusErrNotHumanReadableAddress:              kerrors.ErrNotHumanReadableAddress,
   357  	types.ReceiptStatusErrFeeRatioOutOfRange:                   kerrors.ErrFeeRatioOutOfRange,
   358  	types.ReceiptStatusErrAccountKeyFailNotUpdatable:           kerrors.ErrAccountKeyFailNotUpdatable,
   359  	types.ReceiptStatusErrDifferentAccountKeyType:              kerrors.ErrDifferentAccountKeyType,
   360  	types.ReceiptStatusErrAccountKeyNilUninitializable:         kerrors.ErrAccountKeyNilUninitializable,
   361  	types.ReceiptStatusErrNotOnCurve:                           kerrors.ErrNotOnCurve,
   362  	types.ReceiptStatusErrZeroKeyWeight:                        kerrors.ErrZeroKeyWeight,
   363  	types.ReceiptStatusErrUnserializableKey:                    kerrors.ErrUnserializableKey,
   364  	types.ReceiptStatusErrDuplicatedKey:                        kerrors.ErrDuplicatedKey,
   365  	types.ReceiptStatusErrWeightedSumOverflow:                  kerrors.ErrWeightedSumOverflow,
   366  	types.ReceiptStatusErrUnsatisfiableThreshold:               kerrors.ErrUnsatisfiableThreshold,
   367  	types.ReceiptStatusErrZeroLength:                           kerrors.ErrZeroLength,
   368  	types.ReceiptStatusErrLengthTooLong:                        kerrors.ErrLengthTooLong,
   369  	types.ReceiptStatusErrNestedRoleBasedKey:                   kerrors.ErrNestedCompositeType,
   370  	types.ReceiptStatusErrLegacyTransactionMustBeWithLegacyKey: kerrors.ErrLegacyTransactionMustBeWithLegacyKey,
   371  	types.ReceiptStatusErrDeprecated:                           kerrors.ErrDeprecated,
   372  	types.ReceiptStatusErrNotSupported:                         kerrors.ErrNotSupported,
   373  	types.ReceiptStatusErrInvalidCodeFormat:                    kerrors.ErrInvalidCodeFormat,
   374  }
   375  
   376  // getReceiptStatusFromErrTxFailed returns corresponding ReceiptStatus for VM error.
   377  func getReceiptStatusFromErrTxFailed(errTxFailed error) (status uint) {
   378  	// TODO-Klaytn Add more VM error to ReceiptStatus
   379  	status, ok := errTxFailed2receiptstatus[errTxFailed]
   380  	if !ok {
   381  		// No corresponding receiptStatus available for errTxFailed
   382  		status = types.ReceiptStatusErrDefault
   383  	}
   384  
   385  	return
   386  }
   387  
   388  // GetVMerrFromReceiptStatus returns VM error according to status of receipt.
   389  func GetVMerrFromReceiptStatus(status uint) (errTxFailed error) {
   390  	errTxFailed, ok := receiptstatus2errTxFailed[status]
   391  	if !ok {
   392  		return ErrInvalidReceiptStatus
   393  	}
   394  
   395  	return
   396  }
   397  
   398  func (st *StateTransition) refundGas(refundQuotient uint64) {
   399  	// Apply refund counter, capped a refund quotient
   400  	refund := st.gasUsed() / refundQuotient
   401  	if refund > st.state.GetRefund() {
   402  		refund = st.state.GetRefund()
   403  	}
   404  	st.gas += refund
   405  
   406  	// Return KLAY for remaining gas, exchanged at the original rate.
   407  	remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
   408  
   409  	validatedFeePayer := st.msg.ValidatedFeePayer()
   410  	validatedSender := st.msg.ValidatedSender()
   411  	feeRatio, isRatioTx := st.msg.FeeRatio()
   412  	if isRatioTx {
   413  		feePayer, feeSender := types.CalcFeeWithRatio(feeRatio, remaining)
   414  
   415  		st.state.AddBalance(validatedFeePayer, feePayer)
   416  		st.state.AddBalance(validatedSender, feeSender)
   417  	} else {
   418  		// To make a short circuit, the below routine processes when feeRatio == 100.
   419  		st.state.AddBalance(validatedFeePayer, remaining)
   420  	}
   421  }
   422  
   423  // gasUsed returns the amount of gas used up by the state transition.
   424  func (st *StateTransition) gasUsed() uint64 {
   425  	return st.initialGas - st.gas
   426  }