Skip to content

Commit

Permalink
Merge pull request #1023 from opentensor/release/3.6.0
Browse files Browse the repository at this point in the history
Release 3.6.0
  • Loading branch information
eduardogr committed Dec 13, 2022
2 parents d532ad5 + 844b73d commit 0232ede
Show file tree
Hide file tree
Showing 25 changed files with 714 additions and 353 deletions.
11 changes: 6 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 2.1

orbs:
python: circleci/python@2.0.3
python: circleci/python@2.1.1
# coveralls: coveralls/coveralls@1.0.6

jobs:
Expand All @@ -20,27 +20,28 @@ jobs:
- restore_cache:
name: Restore cached venv
keys:
- v1-pypi-py<< parameters.python-version >>-{{ checksum "requirements.txt" }}
- v1-pypi-py<< parameters.python-version >>-{{ checksum "requirements/prod.txt" }}
- v1-pypi-py<< parameters.python-version >>

- run:
name: Update & Activate venv
command: |
python -m venv env/
. env/bin/activate
pip install -r requirements.txt
python -m pip install --upgrade pip
pip install '.'
- save_cache:
name: Save cached venv
paths:
- "env/"
key: v1-pypi-py<< parameters.python-version >>-{{ checksum "requirements.txt" }}
key: v1-pypi-py<< parameters.python-version >>-{{ checksum "requirements/prod.txt" }}

- run:
name: Install Bittensor
command: |
. env/bin/activate
pip install -e .
pip install -e '.'
- run:
name: Instantiate Mock Wallet & Protos
Expand Down
49 changes: 0 additions & 49 deletions .github/workflows/docker_image_push.yml

This file was deleted.

38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
# Changelog

## 3.5.1 / 2022-11-24

## What's Changed
* [hotfix] pin scalecodec lower by @camfairchild in https://github.com/opentensor/bittensor/pull/1013


**Full Changelog**: https://github.com/opentensor/bittensor/compare/v3.5.0...v3.5.1

## 3.5.0 / 2022-11-24

## What's Changed

- [Fix] allow synapse all (https://github.com/opentensor/bittensor/pull/988)
- allow set synapse All using flag
- add test
- use dot get

- [Feature] Mark registration threads as daemons (https://github.com/opentensor/bittensor/pull/998)
- make solver processes daemons

- [Feature] Validator debug response table (https://github.com/opentensor/bittensor/pull/999)
- Add response table to validator debugging

- [Feature] Validator weight setting improvements (https://github.com/opentensor/bittensor/pull/1000)
- Remove responsive prioritization from validator weight calculation
- Move metagraph_sync just before weight setting
- Add metagraph register to validator
- Update validator epoch conditions
- Log epoch while condition details
- Consume validator nucleus UID queue fully
- Increase synergy table display precision
- Round before casting to int in phrase_cross_entropy
- small fix for changelog and version by @Eugene-hu in https://github.com/opentensor/bittensor/pull/993
- release/3.5.0 by @eduardogr in https://github.com/opentensor/bittensor/pull/1006

**Full Changelog**: https://github.com/opentensor/bittensor/compare/v3.4.3...v3.5.0


## 3.4.3 / 2022-11-15

## What's Changed
Expand Down
26 changes: 26 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
SHELL:=/bin/bash

init-venv:
python3 -m venv venv && source ./venv/bin/activate

clean-venv:
source ./venv/bin/activate && \
pip freeze > make_venv_to_uninstall.txt && \
pip uninstall -r make_venv_to_uninstall.txt && \
rm make_venv_to_uninstall.txt

clean:
rm -rf dist/ && \
rm -rf build/ && \
rm -rf bittensor.egg-info/ && \
rm -rf .pytest_cache/ && \
rm -rf lib/

install:
python3 -m pip install .

install-dev:
python3 -m pip install '.[dev]'

install-cubit:
python3 -m pip install '.[cubit]'
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.5.1
3.6.0
3 changes: 2 additions & 1 deletion bittensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@
nest_asyncio.apply()

# Bittensor code and protocol version.
__version__ = '3.5.1'
__version__ = '3.6.0'
version_split = __version__.split(".")
__version_as_int__ = (100 * int(version_split[0])) + (10 * int(version_split[1])) + (1 * int(version_split[2]))

__new_signature_version__ = 360

# Turn off rich console locals trace.
from rich.traceback import install
Expand Down
101 changes: 65 additions & 36 deletions bittensor/_axon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ def __new__(
if thread_pool == None:
thread_pool = futures.ThreadPoolExecutor( max_workers = config.axon.max_workers )
if server == None:
receiver_hotkey = wallet.hotkey.ss58_address
server = grpc.server( thread_pool,
interceptors=(AuthInterceptor(blacklist=blacklist),),
interceptors=(AuthInterceptor(receiver_hotkey=receiver_hotkey, blacklist=blacklist),),
maximum_concurrent_rpcs = config.axon.maximum_concurrent_rpcs,
options = [('grpc.keepalive_time_ms', 100000),
('grpc.keepalive_timeout_ms', 500000)]
Expand Down Expand Up @@ -341,22 +342,26 @@ def check_forward_callback( forward_callback:Callable, synapses:list = []):
class AuthInterceptor(grpc.ServerInterceptor):
"""Creates a new server interceptor that authenticates incoming messages from passed arguments."""

def __init__(self, key: str = "Bittensor", blacklist: List = []):
def __init__(
self,
receiver_hotkey: str,
blacklist: Callable = None,
):
r"""Creates a new server interceptor that authenticates incoming messages from passed arguments.
Args:
key (str, `optional`):
key for authentication header in the metadata (default = Bittensor)
receiver_hotkey(str):
the SS58 address of the hotkey which should be targeted by RPCs
black_list (Function, `optional`):
black list function that prevents certain pubkeys from sending messages
"""
super().__init__()
self.auth_header_value = key
self.nonces = {}
self.blacklist = blacklist
self.receiver_hotkey = receiver_hotkey

def parse_legacy_signature(
self, signature: str
) -> Union[Tuple[int, str, str, str], None]:
) -> Union[Tuple[int, str, str, str, int], None]:
r"""Attempts to parse a signature using the legacy format, using `bitxx` as a separator"""
parts = signature.split("bitxx")
if len(parts) < 4:
Expand All @@ -367,52 +372,71 @@ def parse_legacy_signature(
except ValueError:
return None
receptor_uuid, parts = parts[-1], parts[:-1]
message, parts = parts[-1], parts[:-1]
pubkey = "".join(parts)
return (nonce, pubkey, message, receptor_uuid)
signature, parts = parts[-1], parts[:-1]
sender_hotkey = "".join(parts)
return (nonce, sender_hotkey, signature, receptor_uuid, 1)

def parse_signature(self, metadata: Dict[str, str]) -> Tuple[int, str, str, str]:
def parse_signature_v2(
self, signature: str
) -> Union[Tuple[int, str, str, str, int], None]:
r"""Attempts to parse a signature using the v2 format"""
parts = signature.split(".")
if len(parts) != 4:
return None
try:
nonce = int(parts[0])
except ValueError:
return None
sender_hotkey = parts[1]
signature = parts[2]
receptor_uuid = parts[3]
return (nonce, sender_hotkey, signature, receptor_uuid, 2)

def parse_signature(
self, metadata: Dict[str, str]
) -> Tuple[int, str, str, str, int]:
r"""Attempts to parse a signature from the metadata"""
signature = metadata.get("bittensor-signature")
if signature is None:
raise Exception("Request signature missing")
parts = self.parse_legacy_signature(signature)
if parts is not None:
return parts
for parser in [self.parse_signature_v2, self.parse_legacy_signature]:
parts = parser(signature)
if parts is not None:
return parts
raise Exception("Unknown signature format")

def check_signature(
self, nonce: int, pubkey: str, signature: str, receptor_uuid: str
self,
nonce: int,
sender_hotkey: str,
signature: str,
receptor_uuid: str,
format: int,
):
r"""verification of signature in metadata. Uses the pubkey and nonce"""
keypair = Keypair(ss58_address=pubkey)
keypair = Keypair(ss58_address=sender_hotkey)
# Build the expected message which was used to build the signature.
message = f"{nonce}{pubkey}{receptor_uuid}"
if format == 2:
message = f"{nonce}.{sender_hotkey}.{self.receiver_hotkey}.{receptor_uuid}"
elif format == 1:
message = f"{nonce}{sender_hotkey}{receptor_uuid}"
else:
raise Exception("Invalid signature version")
# Build the key which uniquely identifies the endpoint that has signed
# the message.
endpoint_key = f"{pubkey}:{receptor_uuid}"
endpoint_key = f"{sender_hotkey}:{receptor_uuid}"

if endpoint_key in self.nonces.keys():
previous_nonce = self.nonces[endpoint_key]
# Nonces must be strictly monotonic over time.
if nonce - previous_nonce <= -10:
if nonce <= previous_nonce:
raise Exception("Nonce is too small")
if not keypair.verify(message, signature):
raise Exception("Signature mismatch")
self.nonces[endpoint_key] = nonce
return

if not keypair.verify(message, signature):
raise Exception("Signature mismatch")
self.nonces[endpoint_key] = nonce

def version_checking(self, metadata: Dict[str, str]):
r"""Checks the header and version in the metadata"""
provided_value = metadata.get("rpc-auth-header")
if provided_value is None or provided_value != self.auth_header_value:
raise Exception("Unexpected caller metadata")

def black_list_checking(self, pubkey: str, method: str):
def black_list_checking(self, hotkey: str, method: str):
r"""Tries to call to blacklist function in the miner and checks if it should blacklist the pubkey"""
if self.blacklist == None:
return
Expand All @@ -424,7 +448,7 @@ def black_list_checking(self, pubkey: str, method: str):
if request_type is None:
raise Exception("Unknown request type")

if self.blacklist(pubkey, request_type):
if self.blacklist(hotkey, request_type):
raise Exception("Request type is blacklisted")

def intercept_service(self, continuation, handler_call_details):
Expand All @@ -433,16 +457,21 @@ def intercept_service(self, continuation, handler_call_details):
metadata = dict(handler_call_details.invocation_metadata)

try:
# version checking
self.version_checking(metadata)

(nonce, pubkey, signature, receptor_uuid) = self.parse_signature(metadata)
(
nonce,
sender_hotkey,
signature,
receptor_uuid,
signature_format,
) = self.parse_signature(metadata)

# signature checking
self.check_signature(nonce, pubkey, signature, receptor_uuid)
self.check_signature(
nonce, sender_hotkey, signature, receptor_uuid, signature_format
)

# blacklist checking
self.black_list_checking(pubkey, method)
self.black_list_checking(sender_hotkey, method)

return continuation(handler_call_details)

Expand Down
24 changes: 18 additions & 6 deletions bittensor/_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -742,15 +742,27 @@ def check_transfer_config( config: 'bittensor.Config'):
sys.exit()
else:
config.dest = str(dest)

# Get current balance and print to user.
if not config.no_prompt:
wallet = bittensor.wallet( config )
subtensor = bittensor.subtensor( config )
with bittensor.__console__.status(":satellite: Checking Balance..."):
account_balance = subtensor.get_balance( wallet.coldkeypub.ss58_address )
bittensor.__console__.print("Balance: [green]{}[/green]".format(account_balance))

# Get amount.
if not config.get('amount'):
amount = Prompt.ask("Enter Tao amount to transfer")
try:
config.amount = float(amount)
except ValueError:
console.print(":cross_mark:[red] Invalid Tao amount[/red] [bold white]{}[/bold white]".format(amount))
sys.exit()
if not config.no_prompt:
amount = Prompt.ask("Enter TAO amount to transfer")
try:
config.amount = float(amount)
except ValueError:
console.print(":cross_mark:[red] Invalid TAO amount[/red] [bold white]{}[/bold white]".format(amount))
sys.exit()
else:
console.print(":cross_mark:[red] Invalid TAO amount[/red] [bold white]{}[/bold white]".format(amount))
sys.exit(1)

def check_unstake_config( config: 'bittensor.Config' ):
if config.subtensor.get('network') == bittensor.defaults.subtensor.network and not config.no_prompt:
Expand Down
Loading

0 comments on commit 0232ede

Please sign in to comment.