diff --git a/cmd/sszgen/gen.go b/cmd/sszgen/gen.go index a60dd10..160432c 100644 --- a/cmd/sszgen/gen.go +++ b/cmd/sszgen/gen.go @@ -8,6 +8,7 @@ import ( "bytes" "fmt" "go/types" + "html/template" "math" "sort" ) @@ -94,6 +95,22 @@ func (ctx *genContext) reset() { ctx.topType = true } +func generate(ctx *genContext, typ *sszContainer) ([]byte, error) { + var codes [][]byte + for _, fn := range []func(ctx *genContext, typ *sszContainer) ([]byte, error){ + generateSizeSSZ, + generateDefineSSZ, + } { + code, err := fn(ctx, typ) + if err != nil { + return nil, err + } + codes = append(codes, code) + } + fmt.Println(string(bytes.Join(codes, []byte("\n")))) + return bytes.Join(codes, []byte("\n")), nil +} + func generateSizeSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { var b bytes.Buffer ctx.reset() @@ -104,7 +121,7 @@ func generateSizeSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { // time or if runtime resolutions are needed var runtime bool for i := range typ.opsets { - if typ.opsets[i].(*opsetStatic).bytes == 0 { + if typ.opsets[i].(*opsetStatic).bytes == nil { runtime = true break } @@ -115,8 +132,12 @@ func generateSizeSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { fmt.Fprintf(&b, "// Cached static size computed on package init.\n") fmt.Fprintf(&b, "var staticSizeCache%s = ", typ.named.Obj().Name()) for i := range typ.opsets { - if bytes := typ.opsets[i].(*opsetStatic).bytes; bytes > 0 { - fmt.Fprintf(&b, "%d", bytes) + if bytes := typ.opsets[i].(*opsetStatic).bytes; bytes != nil { + if len(bytes) == 1 { + fmt.Fprintf(&b, "%d", bytes[0]) + } else { + fmt.Fprintf(&b, "%d*%d", bytes[0], bytes[1]) + } } else { typ := typ.types[i].(*types.Pointer).Elem().(*types.Named) pkg := typ.Obj().Pkg() @@ -140,12 +161,17 @@ func generateSizeSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { fmt.Fprintf(&b, "func (obj *%s) SizeSSZ() uint32 {\n", typ.named.Obj().Name()) fmt.Fprint(&b, " return ") for i := range typ.opsets { - fmt.Fprintf(&b, "%d", typ.opsets[i].(*opsetStatic).bytes) + bytes := typ.opsets[i].(*opsetStatic).bytes + if len(bytes) == 1 { + fmt.Fprintf(&b, "%d", bytes[0]) + } else { + fmt.Fprintf(&b, "%d*%d", bytes[0], bytes[1]) + } if i < len(typ.opsets)-1 { fmt.Fprint(&b, " + ") } } - fmt.Fprintf(&b, "}\n") + fmt.Fprintf(&b, "\n}\n") } } else { // Iterate through the fields to see if the static size can be computed @@ -153,7 +179,7 @@ func generateSizeSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { var runtime bool for i := range typ.opsets { if typ, ok := typ.opsets[i].(*opsetStatic); ok { - if typ.bytes == 0 { + if typ.bytes == nil { runtime = true break } @@ -167,8 +193,12 @@ func generateSizeSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { for i := range typ.opsets { switch t := typ.opsets[i].(type) { case *opsetStatic: - if t.bytes > 0 { - fmt.Fprintf(&b, "%d", t.bytes) + if t.bytes != nil { + if len(t.bytes) == 1 { + fmt.Fprintf(&b, "%d", t.bytes[0]) + } else { + fmt.Fprintf(&b, "%d*%d", t.bytes[0], t.bytes[1]) + } } else { typ := typ.types[i].(*types.Pointer).Elem().(*types.Named) pkg := typ.Obj().Pkg() @@ -190,7 +220,37 @@ func generateSizeSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { fmt.Fprintf(&b, "func (obj *%s) SizeSSZ(fixed bool) uint32 {\n", typ.named.Obj().Name()) fmt.Fprintf(&b, " var size = uint32(staticSizeCache%s)\n", typ.named.Obj().Name()) fmt.Fprintf(&b, " if (fixed) {\n") - fmt.Fprintf(&b, " return staticSizeCache%s\n", typ.named.Obj().Name()) + fmt.Fprintf(&b, " return size\n") + fmt.Fprintf(&b, " }\n") + for i := range typ.opsets { + if _, ok := typ.opsets[i].(*opsetDynamic); ok { + fmt.Fprintf(&b, " size += obj.%s.SizeSSZ(false)\n", typ.fields[i]) + } + } + fmt.Fprintf(&b, " return size\n") + fmt.Fprintf(&b, "}\n") + } else { + fmt.Fprintf(&b, "\n\n// SizeSSZ returns either the static size of the object if fixed == true, or\n// the total size otherwise.\n") + fmt.Fprintf(&b, "func (obj *%s) SizeSSZ(fixed bool) uint32 {\n", typ.named.Obj().Name()) + fmt.Fprintf(&b, " var size = uint32(") + for i := range typ.opsets { + switch t := typ.opsets[i].(type) { + case *opsetStatic: + if len(t.bytes) == 1 { + fmt.Fprintf(&b, "%d", t.bytes[0]) + } else { + fmt.Fprintf(&b, "%d*%d", t.bytes[0], t.bytes[1]) + } + case *opsetDynamic: + fmt.Fprintf(&b, "%d", offsetBytes) + } + if i < len(typ.opsets)-1 { + fmt.Fprint(&b, " + ") + } + } + fmt.Fprintf(&b, ")\n") + fmt.Fprintf(&b, " if (fixed) {\n") + fmt.Fprintf(&b, " return size\n") fmt.Fprintf(&b, " }\n") for i := range typ.opsets { if _, ok := typ.opsets[i].(*opsetDynamic); ok { @@ -214,13 +274,18 @@ func generateDefineSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { // Iterate through the fields names to compute some comment formatting mods var ( maxFieldLength = 0 - maxBytes = 0 + maxBytes = 1 ) for i, field := range typ.fields { maxFieldLength = max(maxFieldLength, len(field)) switch opset := typ.opsets[i].(type) { case *opsetStatic: - maxBytes = max(maxBytes, opset.bytes) + switch len(opset.bytes) { + case 1: + maxBytes = max(maxBytes, opset.bytes[0]) + case 2: + maxBytes = max(maxBytes, opset.bytes[0]*opset.bytes[1]) + } case *opsetDynamic: maxBytes = max(maxBytes, offsetBytes) // offset size } @@ -240,14 +305,19 @@ func generateDefineSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { field := typ.fields[i] switch opset := typ.opsets[i].(type) { case *opsetStatic: - if opset.bytes > 0 { - fmt.Fprintf(&b, "ssz.%s(codec, &obj.%s) // Field ("+indexRule+") - "+nameRule+" - %"+sizeRule+"d bytes\n", opset.define, field, i, field, opset.bytes) - } else { + call := generateCall(opset.define, "codec", "obj."+field, opset.bytes...) + switch len(opset.bytes) { + case 0: typ := typ.types[i].(*types.Pointer).Elem().(*types.Named) - fmt.Fprintf(&b, " ssz.%s(codec, &obj.%s) // Field ("+indexRule+") - "+nameRule+" - %"+sizeRule+"s bytes (%s)\n", opset.define, field, i, field, "?", typ.Obj().Name()) + fmt.Fprintf(&b, " ssz.%s // Field ("+indexRule+") - "+nameRule+" - %"+sizeRule+"s bytes (%s)\n", call, i, field, "?", typ.Obj().Name()) + case 1: + fmt.Fprintf(&b, " ssz.%s // Field ("+indexRule+") - "+nameRule+" - %"+sizeRule+"d bytes\n", call, i, field, opset.bytes[0]) + case 2: + fmt.Fprintf(&b, " ssz.%s // Field ("+indexRule+") - "+nameRule+" - %"+sizeRule+"d bytes\n", call, i, field, opset.bytes[0]*opset.bytes[1]) } case *opsetDynamic: - fmt.Fprintf(&b, " ssz.%s(codec, &obj.%s) // Offset ("+indexRule+") - "+nameRule+" - %"+sizeRule+"d bytes\n", opset.defineOffset, field, i, field, offsetBytes) + call := generateCall(opset.defineOffset, "codec", "obj."+field, opset.limits...) + fmt.Fprintf(&b, " ssz.%s // Offset ("+indexRule+") - "+nameRule+" - %"+sizeRule+"d bytes\n", call, i, field, offsetBytes) } } if !typ.static { @@ -255,7 +325,8 @@ func generateDefineSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { for i := 0; i < len(typ.fields); i++ { field := typ.fields[i] if opset, ok := (typ.opsets[i]).(*opsetDynamic); ok { - fmt.Fprintf(&b, " ssz.%s(codec, &obj.%s) // Field ("+indexRule+") - "+nameRule+" - ? bytes\n", opset.defineContent, field, i, field) + call := generateCall(opset.defineContent, "codec", "obj."+field, opset.limits...) + fmt.Fprintf(&b, " ssz.%s // Field ("+indexRule+") - "+nameRule+" - ? bytes\n", call, i, field) } } } @@ -263,18 +334,26 @@ func generateDefineSSZ(ctx *genContext, typ *sszContainer) ([]byte, error) { return b.Bytes(), nil } -func generate(ctx *genContext, typ *sszContainer) ([]byte, error) { - var codes [][]byte - for _, fn := range []func(ctx *genContext, typ *sszContainer) ([]byte, error){ - generateSizeSSZ, - generateDefineSSZ, - } { - code, err := fn(ctx, typ) - if err != nil { - return nil, err - } - codes = append(codes, code) +// generateCall parses a Go template and fills it with the provided data. This +// could be done more optimally, but we really don't care for a code generator. +func generateCall(tmpl string, recv string, field string, limits ...int) string { + t, err := template.New("").Parse(tmpl) + if err != nil { + panic(err) } - //fmt.Println(string(bytes.Join(codes, []byte("\n")))) - return bytes.Join(codes, []byte("\n")), nil + d := map[string]interface{}{ + "Codec": recv, + "Field": field, + } + if len(limits) > 0 { + d["MaxSize"] = limits[len(limits)-1] + } + if len(limits) > 1 { + d["MaxItems"] = limits[len(limits)-2] + } + buf := new(bytes.Buffer) + if err := t.Execute(buf, d); err != nil { + panic(err) + } + return string(buf.Bytes()) } diff --git a/cmd/sszgen/opset.go b/cmd/sszgen/opset.go index 57d894c..31d0cd9 100644 --- a/cmd/sszgen/opset.go +++ b/cmd/sszgen/opset.go @@ -11,14 +11,7 @@ import ( // opset is a group of methods that define how different pieces of an ssz codec // operates on a given type. It may be static or dynamic. -type opset interface { - defineStatic() string // get the op for the static section - defineDynamic() string // get the op for the dynamic section (optional) - encodeStatic() string // get the op for the static section - encodeDynamic() string // get the op for the dynamic section (optional) - decodeStatic() string // get the op for the static section - decodeDynamic() string // get the op for the dynamic section (optional) -} +type opset interface{} // opsetStatic is a group of methods that define how different pieces of an ssz // codec operates on a given static type. Ideally these would be some go/types @@ -27,16 +20,9 @@ type opsetStatic struct { define string // DefineXYZ method for the ssz.Codec encode string // EncodeXYZ method for the ssz.Encoder decode string // DecodeXYZ method for the ssz.Decoder - bytes int // Number of bytes in the ssz encoding (0 == unknown) + bytes []int // Number of bytes in the ssz encoding (0 == unknown) } -func (os *opsetStatic) defineStatic() string { return os.define } -func (os *opsetStatic) encodeStatic() string { return os.encode } -func (os *opsetStatic) decodeStatic() string { return os.decode } -func (os *opsetStatic) defineDynamic() string { return "" } -func (os *opsetStatic) encodeDynamic() string { return "" } -func (os *opsetStatic) decodeDynamic() string { return "" } - // opsetDynamic is a group of methods that define how different pieces of an ssz // codec operates on a given dynamic type. Ideally these would be some go/types // function values, but alas too much pain, especially with generics. @@ -47,78 +33,231 @@ type opsetDynamic struct { encodeContent string // EncodeXYZContent method for the ssz.Encoder decodeOffset string // DecodeXYZOffset method for the ssz.Decoder decodeContent string // DecodeXYZContent method for the ssz.Decoder + sizes []int // Static item sizes for different dimensions + limits []int // Maximum dynamic item sizes for different dimensions } -func (os *opsetDynamic) defineStatic() string { return os.defineOffset } -func (os *opsetDynamic) encodeStatic() string { return os.encodeOffset } -func (os *opsetDynamic) decodeStatic() string { return os.decodeOffset } -func (os *opsetDynamic) defineDynamic() string { return os.defineContent } -func (os *opsetDynamic) encodeDynamic() string { return os.encodeContent } -func (os *opsetDynamic) decodeDynamic() string { return os.decodeContent } - // resolveBasicOpset retrieves the opset required to handle a basic struct // field. Yes, we could maybe have some of these be "computed" instead of hard // coded, but it makes things brittle for corner-cases. -func (p *parseContext) resolveBasicOpset(typ *types.Basic) (*opsetStatic, error) { +func (p *parseContext) resolveBasicOpset(typ *types.Basic, tags *sizeTag) (opset, error) { + // Sanity check a few tag constraints relevant for all basic types + if tags != nil { + if tags.limit != nil { + return nil, fmt.Errorf("basic type cannot have ssz-max tag") + } + if len(tags.size) != 1 { + return nil, fmt.Errorf("basic type requires 1D ssz-size tag: have %v", tags.size) + } + } + // Return the type-specific opsets switch typ.Kind() { case types.Bool: - return &opsetStatic{"DefineBool", "EncodeBool", "DecodeBool", 1}, nil + if tags != nil && tags.size[0] != 1 { + return nil, fmt.Errorf("boolean basic type requires ssz-size=1: have %d", tags.size[0]) + } + return &opsetStatic{ + "DefineBool({{.Codec}}, &{{.Field}})", + "EncodeBool({{.Codec}}, &{{.Field}})", + "DecodeBool({{.Codec}}, &{{.Field}})", + []int{1}, + }, nil case types.Uint64: - return &opsetStatic{"DefineUint64", "EncodeUint64", "DecodeUint64", 8}, nil + if tags != nil && tags.size[0] != 8 { + return nil, fmt.Errorf("uint64 basic type requires ssz-size=8: have %d", tags.size[0]) + } + return &opsetStatic{ + "DefineUint64({{.Codec}}, &{{.Field}})", + "EncodeUint64({{.Codec}}, &{{.Field}})", + "DecodeUint64({{.Codec}}, &{{.Field}})", + []int{8}, + }, nil default: return nil, fmt.Errorf("unsupported basic type: %s", typ) } } -// resolveUint256Opset retrieves the opset required to handle a uint256 -// struct field implemented using github.com/holiman/uint256. Yay hard code! -func (p *parseContext) resolveUint256Opset() *opsetStatic { - return &opsetStatic{"DefineUint256", "EncodeUint256", "DecodeUint256", 32} -} - -func (p *parseContext) resolveArrayOpset(typ types.Type, size int) (*opsetStatic, error) { +func (p *parseContext) resolveArrayOpset(typ types.Type, size int, tags *sizeTag) (opset, error) { switch typ := typ.(type) { case *types.Basic: + // Sanity check a few tag constraints relevant for all arrays of basic types + if tags != nil { + if tags.limit != nil { + return nil, fmt.Errorf("array of basic type cannot have ssz-max tag") + } + } switch typ.Kind() { case types.Byte: - return &opsetStatic{"DefineStaticBytes", "EncodeStaticBytes", "DecodeStaticBytes", size}, nil + if tags != nil { + if (len(tags.size) != 1 && len(tags.size) != 2) || + (len(tags.size) == 1 && tags.size[0] != size) || + (len(tags.size) == 2 && (tags.size[0] != size || tags.size[1] != 1)) { + return nil, fmt.Errorf("array of byte basic type tag conflict: field is %d bytes, tag wants %v bytes", size, tags.size) + } + } + return &opsetStatic{ + "DefineStaticBytes({{.Codec}}, {{.Field}}[:])", + "EncodeStaticBytes({{.Codec}}, {{.Field}}[:])", + "DecodeStaticBytes({{.Codec}}, {{.Field}}[:])", + []int{size}, + }, nil default: return nil, fmt.Errorf("unsupported array item basic type: %s", typ) } + case *types.Array: + return p.resolveArrayOfArrayOpset(typ.Elem(), size, int(typ.Len()), tags) + + case *types.Named: + return p.resolveArrayOpset(typ.Underlying(), size, tags) + default: return nil, fmt.Errorf("unsupported array item type: %s", typ) } } -func (p *parseContext) resolveSliceOpset(typ types.Type) (*opsetDynamic, error) { +func (p *parseContext) resolveArrayOfArrayOpset(typ types.Type, outerSize, innerSize int, tags *sizeTag) (opset, error) { switch typ := typ.(type) { case *types.Basic: + // Sanity check a few tag constraints relevant for all arrays of basic types + if tags != nil { + if tags.limit != nil { + return nil, fmt.Errorf("array of array of basic type cannot have ssz-max tag") + } + } switch typ.Kind() { case types.Byte: + if tags != nil { + if (len(tags.size) != 2 && len(tags.size) != 3) || + (len(tags.size) == 2 && (tags.size[0] != outerSize || tags.size[1] != innerSize)) || + (len(tags.size) == 3 && (tags.size[0] != outerSize || tags.size[1] != innerSize || tags.size[2] != 1)) { + return nil, fmt.Errorf("array of array of byte basic type tag conflict: field is [%d, %d] bytes, tag wants %v bytes", outerSize, innerSize, tags.size) + } + } + return &opsetStatic{ + "DefineArrayOfStaticBytes({{.Codec}}, {{.Field}}[:])", + "EncodeArrayOfStaticBytes({{.Codec}}, {{.Field}}[:])", + "DecodeArrayOfStaticBytes({{.Codec}}, {{.Field}}[:])", + []int{outerSize, innerSize}, + }, nil + default: + return nil, fmt.Errorf("unsupported array-of-array item basic type: %s", typ) + } + default: + return nil, fmt.Errorf("unsupported array-of-array item type: %s", typ) + } +} + +func (p *parseContext) resolveSliceOpset(typ types.Type, tags *sizeTag) (opset, error) { + // Sanity check a few tag constraints relevant for all slice types + if tags == nil { + return nil, fmt.Errorf("slice type requires ssz tags") + } + switch typ := typ.(type) { + case *types.Basic: + switch typ.Kind() { + case types.Byte: + // Slice of bytes. If we have ssz-size, it's a static slice + if tags.size != nil { + if (len(tags.size) != 1 && len(tags.size) != 2) || + (len(tags.size) == 2 && tags.size[1] != 1) { + return nil, fmt.Errorf("static slice of byte basic type tag conflict: needs [N] or [N, 1] tag, has %v", tags.size) + } + return &opsetStatic{ + "DefineCheckedStaticBytes({{.Codec}}, &{{.Field}}, {{.MaxSize}})", + "EncodeCheckedStaticBytes({{.Codec}}, &{{.Field}})", + "DecodeCheckedStaticBytes({{.Codec}}, &{{.Field}}, {{.MaxSize}})", + []int{tags.size[0]}, + }, nil + } + // Not a static slice of bytes, we need to pull ssz-max for the limits + if tags.limit == nil { + return nil, fmt.Errorf("slice of byte basic type requires ssz-max tag") + } + if len(tags.limit) != 1 { + return nil, fmt.Errorf("dynamic slice of byte basic type tag conflict: needs [N] tag, has %v", tags.limit) + } return &opsetDynamic{ - "DefineDynamicBytesOffset", "DefineDynamicBytesContent", - "EncodeDynamicBytesOffset", "EncodeDynamicBytesContent", - "DecodeDynamicBytesOffset", "DecodeDynamicBytesContent"}, nil + "DefineDynamicBytesOffset({{.Codec}}, &{{.Field}})", + "DefineDynamicBytesContent({{.Codec}}, &{{.Field}}, {{.MaxSize}})", + "EncodeDynamicBytesOffset({{.Codec}}, &{{.Field}})", + "EncodeDynamicBytesContent({{.Codec}}, &{{.Field}}, {{.MaxSize}})", + "DecodeDynamicBytesOffset({{.Codec}}, &{{.Field}})", + "DecodeDynamicBytesContent({{.Codec}}, &{{.Field}}, {{.MaxSize}})", + []int{0}, tags.limit, + }, nil default: return nil, fmt.Errorf("unsupported slice item basic type: %s", typ) } + case *types.Slice: + return p.resolveSliceOfSliceOpset(typ.Elem()) default: return nil, fmt.Errorf("unsupported slice item type: %s", typ) } } -func (p *parseContext) resolvePointerOpset(typ *types.Pointer) (opset, error) { +func (p *parseContext) resolveSliceOfSliceOpset(typ types.Type) (*opsetDynamic, error) { + switch typ := typ.(type) { + case *types.Basic: + switch typ.Kind() { + case types.Byte: + return &opsetDynamic{ + "DefineSliceOfDynamicBytesOffset({{.Codec}}, &{{.Field}})", + "DefineSliceOfDynamicBytesContent({{.Codec}}, &{{.Field}}, {{.MaxItems}}, {{.MaxSize}})", + "EncodeSliceOfDynamicBytesOffset({{.Codec}}, &{{.Field}})", + "EncodeSliceOfDynamicBytesContent({{.Codec}}, &{{.Field}}, {{.MaxItems}}, {{.MaxSize}})", + "DecodeSliceOfDynamicBytesOffset({{.Codec}}, &{{.Field}})", + "DecodeSliceOfDynamicBytesContent({{.Codec}}, &{{.Field}}, {{.MaxItems}}, {{.MaxSize}})", + []int{0, 0}, nil, + }, nil + default: + return nil, fmt.Errorf("unsupported slice-of-slice item basic type: %s", typ) + } + default: + return nil, fmt.Errorf("unsupported slice-of-slice item type: %s", typ) + } +} + +func (p *parseContext) resolvePointerOpset(typ *types.Pointer, tags *sizeTag) (opset, error) { if isUint256(typ.Elem()) { - return &opsetStatic{"DefineUint256", "EncodeUint256", "DecodeUint256", 32}, nil + if tags != nil { + if tags.limit != nil { + return nil, fmt.Errorf("uint256 basic type cannot have ssz-max tag") + } + if len(tags.size) != 1 || tags.size[0] != 32 { + return nil, fmt.Errorf("uint256 basic type tag conflict: filed is [32] bytes, tag wants %v", tags.size) + } + } + return &opsetStatic{ + "DefineUint256({{.Codec}}, &{{.Field}})", + "EncodeUint256({{.Codec}}, &{{.Field}})", + "DecodeUint256({{.Codec}}, &{{.Field}})", + []int{32}, + }, nil } if types.Implements(typ, p.staticObjectIface) { - return &opsetStatic{"DefineStaticObject", "EncodeStaticObject", "DecodeStaticObject", 0}, nil + if tags != nil { + return nil, fmt.Errorf("static object type cannot have any ssz tags") + } + return &opsetStatic{ + "DefineStaticObject({{.Codec}}, &{{.Field}})", + "EncodeStaticObject({{.Codec}}, &{{.Field}})", + "DecodeStaticObject({{.Codec}}, &{{.Field}})", + nil, + }, nil } if types.Implements(typ, p.dynamicObjectIface) { + if tags != nil { + return nil, fmt.Errorf("dynamic object type cannot have any ssz tags") + } return &opsetDynamic{ - "DefineDynamicObjectOffset", "DefineDynamicObjectContent", - "EncodeDynamicObjectOffset", "EncodeDynamicObjectContent", - "DecodeDynamicObjectOffset", "DecodeDynamicObjectContent"}, nil + "DefineDynamicObjectOffset({{.Codec}}, &{{.Field}})", + "DefineDynamicObjectContent({{.Codec}}, &{{.Field}})", + "EncodeDynamicObjectOffset({{.Codec}}, &{{.Field}})", + "EncodeDynamicObjectContent({{.Codec}}, &{{.Field}})", + "DecodeDynamicObjectOffset({{.Codec}}, &{{.Field}})", + "DecodeDynamicObjectContent({{.Codec}}, &{{.Field}})", + nil, nil, + }, nil } return nil, fmt.Errorf("unsupported pointer type %s", typ.String()) } diff --git a/cmd/sszgen/tags.go b/cmd/sszgen/tags.go index c395afe..5cfc293 100644 --- a/cmd/sszgen/tags.go +++ b/cmd/sszgen/tags.go @@ -18,25 +18,22 @@ const ( // sizeTag describes the size restriction for types. type sizeTag struct { - size int64 // 0 means the size is undefined - limit int64 // 0 means the limit is undefined + size []int // 0 means the size for that dimension is undefined + limit []int // 0 means the limit for that dimension is undefined } -func parseTag(input string) (bool, []sizeTag, error) { +func parseTags(input string) (bool, *sizeTag, error) { if len(input) == 0 { return false, nil, nil } var ( ignore bool - tags []sizeTag - setTag = func(i int, v int64, ident string) { - if i >= len(tags) { - tags = append(tags, make([]sizeTag, i-len(tags)+1)...) - } + tags sizeTag + setTag = func(v int, ident string) { if ident == sszMaxTagIdent { - tags[i].limit = v + tags.limit = append(tags.limit, v) } else { - tags[i].size = v + tags.size = append(tags.size, v) } } ) @@ -53,18 +50,21 @@ func parseTag(input string) (bool, []sizeTag, error) { } case sszMaxTagIdent, sszSizeTagIdent: parts := strings.Split(remain, ",") - for i, p := range parts { + for _, p := range parts { if p == "?" { - setTag(i, 0, ident) + setTag(0, ident) continue } num, err := strconv.ParseInt(p, 10, 64) if err != nil { return false, nil, err } - setTag(i, num, ident) + setTag(int(num), ident) } } } - return ignore, tags, nil + if tags.size == nil && tags.limit == nil { + return ignore, nil, nil + } + return ignore, &tags, nil } diff --git a/cmd/sszgen/types.go b/cmd/sszgen/types.go index eb7a3ef..7d1ff94 100644 --- a/cmd/sszgen/types.go +++ b/cmd/sszgen/types.go @@ -34,7 +34,7 @@ func (p *parseContext) makeContainer(named *types.Named, typ *types.Struct) (*ss if !f.Exported() { continue } - ignore, tags, err := parseTag(typ.Tag(i)) + ignore, tags, err := parseTags(typ.Tag(i)) if err != nil { return nil, err } @@ -67,22 +67,22 @@ func (p *parseContext) makeContainer(named *types.Named, typ *types.Struct) (*ss // whether there's a collision between them, or if more tags are needed to fully // derive the size. If the type/tags are in sync and well-defined, an opset will // be returned that the generator can use to create the code. -func (p *parseContext) resolveOpset(typ types.Type, tags []sizeTag) (opset, error) { +func (p *parseContext) resolveOpset(typ types.Type, tags *sizeTag) (opset, error) { switch t := typ.(type) { case *types.Named: return p.resolveOpset(t.Underlying(), tags) case *types.Basic: - return p.resolveBasicOpset(t) + return p.resolveBasicOpset(t, tags) case *types.Array: - return p.resolveArrayOpset(t.Elem(), int(t.Len())) + return p.resolveArrayOpset(t.Elem(), int(t.Len()), tags) case *types.Slice: - return p.resolveSliceOpset(t.Elem()) + return p.resolveSliceOpset(t.Elem(), tags) case *types.Pointer: - return p.resolvePointerOpset(t) + return p.resolvePointerOpset(t, tags) } return nil, fmt.Errorf("unsupported type %s", typ.String()) } diff --git a/tests/testtypes/consensus-spec-tests/attestation.go b/tests/testtypes/consensus-spec-tests/attestation.go index d148ff7..1250d92 100644 --- a/tests/testtypes/consensus-spec-tests/attestation.go +++ b/tests/testtypes/consensus-spec-tests/attestation.go @@ -6,12 +6,6 @@ package consensus_spec_tests import "github.com/karalabe/ssz" -type Attestation struct { - AggregationBits []byte - Data *AttestationData - Signature [96]byte -} - func (a *Attestation) SizeSSZ(fixed bool) uint32 { size := uint32(228) if !fixed { diff --git a/tests/testtypes/consensus-spec-tests/attestation_data.go b/tests/testtypes/consensus-spec-tests/attestation_data.go deleted file mode 100644 index b0b22e5..0000000 --- a/tests/testtypes/consensus-spec-tests/attestation_data.go +++ /dev/null @@ -1,24 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type AttestationData struct { - Slot Slot - Index uint64 - BeaconBlockHash Hash - Source *Checkpoint - Target *Checkpoint -} - -func (a *AttestationData) SizeSSZ() uint32 { return 128 } -func (a *AttestationData) DefineSSZ(codec *ssz.Codec) { - ssz.DefineUint64(codec, &a.Slot) // Field (0) - Slot - 8 bytes - ssz.DefineUint64(codec, &a.Index) // Field (1) - Index - 8 bytes - ssz.DefineStaticBytes(codec, a.BeaconBlockHash[:]) // Field (2) - BeaconBlockHash - 32 bytes - ssz.DefineStaticObject(codec, &a.Source) // Field (3) - Source - 40 bytes - ssz.DefineStaticObject(codec, &a.Target) // Field (4) - Source - 40 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/beacon_block_header.go b/tests/testtypes/consensus-spec-tests/beacon_block_header.go deleted file mode 100644 index ff84c9a..0000000 --- a/tests/testtypes/consensus-spec-tests/beacon_block_header.go +++ /dev/null @@ -1,24 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type BeaconBlockHeader struct { - Slot uint64 - ProposerIndex uint64 - ParentRoot Hash - StateRoot Hash - BodyRoot Hash -} - -func (b *BeaconBlockHeader) SizeSSZ() uint32 { return 112 } -func (b *BeaconBlockHeader) DefineSSZ(codec *ssz.Codec) { - ssz.DefineUint64(codec, &b.Slot) // Field (0) - Slot - 8 bytes - ssz.DefineUint64(codec, &b.ProposerIndex) // Field (1) - ProposerIndex - 8 bytes - ssz.DefineStaticBytes(codec, b.ParentRoot[:]) // Field (2) - ParentRoot - 32 bytes - ssz.DefineStaticBytes(codec, b.StateRoot[:]) // Field (3) - StateRoot - 32 bytes - ssz.DefineStaticBytes(codec, b.BodyRoot[:]) // Field (4) - BodyRoot - 32 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/checkpoint.go b/tests/testtypes/consensus-spec-tests/checkpoint.go deleted file mode 100644 index 43ef467..0000000 --- a/tests/testtypes/consensus-spec-tests/checkpoint.go +++ /dev/null @@ -1,18 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type Checkpoint struct { - Epoch uint64 - Root Hash -} - -func (c *Checkpoint) SizeSSZ() uint32 { return 40 } -func (c *Checkpoint) DefineSSZ(codec *ssz.Codec) { - ssz.DefineUint64(codec, &c.Epoch) // Field (0) - Epoch - 8 bytes - ssz.DefineStaticBytes(codec, c.Root[:]) // Field (1) - Root - 32 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/deposit.go b/tests/testtypes/consensus-spec-tests/deposit.go deleted file mode 100644 index a4bac8c..0000000 --- a/tests/testtypes/consensus-spec-tests/deposit.go +++ /dev/null @@ -1,18 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type Deposit struct { - Proof [33][32]byte - Data *DepositData -} - -func (d *Deposit) SizeSSZ() uint32 { return 33*32 + 184 } -func (d *Deposit) DefineSSZ(codec *ssz.Codec) { - ssz.DefineArrayOfStaticBytes(codec, d.Proof[:]) // Field (0) - Proof - 1056 bytes - ssz.DefineStaticObject(codec, &d.Data) // Field (1) - Data - 184 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/deposit_data.go b/tests/testtypes/consensus-spec-tests/deposit_data.go deleted file mode 100644 index 4fa1672..0000000 --- a/tests/testtypes/consensus-spec-tests/deposit_data.go +++ /dev/null @@ -1,23 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type DepositData struct { - Pubkey [48]byte - WithdrawalCredentials [32]byte - Amount uint64 - Signature [96]byte - Root [32]byte -} - -func (d *DepositData) SizeSSZ() uint32 { return 184 } -func (d *DepositData) DefineSSZ(codec *ssz.Codec) { - ssz.DefineStaticBytes(codec, d.Pubkey[:]) // Field (0) - Pubkey - 48 bytes - ssz.DefineStaticBytes(codec, d.WithdrawalCredentials[:]) // Field (1) - WithdrawalCredentials - 32 bytes - ssz.DefineUint64(codec, &d.Amount) // Field (2) - Amount - 32 bytes - ssz.DefineStaticBytes(codec, d.Signature[:]) // Field (3) - Signature - 32 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/eth1_data.go b/tests/testtypes/consensus-spec-tests/eth1_data.go deleted file mode 100644 index 2575c76..0000000 --- a/tests/testtypes/consensus-spec-tests/eth1_data.go +++ /dev/null @@ -1,20 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type Eth1Data struct { - DepositRoot Hash - DepositCount uint64 - BlockHash Hash -} - -func (d *Eth1Data) SizeSSZ() uint32 { return 72 } -func (d *Eth1Data) DefineSSZ(codec *ssz.Codec) { - ssz.DefineStaticBytes(codec, d.DepositRoot[:]) // Field (0) - DepositRoot - 32 bytes - ssz.DefineUint64(codec, &d.DepositCount) // Field (1) - DepositCount - 8 bytes - ssz.DefineStaticBytes(codec, d.BlockHash[:]) // Field (0) - BlockHash - 32 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/execution_payload.go b/tests/testtypes/consensus-spec-tests/execution_payload.go index 85e71c8..0b44bc9 100644 --- a/tests/testtypes/consensus-spec-tests/execution_payload.go +++ b/tests/testtypes/consensus-spec-tests/execution_payload.go @@ -5,27 +5,9 @@ package consensus_spec_tests import ( - "github.com/holiman/uint256" "github.com/karalabe/ssz" ) -type ExecutionPayload struct { - ParentHash Hash - FeeRecipient Address - StateRoot Hash - ReceiptsRoot Hash - LogsBloom LogsBloom - PrevRandao Hash - BlockNumber uint64 - GasLimit uint64 - GasUsed uint64 - Timestamp uint64 - ExtraData []byte - BaseFeePerGas *uint256.Int - BlockHash Hash - Transactions [][]byte -} - func (e *ExecutionPayload) SizeSSZ(fixed bool) uint32 { size := uint32(508) if !fixed { diff --git a/tests/testtypes/consensus-spec-tests/gen_attestation_data_ssz.go b/tests/testtypes/consensus-spec-tests/gen_attestation_data_ssz.go new file mode 100644 index 0000000..1e5dd2d --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_attestation_data_ssz.go @@ -0,0 +1,22 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// Cached static size computed on package init. +var staticSizeCacheAttestationData = 8 + 8 + 32 + new(Checkpoint).SizeSSZ() + new(Checkpoint).SizeSSZ() + +// SizeSSZ returns the total size of the static ssz object. +func (obj *AttestationData) SizeSSZ() uint32 { + return staticSizeCacheAttestationData +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *AttestationData) DefineSSZ(codec *ssz.Codec) { + ssz.DefineUint64(codec, &obj.Slot) // Field (0) - Slot - 8 bytes + ssz.DefineUint64(codec, &obj.Index) // Field (1) - Index - 8 bytes + ssz.DefineStaticBytes(codec, obj.BeaconBlockHash[:]) // Field (2) - BeaconBlockHash - 32 bytes + ssz.DefineStaticObject(codec, &obj.Source) // Field (3) - Source - ? bytes (Checkpoint) + ssz.DefineStaticObject(codec, &obj.Target) // Field (4) - Target - ? bytes (Checkpoint) +} diff --git a/tests/testtypes/consensus-spec-tests/gen_beacon_block_header_ssz.go b/tests/testtypes/consensus-spec-tests/gen_beacon_block_header_ssz.go new file mode 100644 index 0000000..9b7c2e1 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_beacon_block_header_ssz.go @@ -0,0 +1,19 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *BeaconBlockHeader) SizeSSZ() uint32 { + return 8 + 8 + 32 + 32 + 32 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *BeaconBlockHeader) DefineSSZ(codec *ssz.Codec) { + ssz.DefineUint64(codec, &obj.Slot) // Field (0) - Slot - 8 bytes + ssz.DefineUint64(codec, &obj.ProposerIndex) // Field (1) - ProposerIndex - 8 bytes + ssz.DefineStaticBytes(codec, obj.ParentRoot[:]) // Field (2) - ParentRoot - 32 bytes + ssz.DefineStaticBytes(codec, obj.StateRoot[:]) // Field (3) - StateRoot - 32 bytes + ssz.DefineStaticBytes(codec, obj.BodyRoot[:]) // Field (4) - BodyRoot - 32 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_checkpoint_ssz.go b/tests/testtypes/consensus-spec-tests/gen_checkpoint_ssz.go new file mode 100644 index 0000000..bb81a73 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_checkpoint_ssz.go @@ -0,0 +1,16 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *Checkpoint) SizeSSZ() uint32 { + return 8 + 32 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *Checkpoint) DefineSSZ(codec *ssz.Codec) { + ssz.DefineUint64(codec, &obj.Epoch) // Field (0) - Epoch - 8 bytes + ssz.DefineStaticBytes(codec, obj.Root[:]) // Field (1) - Root - 32 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_deposit_data_ssz.go b/tests/testtypes/consensus-spec-tests/gen_deposit_data_ssz.go new file mode 100644 index 0000000..87a31cf --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_deposit_data_ssz.go @@ -0,0 +1,18 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *DepositData) SizeSSZ() uint32 { + return 48 + 32 + 8 + 96 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *DepositData) DefineSSZ(codec *ssz.Codec) { + ssz.DefineStaticBytes(codec, obj.Pubkey[:]) // Field (0) - Pubkey - 48 bytes + ssz.DefineStaticBytes(codec, obj.WithdrawalCredentials[:]) // Field (1) - WithdrawalCredentials - 32 bytes + ssz.DefineUint64(codec, &obj.Amount) // Field (2) - Amount - 8 bytes + ssz.DefineStaticBytes(codec, obj.Signature[:]) // Field (3) - Signature - 96 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_deposit_ssz.go b/tests/testtypes/consensus-spec-tests/gen_deposit_ssz.go new file mode 100644 index 0000000..0aab01b --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_deposit_ssz.go @@ -0,0 +1,19 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// Cached static size computed on package init. +var staticSizeCacheDeposit = 33*32 + new(DepositData).SizeSSZ() + +// SizeSSZ returns the total size of the static ssz object. +func (obj *Deposit) SizeSSZ() uint32 { + return staticSizeCacheDeposit +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *Deposit) DefineSSZ(codec *ssz.Codec) { + ssz.DefineArrayOfStaticBytes(codec, obj.Proof[:]) // Field (0) - Proof - 1056 bytes + ssz.DefineStaticObject(codec, &obj.Data) // Field (1) - Data - ? bytes (DepositData) +} diff --git a/tests/testtypes/consensus-spec-tests/gen_eth1_data_ssz.go b/tests/testtypes/consensus-spec-tests/gen_eth1_data_ssz.go new file mode 100644 index 0000000..832cfd6 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_eth1_data_ssz.go @@ -0,0 +1,17 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *Eth1Data) SizeSSZ() uint32 { + return 32 + 8 + 32 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *Eth1Data) DefineSSZ(codec *ssz.Codec) { + ssz.DefineStaticBytes(codec, obj.DepositRoot[:]) // Field (0) - DepositRoot - 32 bytes + ssz.DefineUint64(codec, &obj.DepositCount) // Field (1) - DepositCount - 8 bytes + ssz.DefineStaticBytes(codec, obj.BlockHash[:]) // Field (2) - BlockHash - 32 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_historical_batch_ssz.go b/tests/testtypes/consensus-spec-tests/gen_historical_batch_ssz.go new file mode 100644 index 0000000..7711308 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_historical_batch_ssz.go @@ -0,0 +1,16 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *HistoricalBatch) SizeSSZ() uint32 { + return 8192*32 + 8192*32 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *HistoricalBatch) DefineSSZ(codec *ssz.Codec) { + ssz.DefineArrayOfStaticBytes(codec, obj.BlockRoots[:]) // Field (0) - BlockRoots - 262144 bytes + ssz.DefineArrayOfStaticBytes(codec, obj.StateRoots[:]) // Field (1) - StateRoots - 262144 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_proposed_slashing_ssz.go b/tests/testtypes/consensus-spec-tests/gen_proposed_slashing_ssz.go new file mode 100644 index 0000000..ff868a8 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_proposed_slashing_ssz.go @@ -0,0 +1,19 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// Cached static size computed on package init. +var staticSizeCacheProposerSlashing = new(SignedBeaconBlockHeader).SizeSSZ() + new(SignedBeaconBlockHeader).SizeSSZ() + +// SizeSSZ returns the total size of the static ssz object. +func (obj *ProposerSlashing) SizeSSZ() uint32 { + return staticSizeCacheProposerSlashing +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *ProposerSlashing) DefineSSZ(codec *ssz.Codec) { + ssz.DefineStaticObject(codec, &obj.Header1) // Field (0) - Header1 - ? bytes (SignedBeaconBlockHeader) + ssz.DefineStaticObject(codec, &obj.Header2) // Field (1) - Header2 - ? bytes (SignedBeaconBlockHeader) +} diff --git a/tests/testtypes/consensus-spec-tests/gen_signed_beacon_block_header_ssz.go b/tests/testtypes/consensus-spec-tests/gen_signed_beacon_block_header_ssz.go new file mode 100644 index 0000000..d41bf2b --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_signed_beacon_block_header_ssz.go @@ -0,0 +1,19 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// Cached static size computed on package init. +var staticSizeCacheSignedBeaconBlockHeader = new(BeaconBlockHeader).SizeSSZ() + 96 + +// SizeSSZ returns the total size of the static ssz object. +func (obj *SignedBeaconBlockHeader) SizeSSZ() uint32 { + return staticSizeCacheSignedBeaconBlockHeader +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *SignedBeaconBlockHeader) DefineSSZ(codec *ssz.Codec) { + ssz.DefineStaticObject(codec, &obj.Header) // Field (0) - Header - ? bytes (BeaconBlockHeader) + ssz.DefineStaticBytes(codec, obj.Signature[:]) // Field (1) - Signature - 96 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_signed_voluntary_exit_ssz.go b/tests/testtypes/consensus-spec-tests/gen_signed_voluntary_exit_ssz.go new file mode 100644 index 0000000..cb22f5f --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_signed_voluntary_exit_ssz.go @@ -0,0 +1,19 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// Cached static size computed on package init. +var staticSizeCacheSignedVoluntaryExit = new(VoluntaryExit).SizeSSZ() + 96 + +// SizeSSZ returns the total size of the static ssz object. +func (obj *SignedVoluntaryExit) SizeSSZ() uint32 { + return staticSizeCacheSignedVoluntaryExit +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *SignedVoluntaryExit) DefineSSZ(codec *ssz.Codec) { + ssz.DefineStaticObject(codec, &obj.Exit) // Field (0) - Exit - ? bytes (VoluntaryExit) + ssz.DefineStaticBytes(codec, obj.Signature[:]) // Field (1) - Signature - 96 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_validator_ssz.go b/tests/testtypes/consensus-spec-tests/gen_validator_ssz.go new file mode 100644 index 0000000..9c94634 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_validator_ssz.go @@ -0,0 +1,22 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *Validator) SizeSSZ() uint32 { + return 48 + 32 + 8 + 1 + 8 + 8 + 8 + 8 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *Validator) DefineSSZ(codec *ssz.Codec) { + ssz.DefineStaticBytes(codec, obj.Pubkey[:]) // Field (0) - Pubkey - 48 bytes + ssz.DefineStaticBytes(codec, obj.WithdrawalCredentials[:]) // Field (1) - WithdrawalCredentials - 32 bytes + ssz.DefineUint64(codec, &obj.EffectiveBalance) // Field (2) - EffectiveBalance - 8 bytes + ssz.DefineBool(codec, &obj.Slashed) // Field (3) - Slashed - 1 bytes + ssz.DefineUint64(codec, &obj.ActivationEligibilityEpoch) // Field (4) - ActivationEligibilityEpoch - 8 bytes + ssz.DefineUint64(codec, &obj.ActivationEpoch) // Field (5) - ActivationEpoch - 8 bytes + ssz.DefineUint64(codec, &obj.ExitEpoch) // Field (6) - ExitEpoch - 8 bytes + ssz.DefineUint64(codec, &obj.WithdrawableEpoch) // Field (7) - WithdrawableEpoch - 8 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_voluntary_exit_ssz.go b/tests/testtypes/consensus-spec-tests/gen_voluntary_exit_ssz.go new file mode 100644 index 0000000..14853a0 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_voluntary_exit_ssz.go @@ -0,0 +1,16 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *VoluntaryExit) SizeSSZ() uint32 { + return 8 + 8 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *VoluntaryExit) DefineSSZ(codec *ssz.Codec) { + ssz.DefineUint64(codec, &obj.Epoch) // Field (0) - Epoch - 8 bytes + ssz.DefineUint64(codec, &obj.ValidatorIndex) // Field (1) - ValidatorIndex - 8 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_withdrawal_ssz.go b/tests/testtypes/consensus-spec-tests/gen_withdrawal_ssz.go new file mode 100644 index 0000000..fa32e46 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_withdrawal_ssz.go @@ -0,0 +1,18 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *Withdrawal) SizeSSZ() uint32 { + return 8 + 8 + 20 + 8 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *Withdrawal) DefineSSZ(codec *ssz.Codec) { + ssz.DefineUint64(codec, &obj.Index) // Field (0) - Index - 8 bytes + ssz.DefineUint64(codec, &obj.Validator) // Field (1) - Validator - 8 bytes + ssz.DefineStaticBytes(codec, obj.Address[:]) // Field (2) - Address - 20 bytes + ssz.DefineUint64(codec, &obj.Amount) // Field (3) - Amount - 8 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_withdrawal_variation_ssz.go b/tests/testtypes/consensus-spec-tests/gen_withdrawal_variation_ssz.go new file mode 100644 index 0000000..5e1fa65 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_withdrawal_variation_ssz.go @@ -0,0 +1,18 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *WithdrawalVariation) SizeSSZ() uint32 { + return 8 + 8 + 20 + 8 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *WithdrawalVariation) DefineSSZ(codec *ssz.Codec) { + ssz.DefineUint64(codec, &obj.Index) // Field (0) - Index - 8 bytes + ssz.DefineUint64(codec, &obj.Validator) // Field (1) - Validator - 8 bytes + ssz.DefineCheckedStaticBytes(codec, &obj.Address, 20) // Field (2) - Address - 20 bytes + ssz.DefineUint64(codec, &obj.Amount) // Field (3) - Amount - 8 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/historical_batch.go b/tests/testtypes/consensus-spec-tests/historical_batch.go deleted file mode 100644 index e58e743..0000000 --- a/tests/testtypes/consensus-spec-tests/historical_batch.go +++ /dev/null @@ -1,20 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import ( - "github.com/karalabe/ssz" -) - -type HistoricalBatch struct { - BlockRoots [8192]Hash - StateRoots [8192]Hash -} - -func (h *HistoricalBatch) SizeSSZ() uint32 { return 2 * 8192 * 32 } -func (h *HistoricalBatch) DefineSSZ(codec *ssz.Codec) { - ssz.DefineArrayOfStaticBytes(codec, h.BlockRoots[:]) - ssz.DefineArrayOfStaticBytes(codec, h.StateRoots[:]) -} diff --git a/tests/testtypes/consensus-spec-tests/proposer_slashing.go b/tests/testtypes/consensus-spec-tests/proposer_slashing.go deleted file mode 100644 index af3d588..0000000 --- a/tests/testtypes/consensus-spec-tests/proposer_slashing.go +++ /dev/null @@ -1,18 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type ProposerSlashing struct { - Header1 *SignedBeaconBlockHeader - Header2 *SignedBeaconBlockHeader -} - -func (s *ProposerSlashing) SizeSSZ() uint32 { return 416 } -func (s *ProposerSlashing) DefineSSZ(codec *ssz.Codec) { - ssz.DefineStaticObject(codec, &s.Header1) // Field (0) - Header1 - 208 bytes - ssz.DefineStaticObject(codec, &s.Header2) // Field (1) - Header2 - 208 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/signed_beacon_block_header.go b/tests/testtypes/consensus-spec-tests/signed_beacon_block_header.go deleted file mode 100644 index 78fc661..0000000 --- a/tests/testtypes/consensus-spec-tests/signed_beacon_block_header.go +++ /dev/null @@ -1,18 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type SignedBeaconBlockHeader struct { - Header *BeaconBlockHeader - Signature [96]byte -} - -func (s *SignedBeaconBlockHeader) SizeSSZ() uint32 { return 208 } -func (s *SignedBeaconBlockHeader) DefineSSZ(codec *ssz.Codec) { - ssz.DefineStaticObject(codec, &s.Header) // Field (0) - Header - 112 bytes - ssz.DefineStaticBytes(codec, s.Signature[:]) // Field (1) - Signature - 96 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/signed_voluntary_exit.go b/tests/testtypes/consensus-spec-tests/signed_voluntary_exit.go deleted file mode 100644 index 89d74ff..0000000 --- a/tests/testtypes/consensus-spec-tests/signed_voluntary_exit.go +++ /dev/null @@ -1,18 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type SignedVoluntaryExit struct { - Exit *VoluntaryExit `json:"message"` - Signature [96]byte `json:"signature" ssz-size:"96"` -} - -func (v *SignedVoluntaryExit) SizeSSZ() uint32 { return 112 } -func (v *SignedVoluntaryExit) DefineSSZ(codec *ssz.Codec) { - ssz.DefineStaticObject(codec, &v.Exit) // Field (0) - Exit - 16 bytes - ssz.DefineStaticBytes(codec, v.Signature[:]) // Field (1) - Signature - 96 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/types.go b/tests/testtypes/consensus-spec-tests/types.go deleted file mode 100644 index 52e40ad..0000000 --- a/tests/testtypes/consensus-spec-tests/types.go +++ /dev/null @@ -1,14 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -//go:generate go run ../../../cmd/sszgen -type Withdrawal -out gen_withdrawal_ssz.go - -type Withdrawal struct { - Index uint64 `ssz-size:"8"` - Validator uint64 `ssz-size:"8"` - Address Address `ssz-size:"20"` - Amount uint64 `ssz-size:"8"` -} diff --git a/tests/testtypes/consensus-spec-tests/types_consensus.go b/tests/testtypes/consensus-spec-tests/types_consensus.go new file mode 100644 index 0000000..c7c502c --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/types_consensus.go @@ -0,0 +1,128 @@ +// ssz: Go Simple Serialize (SSZ) codec library +// Copyright 2024 ssz Authors +// SPDX-License-Identifier: BSD-3-Clause + +package consensus_spec_tests + +import "github.com/holiman/uint256" + +//go:generate go run ../../../cmd/sszgen -type Checkpoint -out gen_checkpoint_ssz.go +//go:generate go run ../../../cmd/sszgen -type AttestationData -out gen_attestation_data_ssz.go +//go:generate go run ../../../cmd/sszgen -type BeaconBlockHeader -out gen_beacon_block_header_ssz.go +// go:generate go run ../../../cmd/sszgen -type Attestation -out gen_attestation_ssz.go +//go:generate go run ../../../cmd/sszgen -type DepositData -out gen_deposit_data_ssz.go +//go:generate go run ../../../cmd/sszgen -type Deposit -out gen_deposit_ssz.go +//go:generate go run ../../../cmd/sszgen -type Eth1Data -out gen_eth1_data_ssz.go +// go:generate go run ../../../cmd/sszgen -type ExecutionPayload -out gen_execution_payload_ssz.go +//go:generate go run ../../../cmd/sszgen -type HistoricalBatch -out gen_historical_batch_ssz.go +//go:generate go run ../../../cmd/sszgen -type ProposerSlashing -out gen_proposed_slashing_ssz.go +//go:generate go run ../../../cmd/sszgen -type SignedBeaconBlockHeader -out gen_signed_beacon_block_header_ssz.go +//go:generate go run ../../../cmd/sszgen -type SignedVoluntaryExit -out gen_signed_voluntary_exit_ssz.go +//go:generate go run ../../../cmd/sszgen -type VoluntaryExit -out gen_voluntary_exit_ssz.go +//go:generate go run ../../../cmd/sszgen -type Validator -out gen_validator_ssz.go +//go:generate go run ../../../cmd/sszgen -type Withdrawal -out gen_withdrawal_ssz.go + +type Attestation struct { + AggregationBits []byte `ssz-max:"2048"` + Data *AttestationData + Signature [96]byte +} + +type AttestationData struct { + Slot Slot + Index uint64 + BeaconBlockHash Hash + Source *Checkpoint + Target *Checkpoint +} + +type BeaconBlockHeader struct { + Slot uint64 + ProposerIndex uint64 + ParentRoot Hash + StateRoot Hash + BodyRoot Hash +} + +type Checkpoint struct { + Epoch uint64 + Root Hash +} + +type Deposit struct { + Proof [33][32]byte + Data *DepositData +} + +type DepositData struct { + Pubkey [48]byte + WithdrawalCredentials [32]byte + Amount uint64 + Signature [96]byte +} + +type Eth1Data struct { + DepositRoot Hash + DepositCount uint64 + BlockHash Hash +} + +type ExecutionPayload struct { + ParentHash Hash + FeeRecipient Address + StateRoot Hash + ReceiptsRoot Hash + LogsBloom LogsBloom + PrevRandao Hash + BlockNumber uint64 + GasLimit uint64 + GasUsed uint64 + Timestamp uint64 + ExtraData []byte `ssz-max:"32"` + BaseFeePerGas *uint256.Int + BlockHash Hash + Transactions [][]byte `ssz-max:"1048576"` +} + +type HistoricalBatch struct { + BlockRoots [8192]Hash + StateRoots [8192]Hash +} + +type ProposerSlashing struct { + Header1 *SignedBeaconBlockHeader + Header2 *SignedBeaconBlockHeader +} + +type SignedBeaconBlockHeader struct { + Header *BeaconBlockHeader + Signature [96]byte +} + +type SignedVoluntaryExit struct { + Exit *VoluntaryExit + Signature [96]byte +} + +type VoluntaryExit struct { + Epoch uint64 + ValidatorIndex uint64 +} + +type Validator struct { + Pubkey [48]byte + WithdrawalCredentials [32]byte + EffectiveBalance uint64 + Slashed bool + ActivationEligibilityEpoch uint64 + ActivationEpoch uint64 + ExitEpoch uint64 + WithdrawableEpoch uint64 +} + +type Withdrawal struct { + Index uint64 + Validator uint64 + Address Address + Amount uint64 +} diff --git a/tests/testtypes/consensus-spec-tests/types_variation.go b/tests/testtypes/consensus-spec-tests/types_variation.go new file mode 100644 index 0000000..d2c1121 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/types_variation.go @@ -0,0 +1,14 @@ +// ssz: Go Simple Serialize (SSZ) codec library +// Copyright 2024 ssz Authors +// SPDX-License-Identifier: BSD-3-Clause + +package consensus_spec_tests + +//go:generate go run ../../../cmd/sszgen -type WithdrawalVariation -out gen_withdrawal_variation_ssz.go + +type WithdrawalVariation struct { + Index uint64 + Validator uint64 + Address []byte `ssz-size:"20"` // Static type defined via ssz-size tag + Amount uint64 +} diff --git a/tests/testtypes/consensus-spec-tests/validator.go b/tests/testtypes/consensus-spec-tests/validator.go deleted file mode 100644 index bdeb858..0000000 --- a/tests/testtypes/consensus-spec-tests/validator.go +++ /dev/null @@ -1,30 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type Validator struct { - Pubkey [48]byte - WithdrawalCredentials [32]byte - EffectiveBalance uint64 - Slashed bool - ActivationEligibilityEpoch uint64 - ActivationEpoch uint64 - ExitEpoch uint64 - WithdrawableEpoch uint64 -} - -func (v *Validator) SizeSSZ() uint32 { return 121 } -func (v *Validator) DefineSSZ(codec *ssz.Codec) { - ssz.DefineStaticBytes(codec, v.Pubkey[:]) - ssz.DefineStaticBytes(codec, v.WithdrawalCredentials[:]) - ssz.DefineUint64(codec, &v.EffectiveBalance) - ssz.DefineBool(codec, &v.Slashed) - ssz.DefineUint64(codec, &v.ActivationEligibilityEpoch) - ssz.DefineUint64(codec, &v.ActivationEpoch) - ssz.DefineUint64(codec, &v.ExitEpoch) - ssz.DefineUint64(codec, &v.WithdrawableEpoch) -} diff --git a/tests/testtypes/consensus-spec-tests/voluntary_exit.go b/tests/testtypes/consensus-spec-tests/voluntary_exit.go deleted file mode 100644 index b234667..0000000 --- a/tests/testtypes/consensus-spec-tests/voluntary_exit.go +++ /dev/null @@ -1,18 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type VoluntaryExit struct { - Epoch uint64 - ValidatorIndex uint64 -} - -func (v *VoluntaryExit) SizeSSZ() uint32 { return 16 } -func (v *VoluntaryExit) DefineSSZ(codec *ssz.Codec) { - ssz.DefineUint64(codec, &v.Epoch) // Field (0) - Epoch - 8 bytes - ssz.DefineUint64(codec, &v.ValidatorIndex) // Field (1) - ValidatorIndex - 8 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/withdrawal.go b/tests/testtypes/consensus-spec-tests/withdrawal.go deleted file mode 100644 index 4c56ff0..0000000 --- a/tests/testtypes/consensus-spec-tests/withdrawal.go +++ /dev/null @@ -1,15 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -func (w *Withdrawal) SizeSSZ() uint32 { return 44 } -func (w *Withdrawal) DefineSSZ(codec *ssz.Codec) { - ssz.DefineUint64(codec, &w.Index) // Field (0) - Index - 8 bytes - ssz.DefineUint64(codec, &w.Validator) // Field (1) - ValidatorIndex - 8 bytes - ssz.DefineStaticBytes(codec, w.Address[:]) // Field (2) - Address - 20 bytes - ssz.DefineUint64(codec, &w.Amount) // Field (3) - Amount - 8 bytes -} diff --git a/tests/testtypes/consensus-spec-tests/withdrawal_variation.go b/tests/testtypes/consensus-spec-tests/withdrawal_variation.go deleted file mode 100644 index 2b9d33d..0000000 --- a/tests/testtypes/consensus-spec-tests/withdrawal_variation.go +++ /dev/null @@ -1,22 +0,0 @@ -// ssz: Go Simple Serialize (SSZ) codec library -// Copyright 2024 ssz Authors -// SPDX-License-Identifier: BSD-3-Clause - -package consensus_spec_tests - -import "github.com/karalabe/ssz" - -type WithdrawalVariation struct { - Index uint64 `ssz-size:"8"` - Validator uint64 `ssz-size:"8"` - Address []byte `ssz-size:"20"` - Amount uint64 `ssz-size:"8"` -} - -func (w *WithdrawalVariation) SizeSSZ() uint32 { return 44 } -func (w *WithdrawalVariation) DefineSSZ(codec *ssz.Codec) { - ssz.DefineUint64(codec, &w.Index) // Field (0) - Index - 8 bytes - ssz.DefineUint64(codec, &w.Validator) // Field (1) - ValidatorIndex - 8 bytes - ssz.DefineCheckedStaticBytes(codec, &w.Address, 20) // Field (2) - Address - 20 bytes - ssz.DefineUint64(codec, &w.Amount) // Field (3) - Amount - 8 bytes -}