def _fetch_bad_node(self, remote: Node) -> Optional[BadNode]: enode = remote.uri() cursor = self.db.execute('SELECT * from bad_nodes WHERE enode = ?', (enode, )) row = cursor.fetchone() if not row: return None result = BadNode(row['enode'], row['until'], row['reason'], row['error_count']) return result
def record_blacklist(self, remote: Node, timeout_seconds: int, reason: str) -> None: try: record = self._get_record(remote.uri()) except NoResultFound: expires_at = datetime.datetime.utcnow() + datetime.timedelta( seconds=timeout_seconds) self._create_record(remote, expires_at, reason) else: scaled_expires_at = adjust_repeat_offender_timeout( timeout_seconds, record.error_count + 1, ) self._update_record(remote, scaled_expires_at, reason)
def _create_record(self, remote: Node, expires_at: datetime.datetime, reason: str) -> None: uri = remote.uri() record = BlacklistRecord(uri=uri, expires_at=expires_at, reason=reason) self.session.add(record) # mypy doesn't know about the type of the `commit()` function self.session.commit() # type: ignore usable_delta = expires_at - datetime.datetime.utcnow() self.logger.debug( '%s will not be retried for %s because %s', remote, humanize_seconds(usable_delta.total_seconds()), reason, )
def _create_record(self, remote: Node, timeout_seconds: int, reason: str) -> None: uri = remote.uri() expires_at = datetime.datetime.utcnow() + datetime.timedelta( seconds=timeout_seconds) record = BlacklistRecord(uri=uri, expires_at=expires_at, reason=reason) self.session.add(record) # mypy doesn't know about the type of the `commit()` function self.session.commit() # type: ignore self.logger.debug( '%s will not be retried for %s because %s', remote, humanize_seconds(timeout_seconds), reason, )
async def should_connect_to(self, remote: Node) -> bool: try: record = self._get_record(remote.uri()) except NoResultFound: return True now = datetime.datetime.utcnow() if now < record.expires_at: delta = record.expires_at - now self.logger.debug( 'skipping %s, it failed because "%s" and is not usable for %s', remote, record.reason, humanize_seconds(delta.total_seconds()), ) return False return True
def _record_bad_node(self, remote: Node, timeout: int, reason: str) -> None: enode = remote.uri() bad_node = self._fetch_bad_node(remote) now = datetime.datetime.utcnow() if bad_node: new_error_count = bad_node.error_count + 1 usable_time = now + datetime.timedelta(seconds=timeout * new_error_count) local_time = utc_to_local(usable_time) self.logger.debug('%s will not be retried until %s because %s', remote, local_time, reason) self._update_bad_node(enode, usable_time, reason, new_error_count) return usable_time = now + datetime.timedelta(seconds=timeout) local_time = utc_to_local(usable_time) self.logger.debug('%s will not be retried until %s because %s', remote, local_time, reason) self._insert_bad_node(enode, usable_time, reason, error_count=1)
def _update_record(self, remote: Node, expires_at: datetime.datetime, reason: str) -> None: uri = remote.uri() record = self._get_record(uri) if expires_at > record.expires_at: # only update expiration if it is further in the future than the existing expiration record.expires_at = expires_at record.reason = reason record.error_count += 1 self.session.add(record) # mypy doesn't know about the type of the `commit()` function self.session.commit() # type: ignore usable_delta = expires_at - datetime.datetime.utcnow() self.logger.debug( '%s will not be retried for %s because %s', remote, humanize_seconds(usable_delta.total_seconds()), reason, )
def _update_record(self, remote: Node, timeout_seconds: int, reason: str) -> None: uri = remote.uri() record = self._get_record(uri) record.error_count += 1 adjusted_timeout_seconds = int(timeout_seconds * math.sqrt(record.error_count)) record.expires_at += datetime.timedelta( seconds=adjusted_timeout_seconds) record.reason = reason record.error_count += 1 self.session.add(record) # mypy doesn't know about the type of the `commit()` function self.session.commit() # type: ignore self.logger.debug( '%s will not be retried for %s because %s', remote, humanize_seconds(adjusted_timeout_seconds), reason, )
def track_peer_connection(self, remote: Node, is_outbound: bool, last_connected_at: Optional[datetime.datetime], genesis_hash: Hash32, protocol: str, protocol_version: int, network_id: int) -> None: uri = remote.uri() now = datetime.datetime.utcnow() if self._remote_exists(uri): self.logger.debug2("Updated ETH1 peer record: %s", remote) record = self._get_remote(uri) record.updated_at = now if last_connected_at is not None: record.last_connected_at = last_connected_at record.genesis_hash = genesis_hash.hex() record.protocol = protocol record.protocol_version = protocol_version record.network_id = network_id else: self.logger.debug2("New ETH1 peer record: %s", remote) record = Remote( uri=uri, is_outbound=is_outbound, created_at=now, updated_at=now, last_connected_at=last_connected_at, genesis_hash=genesis_hash.hex(), protocol=protocol, protocol_version=protocol_version, network_id=network_id, ) self.session.add(record) self.session.commit() # type: ignore
async def record_blacklist(self, remote: Node, timeout_seconds: int, reason: str) -> None: if self._record_exists(remote.uri()): self._update_record(remote, timeout_seconds, reason) else: self._create_record(remote, timeout_seconds, reason)