Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実践:Ethereumを利用したアプリケーション開発 ~ 技術選択・アーキテクチャ・地雷~

実践:Ethereumを利用したアプリケーション開発 ~ 技術選択・アーキテクチャ・地雷~

# 話すこと
* 現実的なアーキテクチャ
* Web API, indexDB, indexer(ignitor)
* 言語選択・実装・便利ツールチェイン
* Go?
* さよならweb3.js....
* 様々な便利ツールたち
* 骨の折れる実装
* 署名検証@コントラクト
* メタトランザクション(的なもの)
* etc...
* スマートコントラクト開発特有の地雷と対応策

Masashi Salvador Mitsuzawa

November 29, 2019
Tweet

More Decks by Masashi Salvador Mitsuzawa

Other Decks in Programming

Transcript

  1. 実践:Ethereumを利⽤したアプリケーション開発
    技術選択・アーキテクチャ・地雷
    Masashi Salvador Mitsuzawa, Lead Engineer @ LayerX

    View Slide

  2. ⾃⼰紹介
    Masashi Salvador Mitsuzawa
    (@masashisalvador)
    Lead Engineer @ LayerX
    好きな⾔語:Go, JavaScript,
    Haskell, Kotlin
    軸⾜はバックエンドエンジニア
    趣味:⼭・茶道・計算論的神経科
    学 etc

    View Slide

  3. View Slide

  4. 話すこと
    現実的なアーキテクチャ
    Web API, indexDB, indexer(ignitor)
    ⾔語選択・実装・便利ツールチェイン
    Go?
    さよならweb3.js....
    様々な便利ツールたち
    ⾻の折れる実装
    署名検証@コントラクト
    メタトランザクション(的なもの)
    etc...
    スマートコントラクト開発特有の地雷と対応策

    View Slide

  5. 現実的なアーキテクチャのために考えるべきこと
    エンドユーザがWalletを持っている仮定しない
    サーバサイドで鍵を持つ
    鍵を使った認証機構
    EthereumのコントラクトはReadの機能が貧弱
    基本 key-value的にしか引けない
    ⼀覧取得・検索・ページングetc
    コントラクトをマスターとして別DBにindex
    ⾃動執⾏(?)=イベント駆動
    イベントは吐けるがバッチ的な機能はコントラクトにはない
    イベントを⾒る -> 処理をkick

    View Slide

  6. View Slide

  7. 現実的なアーキテクチャと技術選択
    どこまで疎結合にするか
    コンポーネントが多いと作るものが無駄に増える
    何で作るか・何を使って作るか
    Web API
    Frontend
    indexDB何にしよう?(RDB? KVS?)
    indexer, ignitorどうしよう
    ノードは何が良いだろう?コンセンサスアルゴリズムは?

    View Slide

  8. View Slide

  9. さしあたってWeb APIはGoで作ることに
    @とあるプロジェクト

    View Slide

  10. GoでEthereumのコントラクトを叩く
    Contractのbindingsを⽣成する or RPCリクエストを頑張って作る
    gethのツールチェイン abigen
    truffle compile # truffle
    のアーティファクト⽣成
    # jq
    でアーティファクトからabi
    だけ抽出
    for json in `ls contracts/build/contracts/*.json`; do cat $json | jq .abi > $json.abi; done;
    abiからbindingsを⽣成
    abigen --abi /home/contracts/build/contracts/TxRelay.json.abi --pkg contract --type TxRelay --out /home/tx_relay.go mv tx_relay.go api/contracts/
    適切にMakefileを書いて効率化します
    make extract_abi
    make abigen_all

    View Slide

  11. ⽣成されるbindings(読み出し/tx実⾏)

    View Slide

  12. ⽣成されるbindings(イベント監視)

    View Slide

  13. いけそうに⾒えるが...
    buildパイプラインが若⼲⻑い
    contract変更 -> compile -> abigen -> go build
    ライブラリとしてのgethは⼩回りが効かない
    estimateGasとかですら結構やるの⼤変
    バイト列の扱いが各所で異なり⾟い
    "0x1234...." @ Frontend, JavaScript
    [0x11, 0xab,...] @ Web API, Go[32]byte (prefixの0xは不要)
    "0x1234...." @ Contract, Solidity
    Front -> web api -> contractでやり取りする度に変換が必要(つらすぎる)
    何かやろうとするとgethを読まないといけない
    簡単なドキュメント:Ethereum Development with Go

    View Slide

  14. みなさんweb3.js使ってますか?
    みなさんweb3.jsでハマったことないですか?

    View Slide

  15. web3.jsのつらみ
    カジュアルに破壊される後⽅互換性
    かゆい所に⼿が届かないドキュメント (& 突然の404)
    普通にバグってて動かない(1.0.34 - 1.0.37くらい)
    イベントのsubscribe周り
    コントラクトデプロイ -> イベントが履かれているの確認 -> web3.js側が無反応 ->
    原因探る -> 無限に時間が溶ける
    TypeScriptと相性が悪い...(型定義が微妙...)
    他にもいろいろ...

    View Slide

  16. web3.jsを捨てて ethers.jsを使うことに

    View Slide

  17. View Slide

  18. View Slide

  19. ethers.jsの良いところ
    そもそもTypeScriptで開発されている&型定義がイケているの
    かゆい所に⼿が届くドキュメント
    やりたいことが⾃然にできる
    eventを取ってきてRLP decodeしたい
    データをsolidityの keccak
    と同じ⽅式でハッシュ化して署名したい
    コントラクトの関数を動的に呼び替えたい
    eth.send(HogeContractFunction.Create, ...hoge.toArgs())

    View Slide

  20. ethers.jsを使う前提でWeb APIもGo -> TypeScriptへ
    Ethereumは全体的にjsのライブラリが整っているので、NodeJSを使うのは悪い選択肢で
    はなさそう
    Goさん頑張って欲しい
    Rustツカイタイナ〜
    ⾊々なプロジェクトで採⽤しているstack
    WebAPI ... TypeScript(express) + TypeORM + ethers.js
    Frontend ... Nuxt.js
    Tools ... dbmate (migration), Ganache CLI, Truffle

    View Slide

  21. ethers.jsを使い倒すためのツール: buidler.dev
    @nomiclabs/buidler
    consoleからもdeployスクリプトからもethersを使いたい〜
    ethers.jsが使えてTypeScriptフレンドリーなタスクランナー(Yet Another Truffle)
    コントラクトのエラーの詳細なstack trace出⼒
    configがTruffleに⽐べると柔軟
    yarn add --dev @nomiclabs/buidler
    global installだとTypeScirptでconfigが書けない

    View Slide

  22. View Slide

  23. View Slide

  24. その他機能もいろいろ
    pulginでよしなに拡張できる
    builder consoleからethers.jsでノードとインタラクション

    View Slide

  25. その他便利ツール
    indexer
    Consensysの出してるやつ...
    Eventeum (by Consensys)
    the Graph
    Eth.events
    https://scrapbox.io/layerx/Ethereum_Indexer⽐較 に詳しい
    BaaS
    Kaleidoの出来がくっそ良い
    Zether(秘匿送⾦)
    Block explorer
    static analysis tools
    MythX
    etc...

    View Slide

  26. ⾻の折れる(楽しい)実装たち

    View Slide

  27. 署名検証を⽤いた認証
    基本の流れ
    サーバorコントラクトからメッセージを送る
    メッセージを含んだハッシュ値に秘密鍵で署名
    EIP191
    EIP1271
    サーバorコントラクトで検証(= ecrecover)
    実装前のお気持ち:「こんなん⼀瞬やろ」
    実際:結構⼤変
    少しでも⼊⼒が異なるとハッシュが変わる
    Solidityのkeccakに対応するクライアント側の関数isどれ...??
    abi.encodePacked
    なにやってるの ...
    型の指定が雑だとRLPエンコードの違いでハッシュが変わる

    View Slide

  28. View Slide

  29. View Slide

  30. View Slide

  31. 参考
    MetaMaskからsignするときは web3.personal.sign
    でないと処理が⽌まります(安全
    性の観点から、任意のメッセージに署名できる web3.eth.sign
    に⾮対応)
    署名検証 -> WebAPIへのアクセストークン発給とかやることが多そう
    コントラクトエンドで検証するにしろ、サーバサイドでやるにしろ nonce
    は必須
    web3.soliditySha3
    は型が指定できるので安⼼(型が違うとRLPエンコードが変わっ
    て死にます..)
    ethers.js
    の場合
    let sig = ethers.utils.splitSignature(flatSig);
    let recovered = await contract.verifyHash(messageHash, sig.v, sig.r, sig.s);
    utils.solidityKeccak256(types,values)
    utils.soliditySha256(types,values)
    utils.solidityPack(types,values)

    View Slide

  32. メタトランザクション(#とは)
    Gas代を誰かに代りに払ってもらう
    仕様は⾊々提案されている
    ERC1776(m0t0k1ch1さんのブログが詳しい)
    uPortのやつ
    ERC865(ERC20でガスを払う)
    ERC1077
    とあるプロジェクトでやりたかったこと
    モノを売り買いさせる(ETH払い)
    ガスはエンドユーザに払わせない
    署名だけをクライアントで⾏わせる
    できることを勘違いしたこともあり⾟かった...

    View Slide

  33. 実装を始めたくらいのイメージ
    1. txの雛形を作る=関数, 引数をRLPエンコードする
    2. クライアントで署名(!?)
    3. ⼀旦サーバ(Web API)に投げる
    4. サーバ側でネットワークにブロードキャスト(署名する!? & GASを払う)
    基本的には署名した⼈(アドレス)に該当するアカウントからガスが引かれるのでこの仕
    組は無理...
    = msg.sender
    に該当する⼈がかならずガスを払う
    最終的な実装
    1. クライアント側で実⾏したい関数と引数を指定アクセストークンと⼀緒にサーバへ投げつ
    ける
    2. サーバ側は誰が実⾏元(originalな署名者)かを明記して tx
    を作ってネットワークに送信、
    コントラクトでexternal callでtx実⾏

    View Slide

  34. View Slide

  35. View Slide

  36. 勘のいいみなさまはお気づきでしょう

    View Slide

  37. View Slide

  38. 閑話休題

    View Slide

  39. View Slide

  40. 罠・そして罠

    View Slide

  41. 事件簿
    Truffleバグってる事件
    ブロックチェーン調⼦悪い事件
    何故か開発ノードが動かなくなる
    Ganacheのautomineの罠
    偶然動いてた事件
    環境変数複雑過ぎ問題
    サーバとかノードとか多すぎ...
    EVM殿...
    stack too deep
    コントラクトサイズが上限超えてデプロイ不能にに
    mappingはkeys取れない問題
    Solidityむずい
    transferFromむずい

    View Slide

  42. View Slide

  43. 場合によってうまくいく場合と⾏かない場合があります
    なぜでしょう?

    View Slide

  44. Ganache or Ganache with automine
    geth, parity ...etc

    View Slide

  45. View Slide

  46. Truffleバグってる問題

    View Slide

  47. View Slide

  48. Ganacheのバグ
    deployスクリプト中にイベントを吐かないと、イベントのnetworksの項⽬が空になる
    eventを監視してindexしてる君が動かない
    2回デプロイすると直る
    build下を消すと再現
    workaround的に

    View Slide

  49. TIPS
    RLPは読み書きできるとはかどります(死)
    EthereumのTransactionのRLPエンコード / デコード
    ehters.jsおすすめです

    View Slide