diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8f2078956..a505fb451 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -241,7 +241,7 @@ These configurations are updated for releases, but may be out of sync during `de | `RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | | `ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | | `SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | -| `VALIDATOR_REGISTRY_SIZE` | `2**40 (= 1,099,511,627,776)` | | | +| `VALIDATOR_REGISTRY_SIZE` | `2**40` (= 1,099,511,627,776) | | | ### Rewards and penalties @@ -372,7 +372,7 @@ class IndexedAttestation(Container): ```python class PendingAttestation(Container): - aggregation_bitfield: Bytes[MAX_COMMITTEE_SIZE] # Bit set for every attesting participant within a committee + aggregation_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8] data: AttestationData inclusion_delay: Slot proposer_index: ValidatorIndex @@ -439,9 +439,9 @@ class AttesterSlashing(Container): ```python class Attestation(Container): - aggregation_bitfield: Bytes[MAX_COMMITTEE_SIZE] + aggregation_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8] data: AttestationData - custody_bitfield: Bytes[MAX_COMMITTEE_SIZE] + custody_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8] signature: BLSSignature ``` @@ -1629,20 +1629,8 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index) # Verify that there are no duplicate transfers assert len(body.transfers) == len(set(body.transfers)) -<<<<<<< HEAD - all_operations = [ - (body.proposer_slashings, MAX_PROPOSER_SLASHINGS, process_proposer_slashing), - (body.attester_slashings, MAX_ATTESTER_SLASHINGS, process_attester_slashing), - (body.attestations, MAX_ATTESTATIONS, process_attestation), - (body.deposits, MAX_DEPOSITS, process_deposit), - (body.voluntary_exits, MAX_VOLUNTARY_EXITS, process_voluntary_exit), - (body.transfers, MAX_TRANSFERS, process_transfer), - ] # type: List[Tuple[List[Container], int, Callable]] - for operations, max_operations, function in all_operations: - assert len(operations) <= max_operations -======= - for operations, max_operations, function in ( + for operations, function in ( (body.proposer_slashings, process_proposer_slashing), (body.attester_slashings, process_attester_slashing), (body.attestations, process_attestation), @@ -1650,7 +1638,6 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: (body.voluntary_exits, process_voluntary_exit), (body.transfers, process_transfer), ): ->>>>>>> f6a2345f... Update spec for new SSZ with list max length for operation in operations: function(state, operation) ``` diff --git a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py index 942095622..5aadfae32 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py @@ -2,10 +2,6 @@ from typing import Tuple, Iterator from types import GeneratorType -class ValueCheckError(Exception): - pass - - class DefaultingTypeMeta(type): def default(cls): raise Exception("Not implemented") @@ -97,7 +93,7 @@ def coerce_type_maybe(v, typ: SSZType): # shortcut if it's already the type we are looking for if v_typ == typ: return v - elif isinstance(v, int): + elif isinstance(v, int) and not isinstance(v, uint): # do not coerce from one uintX to another uintY return typ(v) elif isinstance(v, (list, tuple)): return typ(*v) @@ -126,7 +122,7 @@ class Container(Series, metaclass=SSZType): else: value = coerce_type_maybe(kwargs[f], t) if not isinstance(value, t): - raise ValueCheckError(f"Bad input for class {self.__class__}:" + raise ValueError(f"Bad input for class {self.__class__}:" f" field: {f} type: {t} value: {value} value type: {type(value)}") setattr(self, f, value) @@ -148,7 +144,7 @@ class Container(Series, metaclass=SSZType): field_typ = self.__class__.__annotations__[name] value = coerce_type_maybe(value, field_typ) if not isinstance(value, field_typ): - raise ValueCheckError(f"Cannot set field of {self.__class__}:" + raise ValueError(f"Cannot set field of {self.__class__}:" f" field: {name} type: {field_typ} value: {value} value type: {type(value)}") super().__setattr__(name, value) @@ -273,7 +269,7 @@ class Elements(ParamsBase, metaclass=ElementsType): items = self.extract_args(*args) if not self.value_check(items): - raise ValueCheckError(f"Bad input for class {self.__class__}: {items}") + raise ValueError(f"Bad input for class {self.__class__}: {items}") self.items = items @classmethod @@ -296,6 +292,16 @@ class Elements(ParamsBase, metaclass=ElementsType): return self.items[i] def __setitem__(self, k, v): + if k < 0: + raise IndexError(f"cannot set item in type {self.__class__} at negative index {k} (to {v})") + if k > len(self.items): + raise IndexError(f"cannot set item in type {self.__class__}" + f" at out of bounds index {k} (to {v}, bound: {len(self.items)})") + typ = self.__class__.elem_type + v = coerce_type_maybe(v, typ) + if not isinstance(v, typ): + raise ValueError(f"Cannot set item in type {self.__class__}," + f" mismatched element type: {v} of {type(v)}, expected {typ}") self.items[k] = v def __len__(self): diff --git a/test_libs/pyspec/eth2spec/utils/ssz/test_ssz_typing.py b/test_libs/pyspec/eth2spec/utils/ssz/test_ssz_typing.py index 291c4b955..0f4a06c5f 100644 --- a/test_libs/pyspec/eth2spec/utils/ssz/test_ssz_typing.py +++ b/test_libs/pyspec/eth2spec/utils/ssz/test_ssz_typing.py @@ -106,9 +106,14 @@ def test_container(): assert v.type().length == 1024 y.a = 42 - y.a = uint16(255) try: - y.a = uint16(256) + y.a = 256 # out of bounds + assert False + except ValueError: + pass + + try: + y.a = uint16(255) # within bounds, wrong type assert False except ValueError: pass @@ -149,3 +154,37 @@ def test_list(): assert isinstance(v, Series) assert issubclass(v.type(), Elements) assert isinstance(v.type(), ElementsType) + + foo = List[uint32, 128](0 for i in range(128)) + foo[0] = 123 + foo[1] = 654 + foo[127] = 222 + assert sum(foo) == 999 + try: + foo[3] = 2**32 # out of bounds + except ValueError: + pass + + try: + foo[3] = uint64(2**32 - 1) # within bounds, wrong type + assert False + except ValueError: + pass + + try: + foo[128] = 100 + assert False + except IndexError: + pass + + try: + foo[-1] = 100 # valid in normal python lists + assert False + except IndexError: + pass + + try: + foo[128] = 100 # out of bounds + assert False + except IndexError: + pass