class ShardHashCalculatorImpl implements ShardHashCalculator {

    @Override
    public byte[] calculateHash(int shardStartHeight, int shardEndHeight) {
        if (shardStartHeight >= shardEndHeight) {
            throw new IllegalArgumentException("shard start height should be less than shard end height " + String.format("start - %d, finish - %d", shardStartHeight, shardEndHeight));
        }
        long startTime = System.currentTimeMillis();
        List<byte[]> blockSignatures = retrieveBlockSignatures(shardStartHeight, shardEndHeight);
        int blocks = blockSignatures.size();
        log.trace("Retrieved {} block signatures in {} ms", blocks, System.currentTimeMillis() - startTime);
        if (blocks == 0) {
            return null;
        }
        long merkleTreeStartTime = System.currentTimeMillis();
        byte[] prevHash = getPrevShardHash(shardStartHeight);
        blockSignatures.add(prevHash);
        byte[] hash = calculateMerkleRoot(blockSignatures);
        log.debug("Built merkle tree in {} ms", System.currentTimeMillis() - merkleTreeStartTime);
        long time = System.currentTimeMillis() - startTime;
        log.debug("Hash calculated in {} s for [{}] blocks, speed {} bpms", time / 1000, blocks, (shardEndHeight - shardStartHeight) / Math.max(time, 1));
        return hash;
    }

    @Inject public  ShardHashCalculatorImpl(Blockchain blockchain, BlockchainConfig blockchainConfig, ShardDao shardDao);
    public  ShardHashCalculatorImpl(Blockchain blockchain, BlockchainConfig blockchainConfig, ShardDao shardDao, int blockSelectLimit);

}