Thanks for the feedback!
We have looked into possible ways for this draft ENSIP to be compatible with multicodec. These are our findings in form of different implementations with and without multicodec. We are open to either implementation in the end and update this draft ENSIP as required.
A) Bypass Multicodec:
First, we’d like to point to the current state of ens/content-hash.js
. When using hex("data:") = 0x646174613a
as prefix, encoding doesn’t work and the decoder nearly works but it removes the first byte in the process. Please see example below,
import {encode, decode } from "@ensdomains/content-hash";
console.log(encode("data:text/plain;base64,SGVsbG8gV29ybGQ"))
//> 00000000000000000000
console.log(decode("646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751"))
//> ata:text/plain;base64,SGVsbG8gV29ybGQ
The extra 0x00
prefix identifier as a spacer/pseudo namespace could prevent any future collision with multicodec.
console.log(decode("00646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751"))
//> data:text/plain;base64,SGVsbG8gV29ybGQ
Quoting @raffy here,
This will bypass multicodec for DataURIs in Contenthash. ens/content-hash.js
and any gateways/clients can easily implement this with basic checks, i.e. checking for if prefix is 0x00646174613a
before encoding and decoding so that ENS clients and gateways can use DataURIs directly without leaving any room for current or future collisions with multicodec formats. This approach will be ENS specific and we can change our ENSIP draft to reflect this.
This is our preferred implementation but we are not married to it.
B) Multicodec Compatible Formats
If multicodec must be used, then we’d like to propose the following options:
1) raw
data type with IPFS namespace
:
IPFS namespace
is compatible with DataURIs using raw
data type.
import { CID } from 'multiformats/cid'
import { identity } from 'multiformats/hashes/identity'
import * as raw from "multiformats/codecs/raw";
const utf8 = new TextEncoder();
let data = utf8.encode('data:text/plain;base64,SGVsbG8gV29ybGQ')
let cid = CID.create(1, raw.code, await identity.digest(data))
IPFS Format :
base32: bafkqajtemf2gcotumv4hil3qnrqws3r3mjqxgzjwgqwfgr2wonreoodhkyzds6lci5iq
base16: f01550026646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751
Contenthash: 0xe30101550026646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751
Namespace | Version | Multiaddr | Multihash | Length | Data |
---|---|---|---|---|---|
ipfs |
1 |
raw |
identity |
38 |
data:text/plain;base64,SGVsbG8gV29ybGQ |
0xe301 |
0x01 |
0x55 |
0x00 |
0x26 |
0x646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751 |
CID Inspector : https://cid.ipfs.tech/#bafkqajtemf2gcotumv4hil3qnrqws3r3mjqxgzjwgqwfgr2wonreoodhkyzds6lci5iq
Public Gateway : https://ipfs.io/ipfs/bafkqajtemf2gcotumv4hil3qnrqws3r3mjqxgzjwgqwfgr2wonreoodhkyzds6lci5iq
Since this method uses IPFS namespace, ens/content-hash.js
and any compatible gateway or client must check if the encoded payload is using raw
as multicodec with identity
(blank
) as multihash; the shorthand prefix for this is 0xe301015500
. Clients can decode the remaining raw data as utf-8
string; if this data is not data:uri
formatted, it should be auto-rendered as plaintext
for correctly formatted data:uri
clients, and gateways can render according to mime or type included in the DataURI payload.
2) plaintextv2
data with IPFS or IPLD namespace
:
This is similar to the previous option but using plaintextv2
instead of raw
as multicodec.
import { CID } from 'multiformats/cid'
import { identity } from 'multiformats/hashes/identity'
const utf8 = new TextEncoder();
let data = utf8.encode('data:text/plain;base64,SGVsbG8gV29ybGQ');
let cid = CID.create(1, 0x706c61, await identity.digest(data))
plaintextv2
format using IPFS namespace
Base32 : bahq5rqidaatgiylume5hizlyoqxxa3dbnfxdwytbonstmnbmkndvm43ci44govrshf4wer2r
Base16 : f01e1d8c1030026646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751
Contenthash :
0xe30101e1d8c1030026646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751
Namespace | Version | Multiaddr | Multihash | Length | Data |
---|---|---|---|---|---|
ipfs |
1 |
plaintextv2 |
identity |
38 |
data:text/plain;base64,SGVsbG8gV29ybGQ |
0xe301 |
0x01 |
0xe1d8c103 |
0x00 |
0x26 |
0x646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751 |
CID Inspector : https://cid.ipfs.tech/#bahq5rqidaatgiylume5hizlyoqxxa3dbnfxdwytbonstmnbmkndvm43ci44govrshf4wer2r
Public Gateway : https://ipfs.io/ipfs/bahq5rqidaatgiylume5hizlyoqxxa3dbnfxdwytbonstmnbmkndvm43ci44govrshf4wer2rh
plaintextv2
format using IPLD namespace
Base32 : bahq5rqidaatgiylume5hizlyoqxxa3dbnfxdwytbonstmnbmkndvm43ci44govrshf4wer2r
Base16 : f01e1d8c1030026646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751
Contenthash :
0xe20101e1d8c1030026646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751
Namespace | Version | Multiaddr | Multihash | Length | Data |
---|---|---|---|---|---|
ipld |
1 |
plaintextv2 |
identity |
38 |
data:text/plain;base64,SGVsbG8gV29ybGQ |
0xe201 |
0x01 |
0xe1d8c103 |
0x00 |
0x26 |
0x646174613a746578742f706c61696e3b6261736536342c534756736247386756323979624751 |
CID Inspector : https://cid.ipfs.tech/#bahq5rqidaatgiylume5hizlyoqxxa3dbnfxdwytbonstmnbmkndvm43ci44govrshf4wer2r
Public Gateway : https://dweb.link/api/v0/dag/get?arg=bahq5rqidaatgiylume5hizlyoqxxa3dbnfxdwytbonstmnbmkndvm43ci44govrshf4wer2r
NOTE:
plaintextv2
is still in draft and IPFS gateways CANNOT yet render it properly resulting in 500 error. Trying to use it as IPLD might require changing the encoding process too. We do not prefer this method.
C) CARv1
strings
CARv1
files as strings can represent IPFS data or IPLD files and directory but this implementation is more complex than previous options so we’ll only mention this as a footnote. We don’t have the bandwidth to implement this. If ENS devs are happy to explore this for future implementation, it’ll be one of best options for fully on- or off-chain generators and IPFS data storage.
Based on this, we are happy to get more feedback and then make changes to the draft ENSIP!