Maison > interface Web > js tutoriel > le corps du texte

200 lignes de code pour implémenter la blockchain Explication détaillée des exemples de blockchain

亚连
Libérer: 2018-05-30 14:15:23
original
2746 Les gens l'ont consulté

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(); 
  } 
}
Copier après la connexion

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(); 
};
Copier après la connexion

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); 
};
Copier après la connexion

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()];
Copier après la connexion

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; 
};
Copier après la connexion

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'); 
  } 
};
Copier après la connexion

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();
Copier après la connexion

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

numéro de téléphone mobile vue, Exemples de vérification régulière par e-mail et d'envoi de code de vérification en 60 secondes

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!