def test_current_contacts_joins_mn_seed_adds_table_to_joiner(self): n1 = '/tmp/n1' make_ipc(n1) mnw1 = Wallet() mn1 = Network(wallet=mnw1, ctx=self.ctx, socket_base=f'ipc://{n1}') mn1.peer_service.table = {'a': 'b', 'c': 'd', 'e': 'f'} mnw2 = Wallet() n2 = '/tmp/n2' make_ipc(n2) mn2 = Network(wallet=mnw2, ctx=self.ctx, socket_base=f'ipc://{n2}', mn_seed='ipc:///tmp/n1') tasks = asyncio.gather(mn1.peer_service.start(), mn2.discovery_server.serve(), stop_server(mn2.discovery_server, 0.3), stop_server(mn1.peer_service, 0.3), mn2.get_current_contacts()) loop = asyncio.get_event_loop() loop.run_until_complete(tasks) self.assertDictEqual(mn1.peer_service.table, mn2.peer_service.table)
def test_start_and_stopping_destroys_servers(self): # Create Network service w1 = Wallet() n1 = NetworkParameters(peer_port=10001, event_port=10002) p1 = Network(wallet=w1, ctx=self.ctx, socket_base='tcp://127.0.0.1', params=n1) # Create Network service w2 = Wallet() n2 = NetworkParameters(peer_port=10003, event_port=10004) p2 = Network(wallet=w2, ctx=self.ctx, socket_base='tcp://127.0.0.1', params=n2) async def stop(n: Network, s): await asyncio.sleep(s) n.peer_service.stop() tasks = asyncio.gather(p1.peer_service.start(), p2.peer_service.start(), stop(p1, 0.3), stop(p2, 0.3)) loop = asyncio.get_event_loop() loop.run_until_complete(tasks)
def test_start_and_stopping_destroys_servers_ipc(self): # Create Network service w1 = Wallet() n1 = NetworkParameters(peer_ipc='peers1', event_ipc='events1', discovery_ipc='discovery1') p1 = Network(wallet=w1, ctx=self.ctx, socket_base='ipc:///tmp', params=n1) # Create Network service w2 = Wallet() n2 = NetworkParameters(peer_ipc='peers2', event_port='events2') p2 = Network(wallet=w2, ctx=self.ctx, socket_base='ipc:///tmp', params=n2) async def stop(n: Network, s): await asyncio.sleep(s) n.peer_service.stop() tasks = asyncio.gather(p1.peer_service.start(), p2.peer_service.start(), stop(p1, 0.3), stop(p2, 0.3)) loop = asyncio.get_event_loop() loop.run_until_complete(tasks)
def test_bootstrap_nodes_ipc(self): w = Wallet() w1 = Wallet() w2 = Wallet() w3 = Wallet() w4 = Wallet() bootnodes = [ _socket('ipc:///tmp/n1/discovery'), _socket('ipc:///tmp/n2/discovery'), _socket('ipc:///tmp/n3/discovery'), _socket('ipc:///tmp/n4/discovery') ] d1 = DiscoveryServer(socket_id=bootnodes[0], wallet=w1, pepper=PEPPER.encode(), ctx=self.ctx, linger=1000, poll_timeout=1000) d2 = DiscoveryServer(socket_id=bootnodes[1], wallet=w2, pepper=PEPPER.encode(), ctx=self.ctx, linger=1000, poll_timeout=1000) d3 = DiscoveryServer(socket_id=bootnodes[2], wallet=w3, pepper=PEPPER.encode(), ctx=self.ctx, linger=1000, poll_timeout=1000) d4 = DiscoveryServer(socket_id=bootnodes[3], wallet=w4, pepper=PEPPER.encode(), ctx=self.ctx, linger=1000, poll_timeout=1000) n = Network(wallet=w, ctx=self.ctx, bootnodes=bootnodes) tasks = asyncio.gather(d1.serve(), d2.serve(), d3.serve(), d4.serve(), stop_server(d1, 1), stop_server(d2, 1), stop_server(d3, 1), stop_server(d4, 1), n.discover_bootnodes(bootnodes)) loop = asyncio.get_event_loop() loop.run_until_complete(tasks) expected_dict = { w.verifying_key().hex(): 'tcp://0.0.0.0', w1.verifying_key().hex(): 'ipc:///tmp/n1', w2.verifying_key().hex(): 'ipc:///tmp/n2', w3.verifying_key().hex(): 'ipc:///tmp/n3', w4.verifying_key().hex(): 'ipc:///tmp/n4' } self.assertDictEqual(n.peer_service.table, expected_dict)
def test_get_sockets_with_service(self): constitution = self.get_vkbook_args() sync.submit_from_genesis_json_file(cilantro_ee.contracts.__path__[0] + '/genesis.json', client=self.client) sync.submit_node_election_contracts( initial_masternodes=constitution['masternodes'], boot_mns=constitution['masternode_min_quorum'], initial_delegates=constitution['delegates'], boot_dels=constitution['delegate_min_quorum'], client=self.client) PhoneBook = VKBook(client=self.client) w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='tcp://127.0.0.1') # 'tcp://127.0.0.1:10003' raw = {'stu': 'tcp://127.0.0.1', 'raghu': 'tcp://127.0.0.2'} p1.peer_service.table = raw expected = { 'stu': _socket('tcp://127.0.0.1:19003'), 'raghu': _socket('tcp://127.0.0.2:19003') } # CHANGE CLIENT TO SOCKET masternodes = Parameters(socket_base='tcp://127.0.0.1', wallet=w1, contacts=MockContacts(['stu'], delegates=['raghu']), ctx=self.ctx) self.assertDictEqual(masternodes.sockets, {}) async def late_refresh(): await asyncio.sleep(0.3) await masternodes.refresh() async def stop(): await asyncio.sleep(0.5) p1.stop() tasks = asyncio.gather(p1.start(discover=False), late_refresh(), stop()) self.loop.run_until_complete(tasks) self.assertEqual( masternodes.get_all_sockets(service=ServiceType.EVENT), expected)
def test_other_peers_add_new_nodes_when_join_event_occurs_ipc(self): # N3 runs discovery server and pings N1 # N1 checks to see if N3 is valid, and if so, adds to their table and pings N2 about the new join # Create Network service w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='ipc:///tmp/n1') # Create Network service w2 = Wallet() p2 = Network(wallet=w2, ctx=self.ctx, socket_base='ipc:///tmp/n2') p2.peer_service.event_service.add_subscription( _socket('ipc:///tmp/n1/events')) # Create Discovery Server w3 = Wallet() d = DiscoveryServer(wallet=w3, socket_id=_socket('ipc:///tmp/n3/discovery'), pepper=PEPPER.encode(), ctx=self.ctx, poll_timeout=2000, linger=2000) # TCP takes a bit longer to bind and is prone to dropping messages... sleep(1) # Construct the join RPC message join_message = ['join', (w3.verifying_key().hex(), 'ipc:///tmp/n3')] join_message = json.dumps(join_message).encode() tasks = asyncio.gather( p1.peer_service.start(), p2.peer_service.start(), d.serve(), services.get(_socket('ipc:///tmp/n1/peers'), msg=join_message, ctx=self.ctx, timeout=1000), stop_server(p1.peer_service, 2), stop_server(p2.peer_service, 2), stop_server(d, 2), ) loop = asyncio.get_event_loop() loop.run_until_complete(tasks) self.assertTrue(w3.verifying_key().hex() in p2.peer_service.table)
def test_ask_returns_table(self): n1 = '/tmp/n1' make_ipc(n1) mnw1 = Wallet() mn1 = Network(wallet=mnw1, ctx=self.ctx, socket_base=f'ipc://{n1}') mn1.peer_service.table = {'a': 'b', 'c': 'd', 'e': 'f'} ask_message = ['ask', ''] ask_message = json.dumps(ask_message).encode() async def get(): return await services.get(_socket('ipc:///tmp/n1/peers'), msg=ask_message, ctx=self.ctx, timeout=500) tasks = asyncio.gather(mn1.peer_service.start(), stop_server(mn1.peer_service, 0.3), get()) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) self.assertDictEqual(json.loads(res[-1]), mn1.peer_service.table)
def test_peer_table_updated_on_join_command(self): # Network params issue w1 = Wallet() p1 = Network(wallet=w1, socket_base='tcp://127.0.0.1', ctx=self.ctx) w2 = Wallet() d = DiscoveryServer(wallet=w2, socket_id=_socket('tcp://127.0.0.1:19000'), pepper=PEPPER.encode(), ctx=self.ctx, linger=200) # 1. start network # 2. start discovery of other side # 3. send join request # 4. check to see if the data has been added join_message = ['join', (w2.verifying_key().hex(), 'tcp://127.0.0.1')] join_message = json.dumps(join_message).encode() tasks = asyncio.gather( p1.peer_service.serve(), d.serve(), services.get(_socket('tcp://127.0.0.1:10002'), msg=join_message, ctx=self.ctx, timeout=1000), stop_server(p1.peer_service, 0.3), stop_server(d, 0.3)) loop = asyncio.get_event_loop() loop.run_until_complete(tasks) self.assertEqual(p1.peer_service.table[w2.verifying_key().hex()], 'tcp://127.0.0.1')
def test_peer_server_returns_all_peers_if_doesnt_have_it_or_more_than_response_amount_ipc( self): w1 = Wallet() p1 = Network(wallet=w1, socket_base='ipc:///tmp', ctx=self.ctx) test_dict = {'test': 'value', 'another': 'one', 'something': 'else'} p1.peer_service.table = test_dict find_message = ['find', 'baloney'] find_message = json.dumps(find_message).encode() tasks = asyncio.gather( p1.peer_service.serve(), stop_server(p1.peer_service, 0.3), services.get(_socket('ipc:///tmp/peers'), msg=find_message, ctx=self.ctx, timeout=300)) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) response = res[-1] response = response.decode() response = json.loads(response) self.assertDictEqual(test_dict, response)
def test_peer_server_returns_peer_when_asked_ipc(self): w1 = Wallet() p1 = Network(wallet=w1, socket_base='ipc:///tmp', ctx=self.ctx) w2 = Wallet() p1.peer_service.table[w2.verifying_key().hex()] = 'inproc://goodtimes' find_message = ['find', w2.verifying_key().hex()] find_message = json.dumps(find_message).encode() tasks = asyncio.gather( p1.peer_service.serve(), stop_server(p1.peer_service, 0.3), services.get(_socket('ipc:///tmp/peers'), msg=find_message, ctx=self.ctx, timeout=300)) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) response = res[-1] response = response.decode() response = json.loads(response) self.assertEqual(response.get(w2.verifying_key().hex()), 'inproc://goodtimes')
def test_event_service_triggered_when_new_node_added_ipc(self): # Create Network service w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='ipc:///tmp') n1 = '/tmp/n1' try: os.mkdir('/tmp/n1') except: pass # Create Discovery Server w2 = Wallet() d = DiscoveryServer(wallet=w2, socket_id=_socket('ipc:///tmp/n1/discovery'), pepper=PEPPER.encode(), ctx=self.ctx, poll_timeout=2000, linger=200) # Create raw subscriber subscriber = self.ctx.socket(zmq.SUB) subscriber.setsockopt(zmq.SUBSCRIBE, b'') subscriber.connect('ipc:///tmp/events') # TCP takes a bit longer to bind and is prone to dropping messages... sleep(0.3) # Construct the join RPC message join_message = ['join', (w2.verifying_key().hex(), 'ipc:///tmp/n1')] join_message = json.dumps(join_message).encode() # Wrap recv() in an async async def recv(): msg = await subscriber.recv() return msg tasks = asyncio.gather( p1.peer_service.start( ), # Start the PeerService which will process RPC and emit events d.serve( ), # Start Discovery so PeerService can verify they are online services.get(_socket('ipc:///tmp/peers'), msg=join_message, ctx=self.ctx, timeout=3000), # Push out a join request stop_server(p1.peer_service, 1), stop_server(d, 1), recv() # Collect the subscription result ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) expected_list = ['join', [w2.verifying_key().hex(), 'ipc:///tmp/n1']] got_list = json.loads(res[-1].decode()) self.assertListEqual(expected_list, got_list)
def test_find_node_requests_from_others_and_returns_key_if_they_have_it_ipc( self): # Create Network service w1 = Wallet() n1 = NetworkParameters(peer_ipc='peers1', event_ipc='events1', discovery_ipc='discovery1') p1 = Network(wallet=w1, ctx=self.ctx, socket_base='ipc:///tmp', params=n1) # Create Network service w2 = Wallet() n2 = NetworkParameters(peer_ipc='peers2', event_port='events2') p2 = Network(wallet=w2, ctx=self.ctx, socket_base='ipc:///tmp', params=n2) async def get(): return await p1.find_node(_socket('ipc:///tmp/peers2'), w2.verifying_key().hex()) async def stop(n: Network, s): await asyncio.sleep(s) n.peer_service.stop() tasks = asyncio.gather( p1.peer_service.start(), p2.peer_service.start(), get(), stop(p1, 0.3), stop(p2, 0.3), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) self.assertEqual(res[2].get(w2.verifying_key().hex()), 'ipc:///tmp')
def test_find_node_fails_if_cant_find_and_retries_are_up(self): # Create Network service w1 = Wallet() n1 = NetworkParameters(peer_port=10001, event_port=10002) p1 = Network(wallet=w1, ctx=self.ctx, socket_base='tcp://127.0.0.1', params=n1) # Create Network service w2 = Wallet() n2 = NetworkParameters(peer_port=10003, event_port=10004) p2 = Network(wallet=w2, ctx=self.ctx, socket_base='tcp://127.0.0.1', params=n2) w3 = Wallet() async def get(): return await p1.find_node(_socket('tcp://127.0.0.1:10003'), w3.verifying_key().hex(), retries=1) async def stop(n: Network, s): await asyncio.sleep(s) n.peer_service.stop() tasks = asyncio.gather( p1.peer_service.start(), p2.peer_service.start(), get(), stop(p1, 0.3), stop(p2, 0.3), ) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) self.assertIsNone(res[2])
def test_contacts_added_if_network_starts_up_and_mn_seed_provided(self): n1 = '/tmp/n1' make_ipc(n1) mnw1 = Wallet() mn1 = Network(wallet=mnw1, ctx=self.ctx, socket_base=f'ipc://{n1}') mn1.peer_service.table = {'a': 'b', 'c': 'd', 'e': 'f'} mnw2 = Wallet() n2 = '/tmp/n2' make_ipc(n2) mn2 = Network(wallet=mnw2, ctx=self.ctx, socket_base=f'ipc://{n2}', mn_seed='ipc:///tmp/n1') tasks = asyncio.gather(mn1.peer_service.start(), mn2.start(), stop_server(mn1.peer_service, 1)) loop = asyncio.get_event_loop() loop.run_until_complete(tasks)
def test_find_node_returns_self_if_asked_on_peer_address_and_self_is_the_value_ipc( self): # Create Network service w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='ipc:///tmp') async def get(): return await p1.find_node(p1.peer_service_address, w1.verifying_key().hex()) loop = asyncio.get_event_loop() res = loop.run_until_complete(get()) self.assertEqual(res.get(w1.verifying_key().hex()), 'ipc:///tmp')
def test_find_node_gets_node_from_self_if_asked_from_self_and_has_it_as_peer_ipc( self): # Create Network service w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='ipc:///tmp') w2 = Wallet() p1.peer_service.table[w2.verifying_key().hex()] = 'ipc:///tmp123' async def get(): return await p1.find_node(p1.peer_service_address, w2.verifying_key().hex()) loop = asyncio.get_event_loop() res = loop.run_until_complete(get()) self.assertEqual(res.get(w2.verifying_key().hex()), 'ipc:///tmp123')
def test_peer_server_returns_self_when_asked(self): w1 = Wallet() p1 = Network(wallet=w1, socket_base='tcp://127.0.0.1', ctx=self.ctx) find_message = ['find', w1.verifying_key().hex()] find_message = json.dumps(find_message).encode() tasks = asyncio.gather( p1.peer_service.serve(), stop_server(p1.peer_service, 0.3), services.get(_socket('tcp://127.0.0.1:19002'), msg=find_message, ctx=self.ctx, timeout=300)) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) response = res[-1] response = response.decode() response = json.loads(response) self.assertEqual(response.get(w1.verifying_key().hex()), 'tcp://127.0.0.1')
def test_event_service_publisher_starts_up_on_init_ipc(self): w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='ipc:///tmp') test_subscriber = self.ctx.socket(zmq.SUB) test_subscriber.setsockopt(zmq.SUBSCRIBE, b'') test_subscriber.connect('ipc:///tmp/events') # TCP takes a bit longer to bind and is prone to dropping messages... sleep(0.1) async def send(): await p1.peer_service.event_publisher.send(b'waaaa') async def recv(): return await test_subscriber.recv() tasks = asyncio.gather(send(), recv(), stop_server(p1.peer_service, 0.1)) loop = asyncio.get_event_loop() res = loop.run_until_complete(tasks) self.assertEqual(res[1], b'waaaa')
def test_refresh_remove_old_nodes(self): vkbook_args = self.get_vkbook_args() sync.submit_vkbook(vkbook_args, overwrite=True) PhoneBook = VKBook() w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='tcp://127.0.0.1') peeps = { 'stu': 'tcp://127.0.0.1', 'raghu': 'tcp://127.0.0.8', 'tejas': 'tcp://127.0.2.1', 'steve': 'tcp://127.0.54.6' } p1.peer_service.table.peers = peeps ctx2 = zmq.asyncio.Context() masternodes = SocketBook( socket_base='tcp://127.0.0.1', service_type=ServiceType.EVENT, ctx=ctx2, phonebook_function=PhoneBook.contract.get_masternodes) self.assertDictEqual(masternodes.sockets, {}) async def late_refresh(): await asyncio.sleep(0.3) await masternodes.refresh() async def stop(): await asyncio.sleep(0.5) p1.stop() tasks = asyncio.gather(p1.start(discover=False), late_refresh(), stop()) self.loop.run_until_complete(tasks) expected = { 'stu': _socket('tcp://127.0.0.1:{}'.format(EVENT_PORT)), 'raghu': _socket('tcp://127.0.0.8:{}'.format(EVENT_PORT)) } self.assertDictEqual(masternodes.sockets, expected) self.ctx.destroy() self.loop.close() self.ctx = zmq.asyncio.Context() self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='tcp://127.0.0.1') peeps = { 'stu': 'tcp://127.0.2.1', 'raghu': 'tcp://127.0.0.8', 'tejas': 'tcp://127.0.2.1', 'steve': 'tcp://127.0.54.6' } p1.peer_service.table.peers = peeps vkbook_args = self.get_vkbook_args(mns=['stu', 'tejas']) sync.submit_vkbook(vkbook_args, overwrite=True) async def late_refresh(): await asyncio.sleep(0.3) await masternodes.refresh() async def stop(): await asyncio.sleep(1) p1.stop() tasks = asyncio.gather(p1.start(discover=False), late_refresh(), stop()) self.loop.run_until_complete(tasks) expected = { 'stu': _socket('tcp://127.0.2.1:{}'.format(EVENT_PORT)), 'tejas': _socket('tcp://127.0.2.1:{}'.format(EVENT_PORT)), } self.assertDictEqual(masternodes.sockets, expected)
def __init__(self, socket_base, ctx: zmq.asyncio.Context, wallet, constitution: dict, overwrite=False, bootnodes=[], network_parameters=NetworkParameters(), driver=BlockchainDriver(), mn_seed=None, debug=True, store=False): self.driver = driver self.store = store self.blocks = None if self.store: self.blocks = MasterStorage() self.waiting_for_confirmation = False self.log = get_logger('NODE') self.log.propagate = debug self.log.info(constitution) self.socket_base = socket_base self.wallet = wallet self.ctx = ctx self.ctx.max_sockets = 50_000 self.client = ContractingClient( driver=self.driver, submission_filename=cilantro_ee.contracts.__path__[0] + '/submission.s.py') # Sync contracts sync.submit_from_genesis_json_file(cilantro_ee.contracts.__path__[0] + '/genesis.json', client=self.client) sync.submit_node_election_contracts( initial_masternodes=constitution['masternodes'], boot_mns=constitution['masternode_min_quorum'], initial_delegates=constitution['delegates'], boot_dels=constitution['delegate_min_quorum'], client=self.client) self.driver.commit() self.driver.clear_pending_state() self.contacts = VKBook( client=self.client, boot_mn=constitution['masternode_min_quorum'], boot_del=constitution['delegate_min_quorum'], ) self.current_masters = deepcopy(self.contacts.masternodes) self.current_delegates = deepcopy(self.contacts.delegates) self.parameters = Parameters(socket_base, ctx, wallet, contacts=self.contacts) self.socket_authenticator = SocketAuthenticator(ctx=self.ctx) self.elect_masternodes = self.client.get_contract('elect_masternodes') self.elect_delegates = self.client.get_contract('elect_delegates') self.masternode_contract = self.client.get_contract('masternodes') self.delegate_contract = self.client.get_contract('delegates') self.update_sockets() # Cilantro version / upgrade self.version_state = self.client.get_contract('upgrade') self.active_upgrade = self.version_state.quick_read('upg_lock') self.tol_mn = self.version_state.quick_read('tol_mn') self.tot_dl = self.version_state.quick_read('tot_dl') if self.tol_mn is None: self.tol_mn = 0 if self.tot_dl is None: self.tot_dl = 0 self.all_votes = self.tol_mn + self.tot_dl self.mn_votes = self.version_state.quick_read('mn_vote') self.dl_votes = self.version_state.quick_read('dl_vote') # self.pending_cnt = self.all_votes - self.vote_cnt # stuff self.network_parameters = network_parameters self.bootnodes = bootnodes self.constitution = constitution self.overwrite = overwrite # Should have a function to get the current NBN self.block_fetcher = BlockFetcher( wallet=self.wallet, ctx=self.ctx, parameters=self.parameters, ) self.network = Network( wallet=self.wallet, ctx=self.ctx, socket_base=socket_base, bootnodes=self.bootnodes, params=self.network_parameters, initial_del_quorum=deepcopy(self.contacts.delegate_quorum_min), initial_mn_quorum=deepcopy(self.contacts.masternode_quorum_min), mn_to_find=deepcopy(self.contacts.masternodes), del_to_find=deepcopy(self.contacts.delegates), mn_seed=mn_seed) self.nbn_inbox = NBNInbox(socket_id=self.network_parameters.resolve( self.socket_base, service_type=ServiceType.BLOCK_NOTIFICATIONS, bind=True), ctx=self.ctx, driver=self.driver, contacts=self.contacts, wallet=wallet) self.reward_manager = RewardManager(driver=self.driver, debug=True) self.running = False
class Node: def __init__(self, socket_base, ctx: zmq.asyncio.Context, wallet, constitution: dict, overwrite=False, bootnodes=[], network_parameters=NetworkParameters(), driver=BlockchainDriver(), mn_seed=None, debug=True, store=False): self.driver = driver self.store = store self.blocks = None if self.store: self.blocks = MasterStorage() self.waiting_for_confirmation = False self.log = get_logger('NODE') self.log.propagate = debug self.log.info(constitution) self.socket_base = socket_base self.wallet = wallet self.ctx = ctx self.ctx.max_sockets = 50_000 self.client = ContractingClient( driver=self.driver, submission_filename=cilantro_ee.contracts.__path__[0] + '/submission.s.py') # Sync contracts sync.submit_from_genesis_json_file(cilantro_ee.contracts.__path__[0] + '/genesis.json', client=self.client) sync.submit_node_election_contracts( initial_masternodes=constitution['masternodes'], boot_mns=constitution['masternode_min_quorum'], initial_delegates=constitution['delegates'], boot_dels=constitution['delegate_min_quorum'], client=self.client) self.driver.commit() self.driver.clear_pending_state() self.contacts = VKBook( client=self.client, boot_mn=constitution['masternode_min_quorum'], boot_del=constitution['delegate_min_quorum'], ) self.current_masters = deepcopy(self.contacts.masternodes) self.current_delegates = deepcopy(self.contacts.delegates) self.parameters = Parameters(socket_base, ctx, wallet, contacts=self.contacts) self.socket_authenticator = SocketAuthenticator(ctx=self.ctx) self.elect_masternodes = self.client.get_contract('elect_masternodes') self.elect_delegates = self.client.get_contract('elect_delegates') self.masternode_contract = self.client.get_contract('masternodes') self.delegate_contract = self.client.get_contract('delegates') self.update_sockets() # Cilantro version / upgrade self.version_state = self.client.get_contract('upgrade') self.active_upgrade = self.version_state.quick_read('upg_lock') self.tol_mn = self.version_state.quick_read('tol_mn') self.tot_dl = self.version_state.quick_read('tot_dl') if self.tol_mn is None: self.tol_mn = 0 if self.tot_dl is None: self.tot_dl = 0 self.all_votes = self.tol_mn + self.tot_dl self.mn_votes = self.version_state.quick_read('mn_vote') self.dl_votes = self.version_state.quick_read('dl_vote') # self.pending_cnt = self.all_votes - self.vote_cnt # stuff self.network_parameters = network_parameters self.bootnodes = bootnodes self.constitution = constitution self.overwrite = overwrite # Should have a function to get the current NBN self.block_fetcher = BlockFetcher( wallet=self.wallet, ctx=self.ctx, parameters=self.parameters, ) self.network = Network( wallet=self.wallet, ctx=self.ctx, socket_base=socket_base, bootnodes=self.bootnodes, params=self.network_parameters, initial_del_quorum=deepcopy(self.contacts.delegate_quorum_min), initial_mn_quorum=deepcopy(self.contacts.masternode_quorum_min), mn_to_find=deepcopy(self.contacts.masternodes), del_to_find=deepcopy(self.contacts.delegates), mn_seed=mn_seed) self.nbn_inbox = NBNInbox(socket_id=self.network_parameters.resolve( self.socket_base, service_type=ServiceType.BLOCK_NOTIFICATIONS, bind=True), ctx=self.ctx, driver=self.driver, contacts=self.contacts, wallet=wallet) self.reward_manager = RewardManager(driver=self.driver, debug=True) self.running = False async def catchup(self, mn_seed): current = self.driver.get_latest_block_num() latest = await self.block_fetcher.get_latest_block_height(mn_seed) if current == 0: current = 1 for i in range(current, latest): block = await self.block_fetcher.get_block_from_master(i, mn_seed) block = block.to_dict() self.process_block(block) while len(self.nbn_inbox.q) > 0: block = self.nbn_inbox.q.pop(0) self.process_block(block) def should_process(self, block): if self.waiting_for_confirmation: return self.driver.latest_block_num <= block['blockNum'] and block[ 'hash'] != 'f' * 64 else: return self.driver.latest_block_num < block['blockNum'] and block[ 'hash'] != 'f' * 64 def process_block(self, block): # self.driver.reads.clear() # self.driver.cache.clear() # # self.log.info(f'PENDING WRITES :{self.driver.pending_writes}') # self.driver.pending_writes.clear() if self.should_process(block): self.log.info('Processing new block...') self.driver.update_with_block(block) self.reward_manager.issue_rewards(block=block) self.update_sockets() if self.store: self.blocks.store_block(block) #self.reward_manager.issue_rewards(block=block) #self.update_sockets() else: self.log.error('Could not store block...') if self.driver.latest_block_num >= block['blockNum']: self.log.error( f'Latest block num = {self.driver.latest_block_num}') self.log.error(f'New block num = {block["blockNum"]}') if block['hash'] == 'f' * 64: self.log.error(f'Block hash = {block["hash"]}') self.driver.delete_pending_nonces() self.driver.cache.clear() self.nbn_inbox.clean() self.nbn_inbox.update_signers() self.version_check() async def start(self): await self.network.start() # Start block server asyncio.ensure_future(self.nbn_inbox.serve()) # Catchup when joining the network if self.network.mn_seed is not None: await self.catchup( self.network_parameters.resolve(self.network.mn_seed, ServiceType.BLOCK_SERVER)) self.log.info(self.network.peers()) self.parameters.sockets.update(self.network.peers()) # Start block server #asyncio.ensure_future(self.nbn_inbox.serve()) self.running = True def stop(self): self.network.stop() self.nbn_inbox.stop() self.running = False def update_sockets(self): od_mn = self.elect_masternodes.quick_read('top_candidate') od_dl = self.elect_delegates.quick_read('top_candidate') masternodes = self.masternode_contract.quick_read('S', 'members') delegates = self.delegate_contract.quick_read('S', 'members') self.socket_authenticator.add_governance_sockets( masternode_list=masternodes, delegate_list=delegates, on_deck_masternode=od_mn, on_deck_delegate=od_dl) def version_check(self): # check for trigger self.version_state = self.client.get_contract('upgrade') self.mn_votes = self.version_state.quick_read('mn_vote') self.dl_votes = self.version_state.quick_read('dl_vote') if self.version_state: self.log.info('Waiting for Consensys on vote') self.log.info('num masters voted -> {}'.format(self.mn_votes)) self.log.info('num delegates voted -> {}'.format(self.dl_votes)) # Given node is either master or delegate default assumes it to be valid # delegate node_type = False for key in self.contacts.masternodes: if self.wallet.verifying_key().hex() == key: self.log.info("Node Type : Master") node_type = True # check for vote consensys vote_consensus = self.version_state.quick_read('upg_consensus') if vote_consensus: self.log.error('Rebooting Node with new version') version_reboot(bn=self.bootnodes, is_master=node_type) else: self.log.info( '{} waiting for vote on upgrade'.format(node_type)) def get_update_state(self): self.active_upgrade = self.version_state.quick_read('upg_lock') start_time = self.version_state.quick_read('upg_init_time') window = self.version_state.quick_read('upg_window') pepper = self.version_state.quick_read('upg_pepper') self.mn_votes = self.version_state.quick_read('mn_vote') self.dl_votes = self.version_state.quick_read('dl_vote') consensus = self.version_state.quick_read('upg_consensus') print("Upgrade -> {} Cil Pepper -> {}\n" "Init time -> {}, Time Window -> {}\n" "Masters -> {}\n" "Delegates -> {}\n" "Votes -> {}\n " "MN-Votes -> {}\n " "DL-Votes -> {}\n " "Consensus -> {}\n".format(self.active_upgrade, pepper, start_time, window, self.tol_mn, self.tot_dl, self.all_votes, self.mn_votes, self.dl_votes, consensus))
def test_refresh_remove_old_nodes(self): constitution = self.get_vkbook_args() sync.submit_from_genesis_json_file(cilantro_ee.contracts.__path__[0] + '/genesis.json', client=self.client) sync.submit_node_election_contracts( initial_masternodes=constitution['masternodes'], boot_mns=constitution['masternode_min_quorum'], initial_delegates=constitution['delegates'], boot_dels=constitution['delegate_min_quorum'], client=self.client) PhoneBook = VKBook(client=self.client) w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='tcp://127.0.0.1') peeps = { 'stu': 'tcp://127.0.0.1', 'raghu': 'tcp://127.0.0.8', 'tejas': 'tcp://127.0.2.1', 'steve': 'tcp://127.0.54.6' } p1.peer_service.table = peeps ctx2 = zmq.asyncio.Context() masternodes = Parameters(socket_base='tcp://127.0.0.1', wallet=w1, contacts=MockContacts(['stu', 'raghu'], ['tejas', 'steve']), ctx=ctx2) self.assertDictEqual(masternodes.sockets, {}) async def late_refresh(): await asyncio.sleep(0.3) await masternodes.refresh() async def stop(): await asyncio.sleep(0.5) p1.stop() tasks = asyncio.gather(p1.start(discover=False), late_refresh(), stop()) self.loop.run_until_complete(tasks) expected = {'stu': 'tcp://127.0.0.1', 'raghu': 'tcp://127.0.0.8'} self.assertDictEqual(masternodes.sockets, expected) self.ctx.destroy() self.loop.close() self.ctx = zmq.asyncio.Context() self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) w1 = Wallet() p1 = Network(wallet=w1, ctx=self.ctx, socket_base='tcp://127.0.0.1') peeps = { 'stu': 'tcp://127.0.2.1', 'raghu': 'tcp://127.0.0.8', 'tejas': 'tcp://127.0.2.1', 'steve': 'tcp://127.0.54.6' } p1.peer_service.table.peers = peeps vkbook_args = self.get_vkbook_args(mns=['stu', 'tejas']) sync.submit_vkbook(vkbook_args, overwrite=True) async def late_refresh(): await asyncio.sleep(0.3) await masternodes.refresh() async def stop(): await asyncio.sleep(1) p1.stop() tasks = asyncio.gather(p1.start(discover=False), late_refresh(), stop()) self.loop.run_until_complete(tasks) expected = { 'stu': 'tcp://127.0.2.1', 'tejas': 'tcp://127.0.2.1', } self.assertDictEqual(masternodes.sockets, expected)
def test_network_start(self): # 4 nodes # 2 bootnodes # 2 mns, 2 delegates bootnodes = ['ipc:///tmp/n1', 'ipc:///tmp/n3'] mnw1 = Wallet() mnw2 = Wallet() masternodes = [mnw1.verifying_key().hex(), mnw2.verifying_key().hex()] dw1 = Wallet() dw2 = Wallet() delegates = [dw1.verifying_key().hex(), dw2.verifying_key().hex()] constitution = { "masternodes": [ mnw1.verifying_key().hex(), mnw2.verifying_key().hex() ], "masternode_min_quorum": 1, "delegates": [ dw1.verifying_key().hex(), dw2.verifying_key().hex() ], "delegate_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) n2 = '/tmp/n2' make_ipc(n2) mn2 = Masternode(wallet=mnw2, ctx=self.ctx, socket_base=f'ipc://{n2}', bootnodes=bootnodes, constitution=constitution, webserver_port=8081) n3 = '/tmp/n3' make_ipc(n3) d1 = Network(wallet=dw1, ctx=self.ctx, socket_base=f'ipc://{n3}', bootnodes=bootnodes, mn_to_find=masternodes, del_to_find=delegates) n4 = '/tmp/n4' make_ipc(n4) d2 = Network(wallet=dw2, ctx=self.ctx, socket_base=f'ipc://{n4}', bootnodes=bootnodes, mn_to_find=masternodes, del_to_find=delegates) # should test to see all ready signals are recieved tasks = asyncio.gather( mn1.start(), mn2.start(), d1.start(), d2.start() ) async def run(): await tasks await asyncio.sleep(5) mn1.stop() mn2.stop() d1.stop() d2.stop() loop = asyncio.get_event_loop() loop.run_until_complete(run())
def test_wait_for_quorum_to_succeed_only_one_master_ipc(self): # 0 tries n1 = '/tmp/n1' try: os.mkdir('/tmp/n1') except: pass mnw1 = Wallet() mn1 = Network(wallet=mnw1, ctx=self.ctx, socket_base=f'ipc://{n1}') n2 = '/tmp/n2' try: os.mkdir('/tmp/n2') except: pass mnw2 = Wallet() mn2 = Network(wallet=mnw2, ctx=self.ctx, socket_base=f'ipc://{n2}') n3 = '/tmp/n3' try: os.mkdir('/tmp/n3') except: pass dw1 = Wallet() d1 = Network(wallet=dw1, ctx=self.ctx, socket_base=f'ipc://{n3}') n4 = '/tmp/n4' try: os.mkdir('/tmp/n4') except: pass dw2 = Wallet() d2 = Network(wallet=dw2, ctx=self.ctx, socket_base=f'ipc://{n4}') async def get(): return await mn1.wait_for_quorum( 1, 0, [mnw1.verifying_key().hex(), mnw2.verifying_key().hex()], [dw1.verifying_key().hex(), dw2.verifying_key().hex()], initial_peers=[_socket('ipc:///tmp/n2/peers')]) async def stop(n: Network, s): await asyncio.sleep(s) n.peer_service.stop() timeout = 0.3 tasks = asyncio.gather( mn1.peer_service.start(), mn2.peer_service.start(), d1.peer_service.start(), d2.peer_service.start(), get(), stop(mn1, timeout), stop(mn2, timeout), stop(d1, timeout), stop(d1, timeout), ) loop = asyncio.get_event_loop() loop.run_until_complete(tasks) self.assertIn(mnw2.verifying_key().hex(), mn1.peer_service.table)
def test_wait_for_quorum_to_succeed_only_one_master(self): # 0 tries mnw1 = Wallet() n1 = NetworkParameters(peer_port=10001, event_port=10002) mn1 = Network(wallet=mnw1, ctx=self.ctx, socket_base='tcp://127.0.0.1', params=n1) # 1 try mnw2 = Wallet() n2 = NetworkParameters(peer_port=10003, event_port=10004) mn2 = Network(wallet=mnw2, ctx=self.ctx, socket_base='tcp://127.0.0.1', params=n2) dw1 = Wallet() n3 = NetworkParameters(peer_port=10005, event_port=10006) d1 = Network(wallet=dw1, ctx=self.ctx, socket_base='tcp://127.0.0.1', params=n3) # 2 tries <- info in this node should be returned dw2 = Wallet() n4 = NetworkParameters(peer_port=10007, event_port=10008) d2 = Network(wallet=dw2, ctx=self.ctx, socket_base='tcp://127.0.0.1', params=n4) async def get(): return await mn1.wait_for_quorum( 1, 0, [mnw1.verifying_key().hex(), mnw2.verifying_key().hex()], [dw1.verifying_key().hex(), dw2.verifying_key().hex()], initial_peers=[_socket('tcp://127.0.0.1:10003')]) async def stop(n: Network, s): await asyncio.sleep(s) n.peer_service.stop() timeout = 0.3 tasks = asyncio.gather( mn1.peer_service.start(), mn2.peer_service.start(), d1.peer_service.start(), d2.peer_service.start(), get(), stop(mn1, timeout), stop(mn2, timeout), stop(d1, timeout), stop(d1, timeout), ) loop = asyncio.get_event_loop() loop.run_until_complete(tasks) self.assertIn(mnw2.verifying_key().hex(), mn1.peer_service.table)