理解 delegatecall 和透明代理:智能合约升级的关键技术
理解 delegatecall 和透明代理:智能合约升级的关键技术
在区块链世界中,智能合约一旦部署便不可更改。然而,随着时间的推移,智能合约可能需要修复漏洞或添加新功能。因此,合约的可升级性变得至关重要。
什么是 delegatecall?
delegatecall 是 Solidity 中的一种低级别函数调用,用于将当前合约的上下文传递给另一个合约。这意味着被调用合约的代码在调用者合约的存储上下文中执行。
类比理解
可以把 delegatecall 想象成一个演员(合约A)在另一个演员(合约B)的剧本(代码)指导下表演。虽然合约A执行的是合约B的代码,但使用的是合约A的道具和场景(存储和上下文)。
delegatecall 的语法
(bool success, bytes memory data) = target.delegatecall(data);
其中,target 是被调用的合约地址,data 是调用的数据。
使用场景
- 代理合约模式(Proxy Pattern):
在这个模式中,一个合约(代理合约)代表另一个合约(逻辑合约)执行代码。通过delegatecall,代理合约能够将调用传递给逻辑合约,从而实现逻辑合约的功能。这种模式使得合约可以在保持地址不变的情况下进行升级。
什么是透明代理(Transparent Proxy Pattern)?
管理员变为工具人,仅能调用代理合约的可升级函数对合约升级,不能通过回调函数调用逻辑合约。其它用户不能调用可升级函数,但是可以调用逻辑合约的函数。
避免函数选择器冲突。
透明代理模式的结构
- 代理合约(Proxy Contract):存储合约地址和数据,通过
delegatecall调用逻辑合约。 - 逻辑合约(Logic Contract):包含实际的业务逻辑,可以随时更换新的逻辑合约以实现升级。
类比理解
可以把透明代理模式想象成一个剧院(代理合约),剧院有一个固定的地址,观众(用户)总是去这个剧院看戏。而剧院里上演的剧目(逻辑合约)可以更换,由剧院经理(代理管理员)决定更换哪部剧。
其实就是设计模式中的代理模式。
透明代理模式的优势
- 可升级性:允许更换逻辑合约,修复漏洞或添加新功能,而无需更换代理合约地址。
- 透明性:用户与代理合约交互时,不需要知道背后的逻辑合约,实现无缝升级。
- 灵活性:可以通过升级逻辑合约来适应不同的业务需求。
DEMO
代理合约
contract TransparentProxy {
address implementation; // logic合约地址
address admin; // 管理员
string public words; // 字符串,可以通过逻辑合约的函数改变
// 构造函数,初始化admin和逻辑合约地址
constructor(address _implementation){
admin = msg.sender;
implementation = _implementation;
}
// fallback函数,将调用委托给逻辑合约
// 不能被admin调用,避免选择器冲突引发意外
fallback() external payable {
require(msg.sender != admin);
(bool success, bytes memory data) = implementation.delegatecall(msg.data);
}
// 升级函数,改变逻辑合约地址,只能由admin调用
function upgrade(address newImplementation) external {
if (msg.sender != admin) revert();
implementation = newImplementation;
}
}
逻辑合约
// 旧逻辑合约
contract Logic1 {
// 状态变量和proxy合约一致,防止插槽冲突
address public implementation;
address public admin;
string public words; // 字符串,可以通过逻辑合约的函数改变
// 改变proxy中状态变量,选择器: 0xc2985578
function foo() public{
words = "old";
}
}
// 新逻辑合约
contract Logic2 {
// 状态变量和proxy合约一致,防止插槽冲突
address public implementation;
address public admin;
string public words; // 字符串,可以通过逻辑合约的函数改变
// 改变proxy中状态变量,选择器:0xc2985578
function foo() public{
words = "new";
}
}

浙公网安备 33010602011771号