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 相关文章推荐
几个比较实用的JavaScript 测试及效验工具
Apr 18 Javascript
Json2Template.js 基于jquery的插件 绑定JavaScript对象到Html模板中
Oct 29 Javascript
jCallout 轻松实现气泡提示功能
Sep 22 Javascript
jQuery实现带滚动线条导航效果的方法
Jan 30 Javascript
基于jQuery实现仿淘宝套餐选择插件
Mar 04 Javascript
使用Angular缓存父页面数据的方法
Jan 03 Javascript
jQuery+C#实现参数RSA加密传输功能【附jsencrypt.js下载】
Jun 26 jQuery
vue.js使用v-pre与v-html输出HTML操作示例
Jul 07 Javascript
微信小程序定位当前城市的方法
Jul 19 Javascript
关于vue编译版本引入的问题的解决
Sep 17 Javascript
基于Vue和Element-Ui搭建项目的方法
Sep 06 Javascript
微信小程序实现同时上传多张图片
Feb 03 Javascript
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
PHP 实现多服务器共享 SESSION 数据
2009/08/15 PHP
PHP生成验证码时“图像因其本身有错无法显示”的解决方法
2013/08/07 PHP
php中删除数组的第一个元素和最后一个元素的函数
2015/03/07 PHP
PHP闭包函数详解
2016/02/13 PHP
图文详解phpstorm配置Xdebug进行调试PHP教程
2016/06/13 PHP
Yii框架引入coreseek分页功能示例
2019/02/08 PHP
解决laravel(5.5)访问public报错的问题
2019/10/12 PHP
PHP用swoole+websocket和redis实现web一对一聊天
2019/11/05 PHP
一些常用的JS功能函数(2009-06-04更新)
2009/06/04 Javascript
Web跨浏览器进程通信(Web跨域)
2013/04/17 Javascript
javascript实现颜色渐变的方法
2013/10/30 Javascript
理运用命名空间让js不产生冲突避免全局变量的泛滥
2014/06/15 Javascript
JavaScript中Number.MAX_VALUE属性的使用方法
2015/06/04 Javascript
使用CDN和AJAX加速WordPress中jQuery的加载
2015/12/05 Javascript
基于jQuery实现仿搜狐辩论投票动画代码(附源码下载)
2016/02/18 Javascript
修复jQuery tablesorter无法正确排序的bug(加千分位数字后)
2016/03/30 Javascript
Bootstrap与KnockoutJs相结合实现分页效果实例详解
2016/05/03 Javascript
Angular2库初探
2017/03/01 Javascript
node.js用fs.rename强制重命名或移动文件夹的方法
2017/12/27 Javascript
Nodejs中怎么实现函数的串行执行
2019/03/02 NodeJs
基于elementUI实现图片预览组件的示例代码
2019/03/31 Javascript
jQuery属性选择器用法实例分析
2019/06/28 jQuery
python中threading超线程用法实例分析
2015/05/16 Python
在python中实现强制关闭线程的示例
2019/01/22 Python
Python使用type关键字创建类步骤详解
2019/07/23 Python
解决matplotlib.pyplot在Jupyter notebook中不显示图像问题
2020/04/22 Python
Python HTMLTestRunner测试报告view按钮失效解决方案
2020/05/25 Python
python给视频添加背景音乐并改变音量的具体方法
2020/07/19 Python
Python中lru_cache的使用和实现详解
2021/01/25 Python
保护环境建议书
2014/03/12 职场文书
高三复习计划
2015/01/19 职场文书
婚礼父母致辞
2015/07/28 职场文书
感恩教育主题班会
2015/08/12 职场文书
我的中国梦心得体会范文
2016/01/05 职场文书
《酸的和甜的》教学反思
2016/02/18 职场文书
java版 联机五子棋游戏
2022/05/04 Java/Android