Skip to content

feat(ipns): add CID support for publish, republishRecord, and resolve#852

Closed
Harshdev098 wants to merge 1 commit intoipfs:mainfrom
Harshdev098:patch-1
Closed

feat(ipns): add CID support for publish, republishRecord, and resolve#852
Harshdev098 wants to merge 1 commit intoipfs:mainfrom
Harshdev098:patch-1

Conversation

@Harshdev098
Copy link
Copy Markdown

Fixes: #801

Added CID encoded IPNS key in publish, republishRecord and resolve methods

@Harshdev098 Harshdev098 requested a review from a team as a code owner September 21, 2025 08:55
Copy link
Copy Markdown
Contributor

@tabcat tabcat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not mean to include publish in the request for changes.

The original issue had to do with usage of the delegated routing client's IPNS methods.
The routing key inputs for those methods are not compatible with these methods in @helia/ipns which caused some issues for me.
I'd be interested in knowing why they take so many different types. It may be good to look at the commit history.
I know the delegated router needs the libp2p key as a CID because that is how it is encoded in the url. But these methods only need the multihash.

Comment thread packages/ipns/src/index.ts Outdated
Comment on lines 524 to 558
// Handle value conversion to string path, with CID support for IPNS names
let valuePath: string
if (CID.asCID(value)) {
const cid = value as CID
if (cid.code === LIBP2P_KEY_CODEC) {
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(cid.multihash.code)) {
throw new Error('Unsupported multihash code for IPNS value')
}
valuePath = `/ipns/${cid.toString(base36)}`
} else {
valuePath = `/ipfs/${cid.toString()}`
}
} else if (typeof value === 'string') {
valuePath = value
} else if (isPublicKey(value)) {
const publicKey = value as PublicKey
const mh = publicKey.toMultihash()
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(mh.code)) {
throw new Error('Unsupported multihash code for IPNS value')
}
const cid = CID.create(1, LIBP2P_KEY_CODEC, mh)
valuePath = `/ipns/${cid.toString(base36)}`
} else {
// Must be MultihashDigest<0x00 | 0x12>
const mh = value as MultihashDigest<0x00 | 0x12>
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(mh.code)) {
throw new Error('Unsupported multihash code for IPNS value')
}
const cid = CID.create(1, LIBP2P_KEY_CODEC, mh)
valuePath = `/ipns/${cid.toString(base36)}`
}

// convert ttl from milliseconds to nanoseconds as createIPNSRecord expects
const ttlNs = options.ttl != null ? BigInt(options.ttl) * 1_000_000n : DEFAULT_TTL_NS
const record = await createIPNSRecord(key, value, sequenceNumber, options.lifetime ?? DEFAULT_LIFETIME_MS, { ...options, ttlNs })
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valuePath is never being used and createIPNSRecord already accepts a CID type.

Publish already supported a CID as a value. I don't remember why a change was requested for this now. This hunk can be removed.

Comment thread packages/ipns/src/index.ts Outdated

async resolve (key: PublicKey | MultihashDigest<0x00 | 0x12>, options: ResolveOptions = {}): Promise<IPNSResolveResult> {
const digest = isPublicKey(key) ? key.toMultihash() : key
async resolve (key: CID | PublicKey | MultihashDigest<0x00 | 0x12>, options: ResolveOptions = {}): Promise<IPNSResolveResult> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Narrow the CID type by specifying the generic types for the code and multihash code. Should match the type from https://github.com/ipfs/helia-delegated-routing-v1-http-api/blob/00aceb97918530d7c17b8256bfb1104d34f19080/packages/client/src/client.ts#L246

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please read this again

Comment on lines +578 to +601
if (CID.asCID(key)) {
const cid = key as CID
if (cid.code !== LIBP2P_KEY_CODEC) {
throw new Error('CID must use libp2p-key codec (0x72) for IPNS names')
}
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(cid.multihash.code)) {
throw new Error('Unsupported multihash code for IPNS key')
}
digest = cid.multihash as MultihashDigest<0x00 | 0x12>
} else if (isPublicKey(key)) {
const publicKey = key as PublicKey
const mh = publicKey.toMultihash() as MultihashDigest<0x00 | 0x12>
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(mh.code)) {
throw new Error('Unsupported multihash code for IPNS key')
}
digest = mh
} else {
const mh = key as MultihashDigest<0x00 | 0x12>
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(mh.code)) {
throw new Error('Unsupported multihash code for IPNS key')
}
digest = mh
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would leave this out and simply normalize the key parameter into a digest like before.
Check if key is CID then return key.multihash and it fits the type of MultihashDigest<0x00 | 0x12>

Comment thread packages/ipns/src/index.ts Outdated
Comment on lines +754 to +856
async republishRecord (key: MultihashDigest<0x00 | 0x12> | string, record: IPNSRecord, options: RepublishRecordOptions = {}): Promise<void> {
async republishRecord (key: CID | MultihashDigest<0x00 | 0x12> | string, record: IPNSRecord, options: RepublishRecordOptions = {}): Promise<void> {
let mh: MultihashDigest<0x00 | 0x12> | undefined
try {
mh = extractPublicKeyFromIPNSRecord(record)?.toMultihash() // embedded public key take precedence, if present
if (mh == null) {
// if no public key is embedded in the record, use the key that was passed in
if (typeof key === 'string') {
if (CID.asCID(key)) {
const cid = key as CID
if (cid.code !== LIBP2P_KEY_CODEC) {
throw new Error('CID must use libp2p-key codec (0x72) for IPNS names')
}
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(cid.multihash.code)) {
throw new Error('Unsupported multihash code for IPNS key')
}
mh = cid.multihash as MultihashDigest<0x00 | 0x12>
} else if (typeof key === 'string') {
let parsedKey = key
if (key.startsWith(IPNS_STRING_PREFIX)) {
// remove the /ipns/ prefix from the key
key = key.slice(IPNS_STRING_PREFIX.length)
parsedKey = key.slice(IPNS_STRING_PREFIX.length)
}
// Convert string key to MultihashDigest
// Preferentially try to parse as CID
try {
mh = peerIdFromString(key).toMultihash()
} catch (err: any) {
throw new Error(`Invalid string key: ${err.message}`)
const cid = CID.parse(parsedKey)
if (cid.code === LIBP2P_KEY_CODEC) {
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(cid.multihash.code)) {
throw new Error('Unsupported multihash code for IPNS key')
}
mh = cid.multihash as MultihashDigest<0x00 | 0x12>
} else {
throw new Error('Invalid CID codec for IPNS name')
}
} catch (err) {
try {
mh = peerIdFromString(parsedKey).toMultihash() as MultihashDigest<0x00 | 0x12>
} catch (e: any) {
throw new Error(`Invalid string key: ${e.message}`)
}
}
} else {
mh = key
const digest = key as MultihashDigest<0x00 | 0x12>
if (![IDENTITY_CODEC, SHA2_256_CODEC].includes(digest.code)) {
throw new Error('Unsupported multihash code for IPNS key')
}
mh = digest
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only change needed was to normalize key to multihash if it was a CID.

@Harshdev098 Harshdev098 requested a review from tabcat October 4, 2025 15:39
@achingbrain
Copy link
Copy Markdown
Member

Closing in favour of #861

@Harshdev098 thanks for taking the time to open this. In future please read the issues carefully and add tests to your PRs - it's not possible to accept untested code as there is nothing to prevent a future regression.

@achingbrain achingbrain closed this Oct 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@helia/ipns methods to accept CID encoded IPNS key

3 participants