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 }