async def _send_message(self, message: Message): encoded: bytes = bytes(message) size = len(encoded) assert len(encoded) < (2**(LENGTH_BYTES * 8)) if not self.outbound_rate_limiter.process_msg_and_check(message): if not is_localhost(self.peer_host): self.log.debug( f"Rate limiting ourselves. message type: {ProtocolMessageTypes(message.type).name}, " f"peer: {self.peer_host}") # TODO: fix this special case. This function has rate limits which are too low. if ProtocolMessageTypes( message.type) != ProtocolMessageTypes.respond_peers: asyncio.create_task( self._wait_and_retry(message, self.outgoing_queue)) return None else: self.log.debug( f"Not rate limiting ourselves. message type: {ProtocolMessageTypes(message.type).name}, " f"peer: {self.peer_host}") await self.ws.send_bytes(encoded) self.log.debug( f"-> {ProtocolMessageTypes(message.type).name} to peer {self.peer_host} {self.peer_node_id}" ) self.bytes_written += size
def connection_closed(self, connection: WSChiaConnection, ban_time: int): if is_localhost(connection.peer_host) and ban_time != 0: self.log.warning( f"Trying to ban localhost for {ban_time}, but will not ban") ban_time = 0 self.log.info( f"Connection closed: {connection.peer_host}, node id: {connection.peer_node_id}" ) if ban_time > 0: ban_until: float = time.time() + ban_time self.log.warning( f"Banning {connection.peer_host} for {ban_time} seconds") if connection.peer_host in self.banned_peers: if ban_until > self.banned_peers[connection.peer_host]: self.banned_peers[connection.peer_host] = ban_until else: self.banned_peers[connection.peer_host] = ban_until if connection.peer_node_id in self.all_connections: self.all_connections.pop(connection.peer_node_id) if connection.connection_type is not None: if connection.peer_node_id in self.connection_by_type[ connection.connection_type]: self.connection_by_type[connection.connection_type].pop( connection.peer_node_id) else: # This means the handshake was enver finished with this peer self.log.debug( f"Invalid connection type for connection {connection.peer_host}," f" while closing. Handshake never finished.") on_disconnect = getattr(self.node, "on_disconnect", None) if on_disconnect is not None: on_disconnect(connection) self.cancel_tasks_from_peer(connection.peer_node_id)
async def _send_message(self, message: Message): encoded: bytes = bytes(message) size = len(encoded) assert len(encoded) < (2**(LENGTH_BYTES * 8)) if not self.outbound_rate_limiter.process_msg_and_check(message): if not is_localhost(self.peer_host): self.log.debug( f"Rate limiting ourselves. message type: {ProtocolMessageTypes(message.type).name}, " f"peer: {self.peer_host}") async def wait_and_retry(msg: Message, queue: asyncio.Queue): try: await asyncio.sleep(1) await queue.put(msg) except Exception as e: self.log.debug( f"Exception {e} while waiting to retry sending rate limited message" ) return asyncio.create_task( wait_and_retry(message, self.outgoing_queue)) return else: self.log.debug( f"Not rate limiting ourselves. message type: {ProtocolMessageTypes(message.type).name}, " f"peer: {self.peer_host}") await self.ws.send_bytes(encoded) self.log.info( f"-> {ProtocolMessageTypes(message.type).name} to peer {self.peer_host} {self.peer_node_id}" ) self.bytes_written += size
def is_duplicate_or_self_connection(self, target_node: PeerInfo) -> bool: if is_localhost(target_node.host) and target_node.port == self._port: # Don't connect to self self.log.debug(f"Not connecting to {target_node}") return True for connection in self.all_connections.values(): if connection.host == target_node.host and connection.peer_server_port == target_node.port: self.log.debug(f"Not connecting to {target_node}, duplicate connection") return True return False
async def _send_message(self, message: Message): encoded: bytes = bytes(message) size = len(encoded) assert len(encoded) < (2**(LENGTH_BYTES * 8)) if not self.outbound_rate_limiter.process_msg_and_check(message): if not is_localhost(self.peer_host): self.log.debug( f"Rate limiting ourselves. message type: {ProtocolMessageTypes(message.type).name}, " f"peer: {self.peer_host}") return else: self.log.debug( f"Not rate limiting ourselves. message type: {ProtocolMessageTypes(message.type).name}, " f"peer: {self.peer_host}") await self.ws.send_bytes(encoded) self.log.info( f"-> {ProtocolMessageTypes(message.type).name} to peer {self.peer_host} {self.peer_node_id}" ) self.bytes_written += size
async def _read_one_message(self) -> Optional[Message]: try: message: WSMessage = await self.ws.receive(30) except asyncio.TimeoutError: # self.ws._closed if we didn't receive a ping / pong if self.ws._closed: asyncio.create_task(self.close()) await asyncio.sleep(3) return None return None if self.connection_type is not None: connection_type_str = NodeType(self.connection_type).name.lower() else: connection_type_str = "" if message.type == WSMsgType.CLOSING: self.log.debug( f"Closing connection to {connection_type_str} {self.peer_host}:" f"{self.peer_server_port}/" f"{self.peer_port}") asyncio.create_task(self.close()) await asyncio.sleep(3) elif message.type == WSMsgType.CLOSE: self.log.debug( f"Peer closed connection {connection_type_str} {self.peer_host}:" f"{self.peer_server_port}/" f"{self.peer_port}") asyncio.create_task(self.close()) await asyncio.sleep(3) elif message.type == WSMsgType.CLOSED: if not self.closed: asyncio.create_task(self.close()) await asyncio.sleep(3) return None elif message.type == WSMsgType.BINARY: data = message.data full_message_loaded: Message = Message.from_bytes(data) self.bytes_read += len(data) self.last_message_time = time.time() try: message_type = ProtocolMessageTypes( full_message_loaded.type).name except Exception: message_type = "Unknown" if not self.inbound_rate_limiter.process_msg_and_check( full_message_loaded): if self.local_type == NodeType.FULL_NODE and not is_localhost( self.peer_host): self.log.error( f"Peer has been rate limited and will be disconnected: {self.peer_host}, " f"message: {message_type}") # Only full node disconnects peers, to prevent abuse and crashing timelords, farmers, etc asyncio.create_task(self.close(300)) await asyncio.sleep(3) return None else: self.log.warning( f"Peer surpassed rate limit {self.peer_host}, message: {message_type}, " f"port {self.peer_port} but not disconnecting") return full_message_loaded return full_message_loaded elif message.type == WSMsgType.ERROR: self.log.error(f"WebSocket Error: {message}") if message.data.code == WSCloseCode.MESSAGE_TOO_BIG: asyncio.create_task(self.close(300)) else: asyncio.create_task(self.close()) await asyncio.sleep(3) else: self.log.error(f"Unexpected WebSocket message type: {message}") asyncio.create_task(self.close()) await asyncio.sleep(3) return None
async def summary( rpc_port: Optional[int], wallet_rpc_port: Optional[int], harvester_rpc_port: Optional[int], farmer_rpc_port: Optional[int], ) -> None: all_harvesters = await get_harvesters(farmer_rpc_port) blockchain_state = await get_blockchain_state(rpc_port) farmer_running = await is_farmer_running(farmer_rpc_port) wallet_not_ready: bool = False wallet_not_running: bool = False amounts = None try: amounts = await get_wallets_stats(wallet_rpc_port) except Exception as e: if isinstance(e, aiohttp.ClientConnectorError): wallet_not_running = True else: wallet_not_ready = True print("Farming status: ", end="") if blockchain_state is None: print("Not available") elif blockchain_state["sync"]["sync_mode"]: print("Syncing") elif not blockchain_state["sync"]["synced"]: print("Not synced or not connected to peers") elif not farmer_running: print("Not running") else: print("Farming") if amounts is not None: print(f"Total chia farmed: {amounts['farmed_amount'] / units['chia']}") print( f"User transaction fees: {amounts['fee_amount'] / units['chia']}") print( f"Block rewards: {(amounts['farmer_reward_amount'] + amounts['pool_reward_amount']) / units['chia']}" ) print(f"Last height farmed: {amounts['last_height_farmed']}") class PlotStats: total_plot_size = 0 total_plots = 0 if all_harvesters is not None: harvesters_local: dict = {} harvesters_remote: dict = {} for harvester in all_harvesters["harvesters"]: ip = harvester["connection"]["host"] if is_localhost(ip): harvesters_local[harvester["connection"] ["node_id"]] = harvester else: if ip not in harvesters_remote: harvesters_remote[ip] = {} harvesters_remote[ip][harvester["connection"] ["node_id"]] = harvester def process_harvesters(harvester_peers_in: dict): for harvester_peer_id, plots in harvester_peers_in.items(): total_plot_size_harvester = sum( map(lambda x: x["file_size"], plots["plots"])) PlotStats.total_plot_size += total_plot_size_harvester PlotStats.total_plots += len(plots["plots"]) print( f" {len(plots['plots'])} plots of size: {format_bytes(total_plot_size_harvester)}" ) if len(harvesters_local) > 0: print(f"Local Harvester{'s' if len(harvesters_local) > 1 else ''}") process_harvesters(harvesters_local) for harvester_ip, harvester_peers in harvesters_remote.items(): print( f"Remote Harvester{'s' if len(harvester_peers) > 1 else ''} for IP: {harvester_ip}" ) process_harvesters(harvester_peers) print(f"Plot count for all harvesters: {PlotStats.total_plots}") print("Total size of plots: ", end="") print(format_bytes(PlotStats.total_plot_size)) else: print("Plot count: Unknown") print("Total size of plots: Unknown") if blockchain_state is not None: print("Estimated network space: ", end="") print(format_bytes(blockchain_state["space"])) else: print("Estimated network space: Unknown") minutes = -1 if blockchain_state is not None and all_harvesters is not None: proportion = PlotStats.total_plot_size / blockchain_state[ "space"] if blockchain_state["space"] else -1 minutes = int((await get_average_block_time(rpc_port) / 60) / proportion) if proportion else -1 if all_harvesters is not None and PlotStats.total_plots == 0: print("Expected time to win: Never (no plots)") else: print("Expected time to win: " + format_minutes(minutes)) if amounts is None: if wallet_not_running: print( "For details on farmed rewards and fees you should run 'chia start wallet' and 'chia wallet show'" ) elif wallet_not_ready: print( "For details on farmed rewards and fees you should run 'chia wallet show'" ) else: print( "Note: log into your key using 'chia wallet show' to see rewards for each key" )