コード例 #1
0
        private void rollForward()
        {
            bool sleep = false;

            ulong lowestBlockNum = getLowestBlockNum();

            ulong syncToBlock = syncTargetBlockNum;

            if (Node.blockChain.Count > 5)
            {
                lock (pendingBlocks)
                {
                    pendingBlocks.RemoveAll(x => x.blockNum < Node.blockChain.getLastBlockNum() - 5);
                }
            }

            lock (pendingBlocks)
            {
                // Loop until we have no more pending blocks
                do
                {
                    handleWatchDog();

                    ulong next_to_apply = lowestBlockNum;
                    if (Node.blockChain.Count > 0)
                    {
                        next_to_apply = Node.blockChain.getLastBlockNum() + 1;
                    }

                    if (next_to_apply > syncToBlock)
                    {
                        // we have everything, clear pending blocks and break
                        pendingBlocks.Clear();
                        lock (requestedBlockTimes)
                        {
                            requestedBlockTimes.Clear();
                        }
                        break;
                    }
                    Block b = pendingBlocks.Find(x => x.blockNum == next_to_apply);
                    if (b == null)
                    {
                        lock (requestedBlockTimes)
                        {
                            if (requestBlockAgain(next_to_apply))
                            {
                                // the node isn't connected yet, wait a while
                                sleep = true;
                            }
                        }
                        break;
                    }
                    b = new Block(b);

                    if (b.version > Block.maxVersion)
                    {
                        Logging.error("Received block {0} with a version higher than this node can handle, discarding the block.", b.blockNum);
                        pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum);
                        Node.blockProcessor.networkUpgraded = true;
                        sleep = true;
                        break;
                    }
                    else
                    {
                        Node.blockProcessor.networkUpgraded = false;
                    }


                    if (next_to_apply > 5)
                    {
                        ulong targetBlock = next_to_apply - 5;

                        Block tb = pendingBlocks.Find(x => x.blockNum == targetBlock);
                        if (tb != null)
                        {
                            if (tb.blockChecksum.SequenceEqual(Node.blockChain.getBlock(tb.blockNum).blockChecksum) && Node.blockProcessor.verifyBlockBasic(tb) == BlockVerifyStatus.Valid)
                            {
                                if (Node.blockProcessor.verifyBlockSignatures(tb))
                                {
                                    Node.blockChain.refreshSignatures(tb, true);
                                }
                                else
                                {
                                    Logging.warn("Target block " + tb.blockNum + " does not have the required consensus.");
                                }
                            }
                            pendingBlocks.RemoveAll(x => x.blockNum == tb.blockNum);
                        }
                    }

                    try
                    {
                        Logging.info(String.Format("Sync: Applying block #{0}/{1}.",
                                                   b.blockNum, syncToBlock));

                        bool ignoreWalletState = true;

                        if (b.blockNum > wsSyncConfirmedBlockNum || Config.fullStorageDataVerification)
                        {
                            ignoreWalletState = false;
                        }

                        b.powField = null;

                        // wallet state is correct as of wsConfirmedBlockNumber, so before that we call
                        // verify with a parameter to ignore WS tests, but do all the others
                        BlockVerifyStatus b_status = BlockVerifyStatus.Valid;

                        if (b.fromLocalStorage)
                        {
                            bool missing = false;
                            foreach (string txid in b.transactions)
                            {
                                if (!running)
                                {
                                    break;
                                }

                                Transaction t = TransactionPool.getTransaction(txid, b.blockNum, true);
                                if (t != null)
                                {
                                    t.applied = 0;
                                    if (!TransactionPool.addTransaction(t, true, null, Config.fullStorageDataVerification))
                                    {
                                        Logging.error("Error adding a transaction {0} from storage", txid);
                                    }
                                }
                                else
                                {
                                    ProtocolMessage.broadcastGetTransaction(txid, b.blockNum);
                                    missing = true;
                                }
                            }
                            if (missing)
                            {
                                sleep = true;
                                break;
                            }
                        }

                        if (b.blockNum > wsSyncConfirmedBlockNum || b.fromLocalStorage == false || Config.fullStorageDataVerification)
                        {
                            b_status = Node.blockProcessor.verifyBlock(b, ignoreWalletState);
                        }
                        else
                        {
                            b_status = Node.blockProcessor.verifyBlockBasic(b, false);
                        }

                        if (b_status == BlockVerifyStatus.Indeterminate)
                        {
                            Logging.info(String.Format("Waiting for missing transactions from block #{0}...", b.blockNum));
                            Thread.Sleep(100);
                            return;
                        }
                        if (b_status != BlockVerifyStatus.Valid)
                        {
                            Logging.warn(String.Format("Block #{0} {1} is invalid. Discarding and requesting a new one.", b.blockNum, Crypto.hashToString(b.blockChecksum)));
                            pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum);
                            requestBlockAgain(b.blockNum);
                            return;
                        }

                        if (!Node.blockProcessor.verifyBlockSignatures(b) && Node.blockChain.Count > 16)
                        {
                            Logging.warn(String.Format("Block #{0} {1} doesn't have the required consensus. Discarding and requesting a new one.", b.blockNum, Crypto.hashToString(b.blockChecksum)));
                            pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum);
                            requestBlockAgain(b.blockNum);
                            return;
                        }

                        bool sigFreezeCheck = Node.blockProcessor.verifySignatureFreezeChecksum(b, null);

                        // Apply transactions when rolling forward from a recover file without a synced WS
                        if (b.blockNum > wsSyncConfirmedBlockNum)
                        {
                            if (Node.blockChain.Count <= 5 || sigFreezeCheck)
                            {
                                Node.blockProcessor.applyAcceptedBlock(b);

                                if (b.version >= BlockVer.v5 && b.lastSuperBlockChecksum == null)
                                {
                                    // skip WS checksum check
                                }
                                else
                                {
                                    byte[] wsChecksum = Node.walletState.calculateWalletStateChecksum();
                                    if (wsChecksum == null || !wsChecksum.SequenceEqual(b.walletStateChecksum))
                                    {
                                        Logging.error(String.Format("After applying block #{0}, walletStateChecksum is incorrect!. Block's WS: {1}, actual WS: {2}", b.blockNum, Crypto.hashToString(b.walletStateChecksum), Crypto.hashToString(wsChecksum)));
                                        handleWatchDog(true);
                                        return;
                                    }
                                }
                                if (b.blockNum % Config.saveWalletStateEveryBlock == 0)
                                {
                                    DLT.Meta.WalletStateStorage.saveWalletState(b.blockNum);
                                }
                            }
                        }
                        else
                        {
                            if (syncToBlock == b.blockNum)
                            {
                                if (b.version >= BlockVer.v5 && b.lastSuperBlockChecksum == null)
                                {
                                    // skip WS checksum check
                                }
                                else
                                {
                                    byte[] wsChecksum = Node.walletState.calculateWalletStateChecksum();
                                    if (wsChecksum == null || !wsChecksum.SequenceEqual(b.walletStateChecksum))
                                    {
                                        Logging.warn(String.Format("Block #{0} is last and has an invalid WSChecksum. Discarding and requesting a new one.", b.blockNum));
                                        pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum);
                                        requestBlockAgain(b.blockNum);
                                        handleWatchDog(true);
                                        return;
                                    }
                                }
                            }
                        }

                        if (Node.blockChain.Count <= 5 || sigFreezeCheck)
                        {
                            //Logging.info(String.Format("Appending block #{0} to blockChain.", b.blockNum));
                            if (b.blockNum <= wsSyncConfirmedBlockNum)
                            {
                                if (!TransactionPool.setAppliedFlagToTransactionsFromBlock(b))
                                {
                                    pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum);
                                    requestBlockAgain(b.blockNum);
                                    return;
                                }
                            }

                            if (b.blockNum > 12 && b.blockNum + 5 >= IxianHandler.getHighestKnownNetworkBlockHeight())
                            {
                                if (Node.isMasterNode())
                                {
                                    byte[][] signature_data = b.applySignature(); // applySignature() will return signature_data, if signature was applied and null, if signature was already present from before
                                    if (signature_data != null)
                                    {
                                        // ProtocolMessage.broadcastNewBlock(localNewBlock);
                                        ProtocolMessage.broadcastNewBlockSignature(b.blockNum, b.blockChecksum, signature_data[0], signature_data[1]);
                                    }
                                }
                            }

                            Node.blockChain.appendBlock(b, !b.fromLocalStorage);
                            resetWatchDog(b.blockNum);
                            if (missingBlocks != null)
                            {
                                missingBlocks.RemoveAll(x => x <= b.blockNum);
                            }
                        }
                        else if (Node.blockChain.Count > 5 && !sigFreezeCheck)
                        {
                            // invalid sigfreeze, waiting for the correct block
                            pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum);
                            return;
                        }
                    }
                    catch (Exception e)
                    {
                        Logging.error(String.Format("Exception occured while syncing block #{0}: {1}", b.blockNum, e));
                    }

                    pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum);
                } while (pendingBlocks.Count > 0 && running);
            }
            if (!sleep && Node.blockChain.getLastBlockNum() >= syncToBlock)
            {
                if (verifyLastBlock())
                {
                    resetWatchDog(0);
                    sleep = false;
                }
                else
                {
                    handleWatchDog(true);
                    sleep = true;
                }
            }

            if (sleep)
            {
                Thread.Sleep(500);
            }
        }