Dieser Artikel stellt hauptsächlich das relevante Wissen über Blockchain in 200 Zeilen Code vor. Er ist sehr gut und hat Referenzwert. Freunde, die ihn benötigen, können darauf zurückgreifen
Das Konzept der Blockchain zu verstehen ist sehr einfach. Blockchain, Transaktionskettenblock): Es wird verteilt (d. h. nicht auf demselben Computer, sondern auf verschiedenen Netzwerkgeräten platziert). Die Datenbank unterstützt das Hosten einer wachsenden Liste von Datensätzen. Aber es ist auch leicht, Blockchain mit dem Ziel zu verwechseln, das wir zu lösen versuchen – in diesem Moment ist das Wort in den Köpfen der Menschen ziemlich stark mit dem Konzept von Transaktionen, Verträgen oder intelligenten Kryptowährungen verbunden.
Nur hier ist Blockchain nicht dasselbe wie Bitcoin, und das Verständnis der Grundlagen der Blockchain ist einfacher als es scheint, insbesondere wenn sie auf Quellcode basiert. In diesem Artikel schlagen wir ein einfaches Modell vor, das mit 200 Codezeilen in JavaScript erstellt wurde. Der Quellcode für dieses Projekt, das wir NaiveChain nennen, finden Sie auf GitHub. Teil 1 und 2: Wenn Sie die Funktionalität flashen müssen, verwenden Sie unseren Spickzettel und wir verwenden Standard-ECMAScript 6.
Blockstruktur
Schritt 1 – Identifizieren Sie die Elemente, die den Block enthalten sollen. Der Einfachheit halber geben wir nur das Nötigste an: Index des vorherigen Blocks (Exponent), Zeitstempel (Zeitstempel), Daten (Daten), Hash und Hash, die aufgezeichnet werden sollen, um die strukturelle Integrität aufrechtzuerhalten die Schaltung.
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-Einheit
Hash-Block muss die Datenintegrität halten . In unserem Fall gilt dies für den Algorithmus SHA-256. Diese Art des Hashings ist für das Mining nicht relevant, da wir in diesem Fall keinen Schutz mit Leistungsnachweis implementieren.
var calculateHash = (index, previousHash, timestamp, data) => { return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); };
Generierungseinheit
Um einen Block zu generieren, müssen wir den Hash des vorherigen Blocks kennen Die Struktur bestimmt bereits die restlichen Elemente. Die Daten werden vom Endbenutzer bereitgestellt.
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); };
Speichereinheit
Blockchain-Speicherarray verwenden. Der erste Block ist immer fest codiert „Genesis Block“.
var getGenesisBlock = () => { return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); }; var blockchain = [getGenesisBlock()];
Bestätigung der Integrität des Blocks
Wir müssen immer in der Lage sein, die Integrität einer Einheit zu bestätigen oder Schaltung. Gerade wenn man neue Einheiten von anderen Einheiten bekommt, muss man sich entscheiden, ob man diese annimmt oder nicht.
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; };
Wählen Sie die längste Kette aus
Die Reihenfolge der Schaltungsblöcke muss explizit angegeben werden, aber im Fall Im Falle eines Konflikts (z. B. wenn zwei Knoten gleichzeitig denselben Block und dieselbe Anzahl erzeugen) wählen wir die Schaltung, die eine größere Anzahl von Blöcken enthält.
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'); } };
Nachrichten an andere Netzwerkknoten
Ein integraler Bestandteil der Website – der Datenaustausch mit anderen Knoten . Die folgenden Regeln werden verwendet, um die Netzwerksynchronisierung aufrechtzuerhalten:
Wenn ein Knoten eine neue Einheit generiert, meldet er diese an das Netzwerk.
Wenn der lokale Computer eine Verbindung zu einem neuen Fest herstellt, fragt er nach Informationen über den zuletzt generierten Block ;
Wenn ein Knoten mit einem Block konfrontiert wird, dessen Indikator größer ist, und er einen Block zur Schaltung hinzufügt oder die Informationen der gesamten Kette anfordert.
Eine automatische Suche nach Peers wird nicht durchgeführt und alle Links werden manuell hinzugefügt.
Steuerung von Einheiten
Benutzer sollten in der Lage sein, Knoten auf irgendeine Weise zu steuern, indem sie den HTTP-Server als Lösung einsetzen. Bei der Interaktion mit Knoten stehen folgende Funktionen zur Verfügung:
eine Liste aller Einheiten drucken;
neue Einheiten mit benutzergenerierten Inhalten erstellen;
eine Liste drucken oder ein Festival hinzufügen.
Der direkteste Weg zur Interaktion – über Curl:
Liste aller Blocknummern auf einem Knoten
curl http://localhost: 3001 /blocks
Architektur
Es ist erwähnenswert, dass die Website auf zwei Webserver verweist: HTTP auf das benutzergesteuerte Gerät und WebSocket auf die P2P-Verbindungen des HTTP-Geräts zwischen Knoten.
Das Folgende sind 200 Zeilen JS-Code
'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();
Das Obige habe ich für alle zusammengestellt. Ich hoffe, es wird für alle hilfreich sein in der Zukunft.
Verwandte Artikel:
Vue implementiert die aktive Klickwechselmethode
Das obige ist der detaillierte Inhalt von200 Codezeilen zur Implementierung der Blockchain. Ausführliche Erläuterung der Blockchain-Beispiele. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!