在从节点请求整个链时,误解了区块链的websocket通信

时间:2018-03-09 02:32:27

标签: javascript node.js graph websocket blockchain

这是一篇很长的帖子,所以我很感激那些回答它的人。我试图理解下面的区块链示例中的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

enter image description here

如前所述,当A创建一个新块时,它会将新块发送到它连接的节点,每个节点将验证它并可能将其添加到它的链中。此处理由processedRecievedBlock()函数完成。让我们说B和C决定将这个块添加到他们的链中,但D后面几个块,所以它必须从A请求整个链。这是我困惑的地方。我预计D会向A发送一条消息,请求整个链,如下所示:

图2

enter image description here

但是,根据processReceivedBlock()函数,在这种情况下,当这一行运行时,D将向其所有连接的套接字广播REQUEST_CHAIN消息:

broadcastMessage(REQUEST_CHAIN,"");

让我们说D连接到E和F.而不是像图2中那样从A请求链,似乎它会将REQUEST_CHAIN消息发送到它的连接套接字,就像这样:

图3

enter image description here

在messageHandler()函数中,将为E和F运行switch语句中的REQUEST_CHAIN选项,它们将点击这行代码:

connection.send(JSON.stringify({ event: CHAIN, message: chain.getChain()}));

据我了解,这将导致E和F将自己的链发送回自己,就像这样:

图4

enter image description here

我想知道为什么当D需要从A请求整个链时,图2不会发生。跟踪代码让我相信图3和图4相反,这两者似乎都没用。

当一个节点必须从另一个节点请求整个链时,我试图找到对此代码中究竟发生了什么的理解。我一定是在误解这些插座正在做什么。

完整源代码:https://github.com/dbjsdev/BrewChain/blob/master/brewNode.js

1 个答案:

答案 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节点从多个来源获取链并存储最新的经过验证的链。

希望有所帮助!