Skip to content

Commit e44cbc5

Browse files
fix(evm-trace-block): handle native tracer errors JSON-RPC errors for "debug_traceBlockByNumber". Fixes [Nibiru#2400 bug](#2400) (#2409)
* refactor: use return values without error for function that always succeeds * fix(TraceBlock): use native tracer behavior, not JS parallel tracer; Make test comparisons less brittle * fix(evmstate): trace block gas inconsistency fixed + error on trace tx failure like geth * finish PR for #2400 * tx hash field * fix(vmtracer): include tx hash as one of the fields for trace results * refactor: PR feedback from Gemini-code-assist
1 parent 57da5c7 commit e44cbc5

File tree

12 files changed

+228
-85
lines changed

12 files changed

+228
-85
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ See https://github.com/dangoslen/changelog-enforcer.
5656
- [#2405](https://github.com/NibiruChain/nibiru/pull/2405) - chore: additional coin logos which could be used externally
5757
- [#2406](https://github.com/NibiruChain/nibiru/pull/2406) - chore: added monad logo svg
5858
- [#2407](https://github.com/NibiruChain/nibiru/pull/2407) - feat(sudo-ante): implement zero gas actors for invoking whitelisted contract
59+
- [#2409](https://github.com/NibiruChain/nibiru/pull/2409) - fix(evm-trace-block): handle native tracer errors JSON-RPC errors for "debug_traceBlockByNumber". Fixes [Nibiru#2400 bug](https://github.com/NibiruChain/nibiru/issues/2400)
5960
- [#2410](https://github.com/NibiruChain/nibiru/pull/2410) -
6061
feat(evm/grpc-query): Update the "/eth.evm.v1.Query/Balance" query to work with
6162
"0x" Ethereum hex and "nibi"-prefixed Bech32 address formats. Return no Eth

app/ante.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func NewAnteHandlerNonEVM(
4747
ante.AnteDecPreventEthereumTxMsgs{}, // reject MsgEthereumTxs
4848
ante.AnteDecAuthzGuard{}, // disable certain messages in authz grant "generic"
4949
authante.NewSetUpContextDecorator(),
50-
ante.AnteDecSaiOracle{PublicKeepers: pk},
50+
ante.AnteDecZeroGasActors{PublicKeepers: pk},
5151
wasmkeeper.NewLimitSimulationGasDecorator(opts.WasmConfig.SimulationGasLimit),
5252
wasmkeeper.NewCountTXDecorator(opts.TxCounterStoreKey),
5353
// TODO: bug(security): Authz is unsafe. Let's include a guard to make

app/ante/fixed_gas.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const (
1717

1818
var (
1919
_ sdk.AnteDecorator = AnteDecEnsureSinglePostPriceMessage{}
20-
_ sdk.AnteDecorator = AnteDecSaiOracle{}
20+
_ sdk.AnteDecorator = AnteDecZeroGasActors{}
2121
)
2222

2323
// AnteDecEnsureSinglePostPriceMessage ensures that there is only one
@@ -61,22 +61,20 @@ func (anteDec AnteDecEnsureSinglePostPriceMessage) AnteHandle(
6161
return next(ctx, tx, simulate)
6262
}
6363

64-
// AnteDecSaiOracle checks for Wasm execute contract calls from a set of
65-
// known senders to the Sai oracle contract(s) and lowers gas costs using a fixed
66-
// gas meter.
67-
type AnteDecSaiOracle struct {
64+
// AnteDecZeroGasActors checks for Wasm execute contract calls from a set of
65+
// known senders to the whitelisted contract(s), giving those transactions zero
66+
// gas costs using a fixed gas meter.
67+
type AnteDecZeroGasActors struct {
6868
keepers.PublicKeepers
6969
}
7070

71-
func (anteDec AnteDecSaiOracle) AnteHandle(
71+
func (anteDec AnteDecZeroGasActors) AnteHandle(
7272
ctx sdk.Context,
7373
tx sdk.Tx,
7474
simulate bool,
7575
next sdk.AnteHandler,
7676
) (newCtx sdk.Context, err error) {
77-
goCtx := sdk.WrapSDKContext(ctx)
78-
resp, _ := anteDec.SudoKeeper.QueryZeroGasActors(goCtx, nil)
79-
zeroGasActors := resp.Actors
77+
zeroGasActors := anteDec.SudoKeeper.GetZeroGasActors(ctx)
8078
if len(zeroGasActors.Senders) == 0 || len(zeroGasActors.Contracts) == 0 {
8179
return next(ctx, tx, simulate)
8280
}

eth/rpc/rpcapi/api_debug.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ func (a *DebugAPI) TraceBlockByNumber(height rpc.BlockNumber, config *evm.TraceC
8585
// Get Tendermint Block
8686
resBlock, err := a.backend.TendermintBlockByNumber(height)
8787
if err != nil {
88-
a.logger.Debug("get block failed", "height", height, "error", err.Error())
88+
err = fmt.Errorf("%s { blockHeight: %d }", err, height)
89+
a.logger.Debug("get block failed", "error", err.Error())
8990
return nil, err
9091
}
9192

eth/rpc/rpcapi/tracing.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ func (b *Backend) TraceBlock(height rpc.BlockNumber,
142142
config *evm.TraceConfig,
143143
block *tmrpctypes.ResultBlock,
144144
) ([]*evm.TxTraceResult, error) {
145-
txs := block.Block.Txs
146-
txsLength := len(txs)
145+
blockTxs := block.Block.Txs
146+
txsLength := len(blockTxs)
147147

148148
if txsLength == 0 {
149149
// If there are no transactions return empty array
@@ -153,10 +153,10 @@ func (b *Backend) TraceBlock(height rpc.BlockNumber,
153153
txDecoder := b.clientCtx.TxConfig.TxDecoder()
154154

155155
var txsMessages []*evm.MsgEthereumTx
156-
for i, tx := range txs {
157-
decodedTx, err := txDecoder(tx)
156+
for i, blockTx := range blockTxs {
157+
decodedTx, err := txDecoder(blockTx)
158158
if err != nil {
159-
b.logger.Error("failed to decode transaction", "hash", txs[i].Hash(), "error", err.Error())
159+
b.logger.Error("failed to decode transaction", "hash", blockTxs[i].Hash(), "error", err.Error())
160160
continue
161161
}
162162

eth/rpc/rpcapi/tracing_test.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func (s *BackendSuite) TestTraceBlock() {
9595
tmBlock *tmrpctypes.ResultBlock
9696
txCount int
9797
traceConfig *evm.TraceConfig
98+
wantErr bool
9899
}{
99100
{
100101
name: "happy: TraceBlock, no txs, tracer: default",
@@ -124,6 +125,18 @@ func (s *BackendSuite) TestTraceBlock() {
124125
txCount: 1,
125126
traceConfig: traceConfigDefaultTracer(),
126127
},
128+
{
129+
name: "sad: TraceBlock with ultra small timeout, causing tracer to stop too early",
130+
blockNumber: *s.SuccessfulTxTransfer().BlockNumberRpc,
131+
tmBlock: tmBlockWithTx,
132+
txCount: 1,
133+
traceConfig: func() *evm.TraceConfig {
134+
cfg := traceConfigCallTracer()
135+
cfg.Timeout = "1ns" // Force immediate timeout
136+
return cfg
137+
}(),
138+
wantErr: true,
139+
},
127140
}
128141

129142
for _, tc := range testCases {
@@ -135,6 +148,10 @@ func (s *BackendSuite) TestTraceBlock() {
135148
tc.traceConfig,
136149
tc.tmBlock,
137150
)
151+
if tc.wantErr {
152+
s.Require().Error(err, tc.wantErr)
153+
return
154+
}
138155
s.Require().NoError(err)
139156
resRes = append(resRes, txTraceResults)
140157
}
@@ -146,7 +163,11 @@ func (s *BackendSuite) TestTraceBlock() {
146163
rpc.BlockNumber(tc.tmBlock.Block.Height),
147164
tc.traceConfig,
148165
)
149-
s.NoError(err)
166+
if tc.wantErr {
167+
s.Require().Error(err)
168+
return
169+
}
170+
s.Require().NoError(err)
150171

151172
var txTraceResults []*evm.TxTraceResult
152173
err = json.Unmarshal(resJson, &txTraceResults)

x/evm/cli/query.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func CmdQueryAccount() *cobra.Command {
9797
offline, _ := cmd.Flags().GetBool("offline")
9898

9999
if offline {
100-
var addrEth = eth.NibiruAddrToEthAddr(addrBech32)
100+
addrEth := eth.NibiruAddrToEthAddr(addrBech32)
101101
resp := new(evm.QueryEthAccountResponse)
102102
resp.EthAddress = addrEth.Hex()
103103
resp.Bech32Address = addrBech32.String()

x/evm/evmstate/grpc_query.go

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -690,29 +690,43 @@ func (k Keeper) TraceBlock(
690690
big.NewInt(ctx.BlockHeight()),
691691
evm.ParseBlockTimeUnixU64(ctx),
692692
)
693-
txsLength := len(req.Txs)
694-
results := make([]*evm.TxTraceResult, 0, txsLength)
695-
696-
txConfig := NewEmptyTxConfig(gethcommon.BytesToHash(ctx.HeaderHash().Bytes()))
697693

694+
// NOTE: Nibiru EVM uses exclusively native tracers and considers JS tracers
695+
// out of scope.
696+
//
697+
// Geth differentiates between native tracers and JS tracers.
698+
// Native tracers are the defaults like the "callTracer" and others have low
699+
// overhead and return errors if any of the txs fail tracing.
700+
//
701+
// JS tracers (geth only) have high overhead. Tracing for them runs a
702+
// parallel process that generates statesin one thread and traces txs in
703+
// separate worker threads. JS tracers store tracing errors for each tx as
704+
// fields of the returned trace result instead of failing the query.
705+
var (
706+
results = make([]evm.TxTraceResult, len(req.Txs))
707+
txConfig = NewEmptyTxConfig(gethcommon.BytesToHash(ctx.HeaderHash().Bytes()))
708+
// Transaction data as an EVM message to be traced.
709+
msg *core.Message
710+
)
698711
for i, tx := range req.Txs {
699712
result := evm.TxTraceResult{}
700713
ethTx := tx.AsTransaction()
701-
txConfig.TxHash = ethTx.Hash()
714+
result.TxHash = ethTx.Hash()
715+
txConfig.TxHash = result.TxHash
702716
txConfig.TxIndex = uint(i)
703-
msg, err := core.TransactionToMessage(ethTx, signer, evmCfg.BaseFeeWei)
704-
if err != nil {
705-
result.Error = err.Error()
706-
continue
707-
}
717+
// Here in "core.TransactionToMessage", the resulting msg is guaranteed
718+
// not to be nil, and potential signer errors are not relevant for
719+
// tracing, as this is only a query.
720+
msg, _ = core.TransactionToMessage(ethTx, signer, evmCfg.BaseFeeWei)
708721
traceResult, logIndex, err := k.TraceEthTxMsg(ctx, evmCfg, txConfig, *msg, req.TraceConfig, tracerConfig)
709722
if err != nil {
710-
result.Error = err.Error()
711-
} else {
712-
txConfig.LogIndex = logIndex
713-
result.Result = traceResult
723+
// Since Nibiru uses native tracers from geth, failure to trace any
724+
// tx means block tracing fails too.
725+
return nil, fmt.Errorf("trace tx error { txhash: %s, blockHeight: %d }: %w", ethTx.Hash().Hex(), ctx.BlockHeight(), err)
714726
}
715-
results = append(results, &result)
727+
txConfig.LogIndex = logIndex
728+
result.Result = traceResult
729+
results[i] = result
716730
}
717731

718732
resultData, err := json.Marshal(results)

0 commit comments

Comments
 (0)