区块模型设计
账本(交易模型)已经介绍完毕。比特币中的两种交易包括用户交易和系统交易,就是转账和挖矿,都会记录到账本中,然后把交易打包成区块,加入到区块链中。
下面介绍区块模型的设计,区块链是区块的一个列表,可以看做一个list形式,区块本身可以看做一个存储交易信息的数据块。区块的信息包括:
区块的索引号
当前区块的hash值
前一个区块的hash值
计算hash值的次数(工作量证明)
生成区块的时间戳
当前区块的交易集合
上面是一个简单区块模型的设计。
共识机制
上面的区块模型设计中,大部分属性都容易理解,只有一个计算hash值的次数,也就是工作量证明属性是一个新概念,下面来详细了解一下。
提到工作量证明,得先说一下共识机制。看到共识机制这几个字,从字面意思来看,共识就是一群人在某一件事上面达成一致意见。比如出现了一个大家都认可的规则,那么大家的一致认可,就是共识。而在这个规则出现之后,如何去让大家认可这个规则、达成共识并去维护发展共识的方式,就是共识机制。
在1982年,莱斯利·兰伯特提出了一个针对点对点通信中的基本问题——分布式系统一致性问题,也就是拜占庭将军问题。这个问题的核心理念是:在整个网络中的任意节点都无法信任与之通信的对方时,如何能创建出共识基础来进行安全的信息交互而无需担心数据被篡改。
莱斯利·兰伯特说:故事让问题变得受欢迎。所以就编了下面这个拜占庭将军问题的故事:拜占庭帝国想要进攻一个无比强大的敌人,派出了10支军队去包围这个敌人。由于各种的原因,这10支军队不能集合在一起进攻,必须分开驻扎,然后同时发起攻击。而这个敌人十分的强大,可以同时抵抗5支拜占庭军队的袭击。拜占庭军队里的任何一支,想要单独进攻的话,都毫无胜算。除非至少超过一半(即6支及以上的军队)同时进攻,才能打败敌人。军队分散在敌人的四周,依靠通信兵来相互传递消息:商量“要不要进攻”和“什么时候进攻”。(因为存在消息丢失的不可靠信道上,试图通过消息传递来达到一致性,是不可能的。所以,在研究拜占庭将军问题的时候,我们已经假定了信道即通信兵是没有问题的,没有叛徒)。
但是如果将军里有叛徒,那么这个叛徒将军可能发送错误消息。比如:告诉其中4只军队要进攻,然后告诉另外5只军队不进攻,然后只有4只军队同时进攻,吃了败仗。剩下5只军队,也无法战胜这个强大的敌人。最后拜占庭军队战败。在这种状态下,拜占庭将军们,能不能找到一种分布式的协议,让他们能够远程协商,并且不用担心有叛徒,保证6支及6支以上军队在同时发起进攻,从而打赢这场仗?
比特币的创始人中本聪解决了这个史上难题,我们都知道比特币是一个分布式网络,一个个节点就像是拜占庭的将军们,至于上述故事中出现叛徒将军发送错误消息的情况,在比特币中很难当个叛徒,很难去篡改真实消息,或者传递假消息。那是因为中本聪在设计比特币系统时,采用了工作量证明机制(POW)。
工作量证明(POW)
什么是工作量证明?还以上面的故事来举例,节点(将军)们会出于自私的目的--奖励比特币(国王的封赏)去争夺记账权(发号施令的权力)并且遵循共识机制(这套奖励规则)。他们需要提供自己的算力来计算,争抢找到一个正确的随机数,就能去记账(发号施令),并且会将该记账信息(号令)同时广播发送到每一个节点(将军)手里,每个节点(将军)都可以对这场竞争胜出的节点的记账信息(号令)进行校验,这样就不会存在故事中有的进攻有的不进攻的情况。一旦有任何节点发现这是在作假,那么这个消息是不会被大家认同的。很难再出现篡改记账信息(传达错误号令)的情况。
如果想成功篡改,那么得要其中一个节点拥有超过系统一半以上的算力(买通超过一半的将军)才行,相对于大家能得到的--比特币奖励(国王封赏)来说,付出那么多简直亏大了,大家都不傻。于是,所有的节点(将军)达成共识,都去乖乖积极挖矿(计算)。这就是比特币的共识机制:工作量证明(POW)。
关于理论,就介绍到这里,网上有很多文章,也有很多书籍来介绍,大家有兴趣可以详细研究各种共识机制。
代码实现
区块模型类代码如下:
其中计算次数在这里简单代表了工作的次数,也就是工作量证明。比特币启动的时候,需要人为写死一个创世区块,这样后来发生的交易都会连接到创世区块后面。
测试挖矿
有了区块模型类,就可以测试基本的挖矿了。首先我们在区块类中创建区块链list:
然后写一个方法来创建创世区块,也就是第一个区块:
然后在Wallet类中定义用户钱包的存储变量:
存储的时候,以钱包地址为key,钱包对象为value,存储在walletMap中。
这样准备工作就做好了,下面来写两个接口:
这两个接口一个是初始化创世区块,一个是用户新建一个钱包,其实就是注册账户。初始化创世区块这一步其实可以在系统启动的时候默认完成,这里为了清晰,写一个方法接口。
下面看一个简单的挖矿接口:
上面的接口中,首先定义了一个系统交易,然后获取区块链中的最后一个区块,工作量属性nonce也是从1开始的,下面的while(true)循环是真正开始挖矿操作。
既然nonce是工作量证明,那么挖矿操作其实就是进行一项工作,什么工作呢?从代码中可以看出,是把上一个区块的哈希值,以及本次交易的数据加上工作量进行哈希操作,然后判断前四位是不是 0000 ,如果是,就相当于挖到矿了。这是一个很简单的工作逻辑,真正的比特币挖矿的工作比这要复杂的多,但是道理是一样的。我们可以把挖矿工作理解为解决一道数学难题,谁的机器快,先解决,谁就先挖到矿。
来测试一下接口,先看创世区块:
再来看新建一个钱包账户:
最后看一下挖矿:
有兴趣可以自己多申请几个钱包多试几次挖矿。另外,创世区块也可以在启动时自动创建: