From 3affc6ed311296e61fbcde67fccfe65cd3e712ee Mon Sep 17 00:00:00 2001 From: minibits-cash Date: Wed, 16 Oct 2024 16:42:23 +0200 Subject: [PATCH] Send large ecash tokens in batches, performance improvements for large wallets. --- package.json | 2 +- src/screens/DeveloperScreen.tsx | 108 ++++++++++++++++++++++------- src/screens/ExportBackupScreen.tsx | 72 +++++++++++-------- src/services/sqlite.ts | 2 +- src/services/wallet/sendTask.ts | 40 ++++++----- src/services/walletService.ts | 69 ++++++++++++------ 6 files changed, 194 insertions(+), 99 deletions(-) diff --git a/package.json b/package.json index 45942ff..1bcb835 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minibits_wallet", - "version": "0.1.9-beta.23", + "version": "0.1.9-beta.24", "private": true, "scripts": { "android:clean": "cd android && ./gradlew clean", diff --git a/src/screens/DeveloperScreen.tsx b/src/screens/DeveloperScreen.tsx index e0a87e1..38a0c19 100644 --- a/src/screens/DeveloperScreen.tsx +++ b/src/screens/DeveloperScreen.tsx @@ -37,6 +37,7 @@ import { LogLevel } from '../services/log/logTypes' import { getSnapshot } from 'mobx-state-tree' import { delay } from '../utils/delay' import RNExitApp from 'react-native-exit-app' +import { TransactionStatus } from '../models/Transaction' // refresh @@ -47,7 +48,7 @@ export const DeveloperScreen: FC> = observ onLeftPress: () => navigation.goBack(), }) - const {transactionsStore, userSettingsStore} = useStores() + const {transactionsStore, userSettingsStore, proofsStore} = useStores() const [isLoading, setIsLoading] = useState(false) const [rnVersion, setRnVersion] = useState('') @@ -75,7 +76,7 @@ export const DeveloperScreen: FC> = observ init() }, []) - // Reset of whole model state and reload from DB + // Reset of transaction model state and reload from DB const syncTransactionsFromDb = async function () { setIsLoading(true) try { @@ -105,6 +106,48 @@ export const DeveloperScreen: FC> = observ } + const deletePending = async function () { + Alert.alert( + translate("common.confirmAlertTitle"), + "This action can not be undone. Use only in development or testing.", + [ + { + text: translate('common.cancel'), + style: 'cancel', + onPress: () => { /* Action canceled */ }, + }, + { + text: translate('common.confirm'), + onPress: async () => { + try { + setIsLoading(true) + const rows = Database.deleteTransactionsByStatus(TransactionStatus.PENDING) + + const pending = proofsStore.allPendingProofs + const pendingCount = proofsStore.pendingProofsCount.valueOf() + + if(pendingCount > 0) { + proofsStore.removeProofs(pending, true, false) // remove pending proofs and spend the in db + } + + if(rows?.length && rows.length > 0) { + await syncTransactionsFromDb() + } + + setIsLoading(false) + setInfo(`Removed ${rows?.length || 0} transactions from the database and ${pendingCount} proofs from the wallet state`) + + } catch (e: any) { + handleError(e) + } + }, + }, + ], + ) + + } + + const toggleLogLevelSelector = () => setIsLogLevelSelectorVisible(previousState => !previousState) @@ -180,9 +223,31 @@ export const DeveloperScreen: FC> = observ style={{color: headerTitle}} /> - + + } + style={$item} + /> + } + /> > = observ } /> } - style={$item} - /> - } - /> - } style={$item} onPress={factoryReset} + topSeparator /> + } /> diff --git a/src/screens/ExportBackupScreen.tsx b/src/screens/ExportBackupScreen.tsx index b87cebf..a8872c9 100644 --- a/src/screens/ExportBackupScreen.tsx +++ b/src/screens/ExportBackupScreen.tsx @@ -42,7 +42,7 @@ import { verticalScale } from '@gocodingnow/rn-size-matters' interface ExportBackupScreenProps extends SettingsStackScreenProps<'ExportBackup'> {} -const OPTIMIZE_FROM_PROOFS_COUNT = 100 +const OPTIMIZE_FROM_PROOFS_COUNT = 5 export const ExportBackupScreen: FC = function ExportBackup(_props) { @@ -65,6 +65,7 @@ export const ExportBackupScreen: FC = const [isLoading, setIsLoading] = useState(false) const [isSendAllSentToQueue, setIsSendAllSentToQueue] = useState(false) const [isReceiveBatchSentToQueue, setIsReceiveBatchSentToQueue] = useState(false) + const [totalProofsCount, setTotalProofsCount] = useState(0) const [totalSentProofsCount, setTotalSentProofsCount] = useState(0) const [totalReceiveErrorCount, setTotalReceiveErrorCount] = useState(0) const [totalReceiveCompleteCount, setTotalReceiveCompleteCount] = useState(0) @@ -85,12 +86,14 @@ export const ExportBackupScreen: FC = await proofsStore.loadProofsFromDatabase() const orphaned = proofsStore.allProofs.filter(proof => !proof.mintUrl) + if (orphaned.length > 0) { setOrphanedProofs(orphaned) setInfo(`Found ${orphaned.length} orphaned proofs not belonging to any active mint. Those won't be included to the backup, but you can copy them separately.`) } // log.trace('[loadProofs]', {refreshedProofs: proofsStore.proofs}) + setTotalProofsCount(proofsStore.proofsCount) setIsLoading(false) } catch (e: any) { handleError(e) @@ -135,7 +138,7 @@ export const ExportBackupScreen: FC = } return () => { - EventEmitter.off('ev_sendTask_result', handleSendAllResult) + EventEmitter.off('ev_sendTask_result', handleSendAllResult) } }, [isSendAllSentToQueue]) @@ -151,14 +154,18 @@ export const ExportBackupScreen: FC = if (error) { setTotalReceiveErrorCount(prev => prev + 1) } else { - setTotalReceiveCompleteCount(prev => prev + 1) - } + setTotalReceiveCompleteCount(prev => prev + 1) + } } if(isReceiveBatchSentToQueue) { EventEmitter.on('ev_receiveTask_result', handleReceiveTaskResult) } + return () => { + EventEmitter.off('ev_receiveTask_result', handleReceiveTaskResult) + } + }, [isReceiveBatchSentToQueue]) @@ -169,12 +176,12 @@ export const ExportBackupScreen: FC = setIsLoading(false) - const currentProofsCount = proofsStore.proofsCount + const currentProofsCount = proofsStore.proofsCount let message = `Original proofs count: ${totalSentProofsCount}, Optimized proofs count: ${currentProofsCount}` if (totalReceiveErrorCount > 0) { - message += `, errors: ${totalReceiveErrorCount}` + message += `, Errors: ${totalReceiveErrorCount}` } setResultModalInfo({ @@ -185,15 +192,18 @@ export const ExportBackupScreen: FC = setIsResultModalVisible(true) } - if(totalReceiveCompleteCount > 0 || totalReceiveCompleteCount > 0) { + if(totalReceiveCompleteCount > 0 || totalReceiveErrorCount > 0) { showProofOptimizationResult() } }, [totalReceiveErrorCount, totalReceiveCompleteCount]) - const toggleResultModal = () => - setIsResultModalVisible(previousState => !previousState) + const toggleResultModal = () => { + setIsResultModalVisible(previousState => !previousState) + WalletTask.syncPendingStateWithMints() + } + const toggleBackupEcashSwitch = () => @@ -221,7 +231,9 @@ export const ExportBackupScreen: FC = { text: translate('common.confirm'), onPress: async () => { - // Moves all wallet proofs to pending in transactions split by mints and by units and in offline mode + // Moves all wallet proofs to pending in transactions + // split by mints and by units and in offline mode. + // Supports batching in case proofs count is above limit. setIsLoading(true) setIsSendAllSentToQueue(true) WalletTask.sendAll() @@ -578,27 +590,27 @@ export const ExportBackupScreen: FC = - {proofsStore.proofsCount + proofsStore.pendingProofsCount > 0 && ( + {totalProofsCount > 0 && ( - {proofsStore.proofsCount > OPTIMIZE_FROM_PROOFS_COUNT && ( -