diff --git a/packages/neuron-wallet/src/block-sync-renderer/index.ts b/packages/neuron-wallet/src/block-sync-renderer/index.ts index 95576c84a7..cf690f014b 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/index.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/index.ts @@ -64,7 +64,7 @@ export const resetSyncTask = async (startTask = true) => { if (startTask) { await WalletService.getInstance().maintainAddressesIfNecessary() - await TransactionPersistor.checkTxLock() + await CommonUtils.retry(3, 5000, TransactionPersistor.checkTxLock) await CommonUtils.sleep(3000) await createBlockSyncTask() } diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/light-synchronizer.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/light-synchronizer.ts index ece089a109..6a7d5bc761 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/light-synchronizer.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/light-synchronizer.ts @@ -267,6 +267,10 @@ export default class LightSynchronizer extends Synchronizer { } private async updateBlockStartNumber(blockNumber: number) { + if (this._needGenerateAddress || !this.pollingIndexer) { + logger.info('LightConnector:\twait for generating address') + return + } const scripts = await this.lightRpc.getScripts() await SyncProgressService.updateBlockNumber( scripts.map(v => v.script.args), diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts index a09055eb58..027bc14967 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts @@ -22,6 +22,7 @@ import LightSynchronizer from './light-synchronizer' import { generateRPC } from '../../utils/ckb-rpc' import { BUNDLED_LIGHT_CKB_URL } from '../../utils/const' import { NetworkType } from '../../models/network' +import WalletService from '../../services/wallets' export default class Queue { #lockHashes: string[] @@ -254,6 +255,9 @@ export default class Queue { .map(addr => addr.walletId) ) if (process.send) { + this.#indexerConnector!.needGenerateAddress = await WalletService.getInstance().checkNeedGenerateAddress([ + ...walletIds, + ]) process.send({ channel: 'check-and-save-wallet-address', message: [...walletIds] }) } else { throw new ShouldInChildProcess() diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/synchronizer.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/synchronizer.ts index 7b1fd0b4e8..b8d1a789a2 100644 --- a/packages/neuron-wallet/src/block-sync-renderer/sync/synchronizer.ts +++ b/packages/neuron-wallet/src/block-sync-renderer/sync/synchronizer.ts @@ -58,6 +58,7 @@ export abstract class Synchronizer { protected addressesByWalletId: Map = new Map() protected pollingIndexer: boolean = false private indexerQueryQueue: QueueObject | undefined + protected _needGenerateAddress: boolean = false abstract connect(): Promise abstract processTxsInNextBlockNumber(): Promise @@ -96,6 +97,10 @@ export abstract class Synchronizer { this.pollingIndexer = false } + public set needGenerateAddress(v: boolean) { + this._needGenerateAddress = v + } + protected async processNextBlockNumber() { // the processNextBlockNumberQueue is a queue to ensure that ONLY one // block processing task runs at a time to avoid the data conflict while syncing diff --git a/packages/neuron-wallet/src/services/addresses.ts b/packages/neuron-wallet/src/services/addresses.ts index 91647a04e7..c9530ec1ca 100644 --- a/packages/neuron-wallet/src/services/addresses.ts +++ b/packages/neuron-wallet/src/services/addresses.ts @@ -95,20 +95,17 @@ export default class AddressService { receivingAddressCount: number = DefaultAddressNumber.Receiving, changeAddressCount: number = DefaultAddressNumber.Change ): Promise { - const [unusedReceivingAddresses, unusedChangeAddresses] = await this.getGroupedUnusedAddressesByWalletId(walletId) - const unusedReceivingCount = unusedReceivingAddresses.length - const unusedChangeCount = unusedChangeAddresses.length - if (unusedReceivingCount > this.minUnusedAddressCount && unusedChangeCount > this.minUnusedAddressCount) { - return undefined - } + const [receivingCount, changeCount] = await this.getAddressCountsToFillGapLimit( + walletId, + receivingAddressCount, + changeAddressCount + ) + if (!receivingCount && !changeCount) return undefined const maxReceivingAddressIndex = await this.maxAddressIndex(walletId, AddressType.Receiving) const maxChangeAddressIndex = await this.maxAddressIndex(walletId, AddressType.Change) const nextReceivingIndex = maxReceivingAddressIndex === undefined ? 0 : maxReceivingAddressIndex + 1 const nextChangeIndex = maxChangeAddressIndex === undefined ? 0 : maxChangeAddressIndex + 1 - const receivingCount: number = unusedReceivingCount > this.minUnusedAddressCount ? 0 : receivingAddressCount - const changeCount: number = unusedChangeCount > this.minUnusedAddressCount ? 0 : changeAddressCount - const currentGeneratedAddresses = await this.generateAndSave( walletId, extendedKey, @@ -140,6 +137,20 @@ export default class AddressService { return allGeneratedAddresses } + public static async getAddressCountsToFillGapLimit( + walletId: string, + receivingAddressCount: number = DefaultAddressNumber.Receiving, + changeAddressCount: number = DefaultAddressNumber.Change + ) { + const [unusedReceivingAddresses, unusedChangeAddresses] = await this.getGroupedUnusedAddressesByWalletId(walletId) + const unusedReceivingCount = unusedReceivingAddresses.length + const unusedChangeCount = unusedChangeAddresses.length + return [ + unusedReceivingCount > this.minUnusedAddressCount ? 0 : receivingAddressCount, + unusedChangeCount > this.minUnusedAddressCount ? 0 : changeAddressCount, + ] + } + public static async generateAndSaveForExtendedKey({ walletId, extendedKey, diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 6d7306c8d4..cc9c15be14 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -110,6 +110,10 @@ export abstract class Wallet { } } + public async needsGenerateAddress() { + return false + } + public abstract checkAndGenerateAddresses( isImporting?: boolean, receivingAddressCount?: number, @@ -179,6 +183,11 @@ export class FileKeystoreWallet extends Wallet { return `${this.id}.json` } + public async needsGenerateAddress() { + const [receiveCount, changeCount] = await AddressService.getAddressCountsToFillGapLimit(this.id) + return receiveCount !== 0 || changeCount !== 0 + } + public checkAndGenerateAddresses = async ( isImporting: boolean = false, receivingAddressCount: number = DefaultAddressNumber.Receiving, @@ -365,6 +374,16 @@ export default class WalletService { } } + public async checkNeedGenerateAddress(walletIds: string[]) { + for (const walletId of new Set(walletIds)) { + const wallet = this.get(walletId) + if (await wallet.needsGenerateAddress()) { + return true + } + } + return false + } + public create = (props: WalletProperties) => { if (!props) { throw new IsRequired('wallet property') diff --git a/packages/neuron-wallet/tests/block-sync-renderer/index/resetSyncTask.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/index/resetSyncTask.test.ts index 8cf8258bab..848f155c9a 100644 --- a/packages/neuron-wallet/tests/block-sync-renderer/index/resetSyncTask.test.ts +++ b/packages/neuron-wallet/tests/block-sync-renderer/index/resetSyncTask.test.ts @@ -5,7 +5,11 @@ describe(`Reset sync task`, () => { jest.doMock('services/wallets', () => ({ getInstance: () => ({ maintainAddressesIfNecessary: stubbedmaintainAddressesIfNecessary }), })) - jest.doMock('utils/common', () => ({ sleep: stubbedSleep, timeout: stubbedTimeout })) + jest.doMock('utils/common', () => ({ + sleep: stubbedSleep, + timeout: stubbedTimeout, + retry: (_: number, __: number, fn: () => void) => fn(), + })) jest.doMock('services/tx', () => ({ TransactionPersistor: { checkTxLock: jest.fn() } })) const blockSyncRenderer = require('block-sync-renderer') diff --git a/packages/neuron-wallet/tests/block-sync-renderer/queue.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/queue.test.ts index d181a4ae5c..0e1e8661cd 100644 --- a/packages/neuron-wallet/tests/block-sync-renderer/queue.test.ts +++ b/packages/neuron-wallet/tests/block-sync-renderer/queue.test.ts @@ -183,6 +183,15 @@ describe('queue', () => { }, } }) + jest.doMock('../../src/services/wallets', () => { + return { + getInstance() { + return { + checkNeedGenerateAddress: jest.fn(), + } + }, + } + }) const Queue = require('../../src/block-sync-renderer/sync/queue').default queue = new Queue(fakeNodeUrl, addresses) })