Switch to more accurate fee estimation endpoint

The API endpoint for fee estimations has been changed to one that delivers more accurate fee estimations.

This is a temporary solution, until a more decentralized approach is found.

Fixes projects/issues/27
This commit is contained in:
cd2357 2020-05-05 17:00:08 +02:00
parent bb2484ab3e
commit e18f0406af
No known key found for this signature in database
GPG Key ID: F26C56748514D0D3
3 changed files with 56 additions and 12 deletions

View File

@ -83,7 +83,7 @@ public class AboutView extends ActivatableView<GridPane, Void> {
"Poloniex (https://poloniex.com)", "Poloniex (https://poloniex.com)",
"Coinmarketcap (https://coinmarketcap.com)")); "Coinmarketcap (https://coinmarketcap.com)"));
if (isBtc) if (isBtc)
addCompactTopLabelTextField(root, ++gridRow, Res.get("setting.about.feeEstimation.label"), "Earn.com (https://bitcoinfees.earn.com)"); addCompactTopLabelTextField(root, ++gridRow, Res.get("setting.about.feeEstimation.label"), "mempool.space (https://mempool.space)");
addTitledGroupBg(root, ++gridRow, 2, Res.get("setting.about.versionDetails"), Layout.GROUP_DISTANCE); addTitledGroupBg(root, ++gridRow, 2, Res.get("setting.about.versionDetails"), Layout.GROUP_DISTANCE);
addCompactTopLabelTextField(root, gridRow, Res.get("setting.about.version"), Version.VERSION, Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE); addCompactTopLabelTextField(root, gridRow, Res.get("setting.about.version"), Version.VERSION, Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);

View File

@ -42,8 +42,8 @@ import java.util.stream.Stream;
@Component @Component
class BitcoinFeeRateProvider extends FeeRateProvider { class BitcoinFeeRateProvider extends FeeRateProvider {
private static final long MIN_FEE_RATE = 10; // satoshi/byte protected static final long MIN_FEE_RATE = 10; // satoshi/byte
private static final long MAX_FEE_RATE = 1000; protected static final long MAX_FEE_RATE = 1000;
private static final int DEFAULT_MAX_BLOCKS = 2; private static final int DEFAULT_MAX_BLOCKS = 2;
private static final int DEFAULT_REFRESH_INTERVAL = 2; private static final int DEFAULT_REFRESH_INTERVAL = 2;
@ -63,9 +63,9 @@ class BitcoinFeeRateProvider extends FeeRateProvider {
private long getEstimatedFeeRate() { private long getEstimatedFeeRate() {
return getFeeRatePredictions() return getFeeRatePredictions()
.filter(p -> p.get("maxDelay") <= maxBlocks) .filter(p -> p.getKey().equalsIgnoreCase("halfHourFee"))
.map(Map.Entry::getValue)
.findFirst() .findFirst()
.map(p -> p.get("maxFee"))
.map(r -> { .map(r -> {
log.info("latest fee rate prediction is {} sat/byte", r); log.info("latest fee rate prediction is {} sat/byte", r);
return r; return r;
@ -75,19 +75,18 @@ class BitcoinFeeRateProvider extends FeeRateProvider {
.orElse(MIN_FEE_RATE); .orElse(MIN_FEE_RATE);
} }
private Stream<Map<String, Long>> getFeeRatePredictions() { private Stream<Map.Entry<String, Long>> getFeeRatePredictions() {
return restTemplate.exchange( return restTemplate.exchange(
RequestEntity RequestEntity
.get(UriComponentsBuilder .get(UriComponentsBuilder
// now using /fees/list because /fees/recommended estimates were too high // Temporarily call mempool.space centralized API endpoint
.fromUriString("https://bitcoinfees.earn.com/api/v1/fees/list") // A more de-centralized solution discussed in https://github.com/bisq-network/projects/issues/27
.fromUriString("https://mempool.space/api/v1/fees/recommended")
.build().toUri()) .build().toUri())
.header("User-Agent", "") // required to avoid 403 .header("User-Agent", "") // required to avoid 403
.build(), .build(),
new ParameterizedTypeReference<Map<String, List<Map<String, Long>>>>() { new ParameterizedTypeReference<Map<String, Long>>() { }
} ).getBody().entrySet().stream();
).getBody().entrySet().stream()
.flatMap(e -> e.getValue().stream());
} }
private static Optional<String[]> args(Environment env) { private static Optional<String[]> args(Environment env) {

View File

@ -0,0 +1,45 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.price.mining.providers;
import bisq.price.mining.FeeRate;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class BitcoinFeeRateProviderTest {
@Test
public void doGet_successfulCall() {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
BitcoinFeeRateProvider feeRateProvider = new BitcoinFeeRateProvider(ctx.getEnvironment());
// Make a call to the API, retrieve the recommended fee rate
// If the API call fails, or the response body cannot be parsed, the test will fail with an exception
FeeRate retrievedFeeRate = feeRateProvider.doGet();
// Check that the FeeRateProvider returns a fee within the defined parameters
assertTrue(retrievedFeeRate.getPrice() >= BitcoinFeeRateProvider.MIN_FEE_RATE);
assertTrue(retrievedFeeRate.getPrice() <= BitcoinFeeRateProvider.MAX_FEE_RATE);
}
}