diff --git a/ethrpc/ethrpc.go b/ethrpc/ethrpc.go index 1294471..f2e3bbb 100644 --- a/ethrpc/ethrpc.go +++ b/ethrpc/ethrpc.go @@ -67,6 +67,7 @@ var ( var _ Interface = &Provider{} var _ RawInterface = &Provider{} var _ StrictnessLevelGetter = &Provider{} +var _ DebugInterface = &Provider{} // Provider adheres to the go-ethereum bind.ContractBackend interface. In case we ever // want to break this interface, we could also write an adapter type to keep them compat. @@ -463,6 +464,24 @@ func (p *Provider) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint6 return result, err } +func (p *Provider) DebugTraceBlockByNumber(ctx context.Context, blockNum *big.Int) ([]*TransactionDebugTrace, error) { + var result []*TransactionDebugTrace + _, err := p.Do(ctx, DebugTraceBlockByNumber(blockNum).Into(&result)) + return result, err +} + +func (p *Provider) DebugTraceBlockByHash(ctx context.Context, blockHash common.Hash) ([]*TransactionDebugTrace, error) { + var result []*TransactionDebugTrace + _, err := p.Do(ctx, DebugTraceBlockByHash(blockHash).Into(&result)) + return result, err +} + +func (p *Provider) DebugTraceTransaction(ctx context.Context, txHash common.Hash) (*CallDebugTrace, error) { + var result *CallDebugTrace + _, err := p.Do(ctx, DebugTraceTransaction(txHash).Into(&result)) + return result, err +} + // ... func (p *Provider) IsStreamingEnabled() bool { return p.nodeWSURL != "" diff --git a/ethrpc/ethrpc_test.go b/ethrpc/ethrpc_test.go index 351d160..ea4dc4b 100644 --- a/ethrpc/ethrpc_test.go +++ b/ethrpc/ethrpc_test.go @@ -225,6 +225,40 @@ func TestRaw(t *testing.T) { } } +// todo: uncomment when those call are available on node-gateway +/*func TestDebugTraceBlockByNumber(t *testing.T) { + p, err := ethrpc.NewProvider("https://nodes.sequence.app/polygon") + require.NoError(t, err) + + ctx := context.Background() + payload, err := p.DebugTraceBlockByNumber(ctx, big.NewInt(38470000)) + + require.NoError(t, err) + require.NotEmpty(t, payload) +} + +func TestDebugTraceBlockByHash(t *testing.T) { + p, err := ethrpc.NewProvider("https://nodes.sequence.app/polygon") + require.NoError(t, err) + + ctx := context.Background() + payload, err := p.DebugTraceBlockByHash(ctx, common.HexToHash("0x4ab1c5d23e74dc9ec309c5e9c44dc5cf4d3739085747d35ab7d7a76983e1d1f0")) + + require.NoError(t, err) + require.NotEmpty(t, payload) +} + +func TestDebugTraceTransaction(t *testing.T) { + p, err := ethrpc.NewProvider("https://nodes.sequence.app/polygon") + require.NoError(t, err) + + ctx := context.Background() + payload, err := p.DebugTraceTransaction(ctx, common.HexToHash("0x971329c0a49974ba20f7cafb1404610ea712aabbd164a66314050d62a1829eb5")) + + require.NoError(t, err) + require.NotEmpty(t, payload) +}*/ + // func TestJWTAuth(t *testing.T) { // p, err := ethrpc.NewProvider("https://dev-nodes.sequence.app/polygon", ethrpc.WithJWTAuthorization("xx")) // require.NoError(t, err) diff --git a/ethrpc/interface.go b/ethrpc/interface.go index 5f1fa80..10395a6 100644 --- a/ethrpc/interface.go +++ b/ethrpc/interface.go @@ -197,3 +197,10 @@ type RawInterface interface { type StrictnessLevelGetter interface { StrictnessLevel() StrictnessLevel } + +// DebugInterface provides additional debugging methods +type DebugInterface interface { + DebugTraceBlockByNumber(ctx context.Context, blockNum *big.Int) ([]*TransactionDebugTrace, error) + DebugTraceBlockByHash(ctx context.Context, blockHash common.Hash) ([]*TransactionDebugTrace, error) + DebugTraceTransaction(ctx context.Context, txHash common.Hash) (*CallDebugTrace, error) +} diff --git a/ethrpc/methods.go b/ethrpc/methods.go index a1fa3c7..ac28d50 100644 --- a/ethrpc/methods.go +++ b/ethrpc/methods.go @@ -418,3 +418,54 @@ func EstimateGas(msg ethereum.CallMsg) CallBuilder[uint64] { intoFn: hexIntoUint64, } } + +type DebugTracer string + +const ( + DebugTracerCallTracer DebugTracer = "callTracer" + DebugTracerPreStateTracer DebugTracer = "prestateTracer" +) + +type debugTracerOptions struct { + Name string `json:"tracer"` +} + +type CallDebugTrace struct { + Type string `json:"type"` + From common.Address `json:"from"` + To common.Address `json:"to"` + Value *hexutil.Big `json:"value"` + Gas *hexutil.Big `json:"gas"` + GasUsed *hexutil.Big `json:"gasUsed"` + Input hexutil.Bytes `json:"input"` + Output hexutil.Bytes `json:"output"` + Error string `json:"error"` + RevertReason string `json:"revertReason"` + Calls []*CallDebugTrace `json:"calls"` +} + +type TransactionDebugTrace struct { + TxHash common.Hash `json:"txHash"` + Result CallDebugTrace `json:"result"` +} + +func DebugTraceBlockByNumber(blockNum *big.Int) CallBuilder[[]*TransactionDebugTrace] { + return CallBuilder[[]*TransactionDebugTrace]{ + method: "debug_traceBlockByNumber", + params: []any{toBlockNumArg(blockNum), debugTracerOptions{Name: string(DebugTracerCallTracer)}}, + } +} + +func DebugTraceBlockByHash(hash common.Hash) CallBuilder[[]*TransactionDebugTrace] { + return CallBuilder[[]*TransactionDebugTrace]{ + method: "debug_traceBlockByHash", + params: []any{hash, debugTracerOptions{Name: string(DebugTracerCallTracer)}}, + } +} + +func DebugTraceTransaction(txHash common.Hash) CallBuilder[*CallDebugTrace] { + return CallBuilder[*CallDebugTrace]{ + method: "debug_traceTransaction", + params: []any{txHash, debugTracerOptions{Name: string(DebugTracerCallTracer)}}, + } +}