Skip to content

Commit

Permalink
feat: Optimize the setting of sync start block in light client mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
yanguoyu committed Jan 12, 2024
1 parent 4907867 commit 6a2b12f
Show file tree
Hide file tree
Showing 14 changed files with 213 additions and 55 deletions.
70 changes: 56 additions & 14 deletions packages/neuron-ui/src/components/PageContainer/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,71 @@
import { useCallback, useEffect, useState } from 'react'
import { TFunction } from 'i18next'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { importedWalletDialogShown } from 'services/localCache'
import { isDark, openExternal, updateWallet, setTheme as setThemeAPI } from 'services/remote'
import { isDark, openExternal, setTheme as setThemeAPI, updateWalletStartBlockNumber } from 'services/remote'
import { Migrate } from 'services/subjects'
import { getExplorerUrl, isSuccessResponse } from 'utils'

const waitConfirmTime = 5

const useCountDown = (second: number) => {
const [countdown, setCountdown] = useState(0)
const countDecreaseTimeoutRef = useRef<ReturnType<typeof setInterval>>()
const resetCountDown = useCallback(() => {
clearTimeout(countDecreaseTimeoutRef.current)
setCountdown(second)
const decrement = () => {
countDecreaseTimeoutRef.current = setInterval(() => {
setCountdown(v => (v > 0 ? v - 1 : v))
}, 1_000)
}
decrement()
}, [setCountdown, countDecreaseTimeoutRef])
return {
countdown,
resetCountDown,
}
}

export const useSetBlockNumber = ({
firstAddress,
walletID,
isMainnet,
isLightClient,
isHomePage,
initStartBlockNumber,
headerTipNumber,
t,
}: {
firstAddress: string
walletID: string
isMainnet: boolean
isLightClient: boolean
isHomePage?: boolean
initStartBlockNumber?: number
headerTipNumber: number
t: TFunction
}) => {
const [isSetStartBlockShown, setIsSetStartBlockShown] = useState(false)
const [startBlockNumber, setStartBlockNumber] = useState('')
const [blockNumberErr, setBlockNumberErr] = useState('')
const onChangeStartBlockNumber = useCallback((e: React.SyntheticEvent<HTMLInputElement>) => {
const { value } = e.currentTarget
const blockNumber = value.replace(/,/g, '')
if (Number.isNaN(+blockNumber) || /[^\d]/.test(blockNumber)) {
return
}
setStartBlockNumber(blockNumber)
setBlockNumberErr('')
}, [])
const isSetLessThanBefore = useMemo(
() => !!(startBlockNumber && initStartBlockNumber && +startBlockNumber < initStartBlockNumber),
[initStartBlockNumber, startBlockNumber]
)
const { countdown, resetCountDown } = useCountDown(waitConfirmTime)
const onChangeStartBlockNumber = useCallback(
(e: React.SyntheticEvent<HTMLInputElement>) => {
const { value } = e.currentTarget
const blockNumber = value.replaceAll(',', '')
if (Number.isNaN(+blockNumber)) {
return
}
setStartBlockNumber(+blockNumber > headerTipNumber ? headerTipNumber.toString() : blockNumber)
setBlockNumberErr(+blockNumber > headerTipNumber ? t('set-start-block-number.reset-to-header-tip-number') : '')
resetCountDown()
},
[resetCountDown, initStartBlockNumber, headerTipNumber, t]
)
const onOpenAddressInExplorer = useCallback(() => {
const explorerUrl = getExplorerUrl(isMainnet)
openExternal(`${explorerUrl}/address/${firstAddress}`)
Expand All @@ -38,7 +75,10 @@ export const useSetBlockNumber = ({
openExternal(`${explorerUrl}/block/${startBlockNumber}`)
}, [startBlockNumber, isMainnet])
const onConfirm = useCallback(() => {
updateWallet({ id: walletID, startBlockNumber: `0x${BigInt(startBlockNumber).toString(16)}` }).then(res => {
updateWalletStartBlockNumber({
id: walletID,
startBlockNumber: `0x${BigInt(startBlockNumber).toString(16)}`,
}).then(res => {
if (isSuccessResponse(res)) {
setIsSetStartBlockShown(false)
} else {
Expand All @@ -48,9 +88,9 @@ export const useSetBlockNumber = ({
}, [startBlockNumber, walletID])
const openDialog = useCallback(() => {
setIsSetStartBlockShown(true)
setStartBlockNumber('')
setStartBlockNumber(initStartBlockNumber?.toString() ?? '')
setBlockNumberErr('')
}, [])
}, [initStartBlockNumber])
useEffect(() => {
if (isHomePage) {
const needShow = importedWalletDialogShown.getStatus(walletID)
Expand All @@ -70,6 +110,8 @@ export const useSetBlockNumber = ({
onViewBlock,
onConfirm,
blockNumberErr,
countdown,
isSetLessThanBefore,
}
}

Expand Down
67 changes: 44 additions & 23 deletions packages/neuron-ui/src/components/PageContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
getNetworkLabelI18nkey,
} from 'utils'
import Alert from 'widgets/Alert'
import { Close, NewTab } from 'widgets/Icons/icon'
import { Attention, Close, NewTab } from 'widgets/Icons/icon'
import { ReactComponent as Sun } from 'widgets/Icons/Sun.svg'
import { ReactComponent as Moon } from 'widgets/Icons/Moon.svg'
import SyncStatusComponent from 'components/SyncStatus'
Expand Down Expand Up @@ -45,7 +45,7 @@ const PageContainer: React.FC<ComponentProps> = props => {
connectionStatus,
networkID,
},
wallet: { addresses, id },
wallet: { addresses, id, startBlockNumber: walletStartBlockNumber },
settings: { networks },
} = useGlobalState()
const { children, head, notice, className, isHomePage } = props
Expand Down Expand Up @@ -93,12 +93,18 @@ const PageContainer: React.FC<ComponentProps> = props => {
onOpenAddressInExplorer,
onViewBlock,
onConfirm,
countdown,
isSetLessThanBefore,
blockNumberErr,
} = useSetBlockNumber({
firstAddress: addresses[0]?.address,
isMainnet,
isLightClient,
walletID: id,
isHomePage,
initStartBlockNumber: walletStartBlockNumber ? Number(walletStartBlockNumber) : undefined,
headerTipNumber: bestKnownBlockNumber,
t,
})
return (
<div className={`${styles.page} ${className || ''}`}>
Expand Down Expand Up @@ -134,6 +140,7 @@ const PageContainer: React.FC<ComponentProps> = props => {
isMigrate={isMigrate}
isLightClient={isLightClient}
onOpenSetStartBlock={openDialog}
startBlockNumber={walletStartBlockNumber}
/>
</div>
</div>
Expand All @@ -148,31 +155,45 @@ const PageContainer: React.FC<ComponentProps> = props => {
<div className={styles.body}>{children}</div>
<Dialog
title={t('set-start-block-number.title')}
confirmText={countdown ? `${t('common.confirm')}(${countdown})` : t('common.confirm')}
show={isSetStartBlockShown}
onCancel={closeDialog}
onConfirm={onConfirm}
disabled={!startBlockNumber}
disabled={!startBlockNumber || !!countdown}
contentClassName={styles.setBlockContent}
>
<p className={styles.startBlockTip}>{t('set-start-block-number.tip')}</p>
<TextField
field="startBlockNumber"
onChange={onChangeStartBlockNumber}
placeholder={t('set-start-block-number.input-place-holder')}
value={localNumberFormatter(startBlockNumber)}
suffix={
startBlockNumber ? (
<button type="button" className={styles.viewAction} onClick={onViewBlock}>
{t('set-start-block-number.view-block')}
<NewTab />
</button>
) : (
<button type="button" className={styles.viewAction} onClick={onOpenAddressInExplorer}>
{t('set-start-block-number.locate-first-tx')}
<NewTab />
</button>
)
}
/>
<div className={styles.setBlockWarn}>
<Attention />
{t('set-start-block-number.warn')}
</div>
<div className={styles.content}>
<p className={styles.startBlockTip}>{t('set-start-block-number.tip')}</p>
<TextField
field="startBlockNumber"
onChange={onChangeStartBlockNumber}
placeholder={t('set-start-block-number.input-place-holder')}
value={localNumberFormatter(startBlockNumber)}
error={blockNumberErr}
suffix={
startBlockNumber ? (
<button type="button" className={styles.viewAction} onClick={onViewBlock}>
{t('set-start-block-number.view-block')}
<NewTab />
</button>
) : (
<button type="button" className={styles.viewAction} onClick={onOpenAddressInExplorer}>
{t('set-start-block-number.locate-first-tx')}
<NewTab />
</button>
)
}
/>
{isSetLessThanBefore ? (
<Alert status="error" className={styles.errorMessage} withIcon={false}>
{t('set-start-block-number.set-less-than-before')}
</Alert>
) : null}
</div>
</Dialog>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,32 @@
}
}

.startBlockTip {
font-weight: 400;
color: var(--secondary-text-color);
.setBlockContent {
padding: 0 0 20px 0;
overflow-y: auto;

.content {
padding: 0 16px 0 16px;
}
.startBlockTip {
font-weight: 400;
color: var(--secondary-text-color);
}

.setBlockWarn {
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--warn-background-color);
color: var(--warn-text-color);
font-size: 12px;
font-weight: 500;

& > svg {
margin-right: 4px;
}
}
}

.viewAction {
Expand Down
15 changes: 13 additions & 2 deletions packages/neuron-ui/src/components/SyncStatus/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { SyncStatus as SyncStatusEnum, ConnectionStatus } from 'utils'
import { SyncStatus as SyncStatusEnum, ConnectionStatus, clsx, localNumberFormatter } from 'utils'
import { Confirming, NewTab } from 'widgets/Icons/icon'
import { ReactComponent as UnexpandStatus } from 'widgets/Icons/UnexpandStatus.svg'
import { ReactComponent as StartBlock } from 'widgets/Icons/StartBlock.svg'
Expand All @@ -13,12 +13,14 @@ const SyncDetail = ({
onOpenValidTarget,
isLightClient,
onOpenSetStartBlock,
startBlockNumber,
}: {
syncBlockNumbers: string
isLookingValidTarget: boolean
onOpenValidTarget: (e: React.SyntheticEvent) => void
isLightClient: boolean
onOpenSetStartBlock: () => void
startBlockNumber?: string
}) => {
const [t] = useTranslation()
return (
Expand All @@ -42,10 +44,16 @@ const SyncDetail = ({
</div>
</div>
)}
{isLightClient && startBlockNumber ? (
<div className={styles.startBlockNumber}>
<div className={styles.title}>{t('network-status.tooltip.start-block-number')}:</div>
<div className={styles.number}>{localNumberFormatter(startBlockNumber)}</div>
</div>
) : null}
{isLightClient && (
<div
role="link"
className={styles.action}
className={clsx(styles.action, styles.setStartBlockNumber)}
onClick={onOpenSetStartBlock}
onKeyPress={onOpenSetStartBlock}
tabIndex={-1}
Expand All @@ -70,6 +78,7 @@ const SyncStatus = ({
isMigrate,
isLightClient,
onOpenSetStartBlock,
startBlockNumber,
}: React.PropsWithoutRef<{
syncStatus: SyncStatusEnum
connectionStatus: State.ConnectionStatus
Expand All @@ -80,6 +89,7 @@ const SyncStatus = ({
isMigrate: boolean
isLightClient: boolean
onOpenSetStartBlock: () => void
startBlockNumber?: string
}>) => {
const [t] = useTranslation()
const [isOpen, setIsOpen] = useState(false)
Expand Down Expand Up @@ -116,6 +126,7 @@ const SyncStatus = ({
onOpenValidTarget={onOpenValidTarget}
isLightClient={isLightClient}
onOpenSetStartBlock={onOpenSetStartBlock}
startBlockNumber={startBlockNumber}
/>
}
trigger="click"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
font-size: 12px;
font-weight: 400;

&:nth-child(2) {
&.setStartBlockNumber {
&::before {
content: '';
display: block;
Expand All @@ -74,10 +74,6 @@
}
}

&:nth-child(3) {
margin-top: 12px;
}

& > div {
display: flex;
align-items: center;
Expand All @@ -95,6 +91,19 @@
}
}
}

.startBlockNumber {
margin-top: 8px;
.title {
font-size: 12px;
font-weight: 400;
}
.number {
color: var(--third-text-color);
font-family: D-DIN-PRO;
font-weight: 700;
}
}
}

.redDot {
Expand Down
6 changes: 5 additions & 1 deletion packages/neuron-ui/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"tooltip": {
"block-synced": "Block Synced",
"looking-valid-target": "Looking for assumed valid target",
"start-block-number": "Start block number",
"set-start-block-number": "Set start block number"
},
"migrating": "migrating..."
Expand Down Expand Up @@ -1124,10 +1125,13 @@
},
"set-start-block-number": {
"title": "Set the start block number",
"warn": "Warning: Transactions before the start block of synchronization will not be synchronized",
"tip": "The start sync block number is configuration when use light client ckb node, then you can set it and quick the sync",
"input-place-holder": "Please enter the start sync block number, eg: 10,100,101",
"locate-first-tx": "Locate the first transaction",
"view-block": "View the block"
"view-block": "View the block",
"set-less-than-before": "The block number you set is smaller than the previous set, the synchronization will restart, please proceed with caution.",
"reset-to-header-tip-number": "Unable to set a block number greater than the header tip block number, reset to the header tip block number."
},
"main": {
"external-node-detected-dialog": {
Expand Down
Loading

0 comments on commit 6a2b12f

Please sign in to comment.