From a4a7abd6b8589ea08d3fd0dbf9e17b5edbbfd342 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 18 Jul 2024 08:41:28 -0600 Subject: [PATCH] look ahead on frost wallet addresses to check for transactions on future addresses --- .../wallet/impl/bitcoin_frost_wallet.dart | 92 +++++++++++++++++++ lib/wallets/wallet/wallet.dart | 4 + 2 files changed, 96 insertions(+) diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart index 8374d9a8a..24a690b2a 100644 --- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart +++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart @@ -1455,6 +1455,98 @@ class BitcoinFrostWallet extends Wallet ); } + Future lookAhead() async { + Address? currentReceiving = await getCurrentReceivingAddress(); + if (currentReceiving == null) { + await generateNewReceivingAddress(); + currentReceiving = await getCurrentReceivingAddress(); + } + Address? currentChange = await getCurrentChangeAddress(); + if (currentChange == null) { + await generateNewChangeAddress(); + currentChange = await getCurrentChangeAddress(); + } + + final List
nextReceivingAddresses = []; + final List
nextChangeAddresses = []; + + int receiveIndex = currentReceiving!.derivationIndex; + int changeIndex = currentChange!.derivationIndex; + for (int i = 0; i < 10; i++) { + final receiveAddress = await _generateAddressSafe( + chain: 0, + startingIndex: receiveIndex + 1, + ); + receiveIndex = receiveAddress.derivationIndex; + nextReceivingAddresses.add(receiveAddress); + + final changeAddress = await _generateAddressSafe( + chain: 1, + startingIndex: changeIndex + 1, + ); + changeIndex = changeAddress.derivationIndex; + nextChangeAddresses.add(changeAddress); + } + + int activeReceiveIndex = currentReceiving.derivationIndex; + int activeChangeIndex = currentChange.derivationIndex; + for (final address in nextReceivingAddresses) { + final txCount = await _fetchTxCount(address: address); + if (txCount > 0) { + activeReceiveIndex = max(activeReceiveIndex, address.derivationIndex); + } + } + for (final address in nextChangeAddresses) { + final txCount = await _fetchTxCount(address: address); + if (txCount > 0) { + activeChangeIndex = max(activeChangeIndex, address.derivationIndex); + } + } + + nextReceivingAddresses + .removeWhere((e) => e.derivationIndex > activeReceiveIndex); + if (nextReceivingAddresses.isNotEmpty) { + await mainDB.updateOrPutAddresses(nextReceivingAddresses); + await info.updateReceivingAddress( + newAddress: nextReceivingAddresses.last.value, + isar: mainDB.isar, + ); + } + nextChangeAddresses + .removeWhere((e) => e.derivationIndex > activeChangeIndex); + if (nextChangeAddresses.isNotEmpty) { + await mainDB.updateOrPutAddresses(nextChangeAddresses); + } + } + + Future
_generateAddressSafe({ + required final int chain, + required int startingIndex, + }) async { + final serializedKeys = (await getSerializedKeys())!; + + Address? address; + while (address == null) { + try { + address = await _generateAddress( + change: chain, + index: startingIndex, + serializedKeys: serializedKeys, + ); + } on FrostdartException catch (e) { + if (e.errorCode == 72) { + // rust doesn't like the addressDerivationData + startingIndex++; + continue; + } else { + rethrow; + } + } + } + + return address; + } + /// Can and will often throw unless [index], [change], and [account] are zero. /// Caller MUST handle exception! Future
_generateAddress({ diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart index 46540eef7..4837eb8d3 100644 --- a/lib/wallets/wallet/wallet.dart +++ b/lib/wallets/wallet/wallet.dart @@ -518,6 +518,10 @@ abstract class Wallet { GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.0, walletId)); await updateChainHeight(); + if (this is BitcoinFrostWallet) { + await (this as BitcoinFrostWallet).lookAhead(); + } + GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.1, walletId)); // TODO: [prio=low] handle this differently. Extra modification of this file for coin specific functionality should be avoided.