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:
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 + 1)}block' \
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)}{await hash_point_format(self.state, tab + 1)}' \
f'{tabulate(tab + 1)}{state_str}' \
f'{tabulate(tab)})'

View File

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

View File

@ -36,6 +36,30 @@ class ActiveStageStateProtocol(
self.stage_factory = stage_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(
self,
previous: NullableReference[

View File

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

View File

@ -11,18 +11,6 @@ StateType = TypeVar('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]:
raise NotImplementedError

View File

@ -24,7 +24,15 @@ class KeyedComparator(
) -> Comparison:
assert isinstance(original, HashPoint)
assert isinstance(key, HashPoint)
return await self.comparator.compare(
(await original.resolve()).key,
(await key.resolve()).key,
original_resolved: Keyed[ComparatorKeyType]
key_resolved: Keyed[ComparatorKeyType]
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:
assert isinstance(original, 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)
key_value: Plain = await key.resolve()
assert isinstance(key_value, Plain)
if key_value.source < original_value.source:
return Left()

View File

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

View File

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

View File

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

View File

@ -29,9 +29,13 @@ class Pair(
async def str(self, tab: int) -> str:
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)' \
f'{tabulate(tab)}{await hash_point_format(self.element0, tab)}' \
f'{tabulate(tab)}{await hash_point_format(self.element1, tab)}'
f'{tabulate(tab)}{e0_str}' \
f'{tabulate(tab)}{e1_str}'
class PairFactory(

View File

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

View File

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

View File

@ -31,12 +31,16 @@ class BalancedCreation(
async def tree(self, treel: TreeType, treer: TreeType, key: HashPoint[ActiveKeyType]) -> TreeType:
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(
BinaryProtocolized(
self,
await self._tree(
await self.protocol.balance(BinaryProtocolized(self, treel)),
await self.protocol.balance(BinaryProtocolized(self, treer)),
balancedl,
balancedr,
key
)
)

View File

@ -1,5 +1,6 @@
from .asserts import *
from .extendableresolver import ExtendableResolver
from .gather import *
from .hash_point_format import *
from .hashpoint import HashPoint
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:
@ -8,6 +8,12 @@ def assert_true(value: bool) -> bool:
return True
def assert_trues(values: Iterable[bool]) -> bool:
for value in values:
assert_true(value)
return True
def assert_false(value: bool) -> bool:
assert value is False
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]':
assert isinstance(key, bytes)
hashpoints = tuple(decrypted.points()) if isinstance(decrypted, RecursiveMentionable) else ()
resolution: tuple[HashPoint[Encrypted[EncryptedType]], ...] = tuple(
[
await cls.encrypt_hashpoint(hash_point, key)
for
hash_point
in
hashpoints
]
resolution = tuple(
await gather(
*(
cls.encrypt_hashpoint(hash_point, key) for hash_point in hashpoints
)
)
)
return cls.construct(
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)
self.table[hash_point.point] = HashPoint.bytes_of_mentioned(value)
if isinstance(value, RecursiveMentionable):
for hash_point in value.points():
await self.save(hash_point)
await gather(
*(self.save(hp) for hp in value.points())
)
async def extend(self, hash_point: HashPoint[Mentioned]) -> 'ExtendableResolver':
await self.save(hash_point)

View File

@ -1,7 +1,14 @@
import functools
import time
from typing import Generic, TypeVar
__all__ = ('Instrumentation', 'Counter', 'Concurrency',)
class Instrumentation:
IType = TypeVar('IType')
class Instrumentation(Generic[IType]):
deinstrumentation = {}
def __init__(self, target, methodname: str):
@ -11,7 +18,7 @@ class Instrumentation:
def instrument(self, method, *args, **kwargs):
raise NotImplementedError
def __enter__(self):
def __enter__(self: IType) -> IType:
assert not hasattr(self, 'method')
self.method = getattr(self.target, self.methodname)
@ -23,6 +30,8 @@ class Instrumentation:
setattr(self.target, self.methodname, self.wrap)
return self
def schedule_deinstrumentation(self):
self.deinstrumentation[self.wrap] = self.method
del self.wrap
@ -45,3 +54,25 @@ class Counter(Instrumentation):
def instrument(self, method, *args, **kwargs):
self.counter += 1
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.v13 import *
from rainbowadn.wrisbt import *
from .delayedresolver import DelayedResolver
from .dictresolver import DictResolver
from .instrumentation import Counter
from .instrumentation import *
class TestAll(unittest.IsolatedAsyncioTestCase):
"""examples rather than real tests"""
@classmethod
def dr(cls) -> ExtendableResolver:
dr = DictResolver()
dr = DelayedResolver(dr, lambda: 0.000)
return dr
async def test_bankchain(self):
with self.subTest('setup'):
dr = DictResolver()
set_gather_asyncio()
with self.subTest('create empty'):
bank: BankChain = BankChain.empty(ReductionChainMetaFactory().loose())
with self.subTest('prepare transactions'):
@ -51,19 +57,22 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
bank = await bank.adds(
[]
)
print(bank.reference.str(0))
print(await bank.reference.str(0))
with self.subTest('verify'):
assert_true(await bank.verify())
with self.subTest('recover'):
await dr.save(HashPoint.of(bank.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'):
assert_true(await bank.verify())
async def test_wrisbt(self):
set_gather_linear()
with self.subTest('setup'):
stoptime = time.process_time()
@ -75,7 +84,6 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
stoptime = now
return delta
dr = DictResolver()
n = 2500
keysize = 7
with self.subTest('create empty'):
@ -89,10 +97,10 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
assert_true(await btree.contains(key))
measure('add')
with self.subTest('save'):
await dr.save(HashPoint.of(btree))
btree = await self.dr().migrate_resolved(btree)
measure('save')
set_gather_asyncio()
with self.subTest('resolve and iterate'):
btree = await dr.migrate_resolved(btree)
assert_eq(len(await btree.keys()), n)
print(btree.height)
measure('resolve and iterate')
@ -106,13 +114,14 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
measure('resolve and add')
async def test_wrisbt_index(self):
set_gather_linear()
with self.subTest('create empty'):
factory: RainbowFactory[Pair[Plain, Plain]] = PairFactory(Plain.factory(), Plain.factory()).loose()
chain: ChainCollectionInterface[Any, Pair[Plain, Plain], WrisbtRoot] = BlockChainFactory(
WrisbtChainProtocol(factory, 2).loose()
).empty().loose()
with self.subTest('fill'):
for _ in range(1000):
for _ in range(100):
chain = await chain.add(
HashPoint.of(
Pair(
@ -122,6 +131,7 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
)
)
with self.subTest('check'):
set_gather_asyncio()
assert_true(await chain.verify())
with self.subTest('measure height'):
reference = await chain.actual_state()
@ -129,6 +139,7 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
print((await reference.resolve()).height)
async def test_avl(self):
set_gather_linear()
tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty(
AVL(PlainComparator(Replace())), Plain.factory()
)
@ -137,6 +148,7 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
print(await tree.reference.str(0))
async def test_avl_stress(self):
set_gather_linear()
protocol = AVL(PlainComparator(Replace()))
tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty(
protocol, Plain.factory()
@ -146,10 +158,10 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
print(await AVL.height(tree.protocolized()))
async def test_encryption(self):
set_gather_asyncio()
instrumentation = Counter(Encrypted, 'encrypt')
with self.subTest('setup'):
key = b'a' * 32
dr = DictResolver()
with self.subTest('create empty'):
tree: ActiveBinaryTree[Plain, Integer] = ActiveBinaryTree.empty(
AVL(PlainComparator(Replace())), Plain.factory()
@ -174,8 +186,7 @@ class TestAll(unittest.IsolatedAsyncioTestCase):
with instrumentation:
eeed = await Encrypted.encrypt(target, key)
print(instrumentation.counter)
await dr.save(HashPoint.of(eeed))
print(await (await dr.migrate_resolved(eeed)).decrypted.str(0))
print(await (await self.dr().migrate_resolved(eeed)).decrypted.str(0))
with self.subTest('re-encrypt'):
new_key = b'b' * 32
target = eeed.decrypted

View File

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

View File

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

View File

@ -49,8 +49,12 @@ class CoinData(RecursiveMentionable, StaticMentionable):
async def str(self, tab: int) -> str:
assert isinstance(tab, int)
return f'{await hash_point_format(self.owner, tab)}' \
f'{tabulate(tab)}{await hash_point_format(self.value, tab)}'
owner_str, value_str = await gather(
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):
@ -90,13 +94,23 @@ class Coin(RecursiveMentionable, StaticMentionable):
async def str(self, tab: int) -> str:
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'(' \
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)}{await hash_point_format(self.index, tab + 1)}' \
f'{tabulate(tab + 1)}{index_str}' \
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):
def __init__(
@ -130,38 +144,57 @@ class TransactionData(RecursiveMentionable, StaticMentionable):
).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(
self,
signatures: NullableReference[Stack[Signature]]
) -> bool:
for coin, signature in zip(
[x async for x in self.iter_in_coins_resolved()],
[x async for x in Stack.iter(signatures)],
strict=True
):
assert_true(
(await signature.resolve()).verify(
await (await coin.data_resolved()).owner.resolve(),
self.hash_point
)
assert_trues(
await gather(
*[
self._signature_verify(coin, signature)
for
coin, signature
in
zip(
await self.in_coins_resolved(),
await Stack.list(signatures),
strict=True
)
]
)
)
return True
def iter_in_coins(self) -> AsyncIterable[HashPoint[Coin]]:
return Stack.iter(self.in_coins)
async def iter_in_coins_resolved(self) -> AsyncIterable[Coin]:
async for coin in self.iter_in_coins():
yield await coin.resolve()
async def in_coins_resolved(self) -> list[Coin]:
return await Stack.list(self.in_coins)
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]]:
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:
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:
assert isinstance(mint, int)
@ -170,7 +203,11 @@ class TransactionData(RecursiveMentionable, StaticMentionable):
async def extra(self, mint: int) -> 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(
self,
@ -179,16 +216,24 @@ class TransactionData(RecursiveMentionable, StaticMentionable):
) -> bool:
assert isinstance(signatures, NullableReference)
assert isinstance(mint, int)
assert_true(await self._verify_signatures(signatures))
assert_true(await self._verify_values(mint))
assert_trues(
await gather(
self._verify_signatures(signatures),
self._verify_values(mint),
)
)
return True
async def str(self, tab: int) -> str:
assert isinstance(tab, int)
in_str, out_str = await gather(
self.in_coins.str(tab),
self.out_coins.str(tab),
)
return f'(in)' \
f'{tabulate(tab)}{await self.in_coins.str(tab)}' \
f'{tabulate(tab)}{in_str}' \
f'{tabulate(tab)}(out)' \
f'{tabulate(tab)}{await self.out_coins.str(tab)}'
f'{tabulate(tab)}{out_str}'
class Transaction(RecursiveMentionable, StaticMentionable):
@ -276,10 +321,14 @@ class Transaction(RecursiveMentionable, StaticMentionable):
async def str(self, tab: int) -> str:
assert isinstance(tab, int)
data_str, signatures_str = await gather(
hash_point_format(self.data, tab + 1),
self.signatures.str(tab + 1),
)
return f'(' \
f'{tabulate(tab + 1)}transaction' \
f'{tabulate(tab + 1)}{hash_point_format(self.data, tab + 1)}' \
f'{tabulate(tab + 1)}{self.signatures.str(tab + 1)}' \
f'{tabulate(tab + 1)}{data_str}' \
f'{tabulate(tab + 1)}{signatures_str}' \
f'{tabulate(tab)})'
@classmethod

View File

@ -156,8 +156,13 @@ class WeakReferenceIndexSetBTree(RecursiveMentionable):
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)}{await hash_point_format(self.child_no(child_index), tab + 1)}'
formatted += ''.join(
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}' \
f'{tabulate(tab)})'

View File

@ -33,9 +33,13 @@ class WrisbtIndex(RecursiveMentionable):
async def str(self, tab: int) -> str:
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)' \
f'{tabulate(tab)}{await hash_point_format(self.total, tab)}' \
f'{tabulate(tab)}{await hash_point_format(self.delta, tab)}'
f'{tabulate(tab)}{total_str}' \
f'{tabulate(tab)}{delta_str}'
class WrisbtIndexFactory(RainbowFactory[WrisbtIndex]):

View File

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

View File

@ -86,7 +86,11 @@ class WrisbtRoot(RecursiveMentionable):
assert isinstance(exclude, WrisbtRoot)
key: bytes = target.point
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
tree: WrisbtRoot = self
value: Mentionable = await target.resolve()