乐趣区

关于web:The-Graph介绍

The Graph 是用于索引和查问区块链数据的去中心化协定。建设 subgraphs 用规范 GraphQL API 查问这些索引解决了去中心化数据遍历的苦楚。

海量的去中心化数据难以统计计算,现通过一个为区块链数据提供索引的主机服务解决了这个问题。应用规范 GraphQL API 查问这些索引(“subgraphs”)。将来,主机服务将演变为具备雷同性能的齐全去中心化的协定。两者都由 Graph Node 的开源实现提供反对,它提供了一种用于查问以太坊和 IPFS 网络数据的公开通明的解决方案,任何人都能够基于其提供的凋谢 API 创立并公布索引数据,即 subgraph。

本篇入门文档通过一个简略交易量统计例子,带你领略一番如传统数据库信息汇聚之旅(收集与抓取),当具备 THe Graph 常识储备后,咱们就开始吧。

次要钻研路线(一路私服到底)

  1. 智能合约 truffer cmd 公布到truffle/ganache 容器(私链)
  2. 合约 adress&abisthegraph 节点(私 node)
  3. markdemo1 工程(the graph)监听,收集数据,解决数据,包装通用查问
  4. the graph 输入查问接口到Dapp2(8000->3000)/query page(8001)
  5. Dapp2 调用合约 交易触发 the graph 输入变动

辅助输入:

  1. the graph subgraphs 官网浏览 https://thegraph.com/explorer 集体 subgraphs 核心 https://thegraph.com/explorer/dashboard
  2. truffle/ganache 对智能合约治理(部署、调试)
  3. Rimax 浏览器版对合约操作
  4. Dapp2 对智能合约的操作
  5. Dapp1 对智能合约的监听
  6. truffle/ganache、ganache cl、the graph 私节点 部署和应用
  7. 各种网络、本机环境、脚本替换踩过的坑(坑就是是为后来者节约工夫)
  8. 公布一个线上 subgraph 到 https://thegraph.com/explorer

线上体验 subgraph

在 https://thegraph.com/explorer 上有很多 subgraph,让咱们来看看 uniswap-v2

Github https://github.com/Uniswap 公布地址
ID QmWTrJJ9W8h3JE19FhCzzPYsJ2tgXZCdUqnbyuo64ToTBN subgraph
Queries (HTTP) https://api.thegraph.com/subg… 大量可体验数据查问

uniswap-v2

关上浏览器体验一下先

2 输出查问性能、参数和条件【点击紫色按钮】—> 到节点数据中心 3 里 ->4. 查问出冀望后果;当让 2 这个通用 API 也能够通过编程形式来调用,传入不同参数,体验下 GraphQL API 查问

{pairs{id}} {pairs(where:{id:”0x00004ee988665cdda9a1080d5792cecd16dc1220″}){id}} {pairs(orderBy:id){id}}

The graph 用 subgraph 跟踪智能合约


数据抓取 / 事件监控数据汇聚及查问

获取存储展现线上智能合约的 subgraph 简略例子 markdemo1

1. 抓以后工夫到上次 update 工夫内的记录
2. 存交易大于 2 的记录
3. 取某客户所以交易记录的条数和汇总金额
4. 以上仅在设想中(实在 the graph 就是踩好坑)

按 the graph 思路来
1) 零碎初始化把链上最近的区块拉下了,定时取最近区块
2)subgraph 的监听事件(原理就是 event 监听统统拉下数据,所以 1,2,3 就无意义)是拉下所有数据
3) 让咱们来看看我踩过的那些坑

  • mac 机器环境遗留问题 brew upgrade 时文件找不到,长期解决找到一个同目录类似文件替换(始终睡不着觉,后找到计划见附录 brew upgrade 装置报错问题解决替换 homebrew-bottles)代理端口 8001 和 the graph 零碎端口抵触,改代理
  • yarn,git 的代理和镜像要不停切换来应答家喻户晓的网络现状
  • docker 里 the graph 拜访里面 truffle/ganache 系统配置,脚本生成一个拜访不可达 ip172.18.2.0,批改为本机 IP 192.168.0.136(不能应用 127.0.0.1 补脑 docker 拜访 localhost 回到哪里?)
  • sel 命令第二次替换合同号要用第一次的合同号:例子程序中有 2 合同,可能都会再批改一次
  • truffle/ganache 每次启动会生成不同的账号序列,所以不同工夫导入合同的 owner 不同的,不要记第一个账号,会坑死人(能够用合同的历史交易记录查看 owner,见 markdemo2)
    4) 写 subgraph 须要留神或曾经实现的脚手架
  • id: ID! 要求每个实体都有一个非空的不反复主键 ID
  • dataSources 数据源配置初始读取块跳过合同公布之前的那些块:startBlock: 6627917

公布 subgraph 例子 markdemo1

先要部署容器公布一个智能合约(可参见 Hardhat + VS code,本篇应用 Ganache 部署)

Step 1: Ganache and Required Parameters

$ ganache-cli -h 0.0.0.0

例如:ganache-cli -h 0.0.0.0 -v /db -b 6 -a 8 -e 1000 -d expect chair toe trade spider wedding say item scare fog shrimp garlic

关上存在库,设置主动挖矿工夫 6,设置 8 个 1000gas 账号,导入现有私钥,(-d,能够是里面,也可用 - m 产生)启动阐明(罕用 -account –db –blockTime)
置信原文,了解更合乎你的口味,技术文档每个人了解的角度不一样关注的重点不一样,用心点也不一样
–db 关上(记得这个目录和文件要有读写权限,能力操作前面的账户导入什么的)
–account:指定账户私钥和账户余额来创立初始测试账户。可屡次设置
请留神,私钥长度为 64 个字符,并且必须以 0x 前缀的十六进制字符串模式输出。余额能够输出为一个整数或 0x 前缀的十六进制值,指定该帐户中 wei 的数量。
应用 –account 时,不会为您创立 HD 钱包。
-u or –unlock: 指定 – unlock… 屡次传递地址或帐户索引以解锁特定帐户。当与 — secure 一起应用时,–unlock 将笼罩指定帐户的锁定状态。
$ ganache-cli –secure –unlock “0x1234…” –unlock “0xabcd…”
-b 或 r –blockTime:指定主动挖矿的 blockTime,以秒为单位。默认值为 0,示意不进行主动挖矿??一交易一块(ganache will instantly mine a new block for every transaction)。

  • -a 或 –accounts:指定启动时要创立的测试账户数量。
  • -e 或 –defaultBalanceEther:调配给每个测试账户的 ether 数量,默认值为 100。
  • -b 或 r –blockTime:指定主动挖矿的 blockTime,以秒为单位。默认值为 0,示意不进行主动挖矿。
  • -d 或 –deterministic:基于预约的助记词(mnemonic)生成固定的测试账户地址。
  • -n 或 –secure:默认锁定所有测试账户,有利于进行第三方交易签名。
  • -m 或 –mnemonic:用于生成测试账户地址的助记词。
  • -p 或 –port:设置监听端口,默认值为 8545。
  • -h 或 –hostname:设置监听主机,默认值同 NodeJS 的 server.listen()。
  • -s 或 –seed:设置生成助记词的种子。
  • -g 或 –gasPrice:设定 Gas 价格,默认值为 20000000000。
  • -l 或 –gasLimit:设定 Gas 下限,默认值为 90000。
  • -f 或 –fork:从一个运行中的以太坊节点客户端软件的指定区块分叉。输出值该当是该节点旳 HTTP 地址和端口,例如http://localhost:8545。可选应用 @标记来指定具体区块,例如:http://localhost:8545@1599200。
  • -i 或 –networkId:指定网络 id。默认值为以后工夫,或应用所分叉链的网络 id。
  • –db:设置保留链数据的目录。如果该门路中曾经有链数据,ganache-cli 将用它初始化链而不是从新创立。
  • –debug:输入 VM 操作码,用于调试。
  • –mem:输入 ganache-cli 内存应用统计信息,这将代替规范的输入信息。
  • –noVMErrorsOnRPCResponse:不把失败的交易作为 RCP 谬误发送。开启这个标记使错误报告形式兼容其余的节点客户端,例如 geth 和 Parity。
-a or --accounts: Specify the number of accounts to generate at startup.
-e or --defaultBalanceEther: Amount of ether to assign each test account. Default is 100.
-b or --blockTime: Specify blockTime in seconds for automatic mining. If you don't specify this flag, ganache will instantly mine a new block for every transaction. Using the --blockTime flag is discouraged unless you have tests which require a specific mining interval.
-d or --deterministic: Generate deterministic addresses based on a pre-defined mnemonic.
-n or --secure: Lock available accounts by default (good for third party transaction signing)
-m or --mnemonic: Use a bip39 mnemonic phrase for generating a PRNG seed, which is in turn used for hierarchical deterministic (HD) account generation.
-p or --port: Port number to listen on. Defaults to 8545.
-h or --host or --hostname: Hostname to listen on. Defaults to 127.0.0.1 (defaults to 0.0.0.0 for Docker instances of ganache-cli).
-s or --seed: Use arbitrary data to generate the HD wallet mnemonic to be used.
-g or --gasPrice: The price of gas in wei (defaults to 20000000000)
-l or --gasLimit: The block gas limit (defaults to 0x6691b7)
--callGasLimit: Sets the transaction gas limit for eth_call and eth_estimateGas calls. Must be specified as a hex string. Defaults to "0x1fffffffffffff" (Number.MAX_SAFE_INTEGER)
-k or --hardfork: Allows users to specify which hardfork should be used. Supported hardforks are byzantium, constantinople, petersburg, istanbul, and muirGlacier (default).
-f or --fork: Fork from another currently running Ethereum client at a given block. Input should be the HTTP location and port of the other client, e.g. http://localhost:8545. You can optionally specify the block to fork from using an @ sign: http://localhost:8545@1599200.
forkCacheSize: number - The maximum size, in bytes, of the in-memory cache for queries on a chain fork. Defaults to 1_073_741_824 bytes (1 gigabyte). You can set this to 0 to disable caching (not recommended), or to -1 for unlimited (will be limited by your node process).
-i or --networkId: Specify the network id ganache-cli will use to identify itself (defaults to the current time or the network id of the forked blockchain if configured)
--chainId: Specify the Chain ID ganache-cli will use for eth_chainId RPC and the CHAINID opcode. For legacy reasons, the default is currently 1337 for eth_chainId RPC and 1 for the CHAINID opcode. Setting this flag will align the chainId values. This will be fixed in the next major version of ganache-cli and ganache-core!
--db: Specify a path to a directory to save the chain database. If a database already exists, ganache-cli will initialize that chain instead of creating a new one.
--debug: Output VM opcodes for debugging
--mem: Output ganache-cli memory usage statistics. This replaces normal output.
-q or --quiet: Run ganache-cli without any logs.
-v or --verbose: Log all requests and responses to stdout
-? or --help: Display help information
--version: Display the version of ganache-cli
--account_keys_path or --acctKeys: Specifies a file to save accounts and private keys to, for testing.
--noVMErrorsOnRPCResponse: Do not transmit transaction failures as RPC errors. Enable this flag for error reporting behaviour which is compatible with other clients such as geth and Parity.
--allowUnlimitedContractSize: Allows unlimited contract sizes while debugging. By enabling this flag, the check within the EVM for contract size limit of 24KB (see EIP-170) is bypassed. Enabling this flag will cause ganache-cli to behave differently than production environments.
--keepAliveTimeout: Sets the HTTP server's keepAliveTimeout in milliseconds. See the NodeJS HTTP docs for details. 5000 by default.
-t or --time: Date (ISO 8601) that the first block should start. Use this feature, along with the evm_increaseTime method to test time-dependent code.

Step 2: Running a local Graph node

在~graph-node/docker 目录下

$ docker-compose up;

#!/bin/bash

docker-compose down -v;

if [-d "data"]
then
  echo "Found old data for the graph node - deleting it";
  # we need to sudo this to remove system locked files
  sudo rm -rf data/;
fi

docker-compose up;

graph-node_1 | Jun 24 01:34:13.558 WARN Trying again after net_version RPC call failed (attempt #18) with result Err(Transport error: Error(Connect, Os { code: 111, kind: ConnectionRefused, message: “Connection refused”})), provider: mainnet-rpc-0
graph-node_1 | Jun 24 01:34:14.517 ERRO Connection to provider failed. Not using this provider, error: deadline has elapsed, provider: mainnet-rpc-0

该报错会引起第三步(Step 3)报错:

Failed to deploy to Graph node http://127.0.0.1:8020/: Ethereum network not supported by registrar: mainnet.
解决:ConnectionRefused 个别是对方服务器不能到达
找到 docker/docker-compose.yml-e 的 ethereum:’mainnet:http://host.docker.internal:8545′
批改为本地:ethereum: ‘mainnet:http://192.168.0.136:8545’

Step 3-0: 公布 markdemo1 合同

$ truffle compile
$ truffle migrate

Migrations:0x83Ad4160F00259D6D329c09A1436386a706e3818
GravatarRegistr:0xE54bA45F29b4247D75e86fD7A83a1E44160610D2

$ sed -i -e  's/0x2E645469f354BB4F5c8a05B3b30A929361cf77eC/0x83Ad4160F00259D6D329c09A1436386a706e3818/g'    subgraph.yaml

Step 3: Deploying to your local Graph Node

$ yarn create-local
$ yarn build && yarn deploy-local

最初例子输入成果如下:(http://127.0.0.1:8000/subgraphs/name/moluoping/markg)

Step 4: Dapp 调用

$ git clone https://github.com/graphprotocol/ethdenver-dapp/
$ echo 'REACT_APP_GRAPHQL_ENDPOINT=http://localhost:8000/subgraphs/name/moluoping/markdemo1' > .env
$ yarn && yarn start

监听智能合约交易事件 subgraph 例子 markdemo2

上一章节简略阐明了一个子 graph 公布过程,上面将在 Dapp 工程中增加上面代码,演示整个智能合约事件监听过程

var Web3 = require("web3")
var web3;
if (typeof web3 !== 'undefined') {web3 = new Web3(web3.currentProvider);
} else {web3 = new Web3(new Web3.providers.WebsocketProvider("ws://127.0.0.1:8545"));
}
web3.eth.defaultAccount = '0x4386997160134D4a67FD6A14DE7f924315D6F0A4';
console.log('defaultAccount:' + web3.eth.defaultAccount)
var contractAbi = [{"constant":false,"inputs":[{"name":"_imageUrl","type":"string"}],"name":"updateGravatarImage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"setMythicalGravatar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"getGravatar","outputs":[{"name":"","type":"string"},{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"gravatarToOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"ownerToGravatar","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_displayName","type":"string"}],"name":"updateGravatarName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_displayName","type":"string"},{"name":"_imageUrl","type":"string"}],"name":"createGravatar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"gravatars","outputs":[{"name":"owner","type":"address"},{"name":"displayName","type":"string"},{"name":"imageUrl","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"displayName","type":"string"},{"indexed":false,"name":"imageUrl","type":"string"}],"name":"NewGravatar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"displayName","type":"string"},{"indexed":false,"name":"imageUrl","type":"string"}],"name":"UpdatedGravatar","type":"event"}]
//Abi data from
// truffle/ganache:markdemo1/abis/Gravity.json
// Remix:web https://remix.ethereum.org/  tab 'SOLIDITY COMPILER'->bottom 'abi'
var contractAbiTruffle=contractAbi
var contractAbiRemix=contractAbi

var contractaAddressRemix ='0x4ef9BEb56eB0Ab92CDeD01Eff9A60554aE594d45'
// Remix:web https://remix.ethereum.org/  tab 'DEPLOY & RUN TRANSACTIONS'->bottom 'Deployed Contracts' list
var contractaAddressTruffle ='0x38FcB3d9c3C8958373D61B702049D695A6725AFE'
//$ truffle migrate

{var MyContract = new web3.eth.Contract(contractAbiRemix, contractaAddressRemix);
    MyContract.methods.updateGravatarName('aaaa').send({from: "0x4386997160134D4a67FD6A14DE7f924315D6F0A4"})
        .then(console.log);
    //from data: this app project http://localhost:3000/F12 history event data returnValues->"owner"
    MyContract.methods.getGravatar('0x38FcB3d9c3C8958373D61B702049D695A6725AFE').call()
        .then(console.log);
}
// {//     var MyContract = new web3.eth.Contract(contractAbiTruffle, contractaAddressTruffle);
//     MyContract.methods.updateGravatarName('bbbb').send({from: '0xC187EB4620dCEF0FFe5C45566969BdF2be3Ea7B7'})
//         .then(console.log);
//     //from data: this app project http://localhost:3000/F12 history event data returnValues->"owner"
//     MyContract.methods.getGravatar('0x38FcB3d9c3C8958373D61B702049D695A6725AFE').call()
//         .then(console.log);
// }

var myEventNew = MyContract.events.NewGravatar({filter:{},
    fromBlock: 0
}, function(error, event){})
    .on('data', function(event){console.log('NewGravatar');
        console.log(event); // same results as the optional callback above
    })
    .on('changed', function(event){// remove event from local database})
    .on('error', console.error);

var myEventUpdate = MyContract.events.UpdatedGravatar({filter:{},
    fromBlock: 0
}, function(error, event){})
    .on('data', function(event){console.log('UpdatedGravatar');
        console.log(event); // same results as the optional callback above
    })
    .on('changed', function(event){// remove event from local database})
    .on('error', console.error);
  1. 上个例子中 truffle/ganache 环境中在 $truffle migrate 可见智能合约地址,Abi 数据能够在 markdemo1 工程 markdemo1/abis/Gravity.json 获取,然而初学者先用 Remix 体验。
  2. 看下面代码
    而后就进去了,数据终于跑起来了 …….

markdemo3(一个销量统计 subgraph)

subgraph 在 the graph 市场上线

1. github 网站注册账号
上 github 网站登录(无账号注册新账号)

2. 获取 thegraph 网站令牌
在 https://thegraph.com/explorer/dashboard/ 关联登录后,获取 tocken

3. 创立 subgraphgraph

graph init --from-example moluo..../markdemo3

graph init –from-contract <CONTRACT_ADDRESS> \ [–network <ETHEREUM_NETWORK>] \ [–abi <FILE>] \ <GITHUB_USER>/<SUBGRAPH_NAME> [<DIRECTORY>]
moluo…. github 账号名 /markdemo3 subgraph 名字 创立工程并编译和产生相干资源

Subgraph name·moluo…./markdemo3
Directory to create the subgraph in·markdemo3
———
✔ Cloning example subgraph
✔ Update subgraph name and commands in package.json
✔ Initialize subgraph repository
✔ Install dependencies with yarn
✔ Generate ABI and schema types with yarn codegen
能够从以上脚本运行看编译过程

4. 公布到线上
a. 用令牌登 thegraph 开发核心

$ graph auth https://api.thegraph.com/deploy/880d70986bfc4172902641d870d96f37

graph auth https://api.thegraph.com/deploy/ <access-token>
<access-token> 为第 2 步的获取 tocken 留神 tocken 与后面有个空格,这是两个参数

# 如果报 The original error was: Cannot find module 'keytar'
$ npm i -g keytar

b. 创立 subgraph 名字
https://thegraph.com/explorer/dashboard/


subgraph 首字母大写,其余随便。

c. 将你的 subgraph 公布到 thegraph.com

$ cd markdemo3
$ yarn deploy

如果没有做 b 步骤,将报错
You may need to create subgraph at https://thegraph.com/explorer…
error Command failed with exit code 1.
c. 如果一起顺利,你能够看到:https://api.thegraph.com/subgraphs/name/moluoping/markdemo3

例子解析(聚焦 subgraph 的 markdemo4)

该例子间接从容器中合同向导生成 subgraph 工程:

$ graph init --from-contract 0x1e1215caD01aD7192832e0DACfA930Caf0132b43  --network mainnet --abi markdemo4.json moluoping/markdemo4

智能合约是从 Remix 中部署的,在 Remix 页面的编译页面能够 copy 到 contract adress,部署页面能够 copy 到 abi 并保留成文件,graph init 会生成性能必要的脚手架文件,并把合同的第一个事件监听函数作为查问实体主动代码生成(其余智能合约函数被正文)

这个工程就简洁很多,因为没有智能合约及智能合约部署相干文件,上面简略介绍下:
1) subgraph.yaml 本例 address,abi 来源于命令行依据将来设置,startBlock 定义监控链上开始区块
source:
address: ‘0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95’
abi: Contract
startBlock: 88888

2) schema.graphql 定义可查问的实体
当初如同都是可被 GraphGl 查问的实体,不可查问的实体如同还没凋谢
ID 必须 string 字段
GraphGl 是图数据库规范,所以多看看多对多关系。

3) mapping.ts 事件处理实现
配置在 subgraph.yaml
eventHandlers:

  • event: Transfer(indexed address,indexed address,uint256)
    handler: handleTransfer
  • event: Burn(indexed address,uint256)
    handler: handleBurn
    file: ./src/mapping.ts
    event 变量蕴含了合约相干(事件,合约函数)
    ExampleEntity “../generated/schema” 蕴含对 the subgraph 本地长久化相干

4) generated 里向导产生的 class
本地读写类 schema.ts
智能合约函数类 Contract.ts

5) 其余
package.json 蕴含了 subgraph 从编译到本地部署、the graph 部署的命令行
其余文件都是 copy 生成的


THe Graph 基础知识

  1. theGraph 社区
    1) 官网
    https://www.thegraph.com/
    https://thegraph.com/docs/define-a-subgraph
    2) 社区入门:以太坊数据索引平台 The Graph 应用教程 https://developer.aliyun.com/article/776668
  2. 常识体系
    1) 深刻理解 The Graph(上
    https://zhuanlan.zhihu.com/p/196773044
    2) 深刻理解 The Graph(下
    https://thegraph.com/blog/the-graph-network-in-depth-part-2
    3) 以太坊开发(一)——Truffle 和 Ganache
    https://blog.csdn.net/TurkeyCock/article/details/79165602
    4) 以太坊测试网络 Rinkeby 应用教程(没钱买币但又想玩以太坊怎么办?用以太坊测试网络吧~~~~)
    https://blog.csdn.net/wuhuimin521/article/details/85135610
  3. 利用
    1) 应用 TheGraph 欠缺 Web3 事件数据检索
    https://learnblockchain.cn/article/1589
    原文链接:https://soliditydeveloper.com/thegraph
    作者:MarkusWaas
    2) 以太坊 truffle+ganache 合约部署调试及 web3.js 事件监听过程记录
    https://www.e-learn.cn/topic/3716459
    原文链接:https://my.oschina.net/u/4277087/blog/4325668
    不羁岁月 提交于 2020-08-06 04:50:03
    3) 全副教程 web3.js 1.0 中文手册
    http://cw.hubwiz.com/card/c/web3.js-1.0/1/4/8/
    https://github.com/bluketalk/sweb3

欢送区块链行业气味相投的小伙伴增加小极微信,退出 blockgeek 区块链技术交换群,独特推动区块链技术遍及和倒退~

退出移动版