bin+lib papyrus_storage

A storage implementation for a Starknet node

26 releases (4 breaking)

0.4.0-rc.0 Jul 15, 2024
0.4.0-dev.3 Jun 10, 2024
0.3.0 Mar 5, 2024
0.2.2 Dec 19, 2023
0.0.3 Jul 27, 2023
Download history 2204/week @ 2024-06-17 2189/week @ 2024-06-24 1085/week @ 2024-07-01 708/week @ 2024-07-08 823/week @ 2024-07-15 1070/week @ 2024-07-22 346/week @ 2024-07-29 204/week @ 2024-08-05 189/week @ 2024-08-12 42/week @ 2024-08-19 20/week @ 2024-08-26 33/week @ 2024-09-02 21/week @ 2024-09-09 76/week @ 2024-09-16 90/week @ 2024-09-23 90/week @ 2024-09-30

280 downloads per month
Used in native_blockifier

Custom license

1MB
11K SLoC

papyrus-storage

Description

papyrus-storage provides a writing and reading interface for various Starknet data structures to a database, designed specifically for Papyrus, a Starknet node.


lib.rs:

A storage implementation for a Starknet node.

This crate provides a writing and reading interface for various Starknet data structures to a database. Enables at most one writing operation and multiple reading operations concurrently. The underlying storage is implemented using the libmdbx crate.

Disclaimer

This crate is still under development and is not keeping backwards compatibility with previous versions. Breaking changes are expected to happen in the near future.

Quick Start

To use this crate, open a storage by calling open_storage to get a StorageWriter and a StorageReader and use them to create StorageTxn instances. The actual functionality is implemented on the transaction in multiple traits.

use papyrus_storage::open_storage;
use papyrus_storage::header::{HeaderStorageReader, HeaderStorageWriter};    // Import the header API.
use starknet_api::block::{BlockHeader, BlockNumber, StarknetVersion};
use starknet_api::core::ChainId;

let db_config = DbConfig {
    path_prefix: dir,
    chain_id: ChainId::Mainnet,
    enforce_file_exists: false,
    min_size: 1 << 20,    // 1MB
    max_size: 1 << 35,    // 32GB
    growth_step: 1 << 26, // 64MB
};
let (reader, mut writer) = open_storage(storage_config)?;
writer
    .begin_rw_txn()?                                            // Start a RW transaction.
    .append_header(BlockNumber(0), &BlockHeader::default())?    // Append a header.
    .commit()?;                                                 // Commit the changes.

let header = reader.begin_ro_txn()?.get_block_header(BlockNumber(0))?;  // Read the header.
assert_eq!(header, Some(BlockHeader::default()));

Storage Version

Attempting to open an existing database using a crate version with a mismatching storage version will result in an error.

The storage version is composed of two components: STORAGE_VERSION_STATE for the state and STORAGE_VERSION_BLOCKS for blocks. Each version consists of a major and a minor version. A higher major version indicates that a re-sync is necessary, while a higher minor version indicates a change that is migratable.

When a storage is opened with StorageScope::StateOnly, only the state version must match. For storage opened with StorageScope::FullArchive, both versions must match the crate's versions.

Incompatibility occurs when the code and the database have differing major versions. However, if the code has the same major version but a higher minor version compared to the database, it will still function properly.

Example cases:

  • Code: {major: 0, minor: 0}, Database: {major: 1, minor: 0} will fail due to major version inequality.
  • Code: {major: 0, minor: 0}, Database: {major: 0, minor: 1} will fail due to the smaller code's minor version.
  • Code: {major: 0, minor: 1}, Database: {major: 0, minor: 0} will succeed since the major versions match and the code's minor version is higher.

Dependencies

~27–41MB
~679K SLoC