Skip to content

Commit

Permalink
fix: wrong returned gas used and handler crash in debug APIs (axieinf…
Browse files Browse the repository at this point in the history
…inity#276)

* fix: wrong returned gas used of system transaction in debug APIs

When using debug APIs, system transaction goes through ApplyMessage which
currently accounts for instrinsicGas and refund while normal flow through
Finalize/FinalizeAndAssemble does not. This commit adds an IsSystemTransaction to
evm's config, when system transaction goes through ApplyMessage, turn on this
flag so that gasUsed does not account for intrinsicGas and refund.

* eth/tracers: fix flatCallTracer crasher (#27304)

FlatCallTracer had a crasher when it was passed `onlyTopCall: true` as config.
This PR ignores config fields inherited from the normal call tracer.
  • Loading branch information
minh-bq committed May 24, 2023
1 parent 34bf8dd commit 30a0907
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 31 deletions.
24 changes: 14 additions & 10 deletions consensus/consortium/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,22 +202,26 @@ func (c *Consortium) GetBestParentBlock(chain *core.BlockChain) (*types.Block, b
return c.v2.GetBestParentBlock(chain)
}

// HandleSubmitBlockReward determines if the transaction is submitBlockReward
// transaction with non-zero msg.value and fixes up the statedb.
// This function bases on the fact that submitBlockReward is the only system
// transaction that may have non-zero msg.value
func HandleSubmitBlockReward(engine consensus.Engine, statedb *state.StateDB, msg core.Message, block *types.Block) {
// HandleSystemTransaction fixes up the statedb when system transaction
// goes through ApplyMessage when tracing/debugging
func HandleSystemTransaction(engine consensus.Engine, statedb *state.StateDB, msg core.Message, block *types.Block) bool {
consortium, ok := engine.(*Consortium)
if !ok {
return
return false
}

if consortium.chainConfig.IsConsortiumV2(new(big.Int).Add(block.Number(), common.Big1)) {
isSystemMsg := consortium.v2.IsSystemMessage(msg, block.Header())
if isSystemMsg && msg.Value().Cmp(common.Big0) > 0 {
balance := statedb.GetBalance(consensus.SystemAddress)
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(block.Coinbase(), balance)
if isSystemMsg {
if msg.Value().Cmp(common.Big0) > 0 {
balance := statedb.GetBalance(consensus.SystemAddress)
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(block.Coinbase(), balance)
}

return true
}
}

return false
}
30 changes: 17 additions & 13 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,14 +304,16 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
contractCreation := msg.To() == nil

// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul)
if err != nil {
return nil, err
}
if st.gas < gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
if !st.evm.Config.IsSystemTransaction {
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul)
if err != nil {
return nil, err
}
if st.gas < gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
}
st.gas -= gas
}
st.gas -= gas

// Check clause 6
if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
Expand All @@ -334,12 +336,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
}

if !london {
// Before EIP-3529: refunds were capped to gasUsed / 2
st.refundGas(params.RefundQuotient)
} else {
// After EIP-3529: refunds are capped to gasUsed / 5
st.refundGas(params.RefundQuotientEIP3529)
if !st.evm.Config.IsSystemTransaction {
if !london {
// Before EIP-3529: refunds were capped to gasUsed / 2
st.refundGas(params.RefundQuotient)
} else {
// After EIP-3529: refunds are capped to gasUsed / 5
st.refundGas(params.RefundQuotientEIP3529)
}
}

effectiveTip := st.gasPrice
Expand Down
2 changes: 2 additions & 0 deletions core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type Config struct {
JumpTable [256]*operation // EVM instruction table, automatically populated if unset

ExtraEips []int // Additional EIPS that are to be enabled

IsSystemTransaction bool // Used by tracer to specially handle system transaction
}

// ScopeContext contains the things that are per-call, such as stack and memory,
Expand Down
4 changes: 3 additions & 1 deletion eth/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,9 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
statedb.Prepare(tx.Hash(), idx)
consortium.HandleSubmitBlockReward(eth.engine, statedb, msg, block)
if consortium.HandleSystemTransaction(eth.engine, statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
Expand Down
20 changes: 15 additions & 5 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
)
statedb.Prepare(tx.Hash(), i)
consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, msg, block)
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
// We intentionally don't return the error here: if we do, then the RPC server will not
Expand Down Expand Up @@ -731,8 +733,10 @@ txloop:
// Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer, block.BaseFee())
statedb.Prepare(tx.Hash(), i)
consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, msg, block)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
failed = err
break txloop
Expand Down Expand Up @@ -827,8 +831,10 @@ txloop:
// Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer, block.BaseFee())
statedb.Prepare(tx.Hash(), i)
consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, msg, block)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
failed = err
break txloop
Expand Down Expand Up @@ -948,7 +954,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
statedb.Prepare(tx.Hash(), i)
consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, msg, block)
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
if writer != nil {
writer.Flush()
Expand Down Expand Up @@ -1134,7 +1142,9 @@ func (api *API) traceTx(
// Call Prepare to clear out the statedb access list
statedb.Prepare(txctx.TxHash, txctx.TxIndex)

consortium.HandleSubmitBlockReward(api.backend.Engine(), statedb, message, block)
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, message, block) {
vmenv.Config.IsSystemTransaction = true
}
_, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
if err != nil {
return nil, fmt.Errorf("tracing failed: %w", err)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
{
"context": {
"difficulty": "3502894804",
"gasLimit": "4722976",
"miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724",
"number": "2289806",
"timestamp": "1513601314"
},
"genesis": {
"alloc": {
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
"balance": "0x0",
"code": "0x",
"nonce": "22",
"storage": {}
},
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
"balance": "0x4d87094125a369d9bd5",
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
"nonce": "1",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
}
},
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
"balance": "0x1780d77678137ac1b775",
"code": "0x",
"nonce": "29072",
"storage": {}
}
},
"config": {
"byzantiumBlock": 1700000,
"chainId": 3,
"daoForkSupport": true,
"eip150Block": 0,
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
"eip155Block": 10,
"eip158Block": 10,
"ethash": {},
"homesteadBlock": 0
},
"difficulty": "3509749784",
"extraData": "0x4554482e45544846414e532e4f52472d4641313738394444",
"gasLimit": "4727564",
"hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440",
"miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3",
"mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada",
"nonce": "0x4eb12e19c16d43da",
"number": "2289805",
"stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f",
"timestamp": "1513601261",
"totalDifficulty": "7143276353481064"
},
"input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4",
"tracerConfig": {
"onlyTopCall": true
},
"result": [
{
"action": {
"callType": "call",
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
"gas": "0x15f90",
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
"value": "0x0"
},
"blockNumber": 2289806,
"result": {
"gasUsed": "0x9751",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
"subtraces": 1,
"traceAddress": [],
"type": "call"
},
{
"action": {
"callType": "call",
"from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
"gas": "0x6d05",
"input": "0x",
"to": "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
"value": "0x6f05b59d3b20000"
},
"blockNumber": 0,
"result": {
"gasUsed": "0x0",
"output": "0x"
},
"subtraces": 0,
"traceAddress": [0],
"type": "call"
}
]
}
4 changes: 3 additions & 1 deletion eth/tracers/native/call_flat.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace
}
}

tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, cfg)
// Create inner call tracer with default configuration, don't forward
// the OnlyTopCall or WithLog to inner for now
tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, nil)
if err != nil {
return nil, err
}
Expand Down
4 changes: 3 additions & 1 deletion les/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
}
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{})
consortium.HandleSubmitBlockReward(leth.engine, statedb, msg, block)
if consortium.HandleSystemTransaction(leth.engine, statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
Expand Down

0 comments on commit 30a0907

Please sign in to comment.