はじめに
スマートコントラクトの優位性として、コードが公開されていて誰もが検証できるということがあります。そしてそのコードが改変されないということも大きな利点として語られます。
自分にとってはここは本当に重要な点であり、また、自分がProxyパターンを利用した実装が好きではない理由のひとつでもあります。
そんなスマートコントラクトも正しい知識がなければ「見えるからこそ騙される」可能性があります。
マジシャンは相手が見えるということを利用しながらトリックを使い相手の視線や思考をコントロールします。
見えるからこそ信じてしまう。
その裏にあるトリックに騙される。
ある意味では、中途半端な知識がある人ほど騙しやすいとも言えるわけで、技術者としてはしっかりとした知識をつけていくことが大事ですよねというお話。
サンプルコントラクト
テストネットにコントラクトをひとつデプロイしました。
https://goerli.etherscan.io/address/0x5ea9b66e3b2b400a4d8990b9f19326329ea0b758#code
contract Main {
SubA a;
constructor(address _a) {
a = SubA(_a);
}
function callSubA() public view returns (string memory){
return a.check();
}
function setOwner(uint256 tokenId) public {
a.setOwner(msg.sender,tokenId);
}
}
contract SubA {
mapping(uint256=>address) public owners;
function check() public pure returns (string memory){
return "SubA was called";
}
function setOwner(address owner, uint256 tokenId) public {
require(owners[tokenId] == address(0));
owners[tokenId] = owner;
}
}
MainコントラクトとSubAコントラクトがあり、MainコントラクトにはcallSubA()とsetOwner()という二つのpublic関数があります。
仮にcallSubA()を呼び出した場合、どういう文字列が返ってくるでしょうか。
callSubAはSubAのcheck()を呼びだしていますから、パっと見では"SubA was called"が返ってくるように見えます。
function check() public pure returns (string memory){
return "SubA was called";
}
しかし、実際にEtherscanで呼びだすと、"HiddenA was called"という文字列が返ってきます。
Verifyが通っているコードのどこを見ても"HiddenA"などという文字列はどこにもありません。
setOwner関数はどうでしょう。
パッと見ではアドレス型のownerと、uint256のtokenIdが渡され、既に登録されていないtokenIdであれば呼び出し元アドレスがownerとしてmappingに登録される。
一度登録されたものについては、誰も更新できなくなる。
このように見えると思います。
しかし、実際にsetOwnerを呼び出してみると、何度でも好きなように更新ができます。
実際の実装としては何の制限もかかっていません。
今回のサンプルは初歩的なコード隠蔽を使っているので、少し知識がある人なら「あ~ やっとんな」と見破ることができると思いますが、人によっては混乱をするでしょう。
コードが見えており、かつ一定の知識があるからこその混乱です。
見えているコードには存在しない文字列が返ってくる。
requireが設定されているはずなのに制限されない。
これらはSolidityの仕組みをしっかりと理解しておかなければ意味がわからない動きとなってしまいます。
悪意のあるコードから非エンジニアを守るのも技術者としての大事な役割
今回のようなシンプルなものだけでなく、より複雑にした隠蔽や偽装はいくらでも考えることができます。
バックドアやラグプルの仕組みとしてひっそりと実装される可能性があるものです。
ライブラリーやプロトコルをうまく利用することも大事ですが、よりコアに近い部分の知識をしっかりと学んでおくことはとても大事だと思います。
「見えているからこそ騙される」ということはあるわけで、ともに切磋琢磨しながら知識を積み重ね、マジシャンズチョイスに引っかからない技術者、非エンジニアを守ることができる技術者になっていければいいなと思います。