Amazon Web Services ブログ
AWS Key Management Service(AWS KMS)を使用して Ethereum EIP-1559トランザクションに署名する
このブログは、How to sign Ethereum EIP-1559 transactions using AWS KMS を翻訳したものです。
Ethereum は、さまざまなユースケースで分散型アプリケーションを作成できる人気のパブリックブロックチェーンです。2020年と2021年には、分散型金融 (DeFi) アプリと非代替トークン (NFT) アプリで広く使用されるようになりました。パーミッションレスな性質により、すべてのユーザーがEthereumアカウントを設定するだけで利用できます。これらのEthereumアカウントは、秘密鍵と公開鍵で構成されています。関連するEthereumのパブリックアドレスは、公開鍵から取得されます。
Ethereumなどのパブリックブロックチェーンとユーザーとしてやり取りする際の課題の1つは、秘密鍵を安全に管理することです。特定のEthereumアドレスについて、ユーザーは対応する秘密鍵を使用してトランザクションに署名することで、資金や資産を転送したり、その他の機密操作を開始したりできます。そのため、秘密鍵の内容は、紛失、盗難、悪意のある攻撃者から慎重に保護する必要があります。
完全に分散化されたアプリケーションでは、通常、ユーザーがEthereumのアカウントとトランザクションを自分で管理することを期待しています。
ただし、特定の種類のアプリケーションでは、自動操作によってキーマテリアルに頻繁にアクセスする場合など、キーマテリアルの管理を外部のプロセスまたはサービスに委託することが望ましい場合があります。これは、NFTプラットフォームでのミンティング(NFTを新たに作成・発行)や取引所での入出金操作などの操作に共通する要件です。
この記事は、AWS キー管理サービス (AWS KMS) を使用してEthereumアカウントを安全に管理する方法を詳しく説明した 2 つの記事シリーズに基づいています。シリーズのPart1またはPart2については、Part1 とPart2 を参照してください。
前の2つの投稿では、次のことが説明されていました。
- Part 1 AWS クラウド開発キット (AWS CDK) を使用してEthereum互換の KMS キーを作成する方法
- Part 2 Ethereumトランザクションを作成し、AWS Lambda と KMS キーを使用して署名し、Amazon Managed BlockchainEthereumインスタンスを使用してこれらのトランザクションをEthereumネットワークに送信する方法
この投稿では、Ethereum改善提案 (EIP) 1559 (EIP-1559)、そのユーザーエクスペリエンス (UX) への影響、プロトコルの変更、および AWS KMS での使用方法について説明します。この投稿は、以前の2つの投稿に基づいています。これらの記事は、Ethereumトランザクション、関連する楕円曲線暗号化、および必要な AWS サービスと一般的なインフラストラクチャについて詳しく紹介しているため、最初に読むことを強くお勧めします。
この投稿では以下について説明します。
- EIP-1559 とは何か
- EIP-1559トランザクションはレガシートランザクションとどう違うのか
- AWS KMS と Lambda を使用して有効な EIP-1559 Ethereumトランザクションを作成し、移植可能にする方法
EIP-1559 とは何ですか?
Ethereum改善提案(EIP)1559は、Ethereumブロックチェーンプロトコルの取引手数料市場の仕組みを大幅に改革したものです。簡単に言うと、EIP-1559 の「Motivation」セクションで述べられているように、これはユーザーがGas代付きのトランザクションを送信し、マイナーが最も高い入札額を持つトランザクションを選択し、含まれるトランザクションが指定したガス代を支払うという、歴史的なオークションメカニズムの修正に関するものです。
従来のトランザクションや EIP-155 トランザクションに使用されていたオークションメカニズムは、複数の非効率性の原因につながります。エンドユーザーにとっては、トランザクションにかかるガスコストを過剰に支払うため、UXが低下し、トランザクションがいつ行われるかが不確実になります。
したがって、この提案の主な利点の1つは、エンドユーザーのUXが向上することです。さらに、経済的利益(たとえば、ETHのバーンによるデフレ圧力など)とセキュリティ上の利点(DOS攻撃やスパム攻撃のコストが長期的に高くなるなど)ももたらします。詳細については、「なぜ 1559?」を参照してください。
Ethereumの手数料市場を改善する方法に関する概念研究は、2018年にビタリック・ブテリンによって開始されました。これにより、2019年から2021年にかけて、EthereumコミュニティによってEIP-1559 が開発されました。2021年8月5日、Ethereumのロンドンネットワークアップグレードの一環として、待望の手数料市場向けEIP-1559アップデートが開始されました。Ethereum仮想マシン (EVM) -compatible Ethereumサイドチェーン) であるポリゴンは、2022 年 1 月 18 日にメインネットで EIP-1559 で稼働しました
大まかに言うと、EIP-1559では、取引の手数料市場がさまざまな方法で変化しました。
- ガス価格を 1 回入札するファーストプライスオークションから、基本料金とチップ(プライオリティフィーとも呼ばれる)がかかるハイブリッドシステムに移行します。
- 固定ブロックサイズから、需要に応じて拡張および縮小できる柔軟なブロックサイズに移行します。ただし、ブロックガスの上限は3,000万ガスです。
- 「手数料はマイナーに全額分配される」仕組みから、基本手数料をバーンしてチップのみをマイナーに送金する新しいモデルに移行します。各ブロックの基本手数料を燃やすことで、プロトコルはETH通貨にデフレ圧力を加えます。
以前、EIP-1559のアップグレード前は、取引に必要なガス量に、ユーザーが指定したガス価格パラメータを掛けるだけで取引手数料が計算されていました。手数料は、ブロックへの取引を含むマイナーに全額振り込まれました。
EIP-1559に移りますが、トランザクション・プライシングの中心となる3つの新しいパラメータについて十分に理解しておく必要があります。
- baseFeePerGas(基本料金)
baseFeePerGas
に、トランザクションに必要なガス量を掛けます。この結果には、ETHで支払う必要のある手数料が記載されており、全額支払い済みです。baseFeePerGas
は、プロトコル自体によってネットワークの混雑レベルに基づいてアルゴリズム的に決定され、ユーザーが設定することはできません。基本料金メカニズムは、ネットワークの使用率を 100% に保つように設計されています。つまり、すべてのブロックはフルブロックでなければなりません (均衡ブロックサイズは 1,500 万)。前のブロックの使用状況に応じて基本料金が調整されます。前のブロックの使用量が 100% を超えると、基本料金が増加します。前のブロックの使用率が 100% 未満の場合、基本料金は下がります。 - maxPriorityFeePerGas(優先手数料)
maxPriorityFeePerGas
に、トランザクションに必要なガス量を掛けます。この手数料はマイナーに直接支払われるため、マイナーチップとも呼ばれます。取引を次のブロックに組み込むことは、マイナーにとってインセンティブになると考えられます。通常のネットワーク負荷条件下では、ブロックにはまだスペースがあるため、通常、マイナーがトランザクションをブロックに追加するには、マイナーチップを低くするだけで十分です。 - maxFeePerGas (最大手数料)
maxFeePerGas
にトランザクションに必要なガス量を掛けます。発生する手数料は、取引に使用できる絶対上限額です。そのため、基本料金と優先料金の合計が最大料金よりも少なくなければなりません。複数のウォレットでは、将来のブロックで基本手数料が上がる可能性があるため、ユーザーの最大手数料(たとえば、現在の基本手数料の2倍)が高くなると推定されます。これにより、トランザクションが次のブロックのいずれかに追加される可能性が高くなります。送信者には、最大手数料と基本手数料 (バーンド)、プライオリティ手数料 (マイナーに支払われる) の差額が返金される点にご注意ください。基本料金+優先手数料が設定された最大料金を超える場合、優先手数料は自動的に調整されます。そのため、これはmaxPriorityFee
(最大優先度手数料)と呼ばれます。
新しい EIP-1559 トランザクションを送信するには、最大手数料と優先手数料を指定する必要があります。これはType 2 トランザクションと呼ばれます。Ethereumは、ガス価格パラメータを指定することにより、レガシー取引(Type 0)の送信と下位互換性があります。
EIP-1559を通常のネットワーク混雑レベルで使用すると、ガスコストを過剰に支払うことなく、トランザクションが次のブロックのいずれかに含まれることがはるかに確実になるため、UXが向上します。
次の例を考えてみましょう。あるユーザーがトランザクションを次のブロックの 1 つに含めたいとします。古い仕組みでは、たとえば 100 gwei(1 gwei = 0.000000001 ether)などの市場価格を確認してから、現在の価格を超えるガス価格を選択する必要がありました。ただし、市場価格が上昇しても、その取引が最終的に次のブロックの1つに追加されるという保証はありません。
ユーザーは、トランザクションが次のブロックに追加されることを保証するために1000 gwei を選択することもできますが、そのトランザクションには多額の支払いが発生します。
EIP-1559では、新しい料金メカニズムと柔軟なブロックスペースにより、これは異なります。ユーザーが最大1000 gweiの手数料と妥当な価格の優先手数料(3 gweiなど)を選択した場合、トランザクションが次のブロックのいずれかに含まれることがはるかに確実になります。さらに、現在の基本料金と優先料金はネットワークによって動的に調整されますが、手動で設定された最大料金は調整されないため、過払いが発生することもありません。
ただし、ネットワークが混雑していて(NFTの販売などにより)、ブロックが 200% 使用されている場合、手数料市場は、EIP-1559アップグレードに提供された優先料金履歴に基づくファーストプライスオークションメカニズムに戻ります。
ソリューション概要
次の図は、このソリューションのアーキテクチャを示しています。
AWS CDK リポジトリで提供されるソリューションの範囲は、赤い点線内の領域に限定されます。
前提条件
この記事を読み進めるには、Part1 の「前提条件と AWS CDK によるソリューションのデプロイ」セクションを読むことをお勧めします。
ソースコードをローカルシステムで使用できるようにするには、GitHub からリポジトリをクローンする必要があります。
AWS KMS キーを使用してEthereum EIP-1559 トランザクションに署名する
この記事の手順に従うと、追加の要件なしにEthereumトランザクションを作成して署名できます。Ethereumネットワークにトランザクションを公開するには、十分な資金があるアカウントを保有する必要があります。RinkebyのようなEthereumテストネットのアカウントに資金を供給するには、Rinkeby faucetを使用できます。
AWS KMS ベースのEthereumアドレスを決定するには、まず AWS KMS ベースのアカウントのパブリックEthereumアドレスを返す Lambda 関数を実行する必要があります。
- Lambda コンソールで、新しく作成したaws-kms-lambda-ethereum-KmsClientEIP1559Function Lambda関数を選択します。
Lambda 関数に付けられたランダムなサフィックスは、AWS CDK がどのようにリソースに名前を付けて識別するかに関係しています。
- Functionsタブを選択したら, Test タブを選択します。
- 新しいテストイベントのリクエストとして、次の JSON スニペットを使用してください。
- Test タブを選択します。
テストイベントが正常に実行されると、次のスクリーンショットに示すように、KMS 公開鍵と一致する Ethereum アドレスが計算され、チェックサムが有効なアドレス (eth_checksum_address
)として返されます。
- 特定の AWS KMS ベースのアドレスで Ethereum トランザクションを作成して署名するには、次の JSON スニペットを使用して Lambda 関数を実行します。
上記のスニペットの値は次のとおりです
amount
は送信するetherの量を指定しますdst_address
はEthereumの宛先アドレスを指定しますnonce
は 送信先アドレスでの現在のトランザクション数を指定しますtype
はトランザクションタイプを指定します (ここで 2 は EIP-1559 トランザクションを指します)chainid
は宛先ネットワークを指し、単純なリプレイ攻撃からの保護を表します (EIP-155)max_priority_fee_per_gas
はオプションで、マイナーに直接支払われるガスの量を表します-
max_fee_per_gas
は、トランザクションをブロックに含めるために支払うことができる最大ガス量です。これにはbase_fee_per_gas
とmax_priority_fee_per_gas
が含まれます
- Test タブを選択します。
AWS KMS ベースのアドレスが一度も使用されていないと仮定すると、最初のトランザクションではnonce
値は 0 でなければなりません。アカウントを以前に使用したことがある場合は、nonce
の正しい値を判断するには、AWS KMS ベースのEthereumアドレスを入力として eth_get_TransactionCount
RPC メソッドを使用する必要があります。
おめでとうございます!KMS キーベースのEthereum EIP-1559 トランザクションが初めて作成されました。
マネージドブロックチェーンEthereumノード経由でトランザクションを送信する手順については、「Amazon Managed Blockchain へのEthereumノードのデプロイ 」を参照してください。参照先の投稿から新しく作成された Lambda 関数は、署名バージョン 4 認証を使用して専用のマネージドブロックチェーン Ethereum ノードで認証します。次の Node.JS の例に示すように、16 進数でエンコードされたEthereumトランザクションをEthereumクライアントの Lambda 関数の入力パラメータとして指定する必要があります。
Ethereum Rinkeby テストネットワークに送信すると、web3 ライブラリはトランザクションのトランザクションハッシュ (tx_id
) を返します。この値を使用して、たとえばEthereum Rinkeby ネットワークの Etherscan 経由でトランザクションの状態を追跡できます。
AWS CDK の詳細については、「内部で何が起こっているのか?」セクションを参照してください。Part 1 にあります。
この記事では主に、EIP-1559 トランザクションが、Part 1 および Part 2 で説明したレガシートランザクションとどのように異なるかに焦点を当てます。
プロトコル仕様
プロトコルレベルでは、EIP-1559では新しいトランザクションタイプが導入されており、Part 2 で説明した署名スキーマの変更も必要になります。
EIP-155: Simple replay attack protection によると、Part 2 で説明した従来のトランザクションタイプは、RLP形式でエンコードされた6つの要素(nonce
、gasprice
、startgas
、to
、value
、data
)のハッシュに基づいて機能していました。
このメカニズムは、2021年8月5日に行われたEthereumロンドンアップデート によってEIP-1559標準が導入された後も有効です。
EIP-1559 トランザクションを有効にするために、新しい EIP-2718 トランザクションタイプ (2
) が導入されました。タイプを 2
に設定して新しいスキーマに従うと、Ethereumピアはトランザクションタイプを EIP-1559 として認識します。
Part 2 で説明した従来のトランザクションと新しい EIP-1559 形式とのトランザクション本体の主な違いは、以前の 6 つのフィールドではなく 9 つのフィールドを含める必要があることです。
新しく必要なフィールドは以下のとおりです
chainid
max_prioirty_fee_per_gas
max_fee_per_gas
access_list
トランザクションフォーマットの変更は、トランザクション署名の変更にも反映されます。
有効な EIP-1559 シグニチャは signature_y_parity
、signature_r
、および signature_s
で構成されています。
Part 1 と Part 2 で説明した従来のトランザクションと比較して、回復値 v
は signature_y_parity
に置き換えられています。
EIP-155 によると、signature_y_parity
ビット{0,1}
はカーブポイントの y
値のパリティであり、r
は secp256k1 署名プロセスの X 値です。
また、従来のトランザクションでは chainid
パラメータを指定する必要はありません。chainid
パラメータは、異なるEthereumネットワーク間の単純なリプレイ保護を意味します。
Ethereumネットワークを表すchainid
、例えばchainid
4のRinkebyは取引の一部としてエンコードされているため、同じ取引を他のネットワークで再生することはできません。
これにより、攻撃者は chainid
1 のEthereumメインネットなど、別のEthereumネットワーク上でトランザクションを再生できなくなります。
nonce はEthereumアカウントの現在のトランザクション数を反映する必要があるため、同じネットワーク上で同じトランザクションを再生することは不可能です。トランザクションが宛先ネットワークですでに受け入れられている場合は、以降のトランザクションで nonceを増やす必要があります。そうしないと、ネットワークによって拒否されます。
このchainid
ベースのリプレイ保護は、最初にEIP-155規格で使用され、後にEIP-1559で採用されました。
JSON RPC に関する考慮事項
EIP-1559 トランザクションタイプ max_prioirty_fee_per_gas
および max_fee_per_gas
に新しく導入されたガス価格変数を設定するために必要な値を提供するために、London hardfork に一連の新しい JSON RPC メソッドが導入されました。
eth_feeHistory
は、ガスごとのブロックベース料金の配列など、過去のガス情報のコレクションを返します。この情報を使用して max_fee_per_gas
パラメータを決定できます。たとえば、alchemy は、このパラメータに基づいて、デフォルトの max_fee_per_gas
値を max_priority_fee_per_gas
+ 2 * base_fee
に設定します。
max_priority_fee_per_gas
は、現在のブロックにトランザクションを含めるために支払うことができる優先手数料(チップ)の見積もりである、ガスあたりの料金を返します。
Lambda 関数 (Ethereum EIP-1559 トランザクション生成)
トランザクション処理ロジック全体は eth_client_eip1559
Lambda 関数にあります。Lambda 関数のソースコードは、aws-kms-ethereum-accounts/_lambda/functions/eth_client_eip1559
フォルダーにあります。
lambda_function.py
ファイルを開くと、リクエストの処理方法の概要が表示されます。lambda_handler(event, context)
関数は、操作パラメータが定義された JSON リクエストを想定しています。この操作パラメータに基づいて、ハンドラーは要求されたロジックを実行します。
Part 2 の Ethereum レガシートランザクションの説明 と同様に、この Lambda 関数でもステータスと署名の操作がサポートされています。
次のコードに示すように、要求されたパラメータは、イベントパラメータとして処理される JSON リクエストを介して署名操作に渡される必要があります。
この記事では、Part 1 と Part 2 で説明したレガシー・トランザクションと、型付きトランザクションとも呼ばれる EIP-1559 タイプのトランザクションの違いに焦点を当てます。ASN.1 スキーマのデコードなどの基本事項は、Part 2ですでに説明されています。
前のコードで示したように、get_tx_params()
メソッドは、type
、maxFeePerGas
、maxPriorityFeePerGass
、および chainId
という 4 つの新しいデータフィールドを使用するようになりました。
トランザクションディクショナリのtype
パラメータに基づいて、目的のトランザクションタイプを決定する eth_account
メソッド serializable_unsigned_transaction_from_dict
を使用しました。対象となるトランザクションタイプは EIP-1559 なので、タイプは 2
に設定する必要があります。
必須パラメータが存在する場合、eth_account
ライブラリはすべてのデータが入力された TypedTransaction
オブジェクトを返します。
この typedTransaction
オブジェクトは、EIP-1559 準拠のハッシュ値を返す hash()
関数を提供するようになりました。このトランザクションペイロードハッシュは次のように定義されます。
使用している web3 ライブラリとバージョンによっては、入力パラメーターとして提供されていないパラメーター (この場合は access_list
など) は null に設定されます。
tx_hash
を使用して署名を計算できるようになりました。従来のトランザクションのプロセスと同様に、ハッシュ値は AWS KMS 経由で署名する必要があり、ECDSA 署名コンポーネントを抽出して EIP-2 に準拠していることを確認する必要があります。次のコードを参照してください
欠落している署名パラメーター (signature_y_parity
) を特定するには、計算された署名 (r
, s
) を tx_hash
、eth_checksum_addr
、および chainid
パラメーターとともに get_recovery_id
メソッドに渡す必要があります。
この方法の目的は、欠落しているパラメーター v
(回復パラメーターとも呼ばれる) を回復することです。
元の送信者アドレスが、r
、s
、parity_y
で表されるハッシュ値と提供された署名から計算できるようにするには、回復パラメータが必要です。このメカニズムでは、送信者のパブリックアドレスをトランザクションに添付する必要がないため、トランザクションのサイズを小さくすることができます。これは、Bitcoin などの他のブロックチェーンとは異なります。
前のコードで示したように、最初は v 値の範囲が chainid
に基づいて計算されます。使用される計算スキーマは {0,1} + CHAIN_ID * 2 + 35
です。ここで {0,1}
は、EIP-155 によると、secp256k1 署名プロセスでの r が X 値である曲線点の Y 値のパリティです。
前のコードに示されているように、Account.recoverHash()
メソッドは 2 回実行されます。recoverHash()
メソッドによって返された計算されたEthereumチェックサムアドレスが、指定された eth_checksum_addr
パラメータと一致する場合、正しい値 v
が見つかり、欠落している signature_y_parity
ビットが返されます。
例として、トランザクションをEthereum Rinkebyテストネットに送信する必要があると仮定しましょう。EIP-155 のチェーン ID のリストで指定されているように、Rinkeby のchainid
は 4 です。
前に説明した計算スキーマを適用すると、{0,1} + CHAIN_ID * 2 + 35
では v_lower
の値は 41 になります。v_range
は 41 と 42 の 2 つの値のリストを表します。
ここで、これら 2 つの値を Account.recoverHash()
メソッドに入力する必要があります。提供されたEthereumアドレスと復元されたEthereumアドレスが一致すると、回復パラメータである v が正しいアドレスを指していることがわかります。
y_parity
の値を求めるには、v
から v_lower
(41 = 0 + 3 * 2 + 35
) を引く必要があります。これにより 0 または 1 が返され、y_parity
ビットが表されます。
次のコードでは、Python eth_account
ライブラリが提供する encode_transactions()
メソッドに y_parity
パラメータを渡せるようになりました。
最後に、返された署名付きトランザクションは 16 進文字列に変換する必要があります。
これには、移植性があり、エンコーディングの問題から保護されているという利点があります。さらに、EthereumのトランザクションIDまたはトランザクションハッシュを計算できます。
次のコードに示すように、署名されたトランザクションと関連するハッシュ値が最後のステップとして返されます。
先に述べたように、署名されたトランザクションがネットワークに送信された後に、Etherscan などでトランザクションハッシュ値を使用して、Ethereumトランザクションのステータスを問い合わせることができます。
クリーンアップ
今後課金されないようにするには、次のコマンドを使用して AWS CDK を使用してリソースを削除します。
AWS CDK によってデプロイされたスタックは、AWS CloudFormation コンソールを使用して削除することもできます。
結論
この一連の投稿では、KMS キーと Lambda を使用してEthereumのキーマテリアルを管理する方法について説明しました。
Part 1では、AWS CDK を使用して、AWS ベースのEthereumトランザクションと署名の作成に必要なサービス、つまり AWS KMS と Lambda をセットアップする方法について説明しました。この投稿では、Managed Blockchain Ethereum モードを使用して、署名済みのトランザクションをEthereum Rinkeby のテスト・ネットワークに送信する方法についても説明しました。
Part 2 では、Ethereumの署名プロセスと関連する楕円曲線暗号の内部動作を説明し、Ethereumのレガシートランザクションを作成して Lambda 関数を使用して署名する方法を詳しく説明しました。
この投稿では、EIP-1559を紹介し、新しい料金メカニズムの仕組みと必要なパラメーターの設定方法について詳しく説明しました。型付きトランザクションの概念を紹介し、レガシートランザクション、EIP-155、およびEIP-1559トランザクションタイプを詳細に比較しました。また、Lambda ベースのメカニズムを使用して、有効な AWS KMS ベースの EIP-1559 Ethereumトランザクションを作成しました。
さあ、デプロイして、最初の EIP-1559 トランザクションに署名し、Amazon Managed Blockchain Ethereum ノード経由で送信しましょう。
著者について
David Dornseiferは、Amazon ProServe ブロックチェーンチームのブロックチェーンアーキテクトです。彼は、顧客がエンドツーエンドのブロックチェーンソリューションを設計、展開、拡張するのを支援することに重点を置いています。
Thomas von Bomhar は、AWS プロフェッショナルサービスチームのブロックチェーンアーキテクトです。彼は2017年からブロックチェーン技術に取り組んでおり、さまざまな業界のお客様向けにエンドツーエンドのEthereumブロックチェーンソリューションを設計および構築することに興奮しています。
このブログは、ソリューションアーキテクトの渡邊英士が翻訳しました。