200-line code implementation blockchain instance details, 200-line blockchain

Source: Internet
Author: User

200-line code implementation blockchain instance details, 200-line blockchain

Understanding the concept of blockchain is very simple (blockchain, transaction chain block): it is distributed (that is, not placed on the same machine, different network devices) the Database supports a growing list of hosting records. However, it is also easy to confuse blockchain with the words we tried to help him solve the goal-in people's minds at that moment, this term is quite strong in dealing with contracts or smart cryptocurrency concepts.

Only here blockchain-is it not the same thing bitcoin, and it seems easier to understand the basic knowledge of blockchain block than it, especially when it is based on source code. In this article, we propose a simple model for establishing 200 lines of code in JavaScript. This project is called the source code of NaiveChain and can be found on GitHub. Part 1 and part 2: If you need to refresh its features, use our memo sheet and we will use the standard ECMAScript 6.
Block Structure

Step 1: determine the elements that should contain blocks. For the sake of simplicity, we only include the most necessary: the index (INDEX), time mark (timestamp), data (data), hash and hash of the previous block, to be recorded, to maintain the structural integrity of the circuit.

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();   } }

 Hash Unit

The hash block must maintain data integrity. In our example, this applies to algorithm SHA-256. This type of hash is unrelated to mining, because in this case, we do not prove that protection is implemented.

var calculateHash = (index, previousHash, timestamp, data) => {   return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); }; 

Generation Unit

To generate a block, we need to know the hash of the previous block so that we have determined the rest of the element in the structure. Data is provided by end users.

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); }; 

Storage Unit

Use a blockchain storage array. The first chunk is always hard-coded "".

var getGenesisBlock = () => {   return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); }; var blockchain = [getGenesisBlock()]; 

Verify block integrity

We must always be able to validate the integrity of the unit or circuit. Especially when you are new units from other units, you must decide whether to accept them.

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(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock));     console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash);     return false;   }   return true; }; 

Select the longest chain

When the order of circuit blocks must be clearly specified, but in the case of a conflict (for example, two nodes are simultaneously generated in the same block and the same number), we select the circuit, A large number of blocks are contained.

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');   } }; 

Messages to other network nodes

A component of the website-data exchange with other nodes. The following rules are used to maintain network synchronization:
When a node generates a new unit, it will report it to the network;
When the local machine is connected to the new feast, he requests information about the last generated block;
When a node is facing a block with an indicator greater than him, it adds information about the complete chain from the block to the circuit or request.
Automatic search is not performed by the same user, and all links are manually added.

Unit Control

The user should be able to control the node in some way by resolving the HTTP server. When interacting with nodes, the following functions are available:
Print the list of all units;
Create a new unit for user-generated content;
Print the list or add festivals.
The most direct way of interaction-through curl:

All blocks on a node # list

Curl http: // localhost: 3001/blocks

Architecture

It is worth noting that this website refers to the P2P connection between two Web servers: the device for HTTP user control and the installation of nodes to the WebSocket HTTP.

The following code is a 200-line JavaScript code.

<span style="font-family:Arial, Helvetica, sans-serif;">'use strict';</span> var CryptoJS = require("crypto-js"); var express = require("express"); var bodyParser = require('body-parser'); var WebSocket = require("ws"); var http_port = process.env.HTTP_PORT || 3001; var p2p_port = process.env.P2P_PORT || 6001; var initialPeers = process.env.PEERS ? process.env.PEERS.split(',') : []; 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();   } } var sockets = []; var MessageType = {   QUERY_LATEST: 0,   QUERY_ALL: 1,   RESPONSE_BLOCKCHAIN: 2 }; var getGenesisBlock = () => {   return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); }; var blockchain = [getGenesisBlock()]; 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)); }; var initP2PServer = () => {   var server = new WebSocket.Server({port: p2p_port});   server.on('connection', ws => initConnection(ws));   console.log('listening websocket p2p port on: ' + p2p_port); }; var initConnection = (ws) => {   sockets.push(ws);   initMessageHandler(ws);   initErrorHandler(ws);   write(ws, queryChainLengthMsg()); }; var initMessageHandler = (ws) => {   ws.on('message', (data) => {     var message = JSON.parse(data);     console.log('Received message' + JSON.stringify(message));     switch (message.type) {       case MessageType.QUERY_LATEST:         write(ws, responseLatestMsg());         break;       case MessageType.QUERY_ALL:         write(ws, responseChainMsg());         break;       case MessageType.RESPONSE_BLOCKCHAIN:         handleBlockchainResponse(message);         break;     }   }); }; var initErrorHandler = (ws) => {   var closeConnection = (ws) => {     console.log('connection failed to peer: ' + ws.url);     sockets.splice(sockets.indexOf(ws), 1);   };   ws.on('close', () => closeConnection(ws));   ws.on('error', () => closeConnection(ws)); }; 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); }; var calculateHashForBlock = (block) => {   return calculateHash(block.index, block.previousHash, block.timestamp, block.data); }; var calculateHash = (index, previousHash, timestamp, data) => {   return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); }; var addBlock = (newBlock) => {   if (isValidNewBlock(newBlock, getLatestBlock())) {     blockchain.push(newBlock);   } }; 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(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock));     console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash);     return false;   }   return true; }; var connectToPeers = (newPeers) => {   newPeers.forEach((peer) => {     var ws = new WebSocket(peer);     ws.on('open', () => initConnection(ws));     ws.on('error', () => {       console.log('connection failed')     });   }); }; var handleBlockchainResponse = (message) => {   var receivedBlocks = JSON.parse(message.data).sort((b1, b2) => (b1.index - b2.index));   var latestBlockReceived = receivedBlocks[receivedBlocks.length - 1];   var latestBlockHeld = getLatestBlock();   if (latestBlockReceived.index > latestBlockHeld.index) {     console.log('blockchain possibly behind. We got: ' + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index);     if (latestBlockHeld.hash === latestBlockReceived.previousHash) {       console.log("We can append the received block to our chain");       blockchain.push(latestBlockReceived);       broadcast(responseLatestMsg());     } else if (receivedBlocks.length === 1) {       console.log("We have to query the chain from our peer");       broadcast(queryAllMsg());     } else {       console.log("Received blockchain is longer than current blockchain");       replaceChain(receivedBlocks);     }   } else {     console.log('received blockchain is not longer than received blockchain. Do nothing');   } }; 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');   } }; var isValidChain = (blockchainToValidate) => {   if (JSON.stringify(blockchainToValidate[0]) !== JSON.stringify(getGenesisBlock())) {     return false;   }   var tempBlocks = [blockchainToValidate[0]];   for (var i = 1; i < blockchainToValidate.length; i++) {     if (isValidNewBlock(blockchainToValidate[i], tempBlocks[i - 1])) {       tempBlocks.push(blockchainToValidate[i]);     } else {       return false;     }   }   return true; }; var getLatestBlock = () => blockchain[blockchain.length - 1]; var queryChainLengthMsg = () => ({'type': MessageType.QUERY_LATEST}); var queryAllMsg = () => ({'type': MessageType.QUERY_ALL}); var responseChainMsg = () =>({   'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(blockchain) }); var responseLatestMsg = () => ({   'type': MessageType.RESPONSE_BLOCKCHAIN,   'data': JSON.stringify([getLatestBlock()]) }); var write = (ws, message) => ws.send(JSON.stringify(message)); var broadcast = (message) => sockets.forEach(socket => write(socket, message)); connectToPeers(initialPeers); initHttpServer(); initP2PServer(); 

Summary

The above is a detailed explanation of the 200-line code implementation blockchain instance provided by xiaobian. I hope it will be helpful to you. If you have any questions, please leave a message for me, the editor will reply to you in a timely manner. Thank you very much for your support for the help House website!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.