Skip to content

Commit

Permalink
eth/tracers/logger: make structlog/json-log stack hex again (ethereum…
Browse files Browse the repository at this point in the history
…#28628)

* common/hexutil: define hex wrappers for uint256.Int

* eth/tracers/logger: make structlog/json-log stack hex again

* common/hexutil: goimports
  • Loading branch information
holiman authored and GrapeBaBa committed Dec 10, 2023
1 parent 86a9f94 commit b532903
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 4 deletions.
45 changes: 45 additions & 0 deletions common/hexutil/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ import (
"math/big"
"reflect"
"strconv"

"github.com/holiman/uint256"
)

var (
bytesT = reflect.TypeOf(Bytes(nil))
bigT = reflect.TypeOf((*Big)(nil))
uintT = reflect.TypeOf(Uint(0))
uint64T = reflect.TypeOf(Uint64(0))
u256T = reflect.TypeOf((*uint256.Int)(nil))
)

// Bytes marshals/unmarshals as a JSON string with 0x prefix.
Expand Down Expand Up @@ -225,6 +228,48 @@ func (b *Big) UnmarshalGraphQL(input interface{}) error {
return err
}

// U256 marshals/unmarshals as a JSON string with 0x prefix.
// The zero value marshals as "0x0".
type U256 uint256.Int

// MarshalText implements encoding.TextMarshaler
func (b U256) MarshalText() ([]byte, error) {
u256 := (*uint256.Int)(&b)
return []byte(u256.Hex()), nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (b *U256) UnmarshalJSON(input []byte) error {
// The uint256.Int.UnmarshalJSON method accepts "dec", "0xhex"; we must be
// more strict, hence we check string and invoke SetFromHex directly.
if !isString(input) {
return errNonString(u256T)
}
// The hex decoder needs to accept empty string ("") as '0', which uint256.Int
// would reject.
if len(input) == 2 {
(*uint256.Int)(b).Clear()
return nil
}
err := (*uint256.Int)(b).SetFromHex(string(input[1 : len(input)-1]))
if err != nil {
return &json.UnmarshalTypeError{Value: err.Error(), Type: u256T}
}
return nil
}

// UnmarshalText implements encoding.TextUnmarshaler
func (b *U256) UnmarshalText(input []byte) error {
// The uint256.Int.UnmarshalText method accepts "dec", "0xhex"; we must be
// more strict, hence we check string and invoke SetFromHex directly.
return (*uint256.Int)(b).SetFromHex(string(input))
}

// String returns the hex encoding of b.
func (b *U256) String() string {
return (*uint256.Int)(b).Hex()
}

// Uint64 marshals/unmarshals as a JSON string with 0x prefix.
// The zero value marshals as "0x0".
type Uint64 uint64
Expand Down
60 changes: 60 additions & 0 deletions common/hexutil/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"errors"
"math/big"
"testing"

"github.com/holiman/uint256"
)

func checkError(t *testing.T, input string, got, want error) bool {
Expand Down Expand Up @@ -176,6 +178,64 @@ func TestUnmarshalBig(t *testing.T) {
}
}

var unmarshalU256Tests = []unmarshalTest{
// invalid encoding
{input: "", wantErr: errJSONEOF},
{input: "null", wantErr: errNonString(u256T)},
{input: "10", wantErr: errNonString(u256T)},
{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, u256T)},
{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, u256T)},
{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, u256T)},
{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, u256T)},
{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, u256T)},
{
input: `"0x10000000000000000000000000000000000000000000000000000000000000000"`,
wantErr: wrapTypeError(ErrBig256Range, u256T),
},

// valid encoding
{input: `""`, want: big.NewInt(0)},
{input: `"0x0"`, want: big.NewInt(0)},
{input: `"0x2"`, want: big.NewInt(0x2)},
{input: `"0x2F2"`, want: big.NewInt(0x2f2)},
{input: `"0X2F2"`, want: big.NewInt(0x2f2)},
{input: `"0x1122aaff"`, want: big.NewInt(0x1122aaff)},
{input: `"0xbBb"`, want: big.NewInt(0xbbb)},
{input: `"0xfffffffff"`, want: big.NewInt(0xfffffffff)},
{
input: `"0x112233445566778899aabbccddeeff"`,
want: referenceBig("112233445566778899aabbccddeeff"),
},
{
input: `"0xffffffffffffffffffffffffffffffffffff"`,
want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
},
{
input: `"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"`,
want: referenceBig("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
},
}

func TestUnmarshalU256(t *testing.T) {
for _, test := range unmarshalU256Tests {
var v U256
err := json.Unmarshal([]byte(test.input), &v)
if !checkError(t, test.input, err, test.wantErr) {
continue
}
if test.want == nil {
continue
}
want := new(uint256.Int)
want.SetFromBig(test.want.(*big.Int))
have := (*uint256.Int)(&v)
if want.Cmp(have) != 0 {
t.Errorf("input %s: value mismatch: have %x, want %x", test.input, have, want)
continue
}
}
}

func BenchmarkUnmarshalBig(b *testing.B) {
input := []byte(`"0x123456789abcdef123456789abcdef"`)
for i := 0; i < b.N; i++ {
Expand Down
16 changes: 12 additions & 4 deletions eth/tracers/logger/gen_structlog.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions eth/tracers/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type structLogMarshaling struct {
GasCost math.HexOrDecimal64
Memory hexutil.Bytes
ReturnData hexutil.Bytes
Stack []hexutil.U256
OpName string `json:"opName"` // adds call to OpName() in MarshalJSON
ErrorString string `json:"error,omitempty"` // adds call to ErrorString() in MarshalJSON
}
Expand Down

0 comments on commit b532903

Please sign in to comment.