diff --git a/rainbowadn/data/collection/stack/stack.py b/rainbowadn/data/collection/stack/stack.py index f291670..f85578b 100644 --- a/rainbowadn/data/collection/stack/stack.py +++ b/rainbowadn/data/collection/stack/stack.py @@ -68,6 +68,19 @@ class Stack(RecursiveMentionable, Generic[ElementType]): assert isinstance(factory, RainbowFactory) return cls.of(factory, map(HashPoint.of, elements)) + @classmethod + def iter( + cls, + reference: NullableReference['Stack[ElementType]'] + ) -> Iterable[HashPoint[ElementType]]: + assert isinstance(reference, NullableReference) + if reference.reference.null(): + pass + else: + stack: Stack[ElementType] = reference.reference.resolve().resolve() + yield stack.element + yield from cls.iter(stack.previous) + class StackFactory(RainbowFactory[Stack[ElementType]], Generic[ElementType]): def __init__(self, factory: RainbowFactory[ElementType]): diff --git a/rainbowadn/testing/test_all.py b/rainbowadn/testing/test_all.py index cf4cdd1..7cd54be 100644 --- a/rainbowadn/testing/test_all.py +++ b/rainbowadn/testing/test_all.py @@ -30,6 +30,7 @@ from rainbowadn.wrisbt.wrisbtroot import WrisbtRoot class TestAll(unittest.TestCase): + """examples rather than real tests""" def test_bankchain(self): with self.subTest('setup'): dr = DictResolver() diff --git a/rainbowadn/v13/bankstate.py b/rainbowadn/v13/bankstate.py index 5800a8a..a3fa8b5 100644 --- a/rainbowadn/v13/bankstate.py +++ b/rainbowadn/v13/bankstate.py @@ -19,7 +19,7 @@ from rainbowadn.hashing.resolverorigin import ResolverOrigin from rainbowadn.hashing.static import StaticFactory, StaticMentionable from rainbowadn.v13.algo import MINT_CONST from rainbowadn.v13.subject import Subject -from rainbowadn.v13.transaction import Coin, Transaction, TransactionData +from rainbowadn.v13.transaction import Coin, Transaction __all__ = ('BankState',) @@ -87,55 +87,63 @@ class BankState(RecursiveMentionable, StaticMentionable): HashPoint.of(Integer(self.length.resolve().integer + 1)) ) - def push(self, transaction: HashPoint[Transaction]) -> 'BankState': - assert isinstance(transaction, HashPoint) - - transaction_resolved = transaction.resolve() - assert isinstance(transaction_resolved, Transaction) - - miner: Nullable[HashPoint[Subject]] = self.miner.reference - assert isinstance(miner, Nullable) - if miner.null(): - mint = MINT_CONST - else: - mint = 0 - - assert transaction_resolved.verify(mint) - transaction_data: TransactionData = transaction_resolved.data.resolve() - assert isinstance(transaction_data, TransactionData) - - minted: ActiveBinaryTree[Coin, Integer] = ActiveBinaryTree( + def minted_tree(self) -> ActiveBinaryTree[Coin, Integer]: + return ActiveBinaryTree( AVLBTBP(HashComparator(Fail())), self.minted ) - assert isinstance(minted, ActiveBinaryTree) - used: ActiveBinaryTree[Coin, Integer] = ActiveBinaryTree( + + def used_tree(self) -> ActiveBinaryTree[Coin, Integer]: + return ActiveBinaryTree( AVLBTBP(HashComparator(Fail())), self.used ) - assert isinstance(used, ActiveBinaryTree) - in_coin: HashPoint[Coin] - for in_coin in transaction_data.iter_in_coins(): - assert isinstance(in_coin, HashPoint) + def use_coins(self, coins: Iterable[HashPoint[Coin]]) -> 'BankState': + minted: ActiveBinaryTree[Coin, Integer] = self.minted_tree() + used: ActiveBinaryTree[Coin, Integer] = self.used_tree() + for in_coin in coins: assert not minted.query_tree().query(in_coin).null() assert used.query_tree().query(in_coin).null() used = used.add(in_coin) - assert isinstance(used, ActiveBinaryTree) + return BankState(self.minted, used.reference, self.miner, self.length) - coin: Coin - for coin, miner in transaction_resolved.iter_coins(mint, miner): - assert isinstance(coin, Coin) - assert isinstance(miner, Nullable) + def mint_coins( + self, + transaction: Transaction + ) -> 'BankState': + assert self.verify(transaction) + miner = self.miner_nullable() + minted: ActiveBinaryTree[Coin, Integer] = self.minted_tree() + for coin, miner in transaction.iter_coins(self.mint(), miner): assert minted.query_tree().query(HashPoint.of(coin)).null() minted = minted.add(HashPoint.of(coin)) assert isinstance(minted, ActiveBinaryTree) + return BankState(minted.reference, self.used, NullableReference(miner, self.miner.factory), self.length) - return BankState( - minted.reference, - used.reference, - NullableReference(miner, self.miner.factory), - self.length + def miner_nullable(self) -> Nullable[HashPoint[Subject]]: + return self.miner.reference + + def mint(self) -> int: + if self.miner_nullable().null(): + return MINT_CONST + else: + return 0 + + def verify(self, transaction: Transaction) -> bool: + assert isinstance(transaction, Transaction) + assert transaction.verify(self.mint()) + return True + + def _push(self, transaction: Transaction) -> 'BankState': + assert isinstance(transaction, Transaction) + return self.use_coins( + transaction.data.resolve().iter_in_coins() + ).mint_coins( + transaction ) + def push(self, transaction: HashPoint[Transaction]) -> 'BankState': + return self._push(transaction.resolve()) + def str(self, tab: int) -> str: assert isinstance(tab, int) return f'(' \ diff --git a/rainbowadn/v13/transaction.py b/rainbowadn/v13/transaction.py index 83e0887..5c87c11 100644 --- a/rainbowadn/v13/transaction.py +++ b/rainbowadn/v13/transaction.py @@ -137,73 +137,26 @@ class TransactionData(RecursiveMentionable, StaticMentionable): def _verify_signatures( self, - in_coins: NullableReference[Stack[Coin]], - signatures: NullableReference[Stack[Signature]], + signatures: NullableReference[Stack[Signature]] ) -> bool: - assert isinstance(in_coins, NullableReference) - assert isinstance(signatures, NullableReference) - if in_coins.reference.null(): - assert signatures.reference.null() - return True - else: - assert not signatures.reference.null() - in_coins_stack: Stack[Coin] = in_coins.reference.resolve().resolve() - assert isinstance(in_coins_stack, Stack) - signatures_stack: Stack[Signature] = signatures.reference.resolve().resolve() - assert isinstance(signatures_stack, Stack) - coin: Coin = in_coins_stack.element.resolve() - assert isinstance(coin, Coin) - coin_data: CoinData = coin.data.resolve() - assert isinstance(coin_data, CoinData) - owner: Subject = coin_data.owner.resolve() - assert isinstance(owner, Subject) - signature: Signature = signatures_stack.element.resolve() - assert isinstance(signature, Signature) - assert signature.verify(owner, self.hash_point) - assert self._verify_signatures(in_coins_stack.previous, signatures_stack.previous) - return True + for coin, signature in zip(self.iter_in_coins(), Stack.iter(signatures), strict=True): + assert signature.resolve().verify( + coin.resolve().data.resolve().owner.resolve(), + self.hash_point + ) + return True def iter_in_coins(self) -> Iterable[HashPoint[Coin]]: - in_coins: NullableReference[Stack[Coin]] = self.in_coins - assert isinstance(in_coins, NullableReference) - while not in_coins.reference.null(): - in_coins_stack: Stack[Coin] = in_coins.reference.resolve().resolve() - assert isinstance(in_coins_stack, Stack) - coin: HashPoint[Coin] = in_coins_stack.element - assert isinstance(coin, HashPoint) - yield coin - in_coins = in_coins_stack.previous - assert isinstance(in_coins, NullableReference) - assert in_coins.reference.null() + return Stack.iter(self.in_coins) def _total_in(self) -> int: - total_in = 0 - coin: HashPoint[Coin] - for coin in self.iter_in_coins(): - assert isinstance(coin, HashPoint) - total_in += coin.resolve().data.resolve().value.resolve().integer - return total_in + return sum(coin.resolve().data.resolve().value.resolve().integer for coin in self.iter_in_coins()) def iter_out_coins(self) -> Iterable[HashPoint[CoinData]]: - out_coins: NullableReference[Stack[CoinData]] = self.out_coins - assert isinstance(out_coins, NullableReference) - while not out_coins.reference.null(): - out_coins_stack: Stack[CoinData] = out_coins.reference.resolve().resolve() - assert isinstance(out_coins_stack, Stack) - coin: HashPoint[CoinData] = out_coins_stack.element - assert isinstance(coin, HashPoint) - yield coin - out_coins = out_coins_stack.previous - assert isinstance(out_coins, NullableReference) - assert out_coins.reference.null() + return Stack.iter(self.out_coins) def _total_out(self) -> int: - total_out = 0 - coin: HashPoint[CoinData] - for coin in self.iter_out_coins(): - assert isinstance(coin, HashPoint) - total_out += coin.resolve().value.resolve().integer - return total_out + return sum(coin.resolve().value.resolve().integer for coin in self.iter_out_coins()) def _verify_values(self, mint: int) -> bool: assert isinstance(mint, int) @@ -221,7 +174,9 @@ class TransactionData(RecursiveMentionable, StaticMentionable): ) -> bool: assert isinstance(signatures, NullableReference) assert isinstance(mint, int) - return self._verify_signatures(self.in_coins, signatures) and self._verify_values(mint) + assert self._verify_signatures(signatures) + assert self._verify_values(mint) + return True def str(self, tab: int) -> str: assert isinstance(tab, int) @@ -308,7 +263,8 @@ class Transaction(RecursiveMentionable, StaticMentionable): assert isinstance(mint, int) data: TransactionData = self.data.resolve() assert isinstance(data, TransactionData) - return data.verify(self.signatures, mint) + assert data.verify(self.signatures, mint) + return True def __str__(self): return f'(transaction)'