Skip to content

Commit

Permalink
Merge pull request #1976 from opentensor/feat/gus-abe/nonce-implement…
Browse files Browse the repository at this point in the history
…ation

Feat: Nonce implementation improved
  • Loading branch information
gus-opentensor committed Jun 12, 2024
2 parents c4a4d51 + 09ae1da commit 2b2bd40
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 20 deletions.
46 changes: 30 additions & 16 deletions bittensor/axon.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
PostProcessException,
SynapseException,
)
from bittensor.constants import ALLOWED_DELTA, V_7_2_0
from bittensor.threadpool import PriorityThreadPoolExecutor
from bittensor.utils import networking

Expand Down Expand Up @@ -342,12 +343,12 @@ def __init__(
self.port = self.config.axon.port
self.external_ip = (
self.config.axon.external_ip
if self.config.axon.external_ip != None
if self.config.axon.external_ip is not None
else bittensor.utils.networking.get_external_ip()
)
self.external_port = (
self.config.axon.external_port
if self.config.axon.external_port != None
if self.config.axon.external_port is not None
else self.config.axon.port
)
self.full_address = str(self.config.axon.ip) + ":" + str(self.config.axon.port)
Expand Down Expand Up @@ -888,25 +889,38 @@ async def default_verify(self, synapse: bittensor.Synapse):
# Build the unique endpoint key.
endpoint_key = f"{synapse.dendrite.hotkey}:{synapse.dendrite.uuid}"

# Check the nonce from the endpoint key with 4 second delta
allowedDelta = 4000000000

# Requests must have nonces to be safe from replays
if synapse.dendrite.nonce is None:
raise Exception("Missing Nonce")

# If we don't have a nonce stored, ensure that the nonce falls within
# a reasonable delta.

# Updated nonce using NTP implementated at v7.2
if (
self.nonces.get(endpoint_key) is None
and synapse.dendrite.nonce <= time.time_ns() - allowedDelta
):
raise Exception("Nonce is too old")
if (
self.nonces.get(endpoint_key) is not None
and synapse.dendrite.nonce <= self.nonces[endpoint_key]
synapse.dendrite.version is not None
and synapse.dendrite.version >= V_7_2_0
):
raise Exception("Nonce is too old")
# If we don't have a nonce stored, ensure that the nonce falls within
# a reasonable delta.
if (
self.nonces.get(endpoint_key) is None
and synapse.dendrite.nonce
<= time.time_ns() - ALLOWED_DELTA - (synapse.timeout or 0)
):
raise Exception("Nonce is too old")
if (
self.nonces.get(endpoint_key) is not None
and synapse.dendrite.nonce <= self.nonces[endpoint_key]
):
raise Exception("Nonce is too old")
else:
if (
endpoint_key in self.nonces.keys()
and self.nonces[endpoint_key] is not None
and synapse.dendrite.nonce <= self.nonces[endpoint_key]
):
raise Exception("Nonce is too small")

if not keypair.verify(message, synapse.dendrite.signature):
raise Exception(
Expand Down Expand Up @@ -1149,7 +1163,7 @@ async def preprocess(self, request: Request) -> bittensor.Synapse:
# Extracts the request name from the URL path.
try:
request_name = request.url.path.split("/")[1]
except:
except Exception:
raise InvalidRequestNameError(
f"Improperly formatted request. Could not parser request {request.url.path}."
)
Expand All @@ -1164,7 +1178,7 @@ async def preprocess(self, request: Request) -> bittensor.Synapse:

try:
synapse = request_synapse.from_headers(request.headers) # type: ignore
except Exception as e:
except Exception:
raise SynapseParsingError(
f"Improperly formatted request. Could not parse headers {request.headers} into synapse of type {request_name}."
)
Expand All @@ -1175,7 +1189,7 @@ async def preprocess(self, request: Request) -> bittensor.Synapse:
{
"version": str(bittensor.__version_as_int__),
"uuid": str(self.axon.uuid),
"nonce": f"{time.time_ns()}",
"nonce": time.time_ns(),
"status_code": 100,
}
)
Expand Down
20 changes: 20 additions & 0 deletions bittensor/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# The MIT License (MIT)
# Copyright © 2023 OpenTensor Foundation

# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
# the Software.

# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.


ALLOWED_DELTA = 4000000000 # Delta of 4 seconds for nonce validation
V_7_2_0 = 7002000
10 changes: 6 additions & 4 deletions bittensor/dendrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import uuid
import time
import aiohttp

import bittensor
from typing import Optional, List, Union, AsyncGenerator, Any
from bittensor.utils.registration import torch, use_torch
Expand Down Expand Up @@ -311,7 +312,7 @@ def query(
try:
loop = asyncio.get_event_loop()
result = loop.run_until_complete(self.forward(*args, **kwargs))
except:
except Exception:
new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)
result = loop.run_until_complete(self.forward(*args, **kwargs))
Expand Down Expand Up @@ -653,8 +654,6 @@ def preprocess_synapse_for_request(
"""
# Set the timeout for the synapse
synapse.timeout = timeout

# Build the Dendrite headers using the local system's details
synapse.dendrite = bittensor.TerminalInfo(
ip=self.external_ip,
version=bittensor.__version_as_int__,
Expand Down Expand Up @@ -705,7 +704,10 @@ def process_server_response(
# Set the attribute in the local synapse from the corresponding
# attribute in the server synapse
setattr(local_synapse, key, getattr(server_synapse, key))
except:
except Exception as e:
bittensor.logging.info(
f"Ignoring error when setting attribute: {e}"
)
# Ignore errors during attribute setting
pass
else:
Expand Down
3 changes: 3 additions & 0 deletions bittensor/utils/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

# Standard Lib
import os
import urllib
import json
import netaddr

# 3rd party
import requests


Expand Down

0 comments on commit 2b2bd40

Please sign in to comment.