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