/// <summary>
        /// Helper method that catches new messages (and handles connection exceptions).
        /// When an exception occurs, we will disconnect with the peer.
        /// </summary>
        /// <param name="node">The node to listen to</param>
        /// <param name="timeout">The message timeout to maintain. Disconnect when timeout has been exceeded.</param>
        /// <returns>The message that we received from the node</returns>
        public async Task <Message> ListenForNewMessage(NetworkNode node, TimeSpan timeout)
        {
            try
            {
                var msg = await node.ReceiveMessageAsync(timeout);

                /*
                 * var delaySec = 0;
                 * Random rnd = new Random();
                 * int delayChance = rnd.Next(1, 100);
                 * if (delayChance > 55 && delayChance < 86)
                 * {
                 *  delaySec = rnd.Next(1, 3);
                 * }
                 * else if (delayChance > 85 && delayChance < 96)
                 * {
                 *  delaySec = rnd.Next(3, 6);
                 * }
                 * else if (delayChance > 95 && delayChance < 101)
                 * {
                 *  delaySec = rnd.Next(7, 13);
                 * }
                 *
                 * await Task.Delay(delaySec * 1000);
                 */
                return(msg);
            }
            catch (Exception)
            {
                await node?.Disconnect();
            }

            return(null);
        }
Esempio n. 2
0
        public override async Task HandleMessage(NetworkNode node, Message msg)
        {
            if (node.HandshakeIsCompleted)
            {
                return;
            }

            var blockchain = _blockchainRepo.GetChainByNetId(_netId);

            try
            {
                if (node.ConnectionType == ConnectionType.Inbound)
                {
                    await HandleInboundHandshakeMessage(node, msg, blockchain);
                }
                else
                {
                    await HandleOutboundHandshakeMessage(node, msg, blockchain);
                }
            }
            catch (Exception)
            {
                node?.Disconnect();
            }
        }
Esempio n. 3
0
 public void Disconnect()
 {
     OnDisconnect?.Invoke();
     NetworkNode.Disconnect(NetworkAddress);
 }
Esempio n. 4
0
        private static void Main(String[] args)
        {
            string servers;

            if (args.Length == 3)
            {
                _port   = int.Parse(args[0]);
                servers = args[1];
                _mesh   = bool.Parse(args[2]);
            }
            else
            {
                Console.Write("Input a port to run on: ");
                _port = int.Parse(Console.ReadLine());
                Console.Write("Input a comma separated list of servers to connect to: ");
                servers = Console.ReadLine();
                Console.Write("Is this a mesh network or chord network? (\"mesh\" for mesh and \"chord\" for chord): ");
                string networkType = Console.ReadLine();
                if (networkType == "mesh")
                {
                    _mesh = true;
                }
                else if (networkType == "chord")
                {
                    _mesh = false;
                }
                else
                {
                    Console.WriteLine("Unknown network type.");
                    return;
                }
            }

            if (_mesh)
            {
                _node = new MeshNetworkNode("MeshNetworkTester" + _port + ".log", LogLevels.Warning);
            }
            else
            {
                _node = new ChordNetworkNode("MeshNetworkTester" + _port + ".log", LogLevels.Warning);
            }

            _node.ReceivedMessage += node_ReceivedMessage;
            _node.ConnectToNetwork(_port,
                                   servers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                   .Select(e => new NodeProperties(e))
                                   .ToList());
            var thisMachine = new NodeProperties("localhost", _port);

            Console.WriteLine("Please enter a command, or type \"help\" for help.");

            bool running = true;

            while (running)
            {
                Console.Write(" > ");
                string command = Console.ReadLine();

                switch (command)
                {
                case "custom":
                    Console.WriteLine("Node to send data to: ");
                    string node = Console.ReadLine();
                    Console.WriteLine("Data to send: ");
                    string data = Console.ReadLine();
                    _node.SendMessage(new NodeProperties(node), data);
                    break;

                case "exit":
                    Console.WriteLine("Shutting down node...");
                    running = false;
                    _node.Disconnect();
                    break;

                case "help":
                    Console.WriteLine("exit: Exits the program\nstatus: Displays the status of the program\nread: Reads a value from the database\nwrite: Writes a value to the database\ncustom: Sends a custom message (warning: this will also output the message on the receiver's side immediately upon receiving it)");
                    break;

                case "read":
                    Console.Write("What is the key (integer): ");
                    int key = int.Parse(Console.ReadLine());

                    string value = null;

                    // If the value is local, read it, otherwise go get it.
                    if (database.ContainsKey(key))
                    {
                        value = database[key];
                    }
                    else
                    {
                        if (_node is MeshNetworkNode)
                        {
                            // Search every node for the value.
                            List <MessageResponseResult> results = new List <MessageResponseResult>();
                            foreach (var neighbor in _node.GetNeighbors())
                            {
                                results.Add(_node.SendMessageResponse(neighbor, "read" + key));
                            }

                            foreach (var result in results)
                            {
                                if (result.SendResult == SendResults.Success &&
                                    result.ResponseResult == ResponseResults.Success)
                                {
                                    if (result.ResponseMessage.Data.StartsWith("y"))
                                    {
                                        value = result.ResponseMessage.Data.Substring(1);
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            // Search for the node that contains the value.
                            var result = ((ChordNetworkNode)_node).SendChordMessageResponse(key, "read" + key);
                            if (result.SendResult == SendResults.Success &&
                                result.ResponseResult == ResponseResults.Success)
                            {
                                if (result.ResponseMessage.Data.StartsWith("y"))
                                {
                                    value = result.ResponseMessage.Data.Substring(1);
                                }
                            }
                        }
                    }

                    if (value == null)
                    {
                        Console.WriteLine("Could not find a value associated with the key " + key + ".");
                    }
                    else
                    {
                        Console.WriteLine("Key: " + key + " Value: " + value);
                    }

                    break;

                case "status":
                    Console.WriteLine("Currently running on " + thisMachine.IpAddress + ":" + thisMachine.Port);
                    Console.WriteLine();
                    if (_node is MeshNetworkNode)
                    {
                        var neighbors = _node.GetNeighbors();
                        Console.WriteLine("Connected Nodes: ");
                        foreach (var neighbor in neighbors)
                        {
                            Console.WriteLine(neighbor.IpAddress + ":" + neighbor.Port);
                        }

                        Console.WriteLine("Currently connected to " + neighbors.Count + " nodes.");
                    }
                    else
                    {
                        var chordNode = (ChordNetworkNode)_node;
                        Console.WriteLine("id: " + chordNode.Id + " Predecessor: " + chordNode.Predecessor +
                                          " Successor: " +
                                          (chordNode.Successor == null ? "self" : chordNode.Successor.ToString()));
                        Console.WriteLine("Fingers:");
                        foreach (var finger in chordNode.GetFingers())
                        {
                            Console.WriteLine(finger.IpAddress + ":" + finger.Port);
                        }
                    }
                    break;

                case "write":
                    Console.Write("What is the key (integer): ");
                    key = int.Parse(Console.ReadLine());
                    Console.Write("What is the value (string): ");
                    value = Console.ReadLine();

                    if (_node is MeshNetworkNode)
                    {
                        // If this is a mesh network, write the value locally.
                        SetValue(key, value);
                    }
                    else
                    {
                        // Find the node that should contain the value and write it there.
                        var dataNode = ((ChordNetworkNode)_node).GetNodeContainingId(key);
                        if (dataNode == null || dataNode.Equals(thisMachine))
                        {
                            SetValue(key, value);
                        }
                        else
                        {
                            ((ChordNetworkNode)_node).SendChordMessage(key, "write" + key + " " + value);
                        }
                    }
                    break;

                default:
                    Console.WriteLine("Unknown command.");
                    break;
                }
            }
        }
Esempio n. 5
0
        // todo Chain of Responsibility pattern, make XXMessageHandler class for each command type
        // and refactor abstractmessagehandler to a regular MessageHandlerHelper
        public override async Task HandleMessage(NetworkNode node, Message msg)
        {
            try
            {
                if (msg.Command == NetworkCommand.CloseConn.ToString())
                {
                    await node.Disconnect();
                }
                else if (msg.Command == NetworkCommand.GetAddr.ToString())
                {
                    // Send our known peers
                    var addresses = new AddrPayload(_nodePool.GetAllRemoteListenEndpoints());
                    await SendMessageToNode(node, NetworkCommand.Addr, addresses);
                }
                else if (msg.Command == NetworkCommand.Addr.ToString())
                {
                    // Connect to all neighbors that the other node knows
                    var payload = (AddrPayload)msg.Payload;
                    foreach (IPEndPoint endpoint in payload.Endpoints)
                    {
                        await _networkManager.ConnectToPeer(endpoint);
                    }
                }
                else if (msg.Command == NetworkCommand.GetHeaders.ToString())
                {
                    // Send our headers
                    var payload = (GetHeadersPayload)msg.Payload;
                    try
                    {
                        var headers        = GetBlocksFromHash(payload.HighestHeightHash, payload.StoppingHash, false).Select(b => b.Header);
                        var headersPayload = new HeadersPayload(headers);
                        await SendMessageToNode(node, NetworkCommand.Headers, headersPayload);
                    }
                    catch (KeyNotFoundException)
                    {
                        // Send empty payload
                        await SendMessageToNode(node, NetworkCommand.NotFound, null);
                    }
                }
                else if (msg.Command == NetworkCommand.GetBlocks.ToString())
                {
                    var payload       = (GetBlocksPayload)msg.Payload;
                    var blocksPayload = new StateBlocksPayload();
                    if (payload.Headers.Count() > 0)
                    {
                        blocksPayload = new StateBlocksPayload(GetBlocksFromHash(payload.Headers.First(), payload.Headers.Last(), true));
                    }

                    await SendMessageToNode(node, NetworkCommand.Blocks, blocksPayload);
                }
                else if (msg.Command == NetworkCommand.Headers.ToString() && node.IsSyncingWithNode)
                {
                    node.SetSyncStatus(SyncStatus.InProgress);
                    var headersPayload = (HeadersPayload)msg.Payload;

                    if (headersPayload.Headers.Count() == 0)
                    {
                        _logger.LogInformation("Successfully synced with remote node.");
                        node.SetSyncStatus(SyncStatus.Succeeded);
                        return;
                    }

                    // Request these blocks
                    var getBlocksPayload = new GetBlocksPayload(headersPayload.Headers.Select(h => h.Hash));
                    await SendMessageToNode(node, NetworkCommand.GetBlocks, getBlocksPayload);
                }
                else if (msg.Command == NetworkCommand.NotFound.ToString() && node.IsSyncingWithNode)
                {
                    node.SetSyncStatus(SyncStatus.Failed); // Restart the syncing process with another node.
                }
                else if (msg.Command == NetworkCommand.Blocks.ToString() && node.IsSyncingWithNode)
                {
                    var blocksPayload = (StateBlocksPayload)msg.Payload;

                    // Todo rewrite this code to support multithreaded 'Blocks' messages. Combine all gathered blocks
                    // until the process has completed and all blocks are downloaded. Then, grab a block that points to the
                    // end of our chain and add it to our chain. Repeat that process until all blocks have been added.

                    var blocksProcessed = 0;

                    lock (_blockchain)
                    {
                        while (blocksPayload.Blocks.Where(b => b.Header.PreviousHash == _blockchain.Blocks.Last().Header.Hash).Any())
                        {
                            var blockToProcess = blocksPayload.Blocks.Where(b => b.Header.PreviousHash == _blockchain.Blocks.Last().Header.Hash).First();

                            if (_blockchain.CurrentHeight % 5 == 0 && _blockchain.CurrentHeight > 0)
                            {
                                _difficulty = _difficultyCalculator.CalculateCurrentDifficulty(_blockchain); // todo use CalculateCurrentDifficulty when testing is done
                            }

                            if (_difficulty < 1)
                            {
                                _difficulty = 1;
                            }
                            var currentTarget = BlockchainConstants.MaximumTarget / _difficulty;                    // todo refactor these 3 lines. They are copy-pasted from the miner.
                            _blockValidator.ValidateBlock(blockToProcess, currentTarget, _blockchain, false, true); // Rethrow when we have a Block- / TransactionRejectedException. We don't want to keep a connection with bad nodes.
                            blocksProcessed++;
                        }
                    }

                    _logger.LogDebug("Downloaded and added {0} new blocks from remote node", blocksProcessed);
                    _logger.LogDebug("Current height: {0}", _blockchain.CurrentHeight);

                    if (blocksProcessed != blocksPayload.Blocks.Count())
                    {
                        _logger.LogError("Added {0} new blocks from remote node, but expected {1}. Sync failed.", blocksProcessed, blocksPayload.Blocks.Count());
                        node.SetSyncStatus(SyncStatus.Failed);
                        return;
                    }

                    _blockchainRepo.Update(_blockchain);

                    // Block batch processed. Keep on ask for more headers.
                    var getHeadersPayload = new GetHeadersPayload(_blockchain.Blocks.Last().Header.Hash);
                    await SendMessageToNode(node, NetworkCommand.GetHeaders, getHeadersPayload);
                }
                else if (msg.Command == NetworkCommand.GetTxPool.ToString())
                {
                    var txPoolPayload = new StateTransactionsPayload(_txPool.GetAllTransactions());
                    await SendMessageToNode(node, NetworkCommand.TxPool, txPoolPayload);
                }
                else if (msg.Command == NetworkCommand.TxPool.ToString())
                {
                    var txPoolPayload = (StateTransactionsPayload)msg.Payload;
                    foreach (var tx in txPoolPayload.Transactions)
                    {
                        _txPool.AddTransaction(tx);
                    }
                }
                else if (msg.Command == NetworkCommand.NewTransaction.ToString())
                {
                    var txPayload = (SingleStateTransactionPayload)msg.Payload;
                    if (_networkManager.IsSyncing)
                    {
                        return;
                    }

                    var validationResult = EventPublisher.GetInstance().PublishUnvalidatedTransactionReceived(node, new TransactionReceivedEventArgs(txPayload.Transaction));
                    if (validationResult == false)
                    {
                        //await node.Disconnect(); // Dishonest node, buuh!
                    }
                }
                else if (msg.Command == NetworkCommand.NewBlock.ToString())
                {
                    var blockPayload = (SingleStateBlockPayload)msg.Payload;
                    if (_networkManager.IsSyncing)
                    {
                        return;
                    }

                    var validationResult = EventPublisher.GetInstance().PublishUnvalidatedBlockCreated(node, new BlockCreatedEventArgs(blockPayload.Block));
                    if (validationResult == false)
                    {
                        //await node.Disconnect(); // Dishonest node, buuh!
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("An {0} occurred during the process of handling a {1} message: {2}. Node will be disconnected.", ex.GetType().Name, msg.Command.ToString(), ex.Message);
                node?.Disconnect();
            }
        }