基于Substreams的子图
Reading time: 7 min
is a new framework for processing blockchain data, developed by StreamingFast for The Graph Network. A substreams modules can output entity changes, which are compatible with Subgraph entities. A subgraph can use such a Substreams module as a data source, bringing the indexing speed and additional data of Substreams to subgraph developers.
This cookbook requires , , and the latest version of Graph CLI (>=0.52.0):
npm install -g @graphprotocol/graph-cli
graph init --from-example substreams-powered-subgraph
A Substreams package is composed of types (defined as ), modules (written in Rust), and a substreams.yaml
file which references the types, and specifies how modules are triggered. , and check out and the for more examples.
该Substreams包可以检测以太坊主网上的合约部署,并跟踪所有新部署合约的创建块和时间戳。为此,在/proto/example.proto中有一个专门的Contract类型(了解更多关于定义Protocol Buffers的信息):
syntax = "proto3";package example;message Contracts {repeated Contract contracts = 1;}message Contract {string address = 1;uint64 blockNumber = 2;string timestamp = 3;uint64 ordinal = 4;}
Substreams包的核心逻辑是lib.rs中的map_contract模块,它处理每个区块,过滤未回滚的Create调用,并返回Contracts:
#[substreams::handlers::map]fn map_contract(block: eth::v2::Block) -> Result<Contracts, substreams::errors::Error> {let contracts = block.transactions().flat_map(|tx| {tx.calls.iter().filter(|call| !call.state_reverted).filter(|call| call.call_type == eth::v2::CallType::Create as i32).map(|call| Contract {address: format!("0x{}", Hex(&call.address)),block_number: block.number,timestamp: block.timestamp_seconds().to_string(),ordinal: tx.begin_ordinal,})}).collect();Ok(Contracts { contracts })}
只要Substreams包有一个模块输出与子图兼容的实体变更,就可以被子图使用。示例Substreams包中还有一个额外的graph_out模块在lib.rs中,它返回一个substreams_entity_change::pb::entity::EntityChanges输出,Graph Node可以处理该输出。
Substreams_entity_change crate还有一个专门的Tables函数,用于生成实体变更(文档)。生成的实体变更必须与相应子图的subgraph.graphql中定义的schema.graphql实体兼容。
#[substreams::handlers::map]pub fn graph_out(contracts: Contracts) -> Result<EntityChanges, substreams::errors::Error> {// hash map of name to a tablelet mut tables = Tables::new();for contract in contracts.contracts.into_iter() {tables.create_row("Contract", contract.address).set("timestamp", contract.timestamp).set("blockNumber", contract.block_number);}Ok(tables.to_entity_changes())}
这些类型和模块在substreams.yaml中汇集在一起:
specVersion: v0.1.0package:name: 'substreams_test' # the name to be used in the .spkgversion: v1.0.1 # the version to use when creating the .spkgimports: # dependenciesentity: https://github.com/streamingfast/substreams-entity-change/releases/download/v0.2.1/substreams-entity-change-v0.2.1.spkgprotobuf: # specifies custom types for use by Substreams modulesfiles:- example.protoimportPaths:- ./protobinaries:default:type: wasm/rust-v1file: ./target/wasm32-unknown-unknown/release/substreams.wasmmodules: # specify modules with their inputs and outputs.- name: map_contractkind: mapinputs:- source: sf.ethereum.type.v2.Blockoutput:type: proto:test.Contracts- name: graph_outkind: mapinputs:- map: map_contractoutput:type: proto:substreams.entity.v1.EntityChanges # this type can be consumed by Graph Node
您可以通过运行substreams graph来检查从区块到map_contract到graph_out的整体"流程":
为了准备这个Substreams包供子图使用,您必须运行以下命令:
yarn substreams:protogen # 生成/src/pb中的类型yarn substreams:build # 构建Substreamsyarn substreams:package # 将Substreams打包成.spkg文件# 或者,yarn substreams:prepare会调用上述所有命令
这些脚本在package.json文件中定义,如果想了解底层的Substreams命令,可以查看这些脚本。
这将根据substreams.yaml中的包名称和版本生成一个spkg文件。spkg文件包含了Graph Node需要获取此Substreams包的所有信息。
如果您更新了Substreams包,根据所做的更改,您可能需要运行部分或全部上述命令,以使spkg保持更新。
Substreams-powered subgraphs引入了一种名为"substreams"的新型数据源。这样的子图只能包含一个数据源。
基于Substreams的子图引入了一种新的数据源类型,"substreams"。这样的子图只能有一个数据源。该数据源必须指定Substreams网络、Substreams包(spkg)的相对文件位置,以及该Substreams包中生成子图兼容实体变更的模块(在本例中为map_entity_changes)。映射是指定的,但只是标识了映射类型("substreams/graph-entities")和apiVersion。
Currently, Subgraph Studio and The Graph Network support Substreams-powered subgraphs which index mainnet
(Mainnet Ethereum).
specVersion: 0.0.4description: Ethereum Contract Tracking Subgraph (powered by Substreams)repository: https://github.com/graphprotocol/graph-toolingschema:file: schema.graphqldataSources:- kind: substreamsname: substream_testnetwork: mainnetsource:package:moduleName: graph_outfile: substreams-test-v1.0.1.spkgmapping:kind: substreams/graph-entitiesapiVersion: 0.0.5
Subgraph.yaml还引用了一个模式文件。对于这个文件的要求没有变化,但是指定的实体必须与subgraph.yaml中引用的Substreams模块生成的实体变更兼容。
type Contract @entity {id: ID!"The timestamp when the contract was deployed"timestamp: String!"The block number of the contract deployment"blockNumber: BigInt!}
有了以上内容,子图开发者可以使用Graph CLI部署这个基于Substreams的子图。
yarn install # 安装graph-cliyarn subgraph:build # 构建子图yarn subgraph:deploy # 部署子图
就是这样!您已经构建并部署了一个基于Substreams的子图。
为了服务基于Substreams的子图,Graph Node必须配置与相关网络的Substreams提供程序,以及用于跟踪链头的Firehose或RPC。这些提供程序可以通过config.toml文件进行配置:
[chains.mainnet]shard = "main"protocol = "ethereum"provider = [{ label = "substreams-provider-mainnet",details = { type = "substreams",url = "https://mainnet-substreams-url.grpc.substreams.io/",token = "exampletokenhere" }},{ label = "firehose-provider-mainnet",details = { type = "firehose",url = "https://mainnet-firehose-url.grpc.firehose.io/",token = "exampletokenhere" }},]