溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Geth 中如何使用GraphQL

發(fā)布時(shí)間:2021-07-30 17:35:38 來(lái)源:億速云 閱讀:172 作者:Leah 欄目:互聯(lián)網(wǎng)科技

Geth 中如何使用GraphQL,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

1、JSON-RPC API有什么問(wèn)題?

讓我們先了解下經(jīng)典的JSON-RPC API存在什么問(wèn)題。

正如其名稱(chēng)所示,JSON-RPC是一種遠(yuǎn)程過(guò)程調(diào)用協(xié)議,它被設(shè)計(jì)用來(lái)調(diào)用遠(yuǎn)端的函數(shù)并返回計(jì)算結(jié)果。JSON-RPC是相當(dāng)寬泛的協(xié)議,你需要在它之上設(shè)計(jì)自己的調(diào)用接口。

但是JSON-RPC的問(wèn)題在于它不支持靈活的查詢(xún),這會(huì)導(dǎo)致計(jì)算資源和數(shù)據(jù)傳輸方面的雙重浪費(fèi):

  • 即使用戶(hù)只需要部分?jǐn)?shù)據(jù),RPC調(diào)用也需要返回大量數(shù)據(jù),造成帶寬的 浪費(fèi)。例如你調(diào)用eth_getBlock的目的只是獲取礦工地址,但是它依然 需要返回完整的區(qū)塊數(shù)據(jù)。

  • 如果用戶(hù)重復(fù)調(diào)用某個(gè)RPC接口,即使每次調(diào)用只返回一點(diǎn)點(diǎn)數(shù)據(jù),也會(huì) 浪費(fèi)節(jié)點(diǎn)的CPU。例如當(dāng)你調(diào)用eth_getTransactionReceipt接口輪詢(xún)某個(gè) 交易的收據(jù)時(shí)。

對(duì)于以太坊的JSON-RPC API,由于區(qū)塊鏈數(shù)據(jù)的結(jié)構(gòu)特點(diǎn),上面的問(wèn)題被進(jìn)一步放大了,多次執(zhí)行一個(gè)查詢(xún)(例如eth_getBalance)需要確保查詢(xún)是同一世界狀態(tài)甚至是在同一個(gè)節(jié)點(diǎn)上:當(dāng)你使用多個(gè)節(jié)點(diǎn)進(jìn)行負(fù)載均衡處理時(shí),不同的后臺(tái)節(jié)點(diǎn)可能有不同的同步延遲,從而可能對(duì)相同的RPC請(qǐng)求返回不同的內(nèi)容。

為了解決這些問(wèn)題,以太坊EIP 1767提出了以太坊節(jié)點(diǎn)的GraphQL接口建議,Geth在1.9.0版本中引入了對(duì)EIP 1767的支持,實(shí)現(xiàn)了完整的原生GraphQL支持。

2、什么是GraphQL?

GraphSQL是為了解決REST API存在的問(wèn)題而提出的一種新的查詢(xún)語(yǔ)言。GraphQL將數(shù)據(jù)對(duì)象關(guān)系 映射到一個(gè)圖(Graph),并設(shè)計(jì)了一種查詢(xún)語(yǔ)言(Query Language)來(lái)遍歷圖中關(guān)系 —— 這也是GraphQL 名稱(chēng)的來(lái)源。

這篇文章非常適合不熟悉GraphQL的開(kāi)發(fā)者快速理解GraphQL的基本概念,以及如何利用NodeJS技術(shù)棧實(shí)現(xiàn)GraphQL的服務(wù)端與客戶(hù)端:從SQL到GraphQL。

3、開(kāi)啟Geth的GraphQL支持

Geth 1.9.0引入的對(duì)GraphQL的原生支持。在啟動(dòng)geth時(shí),使用--graphql命令行標(biāo)志就可以開(kāi)啟GraphQL API接口了。例如,執(zhí)行下面的命令來(lái)接入以太坊G?rli測(cè)試鏈并開(kāi)啟GraphQL API支持:

~$ geth --goerli --graphql

4、Geth GraphQL瀏覽器

一旦開(kāi)啟了Geth的GraphQL支持,就可以通過(guò)Geth預(yù)置的GraphQL瀏覽器來(lái)進(jìn)行測(cè)試,GraphQL服務(wù)默認(rèn)在8547端口監(jiān)聽(tīng),API訪(fǎng)問(wèn)路徑為/graphql??梢允褂萌缦耈RL訪(fǎng)問(wèn)Geth的GraphQL瀏覽器:

http://localhost:8547

界面如下所示,最左邊就是輸入的GraphQL查詢(xún):

Geth 中如何使用GraphQL 為了便于查看,這里列出左邊的GraphQL查詢(xún)語(yǔ)句:

{
  logs(filter: {fromBlock: 0,
    addresses: ["0xf105795bf5d1b1894e70bd04dc846898ab19fa62"],
    topics: [["0x0f0c27adfd84b60b6f456b0e87cdccb1e5fb9603991588d87fa99f5b6b61e670"]]}
  ) {
    transaction {
      hash
      from {
        address
      }
      block{
        number
        timestamp
      }
    }
  }
}

你可以這樣理解上面的GraphQL語(yǔ)句:

  • 查詢(xún)?nèi)罩緇ogs

    • 查詢(xún)條件:使用filter對(duì)象指定

    • 返回字段:transaction,其結(jié)構(gòu)如上所示

5、實(shí)例對(duì)比JSON-RPC API和Geth GraphQL

假設(shè)我們要查詢(xún)最新的10個(gè)區(qū)塊的礦工賬號(hào)以及這些賬號(hào)的余額,使用JSON-RPC的實(shí)現(xiàn)代碼如下:

async function main() {
  const lastBlock = await web3.eth.getBlockNumber()
  result = []

  for (let i = lastBlock; i >= lastBlock - 10; i--) {
    let block = await web3.eth.getBlock(i)
    let blockRes = {}
    blockRes.number = i
    blockRes.miner = {}
    blockRes.miner.address = block.miner
    blockRes.miner.balance = await web3.eth.getBalance(block.miner)
    result.push(blockRes)
  }
  console.log(result);
}

我們需要進(jìn)行10次循環(huán),逐個(gè)查詢(xún)每個(gè)區(qū)塊的礦工賬號(hào)及其余額。在每次循環(huán)中,我們需要調(diào)用兩次RPC API,分別查詢(xún)區(qū)塊數(shù)據(jù)和賬戶(hù)余額,因此總共需要10*2 = 20 次調(diào)用。

下面是獲取同樣數(shù)據(jù)的GraphQL查詢(xún):

{
  blocks(from:lastBlock-10, to:lastBlock) {
    number
    miner{
      address
      balance
    }
  }
}

你可以在Geth GraphQL瀏覽器中輸入并執(zhí)行上面的查詢(xún)語(yǔ)句。令人震驚的是,我們只進(jìn)行1次調(diào)用就完成了之前采用JSON-RPC時(shí)20次調(diào)用才完成的任務(wù)!

6、Geth GraphQL的后向兼容性

在Geth源代碼中,schema.go文件中包含了當(dāng)前的GraphQL語(yǔ)法支持。下表列出了Geth GraphQL目前的實(shí)現(xiàn)狀態(tài),其中簡(jiǎn)要說(shuō)明欄目描述了JSON-RPC對(duì)應(yīng)的Geth GraphQL語(yǔ)句:

<table class="table table-striped"> <thead> <tr> <th>JSON-RPC</th> <th>GraphQL狀態(tài)</th> <th>簡(jiǎn)要說(shuō)明</th> </tr> </thead> <tbody> <tr> <td>eth_blockNumber</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block { number } }</code></td> </tr> <tr> <td>eth_call</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ call(data: { to: "0x...", data: "0x..." }) { data status gasUsed } }</code></td> </tr> <tr> <td>eth_estimateGas</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ estimateGas(data: { to: "0x...", data: "0x..." }) }</code></td> </tr> <tr> <td>eth_gasPrice</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ gasPrice }</code></td> </tr> <tr> <td>eth_getBalance</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ account(address: "0x...") { balance } }</code></td> </tr> <tr> <td>eth_getBlockByHash</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(hash: "0x...") { ... } }</code></td> </tr> <tr> <td>eth_getBlockByNumber</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(number: 123) { ... } }</code></td> </tr> <tr> <td>eth_getBlockTransactionCountByHash</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(hash: "0x...") { transactionCount } }</code></td> </tr> <tr> <td>eth_getBlockTransactionCountByNumber</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(number: x) { transactionCounnt } }</code></td> </tr> <tr> <td>eth_getCode</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ account(address: "0x...") { code } }</code></td> </tr> <tr> <td>eth_getLogs</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ logs(filter: { ... }) { ... } }</code> or <code class="highlighter-rouge">{ block(...) { logs(filter: { ... }) { ... } } }</code></td> </tr> <tr> <td>eth_getStorageAt</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ account(address: "0x...") { storage(slot: "0x...") } }</code></td> </tr> <tr> <td>eth_getTransactionByBlockHashAndIndex</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(hash: "0x...") { transactionAt(index: x) { ... } } }</code></td> </tr> <tr> <td>eth_getTransactionByBlockNumberAndIndex</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(number: n) { transactionAt(index: x) { ... } } }</code></td> </tr> <tr> <td>eth_getTransactionByHash</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ transaction(hash: "0x...") { ... } }</code></td> </tr> <tr> <td>eth_getTransactionCount</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ account(address: "0x...") { transactionCount } }</code></td> </tr> <tr> <td>eth_getTransactionReceipt</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ transaction(hash: "0x...") { ... } }</code></td> </tr> <tr> <td>eth_getUncleByBlockHashAndIndex</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(hash: "0x...") { ommerAt(index: x) { ... } } }</code></td> </tr> <tr> <td>eth_getUncleByBlockNumberAndIndex</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(number: n) { ommerAt(index: x) { ... } } }</code></td> </tr> <tr> <td>eth_getUncleCountByBlockHash</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(hash: "0x...") { ommerCount } }</code></td> </tr> <tr> <td>eth_getUncleCountByBlockNumber</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ block(number: x) { ommerCount } }</code></td> </tr> <tr> <td>eth_protocolVersion</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ protocolVersion }</code></td> </tr> <tr> <td>eth_sendRawTransaction</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">mutation { sendRawTransaction(data: data) }</code></td> </tr> <tr> <td>eth_syncing</td> <td>已實(shí)現(xiàn)</td> <td><code class="highlighter-rouge">{ syncing { ... } }</code></td> </tr> <tr> <td>eth_getCompilers</td> <td>未實(shí)現(xiàn)</td> <td>JSON-RPC已廢棄編譯器功能</td> </tr> <tr> <td>eth_compileLLL</td> <td>未實(shí)現(xiàn)</td> <td>JSON-RPC已廢棄編譯器功能</td> </tr> <tr> <td>eth_compileSolidity</td> <td>未實(shí)現(xiàn)</td> <td>JSON-RPC已廢棄編譯器功能</td> </tr> <tr> <td>eth_compileSerpent</td> <td>未實(shí)現(xiàn)</td> <td>JSON-RPC已廢棄編譯器功能</td> </tr> <tr> <td>eth_newFilter</td> <td>未實(shí)現(xiàn)</td> <td>過(guò)濾器功能可能在未來(lái)EIP中約定</td> </tr> <tr> <td>eth_newBlockFilter</td> <td>未實(shí)現(xiàn)</td> <td>過(guò)濾器功能可能在未來(lái)EIP中約定</td> </tr> <tr> <td>eth_newPendingTransactionFilter</td> <td>未實(shí)現(xiàn)</td> <td>過(guò)濾器功能可能在未來(lái)EIP中約定</td> </tr> <tr> <td>eth_uninstallFilter</td> <td>未實(shí)現(xiàn)</td> <td>過(guò)濾器功能可能在未來(lái)EIP中約定</td> </tr> <tr> <td>eth_getFilterChanges</td> <td>未實(shí)現(xiàn)</td> <td>過(guò)濾器功能可能在未來(lái)EIP中約定</td> </tr> <tr> <td>eth_getFilterLogs</td> <td>未實(shí)現(xiàn)</td> <td>過(guò)濾器功能可能在未來(lái)EIP中約定</td> </tr> <tr> <td>eth_accounts</td> <td>未實(shí)現(xiàn)</td> <td>賬戶(hù)功能不屬于節(jié)點(diǎn)核心API</td> </tr> <tr> <td>eth_sign</td> <td>未實(shí)現(xiàn)</td> <td>賬戶(hù)功能不屬于節(jié)點(diǎn)核心API</td> </tr> <tr> <td>eth_sendTransaction</td> <td>未實(shí)現(xiàn)</td> <td>賬戶(hù)功能不屬于節(jié)點(diǎn)核心API</td> </tr> <tr> <td>eth_coinbase</td> <td>未實(shí)現(xiàn)</td> <td>挖礦相關(guān)功能將單獨(dú)定義</td> </tr> <tr> <td>eth_getWork</td> <td>未實(shí)現(xiàn)</td> <td>挖礦相關(guān)功能將單獨(dú)定義</td> </tr> <tr> <td>eth_hashRate</td> <td>未實(shí)現(xiàn)</td> <td>挖礦相關(guān)功能將單獨(dú)定義</td> </tr> <tr> <td>eth_mining</td> <td>未實(shí)現(xiàn)</td> <td>挖礦相關(guān)功能將單獨(dú)定義</td> </tr> <tr> <td>eth_submitHashrate</td> <td>未實(shí)現(xiàn)</td> <td>挖礦相關(guān)功能將單獨(dú)定義</td> </tr> <tr> <td>eth_submitWork</td> <td>未實(shí)現(xiàn)</td> <td>挖礦相關(guān)功能將單獨(dú)定義</td> </tr> </tbody> </table>


看完上述內(nèi)容,你們掌握Geth 中如何使用GraphQL的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI