Skip to content

Latest commit

 

History

History
948 lines (693 loc) · 26.3 KB

File metadata and controls

948 lines (693 loc) · 26.3 KB

Code Generator

Dynamic SSZ includes a code generation tool (dynssz-gen) that generates optimized SSZ methods for your types, eliminating reflection overhead and improving performance.

Important: How to Use Generated Code

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.

Installation

go install github.com/pk910/dynamic-ssz/dynssz-gen@latest

Verify installation:

dynssz-gen -help

CLI Usage

Basic Usage

Generate SSZ methods for specific types:

dynssz-gen -package /path/to/package -types BeaconBlock,BeaconState -output generated_ssz.go

CLI Flags

Flag Description Default
-package Go package path to analyze Required
-types Comma-separated list of types to generate (see extended format below) Required
-output Output file path Required if types don't specify files
-v Verbose output false
-legacy Generate legacy compatibility methods false
-without-dynamic-expressions Generate only legacy methods, disable dynamic methods 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

Extended Type Specification Format

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"

Examples

Generate All Types to Single File

# In your project directory
dynssz-gen -package . -types Block,Transaction,Validator -output ssz_generated.go

Generate Types to Separate Files

# Each type to its own file
dynssz-gen -package . -types Block:block_ssz.go,Transaction:tx_ssz.go,Validator:validator_ssz.go

Mixed File Specification

# 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.go

Generate with View Support

Generate 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.go

See SSZ Views for detailed documentation on view support.

Generate for External Package

dynssz-gen -package github.com/myproject/types -types BeaconBlock -output beacon_ssz.go

Generate with Verbose Output

dynssz-gen -v -package . -types State,Block -output ssz_methods.go

Generate Legacy Methods

For compatibility with existing fastssz code:

dynssz-gen -legacy -package . -types BeaconState -output legacy_ssz.go

Generate Static Methods Only

For maximum performance with default preset:

dynssz-gen -without-dynamic-expressions -package . -types BeaconState -output static_ssz.go

Generate Both Dynamic and Legacy

For maximum flexibility:

dynssz-gen -legacy -package . -types BeaconState -output full_ssz.go

Generate Streaming Functions

For memory-efficient streaming to/from io.Reader/io.Writer:

dynssz-gen -with-streaming -package . -types BeaconState -output streaming_ssz.go

Programmatic API

Basic Example

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))
    
    // 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()
}

Multiple Files Example

func generateSSZMultipleFiles() error {
    codeGen := codegen.NewCodeGenerator(dynssz.NewDynSsz(nil))
    
    // 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()
}

Generator Options

import "github.com/pk910/dynamic-ssz/codegen"

// Create generator with options
codeGen := codegen.NewCodeGenerator(dynSsz)

// 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{})),
)

View Support Options

import "github.com/pk910/dynamic-ssz/codegen"

codeGen := codegen.NewCodeGenerator(dynSsz)

// 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.

Generated Methods

The code generator produces different methods depending on the flags used:

Default: Dynamic Methods (Spec-Aware)

By default, the generator creates dynamic methods that accept specification values:

MarshalSSZDyn

func (b *BeaconBlock) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) {
    // Generated marshaling with dynamic expression support
}

UnmarshalSSZDyn

func (b *BeaconBlock) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) {
    // Generated unmarshaling with dynamic expression support
}

SizeSSZDyn

func (b *BeaconBlock) SizeSSZDyn(ds sszutils.DynamicSpecs) (size int) {
    // Size calculation with dynamic expression support
}

HashTreeRootWithDyn

func (b *BeaconBlock) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error {
    // Hash tree root with dynamic expression support
}

With -legacy: Additional Legacy Methods

When using -legacy flag, additional fastssz-compatible methods are generated:

MarshalSSZ & MarshalSSZTo

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)
}

UnmarshalSSZ

func (b *BeaconBlock) UnmarshalSSZ(buf []byte) error {
    return b.UnmarshalSSZDyn(dynssz.GetGlobalDynSsz(), buf)
}

SizeSSZ

func (b *BeaconBlock) SizeSSZ() int {
    return b.SizeSSZDyn(dynssz.GetGlobalDynSsz())
}

HashTreeRoot

func (b *BeaconBlock) HashTreeRoot() ([32]byte, error) {
    // Optimized merkle root calculation using global specs
}

With -without-dynamic-expressions: Static Methods Only

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.

Integration with Build Process

Using go:generate

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 ./...

Makefile Integration

.PHONY: generate-ssz
generate-ssz:
    dynssz-gen -package . -types Block,State,Transaction -output ssz_generated.go

.PHONY: build
build: generate-ssz
    go build ./...

CI/CD Integration

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 ./...

Type Support

The generator supports all Dynamic SSZ types and annotations:

Basic Types

  • All unsigned integers: uint8, uint16, uint32, uint64
  • Boolean: bool
  • Fixed arrays: [N]T
  • Slices: []T
  • Byte arrays: []byte, [N]byte
  • Strings: string

Non-Struct Types with sszutils.Annotate[T]()

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.go

The 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.

Advanced Types

  • Large integers: byte arrays or uint64 arrays with ssz-type:"uint256"
  • Bitfields
  • Progressive types
  • Unions: CompatibleUnion[T]
  • Type wrappers: TypeWrapper[D, T]

Annotations

All SSZ annotations are supported:

  • ssz-size
  • ssz-max
  • ssz-type
  • ssz-bitsize (bit-level sizing for bitvectors)
  • dynssz-size
  • dynssz-max
  • dynssz-bitsize (dynamic bit-level sizing for bitvectors)
  • ssz-index

Performance Benefits

Generated code eliminates reflection overhead, pre-calculates sizes, and reduces allocations. See the benchmark repository for real performance comparisons across SSZ libraries.

Advanced Features

Cross-Reference Handling

The code generator automatically handles cross-references between types when they're generated together. This prevents massive code duplication.

How it works:

  1. When generating multiple types, the generator analyzes all types first
  2. If a type references another type being generated, it calls the generated method on that type
  3. If the generator doesn't know about a referenced type, it duplicates the entire marshaling logic inline
  4. 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.go

Generated 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 included

Generated 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.go

Custom Type Handling

The 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
}

Dynamic Expression Support

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 := ds.GetValue("VALIDATOR_REGISTRY_LIMIT")
    // ... use dynamic value for different presets
}

Static Expression Optimization

With -without-dynamic-expressions, expressions are resolved at generation time:

// 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
}

Method Generation Modes

Default Mode (Dynamic Only)

dynssz-gen -package . -types BeaconBlock -output block_ssz.go

Generates: MarshalSSZDyn, UnmarshalSSZDyn, SizeSSZDyn, HashTreeRootWithDyn

Legacy Mode (Dynamic + Legacy)

dynssz-gen -legacy -package . -types BeaconBlock -output block_ssz.go

Generates: All dynamic methods + MarshalSSZ, UnmarshalSSZ, SizeSSZ, HashTreeRoot, MarshalSSZTo

Static Mode (Legacy Only)

dynssz-gen -without-dynamic-expressions -package . -types BeaconBlock -output block_ssz.go

Generates: 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.

With Views: View-Aware Methods

When using the views= type specification, view-aware methods are generated that allow the same runtime type to be serialized with different SSZ schemas:

MarshalSSZDynView

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
}

UnmarshalSSZDynView

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
}

SizeSSZDynView

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
}

HashTreeRootWithDynView

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.

With -with-streaming: Streaming Encoder/Decoder Methods

When using -with-streaming flag, streaming-capable methods are generated:

MarshalSSZEncoder

func (b *BeaconBlock) MarshalSSZEncoder(ds sszutils.DynamicSpecs, encoder sszutils.Encoder) error {
    // Streaming-compatible encoding that works with both buffer and stream encoders
}

UnmarshalSSZDecoder

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.

Troubleshooting

"Type not found" Error

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.go

Cross-Reference Issues

If 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.go

"Invalid type" Error

Check that your type follows SSZ rules:

  • No interfaces (except with ssz-type)
  • No channels or functions
  • Dynamic lists should have ssz-max tags (highly recommended for security)

Generation Differences

If generated code differs from runtime behavior:

  1. Regenerate with verbose mode:

    dynssz-gen -v -package . -types MyType -output debug_ssz.go
  2. Check for custom interfaces that might affect generation

  3. Verify all tags are correctly specified

Build Errors

If generated code doesn't compile:

  1. Ensure all imported types are available
  2. Check for circular dependencies
  3. Verify generated imports are correct

Best Practices

1. Version Control

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

2. Consistent Naming

Use consistent output file naming:

# Good patterns
types_ssz.go
generated_ssz.go
beacon_ssz_generated.go

3. Regular Regeneration

Set up automated regeneration:

# Pre-commit hook
#!/bin/sh
go generate ./...
git add *_ssz.go

4. Partial Generation

Generate only needed methods:

codeGen.BuildFile("output.go",
    codegen.WithNoUnmarshalSSZ(),      // Only marshal and size
    codegen.WithNoHashTreeRoot(),
    codegen.WithReflectType(reflect.TypeOf(MyType{})),
)

5. Cross-Reference Handling

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

Examples

Ethereum Beacon Chain Types

# Generate all beacon chain types together for cross-references
dynssz-gen -package . -types BeaconBlock,BeaconState,Validator,Attestation,BeaconBlockBody -output consensus_types_ssz.go

Separate Files with Cross-References

# 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

Custom Protocol

//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"`
}

With Progressive Types

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"`
}

Migration from fastssz

To migrate from fastssz code generation:

  1. Install dynssz-gen:

    go install github.com/pk910/dynamic-ssz/dynssz-gen@latest
  2. Update generation commands:

    # Old: sszgen -path types -output generated.ssz.go
    # New:
    dynssz-gen -package . -types BeaconBlock,BeaconState -output generated_ssz.go
  3. Add legacy flag if needed:

    dynssz-gen -legacy -package . -types BeaconBlock -output legacy_ssz.go
  4. Update imports in your code:

    // Old: github.com/ferranbt/fastssz
    // New: github.com/pk910/dynamic-ssz

Related Documentation