hugo/content/post/014.区块链学习笔记——概念与简单JS实现/区块链学习笔记——概念与简单JS实现.md
2021-12-12 17:46:25 +00:00

180 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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/