Dynamic SSZ includes a code generation tool (dynssz-gen) that generates optimized SSZ methods for your types, eliminating reflection overhead and improving performance.
Always use ds.MarshalSSZ(), ds.UnmarshalSSZ(), ds.HashTreeRoot(), etc. as your entry points - even when code generation is active. The DynSsz runtime automatically detects and delegates to generated methods (like MarshalSSZDyn, UnmarshalSSZDyn) when they are present on the type.
Do not call generated methods directly from your application code. This creates a circular dependency problem: if you delete the generated file to regenerate it, the direct references to generated methods break compilation, and the code generator cannot analyze your package. By routing everything through DynSsz, your code compiles with or without the generated file - the library simply falls back to reflection when generated methods are absent.
go install github.com/pk910/dynamic-ssz/dynssz-gen@latestVerify installation:
dynssz-gen -helpGenerate SSZ methods for specific types:
dynssz-gen -package /path/to/package -types BeaconBlock,BeaconState -output generated_ssz.goFor larger configurations (many types, per-type options, per-type flag overrides), use a YAML config file instead of long CLI strings:
dynssz-gen --config gen.yamlSee Code Generator Config File for the format reference.
| Flag | Description | Default |
|---|---|---|
-config |
Path to a YAML config file (see config reference) | — |
-package |
Go package path to analyze | Required (unless supplied by config) |
-types |
Comma-separated list of types to generate (see extended format below) | Required (unless supplied by config) |
-output |
Output file path | Required if types don't specify files |
-header |
Custom header comment template for generated files. {hash} and {version} placeholders are substituted. The first line should match ^// Code generated .* DO NOT EDIT\.$ — a warning is printed otherwise, since tooling relies on that convention to recognize generated files. |
dynamic-ssz default header |
-v |
Verbose output | false |
-legacy |
Generate legacy compatibility methods | false |
-without-dynamic-expressions |
Generate only legacy methods, disable dynamic methods. See Freezing spec values. | false |
-without-fastssz |
Generate code without using fast ssz generated methods | false |
-with-streaming |
Generate streaming encoder/decoder functions | false |
-with-extended-types |
Enable support for non-standard extended types (signed ints, floats, big.Int, optionals) | false |
When both --config and CLI flags are provided, any CLI flag that is
explicitly passed overrides the config file's value. See the
config file docs for
precedence details.
The -types flag supports an extended format for specifying output files and view types:
TypeName[:output.go][:views=View1;View2;...][:viewonly]
| Part | Description | Required |
|---|---|---|
TypeName |
Name of the type to generate methods for | Yes |
:output.go |
Output file for this specific type | No (uses -output flag) |
:views=... |
Semicolon-separated list of view types for fork support | No |
:viewonly |
Only generate view-aware methods, not standard methods | No |
View type references can be:
- Local types:
Phase0View - External package types:
github.com/myproject/views.Phase0View
Examples:
# Simple type to default output
-types "BeaconBlock"
# Type to specific file
-types "BeaconBlock:block_ssz.go"
# Type with local view types
-types "BeaconBlock:block_ssz.go:views=Phase0BlockView;AltairBlockView"
# Type with external view types
-types "BeaconBlock:block_ssz.go:views=github.com/views.Phase0View"
# View-only mode (no standard methods)
-types "BeaconBlock:block_ssz.go:views=Phase0View:viewonly"
# Multiple types with mixed configurations
-types "BeaconBlock:block_ssz.go:views=Phase0BlockView,BeaconState:state_ssz.go"# In your project directory
dynssz-gen -package . -types Block,Transaction,Validator -output ssz_generated.go# Each type to its own file
dynssz-gen -package . -types Block:block_ssz.go,Transaction:tx_ssz.go,Validator:validator_ssz.go# Some types to separate files, others to default output
dynssz-gen -package . -types Block:block_ssz.go,Transaction:tx_ssz.go,Validator,ValidatorData -output validators_ssz.goGenerate SSZ methods that support multiple schemas (views) for fork handling:
# Data type with views - generates both standard and view-aware methods
dynssz-gen -package . \
-types "BeaconBlockBody:body_ssz.go:views=Phase0BeaconBlockBodyView;AltairBeaconBlockBodyView" \
-output default.go
# View-only mode - only generates view-aware methods (useful when standard methods already exist)
dynssz-gen -package . \
-types "BeaconBlockBody:body_ssz.go:views=Phase0View;AltairView:viewonly" \
-output default.go
# Views from external packages
dynssz-gen -package . \
-types "BeaconState:state_ssz.go:views=github.com/myproject/views.Phase0StateView" \
-output default.goSee SSZ Views for detailed documentation on view support.
dynssz-gen -package github.com/myproject/types -types BeaconBlock -output beacon_ssz.godynssz-gen -v -package . -types State,Block -output ssz_methods.goFor compatibility with existing fastssz code:
dynssz-gen -legacy -package . -types BeaconState -output legacy_ssz.goFor maximum performance with default preset:
dynssz-gen -without-dynamic-expressions -package . -types BeaconState -output static_ssz.goFor maximum flexibility:
dynssz-gen -legacy -package . -types BeaconState -output full_ssz.goFor memory-efficient streaming to/from io.Reader/io.Writer:
dynssz-gen -with-streaming -package . -types BeaconState -output streaming_ssz.goGeneration succeeds but prints a warning for a type whose encoding is legal yet outside the SSZ spec, so the mismatch is visible rather than silently baked into the generated methods:
warning: mypkg.Attestation.Bits has no ssz-max, so its hash tree root uses a
limit derived from the value rather than the type: it will not match another
implementation
A list or bitlist with no ssz-max has no spec-defined hash tree root, so
generating one at all requires -with-extended-types (see
supported-types.md). The programmatic
API exposes the same list through CodeGenerator.Warnings().
-without-dynamic-expressions bakes the static tag values into the generated
buffer methods. Those methods take no spec set, so they are correct only for a
DynSsz whose spec values match the static ones.
Streaming methods are unaffected: an encoder or decoder method is always handed
a DynSsz, so there is no expression-less form of it and it keeps resolving
spec values. A type generated with both flags therefore has methods that
disagree when the specs are not the defaults, which is by design -- the library
entrypoint picks the ones valid for the configured spec values, and never
serves a baked result to a DynSsz that resolves them differently. Calling the
generated methods directly is what makes the distinction visible, and there the
buffer methods carry the static contract.
package main
import (
"github.com/pk910/dynamic-ssz/codegen"
dynssz "github.com/pk910/dynamic-ssz"
)
func generateSSZ() error {
// Create code generator
codeGen := codegen.NewCodeGenerator(dynssz.NewDynSsz(nil).GetTypeCache())
// Add types to single file
codeGen.BuildFile("generated_ssz.go",
codegen.WithReflectType(reflect.TypeOf(BeaconBlock{})),
codegen.WithReflectType(reflect.TypeOf(BeaconState{})),
)
// Generate code
return codeGen.Generate()
}func generateSSZMultipleFiles() error {
codeGen := codegen.NewCodeGenerator(dynssz.NewDynSsz(nil).GetTypeCache())
// Block types to one file
codeGen.BuildFile("block_ssz.go",
codegen.WithReflectType(reflect.TypeOf(BeaconBlock{})),
codegen.WithReflectType(reflect.TypeOf(BeaconBlockBody{})),
)
// State types to another file
codeGen.BuildFile("state_ssz.go",
codegen.WithReflectType(reflect.TypeOf(BeaconState{})),
codegen.WithReflectType(reflect.TypeOf(Validator{})),
)
// Cross-references between types are handled automatically
return codeGen.Generate()
}import "github.com/pk910/dynamic-ssz/codegen"
// Create generator with options
codeGen := codegen.NewCodeGenerator(dynSsz.GetTypeCache())
// Build file with options
codeGen.BuildFile("output.go",
// Skip marshal method generation
codegen.WithNoMarshalSSZ(),
// Skip unmarshal method generation
codegen.WithNoUnmarshalSSZ(),
// Skip size calculation
codegen.WithNoSizeSSZ(),
// Skip hash tree root generation
codegen.WithNoHashTreeRoot(),
// Generate legacy methods (adds MarshalSSZ, UnmarshalSSZ, etc.)
codegen.WithCreateLegacyFn(),
// Skip dynamic expressions (generates only static legacy methods)
codegen.WithoutDynamicExpressions(),
// Generate streaming encoder function (MarshalSSZEncoder)
codegen.WithCreateEncoderFn(),
// Generate streaming decoder function (UnmarshalSSZDecoder)
codegen.WithCreateDecoderFn(),
// Add type to generate
codegen.WithReflectType(reflect.TypeOf(MyType{})),
)import "github.com/pk910/dynamic-ssz/codegen"
codeGen := codegen.NewCodeGenerator(dynSsz.GetTypeCache())
// Generate type with view support (data + views mode)
codeGen.BuildFile("output.go",
codegen.WithReflectType(
reflect.TypeOf(BeaconBlockBody{}),
// Add view types using reflect.Type
codegen.WithReflectViewTypes(
reflect.TypeOf(Phase0BeaconBlockBodyView{}),
reflect.TypeOf(AltairBeaconBlockBodyView{}),
reflect.TypeOf(BellatrixBeaconBlockBodyView{}),
),
),
)
// Generate type in view-only mode (only view methods, no standard methods)
codeGen.BuildFile("views_only.go",
codegen.WithReflectType(
reflect.TypeOf(BeaconBlockBody{}),
codegen.WithReflectViewTypes(
reflect.TypeOf(Phase0BeaconBlockBodyView{}),
),
codegen.WithViewOnly(), // Only generate view-aware methods
),
)
// Using go/types (for external packages)
codeGen.BuildFile("output.go",
codegen.WithGoTypesType(
goTypesType,
codegen.WithGoTypesViewTypes(phase0ViewType, altairViewType),
),
)
codeGen.Generate()See SSZ Views for detailed documentation on view concepts and usage.
The code generator produces different methods depending on the flags used:
By default, the generator creates dynamic methods that accept specification values:
func (b *BeaconBlock) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) {
// Generated marshaling with dynamic expression support
}func (b *BeaconBlock) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) {
// Generated unmarshaling with dynamic expression support
}func (b *BeaconBlock) SizeSSZDyn(ds sszutils.DynamicSpecs) (size int) {
// Size calculation with dynamic expression support
}func (b *BeaconBlock) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error {
// Hash tree root with dynamic expression support
}When using -legacy flag, additional fastssz-compatible methods are generated:
func (b *BeaconBlock) MarshalSSZ() ([]byte, error) {
return b.MarshalSSZDyn(dynssz.GetGlobalDynSsz(), nil)
}
func (b *BeaconBlock) MarshalSSZTo(buf []byte) ([]byte, error) {
return b.MarshalSSZDyn(dynssz.GetGlobalDynSsz(), buf)
}func (b *BeaconBlock) UnmarshalSSZ(buf []byte) error {
return b.UnmarshalSSZDyn(dynssz.GetGlobalDynSsz(), buf)
}func (b *BeaconBlock) SizeSSZ() int {
return b.SizeSSZDyn(dynssz.GetGlobalDynSsz())
}func (b *BeaconBlock) HashTreeRoot() ([32]byte, error) {
// Optimized merkle root calculation using global specs
}Whether a type additionally carries the static fastssz method set
(MarshalSSZTo, HashTreeRoot, HashTreeRootWith) can depend on the
composition of the generation batch: a type whose nested types are generated in
the same batch delegates to their preset-capable *Dyn methods and then omits
its own static twins. The *Dyn methods and the ds.* entry points are always
present — use those rather than relying on the static method set.
When using -without-dynamic-expressions, only static legacy methods are generated (no *Dyn methods):
func (b *BeaconBlock) MarshalSSZ() ([]byte, error) {
// Static marshaling for default preset only
}
func (b *BeaconBlock) MarshalSSZTo(buf []byte) ([]byte, error) {
// Static marshaling to buffer
}
func (b *BeaconBlock) UnmarshalSSZ(buf []byte) error {
// Static unmarshaling
}
func (b *BeaconBlock) SizeSSZ() int {
// Static size calculation
}
func (b *BeaconBlock) HashTreeRoot() ([32]byte, error) {
// Static hash tree root
}Use case: Generate optimized code for the default preset while falling back to reflection for other presets.
Add generation directives to your code:
//go:generate dynssz-gen -package . -types BeaconBlock,BeaconState -output generated_ssz.go
package types
type BeaconBlock struct {
Slot uint64
ProposerIndex uint64
ParentRoot [32]byte
StateRoot [32]byte
Body BeaconBlockBody
}Run generation:
go generate ./....PHONY: generate-ssz
generate-ssz:
dynssz-gen -package . -types Block,State,Transaction -output ssz_generated.go
.PHONY: build
build: generate-ssz
go build ./...GitHub Actions example:
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Install dynssz-gen
run: go install github.com/pk910/dynamic-ssz/dynssz-gen@latest
- name: Generate SSZ code
run: dynssz-gen -package . -types BeaconBlock,BeaconState -output generated_ssz.go
- name: Build
run: go build ./...
- name: Test
run: go test ./...The generator supports all Dynamic SSZ types and annotations:
- All unsigned integers:
uint8,uint16,uint32,uint64 - Boolean:
bool - Fixed arrays:
[N]T - Slices:
[]T - Byte arrays:
[]byte,[N]byte - Strings:
string
The code generator supports generating SSZ methods for non-struct types (named slices, arrays, etc.) using sszutils.Annotate[T]() to register SSZ annotations. This solves the problem that Go does not allow struct tags on type definitions.
import "github.com/pk910/dynamic-ssz/sszutils"
type Blobs []*Blob
var _ = sszutils.Annotate[Blobs](`ssz-max:"4096"`)
type BlobKZGs [][48]byte
var _ = sszutils.Annotate[BlobKZGs](`ssz-max:"4096" dynssz-max:"MAX_BLOB_COMMITMENTS_PER_BLOCK"`)The tag string uses the same key:"value" syntax as struct tags. All SSZ annotations are supported (ssz-size, ssz-max, ssz-type, dynssz-size, dynssz-max, etc.).
Generate code for these types the same way as struct types:
dynssz-gen -package . -types Blobs -output blobs_ssz.goThe generated code uses the registered annotations:
func (t *Blobs) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
vlen := len(*t)
if vlen > 4096 {
return nil, sszutils.ErrListLengthFn(vlen, 4096)
}
// ...
}Unlike struct field tags, Annotate[T]() works with both the code generator and the runtime reflection path, ensuring consistent behavior across both paths.
See SSZ Annotations for full syntax details.
- Large integers: byte arrays or uint64 arrays with
ssz-type:"uint256" - Bitfields
- Progressive types
- Unions:
Union[T](classic spec) andCompatibleUnion[T](EIP-8016) - Type wrappers:
TypeWrapper[D, T]
All SSZ annotations are supported:
ssz-sizessz-maxssz-typessz-bitsize(bit-level sizing for bitvectors)dynssz-sizedynssz-maxdynssz-bitsize(dynamic bit-level sizing for bitvectors)ssz-index
Generated code eliminates reflection overhead, pre-calculates sizes, and reduces allocations. See the benchmark repository for real performance comparisons across SSZ libraries.
The code generator automatically handles cross-references between types when they're generated together. This prevents massive code duplication.
How it works:
- When generating multiple types, the generator analyzes all types first
- If a type references another type being generated, it calls the generated method on that type
- If the generator doesn't know about a referenced type, it duplicates the entire marshaling logic inline
- Cross-references work across files when types are generated in the same batch
Example:
type BeaconBlock struct {
Body BeaconBlockBody // Reference to another type
}
type BeaconBlockBody struct {
Attestations []Attestation `ssz-max:"128"`
}With cross-reference detection (generating together):
dynssz-gen -package . -types BeaconBlock,BeaconBlockBody -output beacon_ssz.goGenerated code calls the method:
func (b *BeaconBlock) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) ([]byte, error) {
// ... other fields
if dst, err = b.Body.MarshalSSZDyn(ds, dst); err != nil {
return dst, err
}
// ...
}Without cross-reference detection (generating separately):
dynssz-gen -package . -types BeaconBlock -output block_ssz.go # BeaconBlockBody not includedGenerated code duplicates the entire BeaconBlockBody marshaling logic inline, leading to massive code duplication.
Multiple Files with Cross-References:
# These types can reference each other without code duplication
dynssz-gen -package . -types BeaconBlock:block_ssz.go,BeaconBlockBody:block_ssz.go,Attestation:attestation_ssz.goThe generator recognizes custom SSZ interfaces:
type CustomType struct {
// If type implements MarshalSSZ/UnmarshalSSZ,
// generator calls those methods
}
func (c *CustomType) MarshalSSZ() ([]byte, error) {
// Custom implementation
}By default, dynamic methods support runtime specification values:
type State struct {
Validators []Validator `dynssz-max:"VALIDATOR_REGISTRY_LIMIT"`
}
// Generated dynamic method
func (s *State) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) ([]byte, error) {
maxValidators, _ := sszutils.ResolveSpecValueWithDefault(ds, "VALIDATOR_REGISTRY_LIMIT", 1099511627776)
// ... use dynamic value for different presets
}With -without-dynamic-expressions, the expressions are dropped and the static
ssz-* values take their place. Generation never consults spec values of its
own — the generated code resolves expressions against the specs it runs under,
so what a generating machine has loaded cannot reach the output:
// Generated static method (assuming default preset values)
func (s *State) MarshalSSZ() ([]byte, error) {
// Hard-coded limits for maximum performance
// Falls back to reflection for non-default presets
}dynssz-gen -package . -types BeaconBlock -output block_ssz.goGenerates: MarshalSSZDyn, UnmarshalSSZDyn, SizeSSZDyn, HashTreeRootWithDyn
dynssz-gen -legacy -package . -types BeaconBlock -output block_ssz.goGenerates: All dynamic methods + MarshalSSZ, UnmarshalSSZ, SizeSSZ, HashTreeRoot, MarshalSSZTo
dynssz-gen -without-dynamic-expressions -package . -types BeaconBlock -output block_ssz.goGenerates: Only MarshalSSZ, UnmarshalSSZ, SizeSSZ, HashTreeRoot, MarshalSSZTo (no *Dyn methods)
Key Point: -without-dynamic-expressions is especially useful when you want to generate optimized code for the default preset and fall back to reflection-based Dynamic SSZ for other presets.
When using the views= type specification, view-aware methods are generated that allow the same runtime type to be serialized with different SSZ schemas:
func (b *BeaconBlock) MarshalSSZDynView(view any) func(ds sszutils.DynamicSpecs, buf []byte) ([]byte, error) {
// Returns a marshal function for the specified view type, or nil if not supported
switch view.(type) {
case *Phase0BeaconBlockView:
return b.marshalSSZDynPhase0BeaconBlockView
case *AltairBeaconBlockView:
return b.marshalSSZDynAltairBeaconBlockView
}
return nil
}func (b *BeaconBlock) UnmarshalSSZDynView(view any) func(ds sszutils.DynamicSpecs, buf []byte) error {
// Returns an unmarshal function for the specified view type, or nil if not supported
}func (b *BeaconBlock) SizeSSZDynView(view any) func(ds sszutils.DynamicSpecs) int {
// Returns a size function for the specified view type, or nil if not supported
}func (b *BeaconBlock) HashTreeRootWithDynView(view any) func(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error {
// Returns a hash function for the specified view type, or nil if not supported
}These methods implement the DynamicViewMarshaler, DynamicViewUnmarshaler, DynamicViewSizer, and DynamicViewHashRoot interfaces from sszutils. The Dynamic SSZ runtime automatically uses these methods when a view descriptor is provided via WithViewDescriptor().
Note: View methods return nil if the view type is not recognized, causing Dynamic SSZ to fall back to reflection-based processing.
See SSZ Views for detailed documentation on view usage.
When using -with-streaming flag, streaming-capable methods are generated:
func (b *BeaconBlock) MarshalSSZEncoder(ds sszutils.DynamicSpecs, encoder sszutils.Encoder) error {
// Streaming-compatible encoding that works with both buffer and stream encoders
}func (b *BeaconBlock) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, decoder sszutils.Decoder) error {
// Streaming-compatible decoding that works with both buffer and stream decoders
}These methods enable efficient streaming I/O by implementing the DynamicEncoder and DynamicDecoder interfaces. They are automatically used by MarshalSSZWriter and UnmarshalSSZReader when available.
Use case: Generate streaming methods for types that need memory-efficient encoding/decoding to/from io.Reader/io.Writer.
Performance note: Streaming trades memory for CPU time. Expect ~2x CPU overhead for unmarshal and ~1.3x for marshal operations, as streams cannot seek back to update offsets. See Streaming Support for details.
Ensure the type is exported and in the correct package:
# Specify correct package path
dynssz-gen -package github.com/myproject/types -types MyType -output output.goIf types reference each other, generate them together to avoid code duplication:
# Problem: Generating types separately causes massive code duplication
dynssz-gen -package . -types Block -output block_ssz.go # Duplicates Transaction marshaling code inline
dynssz-gen -package . -types Transaction -output tx_ssz.go
# Solution: Generate related types together
dynssz-gen -package . -types Block,Transaction -output types_ssz.go
# Or use per-type files but generate in single command
dynssz-gen -package . -types Block:block_ssz.go,Transaction:tx_ssz.goCheck that your type follows SSZ rules:
- No interfaces (except with
ssz-type) - No channels or functions
- Dynamic lists should have
ssz-maxtags (highly recommended for security)
If generated code differs from runtime behavior:
-
Regenerate with verbose mode:
dynssz-gen -v -package . -types MyType -output debug_ssz.go -
Check for custom interfaces that might affect generation
-
Verify all tags are correctly specified
If generated code doesn't compile:
- Ensure all imported types are available
- Check for circular dependencies
- Verify generated imports are correct
Do commit generated files to your repository:
This ensures:
- Code builds without requiring code generation
- No external tool dependencies for builds
- Consistent builds across environments
- Faster CI/build processes
Use consistent output file naming:
# Good patterns
types_ssz.go
generated_ssz.go
beacon_ssz_generated.goSet up automated regeneration:
# Pre-commit hook
#!/bin/sh
go generate ./...
git add *_ssz.goGenerate only needed methods:
codeGen.BuildFile("output.go",
codegen.WithNoUnmarshalSSZ(), // Only marshal and size
codegen.WithNoHashTreeRoot(),
codegen.WithReflectType(reflect.TypeOf(MyType{})),
)When generating multiple files, ensure proper cross-references:
# Generate all related types together for proper cross-references
dynssz-gen -package . -types Block:block_ssz.go,Transaction:tx_ssz.go,Header:block_ssz.go
# Or generate all at once
dynssz-gen -package . -types Block,Transaction,Header,Validator -output all_ssz.go# Generate all beacon chain types together for cross-references
dynssz-gen -package . -types BeaconBlock,BeaconState,Validator,Attestation,BeaconBlockBody -output consensus_types_ssz.go# Generate to separate files while maintaining cross-references
dynssz-gen -package . -types \
BeaconBlock:block_ssz.go,BeaconBlockBody:block_ssz.go,\
BeaconState:state_ssz.go,Validator:state_ssz.go,\
Attestation:attestation_ssz.go,AttestationData:attestation_ssz.go//go:generate dynssz-gen -package . -types Message,Header,Payload -output protocol_ssz.go
package protocol
type Message struct {
Header Header
Payload Payload `ssz-max:"65536"`
Sig [96]byte
}
type Header struct {
Version uint8
Timestamp uint64
Sender [20]byte
}
type Payload struct {
Type uint16
Data []byte `dynssz-max:"MAX_PAYLOAD_SIZE"`
}type ProgressiveState struct {
// Progressive list for efficiency
Validators []Validator `ssz-type:"progressive-list" dynssz-max:"VALIDATOR_LIMIT"`
// Progressive container with indices
Slot uint64 `ssz-index:"0"`
Extensions *Extensions `ssz-index:"100"`
}To migrate from fastssz code generation:
-
Install dynssz-gen:
go install github.com/pk910/dynamic-ssz/dynssz-gen@latest
-
Update generation commands:
# Old: sszgen -path types -output generated.ssz.go # New: dynssz-gen -package . -types BeaconBlock,BeaconState -output generated_ssz.go
-
Add legacy flag if needed:
dynssz-gen -legacy -package . -types BeaconBlock -output legacy_ssz.go -
Update imports in your code:
// Old: github.com/ferranbt/fastssz // New: github.com/pk910/dynamic-ssz
- Getting Started - Basic usage
- Code Generator Config File - YAML config file format
- API Reference - Generator API details
- SSZ Views - Fork handling with view descriptors
- Streaming Support - Streaming encoding/decoding
- SSZ Annotations - Supported tags
- Supported Types - Type compatibility