深入理解IPFS(3/6):什么是行星命名系统(IPNS)

       这篇文章是“深入理解IPFS”系列文章的续篇(第3部分),它将帮助理解IPFS的基本概念。如果您想了解什么是IPFS及其工作原理,那么您也应该查看第一部分 🙂


       在第2部分中,我们讨论了IPLD(星际关联数据)的意义、工作原理及其技术规范。我们还学习了一个教程,其中我们创建了一个类似于发布系统的媒体,完全使用IPLD。你可以在这里查看:


在这一部分中,我们将深入研究IPFS的命名系统——行星间命名系统(IPNS)。我们将探讨:


需要去使用IPNS? 它与今天的DNS(域名系统)有何可比性,又有何不同?


我们将探讨路由如何在IPFS中工作,以及IPNS如何工作?


,我们会亲手使用IPNS我们将设置我的网站完全使用IPFS堆栈。


希望您从本系列中学到很多关于IPFS的知识。让我们开始吧!


为什么需要IPNS?


为了理解为什么我们需要IPNS,让我们看看目前我们如何使用IPFS访问我们的照片、视频和memes


另外,如果你想要跟随我一起来做,你可以这样下载我的网站:


wget --mirror --convert-links --adjust-extension --page-requisites --no-parent https://vaibhavsaini.com

当我把我的网站加入IPFS时,你会得到如下输出数据:

深入理解IPFS(3/6):什么是行星命名系统(IPNS)  

 现在,我可以在这里访问我的网站:https://gateway.pinata.cloud/ipfs/QmYVd8qstdXtTd1quwv4nJen6XprykxQRLo67Jy7WyiLMB/

但这个链接有几个问题:

首先,它很难读,更不用说记住了。

其次,它是一个不可变的链接。我所说的不可变链接是指这个链接是永久性的(由于内容寻址的本质)。如果我在我的网站的任何地方添加一个逗号,根文件夹的CID就会改变,从而改变到我网站的链接。所以,每次我在我的网站上做任何改动,我都必须把这个新链接给所有想要访问我最新网站的人,这并不酷。

就是IPNS发挥作用的时候了

 

使用IPNS可以生成一个可变链接,其中:

 

将是人类可读和容易记住。

 

指向最新版本的网站,个人资料照片,视频等。

 

IPNS中的名称(链接中的Hash/ IPNS /链接)是公钥的散列。它与一个记录相关联,该记录包含有关它链接到的hash的信息,该hash由相应的私钥签名。新记录可以随时签署和发布。


因此,换句话说,IPNS是一个基于公钥基础设施(或PKI)的全局名称空间,它允许我们构建信任链(因此您可以跟随公钥到达它的路由对等点),为我们提供加密和身份验证,并且实际上仍然与其他名称服务兼容。例如,我们甚至可以将DNS条目、洋葱浏览器地址或比特地址等映射到IPNS地址。


IPNS不是在IPFS上创建可变地址的唯一方法您还可以使用DNSLink(它目前比IPNS快得多,并且使用了更多可读的名称我们将在下面了解更多)。其他社区成员正在探索使用区块链存储公共名称记录的方法。下面是针对分布式web命名系统的不同项目的比较


IPNS和DNS有一些相似之处。两者都在各自的系统中解决类似的问题,前者在内容寻址系统中解决,后者在位置寻址系统中解决。


在定位系统(今天的老式internet)中,我们使用IP:PORT组合来访问数据。因此,在一个位置地址系统中,我的网站地址将是:http://18.205.129.69:80


它既不容易读也不容易记。

 

但这个链接地址总是指向这个地址上承载的最新内容。


使用DNS,我们将这个IP与一个域名相关联,因此您可以访问vaibhavsaini.com网站。


好的,它是如何工作的呢?


IPNS可以通过多种方式实现,但目前的实现使用分布式哈希表(DHT)。因此,只有将每个URI映射到其对应的最新hash映射才能进行解析,而忽略了任何历史映射。从归档的角度来看,这并不好,因为以前版本的文件可能仍然存在于IPFS存储中,但是它们相应的URI映射将丢失。


让我们使用ipns节点模块来理解ipns记录是如何发布的。


const ipns = require('ipns');

const crypto = require('libp2p-crypto'); //for generating RSA keypair

function generateRsaKeypair(){

    //generating an 2048 bit RSA keypair

    crypto.keys.generateKeyPair('RSA', 2048, async(err, keypair) => {

        if(err){

            console.log('error ', err);

        }

        else{

            console.log("nGenerated new RSA Keypairn");

            createIpnsRecord(keypair);

        }

    });

}

/*

Creating an IPNS record with a lifetime

ipns.create(privateKey, value, sequenceNumber, lifetime, [callback])

privateKey (PrivKey RSA Instance): key to be used for cryptographic operations.

value (string): ipfs path of the object to be published.

sequenceNumber (Number): number representing the current version of the record.

lifetime (string): lifetime of the record (in milliseconds).

callback (function): operation result.

*/

function createIpnsRecord(keypair){

    let sequenceNumber = 0;

    let lifetime = 1000000; //1000000 milliseconds

    let value = 'QmYVd8qstdXtTd1quwv4nJen6XprykxQRLo67Jy7WyiLMB'; //hash to my website

    var recordData;

    ipns.create(keypair, value, sequenceNumber, lifetime, (err, entryData) => {

        if(!err){

            //Created new IPNS record

            console.log("nGenerated new IPNS recordn");

            console.log(entryData);

            validateIpnsRecord(entryData, keypair);

        }

    });

}

 

/*

Creating an IPNS record with a fixed expiration datetime.

ipns.createWithExpiration(rsa, value, sequenceNumber, expiration, [callback])

privateKey (PrivKey RSA Instance): key to be used for cryptographic operations.

value (string): ipfs path of the object to be published.

sequenceNumber (Number): number representing the current version of the record.

expiration (Date): Date object.

callback (function): operation result.

*/

function createIpnsRecordWithExpiration(keypair){

    ipns.createWithExpiration(keypair, value, sequenceNumber, expiration, (err, entryData)=>{

        if(!err){

            validateIpnsRecord(entryData);

        }

    });

}

/*

Validate an IPNS record previously stored in a protocol buffer.

ipns.validate(publicKey, ipnsEntry, [callback])

publicKey (PubKey RSA Instance): key to be used for cryptographic operations.

ipnsEntry (Object): ipns entry record (obtained using the create function).

callback (function): operation result.

*/

function validateIpnsRecord(entryData, keypair){

    ipns.validate(keypair.public, entryData, (err)=>{

        //if no err then the validation was successful

        if(!err){

            console.log('nIPNS Record Validation Successfuln');

        }

    });

}

generateRsaKeypair();


上面的代码经过了足够的注释,您也可以在这里查看完整的项目。


如果您想深入了解IPFS中的路由是如何工作的,可以阅读本文。我想在这篇文章中解释一下,但是有太多其他有趣的事情要探索,所以我跳过了😉

 

实际使用IPNS


让我们通过IPNS发布我们的网站:


ipfs name publish QmYVd8qstdXtTd1quwv4nJen6XprykxQRLo67Jy7WyiLMB


       这个过程可能会要几分钟。之后您将会得到如下的输出结果:

Published to Qmb1VVr5xjpXHCTcVm3KF3i88GLFXSetjcxL7PQJRviXSy: /ipfs/QmYVd8qstdXtTd1quwv4nJen6XprykxQRLo67Jy7WyiLMB


现在您可以从这里得到最新的网站地址:https://gateway.pinata.cloud/ipns/Qmb1VVr5xjpXHCTcVm3KF3i88GLFXSetjcxL7PQJRviXSy


注意:IPNS会在大约12小时后忘记(系统存活时间)已发布的名称。您可以运行cron命令配置定时任务,以便在12小时内重新发布。


如果我想添加一个更新的CID,我将使用相同的命令:


ipfs name publish <my_new_CID>


你也可以检查当前CID链接到你的peerID:


ipfs name resolve Qmb1VVr5xjpXHCTcVm3KF3i88GLFXSetjcxL7PQJRviXSy


样操作将返回最新的CID。


为了增加灵活性,您还可以为不同的内容和/或背景使用不同的key(例如下面的键名是vasa_blog)。例如,我可以用一个key发布我的网站,用另一个key发布我的博客,用另一个key发布我的谈话视频。


ipfs key gen --type=rsa --size=2048 vasa_blog
ipfs name publish --key=vasa_blog <cid_to_my_blog>


 这解决了我们上面提到的一个问题(不可变链接的问题)。但是链接仍然很难看。为了制作链接,我们仍然需要使用DNS。还有其他一些系统更适合于内容寻址系统,比如CCN/NDN、XIA。但这需要升级互联网本身,如果没有大规模的需求,这真的很难保证。即使有很大的需求,IPv6还没有完全部署(-这没有给我任何希望看到NDN/CCN大规模部署在核心,没有首先建立使用内容地址网络。这意味着终端开发人员(web开发人员)必须能够使用内容寻址网络非常有效地移动大量数据(视频等),然后才能实现改善底层网络的大量需求。因此,正如我们所看到的,通过使IPFS对最终开发人员可用,我们也可以为这些体系结构创造需求。


言归正传,现在让我们使用DNS创建可读链接。


DNSLink使用DNS TXT将域名(如vaibhavsaini.com)映射到IPFS地址。因为可以编辑DNS记录,所以使用它们可以使域名始终指向IPFS中对象的最新版本(请记住,如果修改对象,IPFS对象的地址会更改)。但我们不希望每次更新网站时都更改TXT记录。因此,我们将添加一个ipns链接而不是ipfs链接。此外,由于DNSLink使用DNS记录,因此它生成的名称通常也易于键入和读取。


DNSLink地址看起来像IPNS地址,但它使用一个域名来代替散列的公钥:


/ipns/vaibhavsaini.com


就像普通的IPFS地址一样,它们可以包含到其他文件的链接:


/ipns/vaibhavsaini.com/assets/images


IPFS客户机或节点试图解析该地址时,它会为vaibhavsaini.com查找一条TXT记录,内容如下:


dnslink=/ipfs/<CID for your content here>

OR

dnslink=/ipns/<hash of public key>


例如,如果你查vaibhavsaini.com的DNS记录,你会看到它的DNSLink条目:

$ dig +noall +answer TXT vaibhavsaini.com

vaibhavsaini.com. 1 IN TXT "dnslink=/ipns/Qmb1VVr5xjpXHCTcVm3KF3i88GLFXSetjcxL7PQJRviXSy"


据此,得到本地址:


/ipns/vaibhavsaini.com/assets/images


然后会得到如下区块 :


/ipns/Qmb1VVr5xjpXHCTcVm3KF3i88GLFXSetjcxL7PQJRviXSy/assets/images


超级酷对吗?


到目前为止,我们将地址从一个复杂的hash简化为一个可读的名称。


但是,我们可以做得更好。


这个(上面的链接)链接仍然相当混乱,坦白地说,如果我们想让今天的Web2用户以最小的努力访问我分散的Web3内容,我们不希望他们必须处理网关和ipns/ipfs前缀,如果他们不需要的话。分散式web社区的一个主要感觉是,用户体验不应该发生太大的变化——转换应该是透明的,但是很容易——这就是分散式web将如何获胜的原因。理想情况下,我们希望得到这样的结果:

https://profile.vaibhavsaini.com


通过子域发布


因此,为了使我们的地址更具可读性,我们可以创建一条A记录,将我们的子域指向监听端口80的HTTP请求的IPFS对等点的IP地址(例如任何公共IPFS网关,或者您自己的网关)。但是等等,我们可以做得更好!


因为我们不想依赖于静态的IP地址,所以我们可以使用CNAME记录来指向网关的DNS记录。这样,如果IP地址改变了,我们仍然可以指向正确的位置。不幸的是,cnamerecord不允许其他记录(比如TXT),但是IPFS的优秀工作人员允许我们为_dnslink.your创建DNS TXT记录,IPFS将查找该域。


当您希望在不放弃对原始DNS域完全控制的情况下,将对DNSLink记录的自动设置或委托控制的安全性交给到第三方时,这也非常有用。


      我使用AWS Route53进行DNS设置;您可以使用任何提供者。


设置CNAME记录

深入理解IPFS(3/6):什么是行星命名系统(IPNS) 

设置_dnslink TXT记录:

深入理解IPFS(3/6):什么是行星命名系统(IPNS) 


这是它最终的样子:


深入理解IPFS(3/6):什么是行星命名系统(IPNS) 


!我们使用IPFS堆栈托管和解析内容,并提供一个地址使任何Web2用户都可以轻松使用该地址。


您可能会注意到地址栏上的“不安全”警告,这是因为我没有安装通配符证书;)


您可能会注意到,网站需要一些时间来解决。这是因为您的网站的内容只在一个节点上。如果你把你的网站固定在几个节点或其他节点上,然后去试图访问你的网站(这意味着你的内容很受欢迎),它会更快地解析:

这部分就讲到这里。感谢Carson Farmer、Mark Pors和Jonybang的文章[1,2,3]。感谢阅读;)


关于作者:


深入理解IPFS(3/6):什么是行星命名系统(IPNS) 


Vaibhav是TowardsBlockchain的联合创始人。麻省理工学院剑桥创新中心孵化启动者。他是高级区块链开发人员,曾参与多个区块链平台,包括以太坊,Quorum,EOS,Nano,Hashgraph,IOTA等。

本文来源于互联网:深入理解IPFS(3/6):什么是行星命名系统(IPNS)

本文由 Ipfs币 作者:ipfs币 发表,其版权均为 Ipfs币 所有,文章内容系作者个人观点,不代表 Ipfs币 对观点赞同或支持。如需转载,请注明文章来源。
43

发表评论