比特币命名系统

比特币名称系统(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 名称被组织成一个全局名称层级。该层级中与命名相关的有三层不同的层级:

  • 命名空间(Namespaces)。 它们是层级中的顶级名称。BNS 命名空间的类比是 DNS 的顶级域。现有的 BNS 命名空间包括 .id, .podcast,和 .helloworld. 所有其他名称恰好属于一个命名空间。任何人都可以创建命名空间,但为了使命名空间被持久化,必须 启动(launched) 以便任何人都可以在其中注册名称。命名空间不属于其创建者所有。

  • BNS 名称(BNS names)。 这些是其记录直接存储在区块链上的名称。这些名称的所有权和状态通过发送区块链交易来控制。示例名称包括 verified.podcastmuneeb.id. 任何人都可以创建 BNS 名称,只要包含它的命名空间已存在。

  • BNS 子域(BNS subdomains)。 这些是其记录存储在链下但集体锚定到区块链的名称。这些名称的所有权和状态存在于 P2P 网络数据中。虽然 BNS 子域由独立的私钥拥有,但 BNS 名称所有者必须广播其子域状态。示例子域包括 jude.personal.idpodsaveamerica.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 年花费了 40 BTC 来创建

命名空间(在交易 .id 5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b281 中)。 命名空间可以长达 1 到 19 个字符,由以下字符组成:).

a-z 子域(Subdomains), 0-9, -,和 _.

BNS 名称被强力拥有,因为其私钥所有者可以生成有效交易来更新其区域文件哈希和所有者。然而,这也带来了代价:名称所有者需要为底层区块链上的交易付费。此外,这种方法将 BNS 名称的注册和操作速率限制在底层区块链的交易带宽之内。

BNS 通过子域克服了这一点。一个

BNS 子域 是一种其状态和所有者存储在区块链外,但其存在和操作历史被锚定到区块链的 BNS 名称。像链上对应项一样,子域在全球范围内唯一、被强力拥有且对人类可读。BNS 为它们提供自己的名称状态和公钥。与链上名称不同,子域可以廉价创建和管理,因为它们以批量方式广播到 BNS 网络。单笔区块链交易最多可以发送 120 个子域操作。 这是通过将子域记录存储在 BNS 名称的区域文件中来实现的。链上名称所有者通过将子域操作编码为

TXT 记录写入 DNS 区域文件来广播子域操作。为了广播区域文件,名称所有者使用 NAME_UPDATE 交易设置新的区域文件哈希并复制该区域文件。这反过来复制了其包含的所有子域操作,并将这组子域操作锚定到一笔链上交易。BNS 节点的共识规则确保只有来自有效 交易的有效子域操作才会被存储。 交易设置新的区域文件哈希并复制该区域文件。这反过来复制了其包含的所有子域操作,并将这组子域操作锚定到一笔链上交易。BNS 节点的共识规则确保只有来自有效 例如,名称

曾经写入过区域文件哈希 verified.podcast 247121450ca0e9af45e85a82e61cd525cd7ba023 ,该哈希对应以下区域文件:$TTL 3600

此区域文件中的记录都编码了一个子域创建。例如, 记录写入 DNS 区域文件来广播子域操作。为了广播区域文件,名称所有者使用 1yeardaily.verified.podcast 解析为: "address": "1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH",

1yeardaily 记录写入 DNS 区域文件来广播子域操作。为了广播区域文件,名称所有者使用 的区域文件中的资源记录 verified.podcast.

子域生命周期

1

创建

子域创建操作由子域所有者创建并编码到链上名称所有者的区域文件中的一条 记录写入 DNS 区域文件来广播子域操作。为了广播区域文件,名称所有者使用 记录中。链上名称所有者通过发出一笔 交易设置新的区域文件哈希并复制该区域文件。这反过来复制了其包含的所有子域操作,并将这组子域操作锚定到一笔链上交易。BNS 节点的共识规则确保只有来自有效 交易来广播该区域文件,从而将子域创建操作锚定到链上。

2

更新

子域更新在链下完成,由子域所有者的私钥创建签名操作。任何链上名称所有者都可以将这些签名操作包含在其区域文件中并通过 交易设置新的区域文件哈希并复制该区域文件。这反过来复制了其包含的所有子域操作,并将这组子域操作锚定到一笔链上交易。BNS 节点的共识规则确保只有来自有效进行广播。操作按序列号排序,并要求有效签名,该签名将此操作与之前操作的公钥链接起来。

3

转移

要更改拥有子域的地址(公钥哈希),子域所有者对子域转移操作进行签名并请求链上名称所有者(通常是创建该子域的人)通过 交易设置新的区域文件哈希并复制该区域文件。这反过来复制了其包含的所有子域操作,并将这组子域操作锚定到一笔链上交易。BNS 节点的共识规则确保只有来自有效进行广播。用于广播的链上名称所有者的区域文件必须存在于 Atlas 网络中以证明不存在冲突操作。

序列和验证规则

  • 子域操作按序列号排序,从 0 开始。每个新操作必须包括:

    • 下一个序列号

    • 哈希为前一子域交易地址的公钥

    • 对应私钥对整个子域操作的签名

  • 如果两个正确签名但冲突的操作具有相同的序列号,则接受区块链历史上较早的那个。无效操作将被忽略。

子域创建与管理规则

  • 子域创建交易只能由与其后缀共享的链上名称的所有者处理(例如,只有 res_publica.id 的所有者才能广播 *.res_publica.id).

  • 的创建)。

  • 子域转移交易只能由创建它的链上名称的所有者广播。

  • 要发送子域创建或子域转移,链上名称所有者的所有区域文件必须存在于 Atlas 网络中。这允许证明不存在冲突操作。

子域更新可以由任何链上名称所有者广播,但子域所有者需要找到一个合作的链上名称所有者将其包含并广播。

要创建子域,子域所有者生成创建操作并将其交给链上名称所有者。创建后,子域所有者可以使用任何链上名称所有者通过提供打包到区域文件中的签名操作来广播更新。

子域注册商 因为子域名称成本低廉,开发者可能为其应用运行子域注册商。例如,名称 personal.id

用于注册用户名而无需用户花费比特币。

有一个参考实现可用:https://github.com/stacks-network/subdomain-registrar。用户仍然拥有他们的子域名;注册商帮助开发者广播子域操作。

BNS 与 DID 标准

BNS 名称符合新兴的去中心化身份基金会(DIF)关于去中心化标识符(DID)的协议规范:http://identity.foundation

其中:

  • did:stack:v0:{address}-{index} {address}

  • 是一个链上公钥哈希(例如比特币地址)。 {index} 指的是该地址创建的第 个名称。

示例:

  • 因为子域名称成本低廉,开发者可能为其应用运行子域注册商。例如,名称did:stack:v0:1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV-0 (该地址创建的第一个名称)

  • jude.iddid:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-1 (该地址在此之前已创建过一个名称)

目的:DID 为公钥提供一个永恒的标识符。公钥可能会改变,但 DID 不会改变。

要使 DID 可解析,名称必须满足以下所有条件:

  • 该名称必须存在

  • 该名称的区域文件哈希必须是格式良好的 DNS 区域文件的哈希

  • DNS 区域文件必须存在于 Stacks 节点的数据中

  • DNS 区域文件必须包含一条 URI 资源记录,该记录指向一个已签名的 JSON Web Token

  • 签署该 JSON Web Token 的公钥(并随其包含)必须哈希为拥有该名称的地址

并非所有名称都会有可解析为公钥的 DID。由标准工具创建的名称将具有可解析的 DID。

一个 RESTful API 正在开发中。

子域的 DID 编码

BNS 中的每个名称和子域都有一个 DID。编码方式不同,以便软件可以确定应走哪条代码路径。

  • 对于链上 BNS 名称, did:stack:v0:{address}-{index} 与拥有该名称的比特币地址相同。目前同时支持版本字节 0 和版本字节 5 的地址(以 13开头,表示 p2pkh p2sh

  • 地址)。 did:stack:v0:{address}-{index} 对于链下的 BNS 子域, S对于由单个私钥拥有的子域,DID 地址具有版本字节 63;对于由 m-of-n 私钥集合拥有的子域,版本字节为 50。也就是说,子域 DID 地址分别以M

停机问题 是一个链上公钥哈希(例如比特币地址)。 开头。 是一个链上公钥哈希(例如比特币地址)。 子域的 DID 的字段与 BNS 名称的 DID 字段是不同的,即使相同地址创建了名称和子域。示例:

  • 名称 abcdefgh123456.iddid:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-0 (该地址创建的第一个名称)

  • 子域 jude.statism.id 由相同地址创建 → did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0

注意:地址 SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i 编码的公钥哈希与 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg相同——区别在于 base58check 的版本字节(63 与 0)。

最后更新于

这有帮助吗?