proof of storage


科学的本质是哲学。哲学的追求有一个极:永恒。有两个底:变和不变。这两个哲学思想,就好比九阳神功和太极剑。学会之后遇山开路,遇水化桥,千变万化无所不通。

基于存储空间的区块链的存储证明和时空证明的算法,也是基于变和不变。目前已经存在的pow 和 pos的算法确实很厉害,不过不影响我们用新的思维去考虑问题。
本文推荐的存储证明和时空证明算法具备以下特点:

  • 准确
  • 快速
  • 经济
  • 永久性不可攻破

有以下场景:

A节点有一个100M的文件file1.txt需要存储,付费给B节点,合同期为180天。A想知道B到底有没有存储这个文件,以及第180天合同到期之前,B是否一直保存了这个文件的全部内容。

方案1:

A节点在/root/dir1/路径下,存储了file1.txt.bak,B节点存储了/home/dir/file1.txt。访问文件时,A节点通过网络访问B节点/home/dir/file1.txt。为了防止B节点赖账,给一个假文件,
A节点将从B节点读取到的文件内容,拿去于A节点/root/dir1/file1.txt.bak对比,完全一致则A节点确定B确实存储了这个文件。合同期结束后,B节点将会收到A节点支付的10块钱(钱放在第三方)。

虽然解决了文件存储证明的问题,但是这种方式并不经济……

方案2:

A节点存储file1.txt.bak文件的一部分(比如每4096 byte,随机存储其中的任意位置4个字节),于是A节点上/root/dir1/file1.txt.json 文件存储的内容为:
{
"node_id":"B_192.168.31.1:8000",
"filename":"file1.txt",
"contract Date of signing": "2019.8.13",
"contract deadline":"2020.2.13",
"contract price":"1.25 $",
"filesize":"100M",
"block_size":4096,
"block_cnt":25600,
"block_label": [
{ "x":"value1"},
{ "y":"value2"},
{ "z":"value3"}
]
}
B节点存储的文件还是/home/dir/file1.txt。由于A自始至终不将标签值告诉B节点json文件内容,B不敢给一个虚假的文件给A,否则就收不到A支付的费用。
B存储了全部100M文件,同时A只存储了100M文件里面每4096字节几个字节,由于信息不对称(A不给B提供任何访问json文件的接口)。所以这种方法是比较安全的。

方案2,解决了方案1的经济不划算问题,有一些小的隐患(A节点存储的内容太少,总有机会碰到B节点不是人为,而是磁盘分区损坏,B也不知道一块数据变了,但是整好A节点上那一个字节对上了,块里面其他地方的数据错了),不过A节点说还想再尝试一下其他的方案,A节点不想存储任何明文。

方案3:

类似于方案2,但是这次不存储任何明文了。默克尔树登场。先看下面一颗二叉树。

最底层存储文件内容的哈希,从左往右是文件的0 ~ 4k、4k ~ 8k、8k ~ 12k、12k ~ 16k的哈希,第二层深度是x5=sha256(string(sha256(block1)) + string(sha256(block2)))
x6=sha256(string(sha256(block3)) + string(sha256(block4)))
B节点存储文件/home/dir/file1.txt、/home/dir/file1.txt.merkeltree。A节点存储/root/dir1/file1.txt.merkeltree。A节点获取到B节点上某一个块时,从树叶计算到树根(方案3到树叶上一层即可),哈希值一致则ok。

区块链存储证明和时空证明_随机数

方案3,可以100%的确保不被人为或意外变更,只能在A文件属主获取文件时验证,A作为客户端不可能一直在下检测文件。而区块链做随巡检,不可能每次都把文件通过网络获取过来,区块链的io是宝贵的,尽量节省。因此方案3也不是特别满意。

方案4:

正如我开篇第一句话讲的那样,技术问题本质是哲学问题,哲学为变和不变,哲学终极为永恒。哲学来源于生活,热爱生活,热爱自然完全有助于工作的提升。

蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。
蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。

废话不多讲,直入正题。在方案4的基础上,节点A存储的不是默克尔树了,存储的是随机值。是原摩尔树每一个节点,与上一个随机数的哈希值。
区块链在存储文件给B的同时,构建默克尔树文件:
{
"node_id":"B_192.168.31.1:8000",
"filename":"file1.txt",
"contract Date of signing": "2019.8.13",
"contract deadline":"2020.2.13",
"contract price":"1.25 $",
"filesize":"100M",
"block_size":4096,
"block_cnt":25600,
"hash_hash_list":[
leaf1:[
"random_cursor":"1",
"hash(hash(block)+random1)":"random1",
"hash(hash(block)+random2)":"random2",
"hash(hash(block)+random3)":"random3",
"hash(hash(block)+random4)":"random4",
"hash(hash(block)+random5)":"random5",
"hash(hash(block)+random6)":"random6",
],
leaf2:[
"random_cursor":"6",
"hash(hash(block)+random1)":"random1",
"hash(hash(block)+random2)":"random2",
"hash(hash(block)+random3)":"random3",
"hash(hash(block)+random4)":"random4",
"hash(hash(block)+random5)":"random5",
"hash(hash(block)+random6)":"random6",
],
leaf3:[
"random_cursor":"4",
"hash(hash(block)+random1)":"random1",
"hash(hash(block)+random2)":"random2",
"hash(hash(block)+random3)":"random3",
"hash(hash(block)+random4)":"random4",
"hash(hash(block)+random5)":"random5",
"hash(hash(block)+random6)":"random6",
],
leaf4:[
"random_cursor":"3",
"hash(hash(block)+random1)":"random1",
"hash(hash(block)+random2)":"random2",
"hash(hash(block)+random3)":"random3",
"hash(hash(block)+random4)":"random4",
"hash(hash(block)+random5)":"random5",
"hash(hash(block)+random6)":"random6",
],
]
}
随机数,是区块链调用random()产生的,写入默克尔树。默克尔树节点存储的是下一层 hash(哈希+随机数): random,一次产生6个。B节点还是存储文件。
区块链巡检文件时,给出随机数数组[random_cursor]对应的随机数给B节点,B回传对应块+区块链指定随机数的哈希值。同时随机数组random_cursor++,当区块链巡检用到第四个随机数后,发出请求让B把块数据传回来。
区块链验证通过后,利用传回来的block内容,重新生成随机数数组。

实际编码时,根据巡检力度和合同期,可将6调整为15或者其他适合值。方案4我相对于方案3比较满意,可以作为区块链存储证明和时空证明的有效方法之一。

区块链存储证明和时空证明_区块链_02

鲁迅说只要去挤一,总能挤出水分来。那么方案4没有问题吗? 问题是有的,单节点存储文件,就有磁盘损坏,节点挂掉,下线的风险。

方案5:

将文件切片成8M一个的文件,96M大小的文件,分片成12 + n个文件,对于不同的文件提供不同收费标准(纠删比例不一样)存储方式。文件切片丢失后,或部分节点下线后,
利用纠删码最大限度的提供文件io服务 或 文件恢复服务。