github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/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 "context" 21 "fmt" 22 "math" 23 "math/big" 24 25 "github.com/ethereum/go-ethereum/common" 26 cmath "github.com/ethereum/go-ethereum/common/math" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/core/vm" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/ethereum/go-ethereum/params" 31 ) 32 33 var emptyCodeHash = crypto.Keccak256Hash(nil) 34 35 /* 36 The State Transitioning Model 37 38 A state transition is a change made when a transaction is applied to the current world state 39 The state transitioning model does all the necessary work to work out a valid new state root. 40 41 1) Nonce handling 42 2) Pre pay gas 43 3) Create a new state object if the recipient is \0*32 44 4) Value transfer 45 == If contract creation == 46 47 4a) Attempt to run transaction data 48 4b) If valid, use result as code for the new state object 49 50 == end == 51 5) Run Script section 52 6) Derive new state root 53 */ 54 type StateTransition struct { 55 gp *GasPool 56 msg Message 57 gas uint64 58 gasPrice *big.Int 59 gasFeeCap *big.Int 60 gasTipCap *big.Int 61 initialGas uint64 62 value *big.Int 63 data []byte 64 state vm.StateDB 65 evm *vm.EVM 66 67 // If true, fee burning and tipping won't happen during transition. Instead, their values will be included in the 68 // ExecutionResult, which caller can use the values to update the balance of burner and coinbase account. 69 // This is useful during parallel state transition, where the common account read/write should be minimized. 70 noFeeBurnAndTip bool 71 } 72 73 // Message represents a message sent to a contract. 74 type Message interface { 75 From() common.Address 76 To() *common.Address 77 78 GasPrice() *big.Int 79 GasFeeCap() *big.Int 80 GasTipCap() *big.Int 81 Gas() uint64 82 Value() *big.Int 83 84 Nonce() uint64 85 IsFake() bool 86 Data() []byte 87 AccessList() types.AccessList 88 } 89 90 // ExecutionResult includes all output after executing given evm 91 // message no matter the execution itself is successful or not. 92 type ExecutionResult struct { 93 UsedGas uint64 // Total used gas but include the refunded gas 94 Err error // Any error encountered during the execution(listed in core/vm/errors.go) 95 ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) 96 SenderInitBalance *big.Int 97 FeeBurnt *big.Int 98 BurntContractAddress common.Address 99 FeeTipped *big.Int 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 != vm.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, interruptCtx context.Context) (*ExecutionResult, error) { 193 return NewStateTransition(evm, msg, gp).TransitionDb(interruptCtx) 194 } 195 196 func ApplyMessageNoFeeBurnOrTip(evm *vm.EVM, msg Message, gp *GasPool, interruptCtx context.Context) (*ExecutionResult, error) { 197 st := NewStateTransition(evm, msg, gp) 198 st.noFeeBurnAndTip = true 199 200 return st.TransitionDb(interruptCtx) 201 } 202 203 // to returns the recipient of the message. 204 func (st *StateTransition) to() common.Address { 205 if st.msg == nil || st.msg.To() == nil /* contract creation */ { 206 return common.Address{} 207 } 208 return *st.msg.To() 209 } 210 211 func (st *StateTransition) buyGas() error { 212 mgval := new(big.Int).SetUint64(st.msg.Gas()) 213 mgval = mgval.Mul(mgval, st.gasPrice) 214 balanceCheck := mgval 215 if st.gasFeeCap != nil { 216 balanceCheck = new(big.Int).SetUint64(st.msg.Gas()) 217 balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap) 218 balanceCheck.Add(balanceCheck, st.value) 219 } 220 if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { 221 return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want) 222 } 223 if err := st.gp.SubGas(st.msg.Gas()); err != nil { 224 return err 225 } 226 st.gas += st.msg.Gas() 227 228 st.initialGas = st.msg.Gas() 229 st.state.SubBalance(st.msg.From(), mgval) 230 return nil 231 } 232 233 func (st *StateTransition) preCheck() error { 234 // Only check transactions that are not fake 235 if !st.msg.IsFake() { 236 // Make sure this transaction's nonce is correct. 237 stNonce := st.state.GetNonce(st.msg.From()) 238 if msgNonce := st.msg.Nonce(); stNonce < msgNonce { 239 return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh, 240 st.msg.From().Hex(), msgNonce, stNonce) 241 } else if stNonce > msgNonce { 242 return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow, 243 st.msg.From().Hex(), msgNonce, stNonce) 244 } else if stNonce+1 < stNonce { 245 return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax, 246 st.msg.From().Hex(), stNonce) 247 } 248 // Make sure the sender is an EOA 249 if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) { 250 return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA, 251 st.msg.From().Hex(), codeHash) 252 } 253 } 254 // Make sure that transaction gasFeeCap is greater than the baseFee (post london) 255 if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { 256 // Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call) 257 if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 { 258 if l := st.gasFeeCap.BitLen(); l > 256 { 259 return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh, 260 st.msg.From().Hex(), l) 261 } 262 if l := st.gasTipCap.BitLen(); l > 256 { 263 return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh, 264 st.msg.From().Hex(), l) 265 } 266 if st.gasFeeCap.Cmp(st.gasTipCap) < 0 { 267 return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap, 268 st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap) 269 } 270 // This will panic if baseFee is nil, but basefee presence is verified 271 // as part of header validation. 272 if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 { 273 return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow, 274 st.msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee) 275 } 276 } 277 } 278 return st.buyGas() 279 } 280 281 // TransitionDb will transition the state by applying the current message and 282 // returning the evm execution result with following fields. 283 // 284 // - used gas: 285 // total gas used (including gas being refunded) 286 // - returndata: 287 // the returned data from evm 288 // - concrete execution error: 289 // various **EVM** error which aborts the execution, 290 // e.g. ErrOutOfGas, ErrExecutionReverted 291 // 292 // However if any consensus issue encountered, return the error directly with 293 // nil evm execution result. 294 func (st *StateTransition) TransitionDb(interruptCtx context.Context) (*ExecutionResult, error) { 295 input1 := st.state.GetBalance(st.msg.From()) 296 297 var input2 *big.Int 298 299 if !st.noFeeBurnAndTip { 300 input2 = st.state.GetBalance(st.evm.Context.Coinbase) 301 } 302 303 // First check this message satisfies all consensus rules before 304 // applying the message. The rules include these clauses 305 // 306 // 1. the nonce of the message caller is correct 307 // 2. caller has enough balance to cover transaction fee(gaslimit * gasprice) 308 // 3. the amount of gas required is available in the block 309 // 4. the purchased gas is enough to cover intrinsic usage 310 // 5. there is no overflow when calculating intrinsic gas 311 // 6. caller has enough balance to cover asset transfer for **topmost** call 312 313 // Check clauses 1-3, buy gas if everything is correct 314 if err := st.preCheck(); err != nil { 315 return nil, err 316 } 317 msg := st.msg 318 sender := vm.AccountRef(msg.From()) 319 homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber) 320 istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber) 321 london := st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) 322 contractCreation := msg.To() == nil 323 324 // Check clauses 4-5, subtract intrinsic gas if everything is correct 325 gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul) 326 if err != nil { 327 return nil, err 328 } 329 if st.gas < gas { 330 return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) 331 } 332 st.gas -= gas 333 334 // Check clause 6 335 if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) { 336 return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex()) 337 } 338 339 // Set up the initial access list. 340 if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil); rules.IsBerlin { 341 st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) 342 } 343 var ( 344 ret []byte 345 vmerr error // vm errors do not effect consensus and are therefore not assigned to err 346 ) 347 if contractCreation { 348 ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value) 349 } else { 350 // Increment the nonce for the next transaction 351 st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) 352 ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value, interruptCtx) 353 } 354 355 if !london { 356 // Before EIP-3529: refunds were capped to gasUsed / 2 357 st.refundGas(params.RefundQuotient) 358 } else { 359 // After EIP-3529: refunds are capped to gasUsed / 5 360 st.refundGas(params.RefundQuotientEIP3529) 361 } 362 effectiveTip := st.gasPrice 363 if london { 364 effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) 365 } 366 amount := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip) 367 368 var burnAmount *big.Int 369 370 var burntContractAddress common.Address 371 372 if london { 373 burntContractAddress = common.HexToAddress(st.evm.ChainConfig().Bor.CalculateBurntContract(st.evm.Context.BlockNumber.Uint64())) 374 burnAmount = new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.evm.Context.BaseFee) 375 376 if !st.noFeeBurnAndTip { 377 st.state.AddBalance(burntContractAddress, burnAmount) 378 } 379 } 380 381 if !st.noFeeBurnAndTip { 382 st.state.AddBalance(st.evm.Context.Coinbase, amount) 383 384 output1 := new(big.Int).Set(input1) 385 output2 := new(big.Int).Set(input2) 386 387 // Deprecating transfer log and will be removed in future fork. PLEASE DO NOT USE this transfer log going forward. Parameters won't get updated as expected going forward with EIP1559 388 // add transfer log 389 AddFeeTransferLog( 390 st.state, 391 392 msg.From(), 393 st.evm.Context.Coinbase, 394 395 amount, 396 input1, 397 input2, 398 output1.Sub(output1, amount), 399 output2.Add(output2, amount), 400 ) 401 } 402 403 return &ExecutionResult{ 404 UsedGas: st.gasUsed(), 405 Err: vmerr, 406 ReturnData: ret, 407 SenderInitBalance: input1, 408 FeeBurnt: burnAmount, 409 BurntContractAddress: burntContractAddress, 410 FeeTipped: amount, 411 }, nil 412 } 413 414 func (st *StateTransition) refundGas(refundQuotient uint64) { 415 // Apply refund counter, capped to a refund quotient 416 refund := st.gasUsed() / refundQuotient 417 if refund > st.state.GetRefund() { 418 refund = st.state.GetRefund() 419 } 420 st.gas += refund 421 422 // Return ETH for remaining gas, exchanged at the original rate. 423 remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) 424 st.state.AddBalance(st.msg.From(), remaining) 425 426 // Also return remaining gas to the block gas counter so it is 427 // available for the next transaction. 428 st.gp.AddGas(st.gas) 429 } 430 431 // gasUsed returns the amount of gas used up by the state transition. 432 func (st *StateTransition) gasUsed() uint64 { 433 return st.initialGas - st.gas 434 }