内容提供
一条协议记录从不携带一个文件。它携带一个 CID——一个存储在 别处之内容的自描述哈希——这把一份 10 MB 的回执挡在每个节点都必须 存储并重放的 gossip 载荷之外,同时仍让一位仲裁员能确证他所 看的图像正是当事方所签署的那一张。
某人仍然得持有那些字节。那个某人是你的节点,而它 已经在这样做了:内容提供默认开启,且不需要 配置。
为何在节点内而非一个守护进程
它的第一个版本通过一个单独的 Kubo
守护进程来 pin,经由 --ipfs-api-url 到达。那可行,且代价比看起来
更大:网络上的第二个 peer 身份、一个 Go 运行时及其驻留
内存与节点的并存,以及端口 5001 上一个未认证的 /api/v0 控制
接口,它让任何能到达它的人都能 pin、unpin 并读取守护进程所持有的
一切——仅靠把它绑定到 loopback 来缓解。
更深的问题是默认值。运行一个守护进程是工作量,因此 pin 是 可选的,因此几乎不会有人开启它——而一个无人主动开启的持久性 保证不是一个保证。一个节点现在在进程内讲 bitswap,在它已经用来 gossip 的同一 libp2p 身份上,这正是让该行为默认开启的原因。 而那反过来正是让奖励溢价度量某个真实之物的原因:在人人 都提供的情况下,该乘数把真正持有并为内容作答的节点与 离线或已修剪的节点分开,而非把不辞辛劳安装了 Go 的操作者与 没有的分开。
你的节点持有什么,以及不持有什么
它持有它已接受之附件记录所引用的内容, 在其保留窗口之内。它并不获取它所见的每一个 CID——一个那样做的 节点将会存储任何人选择指向它的东西。
那个界限不是一个承诺,它是算术:一个附件必须指名一个 结算,而一个结算需要一个针对真实托管的真实预约。你的磁盘被 索取之物的上限,是网络的实际交易量,而 非一个陌生人的耐心。
一切被取回之物在被保留之前都会针对其 CID 检查,无论它 来自一个 peer 还是一个网关。
问问你的节点它正持有什么:
curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"getHeldContent","params":{"cid":"bafkrei..."}}'
# {"jsonrpc":"2.0","id":1,"result":{"content":"<base64>"}} ← 已持有
# {"jsonrpc":"2.0","id":1,"result":{"content":null}} ← 未持有
第一份副本从何而来
Bitswap 在已经拥有区块的 peer 之间移动区块;它不创建 第一份。内容通过界面上传到的任何 pin 服务进入网络, 因此第一个想要某个 CID 的节点必须从更广的 IPFS 网络 获取它,针对该 CID 检查字节,并从此为其 peer 提供它。
--content-gateway https://ipfs.example.com # 默认:https://ipfs.filebase.io
网关是不受信任的传输,不是一个权威。它可以提供 错误的字节、没有字节,或记录谁请求了什么;它无法改变一个 CID 所指名的内容,因为该 CID 是那内容的哈希。不是 CID 所指名之物的 字节会被拒绝,而一个替换任何东西的网关,与一个 干脆宕机的网关无从区分。
隐私是验证唯一无法修复的东西:运营该网关的人 会得知你的节点请求了这个 CID。那正是该标志存在的原因——把它 指向你自己的——也是它是一个后备而非首选的原因。你的 节点更偏好它的 peer。
如果你已经运行 Kubo
--ipfs-api-url http://127.0.0.1:5001 仍然可用,且现在意味着某个
比过去更狭窄的东西:协议内容会另外被 pin 进你的守护进程,
把一份副本放在你的节点自己的保留窗口所不
支配的某处。它不再是一个节点提供内容的方式。
关掉它,以及那要付出什么
openfiat-node --no-content-serving
那个节点什么都不存储,也无法答复一次可取回性挑战,因此 它赚取被降低的份额。那是诚实的结果——它为网络做的 更少——而如果磁盘确实不在那里,它就是正确的标志。节点 无论如何仍然挑战它的 peer:度量谁提供内容是一个节点无论 自身是否存储任何东西都执行的服务。
挑战如何运作
一个节点挑一个网络知道的 CID,向另一个节点索取字节, 并哈希返回之物。一个内容地址就是其内容的哈希,因此 返回正确的字节不是一个节点在没有它们时能做到的事。 这是唯一一个被核对而非被相信的节点质量信号。
只有某些 CID 能裁决这个问题。一个 raw-codec CID 的摘要取自 文件本身;一个 dag-pb CID 寻址一个分块 DAG 的根,因此一个 peer 可能返回正确的文件,却仍未能通过一次朴素的哈希检查。提供者 在 262,144 字节处在两者间切换,因此挑战抽取处于或 低于 256 KiB 的文件——头像几乎总是,附件有时。那足以 把一个 pin 一切的节点与一个什么都不 pin 的节点分开,而这 正是该乘数所需要的;它不是一个节点持有某一个特定 大附件的证明,也没有任何东西声称它是。
该乘数是什么
一个作答的节点保留其完整份额;一个无法作答的节点被缩放到
0.7,因此一个提供的节点赚得大约是一个在其他方面相同、
但不提供的节点的 1.43×。两个数字都是 [PROPOSED — NEEDS SIGN-OFF]——参见
OFS-4100 §9.2 和 crates/rewards/src/params.rs。
该溢价被表述为一种惩罚,其理由并非表述层面的。 每个 epoch 的排放是固定的,而这些乘数决定它如何被划分。 一个高于 1.0 的加成不会凭空为一个 pin 的节点付款,它会 铸造基础设施桶并不包含的排放——而奖励参数 径直拒绝那个。因此 pin 的节点保留其完整份额,而 不 pin 的节点让出它自己的一部分。
之所以是 0.7 而非仅 gossip 的 0.4,是因为相比一个链连接, 存储对网络是一个更小的恩惠:一个不 pin 的节点仍然 中继、验证并提供其他一切。
内容保留多久
不是每个节点都应携带整段历史。
--retention 30 # 默认:一个滚动的 30 天窗口
--retention 365 # 一个更长的窗口,仍然滚动
--retention archival # 永远保留一切——一个显式的选择
30 天也是每个节点欠网络的下限,因此更短的值会被 拒绝而非被悄悄抬高——一个配置为七天却悄悄运行了 三十天的节点,会在做某件不同于其操作者所要求之事。
那个下限正是让驱逐与奖励共存的东西。挑战永远只从 其内的内容抽取,因此一个正确驱逐了去年证据的滚动节点, 永远不会因此被问起,也永远不会因做了正确之事而失去其 份额。同样,任何节点都无法通过声明一个更小的窗口来缩减 它可被问起之物。