[日本語訳] Ethereum / イーサリアム:トランザクションのライフサイクル

この記事は、「Life Cycle of an Ethereum Transaction」を作者の許可をいただいて翻訳したものです。Ethereumのトランザクションがどのように処理されながらネットワークに伝わっていくかを学ぶことができます。

tomonari takahashi
KYUZAN
17 min readDec 14, 2018

--

Photo by Tiraya Adam on Unsplash

トランザクションは、Ethereumブロックチェーンに限らずあらゆるブロックチェーンを考える上で重要な概念です。 Ethereumブロックチェーンとのやり取りには、トランザクションを実行しブロックチェーンの状態を更新します。 Ethereumでトランザクションを実行したときに、実際に何が起こっているのか考えてみたことはありますか?今回はサンプルのコードを用いてトランザクションについて、詳しく見ていきます。この記事では、以下の内容について解説します。

  1. トランザクションがあなたのブラウザ/コンソールから生成されEthereumネットワークを経て再びあなたのブラウザ/コンソールに戻るトランザクションの一連の流れを理解する
  2. 独自のノードを実行する代わりにMetaMaskやMyetherwalletなどのプラグインを使用した時、トランザクションがどのように処理されるのかを理解する
  3. MetaMaskなどのプラグインを信頼しない場合、どうすればよいか

この投稿は、あなたがEthereumの基本的な知識を持っていること、アカウント、GAS、契約などの知識があることを前提としています。なので、これらの概念については詳しく説明しません。あなたがEthereum開発をしたことがない場合は、この記事が役立つかもしれません。この記事では簡単なdappを構築する方法も学べます。またこの記事は、自分でトランザクションを実行したことがある人は理解がより深まります。トランザクションというのは、“あなたがある人やあるコントラクトにEtherを送る”といったものです。トランザクションの他の例は、dappとやりとりする時です。たとえば、ここに行っていくつかのトークンを購入すると、それがトランザクションになります。この記事で用いるコードであなたが候補者に投票すると、それもトランザクションになります。

1. Etereumトランザクションの全貌

では、ここから下に示したコードを実行したと仮定して、この関数呼び出し/トランザクションがどのように処理され、ブロックチェーンに記録されるのか、全体の流れをたどってみましょう。コードの全体はここで確認することができます。このコントラクトは選挙コントラクトです。立候補者を最初に初期化し、誰でもその立候補者に投票できるようになっています。投票の履歴はブロックチェーンに記録されます。

あなたのコンピュータ上でEthereumクライアント(GethまたはParity)をローカルに実行しており、TestnetまたはMainnetに接続しているEthereumクライアントがあり、コントラクトアドレスとABIにアクセスしてトランザクションを実行できる状態になっていると仮定して解説を続けます。

dappを作ったことがある人にとっては、上記のコードは馴染みのあるものだと思います。ブロックチェーン上にデプロイされているVotingというコントラクトがあります。このコントラクトをインスタンス化して、voteForCandidateというメソッドを実行し、このコントラクトに候補名、gasLimit、およびこのトランザクションを実行するアカウント情報を渡します。関数名に書いてある通り、この関数は立候補者に投票するために使用され、投票履歴はブロックチェーンに記録されます。この呼び出しを分解し、このJavaScript関数を実行するとなにが起こっていくのか順に説明します。

1. Raw Transaction Objectを作る

voteForCandidate関数呼び出しは、以下のコードに書いてあるように、まずRaw Transaction(rawTxn)を生成します。 Web3ライブラリは、Raw Transaction Objectを作るために使われます。

では、Raw Transaction Objectが持つフィールドとそれに紐づくデータを見ていきましょう、

nonce:各Ethereumアカウントには、アカウントが実行したトランザクションの総数を記録するためのnonceというフィールドがあります。nonceは新しいトランザクションごとにインクリメントされ、nonceによりネットワークはトランザクションの実行順序を知ることができます。 nonceはリプレイプロテクションにも使用されます。

gasPrice:トランザクションのために支払うGASの単位あたりの価格です。Mainnet上でトランザクションを実行する場合は、ETH Gas Stationが提供する便利なこのサイトで、適切なgasPriceを設定するのがおすすめです。gasPriceの単位はGWei、0.1〜100Gweiの範囲で設定します。gasPriceについてよく理解していない人は一旦別のサイトで理解を深めて、この記事を読み進めることをおすすめします。この記事の後半を理解する上でgasPriceはとても重要な概念になります。

gasLimit:トランザクションに支払う最大GAS。gasLimitは、トランザクションを実行する際に(無限ループのような)問題が発生した場合、実行者のEhterがなくなってしまわないことを保証します。トランザクションが実行されると、残りのGASは実行者のwalletに返金されます。

to:この関数呼び出しを行うコントラクトアドレス。今回は投票処理を行うコントラクトアドレス(0x633296baebc20f33ac2e1c1b105d7cd1f6a0718b)です。

value: 送信したいEther。 voteForCandidate関数の実行に関しては、Etherは送信されないので、値は0です。Etherを別の人やコントラクトに送信するトランザクションを実行する場合は、値を設定します。

data:このデータフィールドの計算方法を見てみましょう。

まず、voteForCandidate(bytes32)のABIから関数シグネチャを取り出し、そのハッシュを生成します。

次にそのハッシュの最初の4バイト(=0xcc9ab267)を取ります。

関数の引数 ‘Nick’をとり、bytes32に変換すると52616d6100000000000000000000000000000000000000000000000000000000となります。

2つ(0xcc9ab267, 52616d6100000000000000000000000000000000000000000000000000000000 )を組み合わせたものがdataの値になります。

2. トランザクションに署名する

Ethereumネットワークは、あなたの代わりに他の誰かがこのトランザクションを実行しないように、実際にそのアカウントを所有者がトランザクションを実行しているか検証する必要があります。その検証は、そのアカウントに対応する秘密鍵を使用してトランザクションに署名することで行うことで実現できます。トランザクションへの署名は次のように行われます。

3. ローカルでトランザクションを検証する

署名されたトランザクションは、あなたのローカルのEthereumノードに提出されます。ローカルノードは、署名されたトランザクションが正当なアカウントアドレスによって実際に署名されたことを公開鍵を用いて検証します。

4. トランザクションをネットワークにブロードキャストする

署名されたトランザクションは、あなたのgeth /parity ノードによって他のノードにブロードキャストされます。そのノードはさらに順番に他のノードにトランザクションをブロードキャストします。トランザクションがネットワークにブロードキャストされると、ローカルノードはトランザクションIDを出力します。このIDを使用してあなたはトランザクションのステータスを追跡できます。このトランザクションIDは、署名されたトランザクションオブジェクトのハッシュです。

公開Ethereumネットワーク上でトランザクションを実行する場合、トランザクションのステータスを追跡するメジャーな方法はetherscan.ioを使うことです。上記の図を見てみると、Etherscanノードにマークされているノードを2つ見つけることができます。 Etherscanはいくつかのノードを世界中で走らせていて、そのノードには素敵なフロントエンドwebappが繋がっています。あなたのトランザクションがEtherscanノードによって取得されると、あなたはpending中のトランザクションをEtherscanのwebappを通して確認できます。

もう一つ覚えておくべきことは、すべてのノードがあなたのトランザクションを受け入れるわけではないということです。ノードの中には、gasPriceの最低価格を設定し、それ以上のgasPriceが指定されたトランザクションのみを受け入れる設定をしているものがあります。あなたがgasPriceをその最低価格より低く設定した場合、そのノードはあなたのトランザクションを無視します。

5. マイナーがトランザクションを受け入れる

図からわかるように、Ethereumネットワークには、マイナーノードと非マイナーノードが混在しています。あなたが知っているように、マイナーはあなたのトランザクションをブロックに含める仕事をする人です。マイナーは、評価前のトランザクションプールを所持しています。

上の図のように、マイナーはプール内のすべてのトランザクションをgasPriceでソートして保管します。gasPriceが高いほど、トランザクションは次のブロックに取り込まれる可能性が高くなります。これは、(より高い報酬を得るための)マイナーノードの一般的な構成です。しかし、マイナーは自分のノードを設定して、好きなようにトランザクションを並べ替えることができます(低いgasPriceだけをマイニングしてネットワークを手助けするマイナーもいます)。

上記の図では、voteForCandidateのトランザクションがマイナーのトランザクションプールの底にあることを確認できます。高額なgasPriceトランザクションが優先的にマイニングされ、それらがブロックに含まれると、マイナーはvoteForCandidateのトランザクションのマイニングを行います。

ここで注意すべきことは、マイナーのプールには所持できるトランザクションの数に限りがあるということです。人気のあるICOセールや、人気のあるdapp(Crypto Kittiesなど)が始まったとしましょう。ユーザーは、自分のトランザクションが他のトランザクションより早くマイナーに処理してもらうために高額のgasPriceでトランザクションを提出します。高額gasPriceトランザクションがプールをいっぱいにすると、あなたの低価格gasPriceトランザクションは破棄されます。立候補者’Nick’はしばらくの間投票を受けることはできません。そのような場合には、トランザクションを再ブロードキャストする必要があるかもしれません。

あなたのトランザクションをプールの上に押し上げるトリックは、同じnonce値を用いてより高いgasPriceでトランザクションを再提出することです。そうすれば、新しいトランザクションがマイナーに受け取られたときに、新しいより高価格gasPriceのトランザクションが古い低価格gasPriceトランザクションを上書きします。nonce値が異なる場合は、別のトランザクションと見なされます(’Nick’に2票を投票することになります)。このことについては、Jim McDonaldの素晴らしい記事があります。

6. マイナーノードは有効なブロックを掘り当ててネットワークにブロードキャストする

マイナーは他のトランザクションと一緒にあなたのトランザクションをブロックに取り込みます。 Ethereumは1ブロックに含めることができるGAS値の上限を設定しています。マイナーはトランザクションのGAS合計値がブロックの上限値を超えない限り複数のトランザクションをブロックに含めることができます。現在のGAS上限値はethstats.netで確認できます。

マイナーがブロックに含めるトランザクションを選択すると、トランザクションは検証され、pending中のブロックに含まれ、Proof of Workが開始されます。 マイナーノードの1つは、最終的に(PoWパズルを解くことによって)有効なブロックを掘り出し、ブロックをブロックチェーンに追加します。Raw Transaction Objectがローカルノードによってブロードキャストされたのと同じように、マイナーノードはこの有効なブロックを他のノードにブロードキャストします。

7. ローカルノードが新しいブロックを受け取り、同期する

最終的にローカルノードは新しいブロックを受け取り、ローカルブロックチェーンを同期します。

truffleを使用してトランザクションを実行する場合、truffleは常にブロックチェーンをポーリングしてブロックチェーンの状態を確認します。トランザクションが確認されると、then()ブロック内のコードを実行し、コンソールログを出力します(この記事で用いたコードの場合)。

2. ローカルノードの代わりにMetaMaskを使う

MetaMaskブラウザプラグインをインストールすると、ブラウザでアカウント管理ができます。秘密鍵はブラウザにのみ保存されるため、アカウントと秘密鍵にアクセスできるのはあなただけです。ブラウザでトランザクションを実行すると、MetaMaskプラグインは関数呼び出しをRaw Transaction Objectに変換し、秘密鍵を使用してトランザクションに署名します。 MetaMaskはトランザクションをブロードキャストするために使用する独自のノードを管理しています。(MetamaskはInfuraがホストするノードを使用します)。MetaMaskを使う方法では、あなたが独自のローカルEthereumノードを実行・管理する必要はありません。

3. オフライン署名

MetaMaskなどのプラグインを使用したくない場合や、ローカルノードが安全ではない可能性がある場合はどうしましょう?その問題を解決するための方法があります。

気づいた人がいるかもしれませんが、最初の2つのステップ(Raw Transaction Objectの生成と署名)は、オンラインで行う必要はありません。トランザクションが改ざんされていないことを絶対に確認したい場合は、オフラインのコンピュータを使用して、関数呼び出しをRaw Transaction Dataに変換し、秘密鍵を使用してトランザクションに署名します。署名されたトランザクション文字列をコピーし、オンラインのコンピュータを使用してネットワークにブロードキャストすることができます。署名されたトランザクションをネットワークにブロードキャストするために使用できるEtherscanInfuraのような多くのサービスがあります。

もう1つの安全なソリューションは、LedgerTrezorなどのハードウェアウォレットを使用することです。これらのウォレットには秘密鍵が格納されており、トランザクションに署名するコードがハードウェア自体にプログラムされています。あなたは署名されたトランザクションを公開する時だけインターネットに接続します。

この記事があなたのEthereumトランザクション理解の手助けになれば何よりです。もしこの記事に誤りを見つけた場合コメントを残してください。修正します。

Jim McDonald、この記事の校正に協力してくれてありがとう。

宣伝: dapp開発に興味があったら、私のサイト zastrin.com を見てみてください! (※この記事の原著の方のサイトです。)

この記事は、「Life Cycle of an Ethereum Transaction」(著者: Mahesh Murthy)を作者の許可をいただいて翻訳したものです。

Thank you Mahesh Murthy!!

--

--

tomonari takahashi
KYUZAN

Engineer at Kyuzan. Inc | Web Developer in Tokyo