def test_signing_key_as_bytes(self): w = Wallet() _w = w.signing_key() self.assertTrue(isinstance(_w, bytes)) _h = w.signing_key(as_hex=True) self.assertTrue(isinstance(_h, str))
def test_nonce_minus_pending_nonce_equal_tx_per_block_fails(self): w = Wallet() expected_processor = secrets.token_bytes(32) balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, w.verifying_key().hex()) self.nonce_manager.set(balances_key, 500000) self.nonce_manager.set_nonce(processor=expected_processor, sender=w.verifying_key(), nonce=1) self.nonce_manager.set_pending_nonce(processor=expected_processor, sender=w.verifying_key(), nonce=16) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=16) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) with self.assertRaises(transaction.TransactionTooManyPendingException): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
def test_submission_prepended_with_con_succeeds(self): w = Wallet() expected_processor = secrets.token_bytes(32) balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, w.verifying_key().hex()) self.nonce_manager.set(balances_key, 500000) tx = TransactionBuilder(w.verifying_key(), contract='submission', function='submit_contract', kwargs={'name': 'con_bad_name', 'code': 'blah'}, stamps=3000, processor=expected_processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
def make_tx(processor, contract_name, function_name, kwargs={}): w = Wallet() batch = TransactionBuilder(sender=w.verifying_key(), contract=contract_name, function=function_name, kwargs=kwargs, stamps=10000, processor=processor, nonce=0) batch.sign(w.signing_key()) b = batch.serialize() tx = transaction_capnp.Transaction.from_bytes_packed(b) currency_contract = 'currency' balances_hash = 'balances' balances_key = '{}{}{}{}{}'.format(currency_contract, config.INDEX_SEPARATOR, balances_hash, config.DELIMITER, w.verifying_key().hex()) driver = ContractDriver() driver.set(balances_key, 1_000_000) driver.commit() return tx
def test_all_valid_with_stamps_when_balance_is_set(self): w = Wallet() expected_processor = secrets.token_bytes(32) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, tx.payload.sender.hex()) self.nonce_manager.set(balances_key, 500000) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) balance = self.nonce_manager.get(balances_key) or 0 self.assertEqual(balance, 500000)
def test_processor_and_nonce_correct_but_not_enough_stamps_returns_false(self): w = Wallet() expected_processor = secrets.token_bytes(32) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) with self.assertRaises(transaction.TransactionSenderTooFewStamps): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, tx.payload.sender.hex()) balance = self.nonce_manager.get(balances_key) or 0 self.assertEqual(balance, 0)
def test_init_wallet_with_seed_returns_deterministic_wallet(self): w = Wallet() a = Wallet(seed=w.signing_key()) self.assertEqual(w.vk, a.vk) self.assertEqual(w.sk, a.sk)
def random_packed_tx(nonce=0, processor=None, give_stamps=False): w = Wallet() processor = secrets.token_bytes(32) if processor is None else processor stamps = random.randint(100_000, 1_000_000) if give_stamps: balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, w.verifying_key().hex()) N.set(balances_key, stamps + 1000) tx = TransactionBuilder( w.verifying_key(), contract=secrets.token_hex(8), function=secrets.token_hex(8), kwargs={secrets.token_hex(8): secrets.token_hex(8)}, stamps=stamps, processor=processor, nonce=nonce) tx.sign(w.signing_key()) #tx.proof = b'\x00' * 32 #tx.proof_generated = True packed_tx = transaction_capnp.Transaction.from_bytes_packed(tx.serialize()) return packed_tx
def test_sending_transfer_of_most_money_doesnt_fail_if_enough_stamps(self): self.nonce_manager.set_var('stamp_cost', 'S', ['value'], value=3000) w = Wallet() expected_processor = secrets.token_bytes(32) balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, w.verifying_key().hex()) self.nonce_manager.set(balances_key, 500000) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 499990, 'to': 'jeff'}, stamps=3000, processor=expected_processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
def build_nodes(num_nodes=1) -> list: nodes = [] for i in range(num_nodes): i = Wallet() nodes.append({ 'sk': i.signing_key(as_hex=True), 'vk': i.verifying_key(as_hex=True) }) print(nodes)
def test_non_strict_fails_if_same_nonce(self): w = Wallet() expected_processor = secrets.token_bytes(32) balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, w.verifying_key().hex()) self.nonce_manager.set(balances_key, 500000) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager, strict=False) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) with self.assertRaises(transaction.TransactionNonceInvalid): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager, strict=False)
def get_tx_batch(): w = Wallet() tx = TransactionBuilder( sender='stu', contract='testing', function='set', kwargs={'var': 'howdy'}, stamps=100_000, processor=b'\x00' * 32, nonce=0 ) tx.sign(w.signing_key()) tx.serialize() currency_contract = 'currency' balances_hash = 'balances' balances_key = '{}{}{}{}{}'.format(currency_contract, config.INDEX_SEPARATOR, balances_hash, config.DELIMITER, w.verifying_key().hex()) driver = BlockchainDriver() driver.set(balances_key, 1_000_000) driver.commit() w = Wallet() tx2 = TransactionBuilder( sender='stu', contract='testing', function='get', kwargs={}, stamps=100_000, processor=b'\x00' * 32, nonce=0 ) tx2.sign(Wallet().signing_key()) tx2.serialize() currency_contract = 'currency' balances_hash = 'balances' balances_key = '{}{}{}{}{}'.format(currency_contract, config.INDEX_SEPARATOR, balances_hash, config.DELIMITER, w.verifying_key().hex()) driver = BlockchainDriver() driver.set(balances_key, 1_000_000) driver.commit() return transaction_list_to_transaction_batch([tx.struct, tx2.struct], wallet=Wallet())
def test_serialize_returns_bytes(self): w = Wallet() tx = TransactionBuilder(sender=w.verifying_key().hex(), stamps=1000000, contract='currency', function='transfer', kwargs={'amount': 'b'}, processor=b'\x00'*32, nonce=0) tx.sign(w.signing_key()) tx_packed = tx.serialize() self.assertTrue(verify_packed_tx(w.verifying_key(), tx_packed))
def test_signing_flips_true(self): w = Wallet() tx = TransactionBuilder(sender=w.verifying_key().hex(), stamps=1000000, contract='currency', function='transfer', kwargs={'amount': 'b'}, processor=b'\x00'*32, nonce=0) self.assertFalse(tx.tx_signed) tx.sign(w.signing_key()) self.assertTrue(tx.tx_signed)
def setUp(self): #m, d = sync.get_masternodes_and_delegates_from_constitution() self.client = ContractingClient() self.client.flush() sync.submit_from_genesis_json_file(cilantro_ee.contracts.__path__[0] + '/genesis.json', client=self.client) sync.submit_node_election_contracts( initial_masternodes=Wallet().verifying_key().hex(), boot_mns=1, initial_delegates=Wallet().verifying_key().hex(), boot_dels=1, client=self.client) w = Wallet() sk, vk = w.signing_key(), w.verifying_key() self.db = DistributedMasterStorage(key=sk, vkbook=VKBook(self.client, 1, 1))
def test_processor_is_expected_but_nonce_is_incorrect_returns_false(self): w = Wallet() expected_processor = secrets.token_bytes(32) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=1) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) with self.assertRaises(transaction.TransactionNonceInvalid): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
class TestProcessor(TestCase): def setUp(self): self.wallet = Wallet() self.client = ContractingClient() sync.submit_from_genesis_json_file(cilantro_ee.contracts.__path__[0] + '/genesis.json', client=ContractingClient()) processor.mint(self.wallet.vk.encode().hex(), 1000000000) self.currency = self.client.get_contract('currency') bal = self.currency.quick_read(variable='balances', key=self.wallet.vk.encode().hex()) self.assertEqual(bal, 1000000000) def tearDown(self): self.client.flush() def test_process_good_tx(self): txb = TransactionBuilder(self.wallet.verifying_key(), contract='currency', function='transfer', kwargs={ 'to': 'jeff', 'amount': 10000 }, stamps=100000, processor=b'\x00' * 32, nonce=0) txb.sign(self.wallet.signing_key()) tx_bytes = txb.serialize() tx = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) print(tx) results = processor.process_transaction(tx) balance_from = results['state_changes']['currency.balances:{}'.format( self.wallet.vk.encode().hex())] balance_jeff = results['state_changes']['currency.balances:jeff'] self.assertEqual(float(balance_from), 1000000000 - 10000) self.assertEqual(float(balance_jeff), 10000)
def make_good_tx(processor): w = Wallet() balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, w.verifying_key().hex()) n.set(balances_key, 500000) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={ 'amount': 10, 'to': 'jeff' }, stamps=500000, processor=processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() return tx_bytes
def make_bad_tx(): w = Wallet() balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, w.verifying_key().hex()) n.set(balances_key, 500000) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={ 'amount': 10, 'to': 'jeff' }, stamps=500000, processor=b'\x00' * 32, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() #tx_struct = transaction_capnp.Transaction.from_bytes_packed(tx_bytes) return tx_bytes
def test_processor_and_nonce_correct_increments_pending_nonce_by_one(self): w = Wallet() expected_processor = secrets.token_bytes(32) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=10000, processor=expected_processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) pending_nonce = self.nonce_manager.get_pending_nonce(expected_processor, w.verifying_key()) self.assertEqual(pending_nonce, 1)
def test_send_to_delegates_doesnt_hang_if_one_is_not_online(self): bootnodes = ['ipc:///tmp/n2', 'ipc:///tmp/n3'] mnw1 = Wallet() mnw2 = Wallet() dw1 = Wallet() dw2 = Wallet() dw3 = Wallet() dw4 = Wallet() constitution = { "masternodes": { "vk_list": [ mnw1.verifying_key().hex(), mnw2.verifying_key().hex() ], "min_quorum": 1 }, "delegates": { "vk_list": [ dw1.verifying_key().hex(), dw2.verifying_key().hex(), dw3.verifying_key().hex(), dw4.verifying_key().hex() ], "min_quorum": 1 }, "witnesses": {}, "schedulers": {}, "notifiers": {}, "enable_stamps": False, "enable_nonces": False } n1 = '/tmp/n1' make_ipc(n1) mn1 = Masternode(wallet=mnw1, ctx=self.ctx, socket_base=f'ipc://{n1}', bootnodes=bootnodes, constitution=constitution, webserver_port=8080, overwrite=True) masternodes = [mnw1.verifying_key().hex(), mnw2.verifying_key().hex()] delegates = [dw1.verifying_key().hex(), dw2.verifying_key().hex(), dw3.verifying_key().hex(), dw4.verifying_key().hex()] contacts = MockContacts( masters=masternodes, delegates=delegates ) d1 = '/tmp/d1' make_ipc(d1) wi1 = WorkInbox(socket_id=_socket(f'ipc://{d1}/incoming_work'), ctx=self.ctx, contacts=contacts, verify=False) d2 = '/tmp/d2' make_ipc(d2) wi2 = WorkInbox(socket_id=_socket(f'ipc://{d2}/incoming_work'), ctx=self.ctx, contacts=contacts, verify=False) d3 = '/tmp/d3' make_ipc(d3) #wi3 = WorkInbox(socket_id=_socket(f'ipc://{d3}/incoming_work'), ctx=self.ctx, contacts=contacts, verify=False) d4 = '/tmp/d4' make_ipc(d4) wi4 = WorkInbox(socket_id=_socket(f'ipc://{d4}/incoming_work'), ctx=self.ctx, contacts=contacts, verify=False) w = Wallet() batch = TransactionBuilder( sender=w.verifying_key(), contract='test', function='testing', kwargs={}, stamps=1_000_000, processor=mnw1.verifying_key(), nonce=0 ) batch.sign(w.signing_key()) b = batch.serialize() tx = transaction_capnp.Transaction.from_bytes_packed(b) currency_contract = 'currency' balances_hash = 'balances' balances_key = '{}{}{}{}{}'.format(currency_contract, config.INDEX_SEPARATOR, balances_hash, config.DELIMITER, w.verifying_key().hex()) driver = BlockchainDriver() driver.set(balances_key, 1_000_000) driver.commit() mn1.tx_batcher.queue.append(tx) mn1.network.peer_service.table.peers = { dw1.verifying_key().hex(): f'ipc://{d1}', dw2.verifying_key().hex(): f'ipc://{d2}', dw3.verifying_key().hex(): f'ipc://{d3}', dw4.verifying_key().hex(): f'ipc://{d4}' } async def late_send(): await asyncio.sleep(0.3) await mn1.parameters.refresh() return await mn1.send_batch_to_delegates() async def stop(): await asyncio.sleep(0.5) wi1.stop() wi2.stop() wi4.stop() mn1.network.stop() tasks = asyncio.gather( mn1.network.start(False), wi1.serve(), wi2.serve(), wi4.serve(), late_send(), stop() ) _, _, _, _, r, _ = self.loop.run_until_complete(tasks) # Make sure the right socket failed for rr in r: if not rr[0]: self.assertEqual(rr[1], f'ipc://{d3}/incoming_work') self.assertTrue(wi1.work[mnw1.verifying_key().hex()]) self.assertTrue(wi2.work[mnw1.verifying_key().hex()]) self.assertTrue(wi4.work[mnw1.verifying_key().hex()])
def setUp(self): w = Wallet() self.sk, self.vk = w.signing_key(), w.verifying_key() self.db = MasterStorage()
def test_multiple_nonces_in_sequence_all_verify(self): w = Wallet() expected_processor = secrets.token_bytes(32) balances_key = '{}{}{}{}{}'.format('currency', config.INDEX_SEPARATOR, 'balances', config.DELIMITER, w.verifying_key().hex()) self.nonce_manager.set(balances_key, 500000) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=0) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=1) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=2) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=3) tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
class DistributedMasterStorage(MasterStorage): def __init__(self, key, distribute_writes=False, config_path=cilantro_ee.__path__[0], vkbook=None): super().__init__(config_path=config_path) self.distribute_writes = distribute_writes self.vkbook = vkbook self.wallet = Wallet(seed=key) self.sk = self.wallet.signing_key() self.vk = self.wallet.verifying_key() self.test_hook = False self.mn_id = 1 self.rep_factor = 3 self.active_masters = 12 self.quorum_needed = 3 def get_master_set(self): if self.test_hook is True: return self.active_masters else: self.active_masters = len(self.vkbook.masternodes) return self.active_masters def set_mn_id(self, vk): if self.test_hook is True: return self.mn_id # this should be rewritten to just pull from Phonebook because it's dynamic now for i in range(self.get_master_set()): if self.vkbook.masternodes[i] == vk: self.mn_id = i return True else: self.mn_id = -1 return False def rep_pool_sz(self): if self.active_masters < self.rep_factor: return -1 self.active_masters = self.get_master_set() pool_sz = round(self.active_masters / self.rep_factor) return pool_sz def build_wr_list(self, curr_node_idx=0, jump_idx=1): # Use slices to make this a one liner tot_mn = len(self.vkbook.masternodes) mn_list = [] # if quorum req not met jump_idx is 0 wr on all active nodes if jump_idx == 0: return self.vkbook.masternodes while curr_node_idx < tot_mn: mn_list.append(self.vkbook.masternodes[curr_node_idx]) curr_node_idx += jump_idx return mn_list @staticmethod def index_from_block(b, nodes=[]): assert len(nodes) > 0, 'Must have at least one block owner!' index = { 'blockNum': b.get('blockNum'), 'hash': b.get('hash'), 'blockOwners': nodes } assert index['hash'] is not None and index['blockNum'] is not None, 'Block hash and number' \ 'must be provided!' return index def evaluate_wr(self, entry=None, node_id=None): """ Function is used to check if currently node is suppose to write given entry :param entry: given block input to be stored :param node_id: master id None is default current master, if specified is for catch up case :return: """ if entry is None: return False pool_sz = self.rep_pool_sz() mn_idx = self.mn_id % pool_sz writers = entry.get('blockNum') % pool_sz # TODO # need gov here to check if given node is voted out if node_id is not None: mn_idx = node_id % pool_sz # overwriting mn_idx if mn_idx == writers: return True else: return False # always write if active master bellow threshold if self.active_masters < self.quorum_needed: self.put(entry, self.BLOCK) mn_list = self.build_wr_list(curr_node_idx=self.mn_id, jump_idx=0) index = self.index_from_block(entry, nodes=mn_list) return self.put(index, self.INDEX) if mn_idx == writers: self.put(entry, self.BLOCK) # build list of mn_sign of master nodes updating index db mn_list = self.build_wr_list(curr_node_idx=writers, jump_idx=pool_sz) assert len( mn_list ) > 0, "block owner list cannot be empty - dumping list -> {}".format( mn_list) # create index records and update entry index = self.index_from_block(entry, nodes=mn_list) return self.put(index, self.INDEX) def update_index(self, block, nodes): index = self.index_from_block(block, nodes=nodes) return self.put(index, MasterStorage.INDEX) def put(self, data, collection=MasterStorage.BLOCK): super().put(data=data, collection=collection)