(required by virtualchain state engine)

    Given the block ID and the list of virtualchain operations in the block,
    do block-level preprocessing:
    * find the state-creation operations we will accept
    * make sure there are no collisions.

    This modifies op_list, but returns nothing.
    This aborts on runtime error.

def db_scan_block( block_id, op_list, db_state=None ):
    """
    (required by virtualchain state engine)

    Given the block ID and the list of virtualchain operations in the block,
    do block-level preprocessing:
    * find the state-creation operations we will accept
    * make sure there are no collisions.

    This modifies op_list, but returns nothing.
    This aborts on runtime error.
    """

    try:
        assert db_state is not None, "BUG: no state given"
    except Exception, e:
        log.exception(e)
        log.error("FATAL: no state given")
        os.abort()

    log.debug("SCAN BEGIN: {} ops at block {}".format(len(op_list), block_id))
    checked_ops = []
    for op_data in op_list:

        try:
            opcode = op_get_opcode_name( op_data['op'] ) 
            assert opcode is not None, "BUG: unknown op '%s'" % op
        except Exception, e:
            log.exception(e)
            log.error("FATAL: invalid operation")
            os.abort()

        if opcode not in OPCODE_CREATION_OPS:
            continue 

        # make sure there are no collisions:
        # build up our collision table in db_state.
        op_check( db_state, op_data, block_id, checked_ops )
        checked_ops.append( op_data )


    # get collision information for this block
    collisions = db_state.find_collisions( checked_ops )

    # reject all operations that will collide 
    db_state.put_collisions( block_id, collisions )
    log.debug("SCAN END: {} ops at block {} ({} collisions)".format(len(op_list), block_id, len(collisions)))