class MockNode: def __init__(self, ctx, index=1, genesis_path=os.path.dirname(os.path.abspath(__file__))): self.wallet = Wallet() self.index = index port = 18000 + index self.ip = f'tcp://127.0.0.1:{port}' self.raw_driver = Driver(collection=f'state-{self.index}') self.driver = ContractDriver(driver=self.raw_driver) self.driver.flush() self.nonces = storage.NonceStorage(nonce_collection=f'nonces-{self.index}', pending_collection=f'pending-{self.index}') self.nonces.flush() self.ctx = ctx self.bootnodes = {} self.constitution = {} self.ready_to_start = False self.started = False self.obj = None self.genesis_path = genesis_path def set_start_variables(self, bootnodes, constitution): self.bootnodes = bootnodes self.constitution = constitution self.ready_to_start = True def flush(self): self.driver.flush() self.nonces.flush()
class TestStorage(TestCase): def setUp(self): self.driver = ContractDriver() self.driver.flush() def tearDown(self): self.driver.flush() def test_get_latest_block_hash_0s_if_none(self): h = storage.get_latest_block_hash(self.driver) self.assertEqual(h, '0' * 64) def test_get_latest_block_hash_correct_after_set(self): storage.set_latest_block_hash('a' * 64, self.driver) h = storage.get_latest_block_hash(self.driver) self.assertEqual(h, 'a' * 64) def test_get_latest_block_height_0_if_none(self): h = storage.get_latest_block_height(self.driver) self.assertEqual(h, 0) def test_get_latest_block_height_correct_after_set(self): storage.set_latest_block_height(123, self.driver) h = storage.get_latest_block_height(self.driver) self.assertEqual(h, 123)
class TestSandbox(TestCase): def setUp(self): self.d = ContractDriver() self.d.flush() with open('../../contracting/contracts/submission.s.py') as f: contract = f.read() self.d.set_contract(name='submission', code=contract, author='sys') self.d.commit() self.recipients = [secrets.token_hex(16) for _ in range(10000)] def tearDown(self): self.d.flush() def test_transfer_performance(self): e = Executor() e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( '../integration/test_contracts/erc20_clone.s.py')) for r in self.recipients: e.execute(sender='stu', contract_name='erc20_clone', function_name='transfer', kwargs={ 'amount': 1, 'to': r })
def test_init_state(self): driver = ContractDriver() driver.flush() sync.sync_genesis_contracts() upg = driver.get_contract_keys('upgrade') self.assertIsNotNone(upg) print('done')
def test_sync_genesis_contracts_if_none_in_instance(self): driver = ContractDriver() driver.flush() sync.sync_genesis_contracts() submission = driver.get_contract('submission') currency = driver.get_contract('currency') upgrade = driver.get_contract('upgrade') self.assertIsNotNone(submission) self.assertIsNotNone(currency) self.assertIsNotNone(upgrade)
class TestFullFlowWithMocks(TestCase): def setUp(self): self.ctx = zmq.asyncio.Context() self.loop = asyncio.new_event_loop() self.driver = ContractDriver(driver=InMemDriver()) self.client = ContractingClient(driver=self.driver) self.client.flush() asyncio.set_event_loop(self.loop) def tearDown(self): self.client.flush() self.driver.flush() self.ctx.destroy() self.loop.close() def test_vote_new_delegate(self): network = mocks.MockNetwork(num_of_masternodes=2, num_of_delegates=2, ctx=self.ctx) stu = Wallet() candidate = Wallet() async def test(): await network.start() network.refresh() await network.make_and_push_tx( wallet=mocks.TEST_FOUNDATION_WALLET, contract='currency', function='transfer', kwargs={ 'amount': 1_000_000, 'to': stu.verifying_key } ) await asyncio.sleep(1) await network.make_and_push_tx( wallet=mocks.TEST_FOUNDATION_WALLET, contract='currency', function='transfer', kwargs={ 'amount': 1_000_000, 'to': candidate.verifying_key } )
def test_submit_contract_with_specific_construction_args(self): driver = ContractDriver() driver.flush() sync.submit_contract_with_construction_args('vkbook', args={ 'masternodes': ['stu', 'raghu'], 'delegates': ['tejas', 'monica'], 'num_boot_mns': 1, 'num_boot_del': 1 }) client = ContractingClient() vkbook = client.get_contract('vkbook') self.assertEqual(vkbook.get_masternodes(), ['stu', 'raghu']) self.assertEqual(vkbook.get_delegates(), ['tejas', 'monica'])
class TestFullFlowWithMocks(TestCase): def setUp(self): self.ctx = zmq.asyncio.Context() self.loop = asyncio.new_event_loop() self.driver = ContractDriver(driver=InMemDriver()) self.client = ContractingClient(driver=self.driver) self.client.flush() asyncio.set_event_loop(self.loop) def tearDown(self): self.client.flush() self.driver.flush() self.ctx.destroy() self.loop.close() def test_mock_network_init_makes_correct_number_of_nodes(self): n = mocks.MockNetwork(num_of_delegates=1, num_of_masternodes=1, ctx=self.ctx) self.assertEqual(len(n.masternodes), 1) self.assertEqual(len(n.delegates), 1) def test_mock_network_init_makes_correct_number_of_nodes_many_nodes(self): n = mocks.MockNetwork(num_of_delegates=123, num_of_masternodes=143, ctx=self.ctx) self.assertEqual(len(n.masternodes), 143) self.assertEqual(len(n.delegates), 123) def test_mock_network_init_creates_correct_bootnodes(self): # 2 mn, 3 delegate expected_ips = [ 'tcp://127.0.0.1:18000', 'tcp://127.0.0.1:18001', 'tcp://127.0.0.1:18002', 'tcp://127.0.0.1:18003', 'tcp://127.0.0.1:18004', ] n = mocks.MockNetwork(num_of_masternodes=2, num_of_delegates=3, ctx=self.ctx) self.assertEqual(n.masternodes[0].ip, expected_ips[0]) self.assertEqual(n.masternodes[1].ip, expected_ips[1]) self.assertEqual(n.delegates[0].ip, expected_ips[2]) self.assertEqual(n.delegates[1].ip, expected_ips[3]) self.assertEqual(n.delegates[2].ip, expected_ips[4]) def test_startup_with_manual_node_creation_and_single_block_works(self): m = mocks.MockMaster(ctx=self.ctx, index=1) d = mocks.MockDelegate(ctx=self.ctx, index=2) bootnodes = { m.wallet.verifying_key: m.ip, d.wallet.verifying_key: d.ip } constitution = { 'masternodes': [m.wallet.verifying_key], 'delegates': [d.wallet.verifying_key] } m.set_start_variables(bootnodes, constitution) d.set_start_variables(bootnodes, constitution) sender = Wallet() async def test(): await asyncio.gather( m.start(), d.start() ) tx_1 = transaction.build_transaction( wallet=mocks.TEST_FOUNDATION_WALLET, contract='currency', function='transfer', kwargs={ 'amount': 1_000_000, 'to': sender.verifying_key }, stamps=10000, nonce=0, processor=m.wallet.verifying_key ) tx_2 = transaction.build_transaction( wallet=sender, contract='currency', function='transfer', kwargs={ 'amount': 1338, 'to': 'jeff' }, stamps=5000, nonce=0, processor=m.wallet.verifying_key ) async with httpx.AsyncClient() as client: await client.post('http://0.0.0.0:18081/', data=tx_1) await asyncio.sleep(2) await client.post('http://0.0.0.0:18081/', data=tx_2) await asyncio.sleep(2) await asyncio.sleep(2) m.stop() d.stop() self.loop.run_until_complete(test()) # dbal = dld.get_var(contract='currency', variable='balances', arguments=['jeff']) mbal = m.driver.get_var(contract='currency', variable='balances', arguments=['jeff']) # self.assertEqual(dbal, 1338) self.assertEqual(mbal, 1338) def test_startup_and_blocks_from_network_object_works(self): network = mocks.MockNetwork(ctx=self.ctx, num_of_masternodes=1, num_of_delegates=1) sender = Wallet() async def test(): await network.start() network.refresh() await network.make_and_push_tx( wallet=mocks.TEST_FOUNDATION_WALLET, contract='currency', function='transfer', kwargs={ 'amount': 1_000_000, 'to': sender.verifying_key } ) await asyncio.sleep(2) await network.make_and_push_tx( wallet=sender, contract='currency', function='transfer', kwargs={ 'amount': 1338, 'to': 'jeff' } ) await asyncio.sleep(2) await network.make_and_push_tx( wallet=sender, contract='currency', function='transfer', kwargs={ 'amount': 444, 'to': 'stu' } ) await asyncio.sleep(2) network.stop()
class TestMasternode(TestCase): def setUp(self): self.ctx = zmq.asyncio.Context() self.loop = asyncio.new_event_loop() self.driver = ContractDriver(driver=InMemDriver()) asyncio.set_event_loop(self.loop) self.authenticator = authentication.SocketAuthenticator( client=ContractingClient(driver=self.driver), ctx=self.ctx) def tearDown(self): self.authenticator.authenticator.stop() self.ctx.destroy() self.loop.close() self.driver.flush() def test_hang_returns_if_not_running(self): driver = ContractDriver(driver=InMemDriver()) node = masternode.Masternode(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) self.loop.run_until_complete(node.hang()) def test_hang_until_tx_queue_has_tx(self): driver = ContractDriver(driver=InMemDriver()) node = masternode.Masternode(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) node.running = True async def late_tx(timeout=0.2): await asyncio.sleep(timeout) node.tx_batcher.queue.append('MOCK TX') tasks = asyncio.gather(node.hang(), late_tx()) self.loop.run_until_complete(tasks) def test_hang_until_nbn_has_block(self): driver = ContractDriver(driver=InMemDriver()) node = masternode.Masternode(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) node.running = True async def late_tx(timeout=0.2): await asyncio.sleep(timeout) node.new_block_processor.q.append('MOCK BLOCK') tasks = asyncio.gather(node.hang(), late_tx()) self.loop.run_until_complete(tasks) def test_broadcast_new_chain_does_nothing_if_no_tx(self): driver = ContractDriver(driver=InMemDriver()) node = masternode.Masternode(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) node.client.set_var(contract='masternodes', variable='S', arguments=['members'], value=['stu', 'jeff']) def test_broadcast_new_chain_sends_messages_to_all_peers(self): mn_wallet = Wallet() mn_bootnode = 'tcp://127.0.0.1:18001' mn_router = router.Router(wallet=mn_wallet, socket_id=mn_bootnode, ctx=self.ctx, secure=True) dl_wallet = Wallet() dl_bootnode = 'tcp://127.0.0.1:18002' dl_router = router.Router(wallet=dl_wallet, socket_id=dl_bootnode, ctx=self.ctx, secure=True) driver = ContractDriver(driver=InMemDriver()) node = masternode.Masternode(socket_base='tcp://127.0.0.1:18003', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [mn_wallet.verifying_key], 'delegates': [dl_wallet.verifying_key] }, driver=driver) node.client.set_var(contract='masternodes', variable='S', arguments=['members'], value=[mn_wallet.verifying_key]) node.client.set_var(contract='delegates', variable='S', arguments=['members'], value=[dl_wallet.verifying_key]) node.socket_authenticator.refresh_governance_sockets() node.network.peers = { mn_wallet.verifying_key: mn_bootnode, dl_wallet.verifying_key: dl_bootnode } node.tx_batcher.queue.append('MOCK TX') tasks = asyncio.gather(mn_router.serve(), dl_router.serve(), node.broadcast_new_blockchain_started(), stop_server(mn_router, 0.2), stop_server(dl_router, 0.2)) self.loop.run_until_complete(tasks) # def test_intermediate_catchup_waits_until_key_in_governance(self): # # A subblock that will have no effect # sbs_1 = { # 'transactions': [ # { # 'stamps_used': 100, # 'state': [ # { # 'key': 'currency.balances:jeff', # 'value': 10000 # } # ], # 'transaction': { # 'payload': { # 'sender': 'jeff', # 'nonce': 0, # 'processor': 'stu' # } # } # } # ] # } # # # A subblock that will add our node to governance # node_wallet = Wallet() # sbs_2 = { # 'transactions': [ # { # 'stamps_used': 100, # 'state': [ # { # 'key': 'masternodes.S:members', # 'value': [node_wallet.verifying_key] # } # ], # 'transaction': { # 'payload': { # 'sender': 'jeff', # 'nonce': 0, # 'processor': 'stu' # } # } # } # ] # } # # blocks = generate_blocks(2, subblocks=[[sbs_1], [sbs_2]]) # # driver = ContractDriver(driver=InMemDriver()) # node = masternode.Masternode( # socket_base='tcp://127.0.0.1:18003', # ctx=self.ctx, # wallet=node_wallet, # constitution={ # 'masternodes': [Wallet().verifying_key], # 'delegates': [Wallet().verifying_key] # }, # driver=driver # ) # # async def add_block_late(timeout=1): # await asyncio.sleep(timeout) # node.new_block_processor.q.append(blocks[1]) # # node.new_block_processor.q.append(blocks[0]) # node.running = True # # tasks = asyncio.gather( # add_block_late(), # node.intermediate_catchup(), # # ) # # self.loop.run_until_complete(tasks) # # self.assertTrue(node.running) # def test_intermediate_catchup_stops_if_not_running(self): # driver = ContractDriver(driver=InMemDriver()) # node_wallet = Wallet() # node = masternode.Masternode( # socket_base='tcp://127.0.0.1:18003', # ctx=self.ctx, # wallet=node_wallet, # constitution={ # 'masternodes': [Wallet().verifying_key], # 'delegates': [Wallet().verifying_key] # }, # driver=driver # ) # # async def stop_late(timeout=1): # await asyncio.sleep(timeout) # node.stop() # # tasks = asyncio.gather( # stop_late(), # node.intermediate_catchup(), # # ) # # self.loop.run_until_complete(tasks) # # self.assertFalse(node.running) def test_send_work_returns_if_no_one_online(self): driver = ContractDriver(driver=InMemDriver()) node_wallet = Wallet() node = masternode.Masternode(socket_base='tcp://127.0.0.1:18003', ctx=self.ctx, wallet=node_wallet, constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) r = self.loop.run_until_complete(node.send_work()) self.assertFalse(r) def test_send_work_multicasts_tx_batch_to_delegates(self): ips = [ 'tcp://127.0.0.1:18001', 'tcp://127.0.0.1:18002', 'tcp://127.0.0.1:18003' ] d1w = Wallet() d2w = Wallet() m1w = Wallet() self.authenticator.add_verifying_key(d1w.verifying_key) self.authenticator.add_verifying_key(d2w.verifying_key) self.authenticator.add_verifying_key(m1w.verifying_key) self.authenticator.configure() d1_r = router.Router(socket_id=ips[0], ctx=self.ctx, wallet=d1w, secure=True) d2_r = router.Router(socket_id=ips[1], ctx=self.ctx, wallet=d2w, secure=True) d1_q = router.QueueProcessor() d2_q = router.QueueProcessor() d1_r.add_service(base.WORK_SERVICE, d1_q) d2_r.add_service(base.WORK_SERVICE, d2_q) node = masternode.Masternode( socket_base=ips[2], ctx=self.ctx, wallet=m1w, constitution={ 'masternodes': [m1w.verifying_key], 'delegates': [d1w.verifying_key, d2w.verifying_key] }, driver=self.driver) node.network.peers = { d1w.verifying_key: ips[0], d2w.verifying_key: ips[1], m1w.verifying_key: ips[2] } tasks = asyncio.gather(d1_r.serve(), d2_r.serve(), node.send_work(), stop_server(d1_r, 1), stop_server(d2_r, 1)) self.loop.run_until_complete(tasks) txb1 = d1_q.q.pop(0) txb2 = d2_q.q.pop(0) self.assertDictEqual(txb1, txb2) def test_new_blockchain_boot_hangs_then_sends_out_broadcast(self): mn_wallet = Wallet() mn_bootnode = 'tcp://127.0.0.1:18001' mn_router = router.Router(wallet=mn_wallet, socket_id=mn_bootnode, ctx=self.ctx, secure=True) dl_wallet = Wallet() dl_bootnode = 'tcp://127.0.0.1:18002' dl_router = router.Router(wallet=dl_wallet, socket_id=dl_bootnode, ctx=self.ctx, secure=True) driver = ContractDriver(driver=InMemDriver()) node = masternode.Masternode(socket_base='tcp://127.0.0.1:18003', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [mn_wallet.verifying_key], 'delegates': [dl_wallet.verifying_key] }, driver=driver) node.client.set_var(contract='masternodes', variable='S', arguments=['members'], value=[mn_wallet.verifying_key]) node.client.set_var(contract='delegates', variable='S', arguments=['members'], value=[dl_wallet.verifying_key]) node.socket_authenticator.refresh_governance_sockets() node.network.peers = { mn_wallet.verifying_key: mn_bootnode, dl_wallet.verifying_key: dl_bootnode } node.tx_batcher.queue.append('MOCK TX') node.running = True async def late_tx(timeout=0.2): await asyncio.sleep(timeout) node.tx_batcher.queue.append('MOCK TX') async def late_kill(timeout=1): node.running = False tasks = asyncio.gather(mn_router.serve(), dl_router.serve(), late_tx(), node.new_blockchain_boot(), late_kill(), stop_server(mn_router, 1), stop_server(dl_router, 1)) self.loop.run_until_complete(tasks)
class TestAtomicSwapContract(TestCase): def setUp(self): self.d = ContractDriver() self.d.flush() with open(contracting.__path__[0] + '/contracts/submission.s.py') as f: contract = f.read() self.d.set_contract(name='submission', code=contract) self.d.commit() self.e = Executor(currency_contract='erc20_clone', metering=False) environment = {'now': Datetime(2019, 1, 1)} self.e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file('./test_contracts/erc20_clone.s.py'), environment=environment) self.e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file('./test_contracts/atomic_swaps.s.py')) def tearDown(self): self.e.bypass_privates = False self.d.flush() def test_initiate_not_enough_approved(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) output = self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5000000 }) self.assertEqual(output['status_code'], 1) self.assertTrue(isinstance(output['result'], AssertionError)) def test_initiate_transfers_coins_correctly(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) atomic_swaps = self.e.execute('stu', 'erc20_clone', 'balance_of', kwargs={'account':'atomic_swaps'}) stu = self.e.execute('stu', 'erc20_clone', 'balance_of', kwargs={'account': 'stu'}) stu_as = self.e.execute('stu', 'erc20_clone', 'allowance', kwargs={'owner': 'stu', 'spender': 'atomic_swaps'}) self.assertEqual(atomic_swaps['result'], 5) self.assertEqual(stu['result'], 999995) self.assertEqual(stu_as['result'], 999995) def test_initiate_writes_to_correct_key_and_properly(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}, auto_commit=True) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }, auto_commit=True) key = 'atomic_swaps.swaps:raghu:eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514' expiration, amount = self.d.get(key) self.assertEqual(expiration, Datetime(2020, 1, 1)) self.assertEqual(amount, 5) def test_redeem_on_wrong_secret_fails(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) output = self.e.execute('raghu', 'atomic_swaps', 'redeem', kwargs={'secret': '00'}) self.assertEqual(output['status_code'], 1) self.assertEqual(str(output['result']), 'Incorrect sender or secret passed.') def test_redeem_on_wrong_sender_fails(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) output = self.e.execute('stu', 'atomic_swaps', 'redeem', kwargs={'secret': '842b65a7d48e3a3c3f0e9d37eaced0b2'}) # status_code, result, stamps_used self.assertEqual(output['status_code'], 1) self.assertEqual(str(output['result']), 'Incorrect sender or secret passed.') def test_past_expiration_fails(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) environment = {'now': Datetime(2021, 1, 1)} output = self.e.execute('raghu', 'atomic_swaps', 'redeem', kwargs={'secret': '842b65a7d48e3a3c3f0e9d37eaced0b2'}, environment=environment) self.assertEqual(output['status_code'], 1) self.assertEqual(str(output['result']), 'Swap has expired.') def test_successful_redeem_transfers_coins_correctly(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) environment = {'now': Datetime(2019, 1, 1)} self.e.execute('raghu', 'atomic_swaps', 'redeem', kwargs={'secret': '842b65a7d48e3a3c3f0e9d37eaced0b2'}, environment=environment) atomic_swaps = self.e.execute('stu', 'erc20_clone', 'balance_of', kwargs={'account': 'atomic_swaps'}) raghu = self.e.execute('stu', 'erc20_clone', 'balance_of', kwargs={'account': 'raghu'}) self.assertEqual(raghu['result'], 5) self.assertEqual(atomic_swaps['result'], 0) def test_successful_redeem_deletes_entry(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) environment = {'now': Datetime(2019, 1, 1)} self.e.execute('raghu', 'atomic_swaps', 'redeem', kwargs={'secret': '842b65a7d48e3a3c3f0e9d37eaced0b2'}, environment=environment) key = 'atomic_swaps.swaps:raghu:eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514' v = self.d.get(key) self.assertEqual(v, None) def test_refund_works(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) environment = {'now': Datetime(2021, 1, 1)} self.e.execute('stu', 'atomic_swaps', 'refund', kwargs={'participant': 'raghu', 'secret': '842b65a7d48e3a3c3f0e9d37eaced0b2'}, environment=environment) atomic_swaps = self.e.execute('stu', 'erc20_clone', 'balance_of', kwargs={'account': 'atomic_swaps'}) stu = self.e.execute('stu', 'erc20_clone', 'balance_of', kwargs={'account': 'stu'}) self.assertEqual(stu['result'], 1000000) self.assertEqual(atomic_swaps['result'], 0) def test_refund_too_early_fails(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) environment = {'now': Datetime(2019, 1, 1)} res = self.e.execute('stu', 'atomic_swaps', 'refund', kwargs={'participant': 'raghu', 'secret': '842b65a7d48e3a3c3f0e9d37eaced0b2'}, environment=environment) self.assertEqual(str(res['result']), 'Swap has not expired.') def test_refund_participant_is_signer_fails(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) environment = {'now': Datetime(2021, 1, 1)} res = self.e.execute('raghu', 'atomic_swaps', 'refund', kwargs={'participant': 'raghu', 'secret': '842b65a7d48e3a3c3f0e9d37eaced0b2'}, environment=environment) self.assertEqual(str(res['result']), 'Caller and signer cannot issue a refund.') def test_refund_fails_with_wrong_secret(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) environment = {'now': Datetime(2019, 1, 1)} res = self.e.execute('stu', 'atomic_swaps', 'refund', kwargs={'participant': 'raghu', 'secret': '00'}, environment=environment) self.assertEqual(str(res['result']), 'No swap to refund found.') def test_refund_resets_swaps(self): self.e.execute('stu', 'erc20_clone', 'approve', kwargs={'amount': 1000000, 'to': 'atomic_swaps'}) self.e.execute('stu', 'atomic_swaps', 'initiate', kwargs={ 'participant': 'raghu', 'expiration': Datetime(2020, 1, 1), 'hashlock': 'eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514', 'amount': 5 }) environment = {'now': Datetime(2021, 1, 1)} self.e.execute('stu', 'atomic_swaps', 'refund', kwargs={'participant': 'raghu', 'secret': '842b65a7d48e3a3c3f0e9d37eaced0b2'}, environment=environment) key = 'atomic_swaps.swaps:raghu:eaf48a02d3a4bb3aeb0ecb337f6efb026ee0bbc460652510cff929de78935514' v = self.d.get(key) self.assertEqual(v, None) def test_trying_to_call_private_function_fails(self): with self.assertRaises(AssertionError): self.e.execute('stu', 'atomic_swaps', '__test', kwargs={}) self.e.bypass_privates = True self.e.execute('stu', 'atomic_swaps', '__test', kwargs={})
class TestFullFlowWithMocks(TestCase): def setUp(self): self.ctx = zmq.asyncio.Context() self.loop = asyncio.new_event_loop() self.driver = ContractDriver(driver=InMemDriver()) self.client = ContractingClient(driver=self.driver) self.client.flush() asyncio.set_event_loop(self.loop) def tearDown(self): self.client.flush() self.driver.flush() self.ctx.destroy() self.loop.close() def test_process_two_tx(self): network = mocks.MockNetwork(num_of_masternodes=2, num_of_delegates=2, ctx=self.ctx) stu = Wallet() stu2 = Wallet() candidate = Wallet() candidate2 = Wallet() N_tx = 3 w_stu = [] for k in range(N_tx): w_stu.append(Wallet()) async def test(): await network.start() network.refresh() await network.make_and_push_tx(wallet=mocks.TEST_FOUNDATION_WALLET, contract='currency', function='transfer', kwargs={ 'amount': 1_000_000, 'to': w_stu[0].verifying_key }) # for k in range(1,N_tx): # await network.make_and_push_tx( # wallet=mocks.TEST_FOUNDATION_WALLET, # contract='currency', # function='transfer', # kwargs={ # 'amount': 2, # 'to': w_stu[0].verifying_key # } # ) for k1 in range(N_tx - 1): # await asyncio.sleep(1) k = N_tx - k1 - 2 await network.make_and_push_tx( wallet=w_stu[k], contract='currency', function='transfer', kwargs={ 'amount': 10, 'to': w_stu[k + 1].verifying_key }, ) await asyncio.sleep(2) self.assertEqual( network.get_var(contract='currency', variable='balances', arguments=[w_stu[N_tx - 1].verifying_key]), 10)
contract_code = file.read() return { 'name': contract_name, 'code': contract_code, } TEST_SUBMISSION_KWARGS = { 'sender': 'stu', 'contract_name': 'submission', 'function_name': 'submit_contract' } d = ContractDriver() d.flush() with open('../../contracting/contracts/submission.s.py') as f: contract = f.read() d.set_contract(name='submission', code=contract, author='sys') d.commit() recipients = [secrets.token_hex(16) for _ in range(1000)] e = Executor() e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( '../integration/test_contracts/erc20_clone.s.py'))
class TestDelegate(TestCase): def setUp(self): self.ctx = zmq.asyncio.Context() self.loop = asyncio.new_event_loop() self.driver = ContractDriver(driver=InMemDriver()) self.client = ContractingClient(driver=self.driver) self.client.flush() asyncio.set_event_loop(self.loop) self.authenticator = authentication.SocketAuthenticator( client=self.client, ctx=self.ctx ) def tearDown(self): self.client.flush() self.driver.flush() self.authenticator.authenticator.stop() self.ctx.destroy() self.loop.close() def test_execute_tx_returns_successful_output(self): test_contract = ''' v = Variable() @construct def seed(): v.set('hello') @export def set(var: str): v.set(var) @export def get(): return v.get() ''' self.client.submit(test_contract, name='testing') self.client.raw_driver.commit() self.client.raw_driver.clear_pending_state() stu = Wallet() tx = transaction.build_transaction( wallet=stu, contract='testing', function='set', kwargs={'var': 'jeff'}, stamps=100_000, processor='0' * 64, nonce=0 ) e = execution.SerialExecutor(executor=self.client.executor) result = e.execute_tx(decode(tx), stamp_cost=20_000) self.assertEqual(result['status'], 0) self.assertEqual(result['state'][0]['key'], 'testing.v') self.assertEqual(result['state'][0]['value'], 'jeff') self.assertEqual(result['stamps_used'], 1) def test_stamp_deduction_on_fail(self): test_contract = ''' @export def eat_stamps(): while True: pass ''' self.client.submit(test_contract, name='testing') self.client.raw_driver.commit() self.client.raw_driver.clear_pending_state() stu = Wallet() self.client.raw_driver.set(f'currency.balances:{stu.verifying_key}', 100000) tx = transaction.build_transaction( wallet=stu, contract='testing', function='eat_stamps', kwargs={}, stamps=10000, processor='0' * 64, nonce=0 ) e = execution.SerialExecutor(executor=self.client.executor) self.client.executor.metering = True result = e.execute_tx(decode(tx), stamp_cost=200) self.assertEqual(result['status'], 1) self.assertEqual(result['state'][0]['key'], f'currency.balances:{stu.verifying_key}') self.assertEqual(result['state'][0]['value'], Decimal('99950.0')) self.assertEqual(result['stamps_used'], 10000) def test_generate_environment_creates_datetime_wrapped_object(self): timestamp = int(time.time()) exe = execution.SerialExecutor(executor=self.client.executor) e = exe.generate_environment(self.client.raw_driver, timestamp, 'A' * 64) t = datetime.utcfromtimestamp(timestamp) #self.assertEqual(type(e['now']), Datetime) self.assertEqual(e['now'].year, t.year) self.assertEqual(e['now'].month, t.month) self.assertEqual(e['now'].day, t.day) self.assertEqual(e['now'].hour, t.hour) self.assertEqual(e['now'].minute, t.minute) self.assertEqual(e['now'].second, t.second) def test_generate_environment_creates_input_hash(self): timestamp = time.time() exe = execution.SerialExecutor(executor=self.client.executor) e = exe.generate_environment(self.client.raw_driver, timestamp, 'A' * 64) self.assertEqual(e['__input_hash'], 'A' * 64) def test_generate_environment_creates_block_hash(self): timestamp = time.time() exe = execution.SerialExecutor(executor=self.client.executor) e = exe.generate_environment(self.client.raw_driver, timestamp, 'A' * 64) self.assertEqual(e['block_hash'], storage.get_latest_block_hash(self.client.raw_driver)) def test_generate_environment_creates_block_num(self): timestamp = time.time() exe = execution.SerialExecutor(executor=self.client.executor) e = exe.generate_environment(self.client.raw_driver, timestamp, 'A' * 64) self.assertEqual(e['block_num'], storage.get_latest_block_height(self.client.raw_driver) + 1) def test_execute_tx_batch_returns_all_transactions(self): test_contract = ''' v = Variable() @construct def seed(): v.set('hello') @export def set(var: str): v.set(var) @export def get(): return v.get() ''' self.client.submit(test_contract, name='testing') self.client.raw_driver.commit() self.client.raw_driver.clear_pending_state() stu = Wallet() tx = transaction.build_transaction( wallet=stu, contract='testing', function='set', kwargs={'var': 'howdy'}, stamps=100_000, processor='0' * 64, nonce=0 ) tx = decode(tx) tx2 = transaction.build_transaction( wallet=stu, contract='testing', function='get', kwargs={}, stamps=100_000, processor='0' * 64, nonce=0 ) tx2 = decode(tx2) tx_batch = { 'transactions': [tx, tx2] } e = execution.SerialExecutor(executor=self.client.executor) results = e.execute_tx_batch( driver=self.client.raw_driver, batch=tx_batch, timestamp=time.time(), input_hash='A' * 64, stamp_cost=20_000 ) td1, td2 = results self.assertEqual(td1['status'], 0) self.assertEqual(td1['state'][0]['key'], 'testing.v') self.assertEqual(td1['state'][0]['value'], 'howdy') self.assertEqual(td1['stamps_used'], 1) self.assertEqual(td2['status'], 0) self.assertEqual(len(td2['state']), 0) self.assertEqual(td2['stamps_used'], 1) def test_execute_tx_batch_returns_all_transactions_4_in_order(self): test_contract = ''' v = Variable() @construct def seed(): v.set('hello') @export def set(var: str): v.set(var) @export def get(): return v.get() ''' self.client.submit(test_contract, name='testing') self.client.raw_driver.commit() self.client.raw_driver.clear_pending_state() stu = Wallet() tx = transaction.build_transaction( wallet=stu, contract='testing', function='set', kwargs={'var': 'howdy'}, stamps=100_000, processor='0' * 64, nonce=0 ) tx = decode(tx) tx2 = transaction.build_transaction( wallet=stu, contract='testing', function='get', kwargs={}, stamps=100_000, processor='0' * 64, nonce=0 ) tx2 = decode(tx2) tx3 = transaction.build_transaction( wallet=stu, contract='testing', function='set', kwargs={'var': 'something'}, stamps=100_000, processor='0' * 64, nonce=0 ) tx3 = decode(tx3) tx4 = transaction.build_transaction( wallet=stu, contract='testing', function='set', kwargs={'var': 'something2'}, stamps=100_000, processor='0' * 64, nonce=0 ) tx4 = decode(tx4) tx_batch = { 'transactions': [tx, tx2, tx3, tx4] } e = execution.SerialExecutor(executor=self.client.executor) results = e.execute_tx_batch( driver=self.client.raw_driver, batch=tx_batch, timestamp=time.time(), input_hash='A' * 64, stamp_cost=20_000 ) td1, td2, td3, td4 = results self.assertEqual(td1['status'], 0) self.assertEqual(td1['state'][0]['key'], 'testing.v') self.assertEqual(td1['state'][0]['value'], 'howdy') self.assertEqual(td1['stamps_used'], 1) self.assertEqual(td2['status'], 0) self.assertEqual(len(td2['state']), 0) self.assertEqual(td2['stamps_used'], 1) self.assertEqual(td3['status'], 0) self.assertEqual(td3['state'][0]['key'], 'testing.v') self.assertEqual(td3['state'][0]['value'], 'something') self.assertEqual(td3['stamps_used'], 1) self.assertEqual(td4['status'], 0) self.assertEqual(td4['state'][0]['key'], 'testing.v') self.assertEqual(td4['state'][0]['value'], 'something2') self.assertEqual(td4['stamps_used'], 1) def test_execute_work_multiple_transaction_batches_works(self): test_contract = ''' v = Variable() @construct def seed(): v.set('hello') @export def set(var: str): v.set(var) @export def get(): return v.get() ''' self.client.submit(test_contract, name='testing') self.client.raw_driver.commit() self.client.raw_driver.clear_pending_state() stu = Wallet() tx1_1 = transaction.build_transaction( wallet=stu, contract='testing', function='set', kwargs={'var': 'howdy'}, stamps=100_000, processor='0' * 64, nonce=0 ) tx1_1 = decode(tx1_1) tx1_2 = transaction.build_transaction( wallet=stu, contract='testing', function='get', kwargs={}, stamps=100_000, processor='0' * 64, nonce=0 ) tx1_2 = decode(tx1_2) tx_batch_1 = { 'transactions': [tx1_1, tx1_2], 'timestamp': time.time(), 'input_hash': 'C' * 64 } tx2_1 = transaction.build_transaction( wallet=stu, contract='testing', function='set', kwargs={'var': '123'}, stamps=100_000, processor='0' * 64, nonce=0 ) tx2_1 = decode(tx2_1) jeff = Wallet() tx2_2 = transaction.build_transaction( wallet=jeff, contract='testing', function='set', kwargs={'var': 'poo'}, stamps=100_000, processor='0' * 64, nonce=0 ) tx2_2 = decode(tx2_2) tx_batch_2 = { 'transactions': [tx2_1, tx2_2], 'timestamp': time.time(), 'input_hash': 'A' * 64 } work = [tx_batch_1, tx_batch_2] exe = execution.SerialExecutor(executor=self.client.executor) results = exe.execute_work( driver=self.client.raw_driver, work=work, previous_block_hash='B' * 64, wallet=Wallet(), stamp_cost=20_000 ) sb1, sb2 = results td1, td2 = sb1['transactions'] self.assertEqual(td1['status'], 0) self.assertEqual(td1['state'][0]['key'], 'testing.v') self.assertEqual(td1['state'][0]['value'], 'howdy') self.assertEqual(td1['stamps_used'], 1) self.assertEqual(td2['status'], 0) self.assertEqual(len(td2['state']), 0) self.assertEqual(td2['stamps_used'], 1) self.assertEqual(sb1['input_hash'], tx_batch_1['input_hash']) self.assertEqual(sb1['subblock'], 0) self.assertEqual(sb1['previous'], 'B' * 64) td1, td2 = sb2['transactions'] self.assertEqual(td1['status'], 0) self.assertEqual(td1['state'][0]['key'], 'testing.v') self.assertEqual(td1['state'][0]['value'], '123') self.assertEqual(td1['stamps_used'], 1) self.assertEqual(td2['status'], 0) self.assertEqual(td2['state'][0]['key'], 'testing.v') self.assertEqual(td2['state'][0]['value'], 'poo') self.assertEqual(td2['stamps_used'], 1) self.assertEqual(sb2['input_hash'], tx_batch_2['input_hash']) self.assertEqual(sb2['subblock'], 1) self.assertEqual(sb2['previous'], 'B' * 64) def test_no_txs_merklizes_and_signs_input_hash(self): tx_batch_1 = { 'transactions': [], 'timestamp': time.time(), 'input_hash': 'A' * 64 } work = [tx_batch_1] w = Wallet() exe = execution.SerialExecutor(executor=self.client.executor) results = exe.execute_work( driver=self.client.raw_driver, work=work, previous_block_hash='B' * 64, wallet=w, stamp_cost=20_000 ) self.assertTrue(verify(w.verifying_key, results[0]['input_hash'], results[0]['merkle_tree']['signature'])) h = hashlib.sha3_256() h.update(bytes.fromhex(results[0]['input_hash'])) self.assertEqual(h.hexdigest(), results[0]['merkle_tree']['leaves'][0]) def test_acquire_work_1_master_gathers_tx_batches(self): ips = [ 'tcp://127.0.0.1:18001', 'tcp://127.0.0.1:18002' ] dw = Wallet() mw = Wallet() self.authenticator.add_verifying_key(mw.verifying_key) self.authenticator.add_verifying_key(dw.verifying_key) self.authenticator.configure() mn = masternode.Masternode( socket_base=ips[0], ctx=self.ctx, wallet=mw, constitution={ 'masternodes': [mw.verifying_key], 'delegates': [dw.verifying_key] }, driver=ContractDriver(driver=InMemDriver()) ) dl = delegate.Delegate( socket_base=ips[1], ctx=self.ctx, wallet=dw, constitution={ 'masternodes': [mw.verifying_key], 'delegates': [dw.verifying_key] }, driver=ContractDriver(driver=InMemDriver()) ) peers = { mw.verifying_key: ips[0], dw.verifying_key: ips[1] } mn.network.peers = peers dl.network.peers = peers tasks = asyncio.gather( mn.router.serve(), dl.router.serve(), mn.send_work(), dl.acquire_work(), stop_server(mn.router, 1), stop_server(dl.router, 1), ) _, _, _, w, _, _ = self.loop.run_until_complete(tasks) self.assertEqual(len(w), 1) self.assertEqual(w[0]['sender'], mw.verifying_key) def test_acquire_work_2_masters_gathers_tx_batches_pads_work_and_waits_if_missing(self): ips = [ 'tcp://127.0.0.1:18001', 'tcp://127.0.0.1:18002' ] dw = Wallet() mw = Wallet() mw2 = Wallet() self.authenticator.add_verifying_key(mw.verifying_key) self.authenticator.add_verifying_key(dw.verifying_key) self.authenticator.configure() mn = masternode.Masternode( socket_base=ips[0], ctx=self.ctx, wallet=mw, constitution={ 'masternodes': [mw.verifying_key, mw2.verifying_key], 'delegates': [dw.verifying_key] }, driver=ContractDriver(driver=InMemDriver()) ) dl = delegate.Delegate( socket_base=ips[1], ctx=self.ctx, wallet=dw, constitution={ 'masternodes': [mw.verifying_key, mw2.verifying_key], 'delegates': [dw.verifying_key] }, driver=ContractDriver(driver=InMemDriver()) ) peers = { mw.verifying_key: ips[0], dw.verifying_key: ips[1], mw2.verifying_key: 'tpc://127.0.0.1:18003' } mn.network.peers = peers dl.network.peers = peers tasks = asyncio.gather( mn.router.serve(), dl.router.serve(), mn.send_work(), dl.acquire_work(), stop_server(mn.router, 1), stop_server(dl.router, 1), ) _, _, _, w, _, _ = self.loop.run_until_complete(tasks) self.assertEqual(len(w), 2) self.assertEqual(w[0]['sender'], mw.verifying_key) self.assertEqual(w[1]['sender'], mw2.verifying_key) self.assertEqual(w[1]['input_hash'], mw2.verifying_key) self.assertEqual(w[1]['signature'], '0' * 128) def test_process_new_work_processes_tx_batch(self): ips = [ 'tcp://127.0.0.1:18001', 'tcp://127.0.0.1:18002' ] dw = Wallet() mw = Wallet() self.authenticator.add_verifying_key(mw.verifying_key) self.authenticator.add_verifying_key(dw.verifying_key) self.authenticator.configure() mn = masternode.Masternode( socket_base=ips[0], ctx=self.ctx, wallet=mw, constitution={ 'masternodes': [mw.verifying_key], 'delegates': [dw.verifying_key] }, driver=ContractDriver(driver=InMemDriver()) ) mnq = router.QueueProcessor() mn.router.add_service(base.CONTENDER_SERVICE, mnq) dl = delegate.Delegate( socket_base=ips[1], ctx=self.ctx, wallet=dw, constitution={ 'masternodes': [mw.verifying_key], 'delegates': [dw.verifying_key] }, driver=ContractDriver(driver=InMemDriver()) ) peers = { mw.verifying_key: ips[0], dw.verifying_key: ips[1] } mn.network.peers = peers dl.network.peers = peers tasks = asyncio.gather( mn.router.serve(), dl.router.serve(), mn.send_work(), dl.process_new_work(), stop_server(mn.router, 1), stop_server(dl.router, 1), ) self.loop.run_until_complete(tasks) sbc = mnq.q.pop(0) self.assertEqual(len(sbc), 1) self.assertEqual(sbc[0]['previous'], '0' * 64) self.assertEqual(sbc[0]['signer'], dw.verifying_key) def test_masternode_delegate_single_loop_works(self): ips = [ 'tcp://127.0.0.1:18001', 'tcp://127.0.0.1:18002' ] dw = Wallet() mw = Wallet() self.authenticator.add_verifying_key(mw.verifying_key) self.authenticator.add_verifying_key(dw.verifying_key) self.authenticator.configure() mn = masternode.Masternode( socket_base=ips[0], ctx=self.ctx, wallet=mw, constitution={ 'masternodes': [mw.verifying_key], 'delegates': [dw.verifying_key] }, driver=ContractDriver(driver=InMemDriver()) ) dl = delegate.Delegate( socket_base=ips[1], ctx=self.ctx, wallet=dw, constitution={ 'masternodes': [mw.verifying_key], 'delegates': [dw.verifying_key] }, driver=ContractDriver(driver=InMemDriver()) ) peers = { mw.verifying_key: ips[0], dw.verifying_key: ips[1] } mn.network.peers = peers dl.network.peers = peers tasks = asyncio.gather( mn.router.serve(), dl.router.serve(), mn.loop(), dl.loop(), stop_server(mn.router, 1), stop_server(dl.router, 1), ) self.loop.run_until_complete(tasks) # sbc = mnq.q.pop(0) # # self.assertEqual(len(sbc), 1) # self.assertEqual(sbc[0]['previous'], '0' * 64) # self.assertEqual(sbc[0]['signer'], dw.verifying_key) # def test_masternode_delegate_single_loop_commits_state_changes(self): # ips = [ # 'tcp://127.0.0.1:18001', # 'tcp://127.0.0.1:18002' # ] # # dw = Wallet() # mw = Wallet() # # self.authenticator.add_verifying_key(mw.verifying_key) # self.authenticator.add_verifying_key(dw.verifying_key) # self.authenticator.configure() # # mnd = ContractDriver(driver=InMemDriver()) # mn = masternode.Masternode( # socket_base=ips[0], # ctx=self.ctx, # wallet=mw, # constitution={ # 'masternodes': [mw.verifying_key], # 'delegates': [dw.verifying_key] # }, # driver=mnd # ) # sender = Wallet() # mnd.set_var(contract='currency', variable='balances', arguments=[sender.verifying_key], value=1_000_000) # # dld = ContractDriver(driver=InMemDriver()) # dld.set_var(contract='currency', variable='balances', arguments=[sender.verifying_key], value=1_000_000) # dl = delegate.Delegate( # socket_base=ips[1], # ctx=self.ctx, # wallet=dw, # constitution={ # 'masternodes': [mw.verifying_key], # 'delegates': [dw.verifying_key] # }, # driver=dld # ) # # tx = transaction.build_transaction( # wallet=sender, # contract='currency', # function='transfer', # kwargs={ # 'amount': 1338, # 'to': 'jeff' # }, # stamps=5000, # nonce=0, # processor=mw.verifying_key # ) # # tx_decoded = decode(tx) # mn.tx_batcher.queue.append(tx_decoded) # # peers = { # mw.verifying_key: ips[0], # dw.verifying_key: ips[1] # } # # mn.network.peers = peers # dl.network.peers = peers # # tasks = asyncio.gather( # mn.router.serve(), # dl.router.serve(), # mn.loop(), # dl.loop(), # stop_server(mn.router, 1), # stop_server(dl.router, 1), # ) # # self.loop.run_until_complete(tasks) # # dbal = dld.get_var(contract='currency', variable='balances', arguments=['jeff']) # mbal = mnd.get_var(contract='currency', variable='balances', arguments=['jeff']) # # self.assertEqual(dbal, 1338) # self.assertEqual(mbal, 1338) def test_masternode_delegate_single_loop_updates_block_num(self): ips = [ 'tcp://127.0.0.1:18001', 'tcp://127.0.0.1:18002' ] dw = Wallet() mw = Wallet() self.authenticator.add_verifying_key(mw.verifying_key) self.authenticator.add_verifying_key(dw.verifying_key) self.authenticator.configure() mnd = ContractDriver(driver=InMemDriver()) mn = masternode.Masternode( socket_base=ips[0], ctx=self.ctx, wallet=mw, constitution={ 'masternodes': [mw.verifying_key], 'delegates': [dw.verifying_key] }, driver=mnd ) sender = Wallet() mnd.set_var(contract='currency', variable='balances', arguments=[sender.verifying_key], value=1_000_000) dld = ContractDriver(driver=InMemDriver()) dld.set_var(contract='currency', variable='balances', arguments=[sender.verifying_key], value=1_000_000) dl = delegate.Delegate( socket_base=ips[1], ctx=self.ctx, wallet=dw, constitution={ 'masternodes': [mw.verifying_key], 'delegates': [dw.verifying_key] }, driver=dld ) tx = transaction.build_transaction( wallet=sender, contract='currency', function='transfer', kwargs={ 'amount': 1338, 'to': 'jeff' }, stamps=5000, nonce=0, processor=mw.verifying_key ) tx_decoded = decode(tx) mn.tx_batcher.queue.append(tx_decoded) peers = { mw.verifying_key: ips[0], dw.verifying_key: ips[1] } mn.network.peers = peers dl.network.peers = peers tasks = asyncio.gather( mn.router.serve(), dl.router.serve(), mn.loop(), dl.loop(), stop_server(mn.router, 1), stop_server(dl.router, 1), ) self.loop.run_until_complete(tasks) dh = storage.get_latest_block_height(dld) mh = storage.get_latest_block_height(mnd) self.assertEqual(dh, 1) self.assertEqual(mh, 1)
class TestUpdatingState(TestCase): def setUp(self): self.driver = ContractDriver() self.nonces = storage.NonceStorage() self.nonces.flush() self.driver.flush() self.driver.clear_pending_state() def tearDown(self): self.nonces.flush() self.driver.flush() self.driver.clear_pending_state() def test_state_updated_to_correct_values_in_tx(self): v1 = self.driver.get('hello', mark=False) v2 = self.driver.get('name', mark=False) self.assertIsNone(v1) self.assertIsNone(v2) storage.update_state_with_transaction(tx=tx_1, driver=self.driver, nonces=self.nonces) v1 = self.driver.get('hello', mark=False) v2 = self.driver.get('name', mark=False) self.assertEqual(v1, 'there') self.assertEqual(v2, 'jeff') def test_nonces_set_to_tx_value(self): n = self.nonces.get_latest_nonce(sender='abc', processor='def') self.assertEqual(n, 0) storage.update_state_with_transaction(tx=tx_1, driver=self.driver, nonces=self.nonces) n = self.nonces.get_latest_nonce(sender='abc', processor='def') self.assertEqual(n, 124) def test_nonces_deleted_after_all_updates(self): self.nonces.set_pending_nonce(sender='abc', processor='def', value=122) n = self.nonces.get_pending_nonce(sender='abc', processor='def') self.assertEqual(n, 122) storage.update_state_with_transaction(tx=tx_1, driver=self.driver, nonces=self.nonces) n = self.nonces.get_pending_nonce(sender='abc', processor='def') self.assertEqual(n, None) def test_multiple_txs_deletes_multiple_nonces(self): self.nonces.set_pending_nonce(sender='abc', processor='def', value=122) n = self.nonces.get_pending_nonce(sender='abc', processor='def') self.assertEqual(n, 122) self.nonces.set_pending_nonce(sender='xxx', processor='yyy', value=4) n = self.nonces.get_pending_nonce(sender='xxx', processor='yyy') self.assertEqual(n, 4) storage.update_state_with_transaction(tx=tx_1, driver=self.driver, nonces=self.nonces) storage.update_state_with_transaction(tx=tx_2, driver=self.driver, nonces=self.nonces) storage.update_state_with_transaction(tx=tx_3, driver=self.driver, nonces=self.nonces) n = self.nonces.get_pending_nonce(sender='abc', processor='def') self.assertEqual(n, None) n = self.nonces.get_pending_nonce(sender='xxx', processor='yyy') self.assertEqual(n, None) n = self.nonces.get_latest_nonce(sender='abc', processor='def') self.assertEqual(n, 125) n = self.nonces.get_latest_nonce(sender='xxx', processor='yyy') self.assertEqual(n, 43) def test_multiple_tx_state_updates_correctly(self): v1 = self.driver.get('hello', mark=False) v2 = self.driver.get('name', mark=False) v3 = self.driver.get('name2', mark=False) v4 = self.driver.get('another', mark=False) v5 = self.driver.get('something', mark=False) self.assertIsNone(v1) self.assertIsNone(v2) self.assertIsNone(v3) self.assertIsNone(v4) self.assertIsNone(v5) storage.update_state_with_transaction(tx=tx_1, driver=self.driver, nonces=self.nonces) storage.update_state_with_transaction(tx=tx_2, driver=self.driver, nonces=self.nonces) storage.update_state_with_transaction(tx=tx_3, driver=self.driver, nonces=self.nonces) v1 = self.driver.get('hello', mark=False) v2 = self.driver.get('name', mark=False) v3 = self.driver.get('name2', mark=False) v4 = self.driver.get('another', mark=False) v5 = self.driver.get('something', mark=False) self.assertEqual(v1, 'there2') self.assertEqual(v2, 'jeff') self.assertEqual(v3, 'jeff2') self.assertEqual(v4, 'value') self.assertEqual(v5, 'else') def test_update_with_block_sets_hash_and_height(self): _hash = storage.get_latest_block_hash(self.driver) num = storage.get_latest_block_height(self.driver) self.assertEqual(_hash, '0' * 64) self.assertEqual(num, 0) storage.update_state_with_block(block=block, driver=self.driver, nonces=self.nonces) _hash = storage.get_latest_block_hash(self.driver) num = storage.get_latest_block_height(self.driver) self.assertEqual(_hash, 'f' * 64) self.assertEqual(num, 555) def test_update_with_block_sets_nonces_correctly(self): self.nonces.set_pending_nonce(sender='abc', processor='def', value=122) n = self.nonces.get_pending_nonce(sender='abc', processor='def') self.assertEqual(n, 122) self.nonces.set_pending_nonce(sender='xxx', processor='yyy', value=4) n = self.nonces.get_pending_nonce(sender='xxx', processor='yyy') self.assertEqual(n, 4) storage.update_state_with_block(block=block, driver=self.driver, nonces=self.nonces) n = self.nonces.get_pending_nonce(sender='abc', processor='def') self.assertEqual(n, None) n = self.nonces.get_pending_nonce(sender='xxx', processor='yyy') self.assertEqual(n, None) n = self.nonces.get_latest_nonce(sender='abc', processor='def') self.assertEqual(n, 125) n = self.nonces.get_latest_nonce(sender='xxx', processor='yyy') self.assertEqual(n, 43) def test_update_state_with_block_sets_state_correctly(self): v1 = self.driver.get('hello', mark=False) v2 = self.driver.get('name', mark=False) v3 = self.driver.get('name2', mark=False) v4 = self.driver.get('another', mark=False) v5 = self.driver.get('something', mark=False) self.assertIsNone(v1) self.assertIsNone(v2) self.assertIsNone(v3) self.assertIsNone(v4) self.assertIsNone(v5) storage.update_state_with_block(block=block, driver=self.driver, nonces=self.nonces) v1 = self.driver.get('hello', mark=False) v2 = self.driver.get('name', mark=False) v3 = self.driver.get('name2', mark=False) v4 = self.driver.get('another', mark=False) v5 = self.driver.get('something', mark=False) self.assertEqual(v1, 'there2') self.assertEqual(v2, 'jeff') self.assertEqual(v3, 'jeff2') self.assertEqual(v4, 'value') self.assertEqual(v5, 'else')
class TestExecutor(TestCase): def setUp(self): self.d = ContractDriver() self.d.flush() with open('../../contracting/contracts/submission.s.py') as f: contract = f.read() self.d.set_contract(name='submission', code=contract) self.d.commit() self.compiler = ContractingCompiler() def tearDown(self): self.d.flush() def test_submission(self): e = Executor(metering=False) code = '''@export def d(): a = 1 return 1 ''' kwargs = {'name': 'stubucks', 'code': code} e.execute(**TEST_SUBMISSION_KWARGS, kwargs=kwargs, auto_commit=True) self.compiler.module_name = 'stubucks' new_code = self.compiler.parse_to_code(code) self.assertEqual(self.d.get_contract('stubucks'), new_code) def test_submission_then_function_call(self): e = Executor(metering=False) code = '''@export def d(): return 1 ''' kwargs = {'name': 'stubuckz', 'code': code} e.execute(**TEST_SUBMISSION_KWARGS, kwargs=kwargs) output = e.execute(sender='stu', contract_name='stubuckz', function_name='d', kwargs={}) self.assertEqual(output['result'], 1) self.assertEqual(output['status_code'], 0) def test_kwarg_helper(self): k = submission_kwargs_for_file( './test_contracts/test_orm_variable_contract.s.py') code = '''v = Variable() @export def set_v(i: int): v.set(i) @export def get_v(): return v.get() ''' self.assertEqual(k['name'], 'test_orm_variable_contract') self.assertEqual(k['code'], code) def test_orm_variable_sets_in_contract(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_variable_contract.s.py'), auto_commit=True) e.execute('stu', 'test_orm_variable_contract', 'set_v', kwargs={'i': 1000}, auto_commit=True) i = self.d.get('test_orm_variable_contract.v') self.assertEqual(i, 1000) def test_orm_variable_gets_in_contract(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_variable_contract.s.py')) res = e.execute('stu', 'test_orm_variable_contract', 'get_v', kwargs={}) self.assertEqual(res['result'], None) def test_orm_variable_gets_and_sets_in_contract(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_variable_contract.s.py')) e.execute('stu', 'test_orm_variable_contract', 'set_v', kwargs={'i': 1000}) res = e.execute('stu', 'test_orm_variable_contract', 'get_v', kwargs={}) self.assertEqual(res['result'], 1000) def test_orm_hash_sets_in_contract(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_hash_contract.s.py'), auto_commit=True) e.execute('stu', 'test_orm_hash_contract', 'set_h', kwargs={ 'k': 'key1', 'v': 1234 }, auto_commit=True) e.execute('stu', 'test_orm_hash_contract', 'set_h', kwargs={ 'k': 'another_key', 'v': 9999 }, auto_commit=True) key1 = self.d.get('test_orm_hash_contract.h:key1') another_key = self.d.get('test_orm_hash_contract.h:another_key') self.assertEqual(key1, 1234) self.assertEqual(another_key, 9999) def test_orm_hash_gets_in_contract(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_hash_contract.s.py')) res = e.execute('stu', 'test_orm_hash_contract', 'get_h', kwargs={'k': 'test'}) self.assertEqual(res['result'], None) def test_orm_hash_gets_and_sets_in_contract(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_hash_contract.s.py')) e.execute('stu', 'test_orm_hash_contract', 'set_h', kwargs={ 'k': 'key1', 'v': 1234 }) e.execute('stu', 'test_orm_hash_contract', 'set_h', kwargs={ 'k': 'another_key', 'v': 9999 }) key1 = e.execute('stu', 'test_orm_hash_contract', 'get_h', kwargs={'k': 'key1'}) another_key = e.execute('stu', 'test_orm_hash_contract', 'get_h', kwargs={'k': 'another_key'}) self.assertEqual(key1['result'], 1234) self.assertEqual(another_key['result'], 9999) def test_orm_foreign_variable_sets_in_contract_doesnt_work(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_variable_contract.s.py')) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_foreign_key_contract.s.py')) e.execute('stu', 'test_orm_variable_contract', 'set_v', kwargs={'i': 1000}) # this should fail status = e.execute('stu', 'test_orm_foreign_key_contract', 'set_fv', kwargs={'i': 999}) self.assertEqual(status['status_code'], 1) i = e.execute('stu', 'test_orm_variable_contract', 'get_v', kwargs={}) self.assertEqual(i['result'], 1000) def test_orm_foreign_variable_gets_in_contract(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_variable_contract.s.py')) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_foreign_key_contract.s.py')) e.execute('stu', 'test_orm_variable_contract', 'set_v', kwargs={'i': 424242}) # this should fail i = e.execute('stu', 'test_orm_foreign_key_contract', 'get_fv', kwargs={}) self.assertEqual(i['result'], 424242) def test_orm_foreign_hash_sets_in_contract_doesnt_work(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_hash_contract.s.py'), auto_commit=True) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_foreign_hash_contract.s.py'), auto_commit=True) e.execute('stu', 'test_orm_hash_contract', 'set_h', kwargs={ 'k': 'key1', 'v': 1234 }, auto_commit=True) e.execute('stu', 'test_orm_hash_contract', 'set_h', kwargs={ 'k': 'another_key', 'v': 9999 }, auto_commit=True) status_1 = e.execute('stu', 'test_orm_foreign_hash_contract', 'set_fh', kwargs={ 'k': 'key1', 'v': 5555 }, auto_commit=True) status_2 = e.execute('stu', 'test_orm_foreign_hash_contract', 'set_fh', kwargs={ 'k': 'another_key', 'v': 1000 }, auto_commit=True) key1 = self.d.get('test_orm_hash_contract.h:key1') another_key = self.d.get('test_orm_hash_contract.h:another_key') self.assertEqual(key1, 1234) self.assertEqual(another_key, 9999) self.assertEqual(status_1['status_code'], 1) self.assertEqual(status_2['status_code'], 1) def test_orm_foreign_hash_gets_and_sets_in_contract(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_hash_contract.s.py')) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_foreign_hash_contract.s.py')) e.execute('stu', 'test_orm_hash_contract', 'set_h', kwargs={ 'k': 'key1', 'v': 1234 }) e.execute('stu', 'test_orm_hash_contract', 'set_h', kwargs={ 'k': 'another_key', 'v': 9999 }) key1 = e.execute('stu', 'test_orm_foreign_hash_contract', 'get_fh', kwargs={'k': 'key1'}) another_key = e.execute('stu', 'test_orm_foreign_hash_contract', 'get_fh', kwargs={'k': 'another_key'}) self.assertEqual(key1['result'], 1234) self.assertEqual(another_key['result'], 9999) def test_orm_contract_not_accessible(self): e = Executor(metering=False) output = e.execute( **TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_orm_no_contract_access.s.py')) self.assertIsInstance(output['result'], Exception) def test_construct_function_sets_properly(self): e = Executor(metering=False) r = e.execute( **TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/test_construct_function_works.s.py')) output = e.execute('stu', 'test_construct_function_works', 'get', kwargs={}) self.assertEqual(output['result'], 42) def test_import_exported_function_works(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/import_this.s.py')) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/importing_that.s.py')) output = e.execute('stu', 'importing_that', 'test', kwargs={}) self.assertEqual(output['result'], 12345 - 1000) def test_arbitrary_environment_passing_works_via_executor(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/i_use_env.s.py')) this_is_a_passed_in_variable = 555 env = {'this_is_a_passed_in_variable': this_is_a_passed_in_variable} output = e.execute('stu', 'i_use_env', 'env_var', kwargs={}, environment=env) self.assertEqual(output['result'], this_is_a_passed_in_variable) def test_arbitrary_environment_passing_fails_if_not_passed_correctly(self): e = Executor(metering=False) e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/i_use_env.s.py')) this_is_a_passed_in_variable = 555 env = { 'this_is_another_passed_in_variable': this_is_a_passed_in_variable } output = e.execute('stu', 'i_use_env', 'env_var', kwargs={}, environment=env) self.assertEqual(output['status_code'], 1)
class TestMetering(TestCase): def setUp(self): # Hard load the submission contract self.d = ContractDriver() self.d.flush() with open(contracting.__path__[0] + '/contracts/submission.s.py') as f: contract = f.read() self.d.set_contract(name='submission', code=contract) self.d.commit() # Execute the currency contract with metering disabled self.e = Executor(driver=self.d) self.e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/currency.s.py'), metering=False, auto_commit=True) def tearDown(self): self.d.flush() def test_simple_execution_deducts_stamps(self): prior_balance = self.d.get('currency.balances:stu') output = self.e.execute('stu', 'currency', 'transfer', kwargs={ 'amount': 100, 'to': 'colin' }, auto_commit=True) new_balance = self.d.get('currency.balances:stu') self.assertEqual(float(prior_balance - new_balance - 100), output['stamps_used'] / STAMPS_PER_TAU) def test_too_few_stamps_fails_and_deducts_properly(self): prior_balance = self.d.get('currency.balances:stu') print(prior_balance) small_amount_of_stamps = 1 * STAMPS_PER_TAU output = self.e.execute('stu', 'currency', 'transfer', kwargs={ 'amount': 100, 'to': 'colin' }, stamps=small_amount_of_stamps, auto_commit=True) print(output) new_balance = self.d.get('currency.balances:stu') self.assertEqual(float(prior_balance - new_balance), output['stamps_used'] / STAMPS_PER_TAU) def test_adding_too_many_stamps_throws_error(self): prior_balance = self.d.get('currency.balances:stu') too_many_stamps = (prior_balance + 1000) * STAMPS_PER_TAU output = self.e.execute('stu', 'currency', 'transfer', kwargs={ 'amount': 100, 'to': 'colin' }, stamps=too_many_stamps, auto_commit=True) self.assertEqual(output['status_code'], 1) def test_adding_all_stamps_with_infinate_loop_eats_all_balance(self): self.d.set('currency.balances:stu', 500) self.d.commit() prior_balance = self.d.get('currency.balances:stu') prior_balance *= STAMPS_PER_TAU self.e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/inf_loop.s.py'), stamps=prior_balance, metering=True, auto_commit=True) new_balance = self.d.get('currency.balances:stu') # Not all stamps will be deducted because it will blow up in the middle of execution self.assertTrue(new_balance < 0.01) def test_submitting_contract_succeeds_with_enough_stamps(self): prior_balance = self.d.get('currency.balances:stu') print(prior_balance) output = self.e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/erc20_clone.s.py'), auto_commit=True) print(output) new_balance = self.d.get('currency.balances:stu') print(new_balance) self.assertEqual(float(prior_balance - new_balance), output['stamps_used'] / STAMPS_PER_TAU) def test_pending_writes_has_deducted_stamp_amount_prior_to_auto_commit( self): prior_balance = self.d.get('currency.balances:stu') output = self.e.execute(**TEST_SUBMISSION_KWARGS, kwargs=submission_kwargs_for_file( './test_contracts/erc20_clone.s.py'), auto_commit=False) self.assertNotEquals( self.e.driver.pending_writes['currency.balances:stu'], prior_balance)
class TestNode(TestCase): def setUp(self): self.ctx = zmq.asyncio.Context() self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.blocks = storage.BlockStorage() self.driver = ContractDriver(driver=InMemDriver()) self.b = masternode.BlockService(blocks=self.blocks, driver=self.driver) self.blocks.drop_collections() self.driver.flush() self.authenticator = authentication.SocketAuthenticator( client=ContractingClient(), ctx=self.ctx) def tearDown(self): self.authenticator.authenticator.stop() self.ctx.destroy() self.loop.close() self.b.blocks.drop_collections() self.b.driver.flush() def test_catchup(self): driver = ContractDriver(driver=InMemDriver()) dl_vk = Wallet().verifying_key mn_bootnode = 'tcp://127.0.0.1:18001' mn_wallet = Wallet() mn_router = router.Router(socket_id=mn_bootnode, ctx=self.ctx, secure=True, wallet=mn_wallet) mn_router.add_service(base.BLOCK_SERVICE, self.b) nw = Wallet() node = base.Node(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=nw, constitution={ 'masternodes': [mn_wallet.verifying_key], 'delegates': [dl_vk] }, driver=driver) self.authenticator.add_verifying_key(mn_wallet.verifying_key) self.authenticator.add_verifying_key(nw.verifying_key) self.authenticator.add_verifying_key(dl_vk) self.authenticator.configure() blocks = generate_blocks(3) self.blocks.store_block(blocks[0]) self.blocks.store_block(blocks[1]) self.blocks.store_block(blocks[2]) storage.set_latest_block_height(3, self.driver) tasks = asyncio.gather( mn_router.serve(), node.catchup('tcp://127.0.0.1:18001', mn_wallet.verifying_key), stop_server(mn_router, 2)) self.loop.run_until_complete(tasks) self.assertEqual(storage.get_latest_block_height(node.driver), 3) def test_catchup_with_nbn_added(self): driver = ContractDriver(driver=InMemDriver()) mn_bootnode = 'tcp://127.0.0.1:18001' mn_wallet = Wallet() mn_router = router.Router(socket_id=mn_bootnode, ctx=self.ctx, secure=True, wallet=mn_wallet) mn_router.add_service(base.BLOCK_SERVICE, self.b) nw = Wallet() dlw = Wallet() node = base.Node(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=nw, constitution={ 'masternodes': [mn_wallet.verifying_key], 'delegates': [dlw.verifying_key] }, driver=driver) self.authenticator.add_verifying_key(mn_wallet.verifying_key) self.authenticator.add_verifying_key(nw.verifying_key) self.authenticator.add_verifying_key(dlw.verifying_key) self.authenticator.configure() blocks = generate_blocks(4) self.blocks.store_block(blocks[0]) self.blocks.store_block(blocks[1]) self.blocks.store_block(blocks[2]) storage.set_latest_block_height(3, self.driver) node.new_block_processor.q.append(blocks[3]) tasks = asyncio.gather( mn_router.serve(), node.catchup('tcp://127.0.0.1:18001', mn_wallet.verifying_key), stop_server(mn_router, 1)) self.loop.run_until_complete(tasks) self.assertEqual(storage.get_latest_block_height(node.driver), 4) def test_should_process_block_false_if_failed_block(self): block = { 'hash': 'f' * 64, 'number': 1, 'previous': '0' * 64, 'subblocks': [] } driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) self.assertFalse(node.should_process(block)) def test_should_process_block_false_if_current_height_not_increment(self): block = { 'hash': 'a' * 64, 'number': 2, 'previous': '0' * 64, 'subblocks': [] } driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) self.assertFalse(node.should_process(block)) def test_should_process_block_false_if_previous_if_not_current_hash(self): block = { 'hash': 'a' * 64, 'number': 1, 'previous': 'b' * 64, 'subblocks': [] } driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) self.assertFalse(node.should_process(block)) def test_should_process_block_false_if_expected_block_not_equal_to_provided_block( self): block = { 'hash': 'a' * 64, 'number': 1, 'previous': '0' * 64, 'subblocks': [] } driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) self.assertFalse(node.should_process(block)) def test_should_process_block_true_if_expected_block_equal_to_block(self): block = canonical.block_from_subblocks(subblocks=[], previous_hash='0' * 64, block_num=1) driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) self.assertTrue(node.should_process(block)) def test_process_new_block_updates_state(self): block = canonical.block_from_subblocks(subblocks=[], previous_hash='0' * 64, block_num=1) driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver) node.process_new_block(block) self.assertEqual(storage.get_latest_block_height(node.driver), 1) self.assertEqual(storage.get_latest_block_hash(node.driver), block['hash']) def test_process_new_block_stores_block_if_should_store(self): block = canonical.block_from_subblocks(subblocks=[], previous_hash='0' * 64, block_num=1) driver = ContractDriver(driver=InMemDriver()) node = base.Node( socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver, store=True, blocks=self.blocks, ) node.process_new_block(block) b = node.blocks.get_block(1) self.assertEqual(b, block) def test_process_new_block_clears_cache(self): block = canonical.block_from_subblocks(subblocks=[], previous_hash='0' * 64, block_num=1) driver = ContractDriver(driver=InMemDriver()) node = base.Node( socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver, store=True, blocks=self.blocks, ) node.driver.cache['test'] = 123 node.process_new_block(block) self.assertIsNone(node.driver.cache.get('test')) def test_process_new_block_cleans_nbn(self): blocks = generate_blocks(2) driver = ContractDriver(driver=InMemDriver()) node = base.Node( socket_base='tcp://127.0.0.1:18002', ctx=self.ctx, wallet=Wallet(), constitution={ 'masternodes': [Wallet().verifying_key], 'delegates': [Wallet().verifying_key] }, driver=driver, store=True, blocks=self.blocks, ) # Add one old and one new block. # Function should only delete the old one node.new_block_processor.q.append(blocks[0]) node.new_block_processor.q.append(blocks[1]) node.process_new_block(blocks[0]) block = node.new_block_processor.q[0] self.assertEqual(block, blocks[1]) self.assertEqual(len(node.new_block_processor.q), 1) def test_start_boots_up_normally(self): # This MN will also provide 'catch up' services mn_bootnode = 'tcp://127.0.0.1:18001' mn_wallet = Wallet() mn_router = router.Router(socket_id=mn_bootnode, ctx=self.ctx, secure=True, wallet=mn_wallet) mn_network = network.Network(wallet=mn_wallet, ip_string=mn_bootnode, ctx=self.ctx, router=mn_router) blocks = generate_blocks(4) self.blocks.store_block(blocks[0]) self.blocks.store_block(blocks[1]) self.blocks.store_block(blocks[2]) storage.set_latest_block_height(3, self.driver) mn_router.add_service( base.BLOCK_SERVICE, masternode.BlockService(self.blocks, self.driver)) dl_bootnode = 'tcp://127.0.0.1:18002' dl_wallet = Wallet() dl_router = router.Router(socket_id=dl_bootnode, ctx=self.ctx, secure=True, wallet=dl_wallet) dl_network = network.Network(wallet=dl_wallet, ip_string=dl_bootnode, ctx=self.ctx, router=dl_router) constitution = { 'masternodes': [mn_wallet.verifying_key], 'delegates': [dl_wallet.verifying_key] } bootnodes = { mn_wallet.verifying_key: mn_bootnode, dl_wallet.verifying_key: dl_bootnode } node_w = Wallet() driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18003', ctx=self.ctx, wallet=node_w, constitution=constitution, driver=driver, store=False, bootnodes=bootnodes) self.authenticator.add_verifying_key(mn_wallet.verifying_key) self.authenticator.add_verifying_key(dl_wallet.verifying_key) self.authenticator.add_verifying_key(node_w.verifying_key) self.authenticator.configure() vks = [mn_wallet.verifying_key, dl_wallet.verifying_key] tasks = asyncio.gather( mn_router.serve(), dl_router.serve(), mn_network.start(bootnodes, vks), dl_network.start(bootnodes, vks), stop_server(mn_router, 0.2), stop_server(dl_router, 0.2), ) self.loop.run_until_complete(tasks) tasks = asyncio.gather(mn_router.serve(), dl_router.serve(), node.start(), stop_server(mn_router, 1), stop_server(dl_router, 1), stop_server(node.router, 1)) self.loop.run_until_complete(tasks) self.assertEqual(storage.get_latest_block_height(node.driver), 3) self.assertEqual(storage.get_latest_block_hash(node.driver), blocks[2]['hash']) def test_new_block_service_appends_to_q_to_process_msg(self): nb = base.NewBlock(driver=ContractDriver()) msg = 'test' self.loop.run_until_complete(nb.process_message(msg)) self.assertEqual(nb.q, [msg]) def test_wait_for_next_holds_until_q_len_greater_than_0(self): nb = base.NewBlock(driver=ContractDriver()) msg = 'test' async def slow_add(): await asyncio.sleep(0.5) await nb.process_message(msg) self.loop.run_until_complete(slow_add()) self.assertEqual(nb.q, [msg]) def test_wait_for_next_pops_first_in_q(self): nb = base.NewBlock(driver=ContractDriver()) msg = 'test' nb.q.append('first') tasks = asyncio.gather(nb.process_message(msg), nb.wait_for_next_nbn()) _, r = self.loop.run_until_complete(tasks) self.assertEqual(r, 'first') def test_wait_for_next_clears_q(self): nb = base.NewBlock(driver=ContractDriver()) nb.q.append('first') nb.q.append('second') nb.q.append('third') tasks = asyncio.gather(nb.wait_for_next_nbn()) self.loop.run_until_complete(tasks) self.assertEqual(nb.q, []) def test_get_member_peers_returns_vk_ip_pairs(self): mn_wallet = Wallet() dl_wallet = Wallet() mn_bootnode = 'tcp://127.0.0.1:18001' dl_bootnode = 'tcp://127.0.0.1:18002' constitution = { 'masternodes': [mn_wallet.verifying_key], 'delegates': [dl_wallet.verifying_key] } bootnodes = { mn_wallet.verifying_key: mn_bootnode, dl_wallet.verifying_key: dl_bootnode } node_w = Wallet() driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18003', ctx=self.ctx, wallet=node_w, constitution=constitution, driver=driver, store=False, bootnodes=bootnodes) # Assume caught up state node.network.peers = bootnodes m = node._get_member_peers('masternodes') d = node._get_member_peers('delegates') self.assertEqual(m, {mn_wallet.verifying_key: mn_bootnode}) self.assertEqual(d, {dl_wallet.verifying_key: dl_bootnode}) def test_get_delegate_peers_returns_deletates(self): mn_wallet = Wallet() dl_wallet = Wallet() mn_bootnode = 'tcp://127.0.0.1:18001' dl_bootnode = 'tcp://127.0.0.1:18002' constitution = { 'masternodes': [mn_wallet.verifying_key], 'delegates': [dl_wallet.verifying_key] } bootnodes = { mn_wallet.verifying_key: mn_bootnode, dl_wallet.verifying_key: dl_bootnode } node_w = Wallet() driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18003', ctx=self.ctx, wallet=node_w, constitution=constitution, driver=driver, store=False, bootnodes=bootnodes) # Assume caught up state node.network.peers = bootnodes d = node.get_delegate_peers() self.assertEqual(d, {dl_wallet.verifying_key: dl_bootnode}) def test_get_masternode_peers_gets_masternodes(self): mn_wallet = Wallet() dl_wallet = Wallet() mn_bootnode = 'tcp://127.0.0.1:18001' dl_bootnode = 'tcp://127.0.0.1:18002' constitution = { 'masternodes': [mn_wallet.verifying_key], 'delegates': [dl_wallet.verifying_key] } bootnodes = { mn_wallet.verifying_key: mn_bootnode, dl_wallet.verifying_key: dl_bootnode } node_w = Wallet() driver = ContractDriver(driver=InMemDriver()) node = base.Node(socket_base='tcp://127.0.0.1:18003', ctx=self.ctx, wallet=node_w, constitution=constitution, driver=driver, store=False, bootnodes=bootnodes) # Assume caught up state node.network.peers = bootnodes m = node.get_masternode_peers() self.assertEqual(m, {mn_wallet.verifying_key: mn_bootnode})