Takes the output of find_zonefile_subdomains, and processes the sequence of subdomain operations.
        Does state-transitions in a big step:
        * loads the current subdomain state for each subdomain affected in @zonefile_subdomain_info
        * computes and executes all valid subdomain creations and subdomain state-transitions on each
          affected subdomain, in blockchain-given and zonefile-given order.
        * stores the resulting subdomain state for each affected subdomain to the subdomain DB

        WARNING: NOT THREAD SAFE.  DO NOT CALL FROM MULTIPLE THREADS

def process_subdomains(self, zonefile_subdomain_info):
        """
        Takes the output of find_zonefile_subdomains, and processes the sequence of subdomain operations.
        Does state-transitions in a big step:
        * loads the current subdomain state for each subdomain affected in @zonefile_subdomain_info
        * computes and executes all valid subdomain creations and subdomain state-transitions on each
          affected subdomain, in blockchain-given and zonefile-given order.
        * stores the resulting subdomain state for each affected subdomain to the subdomain DB

        WARNING: NOT THREAD SAFE.  DO NOT CALL FROM MULTIPLE THREADS
        """

        cursor = self.subdomain_db.cursor()

        # we can afford to be fast and loose here since if the host crashes while this is going on,
        # the node will do a `restore` anyway and wipe this db out.
        db_query_execute(cursor, 'PRAGMA synchronous = off;', ())
        db_query_execute(cursor, 'PRAGMA journal_mode = off;', ())
        db_query_execute(cursor, 'BEGIN', ())

        # no matter what we do, store everything.
        # but, don't accept it yet.
        for subinfo in zonefile_subdomain_info:
            if subinfo['subdomains'] is None:
                continue

            for subrec in subinfo['subdomains']:
                subrec.accepted = False
                log.debug("Store {}".format(subrec))
                self.subdomain_db.update_subdomain_entry(subrec, cur=cursor)

        # at each zone file, find out if its subdomain creates/updates are valid
        for subinfo in zonefile_subdomain_info:

            zfhash = subinfo['zonefile_hash']
            zfindex = subinfo['inv_index']

            log.debug("Process subdomain records in zonefile {} ({})".format(subinfo['zonefile_hash'], subinfo['inv_index']))

            new_subdomain_recs = {}

            # get the set of subdomain records created by this zonefile
            if subinfo['subdomains']:
                for subrec in subinfo['subdomains']:
                    assert subrec.get_fqn() not in new_subdomain_recs, 'BUG: duplicate subdomain record for "{}" in {}'.format(subrec.get_fqn(), zfhash)
                    new_subdomain_recs[subrec.get_fqn()] = subrec
            
            for fqn in new_subdomain_recs:
                immediate_history = self.get_subdomain_history_neighbors(cursor, new_subdomain_recs[fqn])
                inserted = self.subdomain_try_insert(cursor, new_subdomain_recs[fqn], immediate_history)
                if inserted:
                    log.debug("Inserted {}".format(fqn))
                    continue

                log.debug("Rewrite history of {}".format(fqn))

                new_hist = self.make_new_subdomain_history(cursor, new_subdomain_recs[fqn])
                for subrec in new_hist:
                    self.subdomain_db.update_subdomain_entry(subrec, cur=cursor)

                last_accepted = None
                for h in reversed(new_hist):
                    if h.accepted:
                        last_accepted = h
                        break

                if last_accepted:
                    new_fut = self.make_new_subdomain_future(cursor, last_accepted)
                else:
                    new_fut = []

                for subrec in new_fut:
                    self.subdomain_db.update_subdomain_entry(subrec, cur=cursor)

        db_query_execute(cursor, 'END', ())