📜 ⬆️ ⬇️

Blockchain 200 lines of code

The basic concept of the blockchain is quite simple: a distributed database that maintains an ever-growing list of ordered records.

However, many things remain incomprehensible when we talk about the blockchain, there are also many problems that we are trying to solve with its help. This also applies to popular blockchain projects such as Bitcoin (Bitcoin) and Ethereum (Ethereum). The term “blockchain” is usually strongly linked to concepts such as money transfers, smart contracts, or cryptocurrencies.

This makes understanding the blockchain more difficult than it actually is. Especially the source code. Here I will go through a super-simple blockchain implementation of 200 lines of JavaScript code called NaiveChain.
')

Block structure


The first logical step is to determine the structure of the block. To keep everything as simple as possible, we included only the most necessary: ​​index, mark, data, hash, and hash of the previous block.

image
The hash of the previous block must be found in the block to preserve the 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(); } } 

Block hash


The block must be hashed to preserve data integrity. SHA256 is responsible for the content of the block. It should be noted that this hash has nothing to do with the mining, since there is no confirmation of the work - solving the problem.

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

Block generation


To create a block, you need to know the hash of the previous block, and the rest must be created as follows (= index, hash, data, and timestamp). The date block is some information that is passed to the end user.

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

Block storage


In memory, a JavaScript array is used to store the blockchain. The first blockchain block is always the so-called “genesis block”, which has the following code:

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

Check the integrity of the blocks


At any time, we should be able to check whether a block or chain of blocks is valid from the point of view of integrity. This is especially true when we receive new blocks from other nodes and must decide whether to accept them or not.

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

Choose the longest chain


There should always be only one explicit set of blocks in a chain at a time. In the event of a conflict (for example, two nodes as in the created block number 72), we choose a circuit that has the longest row of blocks.

image

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

Communicating with other nodes
An important function of a node is the separation and synchronization of the blockchain with other nodes. Rules - used to maintain network synchronization:


image
Some typical communication scenarios that follow when nodes comply with the described protocol

There is no automatic mutual detection. Locations (= URLs) parties must be added manually.

Node control


The user, in some way, should be able to control the node. This is done by configuring the http server.

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

As you can see, the user can interact with the node in the following ways:


The easiest way to manage a node - for example, using Curl:

#
curl http://localhost:3001/blocks

Architecture


It should be noted that the host actually provides two web servers: one for the user to control the host (http server) and one for peer-to-peer communication between the hosts. (Websocket http server)

image
Main components of NaiveChain

Conclusion


NaiveChain was created for demonstration and training purposes. As long as he does not have a mining algorithm for (PoS of PoW), it cannot be used in a public network. Nevertheless, it implements the basic functions for the blockchain implementation.

Source: https://habr.com/ru/post/323586/


All Articles