Skip to main content

原文準拠 Phase 3:DApp開発

5.1 Capstone — けいじ板を拡張

Midnight Academy Phase 3 / Unit 5 / 5.1 Capstone の原文準拠版。example-bboard を fork し、Compact 契約・TypeScript 連携・テストを拡張して提出する卒業課題を、正確に・やさしく。


📘 Academy原文準拠 | Phase 3 · Unit 5 · Lesson 5.1 Capstone — Extend Your Bulletin Board 内容に忠実な日本語版です。原文(英語)・図・動画は公式 Academy(外部リンク・別タブで開きます)を正本に。

ここまでの10レッスンで、Midnight DApp 開発をひととおり学んできました。開発環境のセットアップから始まり、Compact の基礎、witness(証人)、シールドトークン、そしてけいじ板(bulletin board)のスタック全体まで。いよいよ、自分の手でつくる番です。

この卒業課題(capstone)では、けいじ板の契約に新しい機能を足して拡張します。やることはこんな流れです。

動画で学ぶ(公式)

🎬 Capstone — けいじ板の拡張(公式解説) YouTubeで開く ↗

課題の内容(The assignment)

下の拡張トラックから1つを選びます。あるいは、自分で考えたものを提案してもかまいません。どのトラックも、けいじ板に意味のある機能を足しつつ、このモジュールで学んだパターンをしっかり使う設計になっています。

Track A: Multi-Post Board(複数投稿のボード)

いまのボードは、メッセージをちょうど1件しか持てません。これを、同時に複数の投稿を持てるように拡張します。

変えるところ:

  • Contract(契約):いまの「単一メッセージ」と「owner」の ledger フィールドを、複数の投稿を持てるデータ構造に置きかえます。各投稿には、それぞれ「メッセージ・owner の公開鍵・識別子(identifier)」が必要です。投稿数の上限をどう扱うかも考えましょう(ボードが無限にふくらまないように)。新しい circuit が要ります:post は「置きかえ」ではなくコレクションに追加する形に。takeDown は「どの投稿を消すか」を指定するために投稿の識別子を受け取る形にします。
  • Witnesses(証人):witness はこれまでどおり秘密鍵(secret key)を提供します。ただし takeDown は「どの投稿を消すか」を見分ける手段が要るようになります。投稿の識別子を circuit のパラメータにするのか、それとも何か別のものから導くのか、を考えてみてください。
  • Tests(テスト):シミュレータのテストを書きます。異なるユーザーから複数のメッセージを投稿する/特定の投稿を消す/他人の投稿を消そうとする/投稿数の上限に達する、といったケースを確認します。
  • API/CLI:API の state$ を更新して、投稿の一覧と、そのうちどれが今のユーザーのものかを見せます。CLI のメニューも更新し、どの投稿を消すかをユーザーが選べるようにします。

ここで使う中心概念:Compact でのデータ構造の設計、複数回の disclose() 呼び出し、コレクションによる状態管理、シミュレータの拡張。

Track B: Timed Posts with Expiration(時限つき投稿・期限切れ)

いまのボードでは、投稿は手で消すまでずっと残ります。これに期限(expiration)の仕組みを足して、一定時間が過ぎたら投稿を自動的に「消せる状態」にします。

変えるところ:

  • Contract(契約):各投稿に timestamp(タイムスタンプ)または blockHeight(ブロック高)の ledger フィールドを足し、「いつ投稿されたか」を記録します。新しい circuit(expirePost、または takeDown を改造)を足して、期限のしきい値(threshold)を過ぎたら誰でも投稿を消せるようにします。元の投稿者はいつでも自分の投稿を消せますが、期限切れになれば、誰でもそれを片づけられます。
  • Witnesses(証人):期限チェックに witness のデータが要るのか、それともオンチェーンのデータだけでできるのか、を考えましょう。ブロック高(block height)は circuit のコンテキストから手に入るので、追加の witness は要らないかもしれません。
  • Tests(テスト):しきい値の前は期限切れにできないこと、元の投稿者は早めに自分の投稿を消せること、期限切れの投稿は誰でも消せること、そしてシーケンスカウンタがこれまでどおり正しく増えることを確認します。
  • API/CLI:導出した状態(derived state)に、投稿の経過時間または残り時間を表示します。CLI のメニューに「expire」オプションを足します。

ここで使う中心概念:契約内での時間ベースのロジック、条件つきアクセス制御(owner または 期限切れ)、複数の認可(authorization)経路を持つ circuit の設計。

Track C: Sealed Ownership with Selective Disclosure(封印した所有権と選択的開示)

いまのボードは、owner の導出公開鍵を誰でも見える公開台帳に置いています(といっても、そこから元の鍵を逆算はできません)。これを、所有権に sealedledger フィールドを使うように改造し、owner をオンチェーンから完全に見えなくします。そのうえで、任意の「reveal(明かす)」circuit を足します。

変えるところ:

  • Contract(契約):owner を export ledger から sealed ledger に変えます。post circuit はこれまでどおり公開鍵を導出して保存しますが、それが観察者からは隠れるようになります。revealOwnership circuit を足して、「秘密鍵を明かさずに、自分が owner であることを証明する」ようにします。出力は boolean でも、proof token(証明トークン)でもよいでしょう。takeDown circuit はそのまま動きます。sealed フィールドは circuit の中からはアクセスできるからです。
  • Witnesses(証人):変更は不要です。witness はこれまでどおり秘密鍵を提供します。
  • Tests(テスト):所有権が機能的にはこれまでと同じく働くこと(投稿・消去)を確認しつつ、台帳の状態が、外部からの照会に対して owner フィールドをもう見せないことを確認します。reveal circuit もテストします。
  • API/CLI:owner が公開台帳の状態にもう無いので、導出状態の isOwner の計算を変える必要があります。pureCircuits を使うか、別の仕組みを使うことになります。台帳の表示では、公開鍵のハッシュの代わりに「sealed」と見せます。

ここで使う中心概念:sealed キーワード、プライバシー・バイ・デフォルトの設計、選択的開示(selective disclosure)の circuit、可視性の境界(visibility boundaries)の理解。

Track D: Your Own Extension(自分で考える拡張)

自分で機能を提案してつくります。出発点になりそうなアイデアをいくつか:

  • Upvote/downvote システム — ZK 証明を使って、ユーザーに投稿への投票をさせる(1人1票、しかも誰が投票したかは明かさない
  • プライベートメッセージング — 既存の witness パターンを使い、意図した受信者だけが読める暗号化メッセージを保存する
  • 投稿のカテゴリやタグ — 投稿にメタデータを足し、絞り込み(フィルタ)できるようにする
  • 所有権の譲渡 — 投稿者が、導出したトークンを共有することで、消去する権利を別のユーザーに引き渡せるようにする
  • マルチボード factory — 独立した複数のボードをデプロイし管理する契約をつくる

このトラックを選ぶなら、つくり始める前に、提案する機能を提出物の中で説明してください。そうすれば、開発に時間をかける前に実現可能かどうかのフィードバックをもらえます。

提出の要件(Submission requirements)

どのトラックを選んでも、提出物には次のすべてが含まれていなければなりません。

  1. 書きかえた Compact 契約コンパイルが通る、拡張した bboard.compact ファイル。コンパイルできないコードは自動的に失格です。契約のディレクトリで npm run compact を実行し、エラーがゼロであることを提出前に確認してください。

  2. 更新した TypeScript 連携:契約の変更に合わせて動く、witness・シミュレータ・API のコード。すべての TypeScript が型チェックを通ること(npm run typecheck)。

  3. 動くテスト:足した機能を確かめる、更新または新規のシミュレータテスト。新しい circuit には、最低でも2つのテストを:1つは成功ケース、もう1つは「失敗するはず」のケース。npm run test を実行し、すべてのテストが通ることを確認してください。

  4. README または解説文:短い文書(500〜1000語)で、次を説明します。

    • 何をつくったか、そしてなぜその設計判断をしたか
    • モジュールのどの Compact パターンを使ったか(witness、disclose()sealed、アサーション など)
    • 拡張によって、どんなプライバシー特性を保ったか/変えたか
    • 気づいている制約やトレードオフ
  5. オリジナルの成果物であること:提出物はあなた自身のものでなければなりません。あなたが理解・テスト・適応していない AI 生成コードは見抜かれ、失格になります。私たちはこれをチェックします。解説文は、コードが「何をするか」だけでなく「なぜ動くか」についての、あなたの理解を示すものであるべきです。

提出のしかた(How to submit)

  • example-bboard リポジトリを fork する
  • capstone/<あなたの名前> という名前のブランチを作る(例:capstone/ada-lovelace
  • 変更を加える
  • 確認する:npm run compact が通り、npm run test が通り、npm run typecheck がクリーンであること
  • ブランチを push し、プルリクエスト(PR)を開く
  • PR の説明に解説文を含め、Ready for review(レビューの準備ができました)と記載する

評価基準(Evaluation criteria)

提出物は次の観点で評価されます。

観点 内容
コンパイル・実行できるか これは合否(pass/fail)。契約がコンパイルできない、またはテストが通らないなら、それ以上はレビューされません
正しさ(Correctness) ロジックは、あなたが言うとおりのことを実際にしているか。アサーションは状態遷移を正しく守っているか。見落とした edge case(端のケース)は無いか
プライバシーへの意識 何が開示され、何が秘密のままか考えたか。新しい disclose() を足したなら、そのデータを公開すべき理由を説明できるか。sealed を使ったなら、それが何を隠すか理解しているか
テストの網羅 テストはハッピーパス(正常系)と失敗ケースの両方を覆っているか。セキュリティ特性(例:権限のないユーザーが制限された操作をできないこと)をテストしているか
コードの質 きれいで読みやすく、一貫したスタイルのコードか。既存コードベースで確立されたパターンに従っているか
解説文の質 設計判断の明快な説明と、土台となる概念への理解を示しているか

成功のためのヒント(Tips for success)

  • 契約から始める:まず Compact のコードをコンパイルできる状態にします。契約は土台です。ここで型システムが間違っていると、下流のすべてが壊れます。
  • シミュレータを使う:テストが手元で通るまで、Preprod へのデプロイは試さないこと。シミュレータはミリ秒で動きます。一方、証明の生成は1トランザクションあたり30秒かかります。ロジックを書き、手元でテストし、繰り返し直し、自信が持ててから初めてデプロイしましょう。
  • エラーメッセージを読む:Compact コンパイラは具体的なエラーを出します。「ある値を台帳に保存するには disclose() が必要」と言われたら、それはまさに何をすべきかを教えてくれています。テストでアサーションが失敗したら、エラーメッセージは assert() 呼び出しに書いた文字列と一致します。
  • 変更を絞る:きれいに仕上げた小さな機能は、中途半端で野心的なものに勝ります。Track D を選ぶなら、完成・テスト・説明をすべてやりきれる範囲に絞りましょう。
  • モジュールのレッスンを見直す:詰まったら、関連するレッスンに戻りましょう。witness が動かない? Lesson 26。disclose() がわからない? Lesson 28 の行ごとの解説。provider の問題? Lesson 29。必要なパターンは、すでに終えたレッスンに全部書かれています。

これが準備になること(What this prepares you for)

この capstone をやり遂げるということは、Midnight DApp をゼロから組み・テストし・拡張できるということです。それは本物のスキルです。Midnight のエコシステムはまだ早期で、Compact と SDK を扱える開発者は求められています。

capstone の成果がしっかりしていたら、Midnight Content Bounty Program(外部リンク・別タブで開きます) への貢献も検討してみてください。このプログラムは、教育コンテンツ・コード例・技術ガイドに対して 300〜1,000ドルを支払います。ここで磨いたスキル — Compact 契約を書き、TypeScript 連携を組み、プライバシーパターンを説明すること — は、まさに bounty プログラムが報いるものです。

コントリビューター向けボードで、bounty タグの付いた open issue を見て、今の機会を探してみましょう。

がんばってください。自分が誇れるものをつくりましょう。

開発者として押さえる点

  • 卒業課題の本体は example-bboard を fork → Compact 契約を拡張 → TS 連携を更新 → テストを書く → PR で提出capstone/<名前> ブランチを切る
  • 合否ラインは機械的npm run compact(エラー0)・npm run test(全通過)・npm run typecheck(クリーン)。1つでも欠けると、それ以上レビューされない
  • 新しい circuit には最低2テスト(成功ケース+失敗ケース)。とくに「権限のないユーザーが制限操作をできない」セキュリティ特性を確認する
  • 設計の軸はプライバシー:何を disclose() で公開し、何を sealed で隠すかを説明できること。Track C は export ledgersealed ledger への置きかえと revealOwnership の追加が核心
  • 反復はシミュレータ(ミリ秒)で。証明生成は1トランザクション30秒かかるので、ロジックが固まるまで Preprod デプロイは後回し
  • 提出は自分が理解した・テストした・適応したコードであること。未消化の AI 生成コードは見抜かれ失格になる

やさしい版・公式へ

つぎに読むページ

➡️ 原文準拠コースの入口へ戻る。このコースについて(次のレッスンは順次追加します)