見出し画像

ステートフルプリコンパイルを使用したEVMのカスタマイズ

EVMの独自のカスタマイズされたインスタンスを構築することに興味がある場合は、今日が幸運な日です。ステートフルプリコンパイルは、開発者がSolidityを1行も記述せずに、EVMインスタンスに機能を追加するための新しいインターフェイスを提供します。

ステートフルプリコンパイルは、ステートアクセスを追加することにより、EVMのプリコンパイルの概念に基づいて構築され、さまざまな機能を可能にします。

この記事では、ステートフルプリコンパイルを使用して、通常のスマートコントラクトとまったく同じ方法でプリコンパイルを操作しながら、追加されたネイティブ機能をEVMに実装できるように、それらを拡張する方法について説明します。

ステートフルプリコンパイルを使用して、オンチェーンVRFを実装したり、EVMインスタンスのネイティブコインを作成したり、スマートコントラクトのパフォーマンスとガス効率を高めたりすることができます。

可能性は無限大。ステートフルプリコンパイルの要点は、開発者の手に力を与えることです。

この記事では、ステートフルプリコンパイルとは何か、およびEVMをカスタマイズするためにそれらが提供する潜在的な機能について詳しく説明します。独自のステートフルプリコンパイルの実装に関する完全なウォークスルーについては、近日公開されるより詳細なチュートリアルにご注目ください。

EVMのプリコンパイルとは何ですか?

プリコンパイルされたコントラクトは、次のインターフェイスを実装する単純なプログラムです。

これはバイトスライスを受け取り、2つの値を返します。

  1. 操作を実行するために必要なガスの量

  2. 入力に対してプリコンパイルを実行した結果

プリコンパイルは、Solidityで実装するのが困難で非効率的な暗号化操作やその他の機能を実装するために使用されます。

プリコンパイルはステートレスであり、通常は既存のライブラリを利用します。以下は、Goで記述されたプリコンパイル実装の例です。ほんの数行のコードを使用してSHA256ハッシュ操作を実装します。この例はGoで記述されていますが、プリコンパイルは、特定のEVM実装で使用された言語で記述できます。

プリコンパイルはどのように使用されますか?

スマートコントラクトの開発者は、事前定義されたキーワード(以下の例ではsha256)を使用してプリコンパイルを呼び出すことができます。これにより、開発者は自分で暗号化ライブラリを実装せずに暗号化ライブラリを利用できます(独自の暗号化をロールしないでください)。

内部的には、プリコンパイルは指定されたアドレスを使用してCALLオペコードによって呼び出されます。すべてのCALLオペコード(CALL、STATICCALL、DELEGATECALL、およびCALLCODE)は、プリコンパイルを呼び出すことができます。通常、これらのオペコードはスマートコントラクトを呼び出すために使用され、渡される入力はスマートコントラクト呼び出しにエンコードされたパラメーターを表します。ただし、プリコンパイルの場合、入力はプリコンパイルに直接渡されて操作が実行され、トランザクションの実行コンテキストから必要な量のガスが差し引かれます。

ステートフルプリコンパイルを構築するにはどうすればよいですか?

ステートフルプリコンパイルは、ステートアクセスを追加することにより、プリコンパイルの概念に基づいています。これにより、EVMインスタンスをカスタマイズするためのさまざまな潜在的なユースケースのロックが解除されます。

さて、構築を始めましょう。

まず、関数セレクターについて説明します。各EVMトランザクションにはデータフィールドがあります。分散型取引所(DEX)にトランザクションを発行すると、DEXスマートコントラクトの関数が呼び出され、関数セレクターが呼び出す関数を指定します。関数セレクターと関数への引数は、トランザクションのデータフィールドを構成します。さらに、スマートコントラクトは、CALLオペコードを使用して同じ方法で相互に呼び出すことができます。この場合、関数セレクターとその引数は、CALL操作への入力データとしてエンコードされます。

関数のシグネチャのKECCAK256ハッシュの最初の4バイトは、その関数セレクターです。

たとえば、次の関数がある場合:

次に、その関数セレクターはkeccak256(“ setNone(address)”)[0:4]になり、入力データが合計36バイトになるように、20バイトのアドレスが32バイトのスロットにパックされます。

ステートフルプリコンパイル内で関数セレクターを模倣することにより、ステートフルプリコンパイルの機能用のルーターを追加できるため、Solidityに組み込まれているコントラクトと同じ方法で呼び出すことができます。

statefulPrecompileFunctionは、単一のスマートコントラクト関数を表し、次の機能を備えています。

  • 署名に基づく4バイトの関数セレクター

  • 実行機能

ステートアクセスを実行関数(元のプリコンパイルインターフェイスからの新しい追加)に注入することにより、ステートフルプリコンパイルは独自の状態空間を維持し、EVMの状態と対話することができます。スマートコントラクト呼び出しをそれぞれの関数にルーティングするためのこのインターフェイスを定義したので、実行する必要があるのはGoで実行関数を定義することだけです。

入力として1バイトスライスのみを取り込んだ元のプリコンパイルインターフェイスに制限されなくなったため、これらの実行関数はEVM状態に完全にアクセスでき、はるかに幅広い機能を実装するために使用できます。実際、スマートコントラクトで構築できるものはすべて、ステートフルプリコンパイルで構築することもできます。

ただし、その逆は当てはまりません。ステートフルプリコンパイルは、カスタマイズされたEVMの開発者によって定義されるため、柔軟性と特権がはるかに高くなります(開発者には大きな責任が伴います)。ステートフルプリコンパイルは、バランスを変更したり、他のコントラクトのストレージを読み取り/書き込みしたり、EVMのマークルトライの範囲外の外部ストレージにフックしたりすることもできます(注:状態の一部が移動されるため、これには高速同期の影響が伴います)マークルトライから)。

ステートフルプリコンパイルの唯一の実際の制限は、ネットワーク内のすべてのノードが同じ結果を計算するように、実行関数が決定論的でなければならないことです。

何を構築しましたか?

まだワクワクしていない方のために、私たちが構築したものを見ていきましょう。

スマートコントラクトで構築できるものはすべて、ステートフルプリコンパイルで構築できるようになりました。

EVMを実装するのと同じ言語でステートフルプリコンパイルを構築でき(subnet-evmの場合はGo )、Solidityで実装され、EVMインタープリター内で実行されるプログラムよりも高速かつ安価になります。

ステートフルプリコンパイルはSolidityの範囲外に存在し、EVMでは実行されません。これは、EVMのルールセットに拘束されず、開発者がEVMにシームレスに統合し、Solidityに組み込まれたスマートコントラクトとの完全な互換性を維持しながら、EVMの機能を拡張できることを意味します。

Solidityと同じ方法で関数セレクターを使用するインターフェイスを構築したため、ステートフルプリコンパイルのインターフェイスに一致するSolidityインターフェイスコントラクトを記述し、既存のツールを利用してステートフルプリコンパイルをすぐに操作できます。

これにより、独自の方法でアプリケーションレベルの開発者に権限と責任が与えられます。

繰り返しになりますが、これは危険な機能であり、慎重に使用する必要があります。開発者が非決定論的なステートフルプリコンパイルを構築する場合、変更されたEVMの実行は当然非決定論的です。これにより、ブロックが有効かどうかについて、さまざまなバリデーターが意見を異にする可能性があります。これが発生した場合、バリデーターがネットワークの状態について合意できないときに、チェーンが停止する可能性があります。

ステートフルプリコンパイルを使用してContractDeployer許可リストを実装しましょう

ステートフルプリコンパイルを使用する方法を説明するために、ブロックチェーンベースのゲームで最も要求されている新機能の1つである特定のユースケースを見てみましょう。スマートコントラクトを展開できるユーザーを制限することです。

多くのブロックチェーンベースのゲームは、独自の通貨、バリデーター、および料金パラメーターを使用して独自のネットワークを立ち上げたいと考えています。また、ネットワークの使用をゲームのみに制限したい場合もあります。これを実現するために、許可リストのプリコンパイルを実装して、契約の展開を制限するための構成可能でカスタマイズされたEVMを提供します。

許可リストは、契約の展開が許可されているアドレスを明示的にマークします。管理者または有効としてマークされたアドレスのみがスマートコントラクトの展開を許可されます。最後に、管理者のみが許可リストを変更できます。

まず、実装するSolidityインターフェースを作成します。管理者が任意のアドレスの役割を更新する機能と、任意のアドレスの役割を取得する読み取り機能を追加します。

プリコンパイル自体が機能を提供するため、実際にコントラクトを実装する必要はありませんが、Solidityのインターフェイスを参照として定義し、後でRemixを介してプリコンパイルを操作できるようにします。

次に、管理者が許可リストを更新する機能を実装するために必要なものを見てみましょう。

この関数は、許可リストを変更するための実行関数を作成します。この実行関数:

  • 操作を実行するのに十分なガスがあることを確認します

  • 関数の呼び出し元が管理者の役割を持っていることを確認します

  • プリコンパイルアドレスの状態の状態スペースを更新して、目的のアドレスの変更された役割を反映します

このヘルパー関数を使用して、許可リストの役割をAdmin、Deployer、およびNoneのいずれかに設定するための実行関数を生成できます。

最後の実行関数では、許可リストの現在の状態への読み取りアクセスを提供します。

プリコンパイルに必要な実際の機能をすべて実装したので、必要な関数セレクターとガスコストをすべて組み合わせて、実際のプリコンパイルコントラクトを作成できます。

上記の署名は、Solidityインターフェースに含めた署名と一致します。これは、サードパーティのツールでプリコンパイルのアドレスにそのインターフェイスをデプロイすると、トランザクションの入力データがプリコンパイルで期待されるものと正確に一致し、スマートコントラクト呼び出しが対応する実行関数にルーティングされることを意味します。

最後のステップは、EVMにマイナーな、オプションで構成された変更を加えて、コントラクトデプロイヤーの許可リストが有効になっている場合、EVMがトランザクションにCREATEオペコード内でコントラクトをデプロイするための正しい権限があることを確認することを要求することです。

完全なコードを確認したい場合は、subnet-evmのプリコンパイルパッケージを確認してください。

Remixからのプリコンパイルの使用

Solidityインターフェースをhttps://github.com/ava-labs/subnet-evm/blob/master/precompile/allow_list.solからRemixにコピーして貼り付け、「Compileallow_list.sol」をクリックしてコンパイルできます。

インターフェイスをコンパイルしたら、remixの[Deploy]タブに移動し、環境に合わせて[Injected Web3]を選択して、EVMインスタンスとやり取りできるようにし、プリコンパイルのアドレス「0x020000000000000000」をフィールドに貼り付けます。 「住所」の権利。

「アドレスで」をクリックすると、Solidityで完全に実装されたコントラクトをデプロイしたかのように、そのアドレスにインターフェースがデプロイされ、そこからSolidityでプリコンパイルを直接操作できます。

ステートフルプリコンパイルとサブネットEVMの次は何ですか?

EVMコミュニティ全体が、ステートフルなプリコンパイルに新しい価値を見出し、新しい機能をEVMにシームレスに統合する可能性を見出してくれることを願っています。

コミュニティに役立つ可能性のあるステートフルプリコンパイルのアイデアがある場合は、subnet-evmのフォークを作成し、プルリクエストを作成してください。

https://medium.com/avalancheavax/customizing-the-evm-with-stateful-precompiles-f44a34f39efd

この記事が気に入ったらサポートをしてみませんか?