1.1 区块链基础知识
本节将简单介绍区块链公链的基本概念和技术架构,从交易的产生到“区块”这个名称的产生,从挖矿到区块链攻击,从公链基础功能到基于公链操作系统的可编程环境。本节将从不同的角度,对公链的基本技术术语进行简明阐述,对公链底层技术感兴趣的读者可以根据本文的介绍,检索相关资料,比特币和以太坊在官网都有详细的技术文档和资料,感兴趣的读者可以自行检索,本节仅讲解与DAPP开发相关的技术点。
1.1.1 交易
区块链通常被理解为超级账本,账户与账户之间可以通过交易来完成转账,只是这种转账方式与传统的银行转账有很大的不同。
(1)这是一个完全去中心化的金融系统,区块链账户不需要使用者到银行机构或者其他部门申请,因为整个系统中没有这样的中心化部门来管理账户信息,使用者只需要根据一种非对称加密算法来生成一个密钥对,其公钥作为账户地址,也就是常说的区块链钱包地址,这个地址可以在网络中广播,允许网络中所有的账户获取和使用,如图1.1所示。
图1.1 以太坊钱包的地址
该账户地址是公开的。私钥作为转账交易的签名和密码,由使用者私人保管,每次转账时,需要通过私钥签名来证明交易的合法性。在现实使用中,私钥往往非常长,而且非常复杂,因此区块链钱包会将私钥进行对称加密,通过使用者输入人类能够理解的密码作为私钥加密的密钥,将区块链密钥以密文的形式保存在磁盘空间里。但是如果忘记解密密钥的密码,用户就失去了对账户的操作权限,也就是说即使账户有余额并且可以查看,也无法进行转账和使用,这就是社交媒体经常报道的丢失比特币的情况。
(2)这是一个完全无中心的账本系统,其交易方式与传统的交易系统有着本质的差别,传统的银行系统中,当A转账100元给B时,银行从数据库中将A的账户扣除100元,同时在B的账户下增加100元。在这个过程中,数据库是在银行的严密保护下操作的,扣除与增加金额的操作需要很高的安全级别才能进行,并且查询余额用的数据库和真正写入的数据大多数情况下是分离的。尤其需要注意的是这个过程生成的交易记录至少有2条:1条是从A的账户下扣除金额的记录,另1条是在B的账户下增加金额的记录。
而发生在区块链上的交易则完全不一样,在区块链上每一笔交易都是一条转账记录,如果该交易成功被整个区块链网络认可则转账成功,并且会将转账记录存储在区块链的数据库里面,每个区块链节点都可以访问和操作这个数据库,并且任何人都可以查询交易双方的账户信息。对于比特币网络来说,BTC的转账,除了转给对方,还要将账户下的余额转给自己,这样就会生成多条记录,这样做是因为BTC没有账户余额的设计。
如图1.2所示,Bob给Alice转0.5 BTC时,会生成2条交易记录,1条记录是Bob→Alice,另1条是Bob→Bob,这些交易使用了非对称加密技术的加密和验证签名技术,这个过程属于区块链公链的设计范畴,不在本书讨论范围内。需要指出的是,这样可以在没有任何中心化银行提供服务并且没人掌握交易接收者或者发送者密钥的情况下,实现公开、安全的转账交易。即使交易数据公开在网络中传播,也无法被篡改,即无人可以将Bob转账的0.5 BTC修改为5 BTC,因为任何数据的变更都会导致数据的Hash值变化,进而导致数据的签名无法被校验通过,进而无法被全网认可,也就是说伪造任何报文和交易,都是无法被网络认可的。这样,比特币在没有银行并且公开交易信息的情况下也能转账。
图1.2 比特币网络交易
(3)发生在区块链上的交易,是存储在区块链网络中的所有全节点(拥有所有交易数据的区块链节点叫作全节点)上的,并且也是公开可查的,用户不仅可以查询某个账户下的所有交易,还可以查看其账户余额,这与银行的交易记录也是截然不同的。图1.3所示为比特币区块链浏览器,这些查询系统被称作区块链浏览器。与银行不同的是,即使能看到区块链交易的所有细节及所有账户的余额,也无法将账户与现实世界中的人联系起来,这与银行系统的账户设计完全不同。
图1.3 比特币区块链浏览器
1.1.2 区块
所有的交易信息都会形成一个结构化的账本,它们会被区块链的节点(矿工)按照一定的方式和时间间隔组织起来,存储在区块链节点中。这个用于存储交易信息的结构体就是区块,除了交易信息,区块还要存储一些额外的信息以保证交易数据的完整性和可靠性,区块数据结构如图1.4所示,该结构图仅仅列举了一些关键信息,不同的公链有各自不同的设计。关于区块的生产间隔,不同的区块链网络有不同的设定,比如以太坊出块的时间间隔约为15s,而比特币网络则需要10min才生产一个区块。
图1.4 区块数据结构
区块数据包含区块头与区块体,区块体存储具体的交易及交易相关的原始数据,区块头存储的是原始数据的Hash信息,任何对原始数据的修改,都会引起区块头Hash值的变化,这样对任何信息的篡改都很容易被察觉到并被验证为假数据。除了交易原始数据和对应的Hash信息,还有一些为了维持区块安全性和有效性的附加信息,比如区块高度、区块难度、矿工地址等;不同的公链系统,还有不同的额外信息,比如以太坊会有状态变更的原始数据和对应的默克尔树信息、收据信息和账户余额信息等。
因此,区块的作用就是将不同时间阶段内的交易数据按照一定的格式和数量,打包成结构化数据,方便存储和管理。只有被打包到区块中并且被全公链网络认可的交易,才能算真正的有效交易,此时账户下面的数字货币的数量才会真正地发生增减,如果交易失败则转账无效。
1.1.3 链
区块头和区块体数据也会被当作输入数据做一次Hash运算,其运算结果会被存储在下一个区块的区块头中,这样任何区块内容的修改都会反映到区块的Hash值上,而区块的Hash值又是下一个区块的输入数据,它又会被当作新区块的数据参与一次新区块的Hash运算,随着时间的推移和交易量的增加,所有的区块会通过保存前一个区块的Hash运算结果的方式组成一条链。
图1.5所示为区块链数据结构,对这个链的数据进行任何篡改,都需要修改此链的所有数据及对应的Hash值,只有这样篡改数据才能被校验为正确的数据。这需要非常强大的算力来支持,同时需要比较长的时间才能完成,而在篡改数据的过程中,还会不断有新交易加入区块链,因此从工程实现的角度来讲,这种篡改需要消耗极大量的能源并需要组织巨大量的计算资源,从经济的角度来讲,进行篡改不如进行算力挖矿划算,完全得不偿失。
图1.5 区块链数据结构
将交易打包成数据块,再将数据块以Hash值的方式组织成链式结构,就是区块链定义的来源。这种结构有点类似于计算机数据结构中的单向链,不同的是,这个链式结构不再局限于单个计算机,而是由分布在全世界的节点构成,任何人都可以公开查询,但又无法任意修改。
1.1.4 挖矿
区块在被增加到区块链之前,并不是所有区块都可以生成区块数据,也不是所有区块数据都能被增加到区块链成为最新的数据,这个过程有一定的门槛,需要筛选出一个值得信任的节点来生成数据,然后由其他节点来验证其生成数据的有效性。这个生产区块的过程会得到数字货币的激励,因此很多节点会加入生产区块的竞争。如果某个节点生产的区块数据得到了其他节点的验证,则其他节点会将最新的区块存储在本地,然后加入下一个数据块的生产竞争,这个过程被称作挖矿,而生成数据的节点被称作矿工。
如图1.6所示,所有的交易会被保存在一个交易池中,不同的矿工会选择不同的交易进行打包,然后制作属于自己的区块,假设当前将要生成的区块编号是121,因为区块链网络是一个点对点的网络,没有中心节点进行协调,所以这些矿工节点无法感知到彼此的存在。
在矿工将交易打包成区块之后,还需要查找一个数字n,这个数字n需要满足图1.6中的不等式,得到该数字之后将其放入打包的区块数据中,然后将该区块数据广播到区块链网络中,如果该区块被认可,则这个矿工就成了区块高度121的出块人,而网络中的节点将新生产的区块存储在本地,并将其链接到其他区块数据之后,基于此生产下一个区块。计算有效数字n的过程是需要付出算力的,而这个算力付出的过程是值得信赖的,这就是区块链为何可以在没有中心管理者的情况下正常运作,且任何人都可以在无须信任的情况下参与区块链业务,正所谓“In math we trust”。
图1.6 矿工从交易池中选择交易打包,并通过寻找满足不等式的数据n来挖矿
成为出块人就可以成功拿到奖励,奖励分为系统的奖励和交易中的交易手续费,在每一笔交易数据中,转账人都可以手动设置手续费,这些手续费用于奖励矿工打包的工作。在转账时设置的手续费越高,转账时间就越短,转账速度就越快,这是因为矿工们会优先选择手续费高的交易进行打包,而如果交易的手续费过低,很有可能会因为没有矿工愿意为其打包而导致转账失败。
1.1.5 共识算法
在挖矿的过程中,矿工需要付出算力来查找一个满足条件的数字,这种算力的付出是无法伪造的,必须付出相应的算力和电力之后才能得到正确的数字。当某一个节点发现该数字之后,其他节点可以很快验证该数字的有效性,验证并不用花费太多的算力和能源。也就是说图1.6中查找满足不等式条件的数字的过程是困难的,但是验证不等式的过程是简单的。这种为了持续生成区块而被所有网络节点认可的方案就叫作共识算法,而付出算力来证明自己工作的共识算法被称作PoW(Proof of Work)。
除了PoW这种共识算法,还有一些其他的共识算法,它们的特征都是一样的,全网节点都共同认可并遵守该算法,并且该算法产生的结果无法被伪造,但是可以被轻易验证。目前比较流行的共识算法有DPoS、BFT和PoST等。
● DPoS算法类似于民主选举的运行模式,该算法根据数字货币持有的数量对区块事务进行投票管理,并且轮流来选举出块人进行出块,笔者认为这种弱中心化的方案与区块链的根本价值观背道而驰,但是在编写本书之时,此方案仍然流行。
● BFT是著名的拜占庭容错机制,该机制的产生有着有趣的背景故事,读者可以自行查找相关细节。简单来讲,该方案通过多次通信交互来区分恶意节点和诚实节点,接收诚实节点的区块数据,丢弃恶意节点发送的数据和消息。
● PoST是存储公链的共识算法之一,即统计节点有效存储的数据的大小和时长,将其作为节点的算力,来竞争成为出块节点,算力越大成为出块节点的概率越高,算力越大生成恶意数据的动力就越小,这是通过一种经济手段约束恶意行为的共识算法。
以上共识算法只是众多公链共识算法中的一小部分,是目前比较流行的几种方案。关于算法的技术细节,读者如果感兴趣,可以以本节的内容为线索,进行深入的探究。由于这些技术已经超出了本书的范畴,所以本书仅做简单论述,不再详细讲解。
1.1.6 分叉
因为整个区块链系统是点对点的对等网络,没有统一的中心机构协调各个节点的行为,所以在生产区块时,各个节点的行为都是相互独立的,很有可能同时由多个矿工在同一区块高度生产出2个以上的区块来。这些区块打包的交易很可能是不一样的,同时满足条件的数字n不是唯一的,多个矿工之间生产的数字n是不一样的,但是同样是满足不等式的。在这种情况下,网络中的其他节点很可能同步到不同的区块数据,并且这些数据在数学上都是合法的、有效的。当不同的节点中的不同的区块作为当前最新区块时,就会存在分叉的情况,即不同的矿机对同一高度的区块生产了内容不一样的新区块,并且这些矿工都找到了满足不等式的数字n。
如图1.7所示,矿工A和B同时对编号121的区块进行打包并签名,它们同时广播了自己的区块到系统中,不同的节点有些会收到矿工A的区块数据,然后验证通过,并加入本地的账本,有些会收到矿工B的区块,这样整个系统的账本就会出现不一致的情况。为了解决这个问题,区块链采用了一种长链抛弃短链的决策方式:即当矿工C挖出了第122块数据,并将数据指向了矿工B的121区块时,因为矿工B所在的区块链更长,凝聚了更多的算力,既是最安全的,也是付出算力和资源最多的,此时矿工A所在的区块链在区块120位置发生的分叉将会被抛弃。区块121_A内所包含的交易也将失败,如果有一笔交易既被区块121_A打包,又被区块121_B打包,那么即使区块121_A被抛弃,该交易仍然成功;如果交易只在121_A区块中,则交易会在短链被抛弃前显示成功,在短链被抛弃后显示失败,失败后交易双方的账户余额会恢复到转账之前的状态。
这个分叉非常像我们在微信群里参加某项活动时的报名接龙,由于报名者在看到报名接龙消息后,并不知道其他报名者的报名意愿和状态,很可能出现多个人报同一个序号的情况,在这种情况下,接下来的人会选择其中一个信息次序往下接龙,而未被选中的那一个次序将被抛弃,被抛弃的报名者只能基于最新的接龙信息来重新报名。
图1.7 分叉
1.1.7 攻击
区块链对于交易的组织方式及账户的管理方式决定了只有私钥持有者才有权修改本账户下的数字货币信息。任何区块链网络中的参与者都无法控制或者篡改其他人的账户信息,也可以说从经济的角度看,篡改这些数据的成本极高,这与中心化的银行有着完全不同的特点,在前文曾讲到的A转100元给B的过程中,如果银行有内部员工,在给A扣除金额或者给B增加金额的环节修改数据,则A和B都无法控制这样的事情发生。
但是这并不意味着区块链是绝对安全的,不同于攻击银行是违反法律法规的情况,由于区块链网络是无主的,每个持有数字货币的账户和区块打包的矿工都无须审批、无须信任,随时随地可以参与,因此,只要拥有足够的算力就可以对整个网络发起攻击,比如著名的51%算力攻击,BCH区块链网络的算力大战就证明了区块链在安全上也有自己天然的弱点。除了算力攻击,还有很多中心化银行不会存在,仅属于区块链点对点网络特有的攻击,比如女巫攻击、日食攻击等,在本书的最后会对此类安全问题做一个较为概括的论述。本节仅以一种算力攻击为例,简单讲解一下区块链特有的安全问题。
结合上一节讲到的分叉问题,如果矿工D拥有足够的算力,则当矿工A生产区块121时,矿工D已经生产了区块121,但是矿工D可以将最新的区块保留,而不是将其广播到网络中(区块链代码都是开源的,任何人都可以修改属于自己的版本,只要符合区块链的基本协议,就可以加入区块链网络,只要其行为被网络中的其他节点认可即可),并且继续生产最新的区块122,这样在A生产出来121区块之后、其他矿工生产122之前,矿工D可以将区块121和122一次性地全部广播到网络中,那么之前矿工A生产的区块就会被当作短链而抛弃,而矿工A中的所有交易也将被重置为失效。
在这样的一种攻击模型下,假设Alice在矿工A生产的区块中发生了一笔交易,这笔交易是将余额转到数字货币交易所变现,在数字货币交易所收到这笔交易之后,Alice在数字货币交易所的账户余额会增加。然后Alice将矿工D的2个区块同时广播,则Alice转账到交易所的交易就会失效,Alice的区块链账户余额会恢复,但是因为数字货币交易所的数字余额是中心化管理的,在感知到区块链被攻击之前,Alice可以将数字货币兑换成法币。这样Alice就可以在数字货币余额不变的情况下将其成功变现为法币。