Exemple #1
0
 public Presence(byte[] wallet_address, byte[] node_pubkey, byte[] node_meta, PresenceAddress node_address)
 {
     wallet    = wallet_address;
     pubkey    = node_pubkey;
     metadata  = node_meta;
     addresses = new List <PresenceAddress> {
     };
     addresses.Add(node_address);
 }
Exemple #2
0
        // Generate an initial presence list
        public static void init(string initial_ip, int port, char type)
        {
            Logging.info("Generating presence list.");

            _myPublicAddress = string.Format("{0}:{1}", initial_ip, port);
            _myPresenceType  = type;

            // Initialize with the default presence state
            curNodePresenceAddress = new PresenceAddress(CoreConfig.device_id, _myPublicAddress, type, CoreConfig.productVersion, 0, null);
            curNodePresence        = new Presence(IxianHandler.getWalletStorage().getPrimaryAddress(), IxianHandler.getWalletStorage().getPrimaryPublicKey(), null, curNodePresenceAddress);
        }
Exemple #3
0
        // Update a presence entry. If the wallet address is not found, it creates a new entry in the Presence List.
        // If the wallet address is found in the presence list, it adds any new addresses from the specified presence.
        public static Presence updateEntry(Presence presence, bool return_presence_only_if_updated = false)
        {
            if (presence == null)
            {
                return(null);
            }

            bool updated = false;

            long currentTime = Clock.getNetworkTimestamp();

            lock (presences)
            {
                Presence pr = presences.Find(x => x.wallet.SequenceEqual(presence.wallet));
                if (pr != null)
                {
                    lock (pr)
                    {
                        // Go through all addresses and add any missing ones
                        foreach (PresenceAddress local_addr in presence.addresses)
                        {
                            long lTimestamp = local_addr.lastSeenTime;

                            int expiration_time = CoreConfig.serverPresenceExpiration;

                            if (local_addr.type == 'C')
                            {
                                expiration_time = CoreConfig.clientPresenceExpiration;
                            }

                            // Check for tampering. Includes a +300, -30 second synchronization zone
                            if ((currentTime - lTimestamp) > expiration_time)
                            {
                                Logging.warn(string.Format("[PL] Received expired presence for {0} {1}. Skipping; {2} - {3}", Crypto.hashToString(pr.wallet), local_addr.address, currentTime, lTimestamp));
                                continue;
                            }

                            if ((currentTime - lTimestamp) < -30)
                            {
                                Logging.warn(string.Format("[PL] Potential presence tampering for {0} {1}. Skipping; {2} - {3}", Crypto.hashToString(pr.wallet), local_addr.address, currentTime, lTimestamp));
                                continue;
                            }


                            PresenceAddress addr = pr.addresses.Find(x => x.device == local_addr.device);
                            if (addr != null)
                            {
                                if (addr.lastSeenTime < local_addr.lastSeenTime)
                                {
                                    if (local_addr.signature != null)
                                    {
                                        addr.version      = local_addr.version;
                                        addr.address      = local_addr.address;
                                        addr.lastSeenTime = local_addr.lastSeenTime;
                                        addr.signature    = local_addr.signature;
                                        updated           = true;
                                    }

                                    if (addr.type == 'M' || addr.type == 'H')
                                    {
                                        PeerStorage.addPeerToPeerList(addr.address, presence.wallet);
                                    }

                                    //Console.WriteLine("[PL] Last time updated for {0}", addr.device);
                                }
                            }
                            else
                            {
                                // Add the address if it's not found
                                //Logging.info("[PL] Adding new address for {0}", presence.wallet);
                                pr.addresses.Add(local_addr);

                                if (local_addr.type == 'M' || local_addr.type == 'H')
                                {
                                    PeerStorage.addPeerToPeerList(local_addr.address, presence.wallet);
                                }

                                lock (presenceCount)
                                {
                                    if (!presenceCount.ContainsKey(local_addr.type))
                                    {
                                        presenceCount.Add(local_addr.type, 0);
                                    }
                                    presenceCount[local_addr.type]++;
                                }

                                updated = true;
                            }
                        }

                        if (!updated && return_presence_only_if_updated)
                        {
                            return(null);
                        }
                        else
                        {
                            return(pr);
                        }
                    }
                }
                else
                {
                    // Insert a new entry
                    //Console.WriteLine("[PL] Adding new entry for {0}", presence.wallet);

                    foreach (PresenceAddress pa in presence.addresses)
                    {
                        if (pa.type == 'M' || pa.type == 'H')
                        {
                            PeerStorage.addPeerToPeerList(pa.address, presence.wallet);
                        }

                        lock (presenceCount)
                        {
                            if (!presenceCount.ContainsKey(pa.type))
                            {
                                presenceCount.Add(pa.type, 0);
                            }
                            presenceCount[pa.type]++;
                        }

                        updated = true;
                    }

                    if (updated)
                    {
                        presences.Add(presence);
                    }

                    if (!updated && return_presence_only_if_updated)
                    {
                        return(null);
                    }
                    else
                    {
                        return(presence);
                    }
                }
            }
        }
Exemple #4
0
        // Called when receiving a keepalive network message. The PresenceList will update the appropriate entry based on the timestamp.
        // Returns TRUE if it updated an entry in the PL
        // Sets the out address parameter to be the KA wallet's address or null if an error occured
        public static bool receiveKeepAlive(byte[] bytes, out byte[] address, RemoteEndpoint endpoint)
        {
            address = null;

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

            try
            {
                using (MemoryStream m = new MemoryStream(bytes))
                {
                    using (BinaryReader reader = new BinaryReader(m))
                    {
                        int    keepAliveVersion = reader.ReadInt32();
                        int    walletLen        = reader.ReadInt32();
                        byte[] wallet           = reader.ReadBytes(walletLen);

                        // Assign the out address parameter
                        address = wallet;

                        string deviceid  = reader.ReadString();
                        long   timestamp = reader.ReadInt64();
                        string hostname  = reader.ReadString();
                        char   node_type = '0';

                        node_type = reader.ReadChar();

                        int    sigLen    = reader.ReadInt32();
                        byte[] signature = reader.ReadBytes(sigLen);
                        //Logging.info(String.Format("[PL] KEEPALIVE request from {0}", hostname));

                        if (node_type == 'C' || node_type == 'R')
                        {
                            // all good, continue
                        }
                        else if (node_type == 'M' || node_type == 'H')
                        {
                            if (myPresenceType == 'M' || myPresenceType == 'H')
                            {
                                // check balance
                                if (IxianHandler.getWalletBalance(wallet) < ConsensusConfig.minimumMasterNodeFunds)
                                {
                                    return(false);
                                }
                            }
                        }
                        else
                        {
                            // reject everything else
                            return(false);
                        }

                        lock (presences)
                        {
                            Presence listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet));
                            if (listEntry == null && wallet.SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress()))
                            {
                                Logging.warn("My entry was removed from local PL, readding.");
                                curNodePresence.addresses.Clear();
                                curNodePresence.addresses.Add(curNodePresenceAddress);
                                updateEntry(curNodePresence);
                                listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet));
                            }

                            // Check if no such wallet found in presence list
                            if (listEntry == null)
                            {
                                // request for additional data
                                using (MemoryStream mw = new MemoryStream())
                                {
                                    using (BinaryWriter writer = new BinaryWriter(mw))
                                    {
                                        writer.Write(wallet.Length);
                                        writer.Write(wallet);

                                        if (endpoint != null && endpoint.isConnected())
                                        {
                                            endpoint.sendData(ProtocolMessageCode.getPresence, mw.ToArray(), wallet);
                                        }
                                        else
                                        {
                                            CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'R', 'H' }, ProtocolMessageCode.getPresence, mw.ToArray(), 0, null);
                                        }
                                    }
                                }
                                return(false);
                            }

                            // Verify the signature
                            if (CryptoManager.lib.verifySignature(bytes.Take(bytes.Length - sigLen - 4).ToArray(), listEntry.pubkey, signature) == false)
                            {
                                Logging.warn(string.Format("[PL] KEEPALIVE tampering for {0} {1}, incorrect Sig.", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), hostname));
                                return(false);
                            }

                            PresenceAddress pa = listEntry.addresses.Find(x => x.address == hostname && x.device == deviceid);

                            if (pa != null)
                            {
                                // Check the node type
                                if (pa.lastSeenTime != timestamp)
                                {
                                    // Check for outdated timestamp
                                    if (timestamp < pa.lastSeenTime)
                                    {
                                        // We already have a newer timestamp for this entry
                                        return(false);
                                    }

                                    int expiration_time = CoreConfig.serverPresenceExpiration;

                                    if (pa.type == 'C')
                                    {
                                        expiration_time = CoreConfig.clientPresenceExpiration;
                                    }

                                    // Check for tampering. Includes a +300, -30 second synchronization zone
                                    if ((currentTime - timestamp) > expiration_time)
                                    {
                                        Logging.warn(string.Format("[PL] Received expired KEEPALIVE for {0} {1}. Timestamp {2}", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), pa.address, timestamp));
                                        return(false);
                                    }

                                    if ((currentTime - timestamp) < -30)
                                    {
                                        Logging.warn(string.Format("[PL] Potential KEEPALIVE tampering for {0} {1}. Timestamp {2}", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), pa.address, timestamp));
                                        return(false);
                                    }

                                    // Update the timestamp
                                    pa.lastSeenTime = timestamp;
                                    pa.signature    = signature;
                                    pa.version      = keepAliveVersion;
                                    if (pa.type != node_type)
                                    {
                                        lock (presenceCount)
                                        {
                                            presenceCount[pa.type]--;
                                            if (!presenceCount.ContainsKey(node_type))
                                            {
                                                presenceCount.Add(node_type, 0);
                                            }
                                            presenceCount[node_type]++;
                                        }
                                    }
                                    pa.type = node_type;

                                    //Console.WriteLine("[PL] LASTSEEN for {0} - {1} set to {2}", hostname, deviceid, pa.lastSeenTime);
                                    return(true);
                                }
                            }
                            else
                            {
                                if (wallet.SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress()))
                                {
                                    curNodePresence.addresses.Clear();
                                    curNodePresence.addresses.Add(curNodePresenceAddress);
                                    updateEntry(curNodePresence);
                                    return(true);
                                }
                                else
                                {
                                    using (MemoryStream mw = new MemoryStream())
                                    {
                                        using (BinaryWriter writer = new BinaryWriter(mw))
                                        {
                                            writer.Write(wallet.Length);
                                            writer.Write(wallet);

                                            if (endpoint != null && endpoint.isConnected())
                                            {
                                                endpoint.sendData(ProtocolMessageCode.getPresence, mw.ToArray(), wallet);
                                            }
                                            else
                                            {
                                                CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'R', 'H' }, ProtocolMessageCode.getPresence, mw.ToArray(), 0, null);
                                            }
                                        }
                                    }
                                    return(false);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.error("Exception occured in receiveKeepAlive: " + e);
                return(false);
            }

            return(false);
        }
Exemple #5
0
        public static bool removeAddressEntry(byte[] wallet_address, PresenceAddress address = null)
        {
            lock (presences)
            {
                //Console.WriteLine("[PL] Received removal for {0} : {1}", wallet_address, address.address);
                Presence listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet_address));

                // Check if there is such an entry in the presence list
                if (listEntry != null)
                {
                    lock (listEntry)
                    {
                        List <PresenceAddress> addresses_to_remove = null;

                        if (address != null)
                        {
                            addresses_to_remove = listEntry.addresses.FindAll(x => x == address);
                        }
                        else
                        {
                            addresses_to_remove = new List <PresenceAddress>(listEntry.addresses);
                        }

                        foreach (var addr in addresses_to_remove)
                        {
                            lock (presenceCount)
                            {
                                if (presenceCount.ContainsKey(addr.type))
                                {
                                    presenceCount[addr.type]--;
                                }
                            }
                            listEntry.addresses.Remove(addr);
                        }

                        int address_count = listEntry.addresses.Count;
                        //Console.WriteLine("[PL] --->> Addresses: {0}", address_count);

                        if (address_count == 0)
                        {
                            // Remove it from the list
                            presences.Remove(listEntry);
                        }

                        // If presence address is a relay node, remove all other presences with matching ip:port
                        // TODO: find a better way to handle this while preventing modify-during-enumeration issues
                        if (address != null && address.type == 'R')
                        {
                            // Retrieve the ip+port of the relay address
                            string relay_address = address.address;

                            // Store a copy of the presence list to allow safe modifications while enumerating
                            List <Presence> safe_presences = new List <Presence>(presences);

                            // Go through the entire presence list
                            foreach (Presence pr in safe_presences)
                            {
                                // Store a list of presence addresses that correspond to the relay node we're removing
                                List <PresenceAddress> relayClients = new List <PresenceAddress>();

                                foreach (PresenceAddress pa in pr.addresses)
                                {
                                    if (pa.address.SequenceEqual(relay_address))
                                    {
                                        // Check if it's a client node
                                        if (pa.type == 'C')
                                        {
                                            relayClients.Add(pa);
                                        }
                                    }
                                }

                                // Check if the presence contains at least one relay client
                                if (relayClients.Count > 0)
                                {
                                    // Go through each relay client and safely remove it's address entry
                                    // Note that it also propagates network messages
                                    foreach (PresenceAddress par in relayClients)
                                    {
                                        removeAddressEntry(pr.wallet, par);
                                    }

                                    relayClients.Clear();
                                }
                            }

                            // Clear the safe list of presences
                            safe_presences.Clear();
                        }

                        return(true);
                    }
                }
            }

            return(false);
        }