diff --git a/src/main/java/com/sparrowwallet/sparrow/event/WalletNodeHistoryChangedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/WalletNodeHistoryChangedEvent.java index 483a9d14..5697c57f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/WalletNodeHistoryChangedEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/WalletNodeHistoryChangedEvent.java @@ -14,9 +14,16 @@ import java.util.List; */ public class WalletNodeHistoryChangedEvent { private final String scriptHash; + private final String status; public WalletNodeHistoryChangedEvent(String scriptHash) { this.scriptHash = scriptHash; + this.status = null; + } + + public WalletNodeHistoryChangedEvent(String scriptHash, String status) { + this.scriptHash = scriptHash; + this.status = status; } public WalletNode getWalletNode(Wallet wallet) { @@ -70,4 +77,8 @@ public class WalletNodeHistoryChangedEvent { public String getScriptHash() { return scriptHash; } + + public String getStatus() { + return status; + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java index 0c1c3f5f..033fece2 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java @@ -76,6 +76,10 @@ public class ElectrumServer { private static final Set sameHeightTxioScriptHashes = ConcurrentHashMap.newKeySet(); + private final static Set subscribedRecent = ConcurrentHashMap.newKeySet(); + + private final static Map broadcastRecent = new ConcurrentHashMap<>(); + private static ElectrumServerRpc electrumServerRpc = new SimpleElectrumServerRpc(); private static Cormorant cormorant; @@ -1062,9 +1066,10 @@ public class ElectrumServer { List recentTransactions = feeRatesSource.getRecentMempoolTransactions(); Map setReferences = new HashMap<>(); setReferences.put(recentTransactions.getFirst(), null); - Random random = new Random(); - if(random.nextBoolean()) { - setReferences.put(recentTransactions.get(random.nextInt(recentTransactions.size())), null); + if(recentTransactions.size() > 1) { + Random random = new Random(); + int halfSize = recentTransactions.size() / 2; + setReferences.put(recentTransactions.get(halfSize == 1 ? 1 : random.nextInt(halfSize) + 1), null); } Map transactions = getTransactions(null, setReferences, Collections.emptyMap()); return transactions.values().stream().filter(blxTx -> blxTx.getTransaction() != null).toList(); @@ -1602,6 +1607,31 @@ public class ElectrumServer { Set mempoolRateSizes = electrumServer.getMempoolRateSizes(); EventManager.get().post(new MempoolRateSizesUpdatedEvent(mempoolRateSizes)); } + + @Subscribe + public void walletNodeHistoryChanged(WalletNodeHistoryChangedEvent event) { + String status = broadcastRecent.remove(event.getScriptHash()); + if(status != null && status.equals(event.getStatus())) { + Map subscribeScriptHashes = new HashMap<>(); + Random random = new Random(); + int subscriptions = random.nextInt(2) + 1; + for(int i = 0; i < subscriptions; i++) { + byte[] randomScriptHashBytes = new byte[32]; + random.nextBytes(randomScriptHashBytes); + String randomScriptHash = Utils.bytesToHex(randomScriptHashBytes); + if(!subscribedScriptHashes.containsKey(randomScriptHash)) { + subscribeScriptHashes.put("m/" + subscribeScriptHashes.size(), randomScriptHash); + } + } + + try { + electrumServerRpc.subscribeScriptHashes(transport, null, subscribeScriptHashes); + subscribedRecent.addAll(subscribeScriptHashes.values()); + } catch(ElectrumServerRpcException e) { + log.debug("Error subscribing to recent mempool transaction outputs", e); + } + } + } } public static class ReadRunnable implements Runnable { @@ -2018,13 +2048,12 @@ public class ElectrumServer { return Network.get() != Network.MAINNET && totalBlocks > 2; } - private final static Set subscribedRecent = Collections.newSetFromMap(new ConcurrentHashMap<>()); - private void subscribeRecent(ElectrumServer electrumServer) { Set unsubscribeScriptHashes = new HashSet<>(subscribedRecent); unsubscribeScriptHashes.removeIf(subscribedScriptHashes::containsKey); electrumServerRpc.unsubscribeScriptHashes(transport, unsubscribeScriptHashes); subscribedRecent.removeAll(unsubscribeScriptHashes); + broadcastRecent.clear(); Map subscribeScriptHashes = new HashMap<>(); List recentTransactions = electrumServer.getRecentMempoolTransactions(); @@ -2033,7 +2062,7 @@ public class ElectrumServer { TransactionOutput txOutput = blkTx.getTransaction().getOutputs().get(i); String scriptHash = getScriptHash(txOutput); if(!subscribedScriptHashes.containsKey(scriptHash)) { - subscribeScriptHashes.put("m/" + i, getScriptHash(txOutput)); + subscribeScriptHashes.put("m/" + subscribeScriptHashes.size(), scriptHash); } if(Math.random() < 0.1d) { break; @@ -2042,6 +2071,17 @@ public class ElectrumServer { } if(!subscribeScriptHashes.isEmpty()) { + Random random = new Random(); + int additionalRandomScriptHashes = random.nextInt(8) + 4; + for(int i = 0; i < additionalRandomScriptHashes; i++) { + byte[] randomScriptHashBytes = new byte[32]; + random.nextBytes(randomScriptHashBytes); + String randomScriptHash = Utils.bytesToHex(randomScriptHashBytes); + if(!subscribedScriptHashes.containsKey(randomScriptHash)) { + subscribeScriptHashes.put("m/" + subscribeScriptHashes.size(), randomScriptHash); + } + } + try { electrumServerRpc.subscribeScriptHashes(transport, null, subscribeScriptHashes); subscribedRecent.addAll(subscribeScriptHashes.values()); @@ -2066,6 +2106,9 @@ public class ElectrumServer { Random random = new Random(); if(random.nextBoolean()) { BlockTransaction blkTx = recentTransactions.get(random.nextInt(recentTransactions.size())); + String scriptHash = getScriptHash(blkTx.getTransaction().getOutputs().getFirst()); + String status = getScriptHashStatus(List.of(new ScriptHashTx(0, blkTx.getHashAsString(), blkTx.getFee()))); + broadcastRecent.put(scriptHash, status); electrumServer.broadcastTransaction(blkTx.getTransaction()); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/net/SubscriptionService.java b/src/main/java/com/sparrowwallet/sparrow/net/SubscriptionService.java index 1410a0a0..b7b16a33 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/SubscriptionService.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/SubscriptionService.java @@ -38,6 +38,6 @@ public class SubscriptionService { existingStatuses.add(status); } - Platform.runLater(() -> EventManager.get().post(new WalletNodeHistoryChangedEvent(scriptHash))); + Platform.runLater(() -> EventManager.get().post(new WalletNodeHistoryChangedEvent(scriptHash, status))); } }