javascript实现小型区块链功能


Posted in Javascript onApril 03, 2019
区块链概念
狭义:区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构,并以密码方式保证的不可篡改和不可伪造的分布式账本。
一、挖矿(产生新区块)

首先,区块链是由每一个区块联系而形成的,在产生新区块之前必须先有一个最初始的区块,这个区块也叫创世区块。通过这个创世区块,不停地通过变化随机数(nonce)来计算出符合条件的区块。以下是创世区块基本信息:

const initBlock = {
 index: 0,
 data: 'hey,this is a block chain',
 previousHash: '0',
 timestamp: '1551806536961',
 nonce: 80490,
 hash: '0000352fb27dd1141fa7265833190a53e5776b1111e275db0d9a77bf840081e6'
};
  1. index:是指每个区块的序号
  2. data: 这里存放着区块中所有的信息,例如转账,余额等数据
  3. previousHash: 指的是上一个区块的hash值,创世区块没有上一个,显示0即可
  4. timestamp:指的是创建这个区块的时间
  5. nonce:这个是随机数,挖矿就是通过不停变换这个nonce来计算出符合条件的哈希。
  6. hash: 本区块的hash值,通过前面5个字段的信息进行hash运算得出的值。

接着,通过不停的hash运算计算出符合条件的哈希,即挖矿。挖矿也可以调节难度的大小,例如算出的哈希值必须前3位数必须为1或者末3位数必须为1等等,这个可以自行的去定义,只要最后留一个控制的开关,方便控制即可。可以在定义一个变量

哈希的计算:

.createHash('sha256')
 .update(index + data + previousHash + timestamp + nonce)
 .digest('hex')
_that.difficulty = 3 // 即前3位或者末3位数必须为1,数量越多难度越大

生成了符合条件的hash之后,则产生了新的区块,但是还要对这个区块进行校验看看是否有效,因为可能这是一个被篡改的非法的区块,也有可能和这个链没有任何关系的区块而仅仅只是符合上述哈希的规则而已。所以,需要进行一下校验,,前后区块的有效性。

isValidaBlock(newBlock,lastBlock) {
  if (newBlock.index !== lastBlock.index+1) return false
  if (newBlock.previousHash !== lastBlock.hash) return false
  if (newBlock.timestamp <= lastBlock.timestamp) return false
  if (newBlock.hash.slice(1 ,_that.difficulty) !== '1'.repeat(_that.difficulty)) return false
  if (newBlock.hash !== this.computeHashForBlock(newBlock)) return false //确保随机数正确
  // 都满足则返回true
  return true
 }

除了上面的校验之外,还需要使用上面这个函数对整一个chain进行一个每一个块的校验,以保证每一个块的信息是正确的,是没有被篡改过的是合法的。

二、构建P2P网络

区块链的网络是去中心化的,即没有中心服务器的网络,客户端不需要依赖中心服务器来获取或者处理数据。区块链网络中,有这许许多多的节点,每个节点都是一个独立的成员,他们既是客户端也是服务器,节点与节点直接都是点对点进行连接(peer-to-peer),不需要通过某一个中心服务器进行中转,所以,信息安全的角度来说,点对点的连接方式对信息私密性是非常可靠的。

javascript实现小型区块链功能

虽然,区块链是通过点对点的连接方式进行数据传输,但是,在这之前还需要一个东西作为引导,这个就是种子节点。因为,两个节点之间他们可能不是处在同一个域下,他们之间想要联系,必须有一方知道对方的ip和端口,这样才能和对方联系上。节点ip和端口号,在这个节点创建出来之后,种子节点就会发给它在这个区块链中所有节点的ip和端口号同时记录下这个新伙伴的ip和端口号。

那么,新的节点拿到了这一份"通讯录"之后,就会给这个"通讯录"中的所有小伙伴发个消息,告诉他们有一位新的小伙伴加入,之后,其他节点收到了这个信息,也会在自己的"通讯录"中加上新伙伴的ip和端口号,相当于加入了白名单。这样新的节点接下来就可以和任意的的节点进行通信了。

下面用代码演示一下:

(res)=>{
 _that.remotePeerInfo = res.data.data //1
 _that.addPeersList(res.peersList)    //2
 _that.boardCast(_that.remotePeerInfo) //3
 _that.blockChainUpdate(blockChain,blockData)  //4
}

addPeersList(peers) {
 peers.forEach(peer => {
  if (!_that.peers.find(v => _that.isEqualPeer(peer, v))) {
   _that.peers.push(peer)
  }
 })
}

boardCast(remotePeerInfo) {
 this.peers.forEach(v => {
  this.send(action, v.port, v.address)
 })
}

blockChainUpdate(blockChain,blockData){
 if(newChain.length === 1 ){
 return
 }

 if(_that.isValidaChain(newChain) && newChain.length>_that.blockchain.length){
 _that.blockchain = Object.assign({}, newChain)
 }else{
 console.log('error')
 return
 }

 if (trans.every(v => _that.isValidTransfer(v))) {
 _that.data = trans
 }
}

1.保存种子节点传来的此新节点的信息包括ip和端口号,因为,新节点的ip和端口号是会有改变的情况。

2.接受种子节点传来的节点列表,将列表的节点遍历检查一下,没有相同的就写进列表中。

3.将新节点的信息广播到所有的节点上,同时接受到信息的节点更新一下节点列表

4.将区块链上信息同步一份都本地,同时对种子节点传来的blockchain进行每个区块的信息

三、转账交易

BTC的交易模型是使用的是UTXO

javascript实现小型区块链功能

而这个小型区块链的交易模型使用的是最简单的方法。

区块链中"现金”,它是一个虚拟的东西就是一个字符串,来源于挖矿。每次挖矿成功都会有一定的奖励,得到的这些“钱”就可以在区块链网络中自由的转账交易。

在区块链中,进行记录转账交易的时候是需要一个加密的算法,把所有的信息进行加密之后再push到新区块中的data中,从而完成一笔新交易的记录。以BTC为例,BTC的加密算法是使用elliptic这个加密算法,elliptic是一个非对称性的加密算法,非对称的加密算法的特点就是,私钥是惟一的,只有拥有者才可以和他私钥对应的公钥进行校验 。 nodejs也有对应的库在github上搜索elliptic即可。

{
 "privateKey": "34a425df3eb1f22fb6cb74b0e7298b16ffd7f3fb",
 "publicKey": "ac208623a38d2906b090dbcf3a09378dfe79b77bf39c2b753ef98ea94fe08dc3995a1bd05c917"
}

上面是一个生成好的密钥对格式,仅作为展示,我删减了一部分长度。

使用银行卡进行转账交易的时候,会有一个转出的账号和一个转入的账号,在区块链中的记账也会有这个账号,这个账号就是上面使用生成的密钥对中的公钥,公钥就是地址,或者说公钥代表的就是自己的钱包。

校验的方法,首先使用字段“from”,“to”,“amount”的参数进行sign签名,然后在每次挖矿(记账)的时候,则使用verify(),通过前面的三个参数,和sig进行校验

verify(type,data){
 swtich(type){
  case 'sign':
   const bufferMsg = Buffer.from(`${data.from}-${data.to}-${data.amount}`)
   let signature = Buffer.from(keypair.sign(bufferMsg).toDER()).toString('hex')
    this.signature = signature
  break;
  case 'verify':
    const keypairTemp = ec.keyFromPublic(pub, 'hex')
    const bufferMsg = Buffer.from(`${data.from}-${data.to}-${data.amount}`)
    this.keypair = keypairTemp.verify(bufferMsg, sig)
  break;
  default;
 }
}

转帐的时候需要3步,分别是校验转出账户是否有足够的金额,转出账户就是本地公钥。如有则进行记账并且使用两个地址、金额、时间,还有签名加密打包,之后进行全节点广播。其他节点收到这个信息之后第一件事也是对新区块的有效性做一个校验,通过校验之后就会写入data中。

transfer(data) {
 const timestamp = new Date().getTime()
 const sig = rsa.sign({data.from, data.to, data.amount , timestamp})
 const sigTrans = {data.from, data.to, data.amount ,timestamp, sig }

  // 非创世区块
 if (trans.from !== '0') {
   // 检验余额
  if (!(_that.blance < amount)) { //_that.blance 当前账户余额
   //全节点广播
   _that.send('trans', sigTrans)
  }else{
   console.log('not enough blance')
   return
  }
 }
 this.data.push(sigTrans)
 return sigTrans
}

其他节点收到消息之后,先进行去重校验,然后再更新数据。

四、查询余额

这个链的查询方法比较简单,就是将区块中的每一条交易的信息进行校验和匹配,满足条件的就进行增减,同时忽略精度上的问题。

this.blance = blance(address)
 blance(address) {
  let blance = 0;
  this.blockchain.forEach(block => {
   block.data.forEach(trans => {
    if (address == trans.from) {
     blance -= trans.amount
    }

    if (address == trans.to) {
     blance += trans.amount
    }

   })

  });
  return blance
 }

至此,区块链的最简单的功能就实现完毕。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
js验证表单第二部分
Nov 25 Javascript
syntaxhighlighter 使用方法
Jul 02 Javascript
Javascript 浮点运算的问题分析与解决方法
Aug 27 Javascript
Ionic实现仿通讯录点击滑动及$ionicscrolldelegate使用分析
Jan 18 Javascript
使用three.js 画渐变的直线
Jun 05 Javascript
完美解决jQuery fancybox ie 无法显示关闭按钮的问题
Nov 29 Javascript
node.js中TCP Socket多进程间的消息推送示例详解
Jul 10 Javascript
jQuery使用$.extend(true,object1, object2);实现深拷贝对象的方法分析
Mar 06 jQuery
JavaScript 性能提升之路(推荐)
Apr 10 Javascript
解决微信小程序云开发中获取数据库的内容为空的方法
May 15 Javascript
vue仿ios列表左划删除
Sep 26 Javascript
详解vue3中组件的非兼容变更
Mar 03 Vue.js
vue插槽slot的理解和使用方法
Apr 03 #Javascript
react写一个select组件的实现代码
Apr 03 #Javascript
vue框架下部署上线后刷新报404问题的解决方案(推荐)
Apr 03 #Javascript
JavaScript变速动画函数封装添加任意多个属性
Apr 03 #Javascript
JS中注入eval, Function等系统函数截获动态代码
Apr 03 #Javascript
性能优化篇之Webpack构建速度优化的建议
Apr 03 #Javascript
elementUI多选框反选的实现代码
Apr 03 #Javascript
You might like
老机欣赏|中国60年代精品收音机
2021/03/02 无线电
PHP实现异步调用方法研究与分享
2011/10/27 PHP
PHP中数组定义的几种方法
2013/09/01 PHP
php的socket编程详解
2016/11/20 PHP
php 从指定数字中获取随机组合的简单方法(推荐)
2017/04/05 PHP
javascript[js]获取url参数的代码
2007/10/17 Javascript
SWFObject 2.1以上版本语法介绍
2010/07/10 Javascript
为radio类型的INPUT添加客户端脚本(附加实现JS来禁用onClick事件思路代码)
2010/11/11 Javascript
jQuery UI的Dialog无法提交问题的解决方法
2011/01/11 Javascript
js禁止页面使用右键(简单示例代码)
2013/11/13 Javascript
利用JS判断用户是否上网(连接网络)
2013/12/23 Javascript
jQuery实现table隔行换色和鼠标经过变色的两种方法
2014/06/15 Javascript
一行命令搞定node.js 版本升级
2014/07/20 Javascript
JavaScript采用递归算法计算阶乘实例
2015/08/04 Javascript
微信小程序 闭包写法详细介绍
2016/12/14 Javascript
JS实现HTML标签转义及反转义
2020/04/14 Javascript
shiro授权的实现原理
2017/09/21 Javascript
JS/jQuery实现DIV延时几秒后消失或显示的方法
2018/02/12 jQuery
[00:37]食人魔魔法师轮盘吉兆顺应全新至宝将拥有额外款式
2019/12/19 DOTA
列举Python中吸引人的一些特性
2015/04/09 Python
python实现查找两个字符串中相同字符并输出的方法
2015/07/11 Python
python 中文件输入输出及os模块对文件系统的操作方法
2018/08/27 Python
利用arcgis的python读取要素的X,Y方法
2018/12/22 Python
对python以16进制打印字节数组的方法详解
2019/01/24 Python
对Python _取log的几种方式小结
2019/07/25 Python
Python 操作mysql数据库查询之fetchone(), fetchmany(), fetchall()用法示例
2019/10/17 Python
Python3.9最新版下载与安装图文教程详解(Windows系统为例)
2020/11/28 Python
科茨沃尔德家居商店:Scotts of Stow
2018/06/29 全球购物
泰国第一在线超市:Tops
2021/02/13 全球购物
优秀毕业生自我鉴定
2014/01/19 职场文书
大一工商管理职业生涯规划:有梦最美,行动相随
2014/09/18 职场文书
向国旗敬礼学生寄语大全
2014/09/30 职场文书
一年级班主任工作总结2014
2014/11/08 职场文书
2014年质检员工作总结
2014/11/18 职场文书
2016年元旦致辞
2015/08/01 职场文书
Java中PriorityQueue实现最小堆和最大堆的用法
2021/06/27 Java/Android