在可升级智能合约的背景下,应该何时使用接口和何时使用库? 我阅读了几个类似的问题和博客文章,但没有一个给出直截了当的答案:
我理解在设计可升级性时要考虑的主要标准(除安全性外)是:
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 ...
}
}
考虑到上述标准,哪种解决方案更适合分离存储和逻辑,以及为什么?在其他情况下,其他解决方案更好吗?
答案 0 :(得分:3)
库和接口实际上是不同的,并且在不同的情况下使用。在合同设计中,我个人认为它们不可互换。下面我试图概述两者的关键特征。请注意,interface
我指的是一个抽象合同(这是你在上面的例子中所拥有的)。我在之前的https://medium.com/@elena_di/hi-there-answers-below-6378b08cfcef
<强>库强>:
可以包含逻辑,用于从合同中提取代码以实现可维护性和重用目的
部署一次,然后在合同中引用。它们的字节码是单独部署的,不是引用它们的合同的一部分。这在我上面的文章中定义为单例(&#34;在Solidity&#34中编写可升级的合同;),其中我解释了诸如降低部署成本等好处。
抽象合同/接口
Cannon包含逻辑接口定义
主要用作导入与合同实施交互的其他合同。接口的部署/导入大小比实施者合同
提供可升级性的抽象,我在我的文章“&34;使用'接口'来解除合同间沟通&#34;
我能想到的两者之间的唯一相似之处是它们都不能包含存储变量。
答案 1 :(得分:2)
我希望有人可以用更好的答案来衡量,但这是一个很好的问题,我想发表意见。
简而言之,由于它与可升级合同有关,我不认为这两种方法之间确实存在差异。无论是哪种实现,您仍然拥有单独的存储合同,并且您仍然向存储合同发出call
(一个来自操作合同,一个来自操作合同,另一个来自动作合同,间接地通过库)。
唯一的具体差异来自燃气消耗。通过界面,您将发出一个call
操作。通过一个库,您将添加一个抽象层,最后得到一个delegatecall
,后跟一个call
。然而,天然气开销不是很大,所以在一天结束时,我认为这两种方法非常相似。你采取的方法是个人偏好。
这并不意味着一般来说库不是很有用。我将它们用于常见数据结构或操作的代码重用(例如,因为在Solidity中迭代很麻烦,我有一个库用作基本的可迭代集合)。我没有看到使用它们进行存储合同集成的重要价值。我很想知道那里的Solidity专家是否有不同的观点。