diff --git a/ethrpc/ethrpc.go b/ethrpc/ethrpc.go index 7c5c54ba..0a63ddba 100644 --- a/ethrpc/ethrpc.go +++ b/ethrpc/ethrpc.go @@ -16,6 +16,7 @@ import ( "github.com/0xsequence/ethkit/go-ethereum/accounts/abi/bind" "github.com/0xsequence/ethkit/go-ethereum/common" "github.com/0xsequence/ethkit/go-ethereum/core/types" + "github.com/0xsequence/ethkit/go-ethereum/eth/tracers" "github.com/goware/breaker" "github.com/goware/logger" "github.com/goware/superr" @@ -383,6 +384,12 @@ func (p *Provider) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint6 return result, err } +func (p *Provider) DebugTraceCall(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int, config tracers.TraceConfig) (json.RawMessage, error) { + var result json.RawMessage + err := p.Do(ctx, DebugTraceCall(msg, blockNum, config).Into(&result)) + return result, err +} + // SubscribeFilterLogs is stubbed below so we can adhere to the bind.ContractBackend interface. func (p *Provider) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { return nil, fmt.Errorf("ethrpc: method is unavailable") diff --git a/ethrpc/methods.go b/ethrpc/methods.go index a41d29de..e6639434 100644 --- a/ethrpc/methods.go +++ b/ethrpc/methods.go @@ -10,6 +10,7 @@ import ( "github.com/0xsequence/ethkit/go-ethereum/common" "github.com/0xsequence/ethkit/go-ethereum/common/hexutil" "github.com/0xsequence/ethkit/go-ethereum/core/types" + "github.com/0xsequence/ethkit/go-ethereum/eth/tracers" "github.com/0xsequence/ethkit/go-ethereum/rpc" ) @@ -301,6 +302,13 @@ func SuggestGasTipCap() CallBuilder[*big.Int] { } } +func DebugTraceCall(msg ethereum.CallMsg, blockNum *big.Int, config tracers.TraceConfig) CallBuilder[json.RawMessage] { + return CallBuilder[json.RawMessage]{ + method: "debug_traceCall", + params: []any{toCallArg(msg), toBlockNumArg(blockNum), config}, + } +} + type feeHistoryResult struct { OldestBlock *hexutil.Big `json:"oldestBlock"` Reward [][]*hexutil.Big `json:"reward,omitempty"` diff --git a/go-ethereum/eth/tracers/logger/config.go b/go-ethereum/eth/tracers/logger/config.go new file mode 100644 index 00000000..1a591d38 --- /dev/null +++ b/go-ethereum/eth/tracers/logger/config.go @@ -0,0 +1,14 @@ +package logger + +import "github.com/0xsequence/ethkit/go-ethereum/params" + +type Config struct { + EnableMemory bool // enable memory capture + DisableStack bool // disable stack capture + DisableStorage bool // disable storage capture + EnableReturnData bool // enable return data capture + Debug bool // print output during capture end + Limit int // maximum length of output, but zero means unlimited + // Chain overrides, can be used to execute a trace using future fork rules + Overrides *params.ChainConfig `json:"overrides,omitempty"` +} diff --git a/go-ethereum/eth/tracers/tracers.go b/go-ethereum/eth/tracers/tracers.go new file mode 100644 index 00000000..749c4133 --- /dev/null +++ b/go-ethereum/eth/tracers/tracers.go @@ -0,0 +1,24 @@ +package tracers + +import ( + "encoding/json" + + "github.com/0xsequence/ethkit/go-ethereum/eth/tracers/logger" + "github.com/0xsequence/ethkit/go-ethereum/internal/ethapi" +) + +type TraceCallConfig struct { + TraceConfig + StateOverrides *ethapi.StateOverride + BlockOverrides *ethapi.BlockOverrides +} + +type TraceConfig struct { + *logger.Config + Tracer *string + Timeout *string + Reexec *uint64 + // Config specific to given tracer. Note struct logger + // config are historically embedded in main object. + TracerConfig json.RawMessage +} diff --git a/go-ethereum/internal/ethapi/api.go b/go-ethereum/internal/ethapi/api.go new file mode 100644 index 00000000..29b64e3c --- /dev/null +++ b/go-ethereum/internal/ethapi/api.go @@ -0,0 +1,26 @@ +package ethapi + +import ( + "github.com/0xsequence/ethkit/go-ethereum/common" + "github.com/0xsequence/ethkit/go-ethereum/common/hexutil" +) + +type OverrideAccount struct { + Nonce *hexutil.Uint64 `json:"nonce"` + Code *hexutil.Bytes `json:"code"` + Balance **hexutil.Big `json:"balance"` + State *map[common.Hash]common.Hash `json:"state"` + StateDiff *map[common.Hash]common.Hash `json:"stateDiff"` +} + +type StateOverride map[common.Address]OverrideAccount + +type BlockOverrides struct { + Number *hexutil.Big + Difficulty *hexutil.Big + Time *hexutil.Uint64 + GasLimit *hexutil.Uint64 + Coinbase *common.Address + Random *common.Hash + BaseFee *hexutil.Big +}