†IPFSを実行しながら学んでいく3 ~不変性~ †

2022.07.08

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

††学んだ内容をメモメモ††

IPFSのコマンドラインツールを使いながらIPFSに関して基本的なことを色々と学んでいこうとしています。

前回はIPFSのコンテンツを固定する方法(永続性)について試してみました。

今回はデータの更新に関して試していこうと思います。

データの更新を試す

IPFSでは、IPFSネットワークに追加されると、そのファイルのコンテンツは、ファイルのコンテンツ識別子(CID)を変更せずに変更することができない となっています。

$ echo "Hello, IPFS." > hello
$ ipfs add hello
added QmTp4UwYBop1Qi4MGmHhwJ4VPDZVNpFfmrRVDqU9texC6H hello

$ ipfs cat QmTp4UwYBop1Qi4MGmHhwJ4VPDZVNpFfmrRVDqU9texC6H
Hello, IPFS.

helloというファイルを追加しましたが、このファイルを更新してみましょう。

$ echo "犬、猫" >> hello
$ cat hello
Hello, IPFS.
犬、猫

このファイルをipfsに追加すると,

$ ipfs add hello
added QmZb9UKiX8gAzfo5ZQbwUSaNFe7e1FPAtQgrhud4teHX4q hello

先ほどと内容が違うのでCIDが変更されました。これが不変性の機能です。

$ ipfs cat QmTp4UwYBop1Qi4MGmHhwJ4VPDZVNpFfmrRVDqU9texC6H
Hello, IPFS

$ ipfs cat QmZb9UKiX8gAzfo5ZQbwUSaNFe7e1FPAtQgrhud4teHX4q
Hello, IPFS.
犬、猫

ローカルファイル上では同じ名前のコンテンツですが、IPFS上では別のコンテンツになります。 変更する必要のないデータを保存する時に最適なものとなっています。

更新が必要なものはどう?

Webサイトなど、更新が必要なコンテンツはIPFSでどうすればいいだろう? という疑問が出てきます。 IPFSにWebサイトのコンテンツをアップロードしたら、提供しているサーバーが使用不能になっても、IPFSのネットワークからユーザーは影響を受けずにページを取得できますが、 ページを更新するたびにCIDが変更されると毎回ユーザーに新しいリンクを伝えないといけなくなります。

上記で試したファイルだと、

/ipfs/QmTp4UwYBop1Qi4MGmHhwJ4VPDZVNpFfmrRVDqU9texC6H から /ipfs/QmZb9UKiX8gAzfo5ZQbwUSaNFe7e1FPAtQgrhud4teHX4q に変更。

こういったことを解決するためには、IPNS(InterPlantery Naming Service)という更新可能なアドレスを作成する仕組みを使うことができます。

イメージ)

+--------+      +---------+      +----------+
|  User  | ---> | Pointer |      | QmTp4... |
+--------+      +---------+      +----------+
                     |
                     |           +----------+
                     + --------> | QmZb9... |
                                 +----------+

ユーザーはPointerにアクセスすると、更新されたコンテンツを参照することができます

例)

/ipns/QmSrPmbaUKA3ZodhzPWZnpFgcPMFWF4QsxXbkWfEptTBJd

IPNSを使用すると、CIDを直接扱うという面倒な作業からユーザーを解放できるという利点があります。

IPNSを使ってみる

ファイル作成

IPNSに公開するhtmlファイルを作成します

$ vi index.html

index.htmlの内容は以下のようにしました

<html>
<body>
<p>こんにちは、世界</p>
</body>
</html>

IPFSに追加

作成したHTMLをIPFSに追加します。

$ ipfs add index.html
added QmYfYPRZLjKzj9SqpCFxzdiyop9QXs69LzCLxtprVPKQnb index.html

確認

ipfs cat QmYfYPRZLjKzj9SqpCFxzdiyop9QXs69LzCLxtprVPKQnb
<html>
<body>
<p>こんにちは、世界</p>
</body>
</html>

IPFSデーモンを起動

次のコマンドでデーモンを起動します

$ ipfs daemon

go-ipfs version: 0.13.0
Repo version: 12
System version: amd64/linux
Golang version: go1.18.3
2022/07/05 02:57:17 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas
-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details.
Swarm listening on /ip4/127.0.0.1/tcp/4001
Swarm listening on /ip4/127.0.0.1/udp/4001/quic
Swarm listening on /ip4/172.31.4.63/tcp/4001
Swarm listening on /ip4/172.31.4.63/udp/4001/quic
Swarm listening on /ip6/::1/tcp/4001
Swarm listening on /ip6/::1/udp/4001/quic
Swarm listening on /p2p-circuit
Swarm announcing /ip4/127.0.0.1/tcp/4001
Swarm announcing /ip4/127.0.0.1/udp/4001/quic
Swarm announcing /ip4/13.230.148.139/udp/4001/quic
Swarm announcing /ip4/172.31.4.63/tcp/4001
Swarm announcing /ip4/172.31.4.63/udp/4001/quic
Swarm announcing /ip6/::1/tcp/4001
Swarm announcing /ip6/::1/udp/4001/quic
API server listening on /ip4/127.0.0.1/tcp/5001
WebUI: http://127.0.0.1:5001/webui
Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready

上記のように表示されていると起動しています。

CIDをIPNSに公開

作成したHTMLのハッシュをIPNSに公開します。

ipfs name publish <<コンテンツのCID>>

$ ipfs name publish /ipfs/QmYfYPRZLjKzj9SqpCFxzdiyop9QXs69LzCLxtprVPKQnb
Published to k51qzi5uqu5dic7r0ly7l3d65nsfp7gbbmwv6cj0216kx9fgsfykzdnsdmrdn6: /ipfs/QmYfYPRZLjKzj9SqpCFxzdiyop9QXs69LzCLxtprVPKQnb

少しの時間経過後、公開されます。

k51qz~~~というのが実行しているIPFSの公開鍵またはIPNS名となっていて、ファイルが更新されてもこのキーを使用して引き続きファイルにアクセスできます

Gatewayを通じてファイルにアクセスしてみる

以下のコマンドを利用してIPNSにアクセスしてみます

ローカルでdaemonを立ち上げましたが、出力に

Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080

と表示されていました。

Gatewayへのアクセスは http://127.0.0.1:8080 です。

$ curl 127.0.0.1:8080/ipns/k51qzi5uqu5dic7r0ly7l3d65nsfp7gbbmwv6cj0216kx9fgsfykzdnsdmrdn6
<html>
<body>
<p>こんにちは、世界</p>
</body>
</html>

と、追加したファイルの内容が返ってきました。

ファイルを更新

index.htmlに何か変更を加えた後、再度publishします。

cat index.html
<html>
<body>
<p>こんにちは、世界</p>
<h1>This is Headline level 1</h1>
</body>
</html>
$ ipfs add index.html 
added QmVgGMEeMtzjEGB1QQ3uqncvBTT4TMmMfwAkBkLzNgFdNN index.html

$ ipfs cat QmVgGMEeMtzjEGB1QQ3uqncvBTT4TMmMfwAkBkLzNgFdNN

CIDが変更されました

IPNSを更新

更新したファイルのCIDをpublishします

$ ipfs name publish QmVgGMEeMtzjEGB1QQ3uqncvBTT4TMmMfwAkBkLzNgFdNN
Published to k51qzi5uqu5dic7r0ly7l3d65nsfp7gbbmwv6cj0216kx9fgsfykzdnsdmrdn6: /ipfs/QmVgGMEeMtzjEGB1QQ3uqncvBTT4TMmMfwAkBkLzNgFdNN

先ほどと同じk51qz~~~ というキーが返ってきました

Gatewayを通じてファイルにアクセスしてみる

では先ほどと同じようにgatewayからアクセスしてみます

$ curl 127.0.0.1:8080/ipns/k51qzi5uqu5dic7r0ly7l3d65nsfp7gbbmwv6cj0216kx9fgsfykzdnsdmrdn6
<html>
<body>
<p>こんにちは、世界</p>
<h1>This is Headline level 1</h1>
</body>
</html>

すると、追加した内容が表示されました

キーに関連付けられているファイルのCIDを調べる

ipfs name resolve <<キー>> で、紐づいたCIDを確認できます

$ ipfs name resolve k51qzi5uqu5dic7r0ly7l3d65nsfp7gbbmwv6cj0216kx9fgsfykzdnsdmrdn6
/ipfs/QmVgGMEeMtzjEGB1QQ3uqncvBTT4TMmMfwAkBkLzNgFdNN

QmVgG~~~というのが現在のCIDで、先ほど更新してIPFSに追加したものと一致しました。


コンテンツの不変性は保ちつつ、アクセスするときは常に同じアドレスを使用できるようにIPNSを試してみました。 更新が必要なコンテンツを扱う場合、この考えは役に立ちそうです。

また、IPFSで可変アドレスを作成する方法はIPNSだけでなく、DNSLink というのも使えるようですので次回試してみようと思います

参考