Beispiel #1
0
    def wait_for_close(self, bitcoin_process):
        '''
            Wait for user to close bitcion_qt.
        '''
        initial_wait_seconds = 30
        normal_wait_seconds = 10

        self.log('waiting for bitcoin-qt to be closed by user')
        while bitcoin_utils.is_bitcoin_qt_running():

            max_secs = initial_wait_seconds
            secs = 0
            # wait for bitcoin-qt
            while bitcoin_utils.is_bitcoin_qt_running() and (secs < max_secs):
                try:
                    if bitcoin_process is None:
                        sleep(1)
                    else:
                        bitcoin_process.wait(1)
                except TimeoutExpired:
                    pass
                secs += 1
            max_secs = normal_wait_seconds

            if bitcoin_utils.is_bitcoin_qt_running():
                current_block = self.manager.get_current_block(show_next_backup_time=False)

                if (current_block is not None and current_block > self.current_block):
                    self.current_block = current_block

        self.log(f'current block: {self.current_block}')
        self.log('finished waiting for bitcoin-qt')
Beispiel #2
0
def stop_bitcoin_qt():
    '''
        Stop bitcoin_qt and determine if it ended properly.

        >>> init_database()
        >>> stop_bitcoin_qt()
    '''
    seconds = 0
    while (bitcoin_utils.is_bitcoin_qt_running() and seconds < 60):
        try:
            send_bitcoin_cli_cmd('stop')
            sleep(5)
            seconds += 5
        except:
            pass

    # use brute force if necessary
    if bitcoin_utils.is_bitcoin_qt_running():
        bin_dir = os.path.join(virtualenv_dir(), 'bin')
        args = [os.path.join(bin_dir, 'killmatch'), bitcoin_utils.bitcoin_qt()]
        command.run(*args).stdout

    # give it a little more time to settle down
    sleep(5)

    log(f'bitcoin-qt running: {bitcoin_utils.is_bitcoin_qt_running()}')
Beispiel #3
0
def start_bitcoin_qt():
    '''
        Start bitcoin-qt.

        >>> init_database()
        >>> start_bitcoin_qt()
        >>> stop_bitcoin_qt()
    '''

    bin_dir, data_dir = preferences.get_bitcoin_dirs()

    command_args = []
    cmd = os.path.join(bin_dir, bitcoin_utils.bitcoin_qt())
    command_args.append(cmd)

    data_dir = bitcoin_utils.strip_testnet_from_data_dir(data_dir=data_dir)
    command_args.append(f'-datadir={data_dir}')

    extra_args = preferences.get_extra_args()
    if len(extra_args) > 0:
        for extra_arg in extra_args:
            command_args.append(extra_arg)

    command_args.append('-daemon')

    command.background(*command_args)
    log(f'running : {command_args}')

    # give bitcoind time to start
    secs = 0
    while (not bitcoin_utils.is_bitcoin_qt_running() and secs < 5):
        sleep(1)
        secs += 1
Beispiel #4
0
        def wait(arg):
            ONE_MINUTE = 60

            secs = 0
            while ((utils.is_bitcoind_running()
                    or utils.is_bitcoin_qt_running()) and secs < ONE_MINUTE):
                sleep(1)
                secs += 1
            self.log(f'waited {secs} seconds before retrying "{arg}" command')
Beispiel #5
0
def stop_bitcoin_core_apps():
    '''
        Stop all bitcoin core apps.

        >>> stop_bitcoin_core_apps()
    '''
    if bitcoin_utils.is_bitcoin_qt_running():
        stop_bitcoin_qt()

        # if it's still running, then kill it
        if bitcoin_utils.is_bitcoin_qt_running():
            bin_dir = os.path.join(virtualenv_dir(), 'bin')
            args = [os.path.join(bin_dir, 'killmatch'), bitcoin_utils.bitcoin_qt()]
            command.run(*args).stdout

    if bitcoin_utils.is_bitcoind_running():
        stop_bitcoind()

        # if it's still running, then kill it
        if bitcoin_utils.is_bitcoind_running():
            bin_dir = os.path.join(virtualenv_dir(), 'bin')
            args = [os.path.join(bin_dir, 'killmatch'), bitcoin_utils.bitcoind()]
            command.run(*args).stdout
Beispiel #6
0
    def tearDown(self):

        # make sure nothing is left running
        if is_backup_running():
            InterruptBackup.as_view()(
                self.factory.get('/bitcoin/interrupt_backup/'))
            sleep(20)

        # make sure bitcoin-qt shuts down; 60 secs may not be enough,
        # but don't want to waste time waiting needlessly
        if is_bitcoin_qt_running():
            sleep(60)
            test_utils.stop_bitcoin_qt()

        # some tests might create a .bitcom in the home dir
        test_utils.delete_home_bitcoin_subdir(self.home_bitcoin_subdir_exists)
Beispiel #7
0
def warn_core_running(request, message=None):
    '''
        Warn that one of the bitcoin
        core programs is running.

        >>> from django.test import RequestFactory
        >>> no_backup_message = bytearray(NO_BACKUP_IF_CORE_RUNNING, encoding='utf-8')
        >>> factory = RequestFactory()
        >>> request = factory.get('/bitcoin/preferences/')
        >>> response = warn_core_running(request)
        >>> response.status_code == 200
        True
        >>> b'BitcoinD' in response.content
        True
        >>> no_backup_message in response.content
        False
        >>> request = factory.get('/bitcoin/preferences/')
        >>> response = warn_core_running(request, message=NO_BACKUP_IF_CORE_RUNNING)
        >>> response.status_code == 200
        True
        >>> b'BitcoinD' in response.content
        True
        >>> no_backup_message in response.content
        True
    '''

    if bitcoin_utils.is_bitcoin_qt_running():
        app = 'Bitcoin-QT'
    elif bitcoin_utils.is_bitcoin_tx_running():
        app = 'Bitcoin-TX'
    else:
        app = 'BitcoinD'

    if message is None:
        params = {'app': app}
    else:
        params = {'app': app, 'more': message}

    return render(request, 'bitcoin/core_running.html', params)
Beispiel #8
0
    def send_bitcoin_cli_cmd(self, arg, max_attempts=1):
        '''
            Send a command via bitcoin-cli.

            >>> from blockchain_backup.bitcoin.tests import utils as test_utils
            >>> test_utils.init_database()
            >>> manager = BitcoinManager('blockchain_backup.bitcoin.manager.log')
            >>> manager.send_bitcoin_cli_cmd('getblockchaininfo')
            -1
        '''
        def wait(arg):
            ONE_MINUTE = 60

            secs = 0
            while ((utils.is_bitcoind_running()
                    or utils.is_bitcoin_qt_running()) and secs < ONE_MINUTE):
                sleep(1)
                secs += 1
            self.log(f'waited {secs} seconds before retrying "{arg}" command')

        command_args = self.get_bitcoin_cli_cmd(arg)

        attempts = 0
        result = -1
        while (attempts < max_attempts and result == -1 and
               (utils.is_bitcoind_running() or utils.is_bitcoin_qt_running())):

            try:
                result = command.run(*command_args).stdout
                if attempts > 0:
                    self.log(f'resent "{arg}" command {attempts} times')
            except CalledProcessError as cpe:
                attempts += 1
                self.handle_bitcoin_cli_error(arg, cpe)

                if attempts < max_attempts:
                    wait(arg)

        return result
Beispiel #9
0
    def get_page(self, request):

        global update_task

        log('trying to update blockchain')

        clear_action_updates()

        # check that no other bitcoin-core app is running
        if (bitcoin_utils.is_bitcoin_qt_running()
                or bitcoin_utils.is_bitcoin_tx_running()
                or (bitcoin_utils.is_bitcoind_running() and not updating())):
            response = warn_core_running(request)

        # tell user if another blockchain_backup app is running
        elif bitcoin_utils.is_backup_running(
        ) or bitcoin_utils.is_restore_running():
            response = warn_bcb_app_running(request)

        # tell user if another task is running
        elif accessing_wallet() or backing_up() or restoring():
            response = warn_bcb_task_running(request)

        else:
            NOTICE1 = 'WARNING: Don\'t shut down your computer before you <a class="btn btn-secondary " role="button"'
            NOTICE2 = 'id="stop_button" href="/bitcoin/interrupt_update/" title="Click to stop updating the blockchain">Stop update</a>'
            NOTICE = f'{NOTICE1} {NOTICE2}'

            context = bitcoin_utils.get_blockchain_context()

            data_dir_ok, error = preferences.data_dir_ok()
            if not preferences.bin_dir_ok():
                context['notice'] = BAD_BIN_DIR
                log(BAD_BIN_DIR)
            elif not data_dir_ok:
                context['notice'] = BAD_DATA_DIR
                log(error)
            else:
                context['header'] = "Updating Bitcoin's blockchain"
                context[
                    'notice'] = 'WARNING: Don\'t shut down your computer before you <a class="btn btn-secondary " role="button" id="stop_button" href="/bitcoin/interrupt_update/" title="Click to stop updating the blockchain">Stop update</a>'
                context[
                    'subnotice'] = 'Shutting down before this window says it is safe <em>could damage the blockchain</em>.'
                context['progress'] = 'Starting to update the blockchain'
                context['update_interval'] = '5000'

                if updating():
                    log('already updating blockchain')

                else:
                    from blockchain_backup.bitcoin.update import UpdateTask

                    update_task = UpdateTask()
                    update_task.start()
                    log('UpdateTask started')

            # make sure the button doesn't appear any more
            bitcoin_utils.send_socketio_message('button', ' ')

            log(f'context: {context}')
            response = render(request, 'bitcoin/update.html', context=context)

        return response
Beispiel #10
0
    def get_page(self, request):

        global accessing_wallet_task

        log('accessing bitcoin interactively')

        clear_action_updates()

        # it's ok if bitcoin-qt is running in our task
        if (bitcoin_utils.is_bitcoind_running()
                or bitcoin_utils.is_bitcoin_tx_running()
                or (bitcoin_utils.is_bitcoin_qt_running()
                    and not accessing_wallet())):
            response = warn_core_running(request)

        # tell user if another app is running
        elif bitcoin_utils.is_backup_running(
        ) or bitcoin_utils.is_restore_running():
            response = warn_bcb_app_running(request)

        # tell user if another task is running
        elif updating() or backing_up() or restoring():
            response = warn_bcb_task_running(request)

        else:
            SUBNOTICE1 = "Waiting until you exit Bitcoin-QT.<p>Bitcoin-QT will start in another window."
            SUBNOTICE2 = "You can send and receive transactions from that window."
            SUBNOTICE3 = "After you exit Bitcoin-QT, Blockchain Backup will continue updating the blockchain until it's time to back it up."
            SUBNOTICE4 = "Don't forget to back up your wallet routinely."
            SUBNOTICE = f'{SUBNOTICE1} {SUBNOTICE2} {SUBNOTICE3} {SUBNOTICE4}'

            context = bitcoin_utils.get_blockchain_context()

            data_dir_ok, error = preferences.data_dir_ok()
            if not preferences.bin_dir_ok():
                context['notice'] = BAD_BIN_DIR
            elif not data_dir_ok:
                context['notice'] = BAD_DATA_DIR
                context['subnotice'] = error
            else:
                context[
                    'header'] = "Accessing Bitcoin Core Wallet Interactively"
                context[
                    'notice'] = 'WARNING: Do not shut down your computer until Bitcoin-QT stops completely.'
                context['subnotice'] = SUBNOTICE

                if accessing_wallet():
                    log('already accessing wallet')

                else:
                    from blockchain_backup.bitcoin.access_wallet import AccessWalletTask

                    accessing_wallet_task = AccessWalletTask()
                    accessing_wallet_task.start()
                    log('access wallet started')

                # make sure the button doesn't appear any more
                bitcoin_utils.send_socketio_message('button', ' ')

            response = render(request,
                              'bitcoin/access_wallet.html',
                              context=context)

        return response
Beispiel #11
0
    def format_blockchain_update(self,
                                 blockchain_info,
                                 data_dir,
                                 show_next_backup_time=True):
        '''
            Format the update to the blockchain.

            >>> manager = BitcoinManager('blockchain_backup.bitcoin.manager.log')
            >>> blockchain_info = {
            ...                    "chain": "main",
            ...                    "blocks": 569060,
            ...                    "headers": 569164,
            ...                    "bestblockhash": "0000000000000000001ded7310261af91403b97bf02e227b26cccc35bde3eccd",
            ...                    "difficulty": 6379265451411.053,
            ...                    "mediantime": 1553711097,
            ...                    "warnings": ""
            ...                   }
            >>> data_dir = '/tmp/bitcoin/data/testnet3'
            >>> current_block, progress = manager.format_blockchain_update(
            ...   blockchain_info, data_dir, show_next_backup_time=False)
            >>> current_block == 569060
            True
            >>> progress.find('Next backup in:') > 0
            False
            >>> current_block, progress = manager.format_blockchain_update(
            ...   blockchain_info, data_dir)
            >>> current_block == 569060
            True
            >>> progress.find('Next backup in:') > 0
            True
            >>> blockchain_info = {
            ...                    "chain": "main",
            ...                    "blocks": 2,
            ...                    "headers": 0,
            ...                    "mediantime": 1553711097,
            ...                    "warnings": ""
            ...                   }
            >>> data_dir = '/tmp/bitcoin/data/testnet3'
            >>> manager.format_blockchain_update(blockchain_info, data_dir)
            (2, None)
        '''

        progress = None

        last_known_block = int(blockchain_info['headers'])
        current_block = int(blockchain_info['blocks'])
        epoch_time = gmtime(blockchain_info['mediantime'])
        last_block_time = datetime(epoch_time.tm_year,
                                   epoch_time.tm_mon,
                                   epoch_time.tm_mday,
                                   epoch_time.tm_hour,
                                   epoch_time.tm_min,
                                   epoch_time.tm_sec,
                                   tzinfo=utc)

        if last_known_block > 0:
            previous_known_block = state.get_last_known_block()
            if last_known_block > previous_known_block:
                state.set_last_known_block(last_known_block)
                state.set_last_block_time(last_block_time)
                self.new_blocks_found = True

            time_behind = f'{utils.get_most_recent_confirmation(last_block_time)} ago'
            remaining_blocks = last_known_block - current_block
            if remaining_blocks < 0 or not self.new_blocks_found:
                remaining_blocks = 'Unknown'

            rows = []
            rows.append(
                self.format_row('Number of blocks to update',
                                remaining_blocks))
            rows.append(
                self.format_row(
                    'Most recent confirmation',
                    time_behind,
                    title=
                    'Most recent transaction confirmed on your Bitcoin node'))

            if show_next_backup_time:
                status = utils.get_next_backup_in()
                if status is not None:
                    rows.append(self.format_row('Next backup in', status))

            elif current_block > 0:
                need_backup = utils.need_to_backup(data_dir, current_block)
                if need_backup and utils.is_bitcoin_qt_running():
                    rows.append(
                        self.format_row(
                            '<font color="red">Backup needed</font>',
                            'Stop Bitcoin-QT as soon as possible to protect your blockchain. The backup will start automatically.'
                        ))

            progress = f"<table cellspacing=\"5\">{''.join(rows)}</table>"

        return current_block, progress
Beispiel #12
0
    def run_qt(self):
        '''
            Run bitcon-qt.
        '''
        ok = False
        error_message = None

        self.manager.update_menu(constants.DISABLE_ITEM)

        try:
            command_args = self.get_launch_args()
            if command_args is None:
                ok = False
            else:
                self.manager.rename_logs()

                state.set_start_access_time(now())

                self.log(f'starting bitcoin-qt: {command_args}')
                os.putenv('DISPLAY', ':0.0')

                if bitcoin_utils.is_bitcoin_qt_running():
                    bitcoin_pid = get_pid(bitcoin_utils.bitcoin_qt())
                    bitcoin_process = None
                else:
                    bitcoin_pid = None
                    bitcoin_process = Popen(command_args)

                if bitcoin_process is not None or bitcoin_pid is not None:
                    self.wait_for_close(bitcoin_process)
                    state.set_last_access_time(now())
                    ok = True
                else:
                    self.manager.update_progress(self.BITCOIN_QT_OTHER_APP_RUNNING)
                    ok = False

        except CalledProcessError as cpe:
            ok = False
            stdout = cpe.stdout
            if stdout and not isinstance(stdout, str):
                stdout = stdout.decode()
            stderr = cpe.stderr
            if stderr and not isinstance(stderr, str):
                stderr = stderr.decode()
            __, error_message, log_message = self.manager.process_bitcoin_cli_error(
              'getblockchaininfo', cpe.returncode, stdout, stderr)
            if error_message is None:
                error_message = log_message
            self.log(error_message)

        except BitcoinException as be:
            ok = False
            error_message = str(be)
            self.log(error_message)

        except FileNotFoundError as fnfe:
            ok = False
            error_message = str(fnfe)
            self.log(error_message)

        except Exception:
            self.log(format_exc())

        if ok:
            # check the logs to make sure everything was ok
            ok, error_message = self.manager.bitcoin_finished_ok(
              bitcoin_utils.is_bitcoin_qt_running)

        if ok:
            if self.current_block > 0:
                state.set_last_block_updated(self.current_block)

        else:
            if error_message is None:
                error_message = ''

            self.manager.update_subnotice('{} {}'.format(
               self.BITCOIN_QT_ERROR_LABEL, error_message))

        self.manager.update_progress('&nbsp;')

        return ok, error_message