微微介紹
(DELEGATECALL, Fallback Function, Contract Storage Model)
Proxy
Contract
Logic
Contract
User
pragma solidity >=0.4.0 <=0.6.0;
contract ExampleDapp {
string dapp_name; // state variable
// Get Function
function read_name() public view returns(string) {
return dapp_name;
}
// Set Function
function update_name(string value) public {
dapp_name = value;
}
}
→ 會存在合約 storage 內
→ 改動合約 storage
→ 讀取合約 storage
在 A 合約的 context,執行 B 合約的 function
這個主要是透過 EVM 的 DELEGATECALL 來達成
B 的 function 執行時 存取的是 A 的變數
把所有的 function call 都交給 logic contract 執行
它的 bytecode 只有這樣
其中 bebebebebebebebebebebebebebebebebebebebe 會是 logic contract 的地址
363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3
不過有很讚的 OpenZeppelin 教大家看
因為他是直接寫 bytecode 所以不好懂
原理就是只寫一個 fallback function
把所有 message call 都用 DELEGATECALL 的方式
轉給寫死的 logic contract 來執行
(這個是 OpCode 的好讀版)
收到的 call 沒有對應的 function
就會執行 fallback function
甚至是沒有帶 data,單純送錢的 call
也執行 fallback function
大家知道現在的以太坊區塊鏈
其實有被硬改過
有些歷史被抹掉了 QQ
contract TheDao {
function refund() {
check(sender);
sender.send(value);
update(sender);
}
}
contract Hack {
function fallback() {
if (canRefund) {
TheDao.refund();
}
}
}
bytecode 很短,部署合約很便宜
如果需要大量一模一樣邏輯
但又要不同地址、不同狀態的合約
用 proxy 就很省
就不能用 minimal proxy 的方式
因為它把 logic contract 的地址寫死在 bytecode 了
有點像是寫死在 web server 的程式碼裡面這樣
我們知道合約程式碼是不能修改的
那有可能可以把 logic contract 的地址
寫在 storage (db) 裡面 讓它可以被改嗎
可以啊 不過
這樣可以嗎
不行
contract Proxy {
address public logic;
function upgrade(address newLogic) {
logic = newLogic;
}
function () {
...
...delegatecall...
...
}
}
}
contract Logic {
uint256 public a;
uint256 public b;
function A() {
...
}
function B() {
...
}
}
storage 可以想成一個 sparse 的 array
solidity 的 compliler
會照 variable 宣告的順序
指定它們的 index (slot)
proxy 自己保留的變數
要小心不要讓 logic contract 用到同一個 slot
所以要往後放
保留在 proxy 合約這邊
其它交給 logic 合約的 pattern
非常常見
目前也很多不同作法
來看看 USDC 合約
function 看起來不會衝到
(因為 proxy 優先 沒有才 fallback)
但是要注意一個問題
看起來不同的 function 可能會有一樣的 signature
(function clashing)
合約程式編譯完
function 會有一個 id (signature)
這個 id 是經過一個 hash 然後取前 4 個 bytes 來的
例如 →→→
(Minimal Proxy 可以直接看 bytecode 知道 implementation 合約地址)