rainbowadn/rainbowadn/core/hashpoint.py

70 lines
2.0 KiB
Python

import hashlib
from typing import Generic, TypeVar
from rainbowadn.core.localorigin import LocalOrigin
from rainbowadn.core.mentionable import Mentionable
from rainbowadn.core.origin import Origin
from rainbowadn.core.rainbow_factory import RainbowFactory
__all__ = ('HashPoint',)
Mentioned = TypeVar('Mentioned')
def _hash(source: bytes) -> bytes:
assert isinstance(source, bytes)
return hashlib.sha256(source).digest()
class HashPoint(Generic[Mentioned]):
def __init__(
self,
point: bytes,
origin: Origin[Mentioned]
):
assert isinstance(point, bytes)
assert isinstance(origin, Origin)
assert len(point) == self.HASH_LENGTH
self.point = point
self.origin = origin
self.factory = origin.factory
assert isinstance(self.factory, RainbowFactory)
def __bytes__(self):
return self.point
HASH_LENGTH = len(_hash(b''))
NULL_HASH = b'\0' * HASH_LENGTH
@classmethod
def hash(cls, source: bytes) -> bytes:
assert isinstance(source, bytes)
return _hash(source)
@classmethod
def bytes_of_mentioned(cls, mentioned: Mentionable):
assert isinstance(mentioned, Mentionable)
topology_hash: bytes = mentioned.__topology_hash__()
assert isinstance(topology_hash, bytes)
assert len(topology_hash) == cls.HASH_LENGTH
return topology_hash + bytes(mentioned)
@classmethod
def of(cls, mentioned: Mentioned) -> 'HashPoint[Mentioned]':
assert isinstance(mentioned, Mentionable)
return cls(
cls.hash(cls.bytes_of_mentioned(mentioned)), LocalOrigin(mentioned)
)
def resolve(self) -> Mentioned:
resolved = self.origin.resolve()
assert isinstance(resolved, Mentionable)
assert self.point == self.hash(self.bytes_of_mentioned(resolved))
return resolved
def __eq__(self, other):
if isinstance(other, HashPoint):
return self.point == other.point
else:
return NotImplemented