从全栈开发者迈向Web3弄潮儿
近年来大热的美剧《创业公司(StartUp)》虚构了一种被称为 GenCoin 的数字货币,可用于各种创新式的金融交易场景中。而在我看来,它可以被理解为一种具有 Web3 核心属性的区块链分布式设计产品。如果您对 Web3 还不甚了解的话,让我们先回顾一下 Web 的三个主要时代:
- Web1 - 静态网页(1991 年–2004 年),请参见 --https://en.wikipedia.org/wiki/Web_2.0#Web_1.0
- Web2 - Web 作为一个平台(自 2004 年起),请参见 --https://en.wikipedia.org/wiki/Web_2.0#Web_2.0
- Web3- 去中心化的设计,包含了区块链技术(自 2009 年起,且近年来发展势头迅猛、前景广阔),请参见 --https://en.wikipedia.org/wiki/Web3
在 Web2 时代,Web 服务主要集中和被控制在诸如:谷歌、苹果和亚马逊等少数技术提供商的手里。而作为 Web2 的替代方案(https://consensys.net/blog/blockchain-explained/what-is-web3-here-are-some-ways-to-explain-it-to-a-friend/),Web3 创建了一个无需准入的数据存储方式。其中不存在任何个人或公司控制或拥有着数据,而且数据的真实性也得到了充分保证。这些数据会被存储在区块链网络中的公共分类账本(public ledger)上。因此,不再是由一个实体拥有数据,而是由多个节点(即:运行着区块链的计算机)存储着数据,并就数据是否有效达成了共识。
从比特币(https://bitcoin.org/en/)到以太坊等协议的应用,Web3 以此类数据存储协议为基础,开启了各种全新的用例。例如:
- 由用户而非公司控制着个人身份
- 未经许可的金融系统(如:比特币)可开展贷款、货币、投资等的数字化货币业务
- 由 NFT(https://en.wikipedia.org/wiki/Non-fungible_token)去证明诸如音乐(https://royal.io/)、艺术(https://www.artblocks.io/)等数字项目的数字所有权
- 通过去中心化的自治组织(decentralized autonomous organizations,DAO)临时组建具有相同目的的团体,例如:Constitution DAO(https://www.constitutiondao.com/)和 social DAO(https://www.fwb.help/)
- 通过边玩边赚(Play-to-earn,p2e)的游戏,用户可以在玩游戏的同时,用来谋生(例如 Axie Infinity,https://axieinfinity.com/)
当然,上述应用的关键在于,数字货币的所有权(如:DAO 会员资格、或音乐版权等)都被掌控在用户的手中。在世界上任何地方,只要有互联网连接,任何人都可以自由地交易、销售和构建这些物品,而完全脱离了某个公司或政府的规则控制。对于这样的 Web3 理想主义,我在此不做评判,只是单纯从开发者的角度和您探讨,一个全栈开发者将如何具备 Web3 的技术能力。
源于 2015 年的“全栈开发者”一词是指:一个软件工程师可以为任何级别的软件技术栈做出贡献。例如,面对某个与服务层相关的功能性缺陷,刚刚完成了客户端相关任务的同一开发者,可以无缝“接单”,去高效地抓 bug。您可以通过链接 --https://dzone.com/articles/do-not-publishfull-stack-development-truly-possibl,了解更多有关全栈开发的概念。
为了深入研究 Web3,我依次创建了一个智能合约,以及一个 Dapp 与之进行交互。其中,
- 智能合约(https://www.coinbase.com/learn/crypto-basics/what-is-a-smart-contract)是部署在区块链上的一段代码(我下面会以以太坊(https://ethereum.org/en/what-is-ethereum/)为例)。该合约一旦被部署到区块链上,就不可改变、也无需许可(permissionless),但是任何人都可以检索到它。
- Dapp(decentralized application,去中心化应用)是我们通过 UI(通常来自网页或应用)与智能合约交互的方式。Dapp 会在后端利用智能合约的开放性,采用诸如 IPFS(InterPlanetary File Storage,星际文件存储)的方式,实现文件的分散存储,且不会出现停机。毕竟 DDoS 攻击无法攻击负责存储的每个节点。当然,在考虑部署之前,我们需要针对其安全性,开展全面测试,并处置好代码中的潜在缺陷与漏洞。
目前,针对 Web3 的成熟技术栈组合,通常包括以下组件:
- NPM - 备受 Web2 开发人员欢迎的节点包管理器,请参见 --https://nodejs.org/en/
- Truffle 框架 - 专注于 Web3 的开发工具,请参见 --https://www.trufflesuite.com/
- Ganache – 可以在本地主机上启动私有区块链,请参见 --https://www.trufflesuite.com/ganache
- MetaMask - 以太坊的区块链用户界面与网关,属于开源且去中心化的区块链类型,请参见 --https://metamask.io/
- Solidity – 先进的智能合约编程语言,请参见 --https://solidity.readthedocs.io/en/v0.7.1/
- HTML/CSS/JavaScript - 客户端的层面,请参见 --https://www.w3.org/standards/webdesign/htmlcss
- Web3.js – 通过以太坊网络交互的以太坊 API 库,请参见 --https://web3js.readthedocs.io/en/v1.3.0/
- Infura - 授予以太坊网络访问权限的以太坊 API 服务,请参见 --https://infura.io/
假设有一个居委会即将举办定期选举,附近的居民将对一系列的决议进行投票。那么,我们就可以将该选举构建成为一个以太坊 Dapp。由于数据被存储在公开的区块链上,而不是单个公司的私有服务器上,因此任何人都可以通过与智能合约的交互,以无需许可的方式,检索投票结果。据此,投票结果就不存在被篡改或伪造的情况,进而避免了争议的发生。
首先,我们需要利用前文提到的:Infura、NPM、Truffle 框架、Ganache、以及 Solidity 等 Web3 技术栈组件,来创建一个能与应用协同的智能合约。其创建的流程如下图所示:
我们可以根据该流程,去招募以太坊的开发者,具体内容请参见链接 --https://consensys.net/developers/onboarding-step-2/。
有了智能合约,Web3 工程师便可以使用 NPM、MetaMask、HTML/CSS/JavaScript/React、以及 Web3.js 等 Web3 技术栈组件,构建居委会选举的应用。在本例中,我们将采用 React(https://reactjs.org/) 框架和如下流程:
我会通过 Infura 的注册页面(https://infura.io/register)创建一个免费帐户,并创建一个名为 jvc-homeowners-ballot 的项目:
下图中有关该项目的细节,我会在下文中详细讨论:
Truffle 入门在本地主机上,我创建了一个名为 jvc-homeowners-ballot 的文件夹,并使用 CLI 命令 --truffle init,来初始化 Truffle。初始化完成后的目录结构为:
接着,我用如下命令为基于 Truffle 的钱包 provider,添加了对应的依赖项:
为了创建本地开发网络,我通过命令 ganache 启动 Ganache CLI。
根据 CLI 的如下响应信息,我们可以看到 Ganache 已在本地主机的 8545 端口上运行:
项目文件夹中的 truffle-config.js 文件,会被激活并更新如下代码行:
现在,我们可以在新的终端中通过命令 --truffle console,来启动 Truffle 控制台,能显示如下提示:
我们可以在控制台中,通过命令 --const HDWalletProvider=require('@truffle/hdwallet-provider'); 来创建钱包。当然,它可能会导致未定义的响应。
接下来,我需要通过 Mnemonic Code Converter(https://iancoleman.io/bip39/)网站,生成一个 12 字的助记词(12-word mnemonic phrase,类似私钥),并将其通过如下命令,更新到 Truffle 控制台处:
上述两条命令虽然也会导致未定义的响应,但是钱包的控制台最终会显示如下运行结果:
现在我们需要为 Dapp 获取一些测试资金,并使用 Ropsten Ethereum Faucet(https://faucet.ropsten.be/)将资金添加到现有的、由ConsenSys(https://consensys.net/)创建的MetaMask(https://metamask.io/index.html)钱包中。当然,为了降低意外情况所导致的真实资金损失的风险,您可以在 MetaMask 中创建多个帐户,其中至少有一个帐户可专用于开发和测试。请记住:永远不要与任何人分享您的助记词,也不要在任何地方上传您的私钥!
如下图所示,为了添加测试资金,我需要输入自己的帐户地址:
如下图所示,通过 Ropsten Etherscan 站点,我们可以验证交易是否能够成功完成:
请使用如下命令将 dotenv 依赖项添加到该项目中:
接着,请在项目的根目录下创建一个.env 的新文件,并在其中包含如下两行:
其中,INFURA_API_KEY 是在创建 jvc-homeowners-ballot 项目时给定的项目 ID。注意:请确保.env 文件被包含在.gitignore 文件中,以避免其他有权访问该存储库的人,擅自使用此机密信息。
最后一项准备步骤是更新 truffle-config.js 文件。我们首先需要在文件的顶部添加如下三行:
接着,我们利用 dotenv 将如下网络信息,添加至上述依赖项:
准备好了 Infura、Truffle、以及测试资金后,让我们开始设置智能合约。针对前面的居委会选举示例,我们将使用位于本项目 contracts 文件夹中的 JvcHomeownerBallot.sol 合约:
正如上面的代码所示,该合同将非常简单,参选居民只需选择是或否即可。其对应的 contracts 文件夹结构如下图所示:
有了合约,我们就需要建立部署合约的方法。下面让我们转移到 migrations 文件夹,将如下内容添加到该文件夹下的 2_deploy_contracts.js 文件中:
然后,我们可以使用如下命令执行合约的迁移:
迁移的响应结果为:
至此,我们已将 JvcHomeownersBallot 智能合约部署到了 Ropsten 网络中。我们可以进一步使用如下 URL,来验证智能合约,并在“Deploying JvcHomeownersBallot”日志中提供合约的地址:
或是:
在上述提到的 jvc-homeowners-ballot 文件夹的同级目录,我将创建一个名为 jvc-homeowners-ballot-client 的目录,通过调用 React CLI 和如下命令,来创建同名的 React 应用:
接着,我通过如下命令,将 Web3 的依赖项安装到 React 应用中:
核心的 React 应用一旦就绪,我们就需要建立合约应用的二进制接口(application binary interface,ABI),以便 Dapp 与以太坊生态系统上的各种合约进行通信。
根据 JvcHomeownerBallot.sol 智能合约文件的内容,我们在 build/contracts 文件夹下打开 JvcHomeownersBallet.json 文件,并使用 abi.js 文件的 jvcHomeOwnersBallot 常量的“abi”属性值。具体内容如下:
该文件应当被放置在 React 应用目录 src 的新建子文件夹 abi 内。
下面,我们根据如下配置,从头开始更新 Apps.js:
我们可以通过多种方式找到上面提到的 contactAddress。除了我在此使用的 truffle 的 migrate CLI 命令之外,您还可以使用 Etherscan 站点(https://ropsten.etherscan.io/)。
在开始标准的 React 开发之前,让我们先来看看完整的 App.js 文件 (如下所示):
我们可以使用 Yarn CLI 的如下命令,来启动基于 React 的 Dapp:
在完成编译和验证之后,您会看到如下应用界面:
它拥有三个选项:
- VOTE YES - 提交赞成票
- VOTE NO - 提交反对票
- GET VOTES – 在 Dapp 的下部显示投赞成与反对票的总数
综上所述,一旦建立了智能合约,从客户端的角度来看,我们将能够沿用 Web2 的如下方面到 Web3 上:
- 目前在 Web2 项目中常用的 JavaScript 客户端框架,可以被继续使用。
- NPM 可以被用来包含依赖项,以促进 Web3 的开发。
- 类似于 Web2 应用程序与传统数据存储的交互方式,Web3 的 Truffle 和 MetaMask 库也允许应用程序与数据进行交互。
- 现有的业务规则和 UI/UX 设计,将继续满足产品所有者对于 Web3 特性和功能上的要求。
而 Web3 的独特之处主要体现在:
- 在区块链上构建的 Dapps,都采用同一个事实源向各个信息消费者的请求,提供可靠的数据。
- 我们不再需要知道“谁”参与了交易、或查询存储在区块链智能合约中的信息(哪怕是别的 Dapp 去访问存储的数据)。由于结果总是固定不变的,因此 Dapp 只需关注应用程序的业务规则。正如上述居委会选举的简单示例那样,无论选票被查询多少次,即便是有另一个 Dapp,其结果总是完全相同的。
- 由于其分布式的特性,因此控制权被返回给了消费者,而非停留在少数人的手中。
可见,从全栈开发者迈向 Web3 的学习曲线并不陡峭,而且我们可以寻求各种工具、框架和库的帮助。如果您对上述项目所涉及到的源代码感兴趣的话,可以通过如下链接,访问到它在 GitLab 上两个存储库:
- https://gitlab.com/johnjvester/jvc-homeowners-ballot
- https://gitlab.com/johnjvester/jvc-homeowners-ballot-client
陈峻 (Julian Chen),51CTO 社区编辑,具有十多年的 IT 项目实施经验,善于对内外部资源与风险实施管控,专注传播网络与信息安全知识与经验;持续以博文、专题和译文等形式,分享前沿技术与新知;经常以线上、线下等方式,开展信息安全类培训与授课。