def test_update_with_bitcoin_d_running(self): ''' Test updating with bitcoind already running. ''' # start bitcoind and wait for it to get started test_utils.start_bitcoind() while not is_bitcoind_running(): sleep(1) log('bitcoind is running') request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nBitcoinD Is Running | Blockchain Backup\n</title>" in response.content) self.assertTrue( b'BitcoinD, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse( b'Bitcoin-QT, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse( b'Bitcoin-TX, one of the Bitcoin Core programs, appears to be running' in response.content) if is_bitcoind_running(): test_utils.stop_bitcoind() self.assertTrue(get_backups_enabled())
def test_restore_with_missing_blocks(self): ''' Test restore with missing blocks in blockchain. ''' MINUTE = 60 MAX_SECONDS = 2 * MINUTE # remove a block from the blockchain data_dir = preferences.get_data_dir() block_filename = os.path.join(data_dir, 'blocks', 'blk00000.dat') if os.path.exists(block_filename): os.remove(block_filename) __, preselected_date_dir = state.get_backup_dates_and_dirs() request = self.factory.get('/bitcoin/restore/') response = views.Restore.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue(b"<title>\nAre you sure you want to restore the Bitcoin blockchain? | Blockchain Backup\n</title>" in response.content) self.assertTrue(b'Select backup to restore:' in response.content) self.assertTrue(b'<input type="submit" value="Yes, start restoring" name="yes-start-restoring-button" id="yes-start-restoring-id" alt="Yes, start restoring" class="btn btn-primary font-weight-bold " role="button" title="Restore the blockchain now"/>' in response.content) self.assertTrue(b'<input type="submit" value="No, cancel restore" name="no-cancel-restore-button" id="no-cancel-restore-id" alt="No, cancel restore" class="btn btn-secondary font-weight-bold " role="button" title="Do not restore the blockchain."/>' in response.content) client = Client() response = client.post('/bitcoin/restore/', {'backup_dates_with_dirs': preselected_date_dir[0] }) self.assertEqual(response.status_code, 200) self.assertTrue(b"<title>\nRestoring Bitcoin Blockchain | Blockchain Backup\n</title>" in response.content) self.assertTrue(b'WARNING: Do not shut down your computer until the restore finishes.' in response.content) self.assertTrue(b'Starting to restore the blockchain' in response.content) self.assertFalse(b'<input type="submit" value="Yes, start restoring" name="yes-start-restoring-button" id="yes-start-restoring-id" alt="Yes, start restoring" class="btn btn-primary font-weight-bold " role="button" title="Restore the blockchain now"/>' in response.content) # wait until the restore finishes seconds = 0 while not is_restore_running() and seconds < MAX_SECONDS: sleep(MINUTE) seconds += MINUTE # wait until bitcoind starts test_utils.start_bitcoind() seconds = 0 while not is_bitcoind_running() and seconds < MAX_SECONDS: sleep(MINUTE) seconds += MINUTE self.assertTrue(is_bitcoind_running()) # allow bitcoind to run for a while seconds = 0 while is_bitcoind_running() and seconds < MAX_SECONDS: sleep(MINUTE) seconds += MINUTE if is_bitcoind_running(): test_utils.stop_bitcoind() shutdown, error_message = test_utils.check_bitcoin_log(is_bitcoind_running) self.assertTrue(shutdown) self.assertTrue(error_message is None)
def update(self): ''' Update the blockchain using bitcoind. Returns whether the update ended successfully and whether a backup should start. If any errors while running, bitcoind, disable automatic backups so the user can decide how to proceed. ''' ok = need_backup = False error_message = None self.manager.update_menu(constants.DISABLE_ITEM) self.manager.rename_logs() try: bitcoind_process, bitcoind_pid = self.start_bitcoind() if not self.is_interrupted(): if bitcoind_process is None and bitcoind_pid is None: self.manager.update_notice(self.ERROR_STARTING_BITCOIND) self.manager.update_progress(self.UPDATE_UNEXPECTED_ERROR) ok = False else: need_backup = self.wait_while_updating(bitcoind_process) ok, error_message = self.stop_bitcoind(bitcoind_process, bitcoind_pid, need_backup) except BitcoinException as be: ok = False error_message = str(be) self.log(error_message) except: # 'bare except' because it catches more than "except Exception" self.log(format_exc()) # sometimes bitcoin exits with a non-zero return code, # but it was still ok, so check the logs ok, error_message = self.manager.bitcoin_finished_ok( is_bitcoind_running) if ok: if not need_backup: self.manager.update_progress(' ') elif error_message is not None: # don't allow any more backups until the user tells us it's ok state.set_backups_enabled(False) self.log('error while updating so stopping backups') if is_bitcoind_running(): self.log('retry stopping bitcoind without showing progress') self.retry_stopping(show_progress=False) self.manager.update_subnotice( f'{self.BITCOIND_ERROR_LABEL} {error_message}') return ok, need_backup
def wait_for_shutdown(self, bitcoind_process, bitcoind_pid, need_backup): ''' Wait for bitcoind to shutdown. >>> from blockchain_backup.bitcoin.tests import utils as test_utils >>> need_backup = False >>> test_utils.init_database() >>> update_task = UpdateTask() >>> update_task.manager = BitcoinManager(update_task.log_name) >>> bitcoind_process, bitcoind_pid = update_task.start_bitcoind() >>> update_task.wait_for_shutdown(bitcoind_process, bitcoind_pid, need_backup) ''' try: if is_bitcoind_running(): # get the last block number before we shut down self.current_block = self.manager.get_current_block( show_progress=False) if need_backup: self.manager.update_subnotice(self.STOP_UPDATE_FOR_BACKUP) self.manager.send_bitcoin_cli_cmd('stop', max_attempts=1) # wait until bitcoind terminates if bitcoind_process is None: try: pid, returncode = os.waitpid(bitcoind_pid, os.P_WAIT) self.log(f'waitpid {pid} return code: {returncode}') except ChildProcessError: self.log('update_pid already dead') else: bitcoind_process.wait() self.log( f'bitcoind return code: {bitcoind_process.returncode}') except: # 'bare except' because it catches more than "except Exception" self.log(format_exc())
def retry_stopping(self, show_progress=True): ''' Retry sending the stop command. At times, the process might end, but bitcoin itself is still running. >>> from blockchain_backup.bitcoin.tests import utils as test_utils >>> need_backup = False >>> test_utils.init_database() >>> update_task = UpdateTask() >>> update_task.manager = BitcoinManager(update_task.log_name) >>> update_task.retry_stopping() ''' MAX_SECONDS = 30 seconds = 0 while is_bitcoind_running(): sleep(1) seconds += 1 if seconds > MAX_SECONDS: seconds = 0 self.manager.send_bitcoin_cli_cmd('stop') if show_progress: self.manager.update_progress(self.STOPPING_UPDATE)
def report_error(self, bitcoind_process, bitcoind_pid, error_message, seconds): ''' Report a serious error about stopping bitcoind. >>> from blockchain_backup.bitcoin.tests import utils as test_utils >>> test_utils.init_database() >>> update_task = UpdateTask() >>> update_task.manager = BitcoinManager(update_task.log_name) >>> bitcoind_process, bitcoind_pid = update_task.start_bitcoind() >>> need_backup = False >>> ok, error_message = update_task.stop_bitcoind(bitcoind_process, bitcoind_pid, need_backup) >>> update_task.report_error(bitcoind_process, bitcoind_pid, error_message, 60) ''' # let the user know a serious error has happened if is_bitcoind_running(): if bitcoind_process is None and bitcoind_pid is None: if error_message is None: self.manager.update_progress( f'Unable to stop bitcoind after {seconds/60} minutes') else: if bitcoind_process is None: os.kill(bitcoind_pid, os.SIGTERM) else: bitcoind_process.terminate() self.log('terminated bitcoin process') else: # clear the progress because we're no longer # waiting for bitcoind to shutdown self.manager.update_progress(' ')
def test_access_wallet_with_bitcoind_running(self): ''' Test accessing the wallet with bitcoind already running. ''' # start bitcoind and wait for it to get started test_utils.start_bitcoind() while not is_bitcoind_running(): sleep(1) request = self.factory.get('/bitcoin/access_wallet/') response = AccessWallet.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nBitcoinD Is Running | Blockchain Backup\n</title>" in response.content) self.assertTrue( b'BitcoinD, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse( b'Bitcoin-QT, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse( b'Bitcoin-TX, one of the Bitcoin Core programs, appears to be running' in response.content) test_utils.stop_bitcoind()
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')
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
def stop_bitcoind(): ''' Stop bitcoind and determine if it ended properly. >>> init_database() >>> stop_bitcoind() ''' while (bitcoin_utils.is_bitcoind_running()): sleep(5) send_bitcoin_cli_cmd('stop') # give it a little more time to settle down sleep(5) log(f'bitcoind running: {bitcoin_utils.is_bitcoind_running()}')
def test_restore_with_bad_backup(self): ''' Test restore from a bad back up. ''' MINUTE = 60 MAX_SECONDS = 2 * MINUTE # change the data and backup dirs prefs = test_utils.get_preferences() prefs.data_dir = '/tmp/bitcoin/data-with-missing-file/testnet3/' prefs.backup_dir = '/tmp/bitcoin/data-with-missing-file/testnet3/backups/' preferences.save_preferences(prefs) __, preselected_date_dir = state.get_backup_dates_and_dirs() request = self.factory.get('/bitcoin/restore/') response = views.Restore.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue(b"<title>\nAre you sure you want to restore the Bitcoin blockchain? | Blockchain Backup\n</title>" in response.content) self.assertTrue(b'Select backup to restore:' in response.content) self.assertTrue(b'<input type="submit" value="Yes, start restoring" name="yes-start-restoring-button" id="yes-start-restoring-id" alt="Yes, start restoring" class="btn btn-primary font-weight-bold " role="button" title="Restore the blockchain now"/>' in response.content) self.assertTrue(b'<input type="submit" value="No, cancel restore" name="no-cancel-restore-button" id="no-cancel-restore-id" alt="No, cancel restore" class="btn btn-secondary font-weight-bold " role="button" title="Do not restore the blockchain."/>' in response.content) client = Client() response = client.post('/bitcoin/restore/', {'backup_dates_with_dirs': preselected_date_dir[0] }) self.assertEqual(response.status_code, 200) self.assertTrue(b"<title>\nRestoring Bitcoin Blockchain | Blockchain Backup\n</title>" in response.content) self.assertTrue(b'WARNING: Do not shut down your computer until the restore finishes.' in response.content) self.assertTrue(b'Starting to restore the blockchain' in response.content) self.assertFalse(b'<input type="submit" value="Yes, start restoring" name="yes-start-restoring-button" id="yes-start-restoring-id" alt="Yes, start restoring" class="btn btn-primary font-weight-bold " role="button" title="Restore the blockchain now"/>' in response.content) # wait until the restore finishes seconds = 0 while not is_restore_running() and seconds < MAX_SECONDS: sleep(MINUTE) seconds += MINUTE self.assertFalse(is_bitcoind_running()) self.assertFalse(state.get_backups_enabled()) name = 'last-updated-2020-01-17 14:41' last_updated_file = os.path.join(prefs.backup_dir, 'level1', name) self.assertFalse(os.path.exists(last_updated_file))
def test_backup_with_bitcoind_running(self): ''' Test backing up with bitcoind already running. ''' test_utils.start_bitcoind() while not is_bitcoind_running(): sleep(5) request = self.factory.get('/bitcoin/backup/') response = views.Backup.as_view()(request) # stop bitcoin in case any tests fail test_utils.stop_bitcoind() self.assertEqual(response.status_code, 200) self.assertTrue(b"<title>\nBitcoinD Is Running | Blockchain Backup\n</title>" in response.content) self.assertTrue(b'BitcoinD, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse(b'Bitcoin-QT, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse(b'Bitcoin-TX, one of the Bitcoin Core programs, appears to be running' in response.content)
def test_restore_with_bitcoind_running(self): ''' Test restoring with bitcoind already running. ''' test_utils.start_bitcoind() while not is_bitcoind_running(): sleep(5) request = self.factory.get('/bitcoin/restore/') response = views.Restore.as_view()(request) # stop the task before we start tests in case something fails test_utils.stop_bitcoind() self.assertEqual(response.status_code, 200) self.assertTrue(b"<title>\nBitcoinD Is Running | Blockchain Backup\n</title>" in response.content) self.assertTrue(b'BitcoinD, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse(b'Bitcoin-QT, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse(b'Bitcoin-TX, one of the Bitcoin Core programs, appears to be running' in response.content)
def test_update_with_missing_links(self): ''' Start the update with missing links. ''' # remove links from the chainstate dirname = os.path.join(get_data_dir(), 'chainstate') entries = os.scandir(dirname) for entry in entries: if entry.name.endswith('.ldb'): os.remove(entry.path) request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nUpdating Bitcoin's Blockchain | Blockchain Backup\n</title>" in response.content) self.assertTrue(b"WARNING: Don't shut down your computer before you" in response.content) self.assertTrue( b'<a class="btn btn-secondary " role="button" id="stop_button" href="/bitcoin/interrupt_update/" title="Click to stop updating the blockchain">Stop update</a>' in response.content) self.assertTrue( b'Shutting down before this window says it is safe <em>could damage the blockchain</em>.' in response.content) sleep(60) self.assertFalse(is_bitcoind_running()) shutdown, error_message = test_utils.check_bitcoin_log( is_bitcoind_running) self.assertTrue(shutdown) log(error_message) self.assertTrue( 'Aborted block database rebuild. Exiting.' in error_message or 'Error opening block database.' in error_message or 'Fatal LevelDB error' in error_message) self.assertFalse(get_backups_enabled())
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
def start_bitcoind(): ''' Start bitcoind as a daemon. >>> init_database() >>> start_bitcoind() >>> stop_bitcoind() ''' bin_dir, data_dir = preferences.get_bitcoin_dirs() command_args = [] cmd = os.path.join(bin_dir, bitcoin_utils.bitcoind()) command_args.append(cmd) data_dir = bitcoin_utils.strip_testnet_from_data_dir(data_dir=data_dir) command_args.append(f'-datadir={data_dir}') # don't allow any interaction with the user's wallet command_args.append('-disablewallet') 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 in background: {command_args}') # give bitcoind time to start secs = 0 while (not bitcoin_utils.is_bitcoind_running() and secs < 5): sleep(1) secs += 1
def test_update_with_missing_blocks(self): ''' Start the update with missing blocks. ''' # remove a block from the blockchain block_filename = os.path.join(get_data_dir(), 'blocks', 'blk00000.dat') if os.path.exists(block_filename): os.remove(block_filename) request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nUpdating Bitcoin's Blockchain | Blockchain Backup\n</title>" in response.content) self.assertTrue(b"WARNING: Don't shut down your computer before you" in response.content) self.assertTrue( b'<a class="btn btn-secondary " role="button" id="stop_button" href="/bitcoin/interrupt_update/" title="Click to stop updating the blockchain">Stop update</a>' in response.content) self.assertTrue( b'Shutting down before this window says it is safe <em>could damage the blockchain</em>.' in response.content) sleep(60) self.assertFalse(is_bitcoind_running()) shutdown, error_message = test_utils.check_bitcoin_log( is_bitcoind_running) self.assertTrue(shutdown) error = error_message.strip(' ') error_found = 'Fatal LevelDB error' in error or 'Error opening block database' in error self.assertTrue(error_found) self.assertFalse(get_backups_enabled())
def wait_for_status(self): ''' Wait for bitcoin to clean up. Returns True if bitcoin shutdown successfully; otherwise, False. Error message from bitcoind if this is one; otherwise, None. Seconds waiting. >>> from blockchain_backup.bitcoin.tests import utils as test_utils >>> need_backup = False >>> test_utils.init_database() >>> update_task = UpdateTask() >>> update_task.manager = BitcoinManager(update_task.log_name) >>> update_task.wait_for_status() (True, None, 0) ''' WAIT_SECONDS = 10 MAX_SECONDS = 60 # if bitcoin is not running, then give it more time to see # if the debug log is updated with the status seconds = 0 ok, error_message = self.manager.check_bitcoin_log(is_bitcoind_running) while (not ok and seconds < MAX_SECONDS and not is_bitcoind_running()): sleep(WAIT_SECONDS) seconds += WAIT_SECONDS ok, error_message = self.manager.check_bitcoin_log( is_bitcoind_running) if seconds >= MAX_SECONDS: self.log(f'waited {seconds} seconds for bitcoin to finish.') self.log(f'is_bitcoind_running: {is_bitcoind_running()}') return ok, error_message, seconds
def test_update(self): ''' Start the update via views, wait a few minutes, then interrupt it. ''' request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nUpdating Bitcoin's Blockchain | Blockchain Backup\n</title>" in response.content) self.assertTrue(b"WARNING: Don't shut down your computer before you" in response.content) self.assertTrue( b'<a class="btn btn-secondary " role="button" id="stop_button" href="/bitcoin/interrupt_update/" title="Click to stop updating the blockchain">Stop update</a>' in response.content) self.assertTrue( b'Shutting down before this window says it is safe <em>could damage the blockchain</em>.' in response.content) sleep(180) if is_bitcoind_running(): test_utils.stop_bitcoind()
def wait_while_updating(self, bitcoind_process): ''' Wait for the blockchain to be updated. >>> from blockchain_backup.bitcoin.tests import utils as test_utils >>> test_utils.init_database() >>> update_task = UpdateTask() >>> update_task.manager = BitcoinManager(update_task.log_name) >>> bitcoind_process, bitcoind_pid = update_task.start_bitcoind() >>> need_backup = update_task.wait_while_updating(bitcoind_process) >>> print(need_backup) False >>> update_task.stop_bitcoind(bitcoind_process, bitcoind_pid, need_backup) (False, ' Error opening block database.\\n') ''' def get_secs_to_wait(): ''' Wait longer if no real data available yet. ''' if self.current_block > 0: secs_to_wait = WAIT_SECONDS else: secs_to_wait = WAIT_SECONDS * 2 return secs_to_wait WAIT_SECONDS = 30 # seconds self.log('waiting while updating blockchain') # give the system a few seconds to get it started secs = 0 while (not is_bitcoind_running() and secs < (WAIT_SECONDS * 6) and not self.is_interrupted()): sleep(WAIT_SECONDS) secs += WAIT_SECONDS self.current_block = self.manager.get_current_block() need_backup = need_to_backup(self.manager.data_dir, self.current_block) secs_to_wait = get_secs_to_wait() while (is_bitcoind_running() and not need_backup and not self.is_interrupted()): try: if bitcoind_process is None: sleep(secs_to_wait) else: bitcoind_process.wait(secs_to_wait) except TimeoutExpired: pass if is_bitcoind_running() and not self.is_interrupted(): self.current_block = self.manager.get_current_block() need_backup = need_to_backup(self.manager.data_dir, self.current_block) secs_to_wait = get_secs_to_wait() self.log(f'is_bitcoind_running: {is_bitcoind_running()}') self.log(f'need_backup: {need_backup}') self.log(f'is_interrupted: {self.is_interrupted()}') self.log(f'finished waiting; need backup: {need_backup}') return need_backup
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
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
def start_bitcoind(self): ''' Start bitcoind as a daemon. >>> from blockchain_backup.bitcoin.tests import utils as test_utils >>> need_backup = False >>> test_utils.init_database() >>> update_task = UpdateTask() >>> update_task.manager = BitcoinManager(update_task.log_name) >>> bitcoind_process, bitcoind_pid = update_task.start_bitcoind() >>> update_task.stop_bitcoind(bitcoind_process, bitcoind_pid, need_backup) (False, ' Error opening block database.\\n') ''' if is_bitcoind_running(): bitcoind_process = None bitcoind_pid = get_pid(bitcoind()) if bitcoind_pid is None: sleep(5) bitcoind_pid = get_pid(bitcoind()) self.log(f'bitcoind is already running using pid: {bitcoind_pid}') else: bitcoind_pid = None command_args = [] if self.manager.bin_dir is None: command_args.append(bitcoind()) ok = True else: cmd = os.path.join(self.manager.bin_dir, bitcoind()) command_args.append(cmd) ok = os.path.exists(cmd) if ok: extra_args = preferences.get_extra_args() use_test_net = '-testnet' in extra_args if self.manager.data_dir is not None: data_dir = self.manager.data_dir if use_test_net and data_dir.endswith( constants.TEST_NET_SUBDIR): data_dir = data_dir[:data_dir.rfind(constants. TEST_NET_SUBDIR)] command_args.append(f'-datadir={data_dir}') # don't allow any interaction with the user's wallet command_args.append('-disablewallet') if extra_args: for extra_arg in extra_args: command_args.append(extra_arg) command_args.append('-daemon') try: bitcoind_process = Popen(command_args) self.log( f'bitcoind started: {bitcoind_process is not None}') except FileNotFoundError as fnfe: raise BitcoinException(str(fnfe)) else: bitcoind_process = None self.log( f'{bitcoind()} does not exist in {self.manager.bin_dir}') state.set_start_access_time(now()) return bitcoind_process, bitcoind_pid