Skip to content
Merged
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
60 changes: 15 additions & 45 deletions tests/e2e_tests/test_incentive.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@

import pytest

from bittensor import Balance

from tests.e2e_tests.utils.chain_interactions import (
sudo_set_hyperparameter_values,
wait_epoch,
sudo_set_admin_utils,
)


@pytest.mark.asyncio
@pytest.mark.parametrize("local_chain", [False], indirect=True)
async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wallet):
"""
Test the incentive mechanism and interaction of miners/validators
Expand All @@ -35,21 +31,6 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa
# Verify subnet <netuid> created successfully
assert subtensor.subnet_exists(netuid), "Subnet wasn't created successfully"

# Change tempo to 10
tempo_set = 10
assert (
sudo_set_admin_utils(
local_chain,
alice_wallet,
call_function="sudo_set_tempo",
call_params={"netuid": netuid, "tempo": tempo_set},
return_error_message=True,
)[0]
is True
)
tempo = subtensor.get_subnet_hyperparameters(netuid=netuid).tempo
assert tempo_set == tempo

# Register Bob as a neuron on the subnet
assert subtensor.burned_register(
bob_wallet, netuid
Expand All @@ -60,27 +41,9 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa
len(subtensor.neurons(netuid=netuid)) == 2
), "Alice & Bob not registered in the subnet"

# Add stake for Alice
assert subtensor.add_stake(
alice_wallet,
netuid=netuid,
amount=Balance.from_tao(1_000),
wait_for_inclusion=True,
wait_for_finalization=True,
), "Failed to add stake for Alice"

# Wait for the first epoch to pass
await wait_epoch(subtensor, netuid)

# Add further stake so validator permit is activated
assert subtensor.add_stake(
alice_wallet,
netuid=netuid,
amount=Balance.from_tao(1_000),
wait_for_inclusion=True,
wait_for_finalization=True,
), "Failed to add stake for Alice"

# Get latest metagraph
metagraph = subtensor.metagraph(netuid)

Expand All @@ -91,6 +54,9 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa
assert alice_neuron.dividends == 0
assert alice_neuron.stake.tao > 0
assert alice_neuron.validator_trust == 0
assert alice_neuron.incentive == 0
assert alice_neuron.consensus == 0
assert alice_neuron.rank == 0

bob_neuron = metagraph.neurons[1]

Expand All @@ -109,12 +75,13 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa
)

async with templates.miner(bob_wallet, netuid):
async with templates.validator(alice_wallet, netuid):
# Wait for the Validator to process and set_weights
await asyncio.sleep(5)
async with templates.validator(alice_wallet, netuid) as validator:
# wait for the Validator to process and set_weights
async with asyncio.timeout(15):
await validator.set_weights.wait()

# Wait few epochs
await wait_epoch(subtensor, netuid, times=2)
await wait_epoch(subtensor, netuid, times=4)

# Refresh metagraph
metagraph = subtensor.metagraph(netuid)
Expand All @@ -125,12 +92,15 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa
assert alice_neuron.validator_permit is True
assert alice_neuron.dividends == 1.0
assert alice_neuron.stake.tao > 0
assert alice_neuron.validator_trust == 1
assert alice_neuron.validator_trust > 0.99
assert alice_neuron.incentive < 0.5
assert alice_neuron.consensus < 0.5
assert alice_neuron.rank < 0.5

bob_neuron = metagraph.neurons[1]
assert bob_neuron.incentive == 1
assert bob_neuron.consensus == 1
assert bob_neuron.rank == 1
assert bob_neuron.incentive > 0.5
assert bob_neuron.consensus > 0.5
assert bob_neuron.rank > 0.5
assert bob_neuron.trust == 1

print("✅ Passed test_incentive")
154 changes: 105 additions & 49 deletions tests/e2e_tests/utils/e2e_test_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
import contextlib
import os
import shutil
import subprocess
Expand Down Expand Up @@ -84,6 +83,107 @@ def uninstall_templates(install_dir):


class Templates:
class Miner:
def __init__(self, dir, wallet, netuid):
self.dir = dir
self.wallet = wallet
self.netuid = netuid
self.process = None

self.started = asyncio.Event()

async def __aenter__(self):
self.process = await asyncio.create_subprocess_exec(
sys.executable,
f"{self.dir}/miner.py",
"--netuid",
str(self.netuid),
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9944",
"--wallet.path",
self.wallet.path,
"--wallet.name",
self.wallet.name,
"--wallet.hotkey",
"default",
env={
"BT_LOGGING_INFO": "1",
},
stdout=asyncio.subprocess.PIPE,
)

self.__reader_task = asyncio.create_task(self._reader())

async with asyncio.timeout(30):
await self.started.wait()

return self

async def __aexit__(self, exc_type, exc_value, traceback):
self.process.terminate()
self.__reader_task.cancel()

await self.process.wait()

async def _reader(self):
async for line in self.process.stdout:
if b"Starting main loop" in line:
self.started.set()

class Validator:
def __init__(self, dir, wallet, netuid):
self.dir = dir
self.wallet = wallet
self.netuid = netuid
self.process = None

self.started = asyncio.Event()
self.set_weights = asyncio.Event()

async def __aenter__(self):
self.process = await asyncio.create_subprocess_exec(
sys.executable,
f"{self.dir}/validator.py",
"--netuid",
str(self.netuid),
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9944",
"--wallet.path",
self.wallet.path,
"--wallet.name",
self.wallet.name,
"--wallet.hotkey",
"default",
env={
"BT_LOGGING_INFO": "1",
},
stdout=asyncio.subprocess.PIPE,
)

self.__reader_task = asyncio.create_task(self._reader())

async with asyncio.timeout(30):
await self.started.wait()

return self

async def __aexit__(self, exc_type, exc_value, traceback):
self.process.terminate()
self.__reader_task.cancel()

await self.process.wait()

async def _reader(self):
async for line in self.process.stdout:
if b"Starting validator loop." in line:
self.started.set()
elif b"Successfully set weights and Finalized." in line:
self.set_weights.set()

def __init__(self):
self.dir = clone_or_update_templates()

Expand All @@ -93,52 +193,8 @@ def __enter__(self):
def __exit__(self, exc_type, exc_value, traceback):
uninstall_templates(self.dir)

@contextlib.asynccontextmanager
async def miner(self, wallet, netuid):
process = await asyncio.create_subprocess_exec(
sys.executable,
f"{self.dir}/miner.py",
"--netuid",
str(netuid),
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9944",
"--wallet.path",
wallet.path,
"--wallet.name",
wallet.name,
"--wallet.hotkey",
"default",
)

yield

process.terminate()

await process.wait()

@contextlib.asynccontextmanager
async def validator(self, wallet, netuid):
process = await asyncio.create_subprocess_exec(
sys.executable,
f"{self.dir}/validator.py",
"--netuid",
str(netuid),
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9944",
"--wallet.path",
wallet.path,
"--wallet.name",
wallet.name,
"--wallet.hotkey",
"default",
)

yield

process.terminate()
def miner(self, wallet, netuid):
return self.Miner(self.dir, wallet, netuid)

await process.wait()
def validator(self, wallet, netuid):
return self.Validator(self.dir, wallet, netuid)
Loading