dynssz

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Apr 1, 2024 License: LGPL-3.0 Imports: 7 Imported by: 16

README

Dynamic SSZ (dynssz)

Dynamic SSZ (dynssz) is a Go library designed to provide flexible and dynamic SSZ encoding/decoding for Ethereum data structures. It stands out by using runtime reflection to handle serialization and deserialization of types with variable field sizes, enabling it to support a wide range of Ethereum presets beyond the mainnet. dynssz integrates with fastssz to leverage static type information for encoding/decoding when possible, but its primary advantage lies in its ability to adapt to dynamic field sizes that are not well-suited to static code generation methods.

Features

  • Dynamic Field Sizes: Dynamically handles SSZ encoding/decoding with variable field sizes at runtime.
  • Integration with FastSSZ: Uses fastssz for parts of the serialization process when static type information is applicable, offering a balanced approach to handling Ethereum data.
  • Support for Various Ethereum Presets: Capable of working with non-mainnet Ethereum presets, facilitating a broader range of applications.
  • Minimal Performance Overhead: Designed to minimize the performance impact of dynamic serialization.

Installation

To install dynssz, use the go get command:

go get github.com/pk910/dynamic-ssz

This will download and install the dynssz package into your Go workspace.

Usage

Creating a New DynSsz Instance
import "github.com/pk910/dynamic-ssz"

// Define your dynamic specifications
specs := map[string]any{
    "SYNC_COMMITTEE_SIZE": uint64(32),
    // ...
}

ds := dynssz.NewDynSsz(specs)
Struct Tag Annotations for Dynamic Encoding/Decoding

dynssz utilizes struct tag annotations to indicate how fields should be encoded/decoded, supporting both static and dynamic field sizes:

  • ssz-size: Defines static default field sizes. This tag follows the same format supported by fastssz, allowing seamless integration.
  • dynssz-size: Specifies dynamic sizes derived from spec properties. Use this tag in conjunction with ssz-size for fields that require dynamic sizing. When the resolved size differs from the default, dynssz switches to dynamic handling for that field.

Fields with static sizes do not need the dynssz-size tag. Here's an example of a structure using both tags:

type BeaconState struct {
    GenesisTime                  uint64
    GenesisValidatorsRoot        phase0.Root `ssz-size:"32"`
    Slot                         phase0.Slot
    Fork                         *phase0.Fork
    LatestBlockHeader            *phase0.BeaconBlockHeader
    BlockRoots                   []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"`
    StateRoots                   []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"`
    ...
}
Marshaling an Object
data, err := ds.MarshalSSZ(myObject)
if err != nil {
    log.Fatalf("Failed to marshal SSZ: %v", err)
}
Unmarshaling an Object
err := ds.UnmarshalSSZ(&myObject, data)
if err != nil {
    log.Fatalf("Failed to unmarshal SSZ: %v", err)
}

Performance

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 three scenarios: exclusively using fastssz, exclusively using dynssz, and a combined approach where dynssz defaults to fastssz for static types that do not require dynamic processing. The results highlight the balance between flexibility and speed:

Legend:

  • First number: Unmarshalling time in milliseconds.
  • Second number: Marshalling time in milliseconds.
Mainnet Preset
BeaconBlock Decode + Encode (10,000 times)
  • fastssz only: [4 ms / 2 ms] success
  • dynssz only: [356 ms / 422 ms] success
  • dynssz + fastssz: [12 ms / 6 ms] success
BeaconState Decode + Encode (10,000 times)
  • fastssz only: [12416 ms / 7817 ms] success
  • dynssz only: [38020 ms / 25964 ms] success
  • dynssz + fastssz: [11256 ms / 8135 ms] success
Minimal Preset
BeaconBlock Decode + Encode (10,000 times)
  • fastssz only: [0 ms / 0 ms] failed (unmarshal error)
  • dynssz only: [347 ms / 582 ms] success
  • dynssz + fastssz: [251 ms / 283 ms] success
BeaconState Decode + Encode (10,000 times)
  • fastssz only: [0 ms / 0 ms] failed (unmarshal error)
  • dynssz only: [8450 ms / 8036 ms] success
  • dynssz + fastssz: [1554 ms / 1096 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. While dynssz introduces additional processing time, its flexibility allows it to successfully manage both mainnet and minimal presets. The combined dynssz and fastssz approach significantly improves performance while maintaining this flexibility, making it a viable solution for applications requiring dynamic SSZ processing.

Contributing

We welcome contributions from the community! Please check out the CONTRIBUTING.md file for guidelines on how to contribute to dynssz.

License

dynssz is licensed under the LGPL License. See the LICENSE file for more details.

Acknowledgements

Thanks to all the contributors and the Ethereum community for providing the inspiration and foundation for this project.

Documentation

Overview

dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.

Package dynssz provides dynamic SSZ (Simple Serialize) encoding and decoding for Ethereum data structures. Unlike static code generation approaches, dynssz uses runtime reflection to handle dynamic field sizes, making it suitable for various Ethereum presets beyond the mainnet. It seamlessly integrates with fastssz for optimal performance when static definitions are applicable.

Copyright (c) 2024 by pk910. See LICENSE file for details.

dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.

dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.

dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.

dynssz: Dynamic SSZ encoding/decoding for Ethereum with fastssz efficiency. This file is part of the dynssz package. Copyright (c) 2024 by pk910. Refer to LICENSE for more information.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DynSsz

type DynSsz struct {
	NoFastSsz bool
	// contains filtered or unexported fields
}

func NewDynSsz

func NewDynSsz(specs map[string]any) *DynSsz

NewDynSsz creates a new instance of the DynSsz encoder/decoder. The 'specs' map contains dynamic properties and configurations that will be applied during SSZ serialization and deserialization processes. This allows for flexible and dynamic handling of SSZ encoding/decoding based on the given specifications, making it suitable for various Ethereum presets and custom scenarios. Returns a pointer to the newly created DynSsz instance, ready for use in serializing and deserializing operations.

func (*DynSsz) MarshalSSZ

func (d *DynSsz) MarshalSSZ(source any) ([]byte, error)

MarshalSSZ serializes the given source into its SSZ (Simple Serialize) representation. It dynamically handles the serialization of types, including those with dynamic field sizes, by leveraging reflection at runtime. This method integrates with fastssz for types without dynamic specifications, optimizing performance. It returns the serialized data as a byte slice, or an error if serialization fails.

func (*DynSsz) MarshalSSZTo

func (d *DynSsz) MarshalSSZTo(source any, buf []byte) ([]byte, error)

MarshalSSZTo serializes the given source into its SSZ (Simple Serialize) representation and writes the output to the provided buffer. This method allows direct control over the serialization output buffer, allowing optimizations like buffer reuse. The 'source' parameter is the structure to be serialized, and 'buf' is the pre-allocated slice where the serialized data will be written. It dynamically handles serialization for types with dynamic field sizes, seamlessly integrating with fastssz when possible. Returns the updated buffer containing the serialized data and an error if serialization fails.

func (*DynSsz) SizeSSZ

func (d *DynSsz) SizeSSZ(source any) (int, error)

SizeSSZ calculates the size of the given source object when serialized using SSZ encoding. This function is useful for pre-determining the amount of space needed to serialize a given source object. The 'source' parameter can be any Go value. It dynamically evaluates the size, accommodating types with dynamic field sizes efficiently. Returns the calculated size as an int and an error if the process fails.

func (*DynSsz) UnmarshalSSZ

func (d *DynSsz) UnmarshalSSZ(target any, ssz []byte) error

UnmarshalSSZ decodes the given SSZ-encoded data into the target object. The 'ssz' byte slice contains the SSZ-encoded data, and 'target' is a pointer to the Go value that will hold the decoded data. This method dynamically handles the decoding, accommodating for types with dynamic field sizes. It seamlessly integrates with fastssz for types without dynamic specifications to ensure efficient decoding. Returns an error if decoding fails or if the provided ssz data has not been fully used for decoding.

Directories

Path Synopsis
dynssz-gen module
test module

Jump to

Keyboard shortcuts

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