private static void broadcastBlockHeaderTransactions(Block b, RemoteEndpoint endpoint) { if (!endpoint.isConnected()) { return; } foreach (var txid in b.transactions) { Transaction t = TransactionPool.getAppliedTransaction(txid, b.blockNum, true); if (endpoint.isSubscribedToAddress(NetworkEvents.Type.transactionFrom, new Address(t.pubKey).address)) { endpoint.sendData(ProtocolMessageCode.transactionData, t.getBytes(true), null); } else { foreach (var entry in t.toList) { if (endpoint.isSubscribedToAddress(NetworkEvents.Type.transactionTo, entry.Key)) { endpoint.sendData(ProtocolMessageCode.transactionData, t.getBytes(true), null); } } } } }
/// <summary> /// Subscribes client to transactionFrom, transactionTo and balance /// </summary> /// <remarks> /// This function is used to ensure that the remote endpoing has listed the correct IP and port information for their `PresenceList` entry. /// </remarks> /// <param name="endpoint">Target endpoint to verify for connectivity.</param> public static void subscribeToEvents(RemoteEndpoint endpoint) { if (endpoint.presenceAddress.type != 'M') { return; } // TODO TODO TODO events can be optimized as there is no real need to subscribe them to every connected node // Subscribe to transaction events, for own addresses var my_addresses = IxianHandler.getWalletStorage().getMyAddresses(); Cuckoo filter = new Cuckoo(my_addresses.Count()); foreach (var addr in my_addresses) { filter.Add(addr.address); } byte[] filter_data = filter.getFilterBytes(); byte[] event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.transactionFrom, filter_data); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.transactionTo, filter_data); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.balance, filter_data); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); }
public static bool broadcastGetTransaction(string txid, ulong block_num, RemoteEndpoint endpoint = null) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writerw = new BinaryWriter(mw)) { writerw.Write(txid); writerw.Write(block_num); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::broadcastGetTransaction: {0}", mw.Length)); #endif if (endpoint != null) { if (endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.getTransaction, mw.ToArray()); return(true); } } // TODO TODO TODO TODO TODO determine if historic transaction and send to 'H' instead of 'M' return(broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'H' }, ProtocolMessageCode.getTransaction, mw.ToArray(), block_num)); } } }
/// <summary> /// Prepares and sends the disconnect message to the specified remote endpoint. /// </summary> /// <param name="endpoint">Remote client.</param> /// <param name="code">Disconnection reason.</param> /// <param name="message">Optional text message for the user of the remote client.</param> /// <param name="data">Optional payload to further explain the disconnection reason.</param> /// <param name="removeAddressEntry">If true, the remote address will be removed from the `PresenceList`.</param> public static void sendBye(RemoteEndpoint endpoint, ProtocolByeCode code, string message, string data, bool removeAddressEntry = true) { using (MemoryStream m2 = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(m2)) { writer.Write((int)code); writer.Write(message); writer.Write(data); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("CoreProtocolMessage::sendBye: {0}", m2.Length)); #endif endpoint.sendData(ProtocolMessageCode.bye, m2.ToArray()); Logging.info("Sending bye to {0} with message '{1}' and data '{2}'", endpoint.getFullAddress(), message, data); } } if (removeAddressEntry) { if (endpoint.presence != null && endpoint.presence.wallet != null && endpoint.presenceAddress != null) { PresenceList.removeAddressEntry(endpoint.presence.wallet, endpoint.presenceAddress); } //PeerStorage.removePeer(endpoint.getFullAddress(true)); } }
static public void handleSyncWalletState(byte[] data, RemoteEndpoint endpoint) { if (Node.blockSync.startOutgoingWSSync(endpoint) == false) { Logging.warn(String.Format("Unable to start synchronizing with neighbor {0}", endpoint.presence.addresses[0].address)); return; } // Request the latest walletstate header using (MemoryStream m = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(m)) { ulong walletstate_block = Node.blockSync.pendingWsBlockNum; long walletstate_count = Node.walletState.numWallets; int walletstate_version = Node.walletState.version; // Return the current walletstate block and walletstate count writer.WriteIxiVarInt(walletstate_version); writer.WriteIxiVarInt(walletstate_block); writer.WriteIxiVarInt(walletstate_count); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::parseProtocolMessage2: {0}", m.Length)); #endif endpoint.sendData(ProtocolMessageCode.walletState, m.ToArray()); } } }
public static bool broadcastGetBlockSignatures(ulong block_num, byte[] block_checksum, RemoteEndpoint endpoint) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writerw = new BinaryWriter(mw)) { writerw.WriteIxiVarInt(block_num); writerw.WriteIxiVarInt(block_checksum.Length); writerw.Write(block_checksum); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::broadcastGetBlockSignatures: {0}", mw.Length)); #endif if (endpoint != null) { if (endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.getBlockSignatures2, mw.ToArray()); return(true); } } return(CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'H' }, ProtocolMessageCode.getBlockSignatures2, mw.ToArray(), block_num)); } } }
static void handleGetPresence2(byte[] data, RemoteEndpoint endpoint) { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int walletLen = (int)reader.ReadIxiVarUInt(); byte[] wallet = reader.ReadBytes(walletLen); Presence p = PresenceList.getPresenceByAddress(wallet); if (p != null) { lock (p) { byte[][] presence_chunks = p.getByteChunks(); foreach (byte[] presence_chunk in presence_chunks) { endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk, null); } } } else { // TODO blacklisting point Logging.warn(string.Format("Node has requested presence information about {0} that is not in our PL.", Base58Check.Base58CheckEncoding.EncodePlain(wallet))); } } } }
public static bool broadcastNewBlock(Block b, RemoteEndpoint skipEndpoint = null, RemoteEndpoint endpoint = null, bool force_broadcast = false) { if (!Node.isMasterNode()) { return(true); } if (endpoint != null) { if (endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.blockData, b.getBytes(false), BitConverter.GetBytes(b.blockNum)); return(true); } return(false); } else { if (force_broadcast) { return(CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.blockData, b.getBytes(false), BitConverter.GetBytes(b.blockNum), skipEndpoint)); } else { return(CoreProtocolMessage.addToInventory(new char[] { 'M', 'H' }, new InventoryItemBlock(b.blockChecksum, b.blockNum), skipEndpoint, ProtocolMessageCode.blockData, b.getBytes(false), BitConverter.GetBytes(b.blockNum))); } } }
public static bool broadcastGetBlock(ulong block_num, RemoteEndpoint skipEndpoint = null, RemoteEndpoint endpoint = null, byte include_transactions = 0, bool full_header = false) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writerw = new BinaryWriter(mw)) { writerw.WriteIxiVarInt(block_num); writerw.Write(include_transactions); writerw.Write(full_header); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::broadcastGetBlock: {0}", mw.Length)); #endif if (endpoint != null) { if (endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.getBlock3, mw.ToArray()); return(true); } } return(CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'H' }, ProtocolMessageCode.getBlock3, mw.ToArray(), block_num, skipEndpoint)); } } }
public static void handleGetRandomPresences(byte[] data, RemoteEndpoint endpoint) { if (!endpoint.isConnected()) { return; } using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { char type = reader.ReadChar(); List <Presence> presences = PresenceList.getPresencesByType(type); int presence_count = presences.Count(); if (presence_count > 10) { Random rnd = new Random(); presences = presences.Skip(rnd.Next(presence_count - 10)).Take(10).ToList(); } foreach (Presence presence in presences) { byte[][] presence_chunks = presence.getByteChunks(); foreach (byte[] presence_chunk in presence_chunks) { endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk, null); } } } } }
private bool handleKeepAlive(InventoryItem item, RemoteEndpoint endpoint) { if (endpoint == null) { return(false); } InventoryItemKeepAlive iika = (InventoryItemKeepAlive)item; Presence p = PresenceList.getPresenceByAddress(iika.address); if (p == null) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(mw)) { writer.WriteIxiVarInt(iika.address.Length); writer.Write(iika.address); endpoint.sendData(ProtocolMessageCode.getPresence2, mw.ToArray(), null); } } return(false); } else { var pa = p.addresses.Find(x => x.device.SequenceEqual(iika.deviceId)); if (pa == null || iika.lastSeen > pa.lastSeenTime) { byte[] address_len_bytes = ((ulong)iika.address.Length).GetIxiVarIntBytes(); byte[] device_len_bytes = ((ulong)iika.deviceId.Length).GetIxiVarIntBytes(); byte[] data = new byte[1 + address_len_bytes.Length + iika.address.Length + device_len_bytes.Length + iika.deviceId.Length]; data[0] = 1; Array.Copy(address_len_bytes, 0, data, 1, address_len_bytes.Length); Array.Copy(iika.address, 0, data, 1 + address_len_bytes.Length, iika.address.Length); Array.Copy(device_len_bytes, 0, data, 1 + address_len_bytes.Length + iika.address.Length, device_len_bytes.Length); Array.Copy(iika.deviceId, 0, data, 1 + address_len_bytes.Length + iika.address.Length + device_len_bytes.Length, iika.deviceId.Length); endpoint.sendData(ProtocolMessageCode.getKeepAlives, data, null); return(true); } } return(false); }
private static void subscribeToEvents(RemoteEndpoint endpoint) { CoreProtocolMessage.subscribeToEvents(endpoint); byte[] friend_matcher = FriendList.getFriendCuckooFilter(); if (friend_matcher != null) { byte[] event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.keepAlive, friend_matcher); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); } }
private bool handleSignature(InventoryItem item, RemoteEndpoint endpoint) { InventoryItemSignature iis = (InventoryItemSignature)item; ulong last_block_height = IxianHandler.getLastBlockHeight(); byte[] address = iis.address; ulong block_num = iis.blockNum; if (block_num + 5 > last_block_height && block_num <= last_block_height + 1) { if (block_num == last_block_height + 1) { lock (Node.blockProcessor.localBlockLock) { Block local_block = Node.blockProcessor.localNewBlock; if (local_block == null || local_block.blockNum != block_num) { return(false); } if (!local_block.blockChecksum.SequenceEqual(iis.blockHash) || local_block.hasNodeSignature(address)) { return(false); } } } else { Block sf_block = Node.blockChain.getBlock(block_num); if (!sf_block.blockChecksum.SequenceEqual(iis.blockHash) || sf_block.hasNodeSignature(address)) { return(false); } } byte[] block_num_bytes = block_num.GetIxiVarIntBytes(); byte[] addr_len_bytes = ((ulong)address.Length).GetIxiVarIntBytes(); byte[] data = new byte[block_num_bytes.Length + 1 + addr_len_bytes.Length + address.Length]; Array.Copy(block_num_bytes, data, block_num_bytes.Length); data[block_num_bytes.Length] = 1; Array.Copy(addr_len_bytes, 0, data, block_num_bytes.Length + 1, addr_len_bytes.Length); Array.Copy(address, 0, data, block_num_bytes.Length + 1 + addr_len_bytes.Length, address.Length); if (endpoint == null) { CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'H' }, ProtocolMessageCode.getSignatures, data, block_num); } else { endpoint.sendData(ProtocolMessageCode.getSignatures, data, null); } return(true); } return(false); }
public static void handleGetNextSuperBlock(byte[] data, RemoteEndpoint endpoint) { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { ulong include_segments = reader.ReadIxiVarUInt(); bool full_header = reader.ReadBoolean(); Block block = null; int checksum_len = (int)reader.ReadIxiVarUInt(); byte[] checksum = reader.ReadBytes(checksum_len); block = Node.storage.getBlockByLastSBHash(checksum); if (block != null) { endpoint.sendData(ProtocolMessageCode.blockData, block.getBytes(full_header), BitConverter.GetBytes(block.blockNum)); if (include_segments > 0) { foreach (var entry in block.superBlockSegments.OrderBy(x => x.Key)) { SuperBlockSegment segment = entry.Value; if (segment.blockNum < include_segments) { continue; } Block segment_block = Node.blockChain.getBlock(segment.blockNum, true); endpoint.sendData(ProtocolMessageCode.blockData, segment_block.getBytes(), BitConverter.GetBytes(segment.blockNum)); } } } } } }
public static void broadcastGetKeepAlives(List <InventoryItemKeepAlive> ka_list, RemoteEndpoint endpoint) { int ka_count = ka_list.Count; int max_ka_per_chunk = CoreConfig.maximumKeepAlivesPerChunk; for (int i = 0; i < ka_count;) { using (MemoryStream mOut = new MemoryStream(max_ka_per_chunk * 570)) { using (BinaryWriter writer = new BinaryWriter(mOut)) { int next_ka_count; if (ka_count - i > max_ka_per_chunk) { next_ka_count = max_ka_per_chunk; } else { next_ka_count = ka_count - i; } writer.WriteIxiVarInt(next_ka_count); for (int j = 0; j < next_ka_count && i < ka_count; j++) { InventoryItemKeepAlive ka = ka_list[i]; i++; if (ka == null) { break; } long rollback_len = mOut.Length; writer.WriteIxiVarInt(ka.address.Length); writer.Write(ka.address); writer.WriteIxiVarInt(ka.deviceId.Length); writer.Write(ka.deviceId); if (mOut.Length > CoreConfig.maxMessageSize) { mOut.SetLength(rollback_len); i--; break; } } } endpoint.sendData(ProtocolMessageCode.getKeepAlives, mOut.ToArray(), null); } } }
public static void broadcastGetSignatures(ulong block_num, List <InventoryItemSignature> sig_list, RemoteEndpoint endpoint) { int sig_count = sig_list.Count; int max_sig_per_chunk = ConsensusConfig.maximumBlockSigners; for (int i = 0; i < sig_count;) { using (MemoryStream mOut = new MemoryStream(max_sig_per_chunk * 570)) { using (BinaryWriter writer = new BinaryWriter(mOut)) { writer.WriteIxiVarInt(block_num); int next_sig_count; if (sig_count - i > max_sig_per_chunk) { next_sig_count = max_sig_per_chunk; } else { next_sig_count = sig_count - i; } writer.WriteIxiVarInt(next_sig_count); for (int j = 0; j < next_sig_count && i < sig_count; j++) { InventoryItemSignature sig = sig_list[i]; i++; long out_rollback_len = mOut.Length; writer.WriteIxiVarInt(sig.address.Length); writer.Write(sig.address); if (mOut.Length > CoreConfig.maxMessageSize) { mOut.SetLength(out_rollback_len); i--; break; } } } endpoint.sendData(ProtocolMessageCode.getSignatures, mOut.ToArray(), null); } } }
// Handle the getUnappliedTransactions message // This is called from NetworkProtocol public static void handleGetUnappliedTransactions(byte[] data, RemoteEndpoint endpoint) { Transaction[] txIdArr = TransactionPool.getUnappliedTransactions(); int tx_count = txIdArr.Count(); if (tx_count == 0) { return; } // Go through each chunk for (int i = 0; i < tx_count;) { using (MemoryStream mOut = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(mOut)) { // Generate a chunk of transactions for (int j = 0; j < CoreConfig.maximumTransactionsPerChunk && i < tx_count; j++) { byte[] txBytes = txIdArr[i].getBytes(); i++; long rollback_len = mOut.Length; writer.Write(txBytes.Length); writer.Write(txBytes); if (mOut.Length > CoreConfig.maxMessageSize) { mOut.SetLength(rollback_len); i--; break; } } // Send a chunk #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::handleGetUnappliedTransactions: {0}", mOut.Length)); #endif } endpoint.sendData(ProtocolMessageCode.blockTransactionsChunk, mOut.ToArray()); } } }
public static void broadcastGetTransactions(List <byte[]> tx_list, long msg_id, RemoteEndpoint endpoint) { if (endpoint == null) { return; } int tx_count = tx_list.Count; int max_tx_per_chunk = CoreConfig.maximumTransactionsPerChunk; for (int i = 0; i < tx_count;) { using (MemoryStream mOut = new MemoryStream(max_tx_per_chunk * 570)) { using (BinaryWriter writer = new BinaryWriter(mOut)) { int next_tx_count = tx_count - i; if (next_tx_count > max_tx_per_chunk) { next_tx_count = max_tx_per_chunk; } writer.WriteIxiVarInt(msg_id); writer.WriteIxiVarInt(next_tx_count); for (int j = 0; j < next_tx_count && i < tx_count; j++) { long rollback_len = mOut.Length; writer.WriteIxiVarInt(tx_list[i].Length); writer.Write(tx_list[i]); i++; if (mOut.Length > CoreConfig.maxMessageSize) { mOut.SetLength(rollback_len); i--; break; } } } MessagePriority priority = msg_id > 0 ? MessagePriority.high : MessagePriority.auto; endpoint.sendData(ProtocolMessageCode.getTransactions2, mOut.ToArray(), null, msg_id, priority); } } }
// Sends a single wallet chunk public static void sendWalletStateChunk(RemoteEndpoint endpoint, WsChunk chunk) { using (MemoryStream m = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(m)) { writer.WriteIxiVarInt(chunk.blockNum); writer.WriteIxiVarInt(chunk.chunkNum); writer.WriteIxiVarInt(chunk.wallets.Length); foreach (Wallet w in chunk.wallets) { writer.WriteIxiVarInt(w.id.Length); writer.Write(w.id); byte[] balance_bytes = w.balance.getAmount().ToByteArray(); writer.WriteIxiVarInt(balance_bytes.Length); writer.Write(balance_bytes); if (w.data != null) { writer.WriteIxiVarInt(w.data.Length); writer.Write(w.data); } else { writer.WriteIxiVarInt((int)0); } if (w.publicKey != null) { writer.WriteIxiVarInt(w.publicKey.Length); writer.Write(w.publicKey); } else { writer.WriteIxiVarInt((int)0); } } #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::sendWalletStateChunk: {0}", m.Length)); #endif endpoint.sendData(ProtocolMessageCode.walletStateChunk, m.ToArray()); } } }
public static void handleGetBalance2(byte[] data, RemoteEndpoint endpoint) { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int addrLen = (int)reader.ReadIxiVarUInt(); byte[] address = reader.ReadBytes(addrLen); // Retrieve the latest balance IxiNumber balance = Node.walletState.getWalletBalance(address); // Return the balance for the matching address using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writerw = new BinaryWriter(mw)) { // Send the address writerw.WriteIxiVarInt(address.Length); writerw.Write(address); // Send the balance byte[] balance_bytes = balance.getAmount().ToByteArray(); writerw.WriteIxiVarInt(balance_bytes.Length); writerw.Write(balance_bytes); Block tmp_block = IxianHandler.getLastBlock(); // Send the block height for this balance writerw.WriteIxiVarInt(tmp_block.blockNum); // Send the block checksum for this balance writerw.WriteIxiVarInt(tmp_block.blockChecksum.Length); writerw.Write(tmp_block.blockChecksum); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::parseProtocolMessage: {0}", mw.Length)); #endif endpoint.sendData(ProtocolMessageCode.balance2, mw.ToArray()); } } } } }
// Sends an error stream message to a recipient public static void sendError(byte[] recipient, byte[] sender, byte[] data, RemoteEndpoint endpoint = null) { StreamMessage message = new StreamMessage(); message.type = StreamMessageCode.error; message.recipient = recipient; message.sender = sender; message.data = data; message.encryptionType = StreamMessageEncryptionCode.none; if (endpoint != null) { endpoint.sendData(ProtocolMessageCode.s2data, message.getBytes()); } else { NetworkServer.forwardMessage(recipient, ProtocolMessageCode.s2data, message.getBytes()); } }
public static void handleGetTransaction2(byte[] data, RemoteEndpoint endpoint) { if (Node.blockSync.synchronizing) { return; } using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { // Retrieve the transaction id int txid_len = (int)reader.ReadIxiVarUInt(); byte[] txid = reader.ReadBytes(txid_len); ulong block_num = reader.ReadIxiVarUInt(); Transaction transaction = null; string txid_str = UTF8Encoding.UTF8.GetString(txid); // Check for a transaction corresponding to this id if (block_num == 0 || block_num == Node.blockChain.getLastBlockNum() + 1) { transaction = TransactionPool.getUnappliedTransaction(Transaction.txIdLegacyToV8(txid_str)); } if (transaction == null) { transaction = TransactionPool.getAppliedTransaction(Transaction.txIdLegacyToV8(txid_str), block_num, true); } if (transaction == null) { Logging.warn("I do not have txid '{0}.", Transaction.txIdV8ToLegacy(txid)); return; } Logging.info("Sending transaction {0} - {1} - {2}.", Transaction.txIdV8ToLegacy(transaction.id), Crypto.hashToString(transaction.checksum), transaction.amount); endpoint.sendData(ProtocolMessageCode.transactionData, transaction.getBytes(true)); } } }
public static bool broadcastBlockSignature(byte[] signature, byte[] sig_address, ulong block_num, byte[] block_hash, RemoteEndpoint skipEndpoint = null, RemoteEndpoint endpoint = null) { byte[] signature_data = null; using (MemoryStream m = new MemoryStream(1152)) { using (BinaryWriter writer = new BinaryWriter(m)) { writer.WriteIxiVarInt(block_num); writer.WriteIxiVarInt(block_hash.Length); writer.Write(block_hash); writer.WriteIxiVarInt(signature.Length); writer.Write(signature); writer.WriteIxiVarInt(sig_address.Length); writer.Write(sig_address); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::broadcastNewBlockSignature: {0}", m.Length)); #endif signature_data = m.ToArray(); } } if (endpoint != null) { if (endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.blockSignature2, signature_data); return(true); } return(false); } else { return(CoreProtocolMessage.addToInventory(new char[] { 'M', 'H' }, new InventoryItemSignature(sig_address, block_num, block_hash), skipEndpoint, ProtocolMessageCode.blockSignature2, signature_data, null)); } }
public static bool sendToClient(string neighbor, ProtocolMessageCode code, byte[] data, byte[] helper_data) { RemoteEndpoint client = null; lock (connectedClients) { foreach (RemoteEndpoint ep in connectedClients) { if (ep.getFullAddress() == neighbor) { client = ep; break; } } } if (client != null) { client.sendData(code, data, helper_data); return(true); } return(false); }
private static void subscribeToEvents(RemoteEndpoint endpoint) { if (endpoint.presenceAddress.type != 'M') { return; } // Get presences endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'R' }); endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'M' }); // TODO TODO TODO events can be optimized as there is no real need to subscribe them to every connected node // Subscribe to transaction events byte[] event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.transactionFrom, IxianHandler.getWalletStorage().getPrimaryAddress()); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.transactionTo, IxianHandler.getWalletStorage().getPrimaryAddress()); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.balance, IxianHandler.getWalletStorage().getPrimaryAddress()); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); List <byte[]> match_addresses = FriendList.getHiddenMatchAddresses(); if (match_addresses != null) { foreach (var address in match_addresses) { event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.keepAlive, address); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); } } }
// Unified protocol message parsing public static void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint) { if (endpoint == null) { Logging.error("Endpoint was null. parseProtocolMessage"); return; } try { switch (code) { case ProtocolMessageCode.hello: using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { if (CoreProtocolMessage.processHelloMessage(endpoint, reader)) { int challenge_len = reader.ReadInt32(); byte[] challenge = reader.ReadBytes(challenge_len); byte[] challenge_response = CryptoManager.lib.getSignature(challenge, Node.walletStorage.getPrimaryPrivateKey()); CoreProtocolMessage.sendHelloMessage(endpoint, true, challenge_response); endpoint.helloReceived = true; return; } } } break; case ProtocolMessageCode.helloData: using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { if (CoreProtocolMessage.processHelloMessage(endpoint, reader)) { char node_type = endpoint.presenceAddress.type; if (node_type != 'M' && node_type != 'H') { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.expectingMaster, string.Format("Expecting master node."), "", true); return; } ulong last_block_num = reader.ReadUInt64(); int bcLen = reader.ReadInt32(); byte[] block_checksum = reader.ReadBytes(bcLen); int wsLen = reader.ReadInt32(); byte[] walletstate_checksum = reader.ReadBytes(wsLen); int consensus = reader.ReadInt32(); endpoint.blockHeight = last_block_num; int block_version = reader.ReadInt32(); Node.setLastBlock(last_block_num, block_checksum, walletstate_checksum, block_version); // Check for legacy level ulong legacy_level = reader.ReadUInt64(); // deprecated int challenge_response_len = reader.ReadInt32(); byte[] challenge_response = reader.ReadBytes(challenge_response_len); if (!CryptoManager.lib.verifySignature(endpoint.challenge, endpoint.serverPubKey, challenge_response)) { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.authFailed, string.Format("Invalid challenge response."), "", true); return; } // Process the hello data endpoint.helloReceived = true; NetworkClientManager.recalculateLocalTimeDifference(); } } } break; case ProtocolMessageCode.s2data: { StreamProcessor.receiveData(data, endpoint); } break; case ProtocolMessageCode.s2failed: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { Logging.error("Failed to send s2 data"); } } } break; case ProtocolMessageCode.s2signature: { StreamProcessor.receivedTransactionSignature(data, endpoint); } break; case ProtocolMessageCode.newTransaction: { // Forward the new transaction message to the DLT network CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.newTransaction, data, null); } break; case ProtocolMessageCode.presenceList: { Logging.info("Receiving complete presence list"); PresenceList.syncFromBytes(data); } break; case ProtocolMessageCode.updatePresence: { // Parse the data and update entries in the presence list PresenceList.updateFromBytes(data); } break; case ProtocolMessageCode.keepAlivePresence: { byte[] address = null; bool updated = PresenceList.receiveKeepAlive(data, out address, endpoint); // If a presence entry was updated, broadcast this message again if (updated) { CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R', 'H', 'W' }, ProtocolMessageCode.keepAlivePresence, data, address, endpoint); // Send this keepalive message to all connected clients CoreProtocolMessage.broadcastEventDataMessage(NetworkEvents.Type.keepAlive, address, ProtocolMessageCode.keepAlivePresence, data, address, endpoint); } } break; case ProtocolMessageCode.getPresence: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int walletLen = reader.ReadInt32(); byte[] wallet = reader.ReadBytes(walletLen); Presence p = PresenceList.getPresenceByAddress(wallet); if (p != null) { lock (p) { byte[][] presence_chunks = p.getByteChunks(); foreach (byte[] presence_chunk in presence_chunks) { endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk, null); } } } else { // TODO blacklisting point Logging.warn(string.Format("Node has requested presence information about {0} that is not in our PL.", Base58Check.Base58CheckEncoding.EncodePlain(wallet))); } } } } break; case ProtocolMessageCode.balance: { // TODO: make sure this is received from a DLT node only. using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int address_length = reader.ReadInt32(); byte[] address = reader.ReadBytes(address_length); // Retrieve the latest balance IxiNumber balance = reader.ReadString(); if (address.SequenceEqual(Node.walletStorage.getPrimaryAddress())) { Node.balance = balance; } // Retrieve the blockheight for the balance ulong blockheight = reader.ReadUInt64(); Node.blockHeight = blockheight; } } } break; case ProtocolMessageCode.bye: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { endpoint.stop(); bool byeV1 = false; try { ProtocolByeCode byeCode = (ProtocolByeCode)reader.ReadInt32(); string byeMessage = reader.ReadString(); string byeData = reader.ReadString(); byeV1 = true; switch (byeCode) { case ProtocolByeCode.bye: // all good break; case ProtocolByeCode.forked: // forked node disconnected Logging.info(string.Format("Disconnected with message: {0} {1}", byeMessage, byeData)); break; case ProtocolByeCode.deprecated: // deprecated node disconnected Logging.info(string.Format("Disconnected with message: {0} {1}", byeMessage, byeData)); break; case ProtocolByeCode.incorrectIp: // incorrect IP if (IxiUtils.validateIPv4(byeData)) { if (NetworkClientManager.getConnectedClients(true).Length < 2) { IxianHandler.publicIP = byeData; Logging.info("Changed internal IP Address to " + byeData + ", reconnecting"); } } break; case ProtocolByeCode.notConnectable: // not connectable from the internet Logging.error("This node must be connectable from the internet, to connect to the network."); Logging.error("Please setup uPNP and/or port forwarding on your router for port " + IxianHandler.publicPort + "."); NetworkServer.connectable = false; break; case ProtocolByeCode.insufficientFunds: break; default: Logging.warn(string.Format("Disconnected with message: {0} {1}", byeMessage, byeData)); break; } } catch (Exception) { } if (byeV1) { return; } reader.BaseStream.Seek(0, SeekOrigin.Begin); // Retrieve the message string message = reader.ReadString(); if (message.Length > 0) { Logging.info(string.Format("Disconnected with message: {0}", message)); } else { Logging.info("Disconnected"); } } } } break; case ProtocolMessageCode.extend: { if (Config.isTestClient) { TestClientNode.handleExtendProtocol(data); } } break; default: break; } } catch (Exception e) { Logging.error(string.Format("Error parsing network message. Details: {0}", e.ToString())); } }
static void handleHelloData(byte[] data, RemoteEndpoint endpoint) { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { if (CoreProtocolMessage.processHelloMessageV6(endpoint, reader)) { char node_type = endpoint.presenceAddress.type; if (node_type != 'M' && node_type != 'H') { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.expectingMaster, string.Format("Expecting master node."), "", true); return; } ulong last_block_num = reader.ReadIxiVarUInt(); int bcLen = (int)reader.ReadIxiVarUInt(); byte[] block_checksum = reader.ReadBytes(bcLen); endpoint.blockHeight = last_block_num; int block_version = (int)reader.ReadIxiVarUInt(); try { string public_ip = reader.ReadString(); ((NetworkClient)endpoint).myAddress = public_ip; } catch (Exception) { } string address = NetworkClientManager.getMyAddress(); if (address != null) { if (IxianHandler.publicIP != address) { Logging.info("Setting public IP to " + address); IxianHandler.publicIP = address; } } // Process the hello data endpoint.helloReceived = true; NetworkClientManager.recalculateLocalTimeDifference(); Node.setNetworkBlock(last_block_num, block_checksum, block_version); // Get random presences endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'M' }); endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'H' }); CoreProtocolMessage.subscribeToEvents(endpoint); } } } }
// Called when receiving a keepalive network message. The PresenceList will update the appropriate entry based on the timestamp. // Returns TRUE if it updated an entry in the PL // Sets the out address parameter to be the KA wallet's address or null if an error occured public static bool receiveKeepAlive(byte[] bytes, out byte[] address, RemoteEndpoint endpoint) { address = null; // Get the current timestamp long currentTime = Clock.getNetworkTimestamp(); try { using (MemoryStream m = new MemoryStream(bytes)) { using (BinaryReader reader = new BinaryReader(m)) { int keepAliveVersion = reader.ReadInt32(); int walletLen = reader.ReadInt32(); byte[] wallet = reader.ReadBytes(walletLen); // Assign the out address parameter address = wallet; string deviceid = reader.ReadString(); long timestamp = reader.ReadInt64(); string hostname = reader.ReadString(); char node_type = '0'; node_type = reader.ReadChar(); int sigLen = reader.ReadInt32(); byte[] signature = reader.ReadBytes(sigLen); //Logging.info(String.Format("[PL] KEEPALIVE request from {0}", hostname)); if (node_type == 'C' || node_type == 'R') { // all good, continue } else if (node_type == 'M' || node_type == 'H') { if (myPresenceType == 'M' || myPresenceType == 'H') { // check balance if (IxianHandler.getWalletBalance(wallet) < ConsensusConfig.minimumMasterNodeFunds) { return(false); } } } else { // reject everything else return(false); } lock (presences) { Presence listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet)); if (listEntry == null && wallet.SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress())) { Logging.warn("My entry was removed from local PL, readding."); curNodePresence.addresses.Clear(); curNodePresence.addresses.Add(curNodePresenceAddress); updateEntry(curNodePresence); listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet)); } // Check if no such wallet found in presence list if (listEntry == null) { // request for additional data using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(mw)) { writer.Write(wallet.Length); writer.Write(wallet); if (endpoint != null && endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.getPresence, mw.ToArray(), wallet); } else { CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'R', 'H' }, ProtocolMessageCode.getPresence, mw.ToArray(), 0, null); } } } return(false); } // Verify the signature if (CryptoManager.lib.verifySignature(bytes.Take(bytes.Length - sigLen - 4).ToArray(), listEntry.pubkey, signature) == false) { Logging.warn(string.Format("[PL] KEEPALIVE tampering for {0} {1}, incorrect Sig.", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), hostname)); return(false); } PresenceAddress pa = listEntry.addresses.Find(x => x.address == hostname && x.device == deviceid); if (pa != null) { // Check the node type if (pa.lastSeenTime != timestamp) { // Check for outdated timestamp if (timestamp < pa.lastSeenTime) { // We already have a newer timestamp for this entry return(false); } int expiration_time = CoreConfig.serverPresenceExpiration; if (pa.type == 'C') { expiration_time = CoreConfig.clientPresenceExpiration; } // Check for tampering. Includes a +300, -30 second synchronization zone if ((currentTime - timestamp) > expiration_time) { Logging.warn(string.Format("[PL] Received expired KEEPALIVE for {0} {1}. Timestamp {2}", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), pa.address, timestamp)); return(false); } if ((currentTime - timestamp) < -30) { Logging.warn(string.Format("[PL] Potential KEEPALIVE tampering for {0} {1}. Timestamp {2}", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), pa.address, timestamp)); return(false); } // Update the timestamp pa.lastSeenTime = timestamp; pa.signature = signature; pa.version = keepAliveVersion; if (pa.type != node_type) { lock (presenceCount) { presenceCount[pa.type]--; if (!presenceCount.ContainsKey(node_type)) { presenceCount.Add(node_type, 0); } presenceCount[node_type]++; } } pa.type = node_type; //Console.WriteLine("[PL] LASTSEEN for {0} - {1} set to {2}", hostname, deviceid, pa.lastSeenTime); return(true); } } else { if (wallet.SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress())) { curNodePresence.addresses.Clear(); curNodePresence.addresses.Add(curNodePresenceAddress); updateEntry(curNodePresence); return(true); } else { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(mw)) { writer.Write(wallet.Length); writer.Write(wallet); if (endpoint != null && endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.getPresence, mw.ToArray(), wallet); } else { CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'R', 'H' }, ProtocolMessageCode.getPresence, mw.ToArray(), 0, null); } } } return(false); } } } } } } catch (Exception e) { Logging.error("Exception occured in receiveKeepAlive: " + e); return(false); } return(false); }
// Unified protocol message parsing public static void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint) { if (endpoint == null) { Logging.error("Endpoint was null. parseProtocolMessage"); return; } try { switch (code) { case ProtocolMessageCode.hello: using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { bool processed = false; processed = CoreProtocolMessage.processHelloMessageV6(endpoint, reader, false); if (!processed || (Config.whiteList.Count > 0 && !Config.whiteList.Contains(endpoint.presence.wallet, new ByteArrayComparer()))) { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.bye, string.Format("Access denied."), "", true); return; } endpoint.helloReceived = true; } } break; case ProtocolMessageCode.helloData: using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { if (CoreProtocolMessage.processHelloMessageV6(endpoint, reader)) { char node_type = endpoint.presenceAddress.type; if (node_type != 'M' && node_type != 'H') { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.expectingMaster, string.Format("Expecting master node."), "", true); return; } ulong last_block_num = reader.ReadIxiVarUInt(); int bcLen = (int)reader.ReadIxiVarUInt(); byte[] block_checksum = reader.ReadBytes(bcLen); endpoint.blockHeight = last_block_num; int block_version = (int)reader.ReadIxiVarUInt(); try { string public_ip = reader.ReadString(); ((NetworkClient)endpoint).myAddress = public_ip; } catch (Exception) { } string address = NetworkClientManager.getMyAddress(); if (address != null) { if (IxianHandler.publicIP != address) { Logging.info("Setting public IP to " + address); IxianHandler.publicIP = address; } } // Process the hello data endpoint.helloReceived = true; NetworkClientManager.recalculateLocalTimeDifference(); Node.setNetworkBlock(last_block_num, block_checksum, block_version); // Get random presences endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'M' }); endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'H' }); CoreProtocolMessage.subscribeToEvents(endpoint); } } } break; case ProtocolMessageCode.s2data: { StreamProcessor.receiveData(data, endpoint); } break; case ProtocolMessageCode.s2failed: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { Logging.error("Failed to send s2 data"); } } } break; case ProtocolMessageCode.transactionData: { Transaction tx = new Transaction(data, true); if (endpoint.presenceAddress.type == 'M' || endpoint.presenceAddress.type == 'H') { PendingTransactions.increaseReceivedCount(tx.id, endpoint.presence.wallet); } Node.tiv.receivedNewTransaction(tx); Logging.info("Received new transaction {0}", tx.id); Node.addTransactionToActivityStorage(tx); } break; case ProtocolMessageCode.updatePresence: { // Parse the data and update entries in the presence list PresenceList.updateFromBytes(data, 0); } break; case ProtocolMessageCode.keepAlivePresence: { byte[] address = null; long last_seen = 0; byte[] device_id = null; bool updated = PresenceList.receiveKeepAlive(data, out address, out last_seen, out device_id, endpoint); } break; case ProtocolMessageCode.getPresence: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int walletLen = reader.ReadInt32(); byte[] wallet = reader.ReadBytes(walletLen); Presence p = PresenceList.getPresenceByAddress(wallet); if (p != null) { lock (p) { byte[][] presence_chunks = p.getByteChunks(); foreach (byte[] presence_chunk in presence_chunks) { endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk, null); } } } else { // TODO blacklisting point Logging.warn(string.Format("Node has requested presence information about {0} that is not in our PL.", Base58Check.Base58CheckEncoding.EncodePlain(wallet))); } } } } break; case ProtocolMessageCode.getPresence2: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int walletLen = (int)reader.ReadIxiVarUInt(); byte[] wallet = reader.ReadBytes(walletLen); Presence p = PresenceList.getPresenceByAddress(wallet); if (p != null) { lock (p) { byte[][] presence_chunks = p.getByteChunks(); foreach (byte[] presence_chunk in presence_chunks) { endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk, null); } } } else { // TODO blacklisting point Logging.warn(string.Format("Node has requested presence information about {0} that is not in our PL.", Base58Check.Base58CheckEncoding.EncodePlain(wallet))); } } } } break; case ProtocolMessageCode.balance: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int address_length = reader.ReadInt32(); byte[] address = reader.ReadBytes(address_length); // Retrieve the latest balance IxiNumber balance = reader.ReadString(); if (address.SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress())) { // Retrieve the blockheight for the balance ulong block_height = reader.ReadUInt64(); if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0)) { byte[] block_checksum = reader.ReadBytes(reader.ReadInt32()); Node.balance.address = address; Node.balance.balance = balance; Node.balance.blockHeight = block_height; Node.balance.blockChecksum = block_checksum; Node.balance.lastUpdate = Clock.getTimestamp(); Node.balance.verified = false; } } } } } break; case ProtocolMessageCode.balance2: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int address_length = (int)reader.ReadIxiVarUInt(); byte[] address = reader.ReadBytes(address_length); // Retrieve the latest balance IxiNumber balance = new IxiNumber(new BigInteger(reader.ReadBytes((int)reader.ReadIxiVarUInt()))); if (address.SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress())) { // Retrieve the blockheight for the balance ulong block_height = reader.ReadIxiVarUInt(); if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0)) { byte[] block_checksum = reader.ReadBytes((int)reader.ReadIxiVarUInt()); Node.balance.address = address; Node.balance.balance = balance; Node.balance.blockHeight = block_height; Node.balance.blockChecksum = block_checksum; Node.balance.lastUpdate = Clock.getTimestamp(); Node.balance.verified = false; } } } } } break; case ProtocolMessageCode.bye: CoreProtocolMessage.processBye(data, endpoint); break; case ProtocolMessageCode.blockHeaders2: { // Forward the block headers to the TIV handler Node.tiv.receivedBlockHeaders2(data, endpoint); } break; case ProtocolMessageCode.pitData2: { Node.tiv.receivedPIT2(data, endpoint); } break; default: break; } } catch (Exception e) { Logging.error(string.Format("Error parsing network message. Details: {0}", e.ToString())); } }
// Unified protocol message parsing public static void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint) { if (endpoint == null) { Logging.error("Endpoint was null. parseProtocolMessage"); return; } try { switch (code) { case ProtocolMessageCode.hello: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { CoreProtocolMessage.processHelloMessageV6(endpoint, reader); } } } break; case ProtocolMessageCode.helloData: using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { if (!CoreProtocolMessage.processHelloMessageV6(endpoint, reader)) { return; } ulong last_block_num = reader.ReadIxiVarUInt(); int bcLen = (int)reader.ReadIxiVarUInt(); byte[] block_checksum = reader.ReadBytes(bcLen); endpoint.blockHeight = last_block_num; int block_version = (int)reader.ReadIxiVarUInt(); if (endpoint.presenceAddress.type != 'C') { ulong highest_block_height = IxianHandler.getHighestKnownNetworkBlockHeight(); if (last_block_num + 10 < highest_block_height) { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.tooFarBehind, string.Format("Your node is too far behind, your block height is {0}, highest network block height is {1}.", last_block_num, highest_block_height), highest_block_height.ToString(), true); return; } } // Process the hello data endpoint.helloReceived = true; NetworkClientManager.recalculateLocalTimeDifference(); if (endpoint.presenceAddress.type == 'R') { string[] connected_servers = StreamClientManager.getConnectedClients(true); if (connected_servers.Count() == 1 || !connected_servers.Contains(StreamClientManager.primaryS2Address)) { if (StreamClientManager.primaryS2Address == "") { FriendList.requestAllFriendsPresences(); } // TODO set the primary s2 host more efficiently, perhaps allow for multiple s2 primary hosts StreamClientManager.primaryS2Address = endpoint.getFullAddress(true); // TODO TODO do not set if directly connectable IxianHandler.publicIP = endpoint.address; IxianHandler.publicPort = endpoint.incomingPort; PresenceList.forceSendKeepAlive = true; Logging.info("Forcing KA from networkprotocol"); } } else if (endpoint.presenceAddress.type == 'C') { Friend f = FriendList.getFriend(endpoint.presence.wallet); if (f != null && f.bot) { StreamProcessor.sendGetBotInfo(f); } } if (endpoint.presenceAddress.type == 'M' || endpoint.presenceAddress.type == 'H') { Node.setNetworkBlock(last_block_num, block_checksum, block_version); // Get random presences endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'R' }); endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'M' }); endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] { (byte)'H' }); subscribeToEvents(endpoint); } } } break; case ProtocolMessageCode.s2data: { StreamProcessor.receiveData(data, endpoint); } break; case ProtocolMessageCode.updatePresence: { Logging.info("NET: Receiving presence list update"); // Parse the data and update entries in the presence list Presence p = PresenceList.updateFromBytes(data); if (p == null) { return; } Friend f = FriendList.getFriend(p.wallet); if (f != null) { f.relayIP = p.addresses[0].address; } } break; case ProtocolMessageCode.keepAlivePresence: { byte[] address = null; long last_seen = 0; byte[] device_id = null; bool updated = PresenceList.receiveKeepAlive(data, out address, out last_seen, out device_id, endpoint); Presence p = PresenceList.getPresenceByAddress(address); if (p == null) { return; } Friend f = FriendList.getFriend(p.wallet); if (f != null) { f.relayIP = p.addresses[0].address; } } break; case ProtocolMessageCode.getPresence: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int walletLen = reader.ReadInt32(); byte[] wallet = reader.ReadBytes(walletLen); Presence p = PresenceList.getPresenceByAddress(wallet); if (p != null) { lock (p) { byte[][] presence_chunks = p.getByteChunks(); foreach (byte[] presence_chunk in presence_chunks) { endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk, null); } } } else { // TODO blacklisting point Logging.warn(string.Format("Node has requested presence information about {0} that is not in our PL.", Base58Check.Base58CheckEncoding.EncodePlain(wallet))); } } } } break; case ProtocolMessageCode.getPresence2: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int walletLen = (int)reader.ReadIxiVarUInt(); byte[] wallet = reader.ReadBytes(walletLen); Presence p = PresenceList.getPresenceByAddress(wallet); if (p != null) { lock (p) { byte[][] presence_chunks = p.getByteChunks(); foreach (byte[] presence_chunk in presence_chunks) { endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk, null); } } } else { // TODO blacklisting point Logging.warn(string.Format("Node has requested presence information about {0} that is not in our PL.", Base58Check.Base58CheckEncoding.EncodePlain(wallet))); } } } } break; case ProtocolMessageCode.balance: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int address_length = reader.ReadInt32(); byte[] address = reader.ReadBytes(address_length); // Retrieve the latest balance IxiNumber balance = reader.ReadString(); if (address.SequenceEqual(Node.walletStorage.getPrimaryAddress())) { // Retrieve the blockheight for the balance ulong block_height = reader.ReadUInt64(); if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0)) { byte[] block_checksum = reader.ReadBytes(reader.ReadInt32()); Node.balance.address = address; Node.balance.balance = balance; Node.balance.blockHeight = block_height; Node.balance.blockChecksum = block_checksum; Node.balance.verified = false; } Node.balance.lastUpdate = Clock.getTimestamp(); } } } } break; case ProtocolMessageCode.balance2: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int address_length = (int)reader.ReadIxiVarUInt(); byte[] address = reader.ReadBytes(address_length); // Retrieve the latest balance IxiNumber balance = new IxiNumber(new BigInteger(reader.ReadBytes((int)reader.ReadIxiVarUInt()))); if (address.SequenceEqual(Node.walletStorage.getPrimaryAddress())) { // Retrieve the blockheight for the balance ulong block_height = reader.ReadIxiVarUInt(); if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0)) { byte[] block_checksum = reader.ReadBytes((int)reader.ReadIxiVarUInt()); Node.balance.address = address; Node.balance.balance = balance; Node.balance.blockHeight = block_height; Node.balance.blockChecksum = block_checksum; Node.balance.verified = false; } Node.balance.lastUpdate = Clock.getTimestamp(); } } } } break; case ProtocolMessageCode.newTransaction: case ProtocolMessageCode.transactionData: { // TODO: check for errors/exceptions Transaction transaction = new Transaction(data, true); if (endpoint.presenceAddress.type == 'M' || endpoint.presenceAddress.type == 'H') { PendingTransactions.increaseReceivedCount(transaction.id, endpoint.presence.wallet); } TransactionCache.addUnconfirmedTransaction(transaction); Node.tiv.receivedNewTransaction(transaction); } break; case ProtocolMessageCode.bye: CoreProtocolMessage.processBye(data, endpoint); break; case ProtocolMessageCode.blockHeaders2: { // Forward the block headers to the TIV handler Node.tiv.receivedBlockHeaders2(data, endpoint); } break; case ProtocolMessageCode.pitData2: { Node.tiv.receivedPIT2(data, endpoint); } break; default: break; } } catch (Exception e) { Logging.error("Error parsing network message. Details: {0}", e.ToString()); } }