async def _do_process_communication(self, challenge_hash, challenge_weight, ip, reader, writer): disc: int = create_discriminant(challenge_hash, constants["DISCRIMINANT_SIZE_BITS"]) writer.write((str(len(str(disc))) + str(disc)).encode()) await writer.drain() try: ok = await reader.readexactly(2) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) return if ok.decode() != "OK": return log.info("Got handshake with VDF client.") async with self.lock: self.active_discriminants[challenge_hash] = (writer, challenge_weight, ip) self.active_discriminants_start_time[challenge_hash] = time.time() asyncio.create_task(self._send_iterations(challenge_hash, writer)) # Listen to the client until "STOP" is received. while True: try: data = await reader.readexactly(4) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash in self.active_discriminants: del self.active_discriminants[challenge_hash] if challenge_hash in self.active_discriminants_start_time: del self.active_discriminants_start_time[ challenge_hash] if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) break if data.decode() == "STOP": log.info(f"Stopped client running on ip {ip}.") async with self.lock: writer.write(b"ACK") await writer.drain() break else: try: # This must be a proof, read the continuation. proof = await reader.readexactly(1860) stdout_bytes_io: io.BytesIO = io.BytesIO( bytes.fromhex(data.decode() + proof.decode())) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash in self.active_discriminants: del self.active_discriminants[challenge_hash] if challenge_hash in self.active_discriminants_start_time: del self.active_discriminants_start_time[ challenge_hash] if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) break iterations_needed = uint64( int.from_bytes(stdout_bytes_io.read(8), "big", signed=True)) y = ClassgroupElement.parse(stdout_bytes_io) proof_bytes: bytes = stdout_bytes_io.read() # Verifies our own proof just in case proof_blob = (ClassGroup.from_ab_discriminant( y.a, y.b, disc).serialize() + proof_bytes) x = ClassGroup.from_ab_discriminant(2, 1, disc) if not check_proof_of_time_nwesolowski( disc, x, proof_blob, iterations_needed, constants["DISCRIMINANT_SIZE_BITS"], self.config["n_wesolowski"], ): log.error("My proof is incorrect!") output = ClassgroupElement(y.a, y.b) proof_of_time = ProofOfTime( challenge_hash, iterations_needed, output, self.config["n_wesolowski"], [uint8(b) for b in proof_bytes], ) response = timelord_protocol.ProofOfTimeFinished(proof_of_time) await self._update_avg_ips(challenge_hash, iterations_needed, ip) async with self.lock: self.proofs_to_write.append( OutboundMessage( NodeType.FULL_NODE, Message("proof_of_time_finished", response), Delivery.BROADCAST, )) await self._update_proofs_count(challenge_weight)
async def _do_process_communication(self, challenge_hash, challenge_weight, ip, port): disc: int = create_discriminant(challenge_hash, constants["DISCRIMINANT_SIZE_BITS"]) log.info("Attempting SSH connection") proc = await asyncio.create_subprocess_shell( f"./lib/chiavdf/fast_vdf/vdf_server {port}") # TODO(Florin): Handle connection failure (attempt another server) writer: Optional[StreamWriter] = None reader: Optional[StreamReader] = None for _ in range(10): try: reader, writer = await asyncio.open_connection(ip, port) # socket = writer.get_extra_info("socket") # socket.settimeout(None) break except Exception as e: e_to_str = str(e) await asyncio.sleep(1) if not writer or not reader: raise Exception("Unable to connect to VDF server") writer.write((str(len(str(disc))) + str(disc)).encode()) await writer.drain() ok = await reader.readexactly(2) assert ok.decode() == "OK" log.info("Got handshake with VDF server.") async with self.lock: self.active_discriminants[challenge_hash] = (writer, challenge_weight, ip) self.active_discriminants_start_time[challenge_hash] = time.time() asyncio.create_task(self._send_iterations(challenge_hash, writer)) # Listen to the server until "STOP" is received. while True: try: data = await reader.readexactly(4) except (asyncio.IncompleteReadError, ConnectionResetError) as e: log.warn(f"{type(e)} {e}") break if data.decode() == "STOP": log.info("Stopped server") async with self.lock: writer.write(b"ACK") await writer.drain() await proc.wait() # Server is now available. self.free_servers.append((ip, port)) len_server = len(self.free_servers) log.info(f"Process ended... Server length {len_server}") break else: try: # This must be a proof, read the continuation. proof = await reader.readexactly(1860) stdout_bytes_io: io.BytesIO = io.BytesIO( bytes.fromhex(data.decode() + proof.decode())) except Exception as e: e_to_str = str(e) log.error(f"Socket error: {e_to_str}") iterations_needed = uint64( int.from_bytes(stdout_bytes_io.read(8), "big", signed=True)) y = ClassgroupElement.parse(stdout_bytes_io) proof_bytes: bytes = stdout_bytes_io.read() # Verifies our own proof just in case proof_blob = (ClassGroup.from_ab_discriminant( y.a, y.b, disc).serialize() + proof_bytes) x = ClassGroup.from_ab_discriminant(2, 1, disc) if not check_proof_of_time_nwesolowski( disc, x, proof_blob, iterations_needed, constants["DISCRIMINANT_SIZE_BITS"], self.config["n_wesolowski"], ): log.error("My proof is incorrect!") output = ClassgroupElement(y.a, y.b) proof_of_time = ProofOfTime( challenge_hash, iterations_needed, output, self.config["n_wesolowski"], [uint8(b) for b in proof_bytes], ) response = timelord_protocol.ProofOfTimeFinished(proof_of_time) await self._update_avg_ips(challenge_hash, iterations_needed, ip) async with self.lock: self.proofs_to_write.append( OutboundMessage( NodeType.FULL_NODE, Message("proof_of_time_finished", response), Delivery.BROADCAST, )) await self._update_proofs_count(challenge_weight)