售前客服二维码
文章均源于网络收集编辑侵删
提示:仅接受技术开发咨询!
图书馆是一种特殊的合同。这种合同不具备任何应付功能,也不具备任何后备功能。 (这些限制在编制期间被强制限制,因此您可以使图书馆成为合同。无法持有任何资金)。库由库密钥(库L {})定义,就像合同将由(合同C {})定义一样。
图书馆L {
函数a()返回(地址){>
返回地址(this);
}
}
合同C {
函数a()常量返回(地址){>
//这将表现为库代码是在本合同中编写的
返回L.a();
}
}
要调用库中的函数,必须使用特殊指令(DELEGATECALL),它将调用上下文传递给库,因此它几乎就像是在同一个合同中。合同处理自己的指示。我非常喜欢Solidity文件中的观点。
图书馆可以被认为是其他智能合约的内在基础合同。
从上面的代码中可以看出,如果调用契约C的函数a(),a()将返回契约C的地址而不是库L的地址。这也适用于所有msg属性:msg.sender ,msg.value,msg.sig,msg.data和msg.gas(相反的是写在Solidity文件中,但经过一些实验,看起来像我这样的解释是正确的)。
我们在这里要注意的一件事是我们仍然不知道C类(C类)和库L(库L)是如何连接在一起的,所以我们将尝试理解这个问题。
库是如何连接的?
与显式继承不同,契约C是B {},它链接到库的方式不太清楚。在上面的示例中,Contract C在其自己的函数a()中使用库L.但是,在上面的简短代码中,我们没有提到在库中使用什么地址,并且库L没有出现在编译的块代码(byecode)中。
库的连接发生在位组代码级别。编制合同C时,合同C将为图书馆的地址提供如下形式的保留位置:0073__L_____________________________________ 630dbe671f(0dbe671f是()的功能签名),如果我们不在所有合同中更改合同C.部署了C,这将导致部署失败,因为块代码是非法的。
简单的解释是库连接只是将合同组代码中的所有位置保留到库中,所有这些位置都填充了库的地址。这样完成的位代码可以成功部署到区块链。
好了,现在我们已经介绍了库的基本概念,我们可以理解如何使用库来开发可扩展的智能合约。
图书馆本身无法升级
无法升级库,也无法升级合同。正如我们在本文前面提到的,对库的引用是字节码级别,而不是存储级别。部署合同后,无法修改合同的块代码。因此,对图书馆的引用将与合同一起保留。
所以我们不得不问这个问题,“为什么还有人可以升级这个功能?”
最后,他是如何工作的?
在这里我们将使用一些提示,让我们仔细看看。
我们不直接将用户使用的主合同C连接到部署所需的库,而是将用户使用的主合同C连接到Dispatcher合同。在编译时和部署期间,由于调度程序合同没有在库中实现任何功能,所以一切都不会有问题。这意味着调度程序合同不使用库中的任何代码。调度程序合同只是一个块代码(就像我们在上面的合同C中看到的位组代码一样),在调度程序中。位组代码不需要包含库的地址。我们没有在字节码级别硬编码任何地址,因此我们总是可以用我们需要的任何库替换库。
但是,如果我们不在调度程序合同中使用任何库代码,我们如何在库中实现这些功能?
当事务进入时,主合同(令牌合同)发现事务需要从连接到主合同的库(TokenLib1)调用delegatecall。但是,调用delegatecall并不直接询问该函数。库直接返回,而是通过调度程序合同调用delegatecall。
接下来的事情会变得非常有趣。一旦调度程序合同在其自己的回退函数中收到委托调用,调度程序合同将确定回退函数中需要哪个正确的版本库,然后指示请求将代理调用到正确的库。当库返回数据时,数据将一直返回到主合同。
尽管这种解决方案效果很好,但他仍有一些局限性。
限制
调度程序合同必须知道调用库的内存大小和库返回的值。现在这个问题可以通过映射来解决,函数签名将用于获取返回值的大小。为了简化说明,我们有意避免更多地解释这方面。
上述方法可以在以太坊虚拟机中成功运行,但是如果不同合同之间的存储占用空间相同,我们只能使用它。由于库没有任何存储空间,因此我们必须在调度程序合同中没有存储空间。这就是为什么你需要另一个单独的Dispatcher Storage(见下面的方框)来存储调度程序合同所需的数据。此外,Dispatcher Storage的地址必须写入调度程序合同的位组代码中。
可以发现,用户使用的合同不使用任何特殊技术。唯一的区别是您无法像以前那样连接到特定版本的库,而是连接到计划。合同。
文章均源于网络收集编辑侵删
提示:仅接受技术开发咨询!