Основная концепция блокчейна довольно проста: распределенная база данных, которая поддерживает постоянно растущий список упорядоченных записей.
Однако, многоe остается непонятным, когда мы говорим о блокчейне, так же остается много проблем, которые мы пытаемся решить с его помощью. Это относится и к популярным блокчейн проектам, таким как Биткоин (Bitcoin) и Эфириума (Ethereum). Термин «блокчейн» обычно сильно привязан к концепции типа денежных переводов, смарт-контрактов или криптовалюты.
Это делает понимание блокчейна сложнее, чем есть на самом деле. Особенно исходный код. Здесь я пройдусь по супер-простой реализации блокчейна в 200 строк кода JavaScript под названием NaiveChain.
Первый логический шаг — определиться со структурой блока. Чтобы оставить все как можно проще, мы включили только самое необходимое: индекс, отметка, данные, хэш и хэш предыдущего блока.

Хэш предыдущего блока необходимо найти в блоке для сохранения целостности цепи
Блок должен быть хэширован, чтобы сохранить целостность данных. SHA256 отвечает за содержание блока. Следует отметить, что этот хэш не имеет ничего общего с «майнингом», поскольку нет подтверждения работы — решения задачи.
Для создания блока нужно знать хэш предыдущего блока, а остальное необходимо создавать из следующего содержания (= index, hash, data и timestamp). Блок-дата — это некая информация, которая передается конечному пользователю.
В памяти массив JavaScript используется для хранения блокчейн. Первый блок в блокчейн — это всегда так называемый «генезис-блок», имеющий следующий код:
В любой момент времени мы должны быть в состоянии проверить, является ли блок или цепочка блоков допустимыми с точки зрения целостности. Это особенно актуально, когда мы получаем новые блоки от других узлов и должны решить, принимать их или нет.
Всегда должен быть только один явный набор блоков в цепи в один момент времени. В случае возникновения конфликтов (например, два узла как в созданном блоке № 72) мы выбираем цепь, которая имеет самый длинный ряд блоков.

Общение с другими узлами
Важной функцией узла является — разделение и синхронизация блокчейн с другими узлами. Правила — используемые для поддержания синхронизации сети:

Некоторые типичные коммуникационные сценарии, которые следуют, когда узлы подчиняться описанному протоколу
Нет никакого автоматического взаимного обнаружения. Местоположения (=URL-адреса) стороны должны быть добавлены вручную.
Пользователь, в некотором роде, должен иметь возможность контролировать узел. Это делается путем настройки http-сервера.
Как видно, пользователь может взаимодействовать с узлом следующими способами:
Наиболее простой способ управления узлом — например с помощью Curl:
Следует отметить, что узел фактически предоставляет два веб-сервера: один для пользователя, чтобы контролировать узел (http-сервер) и один для одноранговой (peer-to-peer) связи между узлами.(websocket сервер http)

Основные компоненты NaiveChain
NaiveChain был создан для демонстрационных и учебных целей. До тех пор, пока у него нет «майнинг» алгоритма для (PoS of PoW) он не может использоваться в общедоступной сети. Тем не менее он реализует основные функции для реализации блокчейн.
Однако, многоe остается непонятным, когда мы говорим о блокчейне, так же остается много проблем, которые мы пытаемся решить с его помощью. Это относится и к популярным блокчейн проектам, таким как Биткоин (Bitcoin) и Эфириума (Ethereum). Термин «блокчейн» обычно сильно привязан к концепции типа денежных переводов, смарт-контрактов или криптовалюты.
Это делает понимание блокчейна сложнее, чем есть на самом деле. Особенно исходный код. Здесь я пройдусь по супер-простой реализации блокчейна в 200 строк кода JavaScript под названием NaiveChain.
Структура блока
Первый логический шаг — определиться со структурой блока. Чтобы оставить все как можно проще, мы включили только самое необходимое: индекс, отметка, данные, хэш и хэш предыдущего блока.

Хэш предыдущего блока необходимо найти в блоке для сохранения целостности цепи
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(); } }
Хеш блока
Блок должен быть хэширован, чтобы сохранить целостность данных. SHA256 отвечает за содержание блока. Следует отметить, что этот хэш не имеет ничего общего с «майнингом», поскольку нет подтверждения работы — решения задачи.
var calculateHash = (index, previousHash, timestamp, data) => { return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); };
Генерация блока
Для создания блока нужно знать хэш предыдущего блока, а остальное необходимо создавать из следующего содержания (= index, hash, data и timestamp). Блок-дата — это некая информация, которая передается конечному пользователю.
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); };
Хранение блоков
В памяти массив JavaScript используется для хранения блокчейн. Первый блок в блокчейн — это всегда так называемый «генезис-блок», имеющий следующий код:
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('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash); return false; } return true; };
Выбираем самую длинную цепочку
Всегда должен быть только один явный набор блоков в цепи в один момент времени. В случае возникновения конфликтов (например, два узла как в созданном блоке № 72) мы выбираем цепь, которая имеет самый длинный ряд блоков.

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'); } };
Общение с другими узлами
Важной функцией узла является — разделение и синхронизация блокчейн с другими узлами. Правила — используемые для поддержания синхронизации сети:
- Когда узел генерирует новый блок, он транслирует его в сеть
- Когда узел подключается к новой одноранговой сети он опирается на последний блок
- Когда узел обнаруживает блок, который имеет индекс больший, чем текущий известный блок, он либо добавляет блок в его нынешнем состоянии в свою собственную цепь либо поддерживает для заполнения блокчейна.

Некоторые типичные коммуникационные сценарии, которые следуют, когда узлы подчиняться описанному протоколу
Нет никакого автоматического взаимного обнаружения. Местоположения (=URL-адреса) стороны должны быть добавлены вручную.
Контроль над узлом (node`ой)
Пользователь, в некотором роде, должен иметь возможность контролировать узел. Это делается путем настройки http-сервера.
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)); };
Как видно, пользователь может взаимодействовать с узлом следующими способами:
- Просматривать список всех блоков
- Создавать новый блок с содержанием, заданным пользователем
- Просматривать или добавлять одноранговых пользователей
Наиболее простой способ управления узлом — например с помощью Curl:
#получить все блоки из узла
curl http://localhost:3001/blocksАрхитектура
Следует отметить, что узел фактически предоставляет два веб-сервера: один для пользователя, чтобы контролировать узел (http-сервер) и один для одноранговой (peer-to-peer) связи между узлами.(websocket сервер http)

Основные компоненты NaiveChain
Заключение
NaiveChain был создан для демонстрационных и учебных целей. До тех пор, пока у него нет «майнинг» алгоритма для (PoS of PoW) он не может использоваться в общедоступной сети. Тем не менее он реализует основные функции для реализации блокчейн.