トランザクション
最終編集者: @HiroyukiNaito(opens in a new tab), 2024年7月16日
トランザクションは、アカウントから暗号的に署名された命令のことを意味します。 アカウントはトランザクションを開始し、イーサリアムネットワークの状態を更新します。 最も単純なトランザクションは、あるアカウントから別のアカウントにETHを転送することです。
前提知識
このページの理解を深めるために、事前にアカウントとイーサリアム入門を読むことをお勧めします。
トランザクションとは
イーサリアムトランザクションとは、コントラクトではなく人間によって管理されたアカウントである外部所有アカウント(EOA)によって開始されたアクションを指します。 例えば、BobがAliceに1 ETHを送信するとしましょう。Bobのアカウントから1 ETH引き落とされ、Aliceのアカウントに振り込みされなければなりません。 この状態の変更はトランザクション内で実行されます。
イーサリアムEVM(opens in a new tab)からの図解
EVMの状態を変更するトランザクションは、ネットワーク全体にブロードキャストされる必要があります。 すべてのノードは、EVMで実行されるトランザクションのリクエストをブロードキャストできます。 この後、バリデータがトランザクションを実行し、結果の状態の変更をネットワークに伝播します。
トランザクションにはフィー(手数料)が必要で、検証されたブロックに含まれる必要があります。 この概要を簡単にするために、ガス代と検証については別のページで取り上げます。
送信されたトランザクションには次の情報が含まれます。
from
– 送信者のアドレス。送信者はトランザクションに署名します。 コントラクトアカウントは、トランザクションを送信できません。そのため、外部所有のアカウントとなります。to
– 受信アドレス(外部所有アカウントの場合、トランザクションは値を転送します。 コントラクトアカウントの場合、トランザクションはコントラクトコードを実行します。)signature
– 送信者の識別子。 送信者の秘密鍵がトランザクションに署名し、送信者がこのトランザクションを承認したときに生成されます。nonce
- 連続的に増加するカウンターで、アカウントから送信されるトランザクション番号を示します。value
– 送信者から受信者に送金するETHの量(WEI単位: 1ETHは1e+18weiと等価)。input data
– 任意のデータを含むオプションのフィールド。gasLimit
– トランザクションで消費できるガスユニットの最大量。 EVMが各計算ステップで必要なガス単位を指定します。maxPriorityFeePerGas
- バリデータへのチップとして含める際に消費されるガス代の上限。maxFeePerGas
- トランザクションに対して支払う用意があるガス単位あたりの最大手数料(baseFeePerGas
とmaxPriorityFeePerGas
を含む)
ガスとは、バリデータのトランザクションに必要な計算を意味します。 ユーザーはこの計算に手数料を支払う必要があります。 gasLimit
とmaxPriorityFeePerGas
はバリデータに支払われるトランザクションフィーの上限を決定します。 ガスの詳細
トランザクションオブジェクトは次のようになります。
1{2 from: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",3 to: "0xac03bb73b6a9e108530aff4df5077c2b3d481e5a",4 gasLimit: "21000",5 maxFeePerGas: "300",6 maxPriorityFeePerGas: "10",7 nonce: "0",8 value: "10000000000"9}すべて表示コピー
しかし、トランザクションオブジェクトは送信者の秘密鍵を使って署名する必要があります。 これは、トランザクションが送信者からのみ行われ、不正に送信されなかったことを証明するものです。
Gethのようなイーサリアムクライアントは、この署名プロセスを処理します。
JSON-RPC呼び出しの例:
1{2 "id": 2,3 "jsonrpc": "2.0",4 "method": "account_signTransaction",5 "params": [6 {7 "from": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",8 "gas": "0x55555",9 "maxFeePerGas": "0x1234",10 "maxPriorityFeePerGas": "0x1234",11 "input": "0xabcd",12 "nonce": "0x0",13 "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",14 "value": "0x1234"15 }16 ]17}すべて表示コピー
応答例:
1{2 "jsonrpc": "2.0",3 "id": 2,4 "result": {5 "raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",6 "tx": {7 "nonce": "0x0",8 "maxFeePerGas": "0x1234",9 "maxPriorityFeePerGas": "0x1234",10 "gas": "0x55555",11 "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",12 "value": "0x1234",13 "input": "0xabcd",14 "v": "0x26",15 "r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",16 "s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",17 "hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"18 }19 }20}すべて表示コピー
raw
は、再帰長プレフィックス(RLP)エンコード形式の署名されたトランザクションtx
はJSON形式の署名されたトランザクション
署名ハッシュでトランザクションが送信者から送信され、ネットワークに送信されたことを暗号的に証明することができます。
データ(data)フィールド
大多数のトランザクションは、外部所有アカウント(EOA)からコントラクトにアクセスします。 コントラクトの多くはSolidityで書かれ、 に従ってデータフィールドを解釈します。
最初の4バイトは、関数の名前と引数のハッシュを使用して、どの関数を呼び出すかを指定します。 このデータベース(opens in a new tab)を使用して、セレクターから関数を識別することができます。
残りのコールデータ(calldata)は ABI仕様でエンコードされた(opens in a new tab)引数です。
例えば、このトランザクション(opens in a new tab)を見てみましょう。 詳細をクリックして、コールデータ (calldata)を表示します。
関数セレクタは0xa9059cbb
です。 この署名を持つ既知の関数(opens in a new tab)がいくつかあります。 この場合は、コントラクトのソース コード(opens in a new tab)がイーサリアムにアップロードされているため、transfer(address,uint256)
関数であることがわかります。
残りのデータは以下の通りです。
10000000000000000000000004f6742badb049791cd9a37ea913f2bac38d012792000000000000000000000000000000000000000000000000000000003b0559f4
ABIの仕様により、整数値(20バイトの整数であるアドレスなど)が、ABIに32バイトのワードとして表示され、先頭はゼロで埋めらます。 これから、to
のアドレスが 4f6742badb049791cd9a37ea913f2bac38d01279
(opens in a new tab)であることが解ります。 value
は、0x3b0559f4 = 990206452です。
トランザクションの形式
イーサリアムでは、いくつかの異なる形式のトランザクションがあります。
- 通常のトランザクション: あるアカウントから別のアカウントへのトランザクション。
- コントラクト・デプロイ・トランザクション: 「to」のないトランザクションで、データフィールドがコントラクトコードに使用されているもの。
- コントラクトの実行: デプロイされたスマートコントラクトと相互作用するトランザクション。 この場合、「to」アドレスはスマートコントラクトアドレス。
ガス
前述のように、トランザクションを実行するのにガスが必要です。 単純な送金トランザクションには、21,000ユニットのガスが必要です。
つまり、BobがAliceに1 ETHをbaseFeePerGas
が190 gwei、maxPriorityFeePerGas
が10 gweiで送るためには、Bobは次のフィー(手数料)を支払う必要があります。
1(190 + 10) * 21000 = 4,200,000 gwei2--or--30.0042 ETH
Bobのアカウントから、-1.0042 ETH (Aliceへの送金 1 ETH + ガス代 0.0042 ETH)引き落とされます。
Aliceのアカウントに +1.0 ETH振り込み
ベースフィーは-0.00399 ETHを消費
バリデータは +0.000210 ETH のチップを獲得
イーサリアムEVM(opens in a new tab)からの図解
トランザクションで使用されなかったガス代は、ユーザーアカウントに返金されます。
スマートコントラクトの操作
スマートコントラクトが関わるトランザクションにはガスが必要です。
スマートコントラクトには、コントラクトの状態を変更しないview
(opens in a new tab)やpure
(opens in a new tab)と呼ばれる関数が含まれる場合もあります。 そのため、EOAからこれらの関数を呼び出す際にはガスは不要です。 このシナリオに対応するRPCコールはeth_call
です。
ただし、eth_call
を使用してアクセスする場合とは異なり、view
やpure
関数が内部的に (つまり、コントラクト自身や他のコントラクトから) 呼び出されることも多く、この場合にはガスがかかります。
トランザクションのライフサイクル
トランザクションが送信されると、次のことが実行されます。
- トランザクションハッシュが暗号化によって生成される:
0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017
- 次に、トランザクションはネットワークにブロードキャストされ、保留している他のすべてのネットワークトランザクションで構成されるトランザクションプールに追加される。
- バリデータはトランザクションを検証し、それを「成功」とみなすには、トランザクションをブロックに追加する必要がある。
- 時間と経過とともに、トランザクションを含むブロックは「正当 (justified)」にアップグレードされ、その後「ファイナライズ (finalized) 」になる。 これらのアップグレードにより、トランザクションの成功と非改ざん性がかなり確実になる。 一度ファイナライズされたブロックは、数十億ドルの費用がかかるネットワークレベルの攻撃によってのみでしか変更できない。
ビジュアルデモ
トランザクション、ガス、マイニングに関するAustinの説明動画をご覧ください。
型付トランザクションエンベロープ(Typed Transaction Envelope)
イーサリアムは当初、トランザクション形式は1つのみでした。 各トランザクションには、ノンス (nonce)、ガス代、ガスリミット、toアドレス、値、データ、v、r、sがあります。 これらのフィールドは、以下のようにRLPエンコードされています。
RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])
イーサリアムは、アクセスリストやEIP-1559(opens in a new tab)などの新機能を、レガシーなトランザクション形式に影響を与えずに実装できるよう、複数の種類のトランザクションをサポートするように進化してきました。
EIP-2718(opens in a new tab)では、このトランザクション様式をサポートしています。 これらのトランザクションは、次のように解釈されます。
TransactionType || TransactionPayload
フィールドは次のように定義されます。
TransactionType
は、0~0x7fの数字で、合計128種類のトランザクションタイプが可能TransactionPayload
- トランザクション型式で定義された任意のバイト配列
TransactionType
の値に基づいて、トランザクションは次のように分類されます。
Type 0 (レガシー) トランザクション: イーサリアムのローンチ以来使用されている元のトランザクション形式です。 これらには、EIP-1559(opens in a new tab)の動的ガス料金計算やスマートコントラクトのアクセスリストなどの機能は含まれていません。 レガシートランザクションには、Recursive Length Prefix (RLP)エンコーディングを使用した場合にバイト
0xf8
から始まる、シリアル化された形式で種類を示す特定のプレフィックスがありません。 これらのトランザクションのTransactionType値は0x0
です。Type 1 トランザクション: イーサリアムのベルリンアップグレードの一環としてEIP-2930(opens in a new tab)で導入されたトランザクションです。これらのトランザクションには
accessList
パラメータが含まれています。 このリストは、トランザクションがアクセスする予定のアドレスとストレージキーを指定し、スマートコントラクトを含む複雑なトランザクションにおけるガスコストを削減する可能性があります。 EIP-1559の料金市場の変更はType 1トランザクションには含まれていません。 Type 1トランザクションにはyParity
パラメータも含まれており、これは0x0
または0x1
のどちらかであり、secp256k1署名のy値のパリティを示します。 これらはバイト0x01
で始まることで識別され、そのTransactionType値は0x1
です。Type 2 トランザクション: 一般的にEIP-1559トランザクションと呼ばれるこれらのトランザクションは、イーサリアムのロンドンアップグレードにおけるEIP-1559(opens in a new tab)により導入されました。 これらはイーサリアムネットワークで標準のトランザクションタイプとなっています。 これらのトランザクションは、トランザクションフィーをベースフィーとプライオリティフィーに分けることで予測可能性を向上させる新しい料金市場メカニズムを導入しています。 バイト
0x02
で始まり、maxPriorityFeePerGas
やmaxFeePerGas
などのフィールドを含んでいます。 Type 2トランザクションは、その柔軟性と効率性から現在のデフォルトであり、特にネットワークが混雑している期間中に、ユーザーがトランザクションフィーをより予測可能に管理できる点で好まれています。 これらのトランザクションのTransactionType値は0x2
です。
参考文献
イーサリアムを学ぶために利用したコミュニティリソースはありますか? もしあればページを編集して追加してください!