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_block_from_subblocks_verify_works(self): sbs = random_txs.random_block().subBlocks block = canonical.block_from_subblocks(subblocks=sbs, previous_hash=b'\x00' * 32, block_num=0) prev_hash = block['prevBlockHash'] prop_hash = block['hash'] valid = canonical.verify_block(sbs, prev_hash, prop_hash) self.assertTrue(valid)
def test_fetch_block_from_master(self): # Setup Mongo #sync.seed_vkbook() w = Wallet() c = CilantroStorageDriver(key=w.sk.encode()) c.drop_collections() # Store 20 blocks self.store_blocks(c, 1) w1 = Wallet() m1 = BlockServer(socket_base='tcp://127.0.0.1', wallet=w1, ctx=self.ctx, linger=500, poll_timeout=500, driver=FakeTopBlockManager(101, 'abcd')) class FakeParameters: async def refresh(self): await asyncio.sleep(0.1) def get_masternode_sockets(self, *args): return ['tcp://127.0.0.1:10004'] f = BlockFetcher(wallet=Wallet(), ctx=self.ctx, parameters=FakeParameters()) tasks = asyncio.gather( m1.serve(), f.get_block_from_master( 0, cilantro_ee.sockets.struct._socket('tcp://127.0.0.1:10004')), stop_server(m1, 0.3), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) block_dict = c.get_block(0) del block_dict['blockOwners'] got_block = res[1] got = canonical.block_from_subblocks([s for s in got_block.subBlocks], previous_hash=b'\x00' * 32, block_num=0) self.assertDictEqual(block_dict, got)
def store_blocks(self, c, i, initial_hash=(b'\x00' * 32).hex()): current_hash = initial_hash for _i in range(i): block = random_txs.random_block(block_num=_i) d = canonical.block_from_subblocks([s for s in block.subBlocks], previous_hash=current_hash, block_num=_i) d['blockOwners'] = [secrets.token_bytes(32) for _ in range(12)] c.put(d) del d['_id'] del d['blockOwners'] current_hash = d['hash']
async def gather_subblocks(self, total_contacts, quorum_ratio=0.66, adequate_ratio=0.5, expected_subblocks=4): self.sbc_inbox.expected_subblocks = expected_subblocks self.log.info(f''' ======== Gathering subblocks: Total Contacts: {total_contacts}, Expected SBs: {expected_subblocks} Quorum Ratio: {quorum_ratio}, Adequate Ratio: {adequate_ratio} ======== ''') contenders = BlockContender(total_contacts=total_contacts, required_consensus=quorum_ratio, total_subblocks=expected_subblocks, acceptable_consensus=adequate_ratio) # Add timeout condition. started = time.time() while (not contenders.block_has_consensus() and contenders.responses < contenders.total_contacts) and \ time.time() - started < self.seconds_to_timeout: if self.sbc_inbox.has_sbc(): sbcs = await self.sbc_inbox.receive_sbc( ) # Can probably make this raw sync code contenders.add_sbcs(sbcs) await asyncio.sleep(0) if time.time() - started > self.seconds_to_timeout: self.log.error('BLOCK TIMEOUT!') self.log.info('Done aggregating new block.') block = contenders.get_current_best_block() return canonical.block_from_subblocks( block, previous_hash=self.driver.latest_block_hash, block_num=self.driver.latest_block_num + 1)
def get_block_dict(self, sub_blocks, kind): last_block = self.get_last_n(1, self.INDEX) if len(last_block) > 0: last_block = last_block[0] last_hash = last_block.get('hash') current_block_num = last_block.get('blockNum') else: last_hash = GENESIS_HASH current_block_num = 0 if kind == 0: current_block_num += 1 block_dict = block_from_subblocks(subblocks=sub_blocks, previous_hash=last_hash, block_num=current_block_num) block_dict['blockOwners'] = [m for m in self.vkbook.masternodes], return block_dict
def test_fetch_multiple_blocks_works_with_good_actors(self): w = Wallet() c = CilantroStorageDriver(key=w.sk.encode()) c.drop_collections() # Store 20 blocks self.store_blocks(c, 10) # Good one w1 = Wallet() n1 = '/tmp/n1' make_ipc(n1) m1 = BlockServer(socket_base=f'ipc://{n1}', wallet=w1, ctx=self.ctx, linger=500, poll_timeout=500, driver=FakeTopBlockManager(101, 'abcd'), blocks=c) w2 = Wallet() n2 = '/tmp/n2' make_ipc(n2) m2 = BlockServer(socket_base=f'ipc://{n2}', wallet=w2, ctx=self.ctx, linger=500, poll_timeout=100, driver=FakeTopBlockManager(101, 'abcd'), blocks=c) w3 = Wallet() n3 = '/tmp/n3' make_ipc(n3) m3 = BlockServer(socket_base=f'ipc://{n3}', wallet=w3, ctx=self.ctx, linger=500, poll_timeout=100, driver=FakeTopBlockManager(101, 'abcd'), blocks=c) fake_driver = FakeBlockReciever() class FakeParameters: async def refresh(self): await asyncio.sleep(0.1) def get_masternode_sockets(self, *args): return [ f'ipc://{n1}/blocks', f'ipc://{n2}/blocks', f'ipc://{n3}/blocks', ] f = BlockFetcher(wallet=Wallet(), ctx=self.ctx, parameters=FakeParameters(), blocks=fake_driver) tasks = asyncio.gather( m1.serve(), m2.serve(), m3.serve(), f.fetch_blocks(latest_block_available=9), stop_server(m1, 3), stop_server(m2, 3), stop_server(m3, 3), ) loop = asyncio.get_event_loop() loop.run_until_complete(tasks) last_hash = b'\x00' * 32 for i in range(10): block_dict = c.get_block(i) del block_dict['blockOwners'] got = canonical.block_from_subblocks( [s for s in fake_driver.blocks[i]['subBlocks']], previous_hash=last_hash, block_num=i) last_hash = block_dict['hash'] self.assertDictEqual(block_dict, got)
def test_fetch_block_from_multiple_masters_where_some_are_corrupted(self): w = Wallet() c = CilantroStorageDriver(key=w.sk.encode()) c.drop_collections() # Store 20 blocks self.store_blocks(c, 1) # Good one w1 = Wallet() n1 = '/tmp/n1' make_ipc(n1) m1 = BlockServer(socket_base=f'ipc://{n1}', wallet=w1, ctx=self.ctx, linger=500, poll_timeout=500, driver=FakeTopBlockManager(101, 'abcd'), blocks=c) # Bad Ones bad_block = canonical.block_from_subblocks( [s for s in random_txs.random_block().subBlocks], previous_hash=b'\x01' * 32, block_num=0) bad_block['blockOwners'] = [secrets.token_bytes(32) for _ in range(30)] d = FakeBlockDriver(bad_block) w2 = Wallet() n2 = '/tmp/n2' make_ipc(n2) m2 = BlockServer(socket_base=f'ipc://{n2}', wallet=w2, ctx=self.ctx, linger=500, poll_timeout=100, driver=FakeTopBlockManager(101, 'abcd'), blocks=d) w3 = Wallet() n3 = '/tmp/n3' make_ipc(n3) m3 = BlockServer(socket_base=f'ipc://{n3}', wallet=w3, ctx=self.ctx, linger=500, poll_timeout=100, driver=FakeTopBlockManager(101, 'abcd'), blocks=d) class FakeParameters: async def refresh(self): await asyncio.sleep(0.1) def get_masternode_sockets(self, *args): return [ f'ipc://{n1}/blocks', f'ipc://{n2}/blocks', f'ipc://{n3}/blocks', ] f = BlockFetcher(wallet=Wallet(), ctx=self.ctx, parameters=FakeParameters()) tasks = asyncio.gather( m1.serve(), m2.serve(), m3.serve(), f.find_valid_block(0, latest_hash=b'\x00' * 32, timeout=3000), stop_server(m1, 2), stop_server(m2, 2), stop_server(m3, 2), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) block_dict = c.get_block(0) del block_dict['blockOwners'] got_block = res[3] got = canonical.block_from_subblocks([s for s in got_block.subBlocks], previous_hash=b'\x00' * 32, block_num=0) self.assertDictEqual(block_dict, got)