Skip to content

Commit 8388433

Browse files
committed
Add study notes for 2025-08-16
1 parent 9af9bd4 commit 8388433

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

Hickerzeed.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,121 @@ timezone: UTC+8
1515
## Notes
1616

1717
<!-- Content_START -->
18+
# 2025-08-16
19+
20+
透明代理模式详解
21+
一、代理模式简介
22+
在以太坊的智能合约世界中,合约一旦部署便具有不可修改性。这种特性虽然为合约提供了强大的安全性,但在实际应用场景里,当我们需要修复合约中的bug或者其功能进行升级时,就会面临挑战。为了解决这个问题,代理模式应运而生。代理模式的核心思想以合约的逻辑与数据存储分离开来,从而实现合约的可升级性。
23+
透明代理(Transparent Proxy)是代理模式中流行的一种,由OpenZeppelin提出并在行业内得到了广泛的应用。
24+
二、透明代理的核心问题:函数选择器冲突
25+
代理在模式实际应用中面临的核心挑战是函数冲突问题。当代理约定和逻辑约定中名称和参数都包含相同的函数时,就会产生冲突。例如,若逻辑约定和代理契约都包含upgradeTo(address)函数,那么调用时,系统将无法显式地执行哪个函数。
26+
透明代理模式通过区分管理员和普通用户的调用,巧妙地解决了这个问题:
27+
- 对管理员的调用:直接在代理合约中执行。
28+
- 对普通用户的调用:转发到逻辑合约执行。
29+
三、代码实现分析
30+
3.1 代理合约实现
31+
下面我们来详细分析TransparentProxy.sol关键实现部分:
32+
contract TransparentProxy is Proxy {
33+
// EIP - 1967 存储插槽
34+
bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
35+
bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
36+
37+
constructor(address _initImplementation, address _initAdmin) {
38+
// 设置逻辑合约地址
39+
assembly {
40+
sstore(_IMPLEMENTATION_SLOT, _initImplementation)
41+
}
42+
// 设置管理员地址
43+
assembly {
44+
sstore(_ADMIN_SLOT, _initAdmin)
45+
}
46+
}
47+
48+
// 其他函数...
49+
}
50+
核心技术点
51+
1.EIP - 1967 货架插槽
52+
:透明采用固定的货架来货架实现地址和管理员地址。这些特殊的货架位置遵循EIP - 1967 标准,能够确保不会与逻辑紧密的货架布局产生冲突。
53+
bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
54+
bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
55+
这些值是通过以下公式计算得出的:
56+
// bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)
57+
// bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)
58+
2.内联存储访问存储:代理合约使用内联存储(assembly)直接操作存储,这样做是为了避免使用常规的Solidity存储变量,从而防止存储冲突。
59+
assembly {
60+
sstore(_IMPLEMENTATION_SLOT, _initImplementation)
61+
}
62+
3.代理转发机制:_implementation()函数继承自Proxy合约,其主要作用是提供逻辑合约的地址。
63+
function _implementation() internal view override returns (address) {
64+
address impl;
65+
assembly {
66+
impl := sload(_IMPLEMENTATION_SLOT)
67+
}
68+
return impl;
69+
}
70+
当用户调用转发约定中不存在的函数时,fallback函数(在基类Proxy中实现)调用转发到逻辑约定。
71+
4.升级机制:代理合约提供了一个管理员管理员使用的升级函数:
72+
function upgradeTo(address _newImplementation) external {
73+
require(msg.sender == admin(), "Only admin can upgrade");
74+
assembly {
75+
sstore(_IMPLEMENTATION_SLOT, _newImplementation)
76+
}
77+
}
78+
该函数只能由管理员调用,用于将代理合约指向新的逻辑合约实现。
79+
3.2 逻辑合约设计
80+
我们设计了两个版本的逻辑合约:
81+
TransparentLogicV1.sol
82+
contract TransparentLogicV1 is Initializable, OwnableUpgradeable {
83+
uint256 public value;
84+
85+
function setValue(uint256 _value) public virtual {
86+
value = _value;
87+
}
88+
89+
function getValue() public view virtual returns (uint256) {
90+
return value;
91+
}
92+
93+
function initialize(address initialOwner) public initializer {
94+
__Ownable_init(initialOwner);
95+
}
96+
}
97+
TransparentLogicV2.sol
98+
contract TransparentLogicV2 is TransparentLogicV1 {
99+
uint256 public newValue; // 新增状态变量
100+
101+
function setValue(uint256 _newValue) public virtual override {
102+
newValue = _newValue;
103+
}
104+
105+
function getValue() public view virtual override returns (uint256) {
106+
return value + newValue;
107+
}
108+
}
109+
核心技术点
110+
1.可初始化合约:逻辑合约使用Initializable替代构造函数,这是因为在代理模式下,逻辑合约的构造函数不会被执行。
111+
function initialize(address initialOwner) public initializer {
112+
__Ownable_init(initialOwner);
113+
}
114+
取消constructor构造函数,采用initialize初始化函数,可以在升级合约时自动设置初始化参数,而不是在合约创建时进行设置。
115+
2.状态变量布局:在V2版本中,新增的状态变量newValue被添加到了原有变量之后,这样保持了存储结构的兼容性,是确保升级安全的关键。
116+
四、透明代理使用流程
117+
1.配置逻辑合约V1:首先配置第一个版本的逻辑合约。
118+
2.配置透明代理合约:配置透明代理合约,将其指向V1的地址。
119+
3.交互阶段:调用代理合约的地址,但使用V1的ABI进行交互。
120+
4.升级准备:当需要进行升级时,部署V2逻辑合约。
121+
5.合约升级:管理员调用合约的upgradeTo函数,将其指向V2地址。
122+
6.继续交互:继续使用代理合约地址,但使用 V2 的 ABI 进行交互。
123+
五、最佳实践与安全建议
124+
1.状态设备:在升级合约时,不要修改、删除或重排现有状态设备,以确保存储设备的兼容性。
125+
2.管理员权限分离:考虑使用多签钱包或DAO作为管理员,以增强权限管理的安全性。
126+
3.初始化函数:确保初始化函数有适当的访问控制,防止未授权的初始化操作。
127+
4.升级后验证:每次升级后,都要验证新功能是否正常工作,确保升级的稳定性。
128+
5.存储或冲突规避:特定使用命名模式避免结构体存储冲突,保证持续的正常运行。
129+
六、总结
130+
透明代理模式是Solidity中实现合约可升级性的强大工具,它通过巧妙的设计成功解决了代理模式中的函数选择器冲突问题。深入了解其实现细节和工作原理,对于开发安全、可靠的可升级智能合约系统至关重要。
131+
代理模式虽然为合约开发带来了灵活性,但同时也带来了复杂性和潜在风险。在实际应用中,开发者需要在可升级性和安全性之间进行权衡,严格遵循最佳实践,以保证系统的稳定性和安全性。
132+
18133
# 2025-08-15
19134

20135
UUPS 代理是基于 ERC-1967 标准设计的一种智能合约升级模式。与传统的透明代理模式(Transparent Proxy)不同,UUPS 将升级逻辑内置于实现合约,而不是代理合约本身。代理合约仅用于转发呼叫,所有逻辑由实现合约处理。

0 commit comments

Comments
 (0)