Skip to content

Commit

Permalink
#86drpnck9 - Refactor example_tests/test_update_contract.py to use Bo…
Browse files Browse the repository at this point in the history
…aConstructor
  • Loading branch information
jplippi committed Mar 26, 2024
1 parent 7fd1f46 commit d5249af
Showing 1 changed file with 55 additions and 60 deletions.
115 changes: 55 additions & 60 deletions boa3_test/tests/examples_tests/test_update_contract.py
Original file line number Diff line number Diff line change
@@ -1,101 +1,96 @@
import json

from boa3_test.tests.boa_test import BoaTest # needs to be the first import to avoid circular imports
from neo3.contracts.contract import CONTRACT_HASHES
from neo3.wallet import account

from boa3.internal import constants
from boa3.internal.neo.vm.type.String import String
from boa3.internal.neo3.vm import VMState
from boa3_test.tests.test_drive import neoxp
from boa3_test.tests.test_drive.testrunner.boa_test_runner import BoaTestRunner
from boa3_test.tests import boatestcase
from boa3_test.tests.event import UpdateEvent


class TestUpdateContractTemplate(BoaTest):
class TestUpdateContractTemplate(boatestcase.BoaTestCase):
default_folder: str = 'examples'

OWNER = neoxp.utils.get_account_by_name('owner')
OTHER_ACCOUNT = neoxp.utils.get_account_by_name('testAccount1')
owner: account.Account
other_account: account.Account

GAS_TO_DEPLOY = 1000 * 10 ** 8

def test_update_contract_compile(self):
path = self.get_contract_path('update_contract.py')
path_new = self.get_contract_path('examples/auxiliary_contracts', 'update_contract.py')
self.compile(path)
self.compile(path_new)
@classmethod
def setupTestCase(cls):
cls.owner = cls.node.wallet.account_new(label='owner', password='123')
cls.other_account = cls.node.wallet.account_new(label='otherAccount', password='123')

def test_update_contract(self):
path, _ = self.get_deploy_file_paths('update_contract.py')
runner = BoaTestRunner(runner_id=self.method_name())
super().setupTestCase()

invokes = []
expected_results = []
@classmethod
async def asyncSetupClass(cls) -> None:
await super().asyncSetupClass()

test_account = self.OTHER_ACCOUNT
test_account_script_hash = test_account.script_hash.to_array()
await cls.transfer(CONTRACT_HASHES.GAS_TOKEN, cls.genesis.script_hash, cls.owner.script_hash, 100)
await cls.transfer(CONTRACT_HASHES.GAS_TOKEN, cls.genesis.script_hash, cls.other_account.script_hash, 100)

runner.add_gas(self.OWNER.address, self.GAS_TO_DEPLOY)
update_contract = runner.deploy_contract(path, account=self.OWNER)
runner.update_contracts(export_checkpoint=True)
await cls.set_up_contract('update_contract.py', signing_account=cls.owner)

tx_deploy_notifications = runner.get_transaction_result(update_contract.tx_id).executions[0].notifications
# Transfer emitted when deploying the smart contract
self.assertEqual(2, len(tx_deploy_notifications))
self.assertEqual(1, len([notification
for notification in tx_deploy_notifications if notification.name == 'Transfer']))
self.assertEqual(1, len([notification
for notification in tx_deploy_notifications if notification.name == 'Deploy']))
def test_update_contract_compile(self):
self.assertCompile('update_contract.py')
self.assertCompile('update_contract.py', root_folder='examples/auxiliary_contracts')

async def test_update_contract(self):
# Saving user's balance before calling method to compare it later
tokens_before = runner.call_contract(path, 'balanceOf', test_account_script_hash)
tokens_before, _ = await self.call('balanceOf', [self.other_account.script_hash], return_type=int)

# The bugged method is being called and the user is able to receive tokens for free
invokes.append(runner.call_contract(path, 'method', test_account_script_hash))
expected_results.append(None)
result, notifications = await self.call('method', [self.other_account.script_hash], return_type=None, signing_accounts=[self.other_account])
self.assertIsNone(result)

tokens_after = runner.call_contract(path, 'balanceOf', test_account_script_hash)
tokens_after, _ = await self.call('balanceOf', [self.other_account.script_hash], return_type=int)

runner.execute()
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)
transfer_events = self.filter_events(notifications, notification_type=boatestcase.Nep17TransferEvent)
self.assertEqual(1, len(transfer_events))

# The amount of tokens will be higher after calling the method
self.assertGreater(tokens_after.result, tokens_before.result)

transfer_events = runner.get_events('Transfer', origin=update_contract)
self.assertEqual(1, len(transfer_events))
self.assertGreater(tokens_after, tokens_before)

# new smart contract that has the bug fixed
path_new = self.get_contract_path('examples/auxiliary_contracts', 'update_contract.py')
new_nef, new_manifest = self.get_bytes_output(path_new)
new_nef, new_manifest = self.get_serialized_output(path_new)

arg_manifest = String(json.dumps(new_manifest, separators=(',', ':'))).to_bytes()

# The smart contract will be updated to fix the bug in the method
invokes.append(runner.call_contract(path, 'update_sc', new_nef, arg_manifest, None))
expected_results.append(None)

runner.execute(account=self.OWNER)
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)
result, notifications = await self.call('update_sc', [new_nef, arg_manifest, None], return_type=None, signing_accounts=[self.owner])
self.assertIsNone(result)

# An `Update` event was be emitted after the update
event_update = runner.get_events('Update')
self.assertEqual(1, len(event_update))

runner.run_contract(path, 'update_sc', new_nef, arg_manifest, None, account=self.OWNER)
update_events = self.filter_events(notifications, notification_type=UpdateEvent)
self.assertEqual(1, len(update_events))

# Saving user's balance before calling method to compare it later
tokens_before = runner.call_contract(path, 'balanceOf', test_account_script_hash)
tokens_before, _ = await self.call('balanceOf', [self.other_account.script_hash], return_type=int)

# Now, when method is called, it won't mint new tokens to any user that called it
invokes.append(runner.call_contract(path, 'method', test_account_script_hash))
expected_results.append(None)
result, notifications = await self.call('method', [self.other_account.script_hash], return_type=None, signing_accounts=[self.other_account])
self.assertIsNone(result)

transfer_events = self.filter_events(notifications, notification_type=boatestcase.Nep17TransferEvent)
self.assertEqual(0, len(transfer_events))

# The amount of tokens now is the same before and after calling the method
tokens_after = runner.call_contract(path, 'balanceOf', test_account_script_hash)
tokens_after, _ = await self.call('balanceOf', [self.other_account.script_hash], return_type=int)

self.assertEqual(tokens_after, tokens_before)

runner.get_contract(constants.NEO_SCRIPT)
# If the signing account is the owner, then the method works, and it will mint the new tokens
tokens_before, _ = await self.call('balanceOf', [self.other_account.script_hash], return_type=int)

runner.execute(account=test_account)
self.assertEqual(VMState.HALT, runner.vm_state, msg=runner.error)
result, notifications = await self.call('method', [self.other_account.script_hash], return_type=None, signing_accounts=[self.owner])
self.assertIsNone(result)

self.assertEqual(tokens_after.result, tokens_before.result)
transfer_events = self.filter_events(notifications, notification_type=boatestcase.Nep17TransferEvent)
self.assertEqual(1, len(transfer_events))

# The amount of tokens will be higher after calling the method
tokens_after, _ = await self.call('balanceOf', [self.other_account.script_hash], return_type=int)

for x in range(len(invokes)):
self.assertEqual(expected_results[x], invokes[x].result)
self.assertGreater(tokens_after, tokens_before)

0 comments on commit d5249af

Please sign in to comment.