Skip to content

Commit

Permalink
Recover send and receive from intermittent fails
Browse files Browse the repository at this point in the history
  • Loading branch information
minibits-cash committed Dec 22, 2023
1 parent bfb0b5b commit 7a74981
Show file tree
Hide file tree
Showing 16 changed files with 381 additions and 134 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ android {
applicationId "com.minibits_wallet"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 31
versionCode 32
versionName "0.1.5"
ndk {
abiFilters 'arm64-v8a', 'x86_64', 'x86', 'armeabi-v7a'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "minibits_wallet",
"version": "0.1.5-beta.18",
"version": "0.1.5-beta.19",
"private": true,
"scripts": {
"android:clean": "cd android && ./gradlew clean",
Expand Down
81 changes: 61 additions & 20 deletions src/models/Mint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export enum MintStatus {
export type MintProofsCounter = {
keyset: string
counter: number
inFlightFrom?: number // starting counter index for pending split request sent to mint (for recovery from failure to receive proofs)
inFlightTo?: number // last counter index for pending split request sent to mint
inFlightTid?: number // related tx id
}

/**
Expand All @@ -35,17 +38,35 @@ export const MintModel = types
types.model('MintProofsCounter', {
keyset: types.string,
counter: types.number,
inFlightFrom: types.maybe(types.number),
inFlightTo: types.maybe(types.number),
inFlightTid: types.maybe(types.number)
})
),
color: types.optional(types.string, colors.palette.iconBlue200),
status: types.optional(types.frozen<MintStatus>(), MintStatus.ONLINE),
createdAt: types.optional(types.Date, new Date()),
})
.actions(withSetPropAction)
.views(self => ({
get currentProofsCounter() {
.actions(withSetPropAction) // TODO start to use across app to avoid pure setter methods, e.g. mint.setProp('color', '#ccc')
.actions(self => ({
getOrCreateProofsCounter() {
const currentKeyset = deriveKeysetId(self.keys)
return self.proofsCounters.find(c => c.keyset === currentKeyset)
const currentCounter = self.proofsCounters.find(c => c.keyset === currentKeyset)

if(!currentCounter) {
const newCounter = {
keyset: currentKeyset,
counter: 0,
}

self.proofsCounters.push(newCounter)
const instance = self.proofsCounters.find(c => c.keyset === currentKeyset) as MintProofsCounter

log.trace('[getOrCreateProofsCounter] new', {newCounter: instance})
return instance
}

return currentCounter
},
}))
.actions(self => ({
Expand Down Expand Up @@ -85,29 +106,49 @@ export const MintModel = types
self.keys = keys
self.keysets = cast(self.keysets)
},
increaseProofsCounter(numberOfProofs: number) {
const currentCounter = self.currentProofsCounter
setProofsInFLightFrom(inFlightFrom: number) {
const currentCounter = self.getOrCreateProofsCounter()
currentCounter.inFlightFrom = inFlightFrom

if (currentCounter) {
log.trace('[increaseProofsCounter]', 'Before update', {currentCounter})
currentCounter.counter += numberOfProofs
log.trace('[increaseProofsCounter]', 'Updated proofsCounter', {numberOfProofs, currentCounter})
} else {
// If the counter doesn't exist, create a new one
const currentKeyset = deriveKeysetId(self.keys)
self.proofsCounters = cast(self.proofsCounters)
},
setProofsInFlightTo(inFlightTo: number) {
const currentCounter = self.getOrCreateProofsCounter()
currentCounter.inFlightTo = inFlightTo

const newCounter = {
keyset: currentKeyset,
counter: numberOfProofs,
}
self.proofsCounters = cast(self.proofsCounters)
},
setInFlightTid(inFlightTid: number) {
const currentCounter = self.getOrCreateProofsCounter()
currentCounter.inFlightTid = inFlightTid

self.proofsCounters.push(newCounter)
self.proofsCounters = cast(self.proofsCounters)
},
resetInFlight() {
const currentCounter = self.getOrCreateProofsCounter()
currentCounter.inFlightFrom = undefined
currentCounter.inFlightTo = undefined
currentCounter.inFlightTid = undefined

log.trace('[resetInFlight]', 'Reset proofsCounter')
self.proofsCounters = cast(self.proofsCounters)
},
increaseProofsCounter(numberOfProofs: number) {
const currentCounter = self.getOrCreateProofsCounter()
currentCounter.counter += numberOfProofs
log.trace('[increaseProofsCounter]', 'Increased proofsCounter', {numberOfProofs, currentCounter})

log.trace('[increaseProofsCounter]', 'Adding new proofsCounter', {newCounter})
}
// Make sure to cast the frozen array back to a mutable array
self.proofsCounters = cast(self.proofsCounters)
},
decreaseProofsCounter(numberOfProofs: number) {
const currentCounter = self.getOrCreateProofsCounter()
currentCounter.counter -= numberOfProofs
Math.max(0, currentCounter.counter)
log.trace('[decreaseProofsCounter]', 'Decreased proofsCounter', {numberOfProofs, currentCounter})

self.proofsCounters = cast(self.proofsCounters)
},
}))


Expand Down
24 changes: 1 addition & 23 deletions src/models/MintsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,7 @@ export const MintsStoreModel = types
unblockMint(blockedMint: Mint) {
self.blockedMintUrls.remove(blockedMint.mintUrl)
log.debug('[unblockMint]', 'Mint unblocked in MintsStore')
},
increaseProofsCounter(mintUrl: string, numberOfProofs: number) {
const mintInstance = self.findByUrl(mintUrl)

if(mintInstance) {
mintInstance.increaseProofsCounter(numberOfProofs)
return mintInstance.currentProofsCounter
}

log.warn('[increaseProofsCounter]', 'Could not find mint', {mintUrl})
return 0

},
}
}))
.views(self => ({
get mintCount() {
Expand Down Expand Up @@ -135,16 +123,6 @@ export const MintsStoreModel = types
}
return missingMints
},
currentProofsCounterValue(mintUrl: string) {
const mintInstance = self.findByUrl(mintUrl)

if (mintInstance) {
return mintInstance.currentProofsCounter?.counter || 0
}

log.warn('[currentProofsCounter]', 'Could not find mint', {mintUrl})
return 0
},
}))

export interface MintsStore extends Instance<typeof MintsStoreModel> {}
Expand Down
4 changes: 3 additions & 1 deletion src/models/ProofsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ export const ProofsStoreModel = types

// Handle counter increment
const mintsStore = getRootStore(self).mintsStore
mintsStore.increaseProofsCounter(newProofs[0].mintUrl as string, addedProofs.length)
const mintInstance = mintsStore.findByUrl(newProofs[0].mintUrl as string)

mintInstance?.increaseProofsCounter(addedProofs.length)

log.debug('[addProofs]', `Added new ${addedProofs.length}${isPending ? ' pending' : ''} proofs to the ProofsStore`,)

Expand Down
4 changes: 2 additions & 2 deletions src/models/RelaysStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ export const RelaysStoreModel = types
relayInstance?.setError(error)
}

log.trace('[addOrUpdateRelay]', 'Relay updated in the RelaysStore', {relay})
// log.trace('[addOrUpdateRelay]', 'Relay updated in the RelaysStore', {relay})
} else {
const normalized = NostrClient.getNormalizedRelayUrl(relay.url)

log.trace('[addOrUpdateRelay]', 'Normalized URL', normalized)
// log.trace('[addOrUpdateRelay]', 'Normalized URL', normalized)
relay.url = normalized

const relayInstance = RelayModel.create(relay)
Expand Down
4 changes: 2 additions & 2 deletions src/models/TransactionsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export const TransactionsStoreModel = types
log.debug('[addTransactionsToModel]', `${inStoreTransactions.length} new transactions added to TransactionsStore`,
)
},
updateStatus: flow(function* updateStatus(
updateStatus: flow(function* updateStatus( // TODO append, not replace status to align behavior with updateStatuses
id: number,
status: TransactionStatus,
data: string,
Expand All @@ -110,7 +110,7 @@ export const TransactionsStoreModel = types
// Update in the model
if (transactionInstance) {
transactionInstance.status = status
transactionInstance.data = data
transactionInstance.data = data
log.debug('[updateStatus]', 'Transaction status and data updated in TransactionsStore', {id, status})
}

Expand Down
2 changes: 1 addition & 1 deletion src/navigation/TabsNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export type WalletStackParamList = {
Receive: {encodedToken? : string}
SendOptions: undefined
Send: {contact?: Contact, relays?: string[], paymentOption?: SendOption}
Scan: {expectedType?: IncomingDataType}
Scan: undefined
TranDetail: {id: number}
TranHistory: undefined
PaymentRequests: undefined
Expand Down
2 changes: 1 addition & 1 deletion src/screens/ReceiveOptionsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const ReceiveOptionsScreen: FC<WalletStackScreenProps<'ReceiveOptions'>>


const onScan = async function () {
navigation.navigate('Scan', {})
navigation.navigate('Scan')
}


Expand Down
2 changes: 1 addition & 1 deletion src/screens/RemoteRecoveryScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ export const RemoteRecoveryScreen: FC<AppStackScreenProps<'RemoteRecovery'>> = o
}

// need to move counter by whole interval to avoid duplicate _B!!!
mintsStore.increaseProofsCounter(mint.mintUrl, Math.abs(endIndex - startIndex))
mint.increaseProofsCounter(Math.abs(endIndex - startIndex))

if(newKeys) {updateMintKeys(mint.mintUrl as string, newKeys)}

Expand Down
20 changes: 2 additions & 18 deletions src/screens/ScanScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@ const hasAndroidCameraPermission = async () => {


export const ScanScreen: FC<WalletStackScreenProps<'Scan'>> = function ScanScreen(_props) {
const {navigation, route} = _props
const {navigation} = _props
useHeader({
title: 'Scan QR code',
titleStyle: {fontFamily: typography.primary?.medium},
leftIcon: 'faArrowLeft',
onLeftPress: () => navigation.goBack(),
})

const [shouldLoad, setShouldLoad] = useState<boolean>(false)
const [expected, setExpected] = useState<IncomingDataType>()
const [shouldLoad, setShouldLoad] = useState<boolean>(false)
const [isScanned, setIsScanned] = useState<boolean>(false)
const [error, setError] = useState<AppError | undefined>()

Expand All @@ -44,21 +43,6 @@ export const ScanScreen: FC<WalletStackScreenProps<'Scan'>> = function ScanScree
})()
}, [])


useEffect(() => {
const setExpectedType = async () => {
const {expectedType} = route.params

if(expectedType) {
log.trace('Got expectedType', expectedType)
setExpected(expectedType)
}
}

setExpectedType()
}, [route.params?.expectedType])


const onReadCode = async function(event: any) {
setIsScanned(true)
const scanned = event.nativeEvent.codeStringValue
Expand Down
2 changes: 1 addition & 1 deletion src/screens/SendOptionsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const SendOptionsScreen: FC<WalletStackScreenProps<'SendOptions'>> = obse


const onScan = async function () {
navigation.navigate('Scan', {expectedType: IncomingDataType.INVOICE})
navigation.navigate('Scan')
}


Expand Down
8 changes: 5 additions & 3 deletions src/screens/WalletScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ export const WalletScreen: FC<WalletScreenProps> = observer(
}

Wallet.checkPendingSpent().catch(e => false)
Wallet.checkPendingTopups().catch(e => false)
Wallet.checkPendingTopups().catch(e => false)
Wallet.checkInFlight().catch(e => false)

}, 100)
}, [])
Expand Down Expand Up @@ -245,7 +246,8 @@ export const WalletScreen: FC<WalletScreenProps> = observer(
}

Wallet.checkPendingSpent().catch(e => false)
Wallet.checkPendingTopups().catch(e => false)
Wallet.checkPendingTopups().catch(e => false)
Wallet.checkInFlight().catch(e => false)
}, 100)
}

Expand Down Expand Up @@ -352,7 +354,7 @@ export const WalletScreen: FC<WalletScreenProps> = observer(
}

const gotoScan = function () {
navigation.navigate('Scan', {})
navigation.navigate('Scan')
}

const gotoTranHistory = function () {
Expand Down
9 changes: 8 additions & 1 deletion src/services/cashu/cashuUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Mint} from '../../models/Mint'
import {
getDecodedToken,
AmountPreference,
getDecodedToken,
} from '@cashu/cashu-ts'
import cloneDeep from 'lodash.clonedeep'
import AppError, {Err} from '../../utils/AppError'
Expand Down Expand Up @@ -131,6 +132,11 @@ const getProofsAmount = function (proofs: Array<Proof>): number {
}


const getAmountPreferencesCount = function (amountPreferences: AmountPreference[]): number {
return amountPreferences.reduce((total, preference) => total + preference.count, 0);
}


const getMintsFromToken = function (token: Token): string[] {
const mints = token.token.map(item => item.mint)
return Array.from(new Set(mints)) // make sure the mints are not duplicated
Expand Down Expand Up @@ -266,6 +272,7 @@ export const CashuUtils = {
getTokenAmounts,
getTokenEntryAmount,
getProofsAmount,
getAmountPreferencesCount,
getMintsFromToken,
updateMintProofs,
getProofsFromTokenEntries,
Expand Down
Loading

0 comments on commit 7a74981

Please sign in to comment.