예제 #1
0
        private void OnTimeout(object state)
        {
            lock (context)
            {
                if (timer_height != context.BlockIndex || timer_view != context.ViewNumber)
                {
                    return;
                }
                Log($"timeout: height={timer_height} view={timer_view} state={context.State}");
                if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent))
                {
                    Log($"send prepare request: height={timer_height} view={timer_view}");
                    context.State |= ConsensusState.RequestSent;
                    if (!context.State.HasFlag(ConsensusState.SignatureSent))
                    {
                        context.Timestamp = Math.Max(DateTime.Now.ToTimestamp(), Blockchain.Default.GetHeader(context.PrevHash).Timestamp + 1);
                        context.Nonce     = GetNonce();
                        List <Transaction> transactions = LocalNode.GetMemoryPool().Where(p => CheckPolicy(p)).ToList();

                        Dictionary <UInt160, Transaction> scriptHashDictionary = new Dictionary <UInt160, Transaction>();
                        Console.WriteLine("Mempool count " + transactions.Count.ToString());
                        for (int i = 0; i < transactions.Count; i++)
                        {
                            if (transactions[i].Type == TransactionType.MinerTransaction ||
                                transactions[i].Type == TransactionType.AnonymousContractTransaction ||
                                transactions[i].Type == TransactionType.RingConfidentialTransaction)
                            {
                                continue;
                            }
                            if (transactions[i].Inputs == null || transactions[i].Inputs.Length == 0)
                            {
                                continue;
                            }

                            if (transactions[i].References == null)
                            {
                                transactions.RemoveAt(i);
                                i--;
                                continue;
                            }


                            if (transactions[i].Inputs.Length > 0 &&
                                transactions[i].References.ContainsKey(transactions[i].Inputs[0]) &&
                                LocalNode.KnownHashes.Count > 0)
                            {
                                UInt160 scripthash = transactions[i].References[transactions[i].Inputs[0]].ScriptHash;

                                if (scriptHashDictionary.ContainsKey(scripthash))
                                {
                                    Transaction prevTx = scriptHashDictionary[scripthash];
                                    if (LocalNode.KnownHashes.IndexOf(prevTx.Hash) > LocalNode.KnownHashes.IndexOf(transactions[i].Hash))
                                    {
                                        scriptHashDictionary[scripthash] = transactions[i];
                                        transactions.Remove(prevTx);
                                    }
                                    else
                                    {
                                        transactions.RemoveAt(i);
                                    }

                                    i--;
                                }
                                else
                                {
                                    scriptHashDictionary.Add(scripthash, transactions[i]);
                                }
                            }
                        }


                        Transaction[]      tmpool = LocalNode.GetMemoryPool().ToArray();
                        List <Transaction> consensus_transactions = new List <Transaction>();

                        for (int i = 0; i < transactions.Count; i++)
                        {
                            Transaction tx = transactions[i];
                            if (!tx.Verify(tmpool))
                            {
                                Console.Write("Transaction verify failed : ");

                                transactions.RemoveAt(i);
                                LocalNode.RemoveTxFromMempool(tx.Hash);
                                i--;

                                Console.WriteLine(tx.ToJsonString());
                                continue;
                            }

                            UInt160 fromScriptHash = LocalNode.GetFromAddressFromTx(tx); Console.WriteLine("Step_1_2");

                            if (Blockchain.IsConsensusAddress(fromScriptHash))
                            {
                                consensus_transactions.Add(tx);
                                continue;
                            }
                            else if (tx.GetFee() == Fixed8.Zero && fromScriptHash != UInt160.Zero)
                            {
                                if (LocalNode.freetx_pool.ContainsKey(fromScriptHash) &&
                                    LocalNode.freetx_pool[fromScriptHash].Count >= Blockchain.Default.FreeTransactionLimitPerPeriod &&
                                    Blockchain.Default.Height - LocalNode.freetx_pool[fromScriptHash].ElementAt(LocalNode.freetx_pool[fromScriptHash].Count - 1) < Blockchain.Default.FreeTransactionBlockPeriodNum)
                                {
                                    UInt256 removalHash = transactions[i].Hash;

                                    Console.WriteLine("TX removed " + removalHash);

                                    LocalNode.RemoveTxFromMempool(removalHash);

                                    transactions.RemoveAt(i);
                                    i--;
                                }
                                else
                                {
                                    localNode.AddFreeTxAddressToPool(fromScriptHash);

                                    foreach (RemoteNode node in LocalNode.Default.GetRemoteNodes()) // enqueue message
                                    {
                                        node.EnqueueMessage("blockfree", fromScriptHash);
                                    }
                                }
                            }
                        }

                        if (transactions.Count >= MaxTransactionsPerBlock)
                        {
                            transactions = consensus_transactions.Concat(transactions.OrderByDescending(p => p.NetworkFee / p.Size).Take(MaxTransactionsPerBlock - 1 - consensus_transactions.Count).ToList()).ToList();
                        }

                        transactions.Insert(0, CreateMinerTransaction(transactions, context.BlockIndex, context.Nonce));
                        context.TransactionHashes           = transactions.Select(p => p.Hash).ToArray();
                        context.Transactions                = transactions.ToDictionary(p => p.Hash);
                        context.CurrentConsensus            = wallet.GetChangeAddress();
                        context.NextConsensus               = Blockchain.GetConsensusAddress(Blockchain.Default.GetValidators(transactions).ToArray());
                        context.Signatures[context.MyIndex] = context.MakeHeader().Sign((KeyPair)wallet.GetKey(context.Validators[context.MyIndex]));
                    }
                    SignAndRelay(context.MakePrepareRequest());
                    timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (timer_view + 1)), Timeout.InfiniteTimeSpan);
                }
                else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup))
                {
                    RequestChangeView();
                }
            }
        }