《以太坊技术详解与实战》第4章 - 智能合约与以太坊虚拟机

本章将介绍智能合约、以太坊虚拟机( Ethereum Virtual Machine, EVM ),以及用来编写智能合约的高级语言——Solidity 的基础知识。 通过本章的学习,读者可以掌握智能合约的作用和工作原理,以及如何使用 Solidity 来编写一个智能合约 。

4.1 智能合约

简单地说,智能合约就是区块链上一个包含合约代码和存储空间的虚拟账户,结构如图 4-1 所示 。
在这里插入图片描述
智能合约的行为由合约代码控制,而智能合约的账户存储则保存了合约的状态 。

4.1.1 智能合约的操作
以太坊是一个基于区块链技术的去中心化应用平台,在这个平台上,用户可以十分方便地按需求实现自己的智能合约 。
图 4-3 展示了创建和调用智能合约的流程。 要创建一个智能合约,需要经过编写智能合约、编译成字节码 、 部署到区块链等过程,调用智能合约则是发起一笔指向智能合约地址的交易,智能合约代码分布式地运行在网络中每个节点的以太坊虚拟机中 。
在这里插入图片描述

图 4-4 展示了智能合约的编译过程,左边是使用 Solidity 语言编写的智能合约,右边是使用操作码表示的字节码 。
在这里插入图片描述
字节码由 一连串的字节组成,每一字节表示一个操作 。 基于开发效率等多方面考虑,通常都不会直接书写以太坊虚拟机字节码,而是选择一门高级语言编写智能合约代码,再编译成以太坊字节码部署到区块链上 。

当编译完成得到 以太坊字节码之后,需要创建一个交易将合约部署到区块链上 。 交易的“ data ”字段保存的是以太坊字节码,“ to”的地址为一个空的账户 。 当该交易被“矿工”打包加入区块链时,这个合约就创建完成了,区块链上将出现一个与该智能合约相对应的合约账户,井拥有一个特定的地址,而合约代码将保存在该合约账户中 。

Solidity 还提供了 一个集成开发环境( IDE )一 Remix ,我们不仅可以在这个环境中编写合约代码,还可以进行编译、测试等工作 。 值得强调的是,测试是非常重要的,将一个包含缺陷的智能合约部署到以太坊公有链上可能会造成灾难性后果 。 所以,在将智能合约部署到公有链上之前都要先在测试链上进行充分的测试。

调用一个智能合约时,只需要发起一个指向合约地址的交易,并将合约需要的参数作为“ data”字段保存在交易中即可 。 为了方便合约的调用和参数的传递,以太坊拥有一套交互的标准 。 使用 Solidity 语言编写的智能合约在编译时都会自动生成一个 ABI(程序二进制接口) 。 ABI 是一个固定格式的字符串,包含了合约中各函数的函数名 、参数数目和类型、返回值数目和类型等信息 。 作为服务提供者,合约创建者需要向用户提供合约的 ABI和合约地址,这样用户才能使用合约定义的功能 。

有些合约的逻辑中还包含销毁功能,我们只需要像调用其他函数一样调用这个功能就可以销毁合约 。 当一个合约被销毁后,合约账户的存储和代码都将被清空 。 值得注意的是,这里的清空是指从当前状态清空合约账户井产生新的状态,并没有对过往的区块数据造成任何改变,所以在过往的区块数据中仍然存在这部分数据的记录 。

在软件开发中有一个不得不提的过程,那就是软件升级,无论是进行 bug 修复,还是增加新的功能,都需要对软件进行升级。 对于智能合约来说,部署在区块链上的代码是不可改变的,无法重新部署一个新的合约到相同的地址上,这就对智能合约的升级造成了一定的困难 。 但是我们仍然可以通过一些办法达到对智能合约进行升级的目的,比如可以部署一个拥有调用转发功能的智能合约,将收到的调用转发到另外一个包含逻辑功能的合约地址 。 当进行合约升级时,只需要部署一个新的合约并修改转发的目标地址,以指向新的合约 。

4.1.2 存储方式

4.1.3 指令集和消息调用
以太坊虚拟机有一套专门设计的指令集,包括了大多数常用的算术运算 、 位运算 、 逻辑运算和比较运算,同时还支持条件跳转和无条件跳转 。 除了这些基础指令外,还有一些区块链特有的指令,比如用于合约访问区块号和区块时间戳的指令等 。 以太坊虚拟机的基础数据单元是 256 位,所有指令都以此为单位来传递数据 。 智能合约的编译过程即是将其他高级语言 (比如 Solidity )编写的合约代码转换为指令集表示的字节码 。
为了便于开发者编写功能更加丰富的智能合约,以太坊允许合约在执行过程中通过创建一条“消息”的方式来调用其他合约,称之为消息调用 。 图 4-7 展示了一个消息调用是如何发生的 。
在这里插入图片描述

首先,智能合约 A 创建一条消息发送给智能合约 B。 消息的结构和交易很类似,都由发送者、接收者 、 数据区、以太币数目 、 Gas 等属性组成,但是消息调用属于交易执行的一部分(在指令层看,消息调用是一句 CALL 指令),并不会在区块链中产生一条新的交易记录 。 当智能合约 B 收到消息后,就访问消息的数据区以获取调用参数,执行合约代码,最后将结果返回给智能合约 A 并保存在智能合约 A 预先分配的一块内存空间中 。
从图 4-7 中可以看出,两个合约 A 和 B 的内存和账户存储都是独立的 。 当发起消息、调用时,虚拟机为 B 创建一块全新的内存区域以供 B 使用 。 账户存储则是与合约账户绑定的持久化存储,在合约 B 的代码执行过程中,可以对 B 的账户存储进行读写操作 。
为了防止合约代码陷入恶性循环,以太坊使用 Gas 限制机制 。 当发起一个消息调用时,智能合约可以决定为这次调用分配多少 Gas 。 如果一个消息调用因为 Gas 耗尽而失败,那么最后只会消耗本次调用已经使用的部分 。
除了消息调用之外,还有一种特殊的调用方式,叫做代理调用( delegate call ) 。 它与消息调用的区别是它只从目标合约获取代码并执行,却不会改变当前的上下文环境,包括msg.sender 和 msg.value 、当前账户、存储、内存等,这使得智能合约可以在运行时动态地从其他地址加载代码 。
这个调用方式让使用各种功能库变得方便,比如为了实现一个复杂的功能,可以加载实现了该功能的合约代码并直接对当前的存储进行修改 。

4.1.4 日志

4.2 Solidity 语言

Solidity 是一种用于编写智能合约的高级语言,语法类似于 JavaScript 。 在以太坊平台上, Solidity 编写的智能合约可以被编译成字节码在以太坊虚拟机上运行 。 使用 Solidity 语言编写智能合约避免了直接编写底层的以太坊虚拟机代码,提高了编码效率,同时该语言也具有更好的可读性 。

4.2.1 结构
Solidity 中的合约与面向对象编程语言 中的类( Class )很相似,在一个合约中可以声明多种成员,包括状态变量、函数、函数修改器 、事件等 。 同时,一个合约可以继承另一个合约 。 本节将简单介绍各种成员的形式和作用。

4.2.2 变量类型
 在计算机程序中需要使用变量来存储值 。 值有多种类型,比如整数 、 小数 、字符串等 ,不同类型的值需要存储在不同类型的变量中 。
 Solidity 是一门静态类型语言,每一个变量都必须指定变量的类型,否则无法正确编译 。
 Solidity 提供了 一些基础的变量类型,可以使用这些基础类型组合形成复杂的类型 。 变量类型根据参数传递方式的不同可以分为两类:值类型和引用类型 。 值类型在每次赋值或者作为参数传递时都会创建一份拷贝,引用类型则有两种存储地点,即账户存储和内存。状态变量与部分类型的局部变量(数组、结构体等复杂类型)是默认保存在账户存储中的,而函数的参数和其他简单类型的局部变量则保存在内存中 。 必要时还可以在声明变量时加上 memory 或者 storage 修饰词来强制限定变量的存储地点 。 数据的存储地点非常重要,引用类型在不同的存储位置赋值,其产生的结果完全不同 。
 值类型包括布尔类型、整数类型、地址类型、固定长度字节数组等,引用类型包括数组 、 结构体等 。

  1. 值类型

  2. 引用类型

  3. 类型转换

  4. 运算符

  5. 类型推断

4.2.3 内置单位、全局变量和函数

4.2.4 控制结掏语句
Solidity 与 JavaScript 或者 C 语言有相似的流程控制语句,包括 if-else 、 while 、 do-while 、for、break 、 continue 、 return 、 ?:(三 目运算符)。

4.2.5 函数

4.2.6 constant 函数和 fallback 函数

4.2.7 函数修改器

4.2.8 异常处理

4.2.9 事件和日志

4.2.10 智能合约的继承

4.3 本章小结

在以太坊平台上,智能合约是一段保存在区块链上的逻辑代码,运行在以太坊虚拟机中 。 使用智能合约,用户可以十分方便地在以太坊平台上创建去中心化应用 。 Solidity 是一门用于编写智能合约的高级语言,拥有非常多的用户,可以极大地提高智能合约的开发效率。本章首先为读者介绍了什么是智能合约,通过一个简单的场景讲述了智能合约的工作原理及其优势 。 此外,本章还为读者介绍了部分智能合约的底层工作机制,包括以太坊虚拟机 、存储方式 、 指令集和消息调用等内容 。最后,本章还介绍了 Solidity 语言的基础知识,以及怎样使用 Solidity 语言编写一个智能合约 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值