初识区块链——用JS构建你自己的区块链
前言
认识区块链

calculateHash() {
return SHA256(this.previousHash + this.timestamp + JSON.stringify(this.data)).toString();
}
Block的数据结构
class Block {
constructor(timestamp, data, previousHash = '') {
this.timestamp = timestamp;
this.data = data;
this.previousHash = previousHash;
//对hash的计算必须放在最后,保证所有数据赋值正确后再计算
this.hash = this.calculateHash();
}
calculateHash() {
return SHA256(this.previousHash + this.timestamp + JSON.stringify(this.data)).toString();
}
}
BlockChain的数据结构
class BlockChain {
constructor() {
this.chain = [];
}
}
创世区块
createGenesisBlock() {
return new Block("2018-11-11 00:00:00", "Genesis block of simple chain", "");
}
class BlockChain {
constructor() {
this.chain = [this.createGenesisBlock()];
}
}
添加区块
class BlockChain {
getLatestBlock() {
return this.chain[this.chain.length - 1];
}
addBlock(newBlock) {
//新区块的前一个hash值是现有区块链的最后一个区块的hash值;
newBlock.previousHash = this.getLatestBlock().hash;
//重新计算新区块的hash值(因为指定了previousHash);
newBlock.hash = newBlock.calculateHash();
//把新区块加入到链中;
this.chain.push(newBlock);
}
...
}
校验区块链
isChainValid() {
//遍历所有区块
for (let i = 1; i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
//重新计算当前区块的hash值,若发现hash值对不上,说明该区块有数据被篡改,hash值未重新计算
if (currentBlock.hash !== currentBlock.calculateHash()) {
console.error("hash not equal: " + JSON.stringify(currentBlock));
return false;
}
//判断当前区块的previousHash是否真的等于前一个区块的hash,若不等,说明前一个区块被篡改,虽然hash值被重新计算正确,但是后续区块的hash值并未重新计算,导致整个链断裂
if (currentBlock.previousHash !== previousBlock.calculateHash) {
console.error("previous hash not right: " + JSON.stringify(currentBlock));
return false;
}
}
return true;
}
Just run it
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));
console.log(JSON.stringify(simpleChain, null, 4));
console.log("is the chain valid? " + simpleChain.isChainValid());
ali-186590cc4a7f:simple-chain shanyao$ node main_1.js
{
"chain": [
{
"timestamp": "2018-11-11 00:00:00",
"data": "Genesis block of simple chain",
"previousHash": "",
"hash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89"
},
{
"timestamp": "2018-11-11 00:00:01",
"data": {
"amount": 10
},
"previousHash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89",
"hash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529"
},
{
"timestamp": "2018-11-11 00:00:02",
"data": {
"amount": 20
},
"previousHash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529",
"hash": "274a7a13ed20118e8cb745654934a7e24a4d59333ba17dfbf5d4cfe0fa8a6e34"
}
]
}
is the chain valid? true
篡改下试试
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));
console.log("is the chain valid? " + simpleChain.isChainValid());
//将第2个区块的数据,由10改为15
simpleChain.chain[1].data = {amount: 15};
console.log("is the chain still valid? " + simpleChain.isChainValid());
console.log(JSON.stringify(simpleChain, null, 4));
ali-186590cc4a7f:simple-chain shanyao$ node main_1.js
is the chain valid? true
hash not equal: {"timestamp":"2018-11-11 00:00:01","data":{"amount":15},"previousHash":"fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89","hash":"150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529"}
is the chain still valid? false
{
"chain": [
{
"timestamp": "2018-11-11 00:00:00",
"data": "Genesis block of simple chain",
"previousHash": "",
"hash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89"
},
{
"timestamp": "2018-11-11 00:00:01",
"data": {
"amount": 15
},
"previousHash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89",
"hash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529"
},
{
"timestamp": "2018-11-11 00:00:02",
"data": {
"amount": 20
},
"previousHash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529",
"hash": "274a7a13ed20118e8cb745654934a7e24a4d59333ba17dfbf5d4cfe0fa8a6e34"
}
]
}
再篡改下试试
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));
console.log("is the chain valid? " + simpleChain.isChainValid());
//篡改后重新计算hash值
simpleChain.chain[1].data = {amount: 15};
simpleChain.chain[1].hash = simpleChain.chain[1].calculateHash();
console.log("is the chain still valid? " + simpleChain.isChainValid());
console.log(JSON.stringify(simpleChain, null, 4));
ali-186590cc4a7f:simple-chain shanyao$ node main_1.js
is the chain valid? true
previous hash not right: {"timestamp":"2018-11-11 00:00:02","data":{"amount":20},"previousHash":"150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529","hash":"274a7a13ed20118e8cb745654934a7e24a4d59333ba17dfbf5d4cfe0fa8a6e34"}
is the chain still valid? false
{
"chain": [
{
"timestamp": "2018-11-11 00:00:00",
"data": "Genesis block of simple chain",
"previousHash": "",
"hash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89"
},
{
"timestamp": "2018-11-11 00:00:01",
"data": {
"amount": 15
},
"previousHash": "fd56967ff621a4090ff71ce88fdd456547d1c92d2e93766b7e8791f7a5f91f89",
"hash": "74d139274fb692495b7c805dd5822faa0c5b5e6058b6beef96e87e18ab83a6b1"
},
{
"timestamp": "2018-11-11 00:00:02",
"data": {
"amount": 20
},
"previousHash": "150b196268a0152e9f0e719ac131a722472a809f49bd507965029a78c7400529",
"hash": "274a7a13ed20118e8cb745654934a7e24a4d59333ba17dfbf5d4cfe0fa8a6e34"
}
]
}
是真的无法篡改吗
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));
console.log("is the chain valid? " + simpleChain.isChainValid());
//篡改第2个区块
simpleChain.chain[1].data = {amount: 15};
simpleChain.chain[1].hash = simpleChain.chain[1].calculateHash();
//并把第3个区块也重新计算
simpleChain.chain[2].previousHash = simpleChain.chain[1].hash;
simpleChain.chain[2].hash = simpleChain.chain[2].calculateHash();
console.log("is the chain still valid? " + simpleChain.isChainValid());
console.log(JSON.stringify(simpleChain, null, 4
原文链接
本文为云栖社区原创内容,未经允许不得转载。
初识区块链——用JS构建你自己的区块链的更多相关文章
- 用Hyperledger Fabric(超级账本)来构建Java语言开发区块链的环境
面向 Java 开发人员的链代码简介 您或许听说过区块链,但可能不确定它对 Java™ 开发人员有何用.本教程将帮助大家解惑.我将分步展示如何使用 Hyperledger Fabric v0.6 来构 ...
- 用 Python 构建一个极小的区块链
虽然有些人认为区块链是一个早晚会出现问题的解决方案,但是毫无疑问,这个创新技术是一个计算机技术上的奇迹.那么,究竟什么是区块链呢? 区块链 以比特币(Bitcoin)或其它加密货币按时间顺序公开地记录 ...
- js构建ui的统一异常处理方案(一)
从早期从事基于java的服务器端开发,再到之后从事基于web和js的ui开发,总体感觉基于web页面的ui开发远不如服务器端健壮.主要是早期ie浏览器功能太弱小,很多业务被迫放到服务器端去实现,浏览器 ...
- js基础篇——原型与原型链的详细理解
js中的对象分为两种:普通对象object和函数对象function. function fn1(){}; var fn2 = function(){}; var fn3 = new Function ...
- 全国11省市出台区块链专项政策,Panda Global发现 "区块链+政务"被寄予厚望!
2020年已经过半,回顾2020年的上半年,不难发现其实区块链的变化非常大,今天Panda Global就给大家回顾下上半年全国关于区块链政策的发布情况.今年上半年,全国已有11个省市出台区块链专项政 ...
- 区块链开发学习第三章:私有链上部署helloBlockchain简单合约
前面讲了部署私有链以及新增账户,现在进行到了部署合约了,此操作真是踩了无数无数无数的坑,到写文章为止确实是已经部署好了,但是还有些坑是还没有解决的! 一.Solidity编译器 开始的时候用的http ...
- NativeScript - JS 构建跨平台的原生 APP
使用 NativeScript,你可以用现有的 JavaScript 和 CSS 技术来编写 iOS.Android 和 Windows Phone 原生移动应用程序.由原生平台的呈现引擎呈现界面而不 ...
- 通过Web Api 和 Angular.js 构建单页面的web 程序
通过Web Api 和 Angular.js 构建单页面的web 程序 在传统的web 应用程序中,浏览器端通过向服务器端发送请求,然后服务器端根据这个请求发送HTML到浏览器,这个响应将会影响整个的 ...
- 第十九篇 js高级知识---词法分析和AO 链
上面一篇文章说了js的作用域链,这一节算是对上面的延申,有一个典型的例子,首先看原来的一段代码: var name = "test"; function t() { var b = ...
随机推荐
- sudo命令详解
语法 sudo(选项)(参数) 选项 选项 说明 -b 在后台执行指令: -h 显示帮助: -H 将HOME环境变量设为新身份的HOME环境变量: -k 结束密码的有效期限,也就是下次再执行sudo时 ...
- linux查看分区是否开启acl权限
1.为什么需要ACL权限 ACL的全称是 Access Control List (访问控制列表) .对于文件或者目录,都有相应的操作权限 r(read 读),w(write 写),x(execute ...
- IOS开发中关于runtime的认识
首先要知道我们写的代码在程序运行过程中都会被转化成runtime的C代码执行. runtime突出的一点就是OC中消息传递机制的应用.objc_msgsend(target,SEL); 首先我们先看一 ...
- 详解封装微信小程序组件及小程序坑(附带解决方案)
一.序 上一篇介绍了如何从零开发微信小程序,博客园审核变智障了,每次代码都不算篇幅,好好滴一篇原创,不到3分钟从首页移出来了.这篇介绍一下组件封装和我的踩坑历程. 二.封装微信小程序可复用组件 首先模 ...
- (一) sublime安装和使用
1 下载安装sublime 可以破解也可以不破解 2 html基础架子自动生成插件Emmet的安装 3 Emmet 安装失败解决 4 快捷键设置和汇总 4 其他sublime插件汇总
- 用for; while...do; do...while; 写出九九乘法表
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- ubuntu connect to windows folder share
在windows上给远程登录的用户设置一个账号密码.”右击计算机图标“——"管理”——“本地用户和组”——“用户”.然后右击选择“新用户”,输入账号密码,并勾选“密码永不过期”,这样,在远程 ...
- C++之几个最常
1.同类对象间的数据共享——静态成员 静态数据成员声明静态数据成员要采用关键字static:类静态数据成员的定义和初始化定义:static 数据类型 成员名:初始化:数据类型 类名::静态数据成员名= ...
- Redis安装及使用详解
推荐在Linux系统上安装,这里我采用CentOS6: Redis采用3.0.0版本,官网下载即可 由于Redis是C语言编写,需要安装gcc(部分Linux自带gcc) yum install gc ...
- [Swift]LeetCode258. 各位相加 | Add Digits
Given a non-negative integer num, repeatedly add all its digits until the result has only one digit. ...