This commit is contained in:
AF 2022-06-23 00:51:43 +03:00
parent 1a19695e6e
commit 8daaefa4a4
30 changed files with 536 additions and 150 deletions

88
plot.py Normal file
View File

@ -0,0 +1,88 @@
import asyncio
import random
import matplotlib.pyplot as plt
import numpy as np
from nacl.signing import SigningKey
from rainbowadn.chain import *
from rainbowadn.core import *
from rainbowadn.nullability import *
from rainbowadn.testing.delayedresolver import DelayedResolver
from rainbowadn.testing.dictresolver import DictResolver
from rainbowadn.testing.instrumentation import Concurrency
from rainbowadn.v13 import *
plt.rcParams['figure.figsize'] = [12, 6]
plt.style.use("dark_background")
plt.subplots_adjust(left=0.05, right=0.99, top=0.99, bottom=0.1)
def get_dr() -> ExtendableResolver:
dr = DictResolver()
dr = DelayedResolver(dr, lambda: random.uniform(0.200, 0.500))
return dr
def plot(instrumentation: Concurrency):
plt.plot(*np.array(instrumentation.logs).transpose())
async def plot_every_minute(instrumentation: Concurrency):
while True:
await asyncio.sleep(60)
plot(instrumentation)
plt.show()
plt.clf()
plt.subplots_adjust(left=0.05, right=0.99, top=0.99, bottom=0.1)
async def main():
set_gather_asyncio()
bank: BankChain = BankChain.empty(ReductionChainMetaFactory().loose())
key_0 = SigningKey.generate()
transaction_0 = Transaction.make(
[],
[CoinData.of(Subject(key_0.verify_key), 100_000)],
[]
)
coin_0, coin_1 = await transaction_0.coins(MINT_CONST, NotNull(HashPoint.of(Subject(key_0.verify_key))))
bank = await bank.adds(
[
transaction_0,
Transaction.make(
[coin_1],
[CoinData.of(Subject(SigningKey.generate().verify_key), 10_000)],
[key_0]
),
]
)
for _ in range(16):
bank = await bank.adds(
[
Transaction.make(
[],
[CoinData.of(Subject(SigningKey.generate().verify_key), 0)] * 16,
[]
)
for _ in range(16)
]
)
print('built')
assert_true(await bank.verify())
bank = BankChain.from_reference(
ReductionChainMetaFactory(), await get_dr().migrate_resolved(bank.reference)
)
print('saved')
set_gather_asyncio()
with Concurrency(DelayedResolver, 'sleep') as sleeps:
# task = asyncio.create_task(plot_every_minute(sleeps))
assert_true(await bank.verify())
# task.cancel()
plot(sleeps)
plt.show()
asyncio.run(main())

View File

@ -37,13 +37,18 @@ class Block(RecursiveMentionable, Generic[HeaderType, StateType]):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
return f'{await self.previous.str(tab)}' \ previous_str, header_str, state_str = await gather(
self.previous.str(tab),
hash_point_format(self.header, tab + 1),
hash_point_format(self.state, tab + 1),
)
return f'{previous_str}' \
f'{tabulate(tab)}(' \ f'{tabulate(tab)}(' \
f'{tabulate(tab + 1)}block' \ f'{tabulate(tab + 1)}block' \
f'{tabulate(tab + 1)}(header)' \ f'{tabulate(tab + 1)}(header)' \
f'{tabulate(tab + 1)}{await hash_point_format(self.header, tab + 1)}' \ f'{tabulate(tab + 1)}{header_str}' \
f'{tabulate(tab + 1)}(state)' \ f'{tabulate(tab + 1)}(state)' \
f'{tabulate(tab + 1)}{await hash_point_format(self.state, tab + 1)}' \ f'{tabulate(tab + 1)}{state_str}' \
f'{tabulate(tab)})' f'{tabulate(tab)})'

View File

@ -1,4 +1,3 @@
import asyncio
from typing import Generic, TypeVar from typing import Generic, TypeVar
from rainbowadn.core import * from rainbowadn.core import *
@ -126,8 +125,12 @@ class BlockChain(
previous: ChainCollectionInterface[ previous: ChainCollectionInterface[
Block[HeaderType, StateType], HeaderType, ActualStateType Block[HeaderType, StateType], HeaderType, ActualStateType
] = await self.previous() ] = await self.previous()
assert_true(await self.verify_link(previous.reference)) assert_trues(
assert_true(await asyncio.create_task(previous.verify())) await gather(
self.verify_link(previous.reference),
previous.verify(),
)
)
return True return True
async def _verify_link( async def _verify_link(

View File

@ -36,6 +36,30 @@ class ActiveStageStateProtocol(
self.stage_factory = stage_factory self.stage_factory = stage_factory
self.base_state_factory = base_state_factory self.base_state_factory = base_state_factory
async def verify(
self,
previous: NullableReference[
StateStage[
HeaderType,
BaseStateType,
StageType
]
],
header: HashPoint[HeaderType],
state: HashPoint[
StateStage[
HeaderType,
BaseStateType,
StageType
]
]
) -> bool:
return await self.stage_state_protocol().verify(
previous,
header,
state
)
async def derive( async def derive(
self, self,
previous: NullableReference[ previous: NullableReference[

View File

@ -73,17 +73,17 @@ class StageStage(
else: else:
previous_stage: StageStage[HeaderType, BaseStateType, StageType] = await self.previous.resolve() previous_stage: StageStage[HeaderType, BaseStateType, StageType] = await self.previous.resolve()
assert isinstance(previous_stage, StageStage) assert isinstance(previous_stage, StageStage)
assert_true( assert_trues(
await self.protocol.verify_stage( await gather(
self.protocol.verify_stage(
previous_stage.stage, previous_stage.stage,
self.stage self.stage
) ),
) previous_stage.verify(
assert_true(
await previous_stage.verify(
previous, previous,
header, header,
base_factory base_factory
),
) )
) )
return True return True
@ -102,8 +102,12 @@ class StageStage(
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
return f'{await self.previous.str(tab)}' \ previous_str, stage_str = await gather(
f'{tabulate(tab)}{await hash_point_format(self.stage, tab)}' self.previous.str(tab),
hash_point_format(self.stage, tab)
)
return f'{previous_str}' \
f'{tabulate(tab)}{stage_str}'
class StageStageFactory(RainbowFactory[StageStage[HeaderType, BaseStateType, StageType]]): class StageStageFactory(RainbowFactory[StageStage[HeaderType, BaseStateType, StageType]]):
@ -157,19 +161,19 @@ class StateStage(
assert isinstance(header, HashPoint) assert isinstance(header, HashPoint)
previous_stage: StageStage[HeaderType, BaseStateType, StageType] = await self.previous.resolve() previous_stage: StageStage[HeaderType, BaseStateType, StageType] = await self.previous.resolve()
assert isinstance(previous_stage, StageStage) assert isinstance(previous_stage, StageStage)
assert_true( assert_trues(
await self.protocol.verify_state( await gather(
self.protocol.verify_state(
previous_stage.stage, previous_stage.stage,
self.state self.state
) ),
) previous_stage.verify(
assert_true(
await previous_stage.verify(
previous, previous,
header, header,
self.state.factory self.state.factory
) )
) )
)
return True return True
def points(self) -> Iterable[HashPoint]: def points(self) -> Iterable[HashPoint]:
@ -187,8 +191,12 @@ class StateStage(
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
return f'{await hash_point_format(self.previous, tab)}' \ previous_str, state_str = await gather(
f'{tabulate(tab)}{await hash_point_format(self.state, tab)}' hash_point_format(self.previous, tab),
hash_point_format(self.state, tab),
)
return f'{previous_str}' \
f'{tabulate(tab)}{state_str}'
class StateStageFactory(RainbowFactory[StateStage[HeaderType, BaseStateType, StageType]]): class StateStageFactory(RainbowFactory[StateStage[HeaderType, BaseStateType, StageType]]):

View File

@ -11,18 +11,6 @@ StateType = TypeVar('StateType')
class MetaReductionStateProtocol(ActiveStateProtocol[HeaderType, StateType]): class MetaReductionStateProtocol(ActiveStateProtocol[HeaderType, StateType]):
async 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_eq(state, await self.derive(previous, header))
return True
def _initial_state(self) -> HashPoint[StateType]: def _initial_state(self) -> HashPoint[StateType]:
raise NotImplementedError raise NotImplementedError

View File

@ -24,7 +24,15 @@ class KeyedComparator(
) -> Comparison: ) -> Comparison:
assert isinstance(original, HashPoint) assert isinstance(original, HashPoint)
assert isinstance(key, HashPoint) assert isinstance(key, HashPoint)
return await self.comparator.compare( original_resolved: Keyed[ComparatorKeyType]
(await original.resolve()).key, key_resolved: Keyed[ComparatorKeyType]
(await key.resolve()).key, original_resolved, key_resolved = await gather(
original.resolve(),
key.resolve(),
)
assert isinstance(original_resolved, Keyed)
assert isinstance(key_resolved, Keyed)
return await self.comparator.compare(
original_resolved.key,
key_resolved.key,
) )

View File

@ -10,9 +10,13 @@ class PlainComparator(ProtocolComparator[Plain]):
async def compare(self, original: HashPoint[Plain], key: HashPoint[Plain]) -> Comparison: async def compare(self, original: HashPoint[Plain], key: HashPoint[Plain]) -> Comparison:
assert isinstance(original, HashPoint) assert isinstance(original, HashPoint)
assert isinstance(key, HashPoint) assert isinstance(key, HashPoint)
original_value: Plain = await original.resolve() original_value: Plain
key_value: Plain
original_value, key_value = await gather(
original.resolve(),
key.resolve(),
)
assert isinstance(original_value, Plain) assert isinstance(original_value, Plain)
key_value: Plain = await key.resolve()
assert isinstance(key_value, Plain) assert isinstance(key_value, Plain)
if key_value.source < original_value.source: if key_value.source < original_value.source:
return Left() return Left()

View File

@ -27,8 +27,12 @@ class KeyMetadata(Keyed[ActiveKeyType], Generic[ActiveKeyType, MetaDataType]):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
return f'{await hash_point_format(self.key, tab)}' \ key_str, metadata_str = await gather(
f'{tabulate(tab)}{await hash_point_format(self.metadata, tab)}' hash_point_format(self.key, tab),
hash_point_format(self.metadata, tab)
)
return f'{key_str}' \
f'{tabulate(tab)}{metadata_str}'
class KeyMetadataFactory( class KeyMetadataFactory(

View File

@ -30,8 +30,14 @@ class Array(RecursiveMentionable, Generic[ElementType]):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
formatted = f'(' formatted = f'('
for hash_point in self.array: formatted += ''.join(
formatted += f'{tabulate(tab + 1)}{await hash_point_format(hash_point, tab + 1)}' f'{tabulate(tab + 1)}{hash_point_str}'
for hash_point_str in gather(
*(
hash_point_format(hash_point, tab + 1) for hash_point in self.array
)
)
)
return f'{formatted}' \ return f'{formatted}' \
f'{tabulate(tab)})' f'{tabulate(tab)})'

View File

@ -31,8 +31,12 @@ class Stack(RecursiveMentionable, Generic[ElementType]):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
return f'{await self.previous.str(tab)}' \ previous_str, element_str = await gather(
f'{tabulate(tab)}{await hash_point_format(self.element, tab)}' self.previous.str(tab),
hash_point_format(self.element, tab),
)
return f'{previous_str}' \
f'{tabulate(tab)}{element_str}'
@classmethod @classmethod
def of( def of(
@ -76,6 +80,17 @@ class Stack(RecursiveMentionable, Generic[ElementType]):
async for element in cls.iter(stack.previous): async for element in cls.iter(stack.previous):
yield element yield element
@classmethod
async def list(
cls,
reference: NullableReference['Stack[ElementType]']
) -> list[ElementType]:
return list(
await gather(
*[element.resolve() async for element in cls.iter(reference)]
)
)
class StackFactory(RainbowFactory[Stack[ElementType]], Generic[ElementType]): class StackFactory(RainbowFactory[Stack[ElementType]], Generic[ElementType]):
def __init__(self, factory: RainbowFactory[ElementType]): def __init__(self, factory: RainbowFactory[ElementType]):

View File

@ -29,9 +29,13 @@ class Pair(
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
e0_str, e1_str = await gather(
hash_point_format(self.element0, tab),
hash_point_format(self.element1, tab),
)
return f'(pair)' \ return f'(pair)' \
f'{tabulate(tab)}{await hash_point_format(self.element0, tab)}' \ f'{tabulate(tab)}{e0_str}' \
f'{tabulate(tab)}{await hash_point_format(self.element1, tab)}' f'{tabulate(tab)}{e1_str}'
class PairFactory( class PairFactory(

View File

@ -23,13 +23,17 @@ class AVL(BinaryBalancing[ActiveKeyType, Integer, TreeType]):
creation: BinaryCreation[ActiveKeyType, Integer, TreeType] creation: BinaryCreation[ActiveKeyType, Integer, TreeType]
) -> HashPoint[Integer]: ) -> HashPoint[Integer]:
assert isinstance(creation, BinaryCreation) assert isinstance(creation, BinaryCreation)
height_l, height_r = await gather(
self.height(BinaryProtocolized(creation, treel)),
self.height(BinaryProtocolized(creation, treer)),
)
return HashPoint.of( return HashPoint.of(
Integer( Integer(
1 1
+ +
max( max(
await self.height(BinaryProtocolized(creation, treel)), height_l,
await self.height(BinaryProtocolized(creation, treer)) height_r,
) )
) )
) )
@ -80,7 +84,11 @@ class BalanceAction(
self, self,
case: ProtocolizedBinarySplit[ActiveKeyType, Integer, TreeType] case: ProtocolizedBinarySplit[ActiveKeyType, Integer, TreeType]
) -> TreeType: ) -> TreeType:
delta = (await AVL.height(case.protocolizedl())) - (await AVL.height(case.protocolizedr())) height_l, height_r = await gather(
AVL.height(case.protocolizedl()),
AVL.height(case.protocolizedr()),
)
delta = height_l - height_r
assert isinstance(delta, int) assert isinstance(delta, int)
if delta < -1: if delta < -1:
return await self.on_symmetric(InnerOuter(case.protocol), case.split) return await self.on_symmetric(InnerOuter(case.protocol), case.split)
@ -98,15 +106,19 @@ class BalanceAction(
assert isinstance(symmetry, Symmetric) assert isinstance(symmetry, Symmetric)
assert isinstance(split, BinarySplit) assert isinstance(split, BinarySplit)
splito = await symmetry.protocol.fsplit(symmetry.outer(split)) splito = await symmetry.protocol.fsplit(symmetry.outer(split))
if ( height_oi, height_oo = await gather(
(await AVL.height(symmetry.protocolizedi(splito))) AVL.height(symmetry.protocolizedi(splito)),
> AVL.height(symmetry.protocolizedo(splito)),
(await AVL.height(symmetry.protocolizedo(splito))) )
): if height_oi > height_oo:
splitoi = await symmetry.protocol.fsplit(symmetry.inner(splito)) splitoi = await symmetry.protocol.fsplit(symmetry.inner(splito))
inner, outer = await gather(
symmetry.tree(symmetry.inner(split), symmetry.inner(splitoi), split.key),
symmetry.tree(symmetry.outer(splitoi), symmetry.outer(splito), splito.key),
)
return await symmetry.tree( return await symmetry.tree(
await symmetry.tree(symmetry.inner(split), symmetry.inner(splitoi), split.key), inner,
await symmetry.tree(symmetry.outer(splitoi), symmetry.outer(splito), splito.key), outer,
splitoi.key splitoi.key
) )
else: else:

View File

@ -37,9 +37,14 @@ class BinaryTree(RecursiveMentionable, Generic[TreeKeyType]):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
return f'{await self.treel.str(tab)}' \ treel_str, key_str, treer_str = await gather(
f'{tabulate(tab)}{await hash_point_format(self.key, tab)}' \ self.treel.str(tab),
f'{tabulate(tab)}{await self.treer.str(tab)}' hash_point_format(self.key, tab),
self.treer.str(tab),
)
return f'{treel_str}' \
f'{tabulate(tab)}{key_str}' \
f'{tabulate(tab)}{treer_str}'
class BinaryTreeFactory(RainbowFactory[BinaryTree[TreeKeyType]], Generic[TreeKeyType]): class BinaryTreeFactory(RainbowFactory[BinaryTree[TreeKeyType]], Generic[TreeKeyType]):

View File

@ -31,12 +31,16 @@ class BalancedCreation(
async def tree(self, treel: TreeType, treer: TreeType, key: HashPoint[ActiveKeyType]) -> TreeType: async def tree(self, treel: TreeType, treer: TreeType, key: HashPoint[ActiveKeyType]) -> TreeType:
assert isinstance(key, HashPoint) assert isinstance(key, HashPoint)
balancedl, balancedr = await gather(
self.protocol.balance(BinaryProtocolized(self, treel)),
self.protocol.balance(BinaryProtocolized(self, treer)),
)
return await self.protocol.balance( return await self.protocol.balance(
BinaryProtocolized( BinaryProtocolized(
self, self,
await self._tree( await self._tree(
await self.protocol.balance(BinaryProtocolized(self, treel)), balancedl,
await self.protocol.balance(BinaryProtocolized(self, treer)), balancedr,
key key
) )
) )

View File

@ -1,5 +1,6 @@
from .asserts import * from .asserts import *
from .extendableresolver import ExtendableResolver from .extendableresolver import ExtendableResolver
from .gather import *
from .hash_point_format import * from .hash_point_format import *
from .hashpoint import HashPoint from .hashpoint import HashPoint
from .hashresolver import HashResolver from .hashresolver import HashResolver

View File

@ -1,6 +1,6 @@
from typing import Optional, TypeVar from typing import Iterable, Optional, TypeVar
__all__ = ('assert_true', 'assert_false', 'assert_none', 'assert_eq',) __all__ = ('assert_true', 'assert_trues', 'assert_false', 'assert_none', 'assert_eq',)
def assert_true(value: bool) -> bool: def assert_true(value: bool) -> bool:
@ -8,6 +8,12 @@ def assert_true(value: bool) -> bool:
return True return True
def assert_trues(values: Iterable[bool]) -> bool:
for value in values:
assert_true(value)
return True
def assert_false(value: bool) -> bool: def assert_false(value: bool) -> bool:
assert value is False assert value is False
return True return True

35
rainbowadn/core/gather.py Normal file
View File

@ -0,0 +1,35 @@
import asyncio
from typing import AsyncIterable, TypeVar
__all__ = ('gather', 'asum', 'alist', 'set_gather_asyncio', 'set_gather_linear',)
_gather = asyncio.gather
async def _local_gather(*args):
return [await arg for arg in args]
def set_gather_asyncio():
global _gather
_gather = asyncio.gather
def set_gather_linear():
global _gather
_gather = _local_gather
def gather(*args):
return _gather(*args)
async def asum(iterable):
return sum(await gather(*iterable))
T = TypeVar('T')
async def alist(aiterable: AsyncIterable[T]) -> list[T]:
return [x async for x in aiterable]

View File

@ -40,14 +40,12 @@ class Encrypted(RecursiveMentionable, Generic[EncryptedType]):
async def encrypt(cls, decrypted: EncryptedType, key: bytes) -> 'Encrypted[EncryptedType]': async def encrypt(cls, decrypted: EncryptedType, key: bytes) -> 'Encrypted[EncryptedType]':
assert isinstance(key, bytes) assert isinstance(key, bytes)
hashpoints = tuple(decrypted.points()) if isinstance(decrypted, RecursiveMentionable) else () hashpoints = tuple(decrypted.points()) if isinstance(decrypted, RecursiveMentionable) else ()
resolution: tuple[HashPoint[Encrypted[EncryptedType]], ...] = tuple( resolution = tuple(
[ await gather(
await cls.encrypt_hashpoint(hash_point, key) *(
for cls.encrypt_hashpoint(hash_point, key) for hash_point in hashpoints
hash_point )
in )
hashpoints
]
) )
return cls.construct( return cls.construct(
key, key,

View File

@ -0,0 +1,29 @@
import asyncio
from typing import Callable, TypeVar
from rainbowadn.core import *
__all__ = ('DelayedResolver',)
Mentioned = TypeVar('Mentioned')
class DelayedResolver(ExtendableResolver):
def __init__(self, resolver: HashResolver, delay: Callable[[], float]):
self.resolver = resolver
self.delay = delay
async def sleep(self):
await asyncio.sleep(self.delay())
async def resolve(self, point: bytes) -> tuple[bytes, 'HashResolver']:
assert isinstance(point, bytes)
await self.sleep()
resolved, resolver = await self.resolver.resolve(point)
return resolved, DelayedResolver(resolver, self.delay)
async def extend(self, hash_point: HashPoint[Mentioned]) -> ExtendableResolver:
if isinstance(self.resolver, ExtendableResolver):
return DelayedResolver(await self.resolver.extend(hash_point), self.delay)
else:
raise TypeError

View File

@ -25,8 +25,9 @@ class DictResolver(ExtendableResolver):
assert isinstance(value, Mentionable) assert isinstance(value, Mentionable)
self.table[hash_point.point] = HashPoint.bytes_of_mentioned(value) self.table[hash_point.point] = HashPoint.bytes_of_mentioned(value)
if isinstance(value, RecursiveMentionable): if isinstance(value, RecursiveMentionable):
for hash_point in value.points(): await gather(
await self.save(hash_point) *(self.save(hp) for hp in value.points())
)
async def extend(self, hash_point: HashPoint[Mentioned]) -> 'ExtendableResolver': async def extend(self, hash_point: HashPoint[Mentioned]) -> 'ExtendableResolver':
await self.save(hash_point) await self.save(hash_point)

View File

@ -1,7 +1,14 @@
import functools import functools
import time
from typing import Generic, TypeVar
__all__ = ('Instrumentation', 'Counter', 'Concurrency',)
class Instrumentation: IType = TypeVar('IType')
class Instrumentation(Generic[IType]):
deinstrumentation = {} deinstrumentation = {}
def __init__(self, target, methodname: str): def __init__(self, target, methodname: str):
@ -11,7 +18,7 @@ class Instrumentation:
def instrument(self, method, *args, **kwargs): def instrument(self, method, *args, **kwargs):
raise NotImplementedError raise NotImplementedError
def __enter__(self): def __enter__(self: IType) -> IType:
assert not hasattr(self, 'method') assert not hasattr(self, 'method')
self.method = getattr(self.target, self.methodname) self.method = getattr(self.target, self.methodname)
@ -23,6 +30,8 @@ class Instrumentation:
setattr(self.target, self.methodname, self.wrap) setattr(self.target, self.methodname, self.wrap)
return self
def schedule_deinstrumentation(self): def schedule_deinstrumentation(self):
self.deinstrumentation[self.wrap] = self.method self.deinstrumentation[self.wrap] = self.method
del self.wrap del self.wrap
@ -45,3 +54,25 @@ class Counter(Instrumentation):
def instrument(self, method, *args, **kwargs): def instrument(self, method, *args, **kwargs):
self.counter += 1 self.counter += 1
return method(*args, **kwargs) return method(*args, **kwargs)
class Concurrency(Instrumentation):
start = time.time()
def __init__(self, target, methodname: str):
super().__init__(target, methodname)
self.concurrency = 0
self.logs: list[tuple[float, int]] = []
def time(self) -> float:
return time.time() - self.start
async def instrument(self, method, *args, **kwargs):
self.logs.append((self.time(), self.concurrency))
self.concurrency += 1
self.logs.append((self.time(), self.concurrency))
result = await method(*args, **kwargs)
self.logs.append((self.time(), self.concurrency))
self.concurrency -= 1
self.logs.append((self.time(), self.concurrency))
return result

View File

@ -16,16 +16,22 @@ from rainbowadn.encryption import *
from rainbowadn.nullability import * from rainbowadn.nullability import *
from rainbowadn.v13 import * from rainbowadn.v13 import *
from rainbowadn.wrisbt import * from rainbowadn.wrisbt import *
from .delayedresolver import DelayedResolver
from .dictresolver import DictResolver from .dictresolver import DictResolver
from .instrumentation import Counter from .instrumentation import *
class TestAll(unittest.IsolatedAsyncioTestCase): class TestAll(unittest.IsolatedAsyncioTestCase):
"""examples rather than real tests""" """examples rather than real tests"""
async def test_bankchain(self): @classmethod
with self.subTest('setup'): def dr(cls) -> ExtendableResolver:
dr = DictResolver() dr = DictResolver()
dr = DelayedResolver(dr, lambda: 0.000)
return dr
async def test_bankchain(self):
set_gather_asyncio()
with self.subTest('create empty'): with self.subTest('create empty'):
bank: BankChain = BankChain.empty(ReductionChainMetaFactory().loose()) bank: BankChain = BankChain.empty(ReductionChainMetaFactory().loose())
with self.subTest('prepare transactions'): with self.subTest('prepare transactions'):
@ -51,19 +57,22 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
bank = await bank.adds( bank = await bank.adds(
[] []
) )
print(bank.reference.str(0)) print(await bank.reference.str(0))
with self.subTest('verify'): with self.subTest('verify'):
assert_true(await bank.verify()) assert_true(await bank.verify())
with self.subTest('recover'): with self.subTest('recover'):
await dr.save(HashPoint.of(bank.reference))
bank = BankChain.from_reference( bank = BankChain.from_reference(
ReductionChainMetaFactory(), await dr.migrate_resolved(bank.reference) ReductionChainMetaFactory(), await self.dr().migrate_resolved(bank.reference)
) )
print(bank.reference.str(0)) set_gather_asyncio()
print('recovering')
print(await bank.reference.str(0))
print('recovered')
with self.subTest('verify'): with self.subTest('verify'):
assert_true(await bank.verify()) assert_true(await bank.verify())
async def test_wrisbt(self): async def test_wrisbt(self):
set_gather_linear()
with self.subTest('setup'): with self.subTest('setup'):
stoptime = time.process_time() stoptime = time.process_time()
@ -75,7 +84,6 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
stoptime = now stoptime = now
return delta return delta
dr = DictResolver()
n = 2500 n = 2500
keysize = 7 keysize = 7
with self.subTest('create empty'): with self.subTest('create empty'):
@ -89,10 +97,10 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
assert_true(await btree.contains(key)) assert_true(await btree.contains(key))
measure('add') measure('add')
with self.subTest('save'): with self.subTest('save'):
await dr.save(HashPoint.of(btree)) btree = await self.dr().migrate_resolved(btree)
measure('save') measure('save')
set_gather_asyncio()
with self.subTest('resolve and iterate'): with self.subTest('resolve and iterate'):
btree = await dr.migrate_resolved(btree)
assert_eq(len(await btree.keys()), n) assert_eq(len(await btree.keys()), n)
print(btree.height) print(btree.height)
measure('resolve and iterate') measure('resolve and iterate')
@ -106,13 +114,14 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
measure('resolve and add') measure('resolve and add')
async def test_wrisbt_index(self): async def test_wrisbt_index(self):
set_gather_linear()
with self.subTest('create empty'): with self.subTest('create empty'):
factory: RainbowFactory[Pair[Plain, Plain]] = PairFactory(Plain.factory(), Plain.factory()).loose() factory: RainbowFactory[Pair[Plain, Plain]] = PairFactory(Plain.factory(), Plain.factory()).loose()
chain: ChainCollectionInterface[Any, Pair[Plain, Plain], WrisbtRoot] = BlockChainFactory( chain: ChainCollectionInterface[Any, Pair[Plain, Plain], WrisbtRoot] = BlockChainFactory(
WrisbtChainProtocol(factory, 2).loose() WrisbtChainProtocol(factory, 2).loose()
).empty().loose() ).empty().loose()
with self.subTest('fill'): with self.subTest('fill'):
for _ in range(1000): for _ in range(100):
chain = await chain.add( chain = await chain.add(
HashPoint.of( HashPoint.of(
Pair( Pair(
@ -122,6 +131,7 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
) )
) )
with self.subTest('check'): with self.subTest('check'):
set_gather_asyncio()
assert_true(await chain.verify()) assert_true(await chain.verify())
with self.subTest('measure height'): with self.subTest('measure height'):
reference = await chain.actual_state() reference = await chain.actual_state()
@ -129,6 +139,7 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
print((await reference.resolve()).height) print((await reference.resolve()).height)
async def test_avl(self): async def test_avl(self):
set_gather_linear()
tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty( tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty(
AVL(PlainComparator(Replace())), Plain.factory() AVL(PlainComparator(Replace())), Plain.factory()
) )
@ -137,6 +148,7 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
print(await tree.reference.str(0)) print(await tree.reference.str(0))
async def test_avl_stress(self): async def test_avl_stress(self):
set_gather_linear()
protocol = AVL(PlainComparator(Replace())) protocol = AVL(PlainComparator(Replace()))
tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty( tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty(
protocol, Plain.factory() protocol, Plain.factory()
@ -146,10 +158,10 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
print(await AVL.height(tree.protocolized())) print(await AVL.height(tree.protocolized()))
async def test_encryption(self): async def test_encryption(self):
set_gather_asyncio()
instrumentation = Counter(Encrypted, 'encrypt') instrumentation = Counter(Encrypted, 'encrypt')
with self.subTest('setup'): with self.subTest('setup'):
key = b'a' * 32 key = b'a' * 32
dr = DictResolver()
with self.subTest('create empty'): with self.subTest('create empty'):
tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty( tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty(
AVL(PlainComparator(Replace())), Plain.factory() AVL(PlainComparator(Replace())), Plain.factory()
@ -174,8 +186,7 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
with instrumentation: with instrumentation:
eeed = await Encrypted.encrypt(target, key) eeed = await Encrypted.encrypt(target, key)
print(instrumentation.counter) print(instrumentation.counter)
await dr.save(HashPoint.of(eeed)) print(await (await self.dr().migrate_resolved(eeed)).decrypted.str(0))
print(await (await dr.migrate_resolved(eeed)).decrypted.str(0))
with self.subTest('re-encrypt'): with self.subTest('re-encrypt'):
new_key = b'b' * 32 new_key = b'b' * 32
target = eeed.decrypted target = eeed.decrypted

View File

@ -18,9 +18,14 @@ class BankProtocol(ReductionProtocol[NullableReference[Stack[Transaction]], Bank
reduce: Reducible[NullableReference[Stack[Transaction]], BankState] reduce: Reducible[NullableReference[Stack[Transaction]], BankState]
) -> ReductionResult[NullableReference[Stack[Transaction]], BankState]: ) -> ReductionResult[NullableReference[Stack[Transaction]], BankState]:
assert isinstance(reduce, Reducible) assert isinstance(reduce, Reducible)
bank_state: BankState = await reduce.accumulator.resolve() bank_state: BankState
reference: NullableReference[Stack[Transaction]]
bank_state, reference = await gather(
reduce.accumulator.resolve(),
reduce.reductor.resolve(),
)
assert isinstance(bank_state, BankState) assert isinstance(bank_state, BankState)
reference: NullableReference[Stack[Transaction]] = await reduce.reductor.resolve() assert isinstance(reference, NullableReference)
if reference.null(): if reference.null():
return Reduced(HashPoint.of(bank_state.without_miner())) return Reduced(HashPoint.of(bank_state.without_miner()))
else: else:

View File

@ -90,23 +90,41 @@ class BankState(RecursiveMentionable, StaticMentionable):
minted: ActiveBinaryTree[Coin, Integer] = self.minted_tree() minted: ActiveBinaryTree[Coin, Integer] = self.minted_tree()
used: ActiveBinaryTree[Coin, Integer] = self.used_tree() used: ActiveBinaryTree[Coin, Integer] = self.used_tree()
async for in_coin in coins: async for in_coin in coins:
assert_true(await minted.contains(in_coin)) minted_contains, used_contains, used = await gather(
assert_false(await used.contains(in_coin)) minted.contains(in_coin),
used = await used.add(in_coin) used.contains(in_coin),
used.add(in_coin)
)
assert_true(minted_contains)
assert_false(used_contains)
assert isinstance(used, ActiveBinaryTree)
return BankState(self.minted, used.reference, self.miner, self.length) return BankState(self.minted, used.reference, self.miner, self.length)
async def _mint_coins(
self,
transaction: Transaction
) -> 'BankState':
miner = self.miner_nullable()
minted: ActiveBinaryTree[Coin, Integer] = self.minted_tree()
async for coin, miner in transaction.iter_coins(self.mint(), miner):
minted_contains, minted = await gather(
minted.contains(HashPoint.of(coin)),
minted.add(HashPoint.of(coin)),
)
assert_false(minted_contains)
assert isinstance(minted, ActiveBinaryTree)
return BankState(minted.reference, self.used, NullableReference(miner, self.miner.factory), self.length)
async def mint_coins( async def mint_coins(
self, self,
transaction: Transaction transaction: Transaction
) -> 'BankState': ) -> 'BankState':
assert_true(await self.verify(transaction)) verified, bank_state = await gather(
miner = self.miner_nullable() self.verify(transaction),
minted: ActiveBinaryTree[Coin, Integer] = self.minted_tree() self._mint_coins(transaction),
async for coin, miner in transaction.iter_coins(self.mint(), miner): )
assert_false(await minted.contains(HashPoint.of(coin))) assert_true(verified)
minted = await minted.add(HashPoint.of(coin)) return bank_state
assert isinstance(minted, ActiveBinaryTree)
return BankState(minted.reference, self.used, NullableReference(miner, self.miner.factory), self.length)
def miner_nullable(self) -> Nullable[HashPoint[Subject]]: def miner_nullable(self) -> Nullable[HashPoint[Subject]]:
return self.miner.reference return self.miner.reference
@ -137,14 +155,20 @@ class BankState(RecursiveMentionable, StaticMentionable):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
miner_str, minted_str, used_str, length_str = await gather(
self.miner.str(tab + 1),
self.minted.str(tab + 1),
self.used.str(tab + 1),
hash_point_format(self.length, tab + 1),
)
return f'(' \ return f'(' \
f'{tabulate(tab + 1)}bank' \ f'{tabulate(tab + 1)}bank' \
f'{tabulate(tab + 1)}(miner)' \ f'{tabulate(tab + 1)}(miner)' \
f'{tabulate(tab + 1)}{await self.miner.str(tab + 1)}' \ f'{tabulate(tab + 1)}{miner_str}' \
f'{tabulate(tab + 1)}(minted)' \ f'{tabulate(tab + 1)}(minted)' \
f'{tabulate(tab + 1)}{await self.minted.str(tab + 1)}' \ f'{tabulate(tab + 1)}{minted_str}' \
f'{tabulate(tab + 1)}(used)' \ f'{tabulate(tab + 1)}(used)' \
f'{tabulate(tab + 1)}{await self.used.str(tab + 1)}' \ f'{tabulate(tab + 1)}{used_str}' \
f'{tabulate(tab + 1)}(length)' \ f'{tabulate(tab + 1)}(length)' \
f'{tabulate(tab + 1)}{await hash_point_format(self.length, tab + 1)}' \ f'{tabulate(tab + 1)}{length_str}' \
f'{tabulate(tab)})' f'{tabulate(tab)})'

View File

@ -49,8 +49,12 @@ class CoinData(RecursiveMentionable, StaticMentionable):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
return f'{await hash_point_format(self.owner, tab)}' \ owner_str, value_str = await gather(
f'{tabulate(tab)}{await hash_point_format(self.value, tab)}' hash_point_format(self.owner, tab),
hash_point_format(self.value, tab),
)
return f'{owner_str}' \
f'{tabulate(tab)}{value_str}'
class Coin(RecursiveMentionable, StaticMentionable): class Coin(RecursiveMentionable, StaticMentionable):
@ -90,13 +94,23 @@ class Coin(RecursiveMentionable, StaticMentionable):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
data_str, index_str = await gather(
hash_point_format(self.data, tab + 1),
hash_point_format(self.index, tab + 1),
)
return f'(' \ return f'(' \
f'{tabulate(tab + 1)}coin' \ f'{tabulate(tab + 1)}coin' \
f'{tabulate(tab + 1)}{await hash_point_format(self.data, tab + 1)}' \ f'{tabulate(tab + 1)}{data_str}' \
f'{tabulate(tab + 1)}(origin)' \ f'{tabulate(tab + 1)}(origin)' \
f'{tabulate(tab + 1)}{await hash_point_format(self.index, tab + 1)}' \ f'{tabulate(tab + 1)}{index_str}' \
f'{tabulate(tab)})' f'{tabulate(tab)})'
async def int_value(self) -> int:
return await (await self.data_resolved()).int_value()
async def owner_resolved(self) -> Subject:
return await (await self.data_resolved()).owner.resolve()
class TransactionData(RecursiveMentionable, StaticMentionable): class TransactionData(RecursiveMentionable, StaticMentionable):
def __init__( def __init__(
@ -130,19 +144,32 @@ class TransactionData(RecursiveMentionable, StaticMentionable):
).from_bytes(source[HashPoint.HASH_LENGTH:], resolver), ).from_bytes(source[HashPoint.HASH_LENGTH:], resolver),
) )
async def _signature_verify(self, coin: Coin, signature: Signature) -> bool:
assert_true(
signature.verify(
await coin.owner_resolved(),
self.hash_point
)
)
return True
async def _verify_signatures( async def _verify_signatures(
self, self,
signatures: NullableReference[Stack[Signature]] signatures: NullableReference[Stack[Signature]]
) -> bool: ) -> bool:
for coin, signature in zip( assert_trues(
[x async for x in self.iter_in_coins_resolved()], await gather(
[x async for x in Stack.iter(signatures)], *[
self._signature_verify(coin, signature)
for
coin, signature
in
zip(
await self.in_coins_resolved(),
await Stack.list(signatures),
strict=True strict=True
): )
assert_true( ]
(await signature.resolve()).verify(
await (await coin.data_resolved()).owner.resolve(),
self.hash_point
) )
) )
return True return True
@ -150,18 +177,24 @@ class TransactionData(RecursiveMentionable, StaticMentionable):
def iter_in_coins(self) -> AsyncIterable[HashPoint[Coin]]: def iter_in_coins(self) -> AsyncIterable[HashPoint[Coin]]:
return Stack.iter(self.in_coins) return Stack.iter(self.in_coins)
async def iter_in_coins_resolved(self) -> AsyncIterable[Coin]: async def in_coins_resolved(self) -> list[Coin]:
async for coin in self.iter_in_coins(): return await Stack.list(self.in_coins)
yield await coin.resolve()
async def _total_in(self) -> int: async def _total_in(self) -> int:
return sum([await (await coin.data_resolved()).int_value() async for coin in self.iter_in_coins_resolved()]) return await asum(
coin.int_value() for coin in await self.in_coins_resolved()
)
def iter_out_coins(self) -> AsyncIterable[HashPoint[CoinData]]: def iter_out_coins(self) -> AsyncIterable[HashPoint[CoinData]]:
return Stack.iter(self.out_coins) return Stack.iter(self.out_coins)
async def out_coins_resolved(self) -> list[CoinData]:
return await Stack.list(self.out_coins)
async def _total_out(self) -> int: async def _total_out(self) -> int:
return sum([await (await coin.resolve()).int_value() async for coin in self.iter_out_coins()]) return await asum(
coin.int_value() for coin in await self.out_coins_resolved()
)
async def _verify_values(self, mint: int) -> bool: async def _verify_values(self, mint: int) -> bool:
assert isinstance(mint, int) assert isinstance(mint, int)
@ -170,7 +203,11 @@ class TransactionData(RecursiveMentionable, StaticMentionable):
async def extra(self, mint: int) -> int: async def extra(self, mint: int) -> int:
assert isinstance(mint, int) assert isinstance(mint, int)
return (await self._total_in()) + mint - (await self._total_out()) total_in, total_out = await gather(
self._total_in(),
self._total_out(),
)
return total_in + mint - total_out
async def verify( async def verify(
self, self,
@ -179,16 +216,24 @@ class TransactionData(RecursiveMentionable, StaticMentionable):
) -> bool: ) -> bool:
assert isinstance(signatures, NullableReference) assert isinstance(signatures, NullableReference)
assert isinstance(mint, int) assert isinstance(mint, int)
assert_true(await self._verify_signatures(signatures)) assert_trues(
assert_true(await self._verify_values(mint)) await gather(
self._verify_signatures(signatures),
self._verify_values(mint),
)
)
return True return True
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
in_str, out_str = await gather(
self.in_coins.str(tab),
self.out_coins.str(tab),
)
return f'(in)' \ return f'(in)' \
f'{tabulate(tab)}{await self.in_coins.str(tab)}' \ f'{tabulate(tab)}{in_str}' \
f'{tabulate(tab)}(out)' \ f'{tabulate(tab)}(out)' \
f'{tabulate(tab)}{await self.out_coins.str(tab)}' f'{tabulate(tab)}{out_str}'
class Transaction(RecursiveMentionable, StaticMentionable): class Transaction(RecursiveMentionable, StaticMentionable):
@ -276,10 +321,14 @@ class Transaction(RecursiveMentionable, StaticMentionable):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
data_str, signatures_str = await gather(
hash_point_format(self.data, tab + 1),
self.signatures.str(tab + 1),
)
return f'(' \ return f'(' \
f'{tabulate(tab + 1)}transaction' \ f'{tabulate(tab + 1)}transaction' \
f'{tabulate(tab + 1)}{hash_point_format(self.data, tab + 1)}' \ f'{tabulate(tab + 1)}{data_str}' \
f'{tabulate(tab + 1)}{self.signatures.str(tab + 1)}' \ f'{tabulate(tab + 1)}{signatures_str}' \
f'{tabulate(tab)})' f'{tabulate(tab)})'
@classmethod @classmethod

View File

@ -156,8 +156,13 @@ class WeakReferenceIndexSetBTree(RecursiveMentionable):
f'{tabulate(tab)}(' f'{tabulate(tab)}('
for key_index in range(self.keys): for key_index in range(self.keys):
formatted += f'{tabulate(tab + 1)}{self.key_no(key_index).hex()}' formatted += f'{tabulate(tab + 1)}{self.key_no(key_index).hex()}'
for child_index in range(self.children): formatted += ''.join(
formatted += f'{tabulate(tab + 1)}{await hash_point_format(self.child_no(child_index), tab + 1)}' f'{tabulate(tab + 1)}{child_formatted}' for child_formatted in (
await gather(
hash_point_format(self.child_no(child_index), tab + 1) for child_index in range(self.children)
)
)
)
return f'{formatted}' \ return f'{formatted}' \
f'{tabulate(tab)})' f'{tabulate(tab)})'

View File

@ -33,9 +33,13 @@ class WrisbtIndex(RecursiveMentionable):
async def str(self, tab: int) -> str: async def str(self, tab: int) -> str:
assert isinstance(tab, int) assert isinstance(tab, int)
total_str, delta_str = await gather(
hash_point_format(self.total, tab),
hash_point_format(self.delta, tab),
)
return f'(index)' \ return f'(index)' \
f'{tabulate(tab)}{await hash_point_format(self.total, tab)}' \ f'{tabulate(tab)}{total_str}' \
f'{tabulate(tab)}{await hash_point_format(self.delta, tab)}' f'{tabulate(tab)}{delta_str}'
class WrisbtIndexFactory(RainbowFactory[WrisbtIndex]): class WrisbtIndexFactory(RainbowFactory[WrisbtIndex]):

View File

@ -41,10 +41,15 @@ class WrisbtProtocol(MetaReductionStateProtocol[TargetType, WrisbtIndex]):
total: WrisbtRoot = await index.total.resolve() total: WrisbtRoot = await index.total.resolve()
assert isinstance(total, WrisbtRoot) assert isinstance(total, WrisbtRoot)
total_index, delta_index = await gather(
total.index(header, empty),
empty.index(header, total),
)
return HashPoint.of( return HashPoint.of(
WrisbtIndex( WrisbtIndex(
HashPoint.of(await total.index(header, empty)), HashPoint.of(total_index),
HashPoint.of(await empty.index(header, total)), HashPoint.of(delta_index),
index.keymin index.keymin
) )
) )

View File

@ -86,7 +86,11 @@ class WrisbtRoot(RecursiveMentionable):
assert isinstance(exclude, WrisbtRoot) assert isinstance(exclude, WrisbtRoot)
key: bytes = target.point key: bytes = target.point
assert isinstance(key, bytes) assert isinstance(key, bytes)
if await exclude.contains(key) or await self.contains(key): exclude_contains, self_contains = await gather(
exclude.contains(key),
self.contains(key),
)
if exclude_contains or self_contains:
return self return self
tree: WrisbtRoot = self tree: WrisbtRoot = self
value: Mentionable = await target.resolve() value: Mentionable = await target.resolve()