美文网首页区块链技术与金融白话区块链区块链研习社
【Solidity智能合约系列】02--地址类型

【Solidity智能合约系列】02--地址类型

作者: 唠嗑008 | 来源:发表于2018-05-25 16:15 被阅读20次

    address是以太坊智能合约开发中一种非常重要的类型,它表示的是一个账户地址,在交易中是经常用到的,因为这是一个重要且特殊的类型,所以单独用一个小节来讲解。

    参考
    https://solidity.readthedocs.io/en/develop/types.html
    https://blog.csdn.net/liyuechun520/article/details/78410670

    地址类型(Address)

    address:由20个字节组成(一个以太坊地址的长度),地址类型也有成员,并且是所有合约的基础。

    相关运算符:

    • <=, <, >= , >,==, !=

    注意:
    从0.5.0开始,合约不再继承自地址类型,但仍然可以显式转换为地址。

    地址类型的成员

    • balance and transfer

    通过这个快速索引,可以查看地址类型相关成员。

    可以用balance属性来查询账户余额,用transfer()来向一个地址发送以太币(以wei为单位):

    address x = 0x123;
    address myAddress = this;
    if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);
    

    注意:
    如果x是合约地址,合约的fallback 函数会随transfer调用一起执行(这个是EVM的特性,并且不可阻止),如果合约执行过程中因gas耗光或其他原因失败,转移交易会回滚并且合约会抛异常停止。

    • send()函数

    send ()与transfer()功能类似,但更底层。如果执行失败,transfer()不会因异常停止,而send()会返回false。

    警告:send() 执行有一些风险:如果调用栈的深度超过1024或者接收者的gas耗光,交易都会失败。因此,为了保证以太坊上的交易安全,必须检查send的返回值,如果交易失败,会回退以太币。如果用transfer会更好。

    call(), callcode() 和 delegatecall() 函数

    为了和非ABI协议的合约进行交互,可以使用call() 函数, 它用来向另一个合约发送原始数据,call()可以接收任何类型任意数量的参数,每个参数会按规则(ABI协议)打包成32字节并一一拼接到一起。一个例外是:如果第一个参数恰好4个字节,在这种情况下,会被认为根据ABI协议定义的函数器指定的函数签名而直接使用。如果仅想发送消息体,需要避免第一个参数是4个字节。

    关于ABI协议的详细说明

    address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;
    nameReg.call("register", "MyName");
    nameReg.call(bytes4(keccak256("fun(uint256)")), a);
    

    call()返回一个bool值,以表明执行成功与否。成功的话返回true,发生EVM异常返回false。调用call()无法获取到结果数据(因为需要提前知道返回的数据的编码和数据大小)。

    可以使用.gas()修饰器来调整供应的gas:

    namReg.call.gas(1000000)("register", "MyName");
    

    类似还可以提供附带以太币:

    nameReg.call.value(1 ether)("register", "MyName");
    

    修饰器可以混合使用,调用顺序不重要。

    nameReg.call.gas(1000000).value(1 ether)("register", "MyName");
    

    注意:
    在重载函数上不能使用gasvalue修饰符,

    同样,我们也可以使用delegatecall()方法,它与call()方法的区别在于,仅仅是代码会执行,而其它方面,如(存储,余额等)都是用的当前的合约的数据。delegatecall()方法的目的是用来执行库代码,这个库代码存储在另一个合约中。所以开发者需要保证两个合约中的存储变量能兼容,来保证delegatecall()能顺利执行。在homestead阶段之前,仅有一个受限制的callcode()方法可用,但callcode是无法访问msg.sendermsg.value的值。

    上面的这三个方法call()delegatecall()callcode()都是底层的消息传递调用,最好仅在万不得已才进行使用,因为他们破坏了Solidity的类型安全。

    .gas()在3个方法中都可以使用,但是.value()只能在call()callcode()使用,而不支持delegatecall()

    注意:
    1、所有合约都继承了address类型,因此可以在当前合约中使用address(this).balance查询余额。
    2、callcode不鼓励使用,以后会移除。

    警告:
    上述的函数都是底层的函数,使用时要非常小心。当调用一个未知的时候,可能是恶意的合约,当你把控制权交给它,它可能回调回你的合约,所以要准备好在调用返回时,应对你的状态变量可能被恶意篡改的情况。

    地址常量(Address Literals)

    一个能通过地址合法性检查(address checksum test)十六进制常量就会被认为是地址,例如0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF就是一个地址类型,而不能通过地址合法性检查的39~41位长的十六进制常量,会提示一个警告,被视为普通的有理数常量。

    注意:
    可以通过EIP-55检查地址合法性。

    相关文章

      网友评论

        本文标题:【Solidity智能合约系列】02--地址类型

        本文链接:https://www.haomeiwen.com/subject/hhojjftx.html