Skip to content

Commit 441adc0

Browse files
committed
增加新文章: 区块链的完整性校验方案: Merkle Tree
1 parent f4f632c commit 441adc0

9 files changed

+121
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
+++
2+
title = "区块链的完整性校验方案: Merkle Tree"
3+
date = 2024-10-12T18:22:00-07:00
4+
lastmod = 2024-10-12T23:11:56-07:00
5+
tags = ["blockchain"]
6+
categories = ["blockchain"]
7+
draft = false
8+
toc = true
9+
+++
10+
11+
## <span class="section-num">1</span> 前言 {#前言}
12+
13+
最近通过 [Solidity-103](https://www.wtf.academy/docs/solidity-103) 课程在学习 Solidity, 看到[第36课](https://www.wtf.academy/docs/solidity-103/MerkleTree/) Merkle Tree 的时候着实头疼, 即使我已经了解 Merkle Tree 这数据结构,但是课程还是看得不明所以。 <br/>
14+
15+
所以写下这篇文章,梳理我所理解的 Merkle Tree 及其用途,既加深自己的理解,又践行了[费曼学习法](https://ramsayleung.github.io/zh/post/2022/feynman_technique/) <br/>
16+
17+
18+
## <span class="section-num">2</span> 区块链与交易 {#区块链与交易}
19+
20+
关于区块链的资料有非常多,我也不赘述了. <br/>
21+
22+
简单理解,区块链是由一个一个区块构成的有序链表,每一个区块都记录了一系列交易,并且,每个区块都指向前一个区块,从而形成一个链条。区块链听起来很高级,其实就是个单链表。 <br/>
23+
24+
{{< figure src="/ox-hugo/blockchain.jpg" >}} <br/>
25+
26+
每个区块都会保存对应的交易信息,也会包含元数据信息在头部,包括前一个区块的 hash, 包含的交易数,merkle tree 的根节点 hash,时间戳等信息. <br/>
27+
![](/ox-hugo/block_detail.jpg) <br/>
28+
29+
我们总说区块链是不可窜改,那么它究竟是怎么不可窜改的? <br/>
30+
31+
如果用户想要验证某个区块的某笔交易是否被窜改,他要怎么做? <br/>
32+
最简单的方式自然是把整个区块的交易都下载下来,平均每个区块有1M的数据,验证起来肯定很费时间. <br/>
33+
34+
是否有一个验证方案,可以使用很小的数据集就完成验证? <br/>
35+
36+
有的,那就是 Merkle Tree. <br/>
37+
38+
39+
## <span class="section-num">3</span> Merkle Tree {#merkle-tree}
40+
41+
那什么是 Merkle Tree? <br/>
42+
43+
假如我们有8笔交易被包含在区块中, 每笔交易都可以通过 hash 函数计算出一个 hash 值: <br/>
44+
45+
{{< figure src="/ox-hugo/8transactions.jpg" >}} <br/>
46+
47+
哈希值也可以看做数据,所以可以把 `h1``h2` 拼起来, `h3``h4` 拼起来, 依此类推,再计算出哈希值 `b1``b2` <br/>
48+
49+
{{< figure src="/ox-hugo/merkle_tree_layer_two.jpg" >}} <br/>
50+
51+
递归计算下去,直到计算结果只有一个 hash 值,这个就是所谓的 merkle root, 而 h1-h8 就是所谓的 `leaf node`, 两者之间的就是 `non-leaf node`. <br/>
52+
53+
交易数量恰好是偶数能这么算,如果是奇数,那要怎么算呢?这个时侯,只需要把最后一个 hash 值复制一份,也能算出最终的 merkle root: <br/>
54+
55+
{{< figure src="/ox-hugo/odd_leaf_merkle_tree.jpg" >}} <br/>
56+
57+
58+
## <span class="section-num">4</span> Merkle tree validation {#merkle-tree-validation}
59+
60+
现在有了 Merkle Tree, 如果我们要验证区块中的交易是否被修改,要怎么算呢? <br/>
61+
62+
最简单粗暴的方式肯定是把区块所有的交易下载下来,从头重组整棵 Merkle Tree, 8笔交易计算起来还可以,如果是几千笔呢?几百万笔呢?甚至几亿笔交易呢? <br/>
63+
64+
重组 Merkle Tree 的时间复杂度是 O(N), 如果是1亿笔交易,这意味着你要计算1亿次,太慢了。 <br/>
65+
66+
但是,如果我们利用 Merkle Tree 的特性,从数学的角度,我们只需要少量的Merkle Proof(你可以理解成需要提供的验证数据集), 就可以完成验证. <br/>
67+
68+
回到上文的 Merkle Tree, 假如我们要验证 `tx2` 是否被窜改,我们需要有 Merkle Tree Root 和 Merkle Proof: <br/>
69+
70+
{{< figure src="/ox-hugo/merkle_proof.jpg" >}} <br/>
71+
72+
假设现在我们有 `tx2` 的交易数据,我们只需要 Merkle Proof 提供3个hash 值(图中的绿色部分),然后我们只计算4次(橙色部分),就会算出 Merkle Root Tree 的值,用来和区块头部的 Merkle root 值进行比对。 <br/>
73+
74+
通过 Merkle Proof 提供的数据集,我们就可以把下载8笔交易,计算15次hash,优化成只需3个 hash 值,以及计算4次hash,时间复杂度从O(N)降低成O(logN). <br/>
75+
76+
这个比对似乎不明显,但是以1亿交易为例的话,log(1_000_000_000) ~= 27, 也就是只需要 Merkle Proof 提供27个 hash 值即可, 巨大的性能提升. <br/>
77+
78+
79+
## <span class="section-num">5</span> 区块链的不可窜改性 {#区块链的不可窜改性}
80+
81+
通过Merkle tree root可以保证交易的不可窜改性,而区块 hash 又能保证区块头部的元数据不被窜改. <br/>
82+
83+
因为每个区块都有区块 hash, 区块hash是通过计算头部元数据信息计算出来的: <br/>
84+
85+
{{< figure src="/ox-hugo/block_hash.jpg" >}} <br/>
86+
87+
只要修改了其中一个元数据值,那么 block hash 就会发生变化,而区块链就是一个单链表,通过后一个区块通过 `prev_hash` 指向前一个区块,如果 block hash 发生变化,那么后一个区块就无法正确指向前一个区块了,这个链就断了. <br/>
88+
89+
如果一个恶意的攻击者修改了一个区块中的某个交易,那么Merkle Hash验证就不会通过。 <br/>
90+
91+
所以,他只能重新计算Merkle Hash,然后把区块头的Merkle Hash也修改了。 <br/>
92+
93+
这时,我们就会发现,这个区块本身的Block Hash就变了,所以,下一个区块指向它的链接就断掉了, 他就要把后续所有区块全部重新计算并且伪造出来,才能够修改整个区块链; <br/>
94+
95+
而要修改后续所有区块,这个攻击者必须掌握全网51%以上的算力才行。 <br/>
96+
97+
理论上可行,但是实操难度非常非常非常大. <br/>
98+
99+
100+
## <span class="section-num">6</span> Merkle Tree 版本管理中的应用 {#merkle-tree-版本管理中的应用}
101+
102+
除去区块链,Merkle Tree还被应用于类似 Git 和 Mercurial 这样的版本管理系统中,以Git为例, 假如我们Git项目内有4个文件: <br/>
103+
104+
{{< figure src="/ox-hugo/git_merkle_tree.jpg" >}} <br/>
105+
106+
当你push 代码到远程分支或者从远程分支 pull 代码的时候,Git就计算你的Merkle Tree Root 的值, 比较远程分支的Merkle Tree Root和本地分支的Merkle Tree Root 是否相同: <br/>
107+
108+
如果相同,那就不用更新了;如果不同的话它就会检查左节点或者右节点,并且递归下去, <br/>
109+
直到找到是哪些文件发生了修改,只通过网络传输修改部分的内容, 以提高传输效率. <br/>
110+
111+
不过Git实际用的是Merkle Tree的变体,并不是直接使用Merkle Tree. <br/>
112+
113+
除些之外, Merkle Tree 还在 Cassandra, DynamoDB 这样的NoSQL数据库中被用于检查不同节点数据的一致性, 细节可以看下这个 [Stackoverflow 问题](https://stackoverflow.com/questions/5486304/explain-merkle-trees-for-use-in-eventual-consistency)。 <br/>
114+
115+
116+
## <span class="section-num">7</span> 参考 {#参考}
117+
118+
- [Blockchain for Test Engineers: Merkle Trees](https://alexromanov.github.io/2022/06/19/bchain-test-7-merkle-tree/) <br/>
119+
- [Understanding Merkle Trees](https://medium.com/geekculture/understanding-merkle-trees-f48732772199) <br/>
120+
- [Explain Merkle Trees for use in Eventual Consistency](https://stackoverflow.com/questions/5486304/explain-merkle-trees-for-use-in-eventual-consistency) <br/>
121+

static/ox-hugo/8transactions.jpg

55.9 KB
Loading

static/ox-hugo/block_detail.jpg

74.7 KB
Loading

static/ox-hugo/block_hash.jpg

154 KB
Loading

static/ox-hugo/blockchain.jpg

63.8 KB
Loading

static/ox-hugo/git_merkle_tree.jpg

63.2 KB
Loading

static/ox-hugo/merkle_proof.jpg

137 KB
Loading
94 KB
Loading
175 KB
Loading

0 commit comments

Comments
 (0)