github.com/theQRL/go-zond@v0.1.1/core/state_transition.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "errors" 21 "fmt" 22 "math" 23 "math/big" 24 25 "github.com/theQRL/go-zond/common" 26 cmath "github.com/theQRL/go-zond/common/math" 27 "github.com/theQRL/go-zond/consensus/misc/eip4844" 28 "github.com/theQRL/go-zond/core/types" 29 "github.com/theQRL/go-zond/core/vm" 30 "github.com/theQRL/go-zond/params" 31 ) 32 33 // ExecutionResult includes all output after executing given evm 34 // message no matter the execution itself is successful or not. 35 type ExecutionResult struct { 36 UsedGas uint64 // Total used gas but include the refunded gas 37 Err error // Any error encountered during the execution(listed in core/vm/errors.go) 38 ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) 39 } 40 41 // Unwrap returns the internal evm error which allows us for further 42 // analysis outside. 43 func (result *ExecutionResult) Unwrap() error { 44 return result.Err 45 } 46 47 // Failed returns the indicator whether the execution is successful or not 48 func (result *ExecutionResult) Failed() bool { return result.Err != nil } 49 50 // Return is a helper function to help caller distinguish between revert reason 51 // and function return. Return returns the data after execution if no error occurs. 52 func (result *ExecutionResult) Return() []byte { 53 if result.Err != nil { 54 return nil 55 } 56 return common.CopyBytes(result.ReturnData) 57 } 58 59 // Revert returns the concrete revert reason if the execution is aborted by `REVERT` 60 // opcode. Note the reason can be nil if no data supplied with revert opcode. 61 func (result *ExecutionResult) Revert() []byte { 62 if result.Err != vm.ErrExecutionReverted { 63 return nil 64 } 65 return common.CopyBytes(result.ReturnData) 66 } 67 68 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. 69 func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool) (uint64, error) { 70 // Set the starting gas for the raw transaction 71 var gas uint64 72 if isContractCreation && isHomestead { 73 gas = params.TxGasContractCreation 74 } else { 75 gas = params.TxGas 76 } 77 dataLen := uint64(len(data)) 78 // Bump the required gas by the amount of transactional data 79 if dataLen > 0 { 80 // Zero and non-zero bytes are priced differently 81 var nz uint64 82 for _, byt := range data { 83 if byt != 0 { 84 nz++ 85 } 86 } 87 // Make sure we don't exceed uint64 for all data combinations 88 nonZeroGas := params.TxDataNonZeroGasFrontier 89 if isEIP2028 { 90 nonZeroGas = params.TxDataNonZeroGasEIP2028 91 } 92 if (math.MaxUint64-gas)/nonZeroGas < nz { 93 return 0, ErrGasUintOverflow 94 } 95 gas += nz * nonZeroGas 96 97 z := dataLen - nz 98 if (math.MaxUint64-gas)/params.TxDataZeroGas < z { 99 return 0, ErrGasUintOverflow 100 } 101 gas += z * params.TxDataZeroGas 102 103 if isContractCreation && isEIP3860 { 104 lenWords := toWordSize(dataLen) 105 if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords { 106 return 0, ErrGasUintOverflow 107 } 108 gas += lenWords * params.InitCodeWordGas 109 } 110 } 111 if accessList != nil { 112 gas += uint64(len(accessList)) * params.TxAccessListAddressGas 113 gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas 114 } 115 return gas, nil 116 } 117 118 // toWordSize returns the ceiled word size required for init code payment calculation. 119 func toWordSize(size uint64) uint64 { 120 if size > math.MaxUint64-31 { 121 return math.MaxUint64/32 + 1 122 } 123 124 return (size + 31) / 32 125 } 126 127 // A Message contains the data derived from a single transaction that is relevant to state 128 // processing. 129 type Message struct { 130 To *common.Address 131 From common.Address 132 Nonce uint64 133 Value *big.Int 134 GasLimit uint64 135 GasPrice *big.Int 136 GasFeeCap *big.Int 137 GasTipCap *big.Int 138 Data []byte 139 AccessList types.AccessList 140 BlobGasFeeCap *big.Int 141 BlobHashes []common.Hash 142 143 // When SkipAccountChecks is true, the message nonce is not checked against the 144 // account nonce in state. It also disables checking that the sender is an EOA. 145 // This field will be set to true for operations like RPC eth_call. 146 SkipAccountChecks bool 147 } 148 149 // TransactionToMessage converts a transaction into a Message. 150 func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) { 151 msg := &Message{ 152 Nonce: tx.Nonce(), 153 GasLimit: tx.Gas(), 154 GasPrice: new(big.Int).Set(tx.GasPrice()), 155 GasFeeCap: new(big.Int).Set(tx.GasFeeCap()), 156 GasTipCap: new(big.Int).Set(tx.GasTipCap()), 157 To: tx.To(), 158 Value: tx.Value(), 159 Data: tx.Data(), 160 AccessList: tx.AccessList(), 161 SkipAccountChecks: false, 162 BlobHashes: tx.BlobHashes(), 163 BlobGasFeeCap: tx.BlobGasFeeCap(), 164 } 165 // If baseFee provided, set gasPrice to effectiveGasPrice. 166 if baseFee != nil { 167 msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap) 168 } 169 var err error 170 msg.From, err = types.Sender(s, tx) 171 return msg, err 172 } 173 174 // ApplyMessage computes the new state by applying the given message 175 // against the old state within the environment. 176 // 177 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 178 // the gas used (which includes gas refunds) and an error if it failed. An error always 179 // indicates a core error meaning that the message would always fail for that particular 180 // state and would never be accepted within a block. 181 func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) { 182 return NewStateTransition(evm, msg, gp).TransitionDb() 183 } 184 185 // StateTransition represents a state transition. 186 // 187 // == The State Transitioning Model 188 // 189 // A state transition is a change made when a transaction is applied to the current world 190 // state. The state transitioning model does all the necessary work to work out a valid new 191 // state root. 192 // 193 // 1. Nonce handling 194 // 2. Pre pay gas 195 // 3. Create a new state object if the recipient is nil 196 // 4. Value transfer 197 // 198 // == If contract creation == 199 // 200 // 4a. Attempt to run transaction data 201 // 4b. If valid, use result as code for the new state object 202 // 203 // == end == 204 // 205 // 5. Run Script section 206 // 6. Derive new state root 207 type StateTransition struct { 208 gp *GasPool 209 msg *Message 210 gasRemaining uint64 211 initialGas uint64 212 state vm.StateDB 213 evm *vm.EVM 214 } 215 216 // NewStateTransition initialises and returns a new state transition object. 217 func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition { 218 return &StateTransition{ 219 gp: gp, 220 evm: evm, 221 msg: msg, 222 state: evm.StateDB, 223 } 224 } 225 226 // to returns the recipient of the message. 227 func (st *StateTransition) to() common.Address { 228 if st.msg == nil || st.msg.To == nil /* contract creation */ { 229 return common.Address{} 230 } 231 return *st.msg.To 232 } 233 234 func (st *StateTransition) buyGas() error { 235 mgval := new(big.Int).SetUint64(st.msg.GasLimit) 236 mgval = mgval.Mul(mgval, st.msg.GasPrice) 237 balanceCheck := new(big.Int).Set(mgval) 238 if st.msg.GasFeeCap != nil { 239 balanceCheck.SetUint64(st.msg.GasLimit) 240 balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) 241 balanceCheck.Add(balanceCheck, st.msg.Value) 242 } 243 if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { 244 if blobGas := st.blobGasUsed(); blobGas > 0 { 245 // Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap 246 blobBalanceCheck := new(big.Int).SetUint64(blobGas) 247 blobBalanceCheck.Mul(blobBalanceCheck, st.msg.BlobGasFeeCap) 248 balanceCheck.Add(balanceCheck, blobBalanceCheck) 249 // Pay for blobGasUsed * actual blob fee 250 blobFee := new(big.Int).SetUint64(blobGas) 251 blobFee.Mul(blobFee, eip4844.CalcBlobFee(*st.evm.Context.ExcessBlobGas)) 252 mgval.Add(mgval, blobFee) 253 } 254 } 255 if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { 256 return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) 257 } 258 if err := st.gp.SubGas(st.msg.GasLimit); err != nil { 259 return err 260 } 261 st.gasRemaining += st.msg.GasLimit 262 263 st.initialGas = st.msg.GasLimit 264 st.state.SubBalance(st.msg.From, mgval) 265 return nil 266 } 267 268 func (st *StateTransition) preCheck() error { 269 // Only check transactions that are not fake 270 msg := st.msg 271 if !msg.SkipAccountChecks { 272 // Make sure this transaction's nonce is correct. 273 stNonce := st.state.GetNonce(msg.From) 274 if msgNonce := msg.Nonce; stNonce < msgNonce { 275 return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh, 276 msg.From.Hex(), msgNonce, stNonce) 277 } else if stNonce > msgNonce { 278 return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow, 279 msg.From.Hex(), msgNonce, stNonce) 280 } else if stNonce+1 < stNonce { 281 return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax, 282 msg.From.Hex(), stNonce) 283 } 284 // Make sure the sender is an EOA 285 codeHash := st.state.GetCodeHash(msg.From) 286 if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash { 287 return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA, 288 msg.From.Hex(), codeHash) 289 } 290 } 291 292 // Make sure that transaction gasFeeCap is greater than the baseFee (post london) 293 if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { 294 // Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call) 295 if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 { 296 if l := msg.GasFeeCap.BitLen(); l > 256 { 297 return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh, 298 msg.From.Hex(), l) 299 } 300 if l := msg.GasTipCap.BitLen(); l > 256 { 301 return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh, 302 msg.From.Hex(), l) 303 } 304 if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 { 305 return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap, 306 msg.From.Hex(), msg.GasTipCap, msg.GasFeeCap) 307 } 308 // This will panic if baseFee is nil, but basefee presence is verified 309 // as part of header validation. 310 if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 { 311 return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow, 312 msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee) 313 } 314 } 315 } 316 // Check the blob version validity 317 if msg.BlobHashes != nil { 318 if len(msg.BlobHashes) == 0 { 319 return errors.New("blob transaction missing blob hashes") 320 } 321 for i, hash := range msg.BlobHashes { 322 if hash[0] != params.BlobTxHashVersion { 323 return fmt.Errorf("blob %d hash version mismatch (have %d, supported %d)", 324 i, hash[0], params.BlobTxHashVersion) 325 } 326 } 327 } 328 329 if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { 330 if st.blobGasUsed() > 0 { 331 // Check that the user is paying at least the current blob fee 332 blobFee := eip4844.CalcBlobFee(*st.evm.Context.ExcessBlobGas) 333 if st.msg.BlobGasFeeCap.Cmp(blobFee) < 0 { 334 return fmt.Errorf("%w: address %v have %v want %v", ErrBlobFeeCapTooLow, st.msg.From.Hex(), st.msg.BlobGasFeeCap, blobFee) 335 } 336 } 337 } 338 339 return st.buyGas() 340 } 341 342 // TransitionDb will transition the state by applying the current message and 343 // returning the evm execution result with following fields. 344 // 345 // - used gas: total gas used (including gas being refunded) 346 // - returndata: the returned data from evm 347 // - concrete execution error: various EVM errors which abort the execution, e.g. 348 // ErrOutOfGas, ErrExecutionReverted 349 // 350 // However if any consensus issue encountered, return the error directly with 351 // nil evm execution result. 352 func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { 353 // First check this message satisfies all consensus rules before 354 // applying the message. The rules include these clauses 355 // 356 // 1. the nonce of the message caller is correct 357 // 2. caller has enough balance to cover transaction fee(gaslimit * gasprice) 358 // 3. the amount of gas required is available in the block 359 // 4. the purchased gas is enough to cover intrinsic usage 360 // 5. there is no overflow when calculating intrinsic gas 361 // 6. caller has enough balance to cover asset transfer for **topmost** call 362 363 // Check clauses 1-3, buy gas if everything is correct 364 if err := st.preCheck(); err != nil { 365 return nil, err 366 } 367 368 if tracer := st.evm.Config.Tracer; tracer != nil { 369 tracer.CaptureTxStart(st.initialGas) 370 defer func() { 371 tracer.CaptureTxEnd(st.gasRemaining) 372 }() 373 } 374 375 var ( 376 msg = st.msg 377 sender = vm.AccountRef(msg.From) 378 rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time) 379 contractCreation = msg.To == nil 380 ) 381 382 // Check clauses 4-5, subtract intrinsic gas if everything is correct 383 gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) 384 if err != nil { 385 return nil, err 386 } 387 if st.gasRemaining < gas { 388 return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas) 389 } 390 st.gasRemaining -= gas 391 392 // Check clause 6 393 if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) { 394 return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex()) 395 } 396 397 // Check whether the init code size has been exceeded. 398 if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize { 399 return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize) 400 } 401 402 // Execute the preparatory steps for state transition which includes: 403 // - prepare accessList(post-berlin) 404 // - reset transient storage(eip 1153) 405 st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) 406 407 var ( 408 ret []byte 409 vmerr error // vm errors do not effect consensus and are therefore not assigned to err 410 ) 411 if contractCreation { 412 ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, msg.Value) 413 } else { 414 // Increment the nonce for the next transaction 415 st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1) 416 ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value) 417 } 418 419 if !rules.IsLondon { 420 // Before EIP-3529: refunds were capped to gasUsed / 2 421 st.refundGas(params.RefundQuotient) 422 } else { 423 // After EIP-3529: refunds are capped to gasUsed / 5 424 st.refundGas(params.RefundQuotientEIP3529) 425 } 426 effectiveTip := msg.GasPrice 427 if rules.IsLondon { 428 effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee)) 429 } 430 431 if st.evm.Config.NoBaseFee && msg.GasFeeCap.Sign() == 0 && msg.GasTipCap.Sign() == 0 { 432 // Skip fee payment when NoBaseFee is set and the fee fields 433 // are 0. This avoids a negative effectiveTip being applied to 434 // the coinbase when simulating calls. 435 } else { 436 fee := new(big.Int).SetUint64(st.gasUsed()) 437 fee.Mul(fee, effectiveTip) 438 st.state.AddBalance(st.evm.Context.Coinbase, fee) 439 } 440 441 return &ExecutionResult{ 442 UsedGas: st.gasUsed(), 443 Err: vmerr, 444 ReturnData: ret, 445 }, nil 446 } 447 448 func (st *StateTransition) refundGas(refundQuotient uint64) { 449 // Apply refund counter, capped to a refund quotient 450 refund := st.gasUsed() / refundQuotient 451 if refund > st.state.GetRefund() { 452 refund = st.state.GetRefund() 453 } 454 st.gasRemaining += refund 455 456 // Return ETH for remaining gas, exchanged at the original rate. 457 remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.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.gasRemaining) 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.gasRemaining 468 } 469 470 // blobGasUsed returns the amount of blob gas used by the message. 471 func (st *StateTransition) blobGasUsed() uint64 { 472 return uint64(len(st.msg.BlobHashes) * params.BlobTxBlobGasPerBlob) 473 }