'Validates this block against what is known in the database
:param database: the database to check against
:return: A tuple consisting of a ValidationResult and a list of user string errors'

def validate(self, database):

    result = [ValidationResult.valid]
    errors = []
    crypto = ECCrypto()
    def err(reason):
        result[0] = ValidationResult.invalid
        errors.append(reason)
    blk = database.get(self.public_key, self.sequence_number)
    link = database.get_linked(self)
    prev_blk = database.get_block_before(self)
    next_blk = database.get_block_after(self)
    is_genesis = ((self.sequence_number == GENESIS_SEQ) or (self.previous_hash == GENESIS_HASH))
    is_prev_gap = ((prev_blk.sequence_number != (self.sequence_number - 1)) if prev_blk else True)
    is_next_gap = ((next_blk.sequence_number != (self.sequence_number + 1)) if next_blk else True)
    if ((not prev_blk) and (not next_blk)):
        if (not is_genesis):
            result[0] = ValidationResult.no_info
        else:
            result[0] = ValidationResult.partial_next
    elif ((not prev_blk) and next_blk):
        if (not is_genesis):
            result[0] = ValidationResult.partial_previous
            if is_next_gap:
                result[0] = ValidationResult.partial
        elif is_next_gap:
            result[0] = ValidationResult.partial_next
    elif (prev_blk and (not next_blk)):
        result[0] = ValidationResult.partial_next
        if is_prev_gap:
            result[0] = ValidationResult.partial
    elif (is_prev_gap and is_next_gap):
        result[0] = ValidationResult.partial
    elif is_prev_gap:
        result[0] = ValidationResult.partial_previous
    elif is_next_gap:
        result[0] = ValidationResult.partial_next
    (tx_validate_res, tx_errors) = self.validate_transaction(database)
    if (tx_validate_res != ValidationResult.valid):
        result[0] = tx_validate_res
        errors += tx_errors
    if (self.sequence_number < GENESIS_SEQ):
        err('Sequence    number    is    prior    to    genesis')
    if ((self.link_sequence_number < GENESIS_SEQ) and (self.link_sequence_number != UNKNOWN_SEQ)):
        err('Link    sequence    number    not    empty    and    is    prior    to    genesis')
    if (not crypto.is_valid_public_bin(self.public_key)):
        err('Public    key    is    not    valid')
    else:
        try:
            pck = self.pack(signature=False)
        except:
            pck = None
        if ((pck is None) or (not crypto.is_valid_signature(crypto.key_from_public_bin(self.public_key), pck, self.signature))):
            err('Invalid    signature')
    if (not crypto.is_valid_public_bin(self.link_public_key)):
        err('Linked    public    key    is    not    valid')
    if (self.public_key == self.link_public_key):
        err('Self    signed    block')
    if is_genesis:
        if ((self.sequence_number == GENESIS_SEQ) and (self.previous_hash != GENESIS_HASH)):
            err('Sequence    number    implies    previous    hash    should    be    Genesis    ID')
        if ((self.sequence_number != GENESIS_SEQ) and (self.previous_hash == GENESIS_HASH)):
            err('Sequence    number    implies    previous    hash    should    not    be    Genesis    ID')
    if blk:
        assert ((blk.public_key == self.public_key) and (blk.sequence_number == self.sequence_number)), 'Database    returned    unexpected    block'
        if (blk.link_public_key != self.link_public_key):
            err('Link    public    key    does    not    match    known    block')
        if (blk.link_sequence_number != self.link_sequence_number):
            err('Link    sequence    number    does    not    match    known    block')
        if (blk.previous_hash != self.previous_hash):
            err('Previous    hash    does    not    match    known    block')
        if (blk.signature != self.signature):
            err('Signature    does    not    match    known    block')
        if ((self.hash != blk.hash) and ('Invalid    signature' not in errors) and ('Public    key    is    not    valid' not in errors)):
            err('Double    sign    fraud')
    if link:
        assert ((link.public_key == self.link_public_key) and ((link.link_sequence_number == self.sequence_number) or (link.sequence_number == self.link_sequence_number))), 'Database    returned    unexpected    block'
        if (self.public_key != link.link_public_key):
            err('Public    key    mismatch    on    linked    block')
        elif (self.link_sequence_number != UNKNOWN_SEQ):
            linklinked = database.get_linked(link)
            if ((linklinked is not None) and (linklinked.hash != self.hash)):
                err('Double    countersign    fraud')
    if prev_blk:
        assert ((prev_blk.public_key == self.public_key) and (prev_blk.sequence_number < self.sequence_number)), 'Database    returned    unexpected    block'
        if ((not is_prev_gap) and (prev_blk.hash != self.previous_hash)):
            err('Previous    hash    is    not    equal    to    the    hash    id    of    the    previous    block')
    if next_blk:
        assert ((next_blk.public_key == self.public_key) and (next_blk.sequence_number > self.sequence_number)), 'Database    returned    unexpected    block'
        if ((not is_next_gap) and (next_blk.previous_hash != self.hash)):
            err('Next    hash    is    not    equal    to    the    hash    id    of    the    block')
    return (result[0], errors)
