retrieve min fee rate, adjust block target rates and dont create txes with insufficient fee rate

This commit is contained in:
Craig Raw 2020-09-25 15:22:52 +02:00
parent e878c4ea78
commit e48e40da0d
8 changed files with 58 additions and 6 deletions

2
drongo

@ -1 +1 @@
Subproject commit 2650dafa66623c1205582c555369a5118a343ccf Subproject commit 79eb8b002d01be5195bb7fc7eba6bb34bf3366e3

View file

@ -137,6 +137,8 @@ public class AppController implements Initializable {
private static Map<Integer, Double> targetBlockFeeRates; private static Map<Integer, Double> targetBlockFeeRates;
private static Double minimumRelayFeeRate;
private static CurrencyRate fiatCurrencyExchangeRate; private static CurrencyRate fiatCurrencyExchangeRate;
private static List<Device> devices; private static List<Device> devices;
@ -643,6 +645,10 @@ public class AppController implements Initializable {
return targetBlockFeeRates; return targetBlockFeeRates;
} }
public static Double getMinimumRelayFeeRate() {
return minimumRelayFeeRate;
}
public static CurrencyRate getFiatCurrencyExchangeRate() { public static CurrencyRate getFiatCurrencyExchangeRate() {
return fiatCurrencyExchangeRate; return fiatCurrencyExchangeRate;
} }
@ -1305,6 +1311,7 @@ public class AppController implements Initializable {
public void newConnection(ConnectionEvent event) { public void newConnection(ConnectionEvent event) {
currentBlockHeight = event.getBlockHeight(); currentBlockHeight = event.getBlockHeight();
targetBlockFeeRates = event.getTargetBlockFeeRates(); targetBlockFeeRates = event.getTargetBlockFeeRates();
minimumRelayFeeRate = event.getMinimumRelayFeeRate();
String banner = event.getServerBanner(); String banner = event.getServerBanner();
String status = "Connected to " + Config.get().getElectrumServer() + " at height " + event.getBlockHeight(); String status = "Connected to " + Config.get().getElectrumServer() + " at height " + event.getBlockHeight();
EventManager.get().post(new StatusEvent(status)); EventManager.get().post(new StatusEvent(status));

View file

@ -10,13 +10,15 @@ public class ConnectionEvent extends FeeRatesUpdatedEvent {
private final String serverBanner; private final String serverBanner;
private final int blockHeight; private final int blockHeight;
private final BlockHeader blockHeader; private final BlockHeader blockHeader;
private final Double minimumRelayFeeRate;
public ConnectionEvent(List<String> serverVersion, String serverBanner, int blockHeight, BlockHeader blockHeader, Map<Integer, Double> targetBlockFeeRates) { public ConnectionEvent(List<String> serverVersion, String serverBanner, int blockHeight, BlockHeader blockHeader, Map<Integer, Double> targetBlockFeeRates, Double minimumRelayFeeRate) {
super(targetBlockFeeRates); super(targetBlockFeeRates);
this.serverVersion = serverVersion; this.serverVersion = serverVersion;
this.serverBanner = serverBanner; this.serverBanner = serverBanner;
this.blockHeight = blockHeight; this.blockHeight = blockHeight;
this.blockHeader = blockHeader; this.blockHeader = blockHeader;
this.minimumRelayFeeRate = minimumRelayFeeRate;
} }
public List<String> getServerVersion() { public List<String> getServerVersion() {
@ -34,4 +36,8 @@ public class ConnectionEvent extends FeeRatesUpdatedEvent {
public BlockHeader getBlockHeader() { public BlockHeader getBlockHeader() {
return blockHeader; return blockHeader;
} }
public Double getMinimumRelayFeeRate() {
return minimumRelayFeeRate;
}
} }

View file

@ -205,6 +205,16 @@ public class BatchedElectrumServerRpc implements ElectrumServerRpc {
} }
} }
@Override
public Double getMinimumRelayFee(Transport transport) {
try {
JsonRpcClient client = new JsonRpcClient(transport);
return client.createRequest().returnAs(Double.class).method("blockchain.relayfee").id(1).execute();
} catch(JsonRpcException e) {
throw new ElectrumServerRpcException("Error getting minimum relay fee", e);
}
}
@Override @Override
public String broadcastTransaction(Transport transport, String txHex) { public String broadcastTransaction(Transport transport, String txHex) {
try { try {

View file

@ -528,7 +528,7 @@ public class ElectrumServer {
Map<Integer, Double> targetBlocksFeeRatesSats = new TreeMap<>(); Map<Integer, Double> targetBlocksFeeRatesSats = new TreeMap<>();
for(Integer target : targetBlocksFeeRatesBtcKb.keySet()) { for(Integer target : targetBlocksFeeRatesBtcKb.keySet()) {
targetBlocksFeeRatesSats.put(target, targetBlocksFeeRatesBtcKb.get(target) * Transaction.SATOSHIS_PER_BITCOIN / 1024); targetBlocksFeeRatesSats.put(target, targetBlocksFeeRatesBtcKb.get(target) * Transaction.SATOSHIS_PER_BITCOIN / 1000);
} }
return targetBlocksFeeRatesSats; return targetBlocksFeeRatesSats;
@ -537,6 +537,16 @@ public class ElectrumServer {
} }
} }
public Double getMinimumRelayFee() throws ServerException {
Double minFeeRateBtcKb = electrumServerRpc.getMinimumRelayFee(getTransport());
if(minFeeRateBtcKb != null) {
long minFeeRateSatsKb = (long)(minFeeRateBtcKb * Transaction.SATOSHIS_PER_BITCOIN);
return minFeeRateSatsKb / 1000d;
}
return Transaction.DEFAULT_MIN_RELAY_FEE;
}
public Sha256Hash broadcastTransaction(Transaction transaction) throws ServerException { public Sha256Hash broadcastTransaction(Transaction transaction) throws ServerException {
byte[] rawtxBytes = transaction.bitcoinSerialize(); byte[] rawtxBytes = transaction.bitcoinSerialize();
String rawtxHex = Utils.bytesToHex(rawtxBytes); String rawtxHex = Utils.bytesToHex(rawtxBytes);
@ -667,7 +677,12 @@ public class ElectrumServer {
Map<Integer, Double> blockTargetFeeRates = electrumServer.getFeeEstimates(SendController.TARGET_BLOCKS_RANGE); Map<Integer, Double> blockTargetFeeRates = electrumServer.getFeeEstimates(SendController.TARGET_BLOCKS_RANGE);
feeRatesRetrievedAt = System.currentTimeMillis(); feeRatesRetrievedAt = System.currentTimeMillis();
return new ConnectionEvent(serverVersion, banner, tip.height, tip.getBlockHeader(), blockTargetFeeRates); Double minimumRelayFeeRate = electrumServer.getMinimumRelayFee();
for(Integer blockTarget : blockTargetFeeRates.keySet()) {
blockTargetFeeRates.computeIfPresent(blockTarget, (blocks, feeRate) -> feeRate < minimumRelayFeeRate ? minimumRelayFeeRate : feeRate);
}
return new ConnectionEvent(serverVersion, banner, tip.height, tip.getBlockHeader(), blockTargetFeeRates, minimumRelayFeeRate);
} else { } else {
if(reader.isAlive()) { if(reader.isAlive()) {
electrumServer.ping(); electrumServer.ping();

View file

@ -29,5 +29,7 @@ public interface ElectrumServerRpc {
Map<Integer, Double> getFeeEstimates(Transport transport, List<Integer> targetBlocks); Map<Integer, Double> getFeeEstimates(Transport transport, List<Integer> targetBlocks);
Double getMinimumRelayFee(Transport transport);
String broadcastTransaction(Transport transport, String txHex); String broadcastTransaction(Transport transport, String txHex);
} }

View file

@ -229,6 +229,16 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
return result; return result;
} }
@Override
public Double getMinimumRelayFee(Transport transport) {
try {
JsonRpcClient client = new JsonRpcClient(transport);
return client.createRequest().returnAs(Double.class).method("blockchain.relayfee").id(1).execute();
} catch(JsonRpcException e) {
throw new ElectrumServerRpcException("Error getting minimum relay fee", e);
}
}
@Override @Override
public String broadcastTransaction(Transport transport, String txHex) { public String broadcastTransaction(Transport transport, String txHex) {
try { try {

View file

@ -306,7 +306,9 @@ public class SendController extends WalletFormController implements Initializabl
)); ));
validationSupport.registerValidator(fee, Validator.combine( validationSupport.registerValidator(fee, Validator.combine(
(Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Insufficient Inputs", userFeeSet.get() && insufficientInputsProperty.get()), (Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Insufficient Inputs", userFeeSet.get() && insufficientInputsProperty.get()),
(Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Insufficient Fee", getFeeValueSats() != null && getFeeValueSats() == 0) (Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Insufficient Fee", getFeeValueSats() != null && getFeeValueSats() == 0),
(Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Insufficient Fee Rate", walletTransactionProperty.get() != null &&
(double)walletTransactionProperty.get().getFee() / walletTransactionProperty.get().getTransaction().getVirtualSize() < AppController.getMinimumRelayFeeRate())
)); ));
validationSupport.setValidationDecorator(new StyleClassValidationDecoration()); validationSupport.setValidationDecorator(new StyleClassValidationDecoration());
@ -445,7 +447,7 @@ public class SendController extends WalletFormController implements Initializabl
LinkedHashMap::new)); LinkedHashMap::new));
} }
return retrievedFeeRates; return retrievedFeeRates;
} }
private Double getFeeRate() { private Double getFeeRate() {