【发布时间】:2018-04-25 12:27:55
【问题描述】:
在可升级智能合约的背景下,什么时候应该使用接口,什么时候应该使用库? 我阅读了几个类似的问题和博客文章,但没有一个给出直截了当的答案:
- (Sub) contract vs. library vs. struct vs. Interface
- How to improve smart contact design in order to distinguish data and their manipulation functions for the same domain object?
- Writing upgradable contracts in Solidity
- Interfaces make your Solidity contracts upgradeable
- Library Driven Development in Solidity
- Proxy Libraries in Solidity
- Exploring Code Reuse in Solidity
我了解在设计可升级性时要考虑的主要标准(除了安全性)是:
- 模块化 - 可重用性和更易于维护
- gas 限制 - 拆分大量合约,以便它们可以部署在多个交易中,以免达到 gas 限制
- 升级成本 - 每个合约升级的成本是多少。在一个合同发生(小)变化后,需要重新部署哪些其他合同?
- 执行成本 - 单独的合约可能会导致每次调用的 gas 开销。尽量保持低开销。
This Medium post 建议使用库来封装逻辑(例如,与“存储合约”交互时)并使用接口来解耦合约间通信。其他帖子提出了不同的技术。据我了解,库在部署之前已链接到合同,因此一旦合同发生更改,库就需要重新部署。为什么使用接口与存储合约交互不是更好?
下面我介绍了我目前看到的两种解决方案 - 一种使用库,一种使用接口。 (我想避免使用内联汇编的解决方案...)
库解决方案
StorageWithLib.sol:
contract StorageWithLib {
uint public data;
function getData() public returns(uint) {
return data;
}
}
StorageLib.sol:
import './StorageWithLib.sol';
library StorageLib {
function getData(address _storageContract) public view returns(uint) {
return StorageWithLib(_storageContract).getData();
}
}
ActionWithLib.sol:
import './StorageLib.sol';
contract ActionWithLib {
using StorageLib for address;
address public storageContract;
function ActionWithLib(address _storageContract) public {
storageContract = _storageContract;
}
function doSomething() public {
uint data = storageContract.getData();
// do something with data ...
}
}
接口解决方案
IStorage.sol:
contract IStorage {
function getData() public returns(uint);
}
StorageWithInterface.sol:
import './IStorage.sol';
contract StorageWithInterface is IStorage {
uint public data;
function getData() public returns(uint) {
return data;
}
}
ActionWithInterface.sol:
import './IStorage.sol';
contract ActionWithInterface {
IStorage public storageContract;
function ActionWithInterface(address _storageContract) public {
storageContract = IStorage(_storageContract);
}
function doSomething() public {
uint data = storageContract.getData();
// do something with data ...
}
}
考虑到上述标准,哪种解决方案更适合分离存储和逻辑,为什么?在哪些其他情况下,其他解决方案更好?
【问题讨论】:
标签: interface ethereum solidity smartcontracts