From aa75eb8b6a86b9e79b78247c6b567bc024512f14 Mon Sep 17 00:00:00 2001 From: Gabriel Levcovitz Date: Tue, 12 Aug 2025 11:15:38 -0300 Subject: [PATCH] tests(nano): test actions order --- tests/nanocontracts/test_actions.py | 140 +++++++++++++++++++--------- 1 file changed, 95 insertions(+), 45 deletions(-) diff --git a/tests/nanocontracts/test_actions.py b/tests/nanocontracts/test_actions.py index ff165d710..6fcfb70f1 100644 --- a/tests/nanocontracts/test_actions.py +++ b/tests/nanocontracts/test_actions.py @@ -70,7 +70,7 @@ class TestActions(unittest.TestCase): initial state and every vertex that we'll need. Then, we manually manipulate a tx's nano header adding the required actions and changing inputs/outputs accordingly. - The dag builder deos not currently support authority actions. Even when it supports them, it's good to keep those + The dag builder does not currently support authority actions. Even when it supports them, it's good to keep those tests manual to make basic assertions without the implicitness of the dag builder. """ @@ -467,7 +467,7 @@ def test_acquire_authority_melt_tokens_success(self) -> None: # Check that tx2 successfully executes. assert self.tx2.get_metadata().voided_by is None - def test_mint_tokens_success(self) -> None: + def _test_mint_tokens_success(self, *, invert_actions_order: bool) -> None: # Grant a TKA mint authority to the nano contract and then use it to mint tokens. self.test_grant_authority_mint_success() assert self._get_all_balances() == { @@ -477,12 +477,15 @@ def test_mint_tokens_success(self) -> None: # Add actions so both minted tokens and htr used to mint tokens are in/from the tx outputs/inputs. self._change_tx_balance(tx=self.tx2, update_htr_output=-200, update_tka_output=20000) + nc_actions = [ + NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=1, amount=20000), + NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=0, amount=200), + ] + if invert_actions_order: + nc_actions.reverse() self._set_nano_header( tx=self.tx2, - nc_actions=[ - NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=1, amount=20000), - NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=0, amount=200), - ], + nc_actions=nc_actions, nc_method='mint', nc_args=(self.tka.hash, 20000), ) @@ -506,6 +509,12 @@ def test_mint_tokens_success(self) -> None: tka_total=self.initial_tka_total + 20000, ) + def test_mint_tokens_success(self) -> None: + self._test_mint_tokens_success(invert_actions_order=False) + + def test_mint_tokens_success_inverted(self) -> None: + self._test_mint_tokens_success(invert_actions_order=True) + def test_grant_and_mint_same_tx_success(self) -> None: # Add a GRANT_AUTHORITY action to mint TKA, and add a mint authority input accordingly. # Also add a call to mint @@ -566,7 +575,7 @@ def test_mint_tokens_keep_in_contract_success(self) -> None: tka_total=self.initial_tka_total + 20000, ) - def test_mint_tokens_and_partial_withdrawal_success(self) -> None: + def _test_mint_tokens_and_partial_withdrawal_success(self, *, invert_actions_order: bool) -> None: # Grant a TKA mint authority to the nano contract and then use it to mint tokens. self.test_grant_authority_mint_success() assert self._get_all_balances() == { @@ -576,12 +585,15 @@ def test_mint_tokens_and_partial_withdrawal_success(self) -> None: # Add actions paying for HTR with the input and withdrawing part of the minted token from the contract. self._change_tx_balance(tx=self.tx2, update_htr_output=-200, update_tka_output=10000) + nc_actions = [ + NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=1, amount=10000), + NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=0, amount=200), + ] + if invert_actions_order: + nc_actions.reverse() self._set_nano_header( tx=self.tx2, - nc_actions=[ - NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=1, amount=10000), - NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=0, amount=200), - ], + nc_actions=nc_actions, nc_method='mint', nc_args=(self.tka.hash, 20000) ) @@ -604,7 +616,13 @@ def test_mint_tokens_and_partial_withdrawal_success(self) -> None: tka_total=self.initial_tka_total + 20000, ) - def test_melt_tokens_success(self) -> None: + def test_mint_tokens_and_partial_withdrawal_success(self) -> None: + self._test_mint_tokens_and_partial_withdrawal_success(invert_actions_order=False) + + def test_mint_tokens_and_partial_withdrawal_success_inverted(self) -> None: + self._test_mint_tokens_and_partial_withdrawal_success(invert_actions_order=True) + + def _test_melt_tokens_success(self, *, invert_actions_order: bool) -> None: # Grant a TKA melt authority to the nano contract and then use it to melt tokens. self.test_grant_authority_melt_success() assert self._get_all_balances() == { @@ -614,12 +632,15 @@ def test_melt_tokens_success(self) -> None: # Add actions so both melted tokens and htr received from melt are from/in the tx inputs/outputs. self._change_tx_balance(tx=self.tx2, update_htr_output=5, update_tka_output=-500) + nc_actions = [ + NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=1, amount=500), + NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=0, amount=5), + ] + if invert_actions_order: + nc_actions.reverse() self._set_nano_header( tx=self.tx2, - nc_actions=[ - NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=1, amount=500), - NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=0, amount=5), - ], + nc_actions=nc_actions, nc_method='melt', nc_args=(self.tka.hash, 500) ) @@ -643,6 +664,12 @@ def test_melt_tokens_success(self) -> None: tka_total=self.initial_tka_total - 500, ) + def test_melt_tokens_success(self) -> None: + self._test_melt_tokens_success(invert_actions_order=False) + + def test_melt_tokens_success_inverted(self) -> None: + self._test_melt_tokens_success(invert_actions_order=True) + def test_melt_tokens_from_contract_success(self) -> None: # Grant a TKA melt authority to the nano contract and then use it to melt tokens. self.test_grant_authority_melt_success() @@ -678,7 +705,7 @@ def test_melt_tokens_from_contract_success(self) -> None: tka_total=self.initial_tka_total - 500, ) - def test_melt_tokens_from_contract_and_input_success(self) -> None: + def _test_melt_tokens_from_contract_and_input_success(self, *, invert_actions_order: bool) -> None: # Grant a TKA melt authority to the nano contract and then use it to melt tokens. self.test_grant_authority_melt_success() assert self._get_all_balances() == { @@ -688,12 +715,15 @@ def test_melt_tokens_from_contract_and_input_success(self) -> None: # Add actions so part of the tokens are melted from inputs and part from the contract. self._change_tx_balance(tx=self.tx2, update_htr_output=5, update_tka_output=-250) + nc_actions = [ + NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=1, amount=250), + NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=0, amount=5), + ] + if invert_actions_order: + nc_actions.reverse() self._set_nano_header( tx=self.tx2, - nc_actions=[ - NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=1, amount=250), - NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=0, amount=5), - ], + nc_actions=nc_actions, nc_method='melt', nc_args=(self.tka.hash, 500) ) @@ -716,54 +746,68 @@ def test_melt_tokens_from_contract_and_input_success(self) -> None: tka_total=self.initial_tka_total - 500, ) - def test_acquire_and_grant_same_token_not_allowed(self) -> None: + def test_melt_tokens_from_contract_and_input_success(self) -> None: + self._test_melt_tokens_from_contract_and_input_success(invert_actions_order=False) + + def test_melt_tokens_from_contract_and_input_success_inverted(self) -> None: + self._test_melt_tokens_from_contract_and_input_success(invert_actions_order=True) + + def _test_acquire_and_grant_same_token_not_allowed(self, *, invert_actions_order: bool) -> None: + nc_actions = [ + NanoHeaderAction(type=NCActionType.ACQUIRE_AUTHORITY, token_index=1, amount=TxOutput.TOKEN_MINT_MASK), + NanoHeaderAction(type=NCActionType.GRANT_AUTHORITY, token_index=1, amount=TxOutput.TOKEN_MINT_MASK), + ] + if invert_actions_order: + nc_actions.reverse() self._set_nano_header( tx=self.tx1, - nc_actions=[ - NanoHeaderAction(type=NCActionType.ACQUIRE_AUTHORITY, token_index=1, amount=TxOutput.TOKEN_MINT_MASK), - NanoHeaderAction(type=NCActionType.GRANT_AUTHORITY, token_index=1, amount=TxOutput.TOKEN_MINT_MASK), - ], + nc_actions=nc_actions, ) with pytest.raises(NCInvalidAction) as e: self.manager.verification_service.verifiers.nano_header.verify_actions(self.tx1) assert str(e.value) == f'conflicting actions for token {self.tka.hash_hex}' - def test_grant_and_acquire_same_token_not_allowed(self) -> None: - self._set_nano_header( - tx=self.tx1, - nc_actions=[ - NanoHeaderAction(type=NCActionType.GRANT_AUTHORITY, token_index=1, amount=TxOutput.TOKEN_MINT_MASK), - NanoHeaderAction(type=NCActionType.ACQUIRE_AUTHORITY, token_index=1, amount=TxOutput.TOKEN_MINT_MASK), - ], - ) + def test_acquire_and_grant_same_token_not_allowed(self) -> None: + self._test_acquire_and_grant_same_token_not_allowed(invert_actions_order=False) - with pytest.raises(NCInvalidAction) as e: - self.manager.verification_service.verifiers.nano_header.verify_actions(self.tx1) - assert str(e.value) == f'conflicting actions for token {self.tka.hash_hex}' + def test_acquire_and_grant_same_token_not_allowed_inverted(self) -> None: + self._test_acquire_and_grant_same_token_not_allowed(invert_actions_order=True) - def test_conflicting_actions(self) -> None: + def _test_conflicting_actions(self, *, invert_actions_order: bool) -> None: # Add 2 conflicting actions for the same token. - self._set_nano_header(tx=self.tx1, nc_actions=[ + nc_actions = [ NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=0, amount=1), NanoHeaderAction(type=NCActionType.WITHDRAWAL, token_index=0, amount=2), - ]) + ] + if invert_actions_order: + nc_actions.reverse() + self._set_nano_header(tx=self.tx1, nc_actions=nc_actions) with pytest.raises(NCInvalidAction) as e: self.manager.verification_service.verifiers.nano_header.verify_actions(self.tx1) assert str(e.value) == 'conflicting actions for token 00' - def test_non_conflicting_actions_success(self) -> None: + def test_conflicting_actions(self) -> None: + self._test_conflicting_actions(invert_actions_order=False) + + def test_conflicting_actions_inverted(self) -> None: + self._test_conflicting_actions(invert_actions_order=True) + + def _test_non_conflicting_actions_success(self, *, invert_actions_order: bool) -> None: # Add a GRANT_AUTHORITY action to mint TKA, and add a mint authority input accordingly. # Also add a DEPOSIT action with the same token and update the tx output accordingly. self._change_tx_balance(tx=self.tx1, add_inputs=[self._create_tka_mint_input()]) self._change_tx_balance(tx=self.tx1, update_tka_output=-100) + nc_actions = [ + NanoHeaderAction(type=NCActionType.GRANT_AUTHORITY, token_index=1, amount=TxOutput.TOKEN_MINT_MASK), + NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=1, amount=100), + ] + if invert_actions_order: + nc_actions.reverse() self._set_nano_header( tx=self.tx1, - nc_actions=[ - NanoHeaderAction(type=NCActionType.GRANT_AUTHORITY, token_index=1, amount=TxOutput.TOKEN_MINT_MASK), - NanoHeaderAction(type=NCActionType.DEPOSIT, token_index=1, amount=100), - ], + nc_actions=nc_actions, ) # Execute tx1 @@ -778,6 +822,12 @@ def test_non_conflicting_actions_success(self) -> None: self.tka_balance_key: Balance(value=1100, can_mint=True, can_melt=False), } + def test_non_conflicting_actions_success(self) -> None: + self._test_non_conflicting_actions_success(invert_actions_order=False) + + def test_non_conflicting_actions_success_inverted(self) -> None: + self._test_non_conflicting_actions_success(invert_actions_order=True) + def test_token_index_not_found(self) -> None: # Add an action with a token index out of bounds. self._set_nano_header(tx=self.tx1, nc_actions=[