Solidity Library 介绍
在 Solidity 中,library 是一种不同类型的合约,它没有任何存储空间,也不能拥有 ether,不能被继承。 可将 library 视为 EVM 中的单例,它是一段可以从任何合约中调用的代码,无需再次部署。它的声明是这样: library C {}
。
library 也不能有 payable function 和 fallback function ,这种限制在编译时就有了。
调用库函数将使用特殊指令(DELEGATECALL),这会导致调用上下文被传递给库,就好像它是在合同中运行的代码一样。
library C {
function a() returns (address) {
return address(this);
}
}
contract A {
function a() constant returns (address) {
return C.a();
}
}
这段代码中,当方法 a() 被调用返回的 address 是 A 合约的,而不是 library C 的。msg 变量等全局变量也是一样的道理。
library 如何被调用
具体的连接发生在字节码编译时,当合约 A 编译时,会给 library 地址留出占位符,比如:0073__C_____________________________________630dbe671f。630dbe671f 是方法 a 的签名。library 链接非常简单,只需将合约字节码中的所有占位符替换为区块链中已部署的库的地址即可。 一旦合约和库产生连接,它可以被部署了。
using 的使用
library 可以修改与之相连的合约数据,当将 storage 声明作为参数传递给 library 调用时,所做的任何修改都将保存在合约自己的存储中。
library CounterLib {
struct Counter { uint i; }
function incremented(Counter storage self) returns (uint) {
return ++self.i;
}
}
contract CounterContract {
using CounterLib for CounterLib.Counter;
CounterLib.Counter counter;
function increment() returns (uint) {
return counter.incremented();
}
}
OpenZeppelin
OpenZeppelin 是一个 github 上的开源库,旨在提供安全的 library 供人使用来提升自己合约的健壮性。它们统称为符合 ERC20Lib 标准的库。现在对于实战,ERC20Lib 是包含与管理 ERC20 令牌相关的所有业务逻辑的库。
- 其中的 SafeMath.sol 可以保证数学运算安全性的 library。什么?加减乘除也会出错?这就是上溢、下溢错误。
- 其中的 TokenStorage,它包含使用 token 需要的所有功能,比如收发、存储。
- 这种方法的有趣之处在于 ERC20Lib 和 SafeMathLib 都只需部署一次,所有链接 ERC20Lib 的合约都将使用相同的安全审核代码。
代码重用
parity 钱包事件
多签名钱包的逻辑因为比较复杂,不希望每次都要重新编写, 这时要用一些底层的汇编调用。一个 function 部署时需要先 copy 到本地的栈上再执行。 但是这样 copy 很有风险,多签名钱包被攻击就是这样,合约是以前的合约,但是为了可以 copy 而不用每次部署,但是就是因为没有将原始合约的自杀函数屏蔽掉,有个闲人就把原合约干掉了,代码不复存在了,所以用户 copy 代码时得到空指针,一个 0x0 ,导致 parity 钱包的资金被锁死。
代理 library
想必大家已经知道了无论是合约还是 library 一旦部署就无法修改的了,但是如果我所调用得到 library 升级了,而想用它的最新版该怎么办呢???或是遭遇了上述悲剧怎么办呢?
当然是通过代理模式解决啦。
如图所示:前端用户接口与主合约交互,主合约如果要调用 library 必须通过 dispatcher,而 dispatcher 调取合约的地址是从 dispatcher storage 这个合约中读取的,dispatcher storage 相当于数据库,如果我们调一个新的 library 的话改变它所存的地址就可以了。
但是有些方面需要注意:
- 需要确定该库调用返回的内存大小是多少。 现在可以通过 mapping 将函数签名映射到它们的返回类型大小来解决。
- 鉴于 delegatecall 在 EVM 级别上的工作方式,一个合约只能和具有相同存储空间的另一合约交互。 由于 library 没有存储空间,必须让 dispatcher 也没有存储空间。 这就是为什么一个独立的 dispatcherStorage 来保存所有需要的数据。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Solidity 异常处理
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论