wealdtech/go-ens

Can't decode Contenthash

Closed this issue · 7 comments

Go version 1.16.5 linux/amd64
Version v3.4.6

I ran into an issue earlier where an ipns-ns encoded content hash isn't properly displayed:

package main

import (
	"fmt"

	"github.com/ethereum/go-ethereum/ethclient"
	ens "github.com/wealdtech/go-ens"
)

func main() {
	client, err := ethclient.Dial("http://127.0.0.1:8545")
	if err != nil {
		panic(err)
	}

	// Resolve a name to an address
	domain := "esteroids.eth"
	address, err := ens.Resolve(client, domain)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Address of %s is %s\n", domain, address.Hex())

	resolver, err := ens.NewResolver(client, domain)
	if err != nil {
		panic(err)
	}

	// Get content hash
	content, err := resolver.Contenthash()
	if err != nil {
		panic(err)
	}

	readable, err := ens.ContenthashToString(content)
	if err != nil {
		panic(err)
	}
	fmt.Printf(readable)
}

Which results in the following:

Address of esteroids.eth is 0x7448467f85FfA36Ca763C9E301e270F8ece0C2B8
/ipns �
       �b�%!�(MISSING)�G̍KC�T��R�M����}
ݸ

I've noticed similar behavior with the ENS plugin for coredns (possibly unrelated):

ipfs resolve -r /ipns/esteroids.eth/
Error: could not resolve name: "\\008\\001\\018 \\149\\011\\143b\\185%\\236\\197\\002G\\204\\141\\225\\008KC\\248T\\251\\196R\\137M\\154\\026\\151\\215\\242}\\010\\221\\184" is missing a DNSLink record (https://docs.ipfs.io/concepts/dnslink/)

Am I using this package incorrectly? Thanks for the great project, I've enjoyed working with your tools.

mcdee commented

Chances are it is a different encoding to that which the library supports so far. Any idea which encoding was used for the contenthash?

I think it's ipns-ns. When I use web3.js The contenthash is successfully decoded:

const { resolve } = require('path');
const contentHash = require('content-hash')
var Web3 = require('web3');

var add = 'ws://127.0.0.1:8546'
var web3 = new Web3(new Web3.providers.WebsocketProvider(add));

web3.eth.ens.getAddress('esteroids.eth').then(function (address) {
    console.log(address)
});

web3.eth.ens.getContenthash('esteroids.eth').then(function (result) {
    content_hash = result['decoded']
    content = decodeContenthash(content_hash);
    console.log(content)
});

function decodeContenthash(contenthash) {
    const codec = contentHash.getCodec(contenthash)
    if (codec === 'ipns-ns') {
        try {
            const content = contentHash.decode(contenthash)
            return(`/ipns/${content}`);
        }

        catch (err) {
            console.error(err);
        }
    }
}

Result:

/ipns/12D3KooWKrB93pwXDdeyz2WRMwcSBny5ECjA1JasB4GTo4ijUUtf
0x7448467f85FfA36Ca763C9E301e270F8ece0C2B8

It might be CID v1?

mcdee commented

There have been a few changes made to content hashes (multiformats is somewhat of a moving target).

I have created a branch contenthash-update that should handle the newer style. It has to be a little opinionated in how it generates the text strings due to lack of encoding information in the contenthash, so defaults to the more modern output and base36. Please could you try it and see it now behaves?

(Note you will need to change your import to be go-ens/v3,)

@mcdee thank you for the fix, I can confirm that this works:

Address of esteroids.eth is 0x7448467f85FfA36Ca763C9E301e270F8ece0C2B8
ipns://k51qzi5uqu5djwbl0zcd4g9onue26a8nq97c0m9wp6kir1gibuyjxpkqpoxwag

On an unrelated note, do you know why there seem to be 2 different CIDs for that ipns namespace? Completely different results between the 2 decode methods; they both point to the same location.

mcdee commented

The first character defines the encoding used. In this case 'k' means 'base 36'. There are other encodings available, such as base 58, however base 36 is the currently default so the library will use that.

I will merge the fix and tag a new release. Thank you for testing.

mcdee commented

Release tagged as v3.5.0