Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: wrong returned gas used and handler crash in debug APIs #276

Merged
merged 2 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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