mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
SSZ-QL: Add endpoints (BeaconState/BeaconBlock) (#15888)
* Move ssz_query objects into testing folder (ensuring test objects only used in test environment) * Add containers for response * Export sszInfo * Add QueryBeaconState/Block * Add comments and few refactor * Fix merge conflict issues * Return 500 when calculate offset fails * Add test for QueryBeaconState * Add test for QueryBeaconBlock * Changelog :) * Rename `QuerySSZRequest` to `SSZQueryRequest` * Fix middleware hooks for RPC to accept JSON from client and return SSZ * Convert to `SSZObject` directly from proto * Move marshalling/calculating hash tree root part after `CalculateOffsetAndLength` * Make nogo happy * Add informing comment for using proto unsafe conversion --------- Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
@@ -31,7 +31,7 @@ go_test(
|
||||
deps = [
|
||||
":go_default_library",
|
||||
"//encoding/ssz/query/testutil:go_default_library",
|
||||
"//proto/ssz_query:go_default_library",
|
||||
"//proto/ssz_query/testing:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
const offsetBytes = 4
|
||||
|
||||
// AnalyzeObject analyzes given object and returns its SSZ information.
|
||||
func AnalyzeObject(obj SSZObject) (*sszInfo, error) {
|
||||
func AnalyzeObject(obj SSZObject) (*SszInfo, error) {
|
||||
value := reflect.ValueOf(obj)
|
||||
|
||||
info, err := analyzeType(value, nil)
|
||||
@@ -28,9 +28,9 @@ func AnalyzeObject(obj SSZObject) (*sszInfo, error) {
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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 reflect.Value) error {
|
||||
func PopulateVariableLengthInfo(sszInfo *SszInfo, value reflect.Value) error {
|
||||
if sszInfo == nil {
|
||||
return errors.New("sszInfo is nil")
|
||||
}
|
||||
@@ -124,7 +124,7 @@ func PopulateVariableLengthInfo(sszInfo *sszInfo, value reflect.Value) error {
|
||||
fieldInfo := containerInfo.fields[fieldName]
|
||||
childSszInfo := fieldInfo.sszInfo
|
||||
if childSszInfo == nil {
|
||||
return fmt.Errorf("sszInfo is nil for field %s", fieldName)
|
||||
return fmt.Errorf("SszInfo is nil for field %s", fieldName)
|
||||
}
|
||||
|
||||
// Skip fixed-size fields.
|
||||
@@ -158,7 +158,7 @@ func PopulateVariableLengthInfo(sszInfo *sszInfo, value reflect.Value) error {
|
||||
}
|
||||
|
||||
// analyzeType is an entry point that inspects a reflect.Value and computes its SSZ layout information.
|
||||
func analyzeType(value reflect.Value, tag *reflect.StructTag) (*sszInfo, error) {
|
||||
func analyzeType(value reflect.Value, tag *reflect.StructTag) (*SszInfo, error) {
|
||||
switch value.Kind() {
|
||||
// Basic types (e.g., uintN where N is 8, 16, 32, 64)
|
||||
// NOTE: uint128 and uint256 are represented as []byte in Go,
|
||||
@@ -182,7 +182,7 @@ func analyzeType(value reflect.Value, tag *reflect.StructTag) (*sszInfo, error)
|
||||
}
|
||||
|
||||
// analyzeBasicType analyzes SSZ basic types (uintN, bool) and returns its info.
|
||||
func analyzeBasicType(value reflect.Value) (*sszInfo, error) {
|
||||
func analyzeBasicType(value reflect.Value) (*SszInfo, error) {
|
||||
var sszType SSZType
|
||||
|
||||
switch value.Kind() {
|
||||
@@ -200,7 +200,7 @@ func analyzeBasicType(value reflect.Value) (*sszInfo, error) {
|
||||
return nil, fmt.Errorf("unsupported basic type %v for SSZ calculation", value.Kind())
|
||||
}
|
||||
|
||||
sszInfo := &sszInfo{
|
||||
sszInfo := &SszInfo{
|
||||
sszType: sszType,
|
||||
typ: value.Type(),
|
||||
|
||||
@@ -212,7 +212,7 @@ func analyzeBasicType(value reflect.Value) (*sszInfo, error) {
|
||||
}
|
||||
|
||||
// analyzeHomogeneousColType analyzes homogeneous collection types (e.g., List, Vector, Bitlist, Bitvector) and returns its SSZ info.
|
||||
func analyzeHomogeneousColType(value reflect.Value, tag *reflect.StructTag) (*sszInfo, error) {
|
||||
func analyzeHomogeneousColType(value reflect.Value, tag *reflect.StructTag) (*SszInfo, error) {
|
||||
if value.Kind() != reflect.Slice {
|
||||
return nil, fmt.Errorf("can only analyze slice types, got %v", value.Kind())
|
||||
}
|
||||
@@ -262,9 +262,9 @@ func analyzeHomogeneousColType(value reflect.Value, tag *reflect.StructTag) (*ss
|
||||
}
|
||||
|
||||
// analyzeListType analyzes SSZ List/Bitlist type and returns its SSZ info.
|
||||
func analyzeListType(value reflect.Value, elementInfo *sszInfo, limit uint64, isBitfield bool) (*sszInfo, error) {
|
||||
func analyzeListType(value reflect.Value, elementInfo *SszInfo, limit uint64, isBitfield bool) (*SszInfo, error) {
|
||||
if isBitfield {
|
||||
return &sszInfo{
|
||||
return &SszInfo{
|
||||
sszType: Bitlist,
|
||||
typ: value.Type(),
|
||||
|
||||
@@ -280,7 +280,7 @@ func analyzeListType(value reflect.Value, elementInfo *sszInfo, limit uint64, is
|
||||
return nil, errors.New("element info is required for List")
|
||||
}
|
||||
|
||||
return &sszInfo{
|
||||
return &SszInfo{
|
||||
sszType: List,
|
||||
typ: value.Type(),
|
||||
|
||||
@@ -294,9 +294,9 @@ func analyzeListType(value reflect.Value, elementInfo *sszInfo, limit uint64, is
|
||||
}
|
||||
|
||||
// analyzeVectorType analyzes SSZ Vector/Bitvector type and returns its SSZ info.
|
||||
func analyzeVectorType(value reflect.Value, elementInfo *sszInfo, length uint64, isBitfield bool) (*sszInfo, error) {
|
||||
func analyzeVectorType(value reflect.Value, elementInfo *SszInfo, length uint64, isBitfield bool) (*SszInfo, error) {
|
||||
if isBitfield {
|
||||
return &sszInfo{
|
||||
return &SszInfo{
|
||||
sszType: Bitvector,
|
||||
typ: value.Type(),
|
||||
|
||||
@@ -318,7 +318,7 @@ func analyzeVectorType(value reflect.Value, elementInfo *sszInfo, length uint64,
|
||||
return nil, fmt.Errorf("vector length must be greater than 0, got %d", length)
|
||||
}
|
||||
|
||||
return &sszInfo{
|
||||
return &SszInfo{
|
||||
sszType: Vector,
|
||||
typ: value.Type(),
|
||||
|
||||
@@ -332,7 +332,7 @@ func analyzeVectorType(value reflect.Value, elementInfo *sszInfo, length uint64,
|
||||
}
|
||||
|
||||
// analyzeContainerType analyzes SSZ Container type and returns its SSZ info.
|
||||
func analyzeContainerType(value reflect.Value) (*sszInfo, error) {
|
||||
func analyzeContainerType(value reflect.Value) (*SszInfo, error) {
|
||||
if value.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("can only analyze struct types, got %v", value.Kind())
|
||||
}
|
||||
@@ -386,7 +386,7 @@ func analyzeContainerType(value reflect.Value) (*sszInfo, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return &sszInfo{
|
||||
return &SszInfo{
|
||||
sszType: Container,
|
||||
typ: containerTyp,
|
||||
source: castToSSZObject(value),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package query
|
||||
|
||||
// containerInfo has
|
||||
// 1. fields: a field map that maps a field's JSON name to its sszInfo for nested Containers
|
||||
// 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
|
||||
// 3. fixedOffset: the total size of the fixed part of the container
|
||||
type containerInfo struct {
|
||||
@@ -12,7 +12,7 @@ type containerInfo struct {
|
||||
|
||||
type fieldInfo struct {
|
||||
// sszInfo contains the SSZ information of the field.
|
||||
sszInfo *sszInfo
|
||||
sszInfo *SszInfo
|
||||
// offset is the offset of the field within the parent struct.
|
||||
offset uint64
|
||||
// goFieldName is the name of the field in Go struct.
|
||||
|
||||
@@ -13,7 +13,7 @@ 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
|
||||
element *SszInfo
|
||||
// length is the actual number of elements at runtime (0 if not set).
|
||||
length uint64
|
||||
// elementSizes caches each element's byte size for variable-sized type elements
|
||||
@@ -27,7 +27,7 @@ func (l *listInfo) Limit() uint64 {
|
||||
return l.limit
|
||||
}
|
||||
|
||||
func (l *listInfo) Element() (*sszInfo, error) {
|
||||
func (l *listInfo) Element() (*SszInfo, error) {
|
||||
if l == nil {
|
||||
return nil, errors.New("listInfo is nil")
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
)
|
||||
|
||||
// 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) {
|
||||
// By walking the given path, it accumulates the offsets based on SszInfo.
|
||||
func CalculateOffsetAndLength(sszInfo *SszInfo, path []PathElement) (*SszInfo, uint64, uint64, error) {
|
||||
if sszInfo == nil {
|
||||
return nil, 0, 0, errors.New("sszInfo is nil")
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz/query"
|
||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz/query/testutil"
|
||||
sszquerypb "github.com/OffchainLabs/prysm/v6/proto/ssz_query"
|
||||
sszquerypb "github.com/OffchainLabs/prysm/v6/proto/ssz_query/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
)
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// sszInfo holds the all necessary data for analyzing SSZ data types.
|
||||
type sszInfo struct {
|
||||
// SszInfo holds the all necessary data for analyzing SSZ data types.
|
||||
type SszInfo struct {
|
||||
// Type of the SSZ structure (Basic, Container, List, etc.).
|
||||
sszType SSZType
|
||||
// Type in Go. Need this for unmarshaling.
|
||||
@@ -35,7 +35,7 @@ type sszInfo struct {
|
||||
bitvectorInfo *bitvectorInfo
|
||||
}
|
||||
|
||||
func (info *sszInfo) Size() uint64 {
|
||||
func (info *SszInfo) Size() uint64 {
|
||||
if info == nil {
|
||||
return 0
|
||||
}
|
||||
@@ -72,73 +72,73 @@ func (info *sszInfo) Size() uint64 {
|
||||
}
|
||||
}
|
||||
|
||||
func (info *sszInfo) ContainerInfo() (*containerInfo, error) {
|
||||
func (info *SszInfo) ContainerInfo() (*containerInfo, error) {
|
||||
if info == nil {
|
||||
return nil, errors.New("sszInfo is nil")
|
||||
return nil, errors.New("SszInfo is nil")
|
||||
}
|
||||
|
||||
if info.sszType != Container {
|
||||
return nil, fmt.Errorf("sszInfo is not a Container type, got %s", info.sszType)
|
||||
return nil, fmt.Errorf("SszInfo is not a Container type, got %s", info.sszType)
|
||||
}
|
||||
|
||||
if info.containerInfo == nil {
|
||||
return nil, errors.New("sszInfo.containerInfo is nil")
|
||||
return nil, errors.New("SszInfo.containerInfo is nil")
|
||||
}
|
||||
|
||||
return info.containerInfo, nil
|
||||
}
|
||||
|
||||
func (info *sszInfo) ListInfo() (*listInfo, error) {
|
||||
func (info *SszInfo) ListInfo() (*listInfo, error) {
|
||||
if info == nil {
|
||||
return nil, errors.New("sszInfo is 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 nil, fmt.Errorf("SszInfo is not a List type, got %s", info.sszType)
|
||||
}
|
||||
|
||||
return info.listInfo, nil
|
||||
}
|
||||
|
||||
func (info *sszInfo) VectorInfo() (*vectorInfo, error) {
|
||||
func (info *SszInfo) VectorInfo() (*vectorInfo, error) {
|
||||
if info == nil {
|
||||
return nil, errors.New("sszInfo is nil")
|
||||
return nil, errors.New("SszInfo is nil")
|
||||
}
|
||||
|
||||
if info.sszType != Vector {
|
||||
return nil, fmt.Errorf("sszInfo is not a Vector type, got %s", info.sszType)
|
||||
return nil, fmt.Errorf("SszInfo is not a Vector type, got %s", info.sszType)
|
||||
}
|
||||
|
||||
return info.vectorInfo, nil
|
||||
}
|
||||
|
||||
func (info *sszInfo) BitlistInfo() (*bitlistInfo, error) {
|
||||
func (info *SszInfo) BitlistInfo() (*bitlistInfo, error) {
|
||||
if info == nil {
|
||||
return nil, errors.New("sszInfo is nil")
|
||||
return nil, errors.New("SszInfo is nil")
|
||||
}
|
||||
|
||||
if info.sszType != Bitlist {
|
||||
return nil, fmt.Errorf("sszInfo is not a Bitlist type, got %s", info.sszType)
|
||||
return nil, fmt.Errorf("SszInfo is not a Bitlist type, got %s", info.sszType)
|
||||
}
|
||||
|
||||
return info.bitlistInfo, nil
|
||||
}
|
||||
|
||||
func (info *sszInfo) BitvectorInfo() (*bitvectorInfo, error) {
|
||||
func (info *SszInfo) BitvectorInfo() (*bitvectorInfo, error) {
|
||||
if info == nil {
|
||||
return nil, errors.New("sszInfo is nil")
|
||||
return nil, errors.New("SszInfo is nil")
|
||||
}
|
||||
|
||||
if info.sszType != Bitvector {
|
||||
return nil, fmt.Errorf("sszInfo is not a Bitvector type, got %s", info.sszType)
|
||||
return nil, fmt.Errorf("SszInfo is not a Bitvector type, got %s", info.sszType)
|
||||
}
|
||||
|
||||
return info.bitvectorInfo, nil
|
||||
}
|
||||
|
||||
// String implements the Stringer interface for sszInfo.
|
||||
// String implements the Stringer interface for SszInfo.
|
||||
// This follows the notation used in the consensus specs.
|
||||
func (info *sszInfo) String() string {
|
||||
func (info *SszInfo) String() string {
|
||||
if info == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
@@ -163,8 +163,8 @@ func (info *sszInfo) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// Print returns a string representation of the sszInfo, which is useful for debugging.
|
||||
func (info *sszInfo) Print() string {
|
||||
// Print returns a string representation of the SszInfo, which is useful for debugging.
|
||||
func (info *SszInfo) Print() string {
|
||||
if info == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
@@ -173,7 +173,7 @@ func (info *sszInfo) Print() string {
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func printRecursive(info *sszInfo, builder *strings.Builder, prefix string) {
|
||||
func printRecursive(info *SszInfo, builder *strings.Builder, prefix string) {
|
||||
var sizeDesc string
|
||||
if info.isVariable {
|
||||
sizeDesc = "Variable-size"
|
||||
|
||||
@@ -9,13 +9,13 @@ type SSZObject interface {
|
||||
|
||||
// HashTreeRoot calls the HashTreeRoot method on the stored interface if it implements SSZObject.
|
||||
// Returns the 32-byte hash tree root or an error if the interface doesn't support hashing.
|
||||
func (info *sszInfo) HashTreeRoot() ([32]byte, error) {
|
||||
func (info *SszInfo) HashTreeRoot() ([32]byte, error) {
|
||||
if info == nil {
|
||||
return [32]byte{}, errors.New("sszInfo is nil")
|
||||
return [32]byte{}, errors.New("SszInfo is nil")
|
||||
}
|
||||
|
||||
if info.source == nil {
|
||||
return [32]byte{}, errors.New("sszInfo.source is nil")
|
||||
return [32]byte{}, errors.New("SszInfo.source is nil")
|
||||
}
|
||||
|
||||
// Check if the value implements the Hashable interface
|
||||
|
||||
@@ -5,7 +5,7 @@ import "errors"
|
||||
// vectorInfo holds information about a SSZ Vector type.
|
||||
type vectorInfo struct {
|
||||
// element is the SSZ info of the vector's element type.
|
||||
element *sszInfo
|
||||
element *SszInfo
|
||||
// length is the fixed length of the vector.
|
||||
length uint64
|
||||
}
|
||||
@@ -18,7 +18,7 @@ func (v *vectorInfo) Length() uint64 {
|
||||
return v.length
|
||||
}
|
||||
|
||||
func (v *vectorInfo) Element() (*sszInfo, error) {
|
||||
func (v *vectorInfo) Element() (*SszInfo, error) {
|
||||
if v == nil {
|
||||
return nil, errors.New("vectorInfo is nil")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user