Skip to content

Commit

Permalink
Recovery status
Browse files Browse the repository at this point in the history
  • Loading branch information
kaloudis committed May 28, 2024
1 parent 853684e commit aa3a26f
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 4 deletions.
14 changes: 13 additions & 1 deletion App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { SafeAreaView } from 'react-native-safe-area-context';
import { BackHandler, NativeEventSubscription, StatusBar } from 'react-native';
import {
BackHandler,
NativeEventSubscription,
StatusBar,
LogBox
} from 'react-native';

LogBox.ignoreAllLogs(); //Ignore all log notifications

import Stores from './stores/Stores';
import NavigationService from './NavigationService';
Expand Down Expand Up @@ -139,6 +146,7 @@ import EditFee from './views/EditFee';
import Seed from './views/Settings/Seed';
import SeedRecovery from './views/Settings/SeedRecovery';
import Sync from './views/Sync';
import SyncRecovery from './views/SyncRecovery';
import LspExplanationFees from './views/Explanations/LspExplanationFees';
import LspExplanationRouting from './views/Explanations/LspExplanationRouting';
import LspExplanationWrappedInvoices from './views/Explanations/LspExplanationWrappedInvoices';
Expand Down Expand Up @@ -603,6 +611,10 @@ export default class App extends React.PureComponent {
name="Sync"
component={Sync}
/>
<Stack.Screen
name="SyncRecovery"
component={SyncRecovery}
/>
<Stack.Screen
name="BumpFee"
component={BumpFee}
Expand Down
2 changes: 2 additions & 0 deletions backends/EmbeddedLND.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const {
sendKeysendPaymentV2,
listPayments,
getNetworkInfo,
getRecoveryInfo,
queryRoutes,
lookupInvoice,
fundingStateStep,
Expand Down Expand Up @@ -75,6 +76,7 @@ export default class EmbeddedLND extends LND {
subscribeCustomMessages = async () => await subscribeCustomMessages();
getMyNodeInfo = async () => await getInfo();
getNetworkInfo = async () => await getNetworkInfo();
getRecoveryInfo = async () => await getRecoveryInfo();
getInvoices = async () => await listInvoices();
createInvoice = async (data: any) =>
await addInvoice({
Expand Down
4 changes: 4 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@
"views.OpenChannel.removeAdditionalChannel": "Remove additional channel",
"views.Wallet.BalancePane.sync.title": "Finishing sync",
"views.Wallet.BalancePane.sync.text": "Hang on tight! You will be ready to use Zeus soon.",
"views.Wallet.BalancePane.recovery.title": "Recovery mode",
"views.Wallet.BalancePane.recovery.text": "Please leave ZEUS open until the process completes.",
"views.Wallet.BalancePane.recovery.textAlt": "Leave ZEUS open until completion.",
"views.Wallet.BalancePane.backup.title": "Back up your funds",
"views.Wallet.BalancePane.backup.text": "Create a backup to never lose access to your bitcoin.",
"views.Wallet.BalancePane.backup.action": "Start backup ->",
Expand Down Expand Up @@ -949,6 +952,7 @@
"views.Sync.tip": "Tip",
"views.Sync.numBlocksUntilSynced": "Number of blocks until synced",
"views.LSPS1.pubkeyAndHostNotFound": "Node pubkey and host are not set",
"views.SyncRecovery.title": "Recovering wallet",
"views.LSPS1.timeoutError": "Did not receive response from server",
"views.LSPS1.channelExpiryBlocks": "Channel Expiry Blocks",
"views.LSPS1.maxChannelExpiryBlocks": "Max channel Expiry Blocks",
Expand Down
41 changes: 41 additions & 0 deletions stores/SyncStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import SettingsStore from './SettingsStore';

export default class SyncStore {
@observable public isSyncing: boolean = false;
@observable public isRecovering: boolean = false;
@observable public recoveryProgress: number | null;
@observable public isInExpressGraphSync: boolean = false;
@observable public bestBlockHeight: number;
@observable public currentBlockHeight: number;
Expand All @@ -26,6 +28,7 @@ export default class SyncStore {
@action
public reset = () => {
this.isSyncing = false;
this.isRecovering = false;
this.isInExpressGraphSync = false;
this.error = false;
};
Expand Down Expand Up @@ -137,4 +140,42 @@ export default class SyncStore {
if (queryMempool) this.getBestBlockHeight();
}
};

@action
public checkRecoveryStatus = () => {
BackendUtils.getRecoveryInfo().then((data: any) => {
if (data.recovery_mode && !data.recovery_finished) {
this.startRecovering();
}
});
};

@action
public getRecoveryStatus = async () => {
await BackendUtils.getRecoveryInfo().then((data: any) => {
if (data.recovery_mode) {
if (data.progress) {
this.recoveryProgress = data.progress;
}
if (data.recovery_finished) {
this.isRecovering = false;
this.recoveryProgress = null;
}
} else {
this.isRecovering = false;
this.recoveryProgress = null;
}
return data;
});
};

@action
public startRecovering = async () => {
this.isRecovering = true;

while (this.isRecovering) {
await sleep(2000);
await this.getRecoveryStatus();
}
};
}
1 change: 1 addition & 0 deletions utils/BackendUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class BackendUtils {
this.call('subscribeCustomMessages', args);
getMyNodeInfo = (...args: any[]) => this.call('getMyNodeInfo', args);
getNetworkInfo = (...args: any[]) => this.call('getNetworkInfo', args);
getRecoveryInfo = (...args: any[]) => this.call('getRecoveryInfo', args);
getInvoices = (...args: any[]) => this.call('getInvoices', args);
createInvoice = (...args: any[]) => this.call('createInvoice', args);
getPayments = (...args: any[]) => this.call('getPayments', args);
Expand Down
92 changes: 92 additions & 0 deletions views/SyncRecovery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React from 'react';
import { Dimensions, View } from 'react-native';
import { inject, observer } from 'mobx-react';
import CircularProgress from 'react-native-circular-progress-indicator';
import { StackNavigationProp } from '@react-navigation/stack';

import Button from '../components/Button';
import Screen from '../components/Screen';
import Header from '../components/Header';

import SyncStore from '../stores/SyncStore';

import { localeString } from '../utils/LocaleUtils';
import { themeColor } from '../utils/ThemeUtils';

interface SyncRecoveryProps {
navigation: StackNavigationProp<any, any>;
SyncStore: SyncStore;
}

@inject('SyncStore')
@observer
export default class SyncRecovery extends React.PureComponent<
SyncRecoveryProps,
{}
> {
render() {
const { navigation, SyncStore } = this.props;
const { recoveryProgress } = SyncStore;

const { width } = Dimensions.get('window');

return (
<Screen>
<Header
leftComponent="Back"
centerComponent={{
text: localeString('views.SyncRecovery.title'),
style: {
color: themeColor('text'),
fontFamily: 'PPNeueMontreal-Book'
}
}}
navigation={navigation}
/>
<View style={{ flex: 1, justifyContent: 'center' }}>
<View style={{ alignItems: 'center', marginBottom: 40 }}>
<CircularProgress
value={
recoveryProgress
? Number(
Math.floor(recoveryProgress * 1000) /
1000
) * 100
: 0
}
radius={width / 3}
inActiveStrokeOpacity={0.5}
activeStrokeWidth={width / 20}
inActiveStrokeWidth={width / 40}
progressValueStyle={{
fontWeight: '100',
color: 'white'
}}
activeStrokeColor={themeColor('highlight')}
activeStrokeSecondaryColor={themeColor('error')}
inActiveStrokeColor={themeColor(
'secondaryBackground'
)}
duration={500}
dashedStrokeConfig={{
count: 50,
width: 4
}}
progressFormatter={(value: number) => {
'worklet';
return value.toFixed && value.toFixed(1); // 1 decimal place
}}
valueSuffix="%"
/>
</View>
</View>
<View style={{ bottom: 15 }}>
<Button
title={localeString('general.goBack')}
onPress={() => navigation.goBack()}
/>
</View>
</Screen>
);
}
}
109 changes: 106 additions & 3 deletions views/Wallet/BalancePane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import NodeInfoStore from '../../stores/NodeInfoStore';
import SettingsStore from '../../stores/SettingsStore';
import SyncStore from '../../stores/SyncStore';

import { version, playStore } from '../../package.json';
import { version } from '../../package.json';

import LockIcon from '../../assets/images/SVG/Lock.svg';

Expand Down Expand Up @@ -69,7 +69,13 @@ export default class BalancePane extends React.PureComponent<
pendingOpenBalance
} = BalanceStore;
const { implementation } = SettingsStore;
const { currentBlockHeight, bestBlockHeight, isSyncing } = SyncStore;
const {
currentBlockHeight,
bestBlockHeight,
recoveryProgress,
isSyncing,
isRecovering
} = SyncStore;

const pendingUnconfirmedBalance = new BigNumber(pendingOpenBalance)
.plus(unconfirmedBlockchainBalance)
Expand Down Expand Up @@ -162,6 +168,103 @@ export default class BalancePane extends React.PureComponent<
marginBottom: 20
}}
>
{isRecovering && recoveryProgress !== 1 && (
<TouchableOpacity
onPress={() => {
if (recoveryProgress) {
navigation.navigate('SyncRecovery');
}
}}
>
<View
style={{
backgroundColor:
themeColor('highlight'),
borderRadius: 10,
margin: 20,
marginBottom: 0,
padding: 15,
borderWidth: 0.5
}}
>
<Text
style={{
fontFamily: 'PPNeueMontreal-Medium',
color: themeColor('background')
}}
>
{`${localeString(
'views.Wallet.BalancePane.recovery.title'
)}${
!recoveryProgress
? ` - ${localeString(
'views.Wallet.BalancePane.recovery.textAlt'
).replace('Zeus', 'ZEUS')}`
: ''
}`}
</Text>
{recoveryProgress && (
<Text
style={{
fontFamily:
'PPNeueMontreal-Book',
color: themeColor('background'),
marginTop: 20
}}
>
{localeString(
'views.Wallet.BalancePane.recovery.text'
).replace('Zeus', 'ZEUS')}
</Text>
)}
{recoveryProgress && (
<View
style={{
marginTop: 30,
flex: 1,
flexDirection: 'row',
display: 'flex',
justifyContent: 'space-between',
minWidth: '100%'
}}
>
<LinearProgress
value={
Math.floor(
recoveryProgress * 100
) / 100
}
variant="determinate"
color={themeColor('background')}
trackColor={themeColor(
'secondaryBackground'
)}
style={{
flex: 1,
flexDirection: 'row'
}}
/>
<Text
style={{
fontFamily:
'PPNeueMontreal-Medium',
color: themeColor(
'background'
),
marginTop: -8,
marginLeft: 14,
height: 40
}}
>
{`${Math.floor(
recoveryProgress * 100
).toString()}%`}
</Text>
</View>
)}
</View>
</TouchableOpacity>
)}
{isSyncing && (
<TouchableOpacity
onPress={() => navigation.navigate('Sync')}
Expand Down Expand Up @@ -379,7 +482,7 @@ export default class BalancePane extends React.PureComponent<
marginBottom: -40
}}
>
{playStore ? `v${version}-play` : `v${version}`}
{`v${version}`}
</Text>
</View>
);
Expand Down
12 changes: 12 additions & 0 deletions views/Wallet/Wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { inject, observer } from 'mobx-react';
import RNRestart from 'react-native-restart';
import { StackNavigationProp } from '@react-navigation/stack';
import SystemNavigationBar from 'react-native-system-navigation-bar';
import EncryptedStorage from 'react-native-encrypted-storage';

import ChannelsPane from '../Channels/ChannelsPane';
import BalancePane from './BalancePane';
Expand Down Expand Up @@ -387,6 +388,8 @@ export default class Wallet extends React.Component<WalletProps, WalletState> {
embeddedLndNetwork === 'Testnet'
);
}
if (implementation === 'embedded-lnd')
SyncStore.checkRecoveryStatus();
await NodeInfoStore.getNodeInfo();
NodeInfoStore.getNetworkInfo();
if (BackendUtils.supportsAccounts()) UTXOsStore.listAccounts();
Expand All @@ -399,6 +402,15 @@ export default class Wallet extends React.Component<WalletProps, WalletState> {
});
}
if (recovery) {
const isBackedUp = await EncryptedStorage.getItem(
'backup-complete'
);
if (!isBackedUp) {
await EncryptedStorage.setItem(
'backup-complete',
JSON.stringify(true)
);
}
if (isSyncing) return;
try {
await ChannelBackupStore.recoverStaticChannelBackup();
Expand Down

0 comments on commit aa3a26f

Please sign in to comment.