Example #1
0
            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);
                            }
                        }
                    }
                }
            }
Example #2
0
        /// <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);
        }
Example #3
0
        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));
                }
            }
        }
Example #4
0
        /// <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));
            }
        }
Example #5
0
            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());
                    }
                }
            }
Example #6
0
            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));
                    }
                }
            }
Example #7
0
 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)));
             }
         }
     }
 }
Example #8
0
 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)));
         }
     }
 }
Example #9
0
            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));
                    }
                }
            }
Example #10
0
            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);
        }
Example #12
0
        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);
        }
Example #14
0
            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));
                                }
                            }
                        }
                    }
                }
            }
Example #15
0
            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);
                    }
                }
            }
Example #16
0
            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);
                    }
                }
            }
Example #19
0
            // 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());
                    }
                }
            }
Example #20
0
            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());
                            }
                        }
                    }
                }
            }
Example #21
0
        // 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));
                    }
                }
            }
Example #23
0
            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));
                }
            }
Example #24
0
            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);
            }
Example #25
0
        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);
                }
            }
        }
Example #26
0
        // 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()));
            }
        }
Example #27
0
        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);
                    }
                }
            }
        }
Example #28
0
        // 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);
        }
Example #29
0
        // 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()));
            }
        }
Example #30
0
        // 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());
            }
        }