github.com/MetalBlockchain/subnet-evm@v0.4.9/core/state_transition.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2014 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package core 28 29 import ( 30 "fmt" 31 "math" 32 "math/big" 33 34 "github.com/ethereum/go-ethereum/crypto" 35 36 "github.com/MetalBlockchain/subnet-evm/core/types" 37 "github.com/MetalBlockchain/subnet-evm/core/vm" 38 "github.com/MetalBlockchain/subnet-evm/params" 39 "github.com/MetalBlockchain/subnet-evm/precompile" 40 "github.com/MetalBlockchain/subnet-evm/vmerrs" 41 "github.com/ethereum/go-ethereum/common" 42 ) 43 44 var emptyCodeHash = crypto.Keccak256Hash(nil) 45 46 /* 47 The State Transitioning Model 48 49 A state transition is a change made when a transaction is applied to the current world state 50 The state transitioning model does all the necessary work to work out a valid new state root. 51 52 1) Nonce handling 53 2) Pre pay gas 54 3) Create a new state object if the recipient is \0*32 55 4) Value transfer 56 == If contract creation == 57 4a) Attempt to run transaction data 58 4b) If valid, use result as code for the new state object 59 == end == 60 5) Run Script section 61 6) Derive new state root 62 */ 63 type StateTransition struct { 64 gp *GasPool 65 msg Message 66 gas uint64 67 gasPrice *big.Int 68 gasFeeCap *big.Int 69 gasTipCap *big.Int 70 initialGas uint64 71 value *big.Int 72 data []byte 73 state vm.StateDB 74 evm *vm.EVM 75 } 76 77 // Message represents a message sent to a contract. 78 type Message interface { 79 From() common.Address 80 To() *common.Address 81 82 GasPrice() *big.Int 83 GasFeeCap() *big.Int 84 GasTipCap() *big.Int 85 Gas() uint64 86 Value() *big.Int 87 88 Nonce() uint64 89 IsFake() bool 90 Data() []byte 91 AccessList() types.AccessList 92 } 93 94 // ExecutionResult includes all output after executing given evm 95 // message no matter the execution itself is successful or not. 96 type ExecutionResult struct { 97 UsedGas uint64 // Total used gas but include the refunded gas 98 Err error // Any error encountered during the execution(listed in core/vm/errors.go) 99 ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) 100 } 101 102 // Unwrap returns the internal evm error which allows us for further 103 // analysis outside. 104 func (result *ExecutionResult) Unwrap() error { 105 return result.Err 106 } 107 108 // Failed returns the indicator whether the execution is successful or not 109 func (result *ExecutionResult) Failed() bool { return result.Err != nil } 110 111 // Return is a helper function to help caller distinguish between revert reason 112 // and function return. Return returns the data after execution if no error occurs. 113 func (result *ExecutionResult) Return() []byte { 114 if result.Err != nil { 115 return nil 116 } 117 return common.CopyBytes(result.ReturnData) 118 } 119 120 // Revert returns the concrete revert reason if the execution is aborted by `REVERT` 121 // opcode. Note the reason can be nil if no data supplied with revert opcode. 122 func (result *ExecutionResult) Revert() []byte { 123 if result.Err != vmerrs.ErrExecutionReverted { 124 return nil 125 } 126 return common.CopyBytes(result.ReturnData) 127 } 128 129 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. 130 func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) { 131 // Set the starting gas for the raw transaction 132 var gas uint64 133 if isContractCreation && isHomestead { 134 gas = params.TxGasContractCreation 135 } else { 136 gas = params.TxGas 137 } 138 // Bump the required gas by the amount of transactional data 139 if len(data) > 0 { 140 // Zero and non-zero bytes are priced differently 141 var nz uint64 142 for _, byt := range data { 143 if byt != 0 { 144 nz++ 145 } 146 } 147 // Make sure we don't exceed uint64 for all data combinations 148 nonZeroGas := params.TxDataNonZeroGasFrontier 149 if isEIP2028 { 150 nonZeroGas = params.TxDataNonZeroGasEIP2028 151 } 152 if (math.MaxUint64-gas)/nonZeroGas < nz { 153 return 0, ErrGasUintOverflow 154 } 155 gas += nz * nonZeroGas 156 157 z := uint64(len(data)) - nz 158 if (math.MaxUint64-gas)/params.TxDataZeroGas < z { 159 return 0, ErrGasUintOverflow 160 } 161 gas += z * params.TxDataZeroGas 162 } 163 if accessList != nil { 164 gas += uint64(len(accessList)) * params.TxAccessListAddressGas 165 gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas 166 } 167 return gas, nil 168 } 169 170 // NewStateTransition initialises and returns a new state transition object. 171 func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { 172 return &StateTransition{ 173 gp: gp, 174 evm: evm, 175 msg: msg, 176 gasPrice: msg.GasPrice(), 177 gasFeeCap: msg.GasFeeCap(), 178 gasTipCap: msg.GasTipCap(), 179 value: msg.Value(), 180 data: msg.Data(), 181 state: evm.StateDB, 182 } 183 } 184 185 // ApplyMessage computes the new state by applying the given message 186 // against the old state within the environment. 187 // 188 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 189 // the gas used (which includes gas refunds) and an error if it failed. An error always 190 // indicates a core error meaning that the message would always fail for that particular 191 // state and would never be accepted within a block. 192 func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) { 193 return NewStateTransition(evm, msg, gp).TransitionDb() 194 } 195 196 // to returns the recipient of the message. 197 func (st *StateTransition) to() common.Address { 198 if st.msg == nil || st.msg.To() == nil /* contract creation */ { 199 return common.Address{} 200 } 201 return *st.msg.To() 202 } 203 204 func (st *StateTransition) buyGas() error { 205 mgval := new(big.Int).SetUint64(st.msg.Gas()) 206 mgval = mgval.Mul(mgval, st.gasPrice) 207 balanceCheck := mgval 208 if st.gasFeeCap != nil { 209 balanceCheck = new(big.Int).SetUint64(st.msg.Gas()) 210 balanceCheck.Mul(balanceCheck, st.gasFeeCap) 211 balanceCheck.Add(balanceCheck, st.value) 212 } 213 if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { 214 return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want) 215 } 216 if err := st.gp.SubGas(st.msg.Gas()); err != nil { 217 return err 218 } 219 st.gas += st.msg.Gas() 220 221 st.initialGas = st.msg.Gas() 222 st.state.SubBalance(st.msg.From(), mgval) 223 return nil 224 } 225 226 func (st *StateTransition) preCheck() error { 227 // Only check transactions that are not fake 228 if !st.msg.IsFake() { 229 // Make sure this transaction's nonce is correct. 230 stNonce := st.state.GetNonce(st.msg.From()) 231 if msgNonce := st.msg.Nonce(); stNonce < msgNonce { 232 return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh, 233 st.msg.From().Hex(), msgNonce, stNonce) 234 } else if stNonce > msgNonce { 235 return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow, 236 st.msg.From().Hex(), msgNonce, stNonce) 237 } else if stNonce+1 < stNonce { 238 return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax, 239 st.msg.From().Hex(), stNonce) 240 } 241 // Make sure the sender is an EOA 242 if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) { 243 return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA, 244 st.msg.From().Hex(), codeHash) 245 } 246 // Make sure the sender is not prohibited 247 if vm.IsProhibited(st.msg.From()) { 248 return fmt.Errorf("%w: address %v", vmerrs.ErrAddrProhibited, st.msg.From()) 249 } 250 251 // Check that the sender is on the tx allow list if enabled 252 if st.evm.ChainConfig().IsTxAllowList(st.evm.Context.Time) { 253 txAllowListRole := precompile.GetTxAllowListStatus(st.state, st.msg.From()) 254 if !txAllowListRole.IsEnabled() { 255 return fmt.Errorf("%w: %s", precompile.ErrSenderAddressNotAllowListed, st.msg.From()) 256 } 257 } 258 } 259 // Make sure that transaction gasFeeCap is greater than the baseFee (post london) 260 if st.evm.ChainConfig().IsSubnetEVM(st.evm.Context.Time) { 261 // Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call) 262 if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 { 263 if l := st.gasFeeCap.BitLen(); l > 256 { 264 return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh, 265 st.msg.From().Hex(), l) 266 } 267 if l := st.gasTipCap.BitLen(); l > 256 { 268 return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh, 269 st.msg.From().Hex(), l) 270 } 271 if st.gasFeeCap.Cmp(st.gasTipCap) < 0 { 272 return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap, 273 st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap) 274 } 275 // This will panic if baseFee is nil, but basefee presence is verified 276 // as part of header validation. 277 if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 { 278 return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow, 279 st.msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee) 280 } 281 } 282 } 283 return st.buyGas() 284 } 285 286 // TransitionDb will transition the state by applying the current message and 287 // returning the evm execution result with following fields. 288 // 289 // - used gas: 290 // total gas used (including gas being refunded) 291 // - returndata: 292 // the returned data from evm 293 // - concrete execution error: 294 // various **EVM** error which aborts the execution, 295 // e.g. ErrOutOfGas, ErrExecutionReverted 296 // 297 // However if any consensus issue encountered, return the error directly with 298 // nil evm execution result. 299 func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { 300 // First check this message satisfies all consensus rules before 301 // applying the message. The rules include these clauses 302 // 303 // 1. the nonce of the message caller is correct 304 // 2. caller has enough balance to cover transaction fee(gaslimit * gasprice) 305 // 3. the amount of gas required is available in the block 306 // 4. the message caller is on the tx allow list (if enabled) 307 // 5. the purchased gas is enough to cover intrinsic usage 308 // 6. there is no overflow when calculating intrinsic gas 309 // 7. caller has enough balance to cover asset transfer for **topmost** call 310 311 // Check clauses 1-4, buy gas if everything is correct 312 if err := st.preCheck(); err != nil { 313 return nil, err 314 } 315 if st.evm.Config.Debug { 316 st.evm.Config.Tracer.CaptureTxStart(st.initialGas) 317 defer func() { 318 st.evm.Config.Tracer.CaptureTxEnd(st.gas) 319 }() 320 } 321 322 var ( 323 msg = st.msg 324 sender = vm.AccountRef(msg.From()) 325 rules = st.evm.ChainConfig().AvalancheRules(st.evm.Context.BlockNumber, st.evm.Context.Time) 326 contractCreation = msg.To() == nil 327 ) 328 329 // Check clauses 4-5, subtract intrinsic gas if everything is correct 330 gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) 331 if err != nil { 332 return nil, err 333 } 334 if st.gas < gas { 335 return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) 336 } 337 st.gas -= gas 338 339 // Check clause 6 340 if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) { 341 return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex()) 342 } 343 344 // Set up the initial access list. 345 if rules.IsSubnetEVM { 346 st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) 347 } 348 var ( 349 ret []byte 350 vmerr error // vm errors do not effect consensus and are therefore not assigned to err 351 ) 352 if contractCreation { 353 ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value) 354 } else { 355 // Increment the nonce for the next transaction 356 st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) 357 ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value) 358 } 359 st.refundGas(rules.IsSubnetEVM) 360 st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) 361 362 return &ExecutionResult{ 363 UsedGas: st.gasUsed(), 364 Err: vmerr, 365 ReturnData: ret, 366 }, nil 367 } 368 369 func (st *StateTransition) refundGas(subnetEVM bool) { 370 // Inspired by: https://gist.github.com/holiman/460f952716a74eeb9ab358bb1836d821#gistcomment-3642048 371 if !subnetEVM { 372 // Apply refund counter, capped to half of the used gas. 373 refund := st.gasUsed() / 2 374 if refund > st.state.GetRefund() { 375 refund = st.state.GetRefund() 376 } 377 st.gas += refund 378 } 379 // Return ETH for remaining gas, exchanged at the original rate. 380 remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) 381 st.state.AddBalance(st.msg.From(), remaining) 382 383 // Also return remaining gas to the block gas counter so it is 384 // available for the next transaction. 385 st.gp.AddGas(st.gas) 386 } 387 388 // gasUsed returns the amount of gas used up by the state transition. 389 func (st *StateTransition) gasUsed() uint64 { 390 return st.initialGas - st.gas 391 }