BNSv1(旧版)
本页内容与旧版 BNS v1 有关。
比特币名称系统(BNS)是一种网络系统,可将 Stacks 用户名绑定到链下状态,而无需依赖任何中心化控制点。
Stacks V1 区块链通过一阶名称操作实现 BNS。在 Stacks V2 中,BNS 则通过创世区块期间加载的智能合约来实现。
BNS 中的名称具有三个属性:
名称在全局范围内唯一。 该协议不允许名称冲突,所有行为正常的节点都会将给定名称解析为相同状态。
名称对人类有意义。 每个名称都由其创建者选择。
名称具有强所有权。 只有名称的所有者才能更改其解析到的状态。具体而言,一个名称由一个或多个 ECDSA 私钥拥有。
Stacks 区块链确保每个节点的 BNS 视图与世界上所有其他节点保持同步,因此在一个节点上的查询结果会与其他节点相同。Stacks 区块链节点允许名称所有者将最多 40Kb 的链下状态绑定到其名称上,这些状态将通过 P2P 网络复制到所有其他 Stacks 区块链节点。
对开发者来说,最大的影响是,在 BNS 中,读取名称状态快速且便宜,但写入名称状态缓慢且昂贵。这是因为注册和修改名称需要向底层区块链发送一个或多个交易,而 BNS 节点在这些交易获得足够确认之前不会处理它们。用户和开发者需要获取并花费所需的加密货币(STX)来发送 BNS 交易。
名称系统背后的动机
我们在日常生活中依赖名称系统,而且它们在许多不同的应用中发挥关键作用。例如,当你在社交媒体上查找朋友时,你是在使用该平台的名称系统将他们的名字解析为其个人资料。当你查找一个网站时,你是在使用域名服务将主机名解析为其主机的 IP 地址。当你检出一个 Git 分支时,你是在使用 Git 客户端将分支名解析为提交哈希。当你在密钥服务器上查找某人的 PGP 密钥时,你是在将其密钥 ID 解析为其公钥。
我们希望名称具备哪些属性?在 BNS 中,名称是全局唯一的、对人类有意义的,并且具有强所有权。然而,如果你看看这些例子,就会发现它们每一个只保证其中两个属性。这限制了它们的实用性。
在 DNS 和社交媒体中,名称是全局唯一且人类可读的,但并不具有强所有权。系统运营者对每个名称最终解析到什么拥有最终决定权。
问题:客户端必须信任系统会对给定名称应解析到什么做出正确选择。这包括相信除了系统管理员之外,没有人能够做出这些更改。
在 Git 中,分支名称对人类有意义且具有强所有权,但并非全局唯一。两个不同的 Git 节点可能会将同一个分支名称解析为不同且互不相关的仓库状态。
问题:由于名称可能指向相互冲突的状态,开发者必须找出其他机制来消除歧义。
在 PGP 中,名称就是密钥 ID。它们是全局唯一且由密码学方式拥有的,但并非人类可读。PGP 密钥 ID 源自它们所引用的密钥。
问题:这些名称对大多数用户来说很难记住,因为它们不携带与其在系统中用途相关的语义信息。
BNS 名称同时具备这三个属性,并且不存在这些问题。这使其成为构建各种网络应用程序的强大工具。借助 BNS,我们可以做到以下这些以及更多:
构建主机名无法被劫持的域名服务。
构建用户名无法被钓鱼者窃取的社交媒体平台。
构建仓库分支不会冲突的版本控制系统。
构建用户可以轻松发现并记住彼此密钥的公钥基础设施。
BNS 的组织结构
BNS 名称被组织在一个全局名称层级结构中。这个层级中与命名相关的有三种不同层次:
命名空间。 这些是层级中的顶级名称。BNS 命名空间可类比为 DNS 顶级域。现有的 BNS 命名空间包括
.id,.podcast,以及.helloworld。所有其他名称都且仅属于一个命名空间。任何人都可以创建命名空间,但为了让该命名空间被持久保存,它必须被 启动 ,以便任何人都能在其中注册名称。命名空间不归其创建者所有。BNS 名称。 这些是其记录直接存储在区块链上的名称。这些名称的所有权和状态通过发送区块链交易来控制。示例名称包括
verified.podcast和muneeb.id。只要包含它的命名空间已经存在,任何人都可以创建一个 BNS 名称。BNS 子域。 这些是其记录存储在链下、但整体锚定到区块链上的名称。这些名称的所有权和状态存在于 P2P 网络数据中。虽然 BNS 子域由独立的私钥拥有,但 BNS 名称所有者必须广播其子域状态。示例子域包括
jude.personal.id和podsaveamerica.verified.podcast。与 BNS 命名空间和名称不同,BNS 子域的状态是 不会 区块链共识规则的一部分。
下表总结了这些名称对象之间相似性与差异性的功能对比矩阵:
功能
命名空间
BNS 名称
BNS 子域
全局唯一
X
X
X
对人类有意义
X
X
X
由私钥拥有
X
X
任何人都可创建
X
X
[1]
所有者可更新
X
[1]
状态托管在链上
X
X
状态托管在链下
X
X
行为由共识规则控制
X
X
可能有过期日期
X
[1] 需要 BNS 名称所有者配合广播其交易
命名空间
命名空间是 BNS 中的顶级名称对象。它们控制其中名称的一些属性:
注册成本有多高
在需要续期之前可持续多久
由谁(如果有的话)接收名称注册费用
谁被允许用初始名称为该命名空间预置内容
在撰写本文时,目前规模最大的 BNS 命名空间是 .id 命名空间。 .id 命名空间中的名称旨在用于解析用户身份。 .id 中的短名称比长名称更贵,并且必须由其所有者每两年续期一次。名称注册费用不会支付给任何特定对象——而是被发送到一个“黑洞”中,使其无法再被花费(目的是阻止 ID 囤积者)。
与 DNS 不同,任何人都可以创建命名空间并设置其属性。命名空间按先到先得原则创建,一旦创建,将永久存在。
然而,创建命名空间并不是免费的。命名空间创建者必须销毁加密货币才能这样做。命名空间越短,必须销毁的加密货币就越多(也就是说,短命名空间比长命名空间更有价值)。例如,Blockstack PBC 在 2015 年创建该 .id 命名空间时花费了 40 BTC(在交易 5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b281).
命名空间长度可以在 1 到 19 个字符之间,并由以下字符组成 a-z, 0-9, -,以及 _.
子域
BNS 名称之所以具有强所有权,是因为其私钥的持有者可以生成有效交易来更新其 zone 文件哈希和所有者。不过,这样做的代价是名称所有者必须为区块链中的底层交易付费。此外,这种方法将 BNS 名称注册和操作的速率限制在底层区块链的交易带宽之内。
BNS 通过子域克服了这一点。一个 BNS 子域 是一种 BNS 名称,其状态和所有者存储在区块链之外,但其存在和操作历史锚定在区块链上。与其链上对应物一样,子域是全局唯一的、具有强所有权且人类可读。BNS 为它们提供各自独立的名称状态和公钥。与链上名称不同,子域可以低成本地创建和管理,因为它们是按批次广播到 BNS 网络中的。单笔区块链交易最多可以发送 120 个子域操作。
这是通过将子域记录存储在 BNS 名称的 zone 文件中实现的。链上名称所有者通过将子域操作编码为 DNS zone 文件中的 TXT 记录来进行广播。为了广播该 zone 文件,名称所有者使用一笔 NAME_UPDATE 交易设置新的 zone 文件哈希并复制该 zone 文件。反过来,这会复制其中包含的所有子域操作,并将这组子域操作锚定到一笔链上交易。BNS 节点的共识规则确保只有来自有效 NAME_UPDATE 交易的有效子域操作才会被存储。
例如,名称 verified.podcast 曾写入 zone 文件哈希 247121450ca0e9af45e85a82e61cd525cd7ba023,这是以下 zone 文件的哈希:
每条 TXT 该 zone 文件中的记录都编码了一个子域创建操作。例如, 1yeardaily.verified.podcast 解析为:
这些信息是从 1yeardaily TXT 的 zone 文件中的资源记录提取出来的,用于 verified.podcast.
子域生命周期
创建
子域创建操作由子域所有者创建,并编码到链上名称所有者 zone 文件中的一条 TXT 记录中。链上名称所有者通过发出一笔 NAME_UPDATE 交易来广播该 zone 文件,从而将该子域创建锚定到链上。
更新
子域更新通过使用子域所有者私钥创建已签名操作在链下完成。任何链上名称所有者都可以将这些已签名操作包含到其 zone 文件中,并通过 NAME_UPDATE进行广播。操作按序列号排序,并要求具有有效签名,该签名关联到前一个操作的公钥。
转移
要更改拥有子域的地址(公钥哈希),子域所有者需签署一个子域转移操作,并请求一位链上名称所有者(通常是创建该子域的人)通过 NAME_UPDATE进行广播。进行广播的链上名称所有者的 zone 文件必须存在于 Atlas 网络中,以证明不存在冲突操作。
序列和验证规则
子域操作按序列号排序,从 0 开始。每个新操作都必须包含:
下一个序列号
其哈希值等于前一笔子域交易地址的公钥
对应私钥对整个子域操作的签名
如果两个签名正确但相互冲突的操作具有相同序列号,则区块链历史中更早的那个会被接受。无效操作会被忽略。
子域创建和管理规则
子域创建交易只能由与其后缀共享同一链上名称的所有者处理(例如,只有
res_publica.id的所有者才能为*.res_publica.id).广播创建操作。
要发送子域创建或子域转移,链上名称所有者的所有 zone 文件都必须存在于 Atlas 网络中。这使得证明不存在冲突操作成为可能。
子域更新可以由任何链上名称所有者广播,但子域所有者需要找到愿意合作的链上名称所有者来包含并广播它。
要创建子域,子域所有者生成创建操作并将其交给链上名称所有者。创建完成后,子域所有者可以通过提供打包进 zone 文件中的已签名操作,使用任何链上名称所有者来广播更新。
子域注册器
由于子域名称成本低廉,开发者可以为其应用运行子域注册器。例如,名称 personal.id 被用于注册用户名,而无需用户花费比特币。
有一个参考实现可用:https://github.com/stacks-network/subdomain-registrar。用户仍然拥有其子域名称;注册器帮助开发者广播子域操作。
BNS 与 DID 标准
BNS 名称符合新兴的去中心化身份基金会(DIF)关于去中心化标识符(DID)的协议规范:http://identity.foundation
BNS 中的每个名称都有一个关联的 DID。BNS 的 DID 格式为:
其中:
{address}是链上的公钥哈希(例如比特币地址)。{index}指的是第 n 个由该地址创建的名称。
示例:
personal.id→did:stack:v0:1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV-0(由该地址创建的第一个名称)jude.id→did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-1(该地址在此之前已经创建过一个名称)
用途:DID 为公钥提供一个永久标识符。公钥可以变化,但 DID 不会。
要让 DID 可被解析,对于某个名称,以下条件必须全部成立:
该名称必须存在
该名称的 zone 文件哈希必须是格式良好的 DNS zone 文件的哈希
该 DNS zone 文件必须存在于 Stacks 节点的数据中
该 DNS zone 文件必须包含一个
URI资源记录,其指向一个已签名的 JSON Web Token为该 JSON Web Token 签名的公钥(并且随其一起包含)必须哈希到拥有该名称的地址
并非所有名称都会有可解析为公钥的 DID。通过标准工具创建的名称会有这样的 DID。
一个 RESTful API 正在开发中。
子域的 DID 编码
BNS 中的每个名称和子域都有一个 DID。编码方式不同,以便软件能够确定应采用哪条代码路径。
对于链上 BNS 名称,
{address}与拥有该名称的比特币地址相同。目前,同时支持版本字节 0 和版本字节 5 的地址(以1或3开头的地址,分别表示p2pkh和p2sh地址)。对于链下 BNS 子域,
{address}对于由单个私钥拥有的子域,其版本字节为 63;对于由 m-of-n 私钥集合拥有的子域,其版本字节为 50。也就是说,子域 DID 地址分别以S或M开头。
这个 {index} 子域 DID 的 {index} 字段不同于 BNS 名称 DID 的
字段,即使同一地址创建了名称和子域也是如此。示例:
abcdefgh123456.id→did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-0(由该地址创建的第一个名称)子域
jude.statism.id由同一地址创建 →did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0
注意:地址 SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i 编码的是与 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg相同的公钥哈希——区别在于 base58check 版本字节(63 对 0)。
最后更新于
这有帮助吗?