diff --git a/main.py b/main.py index 9153c0b..08a10c3 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,20 @@ +import os +import time from collections import OrderedDict -from typing import MutableMapping +from typing import Any, MutableMapping import nacl.signing +from rainbowadn.chain.blockchain import BlockChainFactory +from rainbowadn.chain.chaincollectioninterface import ChainCollectionInterface from rainbowadn.chain.reduction.reductionchainmetafactory import ReductionChainMetaFactory +from rainbowadn.data.atomic.integer import Integer +from rainbowadn.data.atomic.plain import Plain +from rainbowadn.data.collection.array.array import Array +from rainbowadn.data.collection.trees.binary.activebinarytree import ActiveBinaryTree +from rainbowadn.data.collection.trees.binary.avl import AVLBTBP +from rainbowadn.data.collection.trees.comparison.comparator import Replace +from rainbowadn.data.collection.trees.comparison.plaincomparator import PlainComparator from rainbowadn.hashing.hashmentionable import HashMentionable from rainbowadn.hashing.hashpoint import HashPoint from rainbowadn.hashing.hashresolver import HashResolver @@ -13,6 +24,8 @@ from rainbowadn.v13.algo import MINT_CONST from rainbowadn.v13.bankchain import BankChain from rainbowadn.v13.subject import Subject from rainbowadn.v13.transaction import CoinData, Transaction +from rainbowadn.wrisbt.wrisbtchainprotocol import WrisbtChainProtocol +from rainbowadn.wrisbt.wrisbtroot import WrisbtRoot class DumbResolver(HashResolver): @@ -37,7 +50,7 @@ class DumbResolver(HashResolver): raise TypeError -def main(): +def main0(): dr = DumbResolver() bank = BankChain.empty(ReductionChainMetaFactory(), dr) key_0 = nacl.signing.SigningKey.generate() @@ -66,8 +79,58 @@ def main(): bank = BankChain.from_reference(ReductionChainMetaFactory(), dr.resolve(HashPoint.of(bank.reference).loose()), dr) print(bank) print(bank.verify()) - for key, value in dr.table.items(): - print(key.hex(), value.hex()) + # for key, value in dr.table.items(): + # print(key.hex(), value.hex()) + + +def main1(): + stoptime = time.process_time() + + def measure(message: str): + nonlocal stoptime + now = time.process_time() + print(message, now - stoptime) + stoptime = now + + dr = DumbResolver() + btree = WrisbtRoot.empty(16) + measure('init') + for _ in range(10000): + btree = btree.add(dr, HashPoint.hash(os.urandom(32))) + btree = btree.add(dr, HashPoint.hash(b'aaa')) + print(btree.contains(dr, HashPoint.hash(b'aaa'))) + measure('add') + dr.save(HashPoint.of(btree)) + measure('save') + btree = dr.resolve(HashPoint.of(btree).loose()) + print(btree) + measure('resolve') + print(btree.height) + print(WrisbtRoot.empty(128).index(dr, HashPoint.of(btree), WrisbtRoot.empty(128)).height) + measure('index') + + +def main2(): + dr = DumbResolver() + chain: ChainCollectionInterface[Any, Plain, Array[WrisbtRoot]] = BlockChainFactory( + WrisbtChainProtocol(dr, Plain.factory(), 2).loose() + ).loose().empty().loose() + for _ in range(1000): + chain = chain.add(HashPoint.of(Plain(os.urandom(16)))) + + assert chain + # noinspection PyUnresolvedReferences + print(dr.resolve(chain.actual_state().reference.value).height) + + +def main(): + dr = DumbResolver() + tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty( + AVLBTBP(PlainComparator(dr, Replace())), Plain.factory() + ) + for i in range(26): + tree = tree.add(HashPoint.of(Plain(bytes([ord('A') + i])))) + print(tree.reference.str(dr, 0)) if __name__ == '__main__': diff --git a/rainbowadn/chain/blockchain.py b/rainbowadn/chain/blockchain.py new file mode 100644 index 0000000..2932412 --- /dev/null +++ b/rainbowadn/chain/blockchain.py @@ -0,0 +1,232 @@ +from typing import Generic, TypeVar + +from rainbowadn.chain.block import Block, BlockFactory +from rainbowadn.chain.blockchainprotocol import BlockChainProtocol +from rainbowadn.chain.chaincollectionfactory import ChainCollectionFactory +from rainbowadn.chain.chaincollectioninterface import ChainCollectionInterface +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.nullability.notnull import NotNull +from rainbowadn.hashing.nullability.null import Null +from rainbowadn.hashing.nullability.nullablereference import NullableReference +from rainbowadn.hashing.rainbow_factory import RainbowFactory + +__all__ = ('BlockChain', 'BlockChainFactory',) + +HeaderType = TypeVar('HeaderType') +StateType = TypeVar('StateType') +ActualStateType = TypeVar('ActualStateType') + + +class BlockChain( + ChainCollectionInterface[ + Block[ + HeaderType, + StateType + ], + HeaderType, + ActualStateType + ], + Generic[HeaderType, StateType, ActualStateType], +): + def __init__( + self, + reference: NullableReference[ + Block[ + HeaderType, + StateType + ] + ], + protocol: BlockChainProtocol[HeaderType, StateType, ActualStateType], + ): + assert isinstance(reference, NullableReference) + assert isinstance(protocol, BlockChainProtocol) + super().__init__(reference, protocol.resolver) + self.protocol = protocol + + def factory(self) -> ChainCollectionFactory[ + Block[ + HeaderType, + StateType + ], + HeaderType, + ActualStateType + ]: + return BlockChainFactory(self.protocol) + + def add( + self, + header: HashPoint[HeaderType] + ) -> ChainCollectionInterface[ + Block[ + HeaderType, + StateType + ], + HeaderType, + ActualStateType + ]: + assert isinstance(header, HashPoint) + return self.factory().from_reference( + NullableReference.off( + self._add(header) + ) + ) + + def state( + self + ) -> NullableReference[ + StateType + ]: + if isinstance(self.reference.reference, Null): + return NullableReference( + Null(), + self.protocol.state_factory + ) + elif isinstance(self.reference.reference, NotNull): + block: Block[ + HeaderType, + StateType + ] = self.resolver.resolve(self.reference.reference.value) + assert isinstance(block, Block) + return NullableReference.of(block.state) + else: + raise TypeError + + def _add( + self, + header: HashPoint[HeaderType] + ) -> Block[ + HeaderType, + StateType + ]: + assert isinstance(header, HashPoint) + return Block( + self.reference, + header, + self.protocol.state_protocol.derive( + self.state(), + header, + ) + ) + + def previous( + self + ) -> ChainCollectionInterface[ + Block[ + HeaderType, + StateType + ], + HeaderType, + ActualStateType + ]: + assert isinstance(self.reference.reference, NotNull) + block: Block[ + HeaderType, + StateType + ] = self.resolver.resolve(self.reference.reference.value) + assert isinstance(block, Block) + return self.factory().from_reference(block.previous) + + def verify(self) -> bool: + if isinstance(self.reference.reference, Null): + return True + elif isinstance(self.reference.reference, NotNull): + return self.verify_link( + self.previous().reference + ) and self.previous().verify() + else: + raise TypeError + + def _verify_link( + self, + block: Block[ + HeaderType, + StateType + ], + previous: NullableReference[ + Block[ + HeaderType, + StateType + ] + ] + ) -> bool: + assert isinstance(block, Block) + assert isinstance(previous, NullableReference) + assert block.previous == previous + previous_chain = self.factory().from_reference(previous) + assert isinstance(previous_chain, BlockChain) + return self.protocol.state_protocol.verify( + previous_chain.state(), + block.header, + block.state, + ) + + def _actual_state_factory(self) -> RainbowFactory[ActualStateType]: + return self.protocol.actual_state_factory() + + def _actual_state( + self, + block: Block[ + HeaderType, + StateType + ] + ) -> HashPoint[ActualStateType]: + assert isinstance(block, Block) + return self.protocol.actual_state(self.resolver.resolve(block.state)) + + def loose(self) -> ChainCollectionInterface[ + Block[ + HeaderType, + StateType + ], + HeaderType, + ActualStateType + ]: + return self + + +class BlockChainFactory( + ChainCollectionFactory[ + Block[ + HeaderType, + StateType + ], + HeaderType, + ActualStateType + ], + Generic[HeaderType, StateType, ActualStateType] +): + def __init__( + self, + protocol: BlockChainProtocol[HeaderType, StateType, ActualStateType], + ): + assert isinstance(protocol, BlockChainProtocol) + self.protocol = protocol + + def empty(self) -> BlockChain[HeaderType, StateType, ActualStateType]: + return BlockChain( + NullableReference( + Null(), + BlockFactory( + self.protocol.header_factory, + self.protocol.state_factory + ) + ), + self.protocol + ) + + def from_reference( + self, + reference: NullableReference[ + Block[ + HeaderType, + StateType + ], + ] + ) -> BlockChain[ + HeaderType, StateType, ActualStateType + ]: + assert isinstance(reference, NullableReference) + return BlockChain( + reference, + self.protocol + ) diff --git a/rainbowadn/chain/blockchainprotocol.py b/rainbowadn/chain/blockchainprotocol.py new file mode 100644 index 0000000..c8b2599 --- /dev/null +++ b/rainbowadn/chain/blockchainprotocol.py @@ -0,0 +1,43 @@ +from typing import Generic, TypeVar + +from rainbowadn.chain.states.activestateprotocol import ActiveStateProtocol +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver +from rainbowadn.hashing.rainbow_factory import RainbowFactory + +__all__ = ('BlockChainProtocol',) + +HeaderType = TypeVar('HeaderType') +StateType = TypeVar('StateType') +ActualStateType = TypeVar('ActualStateType') + + +class BlockChainProtocol( + Generic[HeaderType, StateType, ActualStateType], +): + def __init__( + self, + protocol: ActiveStateProtocol[HeaderType, StateType], + header_factory: RainbowFactory[StateType], + state_factory: RainbowFactory[StateType] + ): + assert isinstance(protocol, ActiveStateProtocol) + assert isinstance(header_factory, RainbowFactory) + assert isinstance(state_factory, RainbowFactory) + self.state_protocol = protocol + self.header_factory = header_factory + self.state_factory = state_factory + self.resolver = protocol.resolver + assert isinstance(self.resolver, HashResolver) + + def actual_state_factory(self) -> RainbowFactory[ActualStateType]: + raise NotImplementedError + + def actual_state( + self, + state: StateType + ) -> HashPoint[ActualStateType]: + raise NotImplementedError + + def loose(self) -> 'BlockChainProtocol[HeaderType, StateType, ActualStateType]': + return self diff --git a/rainbowadn/chain/blockcollectioninterface.py b/rainbowadn/chain/blockcollectioninterface.py index b66f73c..1dd5008 100644 --- a/rainbowadn/chain/blockcollectioninterface.py +++ b/rainbowadn/chain/blockcollectioninterface.py @@ -53,17 +53,17 @@ class BlockCollectionInterface( else: raise TypeError - def _base_state_factory(self) -> RainbowFactory[ActualStateType]: + def _actual_state_factory(self) -> RainbowFactory[ActualStateType]: raise NotImplementedError - def _base_state(self, block: BlockType) -> HashPoint[ActualStateType]: + def _actual_state(self, block: BlockType) -> HashPoint[ActualStateType]: raise NotImplementedError - def base_state(self) -> NullableReference[ActualStateType]: + def actual_state(self) -> NullableReference[ActualStateType]: if isinstance(self.reference.reference, Null): - return NullableReference(Null(), self._base_state_factory()) + return NullableReference(Null(), self._actual_state_factory()) elif isinstance(self.reference.reference, NotNull): - return NullableReference.of(self._base_state(self.resolver.resolve(self.reference.reference.value))) + return NullableReference.of(self._actual_state(self.resolver.resolve(self.reference.reference.value))) else: raise TypeError diff --git a/rainbowadn/chain/chaincollectionfactory.py b/rainbowadn/chain/chaincollectionfactory.py index 32f4ea0..032cee1 100644 --- a/rainbowadn/chain/chaincollectionfactory.py +++ b/rainbowadn/chain/chaincollectionfactory.py @@ -19,3 +19,6 @@ class ChainCollectionFactory(Generic[BlockType, HeaderType, ActualStateType]): reference: NullableReference[BlockType] ) -> ChainCollectionInterface[BlockType, HeaderType, ActualStateType]: raise NotImplementedError + + def loose(self) -> 'ChainCollectionFactory[BlockType, HeaderType, ActualStateType]': + return self diff --git a/rainbowadn/chain/reduction/reductionchain.py b/rainbowadn/chain/reduction/reductionchain.py deleted file mode 100644 index 7a4973e..0000000 --- a/rainbowadn/chain/reduction/reductionchain.py +++ /dev/null @@ -1,306 +0,0 @@ -from typing import Generic, TypeVar - -from rainbowadn.chain.block import Block, BlockFactory -from rainbowadn.chain.blockcollectioninterface import BlockCollectionInterface -from rainbowadn.chain.chaincollectioninterface import ChainCollectionInterface -from rainbowadn.chain.reduction.reduction import Reduction, ReductionFactory -from rainbowadn.chain.reduction.reductionprotocol import ReductionProtocol -from rainbowadn.chain.reduction.reductionstageprotocol import ReductionStageProtocol -from rainbowadn.chain.stages.stage import StageStageFactory, StateStage, StateStageFactory -from rainbowadn.chain.stages.stageprotocol import StageProtocol -from rainbowadn.chain.stages.stagestateprotocol import StageStateProtocol -from rainbowadn.chain.states.stateprotocol import StateProtocol -from rainbowadn.hashing.hashpoint import HashPoint -from rainbowadn.hashing.nullability.notnull import NotNull -from rainbowadn.hashing.nullability.null import Null -from rainbowadn.hashing.nullability.nullablereference import NullableReference -from rainbowadn.hashing.rainbow_factory import RainbowFactory - -__all__ = ('ReductionChain',) - -ReductorType = TypeVar('ReductorType') -AccumulatorType = TypeVar('AccumulatorType') - - -class ReductionChain( - ChainCollectionInterface[ - Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ], - ReductorType, - AccumulatorType - ], - Generic[ReductorType, AccumulatorType] -): - def _verify_link( - self, - block: Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ], - previous: NullableReference[ - Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ] - ] - ) -> bool: - assert isinstance(block, Block) - assert isinstance(previous, NullableReference) - assert block.previous == previous - previous_chain = ReductionChain(previous, self.reductor_factory, self.accumulator_factory, self.protocol) - assert isinstance(previous_chain, BlockCollectionInterface) - state_protocol = StageStateProtocol(self.resolver) - assert isinstance(state_protocol, StateProtocol) - return state_protocol.verify( - previous_chain.state(), - block.header, - block.state, - ) - - def _base_state_factory(self) -> RainbowFactory[AccumulatorType]: - return self.accumulator_factory - - def _base_state( - self, - block: Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ] - ) -> HashPoint[AccumulatorType]: - assert isinstance(block, Block) - return self.resolver.resolve(block.state).state - - def add( - self, - header: HashPoint[ReductorType] - ) -> 'ReductionChain[ReductorType, AccumulatorType]': - assert isinstance(header, HashPoint) - return ReductionChain( - NullableReference.off( - self._add(header) - ), - header.factory, - self.accumulator_factory, - self.protocol - ) - - def __init__( - self, - reference: NullableReference[ - Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ] - ], - reductor_factory: RainbowFactory[ReductorType], - accumulator_factory: RainbowFactory[AccumulatorType], - protocol: ReductionProtocol[ReductorType, AccumulatorType] - ): - assert isinstance(reference, NullableReference) - assert isinstance(reductor_factory, RainbowFactory) - assert isinstance(accumulator_factory, RainbowFactory) - assert isinstance(protocol, ReductionProtocol) - super().__init__(reference, protocol.resolver) - self.reductor_factory = reductor_factory - self.accumulator_factory = accumulator_factory - self.protocol = protocol - - @classmethod - def _state_stage_factory( - cls, - reductor_factory: RainbowFactory[ReductorType], - accumulator_factory: RainbowFactory[AccumulatorType], - protocol: ReductionProtocol[ReductorType, AccumulatorType] - ) -> RainbowFactory[ - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ]: - assert isinstance(reductor_factory, RainbowFactory) - assert isinstance(accumulator_factory, RainbowFactory) - assert isinstance(protocol, ReductionProtocol) - stage_protocol = ReductionStageProtocol(protocol) - assert isinstance(stage_protocol, StageProtocol) - return StateStageFactory( - stage_protocol, - StageStageFactory( - stage_protocol, - ReductionFactory( - reductor_factory, - accumulator_factory - ) - ), - accumulator_factory - ) - - @classmethod - def _block_factory( - cls, - reductor_factory: RainbowFactory[ReductorType], - accumulator_factory: RainbowFactory[AccumulatorType], - protocol: ReductionProtocol[ReductorType, AccumulatorType] - ) -> RainbowFactory[ - Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ] - ]: - assert isinstance(reductor_factory, RainbowFactory) - assert isinstance(accumulator_factory, RainbowFactory) - assert isinstance(protocol, ReductionProtocol) - return BlockFactory( - reductor_factory, - cls._state_stage_factory( - reductor_factory, - accumulator_factory, - protocol - ) - ) - - @classmethod - def empty( - cls, - reductor_factory: RainbowFactory[ReductorType], - accumulator_factory: RainbowFactory[AccumulatorType], - protocol: ReductionProtocol[ReductorType, AccumulatorType] - ) -> 'ReductionChain[ReductorType, AccumulatorType]': - assert isinstance(reductor_factory, RainbowFactory) - assert isinstance(accumulator_factory, RainbowFactory) - assert isinstance(protocol, ReductionProtocol) - return cls( - NullableReference( - Null(), - cls._block_factory( - reductor_factory, - accumulator_factory, - protocol - ) - ), - reductor_factory, - accumulator_factory, - protocol - ) - - def state( - self - ) -> NullableReference[ - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ]: - if isinstance(self.reference.reference, Null): - return NullableReference( - Null(), - self._state_stage_factory( - self.reductor_factory, - self.accumulator_factory, - self.protocol - ) - ) - elif isinstance(self.reference.reference, NotNull): - block: Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ] = self.resolver.resolve(self.reference.reference.value) - assert isinstance(block, Block) - return NullableReference.of(block.state) - else: - raise TypeError - - def _add( - self, - reductor: HashPoint[ReductorType] - ) -> Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ]: - assert isinstance(reductor, HashPoint) - stage_protocol = ReductionStageProtocol(self.protocol) - assert isinstance(stage_protocol, StageProtocol) - return Block( - self.reference, - reductor, - stage_protocol.derive_full( - self.state(), - reductor, - self.accumulator_factory, - ReductionFactory(reductor.factory, self.accumulator_factory) - ) - ) - - def previous( - self - ): - assert isinstance(self.reference.reference, NotNull) - block: Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ] = self.resolver.resolve(self.reference.reference.value) - assert isinstance(block, Block) - return ReductionChain(block.previous, self.reductor_factory, self.accumulator_factory, self.protocol) - - def verify(self) -> bool: - if isinstance(self.reference.reference, Null): - return True - elif isinstance(self.reference.reference, NotNull): - return self.verify_link( - self.previous().reference - ) and self.previous().verify() - else: - raise TypeError - - def loose(self) -> ChainCollectionInterface[ - Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ], - ReductorType, - AccumulatorType - ]: - return self diff --git a/rainbowadn/chain/reduction/reductionchainfactory.py b/rainbowadn/chain/reduction/reductionchainfactory.py deleted file mode 100644 index 473051d..0000000 --- a/rainbowadn/chain/reduction/reductionchainfactory.py +++ /dev/null @@ -1,73 +0,0 @@ -from typing import Generic, TypeVar - -from rainbowadn.chain.block import Block -from rainbowadn.chain.chaincollectionfactory import ChainCollectionFactory -from rainbowadn.chain.reduction.reduction import Reduction -from rainbowadn.chain.reduction.reductionchain import ReductionChain -from rainbowadn.chain.reduction.reductionprotocol import ReductionProtocol -from rainbowadn.chain.stages.stage import StateStage -from rainbowadn.hashing.nullability.nullablereference import NullableReference -from rainbowadn.hashing.rainbow_factory import RainbowFactory - -__all__ = ('ReductionChainFactory',) - -ReductorType = TypeVar('ReductorType') -AccumulatorType = TypeVar('AccumulatorType') - - -class ReductionChainFactory( - ChainCollectionFactory[ - Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ], - ReductorType, - AccumulatorType - ], - Generic[ReductorType, AccumulatorType] -): - def __init__( - self, - reductor_factory: RainbowFactory[ReductorType], - accumulator_factory: RainbowFactory[AccumulatorType], - protocol: ReductionProtocol[ReductorType, AccumulatorType], - ): - assert isinstance(reductor_factory, RainbowFactory) - assert isinstance(accumulator_factory, RainbowFactory) - assert isinstance(protocol, ReductionProtocol) - self.reductor_factory = reductor_factory - self.accumulator_factory = accumulator_factory - self.protocol = protocol - - def empty(self) -> ReductionChain[ReductorType, AccumulatorType]: - return ReductionChain.empty( - self.reductor_factory, - self.accumulator_factory, - self.protocol, - ) - - def from_reference( - self, reference: NullableReference[ - Block[ - ReductorType, - StateStage[ - ReductorType, - AccumulatorType, - Reduction[ReductorType, AccumulatorType] - ] - ], - ] - ) -> ReductionChain[ - ReductorType, AccumulatorType - ]: - assert isinstance(reference, NullableReference) - return ReductionChain( - reference, - self.reductor_factory, - self.accumulator_factory, - self.protocol, - ) diff --git a/rainbowadn/chain/reduction/reductionchainmetafactory.py b/rainbowadn/chain/reduction/reductionchainmetafactory.py index afde93f..5760016 100644 --- a/rainbowadn/chain/reduction/reductionchainmetafactory.py +++ b/rainbowadn/chain/reduction/reductionchainmetafactory.py @@ -2,8 +2,10 @@ from typing import Generic, TypeVar from rainbowadn.chain.abstractreductionchainmetafactory import AbstractReductionChainMetaFactory from rainbowadn.chain.block import Block +from rainbowadn.chain.blockchain import BlockChainFactory +from rainbowadn.chain.chaincollectionfactory import ChainCollectionFactory from rainbowadn.chain.reduction.reduction import Reduction -from rainbowadn.chain.reduction.reductionchainfactory import ReductionChainFactory +from rainbowadn.chain.reduction.reductionchainprotocol import ReductionChainProtocol from rainbowadn.chain.reduction.reductionprotocol import ReductionProtocol from rainbowadn.chain.stages.stage import StateStage from rainbowadn.hashing.rainbow_factory import RainbowFactory @@ -34,9 +36,25 @@ class ReductionChainMetaFactory( reductor_factory: RainbowFactory[ReductorType], accumulator_factory: RainbowFactory[AccumulatorType], protocol: ReductionProtocol[ReductorType, AccumulatorType], - ): - return ReductionChainFactory( - reductor_factory, - accumulator_factory, - protocol, + ) -> ChainCollectionFactory[ + Block[ + ReductorType, + StateStage[ + ReductorType, + AccumulatorType, + Reduction[ReductorType, AccumulatorType] + ] + ], + ReductorType, + AccumulatorType + ]: + assert isinstance(reductor_factory, RainbowFactory) + assert isinstance(accumulator_factory, RainbowFactory) + assert isinstance(protocol, ReductionProtocol) + return BlockChainFactory( + ReductionChainProtocol( + protocol, + reductor_factory, + accumulator_factory, + ) ) diff --git a/rainbowadn/chain/reduction/reductionchainprotocol.py b/rainbowadn/chain/reduction/reductionchainprotocol.py new file mode 100644 index 0000000..d0a66c0 --- /dev/null +++ b/rainbowadn/chain/reduction/reductionchainprotocol.py @@ -0,0 +1,82 @@ +from typing import TypeVar + +from rainbowadn.chain.blockchainprotocol import BlockChainProtocol +from rainbowadn.chain.reduction.reduction import Reduction, ReductionFactory +from rainbowadn.chain.reduction.reductionprotocol import ReductionProtocol +from rainbowadn.chain.reduction.reductionstageprotocol import ReductionStageProtocol +from rainbowadn.chain.stages.derivation.activestageprotocol import ActiveStageProtocol +from rainbowadn.chain.stages.derivation.activestagestateprotocol import ActiveStageStateProtocol +from rainbowadn.chain.stages.stage import StateStage, StateStageFactory +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.rainbow_factory import RainbowFactory + +__all__ = ('ReductionChainProtocol',) + +ReductorType = TypeVar('ReductorType') +AccumulatorType = TypeVar('AccumulatorType') + + +class ReductionChainProtocol( + BlockChainProtocol[ + ReductorType, + StateStage[ + ReductorType, + AccumulatorType, + Reduction[ReductorType, AccumulatorType] + ], + AccumulatorType + ] +): + def __init__( + self, + protocol: ReductionProtocol[ReductorType, AccumulatorType], + reductor_factory: RainbowFactory[ReductorType], + accumulator_factory: RainbowFactory[AccumulatorType], + ): + assert isinstance(protocol, ReductionProtocol) + assert isinstance(reductor_factory, RainbowFactory) + assert isinstance(accumulator_factory, RainbowFactory) + + reduction_factory: RainbowFactory[ + Reduction[ReductorType, AccumulatorType] + ] = ReductionFactory( + reductor_factory, accumulator_factory + ) + assert isinstance(reduction_factory, RainbowFactory) + stage_protocol: ActiveStageProtocol[ + ReductorType, + AccumulatorType, + Reduction[ReductorType, AccumulatorType] + ] = ReductionStageProtocol(protocol) + assert isinstance(stage_protocol, ActiveStageProtocol) + + super().__init__( + ActiveStageStateProtocol( + stage_protocol, + reduction_factory, + accumulator_factory, + ), + reductor_factory, + StateStageFactory( + stage_protocol, + reduction_factory, + accumulator_factory + ) + ) + + self.reductor_factory = reductor_factory + self.accumulator_factory = accumulator_factory + + def actual_state_factory(self) -> RainbowFactory[AccumulatorType]: + return self.accumulator_factory + + def actual_state( + self, + state: StateStage[ + ReductorType, + AccumulatorType, + Reduction[ReductorType, AccumulatorType] + ] + ) -> HashPoint[AccumulatorType]: + assert isinstance(state, StateStage) + return state.state diff --git a/rainbowadn/chain/stages/derivation/activestageprotocol.py b/rainbowadn/chain/stages/derivation/activestageprotocol.py index cac01b2..6410079 100644 --- a/rainbowadn/chain/stages/derivation/activestageprotocol.py +++ b/rainbowadn/chain/stages/derivation/activestageprotocol.py @@ -56,8 +56,10 @@ class ActiveStageProtocol( def _derive_cycle( self, stage: StageStage[HeaderType, BaseStateType, StageType], + stage_factory: RainbowFactory[StageType] ) -> HashPoint[StateStage[HeaderType, BaseStateType, StageType]]: assert isinstance(stage, StageStage) + assert isinstance(stage_factory, RainbowFactory) while True: derived = self.derive_stage_or_state(stage.stage) assert isinstance(derived, Derived) @@ -65,7 +67,7 @@ class ActiveStageProtocol( stage = StageStage(self, NullableReference.off(stage), derived.stage) assert isinstance(stage, StageStage) elif isinstance(derived, DerivedState): - return HashPoint.of(StateStage(self, HashPoint.of(stage), derived.state)) + return HashPoint.of(StateStage(self, HashPoint.of(stage), derived.state, stage_factory)) else: raise TypeError @@ -109,7 +111,8 @@ class ActiveStageProtocol( ), header, stage_factory - ) + ), + stage_factory ) def verify_header( diff --git a/rainbowadn/chain/stages/derivation/activestagestateprotocol.py b/rainbowadn/chain/stages/derivation/activestagestateprotocol.py new file mode 100644 index 0000000..b4d248b --- /dev/null +++ b/rainbowadn/chain/stages/derivation/activestagestateprotocol.py @@ -0,0 +1,91 @@ +from typing import TypeVar + +from rainbowadn.chain.stages.derivation.activestageprotocol import ActiveStageProtocol +from rainbowadn.chain.stages.stage import StateStage +from rainbowadn.chain.states.activestateprotocol import ActiveStateProtocol +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.nullability.nullablereference import NullableReference +from rainbowadn.hashing.rainbow_factory import RainbowFactory + +__all__ = ('ActiveStageStateProtocol',) + +HeaderType = TypeVar('HeaderType') +BaseStateType = TypeVar('BaseStateType') +StageType = TypeVar('StageType') + + +class ActiveStageStateProtocol( + ActiveStateProtocol[ + HeaderType, + StateStage[ + HeaderType, + BaseStateType, + StageType + ] + ] +): + def __init__( + self, + protocol: ActiveStageProtocol, + stage_factory: RainbowFactory[StageType], + base_state_factory: RainbowFactory[BaseStateType], + ): + assert isinstance(protocol, ActiveStageProtocol) + assert isinstance(stage_factory, RainbowFactory) + assert isinstance(base_state_factory, RainbowFactory) + super().__init__(protocol.resolver) + self.protocol = protocol + self.stage_factory = stage_factory + self.base_state_factory = base_state_factory + + def _initial_state(self) -> HashPoint[ + StateStage[ + HeaderType, + BaseStateType, + StageType + ] + ]: + raise TypeError('use .derive()') + + def _derive( + self, + previous: HashPoint[StateStage[ + HeaderType, + BaseStateType, + StageType + ]], + header: HashPoint[HeaderType] + ) -> HashPoint[ + StateStage[ + HeaderType, + BaseStateType, + StageType + ] + ]: + raise TypeError('use .derive()') + + def derive( + self, + previous: NullableReference[ + StateStage[ + HeaderType, + BaseStateType, + StageType + ] + ], + header: HashPoint[HeaderType], + ) -> HashPoint[ + StateStage[ + HeaderType, + BaseStateType, + StageType + ] + ]: + assert isinstance(previous, NullableReference) + assert isinstance(header, HashPoint) + return self.protocol.derive_full( + previous, + header, + self.base_state_factory, + self.stage_factory + ) diff --git a/rainbowadn/chain/stages/stage.py b/rainbowadn/chain/stages/stage.py index 510361e..34b4e53 100644 --- a/rainbowadn/chain/stages/stage.py +++ b/rainbowadn/chain/stages/stage.py @@ -143,14 +143,17 @@ class StateStage( self, protocol: StageProtocol[HeaderType, BaseStateType, StageType], previous: HashPoint[StageStage[HeaderType, BaseStateType, StageType]], - state: HashPoint[BaseStateType] + state: HashPoint[BaseStateType], + stage_factory: RainbowFactory[StageType] ): assert isinstance(protocol, StageProtocol) assert isinstance(previous, HashPoint) assert isinstance(state, HashPoint) + assert isinstance(stage_factory, RainbowFactory) super().__init__(protocol) self.previous = previous self.state = state + self.stage_factory = stage_factory def verify( self, @@ -181,7 +184,7 @@ class StateStage( def __factory__(self) -> RainbowFactory['StateStage[HeaderType, BaseStateType, StageType]']: return StateStageFactory( self.protocol, - self.previous.factory, + self.stage_factory, self.state.factory ) @@ -196,20 +199,27 @@ class StateStageFactory(RainbowFactory[StateStage[HeaderType, BaseStateType, Sta def __init__( self, protocol: StageProtocol[HeaderType, BaseStateType, StageType], - stage_stage_factory: RainbowFactory[StageStage[HeaderType, BaseStateType, StageType]], + stage_factory: RainbowFactory[StageType], state_factory: RainbowFactory[BaseStateType] ): assert isinstance(protocol, StageProtocol) - assert isinstance(stage_stage_factory, RainbowFactory) + assert isinstance(stage_factory, RainbowFactory) assert isinstance(state_factory, RainbowFactory) self.protocol = protocol - self.stage_stage_factory = stage_stage_factory + self.stage_factory = stage_factory self.state_factory = state_factory def from_bytes(self, source: bytes) -> StateStage[HeaderType, BaseStateType, StageType]: assert isinstance(source, bytes) return StateStage( self.protocol, - HashPoint(self.stage_stage_factory, source[:HashPoint.HASH_LENGTH], Null()), + HashPoint( + StageStageFactory( + self.protocol, + self.stage_factory + ), + source[:HashPoint.HASH_LENGTH], Null() + ), HashPoint(self.state_factory, source[HashPoint.HASH_LENGTH:], Null()), + self.stage_factory ) diff --git a/rainbowadn/chain/states/activestateprotocol.py b/rainbowadn/chain/states/activestateprotocol.py new file mode 100644 index 0000000..9df85d2 --- /dev/null +++ b/rainbowadn/chain/states/activestateprotocol.py @@ -0,0 +1,52 @@ +from typing import TypeVar + +from rainbowadn.chain.states.stateprotocol import StateProtocol +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.nullability.notnull import NotNull +from rainbowadn.hashing.nullability.null import Null +from rainbowadn.hashing.nullability.nullablereference import NullableReference + +__all__ = ('ActiveStateProtocol',) + +HeaderType = TypeVar('HeaderType') +StateType = TypeVar('StateType') + + +class ActiveStateProtocol(StateProtocol[HeaderType, StateType]): + def verify( + self, + previous: NullableReference[StateType], + header: HashPoint[HeaderType], + state: HashPoint[StateType] + ) -> bool: + assert isinstance(previous, NullableReference) + assert isinstance(header, HashPoint) + assert isinstance(state, HashPoint) + assert state == self.derive(previous, header) + return True + + def _initial_state(self) -> HashPoint[StateType]: + raise NotImplementedError + + def _derive( + self, + previous: HashPoint[StateType], + header: HashPoint[HeaderType], + ) -> HashPoint[StateType]: + raise NotImplementedError + + def derive( + self, + previous: NullableReference[StateType], + header: HashPoint[HeaderType], + ) -> HashPoint[StateType]: + assert isinstance(previous, NullableReference) + assert isinstance(header, HashPoint) + if isinstance(previous.reference, Null): + previous_state: HashPoint[StateType] = self._initial_state() + elif isinstance(previous.reference, NotNull): + previous_state: HashPoint[StateType] = previous.reference.value + else: + raise TypeError + assert isinstance(previous_state, HashPoint) + return self._derive(previous_state, header) diff --git a/rainbowadn/chain/states/stateprotocol.py b/rainbowadn/chain/states/stateprotocol.py index d5054f8..ffcbce1 100644 --- a/rainbowadn/chain/states/stateprotocol.py +++ b/rainbowadn/chain/states/stateprotocol.py @@ -19,6 +19,6 @@ class StateProtocol(Generic[HeaderType, StateType]): self, previous: NullableReference[StateType], header: HashPoint[HeaderType], - state: NullableReference[StateType] + state: HashPoint[StateType] ) -> bool: raise NotImplementedError diff --git a/rainbowadn/data/atomic/atomic.py b/rainbowadn/data/atomic/atomic.py index 0d7349b..4a2c02d 100644 --- a/rainbowadn/data/atomic/atomic.py +++ b/rainbowadn/data/atomic/atomic.py @@ -1,5 +1,5 @@ import abc -from typing import Generic, TypeVar +from typing import TypeVar from rainbowadn.hashing.hashpoint import HashPoint from rainbowadn.hashing.static import StaticMentionable @@ -9,6 +9,6 @@ __all__ = ('Atomic',) AtomicMentioned = TypeVar('AtomicMentioned') -class Atomic(StaticMentionable[AtomicMentioned], abc.ABC, Generic[AtomicMentioned]): +class Atomic(StaticMentionable, abc.ABC): def __topology_hash__(self) -> bytes: - return HashPoint.NULL_HASH + return HashPoint.hash(b'') diff --git a/rainbowadn/data/atomic/integer.py b/rainbowadn/data/atomic/integer.py index 44378da..f037849 100644 --- a/rainbowadn/data/atomic/integer.py +++ b/rainbowadn/data/atomic/integer.py @@ -3,7 +3,7 @@ from rainbowadn.data.atomic.atomic import Atomic __all__ = ('Integer',) -class Integer(Atomic['Integer']): +class Integer(Atomic): def __init__(self, integer: int): assert isinstance(integer, int) assert integer >= 0 diff --git a/rainbowadn/data/atomic/plain.py b/rainbowadn/data/atomic/plain.py index e859d75..38c277a 100644 --- a/rainbowadn/data/atomic/plain.py +++ b/rainbowadn/data/atomic/plain.py @@ -3,7 +3,7 @@ from rainbowadn.data.atomic.atomic import Atomic __all__ = ('Plain',) -class Plain(Atomic['Plain']): +class Plain(Atomic): def __init__(self, source: bytes): assert isinstance(source, bytes) self.source = source diff --git a/rainbowadn/data/collection/array/__init__.py b/rainbowadn/data/collection/array/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rainbowadn/data/collection/array/array.py b/rainbowadn/data/collection/array/array.py new file mode 100644 index 0000000..cd7d51c --- /dev/null +++ b/rainbowadn/data/collection/array/array.py @@ -0,0 +1,64 @@ +from typing import Generic, Iterable, TypeVar + +from rainbowadn.hashing.hash_point_format import hash_point_format, tabulate +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver +from rainbowadn.hashing.nullability.null import Null +from rainbowadn.hashing.rainbow_factory import RainbowFactory +from rainbowadn.hashing.recursivementionable import RecursiveMentionable + +__all__ = ('Array', 'ArrayFactory',) + +ElementType = TypeVar('ElementType') + + +class Array(RecursiveMentionable, Generic[ElementType]): + def __init__( + self, + factory: RainbowFactory[ElementType], + array: tuple[HashPoint[ElementType], ...] + ): + assert isinstance(factory, RainbowFactory) + assert isinstance(array, tuple) + self.factory = factory + self.array = array + + def points(self) -> Iterable[HashPoint]: + return self.array + + def __bytes__(self): + return b''.join(map(HashPoint.__bytes__, self.array)) + + def __factory__(self) -> RainbowFactory['Array']: + return ArrayFactory(self.factory) + + def str(self, resolver: HashResolver, tab: int) -> str: + assert isinstance(resolver, HashResolver) + assert isinstance(tab, int) + formatted = f'(' + for hash_point in self.array: + formatted += f'{tabulate(tab+1)}{hash_point_format(hash_point,resolver,tab+1)}' + return f'{formatted}' \ + f'{tabulate(tab)})' + + +class ArrayFactory(RainbowFactory[Array], Generic[ElementType]): + def __init__( + self, + factory: RainbowFactory[ElementType] + ): + assert isinstance(factory, RainbowFactory) + self.factory = factory + + def from_bytes(self, source: bytes) -> Array: + assert isinstance(source, bytes) + return Array( + self.factory, + tuple( + HashPoint(self.factory, source[i:i + HashPoint.HASH_LENGTH], Null()) + for + i + in + range(0, len(source), HashPoint.HASH_LENGTH) + ) + ) diff --git a/rainbowadn/data/collection/stack/activestack.py b/rainbowadn/data/collection/stack/activestack.py deleted file mode 100644 index 0510f78..0000000 --- a/rainbowadn/data/collection/stack/activestack.py +++ /dev/null @@ -1,40 +0,0 @@ -from typing import Generic, TypeVar - -from rainbowadn.data.collection.collection_interface.activecollectioninterface import ActiveCollectionInterface -from rainbowadn.data.collection.stack.stack import Stack -from rainbowadn.hashing.hashpoint import HashPoint -from rainbowadn.hashing.hashresolver import HashResolver -from rainbowadn.hashing.nullability.notnull import NotNull -from rainbowadn.hashing.nullability.null import Null -from rainbowadn.hashing.nullability.nullablereference import NullableReference -from rainbowadn.hashing.rainbow_factory import RainbowFactory - -__all__ = ('ActiveStack',) - -ElementType = TypeVar('ElementType') - - -class ActiveStack(ActiveCollectionInterface[Stack[ElementType], ElementType], Generic[ElementType]): - def __init__(self, reference: NullableReference[Stack[ElementType]]): - assert isinstance(reference, NullableReference) - super().__init__(reference) - - def add(self, element: HashPoint[ElementType]) -> 'ActiveStack[ElementType]': - assert isinstance(element, HashPoint) - return ActiveStack(NullableReference.off(Stack(self.reference, element))) - - @classmethod - def empty(cls, factory: RainbowFactory[ElementType]) -> 'ActiveStack[ElementType]': - assert isinstance(factory, RainbowFactory) - return cls(NullableReference(Null(), Stack.factory(factory))) - - def str(self, resolver: HashResolver): - assert isinstance(resolver, HashResolver) - if isinstance(self.reference.reference, Null): - return f'-' - elif isinstance(self.reference.reference, NotNull): - stack: Stack[ElementType] = resolver.resolve(self.reference.reference.value) - assert isinstance(stack, Stack) - return f'{ActiveStack(stack.previous).str(resolver)} {resolver.resolve(stack.element)}' - else: - raise TypeError diff --git a/rainbowadn/data/collection/stack/stack.py b/rainbowadn/data/collection/stack/stack.py index 7287b8d..3004a87 100644 --- a/rainbowadn/data/collection/stack/stack.py +++ b/rainbowadn/data/collection/stack/stack.py @@ -50,9 +50,11 @@ class Stack(RecursiveMentionable, Generic[ElementType]): ]: assert isinstance(factory, RainbowFactory) reference: NullableReference[Stack[ElementType]] = NullableReference(Null(), cls.factory(factory)) + assert isinstance(reference, NullableReference) for element in elements: assert isinstance(element, HashPoint) reference = NullableReference.off(cls(reference, element)) + assert isinstance(reference, NullableReference) return reference @classmethod @@ -63,6 +65,7 @@ class Stack(RecursiveMentionable, Generic[ElementType]): ) -> NullableReference[ 'Stack[ElementType]' ]: + assert isinstance(factory, RainbowFactory) return cls.of(factory, map(HashPoint.of, elements)) diff --git a/rainbowadn/data/collection/trees/b/__init__.py b/rainbowadn/data/collection/trees/b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rainbowadn/data/collection/trees/binary/activebinarytree.py b/rainbowadn/data/collection/trees/binary/activebinarytree.py index fd7604b..f3c144b 100644 --- a/rainbowadn/data/collection/trees/binary/activebinarytree.py +++ b/rainbowadn/data/collection/trees/binary/activebinarytree.py @@ -1,19 +1,22 @@ from typing import Generic, TypeVar -from rainbowadn.data.collection.trees.binary.binarytree import BinaryTree -from rainbowadn.data.collection.trees.comparison.comparator import (Comparator, Comparison, Left, Replace, Right) -from rainbowadn.data.collection.trees.comparison.keyedcomparator import KeyedComparator -from rainbowadn.data.collection.trees.binary.querybinarytree import QueryBinaryTree from rainbowadn.data.collection.collection_interface.activecollectioninterface import ActiveCollectionInterface from rainbowadn.data.collection.collection_interface.querycollectioninterface import QueryCollectionInterface -from rainbowadn.data.collection.keymetadata import KeyMetadata +from rainbowadn.data.collection.keymetadata import KeyMetadata, KeyMetadataFactory from rainbowadn.data.collection.keymetadataquerycollection import KeyMetadataQueryCollection +from rainbowadn.data.collection.trees.binary.balancedtreecreationprotocol import BalancedTreeCreationProtocol +from rainbowadn.data.collection.trees.binary.binarytree import BinaryTree, BinaryTreeFactory +from rainbowadn.data.collection.trees.binary.binarytreebalancingprotocol import BinaryTreeBalancingProtocol +from rainbowadn.data.collection.trees.binary.binarytreecreationprotocol import BinaryTreeCreationProtocol +from rainbowadn.data.collection.trees.binary.querybinarytree import QueryBinaryTree +from rainbowadn.data.collection.trees.comparison.comparator import (Comparator, Comparison, Left, Replace, Right) +from rainbowadn.data.collection.trees.comparison.keyedcomparator import KeyedComparator from rainbowadn.hashing.hashpoint import HashPoint from rainbowadn.hashing.hashresolver import HashResolver from rainbowadn.hashing.nullability.notnull import NotNull from rainbowadn.hashing.nullability.null import Null -from rainbowadn.hashing.nullability.nullable import Nullable from rainbowadn.hashing.nullability.nullablereference import NullableReference +from rainbowadn.hashing.rainbow_factory import RainbowFactory __all__ = ('ActiveBinaryTree',) @@ -27,40 +30,34 @@ class ActiveBinaryTree( ): def __init__( self, - comparator: Comparator[ActiveKeyType], + protocol: BinaryTreeBalancingProtocol[ActiveKeyType, MetaDataType, 'ActiveBinaryTree'], reference: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]] ): - assert isinstance(comparator, Comparator) + assert isinstance(protocol, BinaryTreeBalancingProtocol) assert isinstance(reference, NullableReference) super().__init__(reference) - self.comparator = comparator - self.resolver = comparator.resolver + self.protocol = protocol + self.comparator = protocol.comparator + assert isinstance(self.comparator, Comparator) + self.resolver = protocol.resolver assert isinstance(self.resolver, HashResolver) + self.creation = ActiveCreationProtocol(protocol) + assert isinstance(self.creation, BinaryTreeCreationProtocol) - def empty_metadata(self) -> HashPoint[MetaDataType]: - raise NotImplementedError - - def metadata( - self, - treel: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - treer: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - key: HashPoint[ActiveKeyType] - ) -> HashPoint[MetaDataType]: - raise NotImplementedError - - def _binary_tree( - self, - treel: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - treer: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - key: HashPoint[ActiveKeyType] - ) -> BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]: - assert isinstance(treel, NullableReference) - assert isinstance(treer, NullableReference) - assert isinstance(key, HashPoint) - return BinaryTree( - treel, - treer, - HashPoint.of(KeyMetadata(key, self.metadata(treel, treer, key))) + @classmethod + def empty( + cls, + protocol: BinaryTreeBalancingProtocol[ActiveKeyType, MetaDataType, 'ActiveBinaryTree'], + factory: RainbowFactory[ActiveKeyType] + ): + assert isinstance(protocol, BinaryTreeBalancingProtocol) + assert isinstance(factory, RainbowFactory) + return cls( + protocol, + NullableReference( + Null(), + BinaryTreeFactory(KeyMetadataFactory(factory, protocol.empty_metadata().factory)) + ) ) def create( @@ -68,81 +65,82 @@ class ActiveBinaryTree( reference: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]] ) -> 'ActiveBinaryTree[ActiveKeyType, MetaDataType]': assert isinstance(reference, NullableReference) - return type(self)( - self.comparator, + return ActiveBinaryTree( + self.protocol, reference ) - def active_tree( - self, - treel: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - treer: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - key: HashPoint[ActiveKeyType] - ) -> 'ActiveBinaryTree[ActiveKeyType, MetaDataType]': - assert isinstance(treel, NullableReference) - assert isinstance(treer, NullableReference) - assert isinstance(key, HashPoint) - return self.create( - NullableReference.off( - self._binary_tree( - self.create(treel).balance().reference, - self.create(treer).balance().reference, - key - ) - ) - ).balance() - def add(self, key: HashPoint[ActiveKeyType]) -> 'ActiveBinaryTree[ActiveKeyType, MetaDataType]': assert isinstance(key, HashPoint) - reference: Nullable[ - HashPoint[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]] - ] = self.reference.reference - assert isinstance(reference, Nullable) - if isinstance(reference, Null): - return self.active_tree(self.reference, self.reference, key) - elif isinstance(reference, NotNull): - tree: BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]] = self.resolver.resolve(reference.value) - assert isinstance(tree, BinaryTree) - original: HashPoint[ActiveKeyType] = self.resolver.resolve(tree.key).key + if self.creation.splittable(self): + treel: ActiveBinaryTree[ActiveKeyType, MetaDataType] + original: HashPoint[ActiveKeyType] + treer: ActiveBinaryTree[ActiveKeyType, MetaDataType] + treel, original, _, treer = self.creation.split(self) + assert isinstance(treel, ActiveBinaryTree) assert isinstance(original, HashPoint) + assert isinstance(treer, ActiveBinaryTree) comparison: Comparison = self.comparator.compare(original, key) assert isinstance(comparison, Comparison) if isinstance(comparison, Replace): - return self.active_tree(tree.treel, tree.treer, key) + return self.creation.tree(treel, treer, key) elif isinstance(comparison, Left): - return self.active_tree(self.create(tree.treel).add(key).reference, tree.treer, original) + return self.creation.tree(treel.add(key), treer, original) elif isinstance(comparison, Right): - return self.active_tree(tree.treel, self.create(tree.treer).add(key).reference, original) + return self.creation.tree(treel, treer.add(key), original) else: raise TypeError else: - raise TypeError - - def balance(self) -> 'ActiveBinaryTree[ActiveKeyType, MetaDataType]': - raise NotImplementedError - - def __str__(self): - reference: Nullable[ - HashPoint[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]] - ] = self.reference.reference - assert isinstance(reference, Nullable) - if isinstance(reference, Null): - return '_' - elif isinstance(reference, NotNull): - tree: BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]] = self.resolver.resolve(reference.value) - assert isinstance(tree, BinaryTree) - key: KeyMetadata[ActiveKeyType, MetaDataType] = self.resolver.resolve(tree.key) - assert isinstance(key, KeyMetadata) - return f'( {self.create(tree.treel)}' \ - f' {self.resolver.resolve(key.key)}' \ - f' {self.resolver.resolve(key.metadata)}' \ - f' {self.create(tree.treer)} )' - else: - raise TypeError + return self.creation.tree(self, self, key) def query_tree(self) -> QueryCollectionInterface[ActiveKeyType]: return KeyMetadataQueryCollection( - self.empty_metadata(), - QueryBinaryTree(KeyedComparator(self.resolver, self.comparator), self.reference), + self.protocol.empty_metadata(), + QueryBinaryTree(KeyedComparator(self.comparator), self.reference), self.resolver ) + + +class ActiveCreationProtocol(BalancedTreeCreationProtocol[ActiveKeyType, MetaDataType, ActiveBinaryTree]): + def splittable(self, tree: ActiveBinaryTree[ActiveKeyType, MetaDataType]) -> bool: + assert isinstance(tree, ActiveBinaryTree) + return isinstance(tree.reference.reference, NotNull) + + def split( + self, + tree: ActiveBinaryTree[ActiveKeyType, MetaDataType] + ) -> tuple[ + ActiveBinaryTree[ActiveKeyType, MetaDataType], + HashPoint[ActiveKeyType], + HashPoint[MetaDataType], + ActiveBinaryTree[ActiveKeyType, MetaDataType] + ]: + assert isinstance(tree, ActiveBinaryTree) + assert isinstance(tree.reference.reference, NotNull) + hash_point: HashPoint[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]] = tree.reference.reference.value + assert isinstance(hash_point, HashPoint) + resolved: BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]] = self.resolver.resolve(hash_point) + assert isinstance(resolved, BinaryTree) + key_metadata: KeyMetadata[ActiveKeyType, MetaDataType] = self.resolver.resolve(resolved.key) + assert isinstance(key_metadata, KeyMetadata) + return tree.create(resolved.treel), key_metadata.key, key_metadata.metadata, tree.create(resolved.treer) + + def _tree( + self, + treel: ActiveBinaryTree, + treer: ActiveBinaryTree, + key: HashPoint[ActiveKeyType] + ) -> ActiveBinaryTree: + assert isinstance(treel, ActiveBinaryTree) + assert isinstance(treer, ActiveBinaryTree) + assert isinstance(key, HashPoint) + return ActiveBinaryTree( + self.protocol, + NullableReference.off( + BinaryTree( + treel.reference, + treer.reference, + HashPoint.of(KeyMetadata(key, self.protocol.metadata(treel, treer, key, self))) + ) + ) + ) diff --git a/rainbowadn/data/collection/trees/binary/avl.py b/rainbowadn/data/collection/trees/binary/avl.py index 5a18814..8083b90 100644 --- a/rainbowadn/data/collection/trees/binary/avl.py +++ b/rainbowadn/data/collection/trees/binary/avl.py @@ -1,180 +1,86 @@ -from typing import Generic, TypeVar +from typing import TypeVar from rainbowadn.data.atomic.integer import Integer -from rainbowadn.data.collection.trees.binary.activebinarytree import ActiveBinaryTree -from rainbowadn.data.collection.trees.binary.binarytree import BinaryTree, BinaryTreeFactory -from rainbowadn.data.collection.trees.comparison.comparator import Comparator -from rainbowadn.data.collection.keymetadata import KeyMetadata, KeyMetadataFactory +from rainbowadn.data.collection.trees.binary.binarytreebalancingprotocol import BinaryTreeBalancingProtocol +from rainbowadn.data.collection.trees.binary.binarytreecreationprotocol import BinaryTreeCreationProtocol from rainbowadn.hashing.hashpoint import HashPoint -from rainbowadn.hashing.nullability.notnull import NotNull -from rainbowadn.hashing.nullability.null import Null -from rainbowadn.hashing.nullability.nullable import Nullable -from rainbowadn.hashing.nullability.nullablereference import NullableReference -from rainbowadn.hashing.rainbow_factory import RainbowFactory -__all__ = ('AVLABT',) +__all__ = ('AVLBTBP',) ActiveKeyType = TypeVar('ActiveKeyType') +TreeType = TypeVar('TreeType') -class AVLABT(ActiveBinaryTree[ActiveKeyType, Integer], Generic[ActiveKeyType]): - def __init__( - self, - comparator: Comparator[ActiveKeyType], - reference: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, Integer]]] - ): - assert isinstance(comparator, Comparator) - assert isinstance(reference, NullableReference) - super().__init__(comparator, reference) - - def create( - self, reference: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, Integer]]] - ) -> 'AVLABT[ActiveKeyType]': - assert isinstance(reference, NullableReference) - return type(self)( - self.comparator, - reference - ) - - def height(self) -> int: - reference: Nullable[ - HashPoint[BinaryTree[KeyMetadata[ActiveKeyType, Integer]]] - ] = self.reference.reference - assert isinstance(reference, Nullable) - if isinstance(reference, Null): - return 0 - elif isinstance(reference, NotNull): - tree: BinaryTree[KeyMetadata[ActiveKeyType, Integer]] = self.resolver.resolve(reference.value) - assert isinstance(tree, BinaryTree) - key: KeyMetadata[ActiveKeyType, Integer] = self.resolver.resolve(tree.key) - assert isinstance(key, KeyMetadata) - return self.resolver.resolve(key.metadata).integer - - @classmethod - def empty( - cls, - comparator: Comparator[ActiveKeyType], - factory: RainbowFactory[ActiveKeyType] - ): - assert isinstance(comparator, Comparator) - assert isinstance(factory, RainbowFactory) - return cls( - comparator, - NullableReference( - Null(), - BinaryTreeFactory(KeyMetadataFactory(factory, Integer.factory())) - ) - ) - +class AVLBTBP(BinaryTreeBalancingProtocol[ActiveKeyType, Integer, TreeType]): def empty_metadata(self) -> HashPoint[Integer]: return HashPoint.of(Integer(0)) def metadata( self, - treel: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, Integer]]], - treer: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, Integer]]], - key: HashPoint[ActiveKeyType] + treel: TreeType, + treer: TreeType, + key: HashPoint[ActiveKeyType], + protocol: BinaryTreeCreationProtocol[ActiveKeyType, Integer, TreeType] ) -> HashPoint[Integer]: - assert isinstance(treel, NullableReference) - assert isinstance(treer, NullableReference) - assert isinstance(key, HashPoint) - return HashPoint.of(Integer(1 + max(self.create(treel).height(), self.create(treer).height()))) + return HashPoint.of( + Integer(1 + max(self.height(treel, protocol), self.height(treer, protocol))) + ) - def balance(self) -> ActiveBinaryTree[ActiveKeyType, Integer]: - reference: Nullable[ - HashPoint[BinaryTree[KeyMetadata[ActiveKeyType, Integer]]] - ] = self.reference.reference - assert isinstance(reference, Nullable) - if isinstance(reference, Null): - return self - elif isinstance(reference, NotNull): - tree: BinaryTree[KeyMetadata[ActiveKeyType, Integer]] = self.resolver.resolve(reference.value) - assert isinstance(tree, BinaryTree) - atl = self.create(tree.treel) - assert isinstance(atl, ActiveBinaryTree) - atr = self.create(tree.treer) - assert isinstance(atr, ActiveBinaryTree) - delta = atl.height() - atr.height() + def height( + self, + tree: TreeType, + protocol: BinaryTreeCreationProtocol[ActiveKeyType, Integer, TreeType] + ) -> int: + if protocol.splittable(tree): + _, _, metadata, _ = protocol.split(tree) + return self.resolver.resolve(metadata).integer + else: + return 0 + + def balance( + self, + tree: TreeType, + protocol: BinaryTreeCreationProtocol[ActiveKeyType, Integer, TreeType] + ) -> TreeType: + if protocol.splittable(tree): + treel, key, _, treer = protocol.split(tree) + delta = self.height(treel, protocol) - self.height(treer, protocol) assert isinstance(delta, int) if delta < -1: - assert isinstance(atr.reference.reference, NotNull) - treer: BinaryTree[ - KeyMetadata[ActiveKeyType, Integer] - ] = self.resolver.resolve(atr.reference.reference.value) - assert isinstance(treer, BinaryTree) - atrl = self.create(treer.treel) - assert isinstance(atrl, ActiveBinaryTree) - atrr = self.create(treer.treer) - assert isinstance(atrr, ActiveBinaryTree) - if atrl.height() > atrr.height(): - assert isinstance(atrl.reference.reference, NotNull) - treerl: BinaryTree[ - KeyMetadata[ActiveKeyType, Integer] - ] = self.resolver.resolve(atrl.reference.reference.value) - assert isinstance(treerl, BinaryTree) - return self.active_tree( - self.active_tree( - atl.reference, - treerl.treel, - self.resolver.resolve(tree.key).key - ).reference, - self.active_tree( - treerl.treer, - atrr.reference, - self.resolver.resolve(treer.key).key - ).reference, - self.resolver.resolve(treerl.key).key + assert protocol.splittable(treer) + treerl, keyr, _, treerr = protocol.split(treer) + if self.height(treerl, protocol) > self.height(treerr, protocol): + assert protocol.splittable(treerl) + treerll, keyrl, _, treerlr = protocol.split(treerl) + return protocol.tree( + protocol.tree(treel, treerll, key), + protocol.tree(treerlr, treerr, keyr), + keyrl ) else: - return self.active_tree( - self.active_tree( - atl.reference, - atrl.reference, - self.resolver.resolve(tree.key).key - ).reference, - atrr.reference, - self.resolver.resolve(treer.key).key + return protocol.tree( + protocol.tree(treel, treerl, key), + treerr, + keyr ) elif delta > 1: - assert isinstance(atl.reference.reference, NotNull) - treel: BinaryTree[ - KeyMetadata[ActiveKeyType, Integer] - ] = self.resolver.resolve(atl.reference.reference.value) - assert isinstance(treel, BinaryTree) - atlr = self.create(treel.treer) - assert isinstance(atlr, ActiveBinaryTree) - atll = self.create(treel.treel) - assert isinstance(atll, ActiveBinaryTree) - if atlr.height() > atll.height(): - assert isinstance(atlr.reference.reference, NotNull) - treelr: BinaryTree[ - KeyMetadata[ActiveKeyType, Integer] - ] = self.resolver.resolve(atlr.reference.reference.value) - assert isinstance(treelr, BinaryTree) - return self.active_tree( - self.active_tree( - atll.reference, - treelr.treel, - self.resolver.resolve(treel.key).key - ).reference, - self.active_tree( - treelr.treer, - atr.reference, - self.resolver.resolve(tree.key).key - ).reference, - self.resolver.resolve(treelr.key).key + assert protocol.splittable(treel) + treell, keyl, _, treelr = protocol.split(treel) + if self.height(treelr, protocol) > self.height(treell, protocol): + assert protocol.splittable(treelr) + treelrl, keylr, _, treelrr = protocol.split(treelr) + return protocol.tree( + protocol.tree(treell, treelrl, keyl), + protocol.tree(treelrr, treer, key), + keylr ) else: - return self.active_tree( - atll.reference, - self.active_tree( - atlr.reference, - atr.reference, - self.resolver.resolve(tree.key).key - ).reference, - self.resolver.resolve(treel.key).key + return protocol.tree( + treell, + protocol.tree(treelr, treer, key), + keyl ) else: - return self + return tree else: - raise TypeError + return tree diff --git a/rainbowadn/data/collection/trees/binary/balancedtreecreationprotocol.py b/rainbowadn/data/collection/trees/binary/balancedtreecreationprotocol.py new file mode 100644 index 0000000..7a3a38d --- /dev/null +++ b/rainbowadn/data/collection/trees/binary/balancedtreecreationprotocol.py @@ -0,0 +1,46 @@ +from typing import Generic, TypeVar + +from rainbowadn.data.collection.trees.binary.binarytreebalancingprotocol import BinaryTreeBalancingProtocol +from rainbowadn.data.collection.trees.binary.binarytreecreationprotocol import BinaryTreeCreationProtocol +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver + +__all__ = ('BalancedTreeCreationProtocol',) + +TreeType = TypeVar('TreeType') +ActiveKeyType = TypeVar('ActiveKeyType') +MetaDataType = TypeVar('MetaDataType') + + +class BalancedTreeCreationProtocol( + BinaryTreeCreationProtocol[ActiveKeyType, MetaDataType, TreeType], + Generic[ActiveKeyType, MetaDataType, TreeType] +): + def __init__( + self, + protocol: BinaryTreeBalancingProtocol[ActiveKeyType, MetaDataType, TreeType] + ): + assert isinstance(protocol, BinaryTreeBalancingProtocol) + self.protocol = protocol + self.resolver = protocol.resolver + assert isinstance(self.resolver, HashResolver) + + def splittable(self, tree: TreeType) -> bool: + raise NotImplementedError + + def split(self, tree: TreeType) -> tuple[TreeType, HashPoint[ActiveKeyType], HashPoint[MetaDataType], TreeType]: + raise NotImplementedError + + def _tree(self, treel: TreeType, treer: TreeType, key: HashPoint[ActiveKeyType]) -> TreeType: + raise NotImplementedError + + def tree(self, treel: TreeType, treer: TreeType, key: HashPoint[ActiveKeyType]) -> TreeType: + assert isinstance(key, HashPoint) + return self.protocol.balance( + self._tree( + self.protocol.balance(treel, self), + self.protocol.balance(treer, self), + key + ), + self + ) diff --git a/rainbowadn/data/collection/trees/binary/binarytreebalancingprotocol.py b/rainbowadn/data/collection/trees/binary/binarytreebalancingprotocol.py new file mode 100644 index 0000000..0e95f39 --- /dev/null +++ b/rainbowadn/data/collection/trees/binary/binarytreebalancingprotocol.py @@ -0,0 +1,42 @@ +from typing import Generic, TypeVar + +from rainbowadn.data.collection.trees.binary.binarytreecreationprotocol import BinaryTreeCreationProtocol +from rainbowadn.data.collection.trees.comparison.comparator import Comparator +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver + +__all__ = ('BinaryTreeBalancingProtocol',) + +TreeType = TypeVar('TreeType') +ActiveKeyType = TypeVar('ActiveKeyType') +MetaDataType = TypeVar('MetaDataType') + + +class BinaryTreeBalancingProtocol(Generic[ActiveKeyType, MetaDataType, TreeType]): + def __init__( + self, + comparator: Comparator[ActiveKeyType] + ): + assert isinstance(comparator, Comparator) + self.comparator = comparator + self.resolver = comparator.resolver + assert isinstance(self.resolver, HashResolver) + + def empty_metadata(self) -> HashPoint[MetaDataType]: + raise NotImplementedError + + def metadata( + self, + treel: TreeType, + treer: TreeType, + key: HashPoint[ActiveKeyType], + protocol: BinaryTreeCreationProtocol[ActiveKeyType, MetaDataType, TreeType] + ) -> HashPoint[MetaDataType]: + raise NotImplementedError + + def balance( + self, + tree: TreeType, + protocol: BinaryTreeCreationProtocol[ActiveKeyType, MetaDataType, TreeType] + ) -> TreeType: + raise NotImplementedError diff --git a/rainbowadn/data/collection/trees/binary/binarytreecreationprotocol.py b/rainbowadn/data/collection/trees/binary/binarytreecreationprotocol.py new file mode 100644 index 0000000..1768be8 --- /dev/null +++ b/rainbowadn/data/collection/trees/binary/binarytreecreationprotocol.py @@ -0,0 +1,20 @@ +from typing import Generic, TypeVar + +from rainbowadn.hashing.hashpoint import HashPoint + +__all__ = ('BinaryTreeCreationProtocol',) + +TreeType = TypeVar('TreeType') +ActiveKeyType = TypeVar('ActiveKeyType') +MetaDataType = TypeVar('MetaDataType') + + +class BinaryTreeCreationProtocol(Generic[ActiveKeyType, MetaDataType, TreeType]): + def splittable(self, tree: TreeType) -> bool: + raise NotImplementedError + + def split(self, tree: TreeType) -> tuple[TreeType, HashPoint[ActiveKeyType], HashPoint[MetaDataType], TreeType]: + raise NotImplementedError + + def tree(self, treel: TreeType, treer: TreeType, key: HashPoint[ActiveKeyType]) -> TreeType: + raise NotImplementedError diff --git a/rainbowadn/data/collection/trees/binary/unbalanced.py b/rainbowadn/data/collection/trees/binary/unbalanced.py deleted file mode 100644 index 2c1c8ab..0000000 --- a/rainbowadn/data/collection/trees/binary/unbalanced.py +++ /dev/null @@ -1,75 +0,0 @@ -from typing import Generic, TypeVar - -from rainbowadn.data.collection.trees.binary.activebinarytree import ActiveBinaryTree -from rainbowadn.data.collection.trees.binary.binarytree import BinaryTree, BinaryTreeFactory -from rainbowadn.data.collection.trees.comparison.comparator import Comparator -from rainbowadn.data.collection.keymetadata import KeyMetadata, KeyMetadataFactory -from rainbowadn.hashing.hashpoint import HashPoint -from rainbowadn.hashing.nullability.null import Null -from rainbowadn.hashing.nullability.nullablereference import NullableReference -from rainbowadn.hashing.rainbow_factory import RainbowFactory - -__all__ = ('UnbalancedABT',) - -ActiveKeyType = TypeVar('ActiveKeyType') -MetaDataType = TypeVar('MetaDataType') - - -class UnbalancedABT(ActiveBinaryTree[ActiveKeyType, MetaDataType], Generic[ActiveKeyType, MetaDataType]): - def __init__( - self, - comparator: Comparator[ActiveKeyType], - reference: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - metadata: HashPoint[MetaDataType] - ): - assert isinstance(comparator, Comparator) - assert isinstance(reference, NullableReference) - assert isinstance(metadata, HashPoint) - super().__init__(comparator, reference) - self._metadata = metadata - - def create( - self, reference: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]] - ) -> 'UnbalancedABT[ActiveKeyType, MetaDataType]': - assert isinstance(reference, NullableReference) - return type(self)( - self.comparator, - reference, - self._metadata - ) - - @classmethod - def empty( - cls, - comparator: Comparator[ActiveKeyType], - metadata: HashPoint[MetaDataType], - factory: RainbowFactory[ActiveKeyType] - ): - assert isinstance(comparator, Comparator) - assert isinstance(metadata, HashPoint) - assert isinstance(factory, RainbowFactory) - return cls( - comparator, - NullableReference( - Null(), - BinaryTreeFactory(KeyMetadataFactory(factory, metadata.factory)) - ), - metadata - ) - - def empty_metadata(self) -> HashPoint[MetaDataType]: - return self._metadata - - def metadata( - self, - treel: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - treer: NullableReference[BinaryTree[KeyMetadata[ActiveKeyType, MetaDataType]]], - key: HashPoint[ActiveKeyType] - ) -> HashPoint[MetaDataType]: - assert isinstance(treel, NullableReference) - assert isinstance(treer, NullableReference) - assert isinstance(key, HashPoint) - return self._metadata - - def balance(self) -> 'UnbalancedABT[ActiveKeyType, MetaDataType]': - return self diff --git a/rainbowadn/data/collection/trees/comparison/keyedcomparator.py b/rainbowadn/data/collection/trees/comparison/keyedcomparator.py index be7db26..126d625 100644 --- a/rainbowadn/data/collection/trees/comparison/keyedcomparator.py +++ b/rainbowadn/data/collection/trees/comparison/keyedcomparator.py @@ -1,9 +1,8 @@ from typing import Generic, TypeVar -from rainbowadn.data.collection.trees.comparison.comparator import Comparator, Comparison from rainbowadn.data.collection.keyed import Keyed +from rainbowadn.data.collection.trees.comparison.comparator import Comparator, Comparison from rainbowadn.hashing.hashpoint import HashPoint -from rainbowadn.hashing.hashresolver import HashResolver __all__ = ('KeyedComparator',) @@ -13,11 +12,10 @@ ComparatorKeyType = TypeVar('ComparatorKeyType') class KeyedComparator( Comparator[Keyed[ComparatorKeyType]], Generic[ComparatorKeyType] ): - def __init__(self, resolver: HashResolver, comparator: Comparator[ComparatorKeyType]): - assert isinstance(resolver, HashResolver) + def __init__(self, comparator: Comparator[ComparatorKeyType]): assert isinstance(comparator, Comparator) self.comparator = comparator - super().__init__(resolver) + super().__init__(comparator.resolver) def compare( self, diff --git a/rainbowadn/data/collection/trees/comparison/plaincomparator.py b/rainbowadn/data/collection/trees/comparison/plaincomparator.py index 5e31e6a..986e6fd 100644 --- a/rainbowadn/data/collection/trees/comparison/plaincomparator.py +++ b/rainbowadn/data/collection/trees/comparison/plaincomparator.py @@ -10,8 +10,10 @@ class PlainComparator(ProtocolComparator[Plain]): def compare(self, original: HashPoint[Plain], key: HashPoint[Plain]) -> Comparison: assert isinstance(original, HashPoint) assert isinstance(key, HashPoint) - original_value = self.resolver.resolve(original) - key_value = self.resolver.resolve(key) + original_value: Plain = self.resolver.resolve(original) + assert isinstance(original_value, Plain) + key_value: Plain = self.resolver.resolve(key) + assert isinstance(key, Plain) if key_value.source < original_value.source: return Left() elif key_value.source > original_value.source: diff --git a/rainbowadn/hashing/hashmentionable.py b/rainbowadn/hashing/hashmentionable.py index b92e848..4861432 100644 --- a/rainbowadn/hashing/hashmentionable.py +++ b/rainbowadn/hashing/hashmentionable.py @@ -1,13 +1,17 @@ +from typing import TypeVar + from rainbowadn.hashing.rainbow_factory import RainbowFactory __all__ = ('HashMentionable',) +HashMentioned = TypeVar('HashMentioned') + class HashMentionable: def __bytes__(self): raise NotImplementedError - def __factory__(self) -> RainbowFactory['HashMentionable']: + def __factory__(self: HashMentioned) -> RainbowFactory[HashMentioned]: raise NotImplementedError def __topology_hash__(self) -> bytes: diff --git a/rainbowadn/hashing/hashpoint.py b/rainbowadn/hashing/hashpoint.py index 7abe9e3..e4a6a1b 100644 --- a/rainbowadn/hashing/hashpoint.py +++ b/rainbowadn/hashing/hashpoint.py @@ -12,6 +12,11 @@ __all__ = ('HashPoint',) HashMentioned = TypeVar('HashMentioned') +def _hash(source: bytes) -> bytes: + assert isinstance(source, bytes) + return hashlib.sha256(source).digest() + + class HashPoint(Generic[HashMentioned]): def __init__(self, factory: RainbowFactory[HashMentioned], point: bytes, value: Nullable[HashMentioned]): assert isinstance(factory, RainbowFactory) @@ -25,13 +30,13 @@ class HashPoint(Generic[HashMentioned]): def __bytes__(self): return self.point - HASH_LENGTH = 32 + HASH_LENGTH = len(_hash(b'')) NULL_HASH = b'\0' * HASH_LENGTH @classmethod def hash(cls, source: bytes) -> bytes: assert isinstance(source, bytes) - return hashlib.sha256(source).digest() + return _hash(source) @classmethod def bytes_of_mentioned(cls, mentioned: HashMentionable): diff --git a/rainbowadn/hashing/static.py b/rainbowadn/hashing/static.py index 6bcbb81..913dafb 100644 --- a/rainbowadn/hashing/static.py +++ b/rainbowadn/hashing/static.py @@ -9,16 +9,16 @@ __all__ = ('StaticMentionable', 'StaticFactory',) StaticMentioned = TypeVar('StaticMentioned') -class StaticMentionable(HashMentionable, abc.ABC, Generic[StaticMentioned]): +class StaticMentionable(HashMentionable, abc.ABC): @classmethod - def from_bytes(cls, source: bytes) -> StaticMentioned: + def from_bytes(cls: Type[StaticMentioned], source: bytes) -> StaticMentioned: raise NotImplementedError def __factory__(self) -> RainbowFactory[StaticMentioned]: return self.factory() @classmethod - def factory(cls) -> RainbowFactory[StaticMentioned]: + def factory(cls: Type[StaticMentioned]) -> RainbowFactory[StaticMentioned]: return StaticFactory(cls) diff --git a/rainbowadn/v13/bankstate.py b/rainbowadn/v13/bankstate.py index f2d5af4..69eae1c 100644 --- a/rainbowadn/v13/bankstate.py +++ b/rainbowadn/v13/bankstate.py @@ -3,7 +3,7 @@ from typing import Iterable from rainbowadn.data.atomic.integer import Integer from rainbowadn.data.collection.keymetadata import KeyMetadata, KeyMetadataFactory from rainbowadn.data.collection.trees.binary.activebinarytree import ActiveBinaryTree -from rainbowadn.data.collection.trees.binary.avl import AVLABT +from rainbowadn.data.collection.trees.binary.avl import AVLBTBP from rainbowadn.data.collection.trees.binary.binarytree import BinaryTree, BinaryTreeFactory from rainbowadn.data.collection.trees.comparison.comparator import Fail from rainbowadn.data.collection.trees.comparison.hashcomparator import HashComparator @@ -24,7 +24,7 @@ from rainbowadn.v13.transaction import Coin, Transaction, TransactionData __all__ = ('BankState',) -class BankState(RecursiveMentionable, StaticMentionable['BankState']): +class BankState(RecursiveMentionable, StaticMentionable): def __init__( self, minted: NullableReference[BinaryTree[KeyMetadata[Coin, Integer]]], @@ -107,9 +107,13 @@ class BankState(RecursiveMentionable, StaticMentionable['BankState']): transaction_data: TransactionData = resolver.resolve(transaction_resolved.data) assert isinstance(transaction_data, TransactionData) - minted: ActiveBinaryTree[Coin, Integer] = AVLABT(HashComparator(resolver, Fail()), self.minted) + minted: ActiveBinaryTree[Coin, Integer] = ActiveBinaryTree( + AVLBTBP(HashComparator(resolver, Fail())), self.minted + ) assert isinstance(minted, ActiveBinaryTree) - used: ActiveBinaryTree[Coin, Integer] = AVLABT(HashComparator(resolver, Fail()), self.used) + used: ActiveBinaryTree[Coin, Integer] = ActiveBinaryTree( + AVLBTBP(HashComparator(resolver, Fail())), self.used + ) assert isinstance(used, ActiveBinaryTree) in_coin: HashPoint[Coin] diff --git a/rainbowadn/v13/signature.py b/rainbowadn/v13/signature.py index 2867a15..ac29b5c 100644 --- a/rainbowadn/v13/signature.py +++ b/rainbowadn/v13/signature.py @@ -13,7 +13,7 @@ class BadSignature(nacl.exceptions.BadSignatureError): pass -class Signature(Atomic['Signature']): +class Signature(Atomic): def __init__(self, source: bytes): assert isinstance(source, bytes) assert len(source) == nacl.bindings.crypto_sign_BYTES diff --git a/rainbowadn/v13/subject.py b/rainbowadn/v13/subject.py index b1751f8..cf05169 100644 --- a/rainbowadn/v13/subject.py +++ b/rainbowadn/v13/subject.py @@ -6,7 +6,7 @@ from rainbowadn.data.atomic.atomic import Atomic __all__ = ('Subject',) -class Subject(Atomic['Subject']): +class Subject(Atomic): def __init__(self, verify_key: VerifyKey): assert isinstance(verify_key, VerifyKey) self.verify_key: VerifyKey = verify_key diff --git a/rainbowadn/v13/transaction.py b/rainbowadn/v13/transaction.py index 7483ae9..0223486 100644 --- a/rainbowadn/v13/transaction.py +++ b/rainbowadn/v13/transaction.py @@ -20,7 +20,7 @@ from rainbowadn.v13.subject import Subject __all__ = ('CoinData', 'Coin', 'TransactionData', 'Transaction',) -class CoinData(RecursiveMentionable, StaticMentionable['CoinData']): +class CoinData(RecursiveMentionable, StaticMentionable): def __init__( self, owner: HashPoint[Subject], @@ -56,7 +56,7 @@ class CoinData(RecursiveMentionable, StaticMentionable['CoinData']): f'{tabulate(tab)}{resolver.resolve(self.value)}' -class Coin(RecursiveMentionable, StaticMentionable['Coin']): +class Coin(RecursiveMentionable, StaticMentionable): def __init__( self, data: HashPoint[CoinData], @@ -99,7 +99,7 @@ class Coin(RecursiveMentionable, StaticMentionable['Coin']): f'{tabulate(tab)})' -class TransactionData(RecursiveMentionable, StaticMentionable['TransactionData']): +class TransactionData(RecursiveMentionable, StaticMentionable): def __init__( self, in_coins: NullableReference[Stack[Coin]], @@ -250,7 +250,7 @@ class TransactionData(RecursiveMentionable, StaticMentionable['TransactionData'] f'{tabulate(tab)}{self.out_coins.str(resolver, tab)}' -class Transaction(RecursiveMentionable, StaticMentionable['Transaction']): +class Transaction(RecursiveMentionable, StaticMentionable): def __init__( self, data: HashPoint[TransactionData], diff --git a/rainbowadn/wrisbt/__init__.py b/rainbowadn/wrisbt/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rainbowadn/wrisbt/weakreferenceindexsetbtree.py b/rainbowadn/wrisbt/weakreferenceindexsetbtree.py new file mode 100644 index 0000000..9fd6fb8 --- /dev/null +++ b/rainbowadn/wrisbt/weakreferenceindexsetbtree.py @@ -0,0 +1,312 @@ +import bisect +from typing import Iterable, Sequence + +from rainbowadn.hashing.hash_point_format import hash_point_format, tabulate +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver +from rainbowadn.hashing.nullability.notnull import NotNull +from rainbowadn.hashing.nullability.null import Null +from rainbowadn.hashing.nullability.nullable import Nullable +from rainbowadn.hashing.rainbow_factory import RainbowFactory +from rainbowadn.hashing.recursivementionable import RecursiveMentionable + +__all__ = ('WeakReferenceIndexSetBTree', 'WrisbtFactory',) + + +class WeakReferenceIndexSetBTree(RecursiveMentionable): + def __init__( + self, + source: bytes, + height: int, + keymin: int, + root: bool, + cache: tuple[Nullable['WeakReferenceIndexSetBTree'], ...] + ): + assert isinstance(source, bytes) + assert isinstance(height, int) + assert isinstance(keymin, int) + assert isinstance(root, bool) + assert isinstance(cache, tuple) + + self.length = len(source) // HashPoint.HASH_LENGTH + assert len(source) == self.length * HashPoint.HASH_LENGTH + self.source = source + + assert height >= 0 + self.height = height + self.leaf = height == 0 + + self.empty = self.length == 0 + if self.empty: + assert self.leaf + + if self.leaf: + self.keys = self.length + self.children = 0 + else: + self.keys = self.length // 2 + self.children = self.keys + 1 + assert self.length == self.keys + self.children + + assert keymin > 0 + self.keymin = keymin + + self.root = root + + if not root: + assert keymin <= self.keys + assert self.keys <= 2 * keymin + 1 + + assert len(cache) == self.children + child_index: int + cached: Nullable[WeakReferenceIndexSetBTree] + self.cache = cache + + if self.balanced(): + self._hash_point = HashPoint.of(self) + + def hash_point(self) -> HashPoint['WeakReferenceIndexSetBTree']: + return self._hash_point + + def full(self) -> bool: + return self.keys == 2 * self.keymin + 1 + + def bytes_no(self, index: int) -> bytes: + assert isinstance(index, int) + assert 0 <= index < self.length + return self.source[HashPoint.HASH_LENGTH * index:HashPoint.HASH_LENGTH * (index + 1)] + + def key_no(self, index: int) -> bytes: + assert isinstance(index, int) + assert 0 <= index < self.keys + return self.bytes_no(index) + + def cached_no(self, index: int) -> Nullable['WeakReferenceIndexSetBTree']: + assert isinstance(index, int) + assert 0 <= index < self.children + assert not self.leaf + cached: Nullable[WeakReferenceIndexSetBTree] = self.cache[index] + assert isinstance(cached, Nullable) + if isinstance(cached, NotNull): + tree: WeakReferenceIndexSetBTree = cached.value + assert self.bytes_no(self.keys + index) == tree.hash_point().point + return cached + + def child_no(self, index: int) -> HashPoint['WeakReferenceIndexSetBTree']: + assert isinstance(index, int) + assert 0 <= index < self.children + assert not self.leaf + return HashPoint( + WrisbtFactory(self.height - 1, self.keymin, False), + self.bytes_no(self.keys + index), + self.cached_no(index) + ) + + def balanced(self) -> bool: + return self.keys <= 2 * self.keymin + + def points(self) -> Iterable[HashPoint]: + assert self.balanced() + if self.leaf: + return [] + else: + return [self.child_no(child_index) for child_index in range(self.children)] + + def __bytes__(self): + assert self.balanced() + return self.source + + def __topology_hash__(self) -> bytes: + return HashPoint.hash(self.source[self.keys * HashPoint.HASH_LENGTH:]) + + def __factory__(self) -> RainbowFactory['WeakReferenceIndexSetBTree']: + assert self.balanced() + return WrisbtFactory(self.height, self.keymin, self.root) + + def range(self, left: int, right: int) -> 'WeakReferenceIndexSetBTree': + assert isinstance(left, int) + assert isinstance(right, int) + assert 0 <= left < right <= self.keys + hl: int = HashPoint.HASH_LENGTH + assert isinstance(hl, int) + if self.leaf: + return WeakReferenceIndexSetBTree( + self.source[hl * left:hl * right], + 0, + self.keymin, + False, + () + ) + else: + keybytes: bytes = self.source[hl * left:hl * right] + assert isinstance(keybytes, bytes) + childbytes: bytes = self.source[hl * (self.keys + left):hl * (self.keys + right + 1)] + assert isinstance(childbytes, bytes) + return WeakReferenceIndexSetBTree( + keybytes + childbytes, + self.height, + self.keymin, + False, + self.cache[left:right + 1], + ) + + def split(self) -> tuple['WeakReferenceIndexSetBTree', bytes, 'WeakReferenceIndexSetBTree']: + assert self.full() + return ( + self.range(0, self.keymin), + self.key_no(self.keymin), + self.range(self.keymin + 1, 2 * self.keymin + 1), + ) + + def str(self, resolver: HashResolver, tab: int) -> str: + assert isinstance(resolver, HashResolver) + assert isinstance(tab, int) + + formatted = f'{self.height}' \ + f'{tabulate(tab)}(' + for key_index in range(self.keys): + formatted += f'{tabulate(tab + 1)}{self.key_no(key_index).hex()}' + for child_index in range(self.children): + formatted += f'{tabulate(tab + 1)}{hash_point_format(self.child_no(child_index), resolver, tab + 1)}' + + return f'{formatted}' \ + f'{tabulate(tab)})' + + def contains(self, resolver: HashResolver, key: bytes) -> bool: + assert isinstance(resolver, HashResolver) + assert isinstance(key, bytes) + assert len(key) == HashPoint.HASH_LENGTH + hl: int = HashPoint.HASH_LENGTH + assert isinstance(hl, int) + + assert self.balanced() + + index: int = bisect.bisect_left(KeyView(self), key) + assert isinstance(index, int) + + if index < self.keys and self.key_no(index) == key: + return True + if index < self.keys: + assert key < self.key_no(index) + if index > 0: + assert key > self.key_no(index - 1) + if self.leaf: + return False + child: WeakReferenceIndexSetBTree = resolver.resolve(self.child_no(index)) + assert isinstance(child, WeakReferenceIndexSetBTree) + return child.contains(resolver, key) + + def add(self, resolver: HashResolver, key: bytes) -> 'WeakReferenceIndexSetBTree': + assert isinstance(resolver, HashResolver) + assert isinstance(key, bytes) + assert len(key) == HashPoint.HASH_LENGTH + hl: int = HashPoint.HASH_LENGTH + assert isinstance(hl, int) + + assert self.balanced() + + index: int = bisect.bisect_left(KeyView(self), key) + assert isinstance(index, int) + + if index < self.keys and self.key_no(index) == key: + return self + if index < self.keys: + assert key < self.key_no(index) + if index > 0: + assert key > self.key_no(index - 1) + if self.leaf: + return WeakReferenceIndexSetBTree( + self.source[:hl * index] + key + self.source[hl * index:], + self.height, + self.keymin, + self.root, + () + ) + child: WeakReferenceIndexSetBTree = resolver.resolve(self.child_no(index)) + assert isinstance(child, WeakReferenceIndexSetBTree) + child: WeakReferenceIndexSetBTree = child.add(resolver, key) + assert isinstance(child, WeakReferenceIndexSetBTree) + if child.full(): + left, middle, right = child.split() + assert isinstance(left, WeakReferenceIndexSetBTree) + assert isinstance(middle, bytes) + assert isinstance(right, WeakReferenceIndexSetBTree) + return WeakReferenceIndexSetBTree( + ( + self.source[:hl * index] + + + middle + + + self.source[hl * index:hl * (self.keys + index)] + + + bytes(left.hash_point()) + + + bytes(right.hash_point()) + + + self.source[hl * (self.keys + index + 1):] + ), + self.height, + self.keymin, + self.root, + self.cache[:index] + (NotNull(left), NotNull(right)) + self.cache[index + 1:] + ) + else: + return WeakReferenceIndexSetBTree( + ( + self.source[:hl * (self.keys + index)] + + + bytes(HashPoint.of(child)) + + + self.source[hl * (self.keys + index + 1):] + ), + self.height, + self.keymin, + self.root, + self.cache[:index] + (NotNull(child),) + self.cache[index + 1:] + ) + + def iter_keys(self, resolver: HashResolver) -> Iterable[bytes]: + if self.leaf: + for key_index in range(self.keys): + yield self.key_no(key_index) + else: + for index in range(self.length): + real_index, mode = divmod(index, 2) + if mode: + yield self.key_no(real_index) + else: + yield from resolver.resolve(self.child_no(real_index)).iter_keys(resolver) + + +class KeyView(Sequence[WeakReferenceIndexSetBTree]): + def __init__(self, wrisbt: WeakReferenceIndexSetBTree): + assert isinstance(wrisbt, WeakReferenceIndexSetBTree) + self.wrisbt = wrisbt + + def __len__(self): + return self.wrisbt.keys + + def __getitem__(self, index: int) -> bytes: + return self.wrisbt.key_no(index) + + +class WrisbtFactory(RainbowFactory[WeakReferenceIndexSetBTree]): + def __init__(self, height: int, keymin: int, root: bool): + assert isinstance(height, int) + assert isinstance(keymin, int) + assert isinstance(root, bool) + assert height >= 0 + self.height = height + assert keymin > 0 + self.keymin = keymin + self.root = root + + def from_bytes(self, source: bytes) -> WeakReferenceIndexSetBTree: + assert isinstance(source, bytes) + return WeakReferenceIndexSetBTree( + source, + self.height, + self.keymin, + self.root, + (Null(),) * (len(source) // (2 * HashPoint.HASH_LENGTH) + 1) if self.height else () + ) diff --git a/rainbowadn/wrisbt/wrisbtchainprotocol.py b/rainbowadn/wrisbt/wrisbtchainprotocol.py new file mode 100644 index 0000000..20d0857 --- /dev/null +++ b/rainbowadn/wrisbt/wrisbtchainprotocol.py @@ -0,0 +1,45 @@ +from typing import Generic, TypeVar + +from rainbowadn.chain.blockchainprotocol import BlockChainProtocol +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver +from rainbowadn.hashing.rainbow_factory import RainbowFactory +from rainbowadn.wrisbt.wrisbtindex import WrisbtIndex, WrisbtIndexFactory +from rainbowadn.wrisbt.wrisbtprotocol import WrisbtProtocol +from rainbowadn.wrisbt.wrisbtroot import WrisbtRoot, WrisbtRootFactory + +__all__ = ('WrisbtChainProtocol',) + +TargetType = TypeVar('TargetType') + + +class WrisbtChainProtocol( + BlockChainProtocol[ + TargetType, + WrisbtIndex, + WrisbtRoot + ], + Generic[TargetType] +): + def __init__( + self, + resolver: HashResolver, + total_factory: RainbowFactory[TargetType], + keymin: int + ): + assert isinstance(total_factory, RainbowFactory) + assert isinstance(keymin, int) + assert keymin >= 2 + self.keymin = keymin + super().__init__( + WrisbtProtocol(resolver, keymin), + total_factory, + WrisbtIndexFactory(keymin) + ) + self.total_factory = total_factory + + def actual_state_factory(self) -> RainbowFactory[WrisbtRoot]: + return WrisbtRootFactory(self.keymin) + + def actual_state(self, state: WrisbtIndex) -> HashPoint[WrisbtRoot]: + return state.total diff --git a/rainbowadn/wrisbt/wrisbtindex.py b/rainbowadn/wrisbt/wrisbtindex.py new file mode 100644 index 0000000..c907d13 --- /dev/null +++ b/rainbowadn/wrisbt/wrisbtindex.py @@ -0,0 +1,60 @@ +from typing import Iterable + +from rainbowadn.hashing.hash_point_format import hash_point_format, tabulate +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver +from rainbowadn.hashing.nullability.null import Null +from rainbowadn.hashing.rainbow_factory import RainbowFactory +from rainbowadn.hashing.recursivementionable import RecursiveMentionable +from rainbowadn.wrisbt.wrisbtroot import WrisbtRoot, WrisbtRootFactory + +__all__ = ('WrisbtIndex', 'WrisbtIndexFactory',) + + +class WrisbtIndex(RecursiveMentionable): + def __init__( + self, + total: HashPoint[WrisbtRoot], + delta: HashPoint[WrisbtRoot], + keymin: int + ): + assert isinstance(total, HashPoint) + assert isinstance(delta, HashPoint) + assert isinstance(keymin, int) + self.total = total + self.delta = delta + assert keymin >= 2 + self.keymin = keymin + + def points(self) -> Iterable[HashPoint]: + return [self.total, self.delta] + + def __bytes__(self): + return bytes(self.total) + bytes(self.delta) + + def __factory__(self) -> RainbowFactory['WrisbtIndex']: + return WrisbtIndexFactory(self.keymin) + + def str(self, resolver: HashResolver, tab: int) -> str: + assert isinstance(resolver, HashResolver) + assert isinstance(tab, int) + return f'(index)' \ + f'{tabulate(tab)}{hash_point_format(self.total, resolver, tab)}' \ + f'{tabulate(tab)}{hash_point_format(self.delta, resolver, tab)}' + + +class WrisbtIndexFactory(RainbowFactory[WrisbtIndex]): + def __init__(self, keymin: int): + assert isinstance(keymin, int) + assert keymin >= 2 + self.keymin = keymin + self.root_factory: RainbowFactory[WrisbtRoot] = WrisbtRootFactory(keymin) + assert isinstance(self.root_factory, RainbowFactory) + + def from_bytes(self, source: bytes) -> WrisbtIndex: + assert isinstance(source, bytes) + return WrisbtIndex( + HashPoint(self.root_factory, source[:HashPoint.HASH_LENGTH], Null()), + HashPoint(self.root_factory, source[HashPoint.HASH_LENGTH:], Null()), + self.keymin + ) diff --git a/rainbowadn/wrisbt/wrisbtprotocol.py b/rainbowadn/wrisbt/wrisbtprotocol.py new file mode 100644 index 0000000..5450884 --- /dev/null +++ b/rainbowadn/wrisbt/wrisbtprotocol.py @@ -0,0 +1,52 @@ +from typing import TypeVar + +from rainbowadn.chain.states.activestateprotocol import ActiveStateProtocol +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver +from rainbowadn.wrisbt.wrisbtindex import WrisbtIndex +from rainbowadn.wrisbt.wrisbtroot import WrisbtRoot + +__all__ = ('WrisbtProtocol',) + +TargetType = TypeVar('TargetType') + + +class WrisbtProtocol(ActiveStateProtocol[TargetType, WrisbtIndex]): + def __init__(self, resolver: HashResolver, keymin: int): + assert isinstance(resolver, HashResolver) + assert isinstance(keymin, int) + super().__init__(resolver) + assert keymin >= 2 + self.keymin = keymin + + def _initial_state(self) -> HashPoint[WrisbtIndex]: + return HashPoint.of( + WrisbtIndex( + HashPoint.of(WrisbtRoot.empty(self.keymin)), + HashPoint.of(WrisbtRoot.empty(self.keymin)), + self.keymin + ) + ) + + def _derive( + self, + previous: HashPoint[WrisbtIndex], + header: HashPoint[TargetType] + ) -> HashPoint[WrisbtIndex]: + assert isinstance(previous, HashPoint) + assert isinstance(header, HashPoint) + index = self.resolver.resolve(previous) + assert isinstance(index, WrisbtIndex) + + empty: WrisbtRoot = WrisbtRoot.empty(self.keymin) + assert isinstance(empty, WrisbtRoot) + total: WrisbtRoot = self.resolver.resolve(index.total) + assert isinstance(total, WrisbtRoot) + + return HashPoint.of( + WrisbtIndex( + HashPoint.of(total.index(self.resolver, header, empty)), + HashPoint.of(empty.index(self.resolver, header, total)), + index.keymin + ) + ) diff --git a/rainbowadn/wrisbt/wrisbtroot.py b/rainbowadn/wrisbt/wrisbtroot.py new file mode 100644 index 0000000..5495177 --- /dev/null +++ b/rainbowadn/wrisbt/wrisbtroot.py @@ -0,0 +1,123 @@ +from typing import Iterable, Optional + +from rainbowadn.data.atomic.integer import Integer +from rainbowadn.wrisbt.weakreferenceindexsetbtree import WeakReferenceIndexSetBTree, WrisbtFactory +from rainbowadn.hashing.hash_point_format import hash_point_format, tabulate +from rainbowadn.hashing.hashmentionable import HashMentionable +from rainbowadn.hashing.hashpoint import HashPoint +from rainbowadn.hashing.hashresolver import HashResolver +from rainbowadn.hashing.nullability.notnull import NotNull +from rainbowadn.hashing.nullability.null import Null +from rainbowadn.hashing.rainbow_factory import RainbowFactory +from rainbowadn.hashing.recursivementionable import RecursiveMentionable + +__all__ = ('WrisbtRoot','WrisbtRootFactory',) + + +class WrisbtRoot(RecursiveMentionable): + def __init__(self, root: HashPoint[WeakReferenceIndexSetBTree], height: int, keymin: int): + assert isinstance(root, HashPoint) + assert isinstance(height, int) + assert isinstance(keymin, int) + self.root = root + self.height = height + self.keymin = keymin + + def points(self) -> Iterable[HashPoint]: + return [self.root] + + def __bytes__(self): + return bytes(self.root) + bytes(Integer(self.height)) + + def __factory__(self) -> RainbowFactory['WrisbtRoot']: + return WrisbtRootFactory(self.keymin) + + @classmethod + def empty(cls, keymin: int) -> 'WrisbtRoot': + assert isinstance(keymin, int) + return WrisbtRoot(HashPoint.of(WeakReferenceIndexSetBTree(b'', 0, keymin, True, ())), 0, keymin) + + def str(self, resolver: HashResolver, tab: int) -> str: + assert isinstance(resolver, HashResolver) + assert isinstance(tab, int) + return f'(root)' \ + f'{tabulate(tab)}{self.height}' \ + f'{tabulate(tab)}{hash_point_format(self.root, resolver, tab)}' + + def contains(self, resolver: HashResolver, key: bytes) -> bool: + assert isinstance(resolver, HashResolver) + assert isinstance(key, bytes) + assert len(key) == HashPoint.HASH_LENGTH + + root: WeakReferenceIndexSetBTree = resolver.resolve(self.root) + assert isinstance(root, WeakReferenceIndexSetBTree) + + return root.contains(resolver, key) + + def add(self, resolver: HashResolver, key: bytes) -> 'WrisbtRoot': + assert isinstance(resolver, HashResolver) + assert isinstance(key, bytes) + assert len(key) == HashPoint.HASH_LENGTH + + root: WeakReferenceIndexSetBTree = resolver.resolve(self.root).add(resolver, key) + assert isinstance(root, WeakReferenceIndexSetBTree) + + if root.full(): + left, middle, right = root.split() + assert isinstance(left, WeakReferenceIndexSetBTree) + assert isinstance(middle, bytes) + assert isinstance(right, WeakReferenceIndexSetBTree) + root = WeakReferenceIndexSetBTree( + middle + bytes(HashPoint.of(left)) + bytes(HashPoint.of(right)), + root.height + 1, + root.keymin, + True, + (NotNull(left), NotNull(right)) + ) + assert isinstance(root, WeakReferenceIndexSetBTree) + return self.of(root) + + @classmethod + def of(cls, root: WeakReferenceIndexSetBTree) -> 'WrisbtRoot': + assert isinstance(root, WeakReferenceIndexSetBTree) + return cls(HashPoint.of(root), root.height, root.keymin) + + def keys(self, resolver: HashResolver) -> list[bytes]: + return list(resolver.resolve(self.root).iter_keys(resolver)) + + def index( + self, resolver: HashResolver, target: HashPoint, exclude: Optional['WrisbtRoot'] + ) -> 'WrisbtRoot': + assert isinstance(resolver, HashResolver) + assert isinstance(target, HashPoint) + if exclude is None: + exclude = self.empty(self.keymin) + assert isinstance(exclude, WrisbtRoot) + key: bytes = target.point + assert isinstance(key, bytes) + if exclude.contains(resolver, key) or self.contains(resolver, key): + return self + tree = self + value: HashMentionable = resolver.resolve(target) + assert isinstance(value, HashMentionable) + if isinstance(value, RecursiveMentionable): + for hash_point in value.points(): + tree = tree.index(resolver, hash_point, exclude) + tree = tree.add(resolver, key) + return tree + + +class WrisbtRootFactory(RainbowFactory[WrisbtRoot]): + def __init__(self, keymin: int): + assert isinstance(keymin, int) + self.keymin = keymin + + def from_bytes(self, source: bytes) -> WrisbtRoot: + assert isinstance(source, bytes) + height: int = Integer.from_bytes(source[HashPoint.HASH_LENGTH:]).integer + assert isinstance(height, int) + return WrisbtRoot( + HashPoint(WrisbtFactory(height, self.keymin, True), source[:HashPoint.HASH_LENGTH], Null()), + height, + self.keymin + )