Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 49 additions & 6 deletions gittensor/miner/token_mgmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

from gittensor.constants import BASE_GITHUB_API_URL

# Token cache to avoid re-validating on every request
_cached_token: Optional[str] = None
_cached_validity: Optional[bool] = None
_last_check_time: float = 0.0
TOKEN_CACHE_MAX_AGE_SECONDS = 300 # Re-validate every 5 minutes


def init() -> bool:
"""Initialize and check if GitHub token exists in environment
Expand All @@ -31,11 +37,16 @@

def load_token(quiet: bool = False) -> Optional[str]:
"""
Load GitHub token from environment variable
Load GitHub token from environment variable with caching.

Caches the token validity for 5 minutes to avoid excessive GitHub API calls.
Only re-validates if the token changes or cache expires.

Returns:
Optional[str]: The GitHub access token string if valid, None otherwise
"""
global _cached_token, _cached_validity, _last_check_time

if not quiet:
bt.logging.info('Loading GitHub token from environment.')

Expand All @@ -46,8 +57,26 @@
bt.logging.error('No GitHub token found in GITTENSOR_MINER_PAT environment variable!')
return None

# Test if token is still valid
if is_token_valid(access_token):
# Check if token changed or cache expired
current_time = time.time()
cache_valid = (
_cached_token == access_token and
_cached_validity is not None and
(current_time - _last_check_time) < TOKEN_CACHE_MAX_AGE_SECONDS
)

if cache_valid:
if not quiet:
bt.logging.debug('Using cached GitHub token validity.')
return access_token if _cached_validity else None

# Validate and cache result
is_valid = is_token_valid(access_token)
_cached_token = access_token
_cached_validity = is_valid
_last_check_time = current_time

if is_valid:
if not quiet:
bt.logging.info('GitHub token loaded successfully and is valid.')
return access_token
Expand All @@ -72,10 +101,24 @@
for attempt in range(3):
try:
response = requests.get(f'{BASE_GITHUB_API_URL}/user', headers=headers, timeout=15)
return response.status_code == 200
if response.status_code == 200:
return True
elif response.status_code == 401:
# Unauthorized - token is invalid
return False
elif response.status_code == 429:
# Rate limited - wait and retry with backoff
bt.logging.warning(f'GitHub API rate limited, waiting...')

Check failure on line 111 in gittensor/miner/token_mgmt.py

View workflow job for this annotation

GitHub Actions / ruff-fork

ruff (F541)

gittensor/miner/token_mgmt.py:111:36: F541 f-string without any placeholders help: Remove extraneous `f` prefix
if attempt < 2:
time.sleep(2 ** attempt + 5) # Exponential backoff + 5s
continue
return False
else:
# Other errors - log and retry
bt.logging.warning(f'GitHub API returned status {response.status_code}')
except Exception as e:
bt.logging.warning(f'Error validating GitHub token (attempt {attempt + 1}/3): {e}')
if attempt < 2: # Don't sleep on last attempt
time.sleep(3)
if attempt < 2:
time.sleep(2 ** attempt)

return False
34 changes: 25 additions & 9 deletions neurons/miner.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,34 +53,50 @@ async def blacklist(self, synapse: GitPatSynapse) -> typing.Tuple[bool, str]:
bt.logging.warning('Received a request without a dendrite or hotkey.')
return True, 'Missing dendrite or hotkey'

uid = self.metagraph.hotkeys.index(synapse.dendrite.hotkey)
# Safely get UID, handling case where hotkey is not in metagraph
try:
uid = self.metagraph.hotkeys.index(synapse.dendrite.hotkey)
except ValueError:
# Hotkey not in metagraph
if not self.config.blacklist.allow_non_registered:
bt.logging.trace(f'Blacklisting un-registered hotkey {synapse.dendrite.hotkey}')
return True, 'Unrecognized hotkey'
uid = -1 # Indicate not registered

if not self.config.blacklist.allow_non_registered and synapse.dendrite.hotkey not in self.metagraph.hotkeys:
# Ignore requests from un-registered entities.
bt.logging.trace(f'Blacklisting un-registered hotkey {synapse.dendrite.hotkey}')
return True, 'Unrecognized hotkey'

if self.config.blacklist.force_validator_permit:
# If the config is set to force validator permit, then we should only allow requests from validators.
bt.logging.debug(
f'Validator permit: {self.metagraph.validator_permit[uid]}, Stake: {self.metagraph.S[uid]}'
)
if not self.metagraph.validator_permit[uid] or self.metagraph.S[uid] < self.config.blacklist.min_stake:
bt.logging.warning(f'Blacklisting a request from non-validator hotkey {synapse.dendrite.hotkey}')
return True, 'Non-validator hotkey'
if uid >= 0:
bt.logging.debug(
f'Validator permit: {self.metagraph.validator_permit[uid]}, Stake: {self.metagraph.S[uid]}'
)
if not self.metagraph.validator_permit[uid] or self.metagraph.S[uid] < self.config.blacklist.min_stake:
bt.logging.warning(f'Blacklisting a request from non-validator hotkey {synapse.dendrite.hotkey}')
return True, 'Non-validator hotkey'

bt.logging.trace(f'Not Blacklisting recognized hotkey {synapse.dendrite.hotkey}')
return False, 'Hotkey recognized!'

async def priority(self, synapse: GitPatSynapse) -> float:
"""
Determines the processing priority for incoming token requests.
This function is unchanged.
"""
if synapse.dendrite is None or synapse.dendrite.hotkey is None:
bt.logging.warning('Received a request without a dendrite or hotkey.')
return 0.0

caller_uid = self.metagraph.hotkeys.index(synapse.dendrite.hotkey) # Get the caller index.
# Safely get the caller index, handling case where hotkey is not in metagraph
try:
caller_uid = self.metagraph.hotkeys.index(synapse.dendrite.hotkey) # Get the caller index.
except ValueError:
# Hotkey not in metagraph - return lowest priority
bt.logging.warning(f'Hotkey {synapse.dendrite.hotkey} not in metagraph, returning priority 0.0')
return 0.0

priority = float(self.metagraph.S[caller_uid]) # Return the stake as the priority.
bt.logging.trace(f'Prioritizing {synapse.dendrite.hotkey} with value: {priority}')
return priority
Expand Down
Loading