<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def sanity_check(self):
 """ Check block and throw PyrtlError or PyrtlInternalError if there is an issue. Should not modify anything, only check data structures to make sure they have been built according to the assumptions stated in the Block comments."""


        # TODO: check that the wirevector_by_name is sane
        from .wire import Input, Const, Output
        from .helperfuncs import get_stack, get_stacks

        # check for valid LogicNets (and wires)
        for net in self.logic:
            self.sanity_check_net(net)

        for w in self.wirevector_subset():
            if w.bitwidth is None:
                raise PyrtlError(
                    'error, missing bitwidth for WireVector "%s" \n\n %s' % (w.name, get_stack(w)))

        # check for unique names
        wirevector_names_set = set(x.name for x in self.wirevector_set)
        if len(self.wirevector_set) != len(wirevector_names_set):
            wirevector_names_list = [x.name for x in self.wirevector_set]
            for w in wirevector_names_set:
                wirevector_names_list.remove(w)
            raise PyrtlError('Duplicate wire names found for the following '
                             'different signals: %s' % repr(wirevector_names_list))

        # check for dead input wires (not connected to anything)
        all_input_and_consts = self.wirevector_subset((Input, Const))

        # The following line also checks for duplicate wire drivers
        wire_src_dict, wire_dst_dict = self.net_connections()
        dest_set = set(wire_src_dict.keys())
        arg_set = set(wire_dst_dict.keys())
        full_set = dest_set | arg_set
        connected_minus_allwires = full_set.difference(self.wirevector_set)
        if len(connected_minus_allwires) > 0:
            bad_wire_names = '\n    '.join(str(x) for x in connected_minus_allwires)
            raise PyrtlError('Unknown wires found in net:\n %s \n\n %s' % (bad_wire_names,
                             get_stacks(*connected_minus_allwires)))
        allwires_minus_connected = self.wirevector_set.difference(full_set)
        allwires_minus_connected = allwires_minus_connected.difference(all_input_and_consts)
        #   ^ allow inputs and consts to be unconnected
        if len(allwires_minus_connected) > 0:
            bad_wire_names = '\n    '.join(str(x) for x in allwires_minus_connected)
            raise PyrtlError('Wires declared but not connected:\n %s \n\n %s' % (bad_wire_names,
                             get_stacks(*allwires_minus_connected)))

        # Check for wires that are inputs to a logicNet, but are not block inputs and are never
        # driven.
        ins = arg_set.difference(dest_set)
        undriven = ins.difference(all_input_and_consts)
        if len(undriven) > 0:
            raise PyrtlError('Wires used but never driven: %s \n\n %s' %
                             ([w.name for w in undriven], get_stacks(*undriven)))

        # Check for async memories not specified as such
        self.sanity_check_memory_sync(wire_src_dict)

        if debug_mode:
            # Check for wires that are destinations of a logicNet, but are not outputs and are never
            # used as args.
            outs = dest_set.difference(arg_set)
            unused = outs.difference(self.wirevector_subset(Output))
            if len(unused) > 0:
                names = [w.name for w in unused]
                print('Warning: Wires driven but never used { %s } ' % names)
                print(get_stacks(*unused))