github.com/klaytn/klaytn@v1.12.1/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  	"fmt"
    26  	"math/big"
    27  
    28  	"github.com/klaytn/klaytn/blockchain/types"
    29  	"github.com/klaytn/klaytn/blockchain/vm"
    30  	"github.com/klaytn/klaytn/common"
    31  	"github.com/klaytn/klaytn/kerrors"
    32  	"github.com/klaytn/klaytn/params"
    33  )
    34  
    35  var (
    36  	errInsufficientBalanceForGas         = errors.New("insufficient balance of the sender to pay for gas")
    37  	errInsufficientBalanceForGasFeePayer = errors.New("insufficient balance of the fee payer to pay for gas")
    38  )
    39  
    40  /*
    41  The State Transitioning Model
    42  
    43  A state transition is a change made when a transaction is applied to the current world state
    44  The state transitioning model does all the necessary work to work out a valid new state root.
    45  
    46  1) Nonce handling
    47  2) Pre pay gas
    48  3) Create a new state object if the recipient is \0*32
    49  4) Value transfer
    50  == If contract creation ==
    51  
    52  	4a) Attempt to run transaction data
    53  	4b) If valid, use result as code for the new state object
    54  
    55  == end ==
    56  5) Run Script section
    57  6) Derive new state root
    58  */
    59  type StateTransition struct {
    60  	msg        Message
    61  	gas        uint64
    62  	gasPrice   *big.Int
    63  	gasTipCap  *big.Int
    64  	gasFeeCap  *big.Int
    65  	initialGas uint64
    66  	value      *big.Int
    67  	data       []byte
    68  	state      vm.StateDB
    69  	evm        *vm.EVM
    70  }
    71  
    72  // Message represents a message sent to a contract.
    73  type Message interface {
    74  	// ValidatedSender returns the sender of the transaction.
    75  	// The returned sender should be derived by calling AsMessageAccountKeyPicker().
    76  	ValidatedSender() common.Address
    77  
    78  	// ValidatedFeePayer returns the fee payer of the transaction.
    79  	// The returned fee payer should be derived by calling AsMessageAccountKeyPicker().
    80  	ValidatedFeePayer() common.Address
    81  
    82  	// ValidatedIntrinsicGas returns the intrinsic gas of the transaction.
    83  	// The returned intrinsic gas should be derived by calling AsMessageAccountKeyPicker().
    84  	ValidatedIntrinsicGas() uint64
    85  
    86  	// FeeRatio returns a ratio of tx fee paid by the fee payer in percentage.
    87  	// For example, if it is 30, 30% of tx fee will be paid by the fee payer.
    88  	// 70% will be paid by the sender.
    89  	FeeRatio() (types.FeeRatio, bool)
    90  
    91  	To() *common.Address
    92  
    93  	Hash() common.Hash
    94  
    95  	GasPrice() *big.Int
    96  
    97  	// For TxTypeEthereumDynamicFee
    98  	GasTipCap() *big.Int
    99  	GasFeeCap() *big.Int
   100  	EffectiveGasTip(baseFee *big.Int) *big.Int
   101  	EffectiveGasPrice(header *types.Header) *big.Int
   102  
   103  	Gas() uint64
   104  	Value() *big.Int
   105  
   106  	Nonce() uint64
   107  	CheckNonce() bool
   108  	Data() []byte
   109  
   110  	// IntrinsicGas returns `intrinsic gas` based on the tx type.
   111  	// This value is used to differentiate tx fee based on the tx type.
   112  	IntrinsicGas(currentBlockNumber uint64) (uint64, error)
   113  
   114  	// Type returns the transaction type of the message.
   115  	Type() types.TxType
   116  
   117  	// Validate performs additional validation for each transaction type
   118  	Validate(stateDB types.StateDB, currentBlockNumber uint64) error
   119  
   120  	// Execute performs execution of the transaction according to the transaction type.
   121  	Execute(vm types.VM, stateDB types.StateDB, currentBlockNumber uint64, gas uint64, value *big.Int) ([]byte, uint64, error)
   122  
   123  	AccessList() types.AccessList
   124  }
   125  
   126  // ExecutionResult includes all output after executing given evm
   127  // message no matter the execution itself is successful or not.
   128  type ExecutionResult struct {
   129  	// Total used gas but include the refunded gas
   130  	UsedGas uint64
   131  
   132  	// Indicate status of transaction after execution. If the execution succeed, the status is 1.
   133  	// If it fails, its status value indicates any error encountered during the execution (listed in blockchain/vm/errors.go)
   134  	// This value will be stored in Receipt if Receipt is available.
   135  	// Please see getReceiptStatusFromErrTxFailed() how the status code is derived.
   136  	VmExecutionStatus uint
   137  
   138  	// Returned data from evm(function result or data supplied with revert opcode)
   139  	ReturnData []byte
   140  }
   141  
   142  // Unwrap returns the internal evm error which allows us for further
   143  // analysis outside.
   144  func (result *ExecutionResult) Unwrap() error {
   145  	if !result.Failed() {
   146  		return nil
   147  	}
   148  	errTxFailed, ok := receiptstatus2errTxFailed[result.VmExecutionStatus]
   149  	if !ok {
   150  		return ErrInvalidReceiptStatus
   151  	}
   152  	return errTxFailed
   153  }
   154  
   155  // Failed returns the indicator whether the execution is successful or not
   156  func (result *ExecutionResult) Failed() bool {
   157  	return result.VmExecutionStatus != types.ReceiptStatusSuccessful
   158  }
   159  
   160  // Return is a helper function to help caller distinguish between revert reason
   161  // and function return. Return returns the data after execution if no error occurs.
   162  func (result *ExecutionResult) Return() []byte {
   163  	if result.Failed() {
   164  		return nil
   165  	}
   166  	return common.CopyBytes(result.ReturnData)
   167  }
   168  
   169  // Revert returns the concrete revert reason if the execution is aborted by `REVERT`
   170  // opcode. Note the reason can be nil if no data supplied with revert opcode.
   171  func (result *ExecutionResult) Revert() []byte {
   172  	if result.VmExecutionStatus != types.ReceiptStatusErrExecutionReverted {
   173  		return nil
   174  	}
   175  	return common.CopyBytes(result.ReturnData)
   176  }
   177  
   178  // getReceiptStatusFromErrTxFailed returns corresponding ReceiptStatus for VM error.
   179  func getReceiptStatusFromErrTxFailed(errTxFailed error) (status uint) {
   180  	status, ok := errTxFailed2receiptstatus[errTxFailed]
   181  	if !ok {
   182  		// No corresponding receiptStatus available for errTxFailed
   183  		status = types.ReceiptStatusErrDefault
   184  	}
   185  	return
   186  }
   187  
   188  // NewStateTransition initialises and returns a new state transition object.
   189  func NewStateTransition(evm *vm.EVM, msg Message) *StateTransition {
   190  	// before magma hardfork, effectiveGasPrice is GasPrice of tx
   191  	// after magma hardfork, effectiveGasPrice is BaseFee
   192  	effectiveGasPrice := evm.GasPrice
   193  
   194  	return &StateTransition{
   195  		evm:       evm,
   196  		msg:       msg,
   197  		gasPrice:  effectiveGasPrice,
   198  		gasFeeCap: msg.GasFeeCap(),
   199  		gasTipCap: msg.GasTipCap(),
   200  		value:     msg.Value(),
   201  		data:      msg.Data(),
   202  		state:     evm.StateDB,
   203  	}
   204  }
   205  
   206  // ApplyMessage computes the new state by applying the given message
   207  // against the old state within the environment.
   208  //
   209  // ApplyMessage returns the bytes returned by any EVM execution (if it took place),
   210  // the gas used (which includes gas refunds) and an error if it failed. An error always
   211  // indicates a core error meaning that the message would always fail for that particular
   212  // state and would never be accepted within a block.
   213  func ApplyMessage(evm *vm.EVM, msg Message) (*ExecutionResult, error) {
   214  	return NewStateTransition(evm, msg).TransitionDb()
   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  	// st.gasPrice : gasPrice user set before magma hardfork
   227  	// st.gasPrice : BaseFee after magma hardfork
   228  	mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice)
   229  
   230  	validatedFeePayer := st.msg.ValidatedFeePayer()
   231  	validatedSender := st.msg.ValidatedSender()
   232  	feeRatio, isRatioTx := st.msg.FeeRatio()
   233  	if isRatioTx {
   234  		feePayerFee, senderFee := types.CalcFeeWithRatio(feeRatio, mgval)
   235  
   236  		if st.state.GetBalance(validatedFeePayer).Cmp(feePayerFee) < 0 {
   237  			logger.Debug(errInsufficientBalanceForGasFeePayer.Error(), "feePayer", validatedFeePayer.String(),
   238  				"feePayerBalance", st.state.GetBalance(validatedFeePayer).Uint64(), "feePayerFee", feePayerFee.Uint64(),
   239  				"txHash", st.msg.Hash().String())
   240  			return errInsufficientBalanceForGasFeePayer
   241  		}
   242  
   243  		if st.state.GetBalance(validatedSender).Cmp(senderFee) < 0 {
   244  			logger.Debug(errInsufficientBalanceForGas.Error(), "sender", validatedSender.String(),
   245  				"senderBalance", st.state.GetBalance(validatedSender).Uint64(), "senderFee", senderFee.Uint64(),
   246  				"txHash", st.msg.Hash().String())
   247  			return errInsufficientBalanceForGas
   248  		}
   249  
   250  		st.state.SubBalance(validatedFeePayer, feePayerFee)
   251  		st.state.SubBalance(validatedSender, senderFee)
   252  	} else {
   253  		// to make a short circuit, process the special case feeRatio == MaxFeeRatio
   254  		if st.state.GetBalance(validatedFeePayer).Cmp(mgval) < 0 {
   255  			logger.Debug(errInsufficientBalanceForGasFeePayer.Error(), "feePayer", validatedFeePayer.String(),
   256  				"feePayerBalance", st.state.GetBalance(validatedFeePayer).Uint64(), "feePayerFee", mgval.Uint64(),
   257  				"txHash", st.msg.Hash().String())
   258  			return errInsufficientBalanceForGasFeePayer
   259  		}
   260  
   261  		st.state.SubBalance(validatedFeePayer, mgval)
   262  	}
   263  
   264  	st.gas += st.msg.Gas()
   265  
   266  	st.initialGas = st.msg.Gas()
   267  	return nil
   268  }
   269  
   270  func (st *StateTransition) preCheck() error {
   271  	// when prefetching, skip the nonce and balance check logic.
   272  	// however, st.gas still needs to be set whether it's prefetching or not.
   273  	if st.evm.IsPrefetching() {
   274  		st.gas = st.msg.Gas()
   275  		return nil
   276  	}
   277  
   278  	// Make sure this transaction's nonce is correct.
   279  	if st.msg.CheckNonce() {
   280  		nonce := st.state.GetNonce(st.msg.ValidatedSender())
   281  		if nonce < st.msg.Nonce() {
   282  			logger.Debug(ErrNonceTooHigh.Error(), "account", st.msg.ValidatedSender().String(),
   283  				"accountNonce", nonce, "txNonce", st.msg.Nonce(), "txHash", st.msg.Hash().String())
   284  			return ErrNonceTooHigh
   285  		} else if nonce > st.msg.Nonce() {
   286  			logger.Debug(ErrNonceTooLow.Error(), "account", st.msg.ValidatedSender().String(),
   287  				"accountNonce", nonce, "txNonce", st.msg.Nonce(), "txHash", st.msg.Hash().String())
   288  			return ErrNonceTooLow
   289  		}
   290  	}
   291  	return st.buyGas()
   292  }
   293  
   294  // TransitionDb will transition the state by applying the current message and
   295  // returning the evm execution result with following fields.
   296  //
   297  //   - used gas:
   298  //     total gas used (including gas being refunded)
   299  //   - returndata:
   300  //     the returned data from evm
   301  //   - vm execution status:
   302  //     indicates the execution result of a transaction. if the execution succeed, the status is 1.
   303  //     if it fails, the status indicates various **EVM** errors which abort the execution.
   304  //     e.g. ReceiptStatusErrOutOfGas, ReceiptStatusErrExecutionReverted
   305  //
   306  // However if any consensus issue encountered, return the error directly with
   307  // nil evm execution result.
   308  func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
   309  	// First check this message satisfies all consensus rules before
   310  	// applying the message. The rules include these clauses
   311  	//
   312  	// 1. the nonce of the message caller is correct
   313  	// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice)
   314  	// 3. the amount of gas required is available in the block
   315  	// 4. the purchased gas is enough to cover intrinsic usage
   316  	// 5. there is no overflow when calculating intrinsic gas
   317  	// 6. caller has enough balance to cover asset transfer for **topmost** call
   318  
   319  	// Check clauses 1-3, buy gas if everything is correct
   320  	if err := st.preCheck(); err != nil {
   321  		return nil, err
   322  	}
   323  
   324  	msg := st.msg
   325  
   326  	if st.evm.Config.Debug {
   327  		st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
   328  		defer func() {
   329  			st.evm.Config.Tracer.CaptureTxEnd(st.gas)
   330  		}()
   331  	}
   332  
   333  	// Check clauses 4-5, subtract intrinsic gas if everything is correct
   334  	amount := msg.ValidatedIntrinsicGas()
   335  	if st.gas < amount {
   336  		return nil, ErrIntrinsicGas
   337  	}
   338  	st.gas -= amount
   339  
   340  	// Check clause 6
   341  	if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.ValidatedSender(), msg.Value()) {
   342  		return nil, vm.ErrInsufficientBalance
   343  	}
   344  
   345  	rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber)
   346  
   347  	// Execute the preparatory steps for state transition which includes:
   348  	// - prepare accessList(post-berlin)
   349  	// - reset transient storage(eip 1153)
   350  	st.state.Prepare(rules, msg.ValidatedSender(), msg.ValidatedFeePayer(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
   351  
   352  	// Check whether the init code size has been exceeded.
   353  	if rules.IsShanghai && msg.To() == nil && len(st.data) > params.MaxInitCodeSize {
   354  		return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize)
   355  	}
   356  
   357  	var (
   358  		ret   []byte
   359  		vmerr error
   360  	)
   361  	ret, st.gas, vmerr = msg.Execute(st.evm, st.state, st.evm.Context.BlockNumber.Uint64(), st.gas, st.value)
   362  
   363  	// time-limit error is not a vm error. This error is returned when the EVM is still running while the
   364  	// block proposer's total execution time of txs for a candidate block reached the predefined limit.
   365  	if vmerr == vm.ErrTotalTimeLimitReached {
   366  		return nil, vm.ErrTotalTimeLimitReached
   367  	}
   368  
   369  	if rules.IsKore {
   370  		// After EIP-3529: refunds are capped to gasUsed / 5
   371  		st.refundGas(params.RefundQuotientEIP3529)
   372  	} else {
   373  		// Before EIP-3529: refunds were capped to gasUsed / 2
   374  		st.refundGas(params.RefundQuotient)
   375  	}
   376  
   377  	// Defer transferring Tx fee when DeferredTxFee is true
   378  	if st.evm.ChainConfig().Governance == nil || !st.evm.ChainConfig().Governance.DeferredTxFee() {
   379  		if rules.IsMagma {
   380  			effectiveGasPrice := st.gasPrice
   381  			txFee := getBurnAmountMagma(new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveGasPrice))
   382  			st.state.AddBalance(st.evm.Context.Rewardbase, txFee)
   383  		} else {
   384  			effectiveGasPrice := msg.EffectiveGasPrice(nil)
   385  			st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveGasPrice))
   386  		}
   387  	}
   388  
   389  	return &ExecutionResult{
   390  		UsedGas:           st.gasUsed(),
   391  		VmExecutionStatus: getReceiptStatusFromErrTxFailed(vmerr), // only vm error reach here.
   392  		ReturnData:        ret,
   393  	}, nil
   394  }
   395  
   396  var errTxFailed2receiptstatus = map[error]uint{
   397  	nil:                                             types.ReceiptStatusSuccessful,
   398  	vm.ErrDepth:                                     types.ReceiptStatusErrDepth,
   399  	vm.ErrContractAddressCollision:                  types.ReceiptStatusErrContractAddressCollision,
   400  	vm.ErrCodeStoreOutOfGas:                         types.ReceiptStatusErrCodeStoreOutOfGas,
   401  	vm.ErrMaxCodeSizeExceeded:                       types.ReceiptStatuserrMaxCodeSizeExceed,
   402  	kerrors.ErrOutOfGas:                             types.ReceiptStatusErrOutOfGas,
   403  	vm.ErrWriteProtection:                           types.ReceiptStatusErrWriteProtection,
   404  	vm.ErrExecutionReverted:                         types.ReceiptStatusErrExecutionReverted,
   405  	vm.ErrOpcodeComputationCostLimitReached:         types.ReceiptStatusErrOpcodeComputationCostLimitReached,
   406  	kerrors.ErrAccountAlreadyExists:                 types.ReceiptStatusErrAddressAlreadyExists,
   407  	kerrors.ErrNotProgramAccount:                    types.ReceiptStatusErrNotAProgramAccount,
   408  	kerrors.ErrNotHumanReadableAddress:              types.ReceiptStatusErrNotHumanReadableAddress,
   409  	kerrors.ErrFeeRatioOutOfRange:                   types.ReceiptStatusErrFeeRatioOutOfRange,
   410  	kerrors.ErrAccountKeyFailNotUpdatable:           types.ReceiptStatusErrAccountKeyFailNotUpdatable,
   411  	kerrors.ErrDifferentAccountKeyType:              types.ReceiptStatusErrDifferentAccountKeyType,
   412  	kerrors.ErrAccountKeyNilUninitializable:         types.ReceiptStatusErrAccountKeyNilUninitializable,
   413  	kerrors.ErrNotOnCurve:                           types.ReceiptStatusErrNotOnCurve,
   414  	kerrors.ErrZeroKeyWeight:                        types.ReceiptStatusErrZeroKeyWeight,
   415  	kerrors.ErrUnserializableKey:                    types.ReceiptStatusErrUnserializableKey,
   416  	kerrors.ErrDuplicatedKey:                        types.ReceiptStatusErrDuplicatedKey,
   417  	kerrors.ErrWeightedSumOverflow:                  types.ReceiptStatusErrWeightedSumOverflow,
   418  	kerrors.ErrUnsatisfiableThreshold:               types.ReceiptStatusErrUnsatisfiableThreshold,
   419  	kerrors.ErrZeroLength:                           types.ReceiptStatusErrZeroLength,
   420  	kerrors.ErrLengthTooLong:                        types.ReceiptStatusErrLengthTooLong,
   421  	kerrors.ErrNestedCompositeType:                  types.ReceiptStatusErrNestedRoleBasedKey,
   422  	kerrors.ErrLegacyTransactionMustBeWithLegacyKey: types.ReceiptStatusErrLegacyTransactionMustBeWithLegacyKey,
   423  	kerrors.ErrDeprecated:                           types.ReceiptStatusErrDeprecated,
   424  	kerrors.ErrNotSupported:                         types.ReceiptStatusErrNotSupported,
   425  	kerrors.ErrInvalidCodeFormat:                    types.ReceiptStatusErrInvalidCodeFormat,
   426  }
   427  
   428  var receiptstatus2errTxFailed = map[uint]error{
   429  	types.ReceiptStatusSuccessful:                              nil,
   430  	types.ReceiptStatusErrDefault:                              ErrVMDefault,
   431  	types.ReceiptStatusErrDepth:                                vm.ErrDepth,
   432  	types.ReceiptStatusErrContractAddressCollision:             vm.ErrContractAddressCollision,
   433  	types.ReceiptStatusErrCodeStoreOutOfGas:                    vm.ErrCodeStoreOutOfGas,
   434  	types.ReceiptStatuserrMaxCodeSizeExceed:                    vm.ErrMaxCodeSizeExceeded,
   435  	types.ReceiptStatusErrOutOfGas:                             kerrors.ErrOutOfGas,
   436  	types.ReceiptStatusErrWriteProtection:                      vm.ErrWriteProtection,
   437  	types.ReceiptStatusErrExecutionReverted:                    vm.ErrExecutionReverted,
   438  	types.ReceiptStatusErrOpcodeComputationCostLimitReached:    vm.ErrOpcodeComputationCostLimitReached,
   439  	types.ReceiptStatusErrAddressAlreadyExists:                 kerrors.ErrAccountAlreadyExists,
   440  	types.ReceiptStatusErrNotAProgramAccount:                   kerrors.ErrNotProgramAccount,
   441  	types.ReceiptStatusErrNotHumanReadableAddress:              kerrors.ErrNotHumanReadableAddress,
   442  	types.ReceiptStatusErrFeeRatioOutOfRange:                   kerrors.ErrFeeRatioOutOfRange,
   443  	types.ReceiptStatusErrAccountKeyFailNotUpdatable:           kerrors.ErrAccountKeyFailNotUpdatable,
   444  	types.ReceiptStatusErrDifferentAccountKeyType:              kerrors.ErrDifferentAccountKeyType,
   445  	types.ReceiptStatusErrAccountKeyNilUninitializable:         kerrors.ErrAccountKeyNilUninitializable,
   446  	types.ReceiptStatusErrNotOnCurve:                           kerrors.ErrNotOnCurve,
   447  	types.ReceiptStatusErrZeroKeyWeight:                        kerrors.ErrZeroKeyWeight,
   448  	types.ReceiptStatusErrUnserializableKey:                    kerrors.ErrUnserializableKey,
   449  	types.ReceiptStatusErrDuplicatedKey:                        kerrors.ErrDuplicatedKey,
   450  	types.ReceiptStatusErrWeightedSumOverflow:                  kerrors.ErrWeightedSumOverflow,
   451  	types.ReceiptStatusErrUnsatisfiableThreshold:               kerrors.ErrUnsatisfiableThreshold,
   452  	types.ReceiptStatusErrZeroLength:                           kerrors.ErrZeroLength,
   453  	types.ReceiptStatusErrLengthTooLong:                        kerrors.ErrLengthTooLong,
   454  	types.ReceiptStatusErrNestedRoleBasedKey:                   kerrors.ErrNestedCompositeType,
   455  	types.ReceiptStatusErrLegacyTransactionMustBeWithLegacyKey: kerrors.ErrLegacyTransactionMustBeWithLegacyKey,
   456  	types.ReceiptStatusErrDeprecated:                           kerrors.ErrDeprecated,
   457  	types.ReceiptStatusErrNotSupported:                         kerrors.ErrNotSupported,
   458  	types.ReceiptStatusErrInvalidCodeFormat:                    kerrors.ErrInvalidCodeFormat,
   459  }
   460  
   461  func (st *StateTransition) refundGas(refundQuotient uint64) {
   462  	// Apply refund counter, capped a refund quotient
   463  	refund := st.gasUsed() / refundQuotient
   464  	if refund > st.state.GetRefund() {
   465  		refund = st.state.GetRefund()
   466  	}
   467  	st.gas += refund
   468  
   469  	// Return KLAY for remaining gas, exchanged at the original rate.
   470  	remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
   471  
   472  	validatedFeePayer := st.msg.ValidatedFeePayer()
   473  	validatedSender := st.msg.ValidatedSender()
   474  	feeRatio, isRatioTx := st.msg.FeeRatio()
   475  	if isRatioTx {
   476  		feePayer, feeSender := types.CalcFeeWithRatio(feeRatio, remaining)
   477  
   478  		st.state.AddBalance(validatedFeePayer, feePayer)
   479  		st.state.AddBalance(validatedSender, feeSender)
   480  	} else {
   481  		// To make a short circuit, the below routine processes when feeRatio == 100.
   482  		st.state.AddBalance(validatedFeePayer, remaining)
   483  	}
   484  }
   485  
   486  // gasUsed returns the amount of gas used up by the state transition.
   487  func (st *StateTransition) gasUsed() uint64 {
   488  	return st.initialGas - st.gas
   489  }
   490  
   491  func getBurnAmountMagma(fee *big.Int) *big.Int {
   492  	return new(big.Int).Div(fee, big.NewInt(2))
   493  }