Substreams

repository·develop·Indexed 42 days ago

https://github.com/streamingfast/substreams

A high-performance blockchain indexing engine for The Graph Network that uses Rust modules to process and compose data streams in a parallelized, streaming-first manner. It enables extraction, transformation, and export of data from blockchains such as Solana, Ethereum, Polygon, and BNB. Includes a CLI (version 1.7.2 or higher), a Debug API for tier2 runtime management, and the protodecode package for dynamic protocol buffer message decoding.

Tokens
149.5K
Snippets
403
Records
646
Agent score
52%

What's inside Substreams

  1. Overview of Substreams testing levels

    develop

    Testing for Substreams is categorized into four distinct levels to ensure reliability from individual logic to full pipeline execution:

    1. Unit Testing: Focuses on testing individual handlers using the substreams::testing::map! macro.
    2. Integration Testing: Validates logic using real blockchain data and test fixtures (e.g., via firecore).
    3. End-to-End Testing: Validates the complete pipeline using the substreams CLI.
    4. Performance Testing: Benchmarks and optimizes code using Criterion in production mode.

    Recommended workflow: Start with comprehensive unit tests, progress to integration tests with real data, and conclude with end-to-end validation.

  2. What is Substreams?

    develop

    Substreams is a high-performance blockchain indexing technology developed for The Graph Network. It allows developers to write Rust modules to compose data streams. It is designed for high throughput via parallelization and a streaming-first architecture.

    Key features include:

    • Low-cost caching and archiving of blockchain data (leveraging StreamingFast Firehose).
    • High throughput processing.
    • Cursor-based reorg handling.
  3. Overview of available Substreams Agent Skills

    develop

    The substreams-skills package provides three specialized knowledge domains for AI coding assistants:

    1. Substreams Development (substreams-dev)

    Focuses on building and debugging Substreams projects, including:

    • substreams.yaml manifest configuration.
    • Writing efficient Rust modules (map, store, index types).
    • Protobuf schema design and code generation.
    • Performance optimization and troubleshooting.

    2. Substreams SQL (substreams-sql)

    Focuses on building SQL database sinks from Substreams data, covering:

    • Database Changes Mode (CDC) for real-time row changes.
    • Relational Mappings Mode for normalized table transformations.
    • PostgreSQL patterns and indexing.
    • ClickHouse analytics-optimized schemas and materialized views.
    • Blockchain data modeling best practices.

    3. Substreams Testing (substreams-testing)

    Focuses on application testing, including:

    • Unit Testing with real blockchain data.
    • Integration Testing for end-to-end workflows.
    • Performance Testing (benchmarking and memory profiling).
    • FireCore Tools (Firehose, StreamingFast API).
    • CI/CD Integration for automated pipelines.
  4. Introduction to Substreams

    develop

    Substreams is an indexing technology designed to extract, transform, and export blockchain data. It enables developers to:

    • Extract data from multiple blockchains including Solana, Ethereum, Polygon, and BNB.
    • Apply custom transformations to the raw blockchain data.
    • Export data to various destinations, such as a Postgres database or local files.

    You can leverage pre-built Substreams packages to target specific smart contracts or protocols without writing extraction logic from scratch. For example, the Uniswap v3 Substreams Package can be used to retrieve Uniswap v3 contract data directly.

  5. Overview of Injective Foundational Modules

    develop

    The Injective Foundational Modules provide pre-programmed Substreams that retrieve fundamental data from the Injective blockchain. These modules can be used as inputs for your own custom Substreams.

    Key modules available in the substreams.yaml manifest include:

    • all_transactions: Maps raw Injective blocks (sf.cosmos.type.v2.Block) to a list of transactions (sf.substreams.cosmos.v1.TransactionList).
    • all_events: Maps raw Injective blocks (sf.cosmos.type.v2.Block) to a list of events (sf.substreams.cosmos.v1.EventList).
    • index_events: An index module that uses all_events to create a cache where events are sorted by their type field (e.g., coin_received, message) to improve performance.
    • filtered_events: Uses the index_events cache to filter for specific event types. It accepts a string parameter to specify which event types to consume.
  6. What is a Substreams manifest (substreams.yaml)?

    develop

    A Substreams manifest (substreams.yaml) is a YAML configuration file that defines the properties of a Substreams module. It serves three primary purposes:

    1. Module Definition: It specifies the modules used, their types (map or store), their inputs, and their outputs.
    2. Dependency Management: It identifies dependencies between module inputs and outputs, as well as third-party package imports.
    3. Data Modeling: It defines the schemas (Protobuf definitions) used by the module and how the resulting data should be consumed (e.g., via SQL sinks).

    Example of a basic manifest structure:

    modules:
      - name: map_block
        kind: map
        initialBlock: 12287507
        inputs:
          - source: sf.ethereum.type.v2.Block
        output:
          type: proto:eth.example.MyBlock
  7. What is a Foundational Store?

    develop

    A Foundational Store is a high-performance, multi-backend key-value storage system designed for Substreams ingestion and serving. It is typically used to store data extracted and transformed by Substreams modules so that other modules can perform efficient lookups.

    Key features include:

    • Fork-aware storage: Automatically handles blockchain reorganizations.
    • Multiple backends: Supports Badger (embedded) and PostgreSQL.
    • Block-level versioning: Every entry is tagged with a block number to support historical queries.
    • High-performance serving: Provides a gRPC API for data retrieval.
    • Streaming ingestion: Supports continuous processing via a Substreams sink.
  8. What is a Remote Feed Hosted Store?

    develop

    A Remote Feed Hosted Store is a managed, block-aware key/value store provided by StreamingFast. It allows you to write key/value entries via gRPC and read them back using Substreams modules or direct gRPC calls at specific block heights.

    Key Characteristics

    • Keys: Raw bytes (strings, hashes, addresses, etc.).
    • Values: google.protobuf.Any (any protobuf message tagged with its @type).
    • Readiness: Stores start in a not ready state. Direct reads (Get/GetFirst) will return block_reached = false until the store is marked ready. Substreams modules querying a not-ready store will hang until Feed.SetReady is called with ready: true.
    • Block-aware reads: Every read targets a specific block number. If the response indicates block_reached = false, the data is not yet considered final for that block height.
    • Finality: Data written or deleted via the Remote Feed flow is treated as already final (no fork handling).
  9. What are Delta Updates and when to use them

    develop

    Delta updates allow you to perform atomic database operations like increments, decrements, and conditional updates directly at the database level. This eliminates the need for a 'read-modify-write' pattern (fetching a value, computing a new one, and writing it back).

    Benefits:

    • Performance: Reduces overhead by avoiding expensive reads for every update.
    • Concurrency: Prevents race conditions by letting the database handle computation atomically.

    Note: Delta updates are currently a PostgreSQL-only feature. ClickHouse is not supported.

  10. Handle Block Scoped Data and Blockchain Reorganizations

    develop

    A robust sink must handle both incoming data and blockchain forks (reorganizations).

    Processing Data (HandleBlockScopedData)

    This required handler is called for each block's data. You are responsible for:

    • Decoding and processing the data.
    • Saving the data to your storage.
    • Persisting the cursor: Save the provided *Cursor regularly as a checkpoint to allow recovery from interruptions.

    Handling Reorganizations (HandleBlockUndoSignal)

    This required handler is called when a blockchain reorganization occurs. The undoSignal contains the LastValidBlock.

    CRITICAL: You must treat all data where BlockScopedData.Clock.Number > LastValidBlock.Number as invalid. You must remove or delete this data from your storage to maintain consistency with the canonical chain.