github.com/amazechain/amc@v0.1.3/internal/state_transition.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package internal 18 19 import ( 20 "fmt" 21 "github.com/amazechain/amc/common/transaction" 22 "github.com/amazechain/amc/core" 23 "github.com/amazechain/amc/internal/consensus" 24 vm2 "github.com/amazechain/amc/internal/vm" 25 "github.com/amazechain/amc/internal/vm/evmtypes" 26 "math" 27 28 "github.com/holiman/uint256" 29 30 "github.com/amazechain/amc/common" 31 "github.com/amazechain/amc/common/crypto" 32 cmath "github.com/amazechain/amc/common/math" 33 "github.com/amazechain/amc/common/types" 34 "github.com/amazechain/amc/common/u256" 35 "github.com/amazechain/amc/params" 36 ) 37 38 var emptyCodeHash = crypto.Keccak256Hash(nil) 39 40 /* 41 The State Transitioning Model 42 43 A state transition is a change made when a transaction is applied to the current world state 44 The state transitioning model does all the necessary work to work out a valid new state root. 45 46 1) Nonce handling 47 2) Pre pay gas 48 3) Create a new state object if the recipient is \0*32 49 4) Value transfer 50 == If contract creation == 51 52 4a) Attempt to run transaction data 53 4b) If valid, use result as code for the new state object 54 55 == end == 56 5) Run Script section 57 6) Derive new state root 58 */ 59 type StateTransition struct { 60 gp *common.GasPool 61 msg Message 62 gas uint64 63 gasPrice *uint256.Int 64 gasFeeCap *uint256.Int 65 tip *uint256.Int 66 initialGas uint64 67 value *uint256.Int 68 data []byte 69 state evmtypes.IntraBlockState 70 evm vm2.VMInterface 71 72 //some pre-allocated intermediate variables 73 sharedBuyGas *uint256.Int 74 sharedBuyGasBalance *uint256.Int 75 76 isParlia bool 77 isBor bool 78 } 79 80 // Message represents a message sent to a contract. 81 type Message interface { 82 From() types.Address 83 To() *types.Address 84 85 GasPrice() *uint256.Int 86 FeeCap() *uint256.Int 87 Tip() *uint256.Int 88 Gas() uint64 89 Value() *uint256.Int 90 91 Nonce() uint64 92 CheckNonce() bool 93 Data() []byte 94 AccessList() transaction.AccessList 95 96 IsFree() bool 97 } 98 99 // ExecutionResult includes all output after executing given evm 100 // message no matter the execution itself is successful or not. 101 type ExecutionResult struct { 102 UsedGas uint64 // Total used gas but include the refunded gas 103 Err error // Any error encountered during the execution(listed in core/vm/errors.go) 104 ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) 105 } 106 107 // Unwrap returns the internal evm error which allows us for further 108 // analysis outside. 109 func (result *ExecutionResult) Unwrap() error { 110 return result.Err 111 } 112 113 // Failed returns the indicator whether the execution is successful or not 114 func (result *ExecutionResult) Failed() bool { return result.Err != nil } 115 116 // Return is a helper function to help caller distinguish between revert reason 117 // and function return. Return returns the data after execution if no error occurs. 118 func (result *ExecutionResult) Return() []byte { 119 if result.Err != nil { 120 return nil 121 } 122 return types.CopyBytes(result.ReturnData) 123 } 124 125 // Revert returns the concrete revert reason if the execution is aborted by `REVERT` 126 // opcode. Note the reason can be nil if no data supplied with revert opcode. 127 func (result *ExecutionResult) Revert() []byte { 128 if result.Err != vm2.ErrExecutionReverted { 129 return nil 130 } 131 return types.CopyBytes(result.ReturnData) 132 } 133 134 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. 135 func IntrinsicGas(data []byte, accessList transaction.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool) (uint64, error) { 136 // Set the starting gas for the raw transaction 137 var gas uint64 138 if isContractCreation && isHomestead { 139 gas = params.TxGasContractCreation 140 } else { 141 gas = params.TxGas 142 } 143 dataLen := uint64(len(data)) 144 // Bump the required gas by the amount of transactional data 145 if dataLen > 0 { 146 // Zero and non-zero bytes are priced differently 147 var nz uint64 148 for _, byt := range data { 149 if byt != 0 { 150 nz++ 151 } 152 } 153 // Make sure we don't exceed uint64 for all data combinations 154 nonZeroGas := params.TxDataNonZeroGasFrontier 155 if isEIP2028 { 156 nonZeroGas = params.TxDataNonZeroGasEIP2028 157 } 158 if (math.MaxUint64-gas)/nonZeroGas < nz { 159 return 0, ErrGasUintOverflow 160 } 161 gas += nz * nonZeroGas 162 163 z := dataLen - nz 164 if (math.MaxUint64-gas)/params.TxDataZeroGas < z { 165 return 0, ErrGasUintOverflow 166 } 167 gas += z * params.TxDataZeroGas 168 169 if isContractCreation && isEIP3860 { 170 lenWords := toWordSize(dataLen) 171 if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords { 172 return 0, ErrGasUintOverflow 173 } 174 gas += lenWords * params.InitCodeWordGas 175 } 176 } 177 if accessList != nil { 178 gas += uint64(len(accessList)) * params.TxAccessListAddressGas 179 gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas 180 } 181 return gas, nil 182 } 183 184 // NewStateTransition initialises and returns a new state transition object. 185 func NewStateTransition(evm vm2.VMInterface, msg Message, gp *common.GasPool) *StateTransition { 186 isParlia := evm.ChainConfig().Parlia != nil 187 isBor := evm.ChainConfig().Bor != nil 188 return &StateTransition{ 189 gp: gp, 190 evm: evm, 191 msg: msg, 192 gasPrice: msg.GasPrice(), 193 gasFeeCap: msg.FeeCap(), 194 tip: msg.Tip(), 195 value: msg.Value(), 196 data: msg.Data(), 197 state: evm.IntraBlockState(), 198 199 sharedBuyGas: uint256.NewInt(0), 200 sharedBuyGasBalance: uint256.NewInt(0), 201 202 isParlia: isParlia, 203 isBor: isBor, 204 } 205 } 206 207 // ApplyMessage computes the new state by applying the given message 208 // against the old state within the environment. 209 // 210 // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 211 // the gas used (which includes gas refunds) and an error if it failed. An error always 212 // indicates a core error meaning that the message would always fail for that particular 213 // state and would never be accepted within a block. 214 // `refunds` is false when it is not required to apply gas refunds 215 // `gasBailout` is true when it is not required to fail transaction if the balance is not enough to pay gas. 216 // for trace_call to replicate OE/Pariry behaviour 217 func ApplyMessage(evm vm2.VMInterface, msg Message, gp *common.GasPool, refunds bool, gasBailout bool) (*ExecutionResult, error) { 218 return NewStateTransition(evm, msg, gp).TransitionDb(refunds, gasBailout) 219 } 220 221 // to returns the recipient of the message. 222 func (st *StateTransition) to() types.Address { 223 if st.msg == nil || st.msg.To() == nil /* contract creation */ { 224 return types.Address{} 225 } 226 return *st.msg.To() 227 } 228 229 func (st *StateTransition) buyGas(gasBailout bool) error { 230 mgval := st.sharedBuyGas 231 mgval.SetUint64(st.msg.Gas()) 232 mgval, overflow := mgval.MulOverflow(mgval, st.gasPrice) 233 if overflow { 234 return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) 235 } 236 balanceCheck := mgval 237 if st.gasFeeCap != nil { 238 balanceCheck = st.sharedBuyGasBalance.SetUint64(st.msg.Gas()) 239 balanceCheck, overflow = balanceCheck.MulOverflow(balanceCheck, st.gasFeeCap) 240 if overflow { 241 return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) 242 } 243 balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, st.value) 244 if overflow { 245 return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) 246 } 247 } 248 var subBalance = false 249 if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { 250 if !gasBailout { 251 return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want) 252 } 253 } else { 254 subBalance = true 255 } 256 if err := st.gp.SubGas(st.msg.Gas()); err != nil { 257 if !gasBailout { 258 return err 259 } 260 } 261 st.gas += st.msg.Gas() 262 263 st.initialGas = st.msg.Gas() 264 if subBalance { 265 st.state.SubBalance(st.msg.From(), mgval) 266 } 267 return nil 268 } 269 270 func CheckEip1559TxGasFeeCap(from types.Address, gasFeeCap, tip, baseFee *uint256.Int, isFree bool) error { 271 if gasFeeCap.Lt(tip) { 272 return fmt.Errorf("%w: address %v, tip: %s, gasFeeCap: %s", ErrTipAboveFeeCap, 273 from.Hex(), tip, gasFeeCap) 274 } 275 if baseFee != nil && gasFeeCap.Lt(baseFee) && !isFree { 276 return fmt.Errorf("%w: address %v, gasFeeCap: %s baseFee: %s", ErrFeeCapTooLow, 277 from.Hex(), gasFeeCap, baseFee) 278 } 279 return nil 280 } 281 282 // DESCRIBED: docs/programmers_guide/guide.md#nonce 283 func (st *StateTransition) preCheck(gasBailout bool) error { 284 // Make sure this transaction's nonce is correct. 285 if st.msg.CheckNonce() { 286 stNonce := st.state.GetNonce(st.msg.From()) 287 if msgNonce := st.msg.Nonce(); stNonce < msgNonce { 288 return fmt.Errorf("%w: address %v, tx: %d state: %d", core.ErrNonceTooHigh, 289 st.msg.From().Hex(), msgNonce, stNonce) 290 } else if stNonce > msgNonce { 291 return fmt.Errorf("%w: address %v, tx: %d state: %d", core.ErrNonceTooLow, 292 st.msg.From().Hex(), msgNonce, stNonce) 293 } else if stNonce+1 < stNonce { 294 return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax, 295 st.msg.From().Hex(), stNonce) 296 } 297 298 // Make sure the sender is an EOA (EIP-3607) 299 if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (types.Hash{}) { 300 // types.Hash{} means that the sender is not in the state. 301 // Historically there were transactions with 0 gas price and non-existing sender, 302 // so we have to allow that. 303 return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA, 304 st.msg.From().Hex(), codeHash) 305 } 306 } 307 308 // Make sure the transaction gasFeeCap is greater than the block's baseFee. 309 if st.evm.ChainRules().IsLondon { 310 // Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call) 311 if !st.evm.Config().NoBaseFee || !st.gasFeeCap.IsZero() || !st.tip.IsZero() { 312 if err := CheckEip1559TxGasFeeCap(st.msg.From(), st.gasFeeCap, st.tip, st.evm.Context().BaseFee, st.msg.IsFree()); err != nil { 313 return err 314 } 315 } 316 } 317 return st.buyGas(gasBailout) 318 } 319 320 // TransitionDb will transition the state by applying the current message and 321 // returning the evm execution result with following fields. 322 // 323 // - used gas: 324 // total gas used (including gas being refunded) 325 // - returndata: 326 // the returned data from evm 327 // - concrete execution error: 328 // various **EVM** error which aborts the execution, 329 // e.g. ErrOutOfGas, ErrExecutionReverted 330 // 331 // However if any consensus issue encountered, return the error directly with 332 // nil evm execution result. 333 func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*ExecutionResult, error) { 334 //var input1 *uint256.Int 335 //var input2 *uint256.Int 336 //if st.isBor { 337 // input1 = st.state.GetBalance(st.msg.From()).Clone() 338 // input2 = st.state.GetBalance(st.evm.Context().Coinbase).Clone() 339 //} 340 341 // First check this message satisfies all consensus rules before 342 // applying the message. The rules include these clauses 343 // 344 // 1. the nonce of the message caller is correct 345 // 2. caller has enough balance to cover transaction fee(gaslimit * gasprice) 346 // 3. the amount of gas required is available in the block 347 // 4. the purchased gas is enough to cover intrinsic usage 348 // 5. there is no overflow when calculating intrinsic gas 349 // 6. caller has enough balance to cover asset transfer for **topmost** call 350 351 // BSC always gave gas bailout due to system transactions that set 2^256/2 gas limit and 352 // for Parlia consensus this flag should be always be set 353 if st.isParlia { 354 gasBailout = true 355 } 356 357 // Check clauses 1-3 and 6, buy gas if everything is correct 358 if err := st.preCheck(gasBailout); err != nil { 359 return nil, err 360 } 361 if st.evm.Config().Debug { 362 st.evm.Config().Tracer.CaptureTxStart(st.initialGas) 363 defer func() { 364 st.evm.Config().Tracer.CaptureTxEnd(st.gas) 365 }() 366 } 367 368 msg := st.msg 369 sender := vm2.AccountRef(msg.From()) 370 contractCreation := msg.To() == nil 371 rules := st.evm.ChainRules() 372 373 //if rules.IsNano { 374 // for _, blackListAddr := range types.NanoBlackList { 375 // if blackListAddr == sender.Address() { 376 // return nil, fmt.Errorf("block blacklist account") 377 // } 378 // if msg.To() != nil && *msg.To() == blackListAddr { 379 // return nil, fmt.Errorf("block blacklist account") 380 // } 381 // } 382 //} 383 384 // Check clauses 4-5, subtract intrinsic gas if everything is correct 385 gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) 386 if err != nil { 387 return nil, err 388 } 389 if st.gas < gas { 390 return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) 391 } 392 st.gas -= gas 393 394 var bailout bool 395 // Gas bailout (for trace_call) should only be applied if there is not sufficient balance to perform value transfer 396 if gasBailout { 397 if !msg.Value().IsZero() && !st.evm.Context().CanTransfer(st.state, msg.From(), msg.Value()) { 398 bailout = true 399 } 400 } 401 402 // Set up the initial access list. 403 if rules.IsBerlin { 404 st.state.PrepareAccessList(msg.From(), msg.To(), vm2.ActivePrecompiles(rules), msg.AccessList()) 405 // EIP-3651 warm COINBASE 406 if rules.IsShanghai { 407 st.state.AddAddressToAccessList(st.evm.Context().Coinbase) 408 } 409 } 410 411 var ( 412 ret []byte 413 vmerr error // vm errors do not effect consensus and are therefore not assigned to err 414 ) 415 if contractCreation { 416 // The reason why we don't increment nonce here is that we need the original 417 // nonce to calculate the address of the contract that is being created 418 // It does get incremented inside the `Create` call, after the computation 419 // of the contract's address, but before the execution of the code. 420 ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value) 421 } else { 422 // Increment the nonce for the next transaction 423 st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) 424 ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value, bailout) 425 } 426 if refunds { 427 if rules.IsLondon { 428 // After EIP-3529: refunds are capped to gasUsed / 5 429 st.refundGas(params.RefundQuotientEIP3529) 430 } else { 431 // Before EIP-3529: refunds were capped to gasUsed / 2 432 st.refundGas(params.RefundQuotient) 433 } 434 } 435 effectiveTip := st.gasPrice 436 if rules.IsLondon { 437 if st.gasFeeCap.Gt(st.evm.Context().BaseFee) { 438 effectiveTip = cmath.Min256(st.tip, new(uint256.Int).Sub(st.gasFeeCap, st.evm.Context().BaseFee)) 439 } else { 440 effectiveTip = u256.Num0 441 } 442 } 443 amount := new(uint256.Int).SetUint64(st.gasUsed()) 444 amount.Mul(amount, effectiveTip) // gasUsed * effectiveTip = how much goes to the block producer (miner, validator) 445 if st.isParlia { 446 st.state.AddBalance(consensus.SystemAddress, amount) 447 } else { 448 st.state.AddBalance(st.evm.Context().Coinbase, amount) 449 } 450 if !msg.IsFree() && rules.IsLondon && rules.IsEip1559FeeCollector { 451 burntContractAddress := *st.evm.ChainConfig().Eip1559FeeCollector 452 burnAmount := new(uint256.Int).Mul(new(uint256.Int).SetUint64(st.gasUsed()), st.evm.Context().BaseFee) 453 st.state.AddBalance(burntContractAddress, burnAmount) 454 } 455 //if st.isBor { 456 // // 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 457 // // add transfer log 458 // output1 := input1.Clone() 459 // output2 := input2.Clone() 460 //AddFeeTransferLog( 461 // st.state, 462 // 463 // msg.From(), 464 // st.evm.Context().Coinbase, 465 // 466 // amount, 467 // input1, 468 // input2, 469 // output1.Sub(output1, amount), 470 // output2.Add(output2, amount), 471 // ) 472 //} 473 474 return &ExecutionResult{ 475 UsedGas: st.gasUsed(), 476 Err: vmerr, 477 ReturnData: ret, 478 }, nil 479 } 480 481 func (st *StateTransition) refundGas(refundQuotient uint64) { 482 // Apply refund counter, capped to half of the used gas. 483 refund := st.gasUsed() / refundQuotient 484 if refund > st.state.GetRefund() { 485 refund = st.state.GetRefund() 486 } 487 st.gas += refund 488 489 // Return ETH for remaining gas, exchanged at the original rate. 490 remaining := new(uint256.Int).Mul(new(uint256.Int).SetUint64(st.gas), st.gasPrice) 491 st.state.AddBalance(st.msg.From(), remaining) 492 493 // Also return remaining gas to the block gas counter so it is 494 // available for the next transaction. 495 st.gp.AddGas(st.gas) 496 } 497 498 // gasUsed returns the amount of gas used up by the state transition. 499 func (st *StateTransition) gasUsed() uint64 { 500 return st.initialGas - st.gas 501 } 502 503 // toWordSize returns the ceiled word size required for init code payment calculation. 504 func toWordSize(size uint64) uint64 { 505 if size > math.MaxUint64-31 { 506 return math.MaxUint64/32 + 1 507 } 508 509 return (size + 31) / 32 510 }