Skip to main content

フェーズ4:CompactとDApp開発

Compact の書きかた(文法ツアー)

Compact の本物の文法をやさしく一周。pragma・import・ledger・circuit・witness・constructor・型・disclose まで、実際のコントラクトの形を見ながら理解します。


Compact ってなに? で「契約を書く言葉」だと学びました。 このページでは、本物の文法を一周します。やさしく説明しますが、内容は開発者向けです。

⚠️ バージョンで文法が少し変わります。ここの例はチュートリアルの pragma language_version >= 0.23; に合わせています。最新は必ず公式の Compact リファレンス(外部リンク・別タブで開きます)で確認してください。

まず「いちばん小さい契約」を見る

公式の Counter チュートリアルの契約は、なんとこれだけです。

counter.compact

たった数行ですが、Compact の大事な部品がぜんぶ入っています。順番にほどいていきましょう。

① pragma と import(おまじない2行)

  • pragma language_version >= 0.23; … 「この言葉のバージョンはこれ以上だよ」という宣言。最初に書く。
  • import CompactStandardLibrary; … 便利な道具セット(標準ライブラリ)を読みこむ。CounterMaybepersistentHash などはここから来ます。

② ledger(公開ステート=みんなに見える箱)

  • ledgerチェーンの上に置く公開データを宣言するキーワード(教室のけいじ板)。
  • export を付けると、外(TypeScript側)からも読めるようになります。
  • sealed を付けると、最初(constructor)だけ書ける=あとから変えられない、になります。

箱の種類(Ledger ADT)

ledger に入れられる「箱の種類」がいくつもあります。よく使うものだけ:

箱の種類 なに? 主な操作
Counter 数を数える increment(n) / decrement(n) / read()
Cell<T> 1個の値を入れる read() / write(v)
Set<T> 重複しない集まり insert(x) / member(x) / size()
Map<K,V> キーと値の対応表 insert(k,v) / lookup(k) / member(k)
List<T> 順番つきの並び pushFront(v) / popFront() / length()
MerkleTree<n,T> 証明に便利な木 insert(x) / checkRoot(r)

💡 一部のメソッド(木の root() など)は TypeScript 側でだけ呼べて、Compact の中では呼べません。公式の Ledger ADT(外部リンク・別タブで開きます) で確認しましょう。

③ circuit(入口=やってよい操作)

  • circuit … 契約の処理の単位export circuit外から呼べる入口(トランジション)。
  • (): [][] は「何も返さない(unit / void)」という意味。Compact 独特なので覚えておくと混乱しません。
  • export の付かない circuit内部ヘルパーpure circuit は ledger も witness も触らない計算だけの関数。

④ witness(秘密の入口=手元から渡す)

  • witness秘密データを渡す入口。宣言は Compact に書きますが、中身は TypeScript 側で実装します。
  • ここから来た値は「秘密あつかい」になり、公開する前に disclose(...)(後述)でフタを開ける必要があります。

⑤ constructor(最初の設定)

  • デプロイ時に1回だけ動いて、ledger の初期値を決めます。

⑥ disclose(秘密を公開してよい、と宣言する)

ここが Compact のいちばん大事なルールです。

  • 秘密(witness 由来)の値を、公開 ledger に書く/外に返すときは、必ず disclose(...) で囲みます。
  • disclose は「暗号化」ではありません。「この値は見せてOKだよ」とコンパイラに伝えるだけの印です。
  • 付け忘れると、コンパイラが「秘密が漏れるかも。disclose を書いてね」とエラーを出してくれます(うっかり漏洩の防止)。

もう少し本物:けいじ板(bboard)の一部

公式 Bulletin Board チュートリアルの契約から、雰囲気を(短く)。

bboard.compact(一部)

ここで新しく出た部品:

  • enum … 状態の名前セット(空き / 使用中 など)。
  • Maybe<T> … 「あるかも・ないかも」を表す型。some<T>(v) / none<T>() で作る。
  • Opaque<'string'> … 中身の形を隠した文字列のような値。
  • assert(条件, "メッセージ") … 条件が成り立たなければ取引を失敗させる(ルールの番人)。

よく使う型(早見)

なに?
Boolean true / false
Field 大きな数(暗号で使う数の世界)
Uint<n> n ビットの正の整数(例 Uint<64>
Bytes<n> n バイトのデータ(例 Bytes<32>
Vector<n, T> T が n 個ならんだもの
Opaque<'string'> 形を隠した文字列など
struct / enum 自分で作るまとまり / 名前セット

開発者として理解すべきこと

  • 契約の骨格は pragma → import → ledger → witness → constructor → circuit
  • 公開は ledger、秘密は witness、そして秘密を公開する境目に disclose
  • [] は unit 戻り値、assert はルールの番人、enum/Maybe/Opaque で状態を表す
  • 細かい型やメソッドは暗記せず、公式リファレンス(外部リンク・別タブで開きます)で都度引くのが正解

公式Docsではどこ?

今日のまとめ

  • 契約は短くても ledger(公開)+ witness(秘密)+ circuit(入口) でできている
  • 秘密を見せる境目には必ず disclose
  • 型や箱の種類は公式リファレンスで引く

今はここだけでOK

counter.compact の数行を「これは公開、これは入口」と読めたら、もう Compact の入口は突破です。

📘 もっと正確に(原文準拠コース)

Academy 原文に忠実な詳しい版はこちら:

公式どおりの細かい注意

  • バージョン表記は資料で違う:Academyは pragma language_version >= 0.20、チュートリアルは >= 0.23。最新は公式で確認
  • 文字列型は Opaque<"string">(ダブルクォート)が公式表記
  • public_key() は組み込み関数ではない → persistentHash パターンで自作する
  • witness 由来の値で「分岐」するときも disclose が必要(implicit disclosure エラー)

つぎに読むページ

➡️ 契約を実際に動かす全体像へ。DApp の組み立てかた(5つの部品)