public bool appendBlock(Block b, bool add_to_storage = true) { lock (blocks) { if (b.blockNum > lastBlockNum) { lastBlock = b; lastBlockNum = b.blockNum; if (b.version != lastBlockVersion) { lastBlockVersion = b.version; } } if (b.lastSuperBlockChecksum != null || b.blockNum == 1) { pendingSuperBlocks.Remove(b.blockNum); lastSuperBlockNum = b.blockNum; lastSuperBlockChecksum = b.blockChecksum; } // special case when we are starting up and have an empty chain if (blocks.Count == 0) { blocks.Add(b); lock (blocksDictionary) { blocksDictionary.Add(b.blockNum, b); } Storage.insertBlock(b); return(true); } // check for invalid block appending if (b.blockNum != blocks[blocks.Count - 1].blockNum + 1) { Logging.warn(String.Format("Attempting to add non-sequential block #{0} after block #{1}.", b.blockNum, blocks[blocks.Count - 1].blockNum)); return(false); } if (!b.lastBlockChecksum.SequenceEqual(blocks[blocks.Count - 1].blockChecksum)) { Logging.error(String.Format("Attempting to add a block #{0} with invalid lastBlockChecksum!", b.blockNum)); return(false); } if (b.signatureFreezeChecksum != null && blocks.Count > 5 && !blocks[blocks.Count - 5].calculateSignatureChecksum().SequenceEqual(b.signatureFreezeChecksum)) { Logging.error(String.Format("Attempting to add a block #{0} with invalid sigFreezeChecksum!", b.blockNum)); return(false); } blocks.Add(b); lock (blocksDictionary) { blocksDictionary.Add(b.blockNum, b); } } if (add_to_storage) { // Add block to storage Storage.insertBlock(b); } ConsensusConfig.redactedWindowSize = ConsensusConfig.getRedactedWindowSize(b.version); ConsensusConfig.minRedactedWindowSize = ConsensusConfig.getRedactedWindowSize(b.version); redactChain(); lock (blocks) { if (blocks.Count > 30) { Block tmp_block = getBlock(b.blockNum - 30); if (tmp_block != null) { TransactionPool.compactTransactionsForBlock(tmp_block); tmp_block.compact(); } } compactBlockSigs(b); } lastBlockReceivedTime = Clock.getTimestamp(); return(true); }
public long getTimeSinceLastBLock() { return(Clock.getTimestamp() - lastBlockReceivedTime); }
public void start(Socket socket = null) { if (fullyStopped) { Logging.error("Can't start a fully stopped RemoteEndpoint"); return; } if (running) { return; } if (socket != null) { clientSocket = socket; } if (clientSocket == null) { Logging.error("Could not start NetworkRemoteEndpoint, socket is null"); return; } prepareSocket(clientSocket); remoteIP = (IPEndPoint)clientSocket.RemoteEndPoint; address = remoteIP.Address.ToString(); fullAddress = address + ":" + remoteIP.Port; presence = null; presenceAddress = null; lock (subscribedAddresses) { subscribedAddresses.Clear(); } lastDataReceivedTime = Clock.getTimestamp(); lastDataSentTime = Clock.getTimestamp(); state = RemoteEndpointState.Established; timeDifference = 0; timeSyncComplete = false; timeSyncs.Clear(); running = true; // Abort all related threads if (recvThread != null) { recvThread.Abort(); recvThread = null; } if (sendThread != null) { sendThread.Abort(); sendThread = null; } if (parseThread != null) { parseThread.Abort(); parseThread = null; } try { TLC = new ThreadLiveCheck(); // Start receive thread recvThread = new Thread(new ThreadStart(recvLoop)); recvThread.Name = "Network_Remote_Endpoint_Receive_Thread"; recvThread.Start(); // Start send thread sendThread = new Thread(new ThreadStart(sendLoop)); sendThread.Name = "Network_Remote_Endpoint_Send_Thread"; sendThread.Start(); // Start parse thread parseThread = new Thread(new ThreadStart(parseLoop)); parseThread.Name = "Network_Remote_Endpoint_Parse_Thread"; parseThread.Start(); } catch (Exception e) { Logging.error("Exception start remote endpoint: {0}", e.Message); } }
// Reads data from a socket and returns a byte array protected byte[] readSocketData() { Socket socket = clientSocket; byte[] data = null; // Check for socket availability if (socket.Connected == false) { throw new Exception("Socket already disconnected at other end"); } if (socket.Available < 1) { // Sleep a while to prevent cpu cycle waste Thread.Sleep(10); return(data); } // Read multi-packet messages // TODO: optimize this as it's not very efficient List <byte> big_buffer = new List <byte>(); bool message_found = false; try { int data_length = 0; int header_length = 43; // start byte + int32 (4 bytes) + int32 (4 bytes) + checksum (32 bytes) + header checksum (1 byte) + end byte int bytesToRead = 1; while (message_found == false && socket.Connected && running) { //int pos = bytesToRead > NetworkProtocol.recvByteHist.Length ? NetworkProtocol.recvByteHist.Length - 1 : bytesToRead; /*lock (NetworkProtocol.recvByteHist) * { * NetworkProtocol.recvByteHist[pos]++; * }*/ int byteCounter = socket.Receive(socketReadBuffer, bytesToRead, SocketFlags.None); NetDump.Instance.appendReceived(socket, socketReadBuffer, byteCounter); if (byteCounter > 0) { lastDataReceivedTime = Clock.getTimestamp(); if (big_buffer.Count > 0) { big_buffer.AddRange(socketReadBuffer.Take(byteCounter)); if (big_buffer.Count == header_length) { data_length = getDataLengthFromMessageHeader(big_buffer); if (data_length <= 0) { data_length = 0; big_buffer.Clear(); bytesToRead = 1; } } else if (big_buffer.Count == data_length + header_length) { // we have everything that we need, save the last byte and break message_found = true; } else if (big_buffer.Count < header_length) { bytesToRead = header_length - big_buffer.Count; } else if (big_buffer.Count > data_length + header_length) { Logging.error(String.Format("Unhandled edge case occured in RemoteEndPoint:readSocketData for node {0}", getFullAddress())); return(null); } if (data_length > 0) { bytesToRead = data_length + header_length - big_buffer.Count; if (bytesToRead > 8000) { bytesToRead = 8000; } } } else { if (socketReadBuffer[0] == 'X') // X is the message start byte { big_buffer.Add(socketReadBuffer[0]); bytesToRead = header_length - 1; // header length - start byte } else if (helloReceived == false) { if (socketReadBuffer[0] == 2) { readTimeSyncData(); } } } Thread.Yield(); } else { // sleep a litte while waiting for bytes Thread.Sleep(10); // TODO TODO TODO, should reset the big_buffer if a timeout occurs } } } catch (Exception e) { if (running) { Logging.error(String.Format("NET: endpoint {0} disconnected {1}", getFullAddress(), e)); throw; } } if (message_found) { data = big_buffer.ToArray(); } return(data); }
// Send thread protected void sendLoop() { // Prepare an special message object to use while sending, without locking up the queue messages QueueMessage active_message = new QueueMessage(); if (enableSendTimeSyncMessages) { sendTimeSyncMessages(); } int messageCount = 0; while (running) { TLC.Report(); long curTime = Clock.getTimestamp(); if (curTime - lastDataReceivedTime > CoreConfig.pingTimeout) { // haven't received any data for 10 seconds, stop running Logging.warn(String.Format("Node {0} hasn't received any data from remote endpoint for over {1} seconds, disconnecting.", getFullAddress(), CoreConfig.pingTimeout)); state = RemoteEndpointState.Closed; running = false; break; } if (curTime - lastDataSentTime > CoreConfig.pongInterval) { try { clientSocket.Send(new byte[1] { 1 }, SocketFlags.None); lastDataSentTime = curTime; continue; } catch (Exception) { state = RemoteEndpointState.Closed; running = false; break; } } bool message_found = false; lock (sendQueueMessagesHighPriority) { lock (sendQueueMessagesNormalPriority) { if ((messageCount > 0 && messageCount % 5 == 0) || (sendQueueMessagesNormalPriority.Count == 0 && sendQueueMessagesHighPriority.Count == 0)) { lock (sendQueueMessagesLowPriority) { if (sendQueueMessagesLowPriority.Count > 0) { // Pick the oldest message QueueMessage candidate = sendQueueMessagesLowPriority[0]; active_message.code = candidate.code; active_message.data = candidate.data; active_message.checksum = candidate.checksum; active_message.skipEndpoint = candidate.skipEndpoint; active_message.helperData = candidate.helperData; // Remove it from the queue sendQueueMessagesLowPriority.Remove(candidate); message_found = true; } } messageCount = 0; } if (message_found == false && ((messageCount > 0 && messageCount % 3 == 0) || sendQueueMessagesHighPriority.Count == 0)) { if (sendQueueMessagesNormalPriority.Count > 0) { // Pick the oldest message QueueMessage candidate = sendQueueMessagesNormalPriority[0]; active_message.code = candidate.code; active_message.data = candidate.data; active_message.checksum = candidate.checksum; active_message.skipEndpoint = candidate.skipEndpoint; active_message.helperData = candidate.helperData; // Remove it from the queue sendQueueMessagesNormalPriority.Remove(candidate); message_found = true; } } if (message_found == false && sendQueueMessagesHighPriority.Count > 0) { // Pick the oldest message QueueMessage candidate = sendQueueMessagesHighPriority[0]; active_message.code = candidate.code; active_message.data = candidate.data; active_message.checksum = candidate.checksum; active_message.skipEndpoint = candidate.skipEndpoint; active_message.helperData = candidate.helperData; // Remove it from the queue sendQueueMessagesHighPriority.Remove(candidate); message_found = true; } } } if (message_found) { messageCount++; // Active message set, attempt to send it sendDataInternal(active_message.code, active_message.data, active_message.checksum); if (active_message.code == ProtocolMessageCode.bye) { Thread.Sleep(500); // grace sleep to get the message through running = false; fullyStopped = true; } Thread.Sleep(1); } else { // Sleep for 10ms to prevent cpu waste Thread.Sleep(10); } } }
// Receive thread protected virtual void recvLoop() { socketReadBuffer = new byte[8192]; lastMessageStatTime = DateTime.UtcNow; while (running) { TLC.Report(); // Let the protocol handler receive and handle messages try { byte[] data = readSocketData(); if (data != null) { parseDataInternal(data, this); messagesPerSecond++; } } catch (Exception e) { if (running) { Logging.warn(string.Format("recvRE: Disconnected client {0} with exception {1}", getFullAddress(), e.ToString())); } state = RemoteEndpointState.Closed; } // Check if the client disconnected if (state == RemoteEndpointState.Closed) { running = false; break; } TimeSpan timeSinceLastStat = DateTime.UtcNow - lastMessageStatTime; if (timeSinceLastStat.TotalSeconds < 0 || timeSinceLastStat.TotalSeconds > 2) { lastMessageStatTime = DateTime.UtcNow; lastMessagesPerSecond = (int)(messagesPerSecond / timeSinceLastStat.TotalSeconds); messagesPerSecond = 0; } if (lastMessagesPerSecond < 1) { lastMessagesPerSecond = 1; } // Sleep a while to throttle the client // Check if there are too many messages // TODO TODO TODO this can be handled way better int total_message_count = NetworkQueue.getQueuedMessageCount() + NetworkQueue.getTxQueuedMessageCount(); if (total_message_count > 500) { Thread.Sleep(100 * lastMessagesPerSecond); if (messagesPerSecond == 0) { lastMessageStatTime = DateTime.UtcNow; } lastDataReceivedTime = Clock.getTimestamp(); } else if (total_message_count > 100) { Thread.Sleep(total_message_count / 10); } else { Thread.Sleep(1); } } }