我们不造轮子,我们只是轮子的搬运工。
我们在进行软件开发的时候,往往会用到别人写的一些现成的东西,像python里的tensorflow、numpy、pandas,C++里的Qt、 boost等等。这类别人写好的代码往往被称作“库”(也叫轮子),引用别人的库需要有现成的库文件。
在区块链上,同样也包含这种概念,但是与我们一般编译程序不同,我们引用的代码是已经部署在区块链网络里的代码,不需要本地有这个库。
这一步的教程比较复杂,分为5个部分:
1.自己撰写一个Libirary。
2.生成调用Library所需的Metadata。
3.编辑Metadata。
4.链接Library并部署。
5.查看部署详情。
撰写Library
library其实跟普通的contract没什么区别,只不过它是以library作为key word并且可以让其他的contract调用已经部署过的library,这样不用重复造轮子。
pragma solidity >=0.4.22 <0.6.0;
contract test {
function get () public returns(uint) {
// should call a library method which returns `3`
return LibraryForTest.getFromLib();
}
}
library LibraryForTest {
function getFromLib() public returns(uint) {
return 3;
}
}
首先是在library里制作一个getFromLib的函数,返回值为3,然后再在contract当中建立一个get函数,调用这个getFromLib函数。
要注意的是,在solidity语言当中,返回值的类型也要卸载函数定义当中,通过returns定义返回值类型,这里使用的是uint也就是无符号整型。
进行编译和部署,在部署完后可以在界面内进行调用。(建议使用Ropsten测试网,可以领取测试的手续费)
生成调用Library所需的Metadata
在之前的程序当中,我们将contract和library写在同一个文件里,但是实际上在部署之后,他们将会是两个不同的地址,那么如果contract想引用这个library,就必须知道它的地址。
但library的地址并不会直接显示在合约当中,在编译好的contract的bytecode当中,会有一个placeholder指向这个library的address。
所以在部署一个调用library的contract之前,你需要生成这个contract的metadata,然后将要调用的library的address加入到metadata当中。
接下来我们就来看一下如何找metadata。
metadata在编译(compile)的时候产生,当我们选择左下角的设定,打勾generate metadata的选项,再进行编译。就可以在文件里找到sampleContract_metadata.json的文件。
编辑Metadata
Metadata的deploy当中有我们在编译过程中所需library的所有address。
"deploy": {
"VM:-": {
"linkReferences": {
"browser/.learneth/Deploy with Libraries/2_Generate_Metadata/2_contractSimpleLibrary.sol": {
"aLib": "<address>"
}
},
"autoDeployLib": true
},
"main:1": {
"linkReferences": {
"browser/.learneth/Deploy with Libraries/2_Generate_Metadata/2_contractSimpleLibrary.sol": {
"aLib": "<address>"
}
},
"autoDeployLib": true
},
关键词<address>包含的是已经部署过的library的address,对于每个网络需要进行具体说明。
autoDeployLib是一个bool量,代表remix在进行部署前是否要自动部署这个lib。
一般来说,autoDeploy是true,<address>不会被调用到,remix会进行自动部署。
但是为了更好的模仿现实情况,我们在这里将通过手动链接已经在网络上部署过的VM Lib。
首先,我们将VM的autoDeply设置为false。
手动连接library并部署
如果这个时候我们直接切换到deploy选择simplecontract进行部署,会出现如下错误:
那么首先,我们要先进行VM的部署,在deploy界面上更改contract,有个libA,进行部署。
部署后下面会有一个复制address的按钮,点击就可以复制已经部署好的library地址。
然后复制粘帖到之前我们找到的那个json文件当中。
"VM:-": {
"linkReferences": {
"browser/.learneth/Deploy with Libraries/2_Generate_Metadata/2_contractSimpleLibrary.sol": {
"aLib": "0xf8e81D47203A594245E36C48e151709F0C19fBe8"
}
},
"autoDeployLib": false
},
再次跳回之前的deploy界面,选择simplecontract进行部署,部署即可成功。
查看部署信息
在编译后我们可以查看它的bytecode,在下面有一行小字可以复制到clipboard,贴出来大概是这样:
{
"linkReferences": {
"browser/contractSimpleLibrary.sol": {
"LibraryForTest": [
{
"length": 20,
"start": 109
}
]
}
},
"object": "608060405234801561001057600080fd5b50610101806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80636d4ce63c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b600073__$92b7644c0d8dcc07d172959bb8f25dc6be$__6387cc10e16040518163ffffffff1660e01b815260040160206040518083038186803b158015608e57600080fd5b505af415801560a1573d6000803e3d6000fd5b505050506040513d602081101560b657600080fd5b810190808051906020019092919050505090509056fea265627a7a72315820cc244a6979e5f20d4286dc7691fb21c2e6c9a88c694caea792eb02614a93ad0a64736f6c63430005110032",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO ... ",
"sourceMap": "34:107:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34:107:0;;;;;;;"
}
这个东西看起来可能有些复杂,前面的linkReference内的内容代表被调用库的信息。后面的object(bytecode)代表这个合约将被存在区块链上的字节流,也就是说整个合约能在区块链上查到的就是这一串数字。
在bytecode当中有一段__$92b7644c0d8dcc07d172959bb8f25dc6be __代表的是指向被调用library地址的占位符(placeholder)。
opcodes是区块链实现操作的语言,用于进行交易和转移,被脚本引擎Script所调用。sourcemap是用于调试的源码映射(这个我也不太懂什么意思)。
结语
对于library的部署和调用是智能合约使用当中很基础的一部分,但是从尝试当中也能发现并不是一件简单的事情。由于要将合约放到一个全世界都可以调用的地方,势必要进行压缩和删减。
将部署和调用分开也是为了更好地使用contract和library这两个功能不同的关键字。从架构设计上来说,还有很多值得学习和研究的地方。
参考资料:https://blog.csdn.net/weixin_40959706/article/details/90719518
网友评论