def append_node(self, index, load_directory=None): # Create a folder for the node to write logs to etc. root = os.path.abspath( os.path.join(self._workspace, 'node{}'.format(index))) # ensure the workspace folder exits os.makedirs(root, exist_ok=True) if load_directory and index in load_directory: load_from = self._test_files_dir + \ "/nodes_saved/" + load_directory[index] files = os.listdir(load_from) for f in files: shutil.copy(load_from + f, root) port = self._port_start_range + (self._port_range * index) # Create an instance of the constellation - note we don't clear path since # it should be clear unless load_directory is used instance = ConstellationInstance(self._constellation_exe, port, root, clear_path=False) # configure the lanes and slices instance.lanes = self._lanes instance.slices = self._slices assert len( self._nodes ) == index, "Attempt to add node with an index mismatch. Current len: {}, index: {}".format( len(self._nodes), index) self._nodes.append(instance)
def append_node(self, index, load_directory=None): # Create a folder for the node to write logs to etc. root = os.path.abspath( os.path.join(self._workspace, 'node{}'.format(index))) # ensure the workspace folder exits os.makedirs(root, exist_ok=True) if load_directory and index in load_directory: load_from = self._test_files_dir + \ "/nodes_saved/" + load_directory[index] files = os.listdir(load_from) for f in files: shutil.copy(load_from + f, root) port = self._port_start_range + (self._port_range * index) # Create an instance of the constellation - note we don't clear path since # it should be clear unless load_directory is used instance = ConstellationInstance(self._constellation_exe, port, root, clear_path=False) # Possibly soon to be deprecated functionality - set the block interval instance.block_interval = self._block_interval instance.feature_flags = ['synergetic'] # configure the lanes and slices instance.lanes = self._lanes instance.slices = self._slices assert len(self._nodes) == index, \ "Attempt to add node with an index mismatch. Current len: {}, index: {}".format( len(self._nodes), index) self._nodes.append(instance) # Load in genesis file if not self._pos_mode: self.setup_genesis_benefactor(index)
def run(args): # extract common parameters port_start_range = args.start_port port_range = args.port_range # adjust the port range if needed if args.lanes: estimated_port_range = 10 + args.lanes port_range = max(port_range, estimated_port_range) monitor = None nodes = [] # build up all the instances for n in range(args.network_size): root = os.path.abspath( os.path.join(args.workspace, 'node{}'.format(n + 1))) port = port_start_range + (port_range * n) # ensure the workspace folder exits os.makedirs(root, exist_ok=True) instance = ConstellationInstance(args.application, port, root) # configure the lanes and slices if needed if args.lanes: instance.lanes = args.lanes if args.slices: instance.slices = args.slices nodes.append(instance) if args.interconnect == 'chain': # inter connect the nodes (single chain) for n in range(len(nodes)): for m in range(args.chain_length): o = n - (m + 1) if o >= 0: nodes[n].add_peer(nodes[o]) elif args.interconnect == 'chaos': all_nodes = set(list(range(len(nodes)))) connections_pairs = set() for n in all_nodes: possible_nodes = list() for m in all_nodes - {n}: if (n, m) in connections_pairs or (m, n) in connections_pairs: continue possible_nodes.append(m) if len(possible_nodes) == 0: raise RuntimeError( 'Chaos size too large to support this network, please choose a lower number' ) elif len(possible_nodes) > args.chaos_size: random.shuffle(possible_nodes) possible_nodes = possible_nodes[:args.chaos_size] for m in possible_nodes: connections_pairs.add((n, m)) # build a debug map and print it connection_map = {} for n, m in connections_pairs: connections = connection_map.get(n, set()) connections.add(m) connection_map[n] = connections for n, ms in connection_map.items(): print('- {} -> {}'.format(n, ','.join(map(str, ms)))) # make the connections for n, m in connections_pairs: nodes[n].add_peer(nodes[m]) else: assert False # ensure the first node is always mining nodes[0].block_interval = args.block_interval # It needs to know if it is the only node in the network if len(nodes) == 1: nodes[0].standalone = True # add nodes to monitor list if args.follow: monitor = ConstellationMonitor(nodes) # start all the nodes for n, node in enumerate(nodes): print('Starting Node {}...'.format(n)) node.start() print('Starting Node {}...complete'.format(n)) # allow graceful startup of the network if args.interconnect == 'chain': time.sleep(1.0) # wait for the first one to fail try: # allow the monitor to start if monitor is not None: monitor.start() monitoring = True while monitoring: # evaluate all the nodes for node in nodes: exit_code = node.poll() if exit_code is not None: monitoring = False break # wait for a period time.sleep(0.3) except KeyboardInterrupt: pass # normal fail case # stop all the nodes for n, node in enumerate(nodes): print('Stopping Node {}...'.format(n)) node.stop() print('Stopping Node {}...complete'.format(n))