def test_equality(identity_scheme_registry): base_kwargs = { "sequence_number": 0, "kv_pairs": { b"id": b"mock", b"key1": b"value1", b"key2": b"value2" }, "signature": b"signature", "identity_scheme_registry": identity_scheme_registry, } base_enr = ENR(**base_kwargs) equal_enr = ENR(**base_kwargs) enr_different_sequence_number = ENR( **assoc(base_kwargs, "sequence_number", 1)) enr_different_kv_pairs = ENR( **assoc_in(base_kwargs, ("kv_pairs", b"key1"), b"value2")) enr_different_signature = ENR( **assoc(base_kwargs, "signature", b"different-signature")) assert base_enr == base_enr assert equal_enr == base_enr assert enr_different_sequence_number != base_enr assert enr_different_kv_pairs != base_enr assert enr_different_signature != base_enr
def test_mapping_interface(identity_scheme_registry): kv_pairs = {b"id": b"mock", b"key1": b"value1", b"key2": b"value2"} enr = ENR( signature=b"", sequence_number=0, kv_pairs=kv_pairs, identity_scheme_registry=identity_scheme_registry, ) for key, value in kv_pairs.items(): assert key in enr assert enr[key] == value assert enr.get(key) == value not_a_key = b"key3" assert not_a_key not in kv_pairs assert not_a_key not in enr enr.get(not_a_key) is None assert enr.get(not_a_key, b"default") == b"default" assert tuple(enr.keys()) == tuple(kv_pairs.keys()) assert tuple(enr.values()) == tuple(kv_pairs.values()) assert tuple(enr.items()) == tuple(kv_pairs.items()) assert len(enr) == len(kv_pairs) assert tuple(iter(enr)) == tuple(iter(kv_pairs))
def test_signature_scheme_selection(mock_identity_scheme, identity_scheme_registry): mock_enr = ENR(0, {b"id": b"mock"}, b"", identity_scheme_registry) assert mock_enr.identity_scheme is mock_identity_scheme v4_enr = ENR(0, { b"id": b"v4", b"secp256k1": b"\x02" * 33 }, b"", identity_scheme_registry) assert v4_enr.identity_scheme is V4IdentityScheme with pytest.raises(UnknownIdentityScheme): ENR(0, {b"id": b"other"}, b"", identity_scheme_registry)
def test_real_life_test_vector(): enr = ENR.from_repr(REAL_LIFE_TEST_DATA["repr"]) assert enr.sequence_number == REAL_LIFE_TEST_DATA["sequence_number"] assert enr.public_key == REAL_LIFE_TEST_DATA["public_key"] assert enr.node_id == REAL_LIFE_TEST_DATA["node_id"] assert enr.identity_scheme is REAL_LIFE_TEST_DATA["identity_scheme"] assert dict(enr) == REAL_LIFE_TEST_DATA["kv_pairs"] assert repr(enr) == REAL_LIFE_TEST_DATA["repr"]
def test_inititialization(identity_scheme_registry): valid_sequence_number = 0 valid_kv_pairs = {b"id": b"mock"} valid_signature = b"" # signature is not validated during initialization assert UnsignedENR( sequence_number=valid_sequence_number, kv_pairs=valid_kv_pairs, identity_scheme_registry=identity_scheme_registry, ) assert ENR( sequence_number=valid_sequence_number, kv_pairs=valid_kv_pairs, signature=valid_signature, identity_scheme_registry=identity_scheme_registry, ) with pytest.raises(ValidationError): UnsignedENR( sequence_number=valid_sequence_number, kv_pairs={b"no-id": b""}, identity_scheme_registry=identity_scheme_registry, ) with pytest.raises(ValidationError): ENR( sequence_number=valid_sequence_number, kv_pairs={b"no-id": b""}, signature=valid_signature, identity_scheme_registry=identity_scheme_registry, ) with pytest.raises(ValidationError): UnsignedENR( sequence_number=-1, kv_pairs=valid_kv_pairs, identity_scheme_registry=identity_scheme_registry, ) with pytest.raises(ValidationError): ENR( sequence_number=-1, kv_pairs=valid_kv_pairs, signature=valid_signature, identity_scheme_registry=identity_scheme_registry, )
def test_repr(mock_identity_scheme, identity_scheme_registry): unsigned_enr = UnsignedENR(0, {b"id": b"mock"}, identity_scheme_registry) enr = unsigned_enr.to_signed_enr(b"\x00" * 32) base64_encoded_enr = base64.urlsafe_b64encode(rlp.encode(enr)) represented_enr = repr(enr) assert represented_enr.startswith("enr:") assert base64_encoded_enr.rstrip(b"=").decode() == represented_enr[4:] assert ENR.from_repr(represented_enr, identity_scheme_registry) == enr
def to_enr(self) -> ENRAPI: kv_pairs = { field.key: _decode_enr_value(field.key, field.value) for field in self.fields } return ENR( sequence_number=self.sequence_number, kv_pairs=kv_pairs, signature=self.signature, )
def test_signature_validation(mock_identity_scheme, identity_scheme_registry): unsigned_enr = UnsignedENR(0, {b"id": b"mock"}, identity_scheme_registry) private_key = b"\x00" * 32 enr = unsigned_enr.to_signed_enr(private_key) enr.validate_signature() invalid_signature = b"\xff" * 64 invalid_enr = ENR( enr.sequence_number, dict(enr), invalid_signature, identity_scheme_registry=identity_scheme_registry, ) with pytest.raises(ValidationError): invalid_enr.validate_signature() with pytest.raises(UnknownIdentityScheme): ENR( 0, {b"id": b"unknown"}, b"", identity_scheme_registry=identity_scheme_registry, )
def test_query_with_enr_sequence_number_zero(enr_db): enr = ENR.from_repr( "enr:-Ji4QEdP7fMAICGFlUAxY2cbTYXbPImZzMoKHFyssXNz7zWRNkFZ7Q4EJo3rZsDUVbyo5e_d-zBIDCUHgq72oEIokSaAgmlkgnY0gmlwhMCzfZuJc2VjcDI1NmsxoQNCiVGdz4CJY3sD7bHTrhPcgOu18gfMuyc6kgicqYR_0YN0Y3CC192EdGVzdId2YWx1ZS1Bg3VkcIK0fw" # noqa: E501 ) assert b"test" in enr assert enr.sequence_number == 0 enr_db.set_enr(enr) enr_results = set(enr_db.query(KeyExists(b"test"))) assert len(enr_results) == 1 assert enr in enr_results
def test_record_query_with_key_present_in_earlier_record(conn): # Demonstrate that when we have an *outdated* record with the given key # that it doesn't get returned in the query enr_0 = ENR.from_repr( "enr:-Ji4QP4nHj12UZ8um1c9pplfNYzD7tmDKm5zjWXAQbtvaHQGHYfgHPBNMqPrKjkw1vPnzhxTxYvKxQaYsTsr8tXuG-aAgmlkgnY0gmlwhFIKDgiJc2VjcDI1NmsxoQLBnsAJ3ol6-WoC_oldxmv85K9CVaIxFD1U1qY5ik9-7YN0Y3CCme-EdGVzdId2YWx1ZS1Bg3VkcILjVw" # noqa: E501 ) enr_7 = ENR.from_repr( "enr:-Iu4QAEoWs6MtSYdWONcnR7ekG2lunNxxVlg_xgTKzAUTJDLeqQo06oKbnesHUBl77IFzlnj_GcoYNVnM13ap0i3GAYHgmlkgnY0gmlwhDN7BECJc2VjcDI1NmsxoQLBnsAJ3ol6-WoC_oldxmv85K9CVaIxFD1U1qY5ik9-7YN0Y3CCxMGDdWRwguHh" # noqa: E501 ) assert enr_0.node_id == enr_7.node_id assert enr_0.sequence_number == 0 assert enr_7.sequence_number == 7 assert b"test" in enr_0 assert b"test" not in enr_7 insert_record(conn, Record.from_enr(enr_0)) insert_record(conn, Record.from_enr(enr_7)) results = tuple(query_records(conn, required_keys=(b"test", ))) assert len(results) == 0
def test_official_test_vector(): enr = ENR.from_repr( OFFICIAL_TEST_DATA["repr"]) # use default identity scheme registry assert enr.sequence_number == OFFICIAL_TEST_DATA["sequence_number"] assert dict(enr) == OFFICIAL_TEST_DATA["kv_pairs"] assert enr.public_key == OFFICIAL_TEST_DATA["public_key"] assert enr.node_id == OFFICIAL_TEST_DATA["node_id"] assert enr.identity_scheme is OFFICIAL_TEST_DATA["identity_scheme"] assert repr(enr) == OFFICIAL_TEST_DATA["repr"] unsigned_enr = UnsignedENR(enr.sequence_number, dict(enr)) reconstructed_enr = unsigned_enr.to_signed_enr( OFFICIAL_TEST_DATA["private_key"]) assert reconstructed_enr == enr
def test_enr_with_non_standard_values_for_standard_keys(): custom_kv_pairs = { b"ip": b"too-long-for-ipv4", b"ip6": b"too-short", b"udp": b"\x00\x01\x00", # invalid encoding for an integer b"tcp": b"\x00\x01\x00", # invalid encoding for an integer b"udp6": b"\x00\x01\x00", # invalid encoding for an integer b"tcp6": b"\x00\x01\x00", # invalid encoding for an integer } enr = ENRFactory(custom_kv_pairs=custom_kv_pairs, ) for key, value in custom_kv_pairs.items(): assert enr[key] == value result = ENR.from_repr(repr(enr)) assert result == enr
def test_serialization_roundtrip(identity_scheme_registry): original_enr = ENR( sequence_number=0, kv_pairs={ b"id": b"mock", b"key2": b"value2", # wrong order so that serialization is forced to fix this b"key1": b"value1", }, signature=b"", identity_scheme_registry=identity_scheme_registry, ) encoded = rlp.encode(original_enr) recovered_enr = rlp.decode( encoded, ENR, identity_scheme_registry=identity_scheme_registry) assert recovered_enr == original_enr
def test_record_query_with_enr_sequence_zero(conn): # This is more of a regression test. Previously the SQL query used a # HAVING clause which didn't work correctly when the only record had a # sequence number of 0. enr = ENR.from_repr( "enr:-Ji4QEdP7fMAICGFlUAxY2cbTYXbPImZzMoKHFyssXNz7zWRNkFZ7Q4EJo3rZsDUVbyo5e_d-zBIDCUHgq72oEIokSaAgmlkgnY0gmlwhMCzfZuJc2VjcDI1NmsxoQNCiVGdz4CJY3sD7bHTrhPcgOu18gfMuyc6kgicqYR_0YN0Y3CC192EdGVzdId2YWx1ZS1Bg3VkcIK0fw" # noqa: E501 ) record = Record.from_enr(enr) insert_record(conn, record) assert get_record(conn, record.node_id) == record assert b"test" in enr results = tuple(query_records(conn, required_keys=(b"test", ))) assert len(results) == 1 assert results[0] == record
def deserialize( cls, serialized_enr: Sequence[bytes], identity_scheme_registry: IdentitySchemeRegistryAPI = default_id_scheme_registry, ) -> ENRAPI: from eth_enr.enr import ENR # noqa: F811 cls._validate_serialized_length(serialized_enr) signature = binary.deserialize(serialized_enr[0]) unsigned_enr = ENRContentSedes.deserialize( serialized_enr[1:], identity_scheme_registry=identity_scheme_registry) return ENR( unsigned_enr.sequence_number, dict(unsigned_enr), signature, identity_scheme_registry, )