def get_backup_subdir(): ''' Get subdir name if its in the data directory. >>> from blockchain_backup.bitcoin.preferences import get_preferences, save_preferences >>> from blockchain_backup.bitcoin.tests import utils as test_utils >>> test_utils.init_database() >>> get_backup_subdir() 'backups' >>> prefs = get_preferences() >>> prefs.backup_dir = '/tmp/bitcoin/backups' >>> save_preferences(prefs) >>> get_backup_subdir() is None True ''' from blockchain_backup.bitcoin.preferences import get_backup_dir, get_data_dir data_dir = get_data_dir() backup_dir = get_backup_dir() # get the name of the subdirectory of the backup # if its in the data directory index = backup_dir.find(data_dir) if index >= 0: backup_subdir = backup_dir[index + len(data_dir):] if backup_subdir.startswith(os.sep): backup_subdir = backup_subdir[1:] if backup_subdir.endswith(os.sep): backup_subdir = backup_subdir[:-1] else: backup_subdir = None return backup_subdir
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 test_access_wallet_with_bad_data(self): ''' Test access wallet with bad data ''' MINUTE = 60 WAIT_SECONDS = 10 MAX_SECONDS = 3 * MINUTE # 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/access_wallet/') response = AccessWallet.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nAccessing Bitcoin Core Wallet | Blockchain Backup\n</title>" in response.content) self.assertTrue( b"WARNING: Do not shut down your computer until Bitcoin-QT stops completely." in response.content) self.assertTrue( b'Bitcoin-QT will start in another window.' in response.content) self.assertFalse( b'Shutting down before this window says it is safe <em>could damage the blockchain</em>.' in response.content) done = False error_found = False error_message = None secs = 0 while not done: shutdown, error_message = test_utils.check_bitcoin_log() if error_message: error = error_message.strip(' ') error_found = 'Fatal LevelDB error' in error or 'Error opening block database' in error done = shutdown or error_found or not get_backups_enabled( ) or secs > MAX_SECONDS if not done: sleep(WAIT_SECONDS) secs += WAIT_SECONDS if not error_found: shutdown, error_message = test_utils.check_bitcoin_log() 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) test_utils.stop_bitcoin_qt() self.assertFalse(get_backups_enabled())
def get_page(self, request): # let's see what we know about the environment log('getting home page') clear_action_updates() # last block in django database; may be different from last in blockchain last_block_updated = state.get_last_block_updated() # ready if blockchain-backup has processed some blockchain data bcb_run_already = last_block_updated > 0 bin_dir_ok = preferences.bin_dir_ok() data_dir = preferences.get_data_dir() backup_dir_ok, backup_dir_error = preferences.backup_dir_ok() backup_dir = preferences.get_backup_dir() last_bcb_version = state.get_latest_bcb_version() current_core_version = bitcoin_utils.get_bitcoin_version() last_core_version = state.get_latest_core_version() if bcb_run_already: data_dir_ok, __ = preferences.data_dir_ok() else: if data_dir and os.path.exists(data_dir): data_dir_ok, __ = preferences.data_dir_ok() else: data_dir_ok = False bitcoin_utils.check_for_updates() params = { 'data_dir': data_dir, 'data_dir_ok': data_dir_ok, 'backup_dir': backup_dir, 'backup_dir_ok': backup_dir_ok, 'backup_dir_error': backup_dir_error, 'last_bcb_version': last_bcb_version, 'bcb_up_to_date': last_bcb_version >= BLOCKCHAIN_BACKUP_VERSION, 'last_core_version': last_core_version, 'core_up_to_date': last_core_version >= current_core_version, 'need_backup': bitcoin_utils.get_next_backup_time() < now(), 'last_backed_up_time': state.get_last_backed_up_time(), } #log('params: {}'.format(params)) response = get_home_page_response(request, bcb_run_already, bin_dir_ok, params) return response
def get_page(self, request): error = None data_dir = preferences.get_data_dir() if not os.path.exists(data_dir): try: os.makedirs(data_dir) except: # 'bare except' because it catches more than "except Exception" error = f'Unable to create {data_dir} as {whoami()}' if os.path.exists(data_dir): __, error = bitcoin_utils.is_dir_writeable(data_dir) if error is not None: log(error) messages.error(request, error) response = HttpResponseRedirect('/') return response
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 strip_testnet_from_data_dir(data_dir=None): ''' Get the data dirname without the "testnet3" subdir, if appropriate. >>> from blockchain_backup.bitcoin.tests import utils as test_utils >>> test_utils.init_database() >>> strip_testnet_from_data_dir() '/tmp/bitcoin/data' ''' from blockchain_backup.bitcoin.preferences import get_data_dir, get_extra_args if data_dir is None: data_dir = get_data_dir() use_test_net = constants.TESTNET_FLAG in get_extra_args() if use_test_net and data_dir.endswith(constants.TEST_NET_SUBDIR): new_data_dir = data_dir[:data_dir.rfind(constants.TEST_NET_SUBDIR)] else: new_data_dir = data_dir return new_data_dir
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())