diff --git a/src/core/currency/change-server-connection.ts b/src/core/currency/change-server-connection.ts index c48b706a..953df279 100644 --- a/src/core/currency/change-server-connection.ts +++ b/src/core/currency/change-server-connection.ts @@ -26,6 +26,7 @@ export function connectChangeServer( callbacks: ChangeServerCallbacks ): ChangeServerConnection { let ws: WebSocket + let closing = false function makeWs(): void { ws = new WebSocket(url) ws.binaryType = 'arraybuffer' @@ -38,15 +39,17 @@ export function connectChangeServer( out.connected = false codec.handleClose() callbacks.handleDisconnect() + // Reconnect after 5 seconds, unless intentionally closed: + if (!closing) { + setTimeout(() => { + makeWs() + }, 5000) + } }) ws.addEventListener('error', errEvent => { console.error('changeServer websocket error:', errEvent) ws.close() - // Reconnect after 5 seconds: - setTimeout(() => { - makeWs() - }, 5000) }) ws.addEventListener('open', () => { @@ -87,6 +90,7 @@ export function connectChangeServer( }, close() { + closing = true ws.close() }, diff --git a/src/core/currency/currency-pixie.ts b/src/core/currency/currency-pixie.ts index c1aca16e..1a1514b5 100644 --- a/src/core/currency/currency-pixie.ts +++ b/src/core/currency/currency-pixie.ts @@ -226,7 +226,8 @@ export const currency: TamePixie = combinePixies({ wallet.changeServiceSubscriptions.some( subscription => subscription.status === 'subscribing' || - subscription.status === 'resubscribing' + subscription.status === 'resubscribing' || + subscription.status === 'reconnecting' ) ) const indexToWalletId: Array<{ @@ -292,7 +293,8 @@ export const currency: TamePixie = combinePixies({ .subscribe(subscribeParams) .catch(err => { input.props.log(`Failed to subscribe: ${String(err)}`) - return [0] as SubscribeResult[] + // Return failure result for each subscription in the batch: + return subscribeParams.map(() => 0 as SubscribeResult) }) results.push(...r) } @@ -347,7 +349,8 @@ export const currency: TamePixie = combinePixies({ subscription => subscription.status === 'subscribing' || subscription.status === 'subscribingSlowly' || - subscription.status === 'resubscribing' + subscription.status === 'resubscribing' || + subscription.status === 'reconnecting' ) .map(subscription => ({ ...subscription, diff --git a/src/core/currency/wallet/currency-wallet-callbacks.ts b/src/core/currency/wallet/currency-wallet-callbacks.ts index 2e095ca3..b0b8b9a5 100644 --- a/src/core/currency/wallet/currency-wallet-callbacks.ts +++ b/src/core/currency/wallet/currency-wallet-callbacks.ts @@ -296,15 +296,26 @@ export function makeCurrencyWalletCallbacks( onSubscribeAddresses( paramsOrAddresses: EdgeSubscribedAddress[] | string[] ) { + // Get existing subscriptions to preserve checkpoints + const existingSubscriptions = + input.props.walletState.changeServiceSubscriptions + const subscribedAddresses: EdgeSubscribedAddress[] = - paramsOrAddresses.map(param => - typeof param === 'string' - ? { - address: param, - checkpoint: undefined - } - : param - ) + paramsOrAddresses.map(param => { + const address = typeof param === 'string' ? param : param.address + // Preserve existing checkpoint if we have one for this address. + // Use case-insensitive comparison for blockchain addresses. + const existing = existingSubscriptions.find( + sub => sub.address.toLowerCase() === address.toLowerCase() + ) + // Prefer explicit checkpoint from param, fall back to existing + const explicitCheckpoint = + typeof param === 'object' ? param.checkpoint : undefined + return { + address, + checkpoint: explicitCheckpoint ?? existing?.checkpoint + } + }) // Save subscribed addresses to disk (along with current checkpoint) saveSeenTxCheckpointFile( input, diff --git a/src/core/currency/wallet/currency-wallet-pixie.ts b/src/core/currency/wallet/currency-wallet-pixie.ts index 2b310532..ca229be8 100644 --- a/src/core/currency/wallet/currency-wallet-pixie.ts +++ b/src/core/currency/wallet/currency-wallet-pixie.ts @@ -45,6 +45,7 @@ import { loadSeenTxCheckpointFile, loadTokensFile, loadTxFileNames, + saveSeenTxCheckpointFile, writeTokensFile } from './currency-wallet-files' import { CurrencyWalletState, initialTokenIds } from './currency-wallet-reducer' @@ -273,7 +274,7 @@ export const walletPixie: TamePixie = combinePixies({ ), syncNetworkUpdate: filterPixie( - (_input: CurrencyWalletInput) => { + (input: CurrencyWalletInput) => { return { async update(props) { if (props.walletOutput == null) return @@ -308,6 +309,17 @@ export const walletPixie: TamePixie = combinePixies({ walletId: props.walletId } }) + // Persist the updated checkpoints to disk: + const subscribedAddresses = + walletState.changeServiceSubscriptions.map(subscription => ({ + address: subscription.address, + checkpoint: subscription.checkpoint + })) + await saveSeenTxCheckpointFile( + input, + walletState.seenTxCheckpoint ?? undefined, + subscribedAddresses + ) }, destroy() {} }