How recreate a hash digest of a multihash in IPFS
The hash you're looking for is the hash of the output of ipfs block get QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u
. IPFS hashes the encoded value.
Instead of running:
protoc --decode_raw < /tmp/block.raw | shasum -a 256
Just run:
shasum -a 256 < /tmp/block.raw
but it turns out it returns some other data hash that I don't know how to inspect
That's because we currently use a protobuf inside of a protobuf. The outer protobuf has the structure {Data: DATA, Links: [{Name: ..., Size: ..., Hash: ...}]}
.
In:
1 {
1: 2
2: "Hello World\n"
3: 12
}
The 1 { ... }
part is the Data field of the outer protobuf. However, protoc --decode_raw *recursively* decodes this object so it decodes the
Data` field to:
- Field 1 (DataType): 2 (File)
- Field 2 (Data): "Hello World\n"
- Field 3 (Filesize): 12 (bytes)
For context, the relevant protobuf definitions are:
Outer:
// An IPFS MerkleDAG Link
message PBLink {
// multihash of the target object
optional bytes Hash = 1;
// utf string name. should be unique per object
optional string Name = 2;
// cumulative size of target object
optional uint64 Tsize = 3;
}
// An IPFS MerkleDAG Node
message PBNode {
// refs to other objects
repeated PBLink Links = 2;
// opaque user data
optional bytes Data = 1;
}
Inner:
message Data {
enum DataType {
Raw = 0;
Directory = 1;
File = 2;
Metadata = 3;
Symlink = 4;
HAMTShard = 5;
}
required DataType Type = 1;
optional bytes Data = 2;
optional uint64 filesize = 3;
repeated uint64 blocksizes = 4;
optional uint64 hashType = 5;
optional uint64 fanout = 6;
}
message Metadata {
optional string MimeType = 1;
}
I'm not sure what that encoding is but you can unmarshal the dag data field like this in js-ipfs:
const IPFS = require('ipfs')
const Unixfs = require('ipfs-unixfs')
const ipfs = new IPFS
ipfs.dag.get('QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u', (err, d) => {
console.log(Unixfs.unmarshal(d.value.data).data.toString()))
// prints Hello World
})