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
6 changes: 4 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ LOG_ID_PREFIX=
# and the miner's get_asset_price to Pyth Lazer
# https://pyth-lazer.dourolabs.app/v1/latest_price (requires PYTH_API_KEY).
PYTH_BACKEND=hermes
# Free Bearer token from pythdata.app -> Pyth Terminal. Only required when
# PYTH_BACKEND=pro.
# Miner-only. Bearer token from pythdata.app -> Pyth Terminal, used by
# the miner's get_asset_price live-price fetch via Pyth Lazer when
# PYTH_BACKEND=pro. Validators do NOT need this: on `pro` they read the
# public history endpoint above, which takes no auth.
PYTH_API_KEY=
1 change: 0 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ jobs:
runs-on: ubuntu-latest
env:
PYTH_BACKEND: pro
PYTH_API_KEY: ${{ secrets.PYTH_API_KEY }}
steps:
- name: Checkout code
uses: actions/checkout@v5
Expand Down
6 changes: 6 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
from sqlalchemy import create_engine
from testcontainers.postgres import PostgresContainer

# The scoring tests fetch real prices live from Pyth. Default to the Pro
# router (public, no API key) like CI does — the legacy hermes/benchmarks
# endpoint rate-limits (429) under the suite's call volume. `setdefault`
# leaves an explicit `PYTH_BACKEND=hermes` override untouched.
os.environ.setdefault("PYTH_BACKEND", "pro")

postgres = PostgresContainer("postgres:16-alpine")


Expand Down
10 changes: 10 additions & 0 deletions tests/test_forward.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import datetime, timedelta, timezone
import logging
from unittest.mock import patch

# from numpy.testing import assert_almost_equal
import bittensor as bt
Expand Down Expand Up @@ -73,7 +74,12 @@ def test_calculate_moving_average_and_update_rewards(db_engine: Engine):
print("moving_averages_data", moving_averages_data)


# Pin the miner's live-price fetch (Pyth Lazer on PYTH_BACKEND=pro) so these
# tests don't depend on it. PriceDataProvider's history fetch stays live — it
# hits the public Pyth Pro history endpoint and is part of what's scored.
@patch("synth.miner.simulations.get_asset_price", return_value=90000.0)
def test_calculate_moving_average_and_update_rewards_new_miner(
mock_get_asset_price,
db_engine: Engine,
):
miner_uids = [10, 20, 33, 40, 50, 60]
Expand Down Expand Up @@ -173,7 +179,9 @@ def test_calculate_moving_average_and_update_rewards_new_miner(
print("moving_averages_data", moving_averages_data)


@patch("synth.miner.simulations.get_asset_price", return_value=90000.0)
def test_calculate_moving_average_and_update_rewards_new_miner_registration(
mock_get_asset_price,
db_engine: Engine,
):
Comment on lines +182 to 186
bt.logging._logger.setLevel(logging.DEBUG)
Expand Down Expand Up @@ -314,7 +322,9 @@ def test_calculate_moving_average_and_update_rewards_new_miner_registration(
# assert_almost_equal(sum(miner_weights), 0.5, decimal=12)


@patch("synth.miner.simulations.get_asset_price", return_value=90000.0)
def test_calculate_moving_average_and_update_rewards_only_invalid(
mock_get_asset_price,
db_engine: Engine,
):
handler = MinerDataHandler(db_engine)
Expand Down
10 changes: 8 additions & 2 deletions tests/test_simulations.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from unittest.mock import patch

from synth.miner.simulations import generate_simulations
from synth.simulation_input import SimulationInput
from synth.utils.helpers import get_current_time, round_time_to_minutes
from synth.validator.response_validation_v2 import CORRECT, validate_responses


def test_generate_simulations():
# get_asset_price hits a live price feed (Pyth Lazer on PYTH_BACKEND=pro);
# pin it so these tests exercise the simulation math without a network call.
@patch("synth.miner.simulations.get_asset_price", return_value=90000.0)
def test_generate_simulations(mock_get_asset_price):
result = generate_simulations(
asset="BTC",
start_time="2025-02-04T00:00:00+00:00",
Expand All @@ -21,7 +26,8 @@ def test_generate_simulations():
)


def test_run():
@patch("synth.miner.simulations.get_asset_price", return_value=90000.0)
def test_run(mock_get_asset_price):
simulation_input = SimulationInput(
asset="BTC",
time_increment=300,
Expand Down
51 changes: 29 additions & 22 deletions tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime, timedelta, timezone
from unittest.mock import patch


from sqlalchemy import Engine, insert
Expand Down Expand Up @@ -53,28 +54,34 @@ def prepare_random_predictions(db_engine: Engine, start_time: str):
num_simulations=1,
)

simulation_data = {
miner_uids[0]: (
generate_simulations(start_time=start_time),
response_validation_v2.CORRECT,
"1.2",
),
miner_uids[1]: (
generate_simulations(start_time=start_time),
response_validation_v2.CORRECT,
"3",
),
miner_uids[2]: (
generate_simulations(start_time=start_time),
response_validation_v2.CORRECT,
"15",
),
miner_uids[3]: (
generate_simulations(start_time=start_time),
"time out or internal server error (process time is None)",
"2.1",
),
}
# generate_simulations() fetches a live current price via get_asset_price
# (Pyth Lazer when PYTH_BACKEND=pro). Tests must not depend on that
# external call, so pin the price and let the GBM math run on it.
with patch(
"synth.miner.simulations.get_asset_price", return_value=90000.0
):
simulation_data = {
miner_uids[0]: (
generate_simulations(start_time=start_time),
response_validation_v2.CORRECT,
"1.2",
),
miner_uids[1]: (
generate_simulations(start_time=start_time),
response_validation_v2.CORRECT,
"3",
),
miner_uids[2]: (
generate_simulations(start_time=start_time),
response_validation_v2.CORRECT,
"15",
),
miner_uids[3]: (
generate_simulations(start_time=start_time),
"time out or internal server error (process time is None)",
"2.1",
),
}
handler.save_responses(simulation_data, simulation_input, datetime.now())

return handler, simulation_input, miner_uids
Loading