logo资料库

Solidity官方文档中文版.pdf

第1页 / 共137页
第2页 / 共137页
第3页 / 共137页
第4页 / 共137页
第5页 / 共137页
第6页 / 共137页
第7页 / 共137页
第8页 / 共137页
资料共137页,剩余部分请下载后查看
导读
简介
Solidity 文档
智能合约介绍
一个简单的智能合约
Storage
代币的例子
区块链基础
交易/事务
区块
以太坊虚拟机
总览
账户
交易
Gas
存储,主存和栈
指令集
消息调用
代码调用和库
日志
创建
自毁
安装Solidity
基于浏览器的Solidity
NPM / node.js
二进制安装包
Ethereum.
从源码构建
MacOS X
Ubuntu 系统
安装依赖软件:
编译
Solidity 编程实例
Voting 投票
可能的改进
盲拍
简单的公开拍卖
Blind Auction 盲拍
深入理解 Solidity
源文件的布局
语法和语义
路径
使用真正的编译器
solc:
基于浏览器的solidity
注释
合约的结构
类型
变量类型
布尔类型
整型
地址
注解
请注意
整型常量
字符串常量
引用类型
数据位置
总结
数组
结构体
映射
包括左值操作的操作符
删除
基本类型之间的转换
隐式转换
显式转换
类型推导
单位和全局可用变量
以太单位
时间单位
特殊的变量和函数
块和交易属性
请注意
请注意
数学和加密功能
合约相关的
表达式和控制结构
控制结构
函数调用
具名调用和匿名函数参数
表达式计算的次序
赋值
数组和结构体的组合
异常
合约
创建合约
可见性和访问限制符
访问限制符函数
函数修饰符
常量
回退函数
事件
底层日志的接口
继承
基本构造函数的参数
多继承和线性化
抽象契约
库的常见“坑”
转移Ether
Using For
杂项
存储中状态变量的布局
深奥的特点
内部-优化器
使用命令行编译器
提示和技巧
陷阱
列表
全局变量
函数可见性定义符
编程规范
概述
代码布局
源文件编码方式
引入
函数声明
规范的方式:
通用模式
访问限制
常见问题
基础问题
How do I use .send()?
More Questions?
汇智网 Hubwiz.com Solidity 官方文档中文版 导读 以太坊是什么? 以太坊是一个全新开放的区块链平台,它允许任何人在平台中建立和使用通过 区块链技术运行的去中心化应用。就像比特币一样,以太坊丌受任何人控制, 也丌归任何人所有——它是一个开放源代码项目,由全球范围内的很多人共同 创建。和比特币协议有所丌同的是,以太坊的设计十分灵活,极具适应性。在 以太坊平台上创立新的应用十分简便,随着 Homestead 的发布,任何人都可 以安全地使用该平台上的应用。 本电子书参考的原文最早由众多热心网友发布于极客学院 WIKI (http://wiki.jikexueyuan.com/project/solidity-zh/),由汇智网 (http://www.hubwiz.com)编目整理。 但由于以太坊本身(以及周边生态)的发展非常快,一些实践性内容已经落后 于现状。因此编者建议本电子书的读者,在阅读时应注意吸收核心的理念思想, 而丌要过分关注书中的实践操作环节。 为了弥补这一遗憾,汇智网推出了在线交互式以太坊 DApp 实战开发课程,以 去中心化投票应用(Voting DApp)为课程项目,通过三次迭代开发过程的详 细讲解不在线实践,并且将区块链的理念不去中心化思想贯穿于课程实践过程 中,为希望快速入门区块链开发的开发者提供了一个高效的学习不价值提升途 径。读者可以通过以下链接访问《以太坊 DApp 开发实战入门》在线教程: 1 / 137
汇智网 Hubwiz.com Solidity 官方文档中文版 http://xc.hubwiz.com/course/5a952991adb3847553d205d1?affid=sol 教程预置了开发环境。进入教程后,可以在每一个知识点立刻进行同步实践, 而丌必在开发环境的搭建上浪费时间: 汇智网 Hubwiz.com 2018.2 简介 Solidity 是一种语法类似 JavaScript 的高级语言。它被设计成以编译的方式生成以太坊虚 拟机代码。在后续内容中你将会发现,使用它很容易创建用于投票、众筹、封闭拍卖、多重 签名钱包等等的合约。 注意 目前尝试 Solidity 的最好方式是使用基于浏览器的编译器(需要一点时间加载,请耐心等 待)。 有用链接  Ethereum 2 / 137
汇智网 Hubwiz.com Solidity 官方文档中文版  Browser-Based CompilerChangelog  Story Backlog  Source Code  Gitter Chat Solidity 文档 在下一章中,我们先看一个用 Solidity 写的简单的智能合约,然后介绍一下区块链和以太 坊虚拟机的基础知识。 后续章节会通过一些实用的合约例子,来探索 Solidity 的一系列特性。记住,你可以在浏 览器中尝试这些合约。 最后以及更多扩展章节的内容,会深入到 Solidity 的各个方面。 如有任何关于 Solidiy,或者本文档的问题及改进建议,请在 gitter 频道提出来。 智能合约介绍 一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的 细节。 Storage contract SimpleStorage { uint storedData; function set(uint x) { storedData = x; } function get() constant returns (uint retVal) { return storedData; } } 在 Solidity 中,一个合约由一组代码(合约的函数)和数据(合约的状态)组成。合约位 于以太坊区块链上的一个特殊地址。*uint storedData*; 这行代码声明了一个状态变量, 变量名为 storedData,类型为 uint (256bits 无符号整数)。你可以认为它就像数据库 里面的一个存储单元,跟管理数据库一样,可以通过调用函数查询和修改它。在以太坊中, 3 / 137
汇智网 Hubwiz.com Solidity 官方文档中文版 通常只有合约的拥有者才能这样做。在这个例子中,函数 set 和 get 分别用于修改和查询 变量的值。 跟很多其他语言一样,访问状态变量时,不需要在前面增加 this. 这样的前缀。 这个合约还无法做很多事情(受限于以太坊的基础设施),仅仅是允许任何人储存一个数字。 而且世界上任何一个人都可以来存取这个数字,缺少一个(可靠的)方式来保护你发布的数 字。任何人都可以调用 set 方法设置一个不同的数字覆盖你发布的数字。但是你的数字将会 留存在区块链的历史上。稍后我们会学习如何增加一个存取限制,使得只有你才能修改这个 数字。 代币的例子 接下来的合约将实现一个形式最简单的加密货币。空中取币不再是一个魔术,当然只有创建 合约的人才能做这件事情(想用其他货币发行模式也很简单,只是实现细节上的差异)。而 且任何人都可以发送货币给其他人,不需要注册用户名和密码,只要有一对以太坊的公私钥 即可。 Note 对于在线 solidity 环境来说,这不是一个好的例子。如果你使用在线 solidity 环境 来尝试 这个例子。调用函数时,将无法改变 from 的地址。所以你只能扮演铸币者的角色,可以铸 造货币并发送给其他人,而无法扮演其他人的角色。这点在线 solidity 环境将来会做改进。 contract Coin { //关键字“public”使变量能从合约外部访问。 address public minter; mapping (address => uint) public balances; //事件让轻客户端能高效的对变化做出反应。 event Sent(address from, address to, uint amount); //这个构造函数的代码仅仅只在合约创建的时候被运行。 function Coin() { minter = msg.sender; } function mint(address receiver, uint amount) { if (msg.sender != minter) return; balances[receiver] += amount; } function send(address receiver, uint amount) { if (balances[msg.sender] < amount) return; balances[msg.sender] -= amount; 4 / 137
汇智网 Hubwiz.com Solidity 官方文档中文版 balances[receiver] += amount; Sent(msg.sender, receiver, amount); } } 这个合约引入了一些新的概念,让我们一个一个来看一下。 address public minter; 这行代码声明了一个可公开访问的状态变量,类型为 address。 address 类型的值大小为 160 bits,不支持任何算术操作。适用于存储合约的地址或其他 人的公私钥。public 关键字会自动为其修饰的状态变量生成访问函数。没有 public 关键字 的变量将无法被其他合约访问。另外只有本合约内的代码才能写入。自动生成的函数如下: function minter() returns (address) { return minter; } 当然我们自己增加一个这样的访问函数是行不通的。编译器会报错,指出这个函数与一个状 态变量重名。 下一行代码 mapping (address => uint) public balances; 创建了一个 public 的状态变量, 但是其类型更加的复杂。该类型将一些 address 映射到无符号整数。mapping 可以被认为 是一个哈希表,每一个可能的 key 对应的 value 被虚拟的初始化为全 0.这个类比不是很严 谨,对于一个 mapping,无法获取一个包含其所有 key 或者 value 的链表。所以我们得 自己记着添加了哪些东西到 mapping 中。更好的方式是维护一个这样的链表,或者使用其 他更高级的数据类型。或者只在不受这个缺陷影响的场景中使用 mapping,就像这个例子。 在这个例子中由 public 关键字生成的访问函数将会更加复杂,其代码大致如下: function balances(address _account) returns (uint balance) { return balances[_account]; } 我们可以很方便的通过这个函数查询某个特定账号的余额。 event Sent(address from, address to, uint value); 这行代码声明了一个―事件‖。由 send 函数的最后一行代码触发。客户端(服务端应用也适用)可以以很低的开销来监听这些由区 块链触发的事件。事件触发时,监听者会同时接收到 from,to,value 这些参数值,可以 方便的用于跟踪交易。为了监听这个事件,你可以使用如下代码: Coin.Sent().watch({}, '', function(error, result) { if (!error) { console.log("Coin transfer: " + result.args.amount + " coins were sent from " + result.args.from + " to " + result.args.to + "."); console.log("Balances now:\n" + "Sender: " + Coin.balances.call(result.args.from) + "Receiver: " + Coin.balances.call(result.args.to)); 5 / 137
汇智网 Hubwiz.com Solidity 官方文档中文版 } } 注意在客户端中是如何调用自动生成的 balances 函数的。 这里有个比较特殊的函数 Coin。它是一个构造函数,会在合约创建的时候运行,之后就无 法被调用。它会永久得存储合约创建者的地址。msg(以及 tx 和 block)是一个神奇的全 局变量,它包含了一些可以被合约代码访问的属于区块链的属性。msg.sender 总是存放 着当前函数的外部调用者的地址。 最后,真正被用户或者其他合约调用,用来完成本合约功能的函数是 mint 和 send。如果 合约创建者之外的其他人调用 mint,什么都不会发生。而 send 可以被任何人(拥有一定 数量的代币)调用,发送一些币给其他人。注意,当你通过该合约发送一些代币到某个地址, 在区块链浏览器中查询该地址将什么也看不到。因为发送代币导致的余额变化只存储在该代 币合约的数据存储中。通过事件我们可以很容易创建一个可以追踪你的新币交易和余额的 ―区块链浏览器‖。 区块链基础 对于程序员来说,区块链这个概念其实不难理解。因为最难懂的一些东西(挖矿,哈希,椭 圆曲线加密,点对点网络等等)只是为了提供一系列的特性和保障。你只需要接受这些既有 的特性,不需要关心其底层的技术。就像你如果仅仅是为了使用亚马逊的 AWS,并不需要 了解其内部工作原理。 交易/事务 区块链是一个全局共享的,事务性的数据库。这意味着参与这个网络的每一个人都可以读取 其中的记录。如果你想修改这个数据库中的东西,就必须创建一个事务,并得到其他所有人 的确认。事务这个词意味着你要做的修改(假如你想同时修改两个值)只能被完完全全的实 施或者一点都没有进行。 此外,当你的事务被应用到这个数据库的时候,其他事务不能修改该数据库。 举个例子,想象一张表,里面列出了某个电子货币所有账号的余额。当从一个账户到另外一 个账户的转账请求发生时,这个数据库的事务特性确保从一个账户中减掉的金额会被加到另 一个账户上。如果因为某种原因,往目标账户上增加金额无法进行,那么源账户的金额也不 会发生任何变化。 6 / 137
汇智网 Hubwiz.com Solidity 官方文档中文版 此外,一个事务会被发送者(创建者)进行密码学签名。这项措施非常直观的为数据库的特 定修改增加了访问保护。在电子货币的例子中,一个简单的检查就可以确保只有持有账户密 钥的人,才能从该账户向外转账。 区块 区块链要解决的一个主要难题,在比特币中被称为―双花攻击‖。当网络上出现了两笔交易, 都要花光一个账户中的钱时,会发生什么?一个冲突? 简单的回答是你不需要关心这个问题。这些交易会被排序并打包成―区块‖,然后被所有参与 的节点执行和分发。如果两笔交易相互冲突,排序靠后的交易会被拒绝并剔除出区块。 这些区块按时间排成一个线性序列。这也正是―区块链‖这个词的由来。区块以一个相当规律 的时间间隔加入到链上。对于以太坊,这个间隔大致是 17 秒。 作为―顺序选择机制‖(通常称为―挖矿‖)的一部分,一段区块链可能会时不时被回滚。但这 种情况只会发生在整条链的末端。回滚涉及的区块越多,其发生的概率越小。所以你的交易 可能会被回滚,甚至会被从区块链中删除。但是你等待的越久,这种情况发生的概率就越小。 以太坊虚拟机 总览 以太坊虚拟机(EVM)是以太坊中智能合约的运行环境。它不仅被沙箱封装起来,事实上 它被完全隔离,也就是说运行在 EVM 内部的代码不能接触到网络、文件系统或者其它进程。 甚至智能合约与其它智能合约只有有限的接触。 账户 以太坊中有两类账户,它们共用同一个地址空间。外部账户,该类账户被公钥-私钥对控制 (人类)。合约账户,该类账户被存储在账户中的代码控制。 外部账户的地址是由公钥决定的,合约账户的地址是在创建该合约时确定的(这个地址由合 约创建者的地址和该地址发出过的交易数量计算得到,地址发出过的交易数量也被称作 "nonce") 合约账户存储了代码,外部账户则没有,除了这点以外,这两类账户对于 EVM 来说是一样 的。 7 / 137
汇智网 Hubwiz.com Solidity 官方文档中文版 每个账户有一个 key-value 形式的持久化存储。其中 key 和 value 的长度都是 256 比特, 名字叫做 storage. 另外,每个账户都有一个以太币余额(单位是―Wei"),该账户余额可以通过向它发送带有 以太币的交易来改变。 交易 一笔交易是一条消息,从一个账户发送到另一个账户(可能是相同的账户或者零账户,见下 文)。交易可以包含二进制数据(payload)和以太币。 如果目标账户包含代码,该代码会执行,payload 就是输入数据。 如果目标账户是零账户(账户地址是 0),交易将创建一个新合约。正如上文所讲,这个合 约地址不是零地址,而是由合约创建者的地址和该地址发出过的交易数量(被称为 nonce) 计算得到。创建合约交易的 payload 被当作 EVM 字节码执行。执行的输出做为合约代码 被永久存储。这意味着,为了创建一个合约,你不需要向合约发送真正的合约代码,而是发 送能够返回真正代码的代码。 Gas 以太坊上的每笔交易都会被收取一定数量的 gas,gas 的目的是限制执行交易所需的工作量, 同时为执行支付费用。当 EVM 执行交易时,gas 将按照特定规则被逐渐消耗。 gas price(以太币计)是由交易创建者设置的,发送账户需要预付的交易费用 = gas price * gas amount。 如果执行结束还有 gas 剩余,这些 gas 将被返还给发送账户。 无论执行到什么位置,一旦 gas 被耗尽(比如降为负值),将会触发一个 out-of-gas 异常。 当前调用帧所做的所有状态修改都将被回滚。 存储,主存和栈 每个账户有一块持久化内存区域被称为存储。其形式为 key-value,key 和 value 的长度 均为 256 比特。在合约里,不能遍历账户的存储。相对于另外两种,存储的读操作相对来 说开销较大,修改存储更甚。一个合约只能对它自己的存储进行读写。 第二个内存区被称为主存。合约执行每次消息调用时,都有一块新的,被清除过的主存。主 存可以以字节粒度寻址,但是读写粒度为 32 字节(256 比特)。操作主存的开销随着其增 长而变大(平方级别)。 8 / 137
分享到:
收藏