2019-07-14 11:14:02 +00:00
|
|
|
"""The merkle tree stream generator."""
|
|
|
|
|
2019-08-01 15:21:28 +00:00
|
|
|
from typing import Any, Callable, Iterator, List, Optional
|
2019-07-14 11:14:02 +00:00
|
|
|
|
|
|
|
import attr
|
|
|
|
from flat_tree import FlatTreeAccessor
|
|
|
|
|
|
|
|
Hash = str
|
|
|
|
|
2019-08-01 15:21:28 +00:00
|
|
|
__all__ = ['MerkleTreeIterator', 'MerkleTreeNode']
|
2019-08-01 11:06:32 +00:00
|
|
|
|
2019-07-14 11:14:02 +00:00
|
|
|
flat_tree = FlatTreeAccessor()
|
|
|
|
|
|
|
|
|
|
|
|
@attr.s(auto_attribs=True)
|
|
|
|
class MerkleTreeNode:
|
|
|
|
"""A node in a merkle tree.
|
|
|
|
|
2019-08-01 11:06:32 +00:00
|
|
|
:param index: The index of node
|
|
|
|
:param parent: The parent of the node
|
|
|
|
:param size: The size of the data
|
|
|
|
:param data: The data of the node
|
|
|
|
:param hash: The hash of the data
|
2019-07-14 11:14:02 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
index: int
|
2019-08-01 11:06:32 +00:00
|
|
|
parent: int
|
2019-07-14 11:14:02 +00:00
|
|
|
size: int
|
2019-08-01 15:21:28 +00:00
|
|
|
data: bytes
|
2019-07-14 11:14:02 +00:00
|
|
|
hash: Optional[str] = None
|
|
|
|
|
|
|
|
def __attrs_post_init__(self) -> Any:
|
|
|
|
"""Initialise the parent index."""
|
|
|
|
self.parent = flat_tree.parent(self.index)
|
|
|
|
|
|
|
|
|
|
|
|
@attr.s(auto_attribs=True)
|
2019-08-01 15:21:28 +00:00
|
|
|
class MerkleTreeIterator:
|
|
|
|
"""A merkle tree iterator based on incoming data.
|
2019-07-14 11:14:02 +00:00
|
|
|
|
2019-08-01 11:06:32 +00:00
|
|
|
:param leaf: The leaf hash generation function
|
|
|
|
:param parent: The parent hash generation function
|
|
|
|
:param roots: The tree roots
|
2019-07-14 11:14:02 +00:00
|
|
|
"""
|
|
|
|
|
2019-08-01 15:21:28 +00:00
|
|
|
leaf: Callable[[MerkleTreeNode], Hash]
|
|
|
|
parent: Callable[[MerkleTreeNode, MerkleTreeNode], Hash]
|
2019-08-01 11:06:32 +00:00
|
|
|
roots: List[MerkleTreeNode] = attr.Factory(list)
|
2019-07-14 11:14:02 +00:00
|
|
|
|
2019-08-01 15:21:28 +00:00
|
|
|
_position: int = 0
|
|
|
|
_nodes: List[MerkleTreeNode] = attr.Factory(list)
|
2019-07-14 11:14:02 +00:00
|
|
|
|
2019-08-01 15:21:28 +00:00
|
|
|
def __attrs_post_init__(self) -> Any:
|
|
|
|
"""Initialise parent and block defaults."""
|
|
|
|
try:
|
|
|
|
index = self.roots[len(self.roots) - 1].index
|
|
|
|
except IndexError:
|
|
|
|
index = 0
|
|
|
|
|
|
|
|
right_span = flat_tree.right_span(index)
|
|
|
|
self.blocks = (1 + (right_span / 2)) if self.roots else 0
|
|
|
|
|
|
|
|
for root in self.roots:
|
|
|
|
if not root.parent:
|
|
|
|
root.parent = flat_tree.parent(root.index)
|
|
|
|
|
|
|
|
def __iter__(self) -> Iterator:
|
|
|
|
"""The iterator initialisation."""
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __next__(self) -> MerkleTreeNode:
|
|
|
|
"""The following node."""
|
|
|
|
try:
|
|
|
|
node = self._nodes[self._position]
|
|
|
|
except IndexError:
|
|
|
|
raise StopIteration
|
|
|
|
|
|
|
|
self._position += 1
|
|
|
|
|
|
|
|
return node
|
|
|
|
|
|
|
|
def __len__(self) -> int:
|
|
|
|
"""The number of nodes stored in the tree."""
|
|
|
|
return len(self._nodes)
|
|
|
|
|
|
|
|
def write(self, data: bytes):
|
|
|
|
"""Write a new node to the tree.
|
|
|
|
|
|
|
|
:param data: The new tree data
|
2019-07-14 11:14:02 +00:00
|
|
|
"""
|
2019-08-01 15:21:28 +00:00
|
|
|
index = 2 * self.blocks
|
2019-08-01 11:06:32 +00:00
|
|
|
|
2019-08-01 15:21:28 +00:00
|
|
|
self.blocks += 1
|
2019-08-01 11:06:32 +00:00
|
|
|
|
|
|
|
leaf_node = MerkleTreeNode(
|
|
|
|
index=index,
|
|
|
|
parent=flat_tree.parent(index),
|
|
|
|
hash=None,
|
|
|
|
data=data,
|
|
|
|
size=len(data),
|
|
|
|
)
|
2019-08-01 15:21:28 +00:00
|
|
|
leaf_node.hash = self.leaf(leaf_node)
|
2019-08-01 11:06:32 +00:00
|
|
|
|
|
|
|
self.roots.append(leaf_node)
|
2019-08-01 15:21:28 +00:00
|
|
|
self._nodes.append(leaf_node)
|
2019-08-01 11:06:32 +00:00
|
|
|
|
|
|
|
while len(self.roots) > 1:
|
|
|
|
left = self.roots[len(self.roots) - 2]
|
|
|
|
right = self.roots[len(self.roots) - 1]
|
|
|
|
|
|
|
|
if left.parent != right.parent:
|
|
|
|
break
|
|
|
|
|
|
|
|
self.roots.pop()
|
|
|
|
|
|
|
|
new_node = MerkleTreeNode(
|
|
|
|
index=left.parent,
|
|
|
|
parent=flat_tree.parent(left.parent),
|
2019-08-01 15:21:28 +00:00
|
|
|
hash=self.parent(left, right),
|
2019-08-01 11:06:32 +00:00
|
|
|
size=left.size + right.size,
|
2019-08-01 15:21:28 +00:00
|
|
|
data=b'',
|
2019-08-01 11:06:32 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
self.roots[len(self.roots) - 1] = new_node
|
|
|
|
|
2019-08-01 15:21:28 +00:00
|
|
|
self._nodes.append(new_node)
|