IPFS資料之旅(二):名正才能傳順

買賣虛擬貨幣


我們書接上回。

情景一中,小A想給小B傳一個檔案,大致過程如下:

  • 本地新增檔案;

  • 把檔案的hash給小B;

  • 小B根據檔案hash在IPFS網路中得到這個檔案。

這裡有意不提上傳和下載,點對點的系統並不是上傳檔案到伺服器,再由別人下載。在IPFS中我們只能把檔案上傳到自己的IPFS節點或public gateway(公共閘道器),別人透過雜湊值從IPFS網路中下載。

回憶一下前面提到的IPFS Stack,這次主要涉及到IPLD物件是如何管理,在每個節點是如何儲存的。

新增檔案


我們向自己的IPFS新增檔案的過程如下:


1. 檔案拆分並寫入IPFS基礎資料結構dag(有向無環圖),dag不僅用在IPFS中也用在Filecoin中,參考下文:深度解讀IPFS/Filecoin 2018 update

2. 把dag資料根據系統配置寫入IPFS底層blocks儲存;

3. Flush mfs(Mutable Filesystem)的root目錄,MFS是一個建立在IPFS上面的虛擬檔案系統,提供類似unix檔案系統的API;

4. 遞迴Pin上面flush過的root目錄及其所有檔案,並把狀態寫入底層blockstore儲存。

flush() 方法是用來重新整理緩衝區的,即將緩衝區中的資料立刻寫入檔案,同時清空緩衝區,不需要是被動的等待輸出緩衝區寫入。 一般情況下,檔案關閉後會自動重新整理緩衝區,但有時你需要在關閉前重新整理它,這時就可以使用 flush() 方法。

做儲存的小夥伴肯定這裡會問了,我存1M的資料,肯定要比1M多啊,浪費的空間怎麼辦?IPFS社羣有實驗特性Filestore,可以避免浪費多餘的硬碟空間。

檔案拆分並生成dag

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ export IPFS_PATH=~/.ipfs-private

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ export LIBP2P_FORCE_PNET=1

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ ipfs add --cid-version 1 --wrap-with-directory test_data

added zdj7WkayJ4Y7QmFsHg6pQQ528J7bqSZpGfUk8WfivrNFJyUr6 test_data

added zdj7WXi97o1NcWTq9bVw9BhJLMxEVKjUVbXP1U3V2TBHswPvr

 512.00 KiB / 512.00 KiB [======================================================================================================================] 100.00%

graphmd可以把dag用圖形化方式顯示,例如

https://ipfs.io/docs/examples/example-viewer/example#../graphmd/README.md

檔案拆分策略


檔案拆分方式可以透過--chunker指定。有固定大小和rabin兩種方式。如果不指定,預設是256k一個chunk。

dag (有向無環圖)的型別

ipfs的object來自git。ipfs支援兩種dag,一種是balanced dag,適合隨機訪問;另一個種是trickledag,適合順序訪問。預設情況下ipfs使用balanced dag。ipfs新增檔案時可以用--trickle或-t表示生成trickledag。下面是balanced dag插入資料的過程。


trickledag是這樣的:

新增新的子樹:

需要注意的是使用不同dag或不同的拆分方式都會生成不同的雜湊值,也就是對ipfs來說,是不同的檔案。

CID版本


CID包括multibase,multicodec和multihash。

預設是cidv0,社羣正在做cidv1的工作。有個小工具可以將cid解析成人類可讀的資料。

dag寫入底層儲存:

ipfs預設使用兩種儲存,在~/.ipfs/blocks使用flat fs,在~/.ipfs/datastore使用leveldb。後者在後面提到pin的時候仍然會提到,這裡先跳過。在上面的預設配置中,ipfs會使用base32雜湊值的倒數第二和倒數第三位索引。

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ hexdump  ~/.ipfs-private/blocks/RX/AFKREIHCUSVW2OVNVS7VX35P33XIYNO6AF4TXB7R7CNAF5YZSGULUB3RXQ.data | head

0000000 38b9 a7c4 061f b138 6dca b81a 5aeb a304

0000010 99e6 2ce7 600b d190 f5da 0695 7436 efd3

0000020 97bd 357a 9fa6 e8ab 422d a7d6 051c 4ba1

0000030 6be3 ad89 f3d4 f6d4 72a4 0b94 5a1e 8f61

0000040 2953 1ad3 a5f4 3f30 477a a907 bd65 b6fa

0000050 9658 4883 54fd 318b 6e51 85c3 1772 65d5

0000060 7c6a 3202 2e4b bc48 54b6 1aca 927e 6d7c

0000070 c34d 522e faa1 3883 9bda f5bf d6e7 e1d1

0000080 5d90 4548 7cf2 5c4d e501 9a8e a747 0bdd

0000090 fa7d a186 1565 5839 93b7 0ad3 2c18 bd48

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ hexdump test_data | head

0000000 38b9 a7c4 061f b138 6dca b81a 5aeb a304

0000010 99e6 2ce7 600b d190 f5da 0695 7436 efd3

0000020 97bd 357a 9fa6 e8ab 422d a7d6 051c 4ba1

0000030 6be3 ad89 f3d4 f6d4 72a4 0b94 5a1e 8f61

0000040 2953 1ad3 a5f4 3f30 477a a907 bd65 b6fa

0000050 9658 4883 54fd 318b 6e51 85c3 1772 65d5

0000060 7c6a 3202 2e4b bc48 54b6 1aca 927e 6d7c

0000070 c34d 522e faa1 3883 9bda f5bf d6e7 e1d1

0000080 5d90 4548 7cf2 5c4d e501 9a8e a747 0bdd

0000090 fa7d a186 1565 5839 93b7 0ad3 2c18 bd48

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ cat  ~/.ipfs-private/blocks/KE/AFKREIBOBL5SRHO6FXSR2KPV7TCNEQFPIL2CHLI7226YE2446Q5A7KEKEY.data

welcom to ipfsbit.com

前面我們透過IPFS add新增了”test_data“檔案

上文是拿“welcom to ipfsbit.com“這一句話舉個栗子,透過flat fs方式儲存這句話返回的雜湊值是”bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ cat  ~/.ipfs-private/blocks/KE/AFKREIBOBL5SRHO6FXSR2KPV7TCNEQFPIL2CHLI7226YE2446Q5A7KEKEY.data“而圖中的KE就是倒數第二和倒數第三位的索引。


Append(追加資料)


IPFS做為內容定址的檔案系統。Append資料之後,只有被修改的chunk會被生成新的hash,原有chunk仍然可以用原有hash訪問。例如我們在上面的測試資料test_data後面追加"welcom to ipfsbit.com"字串。由於原本的test_data是512k,ipfs預設是256k一個chunk,正好是兩個chunk。新增的資料會在一個新建的chunk裡面。我們可以用ipfs object get看到前面兩個chunk資料沒有變化。只是最後一個chunk包含我們新增的字串。

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ echo "welcom to ipfsbit.com" >> test_data

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ ipfs add --cid-version 1 --wrap-with-directory test_data

added zdj7We9xdpUKDjQxCXYJ2DMg2YJD87NmuybjoTDxptbitB2cd test_data

added zdj7WfuHAfPSdyS2XL7avfzYudTaYT83ckG1ku1gdv8H96sg7

 512.02 KiB / 512.02 KiB [======================================================================================================================] 100.00%

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ ipfs object get zdj7WkayJ4Y7QmFsHg6pQQ528J7bqSZpGfUk8WfivrNFJyUr6

{"Links":[{"Name":"","Hash":"zb2rhmtzy5H4y7UQxZ3pzf3FE6BAE5PAeLT3yjTrKX5RCcBvj","Size":262144},{"Name":"","Hash":"zb2rhaMcpAWL6rvYay5HX7wsuj6gKnZTPk2ToF5xnf7vtnf6G","Size":262144}],"Data":"\u0008\u0002\u0018\ufffd\ufffd  \ufffd\ufffd\u0010 \ufffd\ufffd\u0010"}

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ ipfs object get zdj7We9xdpUKDjQxCXYJ2DMg2YJD87NmuybjoTDxptbitB2cd

{"Links":[{"Name":"","Hash":"zb2rhmtzy5H4y7UQxZ3pzf3FE6BAE5PAeLT3yjTrKX5RCcBvj","Size":262144},{"Name":"","Hash":"zb2rhaMcpAWL6rvYay5HX7wsuj6gKnZTPk2ToF5xnf7vtnf6G","Size":262144},{"Name":"","Hash":"zb2rhZk1fBPjs9ho7beGQ2itVcETXJ7RYkJmsWpeyXGhvLu8y","Size":22}],"Data":"\u0008\u0002\u0018\ufffd\ufffd  \ufffd\ufffd\u0010 \ufffd\ufffd\u0010 \u0016"}

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ ipfs get zb2rhZk1fBPjs9ho7beGQ2itVcETXJ7RYkJmsWpeyXGhvLu8y

Saving file(s) to zb2rhZk1fBPjs9ho7beGQ2itVcETXJ7RYkJmsWpeyXGhvLu8y

 22 B / 22 B [===============================================================================================================================] 100.00% 0s

bamvor@ipfs-ci-and-test:~/works/ipfs_demo$ cat zb2rhZk1fBPjs9ho7beGQ2itVcETXJ7RYkJmsWpeyXGhvLu8y

welcom to ipfsbit.com

備註

這裡面沒有提到cache,預設是ARCCache。如果配置了BloomFilter,也會開啟BloomFilter。

上面流程只考慮了單獨新增一個檔案的情況,沒有考慮符號連結,目錄的情況。

免責聲明:

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

推荐阅读

;