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

Test Incentive E2E #2002

Merged
merged 3 commits into from
Jun 11, 2024
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
13 changes: 13 additions & 0 deletions tests/e2e_tests/multistep/test_axon.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@
repo_name,
)

"""
Test the axon mechanism.

Verify that:
* axon is registered on network as a miner
* ip
* type
* port

are set correctly, and that the miner is currently running

"""


@pytest.mark.asyncio
async def test_axon(local_chain):
Expand Down
10 changes: 10 additions & 0 deletions tests/e2e_tests/multistep/test_dendrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@

logging.basicConfig(level=logging.INFO)

"""
Test the dendrites mechanism.

Verify that:
* dendrite is registered on network as a validator
* stake successfully
* validator permit is set

"""


@pytest.mark.asyncio
async def test_dendrite(local_chain):
Expand Down
306 changes: 306 additions & 0 deletions tests/e2e_tests/multistep/test_incentive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
import asyncio
import logging
import sys
import time

import pytest

import bittensor
from bittensor.commands import (
RegisterCommand,
RegisterSubnetworkCommand,
StakeCommand,
RootRegisterCommand,
RootSetBoostCommand,
)
from tests.e2e_tests.utils import (
setup_wallet,
template_path,
repo_name,
)

logging.basicConfig(level=logging.INFO)

"""
Test the incentive mechanism.

Verify that for the miner:
* trust
* rank
* consensus
* incentive
are updated with proper values after an epoch has passed.

For the validator verify that:
* validator_permit
* validator_trust
* dividends
* stake
are updated with proper values after an epoch has passed.

"""


@pytest.mark.asyncio
async def test_incentive(local_chain):
opendansor marked this conversation as resolved.
Show resolved Hide resolved
# Register root as Alice - the subnet owner and validator
alice_keypair, alice_exec_command, alice_wallet_path = setup_wallet("//Alice")
alice_exec_command(RegisterSubnetworkCommand, ["s", "create"])
# Verify subnet 1 created successfully
assert local_chain.query("SubtensorModule", "NetworksAdded", [1]).serialize()

# Register Bob as miner
bob_keypair, bob_exec_command, bob_wallet_path = setup_wallet("//Bob")

# Register Alice as neuron to the subnet
alice_exec_command(
RegisterCommand,
[
"s",
"register",
"--netuid",
"1",
"--wallet.name",
"default",
"--wallet.hotkey",
"default",
"--wallet.path",
alice_wallet_path,
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9945",
"--no_prompt",
],
)

# Register Bob as neuron to the subnet
bob_exec_command(
RegisterCommand,
[
"s",
"register",
"--netuid",
"1",
"--wallet.name",
"default",
"--wallet.hotkey",
"default",
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9945",
"--no_prompt",
],
)

subtensor = bittensor.subtensor(network="ws://localhost:9945")
# assert two neurons are in network
assert len(subtensor.neurons(netuid=1)) == 2

# Alice to stake to become to top neuron after the first epoch
alice_exec_command(
StakeCommand,
[
"stake",
"add",
"--amount",
"10000",
],
)

# register Bob as miner
cmd = " ".join(
[
f"{sys.executable}",
f'"{template_path}{repo_name}/neurons/miner.py"',
"--no_prompt",
"--netuid",
"1",
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9945",
"--wallet.path",
bob_wallet_path,
"--wallet.name",
"default",
"--wallet.hotkey",
"default",
"--logging.trace",
]
)

miner_process = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)

# Function to write output to the log file
async def miner_write_output(stream):
log_file = "miner.log"
with open(log_file, "a") as f:
while True:
line = await stream.readline()
if not line:
break
f.write(line.decode())
f.flush()

# Create tasks to read stdout and stderr concurrently
asyncio.create_task(miner_write_output(miner_process.stdout))
asyncio.create_task(miner_write_output(miner_process.stderr))

await asyncio.sleep(
5
) # wait for 5 seconds for the metagraph to refresh with latest data

# register Alice as validator
cmd = " ".join(
[
f"{sys.executable}",
f'"{template_path}{repo_name}/neurons/validator.py"',
"--no_prompt",
"--netuid",
"1",
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9945",
"--wallet.path",
alice_wallet_path,
"--wallet.name",
"default",
"--wallet.hotkey",
"default",
"--logging.trace",
]
)
# run validator in the background

validator_process = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)

# Function to write output to the log file
async def validator_write_output(stream):
log_file = "validator.log"
with open(log_file, "a") as f:
while True:
line = await stream.readline()
if not line:
break
f.write(line.decode())
f.flush()

# Create tasks to read stdout and stderr concurrently
asyncio.create_task(validator_write_output(validator_process.stdout))
asyncio.create_task(validator_write_output(validator_process.stderr))

await asyncio.sleep(
5
) # wait for 5 seconds for the metagraph and subtensor to refresh with latest data

# register validator with root network
alice_exec_command(
RootRegisterCommand,
[
"root",
"register",
"--netuid",
"1",
"--wallet.name",
"default",
"--wallet.hotkey",
"default",
"--subtensor.chain_endpoint",
"ws://localhost:9945",
],
)

alice_exec_command(
RootSetBoostCommand,
[
"root",
"boost",
"--netuid",
"1",
"--increase",
"100",
"--wallet.name",
"default",
"--wallet.hotkey",
"default",
"--subtensor.chain_endpoint",
"ws://localhost:9945",
],
)

# get latest metagraph
metagraph = bittensor.metagraph(netuid=1, network="ws://localhost:9945")

# get current emissions
bob_neuron = metagraph.neurons[1]
assert bob_neuron.incentive == 0
assert bob_neuron.consensus == 0
assert bob_neuron.rank == 0
assert bob_neuron.trust == 0

alice_neuron = metagraph.neurons[0]
assert alice_neuron.validator_permit is False
assert alice_neuron.dividends == 0
assert alice_neuron.stake.tao == 9999.999999
assert alice_neuron.validator_trust == 0

# wait until 360 blocks pass (subnet tempo)
wait_epoch(360, subtensor)

# for some reason the weights do not get set through the template. Set weight manually.
alice_wallet = bittensor.wallet()
alice_wallet._hotkey = alice_keypair
subtensor._do_set_weights(
wallet=alice_wallet,
uids=[1],
vals=[65535],
netuid=1,
version_key=0,
wait_for_inclusion=True,
wait_for_finalization=True,
)

# wait epoch until weight go into effect
wait_epoch(360, subtensor)

# refresh metagraph
metagraph = bittensor.metagraph(netuid=1, network="ws://localhost:9945")

# get current emissions and validate that Alice has gotten tao
bob_neuron = metagraph.neurons[1]
assert bob_neuron.incentive == 1
assert bob_neuron.consensus == 1
assert bob_neuron.rank == 1
assert bob_neuron.trust == 1

alice_neuron = metagraph.neurons[0]
assert alice_neuron.validator_permit is True
assert alice_neuron.dividends == 1
assert alice_neuron.stake.tao == 9999.999999
assert alice_neuron.validator_trust == 1


def wait_epoch(interval, subtensor):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Usually functions-helpers are placed before the functions that call it. It's just easier to navigate.

current_block = subtensor.get_current_block()
next_tempo_block_start = (current_block - (current_block % interval)) + interval
while current_block < next_tempo_block_start:
time.sleep(1) # Wait for 1 second before checking the block number again
current_block = subtensor.get_current_block()
if current_block % 10 == 0:
print(
f"Current Block: {current_block} Next tempo at: {next_tempo_block_start}"
)
logging.info(
f"Current Block: {current_block} Next tempo at: {next_tempo_block_start}"
)
12 changes: 12 additions & 0 deletions tests/e2e_tests/subcommands/weights/test_commit_weights.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
)
from tests.e2e_tests.utils import setup_wallet

"""
Test the Commit/Reveal weights mechanism.

Verify that:
* Weights are commited
* weights are hashed with salt
--- after an epoch ---
* weights are un-hashed with salt
* weights are properly revealed

"""


def test_commit_and_reveal_weights(local_chain):
# Register root as Alice
Expand Down
Loading