Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bittensor shared request layer #1698

Merged
merged 14 commits into from
Feb 16, 2024

Conversation

ifrit98
Copy link
Contributor

@ifrit98 ifrit98 commented Feb 8, 2024

Creates a generic shared request layer for bittensor subnets to facilitate cross-communication. Introduces the bittensor.subnets.SubnetsAPI abstract class to achieve this.

What does Bittensor communication entail? Typically two processes, (1) preparing data for transit (creating and filling synapses) and (2), processing the responses received from the axon(s).

This protocol uses a handler registry system to associate bespoke interfaces for subnets by implementing two simple abstract functions:

  • prepare_synapse
  • process_responses

These can be implemented as extensions of the generic SubnetsAPI interface. E.g.:

This is abstract, generic, and takes(*args, **kwargs) for flexibility. See the extremely simple base class:

class SubnetsAPI(ABC):
    def __init__(self, wallet: "bt.wallet"):
        self.wallet = wallet
        self.dendrite = bt.dendrite(wallet=wallet)

    async def __call__(self, *args, **kwargs):
        return await self.query_api(*args, **kwargs)

    @abstractmethod
    def prepare_synapse(self, *args, **kwargs) -> Any:
        """
        Prepare the synapse-specific payload.
        """
        ...

    @abstractmethod
    def process_responses(self, responses: List[Union["bt.Synapse", Any]]) -> Any:
        """
        Process the responses from the network.
        """
        ...

Here is a toy example:

from bittensor.subnets import SubnetsAPI
from MySubnet import MySynapse

class MySynapseAPI(SubnetsAPI):
    def __init__(self, wallet: "bt.wallet"):
        super().__init__(wallet)
        self.netuid = 99

    def prepare_synapse(self, prompt: str) -> MySynapse:
        # Do any preparatory work to fill the synapse
        data = do_prompt_injection(prompt)

        # Fill the synapse for transit
        synapse = StoreUser(
            messages=[data],
        )
        # Send it along
        return synapse

    def process_responses(self, responses: List[Union["bt.Synapse", Any]]) -> str:
        # Look through the responses for information required by your application
        for response in responses:
            if response.dendrite.status_code != 200:
                continue
            # potentially apply post processing
            result_data = postprocess_data_from_response(response)
        # return data to the client
        return result_data

You can use a subnet API to the registry by doing the following:
(1) Download and install the specific repo you want
(2) Import the appropriate API handler from bespoke subnets
(3) Make the query given the subnet specific API

See simplified example for subnet 21 below:

# Subnet 21 Interface

class RetrieveUserAPI(SubnetsAPI):
    def __init__(self, wallet: "bt.wallet"):
        super().__init__(wallet)
        self.netuid = 21

    def prepare_synapse(self, cid: str) -> RetrieveUser:
        synapse = RetrieveUser(data_hash=cid)
        return synapse

    def process_responses(self, responses: List[Union["bt.Synapse", Any]]) -> bytes:
        success = False
        decrypted_data = b""
        for response in responses:
            .... # retrieve the data
        return data

 

# import the bespoke subnet API
from storage import StoreUserAPI, RetrieveUserAPI

wallet = bt.wallet()
metagraph = ...
query_axon = ... # logic to retrieve desired axons (e.g. validator set)

bt.logging.info(f"Initiating store_handler: {store_handler}")
cid = await StoreUserAPI(
      axons=query_axons,
      data=b"some data",
      encrypt=False,
      ttl=60 * 60 * 24 * 30,
      encoding="utf-8",
      uid=None,
)

# Now retrieve data from SN21 (storage)
retrieve_response = await RetrieveUserAPI(axons=query_axons, cid=cid)

@ifrit98 ifrit98 marked this pull request as ready for review February 14, 2024 20:47
@ifrit98 ifrit98 changed the title (WIP) shared request layer with register Bittensor shared request layer with register Feb 14, 2024
@ifrit98 ifrit98 changed the title Bittensor shared request layer with register Bittensor shared request layer Feb 15, 2024
@ifrit98 ifrit98 merged commit eb43965 into staging Feb 16, 2024
12 checks passed
@ifrit98 ifrit98 mentioned this pull request Feb 16, 2024
@unconst unconst deleted the feature/bittensor-shared-request-layer/phil branch March 27, 2024 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants