mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2026-09-28 01:56:38 -04:00
merge data_layer_types into data_layer_util
This commit is contained in:
@@ -1,197 +0,0 @@
|
||||
from dataclasses import dataclass, field
|
||||
from enum import IntEnum
|
||||
from typing import Dict, List, Optional, Tuple, Type, Union
|
||||
|
||||
import aiosqlite as aiosqlite
|
||||
|
||||
from chia.types.blockchain_format.program import Program
|
||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.util.byte_types import hexstr_to_bytes
|
||||
from chia.util.streamable import Streamable, streamable
|
||||
|
||||
|
||||
class Status(IntEnum):
|
||||
PENDING = 1
|
||||
COMMITTED = 2
|
||||
|
||||
|
||||
class NodeType(IntEnum):
|
||||
# EMPTY = 0
|
||||
INTERNAL = 1
|
||||
TERMINAL = 2
|
||||
|
||||
|
||||
class Side(IntEnum):
|
||||
LEFT = 0
|
||||
RIGHT = 1
|
||||
|
||||
|
||||
class OperationType(IntEnum):
|
||||
INSERT = 0
|
||||
DELETE = 1
|
||||
|
||||
|
||||
class CommitState(IntEnum):
|
||||
OPEN = 0
|
||||
FINALIZED = 1
|
||||
ROLLED_BACK = 2
|
||||
|
||||
|
||||
Node = Union["TerminalNode", "InternalNode"]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TerminalNode:
|
||||
hash: bytes32
|
||||
# generation: int
|
||||
key: bytes
|
||||
value: bytes
|
||||
|
||||
atom: None = field(init=False, default=None)
|
||||
|
||||
@property
|
||||
def pair(self) -> Tuple[bytes32, bytes32]:
|
||||
return Program.to(self.key), Program.to(self.value)
|
||||
|
||||
# It is unclear how to properly satisfy the generic Row normally, let alone for
|
||||
# dict-like rows. https://github.com/python/typeshed/issues/8027
|
||||
@classmethod
|
||||
def from_row(cls, row: aiosqlite.Row) -> "TerminalNode": # type: ignore[type-arg]
|
||||
return cls(
|
||||
hash=bytes32.fromhex(row["hash"]),
|
||||
# generation=row["generation"],
|
||||
key=bytes.fromhex(row["key"]),
|
||||
value=bytes.fromhex(row["value"]),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ProofOfInclusionLayer:
|
||||
other_hash_side: Side
|
||||
other_hash: bytes32
|
||||
combined_hash: bytes32
|
||||
|
||||
@classmethod
|
||||
def from_internal_node(
|
||||
cls,
|
||||
internal_node: "InternalNode",
|
||||
traversal_child_hash: bytes32,
|
||||
) -> "ProofOfInclusionLayer":
|
||||
return ProofOfInclusionLayer(
|
||||
other_hash_side=internal_node.other_child_side(hash=traversal_child_hash),
|
||||
other_hash=internal_node.other_child_hash(hash=traversal_child_hash),
|
||||
combined_hash=internal_node.hash,
|
||||
)
|
||||
|
||||
|
||||
other_side_to_bit = {Side.LEFT: 1, Side.RIGHT: 0}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ProofOfInclusion:
|
||||
node_hash: bytes32
|
||||
root_hash: bytes32
|
||||
# children before parents
|
||||
layers: List[ProofOfInclusionLayer]
|
||||
|
||||
def as_program(self) -> Program:
|
||||
sibling_sides = sum(
|
||||
other_side_to_bit[layer.other_hash_side] << index for index, layer in enumerate(self.layers)
|
||||
)
|
||||
sibling_hashes = [layer.other_hash for layer in self.layers]
|
||||
|
||||
# https://github.com/Chia-Network/clvm/pull/102
|
||||
# https://github.com/Chia-Network/clvm/pull/106
|
||||
return Program.to([sibling_sides, sibling_hashes]) # type: ignore[no-any-return]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class InternalNode:
|
||||
hash: bytes32
|
||||
# generation: int
|
||||
left_hash: bytes32
|
||||
right_hash: bytes32
|
||||
|
||||
pair: Optional[Tuple[Node, Node]] = None
|
||||
atom: None = None
|
||||
|
||||
# It is unclear how to properly satisfy the generic Row normally, let alone for
|
||||
# dict-like rows. https://github.com/python/typeshed/issues/8027
|
||||
@classmethod
|
||||
def from_row(cls, row: aiosqlite.Row) -> "InternalNode": # type: ignore[type-arg]
|
||||
return cls(
|
||||
hash=bytes32(hexstr_to_bytes(row["hash"])),
|
||||
# generation=row["generation"],
|
||||
left_hash=bytes32(hexstr_to_bytes(row["left"])),
|
||||
right_hash=bytes32(hexstr_to_bytes(row["right"])),
|
||||
)
|
||||
|
||||
def other_child_hash(self, hash: bytes32) -> bytes32:
|
||||
if self.left_hash == hash:
|
||||
return self.right_hash
|
||||
elif self.right_hash == hash:
|
||||
return self.left_hash
|
||||
|
||||
# TODO: real exception considerations
|
||||
raise Exception("provided hash not present")
|
||||
|
||||
def other_child_side(self, hash: bytes32) -> Side:
|
||||
if self.left_hash == hash:
|
||||
return Side.RIGHT
|
||||
elif self.right_hash == hash:
|
||||
return Side.LEFT
|
||||
|
||||
# TODO: real exception considerations
|
||||
raise Exception("provided hash not present")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Root:
|
||||
tree_id: bytes32
|
||||
node_hash: Optional[bytes32]
|
||||
generation: int
|
||||
status: Status
|
||||
|
||||
# It is unclear how to properly satisfy the generic Row normally, let alone for
|
||||
# dict-like rows. https://github.com/python/typeshed/issues/8027
|
||||
@classmethod
|
||||
def from_row(cls, row: aiosqlite.Row) -> "Root": # type: ignore[type-arg]
|
||||
raw_node_hash = row["node_hash"]
|
||||
if raw_node_hash is None:
|
||||
node_hash = None
|
||||
else:
|
||||
node_hash = bytes32(hexstr_to_bytes(raw_node_hash))
|
||||
|
||||
return cls(
|
||||
tree_id=bytes32(hexstr_to_bytes(row["tree_id"])),
|
||||
node_hash=node_hash,
|
||||
generation=row["generation"],
|
||||
status=Status(row["status"]),
|
||||
)
|
||||
|
||||
|
||||
node_type_to_class: Dict[NodeType, Union[Type[InternalNode], Type[TerminalNode]]] = {
|
||||
NodeType.INTERNAL: InternalNode,
|
||||
NodeType.TERMINAL: TerminalNode,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Subscription:
|
||||
tree_id: bytes32
|
||||
urls: List[str]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DiffData:
|
||||
type: OperationType
|
||||
key: bytes
|
||||
value: bytes
|
||||
|
||||
|
||||
@streamable
|
||||
@dataclass(frozen=True)
|
||||
class SerializedNode(Streamable):
|
||||
is_terminal: bool
|
||||
value1: bytes
|
||||
value2: bytes
|
||||
@@ -1,9 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from enum import IntEnum
|
||||
from typing import Dict, List, Optional, Tuple, Type, Union
|
||||
|
||||
# TODO: remove or formalize this
|
||||
import aiosqlite as aiosqlite
|
||||
|
||||
from chia.data_layer.data_layer_types import Node, node_type_to_class
|
||||
from chia.types.blockchain_format.program import Program
|
||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.util.byte_types import hexstr_to_bytes
|
||||
from chia.util.streamable import Streamable, streamable
|
||||
|
||||
|
||||
def internal_hash(left_hash: bytes32, right_hash: bytes32) -> bytes32:
|
||||
@@ -35,3 +42,190 @@ async def _debug_dump(db: aiosqlite.Connection, description: str = "") -> None:
|
||||
def row_to_node(row: aiosqlite.Row) -> Node: # type: ignore[type-arg]
|
||||
cls = node_type_to_class[row["node_type"]]
|
||||
return cls.from_row(row=row)
|
||||
|
||||
|
||||
class Status(IntEnum):
|
||||
PENDING = 1
|
||||
COMMITTED = 2
|
||||
|
||||
|
||||
class NodeType(IntEnum):
|
||||
# EMPTY = 0
|
||||
INTERNAL = 1
|
||||
TERMINAL = 2
|
||||
|
||||
|
||||
class Side(IntEnum):
|
||||
LEFT = 0
|
||||
RIGHT = 1
|
||||
|
||||
|
||||
class OperationType(IntEnum):
|
||||
INSERT = 0
|
||||
DELETE = 1
|
||||
|
||||
|
||||
class CommitState(IntEnum):
|
||||
OPEN = 0
|
||||
FINALIZED = 1
|
||||
ROLLED_BACK = 2
|
||||
|
||||
|
||||
Node = Union["TerminalNode", "InternalNode"]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TerminalNode:
|
||||
hash: bytes32
|
||||
# generation: int
|
||||
key: bytes
|
||||
value: bytes
|
||||
|
||||
atom: None = field(init=False, default=None)
|
||||
|
||||
@property
|
||||
def pair(self) -> Tuple[bytes32, bytes32]:
|
||||
return Program.to(self.key), Program.to(self.value)
|
||||
|
||||
# It is unclear how to properly satisfy the generic Row normally, let alone for
|
||||
# dict-like rows. https://github.com/python/typeshed/issues/8027
|
||||
@classmethod
|
||||
def from_row(cls, row: aiosqlite.Row) -> "TerminalNode": # type: ignore[type-arg]
|
||||
return cls(
|
||||
hash=bytes32.fromhex(row["hash"]),
|
||||
# generation=row["generation"],
|
||||
key=bytes.fromhex(row["key"]),
|
||||
value=bytes.fromhex(row["value"]),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ProofOfInclusionLayer:
|
||||
other_hash_side: Side
|
||||
other_hash: bytes32
|
||||
combined_hash: bytes32
|
||||
|
||||
@classmethod
|
||||
def from_internal_node(
|
||||
cls,
|
||||
internal_node: "InternalNode",
|
||||
traversal_child_hash: bytes32,
|
||||
) -> "ProofOfInclusionLayer":
|
||||
return ProofOfInclusionLayer(
|
||||
other_hash_side=internal_node.other_child_side(hash=traversal_child_hash),
|
||||
other_hash=internal_node.other_child_hash(hash=traversal_child_hash),
|
||||
combined_hash=internal_node.hash,
|
||||
)
|
||||
|
||||
|
||||
other_side_to_bit = {Side.LEFT: 1, Side.RIGHT: 0}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ProofOfInclusion:
|
||||
node_hash: bytes32
|
||||
root_hash: bytes32
|
||||
# children before parents
|
||||
layers: List[ProofOfInclusionLayer]
|
||||
|
||||
def as_program(self) -> Program:
|
||||
sibling_sides = sum(
|
||||
other_side_to_bit[layer.other_hash_side] << index for index, layer in enumerate(self.layers)
|
||||
)
|
||||
sibling_hashes = [layer.other_hash for layer in self.layers]
|
||||
|
||||
# https://github.com/Chia-Network/clvm/pull/102
|
||||
# https://github.com/Chia-Network/clvm/pull/106
|
||||
return Program.to([sibling_sides, sibling_hashes]) # type: ignore[no-any-return]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class InternalNode:
|
||||
hash: bytes32
|
||||
# generation: int
|
||||
left_hash: bytes32
|
||||
right_hash: bytes32
|
||||
|
||||
pair: Optional[Tuple[Node, Node]] = None
|
||||
atom: None = None
|
||||
|
||||
# It is unclear how to properly satisfy the generic Row normally, let alone for
|
||||
# dict-like rows. https://github.com/python/typeshed/issues/8027
|
||||
@classmethod
|
||||
def from_row(cls, row: aiosqlite.Row) -> "InternalNode": # type: ignore[type-arg]
|
||||
return cls(
|
||||
hash=bytes32(hexstr_to_bytes(row["hash"])),
|
||||
# generation=row["generation"],
|
||||
left_hash=bytes32(hexstr_to_bytes(row["left"])),
|
||||
right_hash=bytes32(hexstr_to_bytes(row["right"])),
|
||||
)
|
||||
|
||||
def other_child_hash(self, hash: bytes32) -> bytes32:
|
||||
if self.left_hash == hash:
|
||||
return self.right_hash
|
||||
elif self.right_hash == hash:
|
||||
return self.left_hash
|
||||
|
||||
# TODO: real exception considerations
|
||||
raise Exception("provided hash not present")
|
||||
|
||||
def other_child_side(self, hash: bytes32) -> Side:
|
||||
if self.left_hash == hash:
|
||||
return Side.RIGHT
|
||||
elif self.right_hash == hash:
|
||||
return Side.LEFT
|
||||
|
||||
# TODO: real exception considerations
|
||||
raise Exception("provided hash not present")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Root:
|
||||
tree_id: bytes32
|
||||
node_hash: Optional[bytes32]
|
||||
generation: int
|
||||
status: Status
|
||||
|
||||
# It is unclear how to properly satisfy the generic Row normally, let alone for
|
||||
# dict-like rows. https://github.com/python/typeshed/issues/8027
|
||||
@classmethod
|
||||
def from_row(cls, row: aiosqlite.Row) -> "Root": # type: ignore[type-arg]
|
||||
raw_node_hash = row["node_hash"]
|
||||
if raw_node_hash is None:
|
||||
node_hash = None
|
||||
else:
|
||||
node_hash = bytes32(hexstr_to_bytes(raw_node_hash))
|
||||
|
||||
return cls(
|
||||
tree_id=bytes32(hexstr_to_bytes(row["tree_id"])),
|
||||
node_hash=node_hash,
|
||||
generation=row["generation"],
|
||||
status=Status(row["status"]),
|
||||
)
|
||||
|
||||
|
||||
node_type_to_class: Dict[NodeType, Union[Type[InternalNode], Type[TerminalNode]]] = {
|
||||
NodeType.INTERNAL: InternalNode,
|
||||
NodeType.TERMINAL: TerminalNode,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Subscription:
|
||||
tree_id: bytes32
|
||||
urls: List[str]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DiffData:
|
||||
type: OperationType
|
||||
key: bytes
|
||||
value: bytes
|
||||
|
||||
|
||||
@streamable
|
||||
@dataclass(frozen=True)
|
||||
class SerializedNode(Streamable):
|
||||
is_terminal: bool
|
||||
value1: bytes
|
||||
value2: bytes
|
||||
|
||||
@@ -12,7 +12,7 @@ from chia.data_layer.data_layer_errors import (
|
||||
TerminalLeftRightError,
|
||||
TreeGenerationIncrementingError,
|
||||
)
|
||||
from chia.data_layer.data_layer_types import (
|
||||
from chia.data_layer.data_layer_util import (
|
||||
InternalNode,
|
||||
Node,
|
||||
NodeType,
|
||||
@@ -26,8 +26,10 @@ from chia.data_layer.data_layer_types import (
|
||||
DiffData,
|
||||
OperationType,
|
||||
SerializedNode,
|
||||
internal_hash,
|
||||
leaf_hash,
|
||||
row_to_node,
|
||||
)
|
||||
from chia.data_layer.data_layer_util import internal_hash, leaf_hash, row_to_node
|
||||
from chia.types.blockchain_format.program import Program
|
||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.util.byte_types import hexstr_to_bytes
|
||||
|
||||
Reference in New Issue
Block a user