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

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

内容简介:孔乙己懂“回”字的四种写法,你会智能合约的四种调用方式吗?在中大型的项目中,我们不可能在一个智能合约中实现所有的功能,而且这样也不利于分工合作。一般情况下,我们会把代码按功能划分到不同的库或者合约中,然后提供接口互相调用。在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,你分得清吗?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Out of their Minds

Out of their Minds

Dennis Shasha、Cathy Lazere / Springer / 1998-07-02 / USD 16.00

This best-selling book is now available in an inexpensive softcover format. Imagine living during the Renaissance and being able to interview that eras greatest scientists about their inspirations, di......一起来看看 《Out of their Minds》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具