构建以太坊 dApp 的完整指南:前端和后端

面向全栈开发人员的端到端 dApp 教程

目录

面向全栈开发人员的端到端 dApp 教程

什么是 DApp?

后端(智能合约)

前端(Web 用户界面)

数据存储

IPFS

一群

去中心化消息通信协议

拍卖 DApp

拍卖 DApp:后端智能合约

DApp 治理

拍卖 DApp:前端用户界面

进一步分散拍卖 DApp

将拍卖 DApp 存储在 Swarm 上

准备蜂群

将文件上传到 Swarm

以太坊名称服务 (ENS)

ENS 规范

底层:名称所有者和解析者

中间层:.eth 节点

顶层:事迹

注册名称

管理您的 ENS 名称

ENS 解析器

将名称解析为 Swarm 哈希(内容)

从 App 到 DApp

结论


什么是 DApp?

DApp 是一种大部分或完全去中心化的应用程序。

考虑可能分散的应用程序的所有可能方面:

  • 后端软件(应用程序逻辑)
  • 前端软件
  • 数据存储
  • 消息通讯
  • 名称解析

这些中的每一个都可以有些集中或有些分散。例如,前端可以开发为在集中式服务器上运行的 Web 应用程序,或作为在您的设备上运行的移动应用程序。后端和存储可以在私有服务器和专有数据库上,或者您可以使用智能合约和 P2P 存储。

创建 DApp 有很多典型的中心化架构无法提供的优势:

弹性:由于业务逻辑由智能合约控制,DApp 后端将在区块链平台上完全分布和管理。与部署在集中式服务器上的应用程序不同,DApp 不会停机,只要平台仍在运行,它就会继续可用。

透明度:DApp 的链上特性允许每个人检查代码并对其功能更加确定。与 DApp 的任何交互都将永久存储在区块链中。

审查阻力:只要用户有权访问以太坊节点(必要时运行一个),用户将始终能够与 DApp 进行交互,而不受任何集中控制的干扰。一旦代码部署在网络上,任何服务提供商,甚至智能合约的所有者都无法更改代码。

在今天的以太坊生态系统中,很少有真正去中心化的应用程序——大多数仍然依赖中心化服务和服务器来进行部分操作。未来,我们期望任何 DApp 的每个部分都可以以完全去中心化的方式运行。

后端(智能合约)

在 DApp 中,智能合约用于存储业务逻辑(程序代码)和应用程序的相关状态。您可以考虑用智能合约替换常规应用程序中的服务器端(也称为“后端”)组件。当然,这是过于简单化了。主要区别之一是在智能合约中执行的任何计算都非常昂贵,因此应尽可能少。因此,确定应用程序的哪些方面需要可信和分散的执行平台非常重要。

以太坊智能合约允许您构建架构,其中智能合约网络在彼此之间调用和传递数据,随时读取和写入自己的状态变量,其复杂性仅受区块气体限制的限制。部署智能合约后,您的业务逻辑很可能在未来被许多其他开发人员使用。

智能合约架构设计的一个主要考虑因素是智能合约一旦部署就无法更改代码。如果使用可访问的 SELF-DESTRUCT 操作码对其进行编程,则可以将其删除,但除了完全删除之外,不能以任何方式更改该代码。

智能合约架构设计的第二个主要考虑因素是 DApp 大小。一个非常大的单体智能合约可能会花费大量的气体来部署和使用。因此,一些应用程序可能会选择链下计算和外部数据源。但是请记住,让 DApp 的核心业务逻辑依赖于外部数据(例如,来自中央服务器)意味着您的用户必须信任这些外部资源。

前端(Web 用户界面)

与需要开发人员了解 EVM 和 Solidity 等新语言的 dApp 的业务逻辑不同,dApp 的客户端界面可以使用标准的 Web 技术(HTML、CSS、JavaScript 等)。这允许传统的 Web 开发人员使用熟悉的工具、库和框架。与以太坊的交互,例如签名消息、发送交易和管理密钥,通常是通过 Web 浏览器,通过 MetaMask 等扩展程序进行的。

虽然也可以创建移动 dApp,但目前帮助创建移动 dApp 前端的资源很少,主要是由于缺乏可以作为具有密钥管理功能的轻客户端的移动客户端。

前端通常通过 web3.js JavaScript 库链接到以太坊,该库与前端资源捆绑在一起,并由 Web 服务器提供给浏览器。

数据存储

由于高昂的 gas 成本和当前较低的区块 gas 限制,智能合约不太适合存储或处理大量数据。因此,大多数 DApp 使用链下数据存储服务,这意味着它们将大量数据从以太坊链上存储在数据存储平台上。该数据存储平台可以是中心化的(例如,典型的云数据库),也可以是去中心化的,存储在 P2P 平台(如 IPFS)或以太坊自己的 Swarm 平台上。

分散式 P2P 存储非常适合存储和分发大型静态资产,例如图像、视频以及应用程序前端 Web 界面的资源(HTML、CSS、JavaScript 等)。接下来,我们将看看其中的一些选项。

IPFS

星际文件系统 (IPFS) 是一种分散的内容可寻址存储系统,它在 P2P 网络中的对等点之间分配存储的对象。“内容可寻址”意味着每个内容(文件)都经过哈希处理,并且哈希用于标识该文件。然后,您可以通过其哈希请求从任何 IPFS 节点检索任何文件。

IPFS 旨在取代 HTTP 作为交付 Web 应用程序的首选协议。文件存储在 IPFS 上,并且可以从任何 IPFS 节点检索,而不是将 Web 应用程序存储在单个服务器上。

有关 IPFS 的更多信息,请访问https://ipfs.io

一群

Swarm 是另一种内容可寻址的 P2P 存储系统,类似于 IPFS。Swarm 由以太坊基金会创建,作为 Go-Ethereum 工具套件的一部分。与 IPFS 一样,它允许您存储由 Swarm 节点传播和复制的文件。您可以通过哈希引用任何 Swarm 文件来访问它。Swarm 允许您从分散的 P2P 系统而不是中央 Web 服务器访问网站。

Swarm 的主页本身存储在 Swarm 上,可以在您的 Swarm 节点或网关上访问:https ://swarm-gateways.net/bzz:/theswarm.eth/ 。

去中心化消息通信协议

任何应用程序的另一个主要组件是进程间通信。这意味着能够在应用程序之间、应用程序的不同实例之间或应用程序的用户之间交换消息。传统上,这是通过依赖集中式服务器来实现的。然而,基于服务器的协议有多种去中心化的替代方案,通过 P2P 网络提供消息传递。DApps最著名的 P2P 消息传递协议是Whisper,它是以太坊基金会 Go-Ethereum 工具套件的一部分。

可以分散的应用程序的最后一个方面是名称解析。我们将在本章后面仔细研究以太坊的名称服务;不过,现在让我们深入研究一个示例。

拍卖 DApp

拍卖 DApp 允许用户注册“契约”代币,它代表一些独特的资产,例如房屋、汽车、商标等。一旦注册了代币,代币的所有权就会转移到拍卖会DApp,允许它上市出售。拍卖 DApp 列出了每个注册的代币,允许其他用户出价。在每次拍卖期间,用户可以加入专门为该拍卖创建的聊天室。拍卖完成后,契约代币所有权将转移给拍卖的获胜者。

整个拍卖过程如下图所示

我们拍卖 DApp 的主要组件是:

  • 实现 ERC721 不可替代“契约”令牌的智能合约(DeedRepository)
  • 实施拍卖 ( AuctionRepository) 以出售契约的智能合约
  • 使用 Vue/Vuetify JavaScript 框架的 Web 前端
  • 用于连接以太坊链的 web3.js 库(通过 MetaMask 或其他客户端)
  • 一个 Swarm 客户端,用于存储图像等资源
  • Whisper 客户端,为所有参与者创建每次拍卖的聊天室

 

您可以在此处找到拍卖 dApp 的源代码。

拍卖 DApp:后端智能合约

我们的拍卖 DApp 示例由两个智能合约支持,我们需要在以太坊区块链上部署它们以支持应用程序:AuctionRepository 和 DeedRepository。

让我们从DeedRepository.sol: An ERC721 deed token for use in auction中显示的 DeedRepository 开始。该合约是与 ERC721 兼容的不可替代代币。

示例 1 DeedRepository.sol.:用于拍卖的 ERC721 契约代币

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">链接:code/auction_dapp/backend/contracts/DeedRepository.sol[]</span></span></span>

如您所见,该DeedRepository合约是 ERC721 兼容代币的简单实现。

我们的拍卖 DApp 使用DeedRepository合约为每次拍卖发行和跟踪代币。拍卖本身是由 AuctionRepository 合约安排的。该合约太长,无法完整包含在此处,但是AuctionRepository.sol: 主要的 Auction DApp 智能合约显示了合约的主要定义和数据结构。

示例 2 AuctionRepository.sol.:主 Auction DApp 智能合约

AuctionRepository合约通过以下功能管理所有拍卖:

您可以使用本书存储库中的 Truffle 将这些合约部署到您选择的以太坊区块链(例如 Ropsten):

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">$ cd code/auction_dapp/backend 
$ truffle init 
$ truffle compile 
$ truffle migrate --network ropsten</span></span></span>

DApp 治理

如果您通读 Auction dApp 的两个智能合约,您会注意到一些重要的事情:没有对 dApp 具有特殊权限的特殊帐户或角色。每个拍卖都有一个拥有一些特殊能力的所有者,但拍卖 dApp 本身没有特权用户。

这是一个深思熟虑的选择,目的是分散 dApp 的治理并在部署后放弃任何控制。相比之下,一些 dApp 拥有一个或多个具有特殊能力的特权帐户,例如能够终止 DApp 合约、覆盖或更改其配置或“否决”某些操作的能力。通常,在 dApp 中引入这些治理功能是为了避免由于错误而可能出现的未知问题。

治理问题是一个特别难以解决的问题,因为它是一把双刃剑。一方面,特权账户是危险的;如果受到破坏,他们可以破坏 DApp 的安全性。另一方面,没有任何特权帐户,如果发现错误,则没有恢复选项。我们已经在以太坊 DApp 中看到了这两种风险。在 The DAO 和以太坊分叉历史的案例中,有一些特权账户被称为“策展人”,但他们的能力非常有限。这些账户无法覆盖 DAO 攻击者提取的资金。在最近的一个案例中,去中心化交易所 Bancor 遭遇了大规模盗窃,因为一个特权管理账户被盗。事实证明,Bancor 并不像最初假设的那样去中心化。

在构建 DApp 时,您必须决定是否要让智能合约真正独立,启动它们然后无法控制,或者创建特权帐户并冒着被盗用的风险。任何一种选择都有风险,但从长远来看,真正的 DApp 不能对特权账户进行专门的访问——这不是去中心化的。

拍卖 DApp:前端用户界面

部署 Auction DApp 的合约后,您可以使用自己喜欢的 JavaScript 控制台和 web3.js 或其他 web3 库与它们进行交互。但是,大多数用户需要一个易于使用的界面。我们的拍卖 DApp 用户界面是使用 Google 的 Vue2/Vuetify JavaScript 框架构建的。

您可以在repo的 code/auction_dapp/frontend 文件夹中找到用户界面代码。该目录具有以下结构和内容:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">前端/ 
|-- 构建
| |-- 构建.js 
| |-- 检查版本.js 
| |-- 标志.png 
| |-- utils.js 
| |-- vue-loader.conf.js 
| |-- webpack.base.conf.js 
| |-- webpack.dev.conf.js 
| `-- webpack.prod.conf.js 
|-- 配置
| |-- dev.env.js 
| |-- 索引.js 
| `-- prod.env.js 
|-- index.html 
|-- package.json 
|-- package-lock.json 
|-- README.md 
|-- src 
| |-- 应用.vue 
| |-- 组件
| | |-- 拍卖.vue 
| | `-- 主页.vue 
| |-- 配置.js 
| |-- 合同
| | |-- AuctionRepository.json 
| | `-- DeedRepository.json
| |-- main.js 
| |-- 型号
| | |-- AuctionRepository.js 
| | |-- 聊天室.js 
| | `-- DeedRepository.js 
| `-- 路由器
| `-- index.js</span></span></span>

部署合约后,编辑前端配置frontend/src/config.js 并输入已部署的DeedRepositoryAuctionRepository 合约的地址。前端应用程序还需要访问提供 JSON-RPC 和 WebSockets 接口的以太坊节点。配置好前端后,使用本地计算机上的 Web 服务器启动它:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">$ npm 安装
$ npm 运行开发</span></span></span>

Auction dApp 前端将启动,并可通过任何网络浏览器在http://localhost:8080访问。

如果一切顺利,您应该会看到 Auction DApp 用户界面中显示的屏幕,该屏幕说明了在 Web 浏览器中运行的 Auction dApp。

前端

进一步分散拍卖 DApp

我们的 dApp 已经非常分散,但我们可以改进。

AuctionRepository合约独立运作,不受任何监督,对任何人开放。一旦部署它就无法停止,也无法控制任何拍卖。每个拍卖都有一个单独的聊天室,任何人都可以在没有审查或身份证明的情况下就拍卖进行交流。各种拍卖资产,例如描述和相关图像,存储在 Swarm 上,使其难以审查或阻止。

任何人都可以通过手动构建事务或在本地机器上运行 Vue 前端来与 dApp 交互。dApp 代码本身是开源的,并在公共存储库上协作开发。

我们可以做两件事来使这个 dApp 去中心化和有弹性:

  • 将所有应用程序代码存储在 Swarm 或 IPFS 上。
  • 使用以太坊名称服务通过引用名称来访问 dApp。

我们将在下一节探讨第一个选项,我们将在以太坊名称服务 (ENS) 中深入研究第二个选项。

将拍卖 DApp 存储在 Swarm 上

我们在本章前面介绍了 Swarm 中的 Swarm。我们的拍卖 dApp 已经使用 Swarm 来存储每次拍卖的图标图像。这是一个比试图在以太坊上存储数据更有效的解决方案,后者很昂贵。与将这些图像存储在网络服务器或文件服务器等集中式服务中相比,它也更具弹性。

但我们可以更进一步。我们可以将 dApp 本身的整个前端存储在 Swarm 中,并直接从 Swarm 节点运行它,而不是运行 Web 服务器。

准备蜂群

首先,您需要安装 Swarm 并初始化您的 Swarm 节点。Swarm 是以太坊基金会的 Go-Ethereum 工具套件的一部分。请参阅 [ ] 中有关安装 Go-Ethereum 的说明go_ethereum_geth,或者要安装 Swarm 二进制版本,请按照Swarm 文档中的说明进行操作。

安装 Swarm 后,您可以使用 version 命令运行它来检查它是否正常工作:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">$ swarm version
版本:0.3 
Git 提交:37685930d953bcbe023f9bc65b135a8d8b8f1488 
Go 版本:go1.10.1
操作系统:linux</span></span></span>

要开始运行 Swarm,您必须告诉它如何连接到 Geth 实例,以访问 JSON-RPC API。按照入门指南中的说明开始。

当你启动 Swarm 时,你应该会看到如下内容:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">最大对等点数 ETH=25 LES=0 总计=25
启动对等节点实例=swarm/v0.3.1-225171a4/linux...
连接到 ENS API url=http://127.0.0.1:8545 
swarm[ 5955]:[189B blob 数据]
启动 P2P 网络
UDP 侦听器 self=enode://f50c8e19ff841bcd5ce7d2d...
更新 bzz 本地地址 oaddr=9c40be8b83e648d50f40ad3...uaddr=e
启动 Swarm 服务
9c40be8b 蜂巢启动
检测到现有存储。尝试加载对等节点
配置单元 9c40be8b:对等节点已加载
Swarm 网络在 bzz 地址开始:9c40be8b83e648d50f40ad3d35f... 
Pss 已启动
Streamer 已启动
IPC端点打开url=/home/ubuntu/.ethereum/bzzd.ipc 
RLPx listener up self=enode://f50c8e19ff841bcd5ce7d2d...</span></span></span>

您可以通过连接到本地 Swarm 网关 Web 界面来确认您的 Swarm 节点是否正常运行:http://localhost:8500

您应该会在 localhost 上看到类似于 Swarm 网关中的屏幕,并且能够查询任何 Swarm 哈希或 ENS 名称。

本地主机上的 Swarm 网关

将文件上传到 Swarm

一旦你的本地 Swarm 节点和网关运行,你可以上传到 Swarm 并且文件将可以在任何 Swarm 节点上访问,只需参考文件哈希。

让我们通过上传文件来测试一下:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">$ swarm up code/auction_dapp/README.md 
ec13042c83ffc2fb5cb0aa8c53f770d36c9b3b35d0468a0c0a77c97016bb8d7c</span></span></span>

Swarm 已上传README.md文件并返回一个哈希值,您可以使用该哈希值从任何 Swarm 节点访问该文件。例如,您可以使用公共 Swarm 网关

虽然上传一个文件相对简单,但上传整个 dApp 前端就有点复杂了。这是因为各种 dApp 资源(HTML、CSS、JavaScript、库等)具有相互嵌入的引用。通常,Web 服务器将 URL 转换为本地文件并提供正确的资源。我们可以通过打包我们的 dApp 来为 Swarm 实现相同的目标。

在 Auction dApp 中,有一个用于打包所有资源的脚本:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">$ cd code/auction_dapp/frontend 
$ npm run build</span><span style="color:#292929">> 前端@1.0.0 构建 /home/aantonop/Dev/ethereumbook/code/auction_dapp/frontend 
> 节点构建/build.js</span><span style="color:#292929">Hash: 9ee134d8db3c44dd574d 
Version: webpack 3.10.0 
Time: 25665ms 
Asset Size 
static/js/vendor.77913f316aaf102cec11.js 1.25 MB 
static/js/app.5396ead17892922422d4.js 502 kB 
static/js/manifest.87447dd4f5e60a5f9652.js 1.54 kB 
static/css /app.0e50d6a1d2b1ed4daa03d306ced779cc.css 1.13 kB 
static/css/app.0e50d6a1d2b1ed4daa03d306ced779cc.css.map 2.54 kB 
static/js/vendor.77913f316aaf102cec11.js.map 4.74 MB 
static/js/app.5396ead17892922422d4.js.map 893 kB 
static/js /manifest.87447dd4f5e60a5f9652.js.map 7.86 kB 
index.html 1.15 kB</span><span style="color:#292929">构建完成。</span></span></span>

此命令的结果将是一个新目录,code/auction_dapp/frontend/dist它包含整个 Auction DApp 前端,打包在一起:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">dist/ 
|-- index.html 
`-​​- 静态
    |-- css 
    | |-- app.0e50d6a1d2b1ed4daa03d306ced779cc.css 
    | `-- app.0e50d6a1d2b1ed4daa03d306ced779cc.css.map 
    `-- js 
        |-- app.5396ead17892922422d4.js 
        |-- app.5396ead17892922422d4.js.map 
        |-- manifest.87447dd4f5e60a5f9652.js 
        |-- manifest.87447dd4f5e60a5f9652.js.map 
        |-- 供应商.77913f316aaf102cec11.js 
        `-- 供应商.77913f316aaf102cec11.js.map</span></span></span>

现在,您可以使用 up 命令和 --recursive 选项将整个 dApp 上传到 Swarm。在这里,我们还告诉 Swarm index.html 是加载这个 dApp 的默认路径:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">$ swarm --bzzapi <a data-cke-saved-href="http://localhost:8500/" href="http://localhost:8500/" class="au li">http://localhost:8500</a> --recursive \ 
  --defaultpath dist/index.html up dist/</span><span style="color:#292929">ab164cf37dc10647e43a233486cdeffa8334b026e32a480dd9cbd020c12d4581</span></span></span>

现在,我们的整个拍卖 dApp 都托管在 Swarm 上,可以通过 Swarm URL 访问:

  • bzz://ab164cf37dc10647e43a233486cdeffa8334b026e32a480dd9cbd020c12d4581

我们在分散我们的 DApp 方面取得了一些进展,但我们使它更难使用。像这样的 URL 比像auction_dapp.com. 我们是否被迫牺牲可用性来获得去中心化?不必要。

在下一节中,我们将研究以太坊的名称服务,它允许我们使用易于阅读的名称,但仍然保留了我们应用程序的去中心化特性。

以太坊名称服务 (ENS)

你可以设计世界上最好的智能合约,但如果你不为用户提供一个好的界面,他们将无法访问它。

在传统互联网上,域名系统 (DNS) 允许我们在浏览器中使用人类可读的名称,同时在后台将这些名称解析为 IP 地址或其他标识符。在以太坊区块链上,以太坊命名系统(ENS)以去中心化的方式解决了同样的问题。

比如以太坊基金会的捐款地址0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359;在一个支持ENS的钱包里,就是ethereum.eth.

ENS 不仅仅是一个智能合约;它本身就是一个基本的 dApp,提供去中心化的名称服务。此外,许多 dApp 支持 ENS,用于注册、管理和拍卖注册名称。ENS 展示了 dApp 如何协同工作:它是为服务其他 dApp 而构建的 dApp,由 dApp 生态系统支持,嵌入到其他 dApp 中等等。

在本节中,我们将了解 ENS 的工作原理。我们将演示如何设置自己的名称并将其链接到钱包或以太坊地址,如何将 ENS 嵌入另一个 dApp,以及如何使用 ENS 命名您的 dApp 资源以使其更易于使用。

ENS 规范

ENS主要在三个以太坊改进提案中指定:EIP-137,它指定了ENS的基本功能;EIP-162,描述了 .eth 根的拍卖系统;和 EIP-181,它指定了地址的反向解析。

ENS 遵循“三明治”设计理念:底层是一个非常简单的层,后面是更复杂但可替换的代码层,顶层是一个非常简单的层,将所有资金保存在不同的账户中。

底层:名称所有者和解析者

ENS 在“节点”而不是人类可读的名称上运行:使用“Namehash”算法将人类可读的名称转换为节点。

ENS 的基础层是一个由 ERC137 定义的巧妙简单的合约(少于 50 行代码),它只允许节点的所有者设置有关其名称的信息并创建子节点(ENS 相当于 DNS 子域)。

基础层的唯一功能是使节点所有者能够设置有关其自己节点的信息(特别是解析器、生存时间或所有权转移)并创建新子节点的所有者。

Namehash 算法是一种递归算法,可以将任何名称转换为标识该名称的哈希。

“递归”是指我们通过求解一个同类型的较小问题的子问题来解决问题,然后用子问题的解来解决原问题。

Namehash 递归地散列名称的组成部分,为任何有效的输入域生成一个唯一的、固定长度的字符串(或“节点”)。例如 subdomain.example.eth 的 Namehash 节点是keccak('<example.eth>' node) + keccak('<subdomain>'). 我们必须解决的子问题是计算节点 example.eth,即keccak('<.eth>' node) + keccak('<example>'). 首先,我们必须计算 eth 的节点,即keccak(<root node>) + keccak('<eth>').

根节点就是我们所说的递归的“基本情况”,我们显然不能递归地定义它,否则算法永远不会终止!根节点定义为0x0000000000000000000000000000000000000000000000000000000000000000(32 个零字节)。

把这一切放在一起,因此 subdomain.example.eth 的节点是keccak(keccak(keccak(0x0...0 + keccak('eth')) + keccak('example')) + keccak('subdomain'))

概括地说,我们可以定义 Namehash 函数如下(根节点的基本情况,或空名称,后跟递归步骤):

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">namehash([]) = 0x000000000000000000000000000000000000000000000000000 
namehash([label, ...]) = keccak256(namehash(...) + keccak256(label))</span></span></span>

在 Python 中,这变成:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">def namehash(name): 
  if name == '': 
    return '\0' * 32 
  else: 
    label, _, 余数 = name.partition('.') 
    return sha3(namehash(remainder) + sha3(label))</span></span></span>

因此,mastering-ethereum.eth将进行如下处理:

<span style="background-color:#f2f2f2"><span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#292929">namehash('mastering-ethereum.eth') 
⇒ sha3(namehash('eth') + sha3('mastering-ethereum')) 
⇒ sha3(sha3(namehash('') + sha3('eth')) + sha3( 'mastering-ethereum')) 
⇒ sha3(sha3(('\0' * 32) + sha3('eth')) + sha3('mastering-ethereum'))</span></span></span>

当然,子域本身也可以有子域:可能有 a sub.subdomain.example.ethafter subdomain.example.eth,然后是 a sub.sub.subdomain.example.eth,以此类推。为避免昂贵的重新计算,由于 Namehash 仅依赖于名称本身,因此可以预先计算给定名称的节点并将其插入到合约中,从而无需进行字符串操作并允许立即查找 ENS 记录,而不管在原始名称。

如何选择一个有效的名字?
名称由一系列点分隔的标签组成。尽管允许使用大写和小写字母,但所有标签都应遵循 UTS #46 规范化过程,该过程在散列标签之前对标签进行大小写折叠,因此具有不同大小写但拼写相同的名称最终将具有相同的 Namehash。

您可以使用任何长度的标签和域,但为了与传统 DNS 兼容,建议使用以下规则:

  • 每个标签不应超过 64 个字符。
  • 完整的 ENS 名称不应超过 255 个字符。
  • 标签不应以连字符开头或结尾,或以数字开头。

根节点所有权

这种分层系统的结果之一是它依赖于能够创建顶级域 (TLD) 的根节点的所有者。

虽然最终目标是为新 TLD 采用分散的决策流程,但在撰写本文时,根节点由不同国家/地区的人持有的 4-of-7 multisig 控制(构建为 7 DNS 系统的密钥持有者)。因此,需要 7 名密钥持有者中至少 4 名的多数方来进行任何更改。

目前,这些密钥持有者的目的和目标是与社区达成共识,以:

  • 对系统进行评估后,将 .eth TLD 的临时所有权迁移并升级为更永久的合同。
  • 如果社区同意需要它们,则允许添加新的 TLD。
  • 当这样的系统被商定、测试和实施时,将根多重签名的所有权迁移到更加去中心化的合约。
  • 作为处理顶级注册表中任何错误或漏洞的最后手段。

解析器
基本 ENS 合约不能将元数据添加到名称;这就是所谓的“解析合同”的工作。这些是用户创建的合约,可以回答有关名称的问题,例如与应用程序关联的 Swarm 地址、接收应用程序付款的地址(以太币或代币)或应用程序的哈希值是什么(验证它的完整性)。

中间层:.eth 节点

在撰写本文时,唯一可在智能合约中唯一注册的顶级域是 .eth。

注意:目前正在努力使传统 DNS 域所有者声明 ENS 所有权。虽然理论上这适用于 .com,但目前唯一实施的域是.xyz,并且仅在 Ropsten 测试网上

.eth 域名通过拍卖系统分发。没有保留列表或优先级,获得名称的唯一方法是使用系统。拍卖系统是一段复杂的代码(超过 500 行);ENS 中的大部分早期开发工作(和错误!)都在系统的这一部分。但是,它也是可更换和可升级的,不会对资金造成风险——稍后会详细介绍。

维克里拍卖

名字是通过修改后的维克里拍卖分配的。在传统的 Vickrey 拍卖中,每个投标人都提交一个密封的投标,并且所有投标人同时显示,此时出价最高的人赢得拍卖,但只支付第二高的投标。因此,投标人被激励不要低于他们的名字的真实价值,因为投标他们的真实价值会增加他们获胜的机会,但不会影响他们最终支付的价格。

在区块链上,需要进行一些更改:

  • 为了确保投标人不会提交他们无意支付的投标,他们必须预先锁定等于或高于其投标的价值,以保证投标有效。
  • 因为你不能在区块链上隐藏秘密,投标人必须执行至少两个交易(提交-显示过程),以隐藏他们投标的原始价值和名称。
  • 由于您无法在去中心化系统中同时显示所有出价,因此投标人必须自己显示自己的出价;如果他们不这样做,他们将没收锁定的资金。如果没有这种没收,人们可以多次出价并选择只透露一两个,从而将密封投标拍卖变成传统的涨价拍卖。

因此,拍卖是一个四步过程:

  1. 开始拍卖。这是广播注册名称的意图所必需的。这将创建所有拍卖截止日期。这些名称经过散列处理,因此只有在字典中有该名称的人才能知道打开了哪个拍卖。这允许一些隐私,如果您正在创建一个新项目并且不想共享有关它的详细信息,这很有用。您可以同时打开多个虚拟拍卖,因此如果有人关注您,他们不能简单地对您打开的所有拍卖进行投标。
  2. 进行密封投标。您必须在投标截止日期之前通过将给定数量的以太币绑定到秘密消息的哈希值(其中包括名称的哈希值、投标的实际金额和盐)来执行此操作。你可以锁定比实际出价更多的以太币,以掩盖你的真实估值。
  3. 显示出价。在显示期间,您必须进行交易以显示出价,然后计算出最高出价和次高出价,并将以太币发回给未成功的出价者。每次显示出价时,都会重新计算当前的获胜者;因此,在揭示截止日期到期之前设置的最后一个将成为总冠军。
  4. 后清理。如果您是赢家,您可以完成拍卖,以取回您的出价与第二高出价之间的差额。如果您忘记透露,您可以延迟透露并收回您的出价。

顶层:事迹

ENS 的顶层是另一个超级简单的合约,只有一个目的:持有资金。

当您赢得一个名字时,资金实际上并没有发送到任何地方,而只是在您想要持有该名字的期间(至少一年)被锁定。这就像保证回购一样:如果所有者不再想要该名称,他们可以将其卖回系统并收回他们的以太(因此持有该名称的成本是做某事回报大于零的机会成本) .

当然,事实证明,让一个合约持有数百万美元的以太币是非常冒险的,因此 ENS 会为每个新名称创建一个契约合约。契约合约非常简单(大约 50 行代码),它只允许将资金转回单个账户(契约所有者)并由单个实体(注册商合约)调用。这种方法大大减少了漏洞可能使资金面临风险的攻击面。

注册名称

正如我们在 Vickrey 拍卖中看到的那样,在 ENS 中注册名称是一个四步过程。首先,我们为任何可用的名称出价,然后我们在 48 小时后公布我们的出价以确保名称。ENS 注册时间线是显示注册时间线的图表。

让我们注册我们的名字!

我们将使用几个可用的用户友好界面之一来搜索可用名称,对名称 ethereumbook.eth 出价,显示出价并保护名称。

ENS 有许多基于 Web 的界面,允许我们与 ENS DApp 进行交互。对于这个例子,我们将使用MyCrypto 接口,结合 MetaMask 作为我们的钱包。

ENS 注册时间表

首先,我们需要确保我们想要的名称可用。在写这本书的时候,我们真的很想注册这个名字mastering.eth,但可惜的是,在 MyCrypto.com 上搜索 ENS 名字时发现它已经被占用了!由于 ENS 注册仅持续一年,因此将来有可能确保该名称的安全。与此同时,让我们搜索ethereumbook.eth.

图 6. 在 MyCrypto.com 上搜索 ENS 名称

伟大的!名称可用。为了注册它,我们需要开始拍卖 ENS 名称。让我们解锁 MetaMask 并开始拍卖ethereumbook.eth

开始拍卖 ENS 名称

让我们出价。为此,我们需要按照投标 ENS 名称中的步骤进行操作。

竞标 ENS 名称

警告
如 Vickrey 拍卖中所述,您必须在拍卖完成后 48 小时内公开您的出价,否则您将失去出价中的资金。我们是否忘记这样做并自己损失了 0.01 ETH?你打赌我们做到了。

截取屏幕截图,保存您的秘密短语(作为出价的备份),并在您的日历中添加一个提醒以显示日期和时间,这样您就不会忘记并丢失您的资金。

最后,我们通过单击包含您的出价的 MetaMask 交易中显示的绿色大提交按钮来确认交易。

包含您的出价的 MetaMask 交易

如果一切顺利,以这种方式提交交易后,您可以在 48 小时内返回并显示出价,您请求的名称将注册到您的以太坊地址。

管理您的 ENS 名称

注册 ENS 名称后,您可以使用另一个用户友好的界面对其进行管理:ENS 管理器

在那里,在搜索框中输入您要管理的名称(请参阅 ENS 管理器 Web 界面)。您需要解锁您的以太坊钱包(例如 MetaMask),以便 ENS Manager DApp 可以代表您管理该名称。

ENS 管理器 Web 界面

通过这个界面,我们可以创建子域,设置解析器合约(稍后会详细介绍),并将每个名称连接到适当的资源,例如 DApp 前端的 Swarm 地址。

创建 ENS 子域

首先,让我们为示例 Auction DApp 创建一个子域(请参阅添加子域auction.ethereumbook.eth)。我们将命名子域拍卖,因此完全限定名称将是auction.ethereumbook.eth.

添加子域auction.ethereumbook.eth

一旦我们创建了子域,我们就可以auction.ethereumbook.eth在搜索框中输入并管理它,就像我们ethereumbook.eth之前管理域一样。

ENS 解析器

在 ENS 中,解析名称是一个两步过程:

  1. ENS 注册表在散列后使用要解析的名称调用。如果记录存在,则注册表返回其解析器的地址。
  2. 使用适合所请求资源的方法调用解析器。解析器返回所需的结果。

这个两步过程有几个好处。将解析器的功能与命名系统本身分开,为我们提供了更多的灵活性。名称的所有者可以使用自定义解析器来解析任何类型或资源,从而扩展 ENS 的功能。例如,如果将来您想将地理定位资源(经度/纬度)链接到 ENS 名称,您可以创建一个新的解析器来回答geolocation查询。谁知道未来哪些应用程序可能有用?使用自定义解析器,唯一的限制是您的想象力。

为方便起见,有一个默认的公共解析器可以解析各种资源,包括地址(用于钱包或合约)和内容(用于 dApp 或合约源代码的 Swarm 哈希)。

由于我们想将 Auction dApp 链接到 Swarm 哈希,我们可以使用支持内容解析的公共解析器,如设置默认公共解析器所示auction.ethereumbook.eth;我们不需要编写或部署自定义解析器。

为auction.ethereumbook.eth 设置默认的公共解析器

将名称解析为 Swarm 哈希(内容)

一旦将解析器auction.ethereumbook.eth设置为公共解析器,我们就可以将其设置为返回 Swarm 哈希作为我们名称的内容(请参阅将“内容”设置为返回auction.ethereumbook.eth)。

设置“内容”以返回auction.ethereumbook.eth

在等待我们的交易确认的一小段时间之后,我们应该能够正确解析名称。在设置名称之前,可以通过其哈希值在 Swarm 网关上找到我们的 Auction dApp:

或者通过在 DApp 浏览器或 Swarm 网关中搜索 Swarm URL:

  • bzz://ab164cf37dc10647e43a233486cdeffa8334b026e32a480dd9cbd020c12d4581

现在我们已经将它附加到一个名称上,它就容易多了:

我们也可以通过在任何 ENS 兼容的钱包或 DApp 浏览器(例如 Mist)中搜索“auction.ethereumbook.eth”来找到它。

从 App 到 DApp

在过去的几个部分中,我们逐渐构建了一个去中心化的应用程序。我们从一对智能合约开始对 ERC721 契约进行拍卖。这些合约被设计为没有管理或特权账户,因此它们的操作是真正去中心化的。我们添加了一个用 JavaScript 实现的前端,它为我们的 dApp 提供了一个方便且用户友好的界面。拍卖 dApp 使用去中心化存储系统 Swarm 来存储图像等应用资源。dApp 还使用去中心化通信协议 Whisper 为每次拍卖提供加密聊天室,无需任何中央服务器。

我们将整个前端上传到 Swarm,以便我们的 dApp 不依赖任何 Web 服务器来提供文件。最后,我们使用 ENS 为我们的 dApp 分配了一个名称,将其连接到前端的 Swarm 哈希,以便用户可以使用简单易记的人类可读名称访问它。

通过这些步骤中的每一个,我们增加了应用程序的去中心化。最终的结果是一个没有中心权威点、没有中心故障点的 dApp,表达了“web3”的愿景。

Auction dApp 架构展示了 Auction dApp 的完整架构。

拍卖 DApp 架构

结论

正如创始人从最早的设计中所表达的那样,去中心化应用程序是以太坊愿景的高潮。虽然今天很多应用程序称自己为“dApp”,但大多数都没有完全去中心化。

但是,已经可以构建几乎完全去中心化的应用程序。

随着时间的推移,随着技术的进一步成熟,我们越来越多的应用程序可以去中心化,从而产生更具弹性、抗审查和自由的网络。

猜你喜欢

转载自blog.csdn.net/QQ2115448134/article/details/125195916
今日推荐