From c1cf5be616b32a922cb1f665ee4093c6561575e0 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Fri, 21 May 2021 11:48:13 +0200 Subject: [PATCH] add mempool.bisq.services as a broadcaster, broadcast tx twice if possible on mainnet, handle different network broadcaster network capabilities --- .../sparrow/net/BroadcastSource.java | 39 +++++++++++++++++++ .../sparrow/net/ElectrumServer.java | 16 ++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/sparrowwallet/sparrow/net/BroadcastSource.java b/src/main/java/com/sparrowwallet/sparrow/net/BroadcastSource.java index 6d1c9d3d..0c6a9c8f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/BroadcastSource.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/BroadcastSource.java @@ -15,6 +15,7 @@ import java.net.Proxy; import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; +import java.util.List; public enum BroadcastSource { BLOCKSTREAM_INFO("blockstream.info", "https://blockstream.info", "http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion") { @@ -24,6 +25,11 @@ public enum BroadcastSource { return postTransactionData(data); } + @Override + public List getSupportedNetworks() { + return List.of(Network.MAINNET, Network.TESTNET); + } + protected URL getURL(Proxy proxy) throws MalformedURLException { if(Network.get() == Network.MAINNET) { return new URL(getBaseUrl(proxy) + "/api/tx"); @@ -40,6 +46,11 @@ public enum BroadcastSource { return postTransactionData(data); } + @Override + public List getSupportedNetworks() { + return List.of(Network.MAINNET, Network.TESTNET, Network.SIGNET); + } + protected URL getURL(Proxy proxy) throws MalformedURLException { if(Network.get() == Network.MAINNET) { return new URL(getBaseUrl(proxy) + "/api/tx"); @@ -56,6 +67,32 @@ public enum BroadcastSource { return postTransactionData(data); } + @Override + public List getSupportedNetworks() { + return List.of(Network.MAINNET); + } + + protected URL getURL(Proxy proxy) throws MalformedURLException { + if(Network.get() == Network.MAINNET) { + return new URL(getBaseUrl(proxy) + "/api/tx"); + } else if(Network.get() == Network.TESTNET) { + return new URL(getBaseUrl(proxy) + "/testnet/api/tx"); + } else { + throw new IllegalStateException("Cannot broadcast transaction to " + getName() + " on network " + Network.get()); + } + } + }, + MEMPOOL_BISQ_SERVICES("mempool.bisq.services", "https://mempool.bisq.services", "http://mempoolcutehjtynu4k4rd746acmssvj2vz4jbz4setb72clbpx2dfqd.onion") { + public Sha256Hash broadcastTransaction(Transaction transaction) throws BroadcastException { + String data = Utils.bytesToHex(transaction.bitcoinSerialize()); + return postTransactionData(data); + } + + @Override + public List getSupportedNetworks() { + return List.of(Network.MAINNET); + } + protected URL getURL(Proxy proxy) throws MalformedURLException { if(Network.get() == Network.MAINNET) { return new URL(getBaseUrl(proxy) + "/api/tx"); @@ -98,6 +135,8 @@ public enum BroadcastSource { public abstract Sha256Hash broadcastTransaction(Transaction transaction) throws BroadcastException; + public abstract List getSupportedNetworks(); + protected abstract URL getURL(Proxy proxy) throws MalformedURLException; public Sha256Hash postTransactionData(String data) throws BroadcastException { diff --git a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java index 9f3a9527..892875a1 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java @@ -37,6 +37,8 @@ public class ElectrumServer { private static final String[] SUPPORTED_VERSIONS = new String[]{"1.3", "1.4.2"}; + private static final int MINIMUM_BROADCASTS = 2; + public static final BlockTransaction UNFETCHABLE_BLOCK_TRANSACTION = new BlockTransaction(Sha256Hash.ZERO_HASH, 0, null, null, null); private static Transport transport; @@ -1295,15 +1297,23 @@ public class ElectrumServer { protected Sha256Hash call() throws ServerException { //If Tor proxy is configured, try all external broadcast sources in random order before falling back to connected Electrum server if(AppServices.getProxy() != null) { - List broadcastSources = new ArrayList<>(Arrays.asList(BroadcastSource.values())); - while(!broadcastSources.isEmpty()) { + List broadcastSources = Arrays.stream(BroadcastSource.values()).filter(src -> src.getSupportedNetworks().contains(Network.get())).collect(Collectors.toList()); + Sha256Hash txid = null; + for(int i = 1; !broadcastSources.isEmpty(); i++) { try { BroadcastSource broadcastSource = broadcastSources.remove(new Random().nextInt(broadcastSources.size())); - return broadcastSource.broadcastTransaction(transaction); + txid = broadcastSource.broadcastTransaction(transaction); + if(Network.get() != Network.MAINNET || i >= MINIMUM_BROADCASTS || broadcastSources.isEmpty()) { + return txid; + } } catch(BroadcastSource.BroadcastException e) { //ignore, already logged } } + + if(txid != null) { + return txid; + } } ElectrumServer electrumServer = new ElectrumServer();