【转载请标明出处】https://blog.csdn.net/qq_25870633/article/details/82027510
<https://blog.csdn.net/qq_25870633/article/details/82027510>

文章参考自: https://www.zybuluo.com/zhenxi/note/912913
<https://www.zybuluo.com/zhenxi/note/912913>

现在大家都知道很多区块链底层都只是支持存储小量数据【太昂贵了,在黄皮书中有一个gas的消耗规定可以参考。一般账户存储 (storage)
将0值转为非0需要消耗2W的gas,修改非0值需要消耗5K的gas,但将非0改为0可以得到1.5W的gas;而memory 空间每32 byte 消耗 3gas
】,那么我们想把大文件,譬如:图片,视频等等上传到链上怎么办呢?【在以太坊中可以参考把数据存到日志里,日志每个字节花费8个Gas,而合约存储是
每32个字节20,000个Gas】目前市面上比较火的底层 IPFS <星际文件系统> 应该可以满足我们的需求。所以,今天我们的主题是 IPFS 。

首先,我们在说IPFS原理之前,我们先来玩一把IPFS。

安装IPFS:

我的演示环境是

Ubuntu 16.04.4 LTS

git   2.7.4

go   go1.10.3 linux/amd64

node  v10.6.0

npm  6.1.0

docker  1.13.1

docker-compose  1.8.0

首先打开IPFS官网,官网会自动根据当前的浏览器所在的平台显示对应的下载版本。我们下载下来之后,比如说我的是在目录:



我这边是习惯把需要安装的东西都放到 /usr/local 目录下,并且习惯的把需要安装的东西划分目录【我在win上也是一样习惯】,所以是:



开始解压:



解压完之后我们会在当前目录下看到一个 go-ipfs 的目录:



在这里我们需要把 ipfs 移动到  /usr/local/bin 目录下:

【注意】别放错了,不要放在 /usr/bin 下哦。

/usr/bin 下面的都是系统预装的可执行程序,会随着系统升级而改变
/usr/local/bin 目录是给用户放置自己的可执行程序的地方,推荐放在这里,不会被系统升级而覆盖同名文件。



然后我们就可以随便打开一个窗口:



OK,到这位置IPFS已经安装成功,非常方便,解压即要。

通过查看子命令我们可以知道,在终端输入:ipfs init 即可在本机初始化一个 IPFS的节点。

比如,我就在我的 /home/gavin 目录下执行:

初始化IPFS节点:ipfs init

 



QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv

这时候,算是初始化节点成功了,我们会在当前目录看到一个 .ipfs 的掩藏目录:



进入该目录,我们可以看到:



原因是:执行完ipfs init命令后,会在根目录生成一个.ipfs的文件夹存储节点数据。.ipfs节点默认存储空间为10个G。

如果你自己想修改节点默认存储空间,可打开终端执行下面的命令:

更改节点中的配置项:export EDITOR=/usr/bin/vim && ipfs config edit



打开的文件并将里面红框部分改成自己想要的大小:



 

好了我们再回来看看之前 执行完 ipfs init 之后提示我们查看的那个文件(还记得吗?往上翻),

查看本地IPFS的文件:ipfs cat /ipfs/一串文件Hash



里头就有教我们如何快速启用  IPFS 耶!我们按照上述提示进行:



我们可以看到里面都是一些示例的说明,通过这个我们基本上可以了解到很多关于IPFS 的操作了【里面不是有写么?】

查看 当前本地节点的ID:ipfs id



启动一个IPFS 节点服务:ipfs daemon

【注意】如果不启动的话,所有的操作都只是在本地操作而已,包括添加文件,添加文件夹等,都只会在本地而已,并没有会被广播到全网。

根据上面的qick-start中的演示,我们可以使用在另外一个窗口:前台启动一个守护进程,启动IPFS的节点服务 <和全网交互了>



这时候我们根据qick-start的提示,输入:http://localhost:5001/webui
<http://localhost:5001/webui> 就可以看到



 

查看和自己相连的其他节点:ipfs swarm peers

【注意】:这一步必须是 在 ipfs daemon 即 本地服务开启情况下才可以看的,因为这时候才和网络其他节点相连



获取 IPFS 对象的底层结构:ipfs object get 一串文件Hash



将本地文件发布到IPFS网络之中:ipfs name publish 一串文件Hash



从任意节点下载文件:ipfs get 一串文件Hash



最常用的命令为:
init 初始化ipfs本地配置 add <path> 将指定文件添加到IPFS cat <ref> 显示指定的IPFS对象数据 get <ref>
下载指定的IPFS对象 ls <ref> 列表显示指定对象的链接 refs <ref> 列表显示指定对象的链接哈希
好了以上就是对ipfs的一些操作,具体详细的操作参考: http://cw.hubwiz.com/card/c/ipfs/1/12/2/
<http://cw.hubwiz.com/card/c/ipfs/1/12/2/>

下面我们通过一些概念的知识来慢慢深入IPFS的底层机制:

Repo:

首先,需要知道ipfs节点本地是有类似于 repo 的概念存在的。我们可以通过命令查看 本地仓库的统计信息:

ipfs repo stat 



可以看出来,里面有一行为: RepoPath: /home/gavin/.ipfs 可以知道, .ipfs 目录即为 ipfs的本地仓库目录,该目录为 执行
ipfs init 命令即生成的,后续的文件、block等等什么的都会存储在这里面:



在IPFS 中,我们想 ipfs 请求某个文件的时候,是先从 这个 repo 中查找,在 repo
目录中的数据分为两部分:metadata(元数据)、block(真实的数据)。

现在我们先向本地添加一个 文件,然后在查看repo的统计结果:



我们可以看到 NumObjects 和 RepoSize 项的值变大了,是因为我们想本地 repo 添加了 gavin这个文件啊

Bootstrap:

然后我们下面再来理解一个概念: Bootstrap <引导项>

什么是Bootstrap呢?在 ipfs 的config文件中我们会看到:



这些就是在我们ipfs init 之后,生成的 config文件中默认配置好的 一些由 ipfs 官方维护运行的 ipfs
节点,就是为了方便我们寻址和下载文件用的,建议不要删除。当然我们也可以通过命令:ipfs bootstrap list 查看:

 



所以,bootstrap的用法就是,根据 ipfs 默认的 节点列表来提供给我们在请求某个文件时,本地仓库因为没有,而能够先从这些节点中拉取文件的
。【下载下来的文件会保存到自己本地的repo中哦】

Pinning:

ipfs有一个相当积极的缓存机制,可以在对其执行任何ipfs操作后很短时间内将对象保留在本地,但这些对象可能会被定期垃圾清理。
为了防止垃圾收集简单地固定你关心的哈希,固定的方法就是Pinning 
Pinning 是ipfs中非常重要的概念。因为 ipfs试图让它感觉每个单独的对象都是本地的, 固定是允许你告诉ipfs始终保持给定对象本地的机制。

查看本地固定住的内容:ipfs pin ls



ipfs 会默认的把本地上传的文件做固定:【远端下载过来的不会固定,而是短时间的保存在本地 repo 中】使用: ipfs repo gc 即可清空
repo 中的缓存文件

想要删除某个本地上传的文件,需要先接触 固定然后在 gc 操作:ipfs pin rm -r 文件Hash



然后,再: ipfs repo gc 即可:



【注意】:我们可以试验下,先在本地添加一个文件,然后发布,最后再把本地文件删了,然后在执行 ipfs cat 来查看之前的文件,看看能不能从网络中查找到:

我自己试了下貌似不行,而且用 ipfs get  文件hash 也是获取不到之前发布到网络中的同Hash文件,谁试了可以的话和我说声啊。。但是发现了
不管对同一个文件Hash发布N次的结果都是一样的:



好了言归正传,我们接着说底层,参考自:https://www.jianshu.com/p/e4703ad30f65
<https://www.jianshu.com/p/e4703ad30f65>

IPFS获取文件的工作流程

【第一步】:先查询Pinning 如果没有,则进入第二步 
【第二步】:查询本地的repo ,如果没有,则进入第三步 
【第三步】:根据bootstrap list 查寻其它节点 ,如果没有,就真的没有

IPFS的对象:

以下参考自:https://blog.csdn.net/yichigo/article/details/79655922
<https://blog.csdn.net/yichigo/article/details/79655922>

IPFS本质上是一个用于检索和共享IPFS对象的P2P系统。一个IPFS对象是一个具有两个字段的数据结构:

* Data :大小小于256 kB的非结构化数据块(blob)
* Links  : 一个Link结构体的数组。其中包含的Link指向其他IPFS对象。
而Link结构有三个数据字段:

* Name :Link的名字
* Hash :Link指向的IPFS对象的hash
* Size 
:Link指向对象的累计大小,计算Link指向的对象大小,需要计入这个被指对象所指向所有对象的大小(注:除了被指向对象自身的size,如果它里面有link,那么还要把link中的size加进来)
可以通过: ipfs  object get  文件hash 来查看:



json格式如下:
{ "Links":[ { "Name":"AnotherName",
"Hash":"QmVtYjNij3KeyGmcgg7yVXWskLaBtov3UYL9pgcGK3MCWu", "Size":18 }, {
"Name":"SomeName", "Hash":"QmbUSy8HCn8J4TMDRRdxCbK2uCCtkQyZtY6XYv3y7kLgDC",
"Size":58 } ], "Data":"Hello World!" }
读者可能会注意到,所有的散列都是以“Qm”开头的。这是因为它实际上是一个multihash,前两个字节用于指定哈希函数和哈希长度。在上面的例子中,
前两个字节的十六进制是1220,其中12表示这是SHA256哈希函数,20代表哈希函数选择32字节长度计算。

在ipfs中,数据和命名链接 【就是Link里面有 Name的那种】构成的IPFS对象的集合即是 Merkle DAG 结构
。顾名思义,DAG表明了这一种有向无环图,而Merkle说明这是一个密码验证的数据结构,使用加密哈希来寻址内容。读者可以思考为什么在这个图中不可能有环:

下图表示IPFS对象关系,图的节点代表数据对象中的数据,图的边表示指向其他IPFS对象的链接,链接的名称是图的一条边上的标签



 

文件系统(Filesystems)

IPFS可以很容易地表示由文件和目录组成的文件系统。

小文件(Small Files)

IPFS对象表示一个小文件(< 256 kb)时,对象结构中的data是该文件内容(
还会在文件数据的开始和结尾处还要分别附加一小段header数据和一个footer数据),对象中不含链接,即Links数组是空的。【注意】
文件名称不是IPFS对象的一部分,因此两个具有不同名称和相同内容的文件将具有相同的IPFS对象表示,同样具有相同的hash值。



 

大文件(Large Files)

大文件(> 256kb)是由一个链接(Link)列表来表示的,列表中每个链接分别指向的是小于256 kB的文件块,
于是只需用包含了很小的数据量的对象就能代表一个大文件。指向文件块的链接的name字段为空字符串。

目录结构(Directory Structures)

目录由指向表示文件或其他目录的IPFS对象的链接(Link)列表来表示。链接的name字段是文件和目录的名称

目录结构表示为一个IPFS对象图时,它看起来是这样的:



 

【注意】包含Hello World!\n的文件会被的自动去重,文件中的数据仅存储在IPFS中的一个逻辑位置(由其hash寻址)。

版本化文件系统(Versioned File Systems)

IPFS可以表示Git所使用的数据结构,以支持版本化的文件系统。

IPFS提交对象的主要属性是,它包含一个或多个名称为parent0、parent1等链接,这些链接指向先前的提交;另外,还包含一个名字为object
的链接(Git中称为树),指向该提交引用的文件系统结构。

我们以前面的文件系统目录结构为例,这里显示了两个提交(commit):第一个提交是原始结构;第二个提交中,我们更新了文件my_file.txt,内容改成了
Another World!而不是原来的Hello World!:



 

就是以上的这些数据和 命名链接 构成了 markle DAG 

在IPFS的中的BlockChain:



在将状态数据库放在IPFS上时,会发现重复数据——在两个块之间,只有已经更改的状态条目需要显式存储。

在区块链上存储数据和将数据的hash存储在区块链上的区别。

Ethereum + IPFS 时是,
以太坊(Ethereum)平台上,为了最小化状态数据库的膨胀(bloat)(“区块链膨胀”),需要支付相当大的费用来存储相关的状态数据库中的数据。因此,对于更大的数据块来说,Ethereum
存储状态数据库中数据的IPFS hash,而不是存储数据本身,是一种常用的设计模式。

下面推荐一些链接大家看看:

https://zhuanlan.zhihu.com/p/37455540 <https://zhuanlan.zhihu.com/p/37455540>

https://www.zybuluo.com/zhenxi/note/912913
<https://www.zybuluo.com/zhenxi/note/912913>