diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index 1e275aaa742..da5c5b248c0 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -37,7 +37,7 @@ func APIList(db kv.RoDB, borDb kv.RoDB, eth rpchelper.ApiBackend, txPool txpool. erigonImpl := NewErigonAPI(base, db, eth) txpoolImpl := NewTxPoolAPI(base, db, txPool, rawPool, rpcUrl) netImpl := NewNetAPIImpl(eth) - debugImpl := NewPrivateDebugAPI(base, db, cfg.Gascap) + debugImpl := NewPrivateDebugAPI(base, db, cfg.Gascap, ethCfg) traceImpl := NewTraceAPI(base, db, &cfg) web3Impl := NewWeb3APIImpl(eth) dbImpl := NewDBAPIImpl() /* deprecated */ diff --git a/cmd/rpcdaemon/commands/debug_api.go b/cmd/rpcdaemon/commands/debug_api.go index 5ae051690e4..6b3b2e5e28e 100644 --- a/cmd/rpcdaemon/commands/debug_api.go +++ b/cmd/rpcdaemon/commands/debug_api.go @@ -21,6 +21,7 @@ import ( "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/erigon/turbo/adapter/ethapi" "github.com/ledgerwatch/erigon/turbo/transactions" + "github.com/ledgerwatch/erigon/eth/ethconfig" ) // AccountRangeMaxResults is the maximum number of results to be returned per call @@ -37,6 +38,7 @@ type PrivateDebugAPI interface { GetModifiedAccountsByHash(_ context.Context, startHash common.Hash, endHash *common.Hash) ([]common.Address, error) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *tracers.TraceConfig_ZkEvm, stream *jsoniter.Stream) error AccountAt(ctx context.Context, blockHash common.Hash, txIndex uint64, account common.Address) (*AccountResult, error) + TraceTransactionCounters(ctx context.Context, hash common.Hash, config *tracers.TraceConfig_ZkEvm, stream *jsoniter.Stream) error } // PrivateDebugAPIImpl is implementation of the PrivateDebugAPI interface based on remote Db access @@ -44,14 +46,16 @@ type PrivateDebugAPIImpl struct { *BaseAPI db kv.RoDB GasCap uint64 + config *ethconfig.Config } // NewPrivateDebugAPI returns PrivateDebugAPIImpl instance -func NewPrivateDebugAPI(base *BaseAPI, db kv.RoDB, gascap uint64) *PrivateDebugAPIImpl { +func NewPrivateDebugAPI(base *BaseAPI, db kv.RoDB, gascap uint64, config *ethconfig.Config) *PrivateDebugAPIImpl { return &PrivateDebugAPIImpl{ BaseAPI: base, db: db, GasCap: gascap, + config: config, } } diff --git a/cmd/rpcdaemon/commands/tracing_zkevm.go b/cmd/rpcdaemon/commands/tracing_zkevm.go index 6d3030c6de1..21ce600c541 100644 --- a/cmd/rpcdaemon/commands/tracing_zkevm.go +++ b/cmd/rpcdaemon/commands/tracing_zkevm.go @@ -360,3 +360,118 @@ func (api *PrivateDebugAPIImpl) TraceCallMany(ctx context.Context, bundles []Bun stream.WriteArrayEnd() return nil } + +// TraceTransaction implements debug_traceTransaction. Returns Geth style transaction traces. +func (api *PrivateDebugAPIImpl) TraceTransactionCounters(ctx context.Context, hash common.Hash, config *tracers.TraceConfig_ZkEvm, stream *jsoniter.Stream) error { + tx, err := api.db.BeginRo(ctx) + if err != nil { + stream.WriteNil() + return err + } + defer tx.Rollback() + chainConfig, err := api.chainConfig(tx) + if err != nil { + stream.WriteNil() + return err + } + // Retrieve the transaction and assemble its EVM context + blockNum, ok, err := api.txnLookup(ctx, tx, hash) + if err != nil { + stream.WriteNil() + return err + } + if !ok { + stream.WriteNil() + return nil + } + + // check pruning to ensure we have history at this block level + if err = api.BaseAPI.checkPruneHistory(tx, blockNum); err != nil { + stream.WriteNil() + return err + } + + // Private API returns 0 if transaction is not found. + if blockNum == 0 && chainConfig.Bor != nil { + blockNumPtr, err := rawdb.ReadBorTxLookupEntry(tx, hash) + if err != nil { + stream.WriteNil() + return err + } + if blockNumPtr == nil { + stream.WriteNil() + return nil + } + blockNum = *blockNumPtr + } + block, err := api.blockByNumberWithSenders(tx, blockNum) + if err != nil { + stream.WriteNil() + return err + } + if block == nil { + stream.WriteNil() + return nil + } + var txnIndex uint64 + var txn types.Transaction + for i, transaction := range block.Transactions() { + if transaction.Hash() == hash { + txnIndex = uint64(i) + txn = transaction + break + } + } + if txn == nil { + borTx, _, _, _, err := rawdb.ReadBorTransaction(tx, hash) + if err != nil { + stream.WriteNil() + return err + } + + if borTx != nil { + stream.WriteNil() + return nil + } + stream.WriteNil() + return fmt.Errorf("transaction %#x not found", hash) + } + engine := api.engine() + + txEnv, err := transactions.ComputeTxEnv_ZkEvm(ctx, engine, block, chainConfig, api._blockReader, tx, int(txnIndex), api.historyV3(tx)) + if err != nil { + stream.WriteNil() + return err + } + + // counters work + hermezDb := hermez_db.NewHermezDbReader(tx) + forkId, err := hermezDb.GetForkIdByBlockNum(blockNum) + if err != nil { + stream.WriteNil() + return err + } + + smtDepth, err := getSmtDepth(hermezDb, blockNum, config) + if err != nil { + stream.WriteNil() + return err + } + + txCounters := vm.NewTransactionCounter(txn, int(smtDepth), uint16(forkId), api.config.Zk.VirtualCountersSmtReduction, false) + batchCounters := vm.NewBatchCounterCollector(int(smtDepth), uint16(forkId), api.config.Zk.VirtualCountersSmtReduction, false, nil) + + if _, err = batchCounters.AddNewTransactionCounters(txCounters); err != nil { + stream.WriteNil() + return err + } + + // set tracer to counter tracer + if config == nil { + config = &tracers.TraceConfig_ZkEvm{} + } + config.CounterCollector = txCounters + + // Trace the transaction and return + return transactions.TraceTx(ctx, txEnv.Msg, txEnv.BlockContext, txEnv.TxContext, txEnv.Ibs, config, chainConfig, stream, api.evmCallTimeout) +} diff --git a/cmd/rpcdaemon/commands/zkevm_api.go b/cmd/rpcdaemon/commands/zkevm_api.go index cacdbe257d9..2d4682a5fa6 100644 --- a/cmd/rpcdaemon/commands/zkevm_api.go +++ b/cmd/rpcdaemon/commands/zkevm_api.go @@ -12,7 +12,6 @@ import ( "github.com/gateway-fm/cdk-erigon-lib/common/hexutility" "github.com/gateway-fm/cdk-erigon-lib/kv" "github.com/gateway-fm/cdk-erigon-lib/kv/memdb" - jsoniter "github.com/json-iterator/go" zktypes "github.com/ledgerwatch/erigon/zk/types" "github.com/ledgerwatch/log/v3" @@ -26,7 +25,6 @@ import ( "github.com/ledgerwatch/erigon/eth/ethconfig" "github.com/ledgerwatch/erigon/eth/stagedsync" "github.com/ledgerwatch/erigon/eth/stagedsync/stages" - "github.com/ledgerwatch/erigon/eth/tracers" "github.com/ledgerwatch/erigon/rpc" smtDb "github.com/ledgerwatch/erigon/smt/pkg/db" smt "github.com/ledgerwatch/erigon/smt/pkg/smt" @@ -70,7 +68,6 @@ type ZkEvmAPI interface { GetExitRootsByGER(ctx context.Context, globalExitRoot common.Hash) (*ZkExitRoots, error) GetL2BlockInfoTree(ctx context.Context, blockNum rpc.BlockNumberOrHash) (json.RawMessage, error) EstimateCounters(ctx context.Context, argsOrNil *zkevmRPCTransaction) (json.RawMessage, error) - TraceTransactionCounters(ctx context.Context, hash common.Hash, config *tracers.TraceConfig_ZkEvm, stream *jsoniter.Stream) error GetBatchCountersByNumber(ctx context.Context, batchNumRpc rpc.BlockNumber) (res json.RawMessage, err error) GetExitRootTable(ctx context.Context) ([]l1InfoTreeData, error) GetVersionHistory(ctx context.Context) (json.RawMessage, error) diff --git a/cmd/rpcdaemon/commands/zkevm_counters.go b/cmd/rpcdaemon/commands/zkevm_counters.go index e7657805bb3..ae4a73c71e6 100644 --- a/cmd/rpcdaemon/commands/zkevm_counters.go +++ b/cmd/rpcdaemon/commands/zkevm_counters.go @@ -9,7 +9,6 @@ import ( "github.com/gateway-fm/cdk-erigon-lib/common/hexutility" "github.com/gateway-fm/cdk-erigon-lib/kv" "github.com/holiman/uint256" - jsoniter "github.com/json-iterator/go" "github.com/ledgerwatch/erigon/chain" "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/eth/tracers" @@ -24,7 +23,6 @@ import ( "github.com/ledgerwatch/erigon/core/vm" "github.com/ledgerwatch/erigon/core/vm/evmtypes" "github.com/ledgerwatch/erigon/turbo/rpchelper" - "github.com/ledgerwatch/erigon/turbo/transactions" "github.com/ledgerwatch/erigon/zk/hermez_db" ) @@ -301,121 +299,6 @@ func populateCounters(collected *vm.Counters, execResult *core.ExecutionResult, return resJson, nil } -// TraceTransaction implements debug_traceTransaction. Returns Geth style transaction traces. -func (api *ZkEvmAPIImpl) TraceTransactionCounters(ctx context.Context, hash common.Hash, config *tracers.TraceConfig_ZkEvm, stream *jsoniter.Stream) error { - tx, err := api.db.BeginRo(ctx) - if err != nil { - stream.WriteNil() - return err - } - defer tx.Rollback() - chainConfig, err := api.ethApi.chainConfig(tx) - if err != nil { - stream.WriteNil() - return err - } - // Retrieve the transaction and assemble its EVM context - blockNum, ok, err := api.ethApi.txnLookup(ctx, tx, hash) - if err != nil { - stream.WriteNil() - return err - } - if !ok { - stream.WriteNil() - return nil - } - - // check pruning to ensure we have history at this block level - if err = api.ethApi.BaseAPI.checkPruneHistory(tx, blockNum); err != nil { - stream.WriteNil() - return err - } - - // Private API returns 0 if transaction is not found. - if blockNum == 0 && chainConfig.Bor != nil { - blockNumPtr, err := rawdb.ReadBorTxLookupEntry(tx, hash) - if err != nil { - stream.WriteNil() - return err - } - if blockNumPtr == nil { - stream.WriteNil() - return nil - } - blockNum = *blockNumPtr - } - block, err := api.ethApi.blockByNumberWithSenders(tx, blockNum) - if err != nil { - stream.WriteNil() - return err - } - if block == nil { - stream.WriteNil() - return nil - } - var txnIndex uint64 - var txn types.Transaction - for i, transaction := range block.Transactions() { - if transaction.Hash() == hash { - txnIndex = uint64(i) - txn = transaction - break - } - } - if txn == nil { - borTx, _, _, _, err := rawdb.ReadBorTransaction(tx, hash) - if err != nil { - stream.WriteNil() - return err - } - - if borTx != nil { - stream.WriteNil() - return nil - } - stream.WriteNil() - return fmt.Errorf("transaction %#x not found", hash) - } - engine := api.ethApi.engine() - - txEnv, err := transactions.ComputeTxEnv_ZkEvm(ctx, engine, block, chainConfig, api.ethApi._blockReader, tx, int(txnIndex), api.ethApi.historyV3(tx)) - if err != nil { - stream.WriteNil() - return err - } - - // counters work - hermezDb := hermez_db.NewHermezDbReader(tx) - forkId, err := hermezDb.GetForkIdByBlockNum(blockNum) - if err != nil { - stream.WriteNil() - return err - } - - smtDepth, err := getSmtDepth(hermezDb, blockNum, config) - if err != nil { - stream.WriteNil() - return err - } - - txCounters := vm.NewTransactionCounter(txn, int(smtDepth), uint16(forkId), api.config.Zk.VirtualCountersSmtReduction, false) - batchCounters := vm.NewBatchCounterCollector(int(smtDepth), uint16(forkId), api.config.Zk.VirtualCountersSmtReduction, false, nil) - - if _, err = batchCounters.AddNewTransactionCounters(txCounters); err != nil { - stream.WriteNil() - return err - } - - // set tracer to counter tracer - if config == nil { - config = &tracers.TraceConfig_ZkEvm{} - } - config.CounterCollector = txCounters - - // Trace the transaction and return - return transactions.TraceTx(ctx, txEnv.Msg, txEnv.BlockContext, txEnv.TxContext, txEnv.Ibs, config, chainConfig, stream, api.ethApi.evmCallTimeout) -} - func getSmtDepth(hermezDb *hermez_db.HermezDbReader, blockNum uint64, config *tracers.TraceConfig_ZkEvm) (int, error) { var smtDepth int if config != nil && config.SmtDepth != nil {