关闭

NodeJS实现简易区块链

时间: 2019-05-03阅读: 689标签: 区块链

之前由于课程要求,基于Nodejs做了一个实现简易区块链。要求非常简单,结构体记录区块结构,顺便能向链中插入新的区块即可。

但是如果要支持多用户使用,就需要考虑“可信度”的问题。那么按照区块链要求,链上的数据不能被篡改,除非算力超过除了攻击者本身之外其余所以机器的算力。

想了想,就动手做试试咯。


技术调研

在google上搜了搜,发现有个项目不错: https://github.com/lhartikk/naivechain 。大概只有200行,但是其中几十行都是关于搭建ws和http服务器,美中不足的是没有实现批量插入区块链和计算可信度。结合这个项目,基本上可以确定每个区块会封装成一个class(结构化表示),区块链也封装成一个class,再对外暴露接口。


区块定义

为了方便表示区块,将其封装为一个class,它没有任何方法:

/**
 * 区块信息的结构化定义
 */
class Block {
  /**
   * 构造函数
   * @param {Number} index 
   * @param {String} previousHash 
   * @param {Number} timestamp 
   * @param {*} data 
   * @param {String} hash 
   */
  constructor(index, previousHash, timestamp, data, hash) {
    this.index = index // 区块的位置
    this.previousHash = previousHash + '' // 前一个区块的hash
    this.timestamp = timestamp // 生成区块时候的时间戳
    this.data = data // 区块本身携带的数据
    this.hash = hash + '' // 区块根据自身信息和规则生成的hash
  }
}

至于怎么生成hash,这里采用的规则比较简单:

  1. 拼接index、previouHash、timestamp和data,将其字符串化
  2. 利用sha256算法,计算出的记过就是hash

为了方便,会引入一个加密库:

const Cryptojs = require('crypto-js')


链结构定义

很多区块链接在一起,就组成了一条链。这条链,也用class来表示。并且其中实现了很多方法:

  1. 按照加密规则生成hash
  2. 插入新块和检查操作
  3. 批量插入块和检查操作以及可信度计算

1. 起源块

起源块是“硬编码”,因为它前面没数据呀。并且规定它不能被篡改,即不能强制覆盖。我们在构造函数中,直接将生成的起源块放入链中。

class BlockChain {
  constructor() {
    this.blocks = [this.getGenesisBlock()]
  }

  /**
   * 创建区块链起源块, 此块是硬编码
   */
  getGenesisBlock() {
    return new Block(0, '0', 1552801194452, 'genesis block', '810f9e854ade9bb8730d776ea02622b65c02b82ffa163ecfe4cb151a14412ed4')
  }
}

2. 计算下一个区块

BlockChain对象可以根据当前链,自动计算下一个区块。并且与用户传来的区块信息比较,如果一样,说明合法,可以插入;否则,用户的区块就是非法的,不允许插入。

// 方法都是BlockChain对象方法
  /**
   * 根据信息计算hash值
   */
  calcuteHash(index, previousHash, timestamp, data) {
    return CryptoJS.SHA256(index + previousHash + timestamp + data) + ''
  }

  /**
   * 得到区块链中最后一个块节点
   */
  getLatestBlock() {
    return this.blocks[this.blocks.length - 1]
  }

  /**
   * 计算当前链表的下一个区块
   * @param {*} blockData 
   */
  generateNextBlock(blockData) {
    const previousBlock = this.getLatestBlock()
    const nextIndex = previousBlock.index + 1
    const nextTimeStamp = new Date().getTime()
    const nextHash = this.calcuteHash(nextIndex, previousBlock.hash, nextTimeStamp, blockData)
    return new Block(nextIndex, previousBlock.hash, nextTimeStamp, blockData, nextHash)
  }

3. 插入区块

插入区块的时候,需要检查当前块是否合法,如果合法,那么插入并且返回true;否则返回false。

  /**
   * 向区块链添加新节点
   * @param {Block} newBlock 
   */
  addBlock(newBlock) {
    // 合法区块
    if(this.isValidNewBlock(newBlock, this.getLatestBlock())) {
      this.blocks.push(newBlock)
      return true  
    }
    return false
  }

检查的逻辑就就放在了 isValidNewBlock 方法中, 它主要完成3件事情:

  1. 判断新区块的index是否是递增的
  2. 判断previousHash是否和前一个区块的hash相等
  3. 判断新区块的hash是否按约束好的规则生成
  /**
   * 判断新加入的块是否合法
   * @param {Block} newBlock 
   * @param {Block} previousBlock 
   */
  isValidNewBlock(newBlock, previousBlock) {
    if(
      !(newBlock instanceof Block) ||
      !(previousBlock instanceof Block)
    ) {
      return false
    }

    // 判断index
    if(newBlock.index !== previousBlock.index + 1) { 
      return false
    }

    // 判断hash值
    if(newBlock.previousHash !== previousBlock.hash) { 
      return false
    }

    // 计算新块的hash值是否符合规则
    if(this.calcuteHash(newBlock.index, newBlock.previousHash, newBlock.timestamp, newBlock.data) !== newBlock.hash) { 
      return false
    }

    return true
  }

4. 批量插入

批量插入的逻辑比较复杂,比如当前链上有4个区块的下标是:0->1->2->3。除了起源块0不能被覆盖,当插入一条新的下标为“1->2->3->4”的链时候,就可以替换原来的区块。最终结果是:0->1->2->3->4。

在下标index的处理上,假设还是上面的情况,如果传入的链的下标是从大于4的整数开始,显然无法拼接原来的区块链的下标,直接扔掉。

但是如何保证可信度呢?就是当新链(B链)替换原来的链(A链)后,生成新的链(C链)。如果 length(C) > length(A),那么即可覆盖要替换的部分。 这就保证了,只有在算力超过所有算力50%的时候,才能篡改这条链 。

插入新链的方法如下:

  /**
   * 插入新链表
   * @param {Array} newChain 
   */
  addChain(newChain) {
    if(this.isValidNewChain(newChain)) {
      const index = newChain[0].index
      this.blocks.splice(index)
      this.blocks = this.blocks.concat(newChain)
      return true
    }
    return false
  }

实现上面所述逻辑的方法如下:

  /**
   * 判断新插入的区块链是否合法而且可以覆盖原来的节点
   * @param {Array} newChain 
   */
  isValidNewChain(newChain) {
    if(Array.isArray(newChain) === false || newChain.length === 0) {
      return false
    }

    let newChainLength = newChain.length,
      firstBlock = newChain[0]

    // 硬编码的起源块不能改变
    if(firstBlock.index === 0) {
      return false
    }

    // 移植新的链的长度 <= 现有链的长度
    // 新的链不可信
    if(newChainLength + firstBlock.index <= this.blocks.length) {
      return false
    }

    // 下面检查新的链能否移植
    // 以及新的链的每个节点是否符合规则
    if(!this.isValidNewBlock(firstBlock, this.blocks[firstBlock.index - 1])) {
      return false
    }

    for(let i = 1; i < newChainLength; ++i) {
      if(!this.isValidNewBlock(newChain[i], newChain[i - 1])) {
        return false
      }
    }

    return true
  }

5. 为什么需要批量插入?

我当时很奇怪,为什么需要“批量插入”这个方法。后来想明白了(希望没想错)。假设服务器S,以及两个用户A与B。

A与B同时拉取到已知链的数据,然后各自生成。A网速较快,但是算力低,就生成了1个区块,放入了S上。注意:此时S上的区块已经更新。

而B比较惨了,它在本地生成了2个区块,但是受限于网速,只能等网速恢复了传入区块。这时候,按照规则,它是可以覆盖的(算力高嘛)。所以这种情况下,服务器S接受到B的2个区块,更新后的链长度是3(算上起源块),并且A的那个区块已经被覆盖了。


效果测试

虽然没有写服务器,但是还是模拟了上面讲述的第5种情况。代码在 test.js 文件中,直接run即可。看下效果截图吧:


红线上面就是先算出来的,红线下面就是被算力更高的客户端篡改后的区块链。具体模拟过程可以看代码,这里不再冗赘了。

全部代码在都放在: https://github.com/dongyuanxin/node-blockchain

原文链接:https://godbmw.com/passages/2019-05-02-node-block-chain/


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/3181

关闭

区块链的六大层级结构

众所周知, 区块链 是 比特币 的底层技术,那么这个底层技术又是怎么分层级结构的呢?在前面我们介绍了区块链的四大核心技术是其独特的数据结构、分布式存储、密码学和共识机制。今天我们就来聊聊区块链结构的六个层级结构

Web 3.0 前瞻:基于区块链的下一代浏览器

​现在有很多人把区块链崛起成为明星技术的历程,与互联网商业发展的黎明时代相提并论。在 90 年代初期,许多人对待新鲜技术持谨慎态度,却很少有人真正预见到人类的创新活动将会在未来 20 年中拓展到多远的边界

如何使用Vue.js 开发以太坊DApp

Vue 是一套在前端开发中广泛采用的用于构建用户界面的渐进式JavaScript框架。Vue 通过响应的数据绑定和组合的视图组件让界面开发变得非常的简单。这边文章来看看如何使用Vue开发以太坊DApp。

区块链挖矿原来是这么一回事

在整个数字货币领域,很多人都知道挖矿,然而,有些人认为挖矿很赚钱,也有人认为挖矿就是个坑。但是对于挖矿而言,其本质是一种加密的计算。

区块链 PoW 与 PoS 的纷争

有关注区块链的,肯定会经常看到这两个名词 -- PoW 与 PoS。但是很多人对他们的含义的理解存在很多偏差。那么他们的含义与区别是什么呢?简单而言,PoW 和 PoS 是 2 种不同的对记账权利的分配方式。

区块链开发中使用的最流行的编程语言

我们目前正处于一个新兴的区块链开发行业中。区块链技术处于初期阶段,然而这种颠覆性技术已经成功地风靡全球,并且最近经历了一场与众不同的繁荣。由于许多资金充足的项目现在急于建立区块链网络并在其上部署分散的应用程序

区块链是否真如我们想象的那般安全?

如今区块链已成功被黑客攻破。因此我认为,随着区块链技术变得更易于人们使用,安全性将很可能成为区块链落地方面的一个重点问题,那些频繁与区块链打交道的领头公司应更加注意

传统业务如何运用区块链技术

随着十几年的区块链技术的发展,比特币不再是作为区块链应用的代表。随着区块链的去中心化、不可纂改等特性被人熟悉后,传统企业要生存,那么就要创新,故越来越多的传统企业开始转型

12个问题讲明白什么是区块链技术?

为什么要使用区块链技术? 虽然分布式账本肯定有很多优点,但它可能不适用于每个人或所有公司,至少目前还不适用。人们在听到区块链时,通常会产生疑问:区块链是什么?

区块链与数据库到底有何不同?只是名字不一样吗?

区块链被诟病的一大原因,就是区块链分布式账本技术(DLT)已经被吹捧成了一剂包治百病的良药,从支付处理和供应链跟踪到数字身份,再到版权保护

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!