python 简易实现以太坊的MPT树

毕业项目也要设计区块链的块结构,相当伸手党直接找源码,却发现MPT的源码只有go语言的,只好自己做个轮子,只为满足毕业项目需要,很多细节和代码结构没有处理到位,代码重复率也高。做个记录,也希望大家给些建议。
第一次发文,废话不多说,直接贴代码吧,大部分的地方都做了注释。


```python
import hashlib
import time
#定义branch节点类
class Branch_ndoe:
    def __init__(self):
        self.type = 'branch'
        #self.children = {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None,'a': None, 'b': None, 'c': None, 'd': None, 'e': None, 'f': None, 'value': None}
        self.children = {'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, '9': None,
                         'a': None, 'b': None, 'c': None, 'd': None, 'e': None, 'f': None, 'value': False}
        #children字典中的value作为branch表的终止符,同时也记录当前extension节点的状态,没有更新hash值时为False,默认为False
#定义extension节点类
class Extension_node:
    def __init__(self):
        self.type = 'extension'
        self.key = None
        #将branch节点和extension节点捆绑在一起,branch节点作为extension节点的组成元素,对外只有extension和leaf两种类型的节点
        self.value = Branch_ndoe()
        self.prefix = None
        #对节点的hash值
        self.node_hash = None
        #对节点下的数据的hash
        self.node_value = None
#定义leaf节点类
class Leaf_node:
    def __init__(self):
        self.type = 'leaf'
        self.key_end = None
        self.value = None
        self.prefix = None
        #对节点下的数据的hash值
        self.node_value = None
        #对节点的hash值
        self.node_hash = None
#定义MPT树类
class Tree:
    def __init__(self,tree=None):
        #传入MPT树构建
        if tree != None:
            self.root = tree
        #否则,root节点创建新的extension
        else:
            self.root= self.make_extension()
            #默认根节点的前缀是root
            self.root.prefix = 'root'
            #定义树的value和hash
            self.value = None
            self.hash = None

    def add_node(self,node,key,value):
        #父节点为root 的情况
        if node.prefix == 'root':
            #root节点下branch表对应值为空,直接插入
            #默认将key【0】作为extension(root)节点下branch的索引
            #key【1::】才是后续传递的new_key值,即去掉共同前缀的剩余部分
            if self.root.value.children[key[0]] == None:
                self.root.value.children[key[0]] = self.make_leaf(key[1::],key[1::],value)
                # 插入新的leaf节点后,节点数据发生改变,状态改变
                node.value.children['value'] = False
                return
            #root节点下branch表发生冲突,将冲突的节点位置作为参数进行递归
            else:
                self.root.value.children[key[0]] =  self.add_node(self.root.value.children[key[0]],key[1::],value)
                return
        father = node
        #将key值与父节点的前缀字符比较
        #index作为在当前extension(father)节点定位branch表位置的索引
        index = self.diff(father,key)
        #共同前缀
        prefix = key[:index:]
        #除去branch索引后的剩余字符
        new_key = key[index::]

        #如果相同字符数不等于共同前缀长度,则代表新节点与father节点没有共同前缀,发生冲突
        if index != len(father.prefix) and index < len(father.prefix):
            #extension冲突
            if father.type == 'extension':
                #调用函数,创建新的extension节点,解决冲突
                return self.pre_extension(father,prefix,new_key,index,value)
            #leaf冲突
            elif father.type == 'leaf':
                # 调用函数,创建新的extension节点,解决冲突
                return self.pro_extension(father,prefix,new_key,index,value)
        #否则,进入extension的branch中向下遍历
        else:
            #判断extension节点下的branch对应key的value是否为空
            #为空,则添加leaf节点
            if father.value.children[key[index]] == None:
                father.value.children[key[index]] = self.make_leaf(key[index+1::],key[index])
                #插入新的leaf节点后,节点数据发生改变,状态改变
                father.value.children['value'] = False
                return father
                #print(father.value.children[key[index]].key_end)
            #不为空,即发生字符表冲突,向下扩展extension
            else:
                father = self.add_node(father.value.children[key[index]],new_key,value)
                return father
    #解决extension节点与leaf节点的冲突,向前添加extension节点
    def pre_extension(self,node,prefix,key,index,value):
        node_new_prefix = node.prefix[index+1::]
        #创建新的extension节点
        tmp_node = self.make_extension()
        #写入共同前缀
        tmp_node.prefix = prefix
        #将旧的extension节点插入branch表中
        tmp_node.value.children[node.prefix[index]] = node
        #修改旧的extension节点的共同前缀
        tmp_node.value.children[node.prefix[index]].prefix = node_new_prefix
        #插入leaf节点
        tmp_node.value.children[key[0]] = self.make_leaf(key[1::],key[0],value)
        #返回新的extension
        return tmp_node
    #解决leaf节点与leaf节点的冲突,向后添加extension节点,与向前插入基本相同,区别在于不需要修改prefix
    def pro_extension(self,node,prefix,key,index,value):
        leaf = node
        # 创建新的extension节点
        tmp_node = self.make_extension()
        # 写入共同前缀
        tmp_node.prefix = prefix
        # 将旧的leaf节点插入branch表中
        tmp_node.value.children[leaf.key_end[index]] = leaf
        #产生共同前缀,leaf节点的key_end发生改变
        tmp_node.value.children[leaf.key_end[index]].key_end = leaf.key_end[index+1::]
        # 插入新的leaf节点
        tmp_node.value.children[key[0]] = self.make_leaf(key[1::],key[0],value)
        #返回新的extension
        return tmp_node
    #创建叶节点
    def make_leaf(self,key,profix,value):
        tmp_node = Leaf_node()
        tmp_node.key_end = key
        tmp_node.prefix = profix
        # 添加leaf节点的值和hash
        tmp_node.value = value
        #对数据进行hash
        tmp_node.node_value = hashlib.sha256(value.encode('utf-8')).hexdigest()
        #对节点进行hash,顺序在数据hash之后,确保为最后的改动
        tmp_node.node_hash = hashlib.sha256(str(tmp_node).encode('utf-8')).hexdigest()
        return tmp_node

    #创建extension节点
    def make_extension(self):
        tmp_node = Extension_node()
        return tmp_node

    #获取差异值索引
    def diff(self,node,key):
        if len(key) < len(node.prefix):
            lenth = len(key)
        else:
            lenth = len(node.prefix)
        count = 0
        while count < lenth:
            if node.prefix[count] != key[count]:
                return count
            count+=1
        return count
    #遍历MPT树查询
    def traverse_search(self,node,index):
        #最终返回的节点的索引
        result_node = None
        #遍历当前extension节点的branch表
        for key in  node.value.children:
            #终止标志
            if key == 'value':
                break
            #检索到空值,继续循环
            if node.value.children[key] == None:
                continue
            #检索到leaf节点,对比key_end和索引值
            if node.value.children[key].type == 'leaf':
                #如果匹配,返回该节点
                if index[1::] == node.value.children[key].key_end:
                    result_node =  node.value.children[key]
                    break
                #否则继续检索
                else:
                    continue
            #检索到extension,进入到该节点的branch向下索引
            elif node.value.children[key].type == 'extension':
                #记录去除该extension节点的共同前缀后剩余的索引值
                short_key = index[len(node.value.children[key].prefix)+1::]
                #递归向下索引
                result_node = self.traverse_search(node.value.children[key],short_key)
                if result_node != None:
                    break
        return result_node
    #打印MPT树
    #类似遍历MPT树,在遍历期间打印遇到的非空节点信息
    def print_all(self,node):
        print('extension of prefix:',node.prefix)
        for key in node.value.children:
            if key == 'value':
                break
            if node.value.children[key] == None:
                continue
            if node.value.children[key].type == 'leaf':
                print('branch:', key)
                print('leaf of key_end:',node.value.children[key].key_end)
            elif node.value.children[key].type == 'extension':
                print('branch:', key)
                self.print_all(node.value.children[key])

    #更新树,查询之前需要进行更新
    #遍历MPT树,自下向上对每个extension节点的value和hash进行更新
    def update_tree(self,node):
        #临时string,用于聚合extension节点下branch表中非空节点的value值,extension的value值产生自对聚合结果的hash
        tmp_str = ''
        #当节点状态为True,即已更新,直接返回当前值
        if node.value.children['value'] == True:
            return node.node_value
        for key in node.value.children:
            if key == 'value':
                break
            if node.value.children[key] == None:
                continue
            if node.value.children[key].type == 'leaf':
                #聚合leaf节点
                tmp_str = tmp_str + node.value.children[key].node_value
            elif node.value.children[key].type == 'extension':
                #聚合extension节点,同时向下递归遍历
                tmp_str = tmp_str + self.update_tree(node.value.children[key])
        #节点修改状态
        node.value.children['value'] = True
        #更新节点value,hash值
        node.node_value = hashlib.sha256(tmp_str.encode()).hexdigest()
        node.node_hash = hashlib.sha256(str(node).encode()).hexdigest()
        print('prefix:',node.prefix)
        print('node_value:',node.node_value)
        return node.node_value
    #删除节点,因为单纯使用del,没办法达到预想效果
    #通过遍历检索到需要删除的节点,然后使其对应的branch位置设为None值,再用del回收内存
    def delete_node(self,node,hash):
        for key in node.value.children:
            if key == 'value':
                break
            if node.value.children[key] == None:
                continue
            if node.value.children[key].type == 'leaf':
                if hash[1::] == node.value.children[key].key_end:
                    del node.value.children[key]
                    node.value.children[key] = None
                    return True
                else:
                    continue
            elif node.value.children[key].type == 'extension':
                short_hash = hash[len(node.value.children[key].prefix) + 1::]
                if short_hash == '':
                    del node.value.children[key]
                    node.value.children[key] = None
                    print('delete')
                    return True
                elif self.delete_node(node.value.children[key],short_hash):
                    return True

    #后续需要将update_tree精准到节点上,而不是每次都从root开始
    #增操作,同时更新MPT树
    def add(self,key,value,node=None):
        if node == None:
            node = self.root
        self.add_node(node,key,value)
        self.update_tree(self.root)
    #删操作,同时更新MPT树
    def delete(self,key): #有待改进,需要从根节点去寻到节点的父节点进行删除,无法传入节点对象进行删除
        print('delete from str')
        self.delete_node(self.root,key)
        self.update_tree(self.root)
    #改操作,同时更新MPT树(简化,只提供修改leaf节点的value值)
    def update(self,index,value):
        if type(index) == str:
            tmp_node = self.traverse_search(self.root,index)
            tmp_node.value = value
            # 对数据进行hash
            tmp_node.node_value = hashlib.sha256(value.encode('utf-8')).hexdigest()
            # 对节点进行hash,顺序在数据hash之后,确保为最后的改动
            tmp_node.node_hash = hashlib.sha256(str(tmp_node).encode('utf-8')).hexdigest()
        else:
            index.value = value
            # 对数据进行hash
            index.node_value = hashlib.sha256(value.encode('utf-8')).hexdigest()
            # 对节点进行hash,顺序在数据hash之后,确保为最后的改动
            index.node_hash = hashlib.sha256(str(index).encode('utf-8')).hexdigest()
        self.update_tree(tree.root)
    #查操作,相当于提供接口
    def search(self,index):
        if type(index) == str:
            return self.traverse_search(self.root,index).value
        else:
            return index.value
    #抛弃所有leaf节点携带的value
    #遍历整个MPT树,设置leaf节点的value值为None,回收内存
    def drop_all_value(self,node=None):
        #self.update_tree(self.root)
        if node == None:
            node = self.root
        for key in node.value.children:
            if key == 'value':
                break
            if node.value.children[key] == None:
                continue
            if node.value.children[key].type == 'leaf':
                del node.value.children[key].value
                node.value.children[key].value = None
            elif node.value.children[key].type == 'extension':
                self.drop_all_value(node.value.children[key])
    #抛弃整棵树的数据,仅保留根节点的value的hash
    def drop_tree(self):
        #先对当前树的数据进行一次更新
        self.update_tree(self.root)
        self.value = self.root.node_value
        self.hash = self.root.node_hash
        del self.root
        self.root = None
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值