sszutils

package
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: Apache-2.0 Imports: 12 Imported by: 5

Documentation ¶

Overview ¶

Package sszutils provides shared interfaces, encoding/decoding primitives, and utility functions for SSZ (Simple Serialize) operations.

It defines the core interfaces used across the dynamic-ssz library: encoder/decoder abstractions for both buffer and stream modes, hash walker for merkle tree computation, and compatibility interfaces for interoperating with fastssz and dynamic SSZ implementations.

Index ¶

Constants ¶

View Source
const DefaultMaxStreamSize = 512 * 1024 * 1024

DefaultMaxStreamSize is the default upper bound on the total size of an SSZ payload decoded without a known length. Unknown-length decoding is always byte-bounded: the allowance keeps an endless input — and any decode site that has not been taught about open regions — from driving an unbounded wire allocation. It does not bound read time or decoded-object memory.

View Source
const DefaultStreamDecoderBufSize = 2 * 1024

DefaultStreamDecoderBufSize is the default maximum buffer size for StreamDecoder (2KB).

View Source
const DefaultStreamEncoderBufSize = 2 * 1024

DefaultStreamEncoderBufSize is the default internal write buffer size for StreamEncoder (2KB).

View Source
const MaxSszSize = min(math.MaxUint32, math.MaxInt)

MaxSszSize is the largest byte size the library describes. SSZ offsets are 32-bit, so no size a valid encoding refers to passes 2^32-1; on a host whose int is narrower the int bound applies instead. Declared sizes, spec values that size a type, vector byte sizes and container fixed sections are refused past it at analysis and at spec resolution, so a product of two such sizes fits a uint64 and a sum of them fits the platform int without further checks.

Variables ¶

View Source
var (
	// ErrUnexpectedEOF is returned when the SSZ input is shorter than the
	// type requires (e.g. not enough bytes to decode a uint64).
	ErrUnexpectedEOF = fmt.Errorf("unexpected end of SSZ")

	// ErrNegativeRead is returned when an io.Reader violates the io.Reader
	// contract by reporting a negative byte count.
	ErrNegativeRead = fmt.Errorf("reader returned negative byte count")

	// ErrOffset is returned when an SSZ offset is out of range, does not
	// monotonically increase, or a field does not consume exactly the
	// byte range its offset pair implied.
	ErrOffset = fmt.Errorf("incorrect offset")

	// ErrInvalidValueRange is returned when an SSZ value is outside the
	// valid domain for its type (e.g. non-zero padding bits in a
	// bitvector, unterminated bitlist, or invalid union selector).
	ErrInvalidValueRange = fmt.Errorf("invalid value range")

	// ErrVectorLength is returned when a vector or fixed-length byte
	// array has a length that does not match the schema.
	ErrVectorLength = fmt.Errorf("incorrect vector length")

	// ErrListTooBig is returned when a list's length exceeds its declared
	// SSZ maximum.
	ErrListTooBig = fmt.Errorf("list length is higher than max value")

	// ErrNotImplemented is returned when the SSZ codec encounters a Go
	// type or feature it does not support.
	ErrNotImplemented = fmt.Errorf("not implemented")

	// ErrStreamTooLarge is returned when decoding a stream of unknown length
	// would consume more bytes than the decoder's configured maximum. Unknown-
	// length decoding is always bounded; see WithMaxStreamSize.
	ErrStreamTooLarge = fmt.Errorf("ssz stream exceeds maximum size")

	// ErrPayloadTooLarge narrows ErrStreamTooLarge to the case where a
	// caller-supplied read cap was exceeded, as opposed to the decoder's global
	// stream allowance. Both causes are "too large", so this wraps
	// ErrStreamTooLarge and carries its message unchanged; decoders match on it
	// to tell an ssz-max violation apart from a stream-allowance violation
	// instead of attributing every overrun to the schema limit.
	ErrPayloadTooLarge = fmt.Errorf("%w", ErrStreamTooLarge)

	// ErrPlatformOverflow is returned when a SSZ length or count exceeds
	// the platform's integer range (>31-bit sizes on 32-bit platforms).
	ErrPlatformOverflow = fmt.Errorf("value exceeds platform integer range")

	// ErrSszSizeExceeded is returned when a size passes the largest size the
	// 4-byte SSZ offset can express, which no target encodes. A size only this
	// target cannot hold is ErrPlatformOverflow instead.
	ErrSszSizeExceeded = fmt.Errorf("ssz size exceeds the maximum encodable size")

	// ErrChunkLimitExceeded is returned when a walk merkleizes more chunks
	// than the limit it was given holds. Both engines refuse an over-capacity
	// value before it reaches a walker, so the surplus comes from a hash
	// method that left more than one leaf per value.
	ErrChunkLimitExceeded = fmt.Errorf("merkleized more chunks than the limit holds")

	// ErrMaxDepthExceeded is returned when a value nests deeper than the
	// configured maximum. Only recursive types can reach an input-controlled
	// depth; the bound turns what would be an unrecoverable stack overflow into
	// an error the caller can handle. See WithMaxNestingDepth.
	ErrMaxDepthExceeded = fmt.Errorf("maximum nesting depth exceeded")

	// ErrBitlistNotTerminated is an alias for ErrInvalidValueRange,
	// retained for backward compatibility. New code should use
	// ErrInvalidValueRange with a descriptive message instead.
	ErrBitlistNotTerminated = ErrInvalidValueRange

	// ErrInvalidUnionVariant is an alias for ErrInvalidValueRange,
	// retained for backward compatibility. New code should use
	// ErrInvalidValueRange with a descriptive message instead.
	ErrInvalidUnionVariant = ErrInvalidValueRange
)

Sentinel errors for SSZ operations. Downstream consumers can check error categories via errors.Is(err, sszutils.ErrOffset) etc.

View Source
var (
	// ErrUnsupportedType is returned when a Go type kind is fundamentally
	// incompatible with SSZ (e.g. maps, channels, functions, interfaces).
	ErrUnsupportedType = fmt.Errorf("unsupported type")

	// ErrTypeMismatch is returned when the SSZ type assigned via tag or
	// auto-detection does not match the Go type's kind (e.g. ssz-type:"uint64"
	// on a bool field).
	ErrTypeMismatch = fmt.Errorf("type mismatch")

	// ErrInvalidTag is returned when a struct tag is malformed or contains
	// an unrecognized value (e.g. ssz-type:"foobar", non-numeric ssz-size).
	ErrInvalidTag = fmt.Errorf("invalid tag")

	// ErrInvalidConstraint is returned when tag values are syntactically
	// valid but semantically wrong (e.g. ssz-size:2 on a bool, bit-size on
	// a non-bitvector, vector size exceeding array length, duplicate ssz-index).
	ErrInvalidConstraint = fmt.Errorf("invalid constraint")

	// ErrExtendedTypeDisabled is returned when an extended SSZ type (signed
	// integers, floats, optionals, big.Int) is used without enabling the
	// ExtendedTypes flag on the TypeCache.
	ErrExtendedTypeDisabled = fmt.Errorf("extended type not enabled")

	// ErrScopeShapeMismatch is returned when a hashing scope is reduced in a
	// different tree shape than it was opened for: opened for the progressive
	// shape and reduced as a binary tree, or the reverse. The two shapes
	// disagree about what the accumulated chunks mean, so the reduction has no
	// defined answer -- for a progressive scope reduced as binary it even
	// depends on the collapse hints received, which are optional by contract.
	// A scope that declares no shape, opened with Index or with
	// TreeTypeNone, may be reduced either way: that is how generated code
	// before StartTree spells a progressive container.
	ErrScopeShapeMismatch = fmt.Errorf("scope reduced in a shape it was not opened for")

	// ErrMissingInterface is returned when a required method or interface
	// is not found on a type (e.g. missing GetDescriptorType method,
	// custom type without fastssz marshaler/hasher).
	ErrMissingInterface = fmt.Errorf("missing interface")
)

Sentinel errors for type introspection (type cache / descriptor building). These are returned during schema analysis of Go types, not at marshal/unmarshal time. Check with errors.Is(err, sszutils.ErrUnsupportedType) etc.

Functions ¶

func Annotate ¶ added in v1.3.0

func Annotate[T any](tag string) bool

Annotate registers SSZ annotations for a named (non-struct) type T. The tag string uses the same format as Go struct field tags:

var _ = sszutils.Annotate[BlobKZGCommitments](`ssz-max:"4096"`)
var _ = sszutils.Annotate[BlobKZGCommitments](`ssz-max:"4096" dynssz-max:"MAX_BLOB_COMMITMENTS"`)

This is the canonical way to attach SSZ metadata to non-struct types that lack struct field tags. Both the reflection path and the code generator consume these annotations.

Call this at package level (var block or init function) so the annotation is registered before any marshal/unmarshal/codegen operation.

func AppendZeroPadding ¶

func AppendZeroPadding(buf []byte, count int) []byte

AppendZeroPadding appends the specified number of zero bytes to buf

func ByteSlice ¶ added in v1.4.0

func ByteSlice[T ~uint8](s []T) []byte

ByteSlice returns s viewed as a []byte without copying: T has the memory layout of byte, so both slices share the backing array.

func BytesAs ¶ added in v1.4.0

func BytesAs[T ~uint8](b []byte) []T

BytesAs returns b viewed as a []T without copying: T has the memory layout of byte, so both slices share the backing array.

func CalculateBitlistLimit ¶ added in v1.3.2

func CalculateBitlistLimit(maxSize uint64) uint64

CalculateBitlistLimit computes the merkle tree chunk limit for a bitlist with the given maximum bit capacity as ceil(maxSize/256). The computation avoids the uint64 overflow that a naive (maxSize+255)/256 hits near math.MaxUint64, which would otherwise collapse a huge limit to a tiny one and make unrelated bitlist types share a merkleization depth and collide.

func CalculateLimit ¶

func CalculateLimit(maxCapacity, numItems, size uint64) uint64

CalculateLimit computes the merkle tree chunk limit for a list or vector given its maximum capacity, current number of items, and per-item byte size.

ceil(maxCapacity*size/32) is computed in 128-bit so a large ssz-max cannot overflow uint64 and collapse to a small limit (which would make unrelated list types share a merkleization depth and collide).

func CapToInt ¶ added in v1.4.0

func CapToInt(v uint64) int

CapToInt caps a uint64 value to the platform integer range. Allocation capacities and read caps derived from SSZ limits pass through int while the limits themselves span the full uint64 range; nothing above math.MaxInt is reachable in memory, so the cap loses nothing.

func CredibleCount ¶ added in v1.4.0

func CredibleCount(dec Decoder, count, elemSize int) int

CredibleCount returns the count an allocation may be sized from.

When the region's extent is known (a buffer, a stream whose length the caller declared, or a region that fits in the bytes already read) the declared count is returned unchanged. In unknown-length mode the count is only a claim until the bytes behind it arrive, so it is clamped to what the bytes already read account for at elemSize bytes per element, and callers grow the allocation as the rest arrives.

func DecodeByteListInto ¶ added in v1.4.0

func DecodeByteListInto(dec Decoder, dst []byte, maxLen int) ([]byte, error)

DecodeByteListInto consumes a byte list that runs to the end of the current region. When the length is known the destination slice is reused; otherwise the payload is read to EOF. maxLen caps the result (-1 for no cap) and is applied before the payload is allocated.

func DecodeDelegateBuffer ¶ added in v1.4.0

func DecodeDelegateBuffer(dec Decoder, size int) ([]byte, error)

DecodeDelegateBuffer materialises the region a buffer-based delegate needs. A delegate takes a []byte and so cannot consume an open region incrementally. size < 0 means "the whole region", which for an open region means reading to EOF.

func DecodeUint64ListInto ¶ added in v1.4.0

func DecodeUint64ListInto[T ~uint64](dec Decoder, dst []T, maxLen int) ([]T, error)

DecodeUint64ListInto consumes a uint64 list that runs to the end of the current region, reusing dst when the length is known and growing to EOF otherwise. maxLen caps the element count (-1 for no cap).

func DecodeUint64Slice ¶ added in v1.3.0

func DecodeUint64Slice[T ~uint64](dec Decoder, dst []T) error

DecodeUint64Slice decodes uint64 values from a Decoder directly into dst using bulk memory copy. On little-endian architectures (x86, ARM64) this avoids per-element DecodeUint64 overhead. Big-endian architectures decode each element individually.

func EncodeUint64Slice ¶ added in v1.3.0

func EncodeUint64Slice[T ~uint64](enc Encoder, s []T)

EncodeUint64Slice encodes a uint64 slice to an Encoder using bulk memory copy. On little-endian architectures (x86, ARM64) this avoids per-element EncodeUint64 overhead. Big-endian architectures encode each element individually to keep the SSZ output little-endian.

func ErrBigIntTypeExpectedFn ¶ added in v1.3.0

func ErrBigIntTypeExpectedFn(got any) error

ErrBigIntTypeExpectedFn is returned when a BigInt SSZ field does not hold a big.Int value.

func ErrBitlistBytesFn ¶ added in v1.4.0

func ErrBitlistBytesFn(regionBytes, capacityBytes, limit any) error

ErrBitlistBytesFn is returned when a bitlist's encoded byte region already exceeds the byte capacity of its declared bit limit, before the terminator (and thus the exact bit count) has been read.

func ErrBitlistLengthFn ¶ added in v1.3.0

func ErrBitlistLengthFn(length, limit any) error

ErrBitlistLengthFn is returned when a bitlist's bit count exceeds the declared maximum.

func ErrBitlistNotTerminatedFn ¶ added in v1.3.0

func ErrBitlistNotTerminatedFn() error

ErrBitlistNotTerminatedFn is returned when a bitlist is missing its mandatory termination bit.

func ErrBitvectorPaddingFn ¶ added in v1.3.0

func ErrBitvectorPaddingFn() error

ErrBitvectorPaddingFn is returned when a bitvector's padding bits (above the declared bit-size) are non-zero.

func ErrByteVectorEOFFn ¶ added in v1.3.0

func ErrByteVectorEOFFn(have, needed any) error

ErrByteVectorEOFFn is returned when the buffer is too short for a byte vector / byte array.

func ErrChunkLimitFn ¶ added in v1.4.0

func ErrChunkLimitFn(count, limit any) error

ErrChunkLimitFn names the chunk count a walk reduced and the limit it was given for it.

func ErrCustomTypeNotSupportedFn ¶ added in v1.3.0

func ErrCustomTypeNotSupportedFn() error

ErrCustomTypeNotSupportedFn is returned when codegen encounters a custom type that cannot be handled by the code generator.

func ErrElementOffsetOutOfRangeFn ¶ added in v1.3.0

func ErrElementOffsetOutOfRangeFn(end, start, limit any) error

ErrElementOffsetOutOfRangeFn is returned when a dynamic collection element's offset is out of the valid data range.

func ErrFieldNotConsumedFn ¶ added in v1.3.0

func ErrFieldNotConsumedFn(pos, expected any) error

ErrFieldNotConsumedFn is returned when a static-size field did not advance the decoder position by exactly the expected amount.

func ErrFirstOffsetMismatchFn ¶ added in v1.3.0

func ErrFirstOffsetMismatchFn(offset, expected any) error

ErrFirstOffsetMismatchFn is returned when the first dynamic field's offset does not equal the expected static-part length.

func ErrFixedFieldsEOFFn ¶ added in v1.3.0

func ErrFixedFieldsEOFFn(have, needed any) error

ErrFixedFieldsEOFFn is returned when the buffer is too short for the fixed-size portion of a container.

func ErrInvalidBoolValueFn ¶ added in v1.3.0

func ErrInvalidBoolValueFn() error

ErrInvalidBoolValueFn is returned when a bool byte is neither 0 nor 1.

func ErrInvalidListStartOffsetFn ¶ added in v1.3.0

func ErrInvalidListStartOffsetFn(offset, bufLen any) error

ErrInvalidListStartOffsetFn is returned when the first offset in a dynamic list is malformed (not a multiple of 4 or out of range).

func ErrInvalidUnionVariantFn ¶ added in v1.3.0

func ErrInvalidUnionVariantFn() error

ErrInvalidUnionVariantFn is returned when a union selector byte does not match any declared variant.

func ErrLargeUintLengthFn ¶ added in v1.3.0

func ErrLargeUintLengthFn(got, expected any) error

ErrLargeUintLengthFn is returned when a uint128/uint256 backing array has an unexpected byte length.

func ErrListLengthFn ¶ added in v1.3.0

func ErrListLengthFn(length, limit any) error

ErrListLengthFn is returned when a list's element count exceeds the declared maximum.

func ErrListNotAlignedFn ¶ added in v1.3.0

func ErrListNotAlignedFn(length, elemSize any) error

ErrListNotAlignedFn is returned when a list's byte length is not an exact multiple of the element size.

func ErrListOffsetsEOFFn ¶ added in v1.3.0

func ErrListOffsetsEOFFn(have, needed any) error

ErrListOffsetsEOFFn is returned when the buffer is too short for the list offset table.

func ErrListRegionTooSmallFn ¶ added in v1.4.0

func ErrListRegionTooSmallFn(count, minElemSize, available any) error

ErrListRegionTooSmallFn is returned when a dynamic list's offset table declares more elements than the region can physically hold. The table costs four bytes per element and each body costs at least the element's fixed section, so a count above (regionBytes - tableBytes) / minElemSize describes bodies that cannot exist. Rejecting it here keeps a compact offset table from sizing an allocation that the element decode would only fail afterwards.

func ErrMaxDepthExceededFn ¶ added in v1.4.0

func ErrMaxDepthExceededFn(maxDepth any) error

ErrMaxDepthExceededFn is returned when a value nests deeper than the configured maximum.

func ErrNeedBytesFn ¶ added in v1.3.0

func ErrNeedBytesFn(needed int, typeName string) error

ErrNeedBytesFn is returned when a primitive type cannot be decoded because the buffer is too short (e.g. "need 4 bytes for uint32").

func ErrOffsetOutOfRangeFn ¶ added in v1.3.0

func ErrOffsetOutOfRangeFn(offset, prev, limit any) error

ErrOffsetOutOfRangeFn is returned when a field offset is not monotonically increasing or exceeds the data bounds.

func ErrOffsetOverflowFn ¶ added in v1.4.0

func ErrOffsetOverflowFn(offset any) error

ErrOffsetOverflowFn is returned when a computed offset exceeds the 4-byte SSZ offset range, i.e. the encoded object grew past 2^32-1 bytes.

func ErrOptionalFlagEOFFn ¶ added in v1.3.0

func ErrOptionalFlagEOFFn() error

ErrOptionalFlagEOFFn is returned when there is no byte available to read the optional presence flag.

func ErrOptionalValueEOFFn ¶ added in v1.3.0

func ErrOptionalValueEOFFn() error

ErrOptionalValueEOFFn is returned when the buffer is too short for an optional value.

func ErrPayloadTooLargeFn ¶ added in v1.4.0

func ErrPayloadTooLargeFn(length, maxLen any) error

ErrPayloadTooLargeFn is returned when a region consumed to its end (or to EOF) is larger than the caller-supplied maximum.

func ErrPlatformOverflowFn ¶ added in v1.3.0

func ErrPlatformOverflowFn(description string, value any) error

ErrPlatformOverflowFn is returned when a SSZ size or count exceeds the platform's integer range (e.g. >31 bits on 32-bit systems). A value past the SSZ size limit is past every target's reach, not only this one's, so it is reported as the size limit instead. A value of no integer type states no width to weigh, so it is reported against the platform's range.

func ErrPlatformOverflowWidthFn ¶ added in v1.4.0

func ErrPlatformOverflowWidthFn(description string, width uint64) error

ErrPlatformOverflowWidthFn is ErrPlatformOverflowFn for a width already held as a number. Handing one to an any parameter puts it on the heap, and the sites that report this are reached from the walks, so they state the width as a width.

func ErrSszSizeLimitFn ¶ added in v1.4.0

func ErrSszSizeLimitFn(description string, value, elemWidth uint64) error

ErrSszSizeLimitFn is returned when a declared count of elemWidth-byte units states a size past the SSZ size limit. The size is value*elemWidth, weighed by dividing the limit instead of forming it, so a product wide enough to pass the limit cannot wrap before it names the condition it belongs to.

func ErrStaticElementNotConsumedFn ¶ added in v1.3.0

func ErrStaticElementNotConsumedFn(pos, expected any) error

ErrStaticElementNotConsumedFn is returned when a static collection element did not advance the decoder position by exactly the expected amount.

func ErrStreamTooLargeFn ¶ added in v1.4.0

func ErrStreamTooLargeFn(maxSize any) error

ErrStreamTooLargeFn is returned when a stream of unknown length exceeds the decoder's configured maximum stream size.

func ErrTimeTypeExpectedFn ¶ added in v1.3.0

func ErrTimeTypeExpectedFn(got any) error

ErrTimeTypeExpectedFn is returned when a uint64-backed time field does not hold a time.Time value.

func ErrTrailingDataFn ¶ added in v1.3.0

func ErrTrailingDataFn(trailing any) error

ErrTrailingDataFn is returned when a dynamic field or element has unconsumed bytes after decoding.

func ErrUnionSelectorEOFFn ¶ added in v1.3.0

func ErrUnionSelectorEOFFn() error

ErrUnionSelectorEOFFn is returned when there is no byte available to read the union selector.

func ErrUnionTypeMismatchFn ¶ added in v1.3.0

func ErrUnionTypeMismatchFn() error

ErrUnionTypeMismatchFn is returned when the concrete type stored in a union's Data field does not match the expected variant type.

func ErrUnionVariantEOFFn ¶ added in v1.3.0

func ErrUnionVariantEOFFn(have, needed any) error

ErrUnionVariantEOFFn is returned when the buffer is too short for a union variant value.

func ErrUnknownTypeFn ¶ added in v1.3.0

func ErrUnknownTypeFn(typeName any) error

ErrUnknownTypeFn is returned when the type dispatcher encounters a type it does not handle.

func ErrVectorElementsEOFFn ¶ added in v1.3.0

func ErrVectorElementsEOFFn(have, needed any) error

ErrVectorElementsEOFFn is returned when the buffer is too short for static vector elements.

func ErrVectorLengthFn ¶ added in v1.3.0

func ErrVectorLengthFn(length, limit any) error

ErrVectorLengthFn is returned when a vector or fixed-size byte array has more elements than the schema allows.

func ErrVectorOffsetsEOFFn ¶ added in v1.3.0

func ErrVectorOffsetsEOFFn(have, needed any) error

ErrVectorOffsetsEOFFn is returned when the buffer is too short for the vector offset table.

func ErrVectorSizeExceedsArrayFn ¶ added in v1.3.0

func ErrVectorSizeExceedsArrayFn(dynamicSize, arrayLen any) error

ErrVectorSizeExceedsArrayFn is returned when a dynamic size expression yields a vector size larger than the backing Go array. That is a mismatch between the spec values and the Go type rather than anything about the value being encoded, which is why it carries ErrInvalidConstraint -- the same sentinel the reflection engine raises when it catches the mismatch while building the descriptor.

func ErrorWithPath ¶ added in v1.3.0

func ErrorWithPath(err error, segment string) error

ErrorWithPath appends a path segment to an sszError as it bubbles up. If err is not already an sszError, it is wrapped in one. The input error is never mutated: the new level points at it.

func ErrorWithPathf ¶ added in v1.3.0

func ErrorWithPathf(err error, format string, args ...any) error

ErrorWithPathf appends a formatted path segment to an sszError as it bubbles up. If err is not already an sszError, it is wrapped in one. Segments are collected innermost-first and reversed when formatting.

func ExpandSlice ¶ added in v1.1.1

func ExpandSlice[T any](src []T, size int) []T

ExpandSlice grows or shrinks src to length size, zeroing any newly added elements. For size == 0 it returns a non-nil empty slice.

func GetCachedSpecSet ¶ added in v1.4.0

func GetCachedSpecSet[T any](ds DynamicSpecs, build func(DynamicSpecs) ([]uint64, error)) ([]uint64, error)

GetCachedSpecSet returns the spec set of the generated type T under ds, building it with build on the first call for a caching ds and on every call otherwise. The set is shared between callers and must not be written.

Generated code calls this once per method entry with the type's buildDynSSZSpecSet, which resolves every spec expression the type's methods use.

func GetCachedViewSpecSet ¶ added in v1.4.0

func GetCachedViewSpecSet[T, V any](ds DynamicSpecs, build func(DynamicSpecs) ([]uint64, error)) ([]uint64, error)

GetCachedViewSpecSet is GetCachedSpecSet for the methods of T serving its view V, which resolve the view's expressions by a builder of their own.

func GetOffsetSlice ¶ added in v1.2.0

func GetOffsetSlice(size int) []uint32

GetOffsetSlice returns a uint32 slice of the given size from a shared pool, suitable for use as an SSZ offset buffer. The caller must return it via PutOffsetSlice when done.

func GrowSlice ¶ added in v1.4.0

func GrowSlice[T any](src []T, size, allocationLimit int) []T

GrowSlice returns src resized to size, growing capacity geometrically. When a new backing array is needed, a non-negative allocationLimit bounds its capacity; a smaller limit is treated as size, and a negative limit permits unbounded growth. Existing caller-owned capacity is reused as-is because hiding it would not release memory and could force a later reallocation.

ExpandSlice allocates exactly the requested size, which is right when the element count is known up front. Decoding a list whose count is only discovered at EOF resizes once per element, so it needs amortised growth instead.

func HashUint64Slice ¶ added in v1.3.0

func HashUint64Slice[T ~uint64](hh HashWalker, s []T)

HashUint64Slice appends the little-endian encoding of a uint64 slice directly to a HashWalker's buffer. On little-endian architectures (x86, ARM64) this is a single bulk memory copy, avoiding per-element AppendUint64 overhead. Big-endian architectures append each element individually to keep the hashed representation little-endian.

func LookupAnnotation ¶ added in v1.3.0

func LookupAnnotation(t reflect.Type) (string, bool)

LookupAnnotation returns the raw SSZ tag string registered for the given reflect.Type via Annotate[T](), or ("", false) if none was registered.

func MarshalBool ¶

func MarshalBool(dst []byte, b bool) []byte

MarshalBool marshals a boolean to dst

func MarshalFixedBytesSlice ¶ added in v1.3.2

func MarshalFixedBytesSlice[T any](dst []byte, s []T) []byte

MarshalFixedBytesSlice appends the raw contents of a slice whose elements are fixed-size byte arrays (e.g. []Root where Root is [32]byte) to dst in a single copy. Such elements are laid out contiguously without padding, so this avoids the per-element append loop. The element size is taken from the element type.

func MarshalOffset ¶

func MarshalOffset(dst []byte, offset int) []byte

MarshalOffset marshals an offset to dst

func MarshalUint8 ¶

func MarshalUint8(dst []byte, i uint8) []byte

MarshalUint8 marshals a little endian uint8 to dst

func MarshalUint16 ¶

func MarshalUint16(dst []byte, i uint16) []byte

MarshalUint16 marshals a little endian uint16 to dst

func MarshalUint32 ¶

func MarshalUint32(dst []byte, i uint32) []byte

MarshalUint32 marshals a little endian uint32 to dst

func MarshalUint64 ¶

func MarshalUint64(dst []byte, i uint64) []byte

MarshalUint64 marshals a little endian uint64 to dst

func MarshalUint64Slice ¶ added in v1.3.0

func MarshalUint64Slice[T ~uint64](dst []byte, s []T) []byte

MarshalUint64Slice appends the little-endian encoding of a uint64 slice to dst. On little-endian architectures (x86, ARM64) this is a single bulk memory copy, avoiding per-element encoding overhead. Big-endian architectures encode each element individually to keep the SSZ output little-endian.

func Max ¶ added in v1.4.0

func Max[T cmp.Ordered](a, b T) T

Max returns the larger of a and b. See Min.

func Min ¶ added in v1.4.0

func Min[T cmp.Ordered](a, b T) T

Min returns the smaller of a and b. Generated code calls the qualified helpers instead of the min/max builtins, which a target package can shadow with its own function.

func NewSszError ¶ added in v1.3.0

func NewSszError(base error, msg string) error

NewSszError creates a new sszError with the given sentinel and detail message.

func NewSszErrorf ¶ added in v1.3.0

func NewSszErrorf(base error, format string, args ...any) error

NewSszErrorf creates a new sszError with a formatted detail message.

func NextPowerOfTwo ¶ added in v1.1.1

func NextPowerOfTwo(v uint64) uint64

NextPowerOfTwo returns the smallest power of two greater than or equal to v.

func PreallocateDecodeSlice ¶ added in v1.4.0

func PreallocateDecodeSlice[T any](dec Decoder, src []T, count int) []T

PreallocateDecodeSlice sizes src for a dynamic list of count elements. A region whose extent is backed by known input (a buffer, a stream with a declared length, or a region that fits in the bytes already read) is sized exactly. Otherwise the offset table proves the count but not that any body exists, so a byte-bounded prefix is reserved and callers extend it geometrically with GrowSlice as bodies are reached.

ExpandSlice is intentional here: GrowSlice's small-slice capacity floor is a throughput win during incremental growth, but reserving eight wide elements would defeat the byte bound this helper provides.

func PutOffsetSlice ¶ added in v1.2.0

func PutOffsetSlice(slice []uint32)

PutOffsetSlice returns a uint32 offset slice to the shared pool for reuse.

func ReadOffset ¶

func ReadOffset(buf []byte) uint64

ReadOffset reads an offset from buf. A short buffer is treated as zero-padded rather than panicking.

func RegionEmpty ¶ added in v1.4.0

func RegionEmpty(dec Decoder) (bool, error)

RegionEmpty reports whether the current region holds no data. Generated code uses it where emptiness is a semantic discriminator (an absent optional, an empty dynamic list) rather than a validation check, since those cannot be answered from a region length that is not yet known.

func ResolveSpecValueWithDefault ¶ added in v1.2.0

func ResolveSpecValueWithDefault(ds DynamicSpecs, name string, defaultValue uint64) (uint64, error)

ResolveSpecValueWithDefault resolves a named specification value using ds, returning defaultValue if the name is not found.

This helper is called by generated code to resolve dynssz-size/dynssz-max expressions, passing the static ssz-size/ssz-max as defaultValue. A spec value that resolves to 0 would form a zero-length vector or a zero-capacity list, both of which are invalid per the SSZ spec, so it falls back to the positive static value, or errors when there is no positive static fallback — mirroring the reflection path. A name that is not present in the spec set keeps the static value unchanged (the static placeholder convention).

func SizeLimitSentinel ¶ added in v1.4.0

func SizeLimitSentinel(size uint64) error

SizeLimitSentinel is the condition a size this target cannot use belongs to. A size past the 4-byte SSZ offset is ErrSszSizeExceeded: no target encodes it. A narrower one has only run out of int, which a target with a wider one would not have, so it is ErrPlatformOverflow.

func SizeListSlice ¶ added in v1.4.0

func SizeListSlice[T any](dec Decoder, dst []T, count, elemSize int) []T

SizeListSlice sizes dst for a list of count elements of elemSize bytes.

When the region's extent is backed by input known to exist, the slice is allocated exactly -- the common case, and what every buffer or known-length decode does. Otherwise the count is merely declared by the input, so allocating it outright would let a peer turn a few delivered bytes into an arbitrary allocation; the slice is instead seeded from the bytes that have actually arrived and grows as the rest does.

func UnmarshalBool ¶

func UnmarshalBool(src []byte) bool

UnmarshalBool unmarshals a boolean from the src input. An empty buffer decodes to false rather than panicking, and any byte other than 1 decodes to false. It is kept for generated code from earlier versions; the decoders' DecodeBool and the code generated today reject a byte other than 0 or 1.

func UnmarshalFixedBytesSlice ¶ added in v1.3.2

func UnmarshalFixedBytesSlice[T any](dst []T, buf []byte)

UnmarshalFixedBytesSlice bulk-copies a contiguous SSZ byte buffer into dst, a slice whose elements are fixed-size byte arrays (e.g. []Root where Root is [32]byte). dst must already have its final length. Because such elements are laid out contiguously with no padding, the whole slice is decoded with a single memory copy, avoiding the per-element copy loop. This is endian-neutral (raw bytes). The element size is taken from the element type itself.

func UnmarshalUint64Slice ¶ added in v1.3.0

func UnmarshalUint64Slice[T ~uint64](dst []T, buf []byte)

UnmarshalUint64Slice decodes little-endian encoded uint64 values from buf into dst. On little-endian architectures (x86, ARM64) this is a single bulk memory copy. Big-endian architectures decode each element individually. Both paths tolerate a short buf by decoding only the fully covered elements, leaving a trailing partially covered element untouched; callers are expected to have validated the buffer length already.

func UnmarshallUint8 ¶

func UnmarshallUint8(src []byte) uint8

UnmarshallUint8 unmarshals a little endian uint8 from the src input. An empty buffer decodes to zero rather than panicking.

func UnmarshallUint16 ¶

func UnmarshallUint16(src []byte) uint16

UnmarshallUint16 unmarshals a little endian uint16 from the src input. A short buffer is treated as zero-padded rather than panicking.

func UnmarshallUint32 ¶

func UnmarshallUint32(src []byte) uint32

UnmarshallUint32 unmarshals a little endian uint32 from the src input. A short buffer is treated as zero-padded rather than panicking.

func UnmarshallUint64 ¶

func UnmarshallUint64(src []byte) uint64

UnmarshallUint64 unmarshals a little endian uint64 from the src input. A short buffer is treated as zero-padded rather than panicking.

func UpdateOffset ¶

func UpdateOffset(dst []byte, offset int)

UpdateOffset updates the offset in dst

func ZeroBytes ¶

func ZeroBytes() []byte

ZeroBytes returns the shared zero-filled slice. The returned slice must not be modified by callers.

Types ¶

type BufferDecoder ¶ added in v1.2.0

type BufferDecoder struct {
	// contains filtered or unexported fields
}

BufferDecoder is a seekable Decoder implementation backed by an in-memory byte buffer. It supports random-access offset reads via DecodeOffsetAt and byte skipping via SkipBytes.

func NewBufferDecoder ¶ added in v1.2.0

func NewBufferDecoder(buffer []byte) *BufferDecoder

NewBufferDecoder creates a new BufferDecoder that reads SSZ data from the provided byte buffer.

func (*BufferDecoder) Available ¶ added in v1.4.0

func (e *BufferDecoder) Available() int

Available returns the whole remaining region: for a buffer-backed decoder every byte of it is already in memory.

func (*BufferDecoder) DecodeBool ¶ added in v1.2.0

func (e *BufferDecoder) DecodeBool() (bool, error)

DecodeBool reads a single byte and returns its boolean value. Returns ErrUnexpectedEOF if no bytes remain, or ErrInvalidValueRange if the byte is not 0x00 or 0x01.

func (*BufferDecoder) DecodeBytes ¶ added in v1.2.0

func (e *BufferDecoder) DecodeBytes(buf []byte) ([]byte, error)

DecodeBytes reads len(buf) bytes into the provided buffer and returns the filled slice. Returns ErrUnexpectedEOF if fewer bytes remain than requested.

func (*BufferDecoder) DecodeBytesBuf ¶ added in v1.2.0

func (e *BufferDecoder) DecodeBytesBuf(length int) ([]byte, error)

DecodeBytesBuf returns a slice of the underlying buffer containing the next length bytes. If length is negative, all remaining bytes within the current limit are returned. The returned slice shares memory with the decoder's buffer and must not be modified. Returns ErrUnexpectedEOF if fewer bytes remain than requested. DecodeBytesBuf returns the next length bytes (the region remainder for a negative length). The returned slice aliases the decoder's input buffer and must be treated as read-only; callers that keep or mutate it must copy.

func (*BufferDecoder) DecodeOffset ¶ added in v1.2.0

func (e *BufferDecoder) DecodeOffset() (uint32, error)

DecodeOffset reads a 4-byte little-endian SSZ offset from the current position and advances by 4 bytes. Returns ErrUnexpectedEOF if fewer than 4 bytes remain.

func (*BufferDecoder) DecodeOffsetAt ¶ added in v1.2.0

func (e *BufferDecoder) DecodeOffsetAt(pos int) uint32

DecodeOffsetAt reads a 4-byte little-endian SSZ offset at the given absolute position without advancing the current read position. The caller must ensure pos is within bounds.

func (*BufferDecoder) DecodeRemaining ¶ added in v1.4.0

func (e *BufferDecoder) DecodeRemaining(maxLen int) ([]byte, error)

DecodeRemaining consumes the rest of the current region and returns it in a newly allocated slice. If maxLen is non-negative and the region is larger, the call fails without allocating.

func (*BufferDecoder) DecodeUint8 ¶ added in v1.2.0

func (e *BufferDecoder) DecodeUint8() (uint8, error)

DecodeUint8 reads a single byte and returns it as uint8. Returns ErrUnexpectedEOF if no bytes remain.

func (*BufferDecoder) DecodeUint16 ¶ added in v1.2.0

func (e *BufferDecoder) DecodeUint16() (uint16, error)

DecodeUint16 reads 2 bytes in little-endian order and returns a uint16. Returns ErrUnexpectedEOF if fewer than 2 bytes remain.

func (*BufferDecoder) DecodeUint32 ¶ added in v1.2.0

func (e *BufferDecoder) DecodeUint32() (uint32, error)

DecodeUint32 reads 4 bytes in little-endian order and returns a uint32. Returns ErrUnexpectedEOF if fewer than 4 bytes remain.

func (*BufferDecoder) DecodeUint64 ¶ added in v1.2.0

func (e *BufferDecoder) DecodeUint64() (uint64, error)

DecodeUint64 reads 8 bytes in little-endian order and returns a uint64. Returns ErrUnexpectedEOF if fewer than 8 bytes remain.

func (*BufferDecoder) FinishRegion ¶ added in v1.4.0

func (e *BufferDecoder) FinishRegion() error

FinishRegion pops the current region, asserting it was fully consumed. A buffer-backed decoder always knows its length, so no probing is needed.

func (*BufferDecoder) GetLength ¶ added in v1.2.0

func (e *BufferDecoder) GetLength() int

GetLength returns the number of remaining bytes available for reading, taking into account the current limit.

func (*BufferDecoder) GetPosition ¶ added in v1.2.0

func (e *BufferDecoder) GetPosition() int

GetPosition returns the current read position in the buffer.

func (*BufferDecoder) LengthKnown ¶ added in v1.4.0

func (e *BufferDecoder) LengthKnown() bool

LengthKnown always returns true: a buffer-backed decoder always knows how many bytes remain in the current region, and holds them.

func (*BufferDecoder) More ¶ added in v1.4.0

func (e *BufferDecoder) More() (bool, error)

More reports whether the current region holds at least one more byte. It never fails for a buffer-backed decoder.

func (*BufferDecoder) PopLimit ¶ added in v1.2.0

func (e *BufferDecoder) PopLimit() int

PopLimit removes the most recently pushed limit and returns the number of unconsumed bytes that were remaining within that limit.

func (*BufferDecoder) PushLimit ¶ added in v1.2.0

func (e *BufferDecoder) PushLimit(limit int)

PushLimit restricts reading to the next limit bytes from the current position. If the limit extends beyond the enclosing limit, it is clamped. Limits can be nested and must be removed with PopLimit.

func (*BufferDecoder) PushOpenLimit ¶ added in v1.4.0

func (e *BufferDecoder) PushOpenLimit()

PushOpenLimit pushes a region covering the rest of the current region. A buffer-backed decoder always knows its length, so there is nothing open about it; this keeps the call sites uniform across decoder implementations.

func (*BufferDecoder) RegionOpen ¶ added in v1.4.0

func (e *BufferDecoder) RegionOpen() bool

RegionOpen always returns false: a buffer-backed decoder knows where every region ends.

func (*BufferDecoder) Reset ¶ added in v1.4.0

func (e *BufferDecoder) Reset(buffer []byte)

Reset readies the decoder to read another buffer. It keeps the region stack, so a decoder that is reused does not allocate it again.

func (*BufferDecoder) Seekable ¶ added in v1.2.0

func (e *BufferDecoder) Seekable() bool

Seekable returns true, indicating that BufferDecoder supports random-access offset reads via DecodeOffsetAt and byte skipping via SkipBytes.

func (*BufferDecoder) SkipBytes ¶ added in v1.2.0

func (e *BufferDecoder) SkipBytes(n int)

SkipBytes advances the read position by n bytes without reading the data.

type BufferEncoder ¶ added in v1.2.0

type BufferEncoder struct {
	// contains filtered or unexported fields
}

BufferEncoder is a seekable Encoder implementation backed by an in-memory byte buffer. It supports random-access offset writes via EncodeOffsetAt.

func NewBufferEncoder ¶ added in v1.2.0

func NewBufferEncoder(buffer []byte) *BufferEncoder

NewBufferEncoder creates a new BufferEncoder using the provided buffer. Pre-sizing the buffer to the expected output keeps encoding allocation-free; like append, an under-sized buffer grows on demand.

func (*BufferEncoder) EncodeBool ¶ added in v1.2.0

func (e *BufferEncoder) EncodeBool(v bool)

EncodeBool writes a single-byte boolean value (0x00 or 0x01) at the current position and advances by 1 byte.

func (*BufferEncoder) EncodeBytes ¶ added in v1.2.0

func (e *BufferEncoder) EncodeBytes(v []byte)

EncodeBytes copies the given byte slice into the buffer at the current position and advances by len(v) bytes.

func (*BufferEncoder) EncodeOffset ¶ added in v1.2.0

func (e *BufferEncoder) EncodeOffset(v uint32)

EncodeOffset writes a 4-byte little-endian SSZ offset at the current position and advances by 4 bytes.

func (*BufferEncoder) EncodeOffsetAt ¶ added in v1.2.0

func (e *BufferEncoder) EncodeOffsetAt(pos int, v uint32)

EncodeOffsetAt writes a 4-byte little-endian SSZ offset at the given absolute position without advancing the current write position. This is used for back-patching offsets after dynamic-length fields have been written. The position comes from the caller's own GetPosition, so one outside the written buffer is an invariant violation and panics rather than dropping the write.

func (*BufferEncoder) EncodeUint8 ¶ added in v1.2.0

func (e *BufferEncoder) EncodeUint8(v uint8)

EncodeUint8 writes a single byte at the current position and advances by 1 byte.

func (*BufferEncoder) EncodeUint16 ¶ added in v1.2.0

func (e *BufferEncoder) EncodeUint16(v uint16)

EncodeUint16 writes a little-endian uint16 at the current position and advances by 2 bytes.

func (*BufferEncoder) EncodeUint32 ¶ added in v1.2.0

func (e *BufferEncoder) EncodeUint32(v uint32)

EncodeUint32 writes a little-endian uint32 at the current position and advances by 4 bytes.

func (*BufferEncoder) EncodeUint64 ¶ added in v1.2.0

func (e *BufferEncoder) EncodeUint64(v uint64)

EncodeUint64 writes a little-endian uint64 at the current position and advances by 8 bytes.

func (*BufferEncoder) EncodeZeroPadding ¶ added in v1.2.0

func (e *BufferEncoder) EncodeZeroPadding(n int)

EncodeZeroPadding writes n zero bytes at the current position and advances by n bytes. Uses clear for efficient zeroing.

func (*BufferEncoder) GetBuffer ¶ added in v1.2.0

func (e *BufferEncoder) GetBuffer() []byte

GetBuffer returns the buffer contents written so far (from start to current position).

func (*BufferEncoder) GetPosition ¶ added in v1.2.0

func (e *BufferEncoder) GetPosition() int

GetPosition returns the current write position in the buffer.

func (*BufferEncoder) Reset ¶ added in v1.4.0

func (e *BufferEncoder) Reset(buffer []byte)

Reset readies the encoder to write into another buffer, as NewBufferEncoder does for a new one.

func (*BufferEncoder) Seekable ¶ added in v1.2.0

func (e *BufferEncoder) Seekable() bool

Seekable returns true, indicating that BufferEncoder supports random-access offset writes via EncodeOffsetAt.

func (*BufferEncoder) SetBuffer ¶ added in v1.2.0

func (e *BufferEncoder) SetBuffer(buffer []byte)

SetBuffer replaces the underlying buffer and resets the write position to the end of the provided buffer's length, using its full capacity for future writes.

type Decoder ¶ added in v1.2.0

type Decoder interface {
	Seekable() bool   // can use DecodeOffsetAt() and SkipBytes()
	GetPosition() int // return current position
	GetLength() int   // return remaining length (allowance inside an open region)

	// RegionOpen reports whether the current region has no declared end and so
	// runs to EOF. Only the trailing dynamic child at each nesting level can be
	// open, and only while decoding input of unknown length.
	RegionOpen() bool

	// LengthKnown reports whether GetLength is backed by input known to exist,
	// and so may be used to size an allocation.
	//
	// A declared extent is not enough. Inside input of unknown length an offset
	// is validated against the allowance rather than against delivered bytes,
	// so a peer can declare a 500 MB field in a 12-byte payload. The extent is
	// trustworthy once the region fits inside an established total length --
	// supplied by the caller, or discovered at EOF -- or once it fits in bytes
	// already read, which a peer cannot fake without sending them. Reaching EOF
	// alone is not enough: it makes the length exact but leaves a region derived
	// from an earlier offset still claiming bytes that never arrived.
	LengthKnown() bool

	// Available reports how many bytes of the current region are already in
	// memory. It is a lower bound on what the region really contains, so an
	// allocation sized from it is backed by input that demonstrably arrived.
	Available() int

	// More reports whether the current region holds at least one more byte.
	// Inside an open region it probes the underlying reader, so it may fail.
	More() (bool, error)

	// DecodeRemaining consumes the rest of the current region (to the region
	// limit, or to EOF for an open region) and returns it in a newly allocated
	// slice the caller may retain. If maxLen is non-negative and the payload
	// exceeds it, decoding fails instead of allocating. A bounded region the
	// input cannot fill fails with ErrUnexpectedEOF.
	DecodeRemaining(maxLen int) ([]byte, error)

	// PushOpenLimit pushes a region that extends to the end of the input.
	// For decoders with a known length, and for open regions nested inside a
	// bounded one, this is equivalent to PushLimit(GetLength()).
	PushOpenLimit()

	// FinishRegion pops the current region, asserting it was fully consumed.
	//
	// For a bounded region this is PopLimit() == 0. An open region has no
	// known end, so it is established by probing for further input -- which
	// matters because a variable-size type can still stop short: a union
	// selecting a fixed-size variant, an absent optional, or an optional-list
	// with a fixed element all consume less than the region they were given.
	FinishRegion() error

	PushLimit(limit int)
	PopLimit() int
	DecodeBool() (bool, error)
	DecodeUint8() (uint8, error)
	DecodeUint16() (uint16, error)
	DecodeUint32() (uint32, error)
	DecodeUint64() (uint64, error)
	DecodeBytes(buf []byte) ([]byte, error)
	DecodeBytesBuf(len int) ([]byte, error)
	DecodeOffset() (uint32, error)
	DecodeOffsetAt(pos int) uint32
	SkipBytes(n int)
}

Decoder is the interface for reading SSZ-encoded data. It supports both seekable (buffer-backed) and non-seekable (stream-backed) implementations.

Open regions ¶

A stream decoder created without a known total length (see NewUnknownStreamDecoder) decodes SSZ data whose size is only discovered at EOF. SSZ is self-delimiting for every region except the trailing one, so "unknown length" propagates down a single chain: the last dynamic child at each nesting level. Such a region is called an *open* region and is entered with PushOpenLimit.

Decoder state after an error ¶

A decoder must not be reused once a decode has failed. Generated decoders return from inside a pushed region without popping it, so the limit stack is left unbalanced and every subsequent read is clamped to a stale region. This predates open regions — the leaked entry used to be a bounded limit and is now the open marker — and the reflection walk does pop before returning, so the two paths differ in what they leave behind. Discard the decoder and build a new one; the library's own entry points already do.

Inside an open region GetLength cannot report the true remaining length. It deliberately does not return a sentinel: it reports the remaining *allowance* (a finite, plausible upper bound derived from the decoder's maximum stream size) so that code which has not been taught about open regions degrades to a clean ErrUnexpectedEOF at the real end of input rather than deriving an absurd element count or allocation size. Use LengthKnown to distinguish the two cases, More to test for remaining data, and DecodeRemaining to consume a region of unknown extent.

Decoder is not a supported third-party implementation interface: it exists for dynamic-ssz generated code and the library's own decoders, and its method set may change between minor releases.

type DynamicDecoder ¶ added in v1.2.0

type DynamicDecoder interface {
	UnmarshalSSZDecoder(ds DynamicSpecs, decoder Decoder) error
}

DynamicDecoder is the interface implemented by types that can unmarshal using dynamic SSZ and a decoder

type DynamicEncoder ¶ added in v1.2.0

type DynamicEncoder interface {
	MarshalSSZEncoder(ds DynamicSpecs, encoder Encoder) error
}

DynamicEncoder is the interface implemented by types that can marshal themselves using dynamic SSZ and an encoder

type DynamicHashRoot ¶

type DynamicHashRoot interface {
	HashTreeRootWithDyn(ds DynamicSpecs, hh HashWalker) error
}

DynamicHashRoot is the interface implemented by types that can compute their SSZ hash tree root using dynamic specification values and a HashWalker.

type DynamicMarshaler ¶

type DynamicMarshaler interface {
	MarshalSSZDyn(ds DynamicSpecs, buf []byte) ([]byte, error)
}

DynamicMarshaler is the interface implemented by types that can marshal themselves using dynamic SSZ

type DynamicSizer ¶

type DynamicSizer interface {
	SizeSSZDyn(ds DynamicSpecs) int
}

DynamicSizer is the interface implemented by types that can calculate their own SSZ size dynamically.

The size is exact for a value that encodes. It is returned on its own, matching the fastssz shape, so an implementation has no way to report a value it cannot size and returns 0 instead -- indistinguishable from a value that really is zero bytes long. Callers should rely on marshaling, not on this, to reject a value that cannot be encoded.

type DynamicSpecs ¶ added in v1.1.0

type DynamicSpecs interface {
	ResolveSpecValue(name string) (bool, uint64, error)
}

DynamicSpecs is the interface for resolving dynamic specification values at runtime. Implementations provide named values (e.g., "SYNC_COMMITTEE_SIZE") that control SSZ field sizes.

ResolveSpecValue returns whether the named value exists, its uint64 value, and any error. The name may be a simple identifier or a mathematical expression referencing other spec values.

type DynamicUnmarshaler ¶

type DynamicUnmarshaler interface {
	UnmarshalSSZDyn(ds DynamicSpecs, buf []byte) error
}

DynamicUnmarshaler is the interface implemented by types that can unmarshal using dynamic SSZ

type DynamicViewDecoder ¶ added in v1.3.0

type DynamicViewDecoder interface {
	UnmarshalSSZDecoderView(view any) func(ds DynamicSpecs, decoder Decoder) error
}

DynamicViewDecoder is the interface implemented by types that can unmarshal using dynamic SSZ, a decoder, and a view. Returns nil if the view is not supported, otherwise returns the decode function.

type DynamicViewEncoder ¶ added in v1.3.0

type DynamicViewEncoder interface {
	MarshalSSZEncoderView(view any) func(ds DynamicSpecs, encoder Encoder) error
}

DynamicViewEncoder is the interface implemented by types that can marshal themselves using dynamic SSZ, an encoder, and a view. Returns nil if the view is not supported, otherwise returns the encode function.

type DynamicViewHashRoot ¶ added in v1.3.0

type DynamicViewHashRoot interface {
	HashTreeRootWithDynView(view any) func(ds DynamicSpecs, hh HashWalker) error
}

DynamicViewHashRoot is the interface implemented by types that can calculate their own SSZ hash tree root dynamically. Returns nil if the view is not supported, otherwise returns the hash function.

type DynamicViewMarshaler ¶ added in v1.3.0

type DynamicViewMarshaler interface {
	MarshalSSZDynView(view any) func(ds DynamicSpecs, buf []byte) ([]byte, error)
}

DynamicViewMarshaler is the interface implemented by types that can marshal themselves using dynamic SSZ and a view. Returns nil if the view is not supported, otherwise returns the marshal function.

type DynamicViewSizer ¶ added in v1.3.0

type DynamicViewSizer interface {
	SizeSSZDynView(view any) func(ds DynamicSpecs) int
}

DynamicViewSizer is the interface implemented by types that can calculate their own SSZ size dynamically with a view. Returns nil if the view is not supported, otherwise returns the size function.

type DynamicViewUnmarshaler ¶ added in v1.3.0

type DynamicViewUnmarshaler interface {
	UnmarshalSSZDynView(view any) func(ds DynamicSpecs, buf []byte) error
}

DynamicViewUnmarshaler is the interface implemented by types that can unmarshal using dynamic SSZ and a view. Returns nil if the view is not supported, otherwise returns the unmarshal function.

type Encoder ¶ added in v1.2.0

type Encoder interface {
	Seekable() bool // can use EncodeOffsetAt()
	GetPosition() int
	GetBuffer() []byte       // return the output buffer (or a temp buffer if Seekable() is false)
	SetBuffer(buffer []byte) // set new output buffer (or write the buffer to the stream if Seekable() is false)
	EncodeBool(v bool)
	EncodeUint8(v uint8)
	EncodeUint16(v uint16)
	EncodeUint32(v uint32)
	EncodeUint64(v uint64)
	EncodeBytes(v []byte)
	EncodeOffset(v uint32)
	EncodeOffsetAt(pos int, v uint32)
	EncodeZeroPadding(n int)
}

Encoder is the interface for writing SSZ-encoded data. It supports both seekable (buffer-backed) and non-seekable (stream-backed) implementations.

Encoder is not a supported third-party implementation interface: it exists for dynamic-ssz generated code and the library's own encoders, and its method set may change between minor releases.

type FastsszBufferMarshaler ¶ added in v1.4.0

type FastsszBufferMarshaler interface {
	MarshalSSZTo(dst []byte) ([]byte, error)
}

FastsszBufferMarshaler is the interface implemented by types that marshal themselves by appending to the caller's buffer.

type FastsszHashRoot ¶

type FastsszHashRoot interface {
	HashTreeRoot() ([32]byte, error)
}

FastsszHashRoot is the interface implemented by types that can compute their SSZ hash tree root using fastssz.

type FastsszHashRootWith ¶ added in v1.4.0

type FastsszHashRootWith interface {
	HashTreeRootWith(hw HashWalker) error
}

FastsszHashRootWith is the interface implemented by types that hash themselves into a walker the caller supplies. A type whose method takes an equivalent walker interface from another package (fastssz's ssz.HashWalker, say) is called the same way, so the library probes the method's signature rather than this interface; it names the canonical form.

type FastsszMarshaler ¶

type FastsszMarshaler interface {
	FastsszBufferMarshaler
	FastsszValueMarshaler
	FastsszSizer
}

FastsszMarshaler is the interface implemented by types that can marshal themselves into valid SZZ using fastssz. Each of its methods is also an interface of its own, since a type may provide any of them alone and is delegated to for what it provides.

type FastsszSizer ¶ added in v1.4.0

type FastsszSizer interface {
	SizeSSZ() int
}

FastsszSizer is the interface implemented by types that report their own SSZ encoded size.

type FastsszUnmarshaler ¶

type FastsszUnmarshaler interface {
	UnmarshalSSZ(buf []byte) error
}

FastsszUnmarshaler is the interface implemented by types that can unmarshal a SSZ description of themselves

type FastsszValueMarshaler ¶ added in v1.4.0

type FastsszValueMarshaler interface {
	MarshalSSZ() ([]byte, error)
}

FastsszValueMarshaler is the interface implemented by types that marshal themselves into a buffer of their own.

type HashWalker ¶

type HashWalker interface {
	// Hash returns the last 32 bytes of the walker's state: the latest hash
	// generated during merkleize, or bytes appended since that are not
	// merkleized yet; deferred reductions are completed first. The returned
	// slice is only valid until the next walker operation.
	Hash() []byte

	// HashErr reports the first failure the walker recorded, or nil.
	HashErr() error

	// Methods for appending single values
	AppendBool(b bool)
	AppendUint8(i uint8)
	AppendUint16(i uint16)
	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)
	PutProgressiveBitlist(bb []byte)
	PutBool(b bool)
	PutBytes(b []byte)

	// Buffer manipulation methods
	FillUpTo32()
	Append(i []byte)
	Index() int                      // deprecated: opens a scope like StartTree(TreeTypeNone) but without flushing the enclosing scope's pending reductions
	CurrentIndex() int               // returns the current buffer index (debug only)
	StartTree(treeType TreeType) int // start a new SSZ object scope and return the buffer index (close with Merkleize*)
	Collapse()                       // Hint to collapse accumulated chunks if threshold is reached

	// temporary buffer methods
	WithTemp(func(tmp []byte) []byte)

	// Merkleization methods. Each reduce pads a partial trailing chunk of the
	// scope to a full chunk before reducing, so a scope of packed values or a
	// short value needs no FillUpTo32 before it.
	Merkleize(indx int)
	MerkleizeWithMixin(indx int, num, limit uint64)
	MerkleizeProgressive(indx int)
	MerkleizeProgressiveWithMixin(indx int, num uint64)
	MerkleizeProgressiveWithActiveFields(indx int, activeFields []byte)

	// HashRoot methods
	HashRoot() ([32]byte, error)
}

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 SpecSetCache ¶ added in v1.4.0

type SpecSetCache interface {
	// LoadSpecSet returns the set cached under key, or nil.
	LoadSpecSet(key reflect.Type) []uint64
	// StoreSpecSet caches set under key and returns the set now cached, which
	// is another caller's when it stored first.
	StoreSpecSet(key reflect.Type, set []uint64) []uint64
}

SpecSetCache is implemented by a DynamicSpecs that keeps the resolved spec sets of generated types, one per schema they serve, for the lifetime of its spec values. The key is the library's; an implementation holds it opaque. DynSsz implements it; a DynamicSpecs without it resolves the set on every call.

The load and the store are separate so the builder never crosses the interface: an argument of an interface method call escapes, and the builder is a method value, so handing it over would allocate its closure on every method entry. GetCachedSpecSet calls it directly instead, on a miss only.

type StreamDecoder ¶ added in v1.2.0

type StreamDecoder struct {
	// contains filtered or unexported fields
}

StreamDecoder is a non-seekable Decoder implementation that reads SSZ data from an io.Reader. It uses an internal buffer for efficient sequential reads but does not support DecodeOffsetAt or SkipBytes.

A StreamDecoder can operate with a known total length, or — via NewUnknownStreamDecoder — discover the length at EOF. See the Decoder documentation for how open regions behave in the latter mode.

func NewStreamDecoder ¶ added in v1.2.0

func NewStreamDecoder(reader io.Reader, totalLen, maxBufSize int) *StreamDecoder

NewStreamDecoder creates a new StreamDecoder that reads SSZ data from the provided io.Reader. totalLen specifies the total expected byte length of the SSZ payload and is trusted as such: regions and allocations are sized from it before the bytes arrive, so it must come from a source the caller controls. A negative totalLen selects unknown-length mode with the default maximum stream size (see NewUnknownStreamDecoder). maxBufSize controls the maximum internal read buffer size; if <= 0, DefaultStreamDecoderBufSize is used.

func NewUnknownStreamDecoder ¶ added in v1.4.0

func NewUnknownStreamDecoder(reader io.Reader, maxBufSize, maxStreamSize int) *StreamDecoder

NewUnknownStreamDecoder creates a StreamDecoder for an SSZ payload whose total length is not known in advance. The payload is read until EOF.

maxBufSize controls the maximum internal read buffer size (<= 0 selects DefaultStreamDecoderBufSize). maxStreamSize bounds the total payload (<= 0 selects DefaultMaxStreamSize); it can never be unlimited, because it doubles as the allowance GetLength reports inside open regions.

func (*StreamDecoder) Available ¶ added in v1.4.0

func (e *StreamDecoder) Available() int

Available reports how many bytes of the current region are already buffered.

func (*StreamDecoder) DecodeBool ¶ added in v1.2.0

func (e *StreamDecoder) DecodeBool() (bool, error)

func (*StreamDecoder) DecodeBytes ¶ added in v1.2.0

func (e *StreamDecoder) DecodeBytes(buf []byte) ([]byte, error)

func (*StreamDecoder) DecodeBytesBuf ¶ added in v1.2.0

func (e *StreamDecoder) DecodeBytesBuf(l int) ([]byte, error)

DecodeBytesBuf returns the next l bytes (the region remainder for a negative l). The returned slice may alias the decoder's internal read buffer and must be treated as read-only; callers that keep or mutate it must copy.

func (*StreamDecoder) DecodeOffset ¶ added in v1.2.0

func (e *StreamDecoder) DecodeOffset() (uint32, error)

func (*StreamDecoder) DecodeOffsetAt ¶ added in v1.2.0

func (e *StreamDecoder) DecodeOffsetAt(pos int) uint32

func (*StreamDecoder) DecodeRemaining ¶ added in v1.4.0

func (e *StreamDecoder) DecodeRemaining(maxLen int) ([]byte, error)

DecodeRemaining consumes the rest of the current region — to the region limit, or to EOF for an open region — and returns it in a newly allocated slice the caller may retain. If maxLen is non-negative and the payload exceeds it, the call fails without having allocated the full payload.

A bounded region that the input cannot fill fails with ErrUnexpectedEOF; only an open region legitimately ends where the input does.

func (*StreamDecoder) DecodeUint8 ¶ added in v1.2.0

func (e *StreamDecoder) DecodeUint8() (uint8, error)

func (*StreamDecoder) DecodeUint16 ¶ added in v1.2.0

func (e *StreamDecoder) DecodeUint16() (uint16, error)

func (*StreamDecoder) DecodeUint32 ¶ added in v1.2.0

func (e *StreamDecoder) DecodeUint32() (uint32, error)

func (*StreamDecoder) DecodeUint64 ¶ added in v1.2.0

func (e *StreamDecoder) DecodeUint64() (uint64, error)

func (*StreamDecoder) FinishRegion ¶ added in v1.4.0

func (e *StreamDecoder) FinishRegion() error

FinishRegion pops the current region, asserting it was fully consumed.

A bounded region is answered from the limit alone, with no I/O -- that covers every known-length decode, and every region of an unknown-length decode once EOF has closed it. Only a genuinely open region has to probe the reader.

func (*StreamDecoder) GetLength ¶ added in v1.2.0

func (e *StreamDecoder) GetLength() int

GetLength returns the number of bytes remaining in the current region.

Inside an open region the true remaining length is not knowable, so this reports the remaining allowance (maxSize - position) instead of a sentinel. That keeps arithmetic on the result finite and plausible for callers that predate open regions: they derive an over-large region, then fail cleanly with ErrUnexpectedEOF at the real end of input. Use LengthKnown to tell the two cases apart.

func (*StreamDecoder) GetPosition ¶ added in v1.2.0

func (e *StreamDecoder) GetPosition() int

func (*StreamDecoder) LengthKnown ¶ added in v1.4.0

func (e *StreamDecoder) LengthKnown() bool

LengthKnown reports whether GetLength is backed by input known to exist.

A declared extent is not enough. Inside an open region an offset is validated against the allowance rather than against delivered bytes, so PushLimit can derive a bounded region far larger than the input -- a peer can declare a 500 MB field in a 12-byte payload. Sizing an allocation from that is a memory amplification attack.

The extent is trustworthy in two cases: the region fits inside a total stream length that is established (supplied by the caller, or discovered at EOF), or it already fits in bytes that have been read -- which a peer cannot fake without sending them. Reaching EOF is not on its own enough: it makes the length exact but leaves any region derived from an earlier offset in place, still claiming bytes that never arrived.

func (*StreamDecoder) More ¶ added in v1.4.0

func (e *StreamDecoder) More() (bool, error)

More reports whether the current region holds at least one more byte. For a bounded region the answer comes from the limit; for an open region the reader is probed, which is what turns "no more data" into a discovered EOF.

func (*StreamDecoder) PopLimit ¶ added in v1.2.0

func (e *StreamDecoder) PopLimit() int

func (*StreamDecoder) Prefill ¶ added in v1.4.0

func (e *StreamDecoder) Prefill() error

Prefill performs one read into the internal buffer. In unknown-length mode this is worth doing before decoding starts: if the whole payload fits in the buffer, EOF is observed immediately, the stream length becomes exact and no open region is ever created — the decode then runs entirely on the known-length code path, with all of its fail-fast validation intact.

It is a no-op once the length is known or EOF has been seen.

Prefill reads until the internal buffer is full or the reader reports EOF, so it can block on a slow reader. That is not a new constraint: an unknown-length decode consumes the input to EOF regardless, so the producer has to close the stream for the decode to complete at all.

func (*StreamDecoder) PushLimit ¶ added in v1.2.0

func (e *StreamDecoder) PushLimit(limit int)

func (*StreamDecoder) PushOpenLimit ¶ added in v1.4.0

func (e *StreamDecoder) PushOpenLimit()

PushOpenLimit pushes a region that extends to the end of the input. If the enclosing region is bounded, the pushed region simply spans the rest of it.

func (*StreamDecoder) RegionOpen ¶ added in v1.4.0

func (e *StreamDecoder) RegionOpen() bool

RegionOpen reports whether the current region runs to EOF rather than to a declared end.

func (*StreamDecoder) Reset ¶ added in v1.4.0

func (e *StreamDecoder) Reset(reader io.Reader, totalLen, maxBufSize int)

Reset readies the decoder to read another stream, with the arguments of NewStreamDecoder. It keeps the region stack and the read buffer, so a decoder that is reused does not allocate them again; the buffer is used at the length a new decoder would have, so a reused decoder reads its stream in the same steps.

Slices DecodeBytesBuf returned for the previous stream alias the read buffer and are overwritten by the next one.

func (*StreamDecoder) ResetUnknown ¶ added in v1.4.0

func (e *StreamDecoder) ResetUnknown(reader io.Reader, maxBufSize, maxStreamSize int)

ResetUnknown is Reset with the arguments of NewUnknownStreamDecoder.

func (*StreamDecoder) Seekable ¶ added in v1.2.0

func (e *StreamDecoder) Seekable() bool

func (*StreamDecoder) SkipBytes ¶ added in v1.2.0

func (e *StreamDecoder) SkipBytes(n int)

type StreamEncoder ¶ added in v1.2.0

type StreamEncoder struct {
	// contains filtered or unexported fields
}

StreamEncoder is a non-seekable Encoder implementation that writes SSZ data to an io.Writer with internal buffering. It does not support EncodeOffsetAt.

func NewStreamEncoder ¶ added in v1.2.0

func NewStreamEncoder(writer io.Writer, bufSize int) *StreamEncoder

NewStreamEncoder creates a new StreamEncoder that writes SSZ data to the provided io.Writer. bufSize controls the internal write buffer size; if <= 0, DefaultStreamEncoderBufSize is used. Values smaller than 8 (the largest atomic write) are raised to 8 so that primitive encodes never overflow the buffer.

func (*StreamEncoder) EncodeBool ¶ added in v1.2.0

func (e *StreamEncoder) EncodeBool(v bool)

func (*StreamEncoder) EncodeBytes ¶ added in v1.2.0

func (e *StreamEncoder) EncodeBytes(v []byte)

func (*StreamEncoder) EncodeOffset ¶ added in v1.2.0

func (e *StreamEncoder) EncodeOffset(v uint32)

func (*StreamEncoder) EncodeOffsetAt ¶ added in v1.2.0

func (e *StreamEncoder) EncodeOffsetAt(pos int, v uint32)

func (*StreamEncoder) EncodeUint8 ¶ added in v1.2.0

func (e *StreamEncoder) EncodeUint8(v uint8)

func (*StreamEncoder) EncodeUint16 ¶ added in v1.2.0

func (e *StreamEncoder) EncodeUint16(v uint16)

func (*StreamEncoder) EncodeUint32 ¶ added in v1.2.0

func (e *StreamEncoder) EncodeUint32(v uint32)

func (*StreamEncoder) EncodeUint64 ¶ added in v1.2.0

func (e *StreamEncoder) EncodeUint64(v uint64)

func (*StreamEncoder) EncodeZeroPadding ¶ added in v1.2.0

func (e *StreamEncoder) EncodeZeroPadding(n int)

func (*StreamEncoder) Flush ¶ added in v1.3.0

func (e *StreamEncoder) Flush()

Flush flushes any buffered data to the underlying io.Writer.

func (*StreamEncoder) GetBuffer ¶ added in v1.2.0

func (e *StreamEncoder) GetBuffer() []byte

func (*StreamEncoder) GetPosition ¶ added in v1.2.0

func (e *StreamEncoder) GetPosition() int

func (*StreamEncoder) GetWriteError ¶ added in v1.2.0

func (e *StreamEncoder) GetWriteError() error

GetWriteError returns the first write error encountered during encoding, or nil if no errors occurred.

func (*StreamEncoder) Reset ¶ added in v1.4.0

func (e *StreamEncoder) Reset(writer io.Writer)

Reset readies the encoder to write another value to writer. It keeps the write buffer and the scratch buffer, so an encoder that is reused does not allocate them again.

func (*StreamEncoder) Seekable ¶ added in v1.2.0

func (e *StreamEncoder) Seekable() bool

func (*StreamEncoder) SetBuffer ¶ added in v1.2.0

func (e *StreamEncoder) SetBuffer(buffer []byte)

type TreeType ¶ added in v1.3.0

type TreeType uint8

TreeType specifies the merkle tree shape for an SSZ object scope.

const (
	// TreeTypeNone disables incremental hashing for this scope.
	TreeTypeNone TreeType = iota
	// TreeTypeBinary is the standard SSZ binary merkle tree.
	TreeTypeBinary
	// TreeTypeProgressive is the progressive merkle tree (subtree_fill_progressive).
	TreeTypeProgressive

	// TreeTypePacked marks a scope whose elements are packed basic values; it
	// is combined with the shape (TreeTypeBinary|TreeTypePacked). Inside a
	// packed scope the walker's Put* methods append the value's packed bytes
	// instead of a padded chunk; the scope pads the trailing chunk itself.
	TreeTypePacked TreeType = 0x80
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL