前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >[译] 使用 TheGraph 完善Web3 事件数据检索

[译] 使用 TheGraph 完善Web3 事件数据检索

作者头像
Tiny熊
发布于 2020-11-03 06:36:41
发布于 2020-11-03 06:36:41
1.6K00
代码可运行
举报
运行总次数:0
代码可运行

  • 译文出自:登链翻译计划
  • 译者:Tiny 熊

为什么我们需要TheGraph以及如何使用它

以前我们看过Solidity的大图和create-eth-app,它们之前已经提到过TheGraph。这次,我们将仔细研究TheGraph,它在去年已成为开发Dapps的标准堆栈的一部分。

但首先让我们看看传统方式下如何开发...

没有TheGraph时...

因此,让我们来看一个简单的示例,以进行说明。我们都喜欢游戏,所以想象一个简单的游戏,用户下注:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pragma solidity 0.7.1;

contract Game {
    uint256 totalGamesPlayerWon = 0;
    uint256 totalGamesPlayerLost = 0;
    event BetPlaced(address player, uint256 value, bool hasWon);

    function placeBet() external payable {
        bool hasWon = evaluateBetForPlayer(msg.sender);

        if (hasWon) {
            (bool success, ) = msg.sender.call{ value: msg.value * 2 }('');
            require(success, "Transfer failed");
            totalGamesPlayerWon++;
        } else {
            totalGamesPlayerLost++;
        }

        emit BetPlaced(msg.sender, msg.value, hasWon);
    }
}

现在让我们在Dapp中说,我们要显示输/赢的游戏总数,并在有人再次玩时更新它。该方法将是:

  1. 获取totalGamesPlayerWon
  2. 获取totalGamesPlayerLost
  3. 订阅BetPlaced事件。

如下代码所示,我们可以监听Web3中的事件,但这需要处理很多情况。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
GameContract.events.BetPlaced({
    fromBlock: 0
}, function(error, event) { console.log(event); })
.on('data', function(event) {
    // event fired
})
.on('changed', function(event) {
    // event was removed again
})
.on('error', function(error, receipt) {
    // tx rejected
});

现在,对于我们的简单示例来说,这还是可以的。但是,假设我们现在只想显示当前玩家输/赢的赌注数量。好吧,我们不走运,你最好部署一个新合约来存储这些值并获取它们。现在想象一个更复杂的智能合约和Dapp,事情会很快变得混乱。

你可以看到以上方案不是最佳的选择:

  • 不适用于已部署的合约。
  • 存储这些值需要额外的 gas 费用。
  • 需要额外的调用来获取以太坊节点的数据。

现在让我们看一个更好的解决方案。

让我向你介绍GraphQL

首先让我们谈谈最初由Facebook设计和实现的GraphQL,。你可能熟悉传统的Rest API 模型.,现在想像一下,你可以为所需的数据编写查询:

graphql-querygif

这两个图像几乎包含了GraphQL的本质。通过第二个图的查询,我们可以准确定义所需的数据,因此可以在一个请求中获得所有内容,仅此而已。GraphQL服务器处理所有所需数据的提取,因此前端消费者使用起来非常容易。如果你有兴趣对服务器如何精确地处理查询,这里有一个很好的解释。

现在有了这些知识,让我们最终进入区块链部分和TheGraph。

什么是TheGraph?

区块链是一个去中心化的数据库,但是与通常的情况相反,我们没有该数据库的查询语言。检索数据的解决方案是痛苦或完全不可能的。TheGraph是用于索引和查询区块链数据的去中心化协议。你可能已经猜到了,它使用GraphQL作为查询语言。

示例始终是最好的理解方法,因此让我们在游戏合约示例中使用TheGraph。

如何创建Subgraph

定义如何为数据建立索引,称为Subgraph。它需要三个组件:

  1. Manifest 清单(subgraph.yaml)
  2. Schema 模式(schema.graphql)
  3. Mapping 映射(mapping.ts)

清单(subgraph.yaml)

清单是我们的配置文件,它定义:

  • 要索引哪些智能合约(地址,网络,ABI...)
  • 监听哪些事件
  • 其他要监听的内容,例如函数调用或块
  • 被调用的映射函数(请参见下面的mapping.ts)

你可以在此处定义多个合约和处理程序。一个典型的设置是Truffle/Buidler项目代码库中有一个subgraph文件夹。然后,你可以轻松引用到ABI。

为了方便起见,你可能还需要使用mustache之类的模板工具,然后创建一个subgraph.template.yaml并根据最新部署插入地址。有关更高级的示例设置,请参见例如:Aave sub graph repo.

完整的文档可以在这里找到:https://thegraph.com/docs/define-a-subgraph#the-subgraph-manifest。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
specVersion: 0.0.1
description: Placing Bets on Ethereum
repository: - Github link -
schema:
  file: ./schema.graphql
dataSources:
  - kind: ethereum/contract
    name: GameContract
    network: mainnet
    source:
      address: '0x2E6454...cf77eC'
      abi: GameContract
      startBlock: 6175244
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.1
      language: wasm/assemblyscript
      entities:
        - GameContract
      abis:
        - name: GameContract
          file: ../build/contracts/GameContract.json
      eventHandlers:
        - event: PlacedBet(address,uint256,bool)
          handler: handleNewBet
      file: ./src/mapping.ts

模式(schema.graphql)

模式是GraphQL数据定义。它将允许你定义存在的实体及其类型。TheGraph支持的类型有

  • Bytes(字节)
  • ID
  • String(字符串)
  • Boolean(布尔值)
  • Int(整型)
  • BigInt(大整数)
  • BigDecimal(大浮点数)

还可以使用实体作为类型来定义关系。在我们的示例中,我们定义了从玩家到下注的一对多关系。表示该值不能为空。完整的文档可以在这里找到:https://thegraph.com/docs/define-a-subgraph#the-graphql-schema。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Bet @entity {
  id: ID!
  player: Player!
  playerHasWon: Boolean!
  time: Int!
}

type Player @entity {
  id: ID!
  totalPlayedCount: Int
  hasWonCount: Int
  hasLostCount: Int
  bets: [Bet]!
}

映射(mapping.ts)

TheGraph中的映射文件定义了将传入事件转换为实体的函数。它用TypeScript的子集AssemblyScript编写。这意味着可以将其编译为WASM(WebAssembly),以更高效,更便携式地执行映射。

你将需要定义subgraph.yaml文件中命名的每个函数,因此在我们的例子中,我们只需要一个函数:handleNewBet。我们首先尝试从发起人地址作为ID加载为为Player实体。如果不存在,我们将创建一个新实体,并用起始值填充它。

然后,我们创建一个新的Bet实体。此ID为event.transaction.hash.toHex() + “-” + event.logIndex.toString(),确保始终为唯一值。仅使用哈希是不够的,因为有人可能在一次交易中会多次调用智能合约的placeBet函数。

最后我们可以更新Player实体的所有数据。不能将数组直接压入,而需要按如下所示进行更新。我们使用ID来代表下注。最后需要.save()来存储实体。

完整的文档可以在这里找到:https://thegraph.com/docs/define-a-subgraph#writing-mappings。你还可以将日志输出添加到映射文件中,请参阅这里。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Bet, Player } from '../generated/schema';
import { PlacedBet }
    from '../generated/GameContract/GameContract';

export function handleNewBet(event: PlacedBet): void {
  let player = Player.load(
    event.transaction.from.toHex()
  );

  if (player == null) {
    // create if doesn't exist yet
    player = new Player(event.transaction.from.toHex());
    player.bets = new Array<string>(0);
    player.totalPlayedCount = 0;
    player.hasWonCount = 0;
    player.hasLostCount = 0;
  }

  let bet = new Bet(
    event.transaction.hash.toHex()
        + '-'
        + event.logIndex.toString()
  );
  bet.player = player.id;
  bet.playerHasWon = event.params.hasWon;
  bet.time = event.block.timestamp;
  bet.save();

  player.totalPlayedCount++;
  if (event.params.hasWon) {
    player.hasWonCount++;
  } else {
    player.hasLostCount++;
  }

  // update array like this
  let bets = player.bets;
  bets.push(bet.id);
  player.bets = bets;

  player.save();
}

在前端使用

使用类似ApolloBoost的东西,你可以轻松地将TheGraph集成到ReactDapp(或Apollo-Vue)中,尤其是当使用React hooks和Apollo时,获取数据就像编写单个代码一样简单的在组件中进行GraphQl查询,典型的代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// See all subgraphs: https://thegraph.com/explorer/
const client = new ApolloClient({
  uri: "{{ subgraphUrl }}",
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById("root"),
);
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const { loading, error, data } = useQuery(myGraphQlQuery);

React.useEffect(() => {
    if (!loading && !error && data) {
        console.log({ data });
    }
}, [loading, error, data]);

现在,我们可以编写例如这样的查询。这将带给我们

  • 当前用户赢得了多少次
  • 当前用户输了多少次
  • 他之前所有下注的时间戳列表

仅需要对GraphQL服务器进行一个请求。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const myGraphQlQuery = gql`
    players(where: { id: $currentUser }) {
      totalPlayedCount
      hasWonCount
      hasLostCount
      bets {
        time
      }
    }
`;

但是,我们错过了最后一个难题,那就是服务器。你可以自己运行它,也可以使用托管服务。

Graph服务器

GraphExplorer:托管服务

最简单的方法是使用托管服务。按照此处的说明部署subgraph。对于许多项目,你实际上可以在资源管理器中找到现有的subgraph,网址为https://thegraph.com/explorer/.

运行自己的节点

或者,你可以运行自己的节点:https://github.com/graphprotocol/graph-node#quick-start。这样做的原因之一可能是使用托管服务不支持的网络。当前仅支持主网,Kovan,Rinkeby,Ropsten,Goerli,PoA-Core,xDAI和Sokol。

去中心化的未来

GraphQL还为新进入的事件进行“流”支持。TheGraph尚未完全支持,但即将发布。

缺少的一方面仍然是权力下放。TheGraph未来计划具有最终成为完全去中心化协议。这两篇很棒的文章更详细地说明了该计划:

  • https://thegraph.com/blog/the-graph-network-in-depth-part-1
  • https://thegraph.com/blog/the-graph-network-in-depth-part-2

两个关键方面是:

  1. 用户将向索引器支付查询费用。
  2. 索引器将使用Graph通证(GRT)。

本翻译由 Cell Network 赞助支持。

原文链接:https://soliditydeveloper.com/thegraph

作者:MarkusWaas


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深入浅出区块链技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
The Graph入门教程:如何索引合约事件
编写智能合约[1]时,通常状态的变化是通过触发一个事件来表达,The Graph 则是捕捉区块链事件并提供一个查询事件的 GraphQL 接口,让我们可以方便的跟踪数据的变化。实际上很多 DEFI[2] 协议及都是 The Graph 来基于查询数据。
Tiny熊
2021/05/11
2.7K0
The Graph入门教程:如何索引合约事件
TheGraph 去中心化网络服务
之前我们翻译过TheGraph[4]的上一篇文章:使用 TheGraph 进行事件数据检索[5],已经过去了相当长的时间。如果你不知道 TheGraph 是什么,为什么 TheGraph 是有用的,可以读读那篇文章,在那篇文章详细解释了为什么需要 TheGraph 以及如何在中心化托管服务(Hosted Service)中使用它。
Tiny熊
2022/11/07
8990
TheGraph 去中心化网络服务
在以太坊上构建 GraphQL API
dapp[5]的数量继续爆炸性增长,对开发人员(使用 Solidity[6]或其他区块链语言的)的需求[7]也越来越大。
Tiny熊
2021/06/10
1.8K0
在以太坊上构建 GraphQL API
HCTF2018智能合约两则Writeup
这次比赛为了顺应潮流,HCTF出了3道智能合约的题目,其中1道是逆向,2道是智能合约的代码审计题目。
LoRexxar
2023/02/21
3910
HCTF2018智能合约两则Writeup
如何做智能合约审计?
你可以自己学习,或者你可以使用这份便利的一步步的指南来准确地知道在什么时候该做什么,并对合约进行审计。
辉哥
2018/08/10
1.4K0
智能合约游戏之殇——Dice2win安全分析
作者:LoRexxar'@知道创宇404区块链安全研究团队 发布时间:2018/10/18
Seebug漏洞平台
2018/11/05
7060
chainlink 小实战 web3 “捐助我”项目合约及前端交互——关于 《Patrick web3 course Lesson 7-8 》课程代码中文详解
FundMe lesson 的 示例 本质上是一个合约上对 eth 接收和发送的演示,但这个演示增加了前端 ethers 的交互,以及对 chainlink 预言机喂价的使用。
1_bit
2022/10/28
7480
深入以太坊智能合约 ABI
开发 DApp 时要调用在区块链上的 Ethereum 智能合约,就需要智能合约的 ABI。本文希望更多了解 ABI,如为什么需要 ABI?如何解读 Ethereum 的智能合约 ABI?以及如何取得智能的 ABI?
笔阁
2018/09/04
5K0
深入以太坊智能合约 ABI
Uniswap V2 源码学习 (四). 签名和路由
上次我们在研究 router 合约的时候, 有一个 removeLiquidityWithPermit 函数[2], 今天讲讲它和 Pair 的 permit 方法
Tiny熊
2022/05/25
1.3K0
在Polygon网络上构建应用的全栈开发指南
用 Next.js、Tailwind、Solidity[4]、Hardhat[5]、Ethers.js[6]、IPFS 和 Polygon 建立一个 NFT 数字市场
Tiny熊
2021/09/23
2.4K0
在Polygon网络上构建应用的全栈开发指南
以太坊智能合约部署与交互
我们再打开一个终端,打开cluster1的peer02的控制台,直接at到上一个终端部署的智能合约地址并进行set操作
笔阁
2018/09/04
2.7K0
以太坊智能合约部署与交互
[译] 用 Truffle 插件自动在Etherscan上验证合约代码
Etherscan是以太坊上最受欢迎的浏览器。它的一大功能是验证智能合约的源代码[5]。使用户可以在使用合约之前通过源码了解合约的功能。从而增加用户对合约的信任,也因此使开发者受益。
Tiny熊
2020/08/04
2K0
[译] 用 Truffle 插件自动在Etherscan上验证合约代码
创建一个像Opensea一样的NFT市场
使用 Solidity 和 Web3-React 构建一个像 Opensea 一样的 NFT 市场 DApp 是你开启 web3 之旅的一个好步骤。我们来学习编写一个具有完整功能的智能合约实现一个数字藏品的市场。一个集合的 NFT 是这里交易的数字物品。
Tiny熊
2022/11/07
1.8K0
创建一个像Opensea一样的NFT市场
第七课 技术小白如何在45分钟内发行通证(TOKEN)并上线交易
通过逐步的指导和截图举证,一步步带领一个技术小白完成一个数字货币(通证,代币,TOKEN)的发布演示和上线交易。
辉哥
2018/08/10
1.2K0
第七课 技术小白如何在45分钟内发行通证(TOKEN)并上线交易
web3 solidity 基础 ERC20 大白话搞懂
标准是大家遵循的一个协议,根据这个协议大家都知道该怎么去做,例如去吃饭的时候人多,你就需要排队,然后去窗口跟阿姨说你要吃什么,阿姨就会帮你打;若你不准守这个标准,直接冲进后厨,翻开泔水,大喊着我要吃饭…这个时候就完全背离了这个标准,所以被赶走了。
1_bit
2022/10/28
7500
web3 solidity 基础 ERC20 大白话搞懂
Solidity 智能合约开发 - 基础
去年读研的时候上的 HKU 的 <COMP7408 Distributed Ledger and Blockchain Technology>,课程中学习了以太坊智能合约的开发,做了一个简单的图书管理 ÐApp,然后毕业设计也选择了基于 Ethereum 做了一个音乐版权应用,详见 Uright - 区块链音乐版权管理ÐApp,对 Solidity 开发有一些基础了解。
pseudoyu
2023/04/11
7680
Solidity 智能合约开发 - 基础
Art Blocks合约要点分析 - 利用 JavaScript 动态生成图片
Art Blocks 是一个创建链上生成 NFT 的平台。但是你知道在链上和链下究竟保留了什么吗?为什么他们的智能合约中需要 JavaScript?
Tiny熊
2022/11/07
6350
Art Blocks合约要点分析 - 利用 JavaScript 动态生成图片
层级化NFT标准诞生:EIP-6150
因为一些机缘,我最近和几个同行朋友一起提交了一个新的 EIP 协议标准,EIP-6150,这是一个支持层级结构的 NFT 协议标准,撰写此文时处在 Review 状态,改为 Last Call 状态的 PR 还在等待通过。
Keegan小钢
2023/02/28
1.6K0
层级化NFT标准诞生:EIP-6150
智能合约中approve函数详解
我问他为什么不只用Token的标准approve 函数外部提前调用一次、然后直接执行第二步就行了、他们都有各自的理由、咱也不好细问。
终有链响
2024/08/06
1760
智能合约中approve函数详解
以太坊交易签名过程源码解析
向以太坊网络发起一笔交易时,需要使用私钥对交易进行签名。那么从原始的请求数据到最终的签名后的数据,这中间的数据流转是怎样的,经过了什么过程,今天从go-ethereum源码入手,解析下数据的转换。
Tiny熊
2020/07/09
1.5K0
相关推荐
The Graph入门教程:如何索引合约事件
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文