Dynamic SSZ is a Go library for SSZ encoding/decoding with support for dynamic field sizes and code generation. It provides runtime flexibility while maintaining high performance through optional static code generation.
- 🔧 Dynamic Field Sizes - Support for runtime-determined field sizes based on configuration
- ⚡ Reflection-Based Processing - Works instantly with any SSZ-compatible types - no code generation required for prototyping
- 🏗️ Code Generation - Optional static code generation for maximum performance (2-3x faster than dynamic processing)
- 🚀 CLI Tool - Standalone
dynssz-gencommand for easy code generation from any Go package - 🔄 Hybrid Approach - Seamlessly combines with fastssz for optimal efficiency
- 📦 Minimal Dependencies - Core library has minimal external dependencies
- ✅ Spec Compliant - Fully compliant with SSZ specification and Ethereum consensus tests
- ✅ Reflection-based dynamic marshaling/unmarshaling/HTR: Production ready - battle-tested in various toolings and stable
- 🚧 Code generator: Feature complete but in beta stage - hasn't been extensively tested in production environments
go get github.com/pk910/dynamic-sszimport "github.com/pk910/dynamic-ssz"
// Define your types with SSZ tags
type MyStruct struct {
FixedArray [32]byte
DynamicList []uint64 `ssz-max:"1000"`
ConfigBased []byte `ssz-max:"1024" dynssz-max:"MAX_SIZE"`
}
// Create a DynSsz instance with your configuration
specs := map[string]any{
"MAX_SIZE": uint64(2048),
}
ds := dynssz.NewDynSsz(specs)
// Marshal
data, err := ds.MarshalSSZ(myObject)
// Unmarshal
err = ds.UnmarshalSSZ(&myObject, data)
// Hash Tree Root
root, err := ds.HashTreeRoot(myObject)For maximum performance, use code generation. You can use either the CLI tool or the programmatic API:
Install the CLI tool:
go install github.com/pk910/dynamic-ssz/dynssz-gen@latestGenerate SSZ methods:
# Generate for types in current package
dynssz-gen -package . -types "MyStruct,OtherType" -output generated.go
# Generate for types in external package
dynssz-gen -package github.com/example/types -types "Block" -output block_ssz.goFor integration with build systems:
//go:generate go run codegen.go
// codegen.go
package main
import (
"github.com/pk910/dynamic-ssz/codegen"
"reflect"
)
func main() {
generator := codegen.NewCodeGenerator(nil)
generator.BuildFile(
"generated.go",
codegen.WithReflectType(reflect.TypeOf(MyStruct{})),
)
generator.Generate()
}Both approaches generate optimized SSZ methods that are faster than reflection-based encoding.
The performance of dynssz has been benchmarked against fastssz using BeaconBlocks and BeaconStates from small kurtosis testnets, providing a consistent and comparable set of data. These benchmarks compare four scenarios: exclusively using fastssz, exclusively using dynssz, a hybrid approach where dynssz defaults to fastssz for static types, and dynssz with code generation for maximum performance. The results highlight the balance between flexibility and speed:
Legend:
- First number: Unmarshalling time in milliseconds.
- Second number: Marshalling time in milliseconds.
- Third number: Hash tree root time in milliseconds.
- fastssz only: [6 ms / 2 ms / 87 ms] success
- dynssz only: [29 ms / 15 ms / 57 ms] success
- dynssz + fastssz: [9 ms / 3 ms / 64 ms] success
- dynssz + codegen: [6 ms / 2 ms / 55 ms] success
- fastssz only: [5963 ms / 4026 ms / 70919 ms] success
- dynssz only: [15728 ms / 13841 ms / 49248 ms] success
- dynssz + fastssz: [6139 ms / 4094 ms / 36042 ms] success
- dynssz + codegen: [6344 ms / 4869 ms / 36084 ms] success
- fastssz only: failed (unmarshal error: invalid ssz encoding. first variable element offset indexes into fixed value data)
- dynssz only: [34 ms / 20 ms / 78 ms] success
- dynssz + fastssz: [18 ms / 12 ms / 120 ms] success
- dynssz + codegen: [8 ms / 8 ms / 69 ms] success
- fastssz only: failed (unmarshal error: incorrect size)
- dynssz only: [762 ms / 434 ms / 1553 ms] success
- dynssz + fastssz: [413 ms / 264 ms / 3921 ms] success
- dynssz + codegen: [172 ms / 100 ms / 1329 ms] success
These results showcase the dynamic processing capabilities of dynssz, particularly its ability to handle data structures that fastssz cannot process due to its static nature. The code generation option provides the best of both worlds: the flexibility to handle any preset configuration while delivering performance that matches or exceeds fastssz. The hybrid approach with fastssz provides excellent performance for compatible types, while code generation delivers optimal performance across all scenarios.
The library includes comprehensive testing infrastructure:
- Unit Tests: Fast, isolated tests for core functionality
- Spec Tests: Ethereum consensus specification compliance tests
- Examples: Working examples that are automatically tested
- Performance Tests: Benchmarking and regression testing
- Getting Started Guide
- API Reference
- Supported Types
- Code Generation Guide
- Struct Tags & Annotations
- Performance Guide
- Examples
Check out the examples directory for:
- Basic encoding/decoding
- Code generation setup
- Ethereum types integration
- Custom specifications
- Multi-dimensional arrays
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
Dynamic SSZ is licensed under the Apache 2.0 License.