T1 · EVM Engineer
動くコントラクトから、どんな条件でどう壊れるかを理解したコントラクトへ。
EVM を主な開発対象とするコントラクトエンジニア向けです。
このページの T1 は Track を指します。講座の章は「第 T8 章」のようにリンク付きで記し、両者を区別します。講座の T1 は、オンチェーンデータとは何かを扱います。
この Track に向いている人
職種名ではなく、行き詰まっている場所を見てください。次の一つでも当てはまれば適しています。
コントラクトを書けても、安全な理由を説明できない。 テストネットへ配備し、テストも網羅率もよく見えます。「安全とどう分かるか」への最も強い答えは、テストがすべて通ったことです。不十分と分かっていても、何を追加すべきか分かりません。
メインネットの実際のコードを読めない。 中心のコントラクトにはプロキシ、インラインアセンブリ、ビット圧縮、独自エラーがあり、必要な設計判断と技巧の誇示を区別できず、真似もできません。
Gas 最適化を暗記に頼っている。 calldata は memory より安い、変数はまとめる、と覚えていても、storage layout を計算し、どの二変数の交換でいくら削減できるかを説明できません。
面接で定義は答えられても、結果を説明できない。 delegatecall は呼び出し側のストレージで相手のコードを実行すると言えても、具体的にどう事故になるかは、ストレージ衝突という言葉しか出てきません。
境界は一つです。提供するコントラクトに添えるのは「テストした」か、「どの条件で、どのように壊れるかを知っている」か。
まだテストネットへ何も配備していなければ、先に Part B の第 2 段階を終えてください。この Track は動くリポジトリを前提とします。
前提
Part B 全 36 章を読むのが理想です。今始めるなら、知識グラフ上の最短経路は次です。
- 第 6 章
- 第 T1–T4 章
- 第 T5 章
- 第 9 章
- 第 T7 章
- 第 T8 章
- 第 T9 章
- 第 T12 章
- 第 T28 章
| 先に読む章 | グラフ上の理由 |
|---|---|
| 第 6 章 · オンチェーン取引で何が起きるか | 第 T1 章の直接の前提。取引を状態変化と理解しないと、順序の議論につながらない |
| 第 T1 章から第 T4 章 | 状態、署名、取引のライフサイクル、RPC。近道のない四章 |
| 第 T5 章 · EVM Account Model | 第 T7 章の直接の前提。Storage slot は Track 全体の費用の単位 |
| 第 9 章 · Smart Contract は何を変えたか | 第 T7 章の直接の前提で、Part A 側の唯一の必須依存 |
| 第 T7 章、第 T8 章、第 T9 章 | 言語、EVM の費用モデル、標準。ここから本題が始まる |
| 第 T12 章 · Testing & Deployment | 第 T7・T9 章に依存。Fork テストは単発の練習でなく日常の作業 |
| 第 T28 章 · Smart Contract Security | 第 T8・T9・T12 章に依存。揃って初めて、構文より順序を重視する理由が分かる |
学ぶ内容
- Solidity
- Foundry
- Hardhat
- EVM Internals
- DeFi
- Security
六つのテーマは、六科目ではなく四群の問いです。
1.言語とツール:コンパイルできるから検証できるへ
Solidity の深い部分は、継承の線形化順、独自エラーの revert データ、unchecked の適用範囲、一時ストレージの用途まで続きます。構文の問題ではなく、この一行で誰がいくら払うかの問いです。
二つの主要ツールは二者択一ではありません。一方はコントラクト言語でテストを書き、Fuzzing と不変条件を中心に据え、他方はスクリプト言語で配備、タスク、フロントエンドをつなぎます。成熟したリポジトリでは両方を使うことが多く、前者でテスト、後者で配備と連携を行います。空のディレクトリから両方を作り、分担の理由を説明できることを求めます。
2.EVM Internals:Gas を算術にする
配備せずに storage layout を書けるようにします。スロットの割当、同じスロットへまとめる条件、mapping と動的配列の位置を計算します。すると calldata、memory、storage の差は暗記ではなく計算できます。
次はプロキシです。delegatecall は誰のストレージかを変えます。主な配置方式の違いは、実装側の変数がプロキシ自身の変数を上書きしない方法の違いです。
他者のコントラクトで交換すべき二変数を示し、削減するのがコールド書き込みかウォーム書き込みかを説明して自己点検します。
3.DeFi:誰と組み合わせるか
Track T4ほどの深さは不要ですが、主要プロトコルの中心コードを読み、互いにどう悪影響を与えるかを知る必要があります。
- bool を返さない送金、課税トークン、自動で残高が変わるトークン、小数桁が 18 でないトークン
- 精度と丸め。第 T28 章の通り、丸め方向は常にプロトコルに有利にする
- オラクルの失敗。古いデータ、許容幅を超える乖離、ゼロを返すこと
- コールバック付き標準は、ETH を送らない関数にも再入を持ち込む
4.Security:安全を自動実行する
第 T30 章の脅威モデルの四問と不変条件の三種類を、読んだだけでなく毎回書きます。状態を持つ Fuzzing、判決ではなくフィルターとしての静的解析、マルチシグ・タイムロック・停止の権限設計を組み合わせます。
卒業成果物
Fuzzing と Fork テストを経た、メインネットのコントラクト一式。
卒業プロジェクトは、コントラクト、画面、バックエンド、インデックス、配備を横断する Core の締めくくりです。この Track はコントラクト層だけですが、縦に深く掘ります。卒業プロジェクトの層を起点にしても、次の五つで再検証してください。
他者が動かせるか。 clone 後、一コマンドで依存を導入し、一コマンドで全テストを実行します。README に環境変数、Fork 用 RPC の入手先、アーカイブノードがない場合の縮退方法を書きます。
動かないリポジトリは採用や提携では存在しないのと同じなので、常に第一の基準です。
Fuzzing が実際に動き、失敗した記録があるか。 三種類を覆う最低五つの不変条件を用意し、意図的に一つを壊して検出した最短の失敗列と乱数シードを残します。
常に成功する検査は、ない検査と同じ効果でも、誤った安心感を与えます。
外部依存ごとに Fork テストがあるか。 呼び出すすべての外部アドレスに用例を作り、チェーン、ブロック高、選んだ理由を書きます。
Gas の基準があり、増加を説明できるか。 重要な関数のスナップショットをバージョン管理し、増加時には、追加のストレージ書き込みや外部呼び出しを示します。
脅威モデルと更新経路があるか。 四問に答え、明確に防がないものを最低二つ示します。更新可能なら、権限者、反映までの時間、止め方を書きます。
メインネットへは、自分の少額の資金で、前四項目を完了した版だけを配備します。 テストネットのみと、今はメインネットへ進むべきでない理由を提出しても、評価は下げません。判断力を示すからです。
達成したかを判断するには
一つ目はストレージ衝突です。実装のスロット 0 への書き込みが、プロキシのスロット 0 を上書きします。そこに実装アドレスがあれば、通常の代入が任意のコードへ向けてしまいます。
二つ目は呼び出し主体の保持です。delegatecall 先のコードでは、msg.sender と msg.value は最外部の値のままなので、相手の権限検査が直接呼ばれたと想定していると、その検査が成立しなくなります。
追加の論点は、delegatecall 先を破棄・置換できる場合、空のコードを指す殻になり、revert せず何もしないことです。
読み取りをローカル変数へまとめます。初回はコールド、後の二回は元々ウォームなので、省くのはウォーム二回です。想定より小さい数字です。
大きいのは通常書き込みです。複数回を一回にまとめるか、小さな変数を同じスロットにまとめます。
コールドとウォームの費用差、前後のスナップショット比較が答えに必要です。 memory が安いとだけ言うのは、算術ではなく暗記です。
bool を返さずデコードで revert する、課税で受取量が減る、残高が自動変化して持分が合わない、小数桁が異なり比率がずれる、コールバックで再入する、ブラックリストで正常な送金も失敗する、などです。
対応の原則は、送金前後の自分の残高差を使い、戻り値も渡した量も信用しないことです。
監査報告だけを出すべきではありません。不変条件と Fuzzing の記録、防がないものを記した脅威モデル、重要経路の Fork テストを出します。
前二つは境界の理解、三つ目は境界内の検証を示します。監査報告は四つ目であり、一時点の記録です。
正解は一つではありません。三つを確認します。
- 経路(誰が、いくらで、どの順に呼ぶか)を述べていますか。脆弱性の名前だけですか。
- 市場や権限の状態など、発動条件を説明できますか。
- 発生から知るまでの時間を説明できますか。答えられなければ監視がありません。
よくある誤解
網羅率 100 パーセントなら十分
網羅率は各行の実行を測り、すべての呼び出し順は測りません。単独では正しくても、特定の順で丸めや状態のずれが累積します。
網羅率を最低条件にし、確信は状態を持つ Fuzzing と不変条件から得ます。
小さい型は Gas が安い
uint256 を uint8 にしても、同じスロットへまとめなければ安くなるとは限りません。切り詰めやマスクの演算で、かえって高くなることもあります。
測り、変え、また測ります。前後のスナップショットを残し、削減を具体的なスロット変更に対応させます。
更新可能なら安全
リスクがコードの誤りから更新権限の濫用や盗難へ移るだけです。影響範囲は大きく、一度の悪意ある更新ですべての不変条件が失われます。
本当に必要かを先に問い、必要なら権限を最も危険な資産として扱い、マルチシグ、タイムロック、公開された手順を設けます。
監査済みなら安全
監査の能力は範囲に制約されます。脅威モデルがなければ、範囲は実装の正しさだけとなり、経済的な仮定が抜けます。第 T30 章の、17 件を直しても資金を失った例です。
監査前に脅威モデルを渡し、監査後に各指摘を不変条件へ変えます。前者は調査範囲、後者は次の変更で成果を失わないことを決めます。
次に進むには
- 自分のリポジトリとともに、第 T8 章、第 T12 章、第 T30 章を読み直します。
- Track T4 · DeFi Engineerで金融、Track T5 · Security Engineerで安全、Track T3 · Onchain Data Engineerで信頼できるデータを補えます。
- 非技術側は Track N2 · Crypto Productです。コードの書き方より、なぜ署名が二回必要かを問われます。よく答えられる人の発言力は変わります。
- システム全体へ広げるなら卒業プロジェクトへ進みます。
- EVM の費用モデルやオペコードは更新で変わります。最新情報を追う方法で購読方法を学べます。