Skip to content

The Graph GraphNode 和 Subgraph 本地搭建

什么是 The Graph?

官方文档:https://thegraph.com/docs/zh/quick-start/

  • The Graph 是一个去中心化的协议,用于索引和查询区块链的数据。它的目标是使那些难以直接查询的数据变得可访问。
  • 例如,像 Uniswap 这样具有复杂智能合约的项目,以及像 Bored Ape Yacht Club 这样的 NFT 倡议,都在以太坊区块链上存储数据。除了直接从区块链上读取基本数据外,要获取更高级的现实世界查询和操作,比如聚合、搜索、关系和非粗略的过滤,是非常困难的。

The Graph 的工作原理:

  • 子图描述:The Graph 基于子图描述(也称为子图清单)来学习如何索引以太坊数据。子图描述定义了子图感兴趣的智能合约、要注意的合约中的事件,以及如何将事件数据映射到存储在 The Graph 数据库中的数据。
  • 编制索引:一旦编写了子图清单,就可以使用 The Graph CLI 将定义存储在 IPFS 中,并告知索引人开始为该子图的数据编制索引。Graph 节点会不断扫描以太坊的新区块,为你的子图找到以太坊事件并运行你提供的映射处理程序。
  • 查询数据:去中心化的应用程序使用 The Graph 节点的 GraphQL 端点,从区块链的索引中查询数据。The Graph 节点将 GraphQL 查询转化为对其底层数据存储的查询,以便获取这些数据。

Subgraph 创建

打开graph studio 后台 https://thegraph.com/studio/

创建好之后 https://thegraph.com/studio/subgraph/[Your subgraph name ]/

INSTALL GRAPH CLI

bash
npm install -g @graphprotocol/graph-cli

Initialize your subgraph.

bash
graph init --studio xxx-test

logs

ts
ubuntu@xxx:~$ graph init --studio xxx-test 
Warning: In next major version, this flag will be removed. By default we will deploy to the Graph Studio. Learn more about Sunrise of 
 ›   Decentralized Data https://thegraph.com/blog/unveiling-updated-sunrise-decentralized-data/
Warning: In next major version, this flag will be removed. By default we will deploy to the Graph Studio. Learn more about Sunrise of 
 ›   Decentralized Data https://thegraph.com/blog/unveiling-updated-sunrise-decentralized-data/
Warning: In next major version, this flag will be removed. By default we will stop initializing a Git repository.
✔ Protocol · [ Your Protocol ]
✔ Subgraph slug · [ Your Subgraph slug ] 
✔ Directory to create the subgraph in · [ Your Local Dir Name ] 
✔ Ethereum network · [ Your Ethereum network ]
✔ Contract address · [ Your Contract address ]
✖ Failed to fetch ABI from Etherscan: ABI not found, try loading it from a local file
✔ Do you want to retry? (Y/n) · false
✖ Failed to fetch Start Block: Failed to fetch contract creation transaction hash
✔ Do you want to retry? (Y/n) · false
✖ Failed to fetch Contract Name: Failed to fetch contract source code
✔ Do you want to retry? (Y/n) · false
ABI file (path) · [ Your ABI file path ]
✔ Start Block · 0
✔ Contract Name · xxx
✔ Index contract events as entities (Y/n) · true
  Generate subgraph
  Write subgraph to directory
✔ Create subgraph scaffold
✔ Initialize networks config
✔ Initialize subgraph repository
⠇ Install dependencies with yarn

✔ Install dependencies with yarn
✔ Generate ABI and schema types with yarn codegen
Add another contract? (y/n): 
Subgraph xxx-test created in xxx

Next steps:

  1. Run `graph auth` to authenticate with your deploy key.

  2. Type `cd xxx` to enter the subgraph.

  3. Run `yarn deploy` to deploy the subgraph.

Make sure to visit the documentation on https://thegraph.com/docs/ for further information.

初始化完成会在本地创建一个文件夹 [ Your Local Dir Name ]

进入文件夹修改docker-compose.yml 文件,找到这一行:

yaml
ethereum: "mainnet:https://rpc.alg2-test.algen.network"

该行指定了使用的网络和节点,具体参考这个README https://github.com/graphprotocol/graph-node/tree/master/docker

支持的网络:https://thegraph.com/docs/zh/developing/supported-networks/

如果你使用 ARM 芯片的 Mac 需要本地构建镜像

修改完成之后,启动容器,如果没问题了,就可以开始下一步了

yaml
docker-compose up -d

Allocating subgraph name

ts
ubuntu@xxx:~/xxx$ yarn create-local  
yarn run v1.22.22
$ graph create --node http://localhost:8020/ xxx-test
Warning: In next major version, this command will be merged as a subcommand for `graph local`.
Created subgraph: xxx-test
Done in 0.30s.

Local deployment

ts
ubuntu@xxx:~/xxx$ yarn deploy-local  
yarn run v1.22.22
$ graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 xxx-test
Which version label to use? (e.g. "v0.0.1"): v1.0.0
  Skip migration: Bump mapping apiVersion from 0.0.1 to 0.0.2
  Skip migration: Bump mapping apiVersion from 0.0.2 to 0.0.3
  Skip migration: Bump mapping apiVersion from 0.0.3 to 0.0.4
  Skip migration: Bump mapping apiVersion from 0.0.4 to 0.0.5
  Skip migration: Bump mapping apiVersion from 0.0.5 to 0.0.6
  Skip migration: Bump manifest specVersion from 0.0.1 to 0.0.2
  Skip migration: Bump manifest specVersion from 0.0.2 to 0.0.4
✔ Apply migrations
✔ Load subgraph from subgraph.yaml
  Compile data source: XXX => build/XXX/XXX.wasm
✔ Compile subgraph
  Copy schema file build/schema.graphql
  Write subgraph file build/XXX/abis/XXX.json
  Write subgraph manifest build/subgraph.yaml
✔ Write compiled subgraph to build/
  Add file to IPFS build/schema.graphql
                .. xxx
  Add file to IPFS build/XXX/abis/XXX.json
                .. xxx
  Add file to IPFS build/XXX/XXX.wasm
                .. xxx
✔ Upload subgraph to IPFS

Build completed: xxx

Deployed to http://localhost:8000/subgraphs/name/xxx-test/graphql

Subgraph endpoints:
Queries (HTTP):     http://localhost:8000/subgraphs/name/xxx-test

Done in 10.23s.

部署完成之后,使用上面日志输出的链接进行查询 eg:

query {
  _meta {
    block {
      number
    }
    deployment
    hasIndexingErrors
  }
}
query {
  transfers(first: 5) {
    id
    from
    to
    transactionHash
    amount
    blockNumber
    blockTimestamp
  }
  deductionFees(first: 5) {
    id
    from
    transactionHash
    amount
  }
}

添加新的合约地址

可以使用graph add命令添加新的合约地址,但是会卡在✔ Running codegen, 后续使用graph codegen重新生成代码

bash
graph add 0x1234[Your Contract Address] --abi [Your abi file path]
bash
graph codegen
bash
graph build

添加完新的重新部署到graph node

bash
yarn create-local
bash
yarn deploy-local

附:在 subgraph 上进行合约方法调用

typescript
import {OwnershipTransferred} from "../generated/schema"
import {counterEvent} from "./counter";
import {buildDefaultEvent, buildOffer, buildToken} from "./utils";
import {BigInt, Bytes, dataSource} from "@graphprotocol/graph-ts";

let fusionProtocol = FusionProtocol.bind(dataSource.address()); 

export function handleMakeOffer(event: MakeOfferEvent): void {
  ...
  // get highestBid from contract
  let offerList = fusionProtocol.getOfferList(entity.tokenId); 
  ...
  token.save();
  entity.token = token.id;
  entity.save();
}

附:在 subgraph 上查询 ipfs 数据 和 全文搜索

全文搜索查询

定义全文搜索字段

yaml
# subgraph.yaml
specVersion: 1.0.0
features:   
  - fullTextSearch              # 启用全文搜索
  - ipfsOnEthereumContracts     # 启用ipfs查找
indexerHints:
  prune: auto
schema:
  file: ./schema.graphql
dataSources:
  ...
yaml
# docker-compose.yaml
version: "3"
services:
  graph-node:
    image: graphprotocol/graph-node:db8de9e
    ports:
      - "8000:8000"
      - "8001:8001"
      - "8020:8020"
      - "8030:8030"
      - "8040:8040"
    depends_on:
      - ipfs
      - postgres
    extra_hosts:
      - host.docker.internal:host-gateway
    environment:
      postgres_host: postgres
      postgres_user: graph-node
      postgres_pass: let-me-in
      postgres_db: graph-node
      ipfs: "ipfs:5001"
      ethereum: mainnet:https://rpc.alg2-test.algen.network
      GRAPH_LOG: info
      GRAPH_ALLOW_NON_DETERMINISTIC_FULLTEXT_SEARCH: true
  ipfs:
    ...
  postgres:
    ...

查询 ipfs 数据

typescript
import {Address, BigInt, Bytes, dataSource, JSONValue} from "@graphprotocol/graph-ts";
import {ipfs, json} from '@graphprotocol/graph-ts'

export function handleTransfer1(event: Transfer1Event): void {
  ...
  // 从本地的 ipfs 上面取数据
  let ipfshash = 'QmaaTXNNw2oY9Dp1CdvBWxyjnEfLjsxDkBVWD2sYrazptL' // eg
  let metadata = ipfs.cat(ipfshash)  
  if (metadata) {
    const value = json.fromBytes(metadata).toObject().get("license")
    if (value === null) {
      token.tokenMetaData = "_null";
    }else {
      token.tokenMetaData = value.toString()
    }
  }
  ...
  token.save();
  entity.token = token.id
  entity.save()
}

全文搜索(仅支持前缀搜索)

graphql
schema.graphql

type _Schema_
@fulltext(
    name: "tokenSearch"
    language: en
    algorithm: rank
    include: [{ entity: "Token", fields: [{ name: "id" },{name:"tokenIDSuffix4"}] }]
)

type Token @entity {
    id: String! #
    tokenID: BigInt!
    tokenIDSuffix4: String!  # 支持后缀搜索添加
    ...
}

query

graphql
query MyQuery {
  tokenSearch(text: "388:*") {
    id
    tokenID
  }
}

参考链接

文章来源于自己总结和网络转载,内容如有任何问题,请大佬斧正!联系我