Call,CallCode,DelegateCall,StaticCall,你分得清吗?

栏目: C · 发布时间: 5年前

内容简介:孔乙己懂“回”字的四种写法,你会智能合约的四种调用方式吗?在中大型的项目中,我们不可能在一个智能合约中实现所有的功能,而且这样也不利于分工合作。一般情况下,我们会把代码按功能划分到不同的库或者合约中,然后提供接口互相调用。在Solidity中,如果只是为了代码复用,我们会把公共代码抽出来,部署到一个library中,后面就可以像调用C库、Java库一样使用了。但是library中不允许定义任何storage类型的变量,这就意味着library不能修改合约的状态。如果需要修改合约状态,我们需要部署一个新的合

孔乙己懂“回”字的四种写法,你会智能合约的四种调用方式吗?

在中大型的项目中,我们不可能在一个智能合约中实现所有的功能,而且这样也不利于分工合作。一般情况下,我们会把代码按功能划分到不同的库或者合约中,然后提供接口互相调用。

在Solidity中,如果只是为了代码复用,我们会把公共代码抽出来,部署到一个library中,后面就可以像调用C库、 Java 库一样使用了。但是library中不允许定义任何storage类型的变量,这就意味着library不能修改合约的状态。如果需要修改合约状态,我们需要部署一个新的合约,这就涉及到合约调用合约的情况。

合约调用合约有下面4种方式:

  • CALL
  • CALLCODE
  • DELEGATECALL
  • STATICCALL

1.CALL vs. CALLCODE

CALL和CALLCODE的区别在于:代码执行的上下文环境不同。

具体来说,CALL修改的是 被调用者 的storage,而CALLCODE修改的是 调用者 的storage。

Call,CallCode,DelegateCall,StaticCall,你分得清吗?

我们写个合约验证一下我们的理解:

pragma solidity ^0.4.25;

contract A {
    int public x;
    
    function inc_call(address _contractAddress) public {
        _contractAddress.call(bytes4(keccak256("inc()")));
    }
    function inc_callcode(address _contractAddress) public {
        _contractAddress.callcode(bytes4(keccak256("inc()")));
    }
}

contract B {
    int public x;
    
    function inc() public {
        x++;
    }
}

我们先调用一下inc_call(),然后查询合约A和B中x的值有什么变化:

Call,CallCode,DelegateCall,StaticCall,你分得清吗?

可以发现,合约B中的x被修改了,而合约A中的x还等于0。

我们再调用一下inc_callcode()试试:

Call,CallCode,DelegateCall,StaticCall,你分得清吗?

可以发现,这次修改的是合约A中x,合约B中的x保持不变。

2.CALLCODE vs. DELEGATECALL

实际上,可以认为DELEGATECALL是CALLCODE的一个bugfix版本,官方已经不建议使用CALLCODE了。

CALLCODE和DELEGATECALL的区别在于: msg.sender不同

具体来说,DELEGATECALL会一直使用原始调用者的地址,而CALLCODE不会。

Call,CallCode,DelegateCall,StaticCall,你分得清吗?

我们还是写一段代码来验证我们的理解:

pragma solidity ^0.4.25;

contract A {
    int public x;
    
    function inc_callcode(address _contractAddress) public {
        _contractAddress.callcode(bytes4(keccak256("inc()")));
    }
    function inc_delegatecall(address _contractAddress) public {
        _contractAddress.delegatecall(bytes4(keccak256("inc()")));
    }
}

contract B {
    int public x;
    
    event senderAddr(address);
    function inc() public {
        x++;
        emit senderAddr(msg.sender);
    }
}

我们首先调用一下inc_callcode(),观察一下log输出:

Call,CallCode,DelegateCall,StaticCall,你分得清吗?

可以发现,msg.sender指向合约A的地址,而非交易发起者的地址。

我们再调用一下inc_delegatecall(),观察一下log输出:

Call,CallCode,DelegateCall,StaticCall,你分得清吗?

可以发现,msg.sender指向的是交易的发起者。

3.STATICCALL

STATICCALL放在这里似乎有滥竽充数之嫌,因为目前Solidity中并没有一个low level API可以直接调用它,仅仅是计划将来在编译器层面把调用view和pure类型的函数编译成STATICCALL指令。

view类型的函数表明其不能修改状态变量,而pure类型的函数则更加严格,连读取状态变量都不允许。

目前是在编译阶段来检查这一点的,如果不符合规定则会出现编译错误。如果将来换成STATICCALL指令,就可以完全在运行时阶段来保证这一点了,你可能会看到一个执行失败的交易。

话不多说,我们就先看看STATICCALL的实现代码吧:

Call,CallCode,DelegateCall,StaticCall,你分得清吗?

可以看到,解释器增加了一个readOnly属性,STATICCALL会把该属性置为true,如果出现状态变量的写操作,则会返回一个errWriteProtection错误。

就聊到这里,相信大家已经掌握了合约的四种调用方式了吧~

更多文章欢迎关注“鑫鑫点灯”专栏: https://blog.csdn.net/turkeycock

或关注飞久微信公众号:
Call,CallCode,DelegateCall,StaticCall,你分得清吗?

以上所述就是小编给大家介绍的《Call,CallCode,DelegateCall,StaticCall,你分得清吗?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

理解专业程序员

理解专业程序员

(美)杰拉尔德·温伯格(GeraldM.Weinberg) / 刘天北 / 清华大学出版社 / 2006-7 / 25.00元

《理解专业程序员》通过行内专家的独特视角,介绍了如何成为优秀程序员,如何提高工作绩效等问题。全书由多篇讨论程序员职业的短文组成,内容精彩绝伦,是一部任何在这个变化急剧的领域工作的人都不可错过的重要作品。本书论述生动翔实——你肯定能从中认出你自己和你的公司的故事——因此不仅极富教益,而且读来也引人入胜。 各篇主题包括:对于专业程序员重要的若干问题,成为专业程序员的途径,在企业官僚体......一起来看看 《理解专业程序员》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换