diff --git a/lib/db/mysql-db-wrapper.js b/lib/db/mysql-db-wrapper.js index 6171341..dcab303 100644 --- a/lib/db/mysql-db-wrapper.js +++ b/lib/db/mysql-db-wrapper.js @@ -931,6 +931,36 @@ class MySqlDbWrapper { return ret } + /** + * Get the number of indices derived in an interval for a HD chain + * @param {string} xpub - xpub + * @param {integer} chain - HD chain (0 or 1) + * @param {integer} minIdx - min index of derivation + * @param {integer} maxIdx - max index of derivation + * @returns {integer[]} returns an array of number of derived indices + */ + async getHDAccountNbDerivedIndices(xpub, chain, minIdx, maxIdx) { + const sqlQuery = 'SELECT \ + COUNT(`hd_addresses`.`hdAddrIndex`) AS `nbDerivedIndices` \ + FROM `hd_addresses` \ + INNER JOIN `hd` ON `hd_addresses`.`hdID` = `hd`.`hdID` \ + WHERE `hd`.`hdXpub` = ? \ + AND `hd_addresses`.`hdAddrChain` = ? \ + AND `hd_addresses`.`hdAddrIndex` >= ? \ + AND `hd_addresses`.`hdAddrIndex` <= ?' + + const params = [xpub, chain, minIdx, maxIdx] + const query = mysql.format(sqlQuery, params) + const results = await this._query(query) + + if (results.length == 1) { + const nbDerivedIndices = results[0].nbDerivedIndices + return (nbDerivedIndices == null) ? 0 : nbDerivedIndices + } + + return 0 + } + /** * Get the number of transactions for an HD account * @param {string} xpub - xpub diff --git a/tracker/transaction.js b/tracker/transaction.js index e313227..4d381f9 100644 --- a/tracker/transaction.js +++ b/tracker/transaction.js @@ -333,9 +333,24 @@ class Transaction { if (chainMaxUsedIndex < unusedIndices[chain]) continue - // If max derived index is beyond max used index plus gap limit, move on - if (derivedIndices[chain] >= chainMaxUsedIndex + gapLimit[chain]) - continue + // If max derived index is beyond max used index plus gap limit. + if (derivedIndices[chain] >= chainMaxUsedIndex + gapLimit[chain]) { + // Check that we don't have a hole in the next indices + const nbDerivedIndicesForward = await db.getHDAccountNbDerivedIndices( + xpub, + chain, + chainMaxUsedIndex, + chainMaxUsedIndex + gapLimit[chain] + ) + + if (nbDerivedIndicesForward < gapLimit[chain] + 1) { + // Hole detected. Force derivation. + derivedIndices[chain] = chainMaxUsedIndex + } else { + // Move on + continue + } + } let done