ferranbt / fastssz

Fast Ethereum2.0 SSZ encoder/decoder
MIT License
74 stars 44 forks source link

Redefined integers within slices fail to correctly generate ssz methods #92

Closed lightclient closed 2 years ago

lightclient commented 2 years ago

It seems like sszgen is not respecting the slice type when it is an alias of an integer. I think this has to do with one of the previous fixes that took advantage of the implicit conversion between the two.

package main

import (
        "encoding/json"
        "fmt"
        "strconv"
)

type U64Str uint64

func (i U64Str) MarshalJSON() ([]byte, error) {
        return json.Marshal(strconv.FormatUint(uint64(i), 10))
}

func (i *U64Str) UnmarshalJSON(b []byte) error {
        var s string
        if err := json.Unmarshal(b, &s); err != nil {
                return err
        }
        value, err := strconv.ParseInt(s, 10, 64)
        if err != nil {
                return err
        }
        *i = U64Str(value)
        return nil
}

type Foo struct {
        Bar []U64Str `json:"bar" ssz-max:"1024"`
}

func main() {
        input := `{"bar": ["1", "2", "3"]}`

        var val Foo
        if err := json.Unmarshal([]byte(input), &val); err != nil {
                panic(err)
        }
        fmt.Println("success")
}
$ sszgen --path main.go
$ go run .
./main_encoding.go:62:11: cannot use ssz.ExtendUint64(f.Bar, num) (value of type []uint64) as type []U64Str in assignment
./main_encoding.go:62:28: cannot use f.Bar (variable of type []U64Str) as type []uint64 in argument to ssz.ExtendUint64
./main_encoding.go:97:20: cannot use i (variable of type U64Str) as type uint64 in argument to hh.AppendUint64
lightclient commented 2 years ago

This was originally found in https://github.com/flashbots/go-boost-utils/pull/17

ferranbt commented 2 years ago

I never expected that aliases would be that popular. I will take a look.

ferranbt commented 2 years ago

This is a hard issue to solve. The unmarshaller uses this function to efficiently allocate the array, but the function expects []uint type. I do not think the types can be casted.

However, something like this works:

type ArrayUint []uint64

type Case4 struct {
    Val ArrayUint  `ssz-size:"32"`
}