def make_network(masternodes, delegates, ctx, mn_min_quorum=2, del_min_quorum=2): mn_wallets = [Wallet() for _ in range(masternodes)] dl_wallets = [Wallet() for _ in range(delegates)] constitution = { 'masternodes': [mn.verifying_key().hex() for mn in mn_wallets], 'delegates': [dl.verifying_key().hex() for dl in dl_wallets], 'masternode_min_quorum': mn_min_quorum, 'delegate_min_quorum': del_min_quorum, } mns = [] dls = [] bootnodes = None node_count = 0 for wallet in mn_wallets: driver = BlockchainDriver(driver=InMemDriver()) # driver = IsolatedDriver() ipc = f'/tmp/n{node_count}' make_ipc(ipc) if bootnodes is None: bootnodes = [f'ipc://{ipc}'] mn = Masternode(wallet=wallet, ctx=ctx, socket_base=f'ipc://{ipc}', bootnodes=bootnodes, constitution=deepcopy(constitution), webserver_port=18080 + node_count, driver=driver) mns.append(mn) node_count += 1 for wallet in dl_wallets: driver = BlockchainDriver(driver=InMemDriver()) # driver = IsolatedDriver() ipc = f'/tmp/n{node_count}' make_ipc(ipc) dl = Delegate(wallet=wallet, ctx=ctx, socket_base=f'ipc://{ipc}', constitution=deepcopy(constitution), bootnodes=bootnodes, driver=driver) dls.append(dl) node_count += 1 return mns, dls
class TestNode(TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.t = BlockchainDriver() self.c = MasterStorage() self.ctx = zmq.asyncio.Context() def tearDown(self): self.ctx.destroy() self.t.flush() self.c.drop_collections() self.loop.close() def test_catchup(self): fake_block_1 = {'blockNum': 1, 'subBlocks': []} fake_block_2 = {'blockNum': 2, 'subBlocks': []} self.c.store_block(fake_block_1) self.c.store_block(fake_block_2) mn_wallets = [Wallet() for _ in range(2)] dl_wallets = [Wallet() for _ in range(2)] constitution = { 'masternodes': [mn.verifying_key().hex() for mn in mn_wallets], 'delegates': [dl.verifying_key().hex() for dl in dl_wallets], 'masternode_min_quorum': 2, 'delegate_min_quorum': 2, } n = Node(socket_base='tcp://127.0.0.1', ctx=self.ctx, constitution=constitution, wallet=mn_wallets[0]) w = Wallet() m = BlockServer(w, 'tcp://127.0.0.1', self.ctx, linger=500, poll_timeout=500) tasks = asyncio.gather( m.serve(), n.catchup(SocketStruct.from_string('tcp://127.0.0.1:10004')), stop_server(m, 1), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) print(res)
def flush(args): if args.storage_type == 'blocks': MasterStorage().drop_collections() print('All blocks deleted.') elif args.storage_type == 'state': BlockchainDriver().flush() print('State deleted.') elif args.storage_type == 'all': MasterStorage().drop_collections() BlockchainDriver().flush() print('All blocks deleted.') print('State deleted.') else: print('Invalid option. < blocks | state | all >')
def make_tx(processor): w = Wallet() batch = TransactionBuilder( sender=w.verifying_key(), contract='test', function='testing', kwargs={}, stamps=1_000_000, 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 = BlockchainDriver() driver.set(balances_key, 1_000_000) return tx
def __init__(self, wallet, socket_base, ctx=None, network_parameters=NetworkParameters(), linger=500, poll_timeout=200, blocks: CilantroStorageDriver = None, driver=BlockchainDriver()): self.wallet = wallet self.ctx = ctx or zmq.asyncio.Context() self.address = network_parameters.resolve(socket_base, ServiceType.BLOCK_SERVER, bind=True) super().__init__(socket_id=self.address, wallet=self.wallet, ctx=self.ctx, linger=linger, poll_timeout=poll_timeout) self.blocks = blocks or CilantroStorageDriver( key=self.wallet.signing_key()) self.driver = driver self.log = get_logger('BlockServer')
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 setUp(self): self.w = Wallet() self.blocks = CilantroStorageDriver(key=self.w.verifying_key()) self.driver = BlockchainDriver() self.ws = WebServer(wallet=self.w, contracting_client=ContractingClient(), blocks=self.blocks, driver=n) self.ws.client.flush() self.ws.blocks.drop_collections()
def __init__(self, contacts: VKBook, driver: BlockchainDriver = BlockchainDriver(), verify=True, allow_current_block_num=False, *args, **kwargs): self.q = [] self.contacts = contacts self.driver = driver self.verify = verify self.quorum_ratio = 0.50 self.allow_current_block_num = allow_current_block_num self.log = get_logger('NBN') self.signers = len( self.contacts.delegates ) # This has to be updated every block in case a delegate is added or removed super().__init__(*args, **kwargs)
def __init__(self, wallet: Wallet, ctx: zmq.asyncio.Context, blocks: CilantroStorageDriver = None, state=BlockchainDriver(), parameters: Parameters = None): self.parameters = parameters self.wallet = wallet self.ctx = ctx self.blocks = blocks self.state = state self.blocks_to_process = [] self.in_catchup = False self.log = get_logger('Catchup')
def __init__(self, client: ContractingClient, driver: BlockchainDriver = BlockchainDriver(), verify=True, debug=True, *args, **kwargs): self.work = {} self.driver = driver self.verify = verify self.client = client self.masternode_contract = self.client.get_contract('masternodes') self.todo = [] self.accepting_work = False self.log = get_logger('DEL WI') self.log.propagate = debug super().__init__(*args, **kwargs)
from contracting.client import ContractingClient from contracting.db.encoder import encode from cilantro_ee.storage.master import MasterStorage from cilantro_ee.storage import BlockchainDriver from cilantro_ee.messages.capnp_impl import capnp_struct as schemas import ast from . import conf from . import processor import os import capnp app = Sanic(__name__) block_driver = MasterStorage() metadata_driver = BlockchainDriver() client = ContractingClient() #HTTPS ''' from sanic_cors import CORS, cross_origin import ssl SSL_WEB_SERVER_PORT = 443 NUM_WORKERS = 1 ssl_cert = '' ssl_key = '' CORS(app, automatic_options=True) ''' transaction_capnp = capnp.load( os.path.dirname(schemas.__file__) + '/transaction.capnp')
from cilantro_ee.nodes.masternode.webserver import WebServer from cilantro_ee.crypto.wallet import Wallet from contracting.client import ContractingClient from cilantro_ee.storage import BlockchainDriver from cilantro_ee.storage import CilantroStorageDriver from cilantro_ee.crypto.transaction import TransactionBuilder from contracting import config from cilantro_ee.messages.capnp_impl import capnp_struct as schemas import os import capnp transaction_capnp = capnp.load( os.path.dirname(schemas.__file__) + '/transaction.capnp') n = BlockchainDriver() 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' },
def test_block_never_received_goes_through_adequate_consensus(self): a = Aggregator(wallet=Wallet(), socket_id=_socket('tcp://127.0.0.1:8888'), ctx=zmq.asyncio.Context(), driver=BlockchainDriver()) c1 = [MockSBC('input_1', 'res_1', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_4', 3)] c2 = [MockSBC('input_1', 'res_1', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_4', 3)] c3 = [MockSBC('input_1', 'res_1', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_X', 3)] a.sbc_inbox.q = [c1, c2, c3] res = self.loop.run_until_complete(a.gather_subblocks(4, adequate_ratio=0.3)) print(res) self.assertFalse(canonical.block_is_failed(res, '0' * 32, 1))
def test_failed_block_on_one_returns_failed_block(self): a = Aggregator(wallet=Wallet(), socket_id=_socket('tcp://127.0.0.1:8888'), ctx=zmq.asyncio.Context(), driver=BlockchainDriver()) c1 = [MockSBC('input_1', 'res_X', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_4', 3)] c2 = [MockSBC('input_1', 'res_1', 0), MockSBC('input_2', 'res_X', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_4', 3)] c3 = [MockSBC('input_1', 'res_X', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_i', 'res_X', 2), MockSBC('input_4', 'res_4', 3)] c4 = [MockSBC('input_1', 'res_1', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_X', 3)] a.sbc_inbox.q = [c1, c2, c3, c4] res = self.loop.run_until_complete(a.gather_subblocks(4)) print(res) self.assertTrue(canonical.block_is_failed(res, '0' * 64, 1))
def test_mixed_results_still_makes_quorum(self): a = Aggregator(wallet=Wallet(), socket_id=_socket('tcp://127.0.0.1:8888'), ctx=zmq.asyncio.Context(), driver=BlockchainDriver()) c1 = [MockSBC('input_1', 'res_X', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_4', 3)] c2 = [MockSBC('input_1', 'res_1', 0), MockSBC('input_2', 'res_X', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_4', 3)] c3 = [MockSBC('input_1', 'res_1', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_i', 'res_X', 2), MockSBC('input_4', 'res_4', 3)] c4 = [MockSBC('input_1', 'res_1', 0), MockSBC('input_2', 'res_2', 1), MockSBC('input_3', 'res_3', 2), MockSBC('input_4', 'res_X', 3)] a.sbc_inbox.q = [c1, c2, c3, c4] res = self.loop.run_until_complete(a.gather_subblocks(4)) self.assertEqual(res['subBlocks'][0]['merkleLeaves'][0], 'res_1') self.assertEqual(res['subBlocks'][1]['merkleLeaves'][0], 'res_2') self.assertEqual(res['subBlocks'][2]['merkleLeaves'][0], 'res_3') self.assertEqual(res['subBlocks'][3]['merkleLeaves'][0], 'res_4')
def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.t = BlockchainDriver() self.c = MasterStorage() self.ctx = zmq.asyncio.Context()
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()])
class TestBlockServer(TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.t = BlockchainDriver() self.ctx = zmq.asyncio.Context() def tearDown(self): self.ctx.destroy() self.t.flush() self.loop.close() def test_get_latest_block_height(self): w = Wallet() m = BlockServer(w, 'tcp://127.0.0.1', self.ctx, linger=500, poll_timeout=500, driver=self.t) self.t.set_latest_block_num(555) async def get(msg): socket = self.ctx.socket(zmq.DEALER) socket.connect('tcp://127.0.0.1:10004') await socket.send(msg) res = await socket.recv() return res message = Message.get_signed_message_packed_2( wallet=w, msg_type=MessageType.LATEST_BLOCK_HEIGHT_REQUEST, timestamp=int(time.time())) tasks = asyncio.gather( m.serve(), get(message), stop_server(m, 0.2), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) msg_type, msg, sender, timestamp, is_verified = Message.unpack_message_2( res[1]) self.assertEqual(msg.blockHeight, 555) def test_get_latest_block_hash(self): w = Wallet() m = BlockServer(w, 'tcp://127.0.0.1', self.ctx, linger=500, poll_timeout=500) self.t.set_latest_block_hash(b'\xAA' * 32) async def get(msg): socket = self.ctx.socket(zmq.DEALER) socket.connect('tcp://127.0.0.1:10004') await socket.send(msg) res = await socket.recv() return res message = Message.get_signed_message_packed_2( wallet=w, msg_type=MessageType.LATEST_BLOCK_HASH_REQUEST, timestamp=int(time.time())) tasks = asyncio.gather( m.serve(), get(message), stop_server(m, 0.2), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) msg_type, msg, sender, timestamp, is_verified = Message.unpack_message_2( res[1]) self.assertEqual(msg.hash, b'\xAA' * 32) def test_get_block_blob_by_block_data_request(self): block = random_txs.random_block() w = Wallet() c = CilantroStorageDriver(key=w.sk.encode().hex()) c.drop_collections() d = canonical.block_from_subblocks([s for s in block.subBlocks], previous_hash=b'x/00' * 32, block_num=0) d['blockOwners'] = [secrets.token_bytes(32) for _ in range(12)] c.put(d) del d['_id'] del d['blockOwners'] m = BlockServer(w, 'tcp://127.0.0.1', self.ctx, linger=500, poll_timeout=500, driver=c) async def get(msg): socket = self.ctx.socket(zmq.DEALER) socket.connect('tcp://127.0.0.1:10004') await socket.send(msg) res = await socket.recv() return res message = Message.get_signed_message_packed_2( wallet=w, msg_type=MessageType.BLOCK_DATA_REQUEST, blockNum=0) tasks = asyncio.gather( m.serve(), get(message), stop_server(m, 0.2), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) msg_type, msg, sender, timestamp, is_verified = Message.unpack_message_2( res[1]) dd = canonical.block_from_subblocks([s for s in msg.subBlocks], previous_hash=b'x/00' * 32, block_num=0) self.assertDictEqual(d, dd) def test_get_block_blob_by_block_but_failure_returns_bad_request(self): w = Wallet() c = CilantroStorageDriver(key=w.sk.encode().hex()) c.drop_collections() m = BlockServer(w, 'tcp://127.0.0.1', self.ctx, linger=500, poll_timeout=500, driver=c) async def get(msg): socket = self.ctx.socket(zmq.DEALER) socket.connect('tcp://127.0.0.1:10004') await socket.send(msg) res = await socket.recv() return res message = Message.get_signed_message_packed_2( wallet=w, msg_type=MessageType.BLOCK_DATA_REQUEST, blockNum=0) tasks = asyncio.gather( m.serve(), get(message), stop_server(m, 1), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) msg_type, msg, sender, timestamp, is_verified = Message.unpack_message_2( res[1]) self.assertEqual(msg_type, MessageType.BAD_REQUEST)
def transaction_is_valid(tx: transaction_capnp.Transaction, expected_processor: bytes, driver: BlockchainDriver, strict=True, tx_per_block=15): # Validate Signature if not wallet._verify(tx.payload.sender, tx.payload.as_builder().to_bytes_packed(), tx.metadata.signature): raise TransactionSignatureInvalid # Check nonce processor is correct if tx.payload.processor != expected_processor: raise TransactionProcessorInvalid # Attempt to get the current block's pending nonce nonce = driver.get_nonce(tx.payload.processor, tx.payload.sender) or 0 pending_nonce = driver.get_pending_nonce(tx.payload.processor, tx.payload.sender) or nonce if tx.payload.nonce - nonce > tx_per_block or pending_nonce - nonce >= tx_per_block: raise TransactionTooManyPendingException # Strict mode requires exact sequence matching (1, 2, 3, 4). This is for masternodes if strict: if tx.payload.nonce != pending_nonce: raise TransactionNonceInvalid pending_nonce += 1 # However, some of those tx's might fail verification and never make it to delegates. Thus, # delegates shouldn't be as concerned. (1, 2, 4) should be valid for delegates. else: if tx.payload.nonce < pending_nonce: raise TransactionNonceInvalid pending_nonce = tx.payload.nonce + 1 # Validate Stamps if tx.payload.stampsSupplied < 0: raise TransactionStampsNegative currency_contract = 'currency' balances_hash = 'balances' balances_key = '{}{}{}{}{}'.format(currency_contract, config.INDEX_SEPARATOR, balances_hash, config.DELIMITER, tx.payload.sender.hex()) balance = driver.get(balances_key) if balance is None: balance = 0 stamp_to_tau = driver.get_var('stamp_cost', 'S', ['value']) if stamp_to_tau is None: stamp_to_tau = 1 if balance * stamp_to_tau < tx.payload.stampsSupplied: print("bal -> {}, stamp2tau - > {}, txpayload -> {}".format( balance, stamp_to_tau, tx.payload.stampsSupplied)) raise TransactionSenderTooFewStamps # Prevent people from sending their entire balances for free by checking if that is what they are doing. if tx.payload.contractName == 'currency' and tx.payload.functionName == 'transfer': kwargs = decode(tx.payload.kwargs) amount = kwargs.get('amount') # If you have less than 2 transactions worth of tau after trying to send your amount, fail. if ((balance - amount) * stamp_to_tau) / 3000 < 2: print(f'BAL IS: {((balance - amount) * stamp_to_tau) / 3000}') raise TransactionSenderTooFewStamps if tx.payload.contractName == 'submission' and tx.payload.functionName == 'submit_contract': kwargs = decode(tx.payload.kwargs) name = kwargs.get('name') if type(name) != str: raise TransactionContractNameInvalid if not name.startswith('con_'): raise TransactionContractNameInvalid driver.set_pending_nonce(tx.payload.processor, tx.payload.sender, pending_nonce)
class TestTXValidity(TestCase): def setUp(self): self.nonce_manager = BlockchainDriver() self.nonce_manager.flush() def tearDown(self): self.nonce_manager.flush() def test_processor_incorrect_returns_false(self): w = Wallet() expected_processor = secrets.token_bytes(32) given_processor = secrets.token_bytes(32) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=given_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.TransactionProcessorInvalid): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) 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) 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_all_but_wallet_signed_returns_false(self): w = Wallet() x = Wallet() expected_processor = secrets.token_bytes(32) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=0, processor=expected_processor, nonce=0) tx.sign(x.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) with self.assertRaises(transaction.TransactionSignatureInvalid): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) def test_all_but_proof_valid_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=0, processor=expected_processor, nonce=0) tx.proof = b'\00' * 32 tx.proof_generated = True tx.sign(w.signing_key()) tx_bytes = tx.serialize() tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes) with self.assertRaises(transaction.TransactionPOWProofInvalid): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) 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_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_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) def test_non_sequence_fails_in_strict_mode(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=5) 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) def test_greater_than_passes_in_no_strict_mode(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=5) 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) 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 test_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) 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) def test_tx_nonce_minus_nonce_less_than_tx_per_block(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=2) 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) def test_tx_nonce_minus_nonce_greater_than_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=10) tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=20) 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_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_15_in_row_valid_16th_not_due_to_tx_per_block_failing(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) for i in range(15): tx = TransactionBuilder(w.verifying_key(), contract='currency', function='transfer', kwargs={'amount': 10, 'to': 'jeff'}, stamps=500000, processor=expected_processor, nonce=i) 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=15) 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_sending_transfer_of_all_money_fails(self): self.nonce_manager.set_var('stamp_cost', 'S', ['value'], value=3000) stamp_to_tau = self.nonce_manager.get_var('stamp_cost', 'S', ['value']) 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': 500000, '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) with self.assertRaises(transaction.TransactionSenderTooFewStamps): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) def test_sending_transfer_of_most_money_fails_if_only_one_transfer_in_stamps_left(self): self.nonce_manager.set_var('stamp_cost', 'S', ['value'], value=3000) stamp_to_tau = self.nonce_manager.get_var('stamp_cost', 'S', ['value']) 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': 499999, '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) with self.assertRaises(transaction.TransactionSenderTooFewStamps): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) 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 test_submission_not_prepended_with_con_throws_error(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': '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) with self.assertRaises(transaction.TransactionContractNameInvalid): transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager) def test_submission_not_str_throws_error(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': 123, '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) with self.assertRaises(transaction.TransactionContractNameInvalid): 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 setUp(self): self.nonce_manager = BlockchainDriver() self.nonce_manager.flush()
def setUp(self): self.ctx = zmq.asyncio.Context() self.loop = asyncio.get_event_loop() driver = BlockchainDriver() driver.flush()