Parallelize address scanning and unify address display formatting
Some checks failed
check / check (push) Has been cancelled
Some checks failed
check / check (push) Has been cancelled
Scanning: check all gap-limit addresses in parallel per batch instead of sequentially. For a wallet with 1 used address this reduces from 12 sequential RPC round-trips to 1 parallel batch + 1 small follow-up. Display: add shared formatAddressHtml(address, ensName, maxLen) and escapeHtml() to helpers.js. Use them in confirm-tx (was missing color dot entirely) and approval view. Remove duplicate escapeHtml from addressDetail.js.
This commit is contained in:
@@ -166,44 +166,54 @@ async function lookupTokenInfo(contractAddress, rpcUrl) {
|
||||
}
|
||||
|
||||
// Derive HD addresses starting from index 0 and check for on-chain activity.
|
||||
// Stops after gapLimit consecutive addresses with zero balance and zero tx count.
|
||||
// Checks gapLimit addresses in parallel per batch. Stops when an entire
|
||||
// batch has no used addresses (i.e. gapLimit consecutive empty addresses).
|
||||
// Returns { addresses: [{ address, index }], nextIndex }.
|
||||
async function scanForAddresses(xpub, rpcUrl, gapLimit = 5) {
|
||||
log.debugf("scanForAddresses start, gapLimit:", gapLimit);
|
||||
const provider = getProvider(rpcUrl);
|
||||
const used = [];
|
||||
let gap = 0;
|
||||
let index = 0;
|
||||
let checked = 0;
|
||||
let checkUpTo = gapLimit;
|
||||
|
||||
while (gap < gapLimit) {
|
||||
const addr = deriveAddressFromXpub(xpub, index);
|
||||
let balance, txCount;
|
||||
try {
|
||||
[balance, txCount] = await Promise.all([
|
||||
provider.getBalance(addr),
|
||||
provider.getTransactionCount(addr),
|
||||
]);
|
||||
} catch (e) {
|
||||
log.errorf(
|
||||
"scanForAddresses check failed",
|
||||
addr,
|
||||
e.shortMessage || e.message,
|
||||
);
|
||||
// Treat RPC failure as empty to avoid infinite loop
|
||||
gap++;
|
||||
index++;
|
||||
continue;
|
||||
while (checked < checkUpTo) {
|
||||
const batch = [];
|
||||
for (let i = checked; i < checkUpTo; i++) {
|
||||
const addr = deriveAddressFromXpub(xpub, i);
|
||||
batch.push({ addr, index: i });
|
||||
}
|
||||
if (balance > 0n || txCount > 0) {
|
||||
used.push({ address: addr, index });
|
||||
gap = 0;
|
||||
log.debugf("scanForAddresses used", addr, "index:", index);
|
||||
} else {
|
||||
gap++;
|
||||
|
||||
const results = await Promise.all(
|
||||
batch.map(async ({ addr, index }) => {
|
||||
try {
|
||||
const [balance, txCount] = await Promise.all([
|
||||
provider.getBalance(addr),
|
||||
provider.getTransactionCount(addr),
|
||||
]);
|
||||
return { addr, index, isUsed: balance > 0n || txCount > 0 };
|
||||
} catch (e) {
|
||||
log.errorf(
|
||||
"scanForAddresses check failed",
|
||||
addr,
|
||||
e.shortMessage || e.message,
|
||||
);
|
||||
return { addr, index, isUsed: false };
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
checked = checkUpTo;
|
||||
|
||||
for (const r of results) {
|
||||
if (r.isUsed) {
|
||||
used.push({ address: r.addr, index: r.index });
|
||||
log.debugf("scanForAddresses used", r.addr, "index:", r.index);
|
||||
checkUpTo = Math.max(checkUpTo, r.index + 1 + gapLimit);
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
used.sort((a, b) => a.index - b.index);
|
||||
const nextIndex = used.length > 0 ? used[used.length - 1].index + 1 : 1;
|
||||
log.infof(
|
||||
"scanForAddresses done, found:",
|
||||
|
||||
Reference in New Issue
Block a user