Example #1
0
    def start_workpool( self, bitcoind_opts ):
        """
        Make a work pool for ourselves.
        Raise an exception if one already exists.
        NOT THREAD SAFE
        """
        if self.pool is not None:
            raise Exception("Already indexing")

        self.pool = workpool.multiprocess_pool( bitcoind_opts, os.path.abspath( __file__ ) )
        return True
Example #2
0
    def start_workpool(self, bitcoind_opts):
        """
        Make a work pool for ourselves.
        Raise an exception if one already exists.
        NOT THREAD SAFE
        """
        if self.pool is not None:
            raise Exception("Already indexing")

        self.pool = workpool.multiprocess_pool(bitcoind_opts,
                                               os.path.abspath(__file__))
        return True
Example #3
0
    def build(self, bitcoind_opts, end_block_id):
        """
        Top-level call to process all blocks in the blockchain.
        Goes and fetches all OP_RETURN nulldata in order,
        and feeds them into the state engine implementation using its
        'db_parse', 'db_check', 'db_commit', and 'db_save'
        methods.
        
        Note that this method can take some time (hours, days) to complete 
        when called from the first block.
        
        This method is *NOT* thread-safe.  However, it can be interrupted 
        with the "stop_build" method.
        
        Return True on success 
        Return False on error
        Raise an exception on irrecoverable error--the caller should simply try again.
        """

        first_block_id = self.lastblock + 1
        num_workers, worker_batch_size = config.configure_multiprocessing(
            bitcoind_opts)

        rc = True

        # the state can be big.  don't pass it to the slave processes
        free_memory = self.__delete_me
        self.pool = workpool.multiprocess_pool(bitcoind_opts,
                                               initializer=free_memory,
                                               initargs=[self.state])

        try:

            log.debug("Process blocks %s to %s" %
                      (first_block_id, end_block_id))

            for block_id in xrange(first_block_id, end_block_id,
                                   worker_batch_size * num_workers):

                if not rc:
                    break

                if self.pool is None:
                    # interrupted
                    log.debug("Build interrupted")
                    rc = False
                    break

                block_ids = range(
                    block_id,
                    min(block_id + worker_batch_size * num_workers,
                        end_block_id))

                # returns: [(block_id, txs)]
                block_ids_and_txs = transactions.get_nulldata_txs_in_blocks(
                    self.pool, bitcoind_opts, block_ids)

                # process in order by block ID
                block_ids_and_txs.sort()

                for processed_block_id, txs in block_ids_and_txs:

                    if self.get_consensus_at(processed_block_id) is not None:
                        raise Exception(
                            "Already processed block %s (%s)" %
                            (processed_block_id,
                             self.get_consensus_at(processed_block_id)))

                    ops = self.parse_block(block_id, txs)
                    consensus_hash = self.process_block(
                        processed_block_id, ops)

                    log.debug("CONSENSUS(%s): %s" %
                              (processed_block_id,
                               self.get_consensus_at(processed_block_id)))

                    if consensus_hash is None:

                        # fatal error
                        rc = False
                        log.error("Failed to process block %d" %
                                  processed_block_id)
                        break

            log.debug("Last block is %s" % self.lastblock)

        except:

            self.pool.close()
            self.pool.terminate()
            self.pool.join()
            self.pool = None
            raise

        self.pool.close()
        self.pool.terminate()
        self.pool.join()
        self.pool = None
        return rc
    def build( self, bitcoind_opts, end_block_id ):
        """
        Top-level call to process all blocks in the blockchain.
        Goes and fetches all OP_RETURN nulldata in order,
        and feeds them into the state engine implementation using its
        'db_parse', 'db_check', 'db_commit', and 'db_save'
        methods.
        
        Note that this method can take some time (hours, days) to complete 
        when called from the first block.
        
        This method is *NOT* thread-safe.  However, it can be interrupted 
        with the "stop_build" method.
        
        Return True on success 
        Return False on error
        Raise an exception on irrecoverable error--the caller should simply try again.
        """
        
        first_block_id = self.lastblock + 1 
        num_workers, worker_batch_size = config.configure_multiprocessing( bitcoind_opts )

        rc = True

        # the state can be big.  don't pass it to the slave processes
        free_memory = self.__delete_me
        self.pool = workpool.multiprocess_pool( bitcoind_opts, initializer=free_memory, initargs=[self.state] )
        
        try:
            
            log.debug("Process blocks %s to %s" % (first_block_id, end_block_id) )
            
            for block_id in xrange( first_block_id, end_block_id, worker_batch_size * num_workers ):
                
                if not rc:
                    break 
                
                if self.pool is None:
                    # interrupted 
                    log.debug("Build interrupted")
                    rc = False
                    break 
                
                block_ids = range( block_id, min(block_id + worker_batch_size * num_workers, end_block_id) )
               
                # returns: [(block_id, txs)]
                block_ids_and_txs = transactions.get_nulldata_txs_in_blocks( self.pool, bitcoind_opts, block_ids )
                
                # process in order by block ID
                block_ids_and_txs.sort()
               
                for processed_block_id, txs in block_ids_and_txs:

                    if self.get_consensus_at( processed_block_id ) is not None:
                        raise Exception("Already processed block %s (%s)" % (processed_block_id, self.get_consensus_at( processed_block_id )) )

                    ops = self.parse_block( block_id, txs )
                    consensus_hash = self.process_block( processed_block_id, ops )
                    
                    log.debug("CONSENSUS(%s): %s" % (processed_block_id, self.get_consensus_at( processed_block_id )))
                    
                    if consensus_hash is None:
                        
                        # fatal error 
                        rc = False
                        log.error("Failed to process block %d" % processed_block_id )
                        break
            
            log.debug("Last block is %s" % self.lastblock )

        except:
            
            self.pool.close()
            self.pool.terminate()
            self.pool.join()
            self.pool = None
            raise
        
        self.pool.close()
        self.pool.terminate()
        self.pool.join()
        self.pool = None
        return rc