mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 06:55:08 +01:00
Use ListenableFuture and callback when requesting tx fee
This change fixes the blocking problem in the fee rate request api. Also redefined the TxFeeRateInfo. - Redefined grpc.proto message TxFeeRateInfo, added lastFeeServiceRequestTs field. (CLI user may want to know TS of last fee request.) - Adjusted TxFeeRateInfo proto wrapper. - Adjusted CurrencyFormat and BtcTxFeeRateTest to new TxFeeRateInfo. - Added @Getter annotation to FeeService. (CLI user may want to know TS of last fee request). - Pass resultHandler from GrpcWalletsService through CoreApi, to CoreWalletsService's tx fee rate api methods.
This commit is contained in:
parent
faf030fbc5
commit
987d89319e
8 changed files with 107 additions and 61 deletions
|
@ -45,7 +45,7 @@ public class BtcTxFeeRateTest extends MethodTest {
|
|||
log.debug("{} -> Fee rate with no preference: {}", testName(testInfo), txFeeRateInfo);
|
||||
|
||||
assertFalse(txFeeRateInfo.isUseCustomTxFeeRate());
|
||||
assertTrue(txFeeRateInfo.getStdTxFeeRate() > 0);
|
||||
assertTrue(txFeeRateInfo.getFeeServiceRate() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -56,7 +56,7 @@ public class BtcTxFeeRateTest extends MethodTest {
|
|||
|
||||
assertTrue(txFeeRateInfo.isUseCustomTxFeeRate());
|
||||
assertEquals(10, txFeeRateInfo.getCustomTxFeeRate());
|
||||
assertTrue(txFeeRateInfo.getStdTxFeeRate() > 0);
|
||||
assertTrue(txFeeRateInfo.getFeeServiceRate() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -66,7 +66,7 @@ public class BtcTxFeeRateTest extends MethodTest {
|
|||
log.debug("{} -> Fee rate with no preference: {}", testName(testInfo), txFeeRateInfo);
|
||||
|
||||
assertFalse(txFeeRateInfo.isUseCustomTxFeeRate());
|
||||
assertTrue(txFeeRateInfo.getStdTxFeeRate() > 0);
|
||||
assertTrue(txFeeRateInfo.getFeeServiceRate() > 0);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
|
|
@ -57,10 +57,10 @@ public class CurrencyFormat {
|
|||
if (txFeeRateInfo.getUseCustomTxFeeRate())
|
||||
return format("custom tx fee rate: %s sats/byte, network rate: %s sats/byte",
|
||||
formatFeeSatoshis(txFeeRateInfo.getCustomTxFeeRate()),
|
||||
formatFeeSatoshis(txFeeRateInfo.getStdTxFeeRate()));
|
||||
formatFeeSatoshis(txFeeRateInfo.getFeeServiceRate()));
|
||||
else
|
||||
return format("tx fee rate: %s sats/byte",
|
||||
formatFeeSatoshis(txFeeRateInfo.getStdTxFeeRate()));
|
||||
formatFeeSatoshis(txFeeRateInfo.getFeeServiceRate()));
|
||||
}
|
||||
|
||||
static String formatAmountRange(long minAmount, long amount) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import bisq.core.trade.statistics.TradeStatistics3;
|
|||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
|
@ -247,16 +248,21 @@ public class CoreApi {
|
|||
walletsService.sendBsq(address, amount, callback);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo getTxFeeRate() {
|
||||
return walletsService.getTxFeeRate();
|
||||
public void getTxFeeRate(ResultHandler resultHandler) {
|
||||
walletsService.getTxFeeRate(resultHandler);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo setTxFeeRatePreference(long txFeeRate) {
|
||||
return walletsService.setTxFeeRatePreference(txFeeRate);
|
||||
public void setTxFeeRatePreference(long txFeeRate,
|
||||
ResultHandler resultHandler) {
|
||||
walletsService.setTxFeeRatePreference(txFeeRate, resultHandler);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo unsetTxFeeRatePreference() {
|
||||
return walletsService.unsetTxFeeRatePreference();
|
||||
public void unsetTxFeeRatePreference(ResultHandler resultHandler) {
|
||||
walletsService.unsetTxFeeRatePreference(resultHandler);
|
||||
}
|
||||
|
||||
public TxFeeRateInfo getMostRecentTxFeeRateInfo() {
|
||||
return walletsService.getMostRecentTxFeeRateInfo();
|
||||
}
|
||||
|
||||
public void setWalletPassword(String password, String newPassword) {
|
||||
|
|
|
@ -39,6 +39,8 @@ import bisq.core.util.coin.BsqFormatter;
|
|||
|
||||
import bisq.common.Timer;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
@ -52,13 +54,16 @@ import javax.inject.Inject;
|
|||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -88,6 +93,8 @@ class CoreWalletsService {
|
|||
@Nullable
|
||||
private KeyParameter tempAesKey;
|
||||
|
||||
private final ListeningExecutorService executor = Utilities.getSingleThreadListeningExecutor("CoreWalletsService");
|
||||
|
||||
@Inject
|
||||
public CoreWalletsService(Balances balances,
|
||||
WalletsManager walletsManager,
|
||||
|
@ -196,32 +203,50 @@ class CoreWalletsService {
|
|||
}
|
||||
}
|
||||
|
||||
TxFeeRateInfo getTxFeeRate() {
|
||||
void getTxFeeRate(ResultHandler resultHandler) {
|
||||
try {
|
||||
CompletableFuture<Void> feeRequestFuture = CompletableFuture.runAsync(feeService::requestFees);
|
||||
feeRequestFuture.get(); // Block until async fee request is complete.
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new IllegalStateException("could not request fees from fee service.", e);
|
||||
}
|
||||
ListenableFuture<Void> future = (ListenableFuture<Void>) executor.submit(() -> feeService.requestFees());
|
||||
Futures.addCallback(future, new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void ignored) {
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
return new TxFeeRateInfo(feeService.getTxFeePerVbyte().value,
|
||||
preferences.getWithdrawalTxFeeInVbytes(),
|
||||
preferences.isUseCustomWithdrawalTxFee());
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
log.error("", t);
|
||||
throw new IllegalStateException("could not request fees from fee service", t);
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error("", ex);
|
||||
throw new IllegalStateException("could not request fees from fee service", ex);
|
||||
}
|
||||
}
|
||||
|
||||
TxFeeRateInfo setTxFeeRatePreference(long txFeeRate) {
|
||||
void setTxFeeRatePreference(long txFeeRate,
|
||||
ResultHandler resultHandler) {
|
||||
if (txFeeRate <= 0)
|
||||
throw new IllegalStateException("cannot create transactions without fees");
|
||||
|
||||
preferences.setUseCustomWithdrawalTxFee(true);
|
||||
Coin satsPerByte = Coin.valueOf(txFeeRate);
|
||||
preferences.setWithdrawalTxFeeInVbytes(satsPerByte.value);
|
||||
return getTxFeeRate();
|
||||
getTxFeeRate(resultHandler);
|
||||
}
|
||||
|
||||
TxFeeRateInfo unsetTxFeeRatePreference() {
|
||||
void unsetTxFeeRatePreference(ResultHandler resultHandler) {
|
||||
preferences.setUseCustomWithdrawalTxFee(false);
|
||||
return getTxFeeRate();
|
||||
getTxFeeRate(resultHandler);
|
||||
}
|
||||
|
||||
TxFeeRateInfo getMostRecentTxFeeRateInfo() {
|
||||
return new TxFeeRateInfo(
|
||||
preferences.isUseCustomWithdrawalTxFee(),
|
||||
preferences.getWithdrawalTxFeeInVbytes(),
|
||||
feeService.getTxFeePerVbyte().value,
|
||||
feeService.getLastRequest());
|
||||
}
|
||||
|
||||
int getNumConfirmationsForMostRecentTransaction(String addressString) {
|
||||
|
|
|
@ -26,16 +26,19 @@ import lombok.Getter;
|
|||
@Getter
|
||||
public class TxFeeRateInfo implements Payload {
|
||||
|
||||
private final long stdTxFeeRate;
|
||||
private final long customTxFeeRate;
|
||||
private final boolean useCustomTxFeeRate;
|
||||
private final long customTxFeeRate;
|
||||
private final long feeServiceRate;
|
||||
private final long lastFeeServiceRequestTs;
|
||||
|
||||
public TxFeeRateInfo(long stdTxFeeRate,
|
||||
public TxFeeRateInfo(boolean useCustomTxFeeRate,
|
||||
long customTxFeeRate,
|
||||
boolean useCustomTxFeeRate) {
|
||||
this.stdTxFeeRate = stdTxFeeRate;
|
||||
this.customTxFeeRate = customTxFeeRate;
|
||||
long feeServiceRate,
|
||||
long lastFeeServiceRequestTs) {
|
||||
this.useCustomTxFeeRate = useCustomTxFeeRate;
|
||||
this.customTxFeeRate = customTxFeeRate;
|
||||
this.feeServiceRate = feeServiceRate;
|
||||
this.lastFeeServiceRequestTs = lastFeeServiceRequestTs;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -45,25 +48,28 @@ public class TxFeeRateInfo implements Payload {
|
|||
@Override
|
||||
public bisq.proto.grpc.TxFeeRateInfo toProtoMessage() {
|
||||
return bisq.proto.grpc.TxFeeRateInfo.newBuilder()
|
||||
.setStdTxFeeRate(stdTxFeeRate)
|
||||
.setCustomTxFeeRate(customTxFeeRate)
|
||||
.setUseCustomTxFeeRate(useCustomTxFeeRate)
|
||||
.setCustomTxFeeRate(customTxFeeRate)
|
||||
.setFeeServiceRate(feeServiceRate)
|
||||
.setLastFeeServiceRequestTs(lastFeeServiceRequestTs)
|
||||
.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static TxFeeRateInfo fromProto(bisq.proto.grpc.TxFeeRateInfo proto) {
|
||||
return new TxFeeRateInfo(proto.getStdTxFeeRate(),
|
||||
return new TxFeeRateInfo(proto.getUseCustomTxFeeRate(),
|
||||
proto.getCustomTxFeeRate(),
|
||||
proto.getUseCustomTxFeeRate());
|
||||
proto.getFeeServiceRate(),
|
||||
proto.getLastFeeServiceRequestTs());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TxFeeRateInfo{"
|
||||
+ "stdTxFeeRate=" + stdTxFeeRate + " sats/byte"
|
||||
+ ", customTxFeeRate=" + customTxFeeRate + " sats/byte"
|
||||
+ ", useCustomTxFeeRate=" + useCustomTxFeeRate
|
||||
+ "}";
|
||||
return "TxFeeRateInfo{" + "\n" +
|
||||
" useCustomTxFeeRate=" + useCustomTxFeeRate + "\n" +
|
||||
", customTxFeeRate=" + customTxFeeRate + "sats/byte" + "\n" +
|
||||
", feeServiceRate=" + feeServiceRate + "sats/byte" + "\n" +
|
||||
", lastFeeServiceRequestTs=" + lastFeeServiceRequestTs + "\n" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import java.time.Instant;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -96,6 +97,7 @@ public class FeeService {
|
|||
private final IntegerProperty feeUpdateCounter = new SimpleIntegerProperty(0);
|
||||
private long txFeePerVbyte = BTC_DEFAULT_TX_FEE;
|
||||
private Map<String, Long> timeStampMap;
|
||||
@Getter
|
||||
private long lastRequest;
|
||||
private long minFeePerVByte;
|
||||
private long epochInSecondAtLastRequest;
|
||||
|
|
|
@ -174,12 +174,14 @@ class GrpcWalletsService extends WalletsGrpc.WalletsImplBase {
|
|||
public void getTxFeeRate(GetTxFeeRateRequest req,
|
||||
StreamObserver<GetTxFeeRateReply> responseObserver) {
|
||||
try {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.getTxFeeRate();
|
||||
var reply = GetTxFeeRateReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
coreApi.getTxFeeRate(() -> {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.getMostRecentTxFeeRateInfo();
|
||||
var reply = GetTxFeeRateReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
});
|
||||
} catch (IllegalStateException cause) {
|
||||
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||
responseObserver.onError(ex);
|
||||
|
@ -191,12 +193,14 @@ class GrpcWalletsService extends WalletsGrpc.WalletsImplBase {
|
|||
public void setTxFeeRatePreference(SetTxFeeRatePreferenceRequest req,
|
||||
StreamObserver<SetTxFeeRatePreferenceReply> responseObserver) {
|
||||
try {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.setTxFeeRatePreference(req.getTxFeeRatePreference());
|
||||
var reply = SetTxFeeRatePreferenceReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
coreApi.setTxFeeRatePreference(req.getTxFeeRatePreference(), () -> {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.getMostRecentTxFeeRateInfo();
|
||||
var reply = SetTxFeeRatePreferenceReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
});
|
||||
} catch (IllegalStateException cause) {
|
||||
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||
responseObserver.onError(ex);
|
||||
|
@ -208,12 +212,14 @@ class GrpcWalletsService extends WalletsGrpc.WalletsImplBase {
|
|||
public void unsetTxFeeRatePreference(UnsetTxFeeRatePreferenceRequest req,
|
||||
StreamObserver<UnsetTxFeeRatePreferenceReply> responseObserver) {
|
||||
try {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.unsetTxFeeRatePreference();
|
||||
var reply = UnsetTxFeeRatePreferenceReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
coreApi.unsetTxFeeRatePreference(() -> {
|
||||
TxFeeRateInfo txFeeRateInfo = coreApi.getMostRecentTxFeeRateInfo();
|
||||
var reply = UnsetTxFeeRatePreferenceReply.newBuilder()
|
||||
.setTxFeeRateInfo(txFeeRateInfo.toProtoMessage())
|
||||
.build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
});
|
||||
} catch (IllegalStateException cause) {
|
||||
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||
responseObserver.onError(ex);
|
||||
|
|
|
@ -438,9 +438,10 @@ message AddressBalanceInfo {
|
|||
}
|
||||
|
||||
message TxFeeRateInfo {
|
||||
uint64 stdTxFeeRate = 1;
|
||||
bool useCustomTxFeeRate = 1;
|
||||
uint64 customTxFeeRate = 2;
|
||||
bool useCustomTxFeeRate = 3;
|
||||
uint64 feeServiceRate = 3;
|
||||
uint64 lastFeeServiceRequestTs = 4;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Add table
Reference in a new issue