连编程语言都不懂?看完这篇你也会写区块链

咨询了一下业内的程序员叔叔们,对于写区块链的语言他们是这样说的:

“本质上,原理搞懂了,什么主流语言都能实现。”

“呵呵”

狼而,我连什么是编程语言都不懂。

中成才叔叔解释道:

“我们知道,从远古时期到当代,建筑的形态经历了巨变。原材料也从山洞、石板、木材、水泥、钢材演变到复合木材。

但原材料要能够被用于构筑大型建筑,还需要先把它们改造成各种不同形状不同用途的半成品材料,再由这些半成品材料二次组装成完整建筑。

各种不同的【编程语言】就像这不同的建筑原材料,每一种都能够建造出完整的建筑,也可以混合使用。而这些半成品材料,就是这个语言的【类库】,他们决定了这个到底语言能够构建什么样的项目。

类库到底有多重要,开发起来又有多难呢?想想为什么手机操作系统只有 Android 和 iOS,而我国就开发不出来自己的手机操作系统呢?说明这个世界上,有能力建造这种类库的组织只有这两家,这比生产建筑预制材料其实更难。而像这种功能单一数量庞大的类库叫做 SDK,有了它们,我们才能够花很少的人在短时间内开发出一个 App。

编程语言同时又是一种粘合剂,要把这些类库粘合起来才能开发出一个项目,这往往也需要好几个月甚至几年,与建楼的复杂度无异!”

区块链学习更多的是去理解这种去中心化的思想和去中心化的价值所在,语言是程序员们的执行工具。不过由于以太坊和Hyperledger Fabric 对go语言支持最好,所以go语言肯定是要学习的。并且go更专业一些,但是JavaScript 门槛低,运行效率也低,JavaScript 大多用于网页,在服务端跑也是可以。

废话少说,今天将会用 JavaScript 来创建一个简单的区块链来演示它们的内部究竟是如何工作的。

具体分为以下三个部分:

实现一个基本的区块链

实现 POW

交易与挖矿奖励

实现一个基本的区块链

区块链

区块链是由一个个任何人都可以访问的区块构成的公共数据库。这好像没什么特别的,不过它们有一个有趣的属性:它们是不可变的。

一旦一个区块被添加到区块链中,除非让剩余的其余区块失效,否则它是不会再被改变的。

这就是为什么加密货币是基于区块链的原因。你肯定不希望人们在交易完成后再变更交易!

创造一个区块

区块链是由许许多多的区块链接在一起的(这听上去好像没毛病..)。链上的区块通过某种方式允许我们检测到是否有人操纵了之前的任何区块。

那么我们如何确保数据的完整性呢?每个区块都包含一个基于其内容计算出来的 hash。同时也包含了前一个区块的 hash。

下面是一个区块类用 JavaScript 写出来大致的样子:

因为 JavaScript 中并不支持 sha256 所以我引入了 crypto-js 库。然后我定义了一个构造函数来初始化区块的属性。

每一个区块上都被赋予了 index 属性来告知我们这个区块在整个链上的位置。我们同时也生成了一个时间戳,以及需要在区块里存储的一些数据。最后是前一个区块的 hash。

创造一个链

现在我们可以在 Blockchain 类中将区块链接起来了。下面是用 JavaScript 实现的代码:

在构造函数里,我通过创建一个包含创世块的数组来初始化整个链。第一个区块是特殊的,因为它不能指向前一个区块。

我还添加了下面两个方法:

getLatestBlock() 返回我们区块链上最新的区块。

addBlock() 负责将新的区块添加到我们的链上。

为此,我们将前一个区块的 hash 添加到我们新的区块中。这样,我们就可以保持整个链的完整性。

因为只要我们变更了最新区块的内容,我们就需要重新计算它的 hash。当计算完成后,我将把这个区块推进链里(一个数组)。

最后,我创建一个 isChainValid() 来确保没有人篡改过区块链。它会遍历所有的区块来检查每个区块的 hash 是否正确。

它会通过比较 previousHash 来检查每个区块是否指向正确的上一个区块。如果一切都没有问题,它会返回 true 否则会返回 false。

使用区块链

我们的区块链类已经写完啦,可以真正的开始使用它了。

在这里我仅仅是创建了一个区块链的实例,并且命名它为 SavjeeCoin。之后我在链上添加了一些区块。

区块里可以包含任何你想要放的数据,不过在上面的代码里,我选择添加了一个带有 amount 属性的对象。

试着操作吧!

在介绍里我曾说过区块链是不可变的。一旦添加,区块就不可能再变更了。让我们试一下。

我会在一开始通过运行 isChainValid() 来验证整个链的完整性。我们操作过任何区块,所以它会返回 true。

之后我将链上的第一个(索引为 1)区块的数据进行了变更。之后我再次检查整个链的完整性,发现它返回了 false。我们的整个链不再有效了。

结论

这个小栗子还远未达到完成的程度。它还没有实现 POW(工作量证明机制)或 P2P 网络来与其他矿工来进行交流。

但它确实证明了区块链的工作原理。许多人认为原理会非常复杂,但这篇文章证明了区块链的基本概念是非常容易理解和实现的。

实现 POW

在上文中我们用 JavaScript 创建了一个简单的区块链来演示区块链的工作原理。

不过这个实现并不完整,很多人发现依旧可以篡改该系统。没错!我们的区块链需要另一种机制来抵御攻击。让我们来看看我们该如何做到这一点。

问题

现在我们可以很快的创造区块,然后非常迅速的将它们添加进我们的区块链中。

不过这导致了三个问题:

人们可以快速创建区块,然后在我们的链里塞满垃圾。大量的区块会导致我们区块链过载并让它无法使用。

因为创建一个有效的区块太容易了,人们可以篡改链中的某一个区块,然后重新计算所有区块的 hash。即使它们已经篡改了区块,他们仍然可以以有效的区块来作为结束。

你可以通过结合上述两个破绽来有效控制区块链。区块链由 P2P 网络驱动,其中节点会将区块添加到可用的最长链中。

所以你可以篡改区块,然后计算所有其他的区块,最后添加任意多你想要添加的区块。你最后会得到一个最长的链,所有的其他节点都会接受它,然后往上添加自己的区块。

显然我们需要一个方案来解决这些问题:POW(proof-of-work:工作量证明)。

什么是 POW

POW 是在第一个区块链被创造之前就已经存在的一种机制。这是一项简单的技术,通过一定数量的计算来防止滥用。

工作量是防止垃圾填充和篡改的关键。如果它需要大量的算力,那么填充垃圾就不再值得。

比特币通过要求 hash 以特定 0 的数目来实现 POW。这也被称之为难度,不过等一下!一个区块的 hash 怎么可以改变呢?

在比特币的场景下,一个区块包含有各种金融交易信息。我们肯定不希望为了获取正确的 hash 而混淆了那些数据。

为了解决这个问题,区块链添加了一个 Nonce 值。Nonce 是用来查找一个有效 hash 的次数。

而且,因为无法预测 hash 函数的输出,因此在获得满足难度条件的 hash 之前,只能大量组合尝试。寻找到一个有效的 hash(创建一个新的区块)在圈内称之为挖矿。

在比特币的场景下,POW 确保每 10 分钟只能添加一个区块。你可以想象垃圾填充者需要多大的算力来创造一个新区块,他们很难欺骗网络,更不要说篡改整个链。

实现 POW

我们该如何实现呢?我们先来修改我们区块类并在其构造函数中添加 Nonce 变量。我会初始化它并将其值设置为 0。

我们还需要一个新的方法来增加 Nonce,直到我们获得一个有效 hash。强调一下,这是由难度决定的。所以我们会收到作为参数的难度。

最后,我们还需要更改一下 calculateHash() 函数。因为目前它还没有使用 Nonce 来计算 hash。

将它们结合在一起,你会得到如下所示的区块类:

修改区块链

现在,我们的区块已经拥有 Nonce 并且可以被开采了,我们还需要确保我们的区块链支持这种新的行为。

让我们先在区块链中添加一个新的属性来跟踪整条链的难度。我会将它设置为 2(这意味着区块的 hash 必须以 2 个 0 开头)。

现在剩下要做的就是改变 addBlock() 方法,以便在将其添加到链中之前确保实际挖到该区块。下面我们将难度传给区块。

大功告成!我们的区块链现在拥有了 POW 来抵御攻击了。

测试

现在让我们来测试一下我们的区块链,看看在 POW 下添加一个新区块会有什么效果。

我将会使用之前的代码,我们将创建一个新的区块链实例,然后往里添加 2 个区块。

如果你运行了上面的代码,你会发现添加新区块依旧非常快。这是因为目前的难度只有 2(或者你的电脑性能非常好)。

如果你创建了一个难度为 5 的区块链实例,你会发现你的电脑会花费大概 10 秒钟来挖矿。随着难度的提升,你的防御攻击的保护程度越高。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180330A1UB5900?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券