В связи с требованиями курса был реализован простой блокчейн на базе Nodejs. Требования очень простые, структура записывает структуру блока, и, кстати, в цепочку можно вставить новый блок.
Но если вы хотите поддерживать многопользовательское использование, вам необходимо рассмотреть вопрос «достоверности». Затем, в соответствии с требованиями блокчейна, данные в цепочке не могут быть подделаны, если только вычислительная мощность не превышает вычислительную мощность всех машин, кроме самого злоумышленника.
Подумайте об этом, попробуйте.
🔍Посмотреть все руководства / читать оригинал🔍
Технические исследования
Искал в гугле и нашел хороший проект:GitHub.com/Lao HaFlesh хвастается/Это…. Там всего около 200 строк, но десятки строк посвящены построению серверов ws и http, ложка дегтя в том, что пакетная вставка в блокчейн и вычисление достоверности не реализованы.
В сочетании с этим проектом можно в основном определить, что каждый блок будет инкапсулирован в класс (структурированное представление), и блокчейн также будет инкапсулирован в класс, а затем интерфейс будет открыт для внешнего мира.
определение блока
Для удобства представления блок инкапсулирован в виде класса, не имеющего методов:
/**
* 区块信息的结构化定义
*/
class Block {
/**
* 构造函数
* @param {Number} index
* @param {String} previousHash
* @param {Number} timestamp
* @param {*} data
* @param {String} hash
*/
constructor(index, previousHash, timestamp, data, hash) {
this.index = index // 区块的位置
this.previousHash = previousHash + '' // 前一个区块的hash
this.timestamp = timestamp // 生成区块时候的时间戳
this.data = data // 区块本身携带的数据
this.hash = hash + '' // 区块根据自身信息和规则生成的hash
}
}
Что касается того, как генерировать хэш, то здесь используются относительно простые правила:
- Объедините индекс, previouHash, временную метку и данные, чтобы преобразовать их в строку.
- При использовании алгоритма sha256 вычисляемым недостатком является хэш
Для удобства будет введена библиотека шифрования:
const CryptoJS = require('crypto-js')
определение структуры цепи
Многие блоки связаны вместе, чтобы сформировать цепочку. Эта цепочка также представлена классом. И он реализует множество методов:
- Сгенерировать хеш в соответствии с правилами шифрования
- Вставьте новые блоки и проверьте операции
- Массовая вставка блока и проверка операций и расчет достоверности
1. Исходный блок
Исходный блок «жестко закодирован», потому что перед ним нет данных. И оговорено, что его нельзя подделать, то есть нельзя принудительно перезаписать. В конструкторе мы напрямую помещаем сгенерированный блок генезиса в цепочку.
class BlockChain {
constructor() {
this.blocks = [this.getGenesisBlock()]
}
/**
* 创建区块链起源块, 此块是硬编码
*/
getGenesisBlock() {
return new Block(0, '0', 1552801194452, 'genesis block', '810f9e854ade9bb8730d776ea02622b65c02b82ffa163ecfe4cb151a14412ed4')
}
}
2. Рассчитать следующий блок
Объект BlockChain может автоматически вычислять следующий блок на основе текущей цепочки. И по сравнению с информацией о блоке, отправленной пользователем, если она одинакова, это означает, что она легальна и может быть вставлена; в противном случае блок пользователя является незаконным и не может быть вставлен.
// 方法都是BlockChain对象方法
/**
* 根据信息计算hash值
*/
calcuteHash(index, previousHash, timestamp, data) {
return CryptoJS.SHA256(index + previousHash + timestamp + data) + ''
}
/**
* 得到区块链中最后一个块节点
*/
getLatestBlock() {
return this.blocks[this.blocks.length - 1]
}
/**
* 计算当前链表的下一个区块
* @param {*} blockData
*/
generateNextBlock(blockData) {
const previousBlock = this.getLatestBlock()
const nextIndex = previousBlock.index + 1
const nextTimeStamp = new Date().getTime()
const nextHash = this.calcuteHash(nextIndex, previousBlock.hash, nextTimeStamp, blockData)
return new Block(nextIndex, previousBlock.hash, nextTimeStamp, blockData, nextHash)
}
3. Вставьте блок
При вставке блока необходимо проверить, является ли текущий блок допустимым, если он является допустимым, вставьте его и верните true, в противном случае верните false.
/**
* 向区块链添加新节点
* @param {Block} newBlock
*/
addBlock(newBlock) {
// 合法区块
if(this.isValidNewBlock(newBlock, this.getLatestBlock())) {
this.blocks.push(newBlock)
return true
}
return false
}
Логика проверки размещена вisValidNewBlock
метод, он в основном выполняет 3 вещи:
- Определить, увеличивается ли индекс нового блока
- Определить, равен ли previousHash хешу предыдущего блока
- Определить, генерируется ли хэш нового блока в соответствии с ограниченными правилами
/**
* 判断新加入的块是否合法
* @param {Block} newBlock
* @param {Block} previousBlock
*/
isValidNewBlock(newBlock, previousBlock) {
if(
!(newBlock instanceof Block) ||
!(previousBlock instanceof Block)
) {
return false
}
// 判断index
if(newBlock.index !== previousBlock.index + 1) {
return false
}
// 判断hash值
if(newBlock.previousHash !== previousBlock.hash) {
return false
}
// 计算新块的hash值是否符合规则
if(this.calcuteHash(newBlock.index, newBlock.previousHash, newBlock.timestamp, newBlock.data) !== newBlock.hash) {
return false
}
return true
}
4. Объемная вставка
Логика пакетной вставки более сложная, например, индексы 4-х блоков в текущей цепочке: 0->1->2->3. За исключением того, что исходный блок 0 не может быть перезаписан, когда вставляется новая цепочка с нижним индексом «1->2->3->4», исходный блок может быть заменен. Конечный результат: 0->1->2->3->4.
При обработке индекса нижнего индекса, предполагая вышеописанную ситуацию, если индекс входящей цепочки начинается с целого числа больше 4, очевидно, невозможно склеить индекс исходного блокчейна и отбросить его напрямую.
Но как обеспечить доверие? То есть, когда новая цепочка (цепочка B) заменяет исходную цепочку (цепь A), создается новая цепочка (цепочка C). Если длина (C) > длина (A), то заменяемая часть может быть перезаписана.Это гарантирует, что цепочка может быть подделана только тогда, когда вычислительная мощность превышает 50% всей вычислительной мощности..
Вот как вставить новую цепочку:
/**
* 插入新链表
* @param {Array} newChain
*/
addChain(newChain) {
if(this.isValidNewChain(newChain)) {
const index = newChain[0].index
this.blocks.splice(index)
this.blocks = this.blocks.concat(newChain)
return true
}
return false
}
Способ реализации описанной выше логики следующий:
/**
* 判断新插入的区块链是否合法而且可以覆盖原来的节点
* @param {Array} newChain
*/
isValidNewChain(newChain) {
if(Array.isArray(newChain) === false || newChain.length === 0) {
return false
}
let newChainLength = newChain.length,
firstBlock = newChain[0]
// 硬编码的起源块不能改变
if(firstBlock.index === 0) {
return false
}
// 移植新的链的长度 <= 现有链的长度
// 新的链不可信
if(newChainLength + firstBlock.index <= this.blocks.length) {
return false
}
// 下面检查新的链能否移植
// 以及新的链的每个节点是否符合规则
if(!this.isValidNewBlock(firstBlock, this.blocks[firstBlock.index - 1])) {
return false
}
for(let i = 1; i < newChainLength; ++i) {
if(!this.isValidNewBlock(newChain[i], newChain[i - 1])) {
return false
}
}
return true
}
5. Зачем вам пакетные вставки?
Мне было интересно, зачем нужен метод "массовой вставки". Я понял это позже (надеюсь). Предположим, сервер S и два пользователя A и B.
A и B одновременно извлекают данные из известной цепочки, а затем генерируют их по отдельности. Скорость сети A высокая, но вычислительная мощность низкая, поэтому 1 блок генерируется и размещается на S. Примечание. В настоящее время блок на S обновлен.
А B хуже, он генерирует 2 блока локально, но ограниченный скоростью сети, он может только ждать скорости сети, чтобы восстановить входящий блок. В это время по правилам его можно накрыть (вычислительная мощность высокая). Таким образом, в этом случае сервер S получает 2 блока B, обновленная длина цепочки равна 3 (включая исходный блок), а блок A был перезаписан.
тест на эффект
Хотя сервер не записывается, моделируется пятая ситуация, описанная выше. код находится вtest.js
В файле вы можете запустить его напрямую. Взгляните на скриншот эффекта:
Над красной линией находится первый расчет, а под красной линией — блок-цепочка, измененная клиентом с более высокой вычислительной мощностью. Конкретный процесс симуляции можно увидеть в коде, который здесь уже не лишний.
Весь код находится в:GitHub.com/Дунъюаньсинь…
Еще цикл статей
⭐ Добавить в избранное/подписаться на GitHub ⭐
«Фронтальная система знаний»
- Базовые знания JavaScript (часть 1)
- Базовые знания JavaScript (Часть 2)
- ES6 тяжелая и сложная отделка
- Расскажите о порядке выполнения promise/async/await и баге движка V8.
- Реализация исходного кода, которую часто тестируют на фронтенд-интервью
- Flex: начало работы и практика
- ......
Справочник по шаблонам проектирования
- одноэлементный шаблон
- режим стратегии
- прокси-режим
- шаблон итератора
- Модель подписки-публикации
- режим моста
- режим заметки
- Режим шаблона
- Абстрактный заводской узор
- ......
«Прогрессивное руководство по Webpack4»
- Серия руководств webpack4 (2): компиляция ES6
- Серия руководств webpack4 (3): многостраничное решение — извлечение общего кода
- Серия руководств по webpack4 (4): одностраничное решение — разделение кода и отложенная загрузка
- Серия руководств webpack4 (5): обработка CSS
- Серия руководств webpack4 (8): JS Tree Shaking
- Серия руководств webpack4 (12): работа со сторонними библиотеками JavaScript
- серия руководств по webpack4 (пятнадцать): режим разработки и сервер webpack-dev-server
- ......