180 lines
4.9 KiB
Markdown
180 lines
4.9 KiB
Markdown
---
|
||
title: "区块链学习笔记——概念与简单JS实现"
|
||
categories: [ "程序人生","开源项目","算法解析" ]
|
||
tags: [ ]
|
||
draft: false
|
||
slug: "blockchain-01"
|
||
date: "2020-07-12 16:28:00"
|
||
---
|
||
|
||
在哔哩哔哩上看 [是落拓呀][1] 的区块链简明教程,趁热打铁,把自己学习过程记录下来
|
||
本项目的 Github 地址 ↓
|
||
[github repo="taurusxin/taurusxincoin" /]
|
||
|
||
## 区块
|
||
区块即是每一次的交易,比如A转账给B十元,那么这条交易就写在这个区块内
|
||
区块里面实际包含的是
|
||
|
||
- 交易数据
|
||
- 本次交易的 hash
|
||
- 前一次交易的 hash
|
||
|
||
其中本一次交易的 hash 为 "本次交易的数据 + 上一次交易的hash" 的 hash 值
|
||
用简明的伪代码表示就是
|
||
|
||
```javascript
|
||
Block = {
|
||
data = '',
|
||
hash = sha256(data + previousHash),
|
||
previousHash = ''
|
||
}
|
||
```
|
||
|
||
## 链
|
||
链就是一系列区块的总和,与之相联通的就是 hash 值,每一次的交易都有它的 hash,与链表的作用机制相似
|
||
可以理解为一个链表,简明代码表示就是一个数组
|
||
|
||
```javascript
|
||
Chain = {
|
||
blocks[Block]
|
||
}
|
||
```
|
||
|
||
## JS实现
|
||
这里用 node.js 来实现一个简单的区块链
|
||
|
||
初始化项目,安装 crypto-js 依赖
|
||
```cmd
|
||
npm init
|
||
npm install crypto-js -S
|
||
```
|
||
|
||
构建 Block 和 Chain 对象
|
||
```javascript
|
||
class Block {
|
||
constructor(data, previousHash) {
|
||
this.data = data
|
||
this.previousHash = previousHash
|
||
this.hash = this.computeHash()
|
||
}
|
||
|
||
computeHash() {
|
||
return sha256(this.data + this.previousHash).toString()
|
||
}
|
||
}
|
||
```
|
||
构造函数传入了这个对象的 `data` `previousHash` 数据,然后定义了对象成员 `hash` ,用于计算当前区块的 hash
|
||
```javascript
|
||
class Chain {
|
||
constructor() {
|
||
this.chain = [this.bigBang()]
|
||
}
|
||
|
||
bigBang() {
|
||
const genisisBlcok = new Block('我是祖先', '')
|
||
return genisisBlcok
|
||
}
|
||
|
||
getLatestBlock() {
|
||
return this.chain[this.chain.length - 1]
|
||
}
|
||
|
||
addBlockToChain(newBlock) {
|
||
// find the nearest block's hash
|
||
// which is the new block's previous hash
|
||
newBlock.previousHash = this.getLatestBlock().hash
|
||
newBlock.hash = newBlock.computeHash()
|
||
this.chain.push(newBlock)
|
||
}
|
||
|
||
// check the previous hash is equal to previous block's hash
|
||
validateChain() {
|
||
if (this.chain.length === 1) {
|
||
if (this.chain[0].hash !== this.chain[0].computeHash()) {
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
// check if current data has been change
|
||
for (let i = 1; i < this.chain.length; i++) {
|
||
const blockToValidate = this.chain[i]
|
||
if (blockToValidate.hash !== blockToValidate.computeHash()) {
|
||
console.log('data has been change')
|
||
return false
|
||
}
|
||
|
||
const previousBlcok = this.chain[i - 1]
|
||
if (blockToValidate.previousHash !== previousBlcok.hash) {
|
||
console.log('previous and current block lost connection')
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
}
|
||
}
|
||
```
|
||
最初始的 `chain` 只包含一个祖先区块,它没有 `previousHash`,并用 `bigBang` 方法进行初始化,`addBlockToChain` 方法实现了添加一个区块,并自动计算其 hash
|
||
`validateChain()` 方法,从三种情况去校验这个链是否合法。
|
||
1. 只有一个祖先区块时,校验祖先区块数据是否被篡改
|
||
2. 从第二个区块开始遍历是否有数据被篡改
|
||
3. 从第二个区块开始遍历是否有hash值被修改
|
||
|
||
检验代码是否有效
|
||
```js
|
||
const taurusxinChain = new Chain()
|
||
|
||
const block1 = new Block('转账十元', '')
|
||
taurusxinChain.addBlockToChain(block1)
|
||
const block2 = new Block('转账十个十元', '')
|
||
taurusxinChain.addBlockToChain(block2)
|
||
|
||
console.log(taurusxinChain)
|
||
console.log(taurusxinChain.validateChain())
|
||
|
||
// try to change the block data
|
||
taurusxinChain.chain[1].data = '转账一百个十元'
|
||
console.log(taurusxinChain.validateChain())
|
||
|
||
// try to change the block hash
|
||
taurusxinChain.chain[1].hash = taurusxinChain.chain[1].computeHash()
|
||
console.log(taurusxinChain.validateChain())
|
||
```
|
||
|
||
输出结果
|
||
```
|
||
Chain {
|
||
chain: [
|
||
Block {
|
||
data: '我是祖先',
|
||
previousHash: '',
|
||
hash: 'dbf4cebe91cf0212be8ee04289855fc17e0085d45a7b4c69eeb79e7c636b48fc'
|
||
},
|
||
Block {
|
||
data: '转账十元',
|
||
previousHash: 'dbf4cebe91cf0212be8ee04289855fc17e0085d45a7b4c69eeb79e7c636b48fc',
|
||
hash: 'f135810d2aa85703b2f7356877b95de3dad00955830d570568dd42dd52b93500'
|
||
},
|
||
Block {
|
||
data: '转账十个十元',
|
||
previousHash: 'f135810d2aa85703b2f7356877b95de3dad00955830d570568dd42dd52b93500',
|
||
hash: 'ec3caa66201967755657f30156f38207de23c897caa9aa3ca972f413b9a6a749'
|
||
}
|
||
]
|
||
}
|
||
true
|
||
data has been change
|
||
false
|
||
previous and current block lost connection
|
||
false
|
||
```
|
||
第一次生成区块链,校验成功,输出true
|
||
尝试更改第二个区块的数据,输出 `data has been change`
|
||
尝试更改第二个区块的hash值,输出 `previous and current block lost connection`
|
||
|
||
## 下一阶段
|
||
|
||
- 工作量证明
|
||
- 生成钱包地址
|
||
- 加密
|
||
|
||
[1]: https://space.bilibili.com/43276908/ |