mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
SSZ-QL: Handle List type & Populate the actual value dynamically (#15637)
* Add VariableTestContainer in ssz_query.proto * Add listInfo * Use errors.New for making an error with a static string literal * Add listInfo field when analyzing the List type * Persist the field order in the container * Add actualOffset and goFieldName at fieldInfo * Add PopulateFromValue function & update test runner * Handle slice of ssz object for marshalling * Add CalculateOffsetAndLength test * Add comments for better doc * Changelog :) * Apply reviews from Radek * Remove actualOffset and update offset field instead * Add Nested container of variable-sized for testing nested path * Fix offset adding logics: for variable-sized field, always add 4 instead of its fixed size * Fix multiple import issue --------- Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
3
changelog/syjn99_ssz-ql-list.md
Normal file
3
changelog/syjn99_ssz-ql-list.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
### Added
|
||||||
|
|
||||||
|
- Support `List` type for SSZ-QL.
|
||||||
@@ -5,6 +5,7 @@ go_library(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"analyzer.go",
|
"analyzer.go",
|
||||||
"container.go",
|
"container.go",
|
||||||
|
"list.go",
|
||||||
"path.go",
|
"path.go",
|
||||||
"query.go",
|
"query.go",
|
||||||
"ssz_info.go",
|
"ssz_info.go",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package query
|
package query
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -30,6 +31,89 @@ func AnalyzeObject(obj any) (*sszInfo, error) {
|
|||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PopulateVariableLengthInfo populates runtime information for SSZ fields of variable-sized types.
|
||||||
|
// This function updates the sszInfo structure with actual lengths and offsets that can only
|
||||||
|
// be determined at runtime for variable-sized items like Lists and variable-sized Container fields.
|
||||||
|
func PopulateVariableLengthInfo(sszInfo *sszInfo, value any) error {
|
||||||
|
if sszInfo == nil {
|
||||||
|
return errors.New("sszInfo is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == nil {
|
||||||
|
return errors.New("value is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short circuit: If the type is fixed-sized, we don't need to fill in the info.
|
||||||
|
if !sszInfo.isVariable {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sszInfo.sszType {
|
||||||
|
// In List case, we have to set the actual length of the list.
|
||||||
|
case List:
|
||||||
|
listInfo, err := sszInfo.ListInfo()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not get list info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if listInfo == nil {
|
||||||
|
return errors.New("listInfo is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(value)
|
||||||
|
if val.Kind() != reflect.Slice {
|
||||||
|
return fmt.Errorf("expected slice for List type, got %v", val.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
length := uint64(val.Len())
|
||||||
|
if err := listInfo.SetLength(length); err != nil {
|
||||||
|
return fmt.Errorf("could not set list length: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
// In Container case, we need to recursively populate variable-sized fields.
|
||||||
|
case Container:
|
||||||
|
containerInfo, err := sszInfo.ContainerInfo()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not get container info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dereference first in case value is a pointer.
|
||||||
|
derefValue := dereferencePointer(value)
|
||||||
|
|
||||||
|
// Start with the fixed size of this Container.
|
||||||
|
currentOffset := sszInfo.FixedSize()
|
||||||
|
|
||||||
|
for _, fieldName := range containerInfo.order {
|
||||||
|
fieldInfo := containerInfo.fields[fieldName]
|
||||||
|
childSszInfo := fieldInfo.sszInfo
|
||||||
|
if childSszInfo == nil {
|
||||||
|
return fmt.Errorf("sszInfo is nil for field %s", fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip fixed-size fields.
|
||||||
|
if !childSszInfo.isVariable {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the actual offset for variable-sized fields.
|
||||||
|
fieldInfo.offset = currentOffset
|
||||||
|
|
||||||
|
// Recursively populate variable-sized fields.
|
||||||
|
fieldValue := derefValue.FieldByName(fieldInfo.goFieldName)
|
||||||
|
if err := PopulateVariableLengthInfo(childSszInfo, fieldValue.Interface()); err != nil {
|
||||||
|
return fmt.Errorf("could not populate from value for field %s: %w", fieldName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentOffset += childSszInfo.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported SSZ type (%s) for variable size info", sszInfo.sszType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// analyzeType is an entry point that inspects a reflect.Type and computes its SSZ layout information.
|
// analyzeType is an entry point that inspects a reflect.Type and computes its SSZ layout information.
|
||||||
func analyzeType(typ reflect.Type, tag *reflect.StructTag) (*sszInfo, error) {
|
func analyzeType(typ reflect.Type, tag *reflect.StructTag) (*sszInfo, error) {
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
@@ -93,7 +177,7 @@ func analyzeHomogeneousColType(typ reflect.Type, tag *reflect.StructTag) (*sszIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tag == nil {
|
if tag == nil {
|
||||||
return nil, fmt.Errorf("tag is required for slice types")
|
return nil, errors.New("tag is required for slice types")
|
||||||
}
|
}
|
||||||
|
|
||||||
elementInfo, err := analyzeType(typ.Elem(), nil)
|
elementInfo, err := analyzeType(typ.Elem(), nil)
|
||||||
@@ -135,7 +219,7 @@ func analyzeHomogeneousColType(typ reflect.Type, tag *reflect.StructTag) (*sszIn
|
|||||||
// analyzeListType analyzes SSZ List type and returns its SSZ info.
|
// analyzeListType analyzes SSZ List type and returns its SSZ info.
|
||||||
func analyzeListType(typ reflect.Type, elementInfo *sszInfo, limit uint64) (*sszInfo, error) {
|
func analyzeListType(typ reflect.Type, elementInfo *sszInfo, limit uint64) (*sszInfo, error) {
|
||||||
if elementInfo == nil {
|
if elementInfo == nil {
|
||||||
return nil, fmt.Errorf("element info is required for List")
|
return nil, errors.New("element info is required for List")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &sszInfo{
|
return &sszInfo{
|
||||||
@@ -144,13 +228,18 @@ func analyzeListType(typ reflect.Type, elementInfo *sszInfo, limit uint64) (*ssz
|
|||||||
|
|
||||||
fixedSize: offsetBytes,
|
fixedSize: offsetBytes,
|
||||||
isVariable: true,
|
isVariable: true,
|
||||||
|
|
||||||
|
listInfo: &listInfo{
|
||||||
|
limit: limit,
|
||||||
|
element: elementInfo,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// analyzeVectorType analyzes SSZ Vector type and returns its SSZ info.
|
// analyzeVectorType analyzes SSZ Vector type and returns its SSZ info.
|
||||||
func analyzeVectorType(typ reflect.Type, elementInfo *sszInfo, length uint64) (*sszInfo, error) {
|
func analyzeVectorType(typ reflect.Type, elementInfo *sszInfo, length uint64) (*sszInfo, error) {
|
||||||
if elementInfo == nil {
|
if elementInfo == nil {
|
||||||
return nil, fmt.Errorf("element info is required for Vector")
|
return nil, errors.New("element info is required for Vector")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &sszInfo{
|
return &sszInfo{
|
||||||
@@ -168,11 +257,12 @@ func analyzeContainerType(typ reflect.Type) (*sszInfo, error) {
|
|||||||
return nil, fmt.Errorf("can only analyze struct types, got %v", typ.Kind())
|
return nil, fmt.Errorf("can only analyze struct types, got %v", typ.Kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fields := make(map[string]*fieldInfo)
|
||||||
|
order := make([]string, 0, typ.NumField())
|
||||||
|
|
||||||
sszInfo := &sszInfo{
|
sszInfo := &sszInfo{
|
||||||
sszType: Container,
|
sszType: Container,
|
||||||
typ: typ,
|
typ: typ,
|
||||||
|
|
||||||
containerInfo: make(map[string]*fieldInfo),
|
|
||||||
}
|
}
|
||||||
var currentOffset uint64
|
var currentOffset uint64
|
||||||
|
|
||||||
@@ -204,23 +294,31 @@ func analyzeContainerType(typ reflect.Type) (*sszInfo, error) {
|
|||||||
return nil, fmt.Errorf("could not analyze type for field %s: %w", fieldName, err)
|
return nil, fmt.Errorf("could not analyze type for field %s: %w", fieldName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If one of the fields is variable-sized,
|
|
||||||
// the entire struct is considered variable-sized.
|
|
||||||
if info.isVariable {
|
|
||||||
sszInfo.isVariable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store nested struct info.
|
// Store nested struct info.
|
||||||
sszInfo.containerInfo[fieldName] = &fieldInfo{
|
fields[fieldName] = &fieldInfo{
|
||||||
sszInfo: info,
|
sszInfo: info,
|
||||||
offset: currentOffset,
|
offset: currentOffset,
|
||||||
|
goFieldName: field.Name,
|
||||||
}
|
}
|
||||||
|
// Persist order
|
||||||
|
order = append(order, fieldName)
|
||||||
|
|
||||||
// Update the current offset based on the field's fixed size.
|
// Update the current offset depending on whether the field is variable-sized.
|
||||||
currentOffset += info.fixedSize
|
if info.isVariable {
|
||||||
|
// If one of the fields is variable-sized,
|
||||||
|
// the entire struct is considered variable-sized.
|
||||||
|
sszInfo.isVariable = true
|
||||||
|
currentOffset += offsetBytes
|
||||||
|
} else {
|
||||||
|
currentOffset += info.fixedSize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sszInfo.fixedSize = currentOffset
|
sszInfo.fixedSize = currentOffset
|
||||||
|
sszInfo.containerInfo = &containerInfo{
|
||||||
|
fields: fields,
|
||||||
|
order: order,
|
||||||
|
}
|
||||||
|
|
||||||
return sszInfo, nil
|
return sszInfo, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
package query
|
package query
|
||||||
|
|
||||||
// containerInfo maps a field's JSON name to its sszInfo for nested Containers.
|
// containerInfo has
|
||||||
type containerInfo = map[string]*fieldInfo
|
// 1. fields: a field map that maps a field's JSON name to its sszInfo for nested Containers
|
||||||
|
// 2. order: a list of field names in the order they should be serialized
|
||||||
|
type containerInfo struct {
|
||||||
|
fields map[string]*fieldInfo
|
||||||
|
order []string
|
||||||
|
}
|
||||||
|
|
||||||
type fieldInfo struct {
|
type fieldInfo struct {
|
||||||
// sszInfo contains the SSZ information of the field.
|
// sszInfo contains the SSZ information of the field.
|
||||||
sszInfo *sszInfo
|
sszInfo *sszInfo
|
||||||
// offset is the offset of the field within the parent struct.
|
// offset is the offset of the field within the parent struct.
|
||||||
offset uint64
|
offset uint64
|
||||||
|
// goFieldName is the name of the field in Go struct.
|
||||||
|
goFieldName string
|
||||||
}
|
}
|
||||||
|
|||||||
53
encoding/ssz/query/list.go
Normal file
53
encoding/ssz/query/list.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// listInfo holds information about a SSZ List type.
|
||||||
|
//
|
||||||
|
// length is initialized with zero,
|
||||||
|
// and can be set using SetLength while populating the actual SSZ List.
|
||||||
|
type listInfo struct {
|
||||||
|
// limit is the maximum number of elements in the list.
|
||||||
|
limit uint64
|
||||||
|
// element is the SSZ info of the list's element type.
|
||||||
|
element *sszInfo
|
||||||
|
// length is the actual number of elements at runtime (0 if not set).
|
||||||
|
length uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *listInfo) Limit() uint64 {
|
||||||
|
if l == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return l.limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *listInfo) Element() (*sszInfo, error) {
|
||||||
|
if l == nil {
|
||||||
|
return nil, errors.New("listInfo is nil")
|
||||||
|
}
|
||||||
|
return l.element, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *listInfo) Length() uint64 {
|
||||||
|
if l == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return l.length
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *listInfo) SetLength(length uint64) error {
|
||||||
|
if l == nil {
|
||||||
|
return errors.New("listInfo is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if length > l.limit {
|
||||||
|
return fmt.Errorf("length %d exceeds limit %d", length, l.limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.length = length
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,37 +1,38 @@
|
|||||||
package query
|
package query
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CalculateOffsetAndLength calculates the offset and length of a given path within the SSZ object.
|
||||||
|
// By walking the given path, it accumulates the offsets based on sszInfo.
|
||||||
func CalculateOffsetAndLength(sszInfo *sszInfo, path []PathElement) (*sszInfo, uint64, uint64, error) {
|
func CalculateOffsetAndLength(sszInfo *sszInfo, path []PathElement) (*sszInfo, uint64, uint64, error) {
|
||||||
if sszInfo == nil {
|
if sszInfo == nil {
|
||||||
return nil, 0, 0, fmt.Errorf("sszInfo is nil")
|
return nil, 0, 0, errors.New("sszInfo is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
return nil, 0, 0, fmt.Errorf("path is empty")
|
return nil, 0, 0, errors.New("path is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
walk := sszInfo
|
walk := sszInfo
|
||||||
currentOffset := uint64(0)
|
offset := uint64(0)
|
||||||
|
|
||||||
for _, elem := range path {
|
for _, elem := range path {
|
||||||
fieldInfos, err := walk.ContainerInfo()
|
containerInfo, err := walk.ContainerInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, fmt.Errorf("could not get field infos: %w", err)
|
return nil, 0, 0, fmt.Errorf("could not get field infos: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldInfo, exists := fieldInfos[elem.Name]
|
fieldInfo, exists := containerInfo.fields[elem.Name]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, 0, 0, fmt.Errorf("field %s not found in fieldInfos", elem.Name)
|
return nil, 0, 0, fmt.Errorf("field %s not found in containerInfo", elem.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentOffset += fieldInfo.offset
|
offset += fieldInfo.offset
|
||||||
walk = fieldInfo.sszInfo
|
walk = fieldInfo.sszInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
if walk.isVariable {
|
return walk, offset, walk.Size(), nil
|
||||||
return nil, 0, 0, fmt.Errorf("cannot calculate length for variable-sized type")
|
|
||||||
}
|
|
||||||
|
|
||||||
return walk, currentOffset, walk.Size(), nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,100 +6,179 @@ import (
|
|||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz/query"
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz/query"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz/query/testutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz/query/testutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/proto/ssz_query"
|
|
||||||
sszquerypb "github.com/OffchainLabs/prysm/v6/proto/ssz_query"
|
sszquerypb "github.com/OffchainLabs/prysm/v6/proto/ssz_query"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCalculateOffsetAndLength(t *testing.T) {
|
func TestCalculateOffsetAndLength(t *testing.T) {
|
||||||
tests := []struct {
|
type testCase struct {
|
||||||
name string
|
name string
|
||||||
path string
|
path string
|
||||||
expectedOffset uint64
|
expectedOffset uint64
|
||||||
expectedLength uint64
|
expectedLength uint64
|
||||||
}{
|
|
||||||
// Basic integer types
|
|
||||||
{
|
|
||||||
name: "field_uint32",
|
|
||||||
path: ".field_uint32",
|
|
||||||
expectedOffset: 0,
|
|
||||||
expectedLength: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "field_uint64",
|
|
||||||
path: ".field_uint64",
|
|
||||||
expectedOffset: 4,
|
|
||||||
expectedLength: 8,
|
|
||||||
},
|
|
||||||
// Boolean type
|
|
||||||
{
|
|
||||||
name: "field_bool",
|
|
||||||
path: ".field_bool",
|
|
||||||
expectedOffset: 12,
|
|
||||||
expectedLength: 1,
|
|
||||||
},
|
|
||||||
// Fixed-size bytes
|
|
||||||
{
|
|
||||||
name: "field_bytes32",
|
|
||||||
path: ".field_bytes32",
|
|
||||||
expectedOffset: 13,
|
|
||||||
expectedLength: 32,
|
|
||||||
},
|
|
||||||
// Nested container
|
|
||||||
{
|
|
||||||
name: "nested container",
|
|
||||||
path: ".nested",
|
|
||||||
expectedOffset: 45,
|
|
||||||
expectedLength: 40,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "nested value1",
|
|
||||||
path: ".nested.value1",
|
|
||||||
expectedOffset: 45,
|
|
||||||
expectedLength: 8,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "nested value2",
|
|
||||||
path: ".nested.value2",
|
|
||||||
expectedOffset: 53,
|
|
||||||
expectedLength: 32,
|
|
||||||
},
|
|
||||||
// Vector field
|
|
||||||
{
|
|
||||||
name: "vector field",
|
|
||||||
path: ".vector_field",
|
|
||||||
expectedOffset: 85,
|
|
||||||
expectedLength: 192, // 24 * 8 bytes
|
|
||||||
},
|
|
||||||
// Trailing field
|
|
||||||
{
|
|
||||||
name: "trailing_field",
|
|
||||||
path: ".trailing_field",
|
|
||||||
expectedOffset: 277,
|
|
||||||
expectedLength: 56,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
t.Run("FixedTestContainer", func(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
tests := []testCase{
|
||||||
path, err := query.ParsePath(tt.path)
|
// Basic integer types
|
||||||
require.NoError(t, err)
|
{
|
||||||
|
name: "field_uint32",
|
||||||
|
path: ".field_uint32",
|
||||||
|
expectedOffset: 0,
|
||||||
|
expectedLength: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field_uint64",
|
||||||
|
path: ".field_uint64",
|
||||||
|
expectedOffset: 4,
|
||||||
|
expectedLength: 8,
|
||||||
|
},
|
||||||
|
// Boolean type
|
||||||
|
{
|
||||||
|
name: "field_bool",
|
||||||
|
path: ".field_bool",
|
||||||
|
expectedOffset: 12,
|
||||||
|
expectedLength: 1,
|
||||||
|
},
|
||||||
|
// Fixed-size bytes
|
||||||
|
{
|
||||||
|
name: "field_bytes32",
|
||||||
|
path: ".field_bytes32",
|
||||||
|
expectedOffset: 13,
|
||||||
|
expectedLength: 32,
|
||||||
|
},
|
||||||
|
// Nested container
|
||||||
|
{
|
||||||
|
name: "nested container",
|
||||||
|
path: ".nested",
|
||||||
|
expectedOffset: 45,
|
||||||
|
expectedLength: 40,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nested value1",
|
||||||
|
path: ".nested.value1",
|
||||||
|
expectedOffset: 45,
|
||||||
|
expectedLength: 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nested value2",
|
||||||
|
path: ".nested.value2",
|
||||||
|
expectedOffset: 53,
|
||||||
|
expectedLength: 32,
|
||||||
|
},
|
||||||
|
// Vector field
|
||||||
|
{
|
||||||
|
name: "vector field",
|
||||||
|
path: ".vector_field",
|
||||||
|
expectedOffset: 85,
|
||||||
|
expectedLength: 192, // 24 * 8 bytes
|
||||||
|
},
|
||||||
|
// Trailing field
|
||||||
|
{
|
||||||
|
name: "trailing_field",
|
||||||
|
path: ".trailing_field",
|
||||||
|
expectedOffset: 277,
|
||||||
|
expectedLength: 56,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
info, err := query.AnalyzeObject(&sszquerypb.FixedTestContainer{})
|
for _, tt := range tests {
|
||||||
require.NoError(t, err)
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
path, err := query.ParsePath(tt.path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, offset, length, err := query.CalculateOffsetAndLength(info, path)
|
info, err := query.AnalyzeObject(&sszquerypb.FixedTestContainer{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, tt.expectedOffset, offset, "Expected offset to be %d", tt.expectedOffset)
|
_, offset, length, err := query.CalculateOffsetAndLength(info, path)
|
||||||
require.Equal(t, tt.expectedLength, length, "Expected length to be %d", tt.expectedLength)
|
require.NoError(t, err)
|
||||||
})
|
|
||||||
}
|
require.Equal(t, tt.expectedOffset, offset, "Expected offset to be %d", tt.expectedOffset)
|
||||||
|
require.Equal(t, tt.expectedLength, length, "Expected length to be %d", tt.expectedLength)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("VariableTestContainer", func(t *testing.T) {
|
||||||
|
tests := []testCase{
|
||||||
|
// Fixed leading field
|
||||||
|
{
|
||||||
|
name: "leading_field",
|
||||||
|
path: ".leading_field",
|
||||||
|
expectedOffset: 0,
|
||||||
|
expectedLength: 32,
|
||||||
|
},
|
||||||
|
// Variable-size list fields
|
||||||
|
{
|
||||||
|
name: "field_list_uint64",
|
||||||
|
path: ".field_list_uint64",
|
||||||
|
expectedOffset: 100, // First part of variable-sized type.
|
||||||
|
expectedLength: 40, // 5 elements * uint64 (8 bytes each)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field_list_container",
|
||||||
|
path: ".field_list_container",
|
||||||
|
expectedOffset: 140, // Second part of variable-sized type.
|
||||||
|
expectedLength: 120, // 3 elements * FixedNestedContainer (40 bytes each)
|
||||||
|
},
|
||||||
|
// Nested paths
|
||||||
|
{
|
||||||
|
name: "nested",
|
||||||
|
path: ".nested",
|
||||||
|
expectedOffset: 260,
|
||||||
|
// Calculated with:
|
||||||
|
// - Value1: 8 bytes
|
||||||
|
// - field_list_uint64 offset: 4 bytes
|
||||||
|
// - field_list_uint64 length: 40 bytes
|
||||||
|
expectedLength: 52,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nested.value1",
|
||||||
|
path: ".nested.value1",
|
||||||
|
expectedOffset: 260,
|
||||||
|
expectedLength: 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nested.field_list_uint64",
|
||||||
|
path: ".nested.field_list_uint64",
|
||||||
|
expectedOffset: 272,
|
||||||
|
expectedLength: 40,
|
||||||
|
},
|
||||||
|
// Fixed trailing field
|
||||||
|
{
|
||||||
|
name: "trailing_field",
|
||||||
|
path: ".trailing_field",
|
||||||
|
expectedOffset: 44, // After leading_field + 2 offset pointers
|
||||||
|
expectedLength: 56,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
path, err := query.ParsePath(tt.path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
info, err := query.AnalyzeObject(&sszquerypb.VariableTestContainer{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
testContainer := createVariableTestContainer()
|
||||||
|
err = query.PopulateVariableLengthInfo(info, testContainer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, offset, length, err := query.CalculateOffsetAndLength(info, path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, tt.expectedOffset, offset, "Expected offset to be %d", tt.expectedOffset)
|
||||||
|
require.Equal(t, tt.expectedLength, length, "Expected length to be %d", tt.expectedLength)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRoundTripSszInfo(t *testing.T) {
|
func TestRoundTripSszInfo(t *testing.T) {
|
||||||
specs := []testutil.TestSpec{
|
specs := []testutil.TestSpec{
|
||||||
getFixedTestContainerSpec(),
|
getFixedTestContainerSpec(),
|
||||||
|
getVariableTestContainerSpec(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, spec := range specs {
|
for _, spec := range specs {
|
||||||
@@ -107,7 +186,7 @@ func TestRoundTripSszInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFixedTestContainer() any {
|
func createFixedTestContainer() *sszquerypb.FixedTestContainer {
|
||||||
fieldBytes32 := make([]byte, 32)
|
fieldBytes32 := make([]byte, 32)
|
||||||
for i := range fieldBytes32 {
|
for i := range fieldBytes32 {
|
||||||
fieldBytes32[i] = byte(i + 24)
|
fieldBytes32[i] = byte(i + 24)
|
||||||
@@ -123,7 +202,7 @@ func createFixedTestContainer() any {
|
|||||||
trailingField[i] = byte(i + 88)
|
trailingField[i] = byte(i + 88)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ssz_query.FixedTestContainer{
|
return &sszquerypb.FixedTestContainer{
|
||||||
// Basic types
|
// Basic types
|
||||||
FieldUint32: math.MaxUint32,
|
FieldUint32: math.MaxUint32,
|
||||||
FieldUint64: math.MaxUint64,
|
FieldUint64: math.MaxUint64,
|
||||||
@@ -147,7 +226,7 @@ func createFixedTestContainer() any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getFixedTestContainerSpec() testutil.TestSpec {
|
func getFixedTestContainerSpec() testutil.TestSpec {
|
||||||
testContainer := createFixedTestContainer().(*sszquerypb.FixedTestContainer)
|
testContainer := createFixedTestContainer()
|
||||||
|
|
||||||
return testutil.TestSpec{
|
return testutil.TestSpec{
|
||||||
Name: "FixedTestContainer",
|
Name: "FixedTestContainer",
|
||||||
@@ -198,3 +277,90 @@ func getFixedTestContainerSpec() testutil.TestSpec {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createVariableTestContainer() *sszquerypb.VariableTestContainer {
|
||||||
|
leadingField := make([]byte, 32)
|
||||||
|
for i := range leadingField {
|
||||||
|
leadingField[i] = byte(i + 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
trailingField := make([]byte, 56)
|
||||||
|
for i := range trailingField {
|
||||||
|
trailingField[i] = byte(i + 150)
|
||||||
|
}
|
||||||
|
|
||||||
|
nestedContainers := make([]*sszquerypb.FixedNestedContainer, 3)
|
||||||
|
for i := range nestedContainers {
|
||||||
|
value2 := make([]byte, 32)
|
||||||
|
for j := range value2 {
|
||||||
|
value2[j] = byte(j + i*32)
|
||||||
|
}
|
||||||
|
nestedContainers[i] = &sszquerypb.FixedNestedContainer{
|
||||||
|
Value1: uint64(1000 + i),
|
||||||
|
Value2: value2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &sszquerypb.VariableTestContainer{
|
||||||
|
// Fixed leading field
|
||||||
|
LeadingField: leadingField,
|
||||||
|
|
||||||
|
// Variable-size lists
|
||||||
|
FieldListUint64: []uint64{100, 200, 300, 400, 500},
|
||||||
|
FieldListContainer: nestedContainers,
|
||||||
|
|
||||||
|
// Variable nested container
|
||||||
|
Nested: &sszquerypb.VariableNestedContainer{
|
||||||
|
Value1: 42,
|
||||||
|
FieldListUint64: []uint64{1, 2, 3, 4, 5},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Fixed trailing field
|
||||||
|
TrailingField: trailingField,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVariableTestContainerSpec() testutil.TestSpec {
|
||||||
|
testContainer := createVariableTestContainer()
|
||||||
|
|
||||||
|
return testutil.TestSpec{
|
||||||
|
Name: "VariableTestContainer",
|
||||||
|
Type: sszquerypb.VariableTestContainer{},
|
||||||
|
Instance: testContainer,
|
||||||
|
PathTests: []testutil.PathTest{
|
||||||
|
// Fixed leading field
|
||||||
|
{
|
||||||
|
Path: ".leading_field",
|
||||||
|
Expected: testContainer.LeadingField,
|
||||||
|
},
|
||||||
|
// Variable-size list of uint64
|
||||||
|
{
|
||||||
|
Path: ".field_list_uint64",
|
||||||
|
Expected: testContainer.FieldListUint64,
|
||||||
|
},
|
||||||
|
// Variable-size list of (fixed-size) containers
|
||||||
|
{
|
||||||
|
Path: ".field_list_container",
|
||||||
|
Expected: testContainer.FieldListContainer,
|
||||||
|
},
|
||||||
|
// Variable nested container with every path
|
||||||
|
{
|
||||||
|
Path: ".nested",
|
||||||
|
Expected: testContainer.Nested,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: ".nested.value1",
|
||||||
|
Expected: testContainer.Nested.Value1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: ".nested.field_list_uint64",
|
||||||
|
Expected: testContainer.Nested.FieldListUint64,
|
||||||
|
},
|
||||||
|
// Fixed trailing field
|
||||||
|
{
|
||||||
|
Path: ".trailing_field",
|
||||||
|
Expected: testContainer.TrailingField,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package query
|
package query
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,7 +20,10 @@ type sszInfo struct {
|
|||||||
fixedSize uint64
|
fixedSize uint64
|
||||||
|
|
||||||
// For Container types.
|
// For Container types.
|
||||||
containerInfo containerInfo
|
containerInfo *containerInfo
|
||||||
|
|
||||||
|
// For List types.
|
||||||
|
listInfo *listInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *sszInfo) FixedSize() uint64 {
|
func (info *sszInfo) FixedSize() uint64 {
|
||||||
@@ -40,13 +43,33 @@ func (info *sszInfo) Size() uint64 {
|
|||||||
return info.fixedSize
|
return info.fixedSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Handle variable-sized types.
|
switch info.sszType {
|
||||||
return 0
|
case List:
|
||||||
|
length := info.listInfo.length
|
||||||
|
elementSize := info.listInfo.element.Size()
|
||||||
|
|
||||||
|
return length * elementSize
|
||||||
|
|
||||||
|
case Container:
|
||||||
|
size := info.fixedSize
|
||||||
|
for _, fieldInfo := range info.containerInfo.fields {
|
||||||
|
if !fieldInfo.sszInfo.isVariable {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
size += fieldInfo.sszInfo.Size()
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
|
||||||
|
default:
|
||||||
|
// NOTE: Handle other variable-sized types.
|
||||||
|
return 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *sszInfo) ContainerInfo() (containerInfo, error) {
|
func (info *sszInfo) ContainerInfo() (*containerInfo, error) {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return nil, fmt.Errorf("sszInfo is nil")
|
return nil, errors.New("sszInfo is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.sszType != Container {
|
if info.sszType != Container {
|
||||||
@@ -54,12 +77,24 @@ func (info *sszInfo) ContainerInfo() (containerInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if info.containerInfo == nil {
|
if info.containerInfo == nil {
|
||||||
return nil, fmt.Errorf("sszInfo.containerInfo is nil")
|
return nil, errors.New("sszInfo.containerInfo is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
return info.containerInfo, nil
|
return info.containerInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (info *sszInfo) ListInfo() (*listInfo, error) {
|
||||||
|
if info == nil {
|
||||||
|
return nil, errors.New("sszInfo is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.sszType != List {
|
||||||
|
return nil, fmt.Errorf("sszInfo is not a List type, got %s", info.sszType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info.listInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Print returns a string representation of the sszInfo, which is useful for debugging.
|
// Print returns a string representation of the sszInfo, which is useful for debugging.
|
||||||
func (info *sszInfo) Print() string {
|
func (info *sszInfo) Print() string {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
@@ -81,30 +116,28 @@ func printRecursive(info *sszInfo, builder *strings.Builder, prefix string) {
|
|||||||
switch info.sszType {
|
switch info.sszType {
|
||||||
case Container:
|
case Container:
|
||||||
builder.WriteString(fmt.Sprintf("%s: %s (%s / fixed size: %d, total size: %d)\n", info.sszType, info.typ.Name(), sizeDesc, info.FixedSize(), info.Size()))
|
builder.WriteString(fmt.Sprintf("%s: %s (%s / fixed size: %d, total size: %d)\n", info.sszType, info.typ.Name(), sizeDesc, info.FixedSize(), info.Size()))
|
||||||
|
|
||||||
|
for i, key := range info.containerInfo.order {
|
||||||
|
connector := "├─"
|
||||||
|
nextPrefix := prefix + "│ "
|
||||||
|
if i == len(info.containerInfo.order)-1 {
|
||||||
|
connector = "└─"
|
||||||
|
nextPrefix = prefix + " "
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(fmt.Sprintf("%s%s %s (offset: %d) ", prefix, connector, key, info.containerInfo.fields[key].offset))
|
||||||
|
|
||||||
|
if nestedInfo := info.containerInfo.fields[key].sszInfo; nestedInfo != nil {
|
||||||
|
printRecursive(nestedInfo, builder, nextPrefix)
|
||||||
|
} else {
|
||||||
|
builder.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case List:
|
||||||
|
builder.WriteString(fmt.Sprintf("%s[%s] (%s / limit: %d, length: %d, size: %d)\n", info.sszType, info.listInfo.element.typ.Name(), sizeDesc, info.listInfo.limit, info.listInfo.length, info.Size()))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
builder.WriteString(fmt.Sprintf("%s (%s / size: %d)\n", info.sszType, sizeDesc, info.Size()))
|
builder.WriteString(fmt.Sprintf("%s (%s / size: %d)\n", info.sszType, sizeDesc, info.Size()))
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := make([]string, 0, len(info.containerInfo))
|
|
||||||
for k := range info.containerInfo {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
for i, key := range keys {
|
|
||||||
connector := "├─"
|
|
||||||
nextPrefix := prefix + "│ "
|
|
||||||
if i == len(keys)-1 {
|
|
||||||
connector = "└─"
|
|
||||||
nextPrefix = prefix + " "
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WriteString(fmt.Sprintf("%s%s %s (offset: %d) ", prefix, connector, key, info.containerInfo[key].offset))
|
|
||||||
|
|
||||||
if nestedInfo := info.containerInfo[key].sszInfo; nestedInfo != nil {
|
|
||||||
printRecursive(nestedInfo, builder, nextPrefix)
|
|
||||||
} else {
|
|
||||||
builder.WriteString("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ func RunStructTest(t *testing.T, spec TestSpec) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
testInstance := spec.Instance
|
testInstance := spec.Instance
|
||||||
|
err = query.PopulateVariableLengthInfo(info, testInstance)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
marshaller, ok := testInstance.(ssz.Marshaler)
|
marshaller, ok := testInstance.(ssz.Marshaler)
|
||||||
require.Equal(t, true, ok, "Test instance must implement ssz.Marshaler, got %T", testInstance)
|
require.Equal(t, true, ok, "Test instance must implement ssz.Marshaler, got %T", testInstance)
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,12 @@ func marshalAny(value any) ([]byte, error) {
|
|||||||
return marshaler.MarshalSSZ()
|
return marshaler.MarshalSSZ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle custom type aliases by checking if they're based on primitive types
|
|
||||||
valueType := reflect.TypeOf(value)
|
valueType := reflect.TypeOf(value)
|
||||||
|
if valueType.Kind() == reflect.Slice && valueType.Elem().Kind() != reflect.Uint8 {
|
||||||
|
return marshalSlice(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle custom type aliases by checking if they're based on primitive types
|
||||||
if valueType.PkgPath() != "" {
|
if valueType.PkgPath() != "" {
|
||||||
switch valueType.Kind() {
|
switch valueType.Kind() {
|
||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
@@ -47,3 +51,25 @@ func marshalAny(value any) ([]byte, error) {
|
|||||||
return nil, fmt.Errorf("unsupported type for SSZ marshalling: %T", value)
|
return nil, fmt.Errorf("unsupported type for SSZ marshalling: %T", value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func marshalSlice(value any) ([]byte, error) {
|
||||||
|
valueType := reflect.TypeOf(value)
|
||||||
|
|
||||||
|
if valueType.Kind() != reflect.Slice {
|
||||||
|
return nil, fmt.Errorf("expected slice, got %T", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
sliceValue := reflect.ValueOf(value)
|
||||||
|
var result []byte
|
||||||
|
|
||||||
|
// Marshal each element recursively
|
||||||
|
for i := 0; i < sliceValue.Len(); i++ {
|
||||||
|
elem := sliceValue.Index(i).Interface()
|
||||||
|
data, err := marshalAny(elem)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to marshal slice element at index %d: %w", i, err)
|
||||||
|
}
|
||||||
|
result = append(result, data...)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ ssz_gen_marshal(
|
|||||||
objs = [
|
objs = [
|
||||||
"FixedTestContainer",
|
"FixedTestContainer",
|
||||||
"FixedNestedContainer",
|
"FixedNestedContainer",
|
||||||
|
"VariableTestContainer",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
216
proto/ssz_query/ssz_query.pb.go
generated
216
proto/ssz_query/ssz_query.pb.go
generated
@@ -172,6 +172,140 @@ func (x *FixedTestContainer) GetTrailingField() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VariableNestedContainer struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value1 uint64 `protobuf:"varint,1,opt,name=value1,proto3" json:"value1,omitempty"`
|
||||||
|
FieldListUint64 []uint64 `protobuf:"varint,2,rep,packed,name=field_list_uint64,json=fieldListUint64,proto3" json:"field_list_uint64,omitempty" ssz-max:"100"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableNestedContainer) Reset() {
|
||||||
|
*x = VariableNestedContainer{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_proto_ssz_query_ssz_query_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableNestedContainer) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*VariableNestedContainer) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *VariableNestedContainer) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_ssz_query_ssz_query_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use VariableNestedContainer.ProtoReflect.Descriptor instead.
|
||||||
|
func (*VariableNestedContainer) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_ssz_query_ssz_query_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableNestedContainer) GetValue1() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableNestedContainer) GetFieldListUint64() []uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.FieldListUint64
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type VariableTestContainer struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
LeadingField []byte `protobuf:"bytes,1,opt,name=leading_field,json=leadingField,proto3" json:"leading_field,omitempty" ssz-size:"32"`
|
||||||
|
FieldListUint64 []uint64 `protobuf:"varint,2,rep,packed,name=field_list_uint64,json=fieldListUint64,proto3" json:"field_list_uint64,omitempty" ssz-max:"2048"`
|
||||||
|
FieldListContainer []*FixedNestedContainer `protobuf:"bytes,3,rep,name=field_list_container,json=fieldListContainer,proto3" json:"field_list_container,omitempty" ssz-max:"128"`
|
||||||
|
Nested *VariableNestedContainer `protobuf:"bytes,4,opt,name=nested,proto3" json:"nested,omitempty"`
|
||||||
|
TrailingField []byte `protobuf:"bytes,5,opt,name=trailing_field,json=trailingField,proto3" json:"trailing_field,omitempty" ssz-size:"56"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableTestContainer) Reset() {
|
||||||
|
*x = VariableTestContainer{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_proto_ssz_query_ssz_query_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableTestContainer) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*VariableTestContainer) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *VariableTestContainer) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_ssz_query_ssz_query_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use VariableTestContainer.ProtoReflect.Descriptor instead.
|
||||||
|
func (*VariableTestContainer) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_ssz_query_ssz_query_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableTestContainer) GetLeadingField() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.LeadingField
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableTestContainer) GetFieldListUint64() []uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.FieldListUint64
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableTestContainer) GetFieldListContainer() []*FixedNestedContainer {
|
||||||
|
if x != nil {
|
||||||
|
return x.FieldListContainer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableTestContainer) GetNested() *VariableNestedContainer {
|
||||||
|
if x != nil {
|
||||||
|
return x.Nested
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VariableTestContainer) GetTrailingField() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.TrailingField
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var File_proto_ssz_query_ssz_query_proto protoreflect.FileDescriptor
|
var File_proto_ssz_query_ssz_query_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proto_ssz_query_ssz_query_proto_rawDesc = []byte{
|
var file_proto_ssz_query_ssz_query_proto_rawDesc = []byte{
|
||||||
@@ -204,11 +338,37 @@ var file_proto_ssz_query_ssz_query_proto_rawDesc = []byte{
|
|||||||
0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x2d, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x69,
|
0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x2d, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x69,
|
||||||
0x6e, 0x67, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
|
0x6e, 0x67, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
|
||||||
0x8a, 0xb5, 0x18, 0x02, 0x35, 0x36, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67,
|
0x8a, 0xb5, 0x18, 0x02, 0x35, 0x36, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67,
|
||||||
0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
0x46, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x66, 0x0a, 0x17, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c,
|
||||||
0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73,
|
0x65, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
|
||||||
0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
|
0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
|
||||||
0x73, 0x73, 0x7a, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x12, 0x33, 0x0a, 0x11, 0x66, 0x69, 0x65, 0x6c,
|
||||||
0x33,
|
0x64, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x02, 0x20,
|
||||||
|
0x03, 0x28, 0x04, 0x42, 0x07, 0x92, 0xb5, 0x18, 0x03, 0x31, 0x30, 0x30, 0x52, 0x0f, 0x66, 0x69,
|
||||||
|
0x65, 0x6c, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x22, 0xc1, 0x02,
|
||||||
|
0x0a, 0x15, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f,
|
||||||
|
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x64, 0x69,
|
||||||
|
0x6e, 0x67, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
|
||||||
|
0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x46,
|
||||||
|
0x69, 0x65, 0x6c, 0x64, 0x12, 0x34, 0x0a, 0x11, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6c, 0x69,
|
||||||
|
0x73, 0x74, 0x5f, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x42,
|
||||||
|
0x08, 0x92, 0xb5, 0x18, 0x04, 0x32, 0x30, 0x34, 0x38, 0x52, 0x0f, 0x66, 0x69, 0x65, 0x6c, 0x64,
|
||||||
|
0x4c, 0x69, 0x73, 0x74, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x12, 0x5a, 0x0a, 0x14, 0x66, 0x69,
|
||||||
|
0x65, 0x6c, 0x64, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
|
||||||
|
0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x73, 0x7a, 0x5f, 0x71,
|
||||||
|
0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x78, 0x65, 0x64, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64,
|
||||||
|
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x42, 0x07, 0x92, 0xb5, 0x18, 0x03, 0x31,
|
||||||
|
0x32, 0x38, 0x52, 0x12, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e,
|
||||||
|
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x06, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64,
|
||||||
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x73, 0x7a, 0x5f, 0x71, 0x75, 0x65,
|
||||||
|
0x72, 0x79, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x65, 0x73, 0x74, 0x65,
|
||||||
|
0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x06, 0x6e, 0x65, 0x73, 0x74,
|
||||||
|
0x65, 0x64, 0x12, 0x2d, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x66,
|
||||||
|
0x69, 0x65, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02,
|
||||||
|
0x35, 0x36, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x65, 0x6c,
|
||||||
|
0x64, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||||
|
0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79,
|
||||||
|
0x73, 0x6d, 0x2f, 0x76, 0x36, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x73, 0x7a, 0x5f,
|
||||||
|
0x71, 0x75, 0x65, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -223,18 +383,22 @@ func file_proto_ssz_query_ssz_query_proto_rawDescGZIP() []byte {
|
|||||||
return file_proto_ssz_query_ssz_query_proto_rawDescData
|
return file_proto_ssz_query_ssz_query_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_proto_ssz_query_ssz_query_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
var file_proto_ssz_query_ssz_query_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||||
var file_proto_ssz_query_ssz_query_proto_goTypes = []interface{}{
|
var file_proto_ssz_query_ssz_query_proto_goTypes = []interface{}{
|
||||||
(*FixedNestedContainer)(nil), // 0: ssz_query.FixedNestedContainer
|
(*FixedNestedContainer)(nil), // 0: ssz_query.FixedNestedContainer
|
||||||
(*FixedTestContainer)(nil), // 1: ssz_query.FixedTestContainer
|
(*FixedTestContainer)(nil), // 1: ssz_query.FixedTestContainer
|
||||||
|
(*VariableNestedContainer)(nil), // 2: ssz_query.VariableNestedContainer
|
||||||
|
(*VariableTestContainer)(nil), // 3: ssz_query.VariableTestContainer
|
||||||
}
|
}
|
||||||
var file_proto_ssz_query_ssz_query_proto_depIdxs = []int32{
|
var file_proto_ssz_query_ssz_query_proto_depIdxs = []int32{
|
||||||
0, // 0: ssz_query.FixedTestContainer.nested:type_name -> ssz_query.FixedNestedContainer
|
0, // 0: ssz_query.FixedTestContainer.nested:type_name -> ssz_query.FixedNestedContainer
|
||||||
1, // [1:1] is the sub-list for method output_type
|
0, // 1: ssz_query.VariableTestContainer.field_list_container:type_name -> ssz_query.FixedNestedContainer
|
||||||
1, // [1:1] is the sub-list for method input_type
|
2, // 2: ssz_query.VariableTestContainer.nested:type_name -> ssz_query.VariableNestedContainer
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
3, // [3:3] is the sub-list for method output_type
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
3, // [3:3] is the sub-list for method input_type
|
||||||
0, // [0:1] is the sub-list for field type_name
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
|
3, // [3:3] is the sub-list for extension extendee
|
||||||
|
0, // [0:3] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_proto_ssz_query_ssz_query_proto_init() }
|
func init() { file_proto_ssz_query_ssz_query_proto_init() }
|
||||||
@@ -267,6 +431,30 @@ func file_proto_ssz_query_ssz_query_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file_proto_ssz_query_ssz_query_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*VariableNestedContainer); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_proto_ssz_query_ssz_query_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*VariableTestContainer); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
@@ -274,7 +462,7 @@ func file_proto_ssz_query_ssz_query_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_proto_ssz_query_ssz_query_proto_rawDesc,
|
RawDescriptor: file_proto_ssz_query_ssz_query_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 2,
|
NumMessages: 4,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,3 +41,35 @@ message FixedTestContainer {
|
|||||||
// Additional bytes field - test field ordering and offset calculation
|
// Additional bytes field - test field ordering and offset calculation
|
||||||
bytes trailing_field = 11 [ (ethereum.eth.ext.ssz_size) = "56" ]; // Test: trailing field after vector, offset: 277
|
bytes trailing_field = 11 [ (ethereum.eth.ext.ssz_size) = "56" ]; // Test: trailing field after vector, offset: 277
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== VARIABLE-SIZE TEST CONTAINERS =====
|
||||||
|
|
||||||
|
// VariableNestedContainer - nested container for testing nested field access
|
||||||
|
// Tests: nested container navigation, field offset calculations within nested structures
|
||||||
|
message VariableNestedContainer {
|
||||||
|
uint64 value1 = 1;
|
||||||
|
repeated uint64 field_list_uint64 = 2 [ (ethereum.eth.ext.ssz_max) = "100" ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// VariableTestContainer - comprehensive variable-size container for SSZ query testing
|
||||||
|
// Tests: Variable-size lists, offsets in variable containers, mixed fixed/variable fields
|
||||||
|
message VariableTestContainer {
|
||||||
|
// Fixed-size leading field - test fixed field before variable fields
|
||||||
|
// Acts as a baseline to verify offset calculations start correctly
|
||||||
|
bytes leading_field = 1 [ (ethereum.eth.ext.ssz_size) = "32" ]; // Test: fixed 32-byte field at start, offset: 0
|
||||||
|
|
||||||
|
// Variable-size list of basic type - test list with primitive elements
|
||||||
|
// SSZ uses 4-byte offset pointer, actual data stored after all fixed fields
|
||||||
|
repeated uint64 field_list_uint64 = 2 [ (ethereum.eth.ext.ssz_max) = "2048" ]; // Test: List[uint64, 2048] (max 2048 elements)
|
||||||
|
|
||||||
|
// Variable-size list of containers - test list with composite elements
|
||||||
|
// Each container is fixed-size (40 bytes), but list itself is variable
|
||||||
|
repeated FixedNestedContainer field_list_container = 3 [ (ethereum.eth.ext.ssz_max) = "128" ]; // Test: List[FixedNestedContainer, 128]
|
||||||
|
|
||||||
|
// Variable nested container - test nested container access within variable container
|
||||||
|
VariableNestedContainer nested = 4;
|
||||||
|
|
||||||
|
// Fixed-size trailing field - test fixed field after variable fields
|
||||||
|
// Verifies correct offset calculation after variable-size fields
|
||||||
|
bytes trailing_field = 5 [ (ethereum.eth.ext.ssz_size) = "56" ]; // Test: fixed 56-byte field at end, offset: 32 + 4 + 4 + 4 = 44
|
||||||
|
}
|
||||||
|
|||||||
@@ -236,3 +236,348 @@ func (f *FixedTestContainer) HashTreeRootWith(hh *ssz.Hasher) (err error) {
|
|||||||
hh.Merkleize(indx)
|
hh.Merkleize(indx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalSSZ ssz marshals the VariableNestedContainer object
|
||||||
|
func (v *VariableNestedContainer) MarshalSSZ() ([]byte, error) {
|
||||||
|
return ssz.MarshalSSZ(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalSSZTo ssz marshals the VariableNestedContainer object to a target array
|
||||||
|
func (v *VariableNestedContainer) MarshalSSZTo(buf []byte) (dst []byte, err error) {
|
||||||
|
dst = buf
|
||||||
|
offset := int(12)
|
||||||
|
|
||||||
|
// Field (0) 'Value1'
|
||||||
|
dst = ssz.MarshalUint64(dst, v.Value1)
|
||||||
|
|
||||||
|
// Offset (1) 'FieldListUint64'
|
||||||
|
dst = ssz.WriteOffset(dst, offset)
|
||||||
|
offset += len(v.FieldListUint64) * 8
|
||||||
|
|
||||||
|
// Field (1) 'FieldListUint64'
|
||||||
|
if size := len(v.FieldListUint64); size > 100 {
|
||||||
|
err = ssz.ErrListTooBigFn("--.FieldListUint64", size, 100)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for ii := 0; ii < len(v.FieldListUint64); ii++ {
|
||||||
|
dst = ssz.MarshalUint64(dst, v.FieldListUint64[ii])
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalSSZ ssz unmarshals the VariableNestedContainer object
|
||||||
|
func (v *VariableNestedContainer) UnmarshalSSZ(buf []byte) error {
|
||||||
|
var err error
|
||||||
|
size := uint64(len(buf))
|
||||||
|
if size < 12 {
|
||||||
|
return ssz.ErrSize
|
||||||
|
}
|
||||||
|
|
||||||
|
tail := buf
|
||||||
|
var o1 uint64
|
||||||
|
|
||||||
|
// Field (0) 'Value1'
|
||||||
|
v.Value1 = ssz.UnmarshallUint64(buf[0:8])
|
||||||
|
|
||||||
|
// Offset (1) 'FieldListUint64'
|
||||||
|
if o1 = ssz.ReadOffset(buf[8:12]); o1 > size {
|
||||||
|
return ssz.ErrOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
if o1 != 12 {
|
||||||
|
return ssz.ErrInvalidVariableOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (1) 'FieldListUint64'
|
||||||
|
{
|
||||||
|
buf = tail[o1:]
|
||||||
|
num, err := ssz.DivideInt2(len(buf), 8, 100)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.FieldListUint64 = ssz.ExtendUint64(v.FieldListUint64, num)
|
||||||
|
for ii := 0; ii < num; ii++ {
|
||||||
|
v.FieldListUint64[ii] = ssz.UnmarshallUint64(buf[ii*8 : (ii+1)*8])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SizeSSZ returns the ssz encoded size in bytes for the VariableNestedContainer object
|
||||||
|
func (v *VariableNestedContainer) SizeSSZ() (size int) {
|
||||||
|
size = 12
|
||||||
|
|
||||||
|
// Field (1) 'FieldListUint64'
|
||||||
|
size += len(v.FieldListUint64) * 8
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashTreeRoot ssz hashes the VariableNestedContainer object
|
||||||
|
func (v *VariableNestedContainer) HashTreeRoot() ([32]byte, error) {
|
||||||
|
return ssz.HashWithDefaultHasher(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashTreeRootWith ssz hashes the VariableNestedContainer object with a hasher
|
||||||
|
func (v *VariableNestedContainer) HashTreeRootWith(hh *ssz.Hasher) (err error) {
|
||||||
|
indx := hh.Index()
|
||||||
|
|
||||||
|
// Field (0) 'Value1'
|
||||||
|
hh.PutUint64(v.Value1)
|
||||||
|
|
||||||
|
// Field (1) 'FieldListUint64'
|
||||||
|
{
|
||||||
|
if size := len(v.FieldListUint64); size > 100 {
|
||||||
|
err = ssz.ErrListTooBigFn("--.FieldListUint64", size, 100)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subIndx := hh.Index()
|
||||||
|
for _, i := range v.FieldListUint64 {
|
||||||
|
hh.AppendUint64(i)
|
||||||
|
}
|
||||||
|
hh.FillUpTo32()
|
||||||
|
|
||||||
|
numItems := uint64(len(v.FieldListUint64))
|
||||||
|
hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(100, numItems, 8))
|
||||||
|
}
|
||||||
|
|
||||||
|
hh.Merkleize(indx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalSSZ ssz marshals the VariableTestContainer object
|
||||||
|
func (v *VariableTestContainer) MarshalSSZ() ([]byte, error) {
|
||||||
|
return ssz.MarshalSSZ(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalSSZTo ssz marshals the VariableTestContainer object to a target array
|
||||||
|
func (v *VariableTestContainer) MarshalSSZTo(buf []byte) (dst []byte, err error) {
|
||||||
|
dst = buf
|
||||||
|
offset := int(100)
|
||||||
|
|
||||||
|
// Field (0) 'LeadingField'
|
||||||
|
if size := len(v.LeadingField); size != 32 {
|
||||||
|
err = ssz.ErrBytesLengthFn("--.LeadingField", size, 32)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst = append(dst, v.LeadingField...)
|
||||||
|
|
||||||
|
// Offset (1) 'FieldListUint64'
|
||||||
|
dst = ssz.WriteOffset(dst, offset)
|
||||||
|
offset += len(v.FieldListUint64) * 8
|
||||||
|
|
||||||
|
// Offset (2) 'FieldListContainer'
|
||||||
|
dst = ssz.WriteOffset(dst, offset)
|
||||||
|
offset += len(v.FieldListContainer) * 40
|
||||||
|
|
||||||
|
// Offset (3) 'Nested'
|
||||||
|
dst = ssz.WriteOffset(dst, offset)
|
||||||
|
if v.Nested == nil {
|
||||||
|
v.Nested = new(VariableNestedContainer)
|
||||||
|
}
|
||||||
|
offset += v.Nested.SizeSSZ()
|
||||||
|
|
||||||
|
// Field (4) 'TrailingField'
|
||||||
|
if size := len(v.TrailingField); size != 56 {
|
||||||
|
err = ssz.ErrBytesLengthFn("--.TrailingField", size, 56)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst = append(dst, v.TrailingField...)
|
||||||
|
|
||||||
|
// Field (1) 'FieldListUint64'
|
||||||
|
if size := len(v.FieldListUint64); size > 2048 {
|
||||||
|
err = ssz.ErrListTooBigFn("--.FieldListUint64", size, 2048)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for ii := 0; ii < len(v.FieldListUint64); ii++ {
|
||||||
|
dst = ssz.MarshalUint64(dst, v.FieldListUint64[ii])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (2) 'FieldListContainer'
|
||||||
|
if size := len(v.FieldListContainer); size > 128 {
|
||||||
|
err = ssz.ErrListTooBigFn("--.FieldListContainer", size, 128)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for ii := 0; ii < len(v.FieldListContainer); ii++ {
|
||||||
|
if dst, err = v.FieldListContainer[ii].MarshalSSZTo(dst); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (3) 'Nested'
|
||||||
|
if dst, err = v.Nested.MarshalSSZTo(dst); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalSSZ ssz unmarshals the VariableTestContainer object
|
||||||
|
func (v *VariableTestContainer) UnmarshalSSZ(buf []byte) error {
|
||||||
|
var err error
|
||||||
|
size := uint64(len(buf))
|
||||||
|
if size < 100 {
|
||||||
|
return ssz.ErrSize
|
||||||
|
}
|
||||||
|
|
||||||
|
tail := buf
|
||||||
|
var o1, o2, o3 uint64
|
||||||
|
|
||||||
|
// Field (0) 'LeadingField'
|
||||||
|
if cap(v.LeadingField) == 0 {
|
||||||
|
v.LeadingField = make([]byte, 0, len(buf[0:32]))
|
||||||
|
}
|
||||||
|
v.LeadingField = append(v.LeadingField, buf[0:32]...)
|
||||||
|
|
||||||
|
// Offset (1) 'FieldListUint64'
|
||||||
|
if o1 = ssz.ReadOffset(buf[32:36]); o1 > size {
|
||||||
|
return ssz.ErrOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
if o1 != 100 {
|
||||||
|
return ssz.ErrInvalidVariableOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset (2) 'FieldListContainer'
|
||||||
|
if o2 = ssz.ReadOffset(buf[36:40]); o2 > size || o1 > o2 {
|
||||||
|
return ssz.ErrOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset (3) 'Nested'
|
||||||
|
if o3 = ssz.ReadOffset(buf[40:44]); o3 > size || o2 > o3 {
|
||||||
|
return ssz.ErrOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (4) 'TrailingField'
|
||||||
|
if cap(v.TrailingField) == 0 {
|
||||||
|
v.TrailingField = make([]byte, 0, len(buf[44:100]))
|
||||||
|
}
|
||||||
|
v.TrailingField = append(v.TrailingField, buf[44:100]...)
|
||||||
|
|
||||||
|
// Field (1) 'FieldListUint64'
|
||||||
|
{
|
||||||
|
buf = tail[o1:o2]
|
||||||
|
num, err := ssz.DivideInt2(len(buf), 8, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.FieldListUint64 = ssz.ExtendUint64(v.FieldListUint64, num)
|
||||||
|
for ii := 0; ii < num; ii++ {
|
||||||
|
v.FieldListUint64[ii] = ssz.UnmarshallUint64(buf[ii*8 : (ii+1)*8])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (2) 'FieldListContainer'
|
||||||
|
{
|
||||||
|
buf = tail[o2:o3]
|
||||||
|
num, err := ssz.DivideInt2(len(buf), 40, 128)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.FieldListContainer = make([]*FixedNestedContainer, num)
|
||||||
|
for ii := 0; ii < num; ii++ {
|
||||||
|
if v.FieldListContainer[ii] == nil {
|
||||||
|
v.FieldListContainer[ii] = new(FixedNestedContainer)
|
||||||
|
}
|
||||||
|
if err = v.FieldListContainer[ii].UnmarshalSSZ(buf[ii*40 : (ii+1)*40]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (3) 'Nested'
|
||||||
|
{
|
||||||
|
buf = tail[o3:]
|
||||||
|
if v.Nested == nil {
|
||||||
|
v.Nested = new(VariableNestedContainer)
|
||||||
|
}
|
||||||
|
if err = v.Nested.UnmarshalSSZ(buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SizeSSZ returns the ssz encoded size in bytes for the VariableTestContainer object
|
||||||
|
func (v *VariableTestContainer) SizeSSZ() (size int) {
|
||||||
|
size = 100
|
||||||
|
|
||||||
|
// Field (1) 'FieldListUint64'
|
||||||
|
size += len(v.FieldListUint64) * 8
|
||||||
|
|
||||||
|
// Field (2) 'FieldListContainer'
|
||||||
|
size += len(v.FieldListContainer) * 40
|
||||||
|
|
||||||
|
// Field (3) 'Nested'
|
||||||
|
if v.Nested == nil {
|
||||||
|
v.Nested = new(VariableNestedContainer)
|
||||||
|
}
|
||||||
|
size += v.Nested.SizeSSZ()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashTreeRoot ssz hashes the VariableTestContainer object
|
||||||
|
func (v *VariableTestContainer) HashTreeRoot() ([32]byte, error) {
|
||||||
|
return ssz.HashWithDefaultHasher(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashTreeRootWith ssz hashes the VariableTestContainer object with a hasher
|
||||||
|
func (v *VariableTestContainer) HashTreeRootWith(hh *ssz.Hasher) (err error) {
|
||||||
|
indx := hh.Index()
|
||||||
|
|
||||||
|
// Field (0) 'LeadingField'
|
||||||
|
if size := len(v.LeadingField); size != 32 {
|
||||||
|
err = ssz.ErrBytesLengthFn("--.LeadingField", size, 32)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hh.PutBytes(v.LeadingField)
|
||||||
|
|
||||||
|
// Field (1) 'FieldListUint64'
|
||||||
|
{
|
||||||
|
if size := len(v.FieldListUint64); size > 2048 {
|
||||||
|
err = ssz.ErrListTooBigFn("--.FieldListUint64", size, 2048)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subIndx := hh.Index()
|
||||||
|
for _, i := range v.FieldListUint64 {
|
||||||
|
hh.AppendUint64(i)
|
||||||
|
}
|
||||||
|
hh.FillUpTo32()
|
||||||
|
|
||||||
|
numItems := uint64(len(v.FieldListUint64))
|
||||||
|
hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(2048, numItems, 8))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (2) 'FieldListContainer'
|
||||||
|
{
|
||||||
|
subIndx := hh.Index()
|
||||||
|
num := uint64(len(v.FieldListContainer))
|
||||||
|
if num > 128 {
|
||||||
|
err = ssz.ErrIncorrectListSize
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, elem := range v.FieldListContainer {
|
||||||
|
if err = elem.HashTreeRootWith(hh); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hh.MerkleizeWithMixin(subIndx, num, 128)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (3) 'Nested'
|
||||||
|
if err = v.Nested.HashTreeRootWith(hh); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field (4) 'TrailingField'
|
||||||
|
if size := len(v.TrailingField); size != 56 {
|
||||||
|
err = ssz.ErrBytesLengthFn("--.TrailingField", size, 56)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hh.PutBytes(v.TrailingField)
|
||||||
|
|
||||||
|
hh.Merkleize(indx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user