【Solidity基礎】fallback関数について




fallbackとは

fallbackとはシステム稼働中に予期せぬエラーが発生しても機能制限や応答速度を低下させてシステムの稼働を継続することを言います。要はシステムを完璧に止めてしまうより少しでも動いていた方がいいよねという考え方です。

Solidityにはこの仕組みが言語仕様として組み込まれていて、少し複雑な挙動をするので説明したいと思います。

Solidityのfallback関数

Solidityのfallback関数は下記の特徴があります。

  • 無名関数となる
  • 引数を取ることができない
  • 値を返すことができない

一番シンプルなfallback関数はこのようになります。

function () {}

もし、コントラクトでEtherを受け取る処理を実装したい場合はfallback関数にpayable修飾子をつけなければいけません。

function () payable {}

fallback関数でできないこと

fallback関数では2300 gas以上の処理ができないようになっています。下記は2300 gas以上を消費する処理なので実行することができません。

  • storageへの書き込み
  • コントラクトの作成
  • 大量のgasを消費する外部関数の呼び出し
  • Etherの送金

TheDAO事件の原因となったソースコード

これはwithdrawBalance()を何度も呼ぶことができるバグでReentrancyと呼ばれます。msg.sender.call.value(amountToWithdraw)で送金処理を行なっているのですが、msg.senderがコントラクトアドレスの場合、fallback関数を使ってもう1度withdrawBalance()を呼び出し、また送金しての繰り返しをすることができます。

このバグをつかれてThe DAOは65億円相当のトークンを引き出されてしまいました。

// INSECURE
mapping (address => uint) private userBalances;

function withdrawBalance() public {
    uint amountToWithdraw = userBalances[msg.sender];
    require(msg.sender.call.value(amountToWithdraw)()); // At this point, the caller's code is executed, and can call withdrawBalance again
    userBalances[msg.sender] = 0;
}

このバグを修正したコードが下記になります。msg.senderの残高を先に0にしてから送金処理をすることで何度も再実行されても大丈夫なようにしています。

mapping (address => uint) private userBalances;

function withdrawBalance() public {
    uint amountToWithdraw = userBalances[msg.sender];
    userBalances[msg.sender] = 0;
    require(msg.sender.call.value(amountToWithdraw)()); // The user's balance is already 0, so future invocations won't withdraw anything
}

おすすめ書籍

Ethereumを使ったDApps開発を学びたいなら今だとこの1冊が1番良いです!開発環境の構築から使うべきツール、フレームワーク、実装方法・注意点まで網羅的に解説されている書籍なのでおすすめです。出版も2018年1月ということでかなり新しい本で、DMM Bitcoinを作っているネクストカレンシー所属の方が書いているので信頼できます。

ビットコインとブロックチェーンの詳細をしっかりと学びたい方にはこちらの書籍が非常におすすめです。ウォレットの仕組み、楕円曲線暗号、P2Pプロトコル、公開鍵暗号などビットコインを支える技術について詳細に解説されています。また、サンプルコードを通して実際に手を動かして学べるので非常に濃い内容となっています。

The following two tabs change content below.

髙妻智一

2013年CyberAgent新卒入社 スマホゲームを作る子会社に所属し、サーバーサイドのエンジニアを担当。2年目の終わりから新規子会社の立ち上げに参加し、サーバーサイドのエンジニアリーダーとしてサービースのリリースから運用までを担当。 2018年仮想通貨のスマホウォレットを提供するGinco Incにブロックチェーンエンジニアとして入社。






よく読まれている関連記事はこちら




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です