diff --git a/specs/networking/p2p-interface.md b/specs/networking/p2p-interface.md index b3e0db50e..c9bab8406 100644 --- a/specs/networking/p2p-interface.md +++ b/specs/networking/p2p-interface.md @@ -160,7 +160,7 @@ Additional topics are used to propagate lower frequency validator messages. Thei #### Interop -Unaggregated and aggregated attestations from all shards are sent to the `beacon_attestation` topic. Clients are not required to publish aggregate attestations but must be able to process them. +Unaggregated and aggregated attestations from all shards are sent to the `beacon_attestation` topic. Clients are not required to publish aggregate attestations but must be able to process them. All validating clients SHOULD try to perform local attestation aggregation to prepare for block proposing. #### Mainnet @@ -301,7 +301,7 @@ Here, `result` represents the 1-byte response code. The token of the negotiated protocol ID specifies the type of encoding to be used for the req/resp interaction. Two values are possible at this time: -- `ssz`: The contents are [SSZ-encoded](../simple-serialize.md). This encoding type MUST be supported by all clients. For objects containing a single field, only the field is SSZ-encoded not a container with a single field. For example, the `BeaconBlocks` response would be an SSZ-encoded list of `BeaconBlock`s. All SSZ-Lists in the Req/Resp domain will have a maximum list size of `SSZ_MAX_LIST_SIZE`. +- `ssz`: the contents are [SSZ-encoded](#ssz-encoding). This encoding type MUST be supported by all clients. For objects containing a single field, only the field is SSZ-encoded not a container with a single field. For example, the `BeaconBlocks` response would be an SSZ-encoded list of `BeaconBlock`s. All SSZ-Lists in the Req/Resp domain will have a maximum list size of `SSZ_MAX_LIST_SIZE`. - `ssz_snappy`: The contents are SSZ-encoded and then compressed with [Snappy](https://github.com/google/snappy). MAY be supported in the interoperability testnet; MUST be supported in mainnet. #### SSZ-encoding strategy (with or without Snappy) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index 588200f20..5e17962d1 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -63,7 +63,7 @@ * **bitlist**: ordered variable-length collection of `boolean` values, limited to `N` bits * notation `Bitlist[N]` * **union**: union type containing one of the given subtypes - * notation `Union[type_1, type_2, ...]`, e.g. `union[null, uint64]` + * notation `Union[type_0, type_1, ...]`, e.g. `union[null, uint64]` ### Variable-size and fixed-size @@ -79,8 +79,18 @@ For convenience we alias: * `null`: `{}` ### Default values +Assuming a helper function `default(type)` which returns the default value for `type`, we can recursively define the default value for all types. -The default value of a type upon initialization is recursively defined using `0` for `uintN`, `False` for `boolean` and the elements of `Bitvector`, and `[]` for lists and `Bitlist`. Unions default to the first type in the union (with type index zero), which is `null` if present in the union. +| Type | Default Value | +| ---- | ------------- | +| `uintN` | `0` | +| `boolean` | `False` | +| `Container` | `[default(type) for type in container]` | +| `Vector[type, N]` | `[default(type)] * N` | +| `Bitvector[boolean, N]` | `[False] * N` | +| `List[type, N]` | `[]` | +| `Bitlist[boolean, N]` | `[]` | +| `Union[type_0, type_1, ...]` | `default(type_0)` | #### `is_zero` diff --git a/test_generators/ssz_generic/ssz_bitvector.py b/test_generators/ssz_generic/ssz_bitvector.py index 2b04577e8..d84614068 100644 --- a/test_generators/ssz_generic/ssz_bitvector.py +++ b/test_generators/ssz_generic/ssz_bitvector.py @@ -5,11 +5,19 @@ from random import Random from eth2spec.debug.random_value import RandomizationMode, get_random_ssz_object -def bitvector_case_fn(rng: Random, mode: RandomizationMode, size: int): - return get_random_ssz_object(rng, Bitvector[size], +def bitvector_case_fn(rng: Random, mode: RandomizationMode, size: int, invalid_making_pos: int=None): + bits = get_random_ssz_object(rng, Bitvector[size], max_bytes_length=(size + 7) // 8, max_list_length=size, mode=mode, chaos=False) + if invalid_making_pos is not None and invalid_making_pos <= size: + already_invalid = False + for i in range(invalid_making_pos, size): + if bits[i]: + already_invalid = True + if not already_invalid: + bits[invalid_making_pos] = True + return bits def valid_cases(): @@ -23,8 +31,12 @@ def invalid_cases(): # zero length bitvecors are illegal yield 'bitvec_0', invalid_test_case(lambda: b'') rng = Random(1234) + # Create a vector with test_size bits, but make the type typ_size instead, + # which is invalid when used with the given type size + # (and a bit set just after typ_size bits if necessary to avoid the valid 0 padding-but-same-last-byte case) for (typ_size, test_size) in [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (8, 9), (9, 8), (16, 8), (32, 33), (512, 513)]: for mode in [RandomizationMode.mode_random, RandomizationMode.mode_zero, RandomizationMode.mode_max]: yield f'bitvec_{typ_size}_{mode.to_name()}_{test_size}', \ - invalid_test_case(lambda: serialize(bitvector_case_fn(rng, mode, test_size))) + invalid_test_case(lambda: serialize(bitvector_case_fn(rng, mode, test_size, + invalid_making_pos=typ_size))) diff --git a/test_libs/pyspec/eth2spec/debug/random_value.py b/test_libs/pyspec/eth2spec/debug/random_value.py index 9a7d47239..ce1522c32 100644 --- a/test_libs/pyspec/eth2spec/debug/random_value.py +++ b/test_libs/pyspec/eth2spec/debug/random_value.py @@ -94,6 +94,8 @@ def get_random_ssz_object(rng: Random, length = 1 elif mode == RandomizationMode.mode_max_count: length = max_list_length + elif mode == RandomizationMode.mode_nil_count: + length = 0 if typ.length < length: # SSZ imposes a hard limit on lists, we can't put in more than that length = typ.length