The Graph 是用于索引和查问区块链数据的去中心化协定。建设 subgraphs 用规范 GraphQL API 查问这些索引解决了去中心化数据遍历的苦楚。
海量的去中心化数据难以统计计算,现通过一个为区块链数据提供索引的主机服务解决了这个问题。应用规范 GraphQL API 查问这些索引(“subgraphs”)。将来,主机服务将演变为具备雷同性能的齐全去中心化的协定。两者都由 Graph Node 的开源实现提供反对,它提供了一种用于查问以太坊和 IPFS 网络数据的公开通明的解决方案,任何人都能够基于其提供的凋谢 API 创立并公布索引数据,即 subgraph。
本篇入门文档通过一个简略交易量统计例子,带你领略一番如传统数据库信息汇聚之旅(收集与抓取),当具备 THe Graph 常识储备后,咱们就开始吧。
次要钻研路线(一路私服到底)
- 智能合约 被truffer cmd 公布到truffle/ganache 容器(私链)
- 合约 adress&abis与thegraph 节点(私 node)
- markdemo1 工程(the graph)监听,收集数据,解决数据,包装通用查问
- the graph 输入查问接口到Dapp2(8000->3000)/query page(8001)
- Dapp2 调用合约 交易触发 the graph 输入变动
辅助输入:
- the graph subgraphs 官网浏览 https://thegraph.com/explorer 集体 subgraphs 核心 https://thegraph.com/explorer/dashboard
- truffle/ganache 对智能合约治理(部署、调试)
- Rimax 浏览器版对合约操作
- Dapp2 对智能合约的操作
- Dapp1 对智能合约的监听
- truffle/ganache、ganache cl、the graph 私节点 部署和应用
- 各种网络、本机环境、脚本替换踩过的坑(坑就是是为后来者节约工夫)
- 公布一个线上 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);
- 上个例子中 truffle/ganache 环境中在 $truffle migrate 可见智能合约地址,Abi 数据能够在 markdemo1 工程 markdemo1/abis/Gravity.json 获取,然而初学者先用 Remix 体验。
- 看下面代码
而后就进去了,数据终于跑起来了 …….
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 基础知识
- theGraph 社区
1) 官网
https://www.thegraph.com/
https://thegraph.com/docs/define-a-subgraph
2) 社区入门:以太坊数据索引平台 The Graph 应用教程 https://developer.aliyun.com/article/776668 - 常识体系
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 - 利用
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 区块链技术交换群,独特推动区块链技术遍及和倒退~