diff --git a/src/main/java/org/qortal/controller/OnlineAccountsManager.java b/src/main/java/org/qortal/controller/OnlineAccountsManager.java index 39ce8a85..f770bc3a 100644 --- a/src/main/java/org/qortal/controller/OnlineAccountsManager.java +++ b/src/main/java/org/qortal/controller/OnlineAccountsManager.java @@ -66,7 +66,7 @@ public class OnlineAccountsManager { private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(4, new NamedThreadFactory("OnlineAccounts")); private volatile boolean isStopping = false; - private final Set onlineAccountsImportQueue = ConcurrentHashMap.newKeySet(); + private final List onlineAccountsImportQueue = Collections.synchronizedList(new ArrayList<>()); /** * Cache of 'current' online accounts, keyed by timestamp @@ -184,9 +184,12 @@ public class OnlineAccountsManager { LOGGER.debug("Processing online accounts import queue (size: {})", this.onlineAccountsImportQueue.size()); + // Take a copy of onlineAccountsImportQueue so we can safely remove whilst iterating + List onlineAccountsImportQueueCopy = new ArrayList<>(this.onlineAccountsImportQueue); + Set onlineAccountsToAdd = new HashSet<>(); try (final Repository repository = RepositoryManager.getRepository()) { - for (OnlineAccountData onlineAccountData : this.onlineAccountsImportQueue) { + for (OnlineAccountData onlineAccountData : onlineAccountsImportQueueCopy) { if (isStopping) return; @@ -207,6 +210,19 @@ public class OnlineAccountsManager { } } + private boolean importQueueContainsExactMatch(OnlineAccountData acc) { + // Check if an item exists where all properties match exactly + // This is needed because signature and nonce are not compared in OnlineAccountData.equals() + synchronized (onlineAccountsImportQueue) { + return onlineAccountsImportQueue.stream().anyMatch(otherAcc -> + acc.getTimestamp() == otherAcc.getTimestamp() && + Arrays.equals(acc.getPublicKey(), otherAcc.getPublicKey()) && + acc.getNonce() == otherAcc.getNonce() && + Arrays.equals(acc.getSignature(), otherAcc.getSignature()) + ); + } + } + /** * Check if supplied onlineAccountData is superior (i.e. has a nonce value) than existing record. * Two entries are considered equal even if the nonce differs, to prevent multiple variations @@ -809,6 +825,10 @@ public class OnlineAccountsManager { // We have already validated this online account continue; + if (this.importQueueContainsExactMatch(onlineAccountData)) + // Identical online account data already present in queue + continue; + boolean isNewEntry = onlineAccountsImportQueue.add(onlineAccountData); if (isNewEntry)