版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
以太坊Solidity智能合约开发教程
Solidity编程基础学前提示Solidity是比较小众的开发语言,它并不像Java、Python和C#等主流开发语言那样“无所不能”。但是在区块链应用开发领域中,Solidity语言又是很知名的智能合约开发语言,因为它依托著名的以太坊平台,可以说是区块链2.0的代表语言。本章介绍Solidity语言的基础知识。知识要点3.1Solidity的第一个示例程序3.2常量和变量3.3基本数据类型3.4复合数据类型3.1Solidity的第一个示例程序3.1.1实时在线Solidity编辑器Remix3.1.2SolidityHelloworld程序3.1.3使用VisualStudioCode开发Solidity程序3.1.1实时在线Solidity编辑器Remix以太坊提供了一个实时在线的Solidity编辑器:Remix。无需安装和配置任何软件,即可完成以太坊智能合约的在线开发、在线编译、在线测试、在线部署。RemixIDE中文版的网址如下:RemixIDE中文版页面RemixIDE页面分为文件管理器、文件编辑器和开发工具面板3个区域。页面最左侧是文件管理器,其中可以列出了浏览器本地存储的文件。默认情况下,在“文件管理器”中有下面2个文件夹。·browser文件夹:保存智能合约文件;·config文件夹:保存配置文件。
browser文件夹下的默认智能合约
首次访问RemixIDE页面,可以看到在browser文件夹下有2个默认的智能合约文件,即ballot.sol和ballot_test.sol。这是一个关于投票的智能合约示例,以及对该智能合约的测试程序文件管理器中的操作按钮操作按钮说
明创建新文件上传本地文件将browser文件夹下的文件发布到GithubGist.Github是应用广泛的代码分享平台,Gist是Github提供的很实用的功能,使用Gist可以分享代码片段第2个
更新当前的Gist拷贝所有文件到另一个RemixIDE实例连接到本地主机,从而在Remix中访问本地文件系统3.1.2SolidityHelloworld程序1.创建新的Solidity文件2.调整编辑窗口的大小3.编译智能合约1.创建新的Solidity文件
在Remix页面的文件管理器中点击按钮,弹出输入文件名的对话框在Remix中新建文件hello.so【例3-1】pragmasolidity^0.5.1;//声明合约contractDemo{functionhello()publicpurereturns(stringmemory){return"helloworld!";}}pragmasolidity指定程序所使用的Solidity版本,本实例中为0.5.1。^指定版本号向上兼容,本实例的代码在0.5.1~0.6.0(不包含0.6.0)的编译器中都可以编译。在页面右侧的开发工具面板区域中可以选择使用的编译器。在笔者编写本书时,默认的版本为0.5.1+commit.c8a2cb62.Emscripten.clang。在“编译”选项卡中可以选择其他的编译器//指定注释语句。注释是对代码的解释和说明,其目的是增加代码的可读性,让人们能够更加轻松地了解代码。在编译程序的时候,系统不会理会注释语句。contract定义一个智能合约,本实例的智能合约名为Demo。在Solidity语言中,智能合约就类似Java语言中的类,在其中可以定义变量和函数。function定义一个函数。函数是一段代码,需要指定定义函数名、参数和返回值。本实例中定义了一个Demo()函数,函数返回一个字符串helloworld!"。2.调整编辑窗口的大小编辑窗口是编辑代码的区域,它位于页面中心。在编辑窗口的下部是控制台面板,在控制台中可以看到程序运行和调试的情况。将鼠标移至编辑窗口的边缘,可以拖动边框,调整编辑窗口的大小。
在编辑窗口的上面的左侧和右侧各有一个和按钮,分别用于收起和展开左侧或右侧的面板。在编辑窗口的下面也有一个按钮,可以切换控制台面板的显示和隐藏。如果把其他面板都隐藏起来,编辑窗口区域自然也就大了。3.编译智能合约在开发工具面板区域的顶部,有一组选项卡。第一个选项卡就是“编译”。编译是计算机科学中的一个术语,指使用编译程序(也称为编译器,通常由程序的开发商提供)将编程语言编写的源程序经过处理生成目标程序的过程。通俗的说,就是将人能理解的源代码转换得到计算机能够理解的程序。从而为执行程序做好准备。“编译”选项卡Remix的错误提示具体错误提示browser/hello.sol:4:5:SyntaxError:Novisibilityspecified.Didyouintendtoadd"public"?functionhello()purereturns(stringmemory){^(Relevantsourcepartstartshereandspansacrossmultiplelines).3.1.3使用VisualStudioCode开发Solidity程序1.下载和安装VisualStudioCode/download2.安装solidity插件单击左侧导航条中的Extensions图标3.在VisualStudioCode中编辑Solidity程序安装solidity插件后需要重启VisualStudioCode。然后在系统菜单中依次选择File/NewFile,可以新建一个文件,将新文件保存为test.sol,说明这是一个Solidity程序文件。在编辑窗口中输入字符,会触发自动提示的功能。例如,输入pra,会弹出如图3-9所示的提示,选择第一项提示内容,会在编辑窗口中自动完成如下的代码:pragmasolidityversion;输入pra的自动提示:4.在VisualStudioCode中借助solc编译器对Solidity程序进行编译在VisualStudioCode中依次选择File/Preferences/settings打开Settings页面。在搜索框里填写solidity,可以定位与Solidity相关的配置信息。找到Solidity:CompileUsingRemoteVersion,也就是使用远程的solc编译器对程序进行编译。配置Solidity程序的编译器编译test.sol的过程编译过程包含如下信息·使用远程版本v0.5.1+commit.c8a2cb62进行编译;·Solidity的具体版本为0.5.1+commit.c8a2cb62.Emscripten.clang。·在test.sol的第4行第19列处有一个错误,具体为需要指定参数的类型。这里使用的是自动生成的type。单击PROBLEMS标签,查看问题的具体描述在编辑窗口中以波浪线的形式标识问题代码3.2常量和变量3.2.1常量3.2.2变量3.2.1常量常量是内存中用于保存固定值的单元,在程序中常量的值不能发生改变。Solidity常量的数据类型可以是值类型和字符串。可以使用constant关键字定义一个常量,例如:
intconstantx=10;为常量赋值会报错x=20;具体的报错信息如下:browser/constant.sol:8:9:TypeError:Cannotassigntoaconstantvariable.不允许给常量赋值【例3-2】pragmasolidity^0.5.1;//声明合约contractDemo{stringconstanthellostring="helloworld!";functionhello()publicpurereturns(stringmemory){returnhellostring;}}3.2.2变量变量是内存中命名的存储位置,与常量不同的是变量的值可以动态变化。Solidity的标识符命名规则·标识符名字的第1个字符必须是字母或下划线(_);·标识符名字的第1个字符后面可以由字母、下划线(_)或数字(0~9)组成;·标识符名字是区分大小写的。也就是说Score和score是不同的。1.定义变量数据类型变量名;例如,下面的代码声明了一个字符串变量name和整型变量age:stringname;intage;可以将常量赋值到一个变量中。也可以将变量赋值给另外一个变量,例如:stringa;stringb;a="这是一个变量";b=a;a="这是另一个变量";变量赋值后修改变量a的值不会影响到变量b。2.状态变量状态变量是在智能合约体中定义的变量,状态变量在智能合约中全局有效,因此又可以称为全局变量。在函数体中定义的变量只在函数范围内有效,又称为局部变量。例如pragmasolidity^0.5.1;contractDemo{uintstoredData;//…….3.变量的修饰符修饰符可以分为可见性修饰符和存储位置修饰符两种。可见性修饰符用于定义变量在不同的智能合约间的访问权限,具体情况将在第5章结合智能合约编程介绍。存储位置修饰符用于指定变量的存储位置。
storage:指定变量永久地存储在区块中。向storage变量中写入数据是要被扣除手续费(Gas)的。在一个智能合约的不同函数中可以共享访问storage变量。
memory:指定变量存储在内存中。
calldata:指定变量为只读的,通常只有在外部函数中的参数才被强制指定为calldata。calldata变量不会被持久化到区块上。存储位置修饰符的使用方法数据类型可见性修饰符存储位置修饰符变量名例如,下面的代码定义一个storage变量name。
stringpublicstoragename;默认的存储位置修饰符变量的用法默认存储位置修饰符函数的返回值memory函数内部的局部变量memory函数的参数memory全局变量/状态变量storage外部函数的参数calldata4.系统全局变量全局变量名具体描述blockhash(uintblockNumber)返回给定区块的哈希值block.coinbase(addresspayable)当前区块矿工的地址block.difficulty当前区块的难度block.gaslimit当前区块的Gas上限block.number当前区块的区块号block.timestamp当前区块的的时间戳gasleft()返回剩余的Gasmsg.data返回完整的调用数据(calldata)msg.sender返回当前调用函数的调用者的地址msg.sigcalldata的前四个字节msg.value当前消息所附带的以太币,单位为weinowblock.timestamp的别名tx.gasprice交易的gas价格tx.origin交易的发送方3.3基本数据类型Solidity的基本数据类型也称为值类型,包括字符串型整型布尔型定长浮点型字节数组枚举类型地址类型。3.3.1字符串型下面的代码可以定义一个字符串型s。strings字符串的本质是由一组字符组成的字符数组。可以先将字符串数据转换为字节数组bytes类型,然后再通过length属性获取其长度,方法如下:
bytes(s).length【例3-3】pragmasolidity^0.5.1;contractDemo{functionGetStringLength(stringmemory_s)publicpurereturns(uint){returnbytes(_s).length;}}例3-3的执行结果1.字符串的比较2.字符串的拼接假定有a和b两个字符串变量,按照下面是的代码进行字符串拼接是会报错的:
a+b;
在Solidity中没有直接提供字符串拼接的方法,需要自己编程实现此功能。因为实现字符串拼接的功能涉及数组编程,所以相关内容将在3.4.4节中结合实例介绍。3.3.2整型1.整型数据的分类Solidity的整型分为有符号整数和无符号整数。有符号整数又分为int8、int16、int32、…、int256,int后面的数字表示整型数据的大小,单位为bit。这个数字可以从8~256,步长为8。int代表int256.同样的,无符号整数又分为uint8、uint16、uint32、…、uint256,uint代表uint256。2.操作符Solidity的整型操作符包括比较操作符、位操作符、位移操作符和算数操作符。比较操作符比较操作符说明例
子<=小于或等于if(a<=b){……}<
小于if(a<b){……}==等于if(a==b){……}!=不相等if(a!=b){……}>=大于或等于if(a>=b){……}>
大于if(a>b){……}位操作符位操作符可以对两个整型数据进行位操作,返回整数值。操作符说明例
子<<
左位移2<<2的结果是8,因为2的二进制位00000010左移2位就是00000100,也就是8>>
右位移与上面的操作相反8>>2的结果是2&按位与。两个位都是1时,按位与等于1;否则按位与等于13&4的结果是0。因为3的二进制为00000011,4的二进制为00000100,逐位执行按位与操作的结果是00000000,即0|按位或。两个位都是0时,按位或等于0;否则按位与等于13&4的结果是7。因为3的二进制为00000011,4的二进制为00000100,逐位执行按位与操作的结果是00000111,即7^按位异或。两个位不同时,按位异或等于1;否则按位与等于03&4的结果是7。因为3的二进制为00000011,4的二进制为00000100,逐位执行按位与操作的结果是00000111,即7算数操作符算数操作符可以对两个整型数据进行算数操作,返回整数值。比较操作符说明例
子+加法1+1的结果是2-减法2-1的结果是1*乘法2*2的结果是4/除法4/2的结果是2**乘方4**2的结果是16%求余8%3的结果是23.整型数据的上限不同类型的整型数据都是有上限的,比如uint8的上限为255。在上限的基础上再加上1,会出现向上溢出的错误,比如uint8数据255+1得到的结果为0,这与预期的结果是有偏差的。3.3.3定长浮点型所谓定长浮点型指限定长度的带有小数点的浮点数类型。Solidity的定长浮点型分为有符号定长浮点型和无符号定长浮点型两种。有符号定长浮点型的定义格式为fixedMxN。M表示整数部分的位数,必须是8的倍数,范围为8~256;N表示小数部分,范围为0~80。也可以不指定M和N,默认情况下,fixed表示fixed128x19,ufixed表示ufixed128x19。3.3.4布尔类型布尔类型通常用来判断条件是否成立。包含true(逻辑真)和false(逻辑假)。定义布尔类型变量的方法如下:boolbpublic;布尔类型操作符操作符说明!逻辑非操作。如果布尔类型变量a的值为true,则!a的结果是false;如果布尔类型变量a的值为false,则!a的结果是true&&包含两个操作数的逻辑与操作。布尔类型变量a和b都等于true,则a&&b的结果等于true;否则等于false||包含两个操作数的逻辑或操作。布尔类型变量a和b只要有一个等于true,a||b的结果就等于true;当a和b都为false时,a||b等于false==判断2个布尔值是否相等!=判断2个布尔值是否不等3.3.5地址类型地址类型是Solidity语言特有的数据类型,用于表示一个以太坊账户的地址。地址类型数据的长度为20个字节。选择当前智能合约的账户在remix页面中的开发工具面板中,选择“运行”选项卡,可以选择当前智能合约的账户。账户地址的格式如下0x+40个数字例如,下面就是一个以太坊账户地址的例子:0xca35b7d915458ef540ade6068dfe2f44e8fa733c一个以太坊账户地址的长度可以用以下公式计算这是一个16进制数字,每个数字代表4位的二进制数字以太坊账户地址的长度=4位*40=160位又因为1字节=8位,所以以太坊账户地址的长度为20个字节。以太坊中有如下几个特殊的地址智能合约地址this:在智能合约中,this代表当前合约对象的地址。合约拥有者:第一次部署合约时,花费Gas的账户即合约拥有者。已部署合约的地址调用函数时的发起人:调用智能合约中函数时,msg.sender表示调用者的账户地址。例如,下面的代码在智能合约Demo的构造函数中设置合约拥有者_owner的值。【例3-4】pragmasolidity^0.5.1;contractDemo{address_owner;//合约的拥有者
constructor()public{_owner=msg.sender;}
functionGetOwner()publicviewreturns(address){return_owner;}}查看智能合约Demo的拥有者地址3.3.6合约类型每个智能合约都有自己的类型,也可以转换为其继承的智能合约。关于智能合约编程的具体情况,将在第5章介绍。3.4复合数据类型3.4.1枚举类型3.4.2结构体3.4.3映射3.4.4数组3.4.1枚举类型枚举类型是一种自定义类型,如果一个变量只有有效的几种可能的取值,则可以将其定义为枚举类型。可以使用enum关键字定义枚举类型,具体方法如下:enum类型名称{取值1,取值2,取值3,取值4……}例如下面的代码可以定义枚举类型Sex,可选项为Male和Female。
enumSex{Male,Female}
声明枚举类型变量的方法如下:
枚举类型名称变量名;可以将枚举类型与uint类型互相转换例如,将Sex变量sex转换成uint变量isex的代码如下:
uintisex=uint(sex);【例3-5】pragmasolidity^0.5.1;contractPerson{enumSex{Male,Female}stringname;uintage;Sexsex;
functionSetFemale()public{sex=_Sex.Female;}functionGetSex()publicviewreturns(Sex){returnsex;}}例3-5的运行结果3.4.2结构体structBook{stringName;stringPublisher;uintPagecount;uintPrice;}在类wxModelMessage中添加一个静态方法GetCreateTime()privatestaticintGetCreateTime(){DateTimestartDate=newDateTime(1970,1,1,8,0,0);return(int)(DateTime.Now-startDate).TotalSeconds;}初始化一个Book变量b的方法Bookb=Book("以太坊Solidity语言智能合约设计与开发","人民邮电出版社",350,38);【例3-6】结构体类型的使用实例pragmasolidity^0.5.1;contractstructDemo{structBook{stringName;stringPublisher;uintPagecount;uintPrice;}Bookb=Book("以太坊Solidity语言智能合约设计与开发","人民邮电出版社",350,38);
functiongetName()viewpublicreturns(stringmemory){returnb.Name;}functiongetPublisher()viewpublicreturns(stringmemory){returnb.Publisher;}
functiongetPagecount()viewpublicreturns(uint){returnb.Pagecount;}functiongetPrice()viewpublicreturns(uint){returnb.Price;}}例3-6的运行结果3.4.3映射mapping(<键>=><值>)<变量名>;例如,下面的映射可以用于记录对电影的投票数量。键代表电影的id,值代表电影得到的投票数量。
mapping(uint=>uint)movieVote;【例3-7】给电影投票的使用实例pragmasolidity^0.5.1;contractmovieVote{mapping(uint=>uint)publicVoteCount;mapping(address=>uint)publicvoteRecord;functionvote(uint_movieId)publicreturns(stringmemory){if(voteRecord[msg.sender]==0){//未投过票
voteRecord[msg.sender]=_movieId;VoteCount[_movieId]=VoteCount[_movieId]+1;return"投票成功";}return"您已经投过票了";}functiongetVoteCount(uint_movieId)viewpublicreturns(uint){returnVoteCount[_movieId];}
functiongetVoteRecord()viewpublicreturns(uint){returnvoteRecord[msg.sender];}}智能合约movieVote中定义的函数说明如下•vote:为指定的电影投票,参数movieId指定电影Id。voteRecord[msg.sender]==0表示之前未投票,可以进行投票。投票的过程分为两步:第一步以msg.sender为键,将movieId存入voteRecord中,记录当前地址已经投过票;第二步将VoteCount[_movieId]的值加1,记录电影_movieId的投票数量。•getVoteCount:返回指定电影的投票数量。•getVoteRecord:返回当前地址投票的电影Id。给movieId等于1的电影投票重复投票的结果再次在vote按钮后面的输入框中输入2,然后单击vote按钮,在左侧的控制台面板中单击Debug按钮旁边的图标,可以看到运行结果为“
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《组件层压工艺说明》课件
- 吹气球治疗肺部疾病
- 《汇编程序设计》课件
- 《各种各样的绳子》课件
- 儿童常见病治疗
- 医院医疗设备外借流程
- 八省八校2022届高三化学下学期3月第二次联考试题
- 《安全事故案例汇编》课件
- 中国母婴营养品市场洞察报告
- 微课如何撰写岗位说明书之工作目的财经管理人力资源管理系
- 急诊科心内科救心圈运用PDCA循环缩短STEMI患者急诊停留时间品管圈成果汇报
- 儿科运用PDCA降低留置针非计划拔管率品管圈成果汇报书
- 劳动技能实操指导(劳动教育)学习通课后章节答案期末考试题库2023年
- 世界问候日国旗下讲话范文稿:让温暖的问候成为生活的习惯
- 国家开放大学行为表现答案
- 煤矿安全资格证培训全题库大全
- 人教版英语七年级上册全册教材全解及单元测试卷
- 走近湖湘红色人物知到章节答案智慧树2023年湖南工商大学
- 【超星尔雅学习通】探寻中国茶:一片树叶的传奇之旅网课章节答案
- 国家中小学智慧教育平台推动家校共育
- 涵洞八字墙体积计算公式
评论
0/150
提交评论