智能合约编写之Solidity的基础特性 | FISCO BCOS超话区块链专场(篇2)

做者.jpg

如前篇介绍,目前大部分的联盟链平台,包括FISCO BCOS,都采用Solidity做为智能合约开发语言,所以熟悉并上手Solidity十分必要。html

做为一门面向区块链平台设计的图灵完备的编程语言,Solidity支持函数调用、修饰符、重载、事件、继承等多种特性,在区块链社区中,拥有普遍的影响力和踊跃的社区支持。但对于刚接触区块链的人而言,Solidity是一门陌生的语言。java

智能合约编写阶段将从Solidity基础特性、高级特性、设计模式以及编程攻略分别展开,带读者认识Solidity并掌握其运用,更好地进行智能合约开发。git

本篇将围绕Solidity的基础特性,带你们上手开发一个最基本的智能合约。github

智能合约代码结构

任何编程语言都有其规范的代码结构,用于表达在一个代码文件中如何组织和编写代码,Solidity也同样。web

本节,咱们将经过一个简单的合约示例,来了解智能合约的代码结构。编程

代码1.png

上面这段程序包括了如下功能:设计模式

  • 经过构造函数来部署合约
  • 经过setValue函数设置合约状态
  • 经过getValue函数查询合约状态

整个合约主要分为如下几个构成部分:数组

  • 状态变量- _admin, _state,这些变量会被永久保存,也能够被函数修改
  • 构造函数- 用于部署并初始化合约
  • 事件- SetState, 功能相似日志,记录了一个事件的发生
  • 修饰符- onlyAdmin, 用于给函数加一层"外衣"
  • 函数- setState, getState,用于读写状态变量

下面将逐一介绍上述构成部分。网络

 状态变量

状态变量是合约的骨髓,它记录了合约的业务信息。用户能够经过函数来修改这些状态变量,这些修改也会被包含到交易中;交易通过区块链网络确认后,修改即为生效。
uint private _state;
状态变量的声明方式为:[类型]  [访问修饰符-可选] [字段名]数据结构

 构造函数

构造函数用于初始化合约,它容许用户传入一些基本的数据,写入到状态变量中。

在上述例子中,设置了_admin字段,做为后面演示其余功能的前提。
代码2.png
和java不一样的是,构造函数不支持重载,只能指定一个构造函数。

 函数

函数被用来读写状态变量。对变量的修改将会被包含在交易中,经区块链网络确认后才生效。生效后,修改会被永久的保存在区块链帐本中。

函数签名定义了函数名、输入输出参数、访问修饰符、自定义修饰符。
function setState(uint value) public onlyAdmin;

函数还能够返回多个返回值:

代码3.png

在本合约中,还有一个配备了view修饰符的函数。这个view表示了该函数不会修改任何状态变量。

与view相似的还有修饰符pure,其代表该函数是纯函数,连状态变量都不用读,函数的运行仅仅依赖于参数。

代码4.png

若是在view函数中尝试修改状态变量,或者在pure函数中访问状态变量,编译器均会报错。

 事件

事件相似于日志,会被记录到区块链中,客户端能够经过web3订阅这些事件。

定义事件
event SetState(uint value);
构造事件
emit SetState(value);
这里有几点须要注意:

  • 事件的名称能够任意指定,不必定要和函数名挂钩,但推荐二者挂钩,以便清晰地表达发生的事情.
  • 构造事件时,也可不写emit,但由于事件和函数不管是名称仍是参数都高度相关,这样操做很容易笔误将事件写成函数调用,所以不推荐。

代码5.png

 修饰符

修饰符是合约中很是重要的一环。它挂在函数声明上,为函数提供一些额外的功能,例如检查、清理等工做。

在本例中,修饰符onlyAdmin要求函数调用前,须要先检测函数的调用者是否为函数部署时设定的那个管理员(即合约的部署人)。

代码6.png

值得注意的是,定义在修饰符中的下划线“_”,表示函数的调用,指代的是开发者用修饰符修饰的函数。在本例中,表达的是setState函数调用的意思。

智能合约的运行

了解了上述的智能合约示例的结构,就能够直接上手运行,运行合约的方式有多种,你们能够任意采起其中一种:

  • 方法一:可使用FISCO BCOS控制台的方式来部署合约,具体请参考

    https://fisco-bcos-documentat..._CN/latest/docs/installation.html#id7

  • 方法二:使用FISCO BCOS开源项目WeBASE提供的在线ide WEBASE-front运行
  • 方法三:经过在线ide remix来进行合约的部署与运行, remix的地址为

    http://remix.ethereum.org/

本例中使用remix做为运行示例。

 编译

首先,在remix的文件ide中键入代码后,经过编译按钮来编译。成功后会在按钮上出现一个绿色对勾:

图片1.jpg

 部署

编译成功后就可进行部署环节,部署成功后会出现合约实例。

图片2.jpg

 setState

合约部署后,咱们来调用setState(4)。在执行成功后,会产生一条交易收据,里面包含了交易的执行信息。

图片3.jpg

在这里,用户能够看到交易执行状态(status)、交易执行人(from)、交易输入输出(decoded input, decoded output)、交易开销(execution cost)以及交易日志(logs)。

在logs中,咱们看到SetState事件被抛出,里面的参数也记录了事件传入的值4。

若是咱们换一个帐户来执行,那么调用会失败,由于onlyAdmin修饰符会阻止用户调用。

图片4.jpg

getState

调用getState后,能够直接看到所获得的值为4,正好是咱们先前setState所传入的值:

图片5.jpg

Solidity数据类型

在前文的示例中,咱们用到了uint等数据类型。因为Solidity类型设计比较特殊,这里也会简单介绍一下Solidity的数据类型。

 整型系列

Solidity提供了一组数据类型来表示整数, 包含无符号整数与有符号整数。每类整数还可根据长度细分,具体细分类型以下。

屏幕快照 2020-03-11 下午6.28.06.png

定长bytes系列

Solidity提供了bytes1到bytes32的类型,它们是固定长度的字节数组。

用户能够读取定长bytes的内容。

代码7.png

而且,能够将整数类型转换为bytes。

屏幕快照 2020-03-11 下午9.24.55.png

这里有一个关键细节,Solidity采起大端序编码,高地址存的是整数的小端。例如,b[0]是低地址端,它存整数的高端,因此值为0;取b[31]才是1。

代码9.png

变长bytes

从上文中,读者可了解定长byte数组。此外,Solidity还提供了一个变长byte数组:bytes。使用方式相似数组,后文会有介绍。

 string

Solidity提供的string,本质是一串经UTF-8编码的字节数组,它兼容于变长bytes类型。

目前Solidity对string的支持不佳,也没有字符的概念。用户能够将string转成bytes。

代码10.png

要注意的是,当将string转换成bytes时,数据内容自己不会被拷贝,如上文中,str和b变量指向的都是同一个字符串abc。

 address 

address表示帐户地址,它由私钥间接生成,是一个20字节的数据。一样,它也能够被转换为bytes20。

代码11.png

 mapping

mapping表示映射, 是极其重要的数据结构。它与java中的映射存在以下几点差异:

  • 它没法迭代keys,由于它只保存键的哈希,而不保存键值,若是想迭代,能够用开源的可迭代哈希类库
  • 若是一个key未被保存在mapping中,同样能够正常读取到对应value,只是value是空值(字节全为0)。因此它也不须要put、get等操做,用户直接去操做它便可。

代码12.png

 数组

若是数组是状态变量,那么支持push等操做:

代码13.png

数组也能够以局部变量的方式使用,但稍有不一样:

代码14.png

 struct

Solidity容许开发者自定义结构对象。结构体既能够做为状态变量存储,也能够在函数中做为局部变量存在。

代码15.png

本节中只介绍了比较常见的数据类型,更完整的列表可参考Solidity官方网站:

https://solidity.readthedocs....

全局变量

示例合约代码的构造函数中,包含msg.sender。它属于全局变量。在智能合约中,全局变量或全局方法可用于获取和当前区块、交易相关的一些基本信息,如块高、块时间、合约调用者等。

比较经常使用的全局变量是msg变量,表示调用上下文,常见的全局变量有如下几种:

  • msg.sender:合约的直接调用者。

    因为是直接调用者,因此当处于 用户A->合约1->合约2 调用链下,若在合约2内使用msg.sender,获得的会是合约1的地址。若是想获取用户A,能够用tx.origin.

  • tx.origin:交易的"始做俑者",整个调用链的起点。
  • msg.calldata:包含完整的调用信息,包括函数标识、参数等。calldata的前4字节就是函数标识,与msg.sig相同。
  • msg.sig:msg.calldata的前4字节,用于标识函数。

  • block.number:表示当前所在的区块高度。
  • now:表示当前的时间戳。也能够用block.timestamp表示。

这里只列出了部分常见全局变量,完整版本请参考:

https://solidity.readthedocs....

结语

本文以一个简单的示例合约做为引入,介绍了运用Solidity开发智能合约的基本知识。读者能够尝试运行该合约,感觉智能合约的开发。

若想更深刻学习智能合约示例,推荐官方网站示例供读者学习,也可关注本专题后续系列文章:

https://solidity.readthedocs....

在官网的示例中,提供了投票、竞拍、微支付通道等多个案例,这些案例贴近实际生活,是很好的学习资料。

**

下期预告

活动预告2.jpg

FISCO BCOS的代码彻底开源且免费

下载地址↓↓↓

https://github.com/FISCO-BCOS...

相关文章
相关标签/搜索