ALISのICOについての技術的FAQ

こんにちは、ALIS CTOの石井です。

みなさまに応援していただき、ALISのICOは目標額の3.5億円を超える約4億円を調達できました。ありがとうございます。ICOにはEthereumを利用していますが、Ethereum上に構築したICO用スマートコントラクトについて多くの方から技術的な質問をいただいております。
せっかくなので、こちらにまとめます。

前提

Contractのコードを書く時に参考にしているもの(サイトや書籍など)を教えていただきたいです

GitHub上の良質なコードが一番参考になります

公式サイトは期待しない方がいい

  • メンテ不充分。
  • コピペしても動かない場合が多々。

解説記事や本も参考程度にとどめる

  • 進歩がとてつもなく早いのですぐ古くなる。

暗号通貨の開発はバグがあると非常に危険であることが前提ですが、これならいける!という確証をどんな感じに持ちながら開発を進めているのか

「非常に危険」は、たしかにその通りです

  • 一例: 2017年7月、Parityというウォレットで 34億円 の被害が出たバグがこちらです。
  • SolidityはJSライクと謳っていますが、その印象から受けるほど気軽なものではないです。
  • ICOも含め金銭が絡む場合は、当然ですが ミッションクリティカル と認識すべき。
  • 言うまでもなくセキュリティが非常に重要。
  • WEBの開発というよりは組み込み系等の方が感覚的に近い。
  • スマートコントラクトの実装はセキュリティを含むコードの品質が何よりも重要。

ひとまずsmart-contract-best-practicesをすべて読み込む。
極めて優良なドキュメントです。スマートコントラクトを書くエンジニアは必読。日本語に翻訳中

以下の内容は上記のドキュメントに書かれていることでもありますが、具体例としていくつか記載します。

コードをシンプルに保つ

  • 本当に重要じゃないものは実装しない。コード書かないのが一番という場面は多々ある。

とにかくテストをみっちり書く

  • ALISのテストの内容はCircleCIで見られます。
  • 最新ビルドのtest のセクションを展開していただければ。
  • テストコードはGitHubです。
  • テスト書くのにBabel使ったら solidity-coverage でカバレッジ出す時に挫折しました..。できた人いたらご教示ください。

徹底的にライブラリを使う

  • よくできたライブラリを使い、そこでできることは自前で実装しない。
  • ライブラリより品質の高いコード&テストを書ける余裕&自信あるなら別ですが。

外部の人間にみっちりレビューしてもらう

  • ALISの場合は10年超の経験を持つエンジニア5人に丸一日時間を作ってもらいレビューしてもらいました。
  • スマートコントラクトの経験のあるエンジニアは現状、まあ少ない。レビューも大変なのでお気をつけを。
  • 外部の組織にレビューを依頼するのも手。しかしその場合は海外も視野に入れた方が良いかも。
  • バグバウンティープログラム等も実施できれば吉。

その他、いろいろ上記のベストプラクティスに記載があることを実施しました。それでも自分のバグ一つで億が飛ぶので、痺れますけどね。

テストコードが必須で重要だと思いますが、どのようなテストを書いておくべきですか?

できればカバレッジ100%目指したい

  • カバレッジが高いからって安心できるわけではないですが、それでも高いに越したことはない。
  • 閾値テストも全部書くつもりで。
  • ALISでどんなテストを書いたかはCircleCIをご確認ください。

開発環境全般について。Contractのデプロイ先は開発環境(testrpcと)ステージングと本番、みたいな分けはありますか?

コードを書きテストを走らせるのはすべて testrpc

testrpcはテストを走らせるただけのものです。

挙動確認は基本的に gethで構築したプライベートネット

  • 速度という点でテストネットよりも圧倒的に有利。
  • genesis.jsonで最初に大量のETHを格納しておくと楽ができる。
  • difficultyを下げておくとより早い。
  • 立ち上げるたびにチェーンを削除して作り直すと速度が落ちずに済む。

みっちりプライベートネットでテストしたらメインネットで最終テスト

  • gasが高いので気軽にはできない。
  • ALISのICO用コントラクトはデプロイ時に 約2万円 かかりました。

私が実装していたタイミングでは公式のテストネット(ropsten)が攻撃を受けてて使い物にならなかった

  • 今は安定している(はず)。
  • rinkeby は試せておらず。

AlisのContractにおいてはTruffleとZeppelnを採用していますが、どのような経緯でこれを選びましたか?

  • GitHub上で活発に開発が継続している良質なプロジェクトである。
  • テストが適切に書かれている。
  • シンプルでセキュアな実装である。
  • 抽象的な表現でもうしわけないですが、触った感触としていい感じ。

リリース後に修正をカジュアルにしても良いものなのか

  • 答えはNoです。基本的には修正できません。
  • 修正可能とすることもできます。必要があればそうすべきですが、必要が無ければむしろそうすべきではないです。改ざん耐性等のブロックチェーンのメリットを損ねますし、セキュリティ観点でも複雑性は敵です。

ICO以降、Contractのアップデートはどのような内容で行っていきますか?

  • ICO用のコントラクトはトークンとマルチシグウォレット以外は使い捨てです。アップデートしません。トークンとマルチシグウォレットもアップデートできる仕様ではありません。
  • 基本、トークンにはトークンが持つべき機能以外を持たせず周囲のコントラクトがトークンを利用して各種役割を担う予定です。

極力Gas Feeを減らす工夫はどのように行いますか?

  • ICOでは考慮していません。する必要が無いからです。
  • メディアでは非常に重要なので、入念に検討する必要があります。知見が得られたら可能な限りアウトプット致します。

マルチシグWalletの導入目的と導入方法を教えていただきたいです

EOAではプロジェクトとしてセキュアではないから導入しました。

  • 一人がミスしたらすべてが終わる。
  • 例: Mt.Gox
  • ALISでは100億円規模の運用実績(例: Golem)を持つGnosisのマルチシグウォレットを利用しています。
  • 彼らがいかにコードの品質を考えているかはこちらが参考になります
  • 利用するコードに関してはすべてコードを読んで確認しています。
  • セキュリティの都合で詳細は公開できませんが、運用には細心の注意を払い、個人に依存しない体制を採用しています。
  • 外部機関と連携したさらにセキュアな運用を行います。具体的には、身の危険を回避するために、万一アカウントを持つ者が脅迫されたとしてもETHやトークンは引き出せない、という運用を行います。
  • UIは不要なのでコアのSolidityファイルだけ抜き出して使用しています。

private netとmain netの使い分けについて教えていただきたいです。private netは開発用?

切り分けは以下のとおりです

  • Main net: プロダクション環境、最終テストの環境
  • Private net: 統合テスト環境&開発環境
  • testrpc: テストコード流す環境
  • Test net: 今回は不安定だったのであまり使用しませんでした。安定していれば使い倒すべき。

コントラクトにはGASの処理についてはどのようなことが書かれていますか?

  • 今回はコントラクト自体にはgasの処理は書いておりません。

solgraphは、コントラクトのソースコードを解釈してビジュアルにするものだと思いますが、これを見て誰が何を判断しますか?

開発者やQAを担う人が以下を確認しやすくなります。

危ないfunctionがどれか

  • 要注意なfunctionは画像では赤枠で囲まれます。

スコープが適切か

Ethereumのフルノード同期させているのはなぜでしょうか

運用上、もっともセキュアであろうと判断したからです。開発者はフルノードを使用しています。
非エンジニアはgethのlight clientモードを使用しています。

Zepplin内にMultisigWalletクラスがあると思うのですが、ALISのContractでは独自に実装されている(?)ようで、何か理由があるのでしょうか

最新のzeppelin-solidityのリポジトリを見ていただければと思うのですが、もうマルチシグウォレットはありません。
https://github.com/OpenZeppelin/zeppelin-solidity

公式に ConsensSys(Gnosis)の方が良いよ と言って削除されました。
ALISではそちらを使用しています。
https://github.com/gnosis/MultiSigWallet

BurnableTokenはどういう目的で使われているのでしょうか。PoBの必要性があるのでしょうか

※この質問はburnが決定する前にいただきました。

burnの機能は必須と考えています

これは技術的な話というよりも、いかに価値を凝縮させるか。あるいは希釈させるかの話です。
たとえば上限5億トークン、という立て付けでICOを実施します。ICO完了後に、運営が新たに自分たちのために10億トークン発行しました! と発表したらどうなるでしょう。非難轟々なはずです。
なぜならトークンの価値が希釈するからです。
たとえば5億トークンのときに100円の価値が付いてたとすれば、論理的には約33.3円まで価値が希釈されることとなります。(現実的にはいろいろな思惑があってぴったり3分の1とはなりませんが)

話を戻してトークンのburnですが、こちらは逆です。
5億トークンのICO完了後、運営が私たちは自分たちの1億トークンをburnしますと発表した場合を考えてみましょう。これはトークン保有者にとっては得するニュースです。
なぜならトークンの価値が凝縮するからです。
5億トークンの時に100円だった場合、論理的には125円まで価値が凝縮されることとなります。つまり持っているだけで得をするのです。

そしてburnの方法ですが、これはトークン自体にburnの機能を持たせるのがベストと判断しました。無効なアドレスに送信することで実質的にburnする、というアプローチも伝統的に用いられていますが、ERC20準拠トークンではトークンコントラクトのtotalSupplyで常に適切な量を確認できるべきなので、その場合はより適切なburn処理が必要となります。そのためALISトークンにはburnの処理を実装しています。

ブロックとUNIXTIMESTAMP両方使っているのはなぜですか

Ethereumの過渡期だからです。

Ethereumはそのロードマップで、合意形成アルゴリズムを現状のPoWからPoSへの移行を予定していますが、その過程のハードフォークで分裂が起こらないようにdifficulty bombという施策を施しています。これはマイニングのためのdifficultyが漸増するという内容です。

ALISのプロジェクトを開始した当時(2017/05)は、Ethereumのブロックで時間を計るというアプローチが有効でした。しかしdifficulty bombの影響で、時間の見積もりが困難となりました。またEthereumにはメトロポリス・ハードフォークも控えておりブロックによる見積もりは事実上不可能でした。
そのためUNIXTIMESTAMPも併用しています。

なぜ初めからUNIXTIMESTAMPを使用しないのかというと、Ethereumのマイナーに僅かながら不正の余地を与えるからです。
詳細はこちらを御覧ください。zeppelin-solidityでちょうどv1.2.0からv1.3.0にかけて議論が行われ、ブロックタイムからUNIXTIMESTAMPへの切り替えが行われた際のものです。参考になるかと。

今からコントラクトを実装する場合、よほど要件がシビアでないかぎりUNIXTIMESTAMPを使用すべきです。

ICOの時にどのように信頼を得るようにしたか。開発コードを公開するケースがありますが公開していたか?

コードは最初からGitHub上ですべて公開していました。今後も可能な限りオープンソースでの開発に努める予定です。

ICO最中に攻撃やハックを受けたりしたかと思いますが、どのような種類の攻撃を受けてどのようにさばいたか知りたいです。

この観点では、わかりやすくするためスマートコントラクトWEBサイトに分けて回答いたします。

スマートコントラクト

ALISのICOでは、スマートコントラクトへの目立った攻撃はありませんでした。多少の悪意あるトランザクションは存在しますが、コントラクトの中身を考慮していない総当り的・機械的な攻撃であり脅威を感じるほどの内容ではありません。

しかし、スマートコントラクトが攻撃されるのは稀であると考えるのは早計です。一度攻撃が成功したら数億円というお金が手に入るので、むしろ徹底的に付け入るスキが無いか世界中のクラッカーから見られていると考えるべきでしょう。

事実、The DAOやParityなど、過去に何度もスマートコントラクトの脆弱性による数十億円規模の損害が発生しています。これらの攻撃は、どれもコントラクトの中身を入念に検証し実行されています。

ALISではそのような現状を鑑みて、徹底的に品質とセキュリティにこだわりスマートコントラクトを実装しました。そのため、一ヶ月以上に渡り数億円という金額がICO用コントラクト上に存在していましたが、クラッカーにそれを奪われることはありませんでした。

WEBサイト

イスラエルのスタートアップであるCoinDashは、ICO開始直後にWEBサイトをクラックされ8億円弱をクラッカーに奪取されました

ALISではこのような事態を想定し、WEBサイトはAWS S3上に完全に静的なページとして構築しています。これによりクラックのリスクは圧倒的に低減します。詳しくは以前のエントリーを参照してください。

ファイナライズ実施時にAlisTokenのfinishMinting()を行わない理由はなんでしょうか?

アプリケーションの仕様として将来的にmintする予定のためです。
ホワイトペーパーに記載のとおり、ALISのトークン設計では、年間のインフレ率を50%として設定しています(すべてがALISプラットフォーム上に保持されるわけではないため、実際には20%程度と見込んではいます)。これは新たにトークンをmintすることを意味します。mintされたトークンはコンテンツ作成者、評価者に分配されます。

余談になりますが、もしここでfinishMinting()を行った場合、ALISトークンは二度とmintできません。ここがスマートコントラクト、というよりブロックチェーンを扱う上で怖いところなのですが、設計をミスすると取り返しがつきません。この実装を入れていなければ、ホワイトペーパーで想定しているALISのメディアは極めて実現困難になっていたと言えます。これはALISのICOで使用したzeppelin-solidityの仕様なのですが、ミスを起こしやすい仕様ではありました。そのため、zeppelin-solidityの後続のバージョンではfinalizeの処理からfinishMinting()が除却されました

ちなみに将来的にトークンをmintする必要が無い場合、むしろ積極的にmintできないよう実装すべきです。それは、このトークンはもう増えることが無い=mintによる価値の希釈は起こらないという信頼のブロックチェーン上での担保を意味するからです。

備考

  • ICOについて質問をいただいた場合はこちらに随時追記してゆきます。
  • 突っ込み歓迎です。なにかあればお知らせください。
  • 石井のTwitter: https://twitter.com/sot528
One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.