def test_chaindb_get_score(chaindb, sample_beacon_block_params): genesis = BeaconBlock(**sample_beacon_block_params).copy( parent_root=GENESIS_PARENT_HASH, slot=0, ) chaindb.persist_block(genesis, genesis.__class__) genesis_score_key = SchemaV1.make_block_root_to_score_lookup_key( genesis.root) genesis_score = ssz.decode(chaindb.db.get(genesis_score_key), sedes=ssz.sedes.uint64) assert genesis_score == 0 assert chaindb.get_score(genesis.root) == 0 block1 = BeaconBlock(**sample_beacon_block_params).copy( parent_root=genesis.root, slot=1, ) chaindb.persist_block(block1, block1.__class__) block1_score_key = SchemaV1.make_block_root_to_score_lookup_key( block1.root) block1_score = ssz.decode(chaindb.db.get(block1_score_key), sedes=ssz.sedes.uint64) assert block1_score == 1 assert chaindb.get_score(block1.root) == 1
def execute_invalid_ssz_test(test_case, sedes): if "value" in test_case and "ssz" in test_case: raise ValueError( "Test case for invalid inputs contains both value and ssz") if "value" in test_case: value = from_formatted_dict(test_case["value"], sedes, CustomCodec) try: ssz.encode(value, sedes) except SSZException: pass else: raise FailedTestCase( "Serializing invalid value did not yield an exception") elif "ssz" in test_case: serial = decode_hex(test_case["ssz"]) try: ssz.decode(serial, sedes) except SSZException: pass else: raise FailedTestCase( "Deserializing invalid SSZ did not yield an exception") else: raise ValueError( "Test case for invalid inputs contains neither value nor ssz")
def main(): logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s: %(message)s') override_lengths(MINIMAL_SERENITY_CONFIG) with open('state_15.ssz', 'rb') as f: pre_state_encoded = f.read() pre_state = ssz.decode(pre_state_encoded, sedes=BeaconState) with open('block_16.ssz', 'rb') as f: block_encoded = f.read() pre_block = ssz.decode(block_encoded, sedes=BeaconBlock) trinity_post = trinity_transition(pre_state, pre_block) pyspec_post = pyspec_transition(pre_state, pre_block) for index in range(len(pyspec_post.balances)): assert trinity_post.balances[index] == pyspec_post.balances[index] if trinity_post.balances[index] == pyspec_post.balances[index]: continue print(f"trinity balances[{index}]: \t" f"{trinity_post.balances[index].to_bytes(8, 'big').hex()}") print(f"pyspec balances[{index}]: \t" f"{pyspec_post.balances[index].to_bytes(8, 'big').hex()}") print(f"trinity: {trinity_post.current_crosslinks[7]}") print(f"pyspec: {pyspec_post.current_crosslinks[7]}")
def test_byte_vector_invalid_length(value, expected_length): byte_vector = ByteVector(expected_length) with pytest.raises(SerializationError): ssz.encode(value, byte_vector) properly_serialized_value = value with pytest.raises(DeserializationError): ssz.decode(properly_serialized_value, byte_vector)
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)
def _get_genesis_data(self) -> Tuple[Timestamp, Root]: key = SchemaV1.genesis_data() try: data = self.db[key] except KeyError: return default_timestamp, default_root genesis_time = ssz.decode(data[:8], ssz.sedes.uint64) genesis_validators_root = ssz.decode(data[8:], ssz.sedes.bytes32) return Timestamp(genesis_time), Root(genesis_validators_root)
def test_deserialization_for_custom_init_method(): type_3 = SSZType3(2, 1, 3) assert type_3.field1 == 1 assert type_3.field2 == 2 assert type_3.field3 == 3 result = decode(encode(type_3), sedes=SSZType3) assert result.field1 == 1 assert result.field2 == 2 assert result.field3 == 3 result_sedes_encode = decode(encode(type_3, SSZType3), sedes=SSZType3) assert result_sedes_encode.field1 == 1 assert result_sedes_encode.field2 == 2 assert result_sedes_encode.field3 == 3
def test_tuple_of_static_sized_entries(value, serialized): sedes = Vector(uint8, len(value)) assert encode_hex(ssz.encode(value, sedes)) == serialized decoded = ssz.decode(decode_hex(serialized), sedes) assert isinstance(decoded, HashableVector) assert tuple(decoded) == value assert decoded.sedes == sedes
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 beacon_aggregate_and_proof_validator(msg_forwarder: ID, msg: rpc_pb2.Message) -> bool: try: aggregate_and_proof = ssz.decode(msg.data, sedes=AggregateAndProof) except (TypeError, ssz.DeserializationError) as error: # Not correctly encoded logger.debug( bold_red( "Failed to deserialize AggregateAndProof from %s, error=%s" ), encode_hex(msg.data), str(error), ) return False state = chain.get_head_state() state_machine = chain.get_state_machine() attestation = aggregate_and_proof.aggregate try: validate_voting_beacon_block(chain, attestation) run_validate_aggregate_and_proof( state, aggregate_and_proof, state_machine.config, ) except InvalidGossipMessage as error: logger.debug("%s", str(error)) return False return True
async def test_get_canonical_block_range_by_root(request, event_loop): chain_db = get_chain_db() genesis = create_test_block(slot=0) base_branch = create_branch(3, root=genesis) non_canonical_branch = create_branch(3, root=base_branch[-1], state_root=b"\x00" * 32) canonical_branch = create_branch(4, root=base_branch[-1], state_root=b"\x11" * 32) for branch in [[genesis], base_branch, non_canonical_branch, canonical_branch]: chain_db.persist_block_chain(branch, BeaconBlock) alice, response_buffer = await get_request_server_setup( request, event_loop, chain_db) alice.sub_proto.send_get_blocks(base_branch[1].root, 4, request_id=5) response = await response_buffer.msg_queue.get() assert isinstance(response.command, BeaconBlocks) assert response.payload["request_id"] == 5 blocks = tuple( ssz.decode(block, BeaconBlock) for block in response.payload["encoded_blocks"]) assert len(blocks) == 4 assert [block.slot for block in blocks] == [2, 3, 4, 5] assert blocks == base_branch[1:] + canonical_branch[:2]
def committee_index_beacon_attestation_validator( msg_forwarder: ID, msg: rpc_pb2.Message) -> bool: try: attestation = ssz.decode(msg.data, sedes=Attestation) except (TypeError, ssz.DeserializationError) as error: # Not correctly encoded logger.debug( bold_red("Failed to validate attestation=%s, error=%s"), encode_hex(msg.data), str(error), ) return False state_machine = chain.get_state_machine() state = chain.get_head_state() try: validate_subnet_id(attestation, subnet_id) validate_is_unaggregated(attestation) validate_voting_beacon_block(chain, attestation) validate_attestation_propagation_slot_range( state, attestation, ATTESTATION_PROPAGATION_SLOT_RANGE, ) validate_attestation_signature( state, attestation, CommitteeConfig(state_machine.config), ) except InvalidGossipMessage as error: logger.debug("%s", str(error)) return False else: return True
def _get_score(db: BaseDB, block_root: Hash32) -> int: try: encoded_score = db[SchemaV1.make_block_root_to_score_lookup_key(block_root)] except KeyError: raise BlockNotFound("No block with hash {0} found".format( encode_hex(block_root))) return ssz.decode(encoded_score, sedes=ssz.sedes.uint64)
def from_wire_bytes(cls: Type["MessagePacket"], data: bytes) -> "MessagePacket": tag, auth_tag, encrypted_message = ssz.decode(data, MESSAGE_PACKET_SEDES) return cls( tag=tag, auth_tag=auth_tag, encrypted_message=encrypted_message, )
def _decrypt_payload(key: AES128Key, auth_tag: Nonce, encrypted_message: bytes, authenticated_data: bytes, message_registry: RegistryAPI, ) -> ssz.Serializable: plain_text = aesgcm_decrypt( key=key, nonce=auth_tag, cipher_text=encrypted_message, authenticated_data=authenticated_data, ) try: message_id = plain_text[0] except IndexError: raise ValidationError("Decrypted message is empty") try: sedes = message_registry.get_sedes(message_id) except KeyError: raise ValidationError(f"Unknown message type {message_id}") try: message = ssz.decode(plain_text[1:], sedes) except ssz.DeserializationError as error: raise ValidationError("Encrypted message does not contain valid RLP") from error return message
def from_wire_bytes(cls: Type["CompleteHandshakePacket"], data: bytes) -> "CompleteHandshakePacket": tag, header_as_tuple, encrypted_message = ssz.decode(data, COMPLETE_HANDSHAKE_PACKET_SEDES) ( auth_tag, id_nonce, auth_scheme_name, ephemeral_public_key_bytes, public_key_bytes, encrypted_auth_response, ) = header_as_tuple ephemeral_public_key = keys.PublicKey.from_compressed_bytes(ephemeral_public_key_bytes) public_key = keys.PublicKey.from_compressed_bytes(public_key_bytes) header = AuthHeader( auth_tag, id_nonce, auth_scheme_name, ephemeral_public_key, public_key=public_key, encrypted_auth_response=encrypted_auth_response, ) return cls( tag=tag, header=header, encrypted_message=encrypted_message, )
async def test_bcc_receive_server_handle_attestations_checks( request, event_loop, event_bus, monkeypatch): async with get_peer_and_receive_server( request, event_loop, event_bus, ) as (alice, _, bob_recv_server, bob_msg_queue): attestation = Attestation() def _validate_attestations(attestations): return tuple(attestations) monkeypatch.setattr( bob_recv_server, '_validate_attestations', _validate_attestations, ) alice.sub_proto.send_attestation_records([attestation]) msg = await bob_msg_queue.get() assert len(msg['encoded_attestations']) == 1 decoded_attestation = ssz.decode(msg['encoded_attestations'][0], Attestation) assert decoded_attestation == attestation
def _read_state_eth1_data_votes(self, state_root: Root) -> Iterable[Eth1Data]: key = SchemaV1.state_root_to_eth1_data_votes(state_root) roots = _bytes_to_roots(self.db[key]) for root in roots: yield ssz.decode(self.db[bytes(root)], Eth1Data)
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
def mark_finalized_head(self, block: BaseBeaconBlock) -> None: """ Marks the given ``block`` as finalized and stores each newly finalized state and block at their corresponding slot. """ if block.slot > 0: newly_finalized_states = self.get_state_parents( block.state_root, block.slot - self.get_finalized_head(BeaconBlock).slot) + ( block.state_root, ) else: newly_finalized_states = (block.state_root, ) for state_root in newly_finalized_states: slot = ssz.decode(self.db[SchemaV1.state_root_to_slot(state_root)], ssz.uint64) self.db[SchemaV1.slot_to_state_root(slot)] = state_root latest_block_header = self._read_state_block_header(state_root) slot_to_block_root = SchemaV1.slot_to_block_root( latest_block_header.slot) self.db[slot_to_block_root] = latest_block_header.hash_tree_root self.db[SchemaV1.slot_to_block_root(block.slot)] = block.hash_tree_root self.db[SchemaV1.finalized_head_root()] = block.hash_tree_root
def decode_payload(self, data: bytes) -> sedes.Serializable: message_id = data[0] try: sedes = self._payload_sedes[message_id] except KeyError: raise ValueError(f"Unknown message type: {message_id}") return ssz.decode(data[1:], sedes)
async def _handle_attestations(self, peer: BCCPeer, msg: AttestationsMessage) -> None: if not peer.is_operational: return encoded_attestations = msg["encoded_attestations"] attestations = tuple( ssz.decode(encoded_attestation, Attestation) for encoded_attestation in encoded_attestations ) self.logger.debug("Received attestations=%s", attestations) # Validate attestations valid_attestations = self._validate_attestations(attestations) if len(valid_attestations) == 0: return # Check if attestations has been seen already. # Filter out those seen already. valid_new_attestations = tuple( filter( self._is_attestation_new, valid_attestations, ) ) if len(valid_new_attestations) == 0: return # Add the valid and new attestations to attestation pool. self.attestation_pool.batch_add(valid_new_attestations) # Broadcast the valid and new attestations. self._broadcast_attestations(valid_new_attestations, peer)
async def test_get_incomplete_canonical_block_range(request, event_loop, event_bus): chain_db = await get_chain_db() genesis = create_test_block() base_branch = create_branch(3, root=genesis) non_canonical_branch = create_branch(3, root=base_branch[-1], state_root=b"\x00" * 32) canonical_branch = create_branch(4, root=base_branch[-1], state_root=b"\x11" * 32) for branch in [[genesis], base_branch, non_canonical_branch, canonical_branch]: scorings = (higher_slot_scoring for block in branch) await chain_db.coro_persist_block_chain(branch, BeaconBlock, scorings) async with get_request_server_setup(request, event_loop, event_bus, chain_db) as (alice, response_buffer): alice.sub_proto.send_get_blocks(genesis.slot + 3, 10, request_id=5) response = await response_buffer.msg_queue.get() assert isinstance(response.command, BeaconBlocks) assert response.payload["request_id"] == 5 blocks = tuple( ssz.decode(block, BeaconBlock) for block in response.payload["encoded_blocks"]) assert len(blocks) == 5 assert [block.slot for block in blocks ] == [genesis.slot + s for s in [3, 4, 5, 6, 7]] assert blocks == base_branch[-1:] + canonical_branch
def _read_state_current_epoch_attestations( self, state_root: Root) -> Iterable[PendingAttestation]: key = SchemaV1.state_root_to_current_epoch_attestations(state_root) roots = _bytes_to_roots(self.db[key]) for root in roots: yield ssz.decode(self.db[bytes(root)], PendingAttestation)
def beacon_block_validator(msg_forwarder: ID, msg: rpc_pb2.Message) -> bool: try: block = ssz.decode(msg.data, BeaconBlock) except (TypeError, ssz.DeserializationError) as error: logger.debug( bold_red("Failed to validate block=%s, error=%s"), encode_hex(block.signing_root), str(error), ) return False state_machine = chain.get_state_machine(block.slot - 1) state_transition = state_machine.state_transition state = chain.get_head_state() # Fast forward to state in future slot in order to pass # block.slot validity check state = state_transition.apply_state_transition( state, future_slot=block.slot, ) try: validate_proposer_signature(state, block, CommitteeConfig(state_machine.config)) except ValidationError as error: logger.debug( bold_red("Failed to validate block=%s, error=%s"), encode_hex(block.signing_root), str(error), ) return False else: return True
def test_byte_vector(value): byte_vector = ByteVector(len(value)) serialized_value = ssz.encode(value, byte_vector) assert serialized_value == ssz.encode( tuple(bytes([byte_value]) for byte_value in value), Vector(byte, len(value))) assert ssz.decode(serialized_value, byte_vector) == value
def beacon_attestation_validator(msg_forwarder: ID, msg: rpc_pb2.Message) -> bool: try: attestation = ssz.decode(msg.data, sedes=Attestation) except (TypeError, ssz.DeserializationError) as error: # Not correctly encoded logger.debug( bold_red( "Failed to deserialize Attestation from %s, error=%s"), encode_hex(msg.data), str(error), ) return False state = chain.get_head_state() state_machine = chain.get_state_machine() try: validate_voting_beacon_block(chain, attestation) validate_attestation_signature( state, attestation, CommitteeConfig(state_machine.config), ) except InvalidGossipMessage as error: logger.debug("%s", str(error)) return False else: return True
def test_container_of_static_sized_fields(value, serialized): field_names = tuple(str(index) for index in range(len(value))) sedes = Container(tuple((field_name, uint8) for field_name in field_names)) value_dict = {field_name: field_value for field_name, field_value in zip(field_names, value)} assert encode_hex(ssz.encode(value_dict, sedes)) == serialized assert ssz.decode(decode_hex(serialized), sedes) == value_dict
async def test_get_non_canonical_branch(request, event_loop): chain_db = await get_chain_db() genesis = create_test_block() base_branch = create_branch(3, root=genesis) non_canonical_branch = create_branch(3, root=base_branch[-1], state_root=b"\x00" * 32) canonical_branch = create_branch(4, root=base_branch[-1], state_root=b"\x11" * 32) for branch in [[genesis], base_branch, non_canonical_branch, canonical_branch]: await chain_db.coro_persist_block_chain(branch, BeaconBlock) alice, response_buffer = await get_request_server_setup( request, event_loop, chain_db) alice.sub_proto.send_get_blocks(non_canonical_branch[1].signing_root, 3, request_id=5) response = await response_buffer.msg_queue.get() assert isinstance(response.command, BeaconBlocks) assert response.payload["request_id"] == 5 blocks = tuple( ssz.decode(block, BeaconBlock) for block in response.payload["encoded_blocks"]) assert len(blocks) == 1 assert blocks[0].slot == genesis.slot + 5 assert blocks[0] == non_canonical_branch[1]
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