def _bisect_blocks(web3, timestamp, use_left_bound=True):
    """
    Perform a binary search on the blockchain for the block that matches the
    given timestamp.  The `use_left_bound` parameter determines whether to
    return the block to the left or right of the timestamp in the event that no
    block matches the timestamp exactly.
    """
    left_bound = 1
    right_bound = web3.eth.blockNumber

    left_block = web3.eth.getBlock(left_bound)
    if left_block['timestamp'] >= timestamp:
        return 'earliest'
    right_block = web3.eth.getBlock(right_bound)
    if right_block['timestamp'] <= timestamp:
        return 'latest'

    while left_bound < right_bound - 1:
        middle = (left_bound + right_bound) // 2
        middle_block = web3.eth.getBlock(middle)

        if middle_block['timestamp'] < timestamp:
            left_bound = middle
        elif middle_block['timestamp'] > timestamp:
            right_bound = middle
        else:
            return middle
    else:
        if use_left_bound:
            return left_bound
        else:
            return right_bound