比特币名称系统

比特币命名系统 (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.podcast和muneeb.id。只要包含它的命名空间已经存在,任何人都可以创建一个 BNS 名称。BNS 子域(BNS subdomains)。 这些是其记录存储在链下但集体锚定到区块链的名称。这些名称的所有权和状态存在于 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, -,以及 _.
子域(Subdomains)
BNS 名称具有强所有权,因为其私钥的所有者可以生成有效交易来更新其区域文件哈希和所有者。然而,这种做法的代价是要求名称所有者为区块链上的底层交易付费。此外,这种方法将 BNS 名称注册和操作的速率限制在底层区块链的交易带宽之内。
BNS 通过子域来克服这一点。一个 BNS 子域 是一种其状态和所有者存储在区块链之外,但其存在和操作历史锚定到区块链的 BNS 名称。像链上对应物一样,子域在全局范围内唯一、被强烈拥有并且对人类可读。BNS 为它们提供独立的名称状态和公钥。不同于链上名称的是,子域可以廉价地创建和管理,因为它们被成批广播到 BNS 网络。单个区块链交易最多可以发送 120 个子域操作。
这是通过将子域记录存储在 BNS 名称的区域文件中实现的。链上名称所有者通过将子域操作编码为 TXT 记录放入 DNS 区域文件中来广播子域操作。为了广播该区域文件,名称所有者使用一笔 NAME_UPDATE 交易设置新的区域文件哈希并复制该区域文件。这反过来会复制它包含的所有子域操作,并将这组子域操作锚定到一笔链上交易。BNS 节点的共识规则确保只有来自有效 NAME_UPDATE 交易的有效子域操作才会被存储。
例如,名称 verified.podcast 曾经写入过区域文件哈希 247121450ca0e9af45e85a82e61cd525cd7ba023,这是以下区域文件的哈希:
每一条 TXT 该区域文件中的记录都编码了一个子域创建。例如, 1yeardaily.verified.podcast 解析为:
这些信息是从 1yeardaily TXT 在 verified.podcast.
的区域文件中的资源记录提取的
子域生命周期
创建 TXT 子域创建操作由子域所有者创建并编码到链上名称所有者的区域文件中的一条 NAME_UPDATE 记录中。链上名称所有者通过发起一笔
交易来广播该区域文件,从而将子域创建锚定到链上。
更新 NAME_UPDATE子域更新在链下完成,通过使用子域所有者的私钥创建签名操作。任何链上名称所有者都可以将这些签名操作包含在他们的区域文件中并通过
进行广播。操作按照序列号排序,并且需要一个有效签名,该签名链接到前一个操作的公钥。
转移 NAME_UPDATE要更改拥有子域的地址(公钥哈希),子域所有者签署一个子域转移操作,并请求一个链上名称所有者(通常是创建该子域的名称所有者)通过
进行广播。广播的链上名称所有者的区域文件必须存在于 Atlas 网络中以证明不存在冲突操作。
序列和验证规则
子域操作按序列号排序,从 0 开始。每个新操作必须包含:
下一个序列号
哈希为前一次子域交易地址的公钥
对应私钥对整个子域操作的签名
如果两个正确签名但互相冲突的操作具有相同的序列号,则接受区块链历史中更早的那个。无效操作将被忽略。
子域创建与管理规则
子域创建交易只能由与其后缀共享的链上名称的所有者处理(例如,只有res_publica.id的所有者才能为).*.res_publica.id
广播创建交易)。
子域转移交易只能由创建它的链上名称的所有者广播。
要发送子域创建或子域转移,链上名称所有者的所有区域文件必须存在于 Atlas 网络中。这可以用于证明不存在冲突操作。
子域更新可以由任何链上名称所有者广播,但子域所有者需要找到一个合作的链上名称所有者将其包含并广播。
要创建子域,子域所有者生成创建操作并将其交给链上名称所有者。创建后,子域所有者可以使用任何链上名称所有者来广播更新,方法是提供打包到区域文件中的签名操作。 子域注册机构 由于子域名称成本低廉,开发者可以为其应用运行子域注册机构。例如,名称
personal.id
被用来注册用户名,而无需用户花费比特币。
一个参考实现可用:https://github.com/stacks-network/subdomain-registrar。用户仍然拥有他们的子域名称;注册机构帮助开发者广播子域操作。
BNS 与 DID 标准
BNS 中的每个名称都有一个关联的 DID。BNS 的 DID 格式为:
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 令牌
签署该 JSON Web 令牌 的公钥(并包含在令牌中)必须哈希为拥有该名称的地址
并非所有名称都会具有可解析到公钥的 DID。由标准工具创建的名称将具有可解析的 DID。
一个 RESTful API 正在开发中。
子域的 DID 编码
BNS 中的每个名称和子域都有一个 DID。编码不同以便软件可以确定走哪条代码路径。
did:stack:v0:{address}-{index}对于链上 BNS 名称,1与拥有该名称的比特币地址相同。目前同时支持版本字节为 0 和版本字节为 5 的地址(以3或开头的地址,分别表示和p2pkh或p2sh
did:stack:v0:{address}-{index}地址)。对于链下的 BNS 子域,与拥有该名称的比特币地址相同。目前同时支持版本字节为 0 和版本字节为 5 的地址(以对于由单个私钥拥有的子域,版本字节为 63;对于由 m-of-n 私钥集合拥有的子域,版本字节为 50。也就是说,子域 DID 地址分别以S
或 {address} M {address} 开头。
子域的
字段与 BNS 名称的示例:字段是不同的,即使相同的地址创建了名称和子域。示例:did:stack:v0:1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV-0名称
abcdefgh123456.iddid:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-0由同一地址创建的子域
jude.statism.id → did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0 注意:地址 SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i与地址(即)编码相同的公钥哈希,差别在于 base58check 的版本字节(63 与 0)。
最后更新于
这有帮助吗?