建议和反馈

请填写你的反馈内容

智能合约语言 Solidity 教程系列2 - 地址类型介绍

2020-03-24 ·1158次阅读 ·读完需要9分钟

Solidity 教程系列第二篇 - Solidity 地址类型介绍。
Solidity 系列完整的文章列表请查看分类-Solidity

写在前面

Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解,如果你还不了解,建议你先看以太坊是什么

本文前半部分是参考 Solidity 官方文档(当前最新版本:0.4.20)进行翻译,后半部分是结合实际合约代码实例说明类型的使用(仅针对专栏订阅用户)。

地址类型(Address)

地址类型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) 的使用。

  • 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 Literals)

一个能通过地址合法性检查(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

参考文档

Solidity 官方文档-类型

深入浅出区块链 - 打造高质量区块链技术博客,学区块链都来这里,关注知乎微博 掌握区块链技术动态。
我的**知识星球**为各位解答区块链技术问题,欢迎加入讨论。

类型介绍篇一样,打开Remix - Solidity IDE,帖入代码,依次创建合约 AddrTest 及 CallTest,如图:

创建合约后,可以看到,AddrTest 合约内没有命令的函数,显示 fallback。

AddrTest 合约主要是用来说明转入以太币及调用函数式回退函数的调用情况,CallTest 合约是作为 AddrTest 合约的调用者。
CallTest 合约的函数说明:

  • transferEther(address towho): 用来给指定合约地址转账(如果一个函数需要进行货币操作,必须要带上 payable 关键字),转账时填入 AddrTest 的地址(加双引号)作为参数

  • deposit(): 函数上增加 payable 标识,可接收 ether,并会把 ether 存在当前合约,(transferEther 转账前需要先存款)。

  • callfunc() : 调用函数,使用指定的是函数签名。

  • callNoFunc(): 调用不存在的函数,这时被调用的合约的 fallback 函数会执行。

关于 fallback 函数用法可进一步参考这一篇:[Ethereum-Development-Best-Practices][1]及问答
下面截图演示下,存款和转账,其他的调用请读者动手练习。
存款操作如图:

完成后,可以在左下角区域查看日志 Details->value。
然后进行转账,如图:

完成后,可以在左下角区域查看日志 Details->logs 数据,可以看到 fallback 函数被调用。
还可以调用 AddrTest 的 getBalance 查看余额数据。


评论(0)问答(0)
请先登录或注册

请先登陆或注册

相关推荐

火热报名中 | 百度超级链联合BSN重磅启动区块链开发者大赛

#百度超级链&BSN开发者大赛火热报名中#从理想到现实,你和极客世界只差一个智能合约~快来pick XuperChain,开启万元大奖直通车吧! 活动报名地址:https://xch......
百度超级链 · 2020-04-07
5阅读 · 0赞赏 · 0问答

比特币交易原理分析

1.比特币的UTXO模型首先,在讲比特币交易过程之前要说明一个事情。比特币系统是没有余额的概念的,它使用的是UTXO模型(Unspent Transaction Outputs,未使用过的交易输出),......
花落 · 2020-04-07
535阅读 · 0赞赏 · 0问答

极速赛车高手计划364790稳赚群

极速赛车高手计划364790稳赚群......
GavinIsabella · 2020-04-05
77阅读 · 0赞赏 · 0问答

极速赛车人工计划群364790

极速赛车人工计划群364790......
GavinIsabella · 2020-04-05
71阅读 · 0赞赏 · 0问答

Serpent 指南

有关Serpent 1.0的信息请查阅以前的文档Serpent是一种用来编写以太坊合约(Ethereum Contract)的高级编程语言。Serpent翻译成中文意思是”大蛇”,如这个名字所示,这是......
gomez · 2020-04-03
320阅读 · 0赞赏 · 0问答

分析区块链链下扩容:状态通道、TrueBit、Plasma

我们正处于区块链 2.0 转化的时代,目标是大规模的商用。传统的区块链技术,如比特币和以太坊,在性能上面已经显得力不从心,本文就来聊一聊区块链链下扩容技术。比特币和以太坊有多快?作为史上最慢的分布式数......
区块链开发 · 2020-04-01
390阅读 · 0赞赏 · 0问答

Cristante

3340

LK币

37

粉丝

41

笔记

感谢"Cristante"

这篇精彩的笔记,目前已经帮助

  • 0
  • 1
  • 1
  • 5
  • 8
喜欢0
链客社群 加入

微博进入

商务合作>

广告投放>

公司名称:北京链客行科技有限公司

联系方式:010-67707199

ICP备案号:京ICP备18032136号

Copyright:链客区块链技术问答社区 版权所有

感谢您的提问,问题被社区永久收入以便新人查看。一定要记得采纳最佳答案哦!加油!

感谢您的善举,每一次解答会成为新人的灯塔,回答被采纳后获得20算力和相应的LK币奖励

您将赞赏给对方2LK币的奖励哦!感谢您的赞赏!

您将赞赏给对方2LK币的奖励哦!感谢您的赞赏!