Maison > Article > interface Web > 200 lignes de code pour implémenter la blockchain Explication détaillée des exemples de blockchain
Cet article présente principalement les connaissances pertinentes de la blockchain en 200 lignes de code. Il est très bien et a une valeur de référence. Les amis qui en ont besoin peuvent s'y référer
Comprendre le concept de blockchain est très simple (. Block Chain, bloc de chaîne de transactions) : il est distribué (c'est-à-dire non placé sur la même machine, mais sur différents périphériques réseau). La base de données prend en charge l'hébergement d'une liste croissante d'enregistrements. Mais il est également facile de confondre la blockchain avec l'objectif que nous essayons de l'aider à atteindre : à ce moment-là, dans l'esprit des gens, le mot est assez fortement associé au concept de transactions, de contrats ou de crypto-monnaies intelligentes.
Seulement ici, la blockchain n'est pas la même chose que Bitcoin, et comprendre les bases de la blockchain est plus facile qu'il n'y paraît, surtout lorsqu'elle est basée sur le code source. Dans cet article, nous proposons un modèle simple construit avec 200 lignes de code en JavaScript. Le code source de ce projet, que nous appelons NaiveChain, peut être trouvé sur GitHub. Partie 1 et 2 : Si vous avez besoin de flasher ses fonctionnalités, utilisez notre aide-mémoire et nous utiliserons le standard ECMAScript 6.
Structure du bloc
Étape 1 - Identifiez les éléments qui doivent contenir le bloc. Par souci de simplicité, nous n'incluons que l'essentiel : index du bloc précédent (exposant), horodatage (horodatage), données (data), hachage et hachage, à enregistrer afin de maintenir l'intégrité structurelle de le 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(); } }
L'unité de hachage
Le bloc de hachage doit être maintenu Intégrité des données. Dans notre cas, cela s'applique à l'algorithme SHA-256. Ce type de hachage n'est pas pertinent pour le minage car dans ce cas nous ne mettons pas en œuvre de protection avec preuve de performance.
var calculateHash = (index, previousHash, timestamp, data) => { return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); };
Unité de génération
Pour générer un bloc nous avons besoin de connaître le hachage du bloc précédent, Nous avons donc déterminé le reste des éléments de la structure. Les données sont fournies par l'utilisateur final.
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); };
Unité de stockage
Utilisez une matrice de stockage blockchain. Le premier bloc est toujours "Genesis Block" codé en dur.
var getGenesisBlock = () => { return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); }; var blockchain = [getGenesisBlock()];
Confirmation de l'intégrité du bloc
Nous devons toujours être en mesure de confirmer l'intégrité d'une unité ou d'un circuit . Surtout lorsque vous recevez de nouvelles unités d'autres unités, vous devez décider de les accepter ou non.
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; };
Sélectionnez la chaîne la plus longue
L'ordre des blocs de circuit doit être explicitement spécifié, mais dans En cas de conflits (par exemple, deux nœuds génèrent le même bloc et le même numéro en même temps), on choisit le circuit qui contient le plus grand nombre de blocs.
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 vers d'autres nœuds du réseau
Une partie intégrante du site Web - avec les données d'autres nœuds échange. Les règles suivantes sont utilisées pour maintenir la synchronisation du réseau :
Lorsqu'un nœud génère une nouvelle unité, il la signale au réseau
Lorsque la machine locale se connecte à une nouvelle fête, elle demande des informations sur le dernier bloc généré ; ;
Lorsqu'un nœud est confronté à un bloc qui a un indicateur plus grand que lui, et qu'il ajoute un bloc au circuit ou demande la chaîne complète d'informations.
La recherche automatique de pairs n'est pas effectuée et tous les liens sont ajoutés manuellement.
Contrôle des unités
Les utilisateurs devraient pouvoir contrôler les nœuds d'une manière ou d'une autre, en mettant le serveur HTTP à la solution. Lors de l'interaction avec les nœuds, les fonctions suivantes sont disponibles :
imprimer une liste de toutes les unités ;
créer de nouvelles unités avec du contenu généré par l'utilisateur
imprimer une liste ou ajouter un festival ;
La manière la plus directe d'interagir - via curl :
Liste de tous les numéros de blocs sur un nœud
curl http://localhost : 3001 /blocks
Architecture
Il est à noter que le site Web fait référence à deux serveurs Web : HTTP pour l'installation contrôlée par l'utilisateur et WebSocket pour l'installation HTTP. Connexions P2P entre nœuds .
Ce qui suit est 200 lignes de code js
'use strict';
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();
Ce qui précède est ce que j'ai compilé pour tout le monde, j'espère que cela sera utile. à tout le monde à l'avenir.
Articles connexes :
Principes et méthodes de partage des ressources du processus parent et du processus enfant NodeJS
Vue implémente la méthode de changement de clic actif
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!