feature: IPNS support (registration, tracking, republishing, gateway) - #1183
feature: IPNS support (registration, tracking, republishing, gateway)#1183odesenfans wants to merge 18 commits into
Conversation
Add IpnsStatus enum, IpnsRecordDb SQLAlchemy model, FilePinType.IPNS member with IpnsFilePinDb subclass, and the ipfs.ipns config subsection.
…or tests - Change insert_ipns_file_pin to target concrete IpnsFilePinDb subclass - Pass FilePinType.IPNS enum member instead of .value for consistency - Remove redundant type discriminator clause from get_ipns_file_pin - Add status ChoiceType round-trip assertion in upsert test - Parameterize _upsert helper with owner to enable multi-owner testing - Add test_multiple_owners_same_ipns_name to verify two owners can register the same name
…ath coverage Replace assert with explicit error handling in _calculate_ipns_costs to clearly communicate quota requirement to callers. Add comment explaining why stream component is unused in STORE messages. Add ProductPriceType.IPNS to default pricing model test. Add test_ipns_costs_credit_payment to cover credit payment path and test_product_pricing_parses_fixed_fee to verify fixed fee parsing from DEFAULT_PRICE_AGGREGATE.
Implement the IPNS registration flow in StoreMessageHandler: fetch the signed record (or resolve it from the DHT for track-only messages), verify via kubo, enforce the max_size_mib quota, pin the resolved CID, store state in ipns_records and maintain exactly one re-pointable IpnsFilePinDb pin per registration. Stale sequence numbers are safe no-ops; superseded-message costs are cleaned up on update; forget tears down the registration and grace-period-pins the old CID. Also adds delete_ipns_file_pin accessor (needed for clean forget) and 11 focused integration tests covering publish, update, stale sequence, track-only, DHT failure, invalid record, expired record, over-quota, forget teardown, forget-superseded no-op, and cost row migration.
Adds IpnsRepublisher that re-injects stored signed records into the DHT every republish_period_hours (default 4h) and re-resolves each name to adopt newer records published out-of-band. Over-quota content keeps the last good CID pinned and flips status to OVER_QUOTA; expired records flip to EXPIRED and stop being republished. Old CIDs are grace-period-pinned before being dropped. Wires ipns_republisher_task into commands.py guarded by config.ipfs.enabled and config.ipfs.ipns.enabled.
The best registration tie-break now sorts by (sequence, owner) for determinism when multiple registrations have the same sequence. Added test coverage for the 404 case when resolved_cid is None.
For IPNS STORE messages (item_type=ipns), the item_hash is the IPNS name, not the content CID. For uploads that include signed IPNS metadata, verify the uploaded CID against the value inside the signed IPNS record (record.value_cid) instead of message_content.item_hash. Add _verify_ipns_record_and_get_cid helper that decodes and verifies the embedded record via IpfsService.verify_ipns_record, and _check_ipns_upload that asserts the uploaded CID matches. Both ipfs_add_file and ipfs_add_car are updated to use these helpers when item_type is ipns; the existing ipfs item_type path is unchanged.
…erage Add check for None ipfs_service in _verify_ipns_record_and_get_cid to prevent NoneType errors when IPFS is disabled. Extend upload endpoint docstrings and error messages to document support for item_type=ipns. Add comprehensive test coverage for invalid IPNS records with grace period verification.
foxpatch-aleph
left a comment
There was a problem hiding this comment.
Well-structured PR adding comprehensive IPNS support. The code is clean, the architecture separating fetch/process/forget is consistent with existing patterns, the sequence-based self-ordering handles race conditions correctly, cost migration on updates is sound, and test coverage is thorough (44 new tests). No security issues. The only minor concern is that nothing explicitly prevents IPNS messages from having a non-None ref field, but such messages would just pass through the existing dependency check harmlessly.
src/aleph/handlers/content/store.py (line 323): Consider checking for content.ref in _fetch_ipns and raising InvalidMessageFormat if set, since the design doc and implementation assume ref is forbidden for IPNS content. Currently a rogue IPNS message with a ref would silently ignore it.
Summary
Adds first-class, paid IPNS name support to Aleph Cloud. A STORE message with the new
item_type: ipnsregisters an IPNS name (item_hashis the base36k51...name):ipns_record, base64, 10 KiB cap). The node verifies it against the name via kubo, pins the record's value CID within the paid quota (max_size_mib), stores the registration in the newipns_recordstable and injects the record into the DHT. No node ever holds a private key.refis forbidden for IPNS content). The registration keeps exactly one re-pointable pin; replaced CIDs get the existing grace-period treatment and superseded messages stop billing.ipns_recordand the node fetches the current record from the DHT, then proceeds identically (keep-alive for names managed elsewhere).ipfs.ipns.*config) re-injects records (kubo DHT records expire within ~24-48h) and re-resolves names to adopt newer records, with per-record failure isolation. Over-quota content keeps the last good CID pinned (status=over_quota); expired records stop republishing but stay pinned (status=expired).GET /api/v0/ipns/{name}(registration state, used by clients to bootstrap sequence numbers),GET /api/v0/ipns/{name}/raw(302 to/api/v0/storage/raw/{cid}),GET /api/v0/addresses/{address}/ipns. Registered names only: CCNs are not open IPNS resolvers.add_file/add_caraccept IPNS STORE metadata; the uploaded (root) CID must match the signed record's value instead ofitem_hash.CostType.IPNS, covers republish work) plus storage billed on the declared quota, so billing never changes without a message. Defaults live inDEFAULT_PRICE_AGGREGATEunder the newipnsproduct and are tunable via the network pricing aggregate.Dependencies and rollout
ipns-support(newItemType.ipnsshape rule +StoreContentfields), consumed as a git dependency inpyproject.toml. To be swapped for a released version once stabilized.ItemHashvalidation), a clean failure. The network needs to upgrade before IPNS traffic flows, standard for additive message-type changes.0060_c7d2e9f4a1b8createsipns_records;file_pinsgains only a new polymorphic type value.Test plan