diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index afc149fd..ed415ad5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -143,6 +143,8 @@ public class AppController implements Initializable { private static Map targetBlockFeeRates; + private static Map feeRateHistogram; + private static Double minimumRelayFeeRate; private static CurrencyRate fiatCurrencyExchangeRate; @@ -650,6 +652,10 @@ public class AppController implements Initializable { return targetBlockFeeRates; } + public static Map getFeeRateHistogram() { + return feeRateHistogram; + } + public static Double getMinimumRelayFeeRate() { return minimumRelayFeeRate == null ? Transaction.DEFAULT_MIN_RELAY_FEE : minimumRelayFeeRate; } @@ -1429,6 +1435,7 @@ public class AppController implements Initializable { public void newConnection(ConnectionEvent event) { currentBlockHeight = event.getBlockHeight(); targetBlockFeeRates = event.getTargetBlockFeeRates(); + feeRateHistogram = event.getFeeRateHistogram(); minimumRelayFeeRate = event.getMinimumRelayFeeRate(); String banner = event.getServerBanner(); String status = "Connected to " + Config.get().getElectrumServer() + " at height " + event.getBlockHeight(); @@ -1453,6 +1460,7 @@ public class AppController implements Initializable { @Subscribe public void feesUpdated(FeeRatesUpdatedEvent event) { targetBlockFeeRates = event.getTargetBlockFeeRates(); + feeRateHistogram = event.getFeeRateHistogram(); } @Subscribe diff --git a/src/main/java/com/sparrowwallet/sparrow/event/ConnectionEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/ConnectionEvent.java index 4deaed37..67552634 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/ConnectionEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/ConnectionEvent.java @@ -12,8 +12,8 @@ public class ConnectionEvent extends FeeRatesUpdatedEvent { private final BlockHeader blockHeader; private final Double minimumRelayFeeRate; - public ConnectionEvent(List serverVersion, String serverBanner, int blockHeight, BlockHeader blockHeader, Map targetBlockFeeRates, Double minimumRelayFeeRate) { - super(targetBlockFeeRates); + public ConnectionEvent(List serverVersion, String serverBanner, int blockHeight, BlockHeader blockHeader, Map targetBlockFeeRates, Map feeRateHistogram, Double minimumRelayFeeRate) { + super(targetBlockFeeRates, feeRateHistogram); this.serverVersion = serverVersion; this.serverBanner = serverBanner; this.blockHeight = blockHeight; diff --git a/src/main/java/com/sparrowwallet/sparrow/event/FeeRatesUpdatedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/FeeRatesUpdatedEvent.java index 03f3b902..ce5aed83 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/FeeRatesUpdatedEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/FeeRatesUpdatedEvent.java @@ -4,12 +4,18 @@ import java.util.Map; public class FeeRatesUpdatedEvent { private final Map targetBlockFeeRates; + private final Map feeRateHistogram; - public FeeRatesUpdatedEvent(Map targetBlockFeeRates) { + public FeeRatesUpdatedEvent(Map targetBlockFeeRates, Map feeRateHistogram) { this.targetBlockFeeRates = targetBlockFeeRates; + this.feeRateHistogram = feeRateHistogram; } public Map getTargetBlockFeeRates() { return targetBlockFeeRates; } + + public Map getFeeRateHistogram() { + return feeRateHistogram; + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/net/BatchedElectrumServerRpc.java b/src/main/java/com/sparrowwallet/sparrow/net/BatchedElectrumServerRpc.java index 65005697..ad00fe7b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/BatchedElectrumServerRpc.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/BatchedElectrumServerRpc.java @@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.concurrent.atomic.AtomicLong; public class BatchedElectrumServerRpc implements ElectrumServerRpc { @@ -229,6 +230,24 @@ public class BatchedElectrumServerRpc implements ElectrumServerRpc { } } + @Override + public Map getFeeRateHistogram(Transport transport) { + try { + JsonRpcClient client = new JsonRpcClient(transport); + Long[][] feesArray = new RetryLogic(MAX_RETRIES, RETRY_DELAY, IllegalStateException.class).getResult(() -> + client.createRequest().returnAs(Long[][].class).method("mempool.get_fee_histogram").id(idCounter.incrementAndGet()).execute()); + + Map feeRateHistogram = new TreeMap<>(); + for(Long[] feePair : feesArray) { + feeRateHistogram.put(feePair[0], feePair[1]); + } + + return feeRateHistogram; + } catch(Exception e) { + throw new ElectrumServerRpcException("Error getting fee rate histogram", e); + } + } + @Override public Double getMinimumRelayFee(Transport transport) { try { diff --git a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java index 8471307b..312b5cf7 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java @@ -610,6 +610,10 @@ public class ElectrumServer { } } + public Map getFeeRateHistogram() throws ServerException { + return electrumServerRpc.getFeeRateHistogram(getTransport()); + } + public Double getMinimumRelayFee() throws ServerException { Double minFeeRateBtcKb = electrumServerRpc.getMinimumRelayFee(getTransport()); if(minFeeRateBtcKb != null) { @@ -760,6 +764,7 @@ public class ElectrumServer { String banner = electrumServer.getServerBanner(); Map blockTargetFeeRates = electrumServer.getFeeEstimates(SendController.TARGET_BLOCKS_RANGE); + Map feeRateHistogram = electrumServer.getFeeRateHistogram(); feeRatesRetrievedAt = System.currentTimeMillis(); Double minimumRelayFeeRate = electrumServer.getMinimumRelayFee(); @@ -767,7 +772,7 @@ public class ElectrumServer { blockTargetFeeRates.computeIfPresent(blockTarget, (blocks, feeRate) -> feeRate < minimumRelayFeeRate ? minimumRelayFeeRate : feeRate); } - return new ConnectionEvent(serverVersion, banner, tip.height, tip.getBlockHeader(), blockTargetFeeRates, minimumRelayFeeRate); + return new ConnectionEvent(serverVersion, banner, tip.height, tip.getBlockHeader(), blockTargetFeeRates, feeRateHistogram, minimumRelayFeeRate); } else { if(reader.isAlive()) { electrumServer.ping(); @@ -775,8 +780,9 @@ public class ElectrumServer { long elapsed = System.currentTimeMillis() - feeRatesRetrievedAt; if(elapsed > FEE_RATES_PERIOD) { Map blockTargetFeeRates = electrumServer.getFeeEstimates(SendController.TARGET_BLOCKS_RANGE); + Map feeRateHistogram = electrumServer.getFeeRateHistogram(); feeRatesRetrievedAt = System.currentTimeMillis(); - return new FeeRatesUpdatedEvent(blockTargetFeeRates); + return new FeeRatesUpdatedEvent(blockTargetFeeRates, feeRateHistogram); } } else { resetConnection(); diff --git a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServerRpc.java b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServerRpc.java index 09255cbc..7ed5fa85 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServerRpc.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServerRpc.java @@ -30,6 +30,8 @@ public interface ElectrumServerRpc { Map getFeeEstimates(Transport transport, List targetBlocks); + Map getFeeRateHistogram(Transport transport); + Double getMinimumRelayFee(Transport transport); String broadcastTransaction(Transport transport, String txHex); diff --git a/src/main/java/com/sparrowwallet/sparrow/net/SimpleElectrumServerRpc.java b/src/main/java/com/sparrowwallet/sparrow/net/SimpleElectrumServerRpc.java index c0eef1d0..dd1321d4 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/SimpleElectrumServerRpc.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/SimpleElectrumServerRpc.java @@ -246,6 +246,24 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc { return result; } + @Override + public Map getFeeRateHistogram(Transport transport) { + try { + JsonRpcClient client = new JsonRpcClient(transport); + Long[][] feesArray = new RetryLogic(MAX_RETRIES, RETRY_DELAY, IllegalStateException.class).getResult(() -> + client.createRequest().returnAs(Long[][].class).method("mempool.get_fee_histogram").id(idCounter.incrementAndGet()).execute()); + + Map feeRateHistogram = new TreeMap<>(); + for(Long[] feePair : feesArray) { + feeRateHistogram.put(feePair[0], feePair[1]); + } + + return feeRateHistogram; + } catch(Exception e) { + throw new ElectrumServerRpcException("Error getting fee rate histogram", e); + } + } + @Override public Double getMinimumRelayFee(Transport transport) { try {