class HistoricalBatch(ssz.Serializable): fields = [ # Block roots ('block_roots', List(bytes32)), # State roots ('state_roots', List(bytes32)), ] def __init__(self, *, block_roots: Sequence[Hash32], state_roots: Sequence[Hash32], slots_per_historical_root: int) -> None: assert len(block_roots) == slots_per_historical_root assert len(state_roots) == slots_per_historical_root super().__init__( block_roots=block_roots, state_roots=state_roots, ) _hash_tree_root = None @property def hash_tree_root(self) -> Hash32: if self._hash_tree_root is None: self._hash_tree_root = ssz.hash_tree_root(self) return self._hash_tree_root
class IndexedAttestation(ssz.Serializable): fields = [ # Validator indices ("custody_bit_0_indices", List(uint64, 1)), ("custody_bit_1_indices", List(uint64, 1)), # Attestation data ("data", AttestationData), # Aggregate signature ("signature", bytes96), ] def __init__( self, custody_bit_0_indices: Sequence[ValidatorIndex] = default_tuple, custody_bit_1_indices: Sequence[ValidatorIndex] = default_tuple, data: AttestationData = default_attestation_data, signature: BLSSignature = EMPTY_SIGNATURE, ) -> None: super().__init__(custody_bit_0_indices, custody_bit_1_indices, data, signature) def __str__(self) -> str: return (f"custody_bit_0_indices={self.custody_bit_0_indices}," f" custody_bit_1_indices={self.custody_bit_1_indices}," f" data=({self.data})," f" signature={humanize_hash(self.signature)}")
class IndexedAttestation(ssz.Serializable): fields = [ # Validator indices ('custody_bit_0_indices', List(uint64, 1)), ('custody_bit_1_indices', List(uint64, 1)), # Attestation data ('data', AttestationData), # Aggregate signature ('signature', bytes96), ] def __init__( self, custody_bit_0_indices: Sequence[ValidatorIndex] = default_tuple, custody_bit_1_indices: Sequence[ValidatorIndex] = default_tuple, data: AttestationData = default_attestation_data, signature: BLSSignature = EMPTY_SIGNATURE) -> None: super().__init__( custody_bit_0_indices, custody_bit_1_indices, data, signature, ) def __repr__(self) -> str: return f"<IndexedAttestation {self.data}>"
def test_not_serializable(): octopi = (octopus, octopus, octopus) sedes = List(Animal, 2**32) output = to_formatted_dict(octopi, sedes) hashable_octopi = HashableList.from_iterable(octopi, sedes) assert hashable_octopi == from_formatted_dict(output, List(Animal, 2**32))
class State(Serializable): fields = [ ("validators", List(Validator, VALIDATOR_REGISTRY_LIMIT)), ("balances", List(uint64, VALIDATOR_REGISTRY_LIMIT)), ("randao_mixes", Vector(bytes32, EPOCHS_PER_HISTORICAL_VECTOR)), ("latest_block_header", BeaconBlockHeader), ("eth1_data", Eth1Data), ]
def test_invalid_serialized_list(): # ensure that an improperly read offset (not enough bytes) does not # incorrectly register as an empty list due to mis-interpreting the failed # stream read as the stream having been empty. data = decode_hex("0x0001") sedes = List(List(uint8, 2**32), 2**32) with pytest.raises(DeserializationError): ssz.decode(data, sedes=sedes)
class BeaconBlockBody(HashableContainer): fields = [ ("randao_reveal", bytes96), ("eth1_data", Eth1Data), ("graffiti", bytes32), ("proposer_slashings", List(ProposerSlashing, 16)), ("attester_slashings", List(AttesterSlashing, 2)), ("attestations", List(Attestation, 128)), ("deposits", List(Deposit, 16)), ("voluntary_exits", List(SignedVoluntaryExit, 16)), ] @classmethod def create( cls: Type[TBeaconBlockBody], *, randao_reveal: BLSSignature = EMPTY_SIGNATURE, eth1_data: Eth1Data = default_eth1_data, graffiti: Hash32 = ZERO_HASH32, proposer_slashings: Sequence[ProposerSlashing] = default_tuple, attester_slashings: Sequence[AttesterSlashing] = default_tuple, attestations: Sequence[Attestation] = default_tuple, deposits: Sequence[Deposit] = default_tuple, voluntary_exits: Sequence[SignedVoluntaryExit] = default_tuple, ) -> TBeaconBlockBody: return super().create( randao_reveal=randao_reveal, eth1_data=eth1_data, graffiti=graffiti, proposer_slashings=proposer_slashings, attester_slashings=attester_slashings, attestations=attestations, deposits=deposits, voluntary_exits=voluntary_exits, ) @property def is_empty(self) -> bool: return self == BeaconBlockBody.create() def __str__(self) -> str: return ( f"randao_reveal={humanize_hash(self.randao_reveal)}," f" eth1_data=({self.eth1_data})," f" graffiti={humanize_hash(self.graffiti)}," f" proposer_slashings={tuple(slashing for slashing in self.proposer_slashings)}," f" attester_slashings={tuple(slashing for slashing in self.attester_slashings)}," f" attestations={tuple(attestation for attestation in self.attestations)}," f" deposits={tuple(deposit for deposit in self.deposits)}," f" voluntary_exits={tuple(exit for exit in self.voluntary_exits)}," ) def __repr__(self) -> str: return f"<{self.__class__.__name__}: {str(self)}>"
class BeaconBlockBody(ssz.Serializable): fields = [ ('proposer_slashings', List(ProposerSlashing)), ('attester_slashings', List(AttesterSlashing)), ('attestations', List(Attestation)), ('deposits', List(Deposit)), ('exits', List(Exit)), ] def __init__(self, proposer_slashings: Sequence[ProposerSlashing], attester_slashings: Sequence[AttesterSlashing], attestations: Sequence[Attestation], deposits: Sequence[Deposit], exits: Sequence[Exit])-> None: super().__init__( proposer_slashings=proposer_slashings, attester_slashings=attester_slashings, attestations=attestations, deposits=deposits, exits=exits, ) @classmethod def create_empty_body(cls) -> 'BeaconBlockBody': return cls( proposer_slashings=(), attester_slashings=(), attestations=(), deposits=(), exits=(), ) @property def is_empty(self) -> bool: return ( self.proposer_slashings == () and self.attester_slashings == () and self.attestations == () and self.deposits == () and self.exits == () ) @classmethod def cast_block_body(cls, body: 'BeaconBlockBody') -> 'BeaconBlockBody': return cls( proposer_slashings=body.proposer_slashings, attester_slashings=body.attester_slashings, attestations=body.attestations, deposits=body.deposits, exits=body.exits, )
class CompactCommittee(ssz.Serializable): fields = [("pubkeys", List(bytes48, 1)), ("compact_validators", List(uint64, 1))] def __init__( self, pubkeys: Sequence[BLSPubkey] = default_tuple, compact_validators: Sequence[int] = default_tuple, ) -> None: super().__init__(pubkeys=pubkeys, compact_validators=compact_validators)
class BeaconBlockBody(ssz.Serializable): fields = [ ("randao_reveal", bytes96), ("eth1_data", Eth1Data), ("graffiti", bytes32), ("proposer_slashings", List(ProposerSlashing, 1)), ("attester_slashings", List(AttesterSlashing, 1)), ("attestations", List(Attestation, 1)), ("deposits", List(Deposit, 1)), ("voluntary_exits", List(VoluntaryExit, 1)), ] def __init__( self, *, randao_reveal: bytes96 = EMPTY_SIGNATURE, eth1_data: Eth1Data = default_eth1_data, graffiti: Hash32 = ZERO_HASH32, proposer_slashings: Sequence[ProposerSlashing] = default_tuple, attester_slashings: Sequence[AttesterSlashing] = default_tuple, attestations: Sequence[Attestation] = default_tuple, deposits: Sequence[Deposit] = default_tuple, voluntary_exits: Sequence[VoluntaryExit] = default_tuple, ) -> None: super().__init__( randao_reveal=randao_reveal, eth1_data=eth1_data, graffiti=graffiti, proposer_slashings=proposer_slashings, attester_slashings=attester_slashings, attestations=attestations, deposits=deposits, voluntary_exits=voluntary_exits, ) @property def is_empty(self) -> bool: return self == BeaconBlockBody() def __str__(self) -> str: return (f"randao_reveal={humanize_hash(self.randao_reveal)}," f" graffiti={humanize_hash(self.graffiti)}," f" proposer_slashings={self.proposer_slashings}," f" attester_slashings={self.attester_slashings}," f" attestations={self.attestations}," f" deposits={self.deposits}," f" voluntary_exits={self.voluntary_exits},") def __repr__(self) -> str: return f"<{self.__class__.__name__}: {str(self)}>"
class RecentBeaconBlocksRequest(ssz.Serializable): fields = [ ('block_roots', List(bytes32, 1)), ] def __init__(self, block_roots: Sequence[HashTreeRoot]) -> None: super().__init__(block_roots)
class BeaconBlocksResponse(ssz.Serializable): fields = [ ('blocks', List(BeaconBlock, 1)), ] def __init__(self, blocks: Sequence[BeaconBlock]) -> None: super().__init__(blocks)
def test_byte_list(value): serialized_value = ssz.encode(value, byte_list) assert serialized_value == ssz.encode( tuple(bytes([byte_value]) for byte_value in value), List(byte), ) assert ssz.decode(serialized_value, byte_list) == value
class Animal(Serializable): fields = [ ('id_hash', bytes32), ('public_key', bytes48), ('clock_in_records', List(ClockInRecords)), ('vaccinated', boolean), ]
class BeaconBlocksByRootRequest(ssz.Serializable): fields = [ ('block_roots', List(bytes32, 1)), ] def __init__(self, block_roots: Sequence[SigningRoot]) -> None: super().__init__(block_roots)
class IndexedAttestation(HashableContainer): fields = [ # Validator indices ("attesting_indices", List(uint64, 1)), # Attestation data ("data", AttestationData), # Aggregate signature ("signature", bytes96), ] @classmethod def create( cls: Type[TIndexedAttestation], attesting_indices: Sequence[ValidatorIndex] = default_tuple, data: AttestationData = default_attestation_data, signature: BLSSignature = EMPTY_SIGNATURE, ) -> TIndexedAttestation: return super().create( attesting_indices=attesting_indices, data=data, signature=signature ) def __str__(self) -> str: return ( f"attesting_indices={self.attesting_indices}," f" data=({self.data})," f" signature={humanize_hash(self.signature)}" )
class Animal(HashableContainer): fields = [ ("id_hash", bytes32), ("public_key", bytes48), ("clock_in_records", List(ClockInRecords, 2**32)), ("vaccinated", boolean), ]
def parse_type_definition(type_definition): error_message = f"Could not parse type definition {type_definition}" if isinstance(type_definition, str): try: sedes = sedes_by_name[type_definition] except KeyError: raise ValueError(error_message) else: return sedes elif isinstance(type_definition, Sequence): if len(type_definition) == 1: return List(parse_type_definition(type_definition[0])) elif len(type_definition) == 2: element_type = parse_type_definition(type_definition[0]) try: length = int(type_definition[1]) except ValueError: raise ValueError(error_message) return Vector(element_type, length) else: raise ValueError(error_message) elif isinstance(type_definition, Mapping): return Container(tuple( (field_name, parse_type_definition(field_type)) for field_name, field_type in type_definition.items() )) else: raise ValueError(error_message)
class Deposit(ssz.Serializable): """ A :class:`~eth2.beacon.types.deposits.Deposit` contains the data represented by an instance of :class:`~eth2.beacon.types.deposit_data.DepositData`, along with a Merkle proof (``branch`` and ``index``) that can be used to verify inclusion in the canonical deposit tree. """ fields = [ # Merkle branch in the deposit tree ('branch', List(bytes32)), # Index in the deposit tree ('index', uint64), # Deposit data ('deposit_data', DepositData), ] def __init__(self, branch: Sequence[Hash32], index: int, deposit_data: DepositData)-> None: super().__init__( branch, index, deposit_data, )
def test_list(value, serialized): sedes = List(uint8, 2**32) assert encode_hex(ssz.encode(value, sedes)) == serialized decoded = ssz.decode(decode_hex(serialized), sedes) assert isinstance(decoded, HashableList) assert tuple(decoded) == value assert decoded.sedes == sedes
def test_list_of_dynamic_sized_entries(value, serialized): sedes = Vector(List(uint8, 2**32), len(value)) assert encode_hex(ssz.encode(value, sedes)) == serialized decoded = ssz.decode(decode_hex(serialized), sedes) assert isinstance(decoded, HashableVector) assert tuple(tuple(element) for element in decoded) == value assert decoded.sedes == sedes
class BeaconBlocksByRootRequest(HashableContainer): fields = [ ('block_roots', List(bytes32, 64)), ] @classmethod def create(cls, block_roots: Sequence[Root]) -> "BeaconBlocksByRootRequest": return super().create(block_roots=block_roots)
def genesis_validators(validator_count, pubkeys, config): """ Returns ``validator_count`` number of activated validators. """ return HashableList.from_iterable( (create_mock_validator(pubkey=pubkey, config=config) for pubkey in pubkeys[:validator_count]), List(Validator, config.VALIDATOR_REGISTRY_LIMIT), )
class SlashableAttestation(ssz.Serializable): fields = [ # Validator indices ('validator_indices', List(uint64)), # Attestation data ('data', AttestationData), # Custody bitfield ('custody_bitfield', byte_list), # Aggregate signature ('aggregate_signature', bytes96), ] def __init__(self, validator_indices: Sequence[ValidatorIndex], data: AttestationData, custody_bitfield: bytes, aggregate_signature: BLSSignature = EMPTY_SIGNATURE) -> None: super().__init__( validator_indices, data, custody_bitfield, aggregate_signature, ) @property def are_validator_indices_ascending(self) -> bool: for i in range(len(self.validator_indices) - 1): if self.validator_indices[i] >= self.validator_indices[i + 1]: return False return True @property def custody_bit_indices(self) -> Tuple[Tuple[ValidatorIndex, ...], Tuple[ValidatorIndex, ...]]: custody_bit_0_indices = () # type: Tuple[ValidatorIndex, ...] custody_bit_1_indices = () # type: Tuple[ValidatorIndex, ...] for i, validator_index in enumerate(self.validator_indices): if not has_voted(self.custody_bitfield, i): custody_bit_0_indices += (validator_index,) else: custody_bit_1_indices += (validator_index,) return (custody_bit_0_indices, custody_bit_1_indices) @property def message_hashes(self) -> Tuple[Hash32, Hash32]: """ Build the message_hashes that validators are expected to sign for an ``AttesterSlashing`` operation. """ return ( AttestationDataAndCustodyBit(data=self.data, custody_bit=False).root, AttestationDataAndCustodyBit(data=self.data, custody_bit=True).root, )
def test_bytes_n_list_randomized(data, length, sequence_type): sedes = List(BytesN(length)) items = data.draw( st.lists( st.binary( min_size=length, max_size=length, ) ) ) value = sequence_type(items) assert len(hash_tree_root(value, sedes)) == 32
def general_list_sedes_and_values_st(draw, element_sedes_and_elements, size=None): element_sedes, elements = element_sedes_and_elements if size is None: size = draw(st.integers(min_value=1, max_value=10)) max_size = draw(st.integers(min_value=size, max_value=1024)) sedes = List(element_sedes, max_length=max_size) values = st.lists(elements, min_size=size, max_size=size) return sedes, values
def infer_list_sedes(obj): try: first_element, iterator = peek(obj) except StopIteration: # For empty lists we use any empty_list sedes. return empty_list else: try: element_sedes = infer_sedes(first_element) except TypeError: raise TypeError("Could not infer sedes for list elements", obj) else: return List(element_sedes)
class BeaconBlockBody(ssz.Serializable): fields = [ ("randao_reveal", bytes96), ("eth1_data", Eth1Data), ("graffiti", bytes32), ("proposer_slashings", List(ProposerSlashing, 1)), ("attester_slashings", List(AttesterSlashing, 1)), ("attestations", List(Attestation, 1)), ("deposits", List(Deposit, 1)), ("voluntary_exits", List(VoluntaryExit, 1)), ("transfers", List(Transfer, 1)), ] def __init__( self, *, randao_reveal: bytes96 = EMPTY_SIGNATURE, eth1_data: Eth1Data = default_eth1_data, graffiti: Hash32 = ZERO_HASH32, proposer_slashings: Sequence[ProposerSlashing] = default_tuple, attester_slashings: Sequence[AttesterSlashing] = default_tuple, attestations: Sequence[Attestation] = default_tuple, deposits: Sequence[Deposit] = default_tuple, voluntary_exits: Sequence[VoluntaryExit] = default_tuple, transfers: Sequence[Transfer] = default_tuple, ) -> None: super().__init__( randao_reveal=randao_reveal, eth1_data=eth1_data, graffiti=graffiti, proposer_slashings=proposer_slashings, attester_slashings=attester_slashings, attestations=attestations, deposits=deposits, voluntary_exits=voluntary_exits, transfers=transfers, ) @property def is_empty(self) -> bool: return self == BeaconBlockBody()
from ssz.sedes import Container, List, uint8, uint16, uint32, uint256 class ByteList(List): # type: ignore def __init__(self, max_length: int) -> None: super().__init__(element_sedes=uint8, max_length=max_length) def serialize(self, value: bytes) -> bytes: return value def deserialize(self, value: bytes) -> bytes: return value byte_list = ByteList(max_length=2048) PingSedes = Container(field_sedes=(uint32, uint256)) PongSedes = Container(field_sedes=(uint32, uint256)) FindNodesSedes = Container(field_sedes=(List(uint16, max_length=256),)) FoundNodesSedes = Container(field_sedes=(uint8, List(byte_list, max_length=32))) FindContentSedes = Container(field_sedes=(byte_list,)) FoundContentSedes = Container(field_sedes=(List(byte_list, max_length=32), byte_list))
class BeaconBlockBody(ssz.Serializable): fields = [ ('randao_reveal', bytes96), ('eth1_data', Eth1Data), ('proposer_slashings', List('ProposerSlashing')), ('attester_slashings', List(AttesterSlashing)), ('attestations', List(Attestation)), ('deposits', List(Deposit)), ('voluntary_exits', List(VoluntaryExit)), ('transfers', List(Transfer)), ] def __init__(self, *, randao_reveal: bytes96, eth1_data: Eth1Data, proposer_slashings: Sequence['ProposerSlashing'], attester_slashings: Sequence[AttesterSlashing], attestations: Sequence[Attestation], deposits: Sequence[Deposit], voluntary_exits: Sequence[VoluntaryExit], transfers: Sequence[Transfer])-> None: super().__init__( randao_reveal=randao_reveal, eth1_data=eth1_data, proposer_slashings=proposer_slashings, attester_slashings=attester_slashings, attestations=attestations, deposits=deposits, voluntary_exits=voluntary_exits, transfers=transfers, ) @classmethod def create_empty_body(cls) -> 'BeaconBlockBody': return cls( randao_reveal=EMPTY_SIGNATURE, eth1_data=Eth1Data.create_empty_data(), proposer_slashings=(), attester_slashings=(), attestations=(), deposits=(), voluntary_exits=(), transfers=(), ) @property def is_empty(self) -> bool: return ( self.randao_reveal == EMPTY_SIGNATURE and self.eth1_data == Eth1Data.create_empty_data() and self.proposer_slashings == () and self.attester_slashings == () and self.attestations == () and self.deposits == () and self.voluntary_exits == () and self.transfers == () ) @classmethod def cast_block_body(cls, body: 'BeaconBlockBody') -> 'BeaconBlockBody': return cls( randao_reveal=body.randao_reveal, eth1_data=body.eth1_data, proposer_slashings=body.proposer_slashings, attester_slashings=body.attester_slashings, attestations=body.attestations, deposits=body.deposits, voluntary_exits=body.voluntary_exits, transfers=body.transfers, ) _hash_tree_root = None @property def hash_tree_root(self) -> Hash32: if self._hash_tree_root is None: self._hash_tree_root = ssz.hash_tree_root(self) return self._hash_tree_root