classStemNode:def__init__(self,stem:bytes):assertlen(stem)==31,"stem must be 31 bytes"self.stem=stemself.values:list[Optional[bytes]]=[None]*256defset_value(self,index:int,value:bytes):self.values[index]=valueclassInternalNode:def__init__(self):self.left=Noneself.right=NoneclassBinaryTree:def__init__(self):self.root=Nonedefinsert(self,key:bytes,value:bytes):assertlen(key)==32,"key must be 32 bytes"assertlen(value)==32,"value must be 32 bytes"stem=key[:31]subindex=key[31]ifself.rootisNone:self.root=StemNode(stem)self.root.set_value(subindex,value)returnself.root=self._insert(self.root,stem,subindex,value,0)def_insert(self,node,stem,subindex,value,depth):assertdepth<248,"depth must be less than 248"ifnodeisNone:node=StemNode(stem)node.set_value(subindex,value)returnnodestem_bits=self._bytes_to_bits(stem)ifisinstance(node,StemNode):# If the stem already exists, update the value.
# 如果词干已存在,则更新值。
ifnode.stem==stem:node.set_value(subindex,value)returnnodeexisting_stem_bits=self._bytes_to_bits(node.stem)returnself._split_leaf(node,stem_bits,existing_stem_bits,subindex,value,depth)# We're in an internal node, go left or right based on the bit.
# 我们在一个内部节点中,根据该位向左或向右移动。
bit=stem_bits[depth]ifbit==0:node.left=self._insert(node.left,stem,subindex,value,depth+1)else:node.right=self._insert(node.right,stem,subindex,value,depth+1)returnnodedef_split_leaf(self,leaf,stem_bits,existing_stem_bits,subindex,value,depth):# If the stem bits are the same up to this depth, we need to create another
# 如果词干位在此深度之前相同,我们需要创建另一个
# internal node and recurse.
# 内部节点并递归。
ifstem_bits[depth]==existing_stem_bits[depth]:new_internal=InternalNode()bit=stem_bits[depth]ifbit==0:new_internal.left=self._split_leaf(leaf,stem_bits,existing_stem_bits,subindex,value,depth+1)else:new_internal.right=self._split_leaf(leaf,stem_bits,existing_stem_bits,subindex,value,depth+1)returnnew_internalelse:new_internal=InternalNode()bit=stem_bits[depth]stem=self._bits_to_bytes(stem_bits)ifbit==0:new_internal.left=StemNode(stem)new_internal.left.set_value(subindex,value)new_internal.right=leafelse:new_internal.right=StemNode(stem)new_internal.right.set_value(subindex,value)new_internal.left=leafreturnnew_internal
def_hash(self,data):ifdatain(None,b"\x00"*64):returnb"\x00"*32assertlen(data)==64orlen(data)==32,"data must be 32 or 64 bytes"returnblake3(data).digest()# This will be replaced with the final hash function
# 这将被最终哈希函数替换
defmerkelize(self):def_merkelize(node):ifnodeisNone:returnb"\x00"*32ifisinstance(node,InternalNode):left_hash=_merkelize(node.left)right_hash=_merkelize(node.right)returnself._hash(left_hash+right_hash)level=[self._hash(x)forxinnode.values]whilelen(level)>1:new_level=[]foriinrange(0,len(level),2):new_level.append(self._hash(level[i]+level[i+1]))level=new_levelreturnself._hash(node.stem+b"\0"+level[0])return_merkelize(self.root)
树嵌入
我们将把所有信息嵌入提议的单棵树中的唯一 key: value 空间中,而不是像 MPT 那样的两层结构。本节指定哪些树键存储状态的信息(帐户标头数据、代码、存储)。数据以这样一种方式共同定位,即通常一起访问的数据位于同一 StemNode 中,这减少了分支打开。
PUSH_OFFSET=95PUSH1=PUSH_OFFSET+1PUSH32=PUSH_OFFSET+32defchunkify_code(code:bytes)->Sequence[bytes32]:# Pad to multiple of 31 bytes
# 填充到 31 字节的倍数
iflen(code)%31!=0:code+=b'\\x00'*(31-(len(code)%31))# Figure out how much pushdata there is after+including each byte
# 找出在每个字节之后+包括多少推送数据
bytes_to_exec_data=[0]*(len(code)+32)pos=0whilepos<len(code):ifPUSH1<=code[pos]<=PUSH32:pushdata_bytes=code[pos]-PUSH_OFFSETelse:pushdata_bytes=0pos+=1forxinrange(pushdata_bytes):bytes_to_exec_data[pos+x]=pushdata_bytes-xpos+=pushdata_bytes# Output chunks
# 输出块
return[bytes([min(bytes_to_exec_data[pos],31)])+code[pos:pos+31]forposinrange(0,len(code),31)]