社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  区块链

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

区块链前哨 • 6 年前 • 637 次点击  

导语:魔法哥在 “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

写在最后


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

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

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


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/XYkFr5M9m0
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/26860
 
637 次点击