|
10 | 10 | import pytest |
11 | 11 | from consensus_testing import StateExpectation, StateTransitionTestFiller, generate_pre_state |
12 | 12 |
|
13 | | -from lean_spec.subspecs.containers.block import BlockBody |
| 13 | +from lean_spec.subspecs.containers.block import Block, BlockBody |
14 | 14 | from lean_spec.subspecs.containers.block.types import Attestations |
15 | 15 | from lean_spec.subspecs.containers.slot import Slot |
16 | | -from lean_spec.subspecs.containers.state import Validators |
| 16 | +from lean_spec.subspecs.containers.state import State, Validators |
17 | 17 | from lean_spec.subspecs.containers.state.types import ( |
18 | 18 | HistoricalBlockHashes, |
19 | 19 | JustificationRoots, |
|
22 | 22 | ) |
23 | 23 | from lean_spec.subspecs.containers.validator import Validator |
24 | 24 | from lean_spec.subspecs.ssz.hash import hash_tree_root |
25 | | -from lean_spec.types import Bytes32, Bytes52, Uint64 |
| 25 | +from lean_spec.types import Bytes32, Bytes52, Uint64, ValidatorIndex |
26 | 26 |
|
27 | 27 | pytestmark = pytest.mark.valid_until("Devnet") |
28 | 28 |
|
@@ -154,3 +154,103 @@ def test_genesis_custom_validator_set( |
154 | 154 | justifications_validators=JustificationValidators(data=[]), |
155 | 155 | ), |
156 | 156 | ) |
| 157 | + |
| 158 | + |
| 159 | +def test_genesis_block_hash_comparison() -> None: |
| 160 | + """Test that genesis block hashes are deterministic and differ with different inputs.""" |
| 161 | + # Create first genesis state with 3 validators |
| 162 | + # Fill pubkeys with different values (1, 2, 3) |
| 163 | + pubkeys1 = [Bytes52(bytes([i + 1] * 52)) for i in range(3)] |
| 164 | + validators1 = Validators(data=[Validator(pubkey=pubkey) for pubkey in pubkeys1]) |
| 165 | + |
| 166 | + genesis_state1 = State.generate_genesis( |
| 167 | + genesis_time=Uint64(1000), |
| 168 | + validators=validators1, |
| 169 | + ) |
| 170 | + |
| 171 | + # Generate genesis block from first state |
| 172 | + genesis_block1 = Block( |
| 173 | + slot=Slot(0), |
| 174 | + proposer_index=ValidatorIndex(0), |
| 175 | + parent_root=Bytes32.zero(), |
| 176 | + state_root=hash_tree_root(genesis_state1), |
| 177 | + body=BlockBody(attestations=Attestations(data=[])), |
| 178 | + ) |
| 179 | + |
| 180 | + # Compute hash of first genesis block |
| 181 | + genesis_block_hash1 = hash_tree_root(genesis_block1) |
| 182 | + |
| 183 | + # Create a second genesis state with same config but regenerated (should produce same hash) |
| 184 | + genesis_state1_copy = State.generate_genesis( |
| 185 | + genesis_time=Uint64(1000), |
| 186 | + validators=validators1, |
| 187 | + ) |
| 188 | + |
| 189 | + genesis_block1_copy = Block( |
| 190 | + slot=Slot(0), |
| 191 | + proposer_index=ValidatorIndex(0), |
| 192 | + parent_root=Bytes32.zero(), |
| 193 | + state_root=hash_tree_root(genesis_state1_copy), |
| 194 | + body=BlockBody(attestations=Attestations(data=[])), |
| 195 | + ) |
| 196 | + |
| 197 | + genesis_block_hash1_copy = hash_tree_root(genesis_block1_copy) |
| 198 | + |
| 199 | + # Same genesis spec should produce same hash |
| 200 | + assert genesis_block_hash1 == genesis_block_hash1_copy |
| 201 | + |
| 202 | + # Create second genesis state with different validators |
| 203 | + # Fill pubkeys with different values (10, 11, 12) |
| 204 | + pubkeys2 = [Bytes52(bytes([i + 10] * 52)) for i in range(3)] |
| 205 | + validators2 = Validators(data=[Validator(pubkey=pubkey) for pubkey in pubkeys2]) |
| 206 | + |
| 207 | + genesis_state2 = State.generate_genesis( |
| 208 | + genesis_time=Uint64(1000), # Same genesis_time but different validators |
| 209 | + validators=validators2, |
| 210 | + ) |
| 211 | + |
| 212 | + genesis_block2 = Block( |
| 213 | + slot=Slot(0), |
| 214 | + proposer_index=ValidatorIndex(0), |
| 215 | + parent_root=Bytes32.zero(), |
| 216 | + state_root=hash_tree_root(genesis_state2), |
| 217 | + body=BlockBody(attestations=Attestations(data=[])), |
| 218 | + ) |
| 219 | + |
| 220 | + genesis_block_hash2 = hash_tree_root(genesis_block2) |
| 221 | + |
| 222 | + # Different validators should produce different genesis block hash |
| 223 | + assert genesis_block_hash1 != genesis_block_hash2 |
| 224 | + |
| 225 | + # Create third genesis state with same validators but different genesis_time |
| 226 | + # Same as pubkeys1 |
| 227 | + pubkeys3 = [Bytes52(bytes([i + 1] * 52)) for i in range(3)] |
| 228 | + validators3 = Validators(data=[Validator(pubkey=pubkey) for pubkey in pubkeys3]) |
| 229 | + |
| 230 | + genesis_state3 = State.generate_genesis( |
| 231 | + genesis_time=Uint64(2000), # Different genesis_time but same validators |
| 232 | + validators=validators3, |
| 233 | + ) |
| 234 | + |
| 235 | + genesis_block3 = Block( |
| 236 | + slot=Slot(0), |
| 237 | + proposer_index=ValidatorIndex(0), |
| 238 | + parent_root=Bytes32.zero(), |
| 239 | + state_root=hash_tree_root(genesis_state3), |
| 240 | + body=BlockBody(attestations=Attestations(data=[])), |
| 241 | + ) |
| 242 | + |
| 243 | + genesis_block_hash3 = hash_tree_root(genesis_block3) |
| 244 | + |
| 245 | + # Different genesis_time should produce different genesis block hash |
| 246 | + assert genesis_block_hash1 != genesis_block_hash3 |
| 247 | + |
| 248 | + # Compare genesis block hashes with expected hex values |
| 249 | + hash1_hex = f"0x{genesis_block_hash1.hex()}" |
| 250 | + assert hash1_hex == "0x4c0bcc4750b71818224a826cd59f8bcb75ae2920eb3e75b4097b818be6d1049a" |
| 251 | + |
| 252 | + hash2_hex = f"0x{genesis_block_hash2.hex()}" |
| 253 | + assert hash2_hex == "0x639b6162e6b432653a77a64b678717e7634428eda88ad6ccb1862e6397c0c47b" |
| 254 | + |
| 255 | + hash3_hex = f"0x{genesis_block_hash3.hex()}" |
| 256 | + assert hash3_hex == "0x6593976e31c915b5d534e2ee6172652aed7690be24777947de39c726aa2af59e" |
0 commit comments