cormorant: fix descriptor range calculation and extend range from pruned date only where necessary

This commit is contained in:
Craig Raw 2023-11-30 12:54:50 +02:00
parent d425933189
commit 6ee3755ce4

View file

@ -46,6 +46,8 @@ public class BitcoindClient {
private static final int DEFAULT_GAP_LIMIT = 1000; private static final int DEFAULT_GAP_LIMIT = 1000;
private static final int POSTMIX_GAP_LIMIT = 4000; private static final int POSTMIX_GAP_LIMIT = 4000;
private static final long PRUNED_RESCAN_TIMEGAP_MILLIS = 7200*1000;
private final JsonRpcClient jsonRpcClient; private final JsonRpcClient jsonRpcClient;
private final Timer timer = new Timer(true); private final Timer timer = new Timer(true);
private final Store store = new Store(); private final Store store = new Store();
@ -258,7 +260,7 @@ public class BitcoindClient {
} }
private ScanDate getScanDate(String normalizedDescriptor, Wallet wallet, KeyPurpose keyPurpose, Date earliestBirthDate) { private ScanDate getScanDate(String normalizedDescriptor, Wallet wallet, KeyPurpose keyPurpose, Date earliestBirthDate) {
Integer range = (keyPurpose == null ? null : getHighestUsedIndex(normalizedDescriptor, wallet, keyPurpose) + getGapLimit(wallet, keyPurpose)); Integer range = (keyPurpose == null ? null : Math.max(getHighestUsedIndex(normalizedDescriptor, wallet, keyPurpose) + wallet.getGapLimit(), getDefaultRange(wallet, keyPurpose)));
//Force a rescan if loading a wallet with a birthday later than existing transactions, or if the wallet birthdate has been set or changed to an earlier date from the last check //Force a rescan if loading a wallet with a birthday later than existing transactions, or if the wallet birthdate has been set or changed to an earlier date from the last check
boolean forceRescan = false; boolean forceRescan = false;
@ -277,8 +279,8 @@ public class BitcoindClient {
return descriptorUsedIndexes.compute(descriptor, (d, lastHighestUsedIndex) -> lastHighestUsedIndex == null ? highestUsedIndex : Math.max(highestUsedIndex, lastHighestUsedIndex)); return descriptorUsedIndexes.compute(descriptor, (d, lastHighestUsedIndex) -> lastHighestUsedIndex == null ? highestUsedIndex : Math.max(highestUsedIndex, lastHighestUsedIndex));
} }
private int getGapLimit(Wallet wallet, KeyPurpose keyPurpose) { private int getDefaultRange(Wallet wallet, KeyPurpose keyPurpose) {
return Math.max(wallet.getGapLimit(), wallet.getStandardAccountType() == StandardAccount.WHIRLPOOL_POSTMIX && keyPurpose == KeyPurpose.RECEIVE ? POSTMIX_GAP_LIMIT : DEFAULT_GAP_LIMIT); return wallet.getStandardAccountType() == StandardAccount.WHIRLPOOL_POSTMIX && keyPurpose == KeyPurpose.RECEIVE ? POSTMIX_GAP_LIMIT : DEFAULT_GAP_LIMIT;
} }
private void importDescriptors(Map<String, ScanDate> descriptors) throws ScanDateBeforePruneException { private void importDescriptors(Map<String, ScanDate> descriptors) throws ScanDateBeforePruneException {
@ -320,6 +322,7 @@ public class BitcoindClient {
} }
} }
Optional<Date> optPrunedDate = pruned ? getPrunedDate() : Optional.empty();
Map<String, ScanDate> importingDescriptors = new LinkedHashMap<>(descriptors); Map<String, ScanDate> importingDescriptors = new LinkedHashMap<>(descriptors);
importingDescriptors.keySet().removeAll(importedDescriptors.keySet()); importingDescriptors.keySet().removeAll(importedDescriptors.keySet());
for(Map.Entry<String, ScanDate> entry : descriptors.entrySet()) { for(Map.Entry<String, ScanDate> entry : descriptors.entrySet()) {
@ -330,7 +333,10 @@ public class BitcoindClient {
ScanDate scanDate = entry.getValue(); ScanDate scanDate = entry.getValue();
ScanDate importedScanDate = importedDescriptors.get(entry.getKey()); ScanDate importedScanDate = importedDescriptors.get(entry.getKey());
if(scanDate.range != null && importedScanDate != null && importedScanDate.range != null && scanDate.range > importedScanDate.range) { if(scanDate.range != null && importedScanDate != null && importedScanDate.range != null && scanDate.range > importedScanDate.range) {
importingDescriptors.put(entry.getKey(), new ScanDate(importedScanDate.rescanSince == null || scanDate.forceRescan ? scanDate.rescanSince : importedScanDate.rescanSince, scanDate.range, false)); Date rescanSince = scanDate.rescanSince != null && (importedScanDate.rescanSince == null || scanDate.rescanSince.before(importedScanDate.rescanSince)) ? scanDate.rescanSince : importedScanDate.rescanSince;
Optional<Date> optPrunedStart = optPrunedDate.map(date -> new Date(date.getTime() + PRUNED_RESCAN_TIMEGAP_MILLIS));
rescanSince = optPrunedStart.isPresent() && (rescanSince == null || optPrunedStart.get().after(rescanSince)) ? optPrunedStart.get() : rescanSince;
importingDescriptors.put(entry.getKey(), new ScanDate(rescanSince, scanDate.range, false));
} else if(scanDate.forceRescan) { } else if(scanDate.forceRescan) {
if(scanDate.rescanSince != null && (importedScanDate == null || importedScanDate.rescanSince == null || scanDate.rescanSince.before(importedScanDate.rescanSince))) { if(scanDate.rescanSince != null && (importedScanDate == null || importedScanDate.rescanSince == null || scanDate.rescanSince.before(importedScanDate.rescanSince))) {
importingDescriptors.put(entry.getKey(), new ScanDate(scanDate.rescanSince, importedScanDate != null ? importedScanDate.range : scanDate.range, false)); importingDescriptors.put(entry.getKey(), new ScanDate(scanDate.rescanSince, importedScanDate != null ? importedScanDate.range : scanDate.range, false));
@ -338,15 +344,12 @@ public class BitcoindClient {
} }
} }
if(pruned) { if(optPrunedDate.isPresent()) {
Optional<Date> optPrunedDate = getPrunedDate(); Date prunedDate = optPrunedDate.get();
if(optPrunedDate.isPresent()) { Optional<Map.Entry<String, ScanDate>> optPrePruneImport = importingDescriptors.entrySet().stream().filter(entry -> entry.getValue().rescanSince != null && entry.getValue().rescanSince.before(prunedDate)).findFirst();
Date prunedDate = optPrunedDate.get(); if(optPrePruneImport.isPresent()) {
Optional<Map.Entry<String, ScanDate>> optPrePruneImport = importingDescriptors.entrySet().stream().filter(entry -> entry.getValue().rescanSince != null && entry.getValue().rescanSince.before(prunedDate)).findFirst(); Map.Entry<String, ScanDate> prePruneImport = optPrePruneImport.get();
if(optPrePruneImport.isPresent()) { throw new ScanDateBeforePruneException(prePruneImport.getKey(), prePruneImport.getValue().rescanSince, prunedDate);
Map.Entry<String, ScanDate> prePruneImport = optPrePruneImport.get();
throw new ScanDateBeforePruneException(prePruneImport.getKey(), prePruneImport.getValue().rescanSince, prunedDate);
}
} }
} }