0.前言
在上一篇中,中本聪和Gilfoyle搞定了最简单的点对点网络。但是无法正常运行,因为账本还没实现同步机制。为了解决账本的同步,需要先引出交易的同步。
1.账本不一致
咖啡馆,中本聪对着老板Bob说:“老板,这几天Bitcoin系统要升级,暂时无法用了”
Bob说:“我看到了,你们又是搬机器,又是写代码,这次升级动静够大的。”
中本聪说:“是啊,Bitcoin要发生质变了,对了,你家要是有不用的机器也搬过来,我们需要更多节点。”
Bob说:“好啊,我家还真有一台,不过运行Bitcoin我能得到什么好处呢?”
中本聪说:“好处……这个我得想想,暂时还没有,纯是友情支持。”
Bob说:“好吧,看在你是我的老客户,我去给你搬过来。”
中本聪说:“太好了!你真是个慷慨的老板!”
中本聪对Gilfoyle说:“我们将要有第3个节点啦!现在,我们来解决账本的同步问题吧!”
我们假设一个交易场景:
1.Alice账本中的余额是50,并且记账节点1和记账节点2的账本一致。
2.Alice的客户端连接的是记账节点1。
3.Carol的客户端连接的是记账节点2。
4.Alice向节点1发送一个交易消息:Alice to Bob 50
5.Carol向节点2发送一个交易消息:Carol to Alice 30
6.这时候的Alice的正确余额本应该是30。但是由于账本没有同步,所以在节点1中Alice的余额是0,在节点2中Alice的余额是80,都不正确。(见下图)
账本不一致
面对这个场景,应该如何解决账本不一致的问题呢?
中本聪解释到:“解决这个场景还算简单。只需要节点互相将自己的账本发送给对方节点,收到对方的账本后,找出自己账本中缺少的交易记录,然后将此交易记录补充到自己的账本,这样俩个节点的账本就又一致了。”
在上面这个场景中,
节点1补充进自己账本的交易记录是:Carol to Alice 30。
节点2补充进自己账本的交易记录是:Alice to Bob 50。
这样在俩个节点中的账本又恢复一致,Alice的余额都显示为30。(见下图)
账本的同步
Gilfoyle感叹到:“多亏了UTXO机制,由于没有账户模型,交易不会修改过去的记录,只会在账本中新增交易记录,所以,节点间账本不一致也只会缺失彼此的交易记录,而不会存在数据冲突”
中本聪笑到:“别高兴的太早,我感觉不会这么简单。”
中本聪的直觉是准确的,这个同步机制的确存在漏洞,那就是所谓的双花,这还是等后面问题发生了,我们再去讨论,现在我们看看现在的账本同步方案,有没有什么优化空间。
2.交易的同步
中本聪说:“每次节点接受到新的交易,都发送全量账本给对方节点,这样做太浪费网络资源了,其实只需要将新增的交易记录发送给对方节点就够了。对方节点只需要将这条交易记录补充到自己的账本即可。”
Gilfoyle说:“那就是不再同步账本,而只同步增量交易记录。”
中本聪说:“如果只考虑新增交易记录的同步,那么具体步骤应该是这样的。”
中本聪解释着详细的增量交易同步机制:
1.节点1接受到用户通过轻节点发来的最新交易:Alice to Bob 50
2.节点1将这条交易记录写入账本,同时将交易记录通过自己的Socket Server广播出去。(这里之所以将Socket Server发送消息说成是广播,是因为一个Socket Server会连接多个Socket Client,这个传播路径很像广播。而反过来看,Socket Client主动连接Socket Server的行为则是:订阅,就好像用户通过收音机订阅了一个广播频道一样。所以,每个记账节点即能广播又能订阅。)
3.节点2由于订阅了节点1,所以可以收到这条新增交易消息。
4.节点2不可以直接写入自己的账本,因为自己的账本中没准已经存在相同的交易记录。所以要验证这条交易记录是否已经在账本中存在。
Gilfoyle不解的问到:“为什么会存在相同交易记录呢?”
中本聪解释到:“可能是Alice通过客户端同时在向节点1和节点2发起相同的交易请求。
也可能节点1发送同步消息的时候发重复了,这样第一遍节点2就已经将其写入账本了。”
5.如果本交易记录已经存在于节点2的账本中,则什么都不做,结束本次同步行为。
6.如果本交易记录不存在于节点2的账本中,则将其写入账本,同时将这条交易记录广播出去。提供给其它订阅自己的节点,让其它节点进行增量交易的同步。
Gilfoyle问:“为什么节点2还要再次广播这条同步记录,这条消息源头就是节点1给节点2的,节点2如果再广播出去,不就又到了节点1这里,这样不就形成消息的无限循环了吗?”
中本聪解释到:“不会循环的,因为你看第5条,如果发现交易记录之前存在,就会终止。”
中本聪继续解释到:“而节点2为什么要再次广播呢?这是因为,如果节点3加入到了记账网络中,而节点3只订阅了节点2,没有订阅节点1,那么就需要节点2作为一个传话筒,将自己订阅节点1的同步消息传递给节点3。”(见下图)
节点3只订阅了节点2
Gilfoyle说:“明白了,这样就严谨了,在点对点的网络中,节点的角色即是消费者,又是服务者。真是人人为我,我为人人啊!”
中本聪说:“对,这样任何一个节点,广播任何一条消息,都可以一瞬之间传遍整个网络,一石激起千层浪。”
Gilfoyle说:“这让我想到,上周在我家后院看到了一个飞行中的蜂群,蜂群中没有任何一个蜜蜂发出中心化的指令,但是任何蜜蜂根据自己前方的外界环境刺激,发出的信号可以瞬间传遍整个蜂群中的每个个体,使得蜂群可以像一只灵活的动物一样精准的躲避树木等障碍物。这个飞行的怪物看上去智商还很高呢!这就是点对点网络的精髓之处,网络中的每个个体只需要遵守简单的底层规则,大家连接在一起就可以通过平等的协作涌现极其复杂的行为!”
蜂群即网络
中本聪说:“简单规则衍生复杂行为,群系统很神奇吧!”
3.交易内存池
中本聪说:“既然账本不用频繁同步了,我们可以再优化一下,在记账节点中创建一个交易的内存池。将每次收到的新增交易第一时间放入交易内存池中,而不是写入账本。等内存池中的交易积累了一段时间(例如每隔10分钟),再一次性的写入到账本中。”
Gilfoyle说:“这么做的目的是什么?减少硬盘的频繁写入吗?”
中本聪说:“对,减少频繁写硬盘,因为账本是文件,写文件就是在写硬盘。内存访问速度就要比硬盘访问速度快上10万倍以上。”
这就像什么呢?内存就好似人的短期记忆,比如我们在马路上搭讪了一个美女,问人家要电话号,人家告诉你之后,你先记在脑子里,然后继续和美女聊家常,这样搭讪的节奏才flow。等美女走了,你马上要将刚才脑子里记住的电话号码写在小本子上,以免自己忘了。这就好像交易内存池和账本的关系。
记在脑子里的电话号,方便快捷,不会打断你的搭讪动作连续性,但不稳固,没准一个节点断电重启就丢了。而写在小本子上就很麻烦笨重,但很稳固,节点断电也不会丢。
另外,不光是用户的新增交易,节点间的交易同步也会先写入到交易内存池。
这样,就引出了“交易内存池”这个概念。(见下图)
加入交易内存池
4.后记
虽然加入了交易的同步机制,但是现在的同步机制还是有很多漏洞,需要账本的同步来填补漏洞。
本篇重点讨论了交易的同步,并引出了点对点网络的广播机制和交易内存池等概念,下一篇将要讨论账本的同步。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。