iXledgerのブログを要約と翻訳 - One nonce at a time: Ethereum blockchain transactions
今回はイーサリアム担当のValdi Kamenarovさんの記事です。
One nonce at a time: Ethereum blockchain transactions | iXledger
イーサリアムのディープな技術的な話ですので、技術者以外は読み飛ばしてもらってもOKです。というかiXledgerはやはり既にかなりの知見を貯めてますね。この辺りまで行き着いている技術者は世界でも少ないでしょう。
要約
- トランザクションノンスは実はセキュリティ上とても重要な役割を果たしている
- 単一トランザクションを処理する場合は問題ないが複数の顧客のトランザクションを一括で処理したい場合に課題がある
- 解決案は3つあるがどれもメリデメがある
翻訳
ブロックチェーンは素晴らしい技術ですが、他の優れた新しいテクノロジーと同じように、インフラや開発においてはまだまだ長い道のりがあります。
この記事ではiXledgerのエンジニア達が取り組んだ開発における様々なチャレンジの一例を紹介します。
イーサリアムのトランザクションとノンス
詳細に入る前にまずはイーサリアムでどのように処理が動作するのか見て行きましょう。
1つのトランザクションはシンプルに1つの署名されたデータパッケージです。データパッケージはイーサリアムネットワーク上のある外部アカウントから別の外部アカウントへの送信内容が含まれています。
外部アカウントとはイーサリアムの用語で人間が持つアカウントのことです。我々が持っているイーサリアムのウォレットアドレスです。対して自動実行されるアカウントのことをコントラクトアカウントと呼びます。
トランザクションはいくつかの値と1つのノンスからなります。ノンスには次に示すように2つあります。
トランザクションノンス - 送金者によって実行されたトランザクションの数
プルーフオブワークノンス(PoW) - プルーフオブワークの条件を満たすために調整するための意味のない数値。
今日はトランザクションノンスの話です。
ある外部アカウントが新しいトランザクションを送信する場合、その外部アカウントのトランザクションノンスの値が1足されます。
これだけだと良さが全然伝わらないですね。
しかしこれがある事で実は誰かがあなたのアカウントに対してリプレイアタックを仕掛けることが抑止されます。
2つのトランザクションが同じトランザクションノンスでシステムに入力されたら、片方のトランザクションだけが処理され、もう一方は破棄されます。
さらに考慮すべきこととして現在のノンスと新しいノンスの間にギャップがある場合、ギャップが解消されるまで新しいノンスのトランザクションは実行されません。
例で説明します。
https://www.ixledger.com/wp-content/uploads/2018/08/Diagram-Blog-.jpg
もしあなたが複数のトランザクションを送信して、3番目が失敗したとします。その場合3番目のトランザクションが処理されるまで他のトランザクションはストップします。
トランザクションの署名: ノード vs オフライン
取引がネットワークで処理されるためには外部所有アカウントの秘密鍵でパッケージ化して署名する必要があります。
通常、ブロックチェーンノードが処理する場合、ネットワーク経由でプライベートキーをブロックチェーンノードに送信するため、セキュリティリスクが発生します。
もう1つの方法は、トランザクションをブロックチェーンノードの外部で署名し、署名されたパッケージをノードに配信し処理します。この方法はハードウェアウォレットで使用され、プライベートキーがパブリックな場所では決して送信されず、署名されたトランザクションのみが送信されます。こちらはトランザクションを署名する必要があるので手順がやや複雑になります。
課題
ここからが難しい部分です。アプリケーションがすべての顧客の要求を一括してトランザクションを行う必要があると考えてみましょう。
その際トランザクションごとにノンスが正しく設定されていることを事前に確認する必要があります。(そうしないとエラーが起きたら全部の処理が止まるのでかえって非効率になってしまいます。)
例えばEthereumのJSON RPC APIコール(eth_getTransactionCountやライブラリなど)を介してトランザクションノンスを取得する方法がありますが、残念ながら、これはほとんどの場合うまく行きません。この機能は、現在のブロックおよび保留中のブロック内のトランザクションのトランザクション数を取得しますが、トランザクションプール(txpool)に追加のトランザクションが存在する可能性があっても考慮されません。これにより、txpool内のトランザクションですでにノンスが使用されていた場合に間違ったノンスが返されます。
解決案
解決案1:txpoolを使用してアプリケーションでnonceを解決する
eth_getTransactionCountがすべてのトランザクションを返さない場合がありうるのでtxpoolを取得し、潜在的なトランザクションをチェックし、それに応じてノンスを正しく計算することができます。
メリット:ほとんどの場合正しいノンスを持つようになり、ノードに依存しません。(ただし対象のノードが同期していない場合はうまく行きません)
デメリット:作成するトランザクションごとに全件をフェッチして反復する必要があるため非効率的です(処理量が増えてしまいます)
解決案2:パリティノードでの実装を使用する
ParityノードはGethと比較してより豊富な機能を提供します。その1つにnextNonce(アドレス)を使用してnonce値を取得できます。
メリット:最初のソリューションと比較して、ブロックチェーンノードで効率的なノンス処理が行えます。
デメリット:アプリケーションが接続できるノードを制限され、理想的ではありません。(多くのノードがgethを採用している)
解決案3:アプリケーション内でノンスを完全に処理する
トランザクションを順序付けし、ノードに絶えず照会する必要なしにノンスを割り当てることを担当するカスタム・トランザクション・マネージャーを作成することです。
メリット:他の2つのソリューションよりも高速だと思われます。
デメリット:ブロックチェーンのワールドステートから隔離され、独自の問題が発生します。
結局それぞれの案にメリット、デメリットがあり、実現にはトランザクションの再試行やキャンセルなどの複数の追加要件や改善が必要です。
重要なことは、ブロックチェーンのエコシステム全体がまだこのような多くの課題を抱えていることです。
ソフトウェアエンジニアとしての我々の知見を共有することでイーサリアムの改善に役立つことを望んでいます。
以上です。