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