MerkleTree in BTC
Merkle 树是一种用于高效且安全地验证大数据结构完整性和一致性的哈希树。它在比特币网络中起到至关重要的作用。Merkle 树是一种二叉树结构,其中每个叶子节点包含数据块的哈希值,每个非叶子节点包含其子节点哈希值的组合哈希。
比特币网络中的 Merkle 树
在比特币区块链中,每个区块包含多个交易。为了高效地验证区块内的交易,比特币使用了 Merkle 树。区块头包含一个 Merkle 根(Merkle Root),代表了该区块内所有交易的哈希摘要。
Merkle 树的构建
- 叶子节点:每笔交易的哈希值被用作叶子节点。
- 非叶子节点:每对叶子节点的哈希值被组合并哈希,形成上一级节点。这个过程递归进行,直到形成唯一的根节点,即 Merkle 根。
Merkle 树的生成示例
假设一个区块包含四笔交易 \(T1\)、\(T2\)、\(T3\) 和 \(T4\)。生成 Merkle 树的步骤如下:
计算每笔交易的哈希值 \(H1\)、\(H2\)、\(H3\)、\(H4\):
\[H1 = \text{Hash}(T1)
\]\[H2 = \text{Hash}(T2)
\]\[H3 = \text{Hash}(T3)
\]\[H4 = \text{Hash}(T4)
\]计算相邻交易哈希的组合哈希 \(H12\) 和 \(H34\):
\[H12 = \text{Hash}(H1 || H2)
\]\[H34 = \text{Hash}(H3 || H4)
\]计算根节点哈希 \(H1234\):
\[H1234 = \text{Hash}(H12 || H34)
\]
最终,\(H1234\) 就是包含这四笔交易的 Merkle 根。
Merkle 树的作用
- 验证交易:通过 Merkle 树,可以高效地验证某笔交易是否包含在某个区块中,而不需要检查整个区块。
- 轻客户端(SPV):简化支付验证(SPV)客户端可以通过请求区块头和所需交易的 Merkle 路径来验证交易,而不需要下载整个区块链。
Merkle 路径验证
假设我们要验证交易 \(T3\) 是否在某个区块中:
- 获取交易 \(T3\) 的哈希 \(H3\)。
- 获取 \(H3\) 的相邻哈希 \(H4\)。
- 计算组合哈希 \(H34 = \text{Hash}(H3 || H4)\)。
- 获取 \(H34\) 的相邻哈希 \(H12\)。
- 计算根节点哈希 \(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的更多相关文章
- 区块链基础认识-BTC
1.什么是区块链 a.定义: 从本质上来说区块链就是一种通过将用户的某种特定信息(比如交易信息),通过很多台计算机记录保存并同步的过程,每个区块都记录了对应的交易信息,将这些交易信息串联起来就形成了所 ...
- js 校验 btc eth 地址
NPM 安装 npm install wallet-address-validator Browser <script src="wallet-address-validator.mi ...
- ECC椭圆曲线以及计算出公钥的过程(BTC为例)
ECC概念 全称 “ Ellipse Curve Cryptography ” means “ 椭圆 曲线 密码学 ”. 传统加密方法大多基于大质数因子分解困难性来实现,ECC则是通过椭圆曲线方程式 ...
- [转]BTC RPC API GetTransaction
本文转自: GetTransaction GetTransaction gettransaction调用获取指定钱包内交易的详细信息.该调用需要节点 启用钱包功能. 参数 TXID:要查看详情的交易I ...
- [转]BTC手续费计算,如何设置手续费
本文转自:https://blog.csdn.net/servletcome/article/details/81941334 首先BTC的交易手续费和交易金额是没有关系的.不要误认为交易的金额越大手 ...
- 挖矿程序的工作原理(BTC为例)
Mining时代进化:CPU挖矿 -> GPU挖矿 -> FPGA挖矿 -> ASIC挖矿CPU挖矿时代:SENGENERATEGPU挖矿时代:GETWORK Miner:挖矿的程序 ...
- 区块链区块的生成和链接,比特币btc的产生,UTXO的生成和消耗,比特币系统
区块链区块的生成和链接,比特币btc的产生,UTXO的生成和消耗,比特币系统 区块链区块的生成和链接,比特币btc的产生,UTXO的生成和消耗,比特币系统
- BTC和BCH 区别和联系?
在比特币刚刚出现的时期,中本聪对区块的大小限制在1M.这种限制既保障性能较弱的个人电脑能够参与其中,同时也起到了防止攻击者让比特币网络超载的风险发生,毕竟那时系统还很脆弱.在1M的限制下,10分钟一个 ...
- BTC钱包对接流程
BTC钱包对接流程: 部署钱包节点 分析钱包的API 通过JSON-RPC访问钱包API 部署测试 1.部署钱包节点 虚拟币交易平台对接所有的虚拟币之前,都要在自己的服务器上部署一个钱包节点,首先要找 ...
- 比特币BTC全节点搭建
比特币BTC全节点搭建 #环境 ubuntu 16.4 #硬盘500GB #截止2018-12-31磁盘占用超过230GB #客户端安装 #下载页面 #https://bitcoin.org/zh_C ...
随机推荐
- 【工程实践】go语言实现MerkleTree
简介 默克尔树(MerkleTree)是一种典型的二叉树结构,其主要特点为: 最下面的叶节点包含存储数据或其哈希值: 非叶子节点(包括中间节点和根节点)的内容为它的两个孩子节点内容的哈希值. 所以底层 ...
- Vben-admin---ApiSelect Invalid prop: type check failed for prop "onUpdate:value". Expected Function, got Array
在basicFrom组件里添加一个ApiSelect, <template #localSearch="{ model, field }"> <ApiSelect ...
- jeecg-boot中导出excel冲突问题
jeecg-boot自带的库是autopoi,如果自定义导出excel引入poi,则需要POI版本要保持一致,否则会出现冲突的情况,导致这2个都用不了的情况. Autopoi底层用的是POI库,poi ...
- Django信号与扩展:深入理解与实践
title: Django信号与扩展:深入理解与实践 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 后端开发 tag ...
- PageOffice 6 给SaveFilePage指向的保存地址传参
PageOffice给保存方法传递参数的方式有两种: 通过设置保存地址的url中的?传递参数.例如: poCtrl.setSaveFilePage("/save?p1=1") 通过 ...
- Java学习之旅(day.09)
封装 把数据包装起来,给你能看的,不能看的包装起来不让你看 该露的露,该藏的藏 程序设计要求"高内聚,低耦合". 高内聚指类的内部数据操作细节自己完成,不允许外部干涉: 低耦合指仅 ...
- kubernetes 之二进制方式部署
我的资料链接:https://pan.baidu.com/s/18g0sar1N-FMhzY-FCMqOog 两种集群架构图 多master需要在集群上面加个lb,所有的node都需要连接lb,lb帮 ...
- Java手机号校验规则最新
一.最新的Java手机号校验规则 在Java中,进行手机号校验通常使用正则表达式(Regex)来匹配手机号的格式.以下是一个基于当前(截至2024年)中国手机号规则的校验方法: 中国手机号通常以数字1 ...
- Python提取文本文件(.txt)数据的方法
本文介绍基于Python语言,遍历文件夹并从中找到文件名称符合我们需求的多个.txt格式文本文件,并从上述每一个文本文件中,找到我们需要的指定数据,最后得到所有文本文件中我们需要的数据的合集的方法 ...
- Vue cli之项目打包
在项目根目录中执行如下命令: npm run build 注:Vue脚手架打包的项目必须在服务器上运行,不能直接双击运行: 在打包之后项目中出现 dist 目录,dist 目录就是 Vue脚手架项目的 ...