From 2bfce21058b7cc7973b9df7b5394f60315c0e0e3 Mon Sep 17 00:00:00 2001 From: julian <julian@cypherstack.com> Date: Wed, 26 Apr 2023 09:27:29 -0600 Subject: [PATCH] btc restore gap fix --- .../coins/bitcoin/bitcoin_wallet.dart | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/services/coins/bitcoin/bitcoin_wallet.dart b/lib/services/coins/bitcoin/bitcoin_wallet.dart index dd3301835..86d84b0c0 100644 --- a/lib/services/coins/bitcoin/bitcoin_wallet.dart +++ b/lib/services/coins/bitcoin/bitcoin_wallet.dart @@ -423,7 +423,7 @@ class BitcoinWallet extends CoinServiceAPI level: LogLevel.Info); } - Future<Tuple2<List<isar_models.Address>, DerivePathType>> _checkGaps( + Future<Tuple3<List<isar_models.Address>, DerivePathType, int>> _checkGaps( int maxNumberOfIndexesToCheck, int maxUnusedAddressGap, int txCountBatchSize, @@ -433,6 +433,8 @@ class BitcoinWallet extends CoinServiceAPI ) async { List<isar_models.Address> addressArray = []; int gapCounter = 0; + int highestIndexWithHistory = 0; + for (int index = 0; index < maxNumberOfIndexesToCheck && gapCounter < maxUnusedAddressGap; index += txCountBatchSize) { @@ -506,6 +508,9 @@ class BitcoinWallet extends CoinServiceAPI if (count > 0) { iterationsAddressArray.add(txCountCallArgs["${_id}_$k"]!); + // update highest + highestIndexWithHistory = index + k; + // reset counter gapCounter = 0; } @@ -518,7 +523,7 @@ class BitcoinWallet extends CoinServiceAPI // cache all the transactions while waiting for the current function to finish. unawaited(getTransactionCacheEarly(iterationsAddressArray)); } - return Tuple2(addressArray, type); + return Tuple3(addressArray, type, highestIndexWithHistory); } Future<void> getTransactionCacheEarly(List<String> allAddresses) async { @@ -562,9 +567,9 @@ class BitcoinWallet extends CoinServiceAPI DerivePathType.bip84, ]; - final List<Future<Tuple2<List<isar_models.Address>, DerivePathType>>> + final List<Future<Tuple3<List<isar_models.Address>, DerivePathType, int>>> receiveFutures = []; - final List<Future<Tuple2<List<isar_models.Address>, DerivePathType>>> + final List<Future<Tuple3<List<isar_models.Address>, DerivePathType, int>>> changeFutures = []; const receiveChain = 0; @@ -623,6 +628,7 @@ class BitcoinWallet extends CoinServiceAPI final List<isar_models.Address> addressesToStore = []; + int highestReceivingIndexWithHistory = 0; // If restoring a wallet that never received any funds, then set receivingArray manually // If we didn't do this, it'd store an empty array for (final tuple in receiveResults) { @@ -634,10 +640,13 @@ class BitcoinWallet extends CoinServiceAPI ); addressesToStore.add(address); } else { + highestReceivingIndexWithHistory = + max(tuple.item3, highestReceivingIndexWithHistory); addressesToStore.addAll(tuple.item1); } } + int highestChangeIndexWithHistory = 0; // If restoring a wallet that never sent any funds with change, then set changeArray // manually. If we didn't do this, it'd store an empty array. for (final tuple in changeResults) { @@ -649,10 +658,20 @@ class BitcoinWallet extends CoinServiceAPI ); addressesToStore.add(address); } else { + highestChangeIndexWithHistory = + max(tuple.item3, highestChangeIndexWithHistory); addressesToStore.addAll(tuple.item1); } } + // remove extra addresses to help minimize risk of creating a large gap + addressesToStore.removeWhere((e) => + e.subType == isar_models.AddressSubType.change && + e.derivationIndex > highestChangeIndexWithHistory); + addressesToStore.removeWhere((e) => + e.subType == isar_models.AddressSubType.receiving && + e.derivationIndex > highestReceivingIndexWithHistory); + if (isRescan) { await db.updateOrPutAddresses(addressesToStore); } else {