如何使用Merkle树验证交易区块
扫描二维码
随时随地手机看文章
前言
Merkle根是通过将成对的txid散列一起创建的,它为区块中的所有事务提供了一个简短但唯一的认证。
然后将这个merkle根用作于区块头中的字段,这意味着每个区块头将对区块内的每个事务都有一个简洁的表示。
本教程将演示如何计算merkle根字段。
先决条件
本教程将需要访问比特币节点。我们建议以regtest模式配置节点进行,这样我们就可以自由地玩各种场景,而不必浪费真正的BTC。但是您也可以针对testnet或mainnet配置执行这些操作。
在深入到Merkle树之前,让我们先了解一下它们的操作所需的专业术语,称为hash函数或trapdoor函数。这些函数在一个方向上很容易计算,但在没有特殊信息的情况下(称为“陷阱门”)很难在相反的方向上计算(求逆)。Trapdoor功能广泛用于密码学。散列函数是可用于将任意大小的数字数据映射到固定大小的任何函数,输入数据的细微差异会导致输出数据的很大差异。
其中一些散列函数包括md5、sha1和sha256。
使用sha256的示例
gr0kchain@bitcoindev $ echo -en “Hello World” | openssl dgst -sha256
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
这里我们提供数据Hello World并将其传递到opnessl命令,并带有sha256的摘要标志。我们在这里收到的输出是输入数据的认证a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e。任何在相同输入数据上使用sha256的人都会产生相同的哈希值。对数据的轻微更改会导致完全不同的哈希值。
gr0kchain@bitcoindev $ echo -en “Hello World.” | openssl dgst -sha256
f4bb1975bf1f81f76ce824f7536c1e101a8060a632a52289d530a6f600d52c92
关于merkle树的一些背景
在前面的示例中,我们简要介绍了如何从任意输入数据生成唯一的认证。当我们需要为大量数据提供加密证明时,这非常有用。这些数据可以用所谓的merkle或hash树表示。Merkle Trees是一种数据结构,您可以从中派生与前面所指出的相同的哈希。
merkle树的一个特性是,叶节点层中的任何更改都将导致完全不同的merkle根散列。因此,我们可以使用这个数据结构来验证一组数据的完整性。
从命令行计算merkle根目录
让我们完成生成merkle root所需的步骤:
1、生成一个新地址。
gr0kchain@bitcoindev $ bitcoin-cli getnewaddress
mgKkU7NQsDrMZ6uY1J7on9TyKKeH3FNnhH
2、将比特币发送到新地址。
gr0kchain@bitcoindev $ bitcoin-cli sendtoaddress mgKkU7NQsDrMZ6uY1J7on9TyKKeH3FNnhH 1
a99011a19e9894753d6c65c8fa412838ea8042886537588e7205734d5de8956d
3、生成新区块。
gr0kchain@bitcoindev $ bitcoin-cli generate 1
[
“1e871187ba510207d88f1bb0aa1895fb2420066277fdbba7c857b339810dfcec”
]
4、获取区块的信息。
gr0kchain@bitcoindev $ bitcoin-cli getblock
1e871187ba510207d88f1bb0aa1895fb2420066277fdbba7c857b339810dfcec
{
“hash”: “1e871187ba510207d88f1bb0aa1895fb2420066277fdbba7c857b
339810dfcec”,
“confirmations”: 1,
“size”: 553,
“height”: 132,
“version”: 536870912,
“merkleroot”: “25c8487847de572c21bff029a95d9a9fecd9f4c2736984b9
79d37258cd47bd1f”,
“tx”: [
“3bd3a1309a518c381248fdc26c3a6bd62c35db7705069f59206684308cc237b3”,
“a99011a19e9894753d6c65c8fa412838ea8042886537588e7205734d5de8956d”
],
“TIme”: 1553088284,
“medianTIme”: 1553087229,
“nonce”: 3,
“bits”: “207fffff”,
“difficulty”: 4.656542373906925e-10,
“chainwork”: “000000000000000000000000000000000000000000000000000000000000010a”,
“previousblockhash”: “78c3c76fe213ca9f5a0f616b155341eb12b963ce10107b18c9ff612cfc90843d”
}
这里我们可以看到该块的两个事务标识符为3bd3a1309a518c381248fdc26c3a6bd62c35db7705069f59206684308cc237b3(我们的coinbase)和a99011a19e9894753d6c65c8fa412838ea8042886537588e7205734d5de8956d(我们上面执行的事务的标识符)
5、接下来,我们需要将这些字节顺序从大到小颠倒过来(网络字节顺序)
gr0kchain@bitcoindev $ (export LC_ALL=C; xxd -revert -plain
《《《 3bd3a1309a518c381248fdc26c3a6bd62c35db7705069f59206684308cc237b3
| rev | tr -d ‘ ’ | xxd -plain | tr -d ‘ ’)
b337c28c30846620599f060577db352cd66b3a6cc2fd4812388c519a30a1d33b
gr0kchain@bitcoindev $ (export LC_ALL=C; xxd -revert -plain
《《《 a99011a19e9894753d6c65c8fa412838ea8042886537588e7205734d5de8956d
| rev | tr -d ‘ ’ | xxd -plain | tr -d ‘ ’)
6d95e85d4d7305728e583765884280ea382841fac8656c3d7594989ea11190a9
注意:此处使用LC_ALL = C删除所有本地化设置。
6、连接这些值并从二进制数据计算sha256摘要
gr0kchain@bitcoindev $ echo -en “b337c28c30846620599f060577db352
cd66b3a6cc2fd4812388c519a30a1d33b6d95e85d4d7305728e583765884280e
a382841fac8656c3d7594989ea11190a9” | xxd -r -p | sha256
c1f8c1f3b52135cf7f9d0f9422d6d826f4097631615fcc44e3ec70461c27b7b2
7、将此值转换为二进制,并在输出上执行另一个sha256操作
gr0kchain@bitcoindev $ echo -en “c1f8c1f3b52135cf7f9d0f9422d6d82
6f4097631615fcc44e3ec70461c27b7b2” | xxd -r -p | sha256
1fbd47cd5872d379b9846973c2f4d9ec9f9a5da929f0bf212c57de477848c825
8、最后,颠倒顺序从小到大。
gr0kchain@bitcoindev $ (export LC_ALL=C; xxd -revert -plain
《《《 1fbd47cd5872d379b9846973c2f4d9ec9f9a5da929f0bf212c57de477848c825
| rev | tr -d ‘ ’ | xxd -plain | tr -d ‘ ’)
25c8487847de572c21bff029a95d9a9fecd9f4c2736984b979d37258cd47bd1f
我们现在有来自bitcoin-cli getblock命令的原始merkleroot值! 您可以根据需要重复此过程。
只包含coinbase事务的区块的merkle根的异常
上述过程的一个例外是为包含单个事务的区块生成merkle根。
gr0kchain@bitcoindev $ bitcoin-cli generate 1
[
“78c3c76fe213ca9f5a0f616b155341eb12b963ce10107b18c9ff612cfc90843d”
]
gr0kchain@bitcoindev $ bitcoin-cli getblock 78c3c76fe213ca9f5a0f616b155341eb12b963ce10107b18c9ff612cfc90843d
{
“hash”: “78c3c76fe213ca9f5a0f616b155341eb12b963ce10107b18c9ff612cfc90843d”,
“confirmaTIons”: 1,
“size”: 181,
“height”: 131,
“version”: 536870912,
“merkleroot”: “4415425121d3e80d3d733323ecdc981d43b6888241b99c0217a6b7184b021f5e”,
“tx”: [
“4415425121d3e80d3d733323ecdc981d43b6888241b99c0217a6b7184b021f5e”
],
“TIme”: 1553088104,
“mediantime”: 1553087066,
“nonce”: 0,
“bits”: “207fffff”,
“difficulty”: 4.656542373906925e-10,
“chainwork”: “0000000000000000000000000000000000000000000000000000000000000108”,
“previousblockhash”: “0d0c6c9b2c5b48451832c15cf6e8856772df2a0760f8614dbc0734e1e9d7171a”
}
在这里我们可以看到merkle root与coinbase事务的事务id相同。还有另一种情况,如果叶节点的数量不均匀,则将现有的tx id附加到叶节点列表以计算第一级散列对。
结论
在本教程中,我们研究了hash函数、merkle树以及如何计算merkle根。