Building planetable.xyz

IPFS
 
Planet Feature Update 12

更新了对 WalletConnect 的支持,众多针对 IPFS 的改进和新功能,全新的 Monochrom 头像图片集,及其他使用体验上的改进。

WalletConnectV2

Planet 更新了对 WalletConnect 的支持,升级到了 WalletConnectV2 版本。现在你可以使用手机钱包,比如 Rainbow,OKX 在 Planet 里登录,并用来向你关注的内容创作者打赏 ETH。同时,作为一个重要的基础架构,这也让将来 Planet 支持其他更复杂的合约调用或是 L2,成为可能。

新的 IPFS+ENS 网关

当你为站点生成分享链接时,现在可以使用一个新的高性能 IPFS+ENS 网关 eth.sucks。在设定了 content hash 的 ENS 末尾加上 .sucks 就可以访问上面的 IPFS 网站,比如:

可以从设置中选择这个新的网关。

前段时间,Cloudflare 宣布他们会停止维护 cf-ipfs 网关。所以,目前,还能用的 IPFS+ENS 网关,就是这些了:

一个健康的生态系统需要更多的参与者。

IPFS 控制面板

现在点击左下角显示 Online 的区域,会看到一个新的 IPFS 控制面板:

显示 IPFS 的版本信息,空间占用,及实时的带宽消耗。如果需要,甚至可以从这个控制面板里暂时关闭 IPFS 进程。

用本地 IPFS 网关打开任意 IPFS 资源

现在可以从 File 菜单下找到一个新的 Open 选项,用它来打开任意的 IPFS 或者 ENS 资源地址。

复用 Tags

在为内容选择 tag 时,现在可以从之前已经用过的 tag 里点击选择。

新的站点头像图片集 Monochrom

99 个全新设计的站点头像图片。

在站点设置中,可以选择在保存新的站点头像图片时,存储为圆形图片。这样做的用途是,如果你希望在浏览器的收藏夹中也显示圆形图片,而不是默认的方形。

新的快速分享拖拽

可以用拖拽任意图片放到文章列表,就可以打开一个新的快速分享发帖方式。

新的短文本输入发送

按下 CMD+D 就可以打开一个新的短文本输入发送框,配合 Sepia 主题,很适合用来记录和分享一些简短的想法。

比如这是一个使用 Sepia 主题的 microblog 站点:

sepia.olivida.eth

其他修复和改进

  • 修复了一个会发生在 macOS 12/13 上的文章列表异常。如果你使用的是 macOS 14 那么不会遇到这个问题。
  • 可以在搜索结果列表中使用键盘上下选择结果打开。
  • 模版中现在可以读取到文章主图(hero image)的高宽信息。
  • 站点 IPNS 发布完成时,会用本地通知方式显示最新的 CID。
  • 新的站点设置:Do Not Index。写入一个 robots.txt 规则文件告知搜索引擎不要索引网站。
  • 新的站点设置:Prewarm。每次新文章发布时,Planet 可以自动在当前选择的公共网关上访问一次新文章地址,这样新文章在公共网关的 IPFS 节点里就会有一份新鲜的副本,让其他访问者可以更快打开内容。
  • Insider 版本现在会有一个单独的二进制文件名称 Planet-Insider 以更方便地和其他版本共存。
  • 增加了 Filebase 节点的 Peering,如果你使用 Filebase 的 Pinning 服务,那么可以让 Filebase 的节点更容易完成同步。
 
Hashes

No-IntroRedump 是两个由互联网上的游戏爱好者们维护的数据库,目标是获取并保存过去那些通过卡带和碟片发行的老游戏的特征码。

早期的卡带游戏,由于破解和盗版,玩家能够玩到的版本往往已经被修改过。比如你很可能就玩过一个叫做「90 坦克」的游戏,实际上是修改自 NAMCO 的一个叫做 BattleCity 的 Famicom 游戏。而在游戏的开头,往往就会有修改者加上的新的画面,也就是 intro。而 No-Intro 项目就是希望能够维护这样的一个数据库——里面是这些游戏的原始版本的特征码,也就是 hash 值。hash 是一类计算机算法,通过复杂的数学过程,可以获得一个文件的特征。如果两个文件的内容的每一个字节都是相同的,那么就会获得同样的 hash 值。常见的 hash 算法有 MD5,SHA1,SHA256 等等。

IPFS 的 Content-addressing,也就是「内容寻址」技术,也是基于 hash。只是你不能直接在 IPFS 中使用一个文件的 SHA256 值来找到它,而需要通过 IPFS 的 CID。IPFS 的 CID 包括了比整个文件的 hash 更多的信息。

所以,假如像 No-Intro 这样的数据库中除了 SHA-256,同时也包括文件的 CID 值的话,那么就有可能可以通过整个互联网,而不是某台确定的服务器,来获得那个文件了。只是这种不确定性,同时带来了很多的优点和缺点。

优点:

  • 不需要依赖单一的网站地址或者服务器地址:互联网上的大部分地址都无法存在太长时间,平均值甚至不到半年。而 SHA256 或者 CID 是确定的,因此假设如果互联网上确实有 IPFS 服务器存储了某个确定的 CID,那就有机会下载下来。

缺点:

  • 巨大的 overhead。如果你曾经看过 Jeff Dean 的 Latency Numbers Every Programmer Should Know,然后再看 IPFS 内容寻址的过程,就会看到一切都完全发生在一个不确定的网络架构中,因此需要非常多次尝试才有可能拿到有意义的数据,这是巨大的 overhead。

基于内容寻址的技术因为其不需要依赖特定服务器,谁都可以存,因此在理想情况下,如果一个内容确实有很多节点都存了,于是也就实现高度的去中心化。所以在一些理解和需要这样架构的场景中已经得到了应用,比如 NFT 的图片。当你在 mint 一个 NFT 时,大部分情况下,你获得的 token 并不是图片文件本身,而是图片文件的 CID。理想情况下,NFT 的 CID 会有多个 IPFS 节点存储,因此通过 CID 就始终可以获得这张图片。为什么一直强调「理想情况」,因为另外一种情况是,随着时间过去,一件事情没有人在意了,于是本来存有这些 CID 的服务器逐个下线了,最终这个 CID 也就消失了。就像,如果,即使我们知道一个 ROM 的 SHA-256 值,但这个世界上最后一块存有那个 ROM 的硬盘坏了,并且原始的最后一张游戏卡带也坏了的话,那么即使知道 SHA-256 值,那个文件也会永远消失。如果要增加一个文件持续存在下去的可能性,那么尝试多种完全不同的存储和传播方式就是有意义的。

前面提到 IPFS 的内容寻址过程中的不确定性,这或许是一个可能可以解决的用户体验问题。相比通过商业 CDN 加速过的内容,从 IPFS 网络下载东西的体验可能会非常糟糕——因为很多时候如果试着直接在浏览器里访问一个 CID,就卡在那里了,像是什么都没有发生。

早期的拨号互联网,及 BitTorrent 下载也面临同样的用户期待值问题,于是开发者们通过更好的进度条来实现了用户体验优化。

而这样的图形化手段,应该也可以用于改进 IPFS CID 的下载体验。但目前(2024 年 7 月),这样的软件存在于传统的 HTTP 协议和 BT 协议,暂时还没有看到针对 CID 下载的实现。

想象这样的一种可能性:各种下载网站上提供的不只是 https 或者 torrent,也提供或者只提供 CID。下载一个文件的过程是把 CID 放进原生支持 IPFS 通讯协议的下载软件,然后下载软件就可以显示一个非常具体的进度,甚至可以通过多线程同时下载文件的不同部分。对于下载网站的维护者来说,文件存储除了完全自己维护,也有可能通过更多的其他人的服务器来分档存储。而对于各种 retro 内容存档爱好者们来说,自己在意的内容,也多了一种获得和持续存在下去的可能。

 
关于用 PubSub 来实现互动内容的一些构想

PubSub 是 IPFS 中的一项实验性的功能,默认没有在 kubo 发布版本中打开。它的具体工作方式是这样的:

  • 节点 A 向一个名称为 X 的 channel 发布消息
  • 如果节点 B 和 A 互相是 peers,并且节点 B 正在监听同样名称的 channel,那么就可以实时收到这条消息

在 Planet 搭载的 kubo 中,打开了这个功能,因为它可以实现更快的 IPNS 信息更新。这也是 kubo 的另外一个实验性的功能:通过 PubSub 更新 IPNS

于是,基于 PubSub,有可能可以实现一些很有趣的互动玩法。

对文章的点赞和评论

目前 Planet 的信息发布和传播模式,是一种类似广播的单向模式:写文章的人可以把自己的作品向外传递出去,通过 IPNS 或者 ENS,但是无法收到来自读者的反馈,比如评论和点赞之类的互动是不存在的。

如果,Planet 里增加一个基于 PubSub 的互动玩法,就可以这样实现:

  • Planet app 监听所有本地 IPNS 同名的 channel
  • 读者可以向这些 channel 发送点赞或者评论
  • 如果监听方收到这些点赞和评论,就存入本地的 comments.jsonlikes.json 这样的文件,然后定时重新渲染网站发布。

这样的话,就在一个完全去中心化的环境里,实现了点赞和评论。

话题投稿、公共空间、话题广场

PubSub channel 的另外一种用法,可以被当作一个公共容器。

比如你写了一篇关于 Ethereum 这个标签的文章,那么就可以把文章的 IPNS + UUID 作为一条消息发送到一个叫做 planet:tags:ethereum 的 channel。

另外一端,如果有程序持续在监听这个 channel,就可以把所有收到的 URL 保存及抓取,然后生成一个专门关于这个 tag 的网站。

整个发送、接收、展示的步骤,都是自组织、无需许可的。

一些可能的问题

PubSub 机制要能完全按照期待的那样正常工作,需要满足两个稍微有些苛刻的条件:

  • 发送方和接收方需要同时在线。因为中间并没有任何暂存机制,而是一种广播机制,所以如果消息发送的时候,接收方没有在线。那么稍后接收方在线的时候,并不能看到之前的消息。一种解决方式是发送方重复发送很多次,把去重(deduplication)这个问题交给接收方去处理。
  • 发送方和接收方需要是彼此的 peers。这个问题在 WAN 复杂的网络条件下,究竟会如何影响 PubSub 功能的使用体验,及能对此做什么优化,我还需要通过代码尝试更多的实际情况才能知道。
 
💡为什么我们会需要一个甚至多个 Pinning DAO

通过 Planet 发布内容,是一种完全去中心化的 local-first 模式。所有的内容不仅存储是在本地,提供对外服务的 IPFS 节点,也是运行在本地机器上。这样的好处是,整个内容的发布和订阅流程,不会受制于外部的大公司的基础架构。

但这样的完全去中心化的做法,也会带来一些挑战:

因为提供对外服务的 IPFS 节点也在本地,因此需要程序一直运行。这对于 Mac mini 或者 Mac Studio 这样的桌面设备可能不是太大的问题,但是对于笔记本电脑的用户就会是一个问题。

对于笔记本电脑的用户,因为不可能让设备保持 24x7 开机及联网,那么最简单的解决方案还是引入服务器来帮助分发。如果你有自己的 Linux 服务器,那么下面是在自己的服务器上启用 IPFS 来帮助 Planet 内容分发的操作步骤和原理。

安装 IPFS for Linux Server

  • 从这里 https://github.com/ipfs/kubo/releases 下载 Linux 版本的 IPFS 服务器端。就是一个可执行文件,我通常的做法就是把这个文件 ipfs 复制到 /usr/local/bin/ipfs,这样就可以随时运行 ipfs 指令。
  • 启动 IPFS 进程 ipfs daemon,可以使用 screen、tmux 或者 supervisord。

IPFS 进程启动之后,就可以通过下面这样的指令来 pin 内容了。

ipfs pin add /ipns/olivida.eth

所谓 pin 内容这个操作,其实很类似 BitTorrent 下载中的「做种」这个概念。就是,如果一份内容被 pin 了,意味着本地保存了一份经过完整性校验的拷贝,如果网络上的其他节点也要请求这份内容,那么就是所有有拷贝的机器来一起提供,就像 BitTorrent 下载时,是所有 seeder 来一起服务下载请求。

你可以在 pin add 使用 IPNS 地址,无论是 k 开头的原生 IPNS 地址,或者是 ENS 地址,都可以支持:

ipfs pin add /ipns/planetable.eth
ipfs pin add /ipns/k51qzi5uqu5dgv8kzl1anc0m74n6t9ffdjnypdh846ct5wgpljc7rulynxa74a

如果你把这样的指令放到 crontab 中,那么就可以实现追踪 IPNS 背后的 CID 的变化,然后一直 pin 最新内容。

Pinning DAO

上面的这个操作过程,对于没有 Linux 服务器的用户来说,还是太麻烦了。我们需要更简单的方式,而这件事情非常适合做成一个 DAO。

DAO 存在的意义,就是服务成员的共同需求。

Pinning DAO 里,这个共同需求就是:成员需要全世界各地的服务器,来保证发布在 IPFS 上的内容,是永远可用的。为了持续实现这一点,于是需要一个或者多个这样的去中心化自治组织。

我希望接下来能够看到这样的组织的出现。

为了完整实现这个愿景,将会需要构建很多新的开源软件。

比如一个用 RainbowKit 或者 ConnectKit 实现登录的网站,ENS holder 登录并且通过 Juicebox 付款成为 DAO Member 之后,就可以通过这个 DAO 部署在全球各地的基础架构来 pin 自己发布在 ENS 上的网站。

而除了提供 pin 服务之外,DAO 也可以为成员提供自建的 Plausible 流量统计之类的服务。

虽然内容通过 DAO 进行了分发,但是权威版本依然是完全控制在用户本地。而不是像之前,因为使用了 Web 2.0 大公司的平台来存储和分发内容,内容的实际存活就完全被大公司所控制了。如果一个 DAO 提供的服务成员不满意,那完全可以发起另外一个,充分的竞争会带来最好的产品和服务。

 
IPNS

IPNS 是 IPFS 生态中的一个重要组件,全称是 InterPlanetary Name System,一个去中心化的类似域名的系统。

这里是 IPNS 的官方介绍:

内容寻址是 IPFS 找到内容的最基础的方式。但是会有一个问题是,内容 ID 其实是内容的 hash。因此如果内容本身如果发生了任何变化,那么 hash 也会变。所以如果是用内容 ID(CID)来绑定给 ENS 的话,每更新一次博客就去烧 gas 重新设置 ENS 的 Content Hash,在现有的 gas fee 情况下,就太贵了。

而 IPNS 可以解决这个问题。每一个 IPNS 类似加密货币的钱包,会有一对 public key 和 private key。public key 就是 IPNS 的对外的地址,而 private key 可以用来修改这个对外地址所对应的 CID。

因此,当你用 IPNS 来绑定给 ENS 作为 Content Hash 的时候,完整的链条是这样的:

ENS -> IPNS -> CID

其中 ENS 到 IPNS 这层绑定,会需要一次性的 gas 费。

IPNS 到 CID 这一层,是免费的。

这样我们就可以实现用 IPFS 更新内容之后,ENS 上的网站也就能够动态更新,同时只需要消耗一次性的 gas 费。


比如本站的 IPNS 地址是:

k51qzi5uqu5dgbfw2poynnynor8h9kqqoxmzdrxy4h4wnzx1x5p4n40ijtosxk

然后绑定到了 olivida.eth 这个 ENS 域名上。

在所有支持 IPFS + ENS 生态系统的应用中,你可以使用上面的 IPNS 地址或者 ENS 找到同样的内容。

olivida-eth.png

 
关于备份 IPNS Key

目前 Planet 还处在一些非常大的变化中,因此时不时备份你的 IPNS key 是非常有必要的。在 0.6.* 版本中备份的操作方式是侧栏中选中自己的 Planet,然后从 Tools 菜单中按 Export Planet。

export-planet.png

 
IPFS 的性能及优化

如果你之前曾经尝试过去用 IPFS 发布一些东西给别人访问,那么你很可能已经体会过这个技术的慢。比如 ipfs.io 上的各种超时。

因为这个技术的底层是 DHT,也就是类似 BitTorrent 和电驴下载的那种 P2P 技术。如果你曾经用过 BitTorrent 的 DHT 下载,你肯定也经历过刚开始下载的时候,漫长的找节点的过程。及就算是找到了节点之后,各种连不上或者没速度。作为使用同样基础技术的 IPFS,这些问题也同样存在于 IPFS。

所以,如果使用场景场景是发布一些东西,然后让用户去浏览器中通过 ipfs.io 这样的 Public Gateway 去加载,那么很有可能就卡在那里直接卡超时了。Web 2.0 时代的 HTTP 已经被优化到了极致,但是 Public Gateway 的架构决定了那些优化到了 P2P 网络上并不完全适用。

但是,当你在用本地电脑作为 IPFS 节点时,依然是可以有一些技术手段对发布性能进行优化的。

端口转发

你可以把你的公网 IP 的 4001 端口转发到你运行 Planet 的本地电脑上。

IPv6 的入流量

如果你的运营商提供 IPv6 并且你知道怎么设置 IPv6 防火墙,那么你可以在防火墙上打开外部对 4001 端口的访问。

UPnP

如果你的路由器支持 UPnP,那么打开 UPnP 支持可以允许 IPFS 节点更好地进行 P2P 通讯。


4001 端口是 IPFS 的 peer 流量端口,上面的所有操作是只读的。在公网上打开这个端口不会造成安全问题。但是部分入侵检测系统可能会抱怨,比如 UniFi Network 的 IDS 系统就会报告这个端口上有异常。