Skip to content

Commit

Permalink
Merge branch 'master' into COM-253-efficient-receipts-transfer
Browse files Browse the repository at this point in the history
# Conflicts:
#	compute_horde/pyproject.toml
#	compute_horde/tests/settings.py
  • Loading branch information
kkowalski-reef committed Jan 6, 2025
2 parents 0419358 + 57419a1 commit 3e45c7a
Show file tree
Hide file tree
Showing 17 changed files with 613 additions and 1,527 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,38 @@ This is achieved by distributing $TAO tokens to incentivize:
Bittensor's end goal is to create an unstoppable, self-sustaining ecosystem free from single-point control, enabling innovation and resilience for the entire network.
ComputeHorde adds GPU-powered validation to this ecosystem, helping other subnets operate effectively without relying on centralized cloud services.

## Scoring Mechanism (being reworked currently)

The scoring mechanism in ComputeHorde is designed to **incentivize miners to perform organic jobs** while
maintaining accountability and fairness in the network.

The goal is to eliminate the current disincentive where miners avoid organic jobs to prevent penalties for rejecting synthetic jobs.

### Formula (calculated per validator):

- **1 point** for each successfully completed synthetic job.
- (in development) **1 point** for each successfully completed organic job.
- (in development) **1 point** for each **properly rejected** synthetic job.

A **successfully completed job** is one that finishes within a specified timeout.

A synthetic job is considered **properly rejected** when the miner provides a receipt proving they are currently
occupied with an **organic job** from another validator (with a minimum of 50k stake).

### Dancing Bonus

Miners who implement **dancing**—moving their executors between different UIDs—receive a **30% bonus** (as of December 2024) to their scores.

This encourages variance, which is essential for preventing [weight-copying](#discouraging-weight-copying).

### Hardware Classes and Configurable Weights

Each hardware class supported by ComputeHorde has a configurable weight parameter.
These weights determine the relative contribution of a miner's work to their ultimate score.

This system allows the network to prioritize specific hardware classes based on utility and demand,
creating a flexible and fair reward structure.

## Components

### **Facilitator**
Expand Down
30 changes: 28 additions & 2 deletions compute_horde/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# compute-horde

## Common django models
## Receipts

### Common django models

This library contains common Django models for the receipts.
To use them, update your `INSTALLED_APPS`:
```python
Expand All @@ -11,8 +14,31 @@ INSTALLED_APPS = [
]
```

## Migrations
### Migrations

To make new migrations after doing some changes in the model files, run:
```shell
DJANGO_SETTINGS_MODULE=compute_horde.settings uv run django-admin makemigrations
```

## Blockchain

This library contains common logic for interacting with the blockchain (subtensor).

To use it, update your `INSTALLED_APPS`:
```python
INSTALLED_APPS = [
...,
'compute_horde.blockchain',
...,
]
```

### Block cache

This is a cheap-to-query store that stores the current block number.

Usage:

* Add `compute_horde.blockchain.tasks.update_block_cache` as a Celery Beat task with some reasonable frequency (like 1 or 2 s)
* To get the current block number from cache, use `aget_current_block` (or `get_current_block`).
Empty file.
17 changes: 17 additions & 0 deletions compute_horde/compute_horde/blockchain/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from django.apps import AppConfig


class ComputeHordeBlockchainConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "compute_horde.blockchain"
verbose_name = "Blockchain"

def ready(self):
from django.conf import settings

# Check if a required setting is defined
if not hasattr(settings, "BITTENSOR_NETWORK"):
raise ValueError(
"The setting 'BITTENSOR_NETWORK' is required in your settings.py "
"for 'compute_horde.blockchain' to function properly. Please define it."
)
51 changes: 51 additions & 0 deletions compute_horde/compute_horde/blockchain/block_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import asyncio
import functools

import bittensor
from asgiref.sync import async_to_sync
from django.conf import settings
from django.core.cache import cache

_BLOCK_CACHE_KEY = getattr(
settings, "COMPUTE_HORDE_BLOCK_CACHE_KEY", "compute_horde.blockchain.block_cache.current_block"
)
_BLOCK_CACHE_TIMEOUT = getattr(settings, "COMPUTE_HORDE_BLOCK_CACHE_TIMEOUT", 2)


class BlockNotInCacheError(KeyError):
pass


@functools.cache
def _get_subtensor(network):
return bittensor.subtensor(network)


async def aget_current_block(timeout: float = 1.0) -> int:
"""
Gets the current block number from cache. Waits for ``timeout`` seconds if it's not there.
:param timeout: Number of seconds to wait for the block. Pass 0 to return or raise an exception immediately instead.
:raise BlockNotInCacheError: If block was not found in cache.
"""
# Note: cache.get here is not async.
current_block: int = cache.get(_BLOCK_CACHE_KEY)
if current_block is not None:
return current_block

if timeout <= 0:
raise BlockNotInCacheError(_BLOCK_CACHE_KEY)

await asyncio.sleep(timeout)

return await aget_current_block(timeout=0)


get_current_block = async_to_sync(aget_current_block)


def cache_current_block() -> None:
subtensor = _get_subtensor(network=settings.BITTENSOR_NETWORK)
current_block = subtensor.get_current_block()

cache.set(_BLOCK_CACHE_KEY, current_block, _BLOCK_CACHE_TIMEOUT)
13 changes: 13 additions & 0 deletions compute_horde/compute_horde/blockchain/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import logging

from celery import shared_task

from .block_cache import cache_current_block

logger = logging.getLogger(__name__)


@shared_task()
def update_block_cache():
logger.info("Updating block cache")
cache_current_block()
7 changes: 6 additions & 1 deletion compute_horde/compute_horde/settings.py
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
INSTALLED_APPS = ["compute_horde.receipts"]
INSTALLED_APPS = [
"compute_horde.blockchain",
"compute_horde.receipts",
]

BITTENSOR_NETWORK = "local"
1 change: 1 addition & 0 deletions compute_horde/noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def test(session):
"-vv",
"tests",
*session.posargs,
env={"DJANGO_SETTINGS_MODULE": "tests.settings"},
)


Expand Down
Loading

0 comments on commit 3e45c7a

Please sign in to comment.