store

package
v1.0.0-beta.6 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2025 License: Apache-2.0 Imports: 15 Imported by: 0

README

Evolve Storage System

The store package provides a persistent storage solution for Evolve, designed to efficiently store and retrieve blockchain data such as blocks, signatures, state, and metadata.

Overview

The storage system consists of a key-value store interface that allows for the persistence of blockchain data. It leverages the IPFS Datastore interface (go-datastore) with a Badger database implementation by default.

Core Components

Storage Interface

The main interface (Store) defines methods for:

  • Block data storage and retrieval
  • State management
  • Metadata storage
  • Height tracking and querying
Implementation

The DefaultStore is the standard implementation of the Store interface, utilizing a key-value datastore.

Data Organization

The store organizes data using a prefix-based key system:

Prefix Purpose Key Format
h Block headers /h/{height}
d Block data /d/{height}
i Block index (hash -> height) /i/{hash}
c Block signatures /c/{height}
s Chain state s
m Metadata /m/{key}

Block Storage Sequence

sequenceDiagram
    participant App as Application
    participant Store as DefaultStore
    participant DS as Datastore

    App->>Store: SaveBlockData(header, data, signature)
    Store->>Store: Prepare batch
    Store->>DS: Put header
    Store->>DS: Put data
    Store->>DS: Put signature
    Store->>DS: Put block hash → height index
    Store->>DS: Commit batch

    App->>Store: GetBlockData(height)
    Store->>DS: Get header
    DS->>Store: Return header blob
    Store->>Store: Unmarshal header
    Store->>DS: Get data
    DS->>Store: Return data blob
    Store->>Store: Unmarshal data
    Store->>App: Return header, data

Store Component Architecture

classDiagram
    class Store {
        <<interface>>
        +Height() uint64
        +SetHeight(ctx, height)
        +SaveBlockData(ctx, header, data, signature) error
        +GetBlockData(ctx, height) (header, data, error)
        +GetBlockByHash(ctx, hash) (header, data, error)
        +GetSignature(ctx, height) (signature, error)
        +GetSignatureByHash(ctx, hash) (signature, error)
        +UpdateState(ctx, state) error
        +GetState(ctx) (state, error)
        +SetMetadata(ctx, key, value) error
        +GetMetadata(ctx, key) (value, error)
        +Close() error
    }

    class DefaultStore {
        -db ds.Batching
        -height atomic.Uint64
        +Height() uint64
        +SetHeight(ctx, height)
        +SaveBlockData(ctx, header, data, signature) error
        +GetBlockData(ctx, height) (header, data, error)
        +GetBlockByHash(ctx, hash) (header, data, error)
        +GetSignature(ctx, height) (signature, error)
        +GetSignatureByHash(ctx, hash) (signature, error)
        +UpdateState(ctx, state) error
        +GetState(ctx) (state, error)
        +SetMetadata(ctx, key, value) error
        +GetMetadata(ctx, key) (value, error)
        +Close() error
    }

    class Datastore {
        <<interface>>
        +Put(key, value) error
        +Get(key) (value, error)
        +Has(key) (exists, error)
        +Delete(key) error
        +Query(q query.Query) (Results, error)
        +Close() error
    }

    Store <|.. DefaultStore
    DefaultStore --> Datastore : uses

Usage Examples

Creating a Store
// In-memory store (for testing)
kvStore, err := store.NewDefaultInMemoryKVStore()
if err != nil {
    // handle error
}
myStore := store.New(kvStore)

// Persistent store
kvStore, err := store.NewDefaultKVStore("/path/to/root", "data", "ev-db")
if err != nil {
    // handle error
}
myStore := store.New(kvStore)
Saving and Retrieving Data
// Save block data
err := myStore.SaveBlockData(ctx, header, data, signature)

// Get block by height
header, data, err := myStore.GetBlockData(ctx, height)

// Get block by hash
header, data, err := myStore.GetBlockByHash(ctx, blockHash)

// Update state
err := myStore.UpdateState(ctx, newState)

// Get current state
state, err := myStore.GetState(ctx)

// Store metadata
err := myStore.SetMetadata(ctx, "myKey", []byte("myValue"))

// Retrieve metadata
value, err := myStore.GetMetadata(ctx, "myKey")

Advanced Usage: Batching Operations

For performance-critical operations, the underlying datastore supports batching:

batch, err := kvStore.Batch(ctx)
if err != nil {
    // handle error
}

// Add operations to batch
batch.Put(ctx, key1, value1)
batch.Put(ctx, key2, value2)
batch.Delete(ctx, key3)

// Commit all operations atomically
err = batch.Commit(ctx)

Documentation

Index

Constants

View Source
const (
	// GenesisDAHeightKey is the key used for persisting the first DA included height in store.
	// It avoids to walk over the HeightToDAHeightKey to find the first DA included height.
	GenesisDAHeightKey = "gdh"

	// HeightToDAHeightKey is the key prefix used for persisting the mapping from a Evolve height
	// to the DA height where the block's header/data was included.
	// Full keys are like: rhb/<evolve_height>/h and rhb/<evolve_height>/d
	HeightToDAHeightKey = "rhb"

	// DAIncludedHeightKey is the key used for persisting the da included height in store.
	DAIncludedHeightKey = "d"

	// LastBatchDataKey is the key used for persisting the last batch data in store.
	LastBatchDataKey = "l"

	// LastSubmittedHeaderHeightKey is the key used for persisting the last submitted header height in store.
	LastSubmittedHeaderHeightKey = "last-submitted-header-height"
)

Variables

This section is empty.

Functions

func GenerateKey

func GenerateKey(fields []string) string

GenerateKey creates a key from a slice of string fields, joining them with slashes.

func NewDefaultInMemoryKVStore

func NewDefaultInMemoryKVStore() (ds.Batching, error)

NewDefaultInMemoryKVStore builds KVStore that works in-memory (without accessing disk).

func NewDefaultKVStore

func NewDefaultKVStore(rootDir, dbPath, dbName string) (ds.Batching, error)

NewDefaultKVStore creates instance of default key-value store.

func PrefixEntries

func PrefixEntries(ctx context.Context, store ds.Datastore, prefix string) (dsq.Results, error)

PrefixEntries retrieves all entries in the datastore whose keys have the supplied prefix

Types

type DefaultStore

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

DefaultStore is a default store implementation.

func (*DefaultStore) Close

func (s *DefaultStore) Close() error

Close safely closes underlying data storage, to ensure that data is actually saved.

func (*DefaultStore) GetBlockByHash

func (s *DefaultStore) GetBlockByHash(ctx context.Context, hash []byte) (*types.SignedHeader, *types.Data, error)

GetBlockByHash returns block with given block header hash, or error if it's not found in Store.

func (*DefaultStore) GetBlockData

func (s *DefaultStore) GetBlockData(ctx context.Context, height uint64) (*types.SignedHeader, *types.Data, error)

GetBlockData returns block header and data at given height, or error if it's not found in Store.

func (*DefaultStore) GetHeader

func (s *DefaultStore) GetHeader(ctx context.Context, height uint64) (*types.SignedHeader, error)

GetHeader returns the header at the given height or error if it's not found in Store.

func (*DefaultStore) GetMetadata

func (s *DefaultStore) GetMetadata(ctx context.Context, key string) ([]byte, error)

GetMetadata returns values stored for given key with SetMetadata.

func (*DefaultStore) GetSignature

func (s *DefaultStore) GetSignature(ctx context.Context, height uint64) (*types.Signature, error)

GetSignature returns signature for a block with given block header hash, or error if it's not found in Store.

func (*DefaultStore) GetSignatureByHash

func (s *DefaultStore) GetSignatureByHash(ctx context.Context, hash []byte) (*types.Signature, error)

GetSignatureByHash returns signature for a block at given height, or error if it's not found in Store.

func (*DefaultStore) GetState

func (s *DefaultStore) GetState(ctx context.Context) (types.State, error)

GetState returns last state saved with UpdateState.

func (*DefaultStore) GetStateAtHeight

func (s *DefaultStore) GetStateAtHeight(ctx context.Context, height uint64) (types.State, error)

GetStateAtHeight returns the state at the given height. If no state is stored at that height, it returns an error.

func (*DefaultStore) Height

func (s *DefaultStore) Height(ctx context.Context) (uint64, error)

Height returns height of the highest block saved in the Store.

func (*DefaultStore) Rollback

func (s *DefaultStore) Rollback(ctx context.Context, height uint64, aggregator bool) error

Rollback rolls back block data until the given height from the store. When aggregator is true, it will check the latest data included height and prevent rollback further than that. NOTE: this function does not rollback metadata. Those should be handled separately if required. Other stores are not rolled back either.

func (*DefaultStore) SaveBlockData

func (s *DefaultStore) SaveBlockData(ctx context.Context, header *types.SignedHeader, data *types.Data, signature *types.Signature) error

SaveBlockData adds block header and data to the store along with corresponding signature. Stored height is updated if block height is greater than stored value.

func (*DefaultStore) SetHeight

func (s *DefaultStore) SetHeight(ctx context.Context, height uint64) error

SetHeight sets the height saved in the Store if it is higher than the existing height

func (*DefaultStore) SetMetadata

func (s *DefaultStore) SetMetadata(ctx context.Context, key string, value []byte) error

SetMetadata saves arbitrary value in the store.

Metadata is separated from other data by using prefix in KV.

func (*DefaultStore) UpdateState

func (s *DefaultStore) UpdateState(ctx context.Context, state types.State) error

UpdateState updates state saved in Store. Only one State is stored. If there is no State in Store, state will be saved.

type Store

type Store interface {
	// Height returns height of the highest block in store.
	Height(ctx context.Context) (uint64, error)

	// SetHeight sets the height saved in the Store if it is higher than the existing height.
	SetHeight(ctx context.Context, height uint64) error

	// SaveBlockData saves block along with its seen signature (which will be included in the next block).
	SaveBlockData(ctx context.Context, header *types.SignedHeader, data *types.Data, signature *types.Signature) error

	// GetBlockData returns block at given height, or error if it's not found in Store.
	GetBlockData(ctx context.Context, height uint64) (*types.SignedHeader, *types.Data, error)
	// GetBlockByHash returns block with given block header hash, or error if it's not found in Store.
	GetBlockByHash(ctx context.Context, hash []byte) (*types.SignedHeader, *types.Data, error)

	// GetHeader returns the header at the given height or error if it's not found in Store.
	GetHeader(ctx context.Context, height uint64) (*types.SignedHeader, error)

	// GetSignature returns signature for a block at given height, or error if it's not found in Store.
	GetSignature(ctx context.Context, height uint64) (*types.Signature, error)
	// GetSignatureByHash returns signature for a block with given block header hash, or error if it's not found in Store.
	GetSignatureByHash(ctx context.Context, hash []byte) (*types.Signature, error)

	// UpdateState updates state saved in Store. Only one State is stored.
	// If there is no State in Store, state will be saved.
	UpdateState(ctx context.Context, state types.State) error
	// GetState returns last state saved with UpdateState.
	GetState(ctx context.Context) (types.State, error)
	// GetStateAtHeight returns state saved at given height, or error if it's not found in Store.
	GetStateAtHeight(ctx context.Context, height uint64) (types.State, error)

	// SetMetadata saves arbitrary value in the store.
	//
	// This method enables evolve to safely persist any information.
	SetMetadata(ctx context.Context, key string, value []byte) error

	// GetMetadata returns values stored for given key with SetMetadata.
	GetMetadata(ctx context.Context, key string) ([]byte, error)

	// Rollback deletes x height from the ev-node store.
	// Aggregator is used to determine if the rollback is performed on the aggregator node.
	Rollback(ctx context.Context, height uint64, aggregator bool) error

	// Close safely closes underlying data storage, to ensure that data is actually saved.
	Close() error
}

Store is minimal interface for storing and retrieving blocks, commits and state.

func New

func New(ds ds.Batching) Store

New returns new, default store.

Jump to

Keyboard shortcuts

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