Python中国社区  »  区块链

前端工程师如何快速入门区块链 DApp 开发?

前端之巅 • 2 周前 • 22 次点击  

导语:魔法哥在 “QCon 全球软件开发大会” 2018 上海站的演讲广受好评。为让这个演讲发挥更大的价值,本文尝试以图文配合的方式还原现场讲解,尽可能为读者呈现原版体验。

本文转载自魔法哥的公众号:CSS魔法。


大家好,很高兴在 QCon 的讲台上和大家见面!

我的完整网名叫 “CSS魔法”。两年前,我翻译过一本书,叫《CSS 揭秘》。这本书堪称前端领域里的重量级著作,中文版已经累计售出一万七千多册。我也很荣幸,能为前端技术社区做出一点微小的贡献。

一个故事

总的来说,我就是个 “写 CSS 的”。然而今天主题是关于区块链的,为什么一个 “写 CSS 的” 会来讲区块链?我也不知道。我并不想讲区块链,因为大家都不喜欢区块链,都说 “搞区块链的都是骗子”。所以我今天来是想讲故事的。

小明是一名前端工程师,也是一个足球迷。他有一项神奇的技能:他对足球有很深的理解,能够在每届世界杯开赛之前准确预测出最终夺冠的球队。比如,在 2010 年的那届世界杯,小明就预测出了正确的结果。大赛闭幕,小明难掩兴奋之情,想在女朋友面前显摆一下。女朋友很自然地提出质疑,而小明并没有证据来证明自己,只能哑口无言。

小明痛定思痛,决定写一个网站来提前记录自己的预言。

  1. 小明自己设计了网页界面。

  2. 找小伙伴帮忙写了一个后端服务,提供两个接口。

  3. 小明基于这两个接口,写了一个纯前端渲染的网站。

最终网站看起来是这个样子的:

  • 列表页:展示所有已经发布的预言

  • 发布页:可以发布一条新的预言

接下来,小明静静等待下一届世界杯的到来。

时间过得很快,转眼到了 2014 年。这一次,小明再次正确预测出了冠军得主。

有网站帮自己记录预言,小明心想,这次女朋友应该会相信自己了吧!

然而……

女朋友也是懂技术的,她这次仍然提出了一个合理的质疑。小明再次无言以对。小明很受打击,从而再也不看足球了。

这是我听过的最忧伤的故事。当然我今天来并不是为了讲一个忧伤的故事,这个故事其实还有一个完整版。

要讲清楚故事的完整版,我们需要把时间线倒回到 2009 年。因为这一年发生了一件影响深远的事情:比特币诞生!

虽然我前面说 “并不想讲区块链”,但比特币和区块链的出现,确实是我们无法回避的事实。对小明来说也是一样,他也在新闻报导里听说过 “比特币”。当时让他印象最深的一篇报导是:国外有个哥们儿,用一万枚比特币买了两盒披萨。小明感觉比特币就是技术极客对这个世界开的一个玩笑。他并没有把比特币放在心上,很快就忘了这回事儿。

而当他再次听到 “比特币” 这个词,已经是八年后了。

2017年底,仿佛一夜之间,所有人都在谈论比特币和区块链。

原来在此时,单枚比特币的价格已经突破了两万美元,世人无不惊叹。

小明显然错过了一个暴富的好机会。不过他也并不懊恼,毕竟当年的自己确实没看懂比特币的价值,错过也是必然。

真正让小明受到触动的是另一件事情。媒体报导,有一款叫 “加密猫” 的游戏火遍全球,而这款游戏是运行在区块链上的。

让小明震惊的并不是这款游戏有多么受欢迎、游戏内的交易额有多么巨大、游戏开发团队收到了多么巨额的风投,而是这款游戏完全颠覆了小明对于 “区块链” 的认知。

在小明的概念里,“区块链就是比特币,比特币就是区块链”。没想到区块链还可以运行游戏!

游戏也是一种应用程序,“区块链可以运行游戏” 意味着 “区块链可以运行应用”;而作为一名开发者,小明意识到:“我可以在区块链上开发应用”!

此外,媒体的狂轰滥炸还让小明注意到区块链的另一个特性:不可篡改。

“不可篡改”?这听起来非常神奇。小明回想起自己 “记录世界杯预言” 的需求,说不定可以借助区块链得到很好的实现!

因此,小明暗下决心:

讲到这里,小明的故事终于迎来了重头戏。

小明关心的 “区块链应用”,其实有一个更专业的名字,叫 “DApp”。

DApp 全称为 “Decentralized Application”,字面意思是 “去中心化应用”。(“DApp” 这个词通常读作 “dee-app” 或 “dap”;当然如果你愿意,也可以读作 “D-A-P-P”。)

DApp 有一个核心概念叫 “智能合约”。小明看了很多新闻报导,都说智能合约很厉害、可以做很多事情;但它究竟是什么,这些报导都含糊其词。小明觉得有必要在实战中深入理解。

智能合约初探

在动手之前,小明需要先选择一条公链来作为自己的开发平台。

💡 公链

选链就是选平台,类似于我们在开发手机应用时需要选择 iOS 平台或安卓平台。

公链也称 “公有链”,是向大众开放的区块链——个人开发者可以在公链上开发应用,普通用户可以使用公链上的应用。与此对应的还有 “私有链”、“联盟链” 等概念。

小明经过一番调研,最终选择 “星云链” 作为自己的入门公链。这个选择主要基于以下考量:

  • 功能完备

    星云链上线的第一版本就已经具备了 “以太坊” 的所有功能。

    💡 以太坊

    以太坊是第一个支持智能合约的公链,是 DApp 始祖。以太坊也是区块链领域的标杆。

    前面提到的 “加密猫” 游戏正是运行在以太坊之上。

    既然以太坊这么厉害,为什么小明不直接选以太坊?这是因为星云链还有其它突出的优势。

  • 性能优良

    星云链的吞吐量在当前公链中处于第一梯队,远远优于以太坊。不太可能出现 “一个爆款游戏就把整条链拖慢” 的情况。

  • 设计简洁明了

    对小明这样的初学者来说,快速入门、快速做出成果是非常重要的。小明发现,尽管星云链功能齐全,但它的设计理念却相当简洁、符合直觉,对新手开发者相当友好。

  • 采用 JS 作为合约语言

    这可能是最重要的一点。这意味着,对前端工程师来说,在星云链上开发应用没有任何语言障碍。

    星云链的智能合约就运行在 V8 引擎中,对小明来说,没有比这更熟悉的运行环境了。

小明在接下来的实践中,遇到一个又一个问题,也找到了各个问题的答案。

注意:目前各条公链的运行原理大体相同,但细节差异还是不少,因此以下所有内容均基于星云链的特性来讲解。

“智能合约” 这个概念听起来很神秘,但对开发者来说很容易接受——因为合约的本质就是一段代码。

比如上图的右侧就是一段最小化的合约代码(代码的具体内容在这里并不重要,为了避免听众盯着代码看,我给这段代码打了马赛克)。

智能合约的运作方式是这样的:

  • 开发者在写好合约代码之后,需要把它部署到链上。部署成功后会得到一个地址。

    💡 地址

    地址是链上资源的一种定位方式。每个用户在链上都会有一个独一无二的地址,类似账号的概念。

    每个合约也有自己的专属地址。可以类比 IP 地址,我们通过地址就可以找到这个合约。

  • 合约部署上链之后,即处于对外服务状态。合约代码提供若干接口,等待我们调用。

  • 每个合约都有自己的独立存储区。

看到这里,相信大家就有一些画面感了:智能合约采用图灵完备的语言来编写,同时还拥有持久化存储的能力——这意味着我们几乎可以用智能合约做任何事情。

DApp的架构

智能合约在 DApp 中的作用是什么?要回答这个问题,也就相当于回答了另一个问题:“DApp 的架构是怎样的?”

我们先来看看传统 Web 应用的架构。就以小明做的这个网站为例吧:

传统 Web 应用通常会有一个服务端,负责业务逻辑和数据存储,并提供接口。

同时要有一个网页作为用户界面,便于用户使用。网页端通常以 Ajax 的方式调用服务端提供的接口。

我们再来看看 DApp 的架构是怎样的:

DApp 也需要有一个网页作为用户界面(当然也可以是其它的客户端形态,比如桌面应用或手机应用等)。

同样需要有一个部件来完成业务逻辑和数据存储的功能,并为网页端提供接口,这个职能在 DApp 中就是由智能合约来完成的。

网页端以 “合约调用” 的方式来调用合约提供的接口。具体实现方法后面会详细讨论。

这是展示的是星云官网的推荐 DApp。我们大致浏览一下,有很大一部分是游戏,还有一些工具类应用(比如百科、词典),和社交类应用(比如论坛、抢红包)等等。总的来看,DApp 在题材上与传统应用没有明显区别。

DApp实例分析

那么 DApp 在使用上有什么不同之处吗?我们来看一个实际的例子。

这是星云官方提供的 demo 应用,叫 “超级词典”。

这是一个简单的 demo,功能和界面都不复杂,我们可以用它来查词。

比如我们输入一个单词并查询,就可以得到这个词条的解释。

如果我们输入一个词库里没有词条,它会提示找不到解释,并允许我们把这个词条添加进词库。

我们填写好这个词条的解释,准备提交。

在使用传统 Web 应用时,提交数据往往也就是在调用后端接口,并且可以很快拿到提交的结果(本次提交是成功还是失败)。但在 DApp 中,提交数据的过程会有些不同。

比如在这里,请注意,当我们点击 “提交” 按钮后,出现了一个弹窗。

这个弹窗并不是应用本身的一部分,它是由钱包插件提供的界面。

我们可以发现,当前这个 Chrome 浏览器安装了星云链官方提供的钱包插件:

浏览器插件我们都很熟悉,我们可以通过安装插件来扩展浏览器的功能。那 “钱包” 又是什么?

💡 钱包

钱包主要有以下两个作用:

  • 帮用户管理地址(前面已经提到过,地址相当于用户在链上的独一无二的账号)。比如,在钱包里,我们可以看到自己的地址里还有多少 “钱”。

  • 帮用户发起交易、查询交易、管理交易。

又来一个新概念,什么是 “交易”?

💡 交易

区块链的老本行就是记账,就是处理各种交易。

在区块链上,转账显然是一种交易;除此以外,在智能合约时代,我们往链上部署合约、调用合约的接口,也都是通过交易的形式来完成的。

好,我们回到这个弹窗界面。

提交数据其实就是在调用合约的某个接口,我们需要发起交易来完成这个调用,而这个弹窗界面所展示的就是当前交易的信息。我们可以看到,在 “Contract args” 这个字段里有数据,表明本次交易是一次对合约的调用。

这个界面里的所有信息都不需要我们手动填写,只需要简单确认,然后点击 “Confirm” 即可。当然如果你想放弃本次操作,也可以点击 “Reject” 来中止。

确认之后,弹窗会再次提示我们:是否把本次交易发送到区块链网络。我们点击 “Submit” 按钮,发出交易。

随后,我们会进入一个等待界面。我们可以看到,当前的交易状态是 “Pending”,同时会有一个 15 秒的倒计时。

这个倒计时是什么?

这里就涉及到区块链的一个基本概念了。大家都知道,区块链采用了链式数据结构,整个链是由一个个的区块所组成的。不论是完成一次新的转账,还是我们让合约更新自己的数据,都需要由矿工把这些操作打包成一个新区块,并追加到链上。

💡 矿工

矿工是区块链网络中有 “记账权” 的节点,记账权也意味着产生新区块的权力。

当我们把一笔交易发送到区块链网络中时,它会传播到矿工节点那里;矿工节点会逐个执行所有待处理的交易,生成新区块。生成新区块的过程俗称 “打包”,也叫 “出块”。

这个倒计时的 15 秒正是星云链出块的时间间隔。在这个间隔内,矿工需要出块并把新区块广播到网络中,其它节点在收到新区块之后,还需要完成校验和同步等操作。

这个出块周期有点像定点发车,如果你的交易赶上了这班车,就会被打包上链;如果你错过了这班车,或者这班车已经满了,就要等下一班车。

钱包插件会每隔 15 秒检查一下当前交易有没有完成。通常在等待 15 之后,我们就可以看交易的状态变成 “success” 了:

此时,我们就可以放心地关闭这个弹窗了。

回到页面,页面也提示我们刚才的提交操作已经成功了:

然后,我们再次尝试查询这个词条:

在上图中可以看到,刚刚提交的词条解释已经可以查询出来了。

经过这个 demo,我们可以总结出 DApp 在交互上的两大特征

  • 在不写数据的情况下,直接查询就可以获得结果。这个过程跟普通应用没有区别。

  • 在需要写数据的情况下,需要发起交易来调用合约接口。当交易成功之后,即完成 “上链” 过程。

作为一个 DApp 开发者,至少要做好以下准备工作:

  • Chrome + 星云钱包插件。这是 DApp 网页端所需的运行环境。

  • 有自己的地址。我们可以用钱包插件来创建自己的地址。

  • 地址里要有少量余额。原因在于每笔交易都需要向矿工支付少量手续费(术语称作 “gas”)。

    💡 Gas

    Gas 的原意是汽油。就好像搭别人的车需要付 “油费” 一样,让矿工帮你处理交易也需要支付酬劳——这是区块链世界的生态设计。视交易的复杂度不同,收取的 gas 数额也不同。

    星云链的 gas 计价极为低廉,比如价值 1 分钱的星云币足够我们支付数千或数万次交易的 gas。

    在星云官网注册为开发者,即可收到官网空投的少量星云币;同时社区里也有不少热心网友无偿赠送星云币。

  • 星云 Web 钱包。是一个网页版的工具集,后面实战环节会提到它。



    DApp合约端开发


小明在理清了这些基础知识之后,终于要动手实战啦!

在开发传统 Web 应用时,我们一般会先确定后端接口。同理,在开发 DApp 时,我们通常也会先把合约端的接口准备好。

首先,我们需要了解合约代码的编写模式。

讲到这里,终于可以给大家看前面那段 “被打码” 的代码了。这是一段最小化的星云链智能合约代码。我们来看一看它有哪些要素:

  • CommonJS 模块(必须)

    先看一眼最后一行,前端同学们肯定秒懂。整个合约其实就是一个 CommonJS 模块。

  • 导出一个类(必须)

    这个模块导出的是一个类,这个类正是合约的主体。

  • 构造器方法(可选)

    既然合约主体是一个类,而类本身并不能直接运行,那么这就意味着合约每次被调用时,这个类都会被实例化。类可以有(也可以没有)一个构造器方法,这个方法在每次实例化时执行(这是类的基本行为,大家应该都很熟悉了)。构造器方法并不是必需的,我们可以根据实际需要来编写它。

  • 初始化方法(必须)

    这个类需要有一个 init() 方法,这个方法只会在合约部署成功后被自动执行一次,以后就再也无法被调用了。因此,这个初始化方法通常用来完成整个 “应用” 级别的初始化工作。它是必需的,哪怕你的应用不需要初始化,也需要提供一个空的 init() 方法。

  • 私有方法(可选)

    这个类可以有一些私有方法,私有方法可以在类的内部被调用,但它不会暴露成为合约的公开接口。私有方法的特征是下划线开头,比如上图代码中的 _helper()。我们可以根据实际需要定义私有方法,便于合约逻辑的实现,但它不是必需的。

    这个 “下划线” 的命名约定并不是 JS 语言本身的特性,而是星云链智能合约运行环境的设计。这个设计也很符合前端开发者的命名习惯。

  • 公开接口(必须)

    除去上述特定名称的方法和私有方法以外,剩下的所有方法都会作为合约的公开接口暴露出来,以供客户端调用。比如上图代码中的 method()

只要满足以上条件,就是一个合法的智能合约了。也就是说,你可以按照自己的开发习惯来组织合约代码,只要满足上述条件就可以了。

其次,另一项重要的基础知识是 “合约存储区”。

前面提到过,每个合约都有自己的独立存储区,那么智能合约自然也提供了操作存储区的 API。星云链合约存储区提供了多种操作方式,本文为方便讲解,只介绍其中最基础的用法。

在智能合约的运行环境中,有一个 LocalContractStorage 全局对象,它提供了三个最基本的 API(参见上图)。

前端工程师看到这里应该会会心一笑,因为这跟浏览器里的本地存储 API 几乎一致。我们在浏览器端要实现持久化存储,最常用的就是本地存储(localStorage);而在智能合约中,实现持久化存储也是通过类似的 API 和类似的思路来实现的。

👉 值得一提的是,.set() 方法接受的 value 参数可以是复合结构,比如数组或对象等。也就是说,相对于浏览器端的 localStorage.setItem() API,合约存储区的 .set() 方法更方便,不需要手动处理 value 的序列化和反序列化问题。

实现合约接口


接下来,我们就要开始实现合约接口了。

既然智能合约要提供与传统后端功能相当的接口,那不妨先来看盾,传统的后端接口是怎样的。

在小明的网站中,后端至少要提供两个接口,分别对应以下两项功能:

  • 获取预言列表

    /api/getAllItems

    这是一个 GET 接口。不需要参数。返回所有预言组成的数组,每个数组成员都是一个对象,用于记录某条预言的基本数据——内容(content)和发布时间(published_at)。

  • 发布预言

    /api/create

    这显然是一个 POST 接口。在向它提交数据时,需要提供一个 content 参数,以便传入预言内容;并不需要提供发布时间,因为服务端会记录时间。

    在设计这种 “新增” 操作的接口时,我们通常会把发布成功的这一条数据返回,以便客户端立即把新内容渲染出来。

如何在合约端实现这两个接口的功能?别着急,慢慢来。小明先把合约的大致结构写好:

这个合约似乎并不需要在构造器里做什么事儿,留空就行。

然后需要做一些初始化工作。小明需要做的就是在合约存储区里建一个 key,取名 'items',用来保存所有预言。在初始化阶段,显然啥预言也没有,就存一个空数组进去。

随后就要进入重点了,小明开始写两个合约接口。

第一个接口是 “获取预言列表”,即 getAllItems() 方法。

实现这个方法其实非常简单——从存储区里读出 'items' 这个 key 的值,返回就行了。写出的代码也是一目了然。

👉 请留意:这个方法里只有读操作,没有写操作。

第二个接口是 “发布预言”,即 create() 方法。

这个接口稍稍复杂一些,我们一步一步来。

我们先把这条新预言的数据准备好,存到 newItem 变量中备用。

接下来更新存储区:我们先取出所有预言的列表,然后把新预言 push 进去,最后把预言列表写回存储区。

在这个方法的最后,我们把这一条新预言的数据作为函数返回值,以便客户端在拿到调用结果后立即把新预言渲染出来——这与传统后端接口 /api/create 的设计保持一致。

👉 请留意:这个方法需要更新存储区,也就是说,有写操作。

好,两个接口已经全部实现,合约代码就写好了。

合约需要部署到链上才能真正发挥作用。这里请出 “星云 Web 钱包” 来完成合约的部署和测试。

部署合约的操作比较简单,这里就不赘述了。

部署成功之后,还可以测试一下合约行为是否符合预期。(如果发现合约代码有 bug,则需要重新部署。)

准备好合约端之后,小明接下来开始实现客户端。

DApp客户端开发


网页形态的客户端开发大家都很熟悉了,这里不赘述,只着重讲一下 DApp 客户端独有的行为——合约调用。

调用合约有两种情况,或者说,有两种方式:

  • 不需要写数据时

    有些合约接口是不需要向存储区写入数据的,比如仅仅读数据或纯计算。此类调用可以直接调用,并可立即得到结果。

  • 需要写数据时

    有些合约接口是需要向存储区写入数据的,即需要 “上链”。此类接口需要通过发起交易来调用,具体过程在 demo 环节已经展示过了。

在实现这两种类型的合约调用时,需要用到客户端 SDK。它的作用是帮助我们与链交互,我们不用操心区块链网络的具体地址、接口和参数等细节,直接使用 SDK 提供的接口就可以完成调用合约、转账、查询网络状态等操作了。

星云链官方的客户端 SDK 功能完备,但设计风格偏底层,在实际开发中略显繁琐。因此这里推荐一款第三方的 SDK——Nasa.js。

Nasa.js 的安装方式很简单,直接用 npm 就可以。

加载方式也很简单,在页面中引入 nasa.js 文件,随后就可以使用它提供的各种 API 了。

Nasa.js 提供了近 30 个 API,在日常开发中,最常用的是以下三个:

  • Nasa.query()

  • Nasa.call()

  • Nasa.getTxResult()

这三者都与合约调用相关。第一项用于 “不需要写数据” 类型的合约调用,后两项涉及 “需要写数据” 的情况。具体用法会在下面的代码中详细讲解。

小明开始写网页端代码了!他先实现 “展示预言列表” 这个功能。

第一行很简单,就是把合约地址保存好。

接下来,小明需要调用合约的 getAllItems 接口,以获得所有的预言数据,并在页面中渲染出来。这个接口并不需要写数据,因此使用 Nasa.query() API 来调用它。

这个 API 接受三个参数,分别是合约地址、合约接口的函数名、传给函数的参数。

👉 提示:关于第三个参数 “传给函数的参数”,如果合约接口不需要参数,这里就传一个空数组进去;如果合约接口需要参数,就把若干个参数放在一个数组里传进去。由于合约的 getAllItems 接口不需要参数,小明传了空数组进去。

通过 Nasa.query() 发生的合约调用,可以很快得到调用结果,这个过程就好像是在调用一个 Ajax 接口。Nasa.query() 的返回值是一个 Promise,Promise 包裹的值就是合约调用结果——这个设计和常见的 Ajax 库也是十分类似的。

小明在 Promise 的 .then() 回调中拿到合约接口的调用结果。调用结果有一个 execResult 字段,用来保存合约接口函数的返回值。小明通过它可以得到一个包含所有预言数据的数组,然后在网页上就可以渲染出预言列表了。

小明接着实现第二个功能——“发布预言”。

发布页面有一个表单,小明需要给表单的提交事件绑定事件处理函数(代码略),并在这个事件处理函数中实现发布预言的操作(以下代码均写在事件处理函数中)。

前两行是准备工作,把合约地址和已经输入的文字保存好。

接下来,小明需要调用合约的 create 接口,以完成新预言的发布。这个接口需要通过发起交易来完成上链,于是小明使用 Nasa.call() API 来调用它。

这个 API 同样接受三个参数,参数含义与 Nasa.query() 的三个参数完全一致。小明依次传入合适的值。

这个 API 会唤起钱包插件,引导用户完成交易。

这个 API 也返回一个 Promise,但 Promise 包裹的值与 Nasa.query() 不同。因为通过交易来调用合约,无法直接得到调用结果,只有当这一笔交易被矿工处理完成并打包上链,我们才能得到这次合约调用的结果。因此,这个 Promise 只能给我们一个交易流水号,我们随后可以拿着这个流水号向链查询交易的状态和调用结果。

当钱包插件把交易发出后,小明就可以在 .then() 回调中拿到交易流水号(payId)。接下来就轮到 Nasa.getTxResult() 这个 API 出场了。

这个 API 接受一个参数,就是交易流水号;返回一个 Promise,Promise 包裹的值就是本次交易的状态和本次调用的结果。(查询交易结果是一个轮询的过程,不过我们不用操心这些细节,Nasa.js 会自动完成这个过程,我们只需要关心这个 Promise 就可以了。)

在 .then() 回调中,小明把交易流水号传给 Nasa.getTxResult()。由于这个 API 也返回 Promise,小明可以把它 return 出去,让这个 Promise 链条继续往下走。

当查询发现交易被矿工处理完成之后,可以在下一个 .then() 回调中拿到本次交易的状态和本次调用的结果。同样还是在 execResult 字段中,我们可以获取合约接口函数的返回值。

当然保险起见,我们最好先判断一下交易是不是成功了。如果status 字段的值为 1,则表示交易已被正常处理。

小明在这里拿到合约接口函数 create 的返回值(也就是发布成功的这条新预言的数据),把它渲染并添加到页面中就可以了。

👉 提示:以上代码仅仅演示了最核心的逻辑。对于一个体验良好的 DApp 来说,还需要处理好各种交互反馈和错误提示。

至此,整个 DApp 从合约端到客户端,就全部开发完成了。小明把这两端的功能跑通,网站顺利上线。

👉 这里顺便插一句,对 DApp 来说,甚至可以没有 “上线” 这个环节。因为整个应用的业务逻辑已经以智能合约的形式部署上链了,如果小明只打算自己用的话,客户端代码保存为 HTML 页面,在本地打开照样可以用。

网站看起来还是那个网站,不过它的本质已经升级为基于区块链的 DApp 了。

万事具备,小明静静等待下一届世界杯的到来。

2018 年世界杯,小明又一次正确预测出了冠军得主。

小明终于成功地在女朋友面前秀了一把。从此他们幸福地生活在一起……

故事到这里就讲完了。不过在听故事的过程中,大家头脑中可能会冒出一些问题。

其他问题


首先,这个实战案例是不是太简单了?

时间关系,我们无法在短短一次演讲中实现更多的功能。不过,互联网产品都是迭代式开发的嘛,小明确实也打算升级一下这个 DApp。他设想的新功能有:

  • 支持多用户:这么好的应用,只有自己在用太可惜了。小明打算让它支持多用户。

  • 可点赞:有了多用户,就可以加入一些社交元素。比如当你看到一条有意思的预言,可以给它点赞。

  • 可打赏:不止是点赞,你甚至还可以给预言的作者打赏。

先说 “点赞”,这个功能相对比较好实现,合约端新增一个点赞接口,再给预言数据增加一个点赞数的字段,差不多就可以了。

再看 “多用户” 和 “打赏” 功能,乍一看很复杂,但其实在区块链上非常容易实现。

在开发传统 Web App 的时候,如果要识别不同用户,往往需要自己做一套账号系统,或者对接第三方社交账号。而在区块链上就不用这么麻烦,因为每个在链上的用户都有自己独一无二的身份标识——“地址”。DApp 通过地址就可以区分每位用户。

此外,在传统应用中如果要实现打赏功能,就需要接入支付平台,比如银联、支付宝或微信支付等。但这对个人开发者来说是极为困难的。别急,这里又体现出 DApp 的优势了——区块链的老本行就是记账,每条公链通常都有自己的原生货币系统,DApp 直接使用链的支付功能就可以了。

区块链 “原生的账号系统” 和 “原生的支付系统”,堪称 DApp 的两大天生神力!

这样一个 DApp 最终确实被做了出来,叫作 “我是预言帝”。这实际上也是魔法哥自己学习开发 DApp 的第一款作品。

另一个经常被问到的问题是:大家经常提到区块链 “不可篡改”,到底是指什么?小明的女朋友凭什么相信他?

在看完上面的实战案例之后,大家很可能会产生一个疑惑:我可以通过调用合约来更新合约存储区,这算不算 “篡改” 呢?

简单解释一下,区块链的 “不可篡改” 特性,主要有以下两个层面来构成:

  • 不可撤消

    区块链的精髓之一在于链式的数据结构,链式结构保证了新区块一旦追加到链上,就再也无法修改或撤消——这是因为链上的所有区块环环相扣,如果有节点试图修改其中一个区块,后续的区块就无法接上,这个修改会立刻被其它节点发现并判为非法。

    因此,一笔交易一旦上链,就成为历史的一部分,永久地铭刻在那里。

  • 公开透明

    对于公链来说,链上的所有数据都是公开可查的。各条公链通常都会提供一种叫 “区块浏览器” 的工具,通过它可以方便地查到所有区块的内容、每笔交易的详情、任意地址的行为记录,甚至还有智能合约的源代码。

    这意味着区块链上的每一次操作都是公开透明的,智能合约的运行逻辑和数据记录也都是公开透明的,没有暗箱操作的可能性。

说到这里,我们再来回顾一下 “修改合约存储区” 的过程:调用合约来更新存储区,本质上是一次交易,需要打包上链才能生效。因此,“修改合约存储区” 这个操作并不是直接修改已经在链上的历史记录,而是通过新记录在老记录上打补丁,我们在任一时刻得到的数据其实是所有修改记录叠加的结果。

因此,对于 DApp 来说,“不可篡改” 并不是说我们无法修改合约的存储区,而是说任何人都无法 “偷偷摸摸地修改”,因为每一次的修改记录都会明明白白地记录在链上。

讲完这个原理,我们可以把故事的结尾再补充一下。如果小明的女朋友想验证这个 DApp 上展示的预言是否真实可靠,她还需要做这两件事情:

  • Review 合约代码:确认合约的逻辑是否正常。

  • 核对合约的调用记录:确认预言是怎么提交到合约的。

第三个问题,开发者特别关心 DApp 的应用场景。目前已经明朗的应用场景有以下一些:

  • 存证:利用区块链的不可篡改特性来实现存证的需求。比如小明的预言 DApp 就可以归为这一类。

  • 数字资产:加密猫很好地向大众普及了 “数字资产” 的概念,区块链和智能合约可以对数字资产进行确权。

  • 游戏:游戏中虚拟货币和道具的概念与区块链天然契合,目前最火的 DApp 也几乎都是从这个领域里涌现出来的。

实际上区块链应用还处在早期,更多的落地场景还有待我们去探索和发现。

第四个问题,有兴趣尝试 DApp 开发的同学肯定希望获取演讲中提到的各种工具和资源。

由于 DApp 开发需要掌握和学习的资料非常多,魔法哥特别整理了一个资料库,并已在 GitHub 开源:
https://github.com/NasaTeam/Awesome-Nebulas

文中提到的第三方 SDK Nasa.js 实际上也是由魔法哥组队开发的,同样在 GitHub 开源,欢迎你一起来打磨它:
https://github.com/NasaTeam/Nasa.js

写在最后


由于某些原因,区块链技术和区块链行业一直被广泛误解。一方面它被夸大为万能的银弹,一方面它的基础设施还极为简陋,这令很多人敬而远之,甚至 “路转黑”。区块链虽然已经诞生了近十年,但在应用层面仍然非常早期,它还有极大的不确定性,还有无数的未知等待我们去探索。

就像这张图,一片荒芜。探索者们独孤前行,然而他们相信光明的未来。

有人说,“区块链是风口、是潮流”。而我想说的是,“我们不跟随潮流,我们推动潮流——因为我们是开发者”。区块链是什么、能做什么,将由我们这些开发者来定义。期待有更多的开发者加入到这个新世界,我在这里等你!

 活动推荐

推荐一个年末不可错过的线下技术大会,学习来自 Google、微软、亚马逊、BAT、京东、美团、华为等 40+AI 落地案例的干货总结,大会日程已新鲜出炉,点击“阅读原文”即可查看。欢迎扫码下方二维码了解更多大会详情,也可咨询票务小姐姐 Amy 18514549229(微信同号)。



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/Mkn429zXjp
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/27103
 
22 次点击  
分享到微博