def test_run_bad_contract_reverts_to_last_successful_contract_remove_partial( self): """ Tests that running a failing contract reverts any database changes it made before the point of failure """ sender = ALICE_VK receiver = BOB_VK self.interpreter = SenecaInterpreter() dummy_contract = get_contract_exports(self.interpreter.ex, self.interpreter.contracts_table, contract_id='dummy') sender_initial_balance = dummy_contract.get_balance(sender) self.assertEqual(dummy_contract.get_balance(sender), sender_initial_balance) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=False)) self.interpreter.interpret(contract_tx) self.assertEqual(dummy_contract.get_balance(sender), sender_initial_balance + 500) # NOTE it attempts to update the balance to 123 and add the same user again # Updating should work and adding already added user contract_tx = self.ordered_tx( ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=True)) self.interpreter.interpret(contract_tx) self.assertEqual(dummy_contract.get_balance(sender), sender_initial_balance + 500)
def test_rerun_fail(self): orig = SenecaInterpreter._run_contract def mocked_rerun(*args, **kwargs): if kwargs.get('rerun'): return None return orig(*args, **kwargs) sender = ALICE_VK receiver = BOB_VK self.interpreter = SenecaInterpreter() dummy_contract = get_contract_exports(self.interpreter.ex, self.interpreter.contracts_table, contract_id='dummy') sender_initial_balance = dummy_contract.get_balance(sender) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=False)) self.interpreter.interpret(contract_tx) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=True)) with mock.patch( 'cilantro.protocol.interpreter.SenecaInterpreter._run_contract', side_effect=mocked_rerun, autospec=True) as mock_some_method: with self.assertRaises(Exception) as context: self.interpreter.interpret(contract_tx)
def test_flushes_with_update(self): """ Tests that calling .flush on an self.interpreter with update_state=True after interpreting several transactions successfully commits the changes to the database """ sender = ALICE_VK receiver = BOB_VK self.interpreter = SenecaInterpreter() dummy_contract = get_contract_exports(self.interpreter.ex, self.interpreter.contracts_table, contract_id='dummy') sender_initial_balance = dummy_contract.get_balance(sender) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=False)) self.interpreter.interpret(contract_tx) self.assertEqual(dummy_contract.get_balance(sender), sender_initial_balance + 500) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=False)) self.interpreter.interpret(contract_tx) self.interpreter.flush(update_state=True) self.assertEqual(dummy_contract.get_balance(sender), sender_initial_balance + 1000)
def test_interpret_currency(self): amount = 1260 receiver = BOB_VK sender = ALICE_VK contract_tx = self.ordered_tx( ContractTransactionBuilder.create_currency_tx(sender_sk=ALICE_SK, receiver_vk=receiver, amount=amount)) self.interpreter = SenecaInterpreter() currency_contract = get_contract_exports( self.interpreter.ex, self.interpreter.contracts_table, contract_id='currency') sender_initial_balance = currency_contract.get_balance(sender) receiver_initial_balance = currency_contract.get_balance(receiver) self.interpreter.interpret(contract_tx) # Assert the contract ran and updated the expected rows self.assertEqual(currency_contract.get_balance(sender), sender_initial_balance - amount) self.assertEqual(currency_contract.get_balance(receiver), receiver_initial_balance + amount) # Assert the contract was added to the queue self.assertEqual(self.interpreter.queue_size, 1) self.assertEqual(self.interpreter.queue[0], contract_tx.transaction)
def test_check_contract_async_shuffled_adhoc_checks(self): def assertCondition(): self.assertEqual(contracts[0].transaction, self.interpreter.queue[0]) self.assertEqual(contracts[2].transaction, self.interpreter.queue[1]) self.assertEqual(contracts[1].transaction, self.interpreter.queue[2]) self.assertEqual(len(self.interpreter.queue), 3) self.interpreter.stop() sender = ALICE_VK receiver = BOB_VK now = int(time.time() * 1000) self.interpreter = SenecaInterpreter() contracts = [ self.ordered_tx(ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=False)) \ for i in range(5) ] contracts[0]._data.utcTimeMs = now - 2000 contracts[1]._data.utcTimeMs = now contracts[2]._data.utcTimeMs = now - 1000 contracts[3]._data.utcTimeMs = now + 5000 contracts[4]._data.utcTimeMs = now + 6000 for c in contracts: self.interpreter.interpret(c, async=True) t = Timer(2.8, assertCondition) t.start()
def build_test_transaction() -> TransactionBase: """ Utility method to build a random transaction (an instance of a subclass of TransactionBase). Used exclusively for unit/integration tests. :return: An instance of a subclass of TransactionBase """ from cilantro.messages.transaction.contract import ContractTransactionBuilder return ContractTransactionBuilder.random_currency_tx()
def test_creation(self): sk, vk = wallet.new() code = 'while True: do_that_thing' contract_tx = ContractTransactionBuilder.create_contract_tx( sender_sk=sk, code_str=code) self.assertEquals(contract_tx.sender, vk) self.assertEquals(contract_tx.code, code)
def test_run_bad_contract_reverts_to_last_successful_contract(self): """ Tests that running a failing contract reverts any database changes it made before the point of failure """ receiver = BOB_VK sender = ALICE_VK self.interpreter = SenecaInterpreter() currency_contract = get_contract_exports( self.interpreter.ex, self.interpreter.contracts_table, contract_id='currency') sender_initial_balance = currency_contract.get_balance(sender) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_currency_tx(sender_sk=ALICE_SK, receiver_vk=receiver, amount=1000)) self.interpreter.interpret(contract_tx) self.assertEqual(currency_contract.get_balance(sender), sender_initial_balance - 1000) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_currency_tx(sender_sk=ALICE_SK, receiver_vk=receiver, amount=200)) self.interpreter.interpret(contract_tx) self.assertEqual(currency_contract.get_balance(sender), sender_initial_balance - 1200) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_currency_tx(sender_sk=ALICE_SK, receiver_vk=receiver, amount=60)) self.interpreter.interpret(contract_tx) self.assertEqual(currency_contract.get_balance(sender), sender_initial_balance - 1260) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_currency_tx(sender_sk=ALICE_SK, receiver_vk=receiver, amount=3696947)) self.interpreter.interpret(contract_tx) self.assertEqual(currency_contract.get_balance(sender), sender_initial_balance - 1260)
def test_creation(self): """ Tests that a created block data reply has the expected properties """ sk = wallet.new()[0] contracts = [ ContractTransactionBuilder.create_contract_tx(sk, code_str) \ for code_str in ['some random binary', 'some deterministic binary', 'While True: self.eatAss()'] ] tx_binaries = [c.serialize() for c in contracts] bdr = TransactionReply.create(tx_binaries) self.assertEqual(contracts, bdr.transactions)
def test_create_currency_tx(self): sk, vk = wallet.new() sk2, vk2 = wallet.new() amount = 9000 currency_code = ContractTemplate.interpolate_template('currency', amount=amount, receiver=vk2) contract_tx = ContractTransactionBuilder.create_currency_tx( sender_sk=sk, receiver_vk=vk2, amount=amount) self.assertEquals(contract_tx.sender, vk) self.assertEquals(contract_tx.code, currency_code)
def test_restore_to_beginning(self): orig = SenecaInterpreter._run_contract sender = ALICE_VK receiver = BOB_VK self.interpreter = SenecaInterpreter() dummy_contract = get_contract_exports(self.interpreter.ex, self.interpreter.contracts_table, contract_id='dummy') sender_initial_balance = dummy_contract.get_balance(sender) contract_tx = self.ordered_tx( ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=True)) self.interpreter.interpret(contract_tx)
def test_validate_matches_request_no_match(self): """ Tests that a created block data reply has the expected properties """ sk = wallet.new()[0] code_strs = ['some random binary', 'some deterministic binary', 'While True: self.eatAss()'] contracts = [ ContractTransactionBuilder.create_contract_tx(sk, code_str) \ for code_str in code_strs ] tx_binaries = [c.serialize() for c in contracts] tx_hashes = [Hasher.hash(cs+b'bbb') for cs in tx_binaries] bdr_req = TransactionRequest.create(tx_hashes) bdr_rep = TransactionReply.create(tx_binaries) assert not bdr_rep.validate_matches_request(bdr_req)
def test_serialization(self): """ Tests that a message successfully serializes and deserializes. The deserialized object should have the same properties as the original one before it was serialized. """ sk = wallet.new()[0] code_strs = ['some random binary', 'some deterministic binary', 'While True: self.eatAss()'] contracts = [ ContractTransactionBuilder.create_contract_tx(sk, code_str) \ for code_str in code_strs ] tx_binaries = [c.serialize() for c in contracts] original = TransactionReply.create(tx_binaries) original_binary = original.serialize() clone = TransactionReply.from_bytes(original_binary) # deserialize byte object self.assertEqual(original.transactions, clone.transactions)
def test_check_contract_correct_order(self): sender = ALICE_VK receiver = BOB_VK now = int(time.time() * 1000) self.interpreter = SenecaInterpreter() contracts = [ self.ordered_tx(ContractTransactionBuilder.create_dummy_tx(sender_sk=ALICE_SK, receiver_vk=receiver, fail=False)) \ for i in range(5) ] contracts[0]._data.utcTimeMs = now - 2000 contracts[1]._data.utcTimeMs = now - 1000 contracts[2]._data.utcTimeMs = now contracts[3]._data.utcTimeMs = now + 1000 contracts[4]._data.utcTimeMs = now + 2000 for c in contracts: self.interpreter.interpret(c, async=True) self.assertEqual(contracts, [heappop(self.interpreter.heap)[1] for i in range(5)])
def test_queue_binary(self): """ Tests that queue_binary returns a list of serialized ContractTransactions """ sender = ALICE_VK receiver = BOB_VK self.interpreter = SenecaInterpreter() dummy_contract = get_contract_exports(self.interpreter.ex, self.interpreter.contracts_table, contract_id='dummy') contracts = [] for i in range(5): contract_tx = self.ordered_tx( ContractTransactionBuilder.create_dummy_tx( sender_sk=ALICE_SK, receiver_vk=receiver, fail=False)) self.interpreter.interpret(contract_tx) contracts.append(contract_tx.transaction) for actual, expected in zip([c.serialize() for c in contracts], self.interpreter.queue_binary): self.assertEqual(actual, expected)
def publisher(): SLEEP_TIME = 0.05 MAX_TIME = 10 from cilantro.logger import get_logger, overwrite_logger_level from cilantro.utils.test import MPComposer from cilantro.messages.transaction.contract import ContractTransactionBuilder from cilantro.constants.testnet import TESTNET_DELEGATES import time, os log = get_logger("Publisher") sub_info = TESTNET_DELEGATES[1] sub_info['ip'] = os.getenv('HOST_IP') d_info = TESTNET_DELEGATES[0] d_info['ip'] = os.getenv('HOST_IP') pub = MPComposer(sk=d_info['sk']) # Publish on this node's own IP pub.add_pub(os.getenv('HOST_IP')) log.important( "Starting experiment, sending messages every {} seconds for a total of {} seconds" .format(SLEEP_TIME, MAX_TIME)) elapsed_time = 0 while elapsed_time < MAX_TIME: log.notice("Sending pub") msg = ContractTransactionBuilder.random_currency_tx() pub.send_pub_msg(filter='0', message=msg) time.sleep(SLEEP_TIME) elapsed_time += SLEEP_TIME pub.teardown() log.important("Done with experiment!")