Simple Substreams Example
The BlockStats Substreams is a very basic Substreams, extracting data from the Injective blockchain.
Tip: This tutorial teaches you how to build a Substreams from scratch.
Remember that you can auto-generate your Substreams module by using the code-generation tools.
Before You Begin
Clone the BlockStats Substreams GitHub repository and open it in an IDE of your choice (for example, VSCode).
Inspect the Project
Every Substreams project contains three main pieces:
The Protobuf definitions: the outputs of your Substreams, which you define through Protobuf schemas.
The source code: the Rust functions that extract the actual data from the blockchain.
The Substreams manifest: the
substreams.yamlfile contains the configuration of your Substreams.

The
protofolder contains the Protobuf definitions for the output of your Substreams. In this example, only aBlockStatsProtobuf is defined as the output of the Substreams.The
srcfolder contains the source code of the Substreams transformations. Specifically, thelib.rscontains the Rust functions.The
substreams.ymlis the Substreams manifest, which defines relevant information, such as the inputs/outputs of every module or the Protobuf files.
Take a look at the substreams.yaml file:
network: cosmos # 1.
imports:
cosmos: https://github.com/streamingfast/substreams-cosmos/releases/download/v0.1.1/cosmos-v0.1.0.spkg # 2.
protobuf:
files:
- cosmos/v1/stats/stats.proto # 3.
importPaths:
- ./proto
binaries:
default:
type: wasm/rust-v1
file: target/wasm32-unknown-unknown/release/cosmos_block_stats.wasm
modules:
- name: block_to_stats # 4.
kind: map
initialBlock: 64987400
inputs:
- source: sf.cosmos.type.v2.Block # 5.
output:
type: proto:cosmos.v1.BlockStats # 6.The
networkfield specifies which network is the Substreams going to be executed on.Import the Cosmos Block Protobuf, which gives you access to the blockchain data.
Import the user-defined Protobuf schemas (i.e. the outputs of your Substreams).
Define a module.
block_to_stats, which will be mapped to theblock_to_statsRust function in the source code.Define the inputs of the module. In this case, the
BlockCosmos Protobuf.Define the outputs of the module. In this case, the
BlockStatsProtobuf, which you imported in#3.
Run the Substreams
Build the Rust code:
substreams buildRun the Substreams using the
substreams runcommand of the CLI:
substreams run substreams.yaml block_to_stats \
-e mainnet.injective.streamingfast.io:443 \
--start-block=64987400 --stop-block=+1000substreams.yamlis the Substreams manifest with the configurations.block_to_statsis the name of the module that you want to run (in this Substreams, there only one module).-e mainnet.injective.streamingfast.io:443is the StreamingFast (Substreams provider) endpoint that will read execute the Substreams and stream back the data.--start-block=64987400 --stop-block=+1000defines the start and stop block (start at block64987400and finish at block64987500, 100 blocks later).
The
substreams rundisplays the data extract at every block linearly, so it might be difficult to properly read the data if your execution happens through thousands of blocks. Thesubstreams guiallows you to jump between blocks and search content.
substreams gui substreams.yaml block_to_stats \
-e mainnet.injective.streamingfast.io:443 \
--start-block=64987400 --stop-block=+1000Review the GUI Reference to get more information on how to use this utility.
Inspect the Code
The lib.rs file contains the only module defined in this Substreams, block_to_stats.
mod pb;
use crate::pb::sf::cosmos::r#type::v2::Block; // 1.
use crate::pb::cosmos::v1::BlockStats; // 2.
use substreams::errors::Error;
#[substreams::handlers::map]
pub fn block_to_stats(block: Block) -> Result<BlockStats, Error> { // 3.
let mut stats = BlockStats::default(); // 4.
let header = block.header.as_ref().unwrap();
let last_block_id = header.last_block_id.as_ref().unwrap();
stats.block_height = block.height as u64; // 5,
stats.block_hash = hex::encode(block.hash);
stats.block_time = block.time;
stats.block_proposer = hex::encode(&header.proposer_address);
stats.parent_hash = hex::encode(&last_block_id.hash);
stats.parent_height = block.height - 1i64;
stats.num_txs = block.txs.len() as u64; // 6.
Ok(stats) // 7.
}Import the Cosmos
BlockProtobuf object, which is passed as a parameter.Import the
BlockStatsProtobuf object, which is the return type of the function. This Rust object is automatically generated from the Protobuf defined in theprotofolder.Declaration of the Rust function. Input: Injective block. Output:
BlockStatsobject, which is defined by the user and is consumable from the outside world.Creation of the
BlockStatsobject.Add data from the
BlockInjective object to user-definedBlockStatsobject. In this case, theheightof the block.Add more data. In this case, the number of transactions contained in the block.
Last updated
Was this helpful?

