中本聪在Bitcoin P2P Network的论文提到,Merkle Tree在SPV Client应用。我们知道,SPV Client不储存所有的Transaction。当它要确认某个Transaction是否在Block里,就去问Peer,Peer回传Merkle Path,给SPV Client验证就行了。
本篇提出一些问题给大家深入思考:
问题一:Maerkle Tree存在何处?
我们知道,Merkle Tree是一种Binary Hash Tree。它的用途和原理这里就不多说了,不熟的,请大家自己上网找。为了本文讲解方便,列出相关名词。
Merkle Tree里的Node分为两类,Leaf Node与Non-Leaf Node,Non-Leaf Node里面,还有一个惟一的Node叫Root Node,用来代表整个Merkle Tree。
Merkle Tree
简单来说,每一个Transaction的Hash值存在Leaf Node,两两Leaf Node的Hash值存放在上一层的Node,直到Root Node,其值,就是用来代表Block所包含的所有Transaction。
那么,Merkle Tree存在那里?我一直以为是在Block,后来发现,其实Block只存Root Node,连Leaf Node都不存。除了Root Node之外,其它Node都是依照需要,当场计算出来的。我把Block和Transaction的关系,画成下面这张图:
从图中,我们可以很清楚的知道,Block和Transaction都不存Merkle Tree,连Leaf Node都无,只有存在Block Header的Merkle Root,是用来验证它所包含的Transactions完整性的最后一关。
Full Peer会储存完整的Block:Block Size + Block Header + Transaction Counter + Transactions
SPV (Simplified Payment Verification) Client只存精简的Block:Block Size + Block Header
Full Peer会储存完整的Transaction,但也没有Merkle Tree,甚至连Transaction Hash也没有。
Transaction Input的Transaction Hash指的是关连到上一笔的Transaction,而非这一笔。
由此可知道,整个Blockchain、Block、与Transaction的资料结构,在设计上,是以储存空间最小为考量,而非查询方便为考量。这是因为Blockchain是大家共用的帐本,愈小,愈利于传输。
不管是Full Peer还是SPV Client,Transaction有两项要检查:
Full Peer和SPV Client对这两项的检查方式会有所不同,我将会写另一篇文章探讨。本文拿,SPV Client对Transaction做存在性检查,做为一个例子,解释Merkle Tree在这检查的过程中,起了什么样的做用。
检查Transaction是否真的在某个Block里?我猜想的步骤如下:
这里有一个问题:为何不让Full Peer直接给答案就好了?还要丢一个Merkle Path给SPV Client,让它做二次验证?
这是因为,SPV Client无法确认Full Peer是否可信的?Bitcoin世界里,Blockchain是惟一可信的,当然里面的Block、Merkle Root、Transaction都是可信的。若待验证的Transaction透过Merkle Path,可以接到可信的Merkle Root,那么就可以验证Transaction的存在性。
这种验证Transaction存在性的方法,叫做Merkle Path Proof。再次强调,此法无法验证Transaction的合法性,因为无法证明Transaction的Input不是重覆花费。
若Full Peer是恶意的,分析一下欺骗SPV Client的可能性如下:
Transaction不属于Block1:
Full Peer可以骗SPV Client说:Transaction在Block1里吗?不行,因为很难做出一个假的Merkle Path,因为Merkle Root是一个不断SHA256的值,要造假很困难。(题外话,若是SHA1就很容易造假了,因为Google最近发表,在可接受的时间内,产生相同的SHA1出来)
Transaction属于Block1:
Full Peer可以骗SPV Client说:Transaction不在Block1吗?可以。
以后再探讨Bitcoin Network的安全问题。
问题二:除了Merkle Tree,还有什么别的方法,可以用在SPV Client上?
为了建立Merkle Path,Full Peer要先从计算所有Leaf Node开始,再往上算出Non-Leaf Node,直到Root Node。为何不用较简单的List资料结构?Hash所有Leaf Node,放到第1个Node?
List
用List,的确可以减轻Server的运算量,因为不用计算Node。但从Full Peer传给SPV Client的资料量会变很多。原来传给SPV Client的只要Merkle Path,只要Log(2, N),现在要N。想像1个Block有1024笔Transaction,其资料量就是 1024 x 36 (SHA256 size) = 36K bytes。如果传的是Merkle Path,其资料量是 Log (2, 1024) x 36 = 360 bytes。
由此可见,Merkle Tree虽然会增加Full Peer计算Node的负担,但不会很多。计算Leaf Node运算量会比较大,因为它是Hash两个32 bytes的Leaf Node。而传输的资料会少很多。
再来看本文最初提的两个问题:
结论:
-Count