SyncQueueImpl implements SyncQueueIfc { void eraseChain(List<HeaderElement> chain, long startFrom) { if (chain.isEmpty()) return; startFrom = Math.max(darkZoneNum + 1, startFrom); HeaderElement head = chain.get(chain.size() - 1); for (int i = chain.size() - 1; i >= 0; i--) { HeaderElement el = chain.get(i); if (el.header.getNumber() < startFrom) break; Map<ByteArrayWrapper, HeaderElement> gen = headers.get(el.header.getNumber()); gen.remove(new ByteArrayWrapper(el.header.getHash())); if (gen.isEmpty()) { headers.remove(el.header.getNumber()); } } if (head.header.getNumber() == maxNum) { Map<ByteArrayWrapper, HeaderElement> lastValidatedGen = headers.get(darkZoneNum); assert lastValidatedGen.size() == 1; long maxNotEmptyGen = lastValidatedGen.values().iterator().next().header.getNumber(); for (long num = head.header.getNumber(); num >= darkZoneNum; num--) { Map<ByteArrayWrapper, HeaderElement> gen = headers.get(num); if (gen != null && !gen.isEmpty() && num > maxNotEmptyGen) { maxNotEmptyGen = num; break; } } maxNum = maxNotEmptyGen; } } SyncQueueImpl(List<Block> initBlocks);  SyncQueueImpl(Blockchain bc);  SyncQueueImpl(Blockchain bc, Long endBlockNumber); @Override synchronized List<HeadersRequest> requestHeaders(int maxSize, int maxRequests, int maxTotalHeaders); @Override synchronized List<BlockHeaderWrapper> addHeaders(Collection<BlockHeaderWrapper> headers); @Override synchronized ValidatedHeaders addHeadersAndValidate(Collection<BlockHeaderWrapper> headers); @Override synchronized int getHeadersCount(); @Override synchronized BlocksRequest requestBlocks(int maxSize); @Override synchronized List<Block> addBlocks(Collection<Block> blocks); synchronized List<Block> pollBlocks(); SyncQueueImpl withParentHeaderValidator(DependentBlockHeaderRule validator);  }
@Test public void testEraseChain() { List<Block> randomChain = TestUtils.getRandomChain(new byte[32], 0, 1024); SyncQueueImpl queue = new SyncQueueImpl(randomChain); List<Block> chain1 = TestUtils.getRandomChain(randomChain.get(randomChain.size() - 1).getHash(), 1024, SyncQueueImpl.MAX_CHAIN_LEN / 2); queue.addHeaders(createHeadersFromBlocks(chain1, randomPeerId())); List<Block> chain2 = TestUtils.getRandomChain(randomChain.get(randomChain.size() - 1).getHash(), 1024, SyncQueueImpl.MAX_CHAIN_LEN / 2 - 1); queue.addHeaders(createHeadersFromBlocks(chain2, randomPeerId())); List<SyncQueueImpl.HeaderElement> longestChain = queue.getLongestChain(); long maxNum = longestChain.get(longestChain.size() - 1).header.getNumber(); assertEquals(1024 + SyncQueueImpl.MAX_CHAIN_LEN / 2 - 1, maxNum); assertEquals(1024 + SyncQueueImpl.MAX_CHAIN_LEN / 2 - 1, queue.getHeadersCount()); List<Block> chain3 = TestUtils.getRandomChain(chain1.get(chain1.size() - 1).getHash(), 1024 + SyncQueueImpl.MAX_CHAIN_LEN / 2, SyncQueueImpl.MAX_CHAIN_LEN / 10); queue.withParentHeaderValidator(new DependentBlockHeaderRule() { @Override public boolean validate(BlockHeader header, BlockHeader dependency) { return header.getNumber() < chain2.get(chain2.size() - 2).getNumber(); } }); queue.addHeadersAndValidate(createHeadersFromBlocks(chain3, randomPeerId())); longestChain = queue.getLongestChain(); assertEquals(maxNum - 1, queue.getHeadersCount()); assertEquals(chain2.get(chain2.size() - 1).getHeader(), longestChain.get(longestChain.size() - 1).header.getHeader()); }