Skip to content

Commit

Permalink
feat: Adapt ckb light node (#2590) (#2615)
Browse files Browse the repository at this point in the history
Co-authored-by: 严国宇 <[email protected]>
  • Loading branch information
Keith-CY and yanguoyu authored May 29, 2023
1 parent 600dbc5 commit 1dfd255
Show file tree
Hide file tree
Showing 117 changed files with 3,136 additions and 707 deletions.
1 change: 1 addition & 0 deletions .ckb-light-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v0.2.4
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ release
/packages/neuron-wallet/bin/mac
/packages/neuron-wallet/bin/linux
/packages/neuron-wallet/bin/win
/packages/neuron-wallet/light

# misc
.DS_Store
Expand Down
10 changes: 7 additions & 3 deletions packages/neuron-ui/src/components/ClearCache/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const IDs = {
rebuildCacheOption: 'rebuild-cache-option',
}

const ClearCache = ({ dispatch }: { dispatch: StateDispatch }) => {
const ClearCache = ({ dispatch, hideRebuild }: { dispatch: StateDispatch; hideRebuild?: boolean }) => {
const [t] = useTranslation()
const [clearedDate, setClearedDate] = useState(cacheClearDate.load())
const [isClearing, setIsClearing] = useState(false)
Expand Down Expand Up @@ -96,8 +96,12 @@ const ClearCache = ({ dispatch }: { dispatch: StateDispatch }) => {
<div className={styles.options}>
<input type="checkbox" id={IDs.refreshCacheOption} checked disabled />
<label htmlFor={IDs.refreshCacheOption}>{t(`${I18N_PATH}.options.refresh.label`)}</label>
<input type="checkbox" id={IDs.rebuildCacheOption} checked={isRebuild} onChange={toggleIsRebuild} />
<label htmlFor={IDs.rebuildCacheOption}>{t(`${I18N_PATH}.options.rebuild.label`)}</label>
{hideRebuild ? null : (
<>
<input type="checkbox" id={IDs.rebuildCacheOption} checked={isRebuild} onChange={toggleIsRebuild} />
<label htmlFor={IDs.rebuildCacheOption}>{t(`${I18N_PATH}.options.rebuild.label`)}</label>
</>
)}
</div>
<div className={styles.footer}>
<Button type="submit" label={t(`${I18N_PATH}.buttons.ok`)} onClick={handleSubmit} id={IDs.submitClearCache} />
Expand Down
17 changes: 13 additions & 4 deletions packages/neuron-ui/src/components/DataSetting/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React, { useCallback, useEffect, useState } from 'react'
import React, { useCallback, useEffect, useState, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import Button from 'widgets/Button'
import ClearCache from 'components/ClearCache'
import { useDispatch } from 'states'
import { useDispatch, useState as useGlobalState } from 'states'
import { ReactComponent as Attention } from 'widgets/Icons/ExperimentalAttention.svg'
import CopyZone from 'widgets/CopyZone'
import { OpenFolder, InfoCircleOutlined } from 'widgets/Icons/icon'
import { shell } from 'electron'
import Spinner from 'widgets/Spinner'
import { getIsCkbRunExternal } from 'services/remote'
import { isSuccessResponse } from 'utils'
import { LIGHT_NETWORK_TYPE } from 'utils/const'
import { useDataPath } from './hooks'

import styles from './index.module.scss'
Expand Down Expand Up @@ -99,10 +100,18 @@ const SetItem = () => {

const DataSetting = () => {
const dispatch = useDispatch()
const {
chain: { networkID },
settings: { networks = [] },
} = useGlobalState()
const isLightClient = useMemo(() => networks.find(n => n.id === networkID)?.type === LIGHT_NETWORK_TYPE, [
networkID,
networks,
])
return (
<div className={styles.root}>
<SetItem />
<ClearCache dispatch={dispatch} />
{isLightClient ? null : <SetItem />}
<ClearCache dispatch={dispatch} hideRebuild={isLightClient} />
</div>
)
}
Expand Down
41 changes: 39 additions & 2 deletions packages/neuron-ui/src/components/MultisigAddress/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {
getMultisigBalances,
loadMultisigTxJson,
OfflineSignJSON,
getMultisigSyncProgress,
} from 'services/remote'
import { addressToScript, scriptToAddress } from '@nervosnetwork/ckb-sdk-utils'
import { addressToScript, scriptToAddress, scriptToHash } from '@nervosnetwork/ckb-sdk-utils'

export const useSearch = (clearSelected: () => void, onFilterConfig: (searchKey: string) => void) => {
const [keywords, setKeywords] = useState('')
Expand Down Expand Up @@ -279,19 +280,43 @@ export const useSubscription = ({
walletId,
isMainnet,
configs,
isLightClient,
}: {
walletId: string
isMainnet: boolean
configs: MultisigConfig[]
isLightClient: boolean
}) => {
const [multisigBanlances, setMultisigBanlances] = useState<Record<string, string>>({})
const [multisigSyncProgress, setMultisigSyncProgress] = useState<Record<string, number>>({})
const getAndSaveMultisigBalances = useCallback(() => {
getMultisigBalances({ isMainnet, multisigAddresses: configs.map(v => v.fullPayload) }).then(res => {
if (isSuccessResponse(res) && res.result) {
setMultisigBanlances(res.result)
}
})
}, [setMultisigBanlances, isMainnet, configs])
const hashToPayload = useMemo(
() =>
configs.reduce<Record<string, string>>(
(pre, cur) => ({ ...pre, [scriptToHash(addressToScript(cur.fullPayload))]: cur.fullPayload }),
{}
),
[configs]
)
const getAndSaveMultisigSyncProgress = useCallback(() => {
getMultisigSyncProgress(Object.keys(hashToPayload)).then(res => {
if (isSuccessResponse(res) && res.result) {
const tmp: Record<string, number> = {}
res.result.forEach(v => {
if (hashToPayload[v.hash]) {
tmp[hashToPayload[v.hash]] = v.blockStartNumber
}
})
setMultisigSyncProgress(tmp)
}
})
}, [hashToPayload])
useEffect(() => {
const dataUpdateSubscription = MultisigOutputUpdate.subscribe(() => {
getAndSaveMultisigBalances()
Expand All @@ -301,5 +326,17 @@ export const useSubscription = ({
dataUpdateSubscription.unsubscribe()
}
}, [walletId, getAndSaveMultisigBalances])
return multisigBanlances
useEffect(() => {
let interval: ReturnType<typeof setInterval> | undefined
if (isLightClient) {
interval = setInterval(() => {
getAndSaveMultisigSyncProgress()
}, 10000)
getAndSaveMultisigSyncProgress()
}
return () => {
clearInterval(interval)
}
}, [isLightClient, getAndSaveMultisigSyncProgress])
return { multisigBanlances, multisigSyncProgress }
}
19 changes: 16 additions & 3 deletions packages/neuron-ui/src/components/MultisigAddress/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { EditTextField } from 'widgets/TextField'
import { MultisigConfig } from 'services/remote'
import PasswordRequest from 'components/PasswordRequest'
import ApproveMultisigTx from 'components/ApproveMultisigTx'
import { LIGHT_NETWORK_TYPE } from 'utils/const'
import { useSearch, useConfigManage, useExportConfig, useActions, useSubscription } from './hooks'

import styles from './multisigAddress.module.scss'
Expand Down Expand Up @@ -52,6 +53,10 @@ const MultisigAddress = () => {
// eslint-disable-next-line
}, [i18n.language])
const isMainnet = isMainnetUtil(networks, networkID)
const isLightClient = useMemo(() => networks.find(n => n.id === networkID)?.type === LIGHT_NETWORK_TYPE, [
networks,
networkID,
])
const { openDialog, closeDialog, dialogRef, isDialogOpen } = useDialogWrapper()
const {
allConfigs,
Expand All @@ -65,7 +70,12 @@ const MultisigAddress = () => {
walletId,
isMainnet,
})
const multisigBanlances = useSubscription({ walletId, isMainnet, configs: allConfigs })
const { multisigBanlances, multisigSyncProgress } = useSubscription({
walletId,
isMainnet,
configs: allConfigs,
isLightClient,
})
const { deleteAction, infoAction, sendAction, approveAction } = useActions({ deleteConfigById })
const onClickItem = useCallback(
(multisigConfig: MultisigConfig) => (option: { key: string }) => {
Expand Down Expand Up @@ -138,8 +148,10 @@ const MultisigAddress = () => {
<th className={styles.checkBoxTh}>
<input type="checkbox" onChange={onChangeCheckedAll} checked={isAllSelected} />
</th>
{['address', 'alias', 'type', 'balance'].map(field => (
<th key={field}>{t(`multisig-address.table.${field}`)}</th>
{['address', 'alias', 'type', ...(isLightClient ? ['sync-block'] : []), 'balance'].map(field => (
<th key={field} data-field={field}>
{t(`multisig-address.table.${field}`)}
</th>
))}
</tr>
</thead>
Expand Down Expand Up @@ -173,6 +185,7 @@ const MultisigAddress = () => {
&nbsp;of&nbsp;
{v.n}
</td>
{isLightClient ? <td>{multisigSyncProgress?.[v.fullPayload] ?? 0}</td> : null}
<td>
{shannonToCKBFormatter(multisigBanlances[v.fullPayload])}
&nbsp;CKB
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
padding: 8px;
min-width: 40px;
text-align: left;

&[data-field="sync-block"] {
min-width: 70px;
}
}

.checkBoxTh {
Expand Down
90 changes: 58 additions & 32 deletions packages/neuron-ui/src/components/NervosDAO/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
generateDaoDepositTx,
generateDaoClaimTx,
} from 'services/remote'
import { ckbCore, getHeaderByNumber } from 'services/chain'
import { ckbCore, getHeader } from 'services/chain'
import { isErrorWithI18n } from 'exceptions'
import { calculateMaximumWithdraw } from '@nervosnetwork/ckb-sdk-utils'

Expand Down Expand Up @@ -84,12 +84,14 @@ export const useInitData = ({
updateDepositValue,
wallet,
setGenesisBlockTimestamp,
genesisBlockHash,
}: {
clearGeneratedTx: () => void
dispatch: React.Dispatch<StateAction>
updateDepositValue: (value: string) => void
wallet: State.Wallet
setGenesisBlockTimestamp: React.Dispatch<React.SetStateAction<number | undefined>>
genesisBlockHash?: string
}) =>
useEffect(() => {
updateNervosDaoData({ walletID: wallet.id })(dispatch)
Expand All @@ -103,9 +105,11 @@ export const useInitData = ({
: BigInt(0)
}`
)
getHeaderByNumber('0x0')
.then(header => setGenesisBlockTimestamp(+header.timestamp))
.catch(err => console.error(err))
if (genesisBlockHash) {
getHeader(genesisBlockHash)
.then(header => setGenesisBlockTimestamp(+header.timestamp))
.catch(err => console.error(err))
}
return () => {
clearInterval(intervalId)
clearNervosDaoData()(dispatch)
Expand Down Expand Up @@ -450,15 +454,15 @@ export const useOnSlide = ({

export const useUpdateWithdrawList = ({
records,
tipBlockHash,
tipDao,
setWithdrawList,
}: {
records: Readonly<State.NervosDAORecord[]>
tipBlockHash: string
tipDao?: string
setWithdrawList: React.Dispatch<React.SetStateAction<Map<string, string | null>>>
}) =>
useEffect(() => {
if (!tipBlockHash) {
if (!tipDao) {
setWithdrawList(new Map())
return
}
Expand All @@ -473,7 +477,6 @@ export const useUpdateWithdrawList = ({
const blockHashes = [
...(committedTx.map(v => v.txStatus.blockHash).filter(v => !!v) as string[]),
...(records.map(v => (v.depositOutPoint ? v.blockHash : null)).filter(v => !!v) as string[]),
tipBlockHash,
]
return ckbCore.rpc
.createBatchRequest<'getHeader', string[], CKBComponents.BlockHeader[]>(
Expand All @@ -494,7 +497,7 @@ export const useUpdateWithdrawList = ({
const withdrawList = new Map()
records.forEach(record => {
const key = getRecordKey(record)
const withdrawBlockHash = record.depositOutPoint ? record.blockHash : tipBlockHash
const withdrawBlockHash = record.depositOutPoint ? record.blockHash : undefined
const formattedDepositOutPoint = record.depositOutPoint
? {
txHash: record.depositOutPoint.txHash,
Expand All @@ -509,7 +512,7 @@ export const useUpdateWithdrawList = ({
return
}
const depositDAO = hashHeaderMap.get(tx.txStatus.blockHash!)
const withdrawDAO = hashHeaderMap.get(withdrawBlockHash)
const withdrawDAO = withdrawBlockHash ? hashHeaderMap.get(withdrawBlockHash) : tipDao
if (!depositDAO || !withdrawDAO) {
return
}
Expand All @@ -529,7 +532,23 @@ export const useUpdateWithdrawList = ({
.catch(() => {
setWithdrawList(new Map())
})
}, [records, tipBlockHash, setWithdrawList])
}, [records, tipDao, setWithdrawList])

const getBlockHashes = (txHashes: string[]) => {
const batchParams: ['getTransaction', string][] = txHashes.map(v => ['getTransaction', v])
return ckbCore.rpc
.createBatchRequest<'getTransaction', [string], CKBComponents.TransactionWithStatus[]>(batchParams)
.exec()
.then(res => {
return res.map((v, idx) => ({
txHash: txHashes[idx],
blockHash: v.txStatus.blockHash,
}))
})
.catch(() => {
return []
})
}

export const useUpdateDepositEpochList = ({
records,
Expand All @@ -542,28 +561,35 @@ export const useUpdateDepositEpochList = ({
}) =>
useEffect(() => {
if (connectionStatus === 'online') {
const recordKeyIdxMap = new Map<string, number>()
const batchParams: ['getHeaderByNumber', bigint][] = []
records.forEach((record, idx) => {
const depositBlockNumber = record.depositOutPoint
? ckbCore.utils.toUint64Le(record.daoData)
: record.blockNumber
if (depositBlockNumber) {
batchParams.push(['getHeaderByNumber', BigInt(depositBlockNumber)])
recordKeyIdxMap.set(getRecordKey(record), idx)
}
})
ckbCore.rpc
.createBatchRequest<'getHeaderByNumber', any, CKBComponents.BlockHeader[]>(batchParams)
.exec()
.then(res => {
const epochList = new Map()
records.forEach(record => {
const key = getRecordKey(record)
epochList.set(key, recordKeyIdxMap.get(key) !== undefined ? res[recordKeyIdxMap.get(key)!]?.epoch : null)
getBlockHashes(records.map(v => v.depositOutPoint?.txHash).filter(v => !!v) as string[]).then(
depositBlockHashes => {
const recordKeyIdx: string[] = []
const batchParams: ['getHeader', string][] = []
records.forEach((record) => {
if (!record.depositOutPoint && record.blockHash) {
batchParams.push(['getHeader', record.blockHash])
recordKeyIdx.push(record.outPoint.txHash)
}
})
setDepositEpochList(epochList)
})
depositBlockHashes.forEach((v) => {
if (v.blockHash) {
batchParams.push(['getHeader', v.blockHash])
recordKeyIdx.push(v.txHash)
}
})
ckbCore.rpc
.createBatchRequest<'getHeader', any, CKBComponents.BlockHeader[]>(batchParams)
.exec()
.then(res => {
const epochList = new Map()
records.forEach(record => {
const key = record.depositOutPoint ? record.depositOutPoint.txHash : record.outPoint.txHash
epochList.set(key, res[recordKeyIdx.indexOf(key)]?.epoch)
})
setDepositEpochList(epochList)
})
}
)
}
}, [records, setDepositEpochList, connectionStatus])

Expand Down
Loading

2 comments on commit 1dfd255

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Packaging for test is done in 5109429687

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Packaging for test is done in 5112396469

Please sign in to comment.