msg.sender は有害と考えられる
Solidity 開発者にとってこのタイトルはいささか衝撃的かもしれません。気になる方はぜひ読んでみてください。奥深き Cadence 言語の世界へようこそ。
※ Cadence は Flow ブロックチェーンで使われるプログラミング言語です。
※この記事は Flow のこちらのドキュメントを参考に書かれています。
Solidity と Cadence の違い
Solidity 開発者が Cadence でのプログラミングを始める際、誰しもが「msg.sender
をチェックするにはどうしたらいいか」という疑問を抱きます。
Ethereum では、msg.sender
をチェックすることで、関数を呼び出しているアカウントを特定し、その関数の動作を適切に変更できます。これは、Ethereum における権限、所有、セキュリティの鍵となります。
一方、Cadence には msg.sender
はありません。トランザクションは複数のアカウントによって署名される可能性があります。そのため、Cadence には、トランザクションレベルで、呼び出し元を一意に識別する方法がありません。
さらに Ethereum と異なるのは、コントラクトのデータの格納先です。Ethereum では、コントラクトをデプロイすると新たにコントラクト・アカウントが作成され、データは基本的にすべてそのコントラクト・アカウントに格納されます。一方 Flow では、個々のユーザーが所有する NFT などのデータは、各ユーザーのアカウントのストレージ領域に格納されます。
Solidity では、ひとつの中央のコントラクトで msg.sender
をチェックすることで処理を実装します。しかし Cadence では、同じことを実現するために異なるアプローチが必要です。
セキュリティモデルの違いと例
Solidity の設計では、アクセス制御リストによってセキュリティを担保します。
一方 Cadence では、Capability ベースのセキュリティ・モデルに従います。この設計は、コードの堅牢性とセキュリティに明確な利点があると、Flow チームは考えています。
Capability ベースのモデルで、いくつかの一般的な処理がどのように実現されるかを説明します。
管理者権限
管理者の機能(例えば、トークンの mint 機能など)は、Admin リソースに含めます。このリソースは、管理者のアカウント・ストレージに格納します。管理者機能へのアクセスを複数の異なるアカウントに与えたり、取り消すことも可能です。
許可/ブロックのリスト
基本的に、所有するリソースに対するユーザーの制御を制限することは、Flow らしくありません。しかし規制遵守などの理由でどうしてもアカウントの許可/ブロックのリストを実装しなければならない場合は、コントラクトに定義したaccess(contract)
アクセス修飾子をつけた関数を、リソースから呼び出します。この関数の中で、管理者が管理する許可/ブロックのリストをチェックします。
部分的な権限を与える
あるリソースへのアクセスを一時的・部分的に他のユーザーに与えるには、例えば、指定した許容量のみを含んだ新しい Vault を作成する方法があります。ある関数へのアクセス権限については、特定のインターフェースに制約された Capability を他のユーザーに渡すことによって達成できます。
所有
あるアカウントのストレージにリソース(NFT、NFT コレクション、FT Vault など)が含まれている場合、そのアカウントはそれを所有しています。このことを他の場所に記録する必要はありません。
Capability ベースのセキュリティは何が優れているのか?
Solidity におけるアクセス制御リストによるセキュリティと、Cadence における Capaility ベースのセキュリティ、どちらが優れているのでしょうか?実際、これはユースケースによります。
例え話をします。
(※こちらのサイトに良い例があったので内容を拝借しています)
あなたは、貴重品を銀行の貸金庫に保管したいと考えています。そして時には、信頼できる友人に預け入れや引き出しをしてもらいたいと考えています。銀行が金庫へのアクセスを制御する方法は 2 つあります。
- 金庫にアクセスできる人のリストを保持する
(アクセス制御リスト方式) - 1 つまたは複数の金庫の鍵をあなたに渡す
(Capability 方式)
アクセス制御リストの場合;
- 銀行の関与: 銀行はリストを保存し、ユーザーを確認する必要がある
- 偽造: 銀行はリストを保護する必要がある。認証が必要
- 追加: 所有者は銀行を訪問する必要がある
- 委任: 友人は自分の特権を他の誰かに渡せない
- 取消: 友人が信用できなくなったら、所有者は彼の名前を削除できる
Capability ベースの場合;
- 銀行の関与: 銀行はいかなる取引にも関与する必要はない
- 偽造: 鍵は偽造できない
- 追加: 所有者は新しい人に鍵を渡せる
- 委任: 友人は自分の特権を他の誰かに渡せる
- 取消: 所有者は鍵を返してもらうことができるが、友人が鍵のコピーを取ったかどうかわからない
アクセス制御リストと Capability 方式がどう違うのか、イメージがついたでしょうか。
それぞれの利点を考えてみると、利便性は Capability ベースのほうが優れています。毎回、銀行を介して何かを行なう必要がないからです。逆に、友人が敵になることがある場合、アクセス制御リストのほうが良いです。アクセス制御リスト方式では、まったく意図しない第三者に権利が渡ることがないからです。
さて、これをブロックチェーンの場合で考えてみると、アクセス制御リスト方式の場合、この例の銀行に相当する中央のコントラクトが必要になることがわかります。このコントラクトの役割は非常に大きく、ここにバグがあってはなりません。また、すべての操作はこのコントラクトを介して行なう必要があり、これはトランザクション処理をスケールさせる上でボトルネックになります。
Capability 方式では、ボトルネックとなる中央コントラクトは存在せず、また、欠点となりうる「友人が鍵のコピーを取ったかどうかわからない」という点に関しても、すべて情報がオープンなので確認可能です。もちろん Capability 方式にもデメリットはありますが、こちらのほうがブロックチェーンとの相性がいい方式のように思えます。
おわりに
「msg.sender
は有害と考えられる」というのは、かなり挑発的なタイトルでしたが、Flow チームが何を考えて新しいブロックチェーンをつくったのか、この記事を読むことで少しでも理解いただけたら幸いです。
長期的にみたとき、この方式がどう影響してくるのかはとても興味深いです。