libp2p.records package

Submodules

libp2p.records.ipns module

class libp2p.records.ipns.IPNSValidator(*, check_expiration: bool = True)

Bases: Validator

IPNS record validator per https://specs.ipfs.tech/ipns/ipns-record/

IPNS provides mutable pointers to content-addressed data. Records are signed with Ed25519 (default) or RSA keys and validated using the V2 signature format with DAG-CBOR encoded data.

Features:

  • Full V2 record validation with DAG-CBOR

  • Backward compatibility with V1 fields

  • Public key extraction from name or record

  • RFC3339 timestamp validation with nanosecond support

  • Sequence-based record selection

  • Comprehensive error messages for debugging

Example:

from libp2p.records.ipns import IPNSValidator
from libp2p.records.validator import NamespacedValidator

# Register with a DHT's namespaced validator
validator = NamespacedValidator({"ipns": IPNSValidator()})

# Validate an IPNS record
validator.validate("/ipns/<multihash-hex>", record_bytes)

# Select the best record from multiple candidates
best = IPNSValidator().select(key, [record1, record2])
select(key: str, values: list[bytes]) int

Select the best IPNS record from candidates per spec.

Selection algorithm (per IPNS spec section 5.4):

  1. Higher sequence number wins

  2. If sequences are equal, later validity timestamp wins

  3. Invalid (unparseable) records are skipped

Note

This method does not perform full cryptographic validation (signature verification, expiry checks, V1/V2 consistency). It only parses the record to extract sequence and validity for comparison. Callers must call validate() on the winning record before trusting it.

Args:

key: The IPNS key (used for context, not validation here) values: List of serialized IPNS records to compare

Returns:

Index of the best record in the values list

Raises:

ValueError: If values list is empty

validate(key: str, value: bytes) None

Validate an IPNS record per spec section 5.3 (Record Verification).

Validation steps:

  1. Verify namespace is ‘ipns’

  2. Check record size <= 10 KiB

  3. Parse protobuf and verify required V2 fields (signatureV2, data)

  4. Extract public key from record or IPNS name

  5. Decode and validate DAG-CBOR data structure

  6. Verify signatureV2 against “ipns-signature:” + CBOR data

  7. Validate CBOR field types and values

  8. If V1 fields present, confirm they match CBOR values

  9. Check validity expiration (RFC3339 timestamp)

Args:

key: The IPNS key in format “/ipns/<multihash>” value: The serialized IpnsEntry protobuf bytes

Raises:

InvalidRecordType: If any validation step fails

validate_with_details(key: str, value: bytes) ParsedIPNSRecord

Validate an IPNS record and return parsed details.

This is useful for callers that need structured access to the validated record fields (e.g. inspecting sequence, expiry, or content path).

Args:

key: The IPNS key in format “/ipns/<multihash>” value: The serialized IpnsEntry protobuf bytes

Returns:

ParsedIPNSRecord with the validated record details

Raises:

InvalidRecordType: If validation fails

class libp2p.records.ipns.ParsedIPNSRecord(value: bytes, validity: datetime, validity_type: ValidityType, sequence: int, ttl: int | None, public_key_inlined: bool, has_v1_fields: bool)

Bases: object

Parsed and validated IPNS record data.

This provides a structured view of the IPNS record after validation, useful for debugging and inspection.

has_v1_fields: bool

True when legacy V1 protobuf fields (value, validity, signatureV1) are present in the record.

public_key_inlined: bool

True when the public key was inlined in the IPNS name via an identity multihash (typical for Ed25519 keys).

sequence: int

Monotonically increasing sequence number (uint64).

ttl: int | None

Time-to-live hint in nanoseconds, or None if absent.

validity: datetime

Parsed expiration timestamp (timezone-aware UTC).

validity_type: ValidityType

The validity type (currently only ValidityType.EOL).

value: bytes

The content path (e.g. b"/ipfs/Qm...").

class libp2p.records.ipns.ValidityType(value)

Bases: IntEnum

IPNS record validity types per spec.

EOL = 0

libp2p.records.pubkey module

class libp2p.records.pubkey.PublicKeyValidator

Bases: Validator

Validator for public key records.

select(key: str, values: list[bytes]) int

Select a value from a list of public key records.

Args:

key (str): The key associated with the records. values (list[bytes]): A list of public key values.

Returns:

int: Always returns 0 as all public keys are treated identically.

validate(key: str, value: bytes) None

Validate a public key record.

Uses py-multihash v3 is_valid() for efficient validation without exception overhead.

Args:

key (str): The key associated with the record. value (bytes): The value of the record, expected to be a public key.

Raises:
InvalidRecordType: If the namespace is not ‘pk’, the key

is not a valid multihash, the public key cannot be unmarshaled, the peer ID cannot be derived, or the public key does not match the storage key.

libp2p.records.pubkey.unmarshal_public_key(data: bytes) PublicKey

Deserialize a public key from its serialized byte representation. This function takes a byte sequence representing a serialized public key and reconstructs the corresponding PublicKey object based on its type.

Args:

data (bytes): The serialized byte representation of the public key.

Returns:

PublicKey: The deserialized public key object.

Raises:

ValueError: If the key type is unsupported or unrecognized.

Supported Key Types:
  • RSA

  • Ed25519

  • Secp256k1

libp2p.records.record module

libp2p.records.record.make_put_record(key: bytes, value: bytes) Record

Create a new Record object with the specified key and value.

Args:

key (bytes): The key for the record. value (bytes): The value to associate with the key in the record.

Returns:

record_pb2.Record: A Record object containing the provided key and value.

libp2p.records.utils module

exception libp2p.records.utils.InvalidRecordType

Bases: Exception

libp2p.records.utils.split_key(key: str) tuple[str, str]

Split a record key into its type and the rest. The key must start with ‘/’ and contain another ‘/’ to separate the type. Raises InvalidRecordType if the key is invalid.

Args:

key (str): The record key to split.

Returns:

tuple[str, str]: The key type and the rest.

libp2p.records.validator module

class libp2p.records.validator.BlankValidator

Bases: Validator

A permissive validator that accepts all records.

This is used as a default/fallback validator when no specific validator is registered for a namespace and strict validation is not enabled.

select(key: str, values: list[bytes]) int

Select the first value (all values are treated equally).

validate(key: str, value: bytes) None

Accept all records without validation.

exception libp2p.records.validator.ErrBetterRecord(key: str, value: bytes)

Bases: Exception

class libp2p.records.validator.NamespacedValidator(validators: dict[str, Validator], strict_validation: bool = False, fallback_validator: Validator | None = None)

Bases: object

Manages a collection of validators, each associated with a specific namespace.

Following the go-libp2p pattern, this validator can operate in two modes:

  • strict_validation=False (default): Non-namespaced keys are accepted without validation using a fallback BlankValidator

  • strict_validation=True: All keys must match a registered namespace validator, otherwise validation fails with InvalidRecordType

This aligns with go-libp2p/rust-libp2p behavior where:

  • Records are always validated through the validator system

  • Networks can enforce strict namespace requirements for security

add_validator(namespace: str, validator: Validator) None

Add or update a validator for a specific namespace.

Args:

namespace (str): The namespace string (e.g., “pk”, “myapp”). validator (Validator): A Validator instance to handle validation for this namespace.

select(key: str, values: list[bytes]) int

Choose the best value from a list using the namespaced validator.

Args:

key (str): The key used to find the validator. values (List[bytes]): List of candidate values to choose from.

Returns:

int: Index of the selected best value in the input list.

Raises:

ValueError: If the values list is empty. InvalidRecordType: If strict_validation is True and no validator found.

property strict_validation: bool

Return whether strict validation mode is enabled.

validate(key: str, value: bytes) None

Validate a key-value pair using the appropriate namespaced validator.

This method follows the go-libp2p pattern where keys with registered namespace validators are validated by that validator. Non-namespaced keys are handled based on strict_validation setting: if True, raises InvalidRecordType (go-libp2p behavior); if False, uses fallback validator (permissive mode).

Args:

key (str): The key (e.g., “/pk/Qm…” or “my-plain-key”). value (bytes): The value to be validated.

Raises:

InvalidRecordType: If strict_validation is True and no validator found.

validator_by_key(key: str) Validator | None

Retrieve the validator responsible for the given key’s namespace.

Args:

key (str): A namespaced key in the form “/namespace/value”.

Returns:
Validator: The matching validator, the fallback validator if

strict_validation is False and key is non-namespaced, or None if strict_validation is True and no validator matches.

class libp2p.records.validator.Validator

Bases: object

Base class for all validators

select(key: str, values: list[bytes]) int
validate(key: str, value: bytes) None

Subpackages

Module contents