今回は、トランザクション発行を検知して、そのトランザクションより優先して処理を実行してみます。
アカウントごとの役割
アカウントの役割は次の通りです。
- MAIN ACCOUNT (eth.accounts[0])
コントラクト生成者。売り手。自動で攻撃を行う。 - ACCOUNT1 (eth.accounts[1])
買い手。 - ACCOUNT2 (eth.accounts[2])
マイナー。
コントラクトの状態確認
現状のコントラクトの状態を確認します。
[コントラクトの状態]
価格は20 etherであることが確認できます。
自動実行処理を設定(イベント検知)
トランザクションを検知して、priceを自動で20 etherから25 etherに更新する処理を設定します。
コマンドの全体は下記の通りで、gethコンソール上で実行します。
[コマンド]
1 | var filter = web3.eth.filter('pending'); |
上記コマンドの説明は以下の通りです。
- 1行目
マイニングされていないトランザクションのみを抽出するためにフィルタをかけます。 - 2行目
watch関数で監視を開始します。 - 4行目
下記の条件を全て満たしているかどうかを判定します。
①エラーでないこと。
②検知したトランザクションの宛先アドレスとmpt(コントラクト)のアドレスが一致すること。
③fromアドレスが自分でないこと。(自分が発行したトランザクションを対象外とするため) - 6行目
検知したトランザクションのgasPriceを取得して、それよりも1wei大きい値を_gasPriceに格納します。 - 8行目
検知したトランザクションよりも高いgasPriceでupdatePrice処理(価格更新)を呼び出します。
購入トランザクション発行
アカウント1から購入トランザクション(buy関数)を発行します。
[コマンド]
1 | > personal.unlockAccount(eth.accounts[0]) |
14行目以降が、イベントが検知され自動で実行された処理のログになります。
発行されたトランザクションの内容を確認します。
[トランザクションの確認]
アカウント1としてはpriceが20 etherで購入(buy)したはずですが、イベント検知処理により価格更新のトランザクションが優先的に実行されたために25 etherでの購入することになっていることが確認できます。
まとめ
今回のサンプルでは攻撃者がスマートコントラクトのオーナーという前提で行いましたが、逆のパターンもありえます。
自分が作成したスマートコントラクトに対して、TODを突いた攻撃を受ける可能性もあります。
また、作成したスマートコントラクトがTODの影響を受けた場合に問題になるかどうかは、攻撃意思がなくても発生する可能性があります。
スマートコントラクトを実装する際にはTODの影響を受けるかどうかを必ず確認するようにしましょう。