スマートコントラクト概論
アカウントが保持する状態
最小限のものは、
- 公開鍵
- アカウントからの送金命令を検証するため
- バランス
- アカウントにあるトークン残高
- カウンター
- リプレイ攻撃を防ぐ整数
余談: カウンターとリプレイ攻撃について
アカウント \(a\) の送金命令 \(O_a\) には \(a\) の署名がある。
リプレイ攻撃
\(a\) 以外の者が \(a\) の送金命令 \(O_a\) を偽造することは出来ないが、
過去
\(a\) が実行した \(O_a\) のデータは公開されているので、
再度実行させること狙ってブロックチェーンに送りつける。
悪意ある攻撃でなくとも、ウォレットの不調などで、 \(a\) 自身が同じ命令 \(O_a\) を複数回送ってしまうことはある。
再度実行をどう防ぐか → カウンター
カウンター
\(a\) のアカウント状態にカウンター \(c \in \mathbb{N}\) を置く。
\(O_a\) を作る際、現在の \(a\) のカウンター値 \(c\) を記載する: \(O_a[c]\)
ブロックチェーンプロトコルが \(O_a[c]\) を受け取ったら:
- \(a\) のカウンタの値が \(c\) と同じ時
-
\(O_a[c]\) を正当とみなす。\(O_a[c]\) がブロックに取り込まれ、
実行された場合は、 \(a\) のカウンタは \(c+1\) になる - \(a\) カウンタの値が \(c\) ではない時
- \(O_a[c]\) は不正とみなされ、ブロックに取り込まれない
このようにして同一命令の再度実行を防ぐ。
アカウントが保持する状態
- 公開鍵
- バランス(残高)
- カウンター
これらのフィールドもデータだが、変更は強い制限がある:
公開鍵:
変更不可, バランス: 総量の保持, カウンター: 増加のみ
これだけでは汎用データベースにはならない…
汎用データベースに向けて
各アカウントに追加:
- ストレージ
- 汎用データ保存域
- コード
-
ストレージの変更権の認証や変更ロジックを記述。
アカウントごとに独自の動作を設定可能
スマートコントラクト
- 実行トリガー
-
アカウントへの送金によってコードが起動。
(送金額0 = コード起動のためだけのメッセージ) - コード実行の連鎖
-
コードから他のアカウントへの送金が可能。
送金先にコードがあればコード実行が連鎖する
単なるプログラムの実行だけでなく、自動送金も(したければ)できる。 契約の自動執行。
スマートコントラクト実行の安全性
スマートコントラクトとして任意のプログラムが実行できると、
ブロックチェーンは安全性を保つことができない:
- ストレージ以外の記憶域、例えば自分のバランスを書きかえる
- 許可されない情報を読み込みネットワークを介して漏洩させる
- 無限ループなどで分散型サービス拒否攻撃を発生させる
- etc. etc… まあ、なんでもできる
実行できる命令を大幅に制限する必要がある。
仮想機械によるスマートコントラクト実行
スマートコントラクトのコードを
- Virtual Machine の命令列に制限
- 実行を VM インタプリタを使って管理
- 制限されたデータ読み込み (ストレージ + バランス + etc)
- コントラクトのストレージ以外への書き込みを禁止
- I/O の禁止
- 無限ループの禁止
仮想機械によるスマートコントラクト実行
ブロックチェーンごとの独自 VM。 高級言語からの独自コンパイラを必要とする。主にスタックマシン:
最近の流行: 汎用VMを使えば、既存のコンパイラを利用可能:
VM を使っても危険が残る
- スマートコントラクトにバグや脆弱性があると…
-
意図せぬ誤動作(送金)をしてしまう。
(コントラクトは書かれたバグをそのまま実行するだけだが) - 無制限にコンピューターリソースを使いだすと…
-
各ノードが同じコードを実行、それぞれのリソースを使い尽くす。
DDoS によりブロックチェーンが停止する。
前者は、バグのないスマートコントラクトを書いてとしか言えない。 (バグが発生しにくい VM や言語のデザインはあるが)
後者は VM 命令の実行時にリソース管理をすれば回避できる
→
ガス管理
ガス管理
ガスによる計算量制限
ガス: 各種操作の実行時間の見積もり
\[実行時間 ∝ 消費ガス量\]
になるように各操作のガス値を設計
ガスによる送金命令 \(O\) の計算量制限
- 送金命令の作成
- 仮に \(O\) を実行してガス消費見積もり \(g_O\) を宣言
- 送金命令の実行
- スマートコントラクト実行などの各操作がガスを消費していく
- ガス欠
-
\(O\) の実行中、総ガス消費量が見積もり
\(g_O\) を超えたら、ガス欠。
実行を中断。罰金として手数料だけ取られる。 - 正常終了
- 見積もり \(g_O\) を上回るガス消費なく \(O\) が完了できれば成功。
ブロック \(B\) のガス制限
ガスリミット定数 \(G\): 各ブロック \(B\) での総ガス消費量上限
\(B\) の条件として、
\[G \geq \sum_{O\in B} g_O\]
を追加。
ブロック処理の最大時間を \(G\) で制限できる。
\(G\) を消費する時間 < ブロック更新間隔(Tezos は 15秒)
スマートコントラクトのガス消費
- ガス消費
- 各VM命令実行前に、その命令分のガス量を消費。
- ガス欠
- 今までの総消費量が \(O\) の見積もり \(g_O\) を超えたらガス欠。
各VM命令のガス消費量計測
ベンチマークによる実行時間計測と推論
- ベンチマーク
- 各命令に対し、様々な入力を与え、実行時間を計測
- ガスモデル
-
入力に対する実行時間変化のモデル
(ex. \(実行時間 = 入力データサイズの和 * x\)) - ガスパラメータ推論
-
線形回帰による、ベンチマークの計測データのモデルへの適合。
モデルの変数の値を推論。 - VM 実行系への反映
- VM命令の実行部で求めたパラメータを使ったガス消費を行う
ꜩ ガス推論例: 文字列の連結
CONCAT
ベンチマーク
CONCAT
に対し、様々長さの文字列2つを与え、実行時間を計測
{ "workload": [ [ "N_IConcat_string_pair", [ [ "str1", "1201" ], [ "str2", "54391" ] ] ], // 1201 bytes と 54391 bytes の連結 [ "N_IHalt", [] ] ], "measures": [ 3215, 3329, 3693, 3315, 3371, 3810, 3523, 3625, .. // 繰り返し実行し実行時間 nano secs のサンプルを取る { "workload": [ [ "N_IConcat_string_pair", [ [ "str1", "38036" ], [ "str2", "14145" ] ] ], [ "N_IHalt", [] ] ], "measures": [ 3587, 3141, 3197, 3398, 3156, 3202, 3433, 3074, ..
ꜩ ガス推論例: 文字列の連結
CONCAT
モデル
\(a\) と \(b\)
を連結する文字列のそれぞれのバイト数とすると、
おそらく実行時間の増加はその合計に比例するだろう:
\[\mathrm{model}(a, b) = \mathit{intercept} + \mathit{coeff} ~× (a+b)\]
パラメータ
\(\mathit{coeff}\) : 増加率の傾き
\(\mathit{intercept}\) : 切片。
CONCAT
自体の起動に必要な時間
ꜩ ガス推論例: 文字列の連結
CONCAT
線形回帰による推論
Scikit-learn の LASSO回帰を使って、ベンチマークデータからモデルパラメータを推論:
free_variables: builtin/Timer_latency = 13 interpreter/N_IConcat_string_pair_coeff = 0.0612222900743 interpreter/N_IConcat_string_pair_intercept = 37.3123382529 ...
解
\(\mathit{coeff} =
0.06122229\),
\(\mathit{intercept} =
37.3123382\)
ꜩ ガス推論例: 文字列の連結
CONCAT
\(\mathit{coeff} = 0.06122229\), \(\mathit{intercept} = 37.3123382\)
ꜩ ガス推論例: 文字列の連結
CONCAT
VM インタプリタのガス計算関数へ反映
\(\mathit{coeff} = 0.06122229\), \(\mathit{intercept} = 37.3123382\)
(* model interpreter/N_IConcat_string_pair *)
(* fun a b -> 37.3123382529 + 0.0612222900743 * (a + b) *)
let cost_N_IConcat_string size1 size2 =
let v0 = size1 + size2 in
40 + v0 lsr 5 + v0 lsr 6 + v0 lsr 7 + v0 lsr 8
浮動小数点数の計算は遅い
- 切片は 5 の倍数に丸める: 37.3123.. → 40
- 1未満の掛け算はビットシフトに:
v0 * 0.06122229 → v0 lsr 5 + v0 lsr 6 + v0 lsr 7 + v0 lsr 8
= v0 * 0.05859375
DApps のいろいろ
Decentralized Appications
ブロックチェーン、スマートコントラクトを使ったアプリ:
- 価値のやり取りができる
- 非中央集権
- 管理者なしでずっと動く
- コードがオープン
- 誰でも検証可能
- ズルできない(皆がちゃんと検証すれば😜)
DApps の難しさ
- 遅い (Tezos: 15秒/1ブロック)
- 高い
- オープンなので秘密をそのまま置けない (暗号化が必要)
- バグを突かれると金を盗まれる
- 道具が特殊
どんな DApps がある?
- NFT: アートNFTなど
- DEX: 分散取引所
- Name service: DNS
- ゲーム
ꜩ Tezos DApps: NFT
デジタルアートNFTが流行っている
デジタルアートのデータをトークン化して売買
- objkt.com https://objkt.com/
- fxhash https://www.fxhash.xyz/
- 八火堂 https://www.8bidou.com/
- Teia https://teia.art/
Non native token
- Native token
- ブロックチェーンのプロトコルで使っている インセンティブトークン (例: tez for Tezos)
- Non native token
- スマートコントラクト上で実装されているトークン
普通の貨幣と同じような性質をコードで実装:
- 総量の保存 (勝手に鋳造できない)
- 所有量/所有者
- 支払いの仕組み
FT/NFT
- Fungible Token
- 代替可能 ex. あなたと私の10円玉
- Non Fungible Token
- 代替不可能 ex. カードゲームのカード
FT/NFT の実装
アカウントのストレージに所有情報のテーブルを置く
- Fungible Token
-
- 誰が<どれだけ>持っているか
- Non Fungible Token
-
- 誰が<何を><どれだけ>持っているか
- 複数の FT を一つのスマートコントラクトで扱うのと同等
デジタルアート NFT とオフチェーンストレージ
アートデータは大きすぎ、ブロックチェーンに載せられない
(載せてもいいが高い: Tezos だと 0.04円/B。 40,000円/MB)
そこでアートデータのハッシュだけをチェーンに載せる
アートデータ自体はオフチェーンに
- IPFS に置くのが主流。
- オフチェーンデータの永続性に注意
- アート NFT を買ったらオフチェーンデータは手元に取っておきましょう
デジタルアート NFT ?
常にある疑問
誰でもアクセスできるデータのハッシュを<所有>することの意味
- アートデータは IPFS にあり、誰でもアクセスできる
- ハッシュはブロックチェーンにあり、誰でもアクセスできる
- このハッシュは誰が所有している、というデータはある
アートNFTを持っているからと言って、何かが法的に保証されているわけではない。 🤔 投げ銭以上の意味あんのかな?
これからは、ハッシュの所有者に +α の価値を提供できるか
ꜩ 八火堂 NFT
ハッシュしかチェーン上にないアートNFTへのアンチテーゼ
ドット絵に特化した Tezos アート NFT
8x8 dot
の絵。小さいのでアートデータもオンチェーンに。
日本の方が作っています
Fungible Token
FT もあります
- ステーブルコイン (法定通貨とのペグ)
- ユーティリティートークン売買
- サービスの資金を得る
- トークンを使ってサービスを受けられる
DApps: DEX
分散取引所
仮想通貨同士の交換を提供する
DApps: Name service
名前を売るサービス
Tezos Domains https://tezos.domains/en
短い名前を占有、Tezos アカウントなどの情報と紐付けできる:
- 長ーいアカウント: tz1X3rca4Uc8M4peGBhuAQXUhVa38qBJBQpx
- Twitter などのアカウント情報
- ホームページ URL
- Gravatar アイコン: https://en.gravatar.com/
- https://名前.tez.page も提供 (IPFS/リダイレクト)
DApps: ゲーム
Tezos にもいろいろあるようです:
ブロックチェーンは遅いし高い。
ゲームでの意味のある使用には工夫が必要