フォークを用いた迅速かつ容易なサブグラフのデバッグ
Reading time: 7 min
大量のデータを処理する多くのシステムと同様に、The GraphのIndexers(グラフノード)は、サブグラフとターゲットブロックチェーンの同期にかなりの時間がかかる場合があります。デバッグを目的とした素早い変更と、インデックス作成に必要な長い待ち時間の不一致は非常に逆効果であり、私たちはそれを十分に認識しています。そこで、LimeChainが開発したsubgraph forkingを導入し、今回はこの機能を使ってサブグラフのデバッグを大幅に高速化する方法を紹介します。
サブグラフのフォークとは、他のサブグラフのストア(通常はリモート) からエンティティをフェッチするプロセスです。
デバッグの文脈では、サブグラフのフォークにより、ブロックXへの同期を待つことなく、ブロックXで失敗したサブグラフのデバッグを行うことができます。
インデックス作成のためにリモートのGraphノードにサブグラフをデプロイし、ブロックXで失敗した場合でも、ブロックXと同期しているストアを使用して GraphQL クエリを提供することができます。つまり、ブロック X のインデックス作成時に発生するバグを修正するために、この最新のストアを利用できるのです。
簡単に言うと、ブロックXでデバッグされているローカルにデプロイされたサブグラフにインデックス状態の最新のビューを提供するために、ブロックXまでインデックスされたサブグラフを持つことが保証されているリモートGraphノードから 失敗したサブグラフをフォークしようとしているのです。
サブグラフのデバッグに集中し続けるために、物事をシンプルにして、Ethereum Gravity スマート コントラクトのインデックスを作成する example-subgraph を実行してみましょう。
以下は、Gravatar
のインデックスを作成するために定義されたハンドラで、バグが全くありません。
export function handleNewGravatar(event: NewGravatar): void {let gravatar = new Gravatar(event.params.id.toHex().toString())gravatar.owner = event.params.ownergravatar.displayName = event.params.displayNamegravatar.imageUrl = event.params.imageUrlgravatar.save()}export function handleUpdatedGravatar(event: UpdatedGravatar): void {let gravatar = Gravatar.load(event.params.id.toI32().toString())if (gravatar == null) {log.critical('Gravatar not found!', [])return}gravatar.owner = event.params.ownergravatar.displayName = event.params.displayNamegravatar.imageUrl = event.params.imageUrlgravatar.save()}
この場合、残念なことに、この完璧に見えるサブグラフをHostedService にデプロイすると、*"Gravatar not found!"*というエラーで失敗してしまいます。
通常の試すであろう修正方法:
- マッピングソースを変更して問題の解決を試す(解決されないことは分かっていても)
- サブグラフをHostedService(または別のリモートGraphノード)に再デプロイする
- 同期を待つ
- 再び問題が発生した場合は、1に戻る
このように、通常のデバッグ処理とほぼ同じですが、1つだけ、処理を恐ろしく遅くするステップがあります:3. 同期を待つ
サブグラフのフォークを利用することで、このステップを実質的に省略することができます。その方法は次の通りです:
- 適切なフォークベースセットを持つローカルのグラフ・ノードをスピンアップする
- マッピングのソースを変更し、問題を解決する
- ローカルGraphノードにデプロイし、失敗したサブグラフをフォークして、問題のブロックから開始する
- もし再度、壊れる場合1に戻る
さて、ここで2つの疑問が生じます:
- フォークベースとは?
- フォーキングは誰ですか?
回答:
fork-base
は「ベース」URLで、subgraph idが追加されたときのURL (<fork-base>/<subgraph-id>
) はサブグラフのストアに対する有効な GraphQL endpoint であることを示します。- フォーキングは簡単であり煩雑な手間はありません
$ graph deploy <subgraph-name> --debug-fork <subgraph-id> --ipfs http://localhost:5001 --node http://localhost:8020
また、サブグラフマニフェストのdataSources.source.startBlock
フィールドを問題のあるブロックの番号に設定することを忘れないでください。そうすれば、不要なブロックのインデックス作成を省略して、フォークを利用することができます。
そこで、以下の通りです:
- こちらの方法で、
fork-base
オプションをセットして、ローカルグラフノードをスピンアップします。HostedService から、先にデプロイしたバグのあるサブグラフをフォークするからです。
$ cargo run -p graph-node --release -- \--postgres-url postgresql://USERNAME[:PASSWORD]@localhost:5432/graph-node \--ethereum-rpc NETWORK_NAME:[CAPABILITIES]:URL \--ipfs 127.0.0.1:5001--fork-base https://api.thegraph.com/subgraphs/id/
- よく調べてみると、2つのハンドラで
Gravatar
をインデックスする際に使用されるid
表現にミスマッチがあることに気づきました。handleNewGravatar
はそれを hex (event.params.id.toHex()
) に変換しますが、handleUpdatedGravatar
は int32 (event.params.id.toI32()
) を使用するのでhandleUpdatedGravatar
は "Gravatar not found!" でパニックになってしまうのです。両方ともid
を16進数に変換するようにしています。 - 変更後、ローカルのGraphノードにサブグラフをデプロイし、失敗したサブグラフのフォークと
subgraph.yaml
でdataSources.source.startBlock
を6190343
にセットしてください。
$ graph deploy gravity --debug-fork QmNp169tKvomnH3cPXTfGg4ZEhAHA6kEq5oy1XDqAxqHmW --ipfs http://localhost:5001 --node http://localhost:8020
- ローカルのGraphノードが出力するログを調べてみると、すべてうまくいっていることがわかります。
- バグのないサブグラフをリモート グラフ ノードにデプロイし、その後ずっと幸せに暮らしています。 (じゃがいもはありません)
- 終わり