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 }