Astreum

BLOCKCHAIN STORAGE

Storage System

A content-addressed, two-tier storage system where every expression is identified by its BLAKE3 hash. Hot storage keeps data in memory; cold storage persists to disk. Nodes automatically advertise what they hold and request what they need.

Content-Addressed Storage

  • Every expression is stored and retrieved by its 32-byte BLAKE3 hash. The hash is the address.
  • Expressions form a DAG: a link pair can reference sub-expressions by hash pointer rather than embedding them inline. This enables lazy resolution.
  • The storage layer is content-agnostic — it stores raw expression bytes regardless of whether they represent a block, transaction, account state, or application data.

Hot Storage (In-Memory)

  • An in-memory cache for frequently accessed expressions. Implemented as a dictionary keyed by expression hash.
  • Size limit — configurable via hot_storage_limit (default 1 GiB). When the limit is exceeded, least-recently-used entries are evicted.
  • Newly created expressions (blocks, transactions) are written to hot storage first. They are later flushed to cold storage.
  • Storage advertisements are generated from hot storage contents.

Cold Storage (On-Disk)

  • Persistent on-disk storage for long-term data retention. Configured via cold_storage_path (directory) and cold_storage_limit (default 10 GiB).
  • Level-based rollup — data is organized into levels (level_0). Each level has a configurable base unit size (cold_storage_scale: KB, MB, or GB). When a level exceeds its threshold, it merges into the next level.
  • Expressions are serialized to binary and written to level files. An index maps expression hashes to file offsets for O(1) retrieval.
  • Cold storage is initialized on node startup via setup_storage.

Storage Advertisements

  • Nodes periodically announce which expressions they hold via storage advertisements broadcast to peers.
  • An advertisement contains a list of expression hashes the node can serve.
  • A background thread (advertise_storage) runs at a configurable interval (storage_index_interval, default 600 s / 10 min) to scan local storage and broadcast advertisements.
  • Expressions can also be advertised immediately via node.add_expr_advertisement(expr_hash) or node.add_expr_advertisements(expr_hashes).

Storage Requests and Retrieval

  • When a node needs an expression it doesn't have, it broadcasts a STORAGE_REQUEST message containing the expression hash and an offered payment.
  • Peers that hold the expression respond with a STORAGE_RESPONSE containing the serialized expression data.
  • Request tracking — the node maintains a queue of pending requests (node.expr_requests) and a deduplication set (node.add_expr_req / node.has_expr_req).
  • Retries — if a request isn't fulfilled, it is retried up to storage_fetch_retries times (default 8) at intervals of storage_fetch_interval (default 0.25 s).

Storage Pricing

  • Storage retrieval uses a fair-use model. Nodes serve data for free up to fair_use_limit (default 1 MiB) per peer.
  • Beyond the free limit, service continues at no cost as long as the peer's download/upload ratio stays at or above fair_use_ratio (default 0.5). Peers that share data back adequately are never asked to pay.
  • Payment is only requested when a peer exceeds both thresholds. The required price adjusts dynamically based on inbound request pressure (storage_request_current_price, recalculated every storage_request_price_interval seconds).
  • Higher request volume drives the price up; lower volume lets it decay. A floor is enforced via storage_request_minimum_price (default 1).

Storage Contracts

  • When expressions are created on-chain (e.g., via acc.put or contract deployment), a storage contract is generated.
  • The contract records the expression hash, the account that owns it, and a slot allocation in the storage radix trie.
  • Contracts are stored in the special storage account (0x0000...00). Each contract is an expression with slots that can be claimed by storage providers.
  • Claiming — a background thread (claim_storage) monitors pending storage contracts and claims slots for the local node, earning storage fees over time.
  • Claim spacing — claims are deduplicated by era to prevent double-claiming.

Storage Providers

  • Any node can be a storage provider by holding expressions and advertising them. Providers earn fees when they fulfill storage requests.
  • The node tracks known providers and their advertised expressions. Provider information is shared via the P2P routing layer.
  • Storage fees collected from on-chain operations (acc.put, tx.log, etc.) are distributed to providers who hold the corresponding storage contracts.

Configuration Reference

Config KeyDefaultDescription
hot_storage_limit1 GiBMaximum in-memory cache size in bytes
cold_storage_limit10 GiBMaximum on-disk storage size in bytes
cold_storage_scaleMBBase unit for level rollup: KB, MB, or GB
cold_storage_pathautoDirectory for cold storage files (auto: data directory)
storage_index_interval600 sSeconds between storage advertisement scans
storage_request_minimum_price1Minimum price to accept for a storage request
storage_request_price_interval5.0 sSeconds between price recalculation cycles
storage_fetch_interval0.25 sSeconds between storage request retries
storage_fetch_retries8Maximum number of fetch retries per request