200行代码实现blockchain 区块链实例详解


Posted in Javascript onMarch 14, 2018

了解blockchain的概念很简单(区块链,交易链块):它是分布式的(即不是放置在同一台机器上,不同的网络设备上的)数据库支持主办记录日益增长的名单。但是,这也是容易混淆blockchain与我们试图帮他解决了目标 - 在人们心中的那一刻,这个词是相当强烈的交易,合同或智能cryptocurrency的概念有关。

只有在这里blockchain - 是不是一回事比特币,并理解链块的基本知识比它似乎更容易,尤其是在,它是基于源代码的情况下。在本文中,我们提出了建立与在JavaScript中200行代码的简单模型。这个项目,我们称之为NaiveChain的源代码,可以在GitHub上找到。第1部分和第2部分:如果您需要刷上它的功能,使用我们的备忘单,我们将使用标准的ECMAScript 6。
块结构

第一步 - 确定应包含块的元素。为简单起见,我们只包括最必要的:先前块的指数(指数),时间标记(时间戳),数据(数据),散列和散列,要录制,以保持电路的结构完整性。

200行代码实现blockchain 区块链实例详解

class Block { 
  constructor(index, previousHash, timestamp, data, hash) { 
    this.index = index; 
    this.previousHash = previousHash.toString(); 
    this.timestamp = timestamp; 
    this.data = data; 
    this.hash = hash.toString(); 
  } 
}

 散列单元

哈希块需要保持数据的完整性。在我们的例子,这适用于算法SHA-256。这种类型的散列是不相关的开采,因为在这种情况下,我们并没有用表现证明实施保护。

var calculateHash = (index, previousHash, timestamp, data) => { 
  return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); 
};

产生单元

要生成块,我们需要知道前一个块的哈希,使我们在结构已经确定了元素的其余部分。数据由最终用户提供。

var generateNextBlock = (blockData) => { 
  var previousBlock = getLatestBlock(); 
  var nextIndex = previousBlock.index + 1; 
  var nextTimestamp = new Date().getTime() / 1000; 
  var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData); 
  return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash); 
};

存储单元

使用blockchain 存储阵列。第一个块总是硬编码“创世纪块”。

var getGenesisBlock = () => { 
  return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); 
}; 
var blockchain = [getGenesisBlock()];

确认块的完整性

我们必须始终能够确认单元或电路的完整性。尤其是当你从其他单位新的单位,必须决定是否接受它们。

var isValidNewBlock = (newBlock, previousBlock) => { 
  if (previousBlock.index + 1 !== newBlock.index) { 
    console.log('invalid index'); 
    return false; 
  } else if (previousBlock.hash !== newBlock.previousHash) { 
    console.log('invalid previoushash'); 
    return false; 
  } else if (calculateHashForBlock(newBlock) !== newBlock.hash) { 
    console.log(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock)); 
    console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash); 
    return false; 
  } 
  return true; 
};

选择链最长的

在电路块的顺序必须被明确指定,但是在发生冲突的情况下(例如,两个节点同时在同一生成的块和相同数量),我们选择电路,其中包含的块的数量较多。

var replaceChain = (newBlocks) => { 
  if (isValidChain(newBlocks) && newBlocks.length > blockchain.length) { 
    console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); 
    blockchain = newBlocks; 
    broadcast(responseLatestMsg()); 
  } else { 
    console.log('Received blockchain invalid'); 
  } 
};

消息到其它网络节点

该网站的一个组成部分 - 与其他节点的数据交换。下列规则用于维护网络同步:
当一个节点产生新的单元,它会报告给网络;
当本机连接到新的盛宴,他要求有关最后生成的块信息;
当一个节点正面临着一个块,其中有一个指标比他还大,他增加了一个块到电路或请求的完整链条的信息。
自动搜索同龄人不执行,所有环节都手动添加。

单元的控制

用户应该能够以某种方式控制节点,通过将HTTP服务器解决。当与节点相互作用有以下功能:
打印所有单元的列表;
创建用户生成内容的新单元;
打印列表,或添加的节日。
互动的最直接的方式 - 通过卷曲:

200行代码实现blockchain 区块链实例详解

一个节点上的所有块#名单

curl http://localhost:3001/blocks

架构

值得注意的是,该网站是指两个Web服务器:HTTP进行用户控制的装置和向所述的WebSocket HTTP来安装节点之间的P2P连接。

如下为js 200行代码

<span style="font-family:Arial, Helvetica, sans-serif;">'use strict';</span> 
var CryptoJS = require("crypto-js"); 
var express = require("express"); 
var bodyParser = require('body-parser'); 
var WebSocket = require("ws"); 
var http_port = process.env.HTTP_PORT || 3001; 
var p2p_port = process.env.P2P_PORT || 6001; 
var initialPeers = process.env.PEERS ? process.env.PEERS.split(',') : []; 
class Block { 
  constructor(index, previousHash, timestamp, data, hash) { 
    this.index = index; 
    this.previousHash = previousHash.toString(); 
    this.timestamp = timestamp; 
    this.data = data; 
    this.hash = hash.toString(); 
  } 
} 
var sockets = []; 
var MessageType = { 
  QUERY_LATEST: 0, 
  QUERY_ALL: 1, 
  RESPONSE_BLOCKCHAIN: 2 
}; 
var getGenesisBlock = () => { 
  return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); 
}; 
var blockchain = [getGenesisBlock()]; 
var initHttpServer = () => { 
  var app = express(); 
  app.use(bodyParser.json()); 
  app.get('/blocks', (req, res) => res.send(JSON.stringify(blockchain))); 
  app.post('/mineBlock', (req, res) => { 
    var newBlock = generateNextBlock(req.body.data); 
    addBlock(newBlock); 
    broadcast(responseLatestMsg()); 
    console.log('block added: ' + JSON.stringify(newBlock)); 
    res.send(); 
  }); 
  app.get('/peers', (req, res) => { 
    res.send(sockets.map(s => s._socket.remoteAddress + ':' + s._socket.remotePort)); 
  }); 
  app.post('/addPeer', (req, res) => { 
    connectToPeers([req.body.peer]); 
    res.send(); 
  }); 
  app.listen(http_port, () => console.log('Listening http on port: ' + http_port)); 
}; 
var initP2PServer = () => { 
  var server = new WebSocket.Server({port: p2p_port}); 
  server.on('connection', ws => initConnection(ws)); 
  console.log('listening websocket p2p port on: ' + p2p_port); 
}; 
var initConnection = (ws) => { 
  sockets.push(ws); 
  initMessageHandler(ws); 
  initErrorHandler(ws); 
  write(ws, queryChainLengthMsg()); 
}; 
var initMessageHandler = (ws) => { 
  ws.on('message', (data) => { 
    var message = JSON.parse(data); 
    console.log('Received message' + JSON.stringify(message)); 
    switch (message.type) { 
      case MessageType.QUERY_LATEST: 
        write(ws, responseLatestMsg()); 
        break; 
      case MessageType.QUERY_ALL: 
        write(ws, responseChainMsg()); 
        break; 
      case MessageType.RESPONSE_BLOCKCHAIN: 
        handleBlockchainResponse(message); 
        break; 
    } 
  }); 
}; 
var initErrorHandler = (ws) => { 
  var closeConnection = (ws) => { 
    console.log('connection failed to peer: ' + ws.url); 
    sockets.splice(sockets.indexOf(ws), 1); 
  }; 
  ws.on('close', () => closeConnection(ws)); 
  ws.on('error', () => closeConnection(ws)); 
}; 
var generateNextBlock = (blockData) => { 
  var previousBlock = getLatestBlock(); 
  var nextIndex = previousBlock.index + 1; 
  var nextTimestamp = new Date().getTime() / 1000; 
  var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData); 
  return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash); 
}; 
var calculateHashForBlock = (block) => { 
  return calculateHash(block.index, block.previousHash, block.timestamp, block.data); 
}; 
var calculateHash = (index, previousHash, timestamp, data) => { 
  return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); 
}; 
var addBlock = (newBlock) => { 
  if (isValidNewBlock(newBlock, getLatestBlock())) { 
    blockchain.push(newBlock); 
  } 
}; 
var isValidNewBlock = (newBlock, previousBlock) => { 
  if (previousBlock.index + 1 !== newBlock.index) { 
    console.log('invalid index'); 
    return false; 
  } else if (previousBlock.hash !== newBlock.previousHash) { 
    console.log('invalid previoushash'); 
    return false; 
  } else if (calculateHashForBlock(newBlock) !== newBlock.hash) { 
    console.log(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock)); 
    console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash); 
    return false; 
  } 
  return true; 
}; 
var connectToPeers = (newPeers) => { 
  newPeers.forEach((peer) => { 
    var ws = new WebSocket(peer); 
    ws.on('open', () => initConnection(ws)); 
    ws.on('error', () => { 
      console.log('connection failed') 
    }); 
  }); 
}; 
var handleBlockchainResponse = (message) => { 
  var receivedBlocks = JSON.parse(message.data).sort((b1, b2) => (b1.index - b2.index)); 
  var latestBlockReceived = receivedBlocks[receivedBlocks.length - 1]; 
  var latestBlockHeld = getLatestBlock(); 
  if (latestBlockReceived.index > latestBlockHeld.index) { 
    console.log('blockchain possibly behind. We got: ' + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index); 
    if (latestBlockHeld.hash === latestBlockReceived.previousHash) { 
      console.log("We can append the received block to our chain"); 
      blockchain.push(latestBlockReceived); 
      broadcast(responseLatestMsg()); 
    } else if (receivedBlocks.length === 1) { 
      console.log("We have to query the chain from our peer"); 
      broadcast(queryAllMsg()); 
    } else { 
      console.log("Received blockchain is longer than current blockchain"); 
      replaceChain(receivedBlocks); 
    } 
  } else { 
    console.log('received blockchain is not longer than received blockchain. Do nothing'); 
  } 
}; 
var replaceChain = (newBlocks) => { 
  if (isValidChain(newBlocks) && newBlocks.length > blockchain.length) { 
    console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); 
    blockchain = newBlocks; 
    broadcast(responseLatestMsg()); 
  } else { 
    console.log('Received blockchain invalid'); 
  } 
}; 
var isValidChain = (blockchainToValidate) => { 
  if (JSON.stringify(blockchainToValidate[0]) !== JSON.stringify(getGenesisBlock())) { 
    return false; 
  } 
  var tempBlocks = [blockchainToValidate[0]]; 
  for (var i = 1; i < blockchainToValidate.length; i++) { 
    if (isValidNewBlock(blockchainToValidate[i], tempBlocks[i - 1])) { 
      tempBlocks.push(blockchainToValidate[i]); 
    } else { 
      return false; 
    } 
  } 
  return true; 
}; 
var getLatestBlock = () => blockchain[blockchain.length - 1]; 
var queryChainLengthMsg = () => ({'type': MessageType.QUERY_LATEST}); 
var queryAllMsg = () => ({'type': MessageType.QUERY_ALL}); 
var responseChainMsg = () =>({ 
  'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(blockchain) 
}); 
var responseLatestMsg = () => ({ 
  'type': MessageType.RESPONSE_BLOCKCHAIN, 
  'data': JSON.stringify([getLatestBlock()]) 
}); 
var write = (ws, message) => ws.send(JSON.stringify(message)); 
var broadcast = (message) => sockets.forEach(socket => write(socket, message)); 
connectToPeers(initialPeers); 
initHttpServer(); 
initP2PServer();

总结

以上所述是小编给大家介绍的200行代码实现blockchain 区块链实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript面向对象包装类Class封装类库剖析
Jan 24 Javascript
给Flash加一个超链接(推荐使用透明层)兼容主流浏览器
Jun 09 Javascript
Jquery的each里用return true或false代替break或continue
May 21 Javascript
浅析javascript操作 cookie对象
Dec 26 Javascript
Javascript节点关系实例分析
May 15 Javascript
JS实现新浪博客左侧的Blog管理菜单效果代码
Oct 22 Javascript
Node.js实现文件上传
Jul 05 Javascript
JavaScript DOM节点操作方法总结
Aug 23 Javascript
微信小程序 loading 详解及实例代码
Nov 09 Javascript
vue App.vue中的公共组件改变值触发其他组件或.vue页面监听
May 31 Javascript
基于VUE的v-charts的曲线显示功能
Oct 01 Javascript
v-slot和slot、slot-scope之间相互替换实例
Sep 04 Javascript
vue使用iframe嵌入网页的示例代码
Jun 09 #Javascript
JavaScript实现区块链
Mar 14 #Javascript
iview table render集成switch开关的实例
Mar 14 #Javascript
解决Vue.js 2.0 有时双向绑定img src属性失败的问题
Mar 14 #Javascript
Vue.js 动态为img的src赋值方法
Mar 14 #Javascript
基于datepicker定义自己的angular时间组件的示例
Mar 14 #Javascript
vue 过滤器filter实例详解
Mar 14 #Javascript
You might like
PHP 强制下载文件代码
2010/10/24 PHP
我的php学习笔记(毕业设计)
2012/02/21 PHP
PHP多文件上传类实例
2015/03/07 PHP
php基于curl重写file_get_contents函数实例
2016/11/08 PHP
jQuery 中使用JSON的实现代码
2011/12/01 Javascript
jQuery :first选择器使用介绍
2013/08/09 Javascript
js加载之使用DOM方法动态加载Javascript文件
2013/11/08 Javascript
asp.net+js实现金额格式化
2015/02/27 Javascript
JS烟花背景效果实现方法
2015/03/03 Javascript
浅谈JS中的!=、== 、!==、===的用法和区别
2016/09/24 Javascript
JavaScript实现公历转农历功能示例
2017/02/13 Javascript
AngularJS的脏检查深入分析
2017/04/22 Javascript
Bootstrap模态对话框用法简单示例
2018/08/31 Javascript
vue 组件销毁并重置的实现
2020/01/13 Javascript
vue项目中openlayers绘制行政区划
2020/12/24 Vue.js
[01:02:10]DOTA2上海特级锦标赛B组小组赛#2 VG VS Fnatic第一局
2016/02/26 DOTA
Python cookbook(数据结构与算法)对切片命名清除索引的方法
2018/03/13 Python
Python批量提取PDF文件中文本的脚本
2018/03/14 Python
Python中常用的内置方法
2019/01/28 Python
Python自动抢红包教程详解
2019/06/11 Python
详解利用OpenCV提取图像中的矩形区域(PPT屏幕等)
2019/07/01 Python
python读写csv文件实例代码
2019/07/05 Python
Python中的类与类型示例详解
2019/07/10 Python
解决使用export_graphviz可视化树报错的问题
2019/08/09 Python
对Python 中矩阵或者数组相减的法则详解
2019/08/26 Python
详解pandas中iloc, loc和ix的区别和联系
2020/03/09 Python
在Ubuntu 20.04中安装Pycharm 2020.1的图文教程
2020/04/30 Python
Python面向对象特殊属性及方法解析
2020/09/16 Python
tensorflow与numpy的版本兼容性问题的解决
2021/01/08 Python
乔丹诺(Giordano)酒庄德国官网:找到最好的意大利葡萄酒
2017/12/28 全球购物
动物学专业毕业生求职信
2013/10/11 职场文书
法人代表委托书
2014/04/04 职场文书
本科毕业生求职自荐信
2014/04/09 职场文书
新闻稿格式范文
2015/07/18 职场文书
SpringCloud Feign请求头删除修改的操作代码
2022/03/20 Java/Android
Spring Boot优化后启动速度快到飞起技巧示例
2022/07/23 Java/Android