这是一篇很长的帖子,所以我很感激那些回答它的人。我试图理解下面的区块链示例中的websocket通信。
以下是区块链中节点的源代码:
const BrewChain = require('./brewChain');
const WebSocket = require('ws');
const BrewNode = function(port){
let brewSockets = [];
let brewServer;
let _port = port
let chain = new BrewChain();
const REQUEST_CHAIN = "REQUEST_CHAIN";
const REQUEST_BLOCK = "REQUEST_BLOCK";
const BLOCK = "BLOCK";
const CHAIN = "CHAIN";
function init(){
chain.init();
brewServer = new WebSocket.Server({ port: _port });
brewServer.on('connection', (connection) => {
console.log('connection in');
initConnection(connection);
});
}
const messageHandler = (connection) =>{
connection.on('message', (data) => {
const msg = JSON.parse(data);
switch(msg.event){
case REQUEST_CHAIN:
connection.send(JSON.stringify({ event: CHAIN, message: chain.getChain()}))
break;
case REQUEST_BLOCK:
requestLatestBlock(connection);
break;
case BLOCK:
processedRecievedBlock(msg.message);
break;
case CHAIN:
processedRecievedChain(msg.message);
break;
default:
console.log('Unknown message ');
}
});
}
const processedRecievedChain = (blocks) => {
let newChain = blocks.sort((block1, block2) => (block1.index - block2.index))
if(newChain.length > chain.getTotalBlocks() && chain.checkNewChainIsValid(newChain)){
chain.replaceChain(newChain);
console.log('chain replaced');
}
}
const processedRecievedBlock = (block) => {
let currentTopBlock = chain.getLatestBlock();
// Is the same or older?
if(block.index <= currentTopBlock.index){
console.log('No update needed');
return;
}
//Is claiming to be the next in the chain
if(block.previousHash == currentTopBlock.hash){
//Attempt the top block to our chain
chain.addToChain(block);
console.log('New block added');
console.log(chain.getLatestBlock());
}else{
// It is ahead.. we are therefore a few behind, request the whole chain
console.log('requesting chain');
broadcastMessage(REQUEST_CHAIN,"");
}
}
const requestLatestBlock = (connection) => {
connection.send(JSON.stringify({ event: BLOCK, message: chain.getLatestBlock()}))
}
const broadcastMessage = (event, message) => {
brewSockets.forEach(node => node.send(JSON.stringify({ event, message})))
}
const closeConnection = (connection) => {
console.log('closing connection');
brewSockets.splice(brewSockets.indexOf(connection),1);
}
const initConnection = (connection) => {
console.log('init connection');
messageHandler(connection);
requestLatestBlock(connection);
brewSockets.push(connection);
connection.on('error', () => closeConnection(connection));
connection.on('close', () => closeConnection(connection));
}
const createBlock = (teammember) => {
let newBlock = chain.createBlock(teammember)
chain.addToChain(newBlock);
broadcastMessage(BLOCK, newBlock);
}
const getStats = () => {
return {
blocks: chain.getTotalBlocks()
}
}
const addPeer = (host, port) => {
let connection = new WebSocket(`ws://${host}:${port}`);
connection.on('error', (error) =>{
console.log(error);
});
connection.on('open', (msg) =>{
initConnection(connection);
});
}
return {
init,
broadcastMessage,
addPeer,
createBlock,
getStats
}
}
module.exports = BrewNode;
当具有createBlock()函数的节点创建新块时,将使用broadcastMessage()函数从节点向所有连接的套接字广播消息,以告知它们已创建新块。连接的套接字将接收消息,并且在messageHandler()中,它将在switch语句中为每个套接字命中BLOCK选项。我掌握了这个过程,并绘制了一个图表来表明我的理解。
图1
如前所述,当A创建一个新块时,它会将新块发送到它连接的节点,每个节点将验证它并可能将其添加到它的链中。此处理由processedRecievedBlock()函数完成。让我们说B和C决定将这个块添加到他们的链中,但D后面几个块,所以它必须从A请求整个链。这是我困惑的地方。我预计D会向A发送一条消息,请求整个链,如下所示:
图2
但是,根据processReceivedBlock()函数,在这种情况下,当这一行运行时,D将向其所有连接的套接字广播REQUEST_CHAIN消息:
broadcastMessage(REQUEST_CHAIN,"");
让我们说D连接到E和F.而不是像图2中那样从A请求链,似乎它会将REQUEST_CHAIN消息发送到它的连接套接字,就像这样:
图3
在messageHandler()函数中,将为E和F运行switch语句中的REQUEST_CHAIN选项,它们将点击这行代码:
connection.send(JSON.stringify({ event: CHAIN, message: chain.getChain()}));
据我了解,这将导致E和F将自己的链发送回自己,就像这样:
图4
我想知道为什么当D需要从A请求整个链时,图2不会发生。跟踪代码让我相信图3和图4相反,这两者似乎都没用。
当一个节点必须从另一个节点请求整个链时,我试图找到对此代码中究竟发生了什么的理解。我一定是在误解这些插座正在做什么。
完整源代码:https://github.com/dbjsdev/BrewChain/blob/master/brewNode.js
答案 0 :(得分:1)
感谢您提供描述性问题。 :)
大部分都是正确的,图3是该过程的正确描述。但是图4是错误的。
请注意,对等体之间的每个套接字连接都会导致 HH : MM : SS : MS : uS
Thread 1 12 : 59 : 05 : 27 : 407
Thread 2 12 : 59 : 05 : 27 : 586
Thread 3 12 : 59 : 05 : 27 : 879
Thread 4 12 : 59 : 05 : 28 : 113
的不同实例,这些实例在connection
中共同维护。
因此,当A / E / F从D收到brewSockets
的请求时,他们会回复整个链,如下面的代码所示:
connection
然后, D处理connection.send(JSON.stringify({ event: CHAIN, message: chain.getChain()}));
消息:
CHAIN
现在,进入&#39; 为什么&#39;!
首先,基本原则是我们信任网络,而不仅仅是一个节点。因此,您希望从尽可能多的来源验证链的真实性。
其次,您需要来自同行的最新链,而不仅仅是任何随机链。
通过这样做,我们确保任何节点都与同行一样最新。因此,D节点从多个来源获取链并存储最新的经过验证的链。
希望有所帮助!