private void RegisterLoginForm_Shown(object sender, EventArgs e)
        {
            Task.Run(() => CommonHelpers.GetTime());
            Task.Run(() =>
            {
                try
                {
                    if (!System.IO.File.Exists("Community.CsharpSqlite.dll") ||
                        !System.IO.File.Exists("Community.CsharpSqlite.SQLiteClient.dll") ||
                        !System.IO.File.Exists("NetworkCommsDotNetComplete.dll") ||
                        !System.IO.File.Exists("Virgil.Crypto.dll") ||
                        !System.IO.File.Exists("MaterialSkin.dll"))
                    {
                        throw new Exception();
                    }

                    CryptoHelper.GenerateKeyPair();
                }
                catch
                {
                    this.Invoke(new Action(() =>
                    {
                        MessageBox.Show(Properties.Resources.libsError, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        Close();
                    }
                                           ));
                }
            });
        }
        private void CheckDeleteOldPendingItems(object sender, ElapsedEventArgs e)
        {
            var pendingBlocksCopy = new Dictionary <Block, DateTime>(pendingBlocks);

            foreach (var item in pendingBlocksCopy)
            {
                //если ожидающий блок старее 10 минут - проверяем, затем удаляем его
                if ((CommonHelpers.GetTime() - item.Value) > TimeSpan.FromMilliseconds(CommonHelpers.PeersCheckInterval * 10))
                {
                    CheckBlock(GetLastBlockFromPending(item.Key));
                    pendingBlocks.Remove(item.Key);
                    //отмечаем ожидающие транзакции из базы как свободные
                    db.MarkAsFreePendingTransactions(false, item.Key.Transactions);
                }
            }


            var pendingTransactionsCopy = new Dictionary <Transaction, DateTime>(pendingTransactions);

            foreach (var item in pendingTransactionsCopy)
            {
                //если ожидающая транзакция старее 10 минут - проверяем, затем удаляем ее
                if ((CommonHelpers.GetTime() - item.Value) > TimeSpan.FromMilliseconds(CommonHelpers.PeersCheckInterval * 10))
                {
                    CheckTransaction(item.Key);
                    pendingTransactions.Remove(item.Key);
                }
            }
        }
        public static Transaction VoteTransaction(string candidateHash, string votingHash, int votingNumber)
        {
            var tr = new Transaction();

            tr.Type         = TransactionType.Vote;
            tr.Date0        = CommonHelpers.GetTime();
            tr.SenderHash   = VotingsUser.PublicKey;
            tr.RecieverHash = candidateHash;
            tr.VotingNumber = votingNumber;

            tr.PreviousHash = votingHash;

            tr.Hash      = tr.CalcHash();
            tr.Signature = tr.CalcSignature();

            return(tr);
        }
        public static Transaction BanUserTransaction(string cause, string publicHash, string previousHash)
        {
            var tr = new Transaction();

            tr.Type         = TransactionType.BanUser;
            tr.Date0        = CommonHelpers.GetTime();
            tr.SenderHash   = VotingsUser.PublicKey;
            tr.RecieverHash = publicHash;
            tr.PreviousHash = previousHash;

            JObject info = new JObject();

            info["cause"] = cause;
            tr.Info       = info.ToString();

            tr.Hash      = tr.CalcHash();
            tr.Signature = tr.CalcSignature();

            return(tr);
        }
Example #5
0
        public Block(List <Transaction> transactions, Block previousBlock)
        {
            Date0        = CommonHelpers.GetTime();
            PreviousHash = previousBlock.Hash;
            Number       = previousBlock.Number + 1;
            CreatorHash  = VotingsUser.PublicKey;


            List <string> transactionsHashes = new List <string>();

            foreach (var tr in transactions)
            {
                transactionsHashes.Add(tr.Hash);
            }

            Transactions = transactionsHashes;

            Hash      = CalcHash();
            Signature = CalcSignature();
        }
        public static Transaction StartVotingTransation(List <string> candidatesHashes, string nameOfVoting, int votingNumber, string previousVotingHash)
        {
            var tr = new Transaction();

            tr.Type         = TransactionType.StartVoting;
            tr.Date0        = CommonHelpers.GetTime();
            tr.SenderHash   = VotingsUser.PublicKey;
            tr.VotingNumber = votingNumber;

            JObject info       = new JObject();
            JArray  candidates = new JArray(candidatesHashes.ToArray());

            info["candidates"] = candidates;
            info["name"]       = nameOfVoting;
            tr.Info            = info.ToString();

            tr.PreviousHash = previousVotingHash;

            tr.Hash      = tr.CalcHash();
            tr.Signature = tr.CalcSignature();

            return(tr);
        }
        bool CheckStartVotingTransaction(Transaction transaction)
        {
            //проверка хеша и подписи
            if (!(transaction.CheckHash() && transaction.CheckSignature()))
            {
                return(false);
            }

            var prevVoting = db.GetTransaction(transaction.PreviousHash);

            //проверка номера голосования
            if (transaction.VotingNumber != (prevVoting.VotingNumber + 1))
            {
                return(false);
            }

            //проверка даты транзакции
            if (!(transaction.Date0 >= prevVoting.Date0 && transaction.Date0 <= CommonHelpers.GetTime()))
            {
                return(false);
            }

            //проверка, что транзакцию создал корневой клиент
            if (transaction.SenderHash != VotingsUser.RootPublicKey)
            {
                return(false);
            }


            var existsVoting = db.GetVoting(transaction.VotingNumber);

            //проверка существования копий транзакции
            if (existsVoting != null)
            {
                //если копия уже в блоке то выход
                if (existsVoting.Status == TransactionStatus.InBlock)
                {
                    return(false);
                }
                //если копия транзакции старее и при этом свободна, то выход
                else if (existsVoting.Date0 <= transaction.Date0 && existsVoting.Status == TransactionStatus.Free)
                {
                    return(false);
                }
                //иначе удаляем существующую транзакцию из базы
                else
                {
                    db.DeleteTransaction(existsVoting);
                    NewTransaction?.Invoke(this, new IntEventArgs(db.TransactionsCount()));
                }
            }


            try
            {
                var info = JObject.Parse(transaction.Info);
                if (!(info["name"].Value <string>() != ""))
                {
                    return(false);
                }

                if (info["candidates"].Count() == 0)
                {
                    return(false);
                }

                foreach (JToken item in info["candidates"])
                {
                    if (item.Value <string>() == "")
                    {
                        return(false);
                    }
                }
            }
            catch
            {
                return(false);
            }

            return(true);
        }
        bool CheckBanUserTransaction(Transaction transaction)
        {
            //проверка хеша и подписи
            if (!(transaction.CheckHash() && transaction.CheckSignature()))
            {
                return(false);
            }

            //проверка даты транзакции
            if (!(transaction.Date0 >= VotingsUser.RootUserDate && transaction.Date0 <= CommonHelpers.GetTime()))
            {
                return(false);
            }

            //проверка, что транзакцию создал корневой клиент
            if (transaction.SenderHash != VotingsUser.RootPublicKey)
            {
                return(false);
            }


            var recieverCreation = db.GetUserCreation(transaction.RecieverHash);

            //проверка на существование пользователя на заданную дату
            if (recieverCreation.Date0 > transaction.Date0)
            {
                return(false);
            }



            var prevTransaction = db.GetTransaction(transaction.PreviousHash);

            //предыдущая транзакция и транзакция создания пользователя - одно и то же
            if (prevTransaction.Hash != recieverCreation.Hash)
            {
                return(false);
            }
            //проверка чтобы предыдущая транзакция не была новее
            if (transaction.Date0 < prevTransaction.Date0)
            {
                return(false);
            }


            var existsBan = db.GetUserBan(transaction.RecieverHash);

            //проверка существования копий транзакции
            if (existsBan != null)
            {
                //если копия уже в блоке то выход
                if (existsBan.Status == TransactionStatus.InBlock)
                {
                    return(false);
                }
                //если копия транзакции старее и при этом свободна, то выход
                else if (existsBan.Date0 <= transaction.Date0 && existsBan.Status == TransactionStatus.Free)
                {
                    return(false);
                }
                //иначе удаляем существующую транзакцию из базы
                else
                {
                    db.DeleteTransaction(existsBan);
                    NewTransaction?.Invoke(this, new IntEventArgs(db.TransactionsCount()));
                }
            }



            try
            {
                var info = JObject.Parse(transaction.Info);
                if (!(info["cause"].Value <string>() != ""))
                {
                    return(false);
                }
            }
            catch
            {
                return(false);
            }

            return(true);
        }
        bool CheckVoteTransaction(Transaction transaction)
        {
            var voting = db.GetTransaction(transaction.PreviousHash);

            //проверка хеша и подписи
            if (!(transaction.CheckHash() && transaction.CheckSignature()))
            {
                return(false);
            }

            //проверка даты транзакции
            if (!(transaction.Date0 >= voting.Date0 && transaction.Date0 <= CommonHelpers.GetTime()))
            {
                return(false);
            }

            var senderCreation = db.GetUserCreation(transaction.SenderHash);
            var senderBan      = db.GetUserBan(transaction.SenderHash);

            ////проверка создателя транзакции
            //if (senderCreation == null) return false;
            //проверка даты создателя транзакции
            if (!(senderCreation.Date0 <= voting.Date0 &&
                  (senderBan == null || senderBan.Date0 > voting.Date0)))
            {
                return(false);
            }

            var recieverCreation = db.GetUserCreation(transaction.RecieverHash);
            var recieverBan      = db.GetUserBan(transaction.RecieverHash);

            ////проверка получателя транзакции
            //if (recieverCreation == null) return false;
            //проверка даты получателя транзакции
            if (!(recieverCreation.Date0 <= voting.Date0 &&
                  (recieverBan == null || recieverBan.Date0 > voting.Date0)))
            {
                return(false);
            }

            var existsVote = db.GetUserVote(transaction.SenderHash, transaction.VotingNumber);

            //проверка существования копий транзакции
            if (existsVote != null)
            {
                //если копия уже в блоке то выход
                if (existsVote.Status == TransactionStatus.InBlock)
                {
                    return(false);
                }
                //если копия транзакции старее и при этом свободна, то выход
                else if (existsVote.Date0 <= transaction.Date0 && existsVote.Status == TransactionStatus.Free)
                {
                    return(false);
                }
                //иначе удаляем существующую транзакцию из базы
                else
                {
                    db.DeleteTransaction(existsVote);
                    NewTransaction?.Invoke(this, new IntEventArgs(db.TransactionsCount()));
                }
            }

            return(true);
        }
        private bool CheckTransaction(Transaction transaction, EndPoint peerAddress = null)
        {
            if (db.GetTransaction(transaction.Hash) != null)
            {
                return(false);
            }

            bool needWait = false;


            //проверка существования транзакции создания пользователя
            //если ее нет, то транзакция создания и бана пользователя запрашиваются
            if (db.GetUserCreation(transaction.SenderHash) == null)
            {
                //если ее нет и в ожидающих - запрашиваем от пиров
                if (!pendingTransactions.Keys.Any(tr => tr.RecieverHash == transaction.PreviousHash))
                {
                    RequestTransaction(transaction.SenderHash, peerAddress);
                }
                needWait = true;
            }

            //проверяем получателя транзакции только для транзакций бана и посылки голоса
            if ((transaction.Type == TransactionType.BanUser || transaction.Type == TransactionType.Vote) &&
                (db.GetUserCreation(transaction.RecieverHash) == null))
            {
                if (!pendingTransactions.Keys.Any(tr => tr.RecieverHash == transaction.RecieverHash))
                {
                    RequestTransaction(transaction.RecieverHash, peerAddress);
                }
                needWait = true;
            }

            //проверка существования предыдущей транзакции
            if (db.GetTransaction(transaction.PreviousHash) == null)
            {
                if (!pendingTransactions.Keys.Any(tr => tr.Hash == transaction.PreviousHash))
                {
                    RequestTransaction(transaction.PreviousHash, peerAddress);
                }
                needWait = true;
            }


            //если транзакция не в списке ожидающих и запросили инфу, то отправляем ее в список ожидающих
            if (needWait == true)
            {
                if (!pendingTransactions.ContainsKey(transaction))
                {
                    pendingTransactions.Add(transaction, CommonHelpers.GetTime());
                }
                return(false);
            }


            ////проверка транзакции

            //удаляем из ожидающих
            pendingTransactions.Remove(transaction);

            var checkPassed = true;

            switch (transaction.Type)
            {
            case TransactionType.CreateUser:
                checkPassed = CheckCreateUserTransaction(transaction); break;

            case TransactionType.BanUser:
                checkPassed = CheckBanUserTransaction(transaction); break;

            case TransactionType.Vote:
                checkPassed = CheckVoteTransaction(transaction); break;

            case TransactionType.StartVoting:
                checkPassed = CheckStartVotingTransaction(transaction); break;

            default:
                checkPassed = false; break;
            }


            ////если транзакция проверена успешно
            if (checkPassed)
            {
                //добавляем транзакцию в базу
                db.PutTransaction(transaction);

                NetworkComms.Logger.Warn("Added transaction " + transaction.Type.ToString() + " " + transaction.Hash);

                NewTransaction?.Invoke(this, new IntEventArgs(db.TransactionsCount()));

                //если добавили новую транзакцию голосования, то вызываем событие
                if (transaction.Type == TransactionType.StartVoting)
                {
                    NewVoting?.Invoke(this, new IntEventArgs(transaction.VotingNumber));
                }
                else if (transaction.Type == TransactionType.CreateUser)
                {
                    NewUser?.Invoke(this, new IntEventArgs(db.UsersCount()));
                }

                //проверяем нужно ли создавать новый блок
                MakeBlock();

                //ищем в ожидающих транзакции связанные с этой и проверяем их
                var pending = pendingTransactions.Keys.Where(tr =>
                {
                    return(tr.PreviousHash == transaction.Hash ||
                           tr.SenderHash == transaction.RecieverHash ||
                           tr.RecieverHash == transaction.RecieverHash);
                }).ToList();
                foreach (var item in pending)
                {
                    CheckTransaction(item);
                }


                //ищем в ожидающих блоках связанные с этим и проверяем их
                var pending2 = pendingBlocks.Keys.Where(bl =>
                {
                    return(bl.TransactionsBlob.Contains(transaction.Hash) ||
                           bl.CreatorHash == transaction.RecieverHash);
                }).ToList();
                foreach (var item in pending2)
                {
                    CheckBlock(item);
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
        private bool CheckBlock(Block block, EndPoint peerAddress = null)
        {
            if (db.GetBlock(block.Hash) != null)
            {
                return(false);
            }

            var prevBlock = db.GetBlock(block.PreviousHash);
            var creator   = db.GetUserCreation(block.CreatorHash);

            bool needWait = false;


            //проверка существования предыдущего блока
            if (prevBlock == null)
            {
                //если ее нет и в ожидающих - запрашиваем от пиров
                if (!pendingBlocks.Keys.Any(bl => bl.Hash == block.PreviousHash))
                {
                    RequestBlock(block.PreviousHash, peerAddress);
                }
                needWait = true;
            }


            //проверка существования создателя блока
            if (creator == null)
            {
                if (!pendingTransactions.Keys.Any(tr => tr.RecieverHash == block.CreatorHash))
                {
                    RequestTransaction(block.CreatorHash, peerAddress);
                }
                needWait = true;
            }

            if (block.Transactions == null)
            {
                return(false);
            }

            //проверка существования транзакций
            foreach (var itemHash in block.Transactions)
            {
                if (db.GetTransaction(itemHash) == null)
                {
                    if (!pendingTransactions.Keys.Any(tr => tr.Hash == itemHash))
                    {
                        RequestTransaction(itemHash, peerAddress);
                    }
                    needWait = true;
                }
            }


            //если блок не в списке ожидающих и запросили инфу, то отправляем ее в список ожидающих
            if (needWait == true)
            {
                if (!pendingBlocks.ContainsKey(block))
                {
                    pendingBlocks.Add(block, CommonHelpers.GetTime());
                }
                return(false);
            }


            ////если все данные есть, начинаем проверку блока

            //удаляем его из ожидающих
            pendingBlocks.Remove(block);


            //проверка хеша и подписи
            if (!(block.CheckHash() && block.CheckSignature()))
            {
                return(false);
            }


            //проверка даты
            if (!(block.Date0 >= prevBlock.Date0 && block.Date0 <= CommonHelpers.GetTime()))
            {
                return(false);
            }


            //проверка создателя блока
            //var senderCreation = db.GetUserCreation(block.CreatorHash);
            var senderBan = db.GetUserBan(block.CreatorHash);

            if (!(creator.Date0 <= block.Date0 &&
                  (senderBan == null || senderBan.Date0 > block.Date0)))
            {
                return(false);
            }



            //сравнение длины цепочки этого блока с длиной цепочки в базе
            var blockCopyInDB = db.GetBlock(block.Number);

            if (blockCopyInDB != null)
            {
                var lastBlockInChain = GetLastBlockFromPending(block);
                var lastBlockInDB    = db.GetLastBlock();

                //если цепочка нового блока длиннее или цепочки равны, но дата нового блока раньше
                if ((lastBlockInChain.Number > lastBlockInDB.Number) ||
                    (lastBlockInChain.Number == lastBlockInDB.Number && block.Date0 < blockCopyInDB.Date0))
                {
                    //удаляем из базы все блоки начиная с этого
                    for (int i = blockCopyInDB.Number; i <= lastBlockInDB.Number; i++)
                    {
                        var blockToRemove = db.GetBlock(i);
                        db.DeleteBlock(blockToRemove);

                        //СПОРНЫЙ МОМЕНТ
                        //отмечаем транзакции из блока как свободные
                        db.MarkAsFreePendingTransactions(true, blockToRemove.Transactions);
                    }

                    //добавляем блок обратно в ожидающие
                    pendingBlocks.Add(block, CommonHelpers.GetTime());
                    //запускаем проверку последнего ожидающего блока из цепочки (он снова загрузит нужные транзакции)
                    CheckBlock(lastBlockInChain);
                }
                else
                {
                    //СПОРНЫЙ МОМЕНТ
                    //если не приняли новый блок, то освобождаем полученные для него транзакции
                    db.MarkAsFreePendingTransactions(false, block.Transactions);
                }


                NewTransaction?.Invoke(this, new IntEventArgs(db.TransactionsCount()));
                NewBlock?.Invoke(this, new IntEventArgs(db.BlocksCount()));

                return(false);
            }


            //проверка транзакций
            foreach (var itemHash in block.Transactions)
            {
                var tr = db.GetTransaction(itemHash);
                if (tr.Status == TransactionStatus.InBlock || tr.Date0 > block.Date0)
                {
                    return(false);
                }
            }



            ////если все хорошо, добавляем блок в базу
            db.PutBlock(block);

            NetworkComms.Logger.Warn("Added block " + block.Hash);

            NewBlock?.Invoke(this, new IntEventArgs(db.BlocksCount()));

            //помечаем транзакции, что они в блоке
            foreach (var itemHash in block.Transactions)
            {
                var tr = db.GetTransaction(itemHash);
                db.MarkTransaction(tr, TransactionStatus.InBlock);
            }

            //ищем в ожидающих блоках связанные с этим и проверяем их
            var pending = pendingBlocks.Keys.Where(bl => bl.PreviousHash == block.Hash).ToList();

            foreach (var item in pending)
            {
                CheckBlock(item);
            }


            return(true);
        }