private bool processBlockHeader(BlockHeader header) { if (lastBlockHeader != null && lastBlockHeader.blockChecksum != null && !header.lastBlockChecksum.SequenceEqual(lastBlockHeader.blockChecksum)) { Logging.warn("TIV: Invalid last block checksum"); // discard the block // TODO require previous block to get verifications from 3 nodes // if in verification mode, detect liar and flag him // below is an implementation that's good enough for now if (minBlockHeightReorg < lastBlockHeader.blockNum - 7) { minBlockHeightReorg = lastBlockHeader.blockNum - 7; } BlockHeader prev_header = BlockHeaderStorage.getBlockHeader(minBlockHeightReorg); if (prev_header == null) { return(false); } lastBlockHeader = prev_header; ConsensusConfig.redactedWindowSize = ConsensusConfig.getRedactedWindowSize(lastBlockHeader.version); ConsensusConfig.minRedactedWindowSize = ConsensusConfig.getRedactedWindowSize(lastBlockHeader.version); return(false); } if (!header.calculateChecksum().SequenceEqual(header.blockChecksum)) { Logging.warn("TIV: Invalid block checksum"); return(false); } lastBlockHeader = header; ConsensusConfig.redactedWindowSize = ConsensusConfig.getRedactedWindowSize(lastBlockHeader.version); ConsensusConfig.minRedactedWindowSize = ConsensusConfig.getRedactedWindowSize(lastBlockHeader.version); if (BlockHeaderStorage.saveBlockHeader(lastBlockHeader)) { // Cleanup every n blocks if ((header.blockNum > CoreConfig.maxBlockHeadersPerDatabase * 25) && header.blockNum % CoreConfig.maxBlockHeadersPerDatabase == 0) { BlockHeaderStorage.removeAllBlocksBefore(header.blockNum - (CoreConfig.maxBlockHeadersPerDatabase * 25)); } } IxianHandler.receivedBlockHeader(lastBlockHeader, true); return(true); }
private void verifyUnprocessedTransactions() { if (lastBlockHeader == null) { return; } lock (txQueue) { var tmp_txQueue = txQueue.Values.Where(x => x.applied != 0 && x.applied <= lastBlockHeader.blockNum).ToArray(); foreach (var tx in tmp_txQueue) { BlockHeader bh = BlockHeaderStorage.getBlockHeader(tx.applied); if (bh is null) { // TODO: need to wait for the block to arrive, or re-request // maybe something similar to PIT cache, or extend PIT cache to handle older blocks, too continue; } if (bh.version < BlockVer.v6) { txQueue.Remove(tx.id); if (bh.transactions.Contains(tx.id, new ByteArrayComparer())) { // valid IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, true); } else { // invalid IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, false); } } else { lock (pitCache) { // check if we already have the partial tree for this transaction if (pitCache.ContainsKey(tx.applied) && pitCache[tx.applied].pit != null) { // Note: PIT has been verified against the block header when it was received, so additional verification is not needed here. // Note: the PIT we have cached might have been requested for different txids (the current txid could have been added later) // For that reason, the list of TXIDs we requested is stored together with the cached PIT byte[] txid = null; if (bh.version < BlockVer.v8) { txid = UTF8Encoding.UTF8.GetBytes(Transaction.txIdV8ToLegacy(tx.id)); } else { txid = tx.id; } if (pitCache[tx.applied].requestedForTXIDs.Contains(tx.id, new ByteArrayComparer())) { // TODO TODO it shouldn't be immediatelly removed but checked with other nodes first txQueue.Remove(tx.id); if (pitCache[tx.applied].pit.contains(txid)) { // valid IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, true); } else { // invalid IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, false); } } else { // PIT cache for the correct block exists, but it was originally requested for different txids // we have to re-request it for any remaining txids in the queue. (We do not need to request the already-verified ids) requestPITForBlock(tx.applied, txQueue.Values .Where(x => x.applied == tx.applied && x.applied <= lastBlockHeader.blockNum) .Select(x => x.id) .ToList()); continue; } } else { // PIT cache has not been received yet, or maybe it has never been requested for this block requestPITForBlock(tx.applied, txQueue.Values .Where(x => x.applied == tx.applied && x.applied <= lastBlockHeader.blockNum) .Select(x => x.id) .ToList()); } } } } tmp_txQueue = txQueue.Values.Where(x => x.blockHeight + ConsensusConfig.getRedactedWindowSize() < lastBlockHeader.blockNum).ToArray(); foreach (var tx in tmp_txQueue) { txQueue.Remove(tx.id); // invalid IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, false); } } }