diff --git a/src/lean_spec/subspecs/containers/config.py b/src/lean_spec/subspecs/containers/config.py index 28859d20..18289e88 100644 --- a/src/lean_spec/subspecs/containers/config.py +++ b/src/lean_spec/subspecs/containers/config.py @@ -12,8 +12,5 @@ class Config(Container): in the absence of more complex mechanisms like RANDAO or deposits. """ - num_validators: Uint64 - """The total number of validators in the network.""" - genesis_time: Uint64 """The timestamp of the genesis block.""" diff --git a/src/lean_spec/subspecs/containers/state/state.py b/src/lean_spec/subspecs/containers/state/state.py index bf42a9d5..6dc1e26f 100644 --- a/src/lean_spec/subspecs/containers/state/state.py +++ b/src/lean_spec/subspecs/containers/state/state.py @@ -66,7 +66,7 @@ class State(Container): """A bitlist of validators who participated in justifications.""" @classmethod - def generate_genesis(cls, genesis_time: Uint64, num_validators: Uint64) -> "State": + def generate_genesis(cls, genesis_time: Uint64, validators: Validators) -> "State": """ Generate a genesis state with empty history and proper initial values. @@ -74,8 +74,8 @@ def generate_genesis(cls, genesis_time: Uint64, num_validators: Uint64) -> "Stat ---------- genesis_time : Uint64 The genesis timestamp. - num_validators : Uint64 - The number of validators in the genesis state. + validators : Validators + The list of validators in the genesis state. Returns: ------- @@ -84,7 +84,6 @@ def generate_genesis(cls, genesis_time: Uint64, num_validators: Uint64) -> "Stat """ # Configure the genesis state. genesis_config = Config( - num_validators=num_validators, genesis_time=genesis_time, ) @@ -106,7 +105,7 @@ def generate_genesis(cls, genesis_time: Uint64, num_validators: Uint64) -> "Stat latest_finalized=Checkpoint.default(), historical_block_hashes=HistoricalBlockHashes(data=[]), justified_slots=JustifiedSlots(data=[]), - validators=Validators(data=[]), + validators=validators, justifications_roots=JustificationRoots(data=[]), justifications_validators=JustificationValidators(data=[]), ) @@ -129,7 +128,7 @@ def is_proposer(self, validator_index: ValidatorIndex) -> bool: return is_proposer( validator_index=validator_index, slot=self.slot, - num_validators=self.config.num_validators, + num_validators=Uint64(self.validators.count), ) def get_justifications(self) -> Dict[Bytes32, List[Boolean]]: @@ -152,7 +151,7 @@ def get_justifications(self) -> Dict[Bytes32, List[Boolean]]: return justifications # Compute the length of each validator vote slice. - validator_count = self.config.num_validators.as_int() + validator_count = self.validators.count # Extract vote slices for each justified root. flat_votes = list(self.justifications_validators) @@ -195,7 +194,7 @@ def with_justifications( for root in sorted(justifications.keys()): votes = justifications[root] # Validate that the vote list has the expected length. - expected_len = self.config.num_validators.as_int() + expected_len = self.validators.count if len(votes) != expected_len: raise AssertionError(f"Vote list for root {root.hex()} has incorrect length") diff --git a/src/lean_spec/subspecs/containers/state/types.py b/src/lean_spec/subspecs/containers/state/types.py index defeb630..89b7000d 100644 --- a/src/lean_spec/subspecs/containers/state/types.py +++ b/src/lean_spec/subspecs/containers/state/types.py @@ -41,3 +41,8 @@ class Validators(SSZList): ELEMENT_TYPE = Validator LIMIT = DEVNET_CONFIG.validator_registry_limit.as_int() + + @property + def count(self) -> int: + """Return the number of validators in the registry.""" + return len(self.data) diff --git a/src/lean_spec/subspecs/forkchoice/store.py b/src/lean_spec/subspecs/forkchoice/store.py index 5bbd0bdc..6637c00c 100644 --- a/src/lean_spec/subspecs/forkchoice/store.py +++ b/src/lean_spec/subspecs/forkchoice/store.py @@ -365,8 +365,12 @@ def update_safe_target(self) -> None: Computes target that has sufficient (2/3+ majority) vote support. """ + # Get validator count from head state + head_state = self.states[self.head] + num_validators = head_state.validators.count + # Calculate 2/3 majority threshold (ceiling division) - min_target_score = -(-self.config.num_validators * 2 // 3) + min_target_score = -(-num_validators * 2 // 3) # Find head with minimum vote threshold safe_target = get_fork_choice_head( @@ -457,15 +461,16 @@ def produce_block_with_signatures( Raises: AssertionError: If validator lacks proposer authorization for slot """ - # Validate proposer authorization for this slot - if not is_proposer(validator_index, slot, self.config.num_validators): - msg = f"Validator {validator_index} is not the proposer for slot {slot}" - raise AssertionError(msg) - # Get parent block and state to build upon head_root = self.get_proposal_head(slot) head_state = self.states[head_root] + # Validate proposer authorization for this slot + num_validators = Uint64(head_state.validators.count) + if not is_proposer(validator_index, slot, num_validators): + msg = f"Validator {validator_index} is not the proposer for slot {slot}" + raise AssertionError(msg) + # Initialize empty attestation set for iterative collection attestations: list[Attestation] = [] signatures: list[Bytes4000] = [] diff --git a/tests/lean_spec/subspecs/containers/test_state.py b/tests/lean_spec/subspecs/containers/test_state.py index d8c187c0..056a457b 100644 --- a/tests/lean_spec/subspecs/containers/test_state.py +++ b/tests/lean_spec/subspecs/containers/test_state.py @@ -15,6 +15,7 @@ Config, SignedAttestation, State, + Validator, ) from lean_spec.subspecs.containers.block import Attestations from lean_spec.subspecs.containers.slot import Slot @@ -26,7 +27,7 @@ Validators, ) from lean_spec.subspecs.ssz import hash_tree_root -from lean_spec.types import Boolean, Bytes32, Bytes4000, Uint64, ValidatorIndex +from lean_spec.types import Boolean, Bytes32, Bytes52, Bytes4000, Uint64, ValidatorIndex @pytest.fixture @@ -37,11 +38,10 @@ def sample_config() -> Config: Returns ------- Config - A configuration with 4096 validators and genesis_time set to 0. + A configuration with genesis_time set to 0. """ # Create and return a simple configuration used across tests. return Config( - num_validators=DEVNET_CONFIG.validator_registry_limit, genesis_time=Uint64(0), ) @@ -54,7 +54,7 @@ def genesis_state(sample_config: Config) -> State: Parameters ---------- sample_config : Config - The configuration fixture with validator count and genesis time. + The configuration fixture with genesis time. Returns ------- @@ -62,9 +62,12 @@ def genesis_state(sample_config: Config) -> State: A fresh genesis state produced by the class factory. """ # Call the canonical genesis factory with the sample configuration values. + # Create validators list with 4096 validators + num_validators = DEVNET_CONFIG.validator_registry_limit.as_int() + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(num_validators)]) return State.generate_genesis( genesis_time=sample_config.genesis_time, - num_validators=sample_config.num_validators, + validators=validators, ) @@ -205,7 +208,7 @@ def base_state( Parameters ---------- sample_config : Config - Test configuration with 10 validators. + Test configuration. sample_block_header : BlockHeader Zeroed header used as latest_block_header. sample_checkpoint : Checkpoint @@ -217,6 +220,9 @@ def base_state( A State with empty history and justification lists. """ # Build a State with the provided fixtures and no history/justifications. + # Create validators list with registry limit validators + num_validators = DEVNET_CONFIG.validator_registry_limit.as_int() + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(num_validators)]) return State( config=sample_config, slot=Slot(0), @@ -227,7 +233,7 @@ def base_state( justified_slots=JustifiedSlots(data=[]), justifications_roots=JustificationRoots(data=[]), justifications_validators=JustificationValidators(data=[]), - validators=Validators(data=[]), + validators=validators, ) @@ -264,7 +270,7 @@ def test_get_justifications_single_root(base_state: State) -> None: root1 = Bytes32(b"\x01" * 32) # Prepare a vote bitlist with required length; flip two positions to True. - votes1 = [Boolean(False)] * base_state.config.num_validators.as_int() + votes1 = [Boolean(False)] * base_state.validators.count votes1[2] = Boolean(True) # Validator 2 voted votes1[5] = Boolean(True) # Validator 5 voted @@ -300,7 +306,7 @@ def test_get_justifications_multiple_roots(base_state: State) -> None: root3 = Bytes32(b"\x03" * 32) # Validator count for each vote slice. - count = base_state.config.num_validators.as_int() + count = base_state.validators.count # Build per-root vote slices. votes1 = [Boolean(False)] * count @@ -346,6 +352,9 @@ def test_with_justifications_empty( - Ensure original state is unchanged. """ # Build a state populated with a single root and a full votes bitlist. + # Create validators list with registry limit validators + num_validators = DEVNET_CONFIG.validator_registry_limit.as_int() + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(num_validators)]) initial_state = State( config=sample_config, slot=Slot(0), @@ -355,10 +364,8 @@ def test_with_justifications_empty( historical_block_hashes=HistoricalBlockHashes(data=[]), justified_slots=JustifiedSlots(data=[]), justifications_roots=JustificationRoots(data=[Bytes32(b"\x01" * 32)]), - justifications_validators=JustificationValidators( - data=[Boolean(True)] * sample_config.num_validators.as_int() - ), - validators=Validators(data=[]), + justifications_validators=JustificationValidators(data=[Boolean(True)] * num_validators), + validators=validators, ) # Apply an empty justifications map to get a new state snapshot. @@ -388,7 +395,7 @@ def test_with_justifications_deterministic_order(base_state: State) -> None: root2 = Bytes32(b"\x02" * 32) # Build two vote slices of proper length. - count = base_state.config.num_validators.as_int() + count = base_state.validators.count votes1 = [Boolean(False)] * count votes2 = [Boolean(True)] * count # Intentionally supply the dict in unsorted key order. @@ -418,7 +425,7 @@ def test_with_justifications_invalid_length(base_state: State) -> None: root1 = Bytes32(b"\x01" * 32) # Construct an invalid votes bitlist: one short of required length. - invalid_votes = [Boolean(True)] * (base_state.config.num_validators - Uint64(1)).as_int() + invalid_votes = [Boolean(True)] * (base_state.validators.count - 1) justifications = {root1: invalid_votes} # The method asserts on incorrect lengths. @@ -492,9 +499,12 @@ def test_generate_genesis(sample_config: Config) -> None: - Ensure historical/justification lists start empty. """ # Produce a genesis state from the sample config. + # Create validators list with registry limit validators + num_validators = DEVNET_CONFIG.validator_registry_limit.as_int() + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(num_validators)]) state = State.generate_genesis( genesis_time=sample_config.genesis_time, - num_validators=sample_config.num_validators, + validators=validators, ) # Config in state should match the input. diff --git a/tests/lean_spec/subspecs/forkchoice/conftest.py b/tests/lean_spec/subspecs/forkchoice/conftest.py index 8d839597..141ed875 100644 --- a/tests/lean_spec/subspecs/forkchoice/conftest.py +++ b/tests/lean_spec/subspecs/forkchoice/conftest.py @@ -33,7 +33,6 @@ def __init__(self, latest_justified: Checkpoint) -> None: """Initialize a mock state with minimal defaults.""" # Create minimal defaults for all required fields genesis_config = Config( - num_validators=Uint64(4), genesis_time=Uint64(0), ) diff --git a/tests/lean_spec/subspecs/forkchoice/test_attestation_processing.py b/tests/lean_spec/subspecs/forkchoice/test_attestation_processing.py index 862dfa9d..b3ba5f8a 100644 --- a/tests/lean_spec/subspecs/forkchoice/test_attestation_processing.py +++ b/tests/lean_spec/subspecs/forkchoice/test_attestation_processing.py @@ -21,7 +21,7 @@ @pytest.fixture def sample_config() -> Config: """Sample configuration for testing.""" - return Config(num_validators=Uint64(100), genesis_time=Uint64(1000)) + return Config(genesis_time=Uint64(1000)) @pytest.fixture diff --git a/tests/lean_spec/subspecs/forkchoice/test_fork_choice_algorithm.py b/tests/lean_spec/subspecs/forkchoice/test_fork_choice_algorithm.py index 0141840c..39c37aa7 100644 --- a/tests/lean_spec/subspecs/forkchoice/test_fork_choice_algorithm.py +++ b/tests/lean_spec/subspecs/forkchoice/test_fork_choice_algorithm.py @@ -436,7 +436,7 @@ class TestStoreBasedForkChoice: @pytest.fixture def config(self) -> Config: """Sample configuration.""" - return Config(genesis_time=Uint64(1000), num_validators=Uint64(100)) + return Config(genesis_time=Uint64(1000)) def test_store_fork_choice_no_votes(self, config: Config) -> None: """Test Store.get_proposal_head with no votes.""" diff --git a/tests/lean_spec/subspecs/forkchoice/test_store_lifecycle.py b/tests/lean_spec/subspecs/forkchoice/test_store_lifecycle.py index adee9b47..5556f071 100644 --- a/tests/lean_spec/subspecs/forkchoice/test_store_lifecycle.py +++ b/tests/lean_spec/subspecs/forkchoice/test_store_lifecycle.py @@ -29,7 +29,7 @@ @pytest.fixture def sample_config() -> Config: """Sample configuration for testing.""" - return Config(num_validators=Uint64(100), genesis_time=Uint64(1000)) + return Config(genesis_time=Uint64(1000)) @pytest.fixture @@ -57,7 +57,6 @@ class TestStoreCreation: def test_store_creation_basic(self, sample_store: Store) -> None: """Test basic Store creation with required fields.""" assert sample_store.time == Uint64(100) - assert sample_store.config.num_validators == Uint64(100) assert sample_store.head == Bytes32(b"head_root" + b"\x00" * 23) assert sample_store.safe_target == Bytes32(b"safe_root" + b"\x00" * 23) assert isinstance(sample_store.latest_justified, Checkpoint) @@ -65,7 +64,7 @@ def test_store_creation_basic(self, sample_store: Store) -> None: def test_store_initialization_with_data(self) -> None: """Test Store initialization with blocks and states.""" - config = Config(num_validators=Uint64(10), genesis_time=Uint64(2000)) + config = Config(genesis_time=Uint64(2000)) checkpoint = Checkpoint(root=Bytes32(b"test" + b"\x00" * 28), slot=Slot(5)) # Sample block @@ -112,7 +111,7 @@ def test_store_initialization_with_data(self) -> None: def test_store_factory_method(self) -> None: """Test Store.get_forkchoice_store factory method.""" - config = Config(num_validators=Uint64(10), genesis_time=Uint64(1000)) + config = Config(genesis_time=Uint64(1000)) checkpoint = Checkpoint(root=Bytes32(b"genesis" + b"\x00" * 25), slot=Slot(0)) # Create block header for testing @@ -166,7 +165,7 @@ class TestStoreDefaultValues: def test_store_empty_collections_by_default(self) -> None: """Test that Store initializes empty collections by default.""" - config = Config(num_validators=Uint64(5), genesis_time=Uint64(500)) + config = Config(genesis_time=Uint64(500)) checkpoint = Checkpoint(root=Bytes32(b"test" + b"\x00" * 28), slot=Slot(0)) store = Store( @@ -201,7 +200,7 @@ class TestStoreValidation: def test_store_validation_required_fields(self) -> None: """Test that Store validates required fields.""" - config = Config(num_validators=Uint64(5), genesis_time=Uint64(500)) + config = Config(genesis_time=Uint64(500)) checkpoint = Checkpoint(root=Bytes32(b"test" + b"\x00" * 28), slot=Slot(0)) # Should create successfully with all required fields @@ -223,7 +222,7 @@ def test_store_validation_required_fields(self) -> None: def test_store_type_validation(self) -> None: """Test Store validates field types.""" - config = Config(num_validators=Uint64(5), genesis_time=Uint64(500)) + config = Config(genesis_time=Uint64(500)) checkpoint = Checkpoint(root=Bytes32(b"test" + b"\x00" * 28), slot=Slot(0)) # Test with wrong type for time - should work due to Pydantic coercion diff --git a/tests/lean_spec/subspecs/forkchoice/test_time_management.py b/tests/lean_spec/subspecs/forkchoice/test_time_management.py index 8935b2e0..fb162235 100644 --- a/tests/lean_spec/subspecs/forkchoice/test_time_management.py +++ b/tests/lean_spec/subspecs/forkchoice/test_time_management.py @@ -7,12 +7,15 @@ BlockBody, Checkpoint, Config, + State, + Validator, ) from lean_spec.subspecs.containers.block import Attestations from lean_spec.subspecs.containers.slot import Slot +from lean_spec.subspecs.containers.state import Validators from lean_spec.subspecs.forkchoice import Store from lean_spec.subspecs.ssz.hash import hash_tree_root -from lean_spec.types import Bytes32, Uint64, ValidatorIndex +from lean_spec.types import Bytes32, Bytes52, Uint64, ValidatorIndex from .conftest import build_signed_attestation @@ -20,21 +23,40 @@ @pytest.fixture def sample_config() -> Config: """Sample configuration for testing.""" - return Config(num_validators=Uint64(100), genesis_time=Uint64(1000)) + return Config(genesis_time=Uint64(1000)) @pytest.fixture def sample_store(sample_config: Config) -> Store: """Create a sample forkchoice store.""" - checkpoint = Checkpoint(root=Bytes32(b"test_root" + b"\x00" * 23), slot=Slot(0)) + # Create a genesis block with empty body + genesis_block = Block( + slot=Slot(0), + proposer_index=ValidatorIndex(0), + parent_root=Bytes32.zero(), + state_root=Bytes32(b"state" + b"\x00" * 27), + body=BlockBody(attestations=Attestations(data=[])), + ) + genesis_hash = hash_tree_root(genesis_block) + + checkpoint = Checkpoint(root=genesis_hash, slot=Slot(0)) + + # Create genesis state with 10 validators for testing + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(10)]) + state = State.generate_genesis( + genesis_time=sample_config.genesis_time, + validators=validators, + ) return Store( time=Uint64(100), config=sample_config, - head=Bytes32(b"head_root" + b"\x00" * 23), - safe_target=Bytes32(b"safe_root" + b"\x00" * 23), + head=genesis_hash, + safe_target=genesis_hash, latest_justified=checkpoint, latest_finalized=checkpoint, + blocks={genesis_hash: genesis_block}, + states={genesis_hash: state}, ) diff --git a/tests/lean_spec/subspecs/forkchoice/test_validator.py b/tests/lean_spec/subspecs/forkchoice/test_validator.py index 2cb6063e..c17e2d68 100644 --- a/tests/lean_spec/subspecs/forkchoice/test_validator.py +++ b/tests/lean_spec/subspecs/forkchoice/test_validator.py @@ -12,6 +12,7 @@ Config, SignedAttestation, State, + Validator, ) from lean_spec.subspecs.containers.block import Attestations from lean_spec.subspecs.containers.slot import Slot @@ -24,14 +25,14 @@ ) from lean_spec.subspecs.forkchoice import Store from lean_spec.subspecs.ssz.hash import hash_tree_root -from lean_spec.types import Bytes32, Bytes4000, Uint64, ValidatorIndex +from lean_spec.types import Bytes32, Bytes52, Bytes4000, Uint64, ValidatorIndex from lean_spec.types.validator import is_proposer @pytest.fixture def config() -> Config: """Sample configuration for validator testing.""" - return Config(genesis_time=Uint64(1000), num_validators=Uint64(10)) + return Config(genesis_time=Uint64(1000)) @pytest.fixture @@ -49,6 +50,9 @@ def sample_state(config: Config) -> State: # Use a placeholder for genesis - will be updated in store fixture temp_finalized = Checkpoint(root=Bytes32(b"genesis" + b"\x00" * 25), slot=Slot(0)) + # Create validators list with 10 validators for testing + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(10)]) + return State( config=config, slot=Slot(0), @@ -59,7 +63,7 @@ def sample_state(config: Config) -> State: justified_slots=JustifiedSlots(data=[]), justifications_roots=JustificationRoots(data=[]), justifications_validators=JustificationValidators(data=[]), - validators=Validators(data=[]), + validators=validators, ) @@ -473,11 +477,14 @@ def test_validator_edge_cases(self, sample_store: Store) -> None: def test_validator_operations_empty_store(self) -> None: """Test validator operations with minimal store state.""" - config = Config(genesis_time=Uint64(1000), num_validators=Uint64(3)) + config = Config(genesis_time=Uint64(1000)) # Create minimal genesis block first genesis_body = BlockBody(attestations=Attestations(data=[])) + # Create validators list with 3 validators + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(3)]) + # Create minimal state with temporary header checkpoint = Checkpoint.default() state = State( @@ -496,7 +503,7 @@ def test_validator_operations_empty_store(self) -> None: justified_slots=JustifiedSlots(data=[]), justifications_roots=JustificationRoots(data=[]), justifications_validators=JustificationValidators(data=[]), - validators=Validators(data=[]), + validators=validators, ) # Compute consistent state root @@ -567,7 +574,7 @@ def test_produce_block_wrong_proposer(self, sample_store: Store) -> None: def test_produce_block_missing_parent_state(self) -> None: """Test error when parent state is missing.""" - config = Config(genesis_time=Uint64(1000), num_validators=Uint64(5)) + config = Config(genesis_time=Uint64(1000)) checkpoint = Checkpoint(root=Bytes32(b"missing" + b"\x00" * 25), slot=Slot(0)) # Create store with missing parent state @@ -594,8 +601,13 @@ def test_validator_operations_invalid_parameters(self, sample_store: Store) -> N large_validator = ValidatorIndex(1000000) large_slot = Slot(1000000) + # Get the state to determine number of validators + genesis_hash = sample_store.head + state = sample_store.states[genesis_hash] + num_validators = Uint64(state.validators.count) + # is_proposer should work (though likely return False) - result = is_proposer(large_validator, large_slot, sample_store.config.num_validators) + result = is_proposer(large_validator, large_slot, num_validators) assert isinstance(result, bool) # produce_attestation_vote should work for any validator diff --git a/tests/lean_spec/subspecs/forkchoice/test_vote_target_selection.py b/tests/lean_spec/subspecs/forkchoice/test_vote_target_selection.py index 1e8b4212..3c5a2dd9 100644 --- a/tests/lean_spec/subspecs/forkchoice/test_vote_target_selection.py +++ b/tests/lean_spec/subspecs/forkchoice/test_vote_target_selection.py @@ -7,12 +7,15 @@ BlockBody, Checkpoint, Config, + State, + Validator, ) from lean_spec.subspecs.containers.block import Attestations from lean_spec.subspecs.containers.slot import Slot +from lean_spec.subspecs.containers.state import Validators from lean_spec.subspecs.forkchoice import Store from lean_spec.subspecs.ssz.hash import hash_tree_root -from lean_spec.types import Bytes32, Uint64, ValidatorIndex +from lean_spec.types import Bytes32, Bytes52, Uint64, ValidatorIndex from .conftest import build_signed_attestation @@ -20,7 +23,7 @@ @pytest.fixture def config() -> Config: """Sample configuration.""" - return Config(genesis_time=Uint64(1000), num_validators=Uint64(100)) + return Config(genesis_time=Uint64(1000)) class TestVoteTargetCalculation: @@ -293,6 +296,13 @@ def test_update_safe_target_basic(self, config: Config) -> None: checkpoint = Checkpoint(root=genesis_block_hash, slot=Slot(0)) + # Create genesis state with validators + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(100)]) + genesis_state = State.generate_genesis( + genesis_time=config.genesis_time, + validators=validators, + ) + store = Store( time=Uint64(100), config=config, @@ -301,7 +311,7 @@ def test_update_safe_target_basic(self, config: Config) -> None: latest_justified=checkpoint, latest_finalized=checkpoint, blocks={genesis_block_hash: genesis_block}, - states={}, + states={genesis_block_hash: genesis_state}, ) # Update safe target (this tests the method exists and runs) @@ -338,6 +348,15 @@ def test_safe_target_with_votes(self, config: Config) -> None: checkpoint = Checkpoint(root=genesis_hash, slot=Slot(0)) + # Create states with validators + validators = Validators(data=[Validator(pubkey=Bytes52.zero()) for _ in range(100)]) + genesis_state = State.generate_genesis( + genesis_time=config.genesis_time, + validators=validators, + ) + # Create state for block_1 (copy genesis state and update slot) + block_1_state = genesis_state.model_copy(update={"slot": Slot(1)}) + # Add some new votes new_votes = { ValidatorIndex(0): build_signed_attestation( @@ -358,7 +377,7 @@ def test_safe_target_with_votes(self, config: Config) -> None: latest_justified=checkpoint, latest_finalized=checkpoint, blocks=blocks, - states={}, + states={genesis_hash: genesis_state, block_1_hash: block_1_state}, latest_new_votes=new_votes, )