def state_transition(history_id_key, table_name, always_set=[], may_spend_tokens=False):
    """
    Decorator for the check() method on state-transition operations.
    Make sure that:
    * there is a __table__ field set, which names the table in which this record is stored.
    * there is a __history_id_key__ field set, which identifies the table record's primary key.

    Any fields named in @always_set will always be set when the transition is applied.
    That is, fields set here *must* be set on transition, and *will* be set in the database, even if
    they have prior values in the affected name record that might constrain which rows to update.
    """

    def wrap( check ):
        def wrapped_check( state_engine, nameop, block_id, checked_ops ):
            rc = check( state_engine, nameop, block_id, checked_ops )
            if rc:
                # put fields in place 
                nameop['__table__'] = table_name
                nameop['__history_id_key__'] = history_id_key 
                nameop['__state_transition__'] = True
                nameop['__always_set__'] = always_set

                if not may_spend_tokens:
                    state_transition_put_account_payment_info(nameop, None, None, None)

                elif '__account_payment_info__' not in nameop:
                    raise Exception('Operation spends tokens, but no payment account information is set')

                # sanity check
                invariant_tags = state_transition_invariant_tags()
                for tag in invariant_tags:
                    assert tag in nameop, "BUG: missing invariant tag '%s'" % tag

                # sanity check---all required consensus fields must be present
                for required_field in CONSENSUS_FIELDS_REQUIRED:
                    assert required_field in nameop, 'BUG: missing required consensus field {}'.format(required_field)

            return rc
        return wrapped_check
    return wrap