直话Neo系列:Merkle Tree

1 篇文章 0 订阅
1 篇文章 0 订阅

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

梅克尔树—文字版

梅克尔树是一种二叉树,由于它能快速检查和归纳大量数据,被用在区块中记录交易记录的完整性.下面是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中梅克尔树的价值通过根节点体现.

梅克尔树—-图解

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会将最后的那个节点复制,然后两两组成他们的父节点,这样结构就完整了.
这个时候就不得不强调一波梅克尔树的一大优点了,那就是能归纳大量数据,你看,通过这么一波操作,一大波交易就被一个梅克尔树根节点代替了.

梅克尔树—-代码版

这一波主要聊聊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的数据指纹里面啦.
如果你是一个节点,那么检查数据是否被修改就只需要计算一下交易记录的梅克尔树的根节点,然后和区块头的梅克尔跟比较就可以得出结果了.这样的检查是不是很快呢.

梅克尔树—-快速检查

这里属于拓展篇了,原因是小生会在这里和大家聊聊bitcoin对梅克尔树另一中应用,那就是SPV(简单支付验证).为什么说是拓展呢,因为在neo中没找着,而这时一个neo系列.
spv是比特币中一种特殊的协议,通过spv,节点不需要获取完整的公链,只需要下载完整的区块头信息,这个数据量大概是完整公链的1/1000左右.当然了,spv的内容还是很多的,但在本文主要聊聊spv通过梅克尔树进行交易验证(ps:谁让这篇文章是梅克尔树的主场呢).
介绍交易验证之前,先来一段代码,毕竟代码即正义

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

这是比特币区块的一段源码,介绍的是区块的属性.可以看出,比特币区块由两部分组成,分别是区块头部和交易树.这里就是bitcoin和neo的区别了.neo在区块的数据区存放的是交易数组,bitcoin存放的是梅克尔树.也正是这种存储结构引出了spv的交易验证.
因为spv的轻量级客户端没有完整的交易数据,那么当它要去检查交易有效性的时候,必然要去向其他的节点问答案.这些节点则会返回给它一份梅克尔路径证明.
梅克尔路径证明
还记得上面的梅克尔树吗?这里的不同第一个就是叶子节点,bitcoin的叶子节点就是交易数据,而neo的则是哈希值.第二个就是上面涂了不同颜色的块了.
假如现在spv需要验证高度30000区块上的交易e的有效性,那么它首先会去获取涂成黑色的那几个区块,然后通过e—>f —> H(gg) —> H(H(ab)+H(cd)),最后计算出梅克尔跟节点的哈希值,这样就可以和区块头中的梅克尔跟做比较了.然后spv会等待区块累计,当高度达到30006后,就会承认这个交易的有效性.而黑色的那条路径就被称为梅克尔路径证明了.

end

梅克尔树在区块链中是很鲜明的一种树形结构,不仅能提高数据验证的效率,而且能将大量数据归纳为很小的哈希值(neo:256bits).

好吧,结尾很有点干,结束吧,后面还会有很多关于区块链的分享,期待与您共享共赢~

简书地址:https://www.jianshu.com/p/2b082157b3b0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值