大话Neo系列:Merkle Tree

这个系列主要结合neo的源码,和大家分享一下区块链的那些事.
这篇文章和大家家聊聊梅克尔树.

1. 梅克尔树是区块中所有交易记录的数据指纹

梅克尔树是一种二叉树,由于它能快速检查和归纳大量数据,被用在区块中记录交易记录的完整性.下面是neo中Block的属性,是区块的头信息组成:

        public uint Version; //区块版本
        public UInt256 PrevHash; //前一个区块的散列值
        public UInt256 MerkleRoot;// 该区块中所有交易的Merkle树的根
        public uint Timestamp; // 时间戳
        public uint Index; // 区块高度
        public ulong ConsensusData;  //一致性数据  不知道是什么,这个字段以后再说
        public UInt160 NextConsensus; // 下一个区块的记账合约的散列值
        public Witness Script;// 用于验证该区块的脚本

可见区块由区块版本、前一个哈希值、梅克尔树根节点、时间戳、区块高度、下一个区块的记账合约散列、验证脚本组成,今天主要聊一下Block中的Merkle Tree Root.
区块头了解了,那么区块的数据区包含什么了,来了:public Transaction[] Transactions,这就是neo中区块的数据区,一个Transaction的数组.正如大家所知道的:区块链中流通的信息就是交易数据了,在neo中就是Transaction.
将这个的原因是想让大家意识到:梅克尔树在neo中存在于区块头部的根节点,数据区是交易的数组,并不是交易数据的梅克尔树.neo中梅克尔树的价值通过根节点体现.

2. neo生成区块头中的梅克尔根

neo区块中,所有的交易的哈希值构成梅克尔树的叶子节点,叶子节点两两组合做双SHA-256运算得到父节点,以此类推等到最后的根节点,同时根节点被记入区块头部.

    //双SHA-256运算
    public byte[] Hash256(byte[] message)
    {
        return message.Sha256().Sha256();
    }
    //左右孩子组合求父节点的哈希值
    //concat:组合 a.concat(b) = ab
    parents[i].Hash = new UInt256(Crypto.Default.Hash256(parents[i].LeftChild.Hash.ToArray()
.Concat(parents[i].RightChild.Hash.ToArray()).ToArray()));

代码毕竟是一个程序员友好型的东西,那么下面来一波图解,相信聪明的你就get了.


梅克尔树

叶子节点是一个交易的哈希值,父节点的哈希值是左右孩子的哈希值联合进行双哈希运算的来的.大家会看到最后面那个叶子节点和倒数第二个相同.这是因为当缺少一个叶子节点时,梅克尔树会将最后的那个节点复制,然后两两组成他们的父节点,形成了一个完整的树形结构.

neo建树的过程就是通过两两子节点计算父节点的过程.话不多说,源码贴上先

//梅克尔树节点  
internal class MerkleTreeNode
    {
        public UInt256 Hash; //节点哈希值
        public MerkleTreeNode Parent; //父节点
        public MerkleTreeNode LeftChild; //左孩子节点
        public MerkleTreeNode RightChild;//右孩子节点

        public bool IsLeaf => LeftChild == null && RightChild == null;

        public bool IsRoot => Parent == null;
    }
//通过建立梅克尔树获取梅克尔树根节点
private static MerkleTreeNode Build(MerkleTreeNode[] leaves)
        {
            //没有数据,无法建树
            if (leaves.Length == 0) throw new ArgumentException();
            //只有一个数据,那么根节点就是它了
            if (leaves.Length == 1) return leaves[0];
            //父节点数组,new出来的不会保存前面的值
            MerkleTreeNode[] parents = new MerkleTreeNode[(leaves.Length + 1) / 2];
            for (int i = 0; i < parents.Length; i++)
            {
                parents[i] = new MerkleTreeNode();
                //父节点有左右孩子节点
                parents[i].LeftChild = leaves[i * 2];
                leaves[i * 2].Parent = parents[i];
                if (i * 2 + 1 == leaves.Length)
                {
                    //如果叶子节点是奇数,那么最后的叶子节点做复制,两两组成父节点
                    parents[i].RightChild = parents[i].LeftChild;
                }
                else
                {
                    parents[i].RightChild = leaves[i * 2 + 1];
                    leaves[i * 2 + 1].Parent = parents[i];
                }
                //父节点的哈希值为孩子节点哈希值的联合求双SHA256.
                parents[i].Hash = new UInt256(Crypto.Default.Hash256(parents[i].LeftChild.Hash.ToArray().Concat(parents[i].RightChild.Hash.ToArray()).ToArray()));
            }
            //递归计算
            return Build(parents); //TailCall
        }

上面的递归可以通过下面的图示来加深理解

Neo Markle Tree Build

相邻两个子节点组合,生成父节点.缺失右孩子节点的,用左孩子节点补齐.不存储中间变量,只保存最后计算出来的根节点.
通过梅克尔树,大量交易记录就缩小在256bits的数据指纹里面啦.
如果你是一个节点,那么检查数据是否被修改就只需要计算一下交易记录的梅克尔树的根节点,然后和区块头的梅克尔跟比较就可以得出结果了

3. 梅克尔树又用于SPV的交易验证

这里属于拓展篇了,小编想在这里和大家聊聊梅克尔路径认证.归为拓展的原因是neo中没有应用spv.

3.1 spv简介

spv是比特币的轻量级客户端,它的中文为简单支付验证,主要解决的痛点是比特币共识链太大,使非矿工节点需要拉取过多数据。
spv只会下载共识链的去块头的链条,能节省大约1000倍的存储空间。由于没有获取完整的数据,所以spv客户端不能作为矿工节点

3.2 spv通过梅克尔路径进行交易验证

spv没有交易数据,所以如果需要进行交易验证的时候,spv就会发送一条广播,让其他非spv节点给它发送验证数据,bitcoin中,这类数据类型为MerkleBlock。

class CMerkleBlock
{
    public:
        /** Public only for unit testing */
        CBlockHeader header;
        CPartialMerkleTree txn;
        .......
}

这是比特币区块的一段源码,我们暂且称呼它为梅克尔块.
梅克尔块中包含两个重要的数据,一个是区块头,另外一个是梅克尔树。这里的区块头就是比特币区块的区块头,梅克尔树可以根据它的命名看出是一串交易,它实际上是一条梅克尔认证路径。

class CPartialMerkleTree
{
protected:
    /** the total number of transactions in the block */
    unsigned int nTransactions;

    /** node-is-parent-of-matched-txid bits */
    std::vector<bool> vBits;

    /** txids and internal hashes */
    std::vector<uint256> vHash;

    /** flag set when encountering invalid data */
    bool fBad;
    ......

收到spv节点请求的完整节点会把目标区块的区块头和一条验证路径的交易串(交易编号和哈希)发送过来。这样节点就可以通过下图所示的方法进行验证了。(黑色区块就是发送过来的交易)


梅克尔路径证明

spv验证交易e时,只需要通过和交易f、H(gg)、H(H(ab)+H(cd))的计算来计算ROOT的值,然后和区块头中的梅克尔根进行比对就可以进行简单的验证了。这里的整个过程就是梅克尔交易验证,黑色路径为梅克尔认证路径。

3.3 总结

spv可以有效减少非矿工节点对共有链的数据存储,目前neo中并不支持。同时比特币区块数据区存储的是交易的梅克尔树,而neo中则是存放的交易数组。

梅克尔树就讲到这里来,后面还会有很多关于区块链的分享,期待与您共享共赢~

csdn地址:http://blog.csdn.net/little_prog/article/details/79263342

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容