这是一篇很长的帖子,所以我感谢那些回答它的人。我试图理解下面区 block 链示例中的 websocket 通信。
这是区 block 链中一个 Node 的源代码:
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;
当 Node 使用 createBlock() 函数创建新 block 时,会使用 broadcastMessage() 函数从 Node 向所有连接的套接字广播一条消息,告诉它们新 block 已创建。连接的套接字将接收消息,并且在 messageHandler() 中它将为每个套接字命中 switch 语句中的 BLOCK 选项。我掌握了这个过程,并画了一张图来表示我的理解。
图 1
如前所述,当 A 创建一个新 block 时,它会将新 block 发送到它连接的 Node ,每个 Node 将验证它并可能将其添加到它的链中。此处理由 processedRecievedBlock() 函数完成。假设 B 和 C 决定将区 block 添加到他们的链中,但 D 落后了几个区 block ,因此它必须向 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 出现了,它们似乎都没有用。
当一个 Node 必须从另一个 Node 请求整个链时,我试图了解这段代码中到底发生了什么。我一定是误解了这些套接字在做什么。
完整源代码:https://github.com/dbjsdev/BrewChain/blob/master/brewNode.js
最佳答案
感谢您提出描述性问题。 :)
在大多数情况下,您是对的,图 3 是对该过程的该部分的正确描述。但图 4 是错误的。
请注意,对等点之间的每个套接字连接都会导致一个不同的connection
实例,这些实例共同维护在brewSockets
中。
因此,当 A/E/F 收到来自 D 的关于connection
的请求时,它们会响应整个链,如下面的代码所示:
connection.send(JSON.stringify({ event: CHAIN, message: chain.getChain()}));
D 然后处理 CHAIN
消息:
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');
}
}
现在,进入“为什么”!
首先,基本原则是我们信任网络,而不仅仅是一个 Node 。因此,您想从尽可能多的来源验证链的真实性。
其次,您想要来自同行的最新链,而不仅仅是任何随机链。
通过这样做,我们确保任何 Node 都与其对等 Node 一样最新。因此,D Node 从多个来源获取链并存储最新的验证链。
希望对您有所帮助!
关于javascript - 从 Node 请求整个链时误解区 block 链的 websocket 通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49185732/