gather
This commit is contained in:
parent
1a19695e6e
commit
8daaefa4a4
88
plot.py
Normal file
88
plot.py
Normal 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())
|
@ -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)})'
|
||||
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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[
|
||||
|
@ -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]]):
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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()
|
||||
|
@ -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(
|
||||
|
@ -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)})'
|
||||
|
||||
|
@ -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]):
|
||||
|
@ -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(
|
||||
|
@ -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:
|
||||
|
@ -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]):
|
||||
|
@ -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
|
||||
)
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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
35
rainbowadn/core/gather.py
Normal 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]
|
@ -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,
|
||||
|
29
rainbowadn/testing/delayedresolver.py
Normal file
29
rainbowadn/testing/delayedresolver.py
Normal 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
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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)})'
|
||||
|
@ -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
|
||||
|
@ -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)})'
|
||||
|
@ -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]):
|
||||
|
@ -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
|
||||
)
|
||||
)
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user