区块链从基础概念到技术实现的进阶攻略
讲师自我介绍:菜根科技技术总监邢有涛
大家好,近年来,“区块链”技术迅速走红,其去中心化、去信任的机制得到全球市场的认同, 并有望成为下一代“价值互联网”的基础协议。 因此,借这样的机会,首先给大家介绍一下什么是区块链,然后分享当下很流行的以太坊,最后完成一个简单的智能合约,帮助大家对区块链技术有一些初步的了解。
本次分享将包括以下三部分:
区块链入门
以太坊介绍
以太坊开发
a. 构建测试网络
b. 编写合约
一、区块链入门
简单来说,区块链是比特币的底层技术。谈到区块链,就不得不先说一下比特币。对于“比特币(Bitcoin)”这个词,有三层含义。首先,比特币特指一种加密数字货币,是最早也是目前规模最大的加密数字货币。 其次,比特币协议可以被看成一种基于区块链的“价值传输协议”,该协议可以用来描述数字资产是如何在区块链上转移的。最后,比特币系统指底层的共有区块链技术平台,包含去中心化的公开总帐、比特币钱包等软件和系统。
加密数字货币
比特币(Bitcoin)是一种全球通用的加密电子货币(Crypto-Currency),完全交由用户们自治的交易工具。比特币的概念由中本聪(Satoshi Nakamoto)在2008年11月发表的论文《Bitcoin:A Peer-to-Peer Electronic Cash System》中首次提出。与数字货币不同,比特币完全是去中心化的,不依靠特定机构来发行,而是依据特定算法,通过大量的计算产生。比特币系统使用整个P2P网络中众多节点构成的分布式数据库对所有的事务进行确认并记录,并使用密码学的设计来确保货币流通各个环节安全性。
比特币协议
共用标准:包括散列算法(Hash)、Merkle树结构、签名方式、事务验证、地址格式等。
共用结构:包括消息、可变长整数、可变长字符串,网络地址、清单向量(Inventory Vectors)、区块头格式等。
消息类型:包括 version、verack、addr、inv、getdata,getblocks,getheaders,tx,block,headers,getaddr,checkorder,submitorder,reply,ping,alert 这 16 个消息报文的具体定义。
事务脚本
比特币系统
用户:用户通过密钥控制比特币钱包。
事务:每一笔事务都会被广播到整个比特币网络中,由矿工将其写入新的区块。
矿工:通过竞争计算生成在每个节点达成共识的区块链。
区块链:是一个分布式的公共权威账簿,包含了比特币网络发生的所有的事务。
尽管比特币P2P网络中的各个节点相互对等,但是根据所提供的功能不同,各节点可能具有不同的分工。每个比特币节点都是路由、区块链数据库、挖矿、钱包服务的功能集合。一个全节点(Full Node)包括钱包、完整区块链、矿工、网络路由节点四个功能。
现在我们重新回到区块链的话题上来。
什么是区块链?
区块链(Blockchain)是指通过去中心化和去信任的方式集体维护一个可靠数据库的技术方案。该技术方案让参与系统中的任意多个节点,把一段时间系统内全部事务通过密码学算法计算并记录到一个数据块(block),生成该数据块的hash用于链接下个数据块,系统所有参与节点来共同检验记录是否为真,并且每个区块的内容都由后续子链上的区块来保证其内容不可被篡改。 各个参与节点可以在新区块产生确认及奖励分配上达成共识,从而逐渐形成的一个庞大、去中心化的公开账本。
链上的每个区块都可以用来记录货币、股权、债券、数字签名、数字合约,或其它任何数字化内容。在全球网络下,由无数独立的计算机来维护、更新和核查,确保记账结果的公平、公正和公开透明,而无需任何中心化机构的审核和维护。
我们仍然以比特币为例,说明区块链形成过程:
平均每10分钟由“矿工”竞争而产生一个新的区块,并把这段时间内的多笔事务记录到这个新区块中。单笔事务写入比特币区块链至少需要10分钟。
目前每个区块大小限制为1MB,最多能记录约4000笔的事务。比特币区块链最大写入性能大约只有7笔/秒。
为了防止该区块因为子链太短而被其它节点抛弃,需要等待产生6个新的后续区块,才能最终确认该事务已经被可靠地写入区块链中。确保可靠写入需要约60分钟。
每个参与节点都可以保存整个区块链的副本。只要有参与节点存在,区块链数据就不会丢失。
那么,在这样去信任的场景下,该由谁完成账本的记录(即新区块的产生)。为了解决这个问题,必须建立一套共识机制,确保价值的唯一性和不可复制性。 目前常见的包括PoW(Proof of Work,工作量证明),PoS(Proof of Stake,权益证明),DPoS(Delegate Proof of Stake,股份授权证明机制)等。
PoW
比特币区块链主要使用PoW来实现共识。通过使用单向函数挖掘,使得矿工在得到正确的计算结果前,必须经过公开算法的计算,而结果的验证速度非常快。通过验证这个结果,其他矿工就可以确认是执行了一定量的计算工作才得出的。
PoW的优点是:完全去中心化,节点自由进出。
PoS
PoS权益证明,可以看作是PoW的一种升级共识机制,根据每个节点所占代币的比例和时间等比例的降低挖矿难度,从而加快找随机数的速度。当创造一个PoS区块时,矿工需要创建一个币权交易,事务会按设定的比例把一些币发送给矿工。
PoS权益证明方式在一定程度上缩短达成共识的时间,但是仍然需要挖矿的过程才能达成共识。PoS币的规则会造成富者愈富的问题。PoS币的利息越高,那么该币将会产生的不公平性就会越高。
DPoS
DPoS类似于董事会投票,它的原理是让每一个持有比特股的人进行投票,由此产生101位代表可以将其理解为101个超级节点或者矿池,而超级节点彼此的权利是完全相等的。DPoS有点像是美国的议会制度,如果代表不能履行他们的职责(无法生成区块),即被除名,网络会选出新的超级节点来取代他们。
DPoS可以大幅缩小参与验证和记账节点的数量,可以达到秒级的共识验证。
公有链、私有链、联盟链
中本聪巧妙地将以下几个成熟的技术和理论组合的一起,并以此为基础构建区块链技术:
基于去中心化的分布式算法而建立起点对点对等(P2P)网络。
基于非对称加密算法。
基于分布式一致性算法,解决了分布式场景下的拜占庭将军问题。
基于博弈论而精心设计的奖励机制,实现了纳什均衡,确保整个系统的安全和稳定运行。
如果同时具有上述四点要素,可以认为这是一种公共区块链技术,简称公有链。如果只具有前三点要素,将其称为私有区块链技术,简称私有链。而联盟链则介于两者之间,可视为联盟成员内的一种私有链。这里主要介绍公有链和私有链。
公有链是指全世界任何人都可读取的、任何人都能发送事务且能获得有效确认的、任何人都能参与共识过程的区块链。共识过程决定哪个区块可被添加到区块链中和明确当前状态。作为中心化或者准中心化信任的替代物,公有链的安全由加密数字经济维护。加密数字经济采取工作量证明机制或权益证明机制等方式,将经济奖励和加密数字验证结合了起来,并遵循着一般原则:每个人从中可获得的经济奖励,与对共识过程作出的贡献成正比。这些区块链通常被认为是完全去中心化的。
私有链是指其写入权限仅在一个组织手里的区块链。读取权限或者对外开放,或者被限制。相关的应用囊括数据库管理、审计、甚至一个公司,尽管在有些情况下希望它能有公共的可审计性,但在很多的情形下,公共的可读性并非是必须的。
私有链相比于公有链的优点:
事务的效率更高:比特币区块链目前每秒可完成7笔事务,而私有链目前最高可以到每秒10万笔,并且还有提高的空间。显然后者更适应现实世界金融事务的需求。
事务可以回滚:这点对于中心化机构也很重要,在某些情况下,某些事务会因为错误或法律的问题而被要求修改、撤销。
事务费用更低:目前公有链的事务费用是每笔0.10美元,而且随着时间流逝币值趋于增长,导致事务费用也在增长。而私有链的事务费用将会降低一到两个数量级。
仍然是基于分布式网络,保留了分布式记账系统的优点。
提供了更好的隐私保护:公有区块链因为其透明共享总账本的设计,本身不提供隐私保护功能。而私有链可以对读取权限进行限制,从而提供更好的隐私保护。
验证者是公开透明的,不存在一些矿工出于共谋原因而致的51%攻击风险。
节点可以很好地连接:节点互相可以很好地连接,故障可以迅速通过人工干预来修复,并允许使用共识算法减少区块时间,从而更快完成事务。
私有链的缺点:
违背了区块链去中心化的本质,重新引入了若干“信任节点”;
其参与者需要经过审核和验证,从而严格限制了其规模,其安全性容易受到威胁。因此,私有区块链更适合为传统机构所用。
公有链的优点:
保护用户:免受开发者的影响——在公共区块链中的用户更多、更广泛,程序开发者无权干涉
用户的使用方式。反过来说,区块链可以保护使用这些程序的用户。
网络规模效应——公共区块链是开放的,因此有可能被许多外界用户使用和产生一定的网络效应。而在公有链上运行的应用越多,节点越多,那么该区块链条也会越可信。
因此使用公有链,还是私有链,完全根据需求而定。
区块链的演进
区块链1.0:可编程的数字货币
比特币的发明人Satoshi Nakamoto在其2008.11年发表的论文《BitCoin:A Peer-to-Peer Electronic Cash System》中指出:“区块链是指通过去中心化和去信任的方式集体维护一个可靠数据库的技术方案。”
区块链 1.0 的主要应用领域为“加密数字货币”,包括货币的发行机制、分配机制、币值调节机制等。
比特币可视为区块链的首个在金融支付领域中的应用。比特币所产生和使用的区块链,是最早也是目前应用最广泛的公有区块链。
区块链2.0:可编程的智能合约
在2015年10月召开的“2015首届全球区块链峰会”上,以太坊的创始人Vitalik Buterin发表了题为《Visions, Part 1: The Value of Blockchain Technology》主题演讲,并重新定义了区块链:“一个区块链就是一个任何人都可以上传程序并使其自己执行的神奇电脑,每个程序的当前和所有过去状态都是公共可见的,强大的密码经济学保证程序能够按照该区块链协议所定义的方式持续执行。”
区块链成为一种“信任的机器”,通过自我限制和安全加密,确保机器能安全可信地自动执行预设的逻辑。
区块链2.0的主要应用领域为智能合约。智能合约能够令各方自动执行操作,结果由软件验证,而非人类扮演中介。
典型应用:
股权、债权合约
证券与金融合约
互助保险合约
权利登记、转让
博彩
防伪
物联网
区块链3.0:可编程的社会治理
区块链3.0目前没有严格的定义,总的来说有两大类应用:
超越货币、经济、市场的公正性应用。
超越货币、经济、市场的效率和协作。
区块链3.0的主要应用领域为社会治理:
公证、见证
司法仲裁
投票
健康管理
人工智能
去中心化自治组织
身份认证
二、区块链2.0:以太坊Ethereum
Ethereum以太坊是运行在区块链技术上的开放平台,使开发人员能够建立和发布下一代分布式应用DApp。
Ethereum可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易、众筹、公司管理、合约、知识产权、硬件集成的智能资产。
区块链2.0重要的是智能合约、智能资产,而智能合约领域最有影响力的开发平台就是以太坊。
应用场景实例
自行车的所有者会将一个Slock(智能锁)安装到他们的自行车上,并且在以太坊区块链上给自行车注册一个智能合约(一段程序代码)。接下来,任何人都可以向该智能合约发起一个发送一定数量数字货币的请求,合约在接到这个请求之后,会自动将这笔数字货币转发给自行车的所有者,这样发送者可以获得2个小时的使用权。
基本概念
挖矿
挖矿这个词源于对加密货币与黄金的类比。黄金或贵金属很稀有,电子代币也是,增加总量的唯一方法就是挖矿;同时,挖矿也是通过在区块链中创建、验证、发行和传播区块的方法来保护网络的。
挖以太币 = 保护网络 = 验证计算
以太坊,与所有的区块链技术一样,使用激励驱动的安全模式。共识基于选择具有最高总难度的区块。矿工创建区块,其他人检测有效性。
外部账户 vs合约账户
外部账户(EOA)
存储以太币余额
发送transaction(以太币交易或触发合约代码)
私钥控制
没有代码
合约账户
存储以太币余额
相关代码
执行代码(被其他合约的transaction或消息触发)
执行任意复杂的操作;操作自己的永久存储
以太坊区块链上的所有行为都是由外部账户通过transaction触发的。每当合约账户接收到transaction,就按照输入参数的指示执行。合约代码是由参与到网络的每个节点上的以太坊虚拟机执行。
代码执行的唯一语境是区块链上区块的位置和所有可见的数据。区块链的区块代表时间单位,区块链本身是时间维度,代表在链上区块制定的离散时间点上状态的整个历史。
所有以太币余额和价值都以wei为单位:1 ether = 1e18 wei
事务(transaction)
transaction在以太坊里指被签名的数据包,数据包存储着从外部账户发送到区块链上另一账户的消息。
transaction包括:
消息接收人
签名:用于确认发送方身份和发送消息的意图
VALUE:发送方向接收方转移wei的数量
可选数据域,包括发送合约的消息
STARTGAS:代表transaction执行允许采取的运算步骤的最大数量
GASPRICE:代表发送方愿意支付的gas费用
消息(message)
合约可以发送消息给其他的合约。消息是虚拟对象,不能被序列化,只能存在于以太坊的执行环境下。可以被想象成函数调用。
消息包括:
消息发送方
消息接收方
VALUE:发送方向接收方转移wei的数量
可选数据域:发送到合约的实际数据
STARTGAS:限制消息可以触发的代码执行的gas最大值
本质上,消息就像transaction,只不过消息是由合约而不是由外在因素创造的。
GAS
当消息或transaction触发合约执行时,每个指令在每个网络节点都被执行。这是需要代价的:每个执行的操作都有特定的成本,以一定量的gas单元表现。
Gas是transaction发送方需要为每个以太坊区块链上发生的操作所支付的执行费用。Gas名字的灵感来自一个观点:这笔费用就像加密燃料,驱使智能合约的运行。Gas从执行代码的矿工处购买以太币。
Gas和以太币被故意分开,因为Gas单位与自然成本的运算类似,而以太币的价格是根据市场而波动的。
Gas价格实际上由矿工决定,矿工可以拒绝以低于最低限度的gas价格进行transaction。
以太坊客户端会自用使用以太币购买gas,数量是指定的transaction最大支出。
在每个合约执行或每个transaction的运算步骤,以太坊协议都要收费,以防止以太坊网络上发生蓄意攻击或滥用。
每个transaction都必须包含gas限额和愿意支付的gas花费。如果transaction产生的、用于运算步骤的gas总量,包括原始消息和可能引发的子消息,少于或等于gas限额,那么transaction就会进行;如果总量超过限额,那么所有变化都会复原,但是transaction仍然有效,矿工可以收集花费,多余的gas会以以太币的形式偿还给发送方。
估算transaction成本:
transaction花费的以太币总量基于两个因素:
gasUsed是transaction消费的gas总量
gasPrice是gas单元的价格(换算成以太币)
总成本 = gasUsed * gasPrice
gasUsed
以太坊虚拟机上的每个操作都会被指派消费的gas数量。gasUsed是所有执行的操作所需的gas总额。有个电子表格可以看到背后的一些统计。
gasPrice
用户建构并签署transaction,每个用户可以说明自己想要的gasPrice,可以是零。然而Frontier发布的以太坊客户端默认gasPrice是0.05e12 wei。由于矿工会使收入最优化,如果大部分transaction都以0.05e12 wei的gasPrice提交,就很难说服矿工接受价格更低或为0的transaction。
示例transaction成本
我们来做一个只添加2个数字的合约。EVM OPCODE ADD消费3gas。
大概的成本,以默认gas价格计算 (2016年1月)是:
3 * 0.05e12 = 1.5e11 wei
这是个简化的计算,忽略了一些成本。
EVM
EVM:在底层,以太坊基于区块链技术,实现了数据的去中心化、分布式存储和信息交换的信任问题。同时,以太坊实现了一个叫Ethereum Virtual Machine(EVM)的运行时环境,类似JVM,它的主要工作是执行智能合约(该概念下面会介绍)的位元组码。
接口:
1. Javascript Console:以太坊客户端会启动一个相互的console,提供javascript运行环境,可以使用javascript API与节点交互。
2. JSON-RPC server:节点可以启动json-rpc服务器,从而暴露JSON-RPC API
3.命令行:geth
结合以上概念,归纳Ethereum工作流程:
以太坊的基础单元是账户,跟踪每个账户的状态,所有以太坊区块链上的状态转换都是账户之间价值和信息的转移。
外有账户是由人类用户掌控,因为人类用户能够控制私钥,进而控制外有账户。而合约账户则是由内部代码管控。智能合约指的是合约账户中的代码:事务被发送给该账户时所运行的程序。用户可以通过在区块链中部署代码来创建新的合约。
只有外有账户发出事务时,合约账户才会执行相应的操作,合约账户不可能自发地执行。因为以太坊要求节点能够与运算结果保持一致,这就要求保证严格确定执行。
以太坊用户必须向网络支付少量事务费用。这可以使以太坊区块链免受无关紧要或恶意的运算任务干扰,比如分布式拒绝服务(DDoS)攻击或无限循环。事务的发送者必须在激活的合约账户的每一步付款,包括运算和数据存储。费用通过以太坊Gas结算,以太币的形式支付。
事务费用由节点收集,矿工是以太坊网络中收集、传播、确认和执行事务的节点。矿工们将事务分组:以太坊区块链中账户状态的更新被分成的组存储在区块中(Block),矿工们会互相竞争,以使各自的区块(Block)可以添加到区块链的下一个节点上。矿工们每挖到一个成功的区块就会得到以太币奖励,这就为矿工带来了经济激励,促使矿工为以太坊网络贡献硬件和电力。
矿工们通过解决复杂数学问题的任务以便成功地挖到区块(Block)。这被称为工作量证明(PoW)。一个运算问题,如果在算法上解决,比验证解决方法需要更多数量级的资源,那么它就是工作证明的最好选择。为防止比特币网络中已经发生的专用硬件(例如特定用途集成电路)造成的中心化现象,以太坊选择了难以存储的运算问题。这就使以太坊的工作量证明具有抗特定用途集成电路性,和比特币这种由专门硬件控制挖矿的区块链相比,能够带来更加去中心化的安全分布。
三、以太坊开发
搭建本地测试网络
为了搭建本地测试网络,需要完成三件工作:
构建geth客户端
构建solidity编译器
运行geth客户端
以下就分别开始介绍。
Ethereum客户端类似于Java虚拟机,按照黄皮书执行;项目早期,在不同的操作系统中就有多个可以彼此协作的客户端实现:go-ethereum、cpp-ethereum、pyethapp、ruby-ethereum等等。
进入Homestead阶段后,Go客户端(geth)占据了主导地位,因此我们也采用go-ethereum完成测试网络的搭建。
1. 首先在选择的目录下clone客户端代码go-ethereum
2. 构建geth前需要安装额外库:
mac系统:
建议使用gvm管理go的版本:参见-https://github.com/moovweb/gvm
ubuntu系统:
参见-https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Ubuntu
3. 最后,就可以使用以下命令编译geth了:
编译成功生成build/bin/geth
现在进入构建solidity编译器(源码安装)的流程:
1. 首先在选择的目录下clone solidity的编译器代码
2. 安装依赖
3. 最后,就可以使用以下命令编译solc了
geth和solc编译完成后,重新回到go-ethereum代码根目录
1. 创建初始区块:
初始区块是区块链的起始:第一个区块,区块0,唯一没有指向前面区块的一个区块。除非与其他节点具有相同的初始区块,协议确保了这些节点不会和该区块链一致。这样就可以创建任意的私有测试网络区块链。
2. 启动geth:
下面介绍上述命令中的主要参数:
1. --nodiscover:使用这个命令可以确保你的节点不会被非手动添加你的人发现。否则,你的节点可能被陌生人的区块链无意添加,如果他和你有相同的初始文件和网络ID。
2. --rpc:可以激活你节点上的RPC接口。它在geth中通常被默认激活。
3. --rpcapi:这个命令可以决定允许什么API通过RPC进入。在默认情况下,geth可以在RPC激活web3界面。
4. --rpcport:改变RPC上的开放端口。
5. --rpccorsdomain “*”:可以指示什么URL能连接到你的节点来执行RPC定制端任务。
6. --datadir “test/chain”:私有链数据所储存在的数据目录
7. --identity:为节点设置一个身份,使之更容易在端点列表中被辨认出来。
8. --solc:制定solc编译器
智能合约
编写智能合约的高级语言有:solidity、serpent、LLL、Mutan。
Solidity类似于Javascript,也是目前最流行的。
Serpent类似于Python。
LLL是类似于汇编的底层语言。
Mutan是C-like的编程语言,不过已经被废弃了。
我们以multiply为例开始第一个Solidity的智能合约。
第一步:创建一个EOA用户并设置密码
第二步:查看新用户的余额,并且开始挖矿
第三步:新建一个命令窗口,并连接到正在挖矿的窗口
第四步:确认用户余额有所增加
第五步:编译
合约代码如下:
contract test {
function multiply(uint a) returns(uint d) {
return a * 7;
}
}
首先将合约test赋值变量source,然后使用solidity编译器进行编译,将返回结果赋值给contract。
下面简要描述一下contract的字段:
code: 编译的以太坊虚拟机字节代码
info: 从编译器输出的额外元数据
source:源代码
language: 合约语言(Solidity、Serpent、LLL)
languageVersion:合约语言版本
compilerVersion:编译器版本号
abiDefinition:应用的二进制接口定义
第六步:部署合约
确保有解锁的账户和资金,部署完成后,在区块链上就会创建一个合约。这一步骤是需要支付执行的。一旦transaction成功进入区块,账户余额会根据以太坊虚拟机的gas规则被扣减。
第七步:与合约交互
与合约交互典型做法是使用eth.contract()功能的抽象层,它会返回javascript对象。描述合约可用功能的标准方法是ABI定义。
当sendTransaction被调用时,功能调用通过发送transaction来执行。需要花费以太币发送,记录会永久记录在区块链上。这种方式返回的是transaction散列。
当call被调用时,功能在以太坊虚拟机本地执行。用这种方式进行的调用不会记录在区块链上,因此不会改变合约内部状态。这种调用方式被称为恒定功能调用,不花费以太币。
最后,有兴趣的朋友,也可以尝试testrpc和truffle,更加方便。
声明:文中关于“Ethereum Homestead 0.1 documentation”来自ethereum社区。如想了解更多,可通过ethereum社区官网进一步学习。
Q&A
Q1:一次交易都要在以太坊的所有节点的EVM上执行一遍吗?
A1:是的。区块链其实是比较昂贵的,它的目的不是为了提升效率。在Ethereum Homestead里是这样描述的:Each and every full node in the network does the same calculations and stores the same values. Clearly Ethereum is not about optimising efficiency of computation. Its parallel processing is redundantly parallel.
Q2:哪些公司用以太坊做开发基础?
A2:国内的金丘股份,万向区块链实验室,众安保险,蚂蚁金服。
Q3:智能合约的代码量最大是1M吗?也就是一个区块的大小?
A3:1M是比特币的区块限制。
Q4:以太坊同步一次要多久?
A4:比特币区块链的大小约为84.9GB,现在以太坊的区块链还比较小,第一次同步的时候,持续的十个小时左右,于网络速率有关。
Q5:如果由于网络中断,导致出现两条链,当网络恢复后,如何合并这两条链?
A5:不会合并的。最终还是拼的算力。
(接上一问)
Q6:这样不是会导致很多分叉吗?
A6:短时间是可能存在分叉的,但最终不会有分叉存在,例如比特币”为了防止该区块因为子链太短而被其它节点抛弃,那么还得等产生6个新的后续区块,才能最终确认该transaction已经被可靠地写入区块链中。即,确保可靠写入,需要约60分钟。 ”版本升级时,是有可能存在分叉问题的,因为有些矿工不愿意升级。
Q7:如果智能合约太大,无法在一个区块中写入,以太坊如何操作?
A7:因为合约之间可以通过消息调用,所以可以把代码拆开,分别deploy。当然前提是真得有这么大的合约。