mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 23:18:15 -05:00
* updated path processing data types, refactored ParsePath and fixed tests * updated generalized index accordingly, changed input parameter path type from []PathElemen to Path * updated query.go accordingly, changed input parameter path type from []PathElemen to Path * added descriptive changelog * Update encoding/ssz/query/path.go Co-authored-by: Jun Song <87601811+syjn99@users.noreply.github.com> * Added documentation for Path struct and renamed to for clarity * Update encoding/ssz/query/path.go Co-authored-by: Radosław Kapka <radoslaw.kapka@gmail.com> * updated changelog to its correct type: Changed * updated outdated comment in generalized_index.go and removed test in generalized_index_test.go as this one belongs in path_test.go * Added validateRawPath with strict raw-path validation only - no raw-path fixing is added. Added test suite covering * added extra tests for wrongly formated paths --------- Co-authored-by: Jun Song <87601811+syjn99@users.noreply.github.com> Co-authored-by: Radosław Kapka <radoslaw.kapka@gmail.com> Co-authored-by: Radosław Kapka <rkapka@wp.pl>
84 lines
2.6 KiB
Go
84 lines
2.6 KiB
Go
package query
|
|
|
|
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 Path) (*SszInfo, uint64, uint64, error) {
|
|
if sszInfo == nil {
|
|
return nil, 0, 0, errors.New("sszInfo is nil")
|
|
}
|
|
|
|
if len(path.Elements) == 0 {
|
|
return nil, 0, 0, errors.New("path is empty")
|
|
}
|
|
|
|
walk := sszInfo
|
|
offset := uint64(0)
|
|
|
|
for pathIndex, elem := range path.Elements {
|
|
containerInfo, err := walk.ContainerInfo()
|
|
if err != nil {
|
|
return nil, 0, 0, fmt.Errorf("could not get field infos: %w", err)
|
|
}
|
|
|
|
fieldInfo, exists := containerInfo.fields[elem.Name]
|
|
if !exists {
|
|
return nil, 0, 0, fmt.Errorf("field %s not found in containerInfo", elem.Name)
|
|
}
|
|
|
|
offset += fieldInfo.offset
|
|
walk = fieldInfo.sszInfo
|
|
|
|
// Check for accessing List/Vector elements by index
|
|
if elem.Index != nil {
|
|
switch walk.sszType {
|
|
case List:
|
|
index := *elem.Index
|
|
listInfo := walk.listInfo
|
|
if index >= listInfo.length {
|
|
return nil, 0, 0, fmt.Errorf("index %d out of bounds for field %s with size %d", index, elem.Name, listInfo.length)
|
|
}
|
|
|
|
walk = listInfo.element
|
|
if walk.isVariable {
|
|
// Cumulative sum of sizes of previous elements to get the offset.
|
|
for i := range index {
|
|
offset += listInfo.elementSizes[i]
|
|
}
|
|
|
|
// NOTE: When populating recursively, the shared element template is updated for each
|
|
// list item, causing it to retain the size information of the last processed element.
|
|
// This wouldn't be an issue if this is in the middle of the path, as the walk would be updated
|
|
// to the next field's sszInfo, which would have the correct size information.
|
|
// However, if this is the last element in the path, we need to ensure we return the correct size
|
|
// for the indexed element. Hence, we return the size from elementSizes.
|
|
if pathIndex == len(path.Elements)-1 {
|
|
return walk, offset, listInfo.elementSizes[index], nil
|
|
}
|
|
} else {
|
|
offset += index * listInfo.element.Size()
|
|
}
|
|
|
|
case Vector:
|
|
index := *elem.Index
|
|
vectorInfo := walk.vectorInfo
|
|
if index >= vectorInfo.length {
|
|
return nil, 0, 0, fmt.Errorf("index %d out of bounds for field %s with size %d", index, elem.Name, vectorInfo.length)
|
|
}
|
|
|
|
offset += index * vectorInfo.element.Size()
|
|
walk = vectorInfo.element
|
|
|
|
default:
|
|
return nil, 0, 0, fmt.Errorf("field %s of type %s does not support index access", elem.Name, walk.sszType)
|
|
}
|
|
}
|
|
}
|
|
|
|
return walk, offset, walk.Size(), nil
|
|
}
|