はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、ブロックハッシュを使用して、ブロックチェーンのステートを問い合わせられるようにJSON RPCを拡張する提案しているEIP1898についてまとめていきます!

以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。

他にも様々なEIPについてまとめています。

概要

EIP1898は、EthereumのJSON-RPCインターフェースにおけるdefault block parameter(デフォルトブロックパラメータ)」に関する仕様拡張です。 これまでの仕様では、latest(最新ブロック)やfinalized(確定済みブロック)、あるいはブロック番号といった形式でブロックを指定していましたが、EIP1898では「ブロックハッシュ」そのものを使ってブロックを直接指定できるようになります。

この変更により、ノードに対して問い合わせを行う時に、ユーザーはブロックがチェーンの中でどの位置にあるかにかかわらず、そのブロックを明確に特定することが可能になります。 これは、ブロックの再編成(reorg)といったネットワークイベントが発生しても、ユーザーが特定の状態に基づいた正確な情報を取得し続けられるという利点があります。

この機能は、EIP234(トランザクションのトレース機能でブロックハッシュを使用可能にした提案)の汎用化ともいえるもので、より多くのJSON-RPCメソッドに適用範囲を広げることを目的としています。 ブロックハッシュによる明示的な指定が可能になることで、クライアントは自分が関心を持つブロック状態を一貫して追跡しやすくなり、たとえそのブロックが最終的にメインチェーンから外れた場合でも、適切な状態管理が可能になります。

EIP234については以下の記事を参考にしてください。

また、EIP1898はクライアントがノードとの接続を永続的に維持したり、ノード側でクライアントごとの状態を保存する必要がなくなるという意味でも、効率性と柔軟性を向上させる内容となっています。 開発者やアプリケーションにとって、reorgの影響を最小限に抑えつつ、正確なブロック状態を参照できる仕組みは、安定したユーザー体験の提供に貢献します。

仕様

対象となるJSON-RPCメソッド

EIP1898では、Ethereumのクライアントが提供するいくつかのJSON-RPCメソッドに対して、新たに「ブロックハッシュによるブロック指定」を可能にする仕組みを導入しています。 これまでこれらのメソッドでは、ブロック番号や特定のタグ(例:"latest"や"finalized")によって対象ブロックを指定していましたが、今後はそれに加えて「ブロックハッシュ」も使用できるようになります。

対象となるメソッドは以下です。

  • eth_getBalance
  • eth_getStorageAt
  • eth_getTransactionCount
  • eth_getCode
  • eth_call
  • eth_getProof

これらのメソッドでは、これまでdefaultBlockというパラメータを使って、参照したいブロックを次のいずれかの形式で指定していました。

  • 16進数表記のブロック番号(例:"0x10d4f")
  • "earliest"(ジェネシスブロック)
  • "latest"(最新の正規チェーン上のブロック)
  • "pending"(未確定のトランザクションを含む状態)
  • "safe"(最も「セーフ」と見なされたブロック)
  • "finalized"(最終確定済みブロック)

しかし、こうした文字列や数値だけでは、ブロックのハッシュとの明確な区別が難しく、また再編成(reorg)が起きた場合に特定のブロックを確実に指定することが困難でした。 そこで提案されているのが、新しいパラメータ構造です。

新しいパラメータ形式

この仕様により、defaultBlockの代わりに以下のようなオブジェクト形式を使用できるようになります:

json
{
  "blockNumber": "0x10d4f"
}

または、ブロックハッシュを使って明示的に指定することも可能です。

json
{
  "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
}

さらに、blockHashを使用する際には、オプションでrequireCanonicalという真偽値を付け加えることができます。 これは「そのブロックが正規チェーン(canonical chain)上に存在する必要があるかどうか」を指定するもので、以下のように記述します。

json
{
  "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
  "requireCanonical": true
}

この場合、対象のブロックが正規チェーンに含まれていなければエラーになります。 一方でrequireCanonical: falseとした場合は、チェーン上に存在していさえすれば、正規チェーンでなくても許容されます。

エラーハンドリングの仕様

ブロックが見つからなかった場合には、JSON-RPCエラーとして「-32001: Resource not found」が返されるべきです。

もしrequireCanonical: trueで指定されていて、そのブロックが正規チェーンに存在しない場合は、「-32000: Invalid input」という異なるエラーコードが返されるべきです。 この違いにより、クライアントは「ブロックが存在しない」場合と「ブロックは存在するが正規でない」場合を区別できます。

なお、ブロックが存在しない場合には、必ずその時点で「見つからないエラー」を返す必要があり、「正規であるかどうか」のチェックはその次に行われるべきです。

互換性の維持

この新しい構文は、従来のブロック指定方法とも共存可能です。 例えば、以下の3つの指定はすべて同じブロック(ジェネシスブロック)を指すことになります。

json
"earliest"
"0x0"
{ "blockNumber": "0x0" }

同様に、ブロックハッシュを使った次の指定も有効です。

json
{ "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" }
{ "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true }
{ "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false }

このように、新仕様は既存の記法を壊すことなく、より柔軟かつ正確なブロック参照を可能にしています。 JSON-RPCクライアントの実装においても、比較的スムーズな移行が可能となります。

補足

なぜこの仕様変更が必要なのか

EthereumのJSON-RPCには、ブロックチェーンの状態を問い合わせるためのメソッドがいくつか存在します。 例えば、eth_getBalanceでアカウントの残高を取得したり、eth_callでスマートコントラクトの関数を呼び出したりすることができます。 しかし、これらのメソッドでは「どのブロックのステートを参照するか」を完全に明示する方法が存在していません。 指定できるのは「最新ブロック」や「finalized」などのラベルや、ブロック番号だけであり、ブロックハッシュによる一意な指定ができないのです。

この制限により、アプリケーションの開発者は複数のステート参照が必要な場合に、矛盾のないデータを取得することが難しくなります。 例えば、ウォレットが送金直後に送信者と受信者の残高を表示したい場合、まず送信者の残高を取得し、次に受信者の残高を取得するという流れになります。 しかしその間にブロックチェーン上で再編成(reorg)が発生した場合、2つの参照は異なるブロックをもとにしてしまい、整合性のないデータになってしまう可能性があります。

もう少し複雑な例として、分散型取引所のUIが挙げられます。 注文情報がオンチェーンに保存されている場合、UIは各注文をeth_callでひとつずつ参照してデータを取得します。 このときも同様に、途中でチェーンの状態が変わってしまえば、一部の注文データが古いブロックに基づき、他は新しいブロックに基づくという不整合が起こり得ます。

この問題を避けるために、開発者はいくつかの工夫を行うことがあります。 例えば、最新のブロック番号を決め打ちで使い、呼び出しごとにそのブロック番号のハッシュを確認し、不一致があれば最初からやり直すという方法があります。 しかしこの方法では、呼び出し回数が増えるたびにネットワーク負荷がO(n)で増加し、再試行も含めるとさらに大きなコストがかかります。 また、運が悪ければ一度外れたブロックが再び正規チェーンに戻ることで、整合性チェックがすり抜ける可能性もあります。

他にも、ブロックハッシュでフィルタリングできるログ情報(イベント)に依存する方法もありますが、これはスマートコントラクト側が適切なイベントを発行していることが前提になります。 イベントがなければ、意図するステートを再現することができません。 また、parity_subscribeのような独自拡張に頼るケースもありますが、これはクライアントとノード間で常時接続(WebSocketやIPC)が必要になるため、システム設計が複雑になります。

こうした課題を根本的に解決するのが、EIP1898による「ブロックハッシュを明示的に指定する機能」です。 eth_callやeth_getBalanceといったメソッドにブロックハッシュを直接渡せるようになることで、すべてのステート参照を同じブロックに基づいて正確に行うことができるようになります。 これにより、開発者はブロックの整合性やreorgの影響を気にすることなく、安定したアプリケーションの挙動を実現できるのです。

引用

Charles Cooper (@charles-cooper), "EIP-1898: Add blockHash to defaultBlock methods," Ethereum Improvement Proposals, no. 1898, April 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1898.

最後に

今回は「ブロックハッシュを使用して、ブロックチェーンのステートを問い合わせられるようにJSON RPCを拡張する提案しているEIP1898」についてまとめてきました! いかがだったでしょうか?

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

他の媒体でも情報発信しているのでぜひ他も見ていってください!