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); } }