private void HandleBlock(CommandMessage message)
        {
            var block = new Block().DeSerialize(message.Data);

            logger.Debug("Recieved new block from: " + message.Client.ToString());
            chain.AddBlock(block);
            logger.Debug("block added ID:" + Convert.ToBase64String(block.Hash) + "index: " + block.Index);
            BlockOnTheFly.Remove(HexadecimalEncoding.ToHexString(block.Hash));

            //--progress bar
            if (highestIndex < block.Index)
            {
                highestIndex = block.Index;                                                                                  //check best index
            }
            NewBlockArrived?.Invoke(this, new ProgressBarEventArgs(highestIndex, blocksInTransit.Count, reducedBlockCount)); //invoke this, mainly for progress bar now.
            //--progress bar end

            if (blocksInTransit.Count > 0)
            {
                var blockHash = blocksInTransit[0];
                SendGetData(message.Client.ToString(), "block", blockHash);
                BlockOnTheFly.Add(HexadecimalEncoding.ToHexString(blockHash));
                blocksInTransit.RemoveAt(0);
            }
            else
            {
                if (BlockOnTheFly.Count != 0)
                {
                    return;
                }
                reindexing = true;
                chain.ReindexUTXO();                                 // asynch
                WholeChainDownloaded?.Invoke(this, EventArgs.Empty); // invoke this after all is downloaded, cause downloading from lastest to oldest, could cause problems after displaying after each block
                isBusy     = false;
                reindexing = false;
                ProcessNextMessage();
            }
        }
        private void MineTransactions()
        {
            miningInProgress = true;
            logger.Debug("Mining started");
            var startTime = DateTime.Now;

            var txList     = new List <Transaction>();
            var coinBaseTx = Transaction.CoinBaseTx(_loggedUser.Address, ""); //add later

            coinBaseTx.Inputs[0].MagicValue = chain.GetBestHeight() + 1;
            coinBaseTx.MagicVK = chain.GetBestHeight() + 1;
            coinBaseTx.Id      = coinBaseTx.CalculateHash();

            txList.Add(coinBaseTx);
            //fill txList from TransactionPool
            foreach (var txPair in TransactionPool)
            {
                var tx = txPair.Value;
                if (chain.VerifyTransaction(tx))
                {
                    txList.Add(tx);
                }
            }

            if (txList.Count == 0)
            {
                logger.Debug("All txs invalid");
                miningInProgress = false;
                return;
            }


            chain.HashDiscovered += HashDiscovered;
            NotifyGUIisMining(true);
            var newBlock = chain.MineBlock(txList);

            if (newBlock != null)
            {
                //skew for synch
                if (handlingNewBlock || (DateTime.Now - timeSkewBetweenHandlingBlock).Milliseconds < 200)
                {
                    // mined same time as block came
                    logger.Debug($"!New block mined, mining duration: {DateTime.Now - startTime} But discard it, cause handling newRemoteBlock");
                    miningInProgress = false;
                    return;
                }
                NotifyGUIisMining(false);
                handlingNewBlock = true;
                logger.Debug($"New block mined, mining duration: {DateTime.Now - startTime}");
                chain.AddBlock(newBlock);
                //30.4
                var utxoSet = new UTXOSet(chain);
                utxoSet.Update(newBlock);
                //


                //7.4.19
                if (InMemoryBlockChains.Count > 0)
                {
                    logger.Debug("Find best chain");
                    InMemoryBlockChain bestChain = null;
                    var count     = 1;
                    var bestIndex = chain.GetBestHeight();

                    foreach (var chain in InMemoryBlockChains)
                    {
                        var currentIndex = chain.GetLastIndex();

                        if (currentIndex > bestIndex)
                        {
                            bestIndex = currentIndex;
                            count     = 1;
                            bestChain = chain;
                        }
                        else if (currentIndex == bestIndex)
                        {
                            count++;
                        }
                    }
                    if (count == 1)
                    {
                        logger.Debug("Best chain found");
                        BreakMining();//redundant

                        if (bestChain != null)
                        {
                            logger.Debug("Best chain found in subchains, restructualize chain");
                            //if not restruct to new one
                            chain.RestructualizeSubchain(bestChain);
                            InMemoryBlockChains.Clear(); //clear InMemoryChains
                        }
                        else
                        {
                            //if bestChain is null, chain stays local
                            logger.Debug("Best chain found in localchain, do nothing");
                        }
                    }
                    else
                    {
                        logger.Debug("Best chain not found");
                    }
                }

                handlingNewBlock = false;
                if (IncomingMinedNewBlocksMessages.Count > 0)
                {
                    ProcessMessage(IncomingMinedNewBlocksMessages.Dequeue());
                }
                //7.4.19

                //this means pow was broke
                chain.ReindexUTXO();

                chain.HashDiscovered -= HashDiscovered;
                WholeChainDownloaded?.Invoke(this, EventArgs.Empty);
                SendNewBlockMined(newBlock);
                //remove txs from Transaction pool

                RemoveTransactionsFromPool(txList);
            }
            else
            {
                logger.Debug("block added by remote client");
                //I delete txs from txpool in NewBlockMined
                //chain.ReindexUTXO();
            }

            miningInProgress = false;

            if (TransactionPool.Count > 0)
            {
                MineTransactions();
            }
        }
        private void HandleNewBlockMined(CommandMessage rxMsg)
        {
            try
            {
                handlingNewBlock = true;
                PauseMining(); //pause mining if mining

                Block minedBlock   = new Block().DeSerialize(rxMsg.Data);
                var   transactions = minedBlock.Transactions;
                logger.Debug("Recieved block, somebody mined: " + Convert.ToBase64String(minedBlock.Hash));

                var isValid = IsPreviousHashValid(minedBlock.PreviousHash);

                if (!isValid)
                {
                    logger.Debug("Previous hash invalid, try add to fork subchain");
                    if (!VerifyTransactions(transactions))
                    {
                        logger.Debug("Transactions  not valid");
                        ResumeMining();
                        handlingNewBlock = false;
                        return;
                    }

                    //try to add to fork chains
                    var added = false;
                    foreach (var memChain in InMemoryBlockChains)
                    {
                        if (memChain.BelongsToThisChain(minedBlock))
                        {
                            added = memChain.AddBlock(minedBlock);
                            RemoveTransactionsFromPool(minedBlock.Transactions);
                            logger.Debug("Added to subchain");
                        }
                    }

                    if (!added)
                    {
                        var newForkChain = new InMemoryBlockChain();
                        newForkChain.AddBlock(minedBlock);
                        InMemoryBlockChains.Add(newForkChain);
                        logger.Debug("Created new subchain");
                    }
                    PrintCurrentForkChains(InMemoryBlockChains);
                }
                else
                {
                    logger.Debug("Previous hash VALID, add to local chain");

                    if (!VerifyTransactions(transactions))
                    {
                        ResumeMining();
                        handlingNewBlock             = false;
                        timeSkewBetweenHandlingBlock = DateTime.Now;
                        return;
                    }

                    BreakMining();
                    RemoveTransactionsFromPool(minedBlock.Transactions); //remove new block transactions from pool
                    chain.AddBlock(minedBlock);
                    //30.4
                    var utxoSet = new UTXOSet(chain);
                    utxoSet.Update(minedBlock);
                    //
                }

                if (InMemoryBlockChains.Count > 0)
                {
                    logger.Debug("Find best chain");
                    InMemoryBlockChain bestChain = null;
                    var count     = 1;
                    var bestIndex = chain.GetBestHeight();     //local blockchain

                    foreach (var chain in InMemoryBlockChains) //subchains
                    {
                        var currentIndex = chain.GetLastIndex();

                        if (currentIndex > bestIndex)
                        {
                            bestIndex = currentIndex;
                            count     = 1;
                            bestChain = chain;
                        }
                        else if (currentIndex == bestIndex)
                        {
                            count++;
                        }
                    }
                    if (count == 1)
                    {
                        logger.Debug("Best chain found");
                        BreakMining();

                        if (bestChain != null)
                        {
                            logger.Debug("Best chain found in subchains, restructualize chain");
                            //if not restruct to new one
                            chain.RestructualizeSubchain(bestChain);
                            InMemoryBlockChains.Clear(); //clear InMemoryChains
                        }
                        else
                        {
                            //if bestChain is null, chain stays local
                            logger.Debug("Best chain found in localchain, do nothing");
                        }
                    }
                    else
                    {
                        logger.Debug("Best chain not found");
                    }
                }

                WholeChainDownloaded?.Invoke(this, EventArgs.Empty);
                chain.ReindexUTXO(); // asynch
                handlingNewBlock = false;
                if (IncomingMinedNewBlocksMessages.Count > 0)
                {
                    ProcessMessage(IncomingMinedNewBlocksMessages.Dequeue());
                }
            }
            catch (Exception e)
            {
                logger.Error(e.Message);
                logger.Error(e.StackTrace);
            }
        }