精通IPFS:IPFS 啟動之 preStart 函式

買賣虛擬貨幣

上篇說到,在 init 函式初始化系統後,會呼叫 IPFS 物件的 preStart 和 start 方法,進行系統初始化。

這次我們來看第一個方法。

首先來看 preStart 方法,這個方法位於 core/components/pre-start.js 檔案中,它的主要作用是載入倉庫中的內容到記憶體中,它的主體是一個 waterfall,老規矩我們直接來分析它的幾個函式。

  1. 執行第一個函式,呼叫倉庫的配置物件的 get 方法,獲取配置系統配置。具體程式碼如下:

    (cb) => self._repo.config.get(cb)

    我們知道,倉庫的配置物件是在倉庫的建構函式中生成,在初始化方法 init 中設定的。

    現在我們來詳細看下配置物件,這個物件以倉庫物件的 root 為引數建立的,它的所有操作最終都是呼叫這個物件來完成的,也即最終都是儲存儲存在檔案系統的配置檔案中,那麼配置檔案內容是在哪裡被寫入的呢?答案就是倉庫的 init 方法。

    在這個方法中會呼叫配置物件的同名方法來完成儲存所有配置。這裡還有一個問題就是具體的配置是在哪裡定義的,這個問題也比較簡單。

    在前面系統初始化時,即 IPFS 的 init 方法中曾經呼叫 mergeOptions 方法來合併預設配置和使用者透過 config 指定的配置。

    從這個方法可以發現所有預設配置定義在 core/runtime/config-node.js 檔案中,從這個檔案可以發現預設配置如下:

    {
      Addresses: {
        Swarm: [
          '/ip4/0.0.0.0/tcp/4002',
          '/ip4/127.0.0.1/tcp/4003/ws'
        ],
        API: '/ip4/127.0.0.1/tcp/5002',
        Gateway: '/ip4/127.0.0.1/tcp/9090'
      },
      Discovery: {
        MDNS: {
          Enabled: true,
          Interval: 10
        },
        webRTCStar: {
          Enabled: true
        }
      },
      Bootstrap: [
        '/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z',
        '/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
        '/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
        '/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
        '/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
        '/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
        '/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
        '/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
        '/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx',
        '/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z',
        '/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
        '/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
        '/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
        '/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
        '/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
        '/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
        '/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx',
        '/dns4/node0.preload.ipfs.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
        '/dns4/node1.preload.ipfs.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6'
      ],
      Swarm: {
        ConnMgr: {
          LowWater: 200,
          HighWater: 500
        }
      }
    }

    除了系統定義的預設配置和使用者指定的配置之外,在建立節點時把節點的相關資訊,比如節點ID、節點私鑰等也儲存在配置物件的 Identity 屬性上。

    除了上面這些配置之外,在倉庫的初始化方法中又透過 buildConfig 方法把使用者指定的 datastore 和系統預設的資料儲存配置進行了合併。

    統預設的資料儲存配置在 ipfs-repo 專案的 default-datastore.js 檔案中,內容如下:

  2. {
      Spec: {
        type: 'mount',
        mounts: [
          {
            mountpoint: '/blocks',
            type: 'measure',
            prefix: 'flatfs.datastore',
            child: {
              type: 'flatfs',
              path: 'blocks',
              sync: true,
              shardFunc: '/repo/flatfs/shard/v1/next-to-last/2'
            }
          },
          {
            mountpoint: '/',
            type: 'measure',
            prefix: 'leveldb.datastore',
            child: {
              type: 'levelds',
              path: 'datastore',
              compression: 'none'
            }
          }
        ]
      }
    }

    綜上所述,系統的配置來源於前面的幾個地方,這些配置最終在倉庫的 init 方法呼叫配置物件的 set 方法儲存到配置檔案中。那麼在這裡呼叫配置物件的 get 方法正是讀取這些配置。

    4,執行第二個函式,處理系統配置。

    在第一個函式中讀取到系統初始化時設定的所有配置,如果使用者在選項中沒有指定任何配置,那麼直接使用預設的配置;

    否則,呼叫 mergeOptions 方法合併預設的配置和使用者指定的配置,然後呼叫 IPFS 物件的 config 元件的 replace 方法,把合併後的配置儲存到倉庫物件的配置物件中。上述邏輯的程式碼如下:

  (config, cb) => {
    if (!self._options.config) {
      return cb(null, config)
    }
    config = mergeOptions(config, self._options.config)
    self.config.replace(config, (err) => {
      if (err) {
        return cb(err)
      }
      cb(null, config)
    })
  }

  1. 執行第三個函式,檢查配置中是否有 Keychain 。

    如果配置中已有 Keychain,則執行第四個函式,否則,生成它,並儲存在配置物件中。上述邏輯的程式碼如下:

      (config, cb) => {
        if (config.Keychain) {
          return cb(null, config)
        }
        config.Keychain = Keychain.generateOptions()
        self.config.set('Keychain', config.Keychain, (err) => {
          self.log('using default keychain options')
          cb(err, config)
        })
      }

  2. 執行第四個函式,檢查 IPFS 物件是否有 Keychain。具體程式碼比較簡單,程式碼如下:

      (config, cb) => {
        if (self._keychain) {
        } else if (pass) {
          const keychainOptions = Object.assign({ passPhrase: pass }, config.Keychain)
          self._keychain = new Keychain(self._repo.keys, keychainOptions)
        } else {
          self._keychain = new NoKeychain()
        }
        cb(null, config)
      }

  3. 執行第五個函式,根據配置資訊中的節點資訊生成節點ID。同樣比較簡單,程式碼如下:

      (config, cb) => {
        const privKey = config.Identity.PrivKey

    peerId.createFromPrivKey(privKey, (err, id) => {
      cb(err, config, id)
    })

      }

  4. 執行第六個函式,匯入私鑰這個程式碼也比較簡單,具體如下:

      (config, id, cb) => {
        if (!pass) {
          return cb(null, config, id)
        }
        self._keychain.findKeyByName('self', (err) => {
          if (err) {
            return self._keychain.importPeer('self', id, (err) => cb(err, config, id))
          }
          cb(null, config, id)
        })
      }

  5. 執行第七個函式,填充節點的 multiaddr 資訊。程式碼如下,一看就明白,不細講:

      (config, id, cb) => {
        self.log('peer created')
        self._peerInfo = new PeerInfo(id)
        if (config.Addresses && config.Addresses.Swarm) {
          config.Addresses.Swarm.forEach((addr) => {
            let ma = multiaddr(addr)
            if (ma.getPeerId()) {
              ma = ma.encapsulate('/ipfs/' + self._peerInfo.id.toB58String())
            }
            self._peerInfo.multiaddrs.add(ma)
          })
        }
        cb()
      }

  6. 執行最後一個函式,載入已經 pin 的檔案和目錄。程式碼如下,後面講到 pin 時再講。

    (cb) => self.pin._load(cb)

到此,當 preStart 函式就執行完成了,接下來就開始執行 start 函式,這個函式的內容我們留到下次再來分析。

 作者介紹:

喬瘋,區塊鏈狂熱愛好者,熟悉比特幣、EOS、以太坊原始碼及合約的開發,有著數年區塊鏈開發經驗,堅信技術是第一生產力,區塊鏈改變整個人類,開設巴位元專欄以來已經獲得 100多萬次的閱讀量。

參與湖南天河國雲 Ulord 公鏈的開發和麵向區塊鏈行業的風險監控平臺,後者在近期成功入選由工信部評選的 101 個網路安全技術應用試點示範專案

在愛健康金融金融有限公司參與組建彗星資訊科技有限公司,並擔任第一任技術部負責人,開發出了彗星播報等深受大家喜愛的區塊鏈產品。

具有良好的協調溝通能力和團隊協作精神!熟悉Scrum、XP、看板等敏捷專案管理,擁有PMP證書!

熟悉JAVA、Python、NodeJS、C/C++、Linux下的開發,熟悉分散式架構設計!熟悉網際網路金融行業,具有豐富的網際網路金融產品開發經驗,對互聯金融有著深入的瞭解。

關於星鑑網

星鑑網自2018年3月成立至今,採訪了眾多業內大佬,包括萊位元礦池創始人江卓爾、礦海會創始人阿牛,知名佈道者董天一、戴嘉樂,共識實驗室合夥人任錚,YottaChain創始人王東臨、ORA甲骨數鏈創始人石柱、Lambda創始人何曉陽、NBS創始人李萬勝等等將近50位區塊鏈、IPFS、分散式儲存大咖。

同時星鑑網也曝光了行業內超過30多個傳銷盤、資金盤、空氣幣、礦機騙局,守護了業內投資者的利益。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;