class BlockSyncService {

    public BlockProcessResult processBlock(@Nonnull Block block, MessageChannel sender, boolean ignoreMissingHashes) {
        Instant start = Instant.now();
        long bestBlockNumber = this.getBestBlockNumber();
        long blockNumber = block.getNumber();
        final Keccak256 blockHash = block.getHash();
        int syncMaxDistance = syncConfiguration.getChunkSize() * syncConfiguration.getMaxSkeletonChunks();

        tryReleaseStore(bestBlockNumber);
        store.removeHeader(block.getHeader());
        unknownBlockHashes.remove(blockHash);

        if (blockNumber > bestBlockNumber + syncMaxDistance) {
            logger.trace("Block too advanced {} {} from {} ", blockNumber, block.getShortHash(),
                    sender != null ? sender.getPeerNodeID().toString() : "N/A");
            return new BlockProcessResult(false, null, block.getShortHash(),
                    Duration.between(start, Instant.now()));
        }

        if (sender != null) {
            nodeInformation.addBlockToNode(blockHash, sender.getPeerNodeID());
        }

        // already in a blockchain
        if (BlockUtils.blockInSomeBlockChain(block, blockchain)) {
            logger.trace("Block already in a chain {} {}", blockNumber, block.getShortHash());
            return new BlockProcessResult(false, null, block.getShortHash(),
                    Duration.between(start, Instant.now()));
        }
        trySaveStore(block);

        Set<Keccak256> unknownHashes = BlockUtils.unknownDirectAncestorsHashes(block, blockchain, store);
        // We can't add the block if there are missing ancestors or uncles. Request the missing blocks to the sender.
        if (!unknownHashes.isEmpty()) {
            if (!ignoreMissingHashes){
                logger.trace("Missing hashes for block in process {} {}", blockNumber, block.getShortHash());
                requestMissingHashes(sender, unknownHashes);
            }
            return new BlockProcessResult(false, null, block.getShortHash(),
                    Duration.between(start, Instant.now()));
        }

        logger.trace("Trying to add to blockchain");

        Map<Keccak256, ImportResult> connectResult = connectBlocksAndDescendants(sender,
                BlockUtils.sortBlocksByNumber(this.getParentsNotInBlockchain(block)), ignoreMissingHashes);

        return new BlockProcessResult(true, connectResult, block.getShortHash(),
                Duration.between(start, Instant.now()));
    }

    public  BlockSyncService(
            @Nonnull final UscSystemProperties config,
            @Nonnull final BlockStore store,
            @Nonnull final Blockchain blockchain,
            @Nonnull final BlockNodeInformation nodeInformation,
            @Nonnull final SyncConfiguration syncConfiguration);

}