【以太坊】深入理解智能合约(合约调合约)
一、前言      关于智能合约的描述,大家在网上百度能查到一大堆。看来看去也能看个似懂非懂,但是稍微具体点呢,智能合约到底都能干什么,可以转账提现吗?可以合约调用合约吗?可以发布多个合约吗?关于
一、前言
关于智能合约的描述,大家在网上百度能查到一大堆。看来看去也能看个似懂非懂,但是稍微具体点呢,智能合约到底都能干什么,可以转账提现吗?可以合约调用合约吗?可以发布多个合约吗?
关于智能合约的疑问真的很多,只能一边开发一边总结了。以下是我最近关于智能合约的一些新理解。
二、深入理解智能合约
1、一条链上可以发布多个智能合约。
这些智能合约不是相互覆盖的关系,而是可以并存的关系。
但是在发代币和保存数据方面,最好只能有一个合约来声明。因为如果有两个合约都有发代币的内容的话,那么部署第二个发代币合约之后,会新发一个币种,造成数据混乱等问题。
这部分,博主刚开始一直以为一条链上只能有一个智能合约,后来开发中才意识到,原来可以发布多个合约。只要我们保持发币和数据保存部分只有一份就好,其他的逻辑方面的合约可以随便发。
2、智能合约也是个账户
智能合约也是个账户,没有私钥,但是可以收到别人打过来的代币,作为中转账户使用
收款:外部给智能合约转账为了接收Ether,(fallback)回退函数必须标记为payable。
如果没有这样的函数,合约不能通过常规transactions接收Ether。
这部分,博主这边的需求是智能合约接收用户发送的以太币,并且转换成其他币种返回给用户。刚开始根本没想到,智能合约能作为中转账号。很神奇。
3、智能合约提现:(前提必须是合约的操作者)
因为智能合约没有私钥,所以不能像普通账户一样的转账操作。但是在智能合约中,如果操作者是合约发布者的话,可以通过内置的transfer方法来进行转账提现:
//这里的address指的是你要提现的账户地址
//value代表了你要提现的金额
address.transfer(value);
提现部分,刚开始连想都不敢想。没有私钥也能提现转账?transfer前面的地址可以任意变换吗?但是实际操作测试发现,是的,一切都可以实现。
4、智能合约的fallback方法
2300gas限制;http://me.tryblockchain.org/blockchain-solidity-fallback.html
通过这个方法,我们知道了,只有通过this.send(1);这种方式的fallback才是会受到限制的
关于send()和call)的区别;https://ethfans.org/topics/419
为什么会说道fallback()呢,因为我们接收以太币的函数必须是fallback()函数:
//要接收以太币,合约里面必须要有payable关键字
//当我们使用address.send(ether to send)向某个合约直接转帐时,由于这个行为没有发送任何数据,所以接收合约总是会调用fallback函数
function () external payable {
require(msg.sender != address(0));
require(msg.value != 0);
xxxxxxxxxxx
}
但是我们根据上面我给的链接可以看到,fallback()函数为了防止外部攻击和合约漏洞,规定了此函数只能消耗2300gas。超过2300gas函数就会执行失败。我们都知道,随便一个转账都要消耗2w+的gas,这2300个gas怎么可能会够呢。
后面我们在查询资料时候才发现,fallback()函数仅对使用send()方式的有2300gas的限制,对使用call()方式或者其他的操作没有这样的限制。好家伙,原来fallback()也没有想象中那么恐怖。
5、智能合约调用另一个智能合约(重要!!!)
这部分才是遇到的重中之重,刚开始以为只是简单的传入地址就可以调用,但是在实际测试中
,并没有那么简单。
(1)如果两个合约写在一起
https://ethfans.org/topics/653 :直接通过传入地址调用
大家可以参考这两个地址,想必会有个答案。
(2)两个合约不在一起
就像我们平时发布需求,不可能一次都不修改合约的内容。但是合约本身的定义就是不可篡改的,那么我们只有通过多发布几个合约来实现我们的需求了。
下面是示例代码:加入我们要在A合约中调用B合约的test方法
//先引入接口,interface就是个外部合约,你给了地址才能调他的方法。接口的名字是随意的
interface test{
//这里面的方法一定要是我们调用的B合约中的test方法,参数什么的也都保持一致。
//因为是interface,所以函数必须声明为external
function test(address _to, uint256 _value) external returns (bool);
}
//引入接口之后,开始引入我们的A合约
contract xxxxx is Pausable{
using SafeMath for uint256;
uint256 public weiRaised;
//因为solidity是静态语言,所以在我们需要使用某个变量的时候,必须要先声明一下
test test;
function () external payable {
xxxx
//这里使用实例化过的B合约,直接调用它的test方法
require(token.test(msg.xxx, xxx));
xxxxx
}
constructor(address xxx, uint256 xxx, address xx) public {
//此处的_token是B合约的地址
token = test(_token);
}
}
大致步骤:
1、引入接口,接口中写入B合约的方法以及参数。
2、在A合约中申明一个静态变量,实例化B合约之后使用
3、在A合约的构造函数中实例化B合约(传入B合约的地址)
4、在A合约中直接调用B合约中的test方法
interface就是个外部合约,你给了地址才能调他的方法。这里的接口通过传入地址调用。接口中的实现类要和传入地址合约的实现类完全相同。这样在传入地址之后,就能直接调用传入地址合约中的方法。
关于为什么要通过interface方式调用合约,大家可以参考:
通过solidity的接口实现:
https://my.oschina.net/u/2601303/blog/1550469
https://zhuanlan.zhihu.com/p/34017392
三、智能合约消耗gas计算
1、估算智能合约消耗的gas部分:
通过以下网址即可:http://remix.ethereum.org remix
(1)把自己的合约拷贝进去
(2)右边的compile栏目下–》detail按钮左边有个下拉框,选择自己的合约–》点击detail查询
-》搜索GASESTIMATES,然后会看到一个数组。上面的是部署合约和执行合约消耗的gas,下面的是具体方法消耗的gas数量
2、关于合约方法消耗gas多少的问题
(1)一般来讲,当我们操作区块链进行读或者写的时候,都会消耗一定量的gas
(2)调用方法时候消耗的gas对比:https://bitshuo.com/topic/587e03c44dea36e72c1b381b
以上就是这段时间对于智能合约的新理解了。果然是纸上得来终觉浅,还是自己实践起来理解的最快。这里是我平时开发记录的笔记,可能总结的不够全面,大家可以通过给出的链接来学习(PS:有些链接需要翻墙的)。个人认为,智能合约之间的相互调用最值得学习,这部分网上的资料太少了。
加油!
end
更多推荐
所有评论(0)