Esempio n. 1
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 processHelloMessageV6(RemoteEndpoint endpoint, BinaryReader reader, bool set_hello_received = true)
        {
            // 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 = (int)reader.ReadIxiVarUInt();
                endpoint.version = protocol_version;

                Logging.info("Received Hello: Node version {0}", protocol_version);
                // Check for incompatible nodes
                if (protocol_version < 6)
                {
                    Logging.warn("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 = (int)reader.ReadIxiVarUInt();
                byte[] addr    = reader.ReadBytes(addrLen);
                if (addrLen > 70)
                {
                    Logging.error("Hello: Invalid address from {0} - {1}.", endpoint.getFullAddress(true), Base58Check.Base58CheckEncoding.EncodePlain(addr));
                    sendBye(endpoint, ProtocolByeCode.rejected, "Invalid address", "", true);
                    return(false);
                }

                bool   test_net     = reader.ReadBoolean();
                char   node_type    = reader.ReadChar();
                string node_version = reader.ReadString();
                if (node_version.Length > 20)
                {
                    Logging.error("Hello: Invalid node version from {0} - {1}.", endpoint.getFullAddress(true), node_version);
                    sendBye(endpoint, ProtocolByeCode.rejected, "Invalid Node Version", "", true);
                    return(false);
                }

                int    device_id_len = (int)reader.ReadIxiVarUInt();
                byte[] device_id     = reader.ReadBytes(device_id_len);
                if (device_id_len > 32)
                {
                    Logging.error("Hello: Invalid device id from {0} - {1}.", endpoint.getFullAddress(true), Crypto.hashToString(device_id));
                    sendBye(endpoint, ProtocolByeCode.rejected, "Invalid Device ID", "", true);
                    return(false);
                }

                int    pkLen  = (int)reader.ReadIxiVarUInt();
                byte[] pubkey = null;
                if (pkLen > 0)
                {
                    pubkey = reader.ReadBytes(pkLen);
                }

                endpoint.serverPubKey = pubkey;

                int port = (int)reader.ReadIxiVarInt();

                long timestamp = reader.ReadIxiVarInt();

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

                int  challenge = 0;
                bool in_hello  = false;
                if (endpoint.GetType() != typeof(NetworkClient))
                {
                    challenge = (int)reader.ReadIxiVarUInt();
                    in_hello  = true;
                }

                // Check the testnet designator and disconnect on mismatch
                if (test_net != IxianHandler.isTestNet)
                {
                    Logging.warn("Hello: 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, IxianHandler.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("Hello: Pubkey and address do not match.");
                    sendBye(endpoint, ProtocolByeCode.authFailed, "Pubkey and address do not match.", "", true);
                    return(false);
                }

                endpoint.incomingPort = port;

                if (PeerStorage.isBlacklisted(addr) || PeerStorage.isBlacklisted(endpoint.getFullAddress(true)))
                {
                    Logging.warn("Hello: Connected node is blacklisted ({0} - {1}).", endpoint.getFullAddress(true), Base58Check.Base58CheckEncoding.EncodePlain(addr));
                    sendBye(endpoint, ProtocolByeCode.rejected, "Blacklisted", "", true);
                    return(false);
                }

                // 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, Clock.getNetworkTimestamp() - CoreConfig.clientKeepAliveInterval, null);
                }
                else
                {
                    using (MemoryStream mSig = new MemoryStream(1024))
                    {
                        using (BinaryWriter sigWriter = new BinaryWriter(mSig))
                        {
                            sigWriter.Write(ConsensusConfig.ixianChecksumLock);
                            sigWriter.Write(device_id);
                            sigWriter.Write(timestamp);
                            sigWriter.Write(endpoint.getFullAddress(true));
                            if (in_hello)
                            {
                                sigWriter.Write(challenge);
                            }
                            else
                            {
                                sigWriter.Write(endpoint.challenge);
                            }
                        }
                        if (!CryptoManager.lib.verifySignature(mSig.ToArray(), pubkey, signature))
                        {
                            sendBye(endpoint, ProtocolByeCode.incorrectIp, "Verify signature failed in hello message, likely an incorrect IP was specified. Detected IP:", endpoint.address);
                            Logging.warn("Hello: 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, Clock.getNetworkTimestamp() - 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("Hello: Local address mismatch, possible Man-in-the-middle attack.");
                        sendBye(endpoint, ProtocolByeCode.addressMismatch, "Local address mismatch.", "", true);
                        return(false);
                    }

                    PeerStorage.updateLastConnected(endpoint.getFullAddress(true));
                }


                // 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("Hello: 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);
                        }
                    }

                    sendHelloMessageV6(endpoint, true, challenge);
                    if (set_hello_received)
                    {
                        endpoint.helloReceived = true;
                    }
                }


                // 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("Hello: 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. 2
0
        public SortedDictionary <byte[], IxiNumber> generateFromList(byte[] primary_address, IxiNumber total_amount_with_fee, List <byte[]> skip_addresses, List <Transaction> pending_transactions)
        {
            // TODO TODO TODO TODO  this won't work well once wallet v3 is activated
            lock (myAddresses)
            {
                Dictionary <byte[], IxiNumber> tmp_from_list = new Dictionary <byte[], IxiNumber>(new ByteArrayComparer());
                foreach (var entry in myAddresses)
                {
                    if (!entry.Value.keyPair.addressBytes.SequenceEqual(primary_address))
                    {
                        continue;
                    }

                    if (skip_addresses.Contains(entry.Key, new ByteArrayComparer()))
                    {
                        continue;
                    }

                    Wallet wallet = IxianHandler.getWallet(entry.Key);
                    if (wallet.type != WalletType.Normal)
                    {
                        continue;
                    }

                    IxiNumber amount = wallet.balance;
                    if (amount == 0)
                    {
                        continue;
                    }

                    tmp_from_list.Add(entry.Value.nonce, amount);
                }

                var tmp_from_list_ordered = tmp_from_list.OrderBy(x => x.Value.getAmount());

                SortedDictionary <byte[], IxiNumber> from_list = new SortedDictionary <byte[], IxiNumber>(new ByteArrayComparer());

                IxiNumber tmp_total_amount = 0;
                foreach (var entry in tmp_from_list_ordered)
                {
                    IxiNumber balance = entry.Value;
                    if (pending_transactions != null)
                    {
                        var tmp_pending_froms = pending_transactions.FindAll(x => x.fromList.ContainsKey(entry.Key));
                        foreach (var pending_from in tmp_pending_froms)
                        {
                            balance -= pending_from.fromList[entry.Key];
                        }
                    }

                    if (balance <= 0)
                    {
                        continue;
                    }

                    if (tmp_total_amount + balance >= total_amount_with_fee)
                    {
                        IxiNumber tmp_amount = total_amount_with_fee - tmp_total_amount;
                        from_list.Add(entry.Key, tmp_amount);
                        tmp_total_amount += tmp_amount;
                        break;
                    }
                    from_list.Add(entry.Key, balance);
                    tmp_total_amount += balance;
                }

                if (from_list.Count > 0 && tmp_total_amount == total_amount_with_fee)
                {
                    return(from_list);
                }
                return(null);
            }
        }
Esempio n. 3
0
        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);

                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 != Config.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, Config.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 and if so, add the presence

                    // Client is not connectable, don't add a presence
                    return(true);
                }
                else
                if (CryptoManager.lib.verifySignature(Encoding.UTF8.GetBytes(CoreConfig.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);
                }

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

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

                // 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))
                {
                    // Connect to this node only if it's a master node or a full history node
                    if (node_type == 'M' || node_type == 'H')
                    {
                        // Check the wallet balance for the minimum amount of coins
                        IxiNumber balance = Node.walletState.getWalletBalance(addr);
                        if (balance < CoreConfig.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}", CoreConfig.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;
                         *      }
                         *  }
                         * }*/
                    }

                    // we're the server
                    if (node_type == 'M' || node_type == 'H' || node_type == 'R')
                    {
                        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("Older node connected. {0}", e.ToString()));
                sendBye(endpoint, ProtocolByeCode.deprecated, "Please update your Ixian node to connect.", "", true);
                return(false);
            }
            return(true);
        }
Esempio n. 4
0
 public SortedDictionary <byte[], IxiNumber> generateFromListFromAddress(byte[] from_address, IxiNumber total_amount_with_fee, bool full_pubkey = false)
 {
     lock (myAddresses)
     {
         SortedDictionary <byte[], IxiNumber> tmp_from_list = new SortedDictionary <byte[], IxiNumber>(new ByteArrayComparer());
         if (full_pubkey)
         {
             if (!myAddresses.ContainsKey(from_address))
             {
                 return(null);
             }
             AddressData ad = myAddresses[from_address];
             tmp_from_list.Add(ad.nonce, total_amount_with_fee);
         }
         else
         {
             tmp_from_list.Add(new byte[1] {
                 0
             }, total_amount_with_fee);
         }
         return(tmp_from_list);
     }
 }