Browse Source

Merge pull request #529 from mrfelton/fix/sync-issues

Improve feedback to users during sync process
renovate/lint-staged-8.x
Ben Woosley 6 years ago
committed by GitHub
parent
commit
ee6e75aae0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      app/components/Onboarding/Syncing.js
  2. 6
      app/components/Onboarding/Syncing.scss
  3. 5
      app/containers/Root.js
  4. 49
      app/lnd/lib/neutrino.js
  5. 12
      app/reducers/ipc.js
  6. 39
      app/reducers/lnd.js
  7. 16
      app/zap.js

28
app/components/Onboarding/Syncing.js

@ -9,15 +9,18 @@ import styles from './Syncing.scss'
class Syncing extends Component {
componentWillMount() {
const { fetchBlockHeight, newAddress } = this.props
const { fetchBlockHeight, blockHeight, newAddress } = this.props
// If we don't already know the target block height, fetch it now.
if (!blockHeight) {
fetchBlockHeight()
}
newAddress('np2wkh')
}
render() {
const { syncPercentage, address } = this.props
const { syncPercentage, address, blockHeight, lndBlockHeight } = this.props
const copyClicked = () => {
copy(address)
showNotification('Noice', 'Successfully copied to clipboard')
@ -66,14 +69,21 @@ class Syncing extends Component {
<div className={styles.progressBar}>
<div
className={styles.progress}
style={{ width: Number.isNaN(syncPercentage) ? 0 : `${syncPercentage}%` }}
style={{ width: syncPercentage ? `${syncPercentage}%` : 0 }}
/>
</div>
<h4>
{Number.isNaN(parseInt(syncPercentage, 10)) || syncPercentage.toString().length === 0
? ''
: `${syncPercentage}%`}
{typeof syncPercentage === 'undefined' && 'Preparing...'}
{Boolean(syncPercentage >= 0 && syncPercentage < 99) && `${syncPercentage}%`}
{Boolean(syncPercentage >= 99) && 'Finalizing...'}
</h4>
{Boolean(syncPercentage >= 0 && syncPercentage < 99) && (
<span className={styles.progressCounter}>
{Boolean(!blockHeight || !lndBlockHeight) && 'starting...'}
{Boolean(blockHeight && lndBlockHeight) &&
`${lndBlockHeight.toLocaleString()} of ${blockHeight.toLocaleString()}`}
</span>
)}
</section>
</div>
</div>
@ -85,7 +95,9 @@ Syncing.propTypes = {
fetchBlockHeight: PropTypes.func.isRequired,
newAddress: PropTypes.func.isRequired,
address: PropTypes.string.isRequired,
syncPercentage: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired
syncPercentage: PropTypes.number,
blockHeight: PropTypes.number,
lndBlockHeight: PropTypes.number
}
export default Syncing

6
app/components/Onboarding/Syncing.scss

@ -94,6 +94,12 @@
color: $gold;
margin-top: 10px;
}
.progressCounter {
color: $gold;
font-size: 12px;
margin-top: 10px;
}
}
.spinner {

5
app/containers/Root.js

@ -82,8 +82,9 @@ const mapStateToProps = state => ({
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const syncingProps = {
fetchBlockHeight: dispatchProps.fetchBlockHeight,
blockHeight: stateProps.lnd.blockHeight,
lndBlockHeight: stateProps.lnd.lndBlockHeight,
newAddress: dispatchProps.newAddress,
syncPercentage: stateProps.syncPercentage,
address: stateProps.address.address
}
@ -214,7 +215,7 @@ const Root = ({
}
// If we are syncing show the syncing screen
if (lnd.syncing) {
if (lnd.grpcStarted && lnd.syncing) {
return <Syncing {...syncingProps} />
}

49
app/lnd/lib/neutrino.js

@ -10,6 +10,14 @@ class Neutrino extends EventEmitter {
this.alias = alias
this.autopilot = autopilot
this.process = null
this.state = {
grpcProxyStarted: false,
walletOpened: false,
chainSyncStarted: false,
chainSyncFinished: false,
currentBlockHeight: null,
targetBlockHeight: null
}
}
start() {
@ -52,25 +60,58 @@ class Neutrino extends EventEmitter {
}
// gRPC started.
if (!this.state.grpcProxyStarted) {
if (line.includes('gRPC proxy started') && line.includes('password')) {
this.state.grpcProxyStarted = true
this.emit('grpc-proxy-started')
}
}
// Wallet opened.
if (!this.state.walletOpened) {
if (line.includes('gRPC proxy started') && !line.includes('password')) {
this.state.walletOpened = true
this.emit('wallet-opened')
}
}
// LND is all caught up to the blockchain.
// LND syncing has started.
if (!this.state.chainSyncStarted) {
if (line.includes('Syncing to block height')) {
const height = line.match(/Syncing to block height (\d+)/)[1]
this.state.chainSyncStarted = true
this.state.targetBlockHeight = height
this.emit('chain-sync-started')
this.emit('got-final-block-height', height)
}
}
// LND syncing has completed.
if (!this.state.chainSyncFinished) {
if (line.includes('Chain backend is fully synced')) {
this.emit('fully-synced')
this.state.chainSyncFinished = true
this.emit('chain-sync-finished')
}
}
// Pass current block height progress to front end for loading state UX
if (line.includes('Caught up to height') || line.includes('Catching up block hashes')) {
this.emit('got-block-height', line)
if (this.state.chainSyncStarted) {
if (line.includes('Downloading headers for blocks')) {
const height = line.match(/Downloading headers for blocks (\d+) to \d+/)[1]
this.emit('got-current-block-height', height)
} else if (line.includes('Rescanned through block')) {
const height = line.match(/Rescanned through block.+\(height (\d+)/)[1]
this.emit('got-current-block-height', height)
} else if (line.includes('Caught up to height')) {
const height = line.match(/Caught up to height (\d+)/)[1]
this.emit('got-current-block-height', height)
} else if (line.includes('in the last')) {
const height = line.match(/Processed \d* blocks? in the last.+\(height (\d+)/)[1]
this.emit('got-current-block-height', height)
}
}
})
return this.process
}

12
app/reducers/ipc.js

@ -1,5 +1,12 @@
import createIpc from 'redux-electron-ipc'
import { lndSyncing, lndSynced, lndStdout, grpcDisconnected, grpcConnected } from './lnd'
import {
lndSyncing,
lndSynced,
lndBlockHeightTarget,
lndBlockHeight,
grpcDisconnected,
grpcConnected
} from './lnd'
import { receiveInfo } from './info'
import { receiveAddress } from './address'
import { receiveCryptocurrency } from './ticker'
@ -53,7 +60,8 @@ import {
const ipc = createIpc({
lndSyncing,
lndSynced,
lndStdout,
lndBlockHeightTarget,
lndBlockHeight,
grpcDisconnected,
grpcConnected,

39
app/reducers/lnd.js

@ -10,10 +10,9 @@ import { showNotification } from '../notifications'
export const START_SYNCING = 'START_SYNCING'
export const STOP_SYNCING = 'STOP_SYNCING'
export const RECEIVE_LINE = 'RECEIVE_LINE'
export const GET_BLOCK_HEIGHT = 'GET_BLOCK_HEIGHT'
export const RECEIVE_BLOCK_HEIGHT = 'RECEIVE_BLOCK_HEIGHT'
export const RECEIVE_BLOCK = 'RECEIVE_BLOCK'
export const GRPC_DISCONNECTED = 'GRPC_DISCONNECTED'
export const GRPC_CONNECTED = 'GRPC_CONNECTED'
@ -43,29 +42,18 @@ export const lndSynced = () => dispatch => {
export const grpcDisconnected = () => dispatch => dispatch({ type: GRPC_DISCONNECTED })
export const grpcConnected = () => dispatch => dispatch({ type: GRPC_CONNECTED })
// Receive IPC event for LND streaming a line
export const lndStdout = (event, line) => dispatch => {
let height
let trimmed
if (line.includes('Caught up to height')) {
trimmed = line.slice(line.indexOf('Caught up to height') + 'Caught up to height'.length).trim()
height = trimmed.split(' ')[0].split(/(\r\n|\n|\r)/gm)[0]
export const grpcConnected = () => dispatch => {
dispatch(fetchInfo())
dispatch({ type: GRPC_CONNECTED })
}
if (line.includes('Catching up block hashes to height')) {
trimmed = line
.slice(
line.indexOf('Catching up block hashes to height') +
'Catching up block hashes to height'.length
)
.trim()
height = trimmed.match(/[-]{0,1}[\d.]*[\d]+/g)[0]
// Receive IPC event for LND streaming a line
export const lndBlockHeight = (event, height) => dispatch => {
dispatch({ type: RECEIVE_BLOCK, lndBlockHeight: height })
}
dispatch({ type: RECEIVE_LINE, lndBlockHeight: height })
export const lndBlockHeightTarget = (event, height) => dispatch => {
dispatch({ type: RECEIVE_BLOCK_HEIGHT, blockHeight: height })
}
export function getBlockHeight() {
@ -95,14 +83,13 @@ const ACTION_HANDLERS = {
[START_SYNCING]: state => ({ ...state, syncing: true }),
[STOP_SYNCING]: state => ({ ...state, syncing: false }),
[RECEIVE_LINE]: (state, { lndBlockHeight }) => ({ ...state, lndBlockHeight }),
[GET_BLOCK_HEIGHT]: state => ({ ...state, fetchingBlockHeight: true }),
[RECEIVE_BLOCK_HEIGHT]: (state, { blockHeight }) => ({
...state,
blockHeight,
fetchingBlockHeight: false
}),
[RECEIVE_BLOCK]: (state, { lndBlockHeight }) => ({ ...state, lndBlockHeight }),
[GRPC_DISCONNECTED]: state => ({ ...state, grpcStarted: false }),
[GRPC_CONNECTED]: state => ({ ...state, grpcStarted: true })
@ -133,11 +120,11 @@ lndSelectors.syncPercentage = createSelector(
(blockHeight, lndBlockHeight) => {
const percentage = Math.floor((lndBlockHeight / blockHeight) * 100)
if (percentage === Infinity) {
return ''
if (percentage === Infinity || Number.isNaN(percentage)) {
return undefined
}
return percentage
return parseInt(percentage, 10)
}
)

16
app/zap.js

@ -158,16 +158,24 @@ class ZapController {
this.neutrino.on('wallet-opened', () => {
mainLog.info('Wallet opened')
this.startGrpc()
})
this.neutrino.on('chain-sync-started', () => {
mainLog.info('Neutrino sync started')
this.sendMessage('lndSyncing')
})
this.neutrino.on('fully-synced', () => {
mainLog.info('Neutrino fully synced')
this.neutrino.on('chain-sync-finished', () => {
mainLog.info('Neutrino sync finished')
this.sendMessage('lndSynced')
})
this.neutrino.on('got-block-height', line => {
this.sendMessage('lndStdout', line)
this.neutrino.on('got-final-block-height', height => {
this.sendMessage('lndBlockHeightTarget', Number(height))
})
this.neutrino.on('got-current-block-height', height => {
this.sendMessage('lndBlockHeight', Number(height))
})
this.neutrino.start()

Loading…
Cancel
Save