Esempio n. 1
0
 public override string ToString()
 {
     return(RemoteEndpoint.ToString());
 }
Esempio n. 2
0
        // Broadcasts protocol message to a single random node with block height higher than the one specified with parameter block_num
        /// <summary>
        ///  Sends the specified protocol message to one of the connected remote endpoints, chosen randomly.
        /// </summary>
        /// <remarks>
        ///  The payload `data` should be properly formatted for the given `code` - this function will not ensure that this is so and
        ///  the caller must provide a valid message to this function.
        ///  The `skipEndpoint` parameter is useful when re-broadcasting a message received from a specific endpoint and do not wish to echo the same
        ///  data back to the sender.
        ///  The `block_num` parameter is used to filter the remote endpoints based on their latest known block height.
        /// </remarks>
        /// <param name="types">Types of the nodes where the message should be sent.</param>
        /// <param name="code">Ixian protocol code.</param>
        /// <param name="data">Payload data.</param>
        /// <param name="block_num">Block which should be searched for the endpoint addresses.</param>
        /// <param name="skipEndpoint">Minimum block height for endpoints which should receive this message.</param>
        /// <returns>True, if at least one message was sent to at least one remote endpoint. False if no messages were sent.</returns>
        public static bool broadcastProtocolMessageToSingleRandomNode(char[] types, ProtocolMessageCode code, byte[] data, ulong block_num, RemoteEndpoint skipEndpoint = null)
        {
            if (data == null)
            {
                Logging.warn(string.Format("Invalid protocol message data for {0}", code));
                return(false);
            }

            lock (NetworkClientManager.networkClients)
            {
                lock (NetworkServer.connectedClients)
                {
                    int serverCount = 0;
                    int clientCount = 0;
                    List <NetworkClient>  servers = null;
                    List <RemoteEndpoint> clients = null;

                    if (types == null)
                    {
                        servers = NetworkClientManager.networkClients.FindAll(x => x.blockHeight > block_num && x.isConnected() && x.helloReceived);
                        clients = NetworkServer.connectedClients.FindAll(x => x.blockHeight > block_num && x.isConnected() && x.helloReceived);

                        serverCount = servers.Count();
                        clientCount = clients.Count();

                        if (serverCount == 0 && clientCount == 0)
                        {
                            servers = NetworkClientManager.networkClients.FindAll(x => x.blockHeight == block_num && x.isConnected() && x.helloReceived);
                            clients = NetworkServer.connectedClients.FindAll(x => x.blockHeight == block_num && x.isConnected() && x.helloReceived);
                        }
                    }
                    else
                    {
                        servers = NetworkClientManager.networkClients.FindAll(x => x.blockHeight > block_num && x.presenceAddress != null && types.Contains(x.presenceAddress.type) && x.isConnected() && x.helloReceived);
                        clients = NetworkServer.connectedClients.FindAll(x => x.blockHeight > block_num && x.presenceAddress != null && types.Contains(x.presenceAddress.type) && x.isConnected() && x.helloReceived);

                        serverCount = servers.Count();
                        clientCount = clients.Count();

                        if (serverCount == 0 && clientCount == 0)
                        {
                            servers = NetworkClientManager.networkClients.FindAll(x => x.blockHeight == block_num && x.presenceAddress != null && types.Contains(x.presenceAddress.type) && x.isConnected() && x.helloReceived);
                            clients = NetworkServer.connectedClients.FindAll(x => x.blockHeight == block_num && x.presenceAddress != null && types.Contains(x.presenceAddress.type) && x.isConnected() && x.helloReceived);
                        }
                    }

                    serverCount = servers.Count();
                    clientCount = clients.Count();

                    if (serverCount == 0 && clientCount == 0)
                    {
                        return(false);
                    }

                    Random r    = new Random();
                    int    rIdx = r.Next(serverCount + clientCount);

                    RemoteEndpoint re = null;

                    if (rIdx < serverCount)
                    {
                        re = servers[rIdx];
                    }
                    else
                    {
                        re = clients[rIdx - serverCount];
                    }

                    if (re == skipEndpoint && serverCount + clientCount > 1)
                    {
                        if (rIdx + 1 < serverCount)
                        {
                            re = servers[rIdx + 1];
                        }
                        else if (rIdx + 1 < serverCount + clientCount)
                        {
                            re = clients[rIdx + 1 - serverCount];
                        }
                        else if (serverCount > 0)
                        {
                            re = servers[0];
                        }
                        else if (clientCount > 0)
                        {
                            re = clients[0];
                        }
                    }

                    if (re != null && re.isConnected())
                    {
                        re.sendData(code, data);
                        return(true);
                    }
                    return(false);
                }
            }
        }
Esempio n. 3
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, out long last_seen, out byte[] device_id, RemoteEndpoint endpoint)
        {
            address   = null;
            last_seen = 0;
            device_id = null;

            // Get the current timestamp
            long currentTime = Clock.getNetworkTimestamp();

            try
            {
                using (MemoryStream m = new MemoryStream(bytes))
                {
                    using (BinaryReader reader = new BinaryReader(m))
                    {
                        int keepAliveVersion = 0;
                        if (bytes[0] == 1)
                        {
                            // TODO temporary, remove after network upgrade
                            keepAliveVersion = reader.ReadInt32();
                        }
                        else
                        {
                            keepAliveVersion = (int)reader.ReadIxiVarInt();
                        }

                        byte[] wallet;
                        byte[] deviceid;
                        long   timestamp;
                        string hostname;
                        char   node_type = '0';
                        int    sigLen;
                        byte[] signature;

                        long checksum_data_len = 0;

                        byte[] data_to_verify;

                        if (keepAliveVersion == 1)
                        {
                            // TODO temporary, remove after network upgrade
                            int walletLen = reader.ReadInt32();
                            wallet = reader.ReadBytes(walletLen);

                            // Assign the out address parameter
                            address = wallet;

                            string device_id_str = reader.ReadString();
                            device_id = deviceid = System.Guid.Parse(device_id_str).ToByteArray();
                            last_seen = timestamp = reader.ReadInt64();
                            hostname  = reader.ReadString();

                            node_type = reader.ReadChar();

                            checksum_data_len = m.Position;

                            sigLen    = reader.ReadInt32();
                            signature = reader.ReadBytes(sigLen);

                            data_to_verify = bytes.Take((int)checksum_data_len).ToArray();
                        }
                        else
                        {
                            int walletLen = (int)reader.ReadIxiVarUInt();
                            wallet = reader.ReadBytes(walletLen);

                            // Assign the out address parameter
                            address = wallet;

                            int deviceid_len = (int)reader.ReadIxiVarUInt();
                            device_id = deviceid = reader.ReadBytes(deviceid_len);
                            last_seen = timestamp = reader.ReadIxiVarInt();
                            hostname  = reader.ReadString();

                            node_type = reader.ReadChar();

                            checksum_data_len = m.Position;

                            sigLen    = (int)reader.ReadIxiVarUInt();
                            signature = reader.ReadBytes(sigLen);

                            byte[] checksum = Crypto.sha512sq(bytes.Take((int)checksum_data_len).ToArray());
                            data_to_verify = new byte[ConsensusConfig.ixianChecksumLock.Length + checksum.Length];
                            Array.Copy(ConsensusConfig.ixianChecksumLock, data_to_verify, ConsensusConfig.ixianChecksumLock.Length);
                            Array.Copy(checksum, 0, data_to_verify, ConsensusConfig.ixianChecksumLock.Length, checksum.Length);
                        }
                        //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(data_to_verify, 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.SequenceEqual(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);
        }
Esempio n. 4
0
        /// <summary>
        ///  Processes a Hello Ixian protocol message and updates the `PresenceList` as appropriate.
        /// </summary>
        /// <remarks>
        ///  This function should normally be called from `NetworkProtocol.parseProtocolMessage()`
        /// </remarks>
        /// <param name="endpoint">Remote endpoint from which the message was received.</param>
        /// <param name="reader">Reader object placed at the beginning of the hello message data.</param>
        /// <returns>True if the message was formatted properly and accepted.</returns>
        public static bool processHelloMessage(RemoteEndpoint endpoint, BinaryReader reader)
        {
            // Node already has a presence
            if (endpoint.presence != null)
            {
                // Ignore the hello message in this case
                return(false);
            }

            // Another layer to catch any incompatible node exceptions for the hello message
            try
            {
                int protocol_version = reader.ReadInt32();

                Logging.info(string.Format("Received Hello: Node version {0}", protocol_version));
                // Check for incompatible nodes
                if (protocol_version < CoreConfig.protocolVersion)
                {
                    Logging.warn(String.Format("Hello: Connected node version ({0}) is too old! Upgrade the node.", protocol_version));
                    sendBye(endpoint, ProtocolByeCode.deprecated, string.Format("Your node version is too old. Should be at least {0} is {1}", CoreConfig.protocolVersion, protocol_version), CoreConfig.protocolVersion.ToString(), true);
                    return(false);
                }

                int    addrLen = reader.ReadInt32();
                byte[] addr    = reader.ReadBytes(addrLen);

                bool   test_net     = reader.ReadBoolean();
                char   node_type    = reader.ReadChar();
                string node_version = reader.ReadString();
                string device_id    = reader.ReadString();

                int    pkLen  = reader.ReadInt32();
                byte[] pubkey = reader.ReadBytes(pkLen);

                endpoint.serverPubKey = pubkey;

                int  port      = reader.ReadInt32();
                long timestamp = reader.ReadInt64();

                int    sigLen    = reader.ReadInt32();
                byte[] signature = reader.ReadBytes(sigLen);

                // Check the testnet designator and disconnect on mismatch
                if (test_net != CoreConfig.isTestNet)
                {
                    Logging.warn(string.Format("Rejected node {0} due to incorrect testnet designator: {1}", endpoint.fullAddress, test_net));
                    sendBye(endpoint, ProtocolByeCode.incorrectNetworkType, string.Format("Incorrect testnet designator: {0}. Should be {1}", test_net, CoreConfig.isTestNet), test_net.ToString(), true);
                    return(false);
                }

                // Check the address and pubkey and disconnect on mismatch
                if (!addr.SequenceEqual((new Address(pubkey)).address))
                {
                    Logging.warn(string.Format("Pubkey and address do not match."));
                    sendBye(endpoint, ProtocolByeCode.authFailed, "Pubkey and address do not match.", "", true);
                    return(false);
                }

                endpoint.incomingPort = port;

                // Verify the signature
                if (node_type == 'C')
                {
                    // TODO: verify if the client is connectable, then if connectable, check if signature verifies

                    /*if (CryptoManager.lib.verifySignature(Encoding.UTF8.GetBytes(ConsensusConfig.ixianChecksumLockString + "-" + device_id + "-" + timestamp + "-" + endpoint.getFullAddress(true)), pubkey, signature) == false)
                     * {
                     *  CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.incorrectIp, "Verify signature failed in hello message, likely an incorrect IP was specified. Detected IP:", endpoint.address);
                     *  Logging.warn(string.Format("Connected node used an incorrect signature in hello message, likely an incorrect IP was specified. Detected IP: {0}", endpoint.address));
                     *  return false;
                     * }*/
                    // TODO store the full address if connectable
                    // Store the presence address for this remote endpoint
                    endpoint.presenceAddress = new PresenceAddress(device_id, "", node_type, node_version, Core.getCurrentTimestamp() - CoreConfig.clientKeepAliveInterval, null);
                }
                else
                {
                    if (!CryptoManager.lib.verifySignature(Encoding.UTF8.GetBytes(ConsensusConfig.ixianChecksumLockString + "-" + device_id + "-" + timestamp + "-" + endpoint.getFullAddress(true)), pubkey, signature))
                    {
                        CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.incorrectIp, "Verify signature failed in hello message, likely an incorrect IP was specified. Detected IP:", endpoint.address);
                        Logging.warn(string.Format("Connected node used an incorrect signature in hello message, likely an incorrect IP was specified. Detected IP: {0}", endpoint.address));
                        return(false);
                    }

                    // Store the presence address for this remote endpoint
                    endpoint.presenceAddress = new PresenceAddress(device_id, endpoint.getFullAddress(true), node_type, node_version, Core.getCurrentTimestamp() - CoreConfig.serverKeepAliveInterval, null);
                }

                // if we're a client update the network time difference
                if (endpoint.GetType() == typeof(NetworkClient))
                {
                    long timeDiff = endpoint.calculateTimeDifference();

                    // amortize +- 2 seconds
                    if (timeDiff >= -2 && timeDiff <= 2)
                    {
                        timeDiff = 0;
                    }

                    ((NetworkClient)endpoint).timeDifference = timeDiff;


                    // Check the address and local address and disconnect on mismatch
                    if (endpoint.serverWalletAddress != null && !addr.SequenceEqual(endpoint.serverWalletAddress))
                    {
                        Logging.warn(string.Format("Local address mismatch, possible Man-in-the-middle attack."));
                        sendBye(endpoint, ProtocolByeCode.addressMismatch, "Local address mismatch.", "", true);
                        return(false);
                    }
                }


                // Create a temporary presence with the client's address and device id
                Presence presence = new Presence(addr, pubkey, null, endpoint.presenceAddress);

                if (endpoint.GetType() != typeof(NetworkClient))
                {
                    // we're the server

                    if (node_type == 'M' || node_type == 'H' || node_type == 'R')
                    {
                        if (node_type != 'R')
                        {
                            // Check the wallet balance for the minimum amount of coins
                            IxiNumber balance = IxianHandler.getWalletBalance(addr);
                            if (balance < ConsensusConfig.minimumMasterNodeFunds)
                            {
                                Logging.warn(string.Format("Rejected master node {0} due to insufficient funds: {1}", endpoint.getFullAddress(), balance.ToString()));
                                sendBye(endpoint, ProtocolByeCode.insufficientFunds, string.Format("Insufficient funds. Minimum is {0}", ConsensusConfig.minimumMasterNodeFunds), balance.ToString(), true);
                                return(false);
                            }
                        }
                        // Limit to one IP per masternode
                        // TODO TODO TODO - think about this and do it properly

                        /*string[] hostname_split = hostname.Split(':');
                         * if (PresenceList.containsIP(hostname_split[0], 'M'))
                         * {
                         *  using (MemoryStream m2 = new MemoryStream())
                         *  {
                         *      using (BinaryWriter writer = new BinaryWriter(m2))
                         *      {
                         *          writer.Write(string.Format("This IP address ( {0} ) already has a masternode connected.", hostname_split[0]));
                         *          Logging.info(string.Format("Rejected master node {0} due to duplicate IP address", hostname));
                         *          socket.Send(prepareProtocolMessage(ProtocolMessageCode.bye, m2.ToArray()), SocketFlags.None);
                         *          socket.Disconnect(true);
                         *          return;
                         *      }
                         *  }
                         * }*/
                        if (!checkNodeConnectivity(endpoint))
                        {
                            return(false);
                        }
                    }
                }


                // Retrieve the final presence entry from the list (or create a fresh one)
                endpoint.presence = PresenceList.updateEntry(presence);
            }
            catch (Exception e)
            {
                // Disconnect the node in case of any reading errors
                Logging.warn(string.Format("Exception occured in Hello Message {0}", e.ToString()));
                sendBye(endpoint, ProtocolByeCode.deprecated, "Something went wrong during hello, make sure you're running the latest version of Ixian DLT.", "");
                return(false);
            }

            if (NetworkClientManager.getConnectedClients().Count() == 1)
            {
                PresenceList.forceSendKeepAlive = true;
            }

            return(true);
        }
Esempio n. 5
0
        /// <summary>
        ///  Prepares and broadcasts an Ixian protocol message to all connected nodes, filtered by `types`.
        /// </summary>
        /// <remarks>
        ///  The payload `data` should be properly formatted for the given `code` - this function will not ensure that this is so and
        ///  the caller must provide a valid message to this function.
        ///  The `skipEndpoint` parameter is useful when re-broadcasting a message received from a specific endpoint and do not wish to echo the same
        ///  data back to the sender.
        /// </remarks>
        /// <param name="types">Types of nodes to send this message to.</param>
        /// <param name="code">Protocol code.</param>
        /// <param name="data">Message payload</param>
        /// <param name="helper_data">Additional information, as required by the protocol message</param>
        /// <param name="skipEndpoint">Remote endpoint which should be skipped (data should not be sent to it).</param>
        /// <returns>True, if at least one message was sent to at least one other node. False if no messages were sent.</returns>
        public static bool broadcastProtocolMessage(char[] types, ProtocolMessageCode code, byte[] data, byte[] helper_data, RemoteEndpoint skipEndpoint = null)
        {
            if (data == null)
            {
                Logging.warn(string.Format("Invalid protocol message data for {0}", code));
                return(false);
            }

            bool c_result = NetworkClientManager.broadcastData(types, code, data, helper_data, skipEndpoint);
            bool s_result = NetworkServer.broadcastData(types, code, data, helper_data, skipEndpoint);

            if (!c_result && !s_result)
            {
                return(false);
            }

            return(true);
        }
Esempio n. 6
0
        public static void onChat(byte[] raw_message, StreamMessage message, int channel, RemoteEndpoint endpoint)
        {
            if (channel == 0)
            {
                return;
            }

            if (!Node.users.hasUser(endpoint.presence.wallet) || Node.users.getUser(endpoint.presence.wallet).nickData == null)
            {
                requestNickname(endpoint.presence.wallet);
                requestAvatar(endpoint.presence.wallet);
            }

            if (message.id == null)
            {
                return;
            }

            if (Messages.getMessage(message.id, channel) != null)
            {
                return;
            }
            IxiNumber price = getMessagePrice(message.sender, message.data.Length);

            if (price > 0)
            {
                // TODO TODO resend payment request after a while
                // TODO TODO remove pending message after a while
                StreamTransactionRequest str = new StreamTransactionRequest(message.id, price);
                if (pendingMessages.Find(x => x.id.SequenceEqual(message.id)) != null)
                {
                    sendBotAction(message.sender, SpixiBotActionCode.getPayment, str.getBytes(), channel);
                    return;
                }
                pendingMessages.Add(message);
                sendBotAction(message.sender, SpixiBotActionCode.getPayment, str.getBytes(), channel);
            }
            else
            {
                Messages.addMessage(message, channel);
                QuotaManager.addActivity(endpoint.presence.wallet, false);
                // Relay certain messages without transaction
                NetworkServer.forwardMessage(ProtocolMessageCode.s2data, raw_message);
            }
        }
Esempio n. 7
0
 abstract protected bool sendInventoryRequest(InventoryItem item, RemoteEndpoint endpoint);
Esempio n. 8
0
        public static void processBye(byte[] data, RemoteEndpoint endpoint)
        {
            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.incorrectIp:     // incorrect IP
                            if (IxiUtils.validateIPv4(byeData))
                            {
                                if (NetworkClientManager.getConnectedClients(true).Length < 2)
                                {
                                    IxianHandler.publicIP = byeData;
                                    Logging.warn("Changed internal IP Address to " + byeData + ", reconnecting");
                                }
                            }
                            break;

                        case ProtocolByeCode.notConnectable:     // not connectable from the internet
                            NetworkServer.connectable = false;
                            if (!NetworkServer.isConnectable())
                            {
                                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 + ".");
                            }
                            break;

                        default:
                            Logging.warn("Disconnected with message: {0} {1} {2}", byeCode.ToString(), 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.warn("Disconnected with v0 message: {0}", message);
                    }
                    else
                    {
                        Logging.warn("Disconnected v0");
                    }
                }
            }
        }
Esempio n. 9
0
        // Called when an encryption key is received from the S2 server, as per step 4 of the WhitePaper

        /*private static void sendRsaEncryptedMessage(StreamMessage msg, string key, RemoteEndpoint endpoint)
         * {
         * // TODO TODO use transaction code for S2
         *  using (MemoryStream m = new MemoryStream())
         *  {
         *      using (BinaryWriter writer = new BinaryWriter(m))
         *      {
         *          writer.Write(msg.getID());
         *          writer.Write(msg.recipientAddress);
         *          writer.Write(msg.transactionID);
         *      }
         *  }
         *  Console.WriteLine("Sending encrypted message with key {0}", key);
         *
         *          using (MemoryStream m = new MemoryStream())
         *          {
         *              using (BinaryWriter writer = new BinaryWriter(m))
         *              {
         *                  writer.Write(msg.getID());
         *                  writer.Write(msg.recipientAddress);
         *                  writer.Write(msg.transactionID);
         *
         *                  byte[] encrypted_message = CryptoManager.lib.encryptDataS2(msg.data, key);
         *                  int encrypted_count = encrypted_message.Count();
         *
         *                  writer.Write(encrypted_count);
         *                  writer.Write(encrypted_message);
         *
         *                  byte[] ba = ProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.s2data, m.ToArray());
         *                  socket.Send(ba, SocketFlags.None);
         *
         *
         *                  // Update the DLT transaction as well
         *                  Transaction transaction = new Transaction(0, msg.recipientAddress, Node.walletStorage.address);
         *                  transaction.id = msg.transactionID;
         *                  //transaction.data = Encoding.UTF8.GetString(checksum);
         *                  //ProtocolMessage.broadcastProtocolMessage(ProtocolMessageCode.updateTransaction, transaction.getBytes());
         *
         *              }
         *          }
         * }*/

        // Called when receiving S2 data from clients
        public static void receiveData(byte[] bytes, RemoteEndpoint endpoint)
        {
            StreamMessage message = new StreamMessage(bytes);

            if (message.data == null)
            {
                Logging.error(string.Format("Null message data."));
                return;
            }

            Logging.info("Received S2 data from {0} for {1}", Base58Check.Base58CheckEncoding.EncodePlain(message.sender), Base58Check.Base58CheckEncoding.EncodePlain(message.recipient));

            Friend friend = null;

            // decrypt the message if necessary
            // TODO TODO TODO add message receive queue for when the keys aren't available yet
            if (message.encryptionType != StreamMessageEncryptionCode.none)
            {
                byte[] aes_key    = null;
                byte[] chacha_key = null;

                friend = FriendList.getFriend(message.sender);
                if (friend != null)
                {
                    aes_key    = friend.aesKey;
                    chacha_key = friend.chachaKey;
                }
                if (!message.decrypt(Node.walletStorage.getPrimaryPrivateKey(), aes_key, chacha_key))
                {
                    Logging.error("Could not decrypt message from {0}", Base58Check.Base58CheckEncoding.EncodePlain(friend.walletAddress));
                    return;
                }
            }

            // Extract the Spixi message
            SpixiMessage spixi_message = new SpixiMessage(message.data);

            switch (spixi_message.type)
            {
            case SpixiMessageCode.chat:
            {
                // Add the message to the friend list
                FriendList.addMessage(spixi_message.id, message.sender, Encoding.UTF8.GetString(spixi_message.data));
            }
            break;

            case SpixiMessageCode.getNick:
            {
                // Send the nickname to the sender as requested
                handleGetNick(message.sender, Encoding.UTF8.GetString(spixi_message.data));
            }
            break;

            case SpixiMessageCode.nick:
            {
                // Set the nickname for the corresponding address
                if (spixi_message.data != null)
                {
                    FriendList.setNickname(message.sender, Encoding.UTF8.GetString(spixi_message.data));
                }
                else
                {
                    FriendList.setNickname(message.sender, Base58Check.Base58CheckEncoding.EncodePlain(message.sender));
                }
            }
            break;

            case SpixiMessageCode.requestAdd:
            {
                // Friend request
                handleRequestAdd(spixi_message.id, message.sender, spixi_message.data);
            }
            break;

            case SpixiMessageCode.acceptAdd:
            {
                // Friend accepted request
                handleAcceptAdd(message.sender, spixi_message.data);
            }
            break;

            case SpixiMessageCode.sentFunds:
            {
                // Friend requested funds
                handleSentFunds(spixi_message.id, message.sender, Encoding.UTF8.GetString(spixi_message.data));
            }
            break;

            case SpixiMessageCode.requestFunds:
            {
                // Friend requested funds
                handleRequestFunds(spixi_message.id, message.sender, Encoding.UTF8.GetString(spixi_message.data));
            }
            break;

            case SpixiMessageCode.requestFundsResponse:
            {
                handleRequestFundsResponse(spixi_message.id, message.sender, Encoding.UTF8.GetString(spixi_message.data));
            }
            break;

            case SpixiMessageCode.keys:
            {
                handleReceivedKeys(message.sender, spixi_message.data);
            }
            break;

            case SpixiMessageCode.msgReceived:
            {
                handleMsgReceived(message.sender, spixi_message);
                // don't send confirmation back, so just return
                return;
            }

            case SpixiMessageCode.msgRead:
            {
                handleMsgRead(message.sender, spixi_message);
                // don't send confirmation back, so just return
                return;
            }

            case SpixiMessageCode.fileHeader:
            {
                handleFileHeader(message.sender, spixi_message);
            }
            break;
            }

            if (friend == null)
            {
                friend = FriendList.getFriend(message.sender);
            }

            if (friend == null)
            {
                Logging.error("Cannot send received confirmation, friend is null");
                return;
            }

            // Send received confirmation
            StreamMessage msg_received = new StreamMessage();

            msg_received.type           = StreamMessageCode.info;
            msg_received.sender         = IxianHandler.getWalletStorage().getPrimaryAddress();
            msg_received.recipient      = message.sender;
            msg_received.data           = new SpixiMessage(spixi_message.id, SpixiMessageCode.msgReceived, null).getBytes();
            msg_received.transaction    = new byte[1];
            msg_received.sigdata        = new byte[1];
            msg_received.encryptionType = StreamMessageEncryptionCode.none;

            sendMessage(friend, msg_received, true);
        }
Esempio n. 10
0
        /// <summary>
        ///  Reads a protocol message from the specified byte-field and calls appropriate methods to process this message.
        /// </summary>
        /// <remarks>
        ///  This function checks all applicable checksums and validates that the message is complete before calling one of the specialized
        ///  methods to handle actual decoding and processing.
        /// </remarks>
        /// <param name="recv_buffer">Byte-field with an Ixian protocol message.</param>
        /// <param name="endpoint">Remote endpoint from where the message was received.</param>
        public static void readProtocolMessage(QueueMessageRaw raw_message, MessagePriority priority, RemoteEndpoint endpoint)
        {
            if (endpoint == null)
            {
                Logging.error("Endpoint was null. readProtocolMessage");
                return;
            }

            ProtocolMessageCode code = raw_message.code;

            // Filter messages
            if (endpoint.presence == null)
            {
                // Check for presence and only accept hello and bye messages if there is no presence.
                if (code != ProtocolMessageCode.hello &&
                    code != ProtocolMessageCode.helloData &&
                    code != ProtocolMessageCode.bye)
                {
                    return;
                }
            }
            if (raw_message.legacyChecksum != null)
            {
                // Compute checksum of received data
                byte[] local_checksum = Crypto.sha512sqTrunc(raw_message.data, 0, 0, 32);

                // Verify the checksum before proceeding
                if (local_checksum.SequenceEqual(raw_message.legacyChecksum) == false)
                {
                    Logging.error("Dropped message (invalid legacy checksum)");
                    return;
                }
            }
            else
            {
                // Compute checksum of received data
                uint local_checksum = Crc32CAlgorithm.Compute(raw_message.data);

                // Verify the checksum before proceeding
                if (local_checksum != raw_message.checksum)
                {
                    Logging.error("Dropped message (invalid checksum)");
                    return;
                }
            }


            // Can proceed to parse the data parameter based on the protocol message code.
            // Data can contain multiple elements.
            //parseProtocolMessage(code, data, socket, endpoint);
            NetworkQueue.receiveProtocolMessage(code, raw_message.data, Crc32CAlgorithm.Compute(raw_message.data), priority, endpoint);
        }
Esempio n. 11
0
        /// <summary>
        ///  Prepares and sends an Ixian protocol 'Hello' message to the specified remote endpoint.
        /// </summary>
        /// <remarks>
        ///  A valid Ixian 'Hello' message includes certain Node data, verified by a public-key signature, which this function prepares using
        ///  the primary wallet's keypair. If this message is a reply to the other endpoint's hello message, then
        /// </remarks>
        /// <param name="endpoint">Remote endpoint to send the message to.</param>
        /// <param name="sendHelloData">True if the message is the first hello sent to the remote node, false if it is a reply to the challenge.</param>
        /// <param name="challenge_response">Response byte-field to the other node's hello challenge</param>
        public static void sendHelloMessageV6(RemoteEndpoint endpoint, bool sendHelloData, int challenge)
        {
            using (MemoryStream m = new MemoryStream(1856))
            {
                using (BinaryWriter writer = new BinaryWriter(m))
                {
                    string publicHostname = IxianHandler.getFullPublicAddress();

                    // Send the node version
                    writer.WriteIxiVarInt(6);

                    // Send the public node address
                    byte[] address = IxianHandler.getWalletStorage().getPrimaryAddress();
                    writer.WriteIxiVarInt(address.Length);
                    writer.Write(address);

                    // Send the testnet designator
                    writer.Write(IxianHandler.isTestNet);

                    char node_type = PresenceList.myPresenceType;
                    writer.Write(node_type);

                    // Send the version
                    writer.Write(CoreConfig.productVersion);

                    // Send the node device id
                    writer.WriteIxiVarInt(CoreConfig.device_id.Length);
                    writer.Write(CoreConfig.device_id);

                    // Send the wallet public key
                    writer.WriteIxiVarInt(IxianHandler.getWalletStorage().getPrimaryPublicKey().Length);
                    writer.Write(IxianHandler.getWalletStorage().getPrimaryPublicKey());

                    // Send listening port
                    writer.WriteIxiVarInt(IxianHandler.publicPort);

                    // Send timestamp
                    long timestamp = Clock.getTimestamp() + endpoint.calculateTimeDifference();
                    writer.WriteIxiVarInt(timestamp);

                    // generate signature
                    using (MemoryStream mSig = new MemoryStream(1024))
                    {
                        using (BinaryWriter sigWriter = new BinaryWriter(mSig))
                        {
                            sigWriter.Write(ConsensusConfig.ixianChecksumLock);
                            sigWriter.Write(CoreConfig.device_id);
                            sigWriter.Write(timestamp);
                            sigWriter.Write(publicHostname);
                            sigWriter.Write(challenge);
                        }
                        byte[] signature = CryptoManager.lib.getSignature(mSig.ToArray(), IxianHandler.getWalletStorage().getPrimaryPrivateKey());
                        writer.WriteIxiVarInt(signature.Length);
                        writer.Write(signature);
                    }

                    if (sendHelloData)
                    {
                        Block block = IxianHandler.getLastBlock();
                        if (block == null)
                        {
                            Logging.warn("Clients are connecting, but we have no blocks yet to send them!");
                            sendBye(endpoint, ProtocolByeCode.notReady, string.Format("The node isn't ready yet, please try again later."), "", true);
                            return;
                        }


                        writer.WriteIxiVarInt(block.blockNum);

                        writer.WriteIxiVarInt(block.blockChecksum.Length);
                        writer.Write(block.blockChecksum);

                        writer.WriteIxiVarInt(block.version);

                        writer.Write(endpoint.getFullAddress(true));

#if TRACE_MEMSTREAM_SIZES
                        Logging.info(String.Format("CoreProtocolMessage::sendHelloMessage: {0}", m.Length));
#endif

                        endpoint.sendData(ProtocolMessageCode.helloData, m.ToArray());
                    }
                    else
                    {
                        byte[] challenge_bytes = IxiVarInt.GetIxiVarIntBytes(challenge);
                        endpoint.challenge = BitConverter.GetBytes(challenge);
                        writer.Write(challenge_bytes);

#if TRACE_MEMSTREAM_SIZES
                        Logging.info(String.Format("CoreProtocolMessage::sendHelloMessage: {0}", m.Length));
#endif

                        endpoint.sendData(ProtocolMessageCode.hello, m.ToArray());
                    }
                }
            }
        }
Esempio n. 12
0
            static void handleInventory2(byte[] data, RemoteEndpoint endpoint)
            {
                using (MemoryStream m = new MemoryStream(data))
                {
                    using (BinaryReader reader = new BinaryReader(m))
                    {
                        ulong item_count = reader.ReadIxiVarUInt();
                        if (item_count > (ulong)CoreConfig.maxInventoryItems)
                        {
                            Logging.warn("Received {0} inventory items, max items is {1}", item_count, CoreConfig.maxInventoryItems);
                            item_count = (ulong)CoreConfig.maxInventoryItems;
                        }

                        ulong last_block_height = IxianHandler.getLastBlockHeight();

                        Dictionary <ulong, List <InventoryItemSignature> > sig_lists = new Dictionary <ulong, List <InventoryItemSignature> >();
                        List <InventoryItemKeepAlive> ka_list = new List <InventoryItemKeepAlive>();
                        List <byte[]> tx_list            = new List <byte[]>();
                        bool          request_next_block = false;
                        for (ulong i = 0; i < item_count; i++)
                        {
                            ulong         len        = reader.ReadIxiVarUInt();
                            byte[]        item_bytes = reader.ReadBytes((int)len);
                            InventoryItem item       = InventoryCache.decodeInventoryItem(item_bytes);
                            if (item.type == InventoryItemTypes.transaction)
                            {
                                PendingTransactions.increaseReceivedCount(item.hash, endpoint.presence.wallet);
                            }
                            PendingInventoryItem pii = Node.inventoryCache.add(item, endpoint);
                            if (!pii.processed && pii.lastRequested == 0)
                            {
                                // first time we're seeing this inventory item
                                switch (item.type)
                                {
                                case InventoryItemTypes.keepAlive:
                                    ka_list.Add((InventoryItemKeepAlive)item);
                                    pii.lastRequested = Clock.getTimestamp();
                                    break;

                                case InventoryItemTypes.transaction:
                                    tx_list.Add(item.hash);
                                    pii.lastRequested = Clock.getTimestamp();
                                    break;

                                case InventoryItemTypes.blockSignature:
                                    var iis = (InventoryItemSignature)item;
                                    if (iis.blockNum < last_block_height - 5 && iis.blockNum > last_block_height + 6)
                                    {
                                        continue;
                                    }
                                    if (!sig_lists.ContainsKey(iis.blockNum))
                                    {
                                        sig_lists.Add(iis.blockNum, new List <InventoryItemSignature>());
                                    }
                                    sig_lists[iis.blockNum].Add(iis);
                                    pii.lastRequested = Clock.getTimestamp();
                                    break;

                                case InventoryItemTypes.block:
                                    var iib = ((InventoryItemBlock)item);
                                    if (iib.blockNum <= last_block_height)
                                    {
                                        Node.inventoryCache.processInventoryItem(pii);
                                    }
                                    else
                                    {
                                        pii.lastRequested  = Clock.getTimestamp();
                                        request_next_block = true;
                                        if (iib.blockNum > endpoint.blockHeight)
                                        {
                                            endpoint.blockHeight = iib.blockNum;
                                        }

                                        if (iib.blockNum > Node.blockProcessor.highestNetworkBlockNum)
                                        {
                                            Node.blockProcessor.highestNetworkBlockNum = iib.blockNum;
                                        }
                                    }
                                    break;

                                default:
                                    Node.inventoryCache.processInventoryItem(pii);
                                    break;
                                }
                            }
                        }
                        PresenceProtocolMessages.broadcastGetKeepAlives(ka_list, endpoint);
                        if (Node.blockSync.synchronizing)
                        {
                            return;
                        }
                        TransactionProtocolMessages.broadcastGetTransactions(tx_list, 0, endpoint);
                        if (request_next_block)
                        {
                            byte include_tx = 2;
                            if (Node.isMasterNode())
                            {
                                include_tx = 0;
                            }
                            BlockProtocolMessages.broadcastGetBlock(last_block_height + 1, null, endpoint, include_tx, true);
                        }
                        foreach (var sig_list in sig_lists)
                        {
                            SignatureProtocolMessages.broadcastGetSignatures(sig_list.Key, sig_list.Value, endpoint);
                        }
                    }
                }
            }
Esempio n. 13
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:
                        handleHello(data, endpoint);
                        break;

                    case ProtocolMessageCode.helloData:
                        handleHelloData(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBlock:
                        BlockProtocolMessages.handleGetBlock(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBalance:
                        WalletStateProtocolMessages.handleGetBalance(data, endpoint);
                        break;

                    case ProtocolMessageCode.getTransaction:
                        TransactionProtocolMessages.handleGetTransaction(data, endpoint);
                        break;

                    case ProtocolMessageCode.getTransaction2:
                        TransactionProtocolMessages.handleGetTransaction2(data, endpoint);
                        break;

                    case ProtocolMessageCode.getTransaction3:
                        TransactionProtocolMessages.handleGetTransaction3(data, endpoint);
                        break;

                    case ProtocolMessageCode.newTransaction:
                    case ProtocolMessageCode.transactionData:
                        TransactionProtocolMessages.handleTransactionData(data, endpoint);
                        break;

                    case ProtocolMessageCode.bye:
                        CoreProtocolMessage.processBye(data, endpoint);
                        break;

                    case ProtocolMessageCode.newBlock:
                    case ProtocolMessageCode.blockData:
                        BlockProtocolMessages.handleBlockData(data, endpoint);
                        break;

                    case ProtocolMessageCode.syncWalletState:
                        WalletStateProtocolMessages.handleSyncWalletState(data, endpoint);
                        break;

                    case ProtocolMessageCode.walletState:
                        WalletStateProtocolMessages.handleWalletState(data, endpoint);
                        break;

                    case ProtocolMessageCode.getWalletStateChunk:
                        WalletStateProtocolMessages.handleGetWalletStateChunk(data, endpoint);
                        break;

                    case ProtocolMessageCode.walletStateChunk:
                        WalletStateProtocolMessages.handleWalletStateChunk(data, endpoint);
                        break;

                    case ProtocolMessageCode.updatePresence:
                        PresenceProtocolMessages.handleUpdatePresence(data, endpoint);
                        break;

                    case ProtocolMessageCode.keepAlivePresence:
                        PresenceProtocolMessages.handleKeepAlivePresence(data, endpoint);
                        break;

                    case ProtocolMessageCode.getPresence:
                        PresenceProtocolMessages.handleGetPresence(data, endpoint);
                        break;

                    case ProtocolMessageCode.getPresence2:
                        PresenceProtocolMessages.handleGetPresence2(data, endpoint);
                        break;

                    case ProtocolMessageCode.getKeepAlives:
                        PresenceProtocolMessages.handleGetKeepAlives(data, endpoint);
                        break;

                    case ProtocolMessageCode.keepAlivesChunk:
                        PresenceProtocolMessages.handleKeepAlivesChunk(data, endpoint);
                        break;

                    // return 10 random presences of the selected type
                    case ProtocolMessageCode.getRandomPresences:
                        PresenceProtocolMessages.handleGetRandomPresences(data, endpoint);
                        break;

                    case ProtocolMessageCode.getUnappliedTransactions:
                        TransactionProtocolMessages.handleGetUnappliedTransactions(data, endpoint);
                        break;

                    case ProtocolMessageCode.blockTransactionsChunk:
                        BlockProtocolMessages.handleBlockTransactionsChunk(data, endpoint);
                        break;

                    case ProtocolMessageCode.attachEvent:
                        NetworkEvents.handleAttachEventMessage(data, endpoint);
                        break;

                    case ProtocolMessageCode.detachEvent:
                        NetworkEvents.handleDetachEventMessage(data, endpoint);
                        break;

                    case ProtocolMessageCode.blockSignature:
                        SignatureProtocolMessages.handleBlockSignature(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBlockSignatures:
                    {
                        using (MemoryStream m = new MemoryStream(data))
                        {
                            using (BinaryReader reader = new BinaryReader(m))
                            {
                                ulong block_num = reader.ReadUInt64();

                                int    checksum_len = reader.ReadInt32();
                                byte[] checksum     = reader.ReadBytes(checksum_len);

                                SignatureProtocolMessages.handleGetBlockSignatures(block_num, checksum, endpoint);
                            }
                        }
                    }
                    break;

                    case ProtocolMessageCode.blockSignatures:
                        SignatureProtocolMessages.handleSigfreezedBlockSignatures(data, endpoint);
                        break;

                    case ProtocolMessageCode.getNextSuperBlock:
                        BlockProtocolMessages.handleGetNextSuperBlock(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBlockHeaders:
                        BlockProtocolMessages.handleGetBlockHeaders(data, endpoint);
                        break;

                    case ProtocolMessageCode.getPIT:
                        BlockProtocolMessages.handleGetPIT(data, endpoint);
                        break;

                    case ProtocolMessageCode.inventory:
                        handleInventory(data, endpoint);
                        break;

                    case ProtocolMessageCode.inventory2:
                        handleInventory2(data, endpoint);
                        break;

                    case ProtocolMessageCode.getSignatures:
                        SignatureProtocolMessages.handleGetSignatures(data, endpoint);
                        break;

                    case ProtocolMessageCode.signaturesChunk:
                        SignatureProtocolMessages.handleSignaturesChunk(data, endpoint);
                        break;

                    case ProtocolMessageCode.getTransactions:
                        TransactionProtocolMessages.handleGetTransactions(data, endpoint);
                        break;

                    case ProtocolMessageCode.getTransactions2:
                        TransactionProtocolMessages.handleGetTransactions2(data, endpoint);
                        break;

                    case ProtocolMessageCode.transactionsChunk:
                        TransactionProtocolMessages.handleTransactionsChunk(data, endpoint);
                        break;

                    case ProtocolMessageCode.transactionsChunk2:
                        TransactionProtocolMessages.handleTransactionsChunk2(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBlockHeaders2:
                        BlockProtocolMessages.handleGetBlockHeaders2(data, endpoint);
                        break;

                    case ProtocolMessageCode.getPIT2:
                        BlockProtocolMessages.handleGetPIT2(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBlock2:
                        BlockProtocolMessages.handleGetBlock2(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBlock3:
                        BlockProtocolMessages.handleGetBlock3(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBalance2:
                        WalletStateProtocolMessages.handleGetBalance2(data, endpoint);
                        break;

                    case ProtocolMessageCode.getBlockSignatures2:
                    {
                        using (MemoryStream m = new MemoryStream(data))
                        {
                            using (BinaryReader reader = new BinaryReader(m))
                            {
                                ulong block_num = reader.ReadIxiVarUInt();

                                int    checksum_len = (int)reader.ReadIxiVarUInt();
                                byte[] checksum     = reader.ReadBytes(checksum_len);

                                SignatureProtocolMessages.handleGetBlockSignatures2(block_num, checksum, endpoint);
                            }
                        }
                    }
                    break;

                    case ProtocolMessageCode.blockSignature2:
                        SignatureProtocolMessages.handleBlockSignature2(data, endpoint);
                        break;

                    default:
                        break;
                    }
                }
                catch (Exception e)
                {
                    Logging.error("Error parsing network message. Details: {0}", e.ToString());
                }
            }
Esempio n. 14
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))
                            {
                                byte[] challenge_response = null;

                                int    challenge_len = reader.ReadInt32();
                                byte[] challenge     = reader.ReadBytes(challenge_len);

                                challenge_response = CryptoManager.lib.getSignature(challenge, IxianHandler.getWalletStorage().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))
                            {
                                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(); // deprecated

                            endpoint.blockHeight = last_block_num;

                            int block_version = reader.ReadInt32();

                            // 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;
                            }

                            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.sendGetMessages(f);
                                }
                            }

                            if (endpoint.presenceAddress.type == 'M')
                            {
                                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'
                                });

                                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);
                }
                break;

                case ProtocolMessageCode.keepAlivePresence:
                {
                    byte[] address = null;
                    bool   updated = PresenceList.receiveKeepAlive(data, out 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:
                {
                    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.lastUpdate    = Clock.getTimestamp();
                                    Node.balance.verified      = false;
                                }
                            }
                        }
                    }
                }
                break;

                case ProtocolMessageCode.newTransaction:
                case ProtocolMessageCode.transactionData:
                {
                    // TODO: check for errors/exceptions
                    Transaction transaction = new Transaction(data, true);

                    PendingTransactions.increaseReceivedCount(transaction.id);

                    TransactionCache.addUnconfirmedTransaction(transaction);

                    Node.tiv.receivedNewTransaction(transaction);
                }
                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)
                                        {
                                            // TODO TODO do not set if not directly connectable
                                            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;

                                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.blockHeaders:
                {
                    // Forward the block headers to the TIV handler
                    Node.tiv.receivedBlockHeaders(data, endpoint);
                }
                break;

                case ProtocolMessageCode.pitData:
                {
                    Node.tiv.receivedPIT(data, endpoint);
                }
                break;

                default:
                    break;
                }
            }
            catch (Exception e)
            {
                Logging.error(string.Format("Error parsing network message. Details: {0}", e.ToString()));
            }

            if (waitingFor == code)
            {
                blocked = false;
            }
        }
Esempio n. 15
0
        private static void sendReceivedConfirmation(byte[] recipientAddress, byte[] messageId, int channel, RemoteEndpoint endpoint)
        {
            // Send received confirmation
            StreamMessage msg_received = new StreamMessage();

            msg_received.type           = StreamMessageCode.info;
            msg_received.sender         = IxianHandler.getWalletStorage().getPrimaryAddress();
            msg_received.recipient      = recipientAddress;
            msg_received.data           = new SpixiMessage(SpixiMessageCode.msgReceived, messageId, channel).getBytes();
            msg_received.encryptionType = StreamMessageEncryptionCode.none;

            sendMessage(endpoint.presence.wallet, msg_received);
        }
Esempio n. 16
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 (data[0] == 5)
                            {
                                CoreProtocolMessage.processHelloMessageV5(endpoint, reader);
                            }
                            else
                            {
                                CoreProtocolMessage.processHelloMessageV6(endpoint, reader);
                            }
                        }
                    }
                }
                break;


                case ProtocolMessageCode.helloData:
                    using (MemoryStream m = new MemoryStream(data))
                    {
                        using (BinaryReader reader = new BinaryReader(m))
                        {
                            if (data[0] == 5)
                            {
                                if (!CoreProtocolMessage.processHelloMessageV5(endpoint, reader))
                                {
                                    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(); // deprecated

                                endpoint.blockHeight = last_block_num;

                                int block_version = reader.ReadInt32();

                                // 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;
                                }

                                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);
                                }
                            }
                            else
                            {
                                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());
            }
        }
Esempio n. 17
0
        public static void onMsgReaction(StreamMessage reaction_msg, byte[] msg_reaction_data, int channel, RemoteEndpoint endpoint)
        {
            SpixiMessageReaction smr = new SpixiMessageReaction(msg_reaction_data);
            StreamMessage        msg = Messages.getMessage(smr.msgId, channel);

            if (msg == null)
            {
                return;
            }

            Messages.addMessage(reaction_msg, channel, false);
            NetworkServer.forwardMessage(ProtocolMessageCode.s2data, reaction_msg.getBytes());
        }
Esempio n. 18
0
            public static void handleGetPIT2(byte[] data, RemoteEndpoint endpoint)
            {
                MemoryStream ms = new MemoryStream(data);

                using (BinaryReader r = new BinaryReader(ms))
                {
                    ulong  block_num  = r.ReadIxiVarUInt();
                    int    filter_len = (int)r.ReadIxiVarUInt();
                    byte[] filter     = r.ReadBytes(filter_len);
                    Cuckoo cf;
                    try
                    {
                        cf = new Cuckoo(filter);
                    }
                    catch (Exception)
                    {
                        Logging.warn("The Cuckoo filter in the getPIT message was invalid or corrupted!");
                        return;
                    }
                    Block b = Node.blockChain.getBlock(block_num, true, true);
                    if (b is null)
                    {
                        return;
                    }
                    if (b.version < BlockVer.v6)
                    {
                        Logging.warn("Neighbor {0} requested PIT information for block {0}, which was below the minimal PIT version.", endpoint.fullAddress, block_num);
                        return;
                    }
                    PrefixInclusionTree pit = new PrefixInclusionTree(44, 3);
                    List <byte[]>       interesting_transactions = new List <byte[]>();
                    foreach (var tx in b.transactions)
                    {
                        if (b.version < BlockVer.v8)
                        {
                            pit.add(UTF8Encoding.UTF8.GetBytes(Transaction.txIdV8ToLegacy(tx)));
                            if (cf.Contains(tx))
                            {
                                interesting_transactions.Add(UTF8Encoding.UTF8.GetBytes(Transaction.txIdV8ToLegacy(tx)));
                            }
                        }
                        else
                        {
                            pit.add(tx);
                            if (cf.Contains(tx))
                            {
                                interesting_transactions.Add(tx);
                            }
                        }
                    }
                    // make sure we ended up with the correct PIT
                    if (!b.pitChecksum.SequenceEqual(pit.calculateTreeHash()))
                    {
                        // This is a serious error, but I am not sure how to respond to it right now.
                        Logging.error("Reconstructed PIT for block {0} does not match the checksum in block header!", block_num);
                        return;
                    }
                    byte[]       minimal_pit = pit.getMinimumTreeTXList(interesting_transactions);
                    MemoryStream mOut        = new MemoryStream(minimal_pit.Length + 12);
                    using (BinaryWriter w = new BinaryWriter(mOut, Encoding.UTF8, true))
                    {
                        w.WriteIxiVarInt(block_num);
                        w.WriteIxiVarInt(minimal_pit.Length);
                        w.Write(minimal_pit);
                    }
                    endpoint.sendData(ProtocolMessageCode.pitData2, mOut.ToArray());
                }
            }
Esempio n. 19
0
        public static void onBotAction(byte[] action_data, RemoteEndpoint endpoint, int channel = 0)
        {
            SpixiBotAction sba = new SpixiBotAction(action_data);

            switch (sba.action)
            {
            case SpixiBotActionCode.getChannels:
                sendChannels(endpoint);
                break;

            case SpixiBotActionCode.getInfo:
                Node.users.setPubKey(endpoint.presence.wallet, endpoint.serverPubKey, false);
                sendInfo(endpoint.presence.wallet);
                break;

            case SpixiBotActionCode.getUsers:
                sendUsers(endpoint);
                break;

            case SpixiBotActionCode.getUser:
                sendUser(endpoint.presence.wallet, Node.users.getUser(sba.data));
                break;

            case SpixiBotActionCode.payment:
                StreamTransaction stream_tx = new StreamTransaction(sba.data);

                if (!stream_tx.transaction.toList.Keys.First().SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress()))
                {
                    Logging.warn("Received transaction txid " + stream_tx.transaction.id + " from " + Base58Check.Base58CheckEncoding.EncodePlain(endpoint.presence.wallet) + " that's not for this node.");
                    return;
                }

                StreamMessage sm = pendingMessages.Find(x => x.id.SequenceEqual(stream_tx.messageID));
                if (sm == null)
                {
                    // TODO TODO TODO send get message request to the client
                    Logging.warn("Received transaction txid " + stream_tx.transaction.id + " from " + Base58Check.Base58CheckEncoding.EncodePlain(endpoint.presence.wallet) + " but have no message for this transaction.");
                    return;
                }

                IxiNumber price = getMessagePrice(sm.sender, sm.data.Length);
                if (stream_tx.transaction.amount < price)
                {
                    Logging.warn("Received transaction txid " + stream_tx.transaction.id + " from " + Base58Check.Base58CheckEncoding.EncodePlain(endpoint.presence.wallet) + " that has lower than expected amount.");
                    return;
                }

                CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.transactionData, stream_tx.transaction.getBytes(), null);
                CoreProtocolMessage.broadcastGetTransaction(stream_tx.transaction.id, 0, null, false);
                PendingTransactions.addPendingLocalTransaction(stream_tx.transaction, stream_tx.messageID);
                break;

            case SpixiBotActionCode.enableNotifications:
                bool send_notifications = false;
                if (sba.data[0] == 1)
                {
                    send_notifications = true;
                }
                Node.users.getUser(endpoint.presence.wallet).sendNotification = send_notifications;
                Node.users.writeContactsToFile();
                break;
            }
        }
Esempio n. 20
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));
                    }
                }
            }
Esempio n. 21
0
        /// <summary>
        ///  Reads a protocol message from the specified byte-field and calls appropriate methods to process this message.
        /// </summary>
        /// <remarks>
        ///  This function checks all applicable checksums and validates that the message is complete before calling one of the specialized
        ///  methods to handle actual decoding and processing.
        /// </remarks>
        /// <param name="recv_buffer">Byte-field with an Ixian protocol message.</param>
        /// <param name="endpoint">Remote endpoint from where the message was received.</param>
        public static void readProtocolMessage(byte[] recv_buffer, RemoteEndpoint endpoint)
        {
            if (endpoint == null)
            {
                Logging.error("Endpoint was null. readProtocolMessage");
                return;
            }

            ProtocolMessageCode code = ProtocolMessageCode.hello;

            byte[] data = null;

            using (MemoryStream m = new MemoryStream(recv_buffer))
            {
                using (BinaryReader reader = new BinaryReader(m))
                {
                    // Check for multi-message packets. One packet can contain multiple network messages.
                    while (reader.BaseStream.Position < reader.BaseStream.Length)
                    {
                        byte[] data_checksum;
                        try
                        {
                            byte startByte = reader.ReadByte();

                            int message_code = reader.ReadInt32();
                            code = (ProtocolMessageCode)message_code;

                            int data_length = reader.ReadInt32();

                            // If this is a connected client, filter messages
                            if (endpoint.GetType() == typeof(RemoteEndpoint))
                            {
                                if (endpoint.presence == null)
                                {
                                    // Check for presence and only accept hello and syncPL messages if there is no presence.
                                    if (code == ProtocolMessageCode.hello || code == ProtocolMessageCode.getPresenceList || code == ProtocolMessageCode.getBalance || code == ProtocolMessageCode.newTransaction)
                                    {
                                    }
                                    else
                                    {
                                        // Ignore anything else
                                        return;
                                    }
                                }
                            }



                            data_checksum = reader.ReadBytes(32); // sha512qu, 32 bytes
                            byte header_checksum = reader.ReadByte();
                            byte endByte         = reader.ReadByte();
                            data = reader.ReadBytes(data_length);
                        }
                        catch (Exception e)
                        {
                            Logging.error(String.Format("NET: dropped packet. {0}", e));
                            return;
                        }
                        // Compute checksum of received data
                        byte[] local_checksum = Crypto.sha512sqTrunc(data, 0, 0, 32);

                        // Verify the checksum before proceeding
                        if (local_checksum.SequenceEqual(data_checksum) == false)
                        {
                            Logging.error("Dropped message (invalid checksum)");
                            continue;
                        }

                        // Can proceed to parse the data parameter based on the protocol message code.
                        // Data can contain multiple elements.
                        //parseProtocolMessage(code, data, socket, endpoint);
                        NetworkQueue.receiveProtocolMessage(code, data, data_checksum, endpoint);
                    }
                }
            }
        }
Esempio n. 22
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)));
         }
     }
 }
Esempio n. 23
0
        /// <summary>
        ///  Prepares and sends an Ixian protocol 'Hello' message to the specified remote endpoint.
        /// </summary>
        /// <remarks>
        ///  A valid Ixian 'Hello' message includes certain Node data, verified by a public-key signature, which this function prepares using
        ///  the primary wallet's keypair. If this message is a reply to the other endpoint's hello message, then
        /// </remarks>
        /// <param name="endpoint">Remote endpoint to send the message to.</param>
        /// <param name="sendHelloData">True if the message is the first hello sent to the remote node, false if it is a reply to the challenge.</param>
        /// <param name="challenge_response">Response byte-field to the other node's hello challenge</param>
        public static void sendHelloMessage(RemoteEndpoint endpoint, bool sendHelloData, byte[] challenge_response)
        {
            using (MemoryStream m = new MemoryStream(1856))
            {
                using (BinaryWriter writer = new BinaryWriter(m))
                {
                    string publicHostname = IxianHandler.getFullPublicAddress();

                    // Send the node version
                    writer.Write(CoreConfig.protocolVersion);

                    // Send the public node address
                    byte[] address = IxianHandler.getWalletStorage().getPrimaryAddress();
                    writer.Write(address.Length);
                    writer.Write(address);

                    // Send the testnet designator
                    writer.Write(CoreConfig.isTestNet);

                    char node_type = PresenceList.myPresenceType;
                    writer.Write(node_type);

                    // Send the version
                    writer.Write(CoreConfig.productVersion);

                    // Send the node device id
                    writer.Write(CoreConfig.device_id);

                    // Send the wallet public key
                    writer.Write(IxianHandler.getWalletStorage().getPrimaryPublicKey().Length);
                    writer.Write(IxianHandler.getWalletStorage().getPrimaryPublicKey());

                    // Send listening port
                    writer.Write(IxianHandler.publicPort);

                    // Send timestamp
                    long timestamp = Core.getCurrentTimestamp();
                    writer.Write(timestamp);

                    // send signature
                    byte[] signature = CryptoManager.lib.getSignature(Encoding.UTF8.GetBytes(ConsensusConfig.ixianChecksumLockString + "-" + CoreConfig.device_id + "-" + timestamp + "-" + publicHostname), IxianHandler.getWalletStorage().getPrimaryPrivateKey());
                    writer.Write(signature.Length);
                    writer.Write(signature);


                    if (sendHelloData)
                    {
                        Block block = IxianHandler.getLastBlock();
                        if (block == null)
                        {
                            Logging.warn("Clients are connecting, but we have no blocks yet to send them!");
                            return;
                        }


                        ulong lastBlock = block.blockNum;
                        writer.Write(lastBlock);

                        writer.Write(block.blockChecksum.Length);
                        writer.Write(block.blockChecksum);

                        writer.Write(block.walletStateChecksum.Length);
                        writer.Write(block.walletStateChecksum);

                        writer.Write((int)0); // deprecated, can be replaced with something else of type int32

                        writer.Write(block.version);

                        // Write the legacy level
                        writer.Write((ulong)0); // deprecated, can be replaced with something else of type UInt64

                        writer.Write(challenge_response.Length);
                        writer.Write(challenge_response);
#if TRACE_MEMSTREAM_SIZES
                        Logging.info(String.Format("CoreProtocolMessage::sendHelloMessage: {0}", m.Length));
#endif

                        endpoint.sendData(ProtocolMessageCode.helloData, m.ToArray());
                    }
                    else
                    {
                        List <byte> challenge = new List <byte>();

                        challenge.AddRange(IxianHandler.getWalletStorage().getPrimaryAddress());
                        Random rnd = new Random();
                        challenge.AddRange(BitConverter.GetBytes(rnd.Next(20000)));

                        byte[] challenge_bytes = challenge.ToArray();

                        endpoint.challenge = challenge_bytes;

                        writer.Write(challenge_bytes.Length);
                        writer.Write(challenge_bytes);
#if TRACE_MEMSTREAM_SIZES
                        Logging.info(String.Format("CoreProtocolMessage::sendHelloMessage: {0}", m.Length));
#endif

                        endpoint.sendData(ProtocolMessageCode.hello, m.ToArray());
                    }
                }
            }
        }
Esempio n. 24
0
            public static void handleGetBlock3(byte[] data, RemoteEndpoint endpoint)
            {
                if (!Node.isMasterNode())
                {
                    Logging.warn("Block data was requested, but this node isn't a master node");
                    return;
                }

                if (Node.blockSync.synchronizing)
                {
                    return;
                }
                using (MemoryStream m = new MemoryStream(data))
                {
                    using (BinaryReader reader = new BinaryReader(m))
                    {
                        ulong block_number         = reader.ReadIxiVarUInt();
                        byte  include_transactions = reader.ReadByte();
                        bool  full_header          = false;
                        try
                        {
                            full_header = reader.ReadBoolean();
                        }
                        catch (Exception)
                        {
                        }

                        //Logging.info(String.Format("Block #{0} has been requested.", block_number));

                        ulong last_block_height = IxianHandler.getLastBlockHeight() + 1;

                        if (block_number > last_block_height)
                        {
                            return;
                        }

                        Block block = null;
                        if (block_number == last_block_height)
                        {
                            bool haveLock = false;
                            try
                            {
                                Monitor.TryEnter(Node.blockProcessor.localBlockLock, 1000, ref haveLock);
                                if (!haveLock)
                                {
                                    throw new TimeoutException();
                                }

                                Block tmp = Node.blockProcessor.getLocalBlock();
                                if (tmp != null && tmp.blockNum == last_block_height)
                                {
                                    block = tmp;
                                }
                            }
                            finally
                            {
                                if (haveLock)
                                {
                                    Monitor.Exit(Node.blockProcessor.localBlockLock);
                                }
                            }
                        }
                        else
                        {
                            block = Node.blockChain.getBlock(block_number, Config.storeFullHistory);
                        }

                        if (block == null)
                        {
                            Logging.warn("Unable to find block #{0} in the chain!", block_number);
                            return;
                        }
                        //Logging.info(String.Format("Block #{0} ({1}) found, transmitting...", block_number, Crypto.hashToString(block.blockChecksum.Take(4).ToArray())));
                        // Send the block

                        if (include_transactions == 1)
                        {
                            TransactionProtocolMessages.handleGetBlockTransactions3(block_number, false, endpoint);
                        }
                        else if (include_transactions == 2)
                        {
                            TransactionProtocolMessages.handleGetBlockTransactions3(block_number, true, endpoint);
                        }

                        if (!Node.blockProcessor.verifySigFreezedBlock(block))
                        {
                            Logging.warn("Sigfreezed block {0} was requested. but we don't have the correct sigfreeze!", block.blockNum);
                        }

                        bool frozen_sigs_only = true;

                        if (block_number + 5 > IxianHandler.getLastBlockHeight())
                        {
                            if (block.getFrozenSignatureCount() < Node.blockChain.getRequiredConsensus(block_number))
                            {
                                frozen_sigs_only = false;
                            }
                        }

                        endpoint.sendData(ProtocolMessageCode.blockData, block.getBytes(full_header, frozen_sigs_only), BitConverter.GetBytes(block.blockNum), 0, MessagePriority.high);
                    }
                }
            }
Esempio n. 25
0
        // Broadcast an event-specific protocol message across subscribed clients
        // Returns true if it sent the message to at least one endpoint. Returns false if the message couldn't be sent to any endpoints
        /// <summary>
        ///  Broadcasts an event message to all clients who are subscribed to receive the specific event type and wallet address.
        /// </summary>
        /// <remarks>
        ///  Events are filtered by type and address. A client must subscribe to the specifif type for specific addresses in order to receive this data.
        ///  The payload `data` should be properly formatted for the given `code` - this function will not ensure that this is so and
        ///  the caller must provide a valid message to this function.
        ///  The `skipEndpoint` parameter is useful when re-broadcasting a message received from a specific endpoint and do not wish to echo the same
        ///  data back to the sender.
        /// </remarks>
        /// <param name="type">Type of the event message - used to filter subscribers</param>
        /// <param name="address">Address, which triggered the event.</param>
        /// <param name="code">Ixian protocol code.</param>
        /// <param name="data">Payload data.</param>
        /// <param name="helper_data">Optional additional data, as required by `code`.</param>
        /// <param name="skipEndpoint">Endpoint to skip when broadcasting.</param>
        /// <returns>True, if at least one message was sent to at least one remote endpoint. False if no messages were sent.</returns>
        public static bool broadcastEventDataMessage(NetworkEvents.Type type, byte[] address, ProtocolMessageCode code, byte[] data, byte[] helper_data, RemoteEndpoint skipEndpoint = null)
        {
            // Send it to subscribed C nodes
            bool f_result = NetworkServer.broadcastEventData(type, code, data, address, helper_data, skipEndpoint);

            return(f_result);
        }
Esempio n. 26
0
            public static void handleGetBlockHeaders(byte[] data, RemoteEndpoint endpoint)
            {
                using (MemoryStream m = new MemoryStream(data))
                {
                    using (BinaryReader reader = new BinaryReader(m))
                    {
                        ulong from = reader.ReadUInt64();
                        ulong to   = reader.ReadUInt64();

                        ulong totalCount = to - from;
                        if (totalCount < 1)
                        {
                            return;
                        }

                        ulong lastBlockNum = Node.blockChain.getLastBlockNum();

                        if (from > lastBlockNum - 1)
                        {
                            return;
                        }

                        if (to > lastBlockNum)
                        {
                            to = lastBlockNum;
                        }

                        // Adjust total count if necessary
                        totalCount = to - from;
                        if (totalCount < 1)
                        {
                            return;
                        }

                        // Cap total block headers sent
                        if (totalCount > (ulong)CoreConfig.maximumBlockHeadersPerChunk)
                        {
                            totalCount = (ulong)CoreConfig.maximumBlockHeadersPerChunk;
                        }

                        if (endpoint == null)
                        {
                            return;
                        }

                        if (!endpoint.isConnected())
                        {
                            return;
                        }

                        // TODO TODO TODO block headers should be read from a separate storage and every node should keep a full copy
                        for (ulong i = 0; i < totalCount;)
                        {
                            bool found = false;
                            using (MemoryStream mOut = new MemoryStream())
                            {
                                using (BinaryWriter writer = new BinaryWriter(mOut))
                                {
                                    for (int j = 0; j < CoreConfig.maximumBlockHeadersPerChunk && i < totalCount; j++)
                                    {
                                        Block block = Node.blockChain.getBlock(from + i, true, true);
                                        i++;
                                        if (block == null)
                                        {
                                            break;
                                        }

                                        long rollback_len = mOut.Length;

                                        found = true;
                                        BlockHeader header      = new BlockHeader(block);
                                        byte[]      headerBytes = header.getBytes();
                                        writer.Write(headerBytes.Length);
                                        writer.Write(headerBytes);

                                        if (mOut.Length > CoreConfig.maxMessageSize)
                                        {
                                            mOut.SetLength(rollback_len);
                                            i--;
                                            break;
                                        }

                                        broadcastBlockHeaderTransactions(block, endpoint);
                                    }
                                }
                                if (!found)
                                {
                                    break;
                                }
                                endpoint.sendData(ProtocolMessageCode.blockHeaders, mOut.ToArray());
                            }
                        }
                    }
                }
            }
Esempio n. 27
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))
                            {
                                byte[] challenge_response = null;
                                try
                                {
                                    // TODO TODO TODO TODO TODO try/catch wrapper will be removed when everybody upgrades
                                    int    challenge_len = reader.ReadInt32();
                                    byte[] challenge     = reader.ReadBytes(challenge_len);

                                    challenge_response = CryptoManager.lib.getSignature(challenge, Node.walletStorage.getPrimaryPrivateKey());
                                }
                                catch (Exception e)
                                {
                                }


                                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);
                                Node.setRequiredConsensus(consensus);

                                // Check for legacy level
                                ulong legacy_level = reader.ReadUInt64();

                                // Check for legacy node
                                if (Legacy.isLegacy(legacy_level))
                                {
                                    // TODO TODO TODO TODO check this out
                                    //endpoint.setLegacy(true);
                                }

                                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.syncPresenceList:
                {
                    byte[] pdata = PresenceList.getBytes();
                    byte[] ba    = CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.presenceList, pdata);
                    endpoint.sendData(ProtocolMessageCode.presenceList, pdata);
                }
                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);

                    // 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);
                            lock (PresenceList.presences)
                            {
                                // TODO re-verify this
                                Presence p = PresenceList.presences.Find(x => x.wallet.SequenceEqual(wallet));
                                if (p != null)
                                {
                                    byte[][] presence_chunks = p.getByteChunks();
                                    int      i = 0;
                                    foreach (byte[] presence_chunk in presence_chunks)
                                    {
                                        endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk);
                                        i++;
                                    }
                                }
                                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().Length < 2)
                                        {
                                            Config.publicServerIP = 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 " + Config.serverPort + ".");
                                    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()));
            }
        }
Esempio n. 28
0
        // Called when receiving S2 data from clients
        public static void receiveData(byte[] bytes, RemoteEndpoint endpoint)
        {
            // TODO Verify signature for all relevant messages

            string endpoint_wallet_string = Base58Check.Base58CheckEncoding.EncodePlain(endpoint.presence.wallet);

            Logging.info(string.Format("Receiving S2 data from {0}", endpoint_wallet_string));

            StreamMessage message = new StreamMessage(bytes);

            // Don't allow clients to send error stream messages, as it's reserved for S2 nodes only
            if (message.type == StreamMessageCode.error)
            {
                Logging.warn(string.Format("Discarding error message type from {0}", endpoint_wallet_string));
                return;
            }

            // Discard messages not sent to this node
            if (!IxianHandler.getWalletStorage().isMyAddress(message.recipient))
            {
                Logging.warn(string.Format("Discarding message that wasn't sent to this node from {0}", endpoint_wallet_string));
                return;
            }

            if (message.encryptionType != StreamMessageEncryptionCode.none && !message.decrypt(IxianHandler.getWalletStorage().getPrimaryPrivateKey(), null, null))
            {
                Logging.error("Could not decrypt message from {0}", Base58Check.Base58CheckEncoding.EncodePlain(message.sender));
                return;
            }

            SpixiMessage spixi_msg = new SpixiMessage(message.data);

            int channel = 0;

            if (spixi_msg != null)
            {
                channel = spixi_msg.channel;
            }

            if (message.requireRcvConfirmation)
            {
                switch (spixi_msg.type)
                {
                case SpixiMessageCode.msgReceived:
                case SpixiMessageCode.msgRead:
                case SpixiMessageCode.requestFileData:
                case SpixiMessageCode.fileData:
                case SpixiMessageCode.appData:
                case SpixiMessageCode.msgTyping:
                    // do not send received confirmation
                    break;

                case SpixiMessageCode.chat:
                    sendReceivedConfirmation(message.sender, message.id, channel, endpoint);
                    break;

                default:
                    sendReceivedConfirmation(message.sender, message.id, -1, endpoint);
                    break;
                }
            }

            switch (spixi_msg.type)
            {
            case SpixiMessageCode.requestAdd:
                // Friend request
                if (!new Address(spixi_msg.data).address.SequenceEqual(message.sender) || !message.verifySignature(spixi_msg.data))
                {
                    Logging.error("Unable to verify signature for message type: {0}, id: {1}, from: {2}.", message.type, Crypto.hashToString(message.id), Base58Check.Base58CheckEncoding.EncodePlain(message.sender));
                }
                else
                {
                    sendAcceptAdd(endpoint.presence.wallet, endpoint.presence.pubkey);
                    sendAvatar(endpoint.presence.wallet, null);
                }
                break;

            case SpixiMessageCode.getPubKey:
                if (Node.users.hasUser(spixi_msg.data))
                {
                    StreamMessage sm = new StreamMessage();
                    sm.type           = StreamMessageCode.info;
                    sm.sender         = IxianHandler.getWalletStorage().getPrimaryAddress();
                    sm.recipient      = message.sender;
                    sm.data           = new SpixiMessage(SpixiMessageCode.pubKey, Node.users.getUser(spixi_msg.data).publicKey).getBytes();
                    sm.encryptionType = StreamMessageEncryptionCode.none;

                    sendMessage(endpoint.presence.wallet, sm);
                }
                break;

            case SpixiMessageCode.getNick:
                sendNickname(endpoint.presence.wallet, spixi_msg.data);
                break;

            case SpixiMessageCode.getAvatar:
                sendAvatar(endpoint.presence.wallet, spixi_msg.data);
                break;

            case SpixiMessageCode.nick:
                Node.users.setPubKey(endpoint.presence.wallet, endpoint.serverPubKey, false);
                Node.users.setNick(endpoint.presence.wallet, message.getBytes());
                break;

            case SpixiMessageCode.avatar:
                Node.users.setPubKey(endpoint.presence.wallet, endpoint.serverPubKey, false);
                if (message.data.Length < 500000)
                {
                    if (message.data == null)
                    {
                        Node.users.setAvatar(endpoint.presence.wallet, null);
                    }
                    else
                    {
                        Node.users.setAvatar(endpoint.presence.wallet, message.getBytes());
                    }
                }
                break;

            case SpixiMessageCode.chat:
                onChat(bytes, message, channel, endpoint);
                break;

            case SpixiMessageCode.botGetMessages:
                Messages.sendMessages(endpoint.presence.wallet, channel, spixi_msg.data);
                break;

            case SpixiMessageCode.msgReceived:
            {
                // don't send confirmation back, so just return
                return;
            }

            case SpixiMessageCode.msgRead:
            {
                // don't send confirmation back, so just return
                return;
            }

            case SpixiMessageCode.botAction:
                onBotAction(spixi_msg.data, endpoint);
                break;

            case SpixiMessageCode.msgDelete:
                onMsgDelete(spixi_msg.data, channel, endpoint);
                break;

            case SpixiMessageCode.msgReaction:
                onMsgReaction(message, spixi_msg.data, channel, endpoint);
                break;

            case SpixiMessageCode.leave:
                onLeave(message.sender);

                break;

            default:
                Logging.warn("Received message type that isn't handled {0}", spixi_msg.type);
                break;
            }

            // TODO: commented for development purposes ONLY!

            /*
             *          // Extract the transaction
             *          Transaction transaction = new Transaction(message.transaction);
             *
             *          // Validate transaction sender
             *          if(transaction.from.SequenceEqual(message.sender) == false)
             *          {
             *              Logging.error(string.Format("Relayed message transaction mismatch for {0}", endpoint_wallet_string));
             *              sendError(message.sender);
             *              return;
             *          }
             *
             *          // Validate transaction amount and fee
             *          if(transaction.amount < CoreConfig.relayPriceInitial || transaction.fee < CoreConfig.transactionPrice)
             *          {
             *              Logging.error(string.Format("Relayed message transaction amount too low for {0}", endpoint_wallet_string));
             *              sendError(message.sender);
             *              return;
             *          }
             *
             *          // Validate transaction receiver
             *          if (transaction.toList.Keys.First().SequenceEqual(IxianHandler.getWalletStorage().address) == false)
             *          {
             *              Logging.error("Relayed message transaction receiver is not this S2 node");
             *              sendError(message.sender);
             *              return;
             *          }
             *
             *          // Update the recipient dictionary
             *          if (dataRelays.ContainsKey(message.recipient))
             *          {
             *              dataRelays[message.recipient]++;
             *              if(dataRelays[message.recipient] > Config.relayDataMessageQuota)
             *              {
             *                  Logging.error(string.Format("Exceeded amount of unpaid data relay messages for {0}", endpoint_wallet_string));
             *                  sendError(message.sender);
             *                  return;
             *              }
             *          }
             *          else
             *          {
             *              dataRelays.Add(message.recipient, 1);
             *          }
             *
             *
             *          // Store the transaction
             *          StreamTransaction streamTransaction = new StreamTransaction();
             *          streamTransaction.messageID = message.getID();
             *          streamTransaction.transaction = transaction;
             *          lock (transactions)
             *          {
             *              transactions.Add(streamTransaction);
             *          }
             *
             *          // For testing purposes, allow the S2 node to receive relay data itself
             *          if (message.recipient.SequenceEqual(IxianHandler.getWalletStorage().getWalletAddress()))
             *          {
             *              string test = Encoding.UTF8.GetString(message.data);
             *              Logging.info(test);
             *
             *              return;
             *          }
             *
             *          Logging.info("NET: Forwarding S2 data");
             *          NetworkStreamServer.forwardMessage(message.recipient, DLT.Network.ProtocolMessageCode.s2data, bytes);
             */
        }
Esempio n. 29
0
 public override void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint)
 {
     ProtocolMessage.parseProtocolMessage(code, data, endpoint);
 }
        internal static void LoadRabbitEndpoints()
        {
            try
            {
                string connString       = _localhostConnString;
                var    remoteEndpoints  = new Dictionary <int, RemoteEndpoint>();
                var    removedEndpoints = new List <int>();
                var    newEndpoints     = new List <int>();
                var    oldEndpoints     = _remoteEndpoints.Keys.ToList();


                using (SqlConnection conn = new SqlConnection(connString))
                {
                    using (SqlCommand cmd = conn.CreateCommand())
                    {
                        cmd.CommandText = "rmq.pr_GetRabbitEndpoints";
                        cmd.CommandType = CommandType.StoredProcedure;

                        conn.Open();
                        var dr = cmd.ExecuteReader();

                        if (dr.HasRows)
                        {
                            while (dr.Read())
                            {
                                var re = new RemoteEndpoint(dr);
                                remoteEndpoints.Add(re.EndpointId, re);
                                _remoteEndpoints.Add(re.EndpointId, re);
                            }
                        }
                    }

                    //tear down rabbit publishers
                    removedEndpoints = _remoteEndpoints.Keys.Except(remoteEndpoints.Keys).ToList();
                    if (removedEndpoints.Any())
                    {
                        foreach (var id in removedEndpoints)
                        {
                            RemoteEndpoint  e1;
                            RabbitPublisher rp1;
                            if (_rabbitPublishers.TryGetValue(id, out rp1))
                            {
                                rp1.Shutdown();
                                _rabbitPublishers.Remove(id);
                            }

                            _remoteEndpoints.Remove(id);
                        }
                    }

                    newEndpoints = _remoteEndpoints.Keys.Except(oldEndpoints).ToList();
                    if (newEndpoints.Any())
                    {
                        foreach (var id in newEndpoints)
                        {
                            var rep = _remoteEndpoints.Where(ex => ex.Key == id).Select(r => r.Value).FirstOrDefault();
                            var rp  = new RabbitPublisher(rep.ConnectionString, id);
                            _rabbitPublishers.Add(id, rp);
                            rp.InternalConnect();
                        }
                    }
                }

                if (remoteEndpoints.Count == 0)
                {
                    //TearDownConnections();
                    throw new ApplicationException("No enabled rabbit endpoints exists");
                }
            }

            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Error in: RabbitMQSqlServer.LoadRabbitEndpoints. The error is: Error rabbit endpoints: {0}", ex.Message));
            }
        }