def _run_single(self, hosts, rate, bench_parameters, node_parameters, debug=False): Print.info('Booting testbed...') # Kill any potentially unfinished run and delete logs. self.kill(hosts=hosts, delete_logs=True) Print.info('Killed previous instances') sleep(10) # Run the clients (they will wait for the nodes to be ready). # Filter all faulty nodes from the client addresses (or they will wait # for the faulty nodes to be online). committee = Committee.load(PathMaker.committee_file()) addresses = [f'{x}:{self.settings.front_port}' for x in hosts] rate_share = ceil(rate / committee.size()) # Take faults into account. timeout = node_parameters.timeout_delay client_logs = [PathMaker.client_log_file(i) for i in range(len(hosts))] for host, addr, log_file in zip(hosts, addresses, client_logs): cmd = CommandMaker.run_client(addr, bench_parameters.tx_size, rate_share, timeout, nodes=addresses) self._background_run(host, cmd, log_file) Print.info('Clients boosted...') sleep(10) # Run the nodes. key_files = [PathMaker.key_file(i) for i in range(len(hosts))] dbs = [PathMaker.db_path(i) for i in range(len(hosts))] node_logs = [PathMaker.node_log_file(i) for i in range(len(hosts))] threshold_key_files = [ PathMaker.threshold_key_file(i) for i in range(len(hosts)) ] for host, key_file, threshold_key_file, db, log_file in zip( hosts, key_files, threshold_key_files, dbs, node_logs): cmd = CommandMaker.run_node(key_file, threshold_key_file, PathMaker.committee_file(), db, PathMaker.parameters_file(), debug=debug) self._background_run(host, cmd, log_file) # Wait for the nodes to synchronize Print.info('Waiting for the nodes to synchronize...') sleep(node_parameters.timeout_delay / 1000) # Wait for all transactions to be processed. duration = bench_parameters.duration for _ in progress_bar(range(100), prefix=f'Running benchmark ({duration} sec):'): sleep(ceil(duration / 100)) self.kill(hosts=hosts, delete_logs=False)
def _config(self, hosts, node_parameters): Print.info('Generating configuration files...') # Cleanup all local configuration files. cmd = CommandMaker.cleanup() subprocess.run([cmd], shell=True, stderr=subprocess.DEVNULL) # Recompile the latest code. cmd = CommandMaker.compile().split() subprocess.run(cmd, check=True, cwd=PathMaker.node_crate_path()) # Create alias for the client and nodes binary. cmd = CommandMaker.alias_binaries(PathMaker.binary_path()) subprocess.run([cmd], shell=True) # Generate configuration files. keys = [] key_files = [PathMaker.key_file(i) for i in range(len(hosts))] for filename in key_files: cmd = CommandMaker.generate_key(filename).split() subprocess.run(cmd, check=True) keys += [Key.from_file(filename)] # Generate threshold signature files. nodes = len(hosts) cmd = './node threshold_keys' for i in range(nodes): cmd += ' --filename ' + PathMaker.threshold_key_file(i) cmd = cmd.split() subprocess.run(cmd, capture_output=True, check=True) names = [x.name for x in keys] consensus_addr = [f'{x}:{self.settings.consensus_port}' for x in hosts] front_addr = [f'{x}:{self.settings.front_port}' for x in hosts] tss_keys = [] for i in range(nodes): tss_keys += [TSSKey.from_file(PathMaker.threshold_key_file(i))] ids = [x.id for x in tss_keys] mempool_addr = [f'{x}:{self.settings.mempool_port}' for x in hosts] committee = Committee(names, ids, consensus_addr, front_addr, mempool_addr) committee.print(PathMaker.committee_file()) node_parameters.print(PathMaker.parameters_file()) # Cleanup all nodes. cmd = f'{CommandMaker.cleanup()} || true' g = Group(*hosts, user='******', connect_kwargs=self.connect) g.run(cmd, hide=True) # Upload configuration files. progress = progress_bar(hosts, prefix='Uploading config files:') for i, host in enumerate(progress): c = Connection(host, user='******', connect_kwargs=self.connect) c.put(PathMaker.committee_file(), '.') c.put(PathMaker.key_file(i), '.') c.put(PathMaker.threshold_key_file(i), '.') c.put(PathMaker.parameters_file(), '.') return committee
def _run_single(self, hosts, rate, bench_parameters, node_parameters, debug=False): Print.info('Booting testbed...') # Kill any potentially unfinished run and delete logs. self.kill(hosts=hosts, delete_logs=True) # Run the clients (they will wait for the nodes to be ready). committee = Committee.load(PathMaker.committee_file()) addresses = committee.front_addresses() rate_share = ceil(rate / committee.size()) timeout = node_parameters.timeout_delay client_logs = [PathMaker.client_log_file(i) for i in range(len(hosts))] for host, addr, log_file in zip(hosts, addresses, client_logs): cmd = CommandMaker.run_client(addr, bench_parameters.tx_size, rate_share, timeout, nodes=addresses) self._background_run(host, cmd, log_file) # Run the nodes. key_files = [PathMaker.key_file(i) for i in range(len(hosts))] dbs = [PathMaker.db_path(i) for i in range(len(hosts))] node_logs = [PathMaker.node_log_file(i) for i in range(len(hosts))] for host, key_file, db, log_file in zip(hosts, key_files, dbs, node_logs): cmd = CommandMaker.run_node(key_file, PathMaker.committee_file(), db, PathMaker.parameters_file(), debug=debug) self._background_run(host, cmd, log_file) # Wait for the nodes to synchronize Print.info('Waiting for the nodes to synchronize...') sleep(2 * node_parameters.timeout_delay / 1000) # Wait for all transactions to be processed. duration = bench_parameters.duration for _ in progress_bar(range(20), prefix=f'Running benchmark ({duration} sec):'): sleep(ceil(duration / 20)) self.kill(hosts=hosts, delete_logs=False)
def kill(self, hosts=[], delete_logs=False): assert isinstance(hosts, list) assert isinstance(delete_logs, bool) hosts = hosts if hosts else self.manager.hosts(flat=True) delete_logs = CommandMaker.clean_logs() if delete_logs else 'true' cmd = [delete_logs, f'({CommandMaker.kill()} || true)'] try: g = Group(*hosts, user='******', connect_kwargs=self.connect) g.run(' && '.join(cmd), hide=True) except GroupException as e: raise BenchError('Failed to kill nodes', FabricError(e))
def _update(self, hosts): Print.info( f'Updating {len(hosts)} nodes (branch "{self.settings.branch}")...' ) cmd = [ f'(cd {self.settings.repo_name} && git fetch -f)', f'(cd {self.settings.repo_name} && git checkout -f {self.settings.branch})', f'(cd {self.settings.repo_name} && git pull -f)', 'source $HOME/.cargo/env', f'(cd {self.settings.repo_name}/node && {CommandMaker.compile()})', CommandMaker.alias_binaries( f'./{self.settings.repo_name}/target/release/') ] g = Group(*hosts, user='******', connect_kwargs=self.connect) g.run(' && '.join(cmd), hide=True)
def _logs(self, hosts): # Delete local logs (if any). cmd = CommandMaker.clean_logs() subprocess.run([cmd], shell=True, stderr=subprocess.DEVNULL) # Download log files. progress = progress_bar(hosts, prefix='Downloading logs:') for i, host in enumerate(progress): c = Connection(host, user='******', connect_kwargs=self.connect) c.get(PathMaker.node_log_file(i), local=PathMaker.node_log_file(i)) c.get(PathMaker.client_log_file(i), local=PathMaker.client_log_file(i)) # Parse logs and return the parser. Print.info('Parsing logs and computing performance...') return LogParser.process(PathMaker.logs_path())
def run(self, debug=False): assert isinstance(debug, bool) Print.heading('Starting local benchmark') # Kill any previous testbed. self._kill_nodes() try: Print.info('Setting up testbed...') nodes, rate = self.nodes[0], self.rate[0] # Cleanup all files. cmd = f'{CommandMaker.clean_logs()} ; {CommandMaker.cleanup()}' subprocess.run([cmd], shell=True, stderr=subprocess.DEVNULL) sleep(0.5) # Removing the store may take time. # Recompile the latest code. cmd = CommandMaker.compile().split() subprocess.run(cmd, check=True, cwd=PathMaker.node_crate_path()) # Create alias for the client and nodes binary. cmd = CommandMaker.alias_binaries(PathMaker.binary_path()) subprocess.run([cmd], shell=True) # Generate configuration files. keys = [] key_files = [PathMaker.key_file(i) for i in range(nodes)] for filename in key_files: cmd = CommandMaker.generate_key(filename).split() subprocess.run(cmd, check=True) keys += [Key.from_file(filename)] names = [x.name for x in keys] committee = LocalCommittee(names, self.BASE_PORT) committee.print(PathMaker.committee_file()) self.node_parameters.print(PathMaker.parameters_file()) # Run the clients (they will wait for the nodes to be ready). addresses = committee.front_addresses() rate_share = ceil(rate / nodes) timeout = self.node_parameters.timeout_delay client_logs = [PathMaker.client_log_file(i) for i in range(nodes)] for addr, log_file in zip(addresses, client_logs): cmd = CommandMaker.run_client(addr, self.tx_size, rate_share, timeout) self._background_run(cmd, log_file) # Run the nodes. dbs = [PathMaker.db_path(i) for i in range(nodes)] node_logs = [PathMaker.node_log_file(i) for i in range(nodes)] for key_file, db, log_file in zip(key_files, dbs, node_logs): cmd = CommandMaker.run_node(key_file, PathMaker.committee_file(), db, PathMaker.parameters_file(), debug=debug) self._background_run(cmd, log_file) # Wait for the nodes to synchronize Print.info('Waiting for the nodes to synchronize...') sleep(2 * self.node_parameters.timeout_delay / 1000) # Wait for all transactions to be processed. Print.info(f'Running benchmark ({self.duration} sec)...') sleep(self.duration) self._kill_nodes() # Parse logs and return the parser. Print.info('Parsing logs...') return LogParser.process('./logs') except (subprocess.SubprocessError, ParseError) as e: self._kill_nodes() raise BenchError('Failed to run benchmark', e)
def _kill_nodes(self): try: cmd = CommandMaker.kill().split() subprocess.run(cmd, stderr=subprocess.DEVNULL) except subprocess.SubprocessError as e: raise BenchError('Failed to kill testbed', e)
def run(self, debug=False): assert isinstance(debug, bool) Print.heading('Starting local benchmark') # Kill any previous testbed. self._kill_nodes() try: Print.info('Setting up testbed...') nodes, rate = self.nodes[0], self.rate[0] # Cleanup all files. cmd = f'{CommandMaker.clean_logs()} ; {CommandMaker.cleanup()}' subprocess.run([cmd], shell=True, stderr=subprocess.DEVNULL) sleep(0.5) # Removing the store may take time. # Recompile the latest code. cmd = CommandMaker.compile().split() subprocess.run(cmd, check=True, cwd=PathMaker.node_crate_path()) # Create alias for the client and nodes binary. cmd = CommandMaker.alias_binaries(PathMaker.binary_path()) subprocess.run([cmd], shell=True) # Generate configuration files. keys = [] key_files = [PathMaker.key_file(i) for i in range(nodes)] for filename in key_files: cmd = CommandMaker.generate_key(filename).split() subprocess.run(cmd, check=True) keys += [Key.from_file(filename)] # Generate threshold signature files. cmd = './node threshold_keys' for i in range(nodes): cmd += ' --filename ' + PathMaker.threshold_key_file(i) # print(cmd) cmd = cmd.split() subprocess.run(cmd, capture_output=True, check=True) names = [x.name for x in keys] tss_keys = [] for i in range(nodes): tss_keys += [TSSKey.from_file(PathMaker.threshold_key_file(i))] ids = [x.id for x in tss_keys] committee = LocalCommittee(names, ids, self.BASE_PORT) committee.print(PathMaker.committee_file()) self.node_parameters.print(PathMaker.parameters_file()) # Do not boot faulty nodes. nodes = nodes - self.faults # Run the clients (they will wait for the nodes to be ready). addresses = committee.front rate_share = ceil(rate / nodes) timeout = self.node_parameters.timeout_delay client_logs = [PathMaker.client_log_file(i) for i in range(nodes)] for addr, log_file in zip(addresses, client_logs): cmd = CommandMaker.run_client(addr, self.tx_size, rate_share, timeout) self._background_run(cmd, log_file) if self.node_parameters.protocol == 0: Print.info('Running HotStuff') elif self.node_parameters.protocol == 1: Print.info('Running Async HotStuff') elif self.node_parameters.protocol == 2: Print.info('Running TwoChainVABA') else: Print.info('Wrong protocol type!') return Print.info(f'{self.faults} faults') Print.info( f'Timeout {self.node_parameters.timeout_delay} ms, Network delay {self.node_parameters.network_delay} ms' ) Print.info(f'DDOS attack {self.node_parameters.ddos}') # Run the nodes. dbs = [PathMaker.db_path(i) for i in range(nodes)] node_logs = [PathMaker.node_log_file(i) for i in range(nodes)] threshold_key_files = [ PathMaker.threshold_key_file(i) for i in range(nodes) ] for key_file, threshold_key_file, db, log_file in zip( key_files, threshold_key_files, dbs, node_logs): cmd = CommandMaker.run_node(key_file, threshold_key_file, PathMaker.committee_file(), db, PathMaker.parameters_file(), debug=debug) self._background_run(cmd, log_file) # Wait for the nodes to synchronize Print.info('Waiting for the nodes to synchronize...') sleep(2 * self.node_parameters.timeout_delay / 1000) # Wait for all transactions to be processed. Print.info(f'Running benchmark ({self.duration} sec)...') sleep(self.duration) self._kill_nodes() # Parse logs and return the parser. Print.info('Parsing logs...') return LogParser.process('./logs', self.faults, self.node_parameters.protocol, self.node_parameters.ddos) except (subprocess.SubprocessError, ParseError) as e: self._kill_nodes() raise BenchError('Failed to run benchmark', e)