Repository navigation
fix: handle invalid address in consensus contract snapshot creation #1763
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
base: v0.123-dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,18 +6,26 @@ | |
| def get_validators_for_transaction( | ||
| nodes: list[dict], | ||
| num_validators: int | None = None, | ||
| rng=np.random.default_rng(seed=int(datetime.now().timestamp())), | ||
| rng: np.random.Generator | None = None, | ||
| ) -> list[dict]: | ||
| """ | ||
| Returns subset of validators for a transaction. | ||
| The selelction and order is given by a random sampling based on the stake of the validators. | ||
| """ | ||
| if rng is None: | ||
| rng = np.random.default_rng(seed=int(datetime.now().timestamp())) | ||
|
Comment on lines
+15
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift 🔎 Supported by static analysis🤖 get_repo_knowledge executed:
Length of output: 6074 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- backend/consensus/vrf.py ---'
cat -n backend/consensus/vrf.py
printf '%s\n' '--- tests/unit/test_vrf.py relevant range ---'
sed -n '1,130p' tests/unit/test_vrf.py
printf '%s\n' '--- direct VRF and validator-selection bindings ---'
rg -n -S "get_validators_for_transaction|default_rng|VRF|vrf|rng|validator" backend/consensus tests/unit/test_vrf.pyRepository: genlayerlabs/genlayer-studio Length of output: 50384 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- repository file list for consensus and VRF tests ---'
git ls-files backend/consensus tests/unit | rg '(^|/)(vrf|.*consensus.*|test_vrf).*\.py$'
printf '%s\n' '--- imports and call sites for the exact selector ---'
rg -n -S -C 3 "get_validators_for_transaction|from .*vrf|import .*vrf" backend testsRepository: genlayerlabs/genlayer-studio Length of output: 9981 🏁 Script executed: #!/bin/bash
set -eu
cat -n backend/consensus/vrf.py
sed -n '1,130p' tests/unit/test_vrf.py
rg -n -S -C 3 "get_validators_for_transaction|default_rng|VRF|vrf|rng" backend/consensus tests/unit/test_vrf.pyRepository: genlayerlabs/genlayer-studio Length of output: 14572 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- backend/consensus/vrf.py ---'
cat -n backend/consensus/vrf.py
printf '%s\n' '--- tests/unit/test_vrf.py ---'
sed -n '1,130p' tests/unit/test_vrf.py
printf '%s\n' '--- bindings and related contracts ---'
rg -n -S -C 3 "get_validators_for_transaction|default_rng|VRF|vrf|rng|validator rotation" backend/consensus tests/unit/test_vrf.pyRepository: genlayerlabs/genlayer-studio Length of output: 14675 Use the consensus VRF for validator selection.
📍 Affects 2 files
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| if num_validators is None: | ||
| num_validators = DEFAULT_VALIDATORS_COUNT | ||
|
|
||
| num_validators = min(num_validators, len(nodes)) | ||
|
|
||
| total_stake = sum(validator["stake"] for validator in nodes) | ||
| if total_stake == 0: | ||
| raise ValueError( | ||
| "Cannot select validators: all stakes are zero. " | ||
| "At least one validator must have a positive stake." | ||
| ) | ||
| probabilities = [validator["stake"] / total_stake for validator in nodes] | ||
|
|
||
| selected_validators = rng.choice( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| from backend.consensus.vrf import get_validators_for_transaction | ||
| from unittest.mock import Mock | ||
| import pytest | ||
|
|
||
|
|
||
| def list_of_dicts_to_set(list_of_dicts: list[dict]) -> set: | ||
|
|
@@ -66,3 +67,21 @@ def choice_mock(a, p, size, replace): | |
|
|
||
| rng.choice.assert_called_once() | ||
| assert validators == [{"stake": 3}, {"stake": 2}, {"stake": 1}] | ||
|
|
||
|
|
||
| def test_get_validators_zero_stake_raises(): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Add return type annotations to the new test functions. Add Also applies to: 79-79 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| """When all stakes are zero, selection should raise ValueError.""" | ||
| nodes = [{"stake": 0}, {"stake": 0}] | ||
| with pytest.raises(ValueError, match="all stakes are zero"): | ||
| get_validators_for_transaction(nodes, 1) | ||
|
|
||
|
|
||
| def test_get_validators_rng_not_shared_between_calls(): | ||
| """Each call without an explicit rng should get a fresh generator.""" | ||
| nodes = [{"stake": 1}, {"stake": 2}, {"stake": 3}] | ||
| # Call twice without passing rng — the default must be created fresh each time. | ||
| v1 = get_validators_for_transaction(nodes, 1) | ||
| v2 = get_validators_for_transaction(nodes, 1) | ||
| # Both should succeed (no shared mutable state corruption). | ||
| assert len(v1) == 1 | ||
| assert len(v2) == 1 | ||
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.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🤖 get_repo_knowledge executed:
get_repo_knowledge genlayerlabs/genlayer-studio /tmp/coderabbit-repo-knowledge/genlayerlabs-genlayer-studio-28a9f580/learningsLength of output: 3630
🏁 Script executed:
Repository: genlayerlabs/genlayer-studio
Length of output: 50385
🏁 Script executed:
Repository: genlayerlabs/genlayer-studio
Length of output: 15017
Handle
Nonefromcontract_snapshot_factory.When
TransactionContextenters the legacy hydration path andcontract_snapshot_factoryreturnsNonefor an invalid or absenttransaction.to_address, the code dereferencesfresh.balanceoutside theContractNotFoundErrorhandler. This raisesAttributeErrorinstead of producing a controlled transaction failure. Make the factory raise a domain error, or handleNoneat every caller. IfNoneremains valid, update the factory and injected callable types toContractSnapshot | None.🤖 Prompt for AI Agents
Source: Coding guidelines