Merkle 树是一种用于高效且安全地验证大数据结构完整性和一致性的哈希树。它在比特币网络中起到至关重要的作用。Merkle 树是一种二叉树结构,其中每个叶子节点包含数据块的哈希值,每个非叶子节点包含其子节点哈希值的组合哈希。

比特币网络中的 Merkle 树

在比特币区块链中,每个区块包含多个交易。为了高效地验证区块内的交易,比特币使用了 Merkle 树。区块头包含一个 Merkle 根(Merkle Root),代表了该区块内所有交易的哈希摘要。

Merkle 树的构建

  1. 叶子节点:每笔交易的哈希值被用作叶子节点。
  2. 非叶子节点:每对叶子节点的哈希值被组合并哈希,形成上一级节点。这个过程递归进行,直到形成唯一的根节点,即 Merkle 根。

Merkle 树的生成示例

假设一个区块包含四笔交易 \(T1\)、\(T2\)、\(T3\) 和 \(T4\)。生成 Merkle 树的步骤如下:

  1. 计算每笔交易的哈希值 \(H1\)、\(H2\)、\(H3\)、\(H4\):

    \[H1 = \text{Hash}(T1)
    \]
    \[H2 = \text{Hash}(T2)
    \]
    \[H3 = \text{Hash}(T3)
    \]
    \[H4 = \text{Hash}(T4)
    \]
  2. 计算相邻交易哈希的组合哈希 \(H12\) 和 \(H34\):

    \[H12 = \text{Hash}(H1 || H2)
    \]
    \[H34 = \text{Hash}(H3 || H4)
    \]
  3. 计算根节点哈希 \(H1234\):

    \[H1234 = \text{Hash}(H12 || H34)
    \]

最终,\(H1234\) 就是包含这四笔交易的 Merkle 根。

Merkle 树的作用

  1. 验证交易:通过 Merkle 树,可以高效地验证某笔交易是否包含在某个区块中,而不需要检查整个区块。
  2. 轻客户端(SPV):简化支付验证(SPV)客户端可以通过请求区块头和所需交易的 Merkle 路径来验证交易,而不需要下载整个区块链。

Merkle 路径验证

假设我们要验证交易 \(T3\) 是否在某个区块中:

  1. 获取交易 \(T3\) 的哈希 \(H3\)。
  2. 获取 \(H3\) 的相邻哈希 \(H4\)。
  3. 计算组合哈希 \(H34 = \text{Hash}(H3 || H4)\)。
  4. 获取 \(H34\) 的相邻哈希 \(H12\)。
  5. 计算根节点哈希 \(H1234 = \text{Hash}(H12 || H34)\) 并与区块头中的 Merkle 根比较。

如果计算出的根哈希值与区块头中的 Merkle 根匹配,则验证成功,说明交易 \(T3\) 包含在该区块中。

btcd 中的 Merkle 树实现

btcd 中,Merkle 树的实现主要在 blockchain/merkle.go 文件中。以下是该文件中关键部分的详细说明:

// HashMerkleBranches 采用两个哈希值,分别视为左树节点和右树节点,并返回它们串联的哈希值。用于帮助生成默克尔树
func HashMerkleBranches(left, right *chainhash.Hash) chainhash.Hash {
// Concatenate the left and right nodes.
var hash [chainhash.HashSize * 2]byte
copy(hash[:chainhash.HashSize], left[:])
copy(hash[chainhash.HashSize:], right[:]) return chainhash.DoubleHashRaw(func(w io.Writer) error {
_, err := w.Write(hash[:])
return err
})
} // BuildMerkleTreeStore creates a merkle tree from a slice of transactions,
// stores it using a linear array, and returns a slice of the backing array. A
// linear array was chosen as opposed to an actual tree structure since it uses
// about half as much memory. The following describes a merkle tree and how it
// is stored in a linear array.
func BuildMerkleTreeStore(transactions []*btcutil.Tx, witness bool) []*chainhash.Hash {
// Calculate how many entries are required to hold the binary merkle
// tree as a linear array and create an array of that size.
nextPoT := nextPowerOfTwo(len(transactions))
arraySize := nextPoT*2 - 1
merkles := make([]*chainhash.Hash, arraySize) // Create the base transaction hashes and populate the array with them.
for i, tx := range transactions {
// If we're computing a witness merkle root, instead of the
// regular txid, we use the modified wtxid which includes a
// transaction's witness data within the digest. Additionally,
// the coinbase's wtxid is all zeroes.
switch {
case witness && i == 0:
var zeroHash chainhash.Hash
merkles[i] = &zeroHash
case witness:
wSha := tx.MsgTx().WitnessHash()
merkles[i] = &wSha
default:
merkles[i] = tx.Hash()
} } // Start the array offset after the last transaction and adjusted to the
// next power of two.
offset := nextPoT
for i := 0; i < arraySize-1; i += 2 {
switch {
// When there is no left child node, the parent is nil too.
case merkles[i] == nil:
merkles[offset] = nil // When there is no right child, the parent is generated by
// hashing the concatenation of the left child with itself.
case merkles[i+1] == nil:
newHash := HashMerkleBranches(merkles[i], merkles[i])
merkles[offset] = &newHash // The normal case sets the parent node to the double sha256
// of the concatenation of the left and right children.
default:
newHash := HashMerkleBranches(merkles[i], merkles[i+1])
merkles[offset] = &newHash
}
offset++
} return merkles
}

BuildMerkleTreeStore 从交易切片创建默克尔树,使用线性数组存储它,并返回支持数组的切片。选择线性数组而不是实际的树结构,因为它可以节省大约一半的内存。下面描述了merkle树以及它如何存储在线性数组中。

         root = h1234 = h(h12 + h34)
/ \
h12 = h(h1 + h2) h34 = h(h3 + h4)
/ \ / \
h1 = h(tx1) h2 = h(tx2) h3 = h(tx3) h4 = h(tx4)

以上存储为线性数组如下:

[h1 h2 h3 h4 h12 h34 root]

如上所示,默克尔根始终是数组中的最后一个元素。


声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。

Author: mengbin

blog: mengbin

Github: mengbin92

cnblogs: 恋水无意

腾讯云开发者社区:孟斯特


MerkleTree in BTC的更多相关文章

  1. 区块链基础认识-BTC

    1.什么是区块链 a.定义: 从本质上来说区块链就是一种通过将用户的某种特定信息(比如交易信息),通过很多台计算机记录保存并同步的过程,每个区块都记录了对应的交易信息,将这些交易信息串联起来就形成了所 ...

  2. js 校验 btc eth 地址

    NPM 安装 npm install wallet-address-validator Browser <script src="wallet-address-validator.mi ...

  3. ECC椭圆曲线以及计算出公钥的过程(BTC为例)

    ECC概念 全称 “ Ellipse Curve Cryptography ”  means “ 椭圆 曲线 密码学 ”. 传统加密方法大多基于大质数因子分解困难性来实现,ECC则是通过椭圆曲线方程式 ...

  4. [转]BTC RPC API GetTransaction

    本文转自: GetTransaction GetTransaction gettransaction调用获取指定钱包内交易的详细信息.该调用需要节点 启用钱包功能. 参数 TXID:要查看详情的交易I ...

  5. [转]BTC手续费计算,如何设置手续费

    本文转自:https://blog.csdn.net/servletcome/article/details/81941334 首先BTC的交易手续费和交易金额是没有关系的.不要误认为交易的金额越大手 ...

  6. 挖矿程序的工作原理(BTC为例)

    Mining时代进化:CPU挖矿 -> GPU挖矿 -> FPGA挖矿 -> ASIC挖矿CPU挖矿时代:SENGENERATEGPU挖矿时代:GETWORK Miner:挖矿的程序 ...

  7. 区块链区块的生成和链接,比特币btc的产生,UTXO的生成和消耗,比特币系统

    区块链区块的生成和链接,比特币btc的产生,UTXO的生成和消耗,比特币系统 区块链区块的生成和链接,比特币btc的产生,UTXO的生成和消耗,比特币系统

  8. BTC和BCH 区别和联系?

    在比特币刚刚出现的时期,中本聪对区块的大小限制在1M.这种限制既保障性能较弱的个人电脑能够参与其中,同时也起到了防止攻击者让比特币网络超载的风险发生,毕竟那时系统还很脆弱.在1M的限制下,10分钟一个 ...

  9. BTC钱包对接流程

    BTC钱包对接流程: 部署钱包节点 分析钱包的API 通过JSON-RPC访问钱包API 部署测试 1.部署钱包节点 虚拟币交易平台对接所有的虚拟币之前,都要在自己的服务器上部署一个钱包节点,首先要找 ...

  10. 比特币BTC全节点搭建

    比特币BTC全节点搭建 #环境 ubuntu 16.4 #硬盘500GB #截止2018-12-31磁盘占用超过230GB #客户端安装 #下载页面 #https://bitcoin.org/zh_C ...

随机推荐

  1. go http请求如果参数中带有"等特殊字符,参数传输可能会出现问题

    编码完整的URL url.QueryEscape(urlStr) 编码完整的URL 如果我们要对完整的 URL 进行编码呢? 就是PHP中 urlencode() 函数的功能. 在 GO 语言下可以直 ...

  2. 数据结构单向链表——找到并输出倒数第k个结点的数据

    /********************************************************************************************** * fu ...

  3. JDK源码阅读-------自学笔记(十八)(java.lang.Enum枚举类)

    枚举类简介 如果有必要定义一组常量的时候使用 所有的枚举类型隐性地继承自 java.lang.Enum,枚举实质上还是类. 每一个枚举中的成员,就相当于枚举的一个对象,默认都是public stati ...

  4. Ceph存储池管理

    目录 Ceph存储池 1. Ceph的存储流程 1. 数据写入 2. 数据读取 2. 资源池的配置 2.1 资源池创建 pgp是什么 (Placement Group for Placement pu ...

  5. Http 代理工具 实战 支持网页与QQ代理

    前言: 有些公司不让员工上Q或封掉某些网站,这时候,干着急没办法,只能鄱墙.如果上网搜代理IP,很少能用,用HTTP-Tunnel Client代理软件,免费的也是经常性的掉线.正好手头上有N台服务器 ...

  6. 智影AI故事转视频创作神器!快速开启AI绘画小说推文之旅

    1.前言 1.1 生成内容形式 生成内容形式主要包含三种,PGC(Professionally Generated Content).UGC(User Generated Content).AIGC( ...

  7. Oracle优化神技之临时表

    Oracle临时表在处理临时数据.会话数据隔离和复杂查询优化方面非常有用. 其底层逻辑是通过Oracle特殊的临时表来减少I/O操作和日志开销,提高了数据库性能和查询效率.开发者可以根据具体需求和场景 ...

  8. 京东web端h5st—4.7逆向分析

    声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 目标网站 aHR0cHM6 ...

  9. [SHOI2011]双倍回文 题解

    [SHOI2011]双倍回文 题解 看了一些写回文自动机的大佬的代码,我深感敬畏,于是我转身向Manacher走去 现在荣登最优解第一页-- 说实话,这个方法的复杂度是很玄学的,但是加了一些优化之后, ...

  10. kettle从入门到精通 第三十课 mysql 数据连接常用配置

    1.我们平常用的最多的数据库就是mysql了,这里我以mysql为例说下数据库连接池配置.为啥要用连接池,因为数据库建立连接很费性能,所以就建立连接池(提前建立好一批连接)缓存起来提高性能.下图中my ...