9 分钟
在 Arweave 上构建子图
Graph Node和Subgraph Studio中的Arweave支持处于测试阶段:对构建Arweave子图有任何疑问,请通过Discord联系我们!
在本指南中,您将学习如何构建和部署子图以索引Arweave区块链。
Arweave是什么?
Arweave 协议允许开发者永久存储数据,这是 Arweave 和 IPFS 的主要区别,IPFS 没有这个特性,永久性和存储在 Arweave 上的文件不能被更改或删除。
Arweave 已经构建了许多库,用于将协议集成到许多不同的编程语言中。更多信息可以查看:
Arweave子图是什么?
Graph 允许您构建称为“子图 ”的自定义开放 API。子图用于告诉索引人(服务器操作员) 在区块链上索引哪些数据,并保存在他们的服务器上,以便您能够在任何时候使用 GraphQL 查询它。
Graph节点 现在能够在 Arweave 协议上索引数据。当前的集成只是索引 Arweave 作为一个区块链(区块和交易) ,它还没有索引存储的文件。
构建 Arweave 子图
为了能够构建和部署 Arweave 子图,您需要两个包:
@graphprotocol/graph-cli
高于0.30.2版本-这是一个用于构建和部署子图的命令行工具。点击这里下载使用npm
。@ graph protocol/graph-ts
0.27.0以上版本-这是子图特定类型的库。点击这里下载使用npm
。
子图的组成部分
一个子图有三个组成部分:
1. 数据源明细 - subgraph.yaml
定义感兴趣的数据源,以及如何处理它们。Arweave是一种新型数据源。
2. 数据查询结构- schema.graphql
在这里,您可以定义在使用 GraphQL 索引子图之后希望能够查询的数据。这实际上类似于 API 的模型,其中模型定义了请求主体的结构。
现有文档涵盖了对 Arweave 子图的需求。
3. AssemblyScript 映射 - mapping.ts
这种逻辑决定了当有人与您正在监听的数据源进行交互时,应该如何检索和存储数据。数据将被翻译并根据您列出的模式进行存储。
在子图开发过程中,有两个关键命令:
1$ graph codegen # generates types from the schema file identified in the manifest2$ graph build # generates Web Assembly from the AssemblyScript files, and prepares all the Subgraph files in a /build folder
子图清单定义
子图清单subgraph.yaml
标识子图的数据源、感兴趣的触发器以及应该响应这些触发器而运行的函数。下面是 Arweave 子图的子图清单示例:
1specVersion: 1.3.02description: Arweave Blocks Indexing3schema:4 file: ./schema.graphql # link to the schema file5dataSources:6 - kind: arweave7 name: arweave-blocks8 network: arweave-mainnet # The Graph only supports Arweave Mainnet9 source:10 owner: 'ID-OF-AN-OWNER' # The public key of an Arweave wallet11 startBlock: 0 # set this to 0 to start indexing from chain genesis12 mapping:13 apiVersion: 0.0.914 language: wasm/assemblyscript15 file: ./src/blocks.ts # link to the file with the Assemblyscript mappings16 entities:17 - Block18 - Transaction19 blockHandlers:20 - handler: handleBlock # the function name in the mapping file21 transactionHandlers:22 - handler: handleTx # the function name in the mapping file
- Arweave子图引入了一种新的数据源(
arweave
)。 - 网络应该对应于托管Graph节点上的网络。在Subgraph Studio上,Arweave 的主网是
Arweave-mainnet
。 - Arweave 数据源引入了一个可选的 source. owner 字段,它是 Arweave 钱包的公钥
Arweave 数据源支持两种类型的处理程序:
blockHandlers
在每个新的 Arweave 区块上运行,不需要 source. owner。transactionHandlers
- 在数据源的source.owner
是所有者的每个交易上运行。目前,transactionHandlers
需要一个所有者,如果用户想要处理所有交易,他们应该提供""作为source.owner
Source.Owner 可以是所有者的地址,也可以是他们的公钥。
交易是 Arweave permaweb 的构建区块,它们是终端用户创建的对象。
注意: 目前还不支持Irys(先前的Bundl)交易。
模式定义
数据查询结构定义描述了生成的子图数据库的结构以及实体之间的关系,无需与原始数据源有关。这里有关于子图模式定义的更多细节。
AssemblyScript 映射
处理事件的处理程序是用 AssemblyScript 编写的。
Arweave索引将Arweave特定的数据类型引入AssemblyScript API。
1class Block {2 timestamp: u643 lastRetarget: u644 height: u645 indepHash: Bytes6 nonce: Bytes7 previousBlock: Bytes8 diff: Bytes9 hash: Bytes10 txRoot: Bytes11 txs: Bytes[]12 walletList: Bytes13 rewardAddr: Bytes14 tags: Tag[]15 rewardPool: Bytes16 weaveSize: Bytes17 blockSize: Bytes18 cumulativeDiff: Bytes19 hashListMerkle: Bytes20 poa: ProofOfAccess21}2223class Transaction {24 format: u3225 id: Bytes26 lastTx: Bytes27 owner: Bytes28 tags: Tag[]29 target: Bytes30 quantity: Bytes31 data: Bytes32 dataSize: Bytes33 dataRoot: Bytes34 signature: Bytes35 reward: Bytes36}
区块处理程序接收Block
,而交易接收Transaction
.。
写 Arweave 子图的映射与写 Etherum 子图的映射非常相似。了解更多信息,请点击这里。
将Arweave子图部署到Subgraph Studio
一旦您的子图已经在Subgraph Studio控制板上创建,您就可以通过使用graph deploy
CLI 命令进行部署。
1graph deploy --access-token <your-access-token>
查询 Arweave 子图
Arweave 子图的 GraphQL 端点由模式定义和现有的 API 接口决定。有关更多信息,请访问 GraphQLAPI 文档。
示例子图
下面是一个子图的例子,以供参考:
常见问题
子图可以索引 Arweave 和其他链吗?
不,子图只能支持来自一个链或网络的数据源。
我可以索引存储在 Arweave 上的文件吗?
目前,Graph 只是将 Arweave 索引为区块链(它的区块和交易)。
我可以识别我的子图中的 Bundlr 包吗?
目前还不支持。
如何筛选特定账户的交易?
Source.owner可以是用户的公钥或账户地址。
当前的加密格式是什么?
数据通常以字节的形式传递到映射中,如果直接存储字节,则以十六进制
格式(例如,区块和和交易hashes)返回。您可能希望在映射中转换为 base64
或 base64 URL
安全格式,以便与 Arweave Explorer 等区块浏览器中显示的内容相匹配。
可以使用以下 bytesToBase64(字节: Uint8Array,urlSafe: boolean): string
辅助函数,并将其添加到 graph-ts
:
1const base64Alphabet = [2 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",3 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",4 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",5 "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",6 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"7];89const base64UrlAlphabet = [10 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",11 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",12 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",13 "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",14 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", "_"15];1617function bytesToBase64(bytes: Uint8Array, urlSafe: boolean): string {18 let alphabet = urlSafe? base64UrlAlphabet : base64Alphabet;1920 let result = '', i: i32, l = bytes.length;21 for (i = 2; i < l; i += 3) {22 result += alphabet[bytes[i - 2] >> 2];23 result += alphabet[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];24 result += alphabet[((bytes[i - 1] & 0x0F) << 2) | (bytes[i] >> 6)];25 result += alphabet[bytes[i] & 0x3F];26 }27 if (i === l + 1) { // 1 octet yet to write28 result += alphabet[bytes[i - 2] >> 2];29 result += alphabet[(bytes[i - 2] & 0x03) << 4];30 if (!urlSafe) {31 result += "==";32 }33 }34 if (!urlSafe && i === l) { // 2 octets yet to write35 result += alphabet[bytes[i - 2] >> 2];36 result += alphabet[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];37 result += alphabet[(bytes[i - 1] & 0x0F) << 2];38 if (!urlSafe) {39 result += "=";40 }41 }42 return result;43}