Mik*_*ike 6 interface ethereum solidity smartcontracts
在可升级的智能合约的背景下,何时应该使用接口和库?我读了几个类似的问题和博客文章,但没有一个给出一个直截了当的答案:
我了解在设计可升级性时要考虑的主要标准(除了安全性)是:
这篇Medium帖子建议使用库来封装逻辑(例如,当与"存储契约"交互时)并使用接口来解耦合同间通信.其他帖子提出了不同的技巧 据我所知,库在部署之前与合同相关联,因此一旦合同发生变化,就需要重新部署库.为什么使用接口与存储合同进行交互并不是更好?
下面我介绍我到目前为止看到的两个解决方案 - 一个是库,另一个是接口.(我想避免使用内联汇编的解决方案......)
StorageWithLib.sol:
contract StorageWithLib {
uint public data;
function getData() public returns(uint) {
return data;
}
}
Run Code Online (Sandbox Code Playgroud)
StorageLib.sol:
import './StorageWithLib.sol';
library StorageLib {
function getData(address _storageContract) public view returns(uint) {
return StorageWithLib(_storageContract).getData();
}
}
Run Code Online (Sandbox Code Playgroud)
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 ...
}
}
Run Code Online (Sandbox Code Playgroud)
IStorage.sol:
contract IStorage {
function getData() public returns(uint);
}
Run Code Online (Sandbox Code Playgroud)
StorageWithInterface.sol:
import './IStorage.sol';
contract StorageWithInterface is IStorage {
uint public data;
function getData() public returns(uint) {
return data;
}
}
Run Code Online (Sandbox Code Playgroud)
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 ...
}
}
Run Code Online (Sandbox Code Playgroud)
考虑到上述标准,哪种解决方案更适合分离存储和逻辑,为什么?在其他情况下,其他解决方案更好吗?
小智 5
库和接口确实不同,并且在不同的情况下使用。我个人认为它们在合同设计中不可互换。下面我试图概述两者的主要特征。请注意,interface我的意思是抽象合同(这就是上面示例中的合同)。在我之前强调的 Solidity 接口中仍然存在问题https://medium.com/@elena_di/hi-there-answers-below-6378b08cfcef
图书馆:
\n\n可以包含逻辑并用于从合约中提取代码以实现可维护性和重用目的
部署一次,然后在合同中引用。它们的字节码是单独部署的,不是引用它们的合约的一部分。这在我上面的文章(“在 Solidity 中编写可升级合约”)中被定义为单例,其中我解释了诸如降低部署成本之类的好处。
抽象合约/接口
\n\nCannon 只包含接口定义的逻辑
主要用作其他合约的导入,提供与合约实现的交互。接口的部署/导入大小比实施者合约小得多
提供可升级性的抽象,我也在我的文章“使用 \xe2\x80\x98interfaces\xe2\x80\x99 解耦合约间通信”部分中进行了描述
我认为上述两者之间唯一的相似之处是它们都不能包含存储变量。
\n我希望有人能给出更好的答案,但这是一个很好的问题,我想发表我的意见。
简而言之,由于它专门与可升级合约相关,因此我认为这两种方法之间并没有真正的区别。无论采用哪种实现方式,您仍然拥有单独的存储合约,并且仍然call向存储合约发出 a (一个通过接口从操作合约发出,另一个通过库间接从操作合约发出)。
唯一具体的区别在于天然气消耗。通过该界面,您将发出一个call操作。通过一个库,您将添加一层抽象,并最终得到一个delegatecall后跟一个call. 不过,天然气开销并不是很大,所以归根结底,我认为这两种方法非常相似。您采取的方法是个人喜好。
这并不意味着库通常没有用。我经常使用它们来实现常见数据结构或操作的代码重用(例如,由于在 Solidity 中进行迭代很痛苦,所以我有一个库可以用作基本的可迭代集合)。我只是不认为将它们用于我的存储合同集成有多大价值。我很好奇 Solidity 专家是否有不同的观点。