本文首发于深刻浅出区块链社区 原文连接:智能合约语言 Solidity 教程系列2 - 地址类型介绍原文已更新,请读者前往原文阅读html
Solidity教程系列第二篇 - Solidity地址类型介绍. Solidity 系列完整的文章列表请查看分类-Solidity。git
Solidity是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解,若是你还不了解,建议你先看以太坊是什么github
本文前半部分是参考Solidity官方文档(当前最新版本:0.4.20)进行翻译,后半部分是结合实际合约代码实例说明类型的使用(仅针对专栏订阅用户)。编程
地址类型address是一个值类型,安全
地址: 20字节(一个以太坊地址的长度),地址类型也有成员,地址是全部合约的基础 支持的运算符:编程语言
注意:从0.5.0开始,合约再也不继承自地址类型,但仍然能够显式转换为地址。函数
balance 属性及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耗光或其余缘由失败,转移交易会还原而且合约会抛异常中止。区块链
关于回退函数(fallback 函数),简单来讲它是合约中无函数名函数,下面代码事例中,进进一步讲解回退函数(fallback) 的使用。ui
send() 函数 send 与transfer对应,但更底层。若是执行失败,transfer不会因异常中止,而send会返回false。
警告:send() 执行有一些风险:若是调用栈的深度超过1024或gas耗光,交易都会失败。所以,为了保证安全,必须检查send的返回值,若是交易失败,会回退以太币。若是用transfer会更好。
call(), callcode() 和 delegatecall() 函数 为了和非ABI协议的合约进行交互,可使用call() 函数, 它用来向另外一个合约发送原始数据,支持任何类型任意数量的参数,每一个参数会按规则(ABI协议)打包成32字节并一一拼接到一块儿。一个例外是:若是第一个参数刚好4个字节,在这种状况下,会被认为根据ABI协议定义的函数器指定的函数签名而直接使用。若是仅想发送消息体,须要避免第一个参数是4个字节。以下面的例子:
address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2; nameReg.call("register", "MyName"); nameReg.call(bytes4(keccak256("fun(uint256)")), a);
call函数返回一个bool值,以代表执行成功与否。正常结束返回true,异常终止返回false。但没法获取到结果数据,由于须要提早知道返回的数据的编码和数据大小(因不知道对方使用的协议格式,因此也不会知道返回的结果如何解析)。 还能够提供**.gas()**修饰器进行调用:
namReg.call.gas(1000000)("register", "MyName");
相似还能够提供附带以太币:
nameReg.call.value(1 ether)("register", "MyName");
修饰器能够混合使用,修饰器调用顺序无所谓。
nameReg.call.gas(1000000).value(1 ether)("register", "MyName");
注解:目前还不能在重载函数上使用gas或value修饰符,A workaround is to introduce a special case for gas and value and just re-check whether they are present at the point of overload resolution.(这句我怕翻译的不许确,引用原文)
一样咱们也可使用delegatecall(),它与call方法的区别在于,仅仅是代码会执行,而其它方面,如(存储,余额等)都是用的当前的合约的数据。delegatecall()方法的目的是用来执行另外一个合约中的库代码。因此开发者须要保证两个合约中的存储变量能兼容,来保证delegatecall()能顺利执行。在homestead阶段以前,仅有一个受限的callcode()方法可用,但callcode未提供对msg.sender,msg.value的访问权限。
上面的这三个方法call(),delegatecall(),callcode()都是底层的消息传递调用,最好仅在万不得已才进行使用,由于他们破坏了Solidity的类型安全。 .gas() 在call(), callcode() 和 delegatecall() 函数下均可以使用, delegatecall()不支持.value()
注解:全部合约都继承了address的成员,所以可使用this.balance查询余额。 callcode不鼓励使用,之后会移除。
警告:上述的函数都是底层的函数,使用时要异常当心。当调用一个未知的,多是恶意的合约时,当你把控制权交给它,它可能回调回你的合约,因此要准备好在调用返回时,应对你的状态变量可能被恶意篡改的状况。
一个能经过地址合法性检查(address checksum test)十六进制常量就会被认为是地址,如0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF。而不能经过地址合法性检查的39到41位长的十六进制常量,会提示一个警告,被视为普通的有理数常量。
地址合法性检查定义在EIP-55
pragma solidity ^0.4.0; contract AddrTest{ event logdata(bytes data); function() payable { logdata(msg.data); } function getBalance() returns (uint) { return this.balance; } uint score = 0; function setScore(uint s) public { score = s; } function getScore() returns ( uint){ return score; } } contract CallTest{ function deposit() payable { } event logSendEvent(address to, uint value); function transferEther(address towho) payable { towho.transfer(10); logSendEvent(towho, 10); } function callNoFunc(address addr) returns (bool){ return addr.call("tinyxiong", 1234); } function callfunc(address addr) returns (bool){ bytes4 methodId = bytes4(keccak256("setScore(uint256)")); return addr.call(methodId, 100); } function getBalance() returns (uint) { return this.balance; } }
代码运行及讲解,请订阅区块链技术查看。
咱们也推出了目前市面上最全的视频教程:深刻详解以太坊智能合约语言Solidity 目前咱们也在招募课程体验师,能够点击连接了解。
☛ 深刻浅出区块链 - 系统学习区块链,打造最好的区块链技术博客。
☛ 个人知识星球为各位解答区块链技术问题,欢迎加入讨论。
☛ 关注公众号“深刻浅出区块链技术”第一时间获取区块链技术信息。