':param block_a:         The first block address.
:param block_b:         The second block address.
:param check_constants: Whether or not to require matching constants in blocks.
:returns:               Whether or not the blocks appear to be identical.'

def blocks_probably_identical(self, block_a, block_b, check_constants=False):

    if (self._project_a.is_hooked(block_a) and self._project_b.is_hooked(block_b)):
        return (self._project_a._sim_procedures[block_a] == self._project_b._sim_procedures[block_b])
    try:
        block_a = NormalizedBlock(block_a, self._function_a)
    except (SimMemoryError, SimEngineError):
        block_a = None
    try:
        block_b = NormalizedBlock(block_b, self._function_b)
    except (SimMemoryError, SimEngineError):
        block_b = None
    if ((block_a is None) and (block_b is None)):
        return True
    elif ((block_a is None) or (block_b is None)):
        return False
    if (len(block_a.blocks) != len(block_b.blocks)):
        return False
    try:
        diff_constants = FunctionDiff._block_diff_constants(block_a, block_b)
    except UnmatchedStatementsException:
        return False
    if (not check_constants):
        return True
    acceptable_differences = self._get_acceptable_constant_differences(block_a, block_b)
    for c in diff_constants:
        if ((c.value_a, c.value_b) in self._block_matches):
            continue
        if ((self._bindiff is not None) and ((c.value_a and c.value_b) in self._bindiff.function_matches)):
            continue
        if (self._project_a.loader.main_object.contains_addr(c.value_a) and self._project_b.loader.main_object.contains_addr(c.value_b)):
            continue
        if ((c.value_b - c.value_a) in acceptable_differences):
            continue
        return False
    return True
