• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lmittmann / w3 / 13391512004

18 Feb 2025 01:19PM UTC coverage: 63.77% (+0.3%) from 63.49%
13391512004

push

github

web-flow
module/debug: fix `Trace.UnmarshalJSON` (#225)

* internal/hexutil: added `Bytes` type that unmarshals both with and without 0x-prefix

* module/debug: fix `Trace.UnmarshalJSON`

---------

Co-authored-by: lmittmann <lmittmann@users.noreply.github.com>

28 of 30 new or added lines in 2 files covered. (93.33%)

2033 of 3188 relevant lines covered (63.77%)

755.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.17
/module/debug/trace.go
1
package debug
2

3
import (
4
        "encoding/hex"
5
        "encoding/json"
6
        "fmt"
7
        "math/big"
8

9
        "github.com/ethereum/go-ethereum/common"
10
        "github.com/ethereum/go-ethereum/core/vm"
11
        "github.com/holiman/uint256"
12
        "github.com/lmittmann/w3/internal/hexutil"
13
        "github.com/lmittmann/w3/internal/module"
14
        "github.com/lmittmann/w3/w3types"
15
)
16

17
// TraceCall requests the trace of the given message.
18
func TraceCall(msg *w3types.Message, blockNumber *big.Int, config *TraceConfig) w3types.RPCCallerFactory[*Trace] {
1✔
19
        if config == nil {
1✔
20
                config = &TraceConfig{}
×
21
        }
×
22
        return module.NewFactory(
1✔
23
                "debug_traceCall",
1✔
24
                []any{msg, module.BlockNumberArg(blockNumber), config},
1✔
25
                module.WithArgsWrapper[*Trace](msgArgsWrapper),
1✔
26
        )
1✔
27
}
28

29
// TraceTx requests the trace of the transaction with the given hash.
30
func TraceTx(txHash common.Hash, config *TraceConfig) w3types.RPCCallerFactory[*Trace] {
2✔
31
        if config == nil {
3✔
32
                config = &TraceConfig{}
1✔
33
        }
1✔
34
        return module.NewFactory[*Trace](
2✔
35
                "debug_traceTransaction",
2✔
36
                []any{txHash, config},
2✔
37
        )
2✔
38
}
39

40
type TraceConfig struct {
41
        Overrides      w3types.State           // Override account state
42
        BlockOverrides *w3types.BlockOverrides // Override block state
43
        EnableStack    bool                    // Enable stack capture
44
        EnableMemory   bool                    // Enable memory capture
45
        EnableStorage  bool                    // Enable storage capture
46
        Limit          uint64                  // Maximum number of StructLog's to capture (all if zero)
47
}
48

49
// MarshalJSON implements the [json.Marshaler].
50
func (c *TraceConfig) MarshalJSON() ([]byte, error) {
3✔
51
        type config struct {
3✔
52
                Overrides        w3types.State           `json:"stateOverrides,omitempty"`
3✔
53
                BlockOverrides   *w3types.BlockOverrides `json:"blockOverrides,omitempty"`
3✔
54
                DisableStorage   bool                    `json:"disableStorage,omitempty"`
3✔
55
                DisableStack     bool                    `json:"disableStack,omitempty"`
3✔
56
                EnableMemory     bool                    `json:"enableMemory,omitempty"`
3✔
57
                EnableReturnData bool                    `json:"enableReturnData,omitempty"`
3✔
58
                Limit            uint64                  `json:"limit,omitempty"`
3✔
59
        }
3✔
60

3✔
61
        return json.Marshal(config{
3✔
62
                Overrides:        c.Overrides,
3✔
63
                BlockOverrides:   c.BlockOverrides,
3✔
64
                DisableStorage:   !c.EnableStorage,
3✔
65
                DisableStack:     !c.EnableStack,
3✔
66
                EnableMemory:     c.EnableMemory,
3✔
67
                EnableReturnData: true,
3✔
68
                Limit:            c.Limit,
3✔
69
        })
3✔
70
}
3✔
71

72
type Trace struct {
73
        Gas        uint64       `json:"gas"`
74
        Failed     bool         `json:"failed"`
75
        Output     []byte       `json:"returnValue"`
76
        StructLogs []*StructLog `json:"structLogs"`
77
}
78

79
func (t *Trace) UnmarshalJSON(data []byte) error {
3✔
80
        type trace struct {
3✔
81
                Gas        uint64        `json:"gas"`
3✔
82
                Failed     bool          `json:"failed"`
3✔
83
                Output     hexutil.Bytes `json:"returnValue"`
3✔
84
                StructLogs []*StructLog  `json:"structLogs"`
3✔
85
        }
3✔
86

3✔
87
        var dec trace
3✔
88
        if err := json.Unmarshal(data, &dec); err != nil {
3✔
NEW
89
                return err
×
NEW
90
        }
×
91

92
        t.Gas = dec.Gas
3✔
93
        t.Failed = dec.Failed
3✔
94
        t.Output = dec.Output
3✔
95
        t.StructLogs = dec.StructLogs
3✔
96
        return nil
3✔
97
}
98

99
type StructLog struct {
100
        Pc      uint64
101
        Depth   uint
102
        Gas     uint64
103
        GasCost uint
104
        Op      vm.OpCode
105
        Stack   []uint256.Int
106
        Memory  []byte
107
        Storage w3types.Storage
108
}
109

110
func (l *StructLog) UnmarshalJSON(data []byte) error {
3✔
111
        type structLog struct {
3✔
112
                Pc      uint64
3✔
113
                Depth   uint
3✔
114
                Gas     uint64
3✔
115
                GasCost uint
3✔
116
                Op      string
3✔
117
                Stack   []uint256.Int
3✔
118
                Memory  memory
3✔
119
                Storage map[optionalPrefixedHash]optionalPrefixedHash
3✔
120
        }
3✔
121

3✔
122
        var dec structLog
3✔
123
        if err := json.Unmarshal(data, &dec); err != nil {
3✔
124
                return err
×
125
        }
×
126

127
        l.Pc = dec.Pc
3✔
128
        l.Depth = dec.Depth
3✔
129
        l.Gas = dec.Gas
3✔
130
        l.GasCost = dec.GasCost
3✔
131
        l.Op = vm.StringToOp(dec.Op)
3✔
132
        l.Stack = dec.Stack
3✔
133
        l.Memory = dec.Memory
3✔
134

3✔
135
        if len(dec.Storage) > 0 {
3✔
136
                l.Storage = make(w3types.Storage, len(dec.Storage))
×
137
                for k, v := range dec.Storage {
×
138
                        l.Storage[(common.Hash)(k)] = (common.Hash)(v)
×
139
                }
×
140
        }
141
        return nil
3✔
142
}
143

144
// optionalPrefixedHash is a helper for unmarshaling hashes with or without
145
// "0x"-prefix.
146
type optionalPrefixedHash common.Hash
147

148
func (h *optionalPrefixedHash) UnmarshalText(data []byte) error {
3✔
149
        if len(data) > 2 && data[0] == '0' && (data[1] == 'x' || data[1] == 'X') {
3✔
150
                data = data[2:]
×
151
        }
×
152

153
        if len(data) != 2*common.HashLength {
3✔
154
                return fmt.Errorf("hex string has length %d, want 64", len(data))
×
155
        }
×
156

157
        _, err := hex.Decode((*h)[:], data)
3✔
158
        return err
3✔
159
}
160

161
type memory []byte
162

163
func (m *memory) UnmarshalJSON(data []byte) error {
3✔
164
        var dec []optionalPrefixedHash
3✔
165
        if err := json.Unmarshal(data, &dec); err != nil {
3✔
166
                return err
×
167
        }
×
168

169
        *m = make([]byte, 0, 32*len(dec))
3✔
170
        for _, data := range dec {
6✔
171
                *m = append(*m, data[:]...)
3✔
172
        }
3✔
173
        return nil
3✔
174
}
175

176
func msgArgsWrapper(slice []any) ([]any, error) {
2✔
177
        msg := slice[0].(*w3types.Message)
2✔
178
        if msg.Input != nil || msg.Func == nil {
4✔
179
                return slice, nil
2✔
180
        }
2✔
181

182
        input, err := msg.Func.EncodeArgs(msg.Args...)
×
183
        if err != nil {
×
184
                return nil, err
×
185
        }
×
186
        msg.Input = input
×
187
        slice[0] = msg
×
188
        return slice, nil
×
189
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc