官方文档|网络角色之索引人2:基础设施
索引人基础设施的中心是Graph节点,它监控Ethereum,根据子图定义提取和加载数据,并以GraphQL的 API形式为其服务。

发布时间:2021.02.12
原文作者:The Graph
翻译:The Graph 社区成员
原文出处:https://thegraph.com/docs/network#infrastructure
翻译出处:https://mp.weixin.qq.com/s/0RN-nBfQOJFRRBEcXKtt4g
基础设施
索引人基础设施的中心是Graph节点,它监控Ethereum,根据子图定义提取和加载数据,并以GraphQL的 API形式为其服务。Graph节点需要连接到Ethereum EVM节点端点,以及IPFS节点,用于采购数据;PostgreSQL数据库用于其存储;以及索引人组件,促进其与网络的交互。
- PostgreSQL 数据库:Graph节点的主要存储,这是存储子图数据的地方。索引人服务和代理也使用数据库来存储状态通道数据、成本模型和索引规则。
- Ethereum endpoint 以太坊端点:公开以太坊JSON-RPC API的端点。这可能采取单个Ethereum客户端的形式,也可能是一个更复杂的设置,在多个客户端之间进行负载平衡。需要注意的是,某些子图将需要特定的Ethereum客户端功能,如存档模式和跟踪API。
- IPFS节点(版本小于5):子图部署元数据存储在IPFS网络上。Graph节点主要在子图部署过程中访问IPFS节点,以获取子图清单和所有链接文件。网络索引人不需要托管自己的IPFS节点,网络的IPFS节点托管在ipfs.network.thegraph。
- 索引人服务:处理与网络的所有必要的外部通信。共享成本模型和索引状态,将来自网关的查询请求传递给一个Graph节点,并通过状态通道与网关管理查询支付。
- 索引人代理:促进索引人在链上的交互,包括在网络上注册,管理子图部署到其Graph节点,以及管理分配。
- Prometheus 指标服务器:Graph节点 和 Indexer 组件将其指标记录到指标服务器。
注意:为了支持敏捷扩展,建议在不同的节点集之间分开查询和索引问题:查询节点和索引节点。
端口概述
重要:公开暴露端口时要小心,管理端口应保持锁定。这包括下面详述的 Graph节点 JSON-RPC 和索引人管理端点。
在Google Cloud上使用Terraform建立基础架构
安装先决条件
创建一个谷歌云项目
- 克隆或导航到索引人存储库。
- 导航到./terraform目录,这是所有命令应该执行的地方。
cd terraform
- 通过谷歌云认证并创建一个新项目。
gcloud auth login
project=<PROJECT_NAME>
gcloud projects create --enable-cloud-apis $project
- 使用 Google Cloud Console 的计费页面为新项目启用计费。
- 创建谷歌云配置。
proj_id=$(gcloud projects list --format='get(project_id)' --filter="name=$project")
gcloud config configurations create $project
gcloud config set project "$proj_id"
gcloud config set compute/region us-central1
gcloud config set compute/zone us-central1-a
- 启用所需的 Google Cloud API。
gcloud services enable compute.googleapis.com
gcloud services enable container.googleapis.com
gcloud services enable servicenetworking.googleapis.com
gcloud services enable sqladmin.googleapis.com
- 创建一个服务账户。
svc_name=<SERVICE_ACCOUNT_NAME>
gcloud iam service-accounts create $svc_name
--description="Service account for Terraform"
--display-name="$svc_name"
gcloud iam service-accounts list
# Get the email of the service account from the list
svc=$(gcloud iam service-accounts list --format='get(email)'
--filter="displayName=$svc_name")
gcloud iam service-accounts keys create .gcloud-credentials.json
--iam-account="$svc"
gcloud projects add-iam-policy-binding $proj_id
--member serviceAccount:$svc
--role roles/editor
- 启用将在下一步中创建的数据库和Kubernetes集群之间的对等连接。
gcloud compute addresses create google-managed-services-default
--prefix-length=20
--purpose=VPC_PEERING
--network default
--global
--description 'IP Range for peer networks.'
gcloud services vpc-peerings connect
--network=default
--ranges=google-managed-services-default
- 创建最小的terraform配置文件(根据需要更新)。
indexer=<INDEXER_NAME>
cat > terraform.tfvars <<EOF
project = "$proj_id"
indexer = "$indexer"
database_password = "<database passowrd>"
EOF
使用Terraform创建基础设施
在运行任何命令之前,先阅读variables.tf,并在这个目录下创建一个文件terraform.tfvars(或者修改我们在上一步创建的文件)。对于每一个想要覆盖默认值的变量,或者需要设置值的变量,在terraform.tfvars中输入一个设置。
- 运行以下命令来创建基础设施。
# Install required plugins
terraform init
# View plan for resources to be created
terraform plan
# Create the resources (expect it to take up to 30 minutes)
terraform apply
- 将新集群的凭证下载到~/. kube/config中,并将其设置为你的默认上下文。
gcloud container clusters get-credentials $indexer
kubectl config use-context $(kubectl config get-contexts --output='name'
| grep $indexer))
为索引人创建Kubernetes组件
- 将目录`k8s/overlays`复制到新的目录$dir中,并调整`$dir/kustomization.yaml`中的bases条目,使其指向目录`k8s/base`。
- 读取$dir中的所有文件,并按照注释中的指示调整任何值。
- 用kubectl apply -k $dir部署所有资源。
Graph节点
Graph节点是一个开源的Rust实现,它将Ethereum区块链事件源化,以确定地更新一个数据存储,可以通过GraphQL端点进行查询。开发者使用子图来定义他们的模式,以及一组用于转换区块链来源数据的映射,Graph节点处理同步整个链,监控新的区块,并通过GraphQL端点提供服务。
开始
来自来源
安装先决条件
- Rust
- PostgreSQL
- IPFS
- Ubuntu用户的附加要求:要在Ubuntu上运行Graph节点,可能需要一些附加的软件包。
sudo apt-get install -y clang libpg-dev libssl-dev pkg-config
设置
1.启动PostgreSQL数据库服务器
initdb -D .postgres
pg_ctl -D .postgres -l logfile start
createdb graph-node
2.克隆Graph节点 repo,并通过运行 cargo build来构建源代码。
3.现在,所有的依赖关系都已设置完毕,启动Graph节点。
cargo run -p graph-node --release -- \
--postgres-url postgresql://[USERNAME]:[PASSWORD]@localhost:5432/graph-node --ethereum-rpc [NETWORK_NAME]:[URL] \
--ipfs https://ipfs.network.thegraph.com
使用Docker
先决条件
- Ethereum 节点
默认情况下,docker 编译设置将使用 mainnet: http://host.docker.internal:8545 连接到主机上的 Ethereum 节点。你可以通过更新docker-compose.yaml来替换这个网络名和url。
设置
1.克隆Graph节点并导航到Docker目录。
git clone http://github.com/graphprotocol/gaph-node
cd graph-node/docker
2.仅适用于linux用户 - 在docker-compose.yaml中使用主机IP地址代替host.docker.internal,并使用附带的脚本。
./setup.sh
3.启动一个本地Graph节点,它将连接到你的Ethereum端点。
docker-compose up
索引人组件
要成功地参与网络,需要几乎持续的监控和互动,所以我们建立了一套Typescript应用程序,以方便索引人的网络参与。有三个索引人组件。
- 索引人代理
代理监控网络和索引人自身的基础设施,并管理哪些子图部署被索引和分配到链上,以及分配到每个子图的数量。 - 索引人服务
唯一需要对外暴露的组件,该服务将子图查询传递给节点,管理查询支付的状态通道,将重要的决策信息分享给网关等客户端。 - 索引人 CLI
用于管理索引人代理的命令行界面。它允许索引人管理成本模型和索引规则。
开始
索引人代理和索引人服务应该与你的Graph节点基础架构共同定位。有很多方法可以为你的索引人组件设置虚拟执行环境,这里我们将解释如何使用NPM包或源码在裸机上运行它们,或者通过谷歌云Kubernetes引擎上的kubernetes和docker运行。如果这些设置示例不能很好地翻译到你的基础架构上,很可能会有一个社区指南可以参考,快来Discord上打招呼吧!记得在启动你的索引人组件之前,要先在协议中打委托!
来自NPM包
npm install -g @graphprotocol/indexer-service
npm install -g @graphprotocol/indexer-agent
# Indexer CLI is a plugin for Graph CLI, so both need to be installed:
npm install -g @graphprotocol/graph-cli
npm install -g @graphprotocol/indexer-cli
# Indexer service
graph-indexer-service start ...
# Indexer agent
graph-indexer-agent start ...
# Indexer CLI
#Forward the port of your agent pod if using Kubernetes
kubectl port-forward pod/POD_ID 18000:8000
graph indexer connect http://localhost:18000/
graph indexer ...
来自来源
# From Repo root directory
yarn
# Indexer Service
cd packages/indexer-service
./bin/graph-indexer-service start ...
# Indexer agent
cd packages/indexer-agent
./bin/graph-indexer-service start ...
# Indexer CLI
cd packages/indexer-cli
./bin/graph-indexer-cli indexer connect http://localhost:18000/
./bin/graph-indexer-cli indexer ...
使用docker
- 从注册表中提取图像
docker pull ghcr.io/graphprotocol/indexer-service:stest
docker pull ghcr.io/graphprotocol/indexer-agent:stest
或从源头在本地建立图像
# Indexer service
docker build \
--build-arg NPM_TOKEN=<npm-token> \
-f Dockerfile.indexer-service \
-t indexer-service:latest \
# Indexer agent
docker build \
--build-arg NPM_TOKEN=<npm-token> \
-f Dockerfile.indexer-agent \
-t indexer-agent:latest \
- 运行组件
docker run -p 7600:7600 -it indexer-service:latest ...
docker run -p 18000:8000 -it indexer-agent:last ...
注意:启动容器后,索引人服务应该在http://localhost:7600,索引人代理应该在http://localhost:18000/,暴露索引人管理API。
使用K8s和Terraform
请参阅在Google Cloud上使用Terraform设置服务器基础架构一节。
使用方法
注意:所有的运行时配置变量可以在启动时作为参数应用到命令中,也可以使用格式为COMPONENT_NAME_VARIABLE_NAME(ex. INDEXER_AGENT_ETHEREUM)的环境变量。
索引代理
graph-indexer-agent start \
--ethereum <MAINNET_ETH_ENDPOINT> \
--ethereum-network mainnet \
--mnemonic <MNEMONIC> \
--indexer-address <INDEXER_ADDRESS> \
--graph-node-query-endpoint http://localhost:8000/ \
--graph-node-status-endpoint http://localhost:8030/graphql \
--graph-node-admin-endpoint http://localhost:8020/ \
--public-indexer-url http://localhost:7600/ \
--indexer-geo-coordinates <YOUR_COORDINATES> \
--index-node-ids default \
--indexer-management-port 18000 \
--metrics-port 7040 \
--network-subgraph-endpoint https://gateway.network.thegraph.com/network \
--default-allocation-amount 100 \
--register true \
--inject-dai true \
--postgres-host localhost \
--postgres-port 5432 \
--postgres-username <DB_USERNAME> \
--postgres-password <DB_PASSWORD> \
--postgres-database indexer \
| pino-pretty
索引人服务
SERVER_HOST=localhost \
SERVER_PORT=5432 \
SERVER_DB_NAME=is_staging \
SERVER_DB_USER=<DB_USERNAME> \
SERVER_DB_PASSWORD=<DB_PASSWORD> \
graph-indexer-service start \
--ethereum <MAINNET_ETH_ENDPOINT> \
--ethereum-network mainnet \
--mnemonic <MNEMONIC> \
--indexer-address <INDEXER_ADDRESS> \
--port 7600 \
--metrics-port 7300 \
--graph-node-query-endpoint http://localhost:8000/ \
--graph-node-status-endpoint http://localhost:8030/graphql \
--postgres-host localhost \
--postgres-port 5432 \
--postgres-username <DB_USERNAME> \
--postgres-password <DB_PASSWORD> \
--postgres-database is_staging \
--network-subgraph-endpoint https://gateway.network.thegraph.com/network \
| pino-pretty
索引人CLI
Indexer CLI是@graphprotocol/graph-cli的一个插件,可以在终端的graph indexer处访问。
graph indexer connect http://localhost:18000
graph indexer status
使用索引人CLI管理索引人
索引人代理需要来自索引人的输入,才能代表索引人自主地与网络交互。定义索引人代理行为的机制是索引规则。使用索引规则,索引人可以应用其特定的策略来选择子图进行索引和服务查询。规则是通过由代理提供的GraphQL API来管理的,被称为索引人管理API。与索引管理 API 交互的建议工具是 索引人CLI,它是 Graph CLI 的扩展。
使用方法
索引人 CLI 连接到索引人代理,通常是通过端口转发,因此 CLI 不需要运行在同一服务器或集群上。为了帮助你入门,并提供一些上下文,这里将简要介绍CLI。
- graph indexer connect < url>
连接到索引人管理API。通常情况下,与服务器的连接是通过端口转发打开的,所以CLI可以很容易地进行远程操作。(例如:kubectl port-forward pod/<indexer-agent-pod> 8000:8000) - graph indexer rules get [options] <deployment-id< [<key1> ...]
获取一个或多个索引规则,使用 all 作为 <deployment-id> 来获取所有规则,或使用 global 来获取全局默认规则。可以使用额外的参数 --merged 来指定将特定部署规则与全局规则合并。这就是它们在索引人代理中的应用方式。 - graph indexer rules set [options] <deployment-id> <key1> <value1> ...
设置一个或多个索引规则。 - graph indexer rules start [options] <deployment-id>
开始索引子图部署(如果可用),并将其 decisionBasis 设置为 always,这样索引人代理将始终选择对其进行索引。如果全局规则被设置为总是,那么网络上所有可用的子图都将被索引。 - graph indexer rules stop [options] <deployment-id>
停止对某个部署进行索引,并将其 decisionBasis 设置为 never,这样它在决定要索引的部署时就会跳过这个部署。 - graph indexer rules maybe [options] <deployment-id>
将部署的decisionBasis设置为规则,这样索引人代理将使用索引规则来决定是否对这个部署进行索引。
所有在输出中显示规则的命令都可以使用-output参数在支持的输出格式(table、yaml和json)之间进行选择
索引规则
索引规则既可以作为全局默认值应用,也可以使用其ID应用于特定的子图部署。deployment和 decisionBasis 字段是强制性的,而所有其他字段是可选的。当索引规则将规则作为 decisionBasis 时,索引人代理将比较该规则上的非空阈值和从网络中获取的相应部署的值。如果子图部署的值高于(或低于)任何一个阈值,它将被选择用于索引。
例如,如果全局规则的minStake为5(GRT),则任何分配给它的权益超过5(GRT)的子图部署都将被索引。阈值规则包括maxAllocationPercentage、minSignal,maxSignal、minStake和minAverageQueryFees。
数据模型:
type IndexingRule {
deployment: string
allocationAmount: string | null
parallelAllocations: number | null
decisionBasis: IndexingDecisionBasis
maxAllocationPercentage: number | null
minSignal: string | null
maxSignal: string | null
minStake: string | null
minAverageQueryFees: string | null
custom: string | null
}
IndexingDecisionBasis {
rules
never
always
}
成本模式
成本模型根据市场和查询属性为查询提供动态定价。索引服务处与网关共享每个子网的成本模型,它们打算对每个子网的查询作出回应。而网关则使用成本模型来做出每个查询的索引人选择决定,并与所选的索引人进行付费谈判。
Agora
Agora语言提供了一种灵活的格式来声明查询的成本模型。Agora价格模型是一系列的语句,它们按照GraphQL查询中每个顶层查询的顺序执行。对于每个顶层查询,第一个与其匹配的语句决定了该查询的价格。
语句由一个用于匹配GraphQL查询的谓词和一个成本表达式组成,该表达式在评估时输出一个以十进制GRT表示的成本。查询的命名参数位置中的值可以在谓词中捕获并在表达式中使用。也可以在表达式中设置全局,并代替占位符。
成本模型示例:
# This statement captures the skip value,
# uses a boolean expression in the predicate to match specific queries that use skip
# and a cost expression to calculate the cost based on the skip value and the SYSTEM_LOAD global
query { pairs(skip: $skip) { id } } when $skip > 2000 => 0.0001 * $skip * $SYSTEM_LOAD;
# This default will match any GraphQL expression.
# It uses a Global substituted into the expression to calculate cost
default => 0.1 * $SYSTEM_LOAD;
使用上述模型的查询成本计算示例。
应用成本模式
成本模型是通过索引人CLI应用的,CLI将它们传递给索引人代理的索引人管理API,以便存储在数据库中。然后,索引人服务将接收这些模型,并在网关要求时将成本模型提供给它们。
indexer cost set variables '{ "SYSTEM_LOAD": 1.4 }'
indexer cost set model my_model.agora
与网络的交互
在协议中进行质押
作为索引人参与网络的第一步是批准协议、质押资金,以及(可选)设置一个操作员地址以进行日常协议交互。注意:在这些说明中,Remix将用于合约交互,但请随意使用您选择的工具(OneClickDapp、ABItopic和MyCrypto是其他一些已知的工具)。
一旦索引人在协议中质押了GRT,索引人组件就可以被启动并开始与网络进行交互。
- 在浏览器中打开Remix应用
- 在File Explorer中创建一个名为Staking.abi的文件,其中包含staking ABI。
- 选择Staking.abi并在编辑器中打开,切换到Remix界面的Deploy and Run Transactions事务部分。
- 在环境下选择Injected Web3,在Account下选择你的索引人地址。
- 调用approveProtocol()来批准协议合约,以便从钱包中提取代币(或代币锁合约)。
- 调用stake()在协议中对GRT进行质押。
- (可选)索引人可以批准另一个地址作为其索引人基础设施的操作者,以便将控制资金的密钥与执行日常操作的密钥分开,如在子图上分配和服务(付费)查询。为了设置操作员,用操作员地址调用setOperator()。
- (可选)为了控制奖励的分配和战略性地吸引委托人索引人可以通过更新他们的indexingRewardCut(索引奖励分成)、queryFeeCut(查询费分成)和cooldownBlocks(参数冷却时间)来更新他们的委托参数。为此,需要调用setDelegationParameters()。下面的例子设置queryFeeCut将95%的查询返利分配给索引人,5%分配给委托人,设置indexingRewardCut将60%的索引奖励分配给索引人,40%分配给委托人,设置cooldownBlocks周期为500块。
setDelegationParameters(950000, 600000, 500)
分配的生命周期
被索引人创建后,一个健康的配置会经历四种状态。
- Active 活跃
一旦在链上创建分配( allocateFrom()),它就被认为是活跃的。索引人自身和/或被委托的一部分权益被分配给子图部署,这使得他们可以要求索引奖励并为该子图部署提供查询。索引人代理根据索引人规则管理创建分配。 - Closed 关闭
索引人可以在1个纪元过去后自由关闭一个分配(closeAllocation()),或者他们的索引人代理将在maxAllocationEpochs(当前为28天)之后自动关闭该分配。当一个分配以有效的索引证明(POI)关闭时,他们的索引奖励将被分配给索引人及其委托人(参见下面的"奖励是如何分配的?"以了解更多)。 - Finalized 完成
一旦一个分配被关闭,就会有一个争议期,之后该分配被认为是最终确定的,它的查询费返利可以被申领(claim())。索引代理监控网络以检测最终完成的分配,如果它们高于一个可配置的(可选择的)阈值,—-allocation-claim-threshold,则对它们进行申领。 - Claimed 申领
分配的最终状态;它已经完成了作为活跃分配的过程,所有符合条件的奖励已经分配完毕,其查询费返利也已申领。