メインコンテンツへスキップ
Change page

トランザクション

最終編集者: @HiroyukiNaito(opens in a new tab), 2024年1月9日

トランザクションは、アカウントから暗号的に署名された命令のことを意味します。 アカウントはトランザクションを開始し、イーサリアムネットワークの状態を更新します。 最も単純なトランザクションは、あるアカウントから別のアカウントに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 - トランザクションに対して支払う用意があるガス単位あたりの最大手数料(baseFeePerGasmaxPriorityFeePerGasを含む)

ガスとは、バリデータのトランザクションに必要な計算を意味します。 ユーザーはこの計算に手数料を支払う必要があります。 gasLimitmaxPriorityFeePerGas はバリデータに支払われるトランザクションフィーの上限を決定します。 ガスの詳細

トランザクションオブジェクトは次のようになります。

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}
すべて表示
コピー

署名ハッシュでトランザクションが送信者から送信され、ネットワークに送信されたことを暗号的に証明することができます。

データ(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)関数であることがわかります。

残りのデータは以下の通りです。

10000000000000000000000004f6742badb049791cd9a37ea913f2bac38d01279
2000000000000000000000000000000000000000000000000000000003b0559f4

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 gwei
2--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)からの図解

トランザクションで使用されなかったガス代は、ユーザーアカウントに返金されます。

トランザクションのライフサイクル

トランザクションが送信されると、次のことが実行されます。

  1. トランザクションハッシュが暗号化によって生成される: 0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017
  2. 次に、トランザクションはネットワークにブロードキャストされ、保留している他のすべてのネットワークトランザクションで構成されるトランザクションプールに追加される。
  3. バリデータはトランザクションを検証し、それを「成功」とみなすには、トランザクションをブロックに追加する必要がある。
  4. 時間と経過とともに、トランザクションを含むブロックは「正当 (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 - トランザクション型式で定義された任意のバイト配列

参考文献

役に立ったコミュニティリソースがあれば、 ぜひこのページに追加してください。

この記事は役に立ちましたか?