-
Notifications
You must be signed in to change notification settings - Fork 8
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
feat: allow configuring validators from envvar #585
Merged
AgustinRamiroDiaz
merged 6 commits into
main
from
567-sim-deploy-allow-configuring-validators-from-a-file
Nov 11, 2024
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ef00a6c
init feature
AgustinRamiroDiaz ad794e8
add unit tests
AgustinRamiroDiaz b28e2ce
handle amount and fix
AgustinRamiroDiaz dccd85b
improve example
AgustinRamiroDiaz b7bf073
more retries in healthcheck
AgustinRamiroDiaz 8814540
fix e2e test
AgustinRamiroDiaz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import json | ||
from dataclasses import dataclass | ||
from backend.database_handler.accounts_manager import AccountsManager | ||
from backend.database_handler.validators_registry import ValidatorsRegistry | ||
|
||
|
||
@dataclass | ||
class ValidatorConfig: | ||
stake: int | ||
provider: str | ||
model: str | ||
config: dict | None = None | ||
plugin: str | None = None | ||
plugin_config: dict | None = None | ||
amount: int = 1 | ||
|
||
|
||
def initialize_validators( | ||
validators_json: str, | ||
validators_registry: ValidatorsRegistry, | ||
accounts_manager: AccountsManager, | ||
validator_creator=None, | ||
): | ||
""" | ||
Idempotently initialize validators from a JSON string by deleting all existing validators and creating new ones. | ||
|
||
Args: | ||
validators_json: JSON string containing validator configurations | ||
validators_registry: Registry to store validator information | ||
accounts_manager: AccountsManager to create validator accounts | ||
validator_creator: Function to create validators (defaults to endpoints.create_validator) | ||
""" | ||
|
||
if not validators_json: | ||
print("No validators to initialize") | ||
return | ||
|
||
# If no validator_creator is provided, import the default one | ||
if validator_creator is None: | ||
from backend.protocol_rpc.endpoints import create_validator | ||
|
||
validator_creator = create_validator | ||
|
||
try: | ||
validators_data = json.loads(validators_json) | ||
except json.JSONDecodeError as e: | ||
raise ValueError(f"Invalid JSON in validators_json: {str(e)}") | ||
|
||
if not isinstance(validators_data, list): | ||
raise ValueError("validators_json must contain a JSON array") | ||
|
||
# Delete all existing validators | ||
validators_registry.delete_all_validators() | ||
|
||
# Create new validators | ||
for validator_data in validators_data: | ||
try: | ||
validator = ValidatorConfig(**validator_data) | ||
|
||
for _ in range(validator.amount): | ||
validator_creator( | ||
validators_registry, | ||
accounts_manager, | ||
validator.stake, | ||
validator.provider, | ||
validator.model, | ||
validator.config, | ||
validator.plugin, | ||
validator.plugin_config, | ||
) | ||
|
||
except Exception as e: | ||
raise ValueError(f"Failed to create validator `{validator_data}`: {str(e)}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import pytest | ||
from unittest.mock import Mock | ||
from backend.protocol_rpc.validators_init import initialize_validators | ||
|
||
|
||
def test_initialize_validators_empty_json(): | ||
"""Test that empty JSON string returns without doing anything""" | ||
mock_registry = Mock() | ||
mock_accounts = Mock() | ||
mock_creator = Mock() | ||
|
||
initialize_validators("", mock_registry, mock_accounts, mock_creator) | ||
|
||
mock_registry.delete_all_validators.assert_not_called() | ||
mock_creator.assert_not_called() | ||
|
||
|
||
def test_initialize_validators_invalid_json(): | ||
"""Test that invalid JSON raises ValueError""" | ||
mock_registry = Mock() | ||
mock_accounts = Mock() | ||
mock_creator = Mock() | ||
|
||
with pytest.raises(ValueError, match="Invalid JSON"): | ||
initialize_validators( | ||
"{invalid json", mock_registry, mock_accounts, mock_creator | ||
) | ||
|
||
|
||
def test_initialize_validators_non_array_json(): | ||
"""Test that non-array JSON raises ValueError""" | ||
mock_registry = Mock() | ||
mock_accounts = Mock() | ||
mock_creator = Mock() | ||
|
||
with pytest.raises(ValueError, match="must contain a JSON array"): | ||
initialize_validators("{}", mock_registry, mock_accounts, mock_creator) | ||
|
||
|
||
def test_initialize_validators_success(): | ||
"""Test successful initialization of validators""" | ||
mock_registry = Mock() | ||
mock_accounts = Mock() | ||
mock_creator = Mock() | ||
|
||
validators_json = """[ | ||
{ | ||
"stake": 100, | ||
"provider": "test-provider", | ||
"model": "test-model", | ||
"config": {"key": "value"}, | ||
"plugin": "test-plugin", | ||
"plugin_config": {"plugin_key": "plugin_value"} | ||
}, | ||
{ | ||
"stake": 200, | ||
"provider": "another-provider", | ||
"model": "another-model", | ||
"amount": 2 | ||
} | ||
]""" | ||
|
||
initialize_validators(validators_json, mock_registry, mock_accounts, mock_creator) | ||
|
||
# Verify that existing validators were deleted | ||
mock_registry.delete_all_validators.assert_called_once() | ||
|
||
# Verify that creator was called for each validator with correct arguments | ||
assert mock_creator.call_count == 3 | ||
|
||
# Check first validator creation call | ||
mock_creator.assert_any_call( | ||
mock_registry, | ||
mock_accounts, | ||
100, | ||
"test-provider", | ||
"test-model", | ||
{"key": "value"}, | ||
"test-plugin", | ||
{"plugin_key": "plugin_value"}, | ||
) | ||
|
||
# Check second validator creation call | ||
mock_creator.assert_any_call( | ||
mock_registry, | ||
mock_accounts, | ||
200, | ||
"another-provider", | ||
"another-model", | ||
None, | ||
None, | ||
None, | ||
) | ||
|
||
mock_creator.assert_any_call( | ||
mock_registry, | ||
mock_accounts, | ||
200, | ||
"another-provider", | ||
"another-model", | ||
None, | ||
None, | ||
None, | ||
) | ||
|
||
|
||
def test_initialize_validators_invalid_config(): | ||
"""Test that invalid validator configuration raises ValueError""" | ||
mock_registry = Mock() | ||
mock_accounts = Mock() | ||
mock_creator = Mock() | ||
|
||
# Missing required field 'model' | ||
validators_json = """[ | ||
{ | ||
"stake": 100, | ||
"provider": "test-provider" | ||
} | ||
]""" | ||
|
||
with pytest.raises(ValueError, match="Failed to create validator"): | ||
initialize_validators( | ||
validators_json, mock_registry, mock_accounts, mock_creator | ||
) | ||
|
||
|
||
def test_initialize_validators_creator_error(): | ||
"""Test that creator function errors are properly handled""" | ||
mock_registry = Mock() | ||
mock_accounts = Mock() | ||
mock_creator = Mock(side_effect=Exception("Creator error")) | ||
|
||
validators_json = """[ | ||
{ | ||
"stake": 100, | ||
"provider": "test-provider", | ||
"model": "test-model" | ||
} | ||
]""" | ||
|
||
with pytest.raises(ValueError, match="Failed to create validator.*Creator error"): | ||
initialize_validators( | ||
validators_json, mock_registry, mock_accounts, mock_creator | ||
) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
e2e tests were broken prior to this PR