Skip to content
Permalink
Browse files

feat(lnd): track wallet recovery process

Fix #2080
  • Loading branch information...
mrfelton committed Apr 22, 2019
1 parent 4e6107a commit f31f0c688e657f80c2439e8b4de019acc122c559
@@ -12,43 +12,58 @@ import messages from './messages'
const getSyncMessages = ({
syncStatus,
syncPercentage,
recoveryPercentage,
neutrinoBlockHeight,
neutrinoCfilterHeight,
neutrinoRecoveryHeight,
blockHeight,
intl,
syncMessageExtraDetail,
syncMessageDetail,
}) => {
let caption = intl.formatMessage({ ...messages.sync_caption })
let mainMessage
let extraDetailMessage = syncMessageExtraDetail
let detailMessage = syncMessageDetail

if (syncStatus === 'waiting') {
mainMessage = intl.formatMessage({ ...messages.waiting_for_peers })
} else if (syncStatus === 'in-progress') {
} else if (['in-progress', 'recovering'].includes(syncStatus)) {
if (typeof syncPercentage === 'undefined') {
mainMessage = intl.formatMessage({ ...messages.preparing })
detailMessage = null
extraDetailMessage = null
} else {
mainMessage = `${syncPercentage}%`
detailMessage = intl.formatMessage(
{ ...messages.block_progress },
{
currentBlock: neutrinoBlockHeight.toLocaleString(),
totalBlocks: blockHeight.toLocaleString(),
}
)
extraDetailMessage = intl.formatMessage(
{ ...messages.filter_progress },
{
currentFilter: neutrinoCfilterHeight.toLocaleString(),
totalFilters: blockHeight.toLocaleString(),
}
)
if (syncStatus === 'in-progress') {
mainMessage = `${syncPercentage}%`
detailMessage = intl.formatMessage(
{ ...messages.block_progress },
{
currentBlock: neutrinoBlockHeight.toLocaleString(),
totalBlocks: blockHeight.toLocaleString(),
}
)
extraDetailMessage = intl.formatMessage(
{ ...messages.filter_progress },
{
currentFilter: neutrinoCfilterHeight.toLocaleString(),
totalFilters: blockHeight.toLocaleString(),
}
)
} else if (syncStatus === 'recovering') {
caption = intl.formatMessage({ ...messages.recovery_caption })
mainMessage = `${recoveryPercentage}%`
detailMessage = intl.formatMessage(
{ ...messages.filter_progress },
{
currentFilter: neutrinoRecoveryHeight.toLocaleString(),
totalFilters: blockHeight.toLocaleString(),
}
)
}
}
}
return { mainMessage, extraDetailMessage, detailMessage }
return { caption, mainMessage, extraDetailMessage, detailMessage }
}

const Syncing = props => {
@@ -79,10 +94,12 @@ const Syncing = props => {
const {
hasSynced,
syncPercentage,
recoveryPercentage,
address,
blockHeight,
neutrinoBlockHeight,
neutrinoCfilterHeight,
neutrinoRecoveryHeight,
isLightningGrpcActive,
network,
showNotification,
@@ -98,11 +115,13 @@ const Syncing = props => {
return <Redirect to="/app" />
}

const { mainMessage, extraDetailMessage, detailMessage } = getSyncMessages({
const { caption, mainMessage, extraDetailMessage, detailMessage } = getSyncMessages({
syncStatus,
syncPercentage,
recoveryPercentage,
neutrinoBlockHeight,
neutrinoCfilterHeight,
neutrinoRecoveryHeight,
blockHeight,
intl,
syncMessageExtraDetail,
@@ -173,16 +192,27 @@ const Syncing = props => {
width={9 / 16}
>
<Text fontWeight="normal" mb={3}>
<FormattedMessage {...messages.sync_caption} />
{caption}
</Text>
<Heading.h1 mb={2}>{mainMessage}</Heading.h1>
<Box bg="grey" css={{ height: '4px' }} mb={2} width={1}>
<Box
bg="lightningOrange"
css={{ height: '100%' }}
width={syncPercentage ? `${syncPercentage}%` : 0}
/>
</Box>
{syncStatus === 'in-progress' && (
<Box bg="grey" css={{ height: '4px' }} mb={2} width={1}>
<Box
bg="lightningOrange"
css={{ height: '100%' }}
width={syncPercentage ? `${syncPercentage}%` : 0}
/>
</Box>
)}
{syncStatus === 'recovering' && (
<Box bg="grey" css={{ height: '4px' }} mb={2} width={1}>
<Box
bg="lightningOrange"
css={{ height: '100%' }}
width={recoveryPercentage ? `${recoveryPercentage}%` : 0}
/>
</Box>
)}

<Text>{detailMessage}</Text>
<Text>{extraDetailMessage}</Text>
@@ -201,6 +231,8 @@ Syncing.propTypes = {
network: PropTypes.string,
neutrinoBlockHeight: PropTypes.number,
neutrinoCfilterHeight: PropTypes.number,
neutrinoRecoveryHeight: PropTypes.number,
recoveryPercentage: PropTypes.number,
setIsWalletOpen: PropTypes.func.isRequired,
showNotification: PropTypes.func.isRequired,
syncPercentage: PropTypes.number,
@@ -6,12 +6,14 @@ export default defineMessages({
grab_coffee: 'you might want to grab a coffee or try again later!',
waiting_for_peers: 'Waiting for peers…',
preparing: 'Preparing…',
recovering: 'Recovering…',
sync_title: 'Welcome back to your wallet!',
sync_description: 'Please wait while we fetch all of your latest data from the blockchain.',
fund_title: 'Fund your wallet',
fund_description: 'Might as well fund your wallet while you’re waiting to sync.',
fund_link: 'Get testnet coins',
sync_caption: 'Syncing with the blockchain',
recovery_caption: 'Recovering wallet',
block_progress: 'Block {currentBlock} of {totalBlocks}',
filter_progress: 'Commitment Filter {currentFilter} of {totalFilters}',
tutorials_list_description: 'Need help? Have a look at our tutorials',
@@ -15,9 +15,11 @@ const mapStateToProps = state => ({
hasSynced: infoSelectors.hasSynced(state),
syncStatus: neutrinoSelectors.neutrinoSyncStatus(state),
syncPercentage: neutrinoSelectors.neutrinoSyncPercentage(state),
recoveryPercentage: neutrinoSelectors.neutrinoRecoveryPercentage(state),
blockHeight: neutrinoSelectors.blockHeight(state),
neutrinoBlockHeight: neutrinoSelectors.neutrinoBlockHeight(state),
neutrinoCfilterHeight: neutrinoSelectors.neutrinoCfilterHeight(state),
neutrinoRecoveryHeight: neutrinoSelectors.neutrinoRecoveryHeight(state),
isLightningGrpcActive: state.lnd.isLightningGrpcActive,
network: state.info.network,
})
@@ -20,10 +20,12 @@ export const STOP_NEUTRINO_FAILURE = 'STOP_NEUTRINO_FAILURE'
export const RECEIVE_CURRENT_BLOCK_HEIGHT = 'RECEIVE_CURRENT_BLOCK_HEIGHT'
export const RECEIVE_LND_BLOCK_HEIGHT = 'RECEIVE_LND_BLOCK_HEIGHT'
export const RECEIVE_LND_CFILTER_HEIGHT = 'RECEIVE_LND_CFILTER_HEIGHT'
export const RECEIVE_LND_RECOVERY_HEIGHT = 'RECEIVE_LND_RECOVERY_HEIGHT'

export const SET_SYNC_STATUS_PENDING = 'SET_SYNC_STATUS_PENDING'
export const SET_SYNC_STATUS_WAITING = 'SET_SYNC_STATUS_WAITING'
export const SET_SYNC_STATUS_IN_PROGRESS = 'SET_SYNC_STATUS_IN_PROGRESS'
export const SET_SYNC_STATUS_RECOVERING = 'SET_SYNC_STATUS_RECOVERING'
export const SET_SYNC_STATUS_COMPLETE = 'SET_SYNC_STATUS_COMPLETE'

export const SET_GRPC_ACTIVE_INTERFACE = 'SET_GRPC_ACTIVE_INTERFACE'
@@ -101,6 +103,10 @@ export const initNeutrino = () => async (dispatch, getState) => {
'NEUTRINO_GOT_LND_CFILTER_HEIGHT',
proxyValue(height => dispatch(neutrinoCfilterHeight(height)))
)
neutrino.on(
'NEUTRINO_GOT_WALLET_RECOVERY_HEIGHT',
proxyValue(height => dispatch(neutrinoRecoveryHeight(height)))
)

// Hook up event listeners for sync status updates.
neutrino.on(
@@ -115,6 +121,10 @@ export const initNeutrino = () => async (dispatch, getState) => {
'NEUTRINO_CHAIN_SYNC_IN_PROGRESS',
proxyValue(() => dispatch(neutrinoSyncStatus('NEUTRINO_CHAIN_SYNC_IN_PROGRESS')))
)
neutrino.on(
'NEUTRINO_WALLET_RECOVERY_IN_PROGRESS',
proxyValue(() => dispatch(neutrinoSyncStatus('NEUTRINO_WALLET_RECOVERY_IN_PROGRESS')))
)
neutrino.on(
'NEUTRINO_CHAIN_SYNC_COMPLETE',
proxyValue(() => dispatch(neutrinoSyncStatus('NEUTRINO_CHAIN_SYNC_COMPLETE')))
@@ -220,18 +230,29 @@ export const neutrinoCfilterHeight = height => dispatch => {
dispatch({ type: RECEIVE_LND_CFILTER_HEIGHT, neutrinoCfilterHeight: height })
}

// Receive wallet recovery height.
export const neutrinoRecoveryHeight = height => dispatch => {
dispatch({ type: RECEIVE_LND_RECOVERY_HEIGHT, neutrinoRecoveryHeight: height })
}

// Receive LND sync status change.
export const neutrinoSyncStatus = status => async dispatch => {
const notifTitle = 'Lightning Node Synced'
const notifBody = "Visa who? You're your own payment processor now!"

switch (status) {
case 'NEUTRINO_CHAIN_SYNC_PENDING':
dispatch({ type: SET_SYNC_STATUS_PENDING })
break
case 'NEUTRINO_CHAIN_SYNC_WAITING':
dispatch({ type: SET_SYNC_STATUS_WAITING })
break
case 'NEUTRINO_CHAIN_SYNC_IN_PROGRESS':
dispatch({ type: SET_SYNC_STATUS_IN_PROGRESS })
break
case 'NEUTRINO_WALLET_RECOVERY_IN_PROGRESS':
dispatch({ type: SET_SYNC_STATUS_RECOVERING })
break
case 'NEUTRINO_CHAIN_SYNC_COMPLETE':
dispatch({ type: SET_SYNC_STATUS_COMPLETE })

@@ -241,8 +262,6 @@ export const neutrinoSyncStatus = status => async dispatch => {
// HTML 5 desktop notification for the new transaction
showSystemNotification(notifTitle, notifBody)
break
case 'NEUTRINO_CHAIN_SYNC_PENDING':
dispatch({ type: SET_SYNC_STATUS_PENDING })
}
}

@@ -296,11 +315,17 @@ const ACTION_HANDLERS = {
neutrinoCfilterHeight,
neutrinoFirstCfilterHeight: state.neutrinoFirstCfilterHeight || neutrinoCfilterHeight,
}),
[RECEIVE_LND_RECOVERY_HEIGHT]: (state, { neutrinoRecoveryHeight }) => ({
...state,
neutrinoRecoveryHeight,
neutrinoFirstRecoveryHeight: state.neutrinoFirstRecoveryHeight || neutrinoRecoveryHeight,
}),

[SET_SYNC_STATUS_PENDING]: state => ({ ...state, syncStatus: 'pending' }),
[SET_SYNC_STATUS_WAITING]: state => ({ ...state, syncStatus: 'waiting' }),
[SET_SYNC_STATUS_IN_PROGRESS]: state => ({ ...state, syncStatus: 'in-progress' }),
[SET_SYNC_STATUS_COMPLETE]: state => ({ ...state, syncStatus: 'complete' }),
[SET_SYNC_STATUS_RECOVERING]: state => ({ ...state, syncStatus: 'recovering' }),

[SET_GRPC_ACTIVE_INTERFACE]: (state, { grpcActiveInterface }) => ({
...state,
@@ -336,6 +361,8 @@ const initialState = {
neutrinoBlockHeight: 0,
neutrinoFirstCfilterHeight: 0,
neutrinoCfilterHeight: 0,
neutrinoRecoveryHeight: 0,
neutrinoFirstRecoveryHeight: 0,
startNeutrinoError: null,
stopNeutrinoError: null,
neutrinoCrashCode: null,
@@ -355,6 +382,8 @@ const neutrinoBlockHeightSelector = state => state.neutrino.neutrinoBlockHeight
const neutrinoFirstBlockHeightSelector = state => state.neutrino.neutrinoFirstBlockHeight
const neutrinoCfilterHeightSelector = state => state.neutrino.neutrinoCfilterHeight
const neutrinoFirstCfilterHeightSelector = state => state.neutrino.neutrinoFirstCfilterHeight
const neutrinoRecoveryHeightSelector = state => state.neutrino.neutrinoRecoveryHeight
const neutrinoFirstRecoveryHeightSelector = state => state.neutrino.neutrinoFirstRecoveryHeight
const isNeutrinoCrashedSelector = state => state.neutrino.isNeutrinoCrashed
const neutrinoCrashCodeSelector = state => state.neutrino.neutrinoCrashCode
const neutrinoCrashSignalSelector = state => state.neutrino.neutrinoCrashSignal
@@ -367,6 +396,7 @@ neutrinoSelectors.neutrinoSyncStatus = neutrinoSyncStatusSelector
neutrinoSelectors.blockHeight = blockHeightSelector
neutrinoSelectors.neutrinoBlockHeight = neutrinoBlockHeightSelector
neutrinoSelectors.neutrinoCfilterHeight = neutrinoCfilterHeightSelector
neutrinoSelectors.neutrinoRecoveryHeight = neutrinoRecoveryHeightSelector

neutrinoSelectors.neutrinoSyncPercentage = createSelector(
blockHeightSelector,
@@ -405,6 +435,26 @@ neutrinoSelectors.neutrinoSyncPercentage = createSelector(
}
)

neutrinoSelectors.neutrinoRecoveryPercentage = createSelector(
blockHeightSelector,
neutrinoRecoveryHeightSelector,
neutrinoFirstRecoveryHeightSelector,
(blockHeight, neutrinoRecoveryHeight, neutrinoFirstRecoveryHeight) => {
// filters
const filtersToSync = blockHeight - neutrinoFirstRecoveryHeight
const filtersRemaining = blockHeight - neutrinoRecoveryHeight
const filtersDone = filtersToSync - filtersRemaining

const percentage = Math.floor((filtersDone / filtersToSync) * 100)

if (percentage === Infinity || Number.isNaN(percentage)) {
return undefined
}

return parseInt(percentage, 10)
}
)

neutrinoSelectors.isNeutrinoCrashed = isNeutrinoCrashedSelector

neutrinoSelectors.neutrinoCrashReason = createSelector(

0 comments on commit f31f0c6

Please sign in to comment.
You can’t perform that action at this time.