【问题标题】:How recreate a hash digest of a multihash in IPFS如何在 IPFS 中重新创建多重哈希的哈希摘要
【发布时间】:2019-01-10 07:51:43
【问题描述】:

假设我像这样向 IPFS 添加数据:

$ echo Hello World | ipfs add

这将给我QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u - 一个 CID,它是 Base58 编码的 Multihash。

将其转换为 Base16,告诉我 IPFS 添加的哈希摘要是 SHA2-256 哈希:

12 - 20 - 74410577111096cd817a3faed78630f2245636beded412d3b212a2e09ba593ca
<hash-type> - <hash-length> - <hash-digest>

我知道 IPFS 不仅对数据进行哈希处理,而且实际上首先将其序列化为 Unixfs protobuf,然后将其放入 dag 中。

我想揭开神秘面纱,如何到达74410577111096cd817a3faed78630f2245636beded412d3b212a2e09ba593ca,但我不确定如何获取保存带有数据的 Unixfs protobuf 的已创建 dag。

例如,我可以将序列化的原始数据写入磁盘并使用 protobuf 解码器对其进行检查:

$ ipfs block get QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u > /tmp/block.raw
$ protoc --decode_raw < /tmp/block.raw

这将为我提供可读格式的序列化数据:

1 {
  1: 2
  2: "Hello World\n"
  3: 12
}

但是,通过 SHA-256 的管道仍然会给我一个不同的哈希值,这是有道理的,因为 IPFS 将 protobuf 放在一个 dag 中并对其进行多重哈希处理。

$ protoc --decode_raw < /tmp/block.raw | shasum -a 256

所以我决定弄清楚如何获取该 dag 节点,自己对其进行哈希处理以获得我正在寻找的哈希值。

我希望使用 ipfs dag get QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u 会给我一个多重哈希,然后可以对其进行解码,但结果它返回了一些我不知道如何检查的其他数据哈希:

$ ipfs dag get QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u
$ {"data":"CAISDEhlbGxvIFdvcmxkChgM","links":[]}

关于如何从这里解码data 的任何想法?

更新

data是原始数据的Base64表示:https://github.com/ipfs/go-ipfs/issues/4115

【问题讨论】:

    标签: ipfs


    【解决方案1】:

    我不确定该编码是什么,但您可以像这样在 js-ipfs 中解组 dag 数据字段:

    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
    })

    【讨论】:

    • 我会看看我是否可以使用 JS API 来从中获得更多收益,但是仅仅解组数据并不是我真正想要的。真的想弄清楚,我如何得到生成 74410577111096cd817a3faed78630f2245636beded412d3b212a2e09ba593ca 哈希的数据结构:)
    【解决方案2】:

    您要查找的哈希是ipfs block get QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u 输出的哈希。 IPFS 对编码值进行哈希处理。

    而不是运行:

    protoc --decode_raw < /tmp/block.raw | shasum -a 256
    

    只要运行:

    shasum -a 256 < /tmp/block.raw
    

    但事实证明它返回了一些我不知道如何检查的其他数据哈希

    这是因为我们目前在 protobuf 中使用了 protobuf。外部 protobuf 的结构为 {Data: DATA, Links: [{Name: ..., Size: ..., Hash: ...}]}

    在:

    1 {
      1: 2
      2: "Hello World\n"
      3: 12
    }
    

    1 { ... } 部分是外部 protobuf 的 Data 字段。但是,protoc --decode_raw *recursively* decodes this object so it decodes theData` 字段:

    • 字段 1(数据类型):2(文件)
    • 字段 2(数据):“Hello World\n”
    • 字段 3(文件大小):12(字节)

    对于上下文,相关的 protobuf 定义是:

    外层:

    // 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;
    }
    

    内部:

    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;
    }
    

    【讨论】:

      【解决方案3】:

      根据 Steven 的回答,使用 protobuf 是有效的。这是我的方法的完整代码。

      ipfs.proto

      syntax = "proto3";
      
      message PBNode {
      bytes Data = 1;
      }
      
      message PBLink {
      bytes Hash = 1;
      string Name = 2;
      uint64 Tsize = 3;
      }
      
      message Data {
      enum DataType {
          Raw = 0;
          Directory = 1;
          File = 2;
          Metadata = 3;
          Symlink = 4;
          HAMTShard = 5;
      }
      DataType Type = 1;
      bytes Data = 2;
      }
      

      cid.js

      const mh = require('multihashes');
      const axios = require('axios');
      const crypto = require('crypto');
      const protobuf = require("protobufjs");
      const IPFS = protobuf.loadSync('./ipfs.proto').lookupType('PBNode');
      
      class CID {
      /**
      * convert IPFS multihash to sha2-256 hash string
      * @param {string} multihash
      * @param {boolean} prefix
      * @returns {string} sha2-256 hash string starting with 0x
      */
      static toHash(multihash, prefix = false) {
          return prefix ? '0x' : ''
          + mh.decode(mh.fromB58String(multihash)).digest.toString('hex')
      }
      
      /**
      * convert sha2-256 hash string to IPFS multihash
      * @param {string} str
      * @returns {string} IPFS multihash starting with Qm
      */
      static fromHash(str) {
          str = str.startsWith('0x') ? str.slice(2) : str;
          return mh.toB58String(mh.encode(Buffer.from(str, 'hex'), 'sha2-256'))
      }
      
      /**
      * hash the buffer and get the SHA256 result compatible with IPFS multihash
      * @param {Buffer} buf
      * @returns {string}
      */
      static hash(buf) {
          const r = IPFS.encode({
          Data: {
              Type: 2,
              Data: buf,
              filesize: buf.length
          }
      
          }).finish();
          return crypto.createHash('sha256').update(r).digest('hex');
      }
      }
      
      async function ipfsGet(cid) {
      const x = await axios.get(`http://your.address.xxx/ipfs/${cid}`, {
          responseType: 'arraybuffer'
      });
      return Buffer.from(x.data);
      }
      
      const r = "QmfQj4DUWEudeFdWKVzPaTbYimdYzsp14DZX1VLV1BbtdN";
      const hashFromCID = CID.toHash(r);
      console.log(hashFromCID);
      ipfsGet(r).then(buf => {
      const hashCalculated = CID.hash(buf);
      console.log(hashCalculated);
      console.log(hashCalculated === hashFromCID);
      console.log(CID.fromHash(hashCalculated) === r)
      });
      
      module.exports = CID;

      【讨论】:

        猜你喜欢
        • 2017-04-21
        • 2011-09-20
        • 2021-06-24
        • 2011-04-20
        • 1970-01-01
        • 2013-12-20
        • 1970-01-01
        • 1970-01-01
        • 2021-02-13
        相关资源
        最近更新 更多