Skip to content

Commit

Permalink
fix: Fix multisig with light client (#2682)
Browse files Browse the repository at this point in the history
* fix: Fix multisig with light client

1. Any multisig script should sync from 0.
2. When adding multisig address after deletion, it should start sync again.
3. Every 10s to refresh multisig sync height, not when multisig address changes.
  • Loading branch information
yanguoyu authored May 26, 2023
1 parent 8b59e20 commit d84682a
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 23 deletions.
16 changes: 11 additions & 5 deletions packages/neuron-ui/src/components/MultisigAddress/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,17 +320,23 @@ export const useSubscription = ({
useEffect(() => {
const dataUpdateSubscription = MultisigOutputUpdate.subscribe(() => {
getAndSaveMultisigBalances()
if (isLightClient) {
getAndSaveMultisigSyncProgress()
}
})
getAndSaveMultisigBalances()
return () => {
dataUpdateSubscription.unsubscribe()
}
}, [walletId, getAndSaveMultisigBalances])
useEffect(() => {
let interval: ReturnType<typeof setInterval> | undefined
if (isLightClient) {
interval = setInterval(() => {
getAndSaveMultisigSyncProgress()
}, 10000)
getAndSaveMultisigSyncProgress()
}
return () => {
dataUpdateSubscription.unsubscribe()
clearInterval(interval)
}
}, [walletId, getAndSaveMultisigBalances])
}, [isLightClient, getAndSaveMultisigSyncProgress])
return { multisigBanlances, multisigSyncProgress }
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ export default class LightConnector extends Connector<CKBComponents.Hash> {
})
}

private async initSyncProgress(appendScripts?: AppendScript[]) {
if (!this.addressMetas.length && !appendScripts?.length) {
private async initSyncProgress(appendScripts: AppendScript[] = []) {
if (!this.addressMetas.length && !appendScripts.length) {
return
}
const syncScripts = await this.lightRpc.getScripts()
Expand All @@ -181,27 +181,35 @@ export default class LightConnector extends Connector<CKBComponents.Hash> {
}))
})
.flat()
.concat(appendScripts ?? [])
const walletMinBlockNumber = await SyncProgressService.getWalletMinBlockNumber()
const wallets = await WalletService.getInstance().getAll()
const walletStartBlockMap = wallets.reduce<Record<string, string | undefined>>(
(pre, cur) => ({ ...pre, [cur.id]: cur.startBlockNumberInLight }),
{}
)
const setScriptsParams = allScripts.map(v => ({
...v,
blockNumber:
existSyncscripts[scriptToHash(v.script)]?.blockNumber ??
walletStartBlockMap[v.walletId] ??
`0x${(walletMinBlockNumber?.[v.walletId] ?? 0).toString(16)}`
}))
const otherTypeSyncProgress = await SyncProgressService.getOtherTypeSyncProgress()
const setScriptsParams = [
...allScripts.map(v => ({
...v,
blockNumber:
existSyncscripts[scriptToHash(v.script)]?.blockNumber ??
walletStartBlockMap[v.walletId] ??
`0x${(walletMinBlockNumber?.[v.walletId] ?? 0).toString(16)}`
})),
...appendScripts.map(v => ({
...v,
blockNumber:
existSyncscripts[scriptToHash(v.script)]?.blockNumber ??
`0x${(otherTypeSyncProgress[scriptToHash(v.script)] ?? 0).toString(16)}`
}))
]
await this.lightRpc.setScripts(setScriptsParams)
await SyncProgressService.resetSyncProgress(allScripts)
const walletIds = [...new Set(this.addressMetas.map(v => v.walletId))]
await SyncProgressService.removeWalletsByExists(walletIds)
await SyncProgressService.resetSyncProgress([allScripts, appendScripts].flat())
await SyncProgressService.updateSyncProgressFlag(walletIds)
await SyncProgressService.removeByHashesAndAddressType(
SyncAddressType.Multisig,
appendScripts?.map(v => scriptToHash(v.script))
appendScripts.map(v => scriptToHash(v.script))
)
}

Expand Down
19 changes: 17 additions & 2 deletions packages/neuron-wallet/src/services/sync-progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@ export default class SyncProgressService {
.execute()
}

static async removeWalletsByExists(existWalletIds: string[]) {
static async updateSyncProgressFlag(existWalletIds: string[]) {
await getConnection()
.createQueryBuilder()
.update(SyncProgress)
.set({ delete: true })
.where({ walletId: Not(In(existWalletIds)) })
.execute()
await getConnection()
.createQueryBuilder()
.update(SyncProgress)
.set({ delete: false })
.where({ walletId: In(existWalletIds) })
.execute()
}

static async removeByHashesAndAddressType(addressType: SyncAddressType, existHashes?: string[]) {
Expand Down Expand Up @@ -84,7 +90,7 @@ export default class SyncProgressService {
const item = await getConnection()
.getRepository(SyncProgress)
.createQueryBuilder()
.where({ delete: false, ...(currentWallet ? { walletId: currentWallet.id } : {}) })
.where({ delete: false, addressType: SyncAddressType.Default, ...(currentWallet ? { walletId: currentWallet.id } : {}) })
.orderBy('blockEndNumber', 'ASC')
.getOne()
return item?.blockEndNumber || 0
Expand All @@ -101,6 +107,15 @@ export default class SyncProgressService {
return items.reduce<Record<string, number>>((pre, cur) => ({ ...pre, [cur.walletId]: cur.blockStartNumber }), {})
}

static async getOtherTypeSyncProgress() {
const items = await getConnection()
.getRepository(SyncProgress)
.find({
addressType: SyncAddressType.Multisig,
})
return items.reduce<Record<string, number>>((pre, cur) => ({ ...pre, [cur.hash]: cur.blockStartNumber }), {})
}

static async getSyncProgressByHashes(hashes: string[]) {
return await getConnection()
.getRepository(SyncProgress)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ const getCurrentWalletMinBlockNumberMock = jest.fn()
const getAllSyncStatusToMapMock = jest.fn()
const resetSyncProgressMock = jest.fn()
const updateSyncStatusMock = jest.fn()
const removeWalletsByExistsMock = jest.fn()
const updateSyncProgressFlagMock = jest.fn()
const getWalletMinBlockNumberMock = jest.fn()
const removeByHashesAndAddressType = jest.fn()
const getOtherTypeSyncProgressMock = jest.fn()

const setScriptsMock = jest.fn()
const getScriptsMock = jest.fn()
Expand All @@ -31,6 +32,7 @@ function mockReset() {
resetSyncProgressMock.mockReset()
updateSyncStatusMock.mockReset()
getWalletMinBlockNumberMock.mockReset()
getOtherTypeSyncProgressMock.mockReset()

setScriptsMock.mockReset()
getScriptsMock.mockReset()
Expand All @@ -52,9 +54,10 @@ jest.mock('../../src/services/sync-progress', () => {
static getAllSyncStatusToMap: any = () => getAllSyncStatusToMapMock()
static resetSyncProgress: any = (arg: any) => resetSyncProgressMock(arg)
static updateSyncStatus: any = (hash: string, update: any) => updateSyncStatusMock(hash, update)
static removeWalletsByExists: any = (walletIds: string[]) => removeWalletsByExistsMock(walletIds)
static updateSyncProgressFlag: any = (walletIds: string[]) => updateSyncProgressFlagMock(walletIds)
static getWalletMinBlockNumber: any = () => getWalletMinBlockNumberMock()
static removeByHashesAndAddressType: any = (type: number, scripts: CKBComponents.Script[]) => removeByHashesAndAddressType(type, scripts)
static getOtherTypeSyncProgress: any = () => getOtherTypeSyncProgressMock()
}
})

Expand Down Expand Up @@ -101,6 +104,8 @@ describe('test light connector', () => {
beforeEach(() => {
walletGetAllMock.mockReturnValue([])
createBatchRequestMock.mockResolvedValue([])
getMultisigConfigForLightMock.mockResolvedValue([])
getOtherTypeSyncProgressMock.mockResolvedValue({})
})
afterEach(() => {
mockReset()
Expand Down Expand Up @@ -287,7 +292,7 @@ describe('test light connector', () => {
{ script: addressMeta.generateACPLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId' },
{ script: addressMeta.generateLegacyACPLockScript().toSDK(), scriptType: 'lock', walletId: 'walletId' },
])
expect(removeWalletsByExistsMock).toBeCalledWith(['walletId'])
expect(updateSyncProgressFlagMock).toBeCalledWith(['walletId'])
})
it('set new script with the synced min block number', async () => {
getScriptsMock.mockResolvedValue([])
Expand Down

1 comment on commit d84682a

@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 5086708030

Please sign in to comment.