Documentation
¶
Overview ¶
dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.
Package dynssz provides dynamic SSZ (Simple Serialize) encoding and decoding for Ethereum data structures. Unlike static code generation approaches, dynssz uses runtime reflection to handle dynamic field sizes, making it suitable for various Ethereum presets beyond the mainnet. It seamlessly integrates with fastssz for optimal performance when static definitions are applicable.
Copyright (c) 2024 by pk910. See LICENSE file for details.
dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.
dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.
dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.
dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.
dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.
dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file implements cached type descriptors with unsafe pointer optimization. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.
dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.
Index ¶
- Variables
- func CalculateLimit(maxCapacity, numItems, size uint64) uint64
- type DynFieldDescriptor
- type DynSsz
- func (d *DynSsz) GetTypeCache() *TypeCache
- func (d *DynSsz) HashTreeRoot(source any) ([32]byte, error)
- func (d *DynSsz) MarshalSSZ(source any) ([]byte, error)
- func (d *DynSsz) MarshalSSZTo(source any, buf []byte) ([]byte, error)
- func (d *DynSsz) SizeSSZ(source any) (int, error)
- func (d *DynSsz) UnmarshalSSZ(target any, ssz []byte) error
- type FieldDescriptor
- type HashFn
- type HashWalker
- type Hasher
- func (h *Hasher) Append(i []byte)
- func (h *Hasher) AppendBytes32(b []byte)
- func (h *Hasher) AppendUint8(i uint8)
- func (h *Hasher) AppendUint32(i uint32)
- func (h *Hasher) AppendUint64(i uint64)
- func (h *Hasher) FillUpTo32()
- func (h *Hasher) Hash() []byte
- func (h *Hasher) HashRoot() (res [32]byte, err error)
- func (h *Hasher) Index() int
- func (h *Hasher) Merkleize(indx int)
- func (h *Hasher) MerkleizeWithMixin(indx int, num, limit uint64)
- func (h *Hasher) PutBitlist(bb []byte, maxSize uint64)
- func (h *Hasher) PutBool(b bool)
- func (h *Hasher) PutBytes(b []byte)
- func (h *Hasher) PutRootVector(b [][]byte, maxCapacity ...uint64) error
- func (h *Hasher) PutUint8(i uint8)
- func (h *Hasher) PutUint16(i uint16)
- func (h *Hasher) PutUint32(i uint32)
- func (h *Hasher) PutUint64(i uint64)
- func (h *Hasher) PutUint64Array(b []uint64, maxCapacity ...uint64)
- func (h *Hasher) Reset()
- type HasherPool
- type SszMaxSizeHint
- type SszSizeHint
- type TypeCache
- type TypeDescriptor
Constants ¶
This section is empty.
Variables ¶
var ( // ErrIncorrectByteSize means that the byte size is incorrect ErrIncorrectByteSize = fmt.Errorf("incorrect byte size") // ErrIncorrectListSize means that the size of the list is incorrect ErrIncorrectListSize = fmt.Errorf("incorrect list size") )
var ( ErrOffset = fmt.Errorf("incorrect offset") ErrSize = fmt.Errorf("incorrect size") ErrBytesLength = fmt.Errorf("bytes array does not have the correct length") ErrVectorLength = fmt.Errorf("vector does not have the correct length") ErrListTooBig = fmt.Errorf("list length is higher than max value") ErrEmptyBitlist = fmt.Errorf("bitlist is empty") ErrInvalidVariableOffset = fmt.Errorf("invalid ssz encoding. first variable element offset indexes into fixed value data") )
Functions ¶
func CalculateLimit ¶ added in v0.0.6
Types ¶
type DynFieldDescriptor ¶ added in v1.0.0
type DynFieldDescriptor struct {
Field *FieldDescriptor
Offset uint32
}
DynFieldDescriptor represents a dynamic field descriptor for a struct
type DynSsz ¶
type DynSsz struct {
// NoFastSsz disables the use of fastssz for static types.
// When true, all encoding/decoding uses reflection-based processing.
// Generally not recommended unless you need consistent behavior across all types.
NoFastSsz bool
// NoFastHash disables the use of optimized hash tree root calculation.
// When true, uses the standard hasher instead of the fast gohashtree implementation.
NoFastHash bool
// Verbose enables detailed logging of encoding/decoding operations.
// Useful for debugging but impacts performance.
Verbose bool
// contains filtered or unexported fields
}
DynSsz is a dynamic SSZ encoder/decoder that uses runtime reflection to handle dynamic field sizes. It provides flexible SSZ encoding/decoding for any Go data structures that can adapt to different specifications through dynamic field sizing. While commonly used with Ethereum data structures and presets (mainnet, minimal, custom), it works with any SSZ-compatible types.
The instance maintains caches for type descriptors and specification values to optimize performance. It's recommended to reuse the same DynSsz instance across operations to benefit from caching.
Key features:
- Hybrid approach: automatically uses fastssz for static types, reflection for dynamic types
- Type caching: reduces overhead for repeated operations on the same types
- Specification support: handles dynamic field sizes based on runtime specifications
- Thread-safe: can be safely used from multiple goroutines
Example usage:
specs := map[string]any{
"SLOTS_PER_HISTORICAL_ROOT": uint64(8192),
"SYNC_COMMITTEE_SIZE": uint64(512),
}
ds := dynssz.NewDynSsz(specs)
// Marshal
data, err := ds.MarshalSSZ(myStruct)
// Unmarshal
err = ds.UnmarshalSSZ(&myStruct, data)
// Hash tree root
root, err := ds.HashTreeRoot(myStruct)
func NewDynSsz ¶
NewDynSsz creates a new instance of the DynSsz encoder/decoder.
The specs map contains dynamic properties and configurations that control SSZ serialization and deserialization. These specifications allow the library to handle different configurations by defining dynamic field sizes at runtime. While commonly used with Ethereum presets (mainnet, minimal, custom), they can define any dynamic sizing parameters for your data structures.
For non-Ethereum use cases, you can define any specifications relevant to your data structures.
The library supports mathematical expressions in dynssz-size tags that reference these specification values, enabling complex dynamic sizing behavior.
Parameters:
- specs: A map of specification names to their values. Can be nil for default behavior.
Returns:
- *DynSsz: A new DynSsz instance ready for encoding/decoding operations
Example:
// Ethereum mainnet specifications
specs := map[string]any{
"SLOTS_PER_HISTORICAL_ROOT": uint64(8192),
"SYNC_COMMITTEE_SIZE": uint64(512),
}
ds := dynssz.NewDynSsz(specs)
// Custom application specifications
customSpecs := map[string]any{
"MAX_ITEMS": uint64(1000),
"BUFFER_SIZE": uint64(4096),
"CUSTOM_ARRAY_LENGTH": uint64(256),
}
dsCustom := dynssz.NewDynSsz(customSpecs)
func (*DynSsz) GetTypeCache ¶ added in v1.0.0
GetTypeCache returns the type cache for the DynSsz instance.
The type cache stores computed type descriptors for types used in encoding/decoding operations. Type descriptors contain optimized information about how to serialize/deserialize specific types, including field offsets, size information, and whether fastssz can be used.
This method is primarily useful for debugging, performance analysis, or advanced use cases where you need to inspect the cached type information.
Returns:
- *TypeCache: The type cache instance containing all cached type descriptors
Example:
ds := dynssz.NewDynSsz(specs) cache := ds.GetTypeCache() // Dump type descriptor for debugging json, err := cache.DumpTypeDescriptor(reflect.TypeOf(myStruct))
func (*DynSsz) HashTreeRoot ¶ added in v0.0.6
HashTreeRoot computes the hash tree root of the given source object. This method uses the default hasher pool to get a new hasher instance, builds the root from the source object, and returns the computed hash root. It returns the computed hash root and an error if the process fails.
func (*DynSsz) MarshalSSZ ¶
MarshalSSZ serializes the given source into its SSZ (Simple Serialize) representation.
This method dynamically handles the serialization of Go types to SSZ format, supporting both static and dynamic field sizes. For types without dynamic specifications, it automatically uses fastssz for optimal performance. For types with dynamic field sizes (based on runtime specifications), it uses reflection-based processing.
The method allocates a new byte slice for the result. For high-performance scenarios with frequent allocations, consider using MarshalSSZTo with a pre-allocated buffer.
Parameters:
- source: Any Go value to be serialized. Must be a type supported by SSZ encoding.
Returns:
- []byte: The SSZ-encoded data as a new byte slice
- error: An error if serialization fails due to unsupported types, encoding errors, or size mismatches
Supported types include:
- Basic types: bool, uint8, uint16, uint32, uint64
- Arrays and slices of supported types
- Structs with appropriate SSZ tags
- Pointers to supported types
- Types implementing fastssz.Marshaler interface
Example:
header := &phase0.BeaconBlockHeader{
Slot: 12345,
ProposerIndex: 42,
// ... other fields
}
data, err := ds.MarshalSSZ(header)
if err != nil {
log.Fatal("Failed to marshal:", err)
}
fmt.Printf("Encoded %d bytes\n", len(data))
func (*DynSsz) MarshalSSZTo ¶
MarshalSSZTo serializes the given source into its SSZ (Simple Serialize) representation and writes the output to the provided buffer. This method allows direct control over the serialization output buffer, allowing optimizations like buffer reuse. The 'source' parameter is the structure to be serialized, and 'buf' is the pre-allocated slice where the serialized data will be written. It dynamically handles serialization for types with dynamic field sizes, seamlessly integrating with fastssz when possible. Returns the updated buffer containing the serialized data and an error if serialization fails.
func (*DynSsz) SizeSSZ ¶
SizeSSZ calculates the size of the given source object when serialized using SSZ encoding. This function is useful for pre-determining the amount of space needed to serialize a given source object. The 'source' parameter can be any Go value. It dynamically evaluates the size, accommodating types with dynamic field sizes efficiently. Returns the calculated size as an int and an error if the process fails.
func (*DynSsz) UnmarshalSSZ ¶
UnmarshalSSZ decodes the given SSZ-encoded data into the target object. The 'ssz' byte slice contains the SSZ-encoded data, and 'target' is a pointer to the Go value that will hold the decoded data. This method dynamically handles the decoding, accommodating for types with dynamic field sizes. It seamlessly integrates with fastssz for types without dynamic specifications to ensure efficient decoding. Returns an error if decoding fails or if the provided ssz data has not been fully used for decoding.
type FieldDescriptor ¶ added in v1.0.0
type FieldDescriptor struct {
Name string
Offset uintptr // Unsafe offset within the struct
Type *TypeDescriptor // Type descriptor
Index int16 // Index of the field in the struct
Size int32 // SSZ size (-1 if dynamic)
IsPtr bool // Whether field is a pointer
IsDynamic bool // Whether field has dynamic size
}
FieldDescriptor represents a cached descriptor for a struct field
type HashFn ¶ added in v0.0.6
func NativeHashWrapper ¶ added in v0.0.6
NativeHashWrapper wraps a hash.Hash function into a HashFn
type HashWalker ¶ added in v1.0.0
type HashWalker interface {
// Hash returns the latest hash generated during merkleize
Hash() []byte
// Methods for appending single values
AppendUint8(i uint8)
AppendUint32(i uint32)
AppendUint64(i uint64)
AppendBytes32(b []byte)
// Methods for putting values into the buffer
PutUint64Array(b []uint64, maxCapacity ...uint64)
PutUint64(i uint64)
PutUint32(i uint32)
PutUint16(i uint16)
PutUint8(i uint8)
PutBitlist(bb []byte, maxSize uint64)
PutBool(b bool)
PutBytes(b []byte)
// Buffer manipulation methods
FillUpTo32()
Append(i []byte)
Index() int
// Merkleization methods
Merkleize(indx int)
MerkleizeWithMixin(indx int, num, limit uint64)
}
HashWalker is our own interface that mirrors fastssz.HashWalker This allows us to avoid importing fastssz directly while still being compatible with types that implement HashTreeRootWith
type Hasher ¶ added in v0.0.6
type Hasher struct {
// contains filtered or unexported fields
}
Hasher is a utility tool to hash SSZ structs
func NewHasher ¶ added in v0.0.6
func NewHasher() *Hasher
NewHasher creates a new Hasher object with sha256 hash
func NewHasherWithHash ¶ added in v0.0.6
NewHasherWithHash creates a new Hasher object with a custom hash.Hash function
func NewHasherWithHashFn ¶ added in v0.0.6
NewHasherWithHashFn creates a new Hasher object with a custom HashFn function
func (*Hasher) AppendBytes32 ¶ added in v0.0.6
func (*Hasher) AppendUint8 ¶ added in v0.0.6
func (*Hasher) AppendUint32 ¶ added in v0.0.6
func (*Hasher) AppendUint64 ¶ added in v0.0.6
func (*Hasher) FillUpTo32 ¶ added in v0.0.6
func (h *Hasher) FillUpTo32()
func (*Hasher) Merkleize ¶ added in v0.0.6
Merkleize is used to merkleize the last group of the hasher
func (*Hasher) MerkleizeWithMixin ¶ added in v0.0.6
MerkleizeWithMixin is used to merkleize the last group of the hasher
func (*Hasher) PutBitlist ¶ added in v0.0.6
PutBitlist appends a ssz bitlist
func (*Hasher) PutRootVector ¶ added in v0.0.6
PutRootVector appends an array of roots
func (*Hasher) PutUint64Array ¶ added in v0.0.6
PutUint64Array appends an array of uint64
type HasherPool ¶ added in v0.0.6
type HasherPool struct {
HashFn HashFn
// contains filtered or unexported fields
}
HasherPool may be used for pooling Hashers for similarly typed SSZs.
var DefaultHasherPool HasherPool
DefaultHasherPool is a default hasher pool
var FastHasherPool HasherPool = HasherPool{ HashFn: gohashtree.HashByteSlice, }
func (*HasherPool) Get ¶ added in v0.0.6
func (hh *HasherPool) Get() *Hasher
Get acquires a Hasher from the pool.
func (*HasherPool) Put ¶ added in v0.0.6
func (hh *HasherPool) Put(h *Hasher)
Put releases the Hasher to the pool.
type SszMaxSizeHint ¶ added in v1.0.0
type SszSizeHint ¶ added in v1.0.0
type TypeCache ¶ added in v1.0.0
type TypeCache struct {
// contains filtered or unexported fields
}
TypeCache manages cached type descriptors
func NewTypeCache ¶ added in v1.0.0
NewTypeCache creates a new type cache
func (*TypeCache) DumpAllCachedTypes ¶ added in v1.0.0
DumpAllCachedTypes returns a JSON representation of all cached type descriptors
func (*TypeCache) DumpTypeDescriptor ¶ added in v1.0.0
DumpTypeDescriptor returns a JSON representation of a type descriptor for debugging
func (*TypeCache) GetTypeDescriptor ¶ added in v1.0.0
func (tc *TypeCache) GetTypeDescriptor(t reflect.Type, sizeHints []SszSizeHint, maxSizeHints []SszMaxSizeHint) (*TypeDescriptor, error)
GetTypeDescriptor returns a cached type descriptor, computing it if necessary, ensuring sequential processing
type TypeDescriptor ¶ added in v1.0.0
type TypeDescriptor struct {
Kind reflect.Kind
Type reflect.Type
Size int32 // SSZ size (-1 if dynamic)
Len uint32 // Length of array/slice
Fields []FieldDescriptor // For structs
DynFields []DynFieldDescriptor // Dynamic struct fields
ElemDesc *TypeDescriptor // For slices/arrays
SizeHints []SszSizeHint // Size hints from tags
MaxSizeHints []SszMaxSizeHint // Max size hints from tags
HasDynamicSize bool // Whether this type uses dynamic spec size value that differs from the default
HasDynamicMax bool // Whether this type uses dynamic spec max value that differs from the default
IsFastSSZMarshaler bool // Whether the type implements fastssz.Marshaler
IsFastSSZHasher bool // Whether the type implements fastssz.HashRoot
HasHashTreeRootWith bool // Whether the type implements HashTreeRootWith
IsPtr bool // Whether this is a pointer type
IsByteArray bool // Whether this is a byte array
}
TypeDescriptor represents a cached, optimized descriptor for a type's SSZ encoding/decoding