remove mempool service
This commit is contained in:
parent
0843f27b63
commit
a1829ee9f3
@ -34,7 +34,6 @@ import haveno.core.offer.OpenOfferManager;
|
|||||||
import haveno.core.offer.TriggerPriceService;
|
import haveno.core.offer.TriggerPriceService;
|
||||||
import haveno.core.payment.AmazonGiftCardAccount;
|
import haveno.core.payment.AmazonGiftCardAccount;
|
||||||
import haveno.core.payment.RevolutAccount;
|
import haveno.core.payment.RevolutAccount;
|
||||||
import haveno.core.provider.mempool.MempoolService;
|
|
||||||
import haveno.core.provider.price.PriceFeedService;
|
import haveno.core.provider.price.PriceFeedService;
|
||||||
import haveno.core.support.dispute.arbitration.ArbitrationManager;
|
import haveno.core.support.dispute.arbitration.ArbitrationManager;
|
||||||
import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||||
@ -93,7 +92,6 @@ public class DomainInitialisation {
|
|||||||
private final MarketAlerts marketAlerts;
|
private final MarketAlerts marketAlerts;
|
||||||
private final User user;
|
private final User user;
|
||||||
private final TriggerPriceService triggerPriceService;
|
private final TriggerPriceService triggerPriceService;
|
||||||
private final MempoolService mempoolService;
|
|
||||||
private final MailboxMessageService mailboxMessageService;
|
private final MailboxMessageService mailboxMessageService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@ -126,7 +124,6 @@ public class DomainInitialisation {
|
|||||||
MarketAlerts marketAlerts,
|
MarketAlerts marketAlerts,
|
||||||
User user,
|
User user,
|
||||||
TriggerPriceService triggerPriceService,
|
TriggerPriceService triggerPriceService,
|
||||||
MempoolService mempoolService,
|
|
||||||
MailboxMessageService mailboxMessageService) {
|
MailboxMessageService mailboxMessageService) {
|
||||||
this.clockWatcher = clockWatcher;
|
this.clockWatcher = clockWatcher;
|
||||||
this.arbitrationManager = arbitrationManager;
|
this.arbitrationManager = arbitrationManager;
|
||||||
@ -157,7 +154,6 @@ public class DomainInitialisation {
|
|||||||
this.marketAlerts = marketAlerts;
|
this.marketAlerts = marketAlerts;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.triggerPriceService = triggerPriceService;
|
this.triggerPriceService = triggerPriceService;
|
||||||
this.mempoolService = mempoolService;
|
|
||||||
this.mailboxMessageService = mailboxMessageService;
|
this.mailboxMessageService = mailboxMessageService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +211,6 @@ public class DomainInitialisation {
|
|||||||
priceAlert.onAllServicesInitialized();
|
priceAlert.onAllServicesInitialized();
|
||||||
marketAlerts.onAllServicesInitialized();
|
marketAlerts.onAllServicesInitialized();
|
||||||
triggerPriceService.onAllServicesInitialized();
|
triggerPriceService.onAllServicesInitialized();
|
||||||
mempoolService.onAllServicesInitialized();
|
|
||||||
|
|
||||||
mailboxMessageService.onAllServicesInitialized();
|
mailboxMessageService.onAllServicesInitialized();
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import haveno.core.locale.CurrencyUtil;
|
|||||||
import haveno.core.monetary.CryptoMoney;
|
import haveno.core.monetary.CryptoMoney;
|
||||||
import haveno.core.monetary.Price;
|
import haveno.core.monetary.Price;
|
||||||
import haveno.core.monetary.TraditionalMoney;
|
import haveno.core.monetary.TraditionalMoney;
|
||||||
import haveno.core.provider.mempool.MempoolService;
|
|
||||||
import haveno.core.provider.price.MarketPrice;
|
import haveno.core.provider.price.MarketPrice;
|
||||||
import haveno.core.provider.price.PriceFeedService;
|
import haveno.core.provider.price.PriceFeedService;
|
||||||
import haveno.network.p2p.BootstrapListener;
|
import haveno.network.p2p.BootstrapListener;
|
||||||
@ -47,18 +46,15 @@ import static haveno.common.util.MathUtils.scaleUpByPowerOf10;
|
|||||||
public class TriggerPriceService {
|
public class TriggerPriceService {
|
||||||
private final P2PService p2PService;
|
private final P2PService p2PService;
|
||||||
private final OpenOfferManager openOfferManager;
|
private final OpenOfferManager openOfferManager;
|
||||||
private final MempoolService mempoolService;
|
|
||||||
private final PriceFeedService priceFeedService;
|
private final PriceFeedService priceFeedService;
|
||||||
private final Map<String, Set<OpenOffer>> openOffersByCurrency = new HashMap<>();
|
private final Map<String, Set<OpenOffer>> openOffersByCurrency = new HashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TriggerPriceService(P2PService p2PService,
|
public TriggerPriceService(P2PService p2PService,
|
||||||
OpenOfferManager openOfferManager,
|
OpenOfferManager openOfferManager,
|
||||||
MempoolService mempoolService,
|
|
||||||
PriceFeedService priceFeedService) {
|
PriceFeedService priceFeedService) {
|
||||||
this.p2PService = p2PService;
|
this.p2PService = p2PService;
|
||||||
this.openOfferManager = openOfferManager;
|
this.openOfferManager = openOfferManager;
|
||||||
this.mempoolService = mempoolService;
|
|
||||||
this.priceFeedService = priceFeedService;
|
this.priceFeedService = priceFeedService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,19 +148,7 @@ public class TriggerPriceService {
|
|||||||
}, errorMessage -> {
|
}, errorMessage -> {
|
||||||
});
|
});
|
||||||
} else if (openOffer.getState() == OpenOffer.State.AVAILABLE) {
|
} else if (openOffer.getState() == OpenOffer.State.AVAILABLE) {
|
||||||
// check the mempool if it has not been done before
|
// TODO: check if open offer's reserve tx is failed or double spend seen
|
||||||
if (openOffer.getMempoolStatus() < 0 && mempoolService.canRequestBeMade(openOffer.getOffer().getOfferPayload())) {
|
|
||||||
mempoolService.validateOfferMakerTx(openOffer.getOffer().getOfferPayload(), (txValidator -> {
|
|
||||||
openOffer.setMempoolStatus(txValidator.isFail() ? 0 : 1);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// if the mempool indicated failure then deactivate the open offer
|
|
||||||
if (openOffer.getMempoolStatus() == 0) {
|
|
||||||
log.info("Deactivating open offer {} due to mempool validation", openOffer.getOffer().getShortId());
|
|
||||||
openOfferManager.deactivateOpenOffer(openOffer, () -> {
|
|
||||||
}, errorMessage -> {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Haveno.
|
|
||||||
*
|
|
||||||
* Haveno 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.
|
|
||||||
*
|
|
||||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package haveno.core.provider.mempool;
|
|
||||||
|
|
||||||
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 com.google.common.util.concurrent.SettableFuture;
|
|
||||||
import haveno.common.util.Utilities;
|
|
||||||
import haveno.core.provider.MempoolHttpClient;
|
|
||||||
import haveno.core.user.Preferences;
|
|
||||||
import haveno.network.Socks5ProxyProvider;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class MempoolRequest {
|
|
||||||
private static final ListeningExecutorService executorService = Utilities.getListeningExecutorService("MempoolRequest", 3, 5, 10 * 60);
|
|
||||||
private final List<String> txBroadcastServices = new ArrayList<>();
|
|
||||||
private final MempoolHttpClient mempoolHttpClient;
|
|
||||||
|
|
||||||
public MempoolRequest(Preferences preferences, Socks5ProxyProvider socks5ProxyProvider) {
|
|
||||||
this.txBroadcastServices.addAll(preferences.getDefaultTxBroadcastServices());
|
|
||||||
this.mempoolHttpClient = new MempoolHttpClient(socks5ProxyProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getTxStatus(SettableFuture<String> mempoolServiceCallback, String txId) {
|
|
||||||
mempoolHttpClient.setBaseUrl(getRandomServiceAddress(txBroadcastServices));
|
|
||||||
ListenableFuture<String> future = executorService.submit(() -> {
|
|
||||||
Thread.currentThread().setName("MempoolRequest @ " + mempoolHttpClient.getBaseUrl());
|
|
||||||
log.info("Making http request for information on txId: {}", txId);
|
|
||||||
return mempoolHttpClient.getTxDetails(txId);
|
|
||||||
});
|
|
||||||
|
|
||||||
Futures.addCallback(future, new FutureCallback<>() {
|
|
||||||
public void onSuccess(String mempoolData) {
|
|
||||||
log.info("Received mempoolData of [{}] from provider", mempoolData);
|
|
||||||
mempoolServiceCallback.set(mempoolData);
|
|
||||||
}
|
|
||||||
public void onFailure(@NotNull Throwable throwable) {
|
|
||||||
mempoolServiceCallback.setException(throwable);
|
|
||||||
}
|
|
||||||
}, MoreExecutors.directExecutor());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean switchToAnotherProvider() {
|
|
||||||
txBroadcastServices.remove(mempoolHttpClient.getBaseUrl());
|
|
||||||
return txBroadcastServices.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String getRandomServiceAddress(List<String> txBroadcastServices) {
|
|
||||||
List<String> list = checkNotNull(txBroadcastServices);
|
|
||||||
return !list.isEmpty() ? list.get(new Random().nextInt(list.size())) : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,257 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Haveno.
|
|
||||||
*
|
|
||||||
* Haveno 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.
|
|
||||||
*
|
|
||||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package haveno.core.provider.mempool;
|
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
import com.google.common.util.concurrent.Futures;
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import haveno.common.UserThread;
|
|
||||||
import haveno.common.config.Config;
|
|
||||||
import haveno.core.filter.FilterManager;
|
|
||||||
import haveno.core.offer.OfferPayload;
|
|
||||||
import haveno.core.trade.Trade;
|
|
||||||
import haveno.core.user.Preferences;
|
|
||||||
import haveno.network.Socks5ProxyProvider;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.bitcoinj.core.Coin;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Singleton
|
|
||||||
public class MempoolService {
|
|
||||||
private final Socks5ProxyProvider socks5ProxyProvider;
|
|
||||||
private final Config config;
|
|
||||||
private final Preferences preferences;
|
|
||||||
private final FilterManager filterManager;
|
|
||||||
private final List<String> btcFeeReceivers = new ArrayList<>();
|
|
||||||
@Getter
|
|
||||||
private int outstandingRequests = 0;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public MempoolService(Socks5ProxyProvider socks5ProxyProvider,
|
|
||||||
Config config,
|
|
||||||
Preferences preferences,
|
|
||||||
FilterManager filterManager) {
|
|
||||||
this.socks5ProxyProvider = socks5ProxyProvider;
|
|
||||||
this.config = config;
|
|
||||||
this.preferences = preferences;
|
|
||||||
this.filterManager = filterManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onAllServicesInitialized() {
|
|
||||||
btcFeeReceivers.addAll(getAllBtcFeeReceivers());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canRequestBeMade() {
|
|
||||||
return outstandingRequests < 5; // limit max simultaneous lookups
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canRequestBeMade(OfferPayload offerPayload) {
|
|
||||||
// when validating a new offer, wait 1 block for the tx to propagate
|
|
||||||
return canRequestBeMade();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateOfferMakerTx(OfferPayload offerPayload, Consumer<TxValidator> resultHandler) {
|
|
||||||
validateOfferMakerTx(new TxValidator( offerPayload.getOfferFeeTxId(), Coin.valueOf(offerPayload.getAmount())), resultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateOfferMakerTx(TxValidator txValidator, Consumer<TxValidator> resultHandler) {
|
|
||||||
if (!isServiceSupported()) {
|
|
||||||
UserThread.runAfter(() -> resultHandler.accept(txValidator.endResult("mempool request not supported, bypassing", true)), 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MempoolRequest mempoolRequest = new MempoolRequest(preferences, socks5ProxyProvider);
|
|
||||||
validateOfferMakerTx(mempoolRequest, txValidator, resultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateOfferTakerTx(Trade trade, Consumer<TxValidator> resultHandler) {
|
|
||||||
throw new RuntimeException("MempoolService.validateOfferTakerTx needs updated for XMR");
|
|
||||||
//validateOfferTakerTx(new TxValidator( trade.getTakerFeeTxId(), trade.getTradeAmount(),resultHandler));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateOfferTakerTx(TxValidator txValidator, Consumer<TxValidator> resultHandler) {
|
|
||||||
if (!isServiceSupported()) {
|
|
||||||
UserThread.runAfter(() -> resultHandler.accept(txValidator.endResult("mempool request not supported, bypassing", true)), 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MempoolRequest mempoolRequest = new MempoolRequest(preferences, socks5ProxyProvider);
|
|
||||||
validateOfferTakerTx(mempoolRequest, txValidator, resultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkTxIsConfirmed(String txId, Consumer<TxValidator> resultHandler) {
|
|
||||||
TxValidator txValidator = new TxValidator(txId);
|
|
||||||
if (!isServiceSupported()) {
|
|
||||||
UserThread.runAfter(() -> resultHandler.accept(txValidator.endResult("mempool request not supported, bypassing", true)), 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MempoolRequest mempoolRequest = new MempoolRequest(preferences, socks5ProxyProvider);
|
|
||||||
SettableFuture<String> future = SettableFuture.create();
|
|
||||||
Futures.addCallback(future, callbackForTxRequest(mempoolRequest, txValidator, resultHandler), MoreExecutors.directExecutor());
|
|
||||||
mempoolRequest.getTxStatus(future, txId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ///////////////////////////
|
|
||||||
|
|
||||||
private void validateOfferMakerTx(MempoolRequest mempoolRequest,
|
|
||||||
TxValidator txValidator,
|
|
||||||
Consumer<TxValidator> resultHandler) {
|
|
||||||
SettableFuture<String> future = SettableFuture.create();
|
|
||||||
Futures.addCallback(future, callbackForMakerTxValidation(mempoolRequest, txValidator, resultHandler), MoreExecutors.directExecutor());
|
|
||||||
mempoolRequest.getTxStatus(future, txValidator.getTxId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateOfferTakerTx(MempoolRequest mempoolRequest,
|
|
||||||
TxValidator txValidator,
|
|
||||||
Consumer<TxValidator> resultHandler) {
|
|
||||||
SettableFuture<String> future = SettableFuture.create();
|
|
||||||
Futures.addCallback(future, callbackForTakerTxValidation(mempoolRequest, txValidator, resultHandler), MoreExecutors.directExecutor());
|
|
||||||
mempoolRequest.getTxStatus(future, txValidator.getTxId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private FutureCallback<String> callbackForMakerTxValidation(MempoolRequest theRequest,
|
|
||||||
TxValidator txValidator,
|
|
||||||
Consumer<TxValidator> resultHandler) {
|
|
||||||
outstandingRequests++;
|
|
||||||
FutureCallback<String> myCallback = new FutureCallback<>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable String jsonTxt) {
|
|
||||||
UserThread.execute(() -> {
|
|
||||||
outstandingRequests--;
|
|
||||||
resultHandler.accept(txValidator.endResult("onSuccess", true));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable throwable) {
|
|
||||||
log.warn("onFailure - {}", throwable.toString());
|
|
||||||
UserThread.execute(() -> {
|
|
||||||
outstandingRequests--;
|
|
||||||
if (theRequest.switchToAnotherProvider()) {
|
|
||||||
validateOfferMakerTx(theRequest, txValidator, resultHandler);
|
|
||||||
} else {
|
|
||||||
// exhausted all providers, let user know of failure
|
|
||||||
resultHandler.accept(txValidator.endResult("Tx not found", false));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return myCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FutureCallback<String> callbackForTakerTxValidation(MempoolRequest theRequest,
|
|
||||||
TxValidator txValidator,
|
|
||||||
Consumer<TxValidator> resultHandler) {
|
|
||||||
outstandingRequests++;
|
|
||||||
FutureCallback<String> myCallback = new FutureCallback<>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable String jsonTxt) {
|
|
||||||
UserThread.execute(() -> {
|
|
||||||
outstandingRequests--;
|
|
||||||
resultHandler.accept(txValidator.endResult("onSuccess", true));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable throwable) {
|
|
||||||
log.warn("onFailure - {}", throwable.toString());
|
|
||||||
UserThread.execute(() -> {
|
|
||||||
outstandingRequests--;
|
|
||||||
if (theRequest.switchToAnotherProvider()) {
|
|
||||||
validateOfferTakerTx(theRequest, txValidator, resultHandler);
|
|
||||||
} else {
|
|
||||||
// exhausted all providers, let user know of failure
|
|
||||||
resultHandler.accept(txValidator.endResult("Tx not found", false));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return myCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FutureCallback<String> callbackForTxRequest(MempoolRequest theRequest,
|
|
||||||
TxValidator txValidator,
|
|
||||||
Consumer<TxValidator> resultHandler) {
|
|
||||||
outstandingRequests++;
|
|
||||||
FutureCallback<String> myCallback = new FutureCallback<>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable String jsonTxt) {
|
|
||||||
UserThread.execute(() -> {
|
|
||||||
outstandingRequests--;
|
|
||||||
txValidator.setJsonTxt(jsonTxt);
|
|
||||||
resultHandler.accept(txValidator);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable throwable) {
|
|
||||||
log.warn("onFailure - {}", throwable.toString());
|
|
||||||
UserThread.execute(() -> {
|
|
||||||
outstandingRequests--;
|
|
||||||
resultHandler.accept(txValidator.endResult("Tx not found", false));
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return myCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
// /////////////////////////////
|
|
||||||
|
|
||||||
private List<String> getAllBtcFeeReceivers() {
|
|
||||||
List<String> btcFeeReceivers = new ArrayList<>();
|
|
||||||
// fee receivers from filter ref: bisq-network/bisq/pull/4294
|
|
||||||
List<String> feeReceivers = Optional.ofNullable(filterManager.getFilter())
|
|
||||||
.flatMap(f -> Optional.ofNullable(f.getBtcFeeReceiverAddresses()))
|
|
||||||
.orElse(List.of());
|
|
||||||
feeReceivers.forEach(e -> {
|
|
||||||
try {
|
|
||||||
btcFeeReceivers.add(e.split("#")[0]); // victim's receiver address
|
|
||||||
} catch (RuntimeException ignore) {
|
|
||||||
// If input format is not as expected we ignore entry
|
|
||||||
}
|
|
||||||
});
|
|
||||||
log.info("Known BTC fee receivers: {}", btcFeeReceivers.toString());
|
|
||||||
|
|
||||||
return btcFeeReceivers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isServiceSupported() {
|
|
||||||
if (filterManager.getFilter() != null && filterManager.getFilter().isDisableMempoolValidation()) {
|
|
||||||
log.info("MempoolService bypassed by filter setting disableMempoolValidation=true");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (config.bypassMempoolValidation) {
|
|
||||||
log.info("MempoolService bypassed by config setting bypassMempoolValidation=true");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!Config.baseCurrencyNetwork().isMainnet()) {
|
|
||||||
log.info("MempoolService only supports mainnet");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Haveno.
|
|
||||||
*
|
|
||||||
* Haveno 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.
|
|
||||||
*
|
|
||||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package haveno.core.provider.mempool;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.bitcoinj.core.Coin;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Getter
|
|
||||||
public class TxValidator {
|
|
||||||
|
|
||||||
private final List<String> errorList;
|
|
||||||
private final String txId;
|
|
||||||
private Coin amount;
|
|
||||||
@Setter
|
|
||||||
private String jsonTxt;
|
|
||||||
|
|
||||||
|
|
||||||
public TxValidator(String txId, Coin amount) {
|
|
||||||
this.txId = txId;
|
|
||||||
this.amount = amount;
|
|
||||||
this.errorList = new ArrayList<>();
|
|
||||||
this.jsonTxt = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public TxValidator(String txId) {
|
|
||||||
this.txId = txId;
|
|
||||||
this.errorList = new ArrayList<>();
|
|
||||||
this.jsonTxt = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public TxValidator endResult(String title, boolean status) {
|
|
||||||
log.info("{} : {}", title, status ? "SUCCESS" : "FAIL");
|
|
||||||
if (!status) {
|
|
||||||
errorList.add(title);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFail() {
|
|
||||||
return errorList.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getResult() {
|
|
||||||
return errorList.size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String errorSummary() {
|
|
||||||
return errorList.toString().substring(0, Math.min(85, errorList.toString().length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return errorList.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Haveno.
|
|
||||||
*
|
|
||||||
* Haveno 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.
|
|
||||||
*
|
|
||||||
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package haveno.core.provider.mempool;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.bitcoinj.core.Coin;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
public class TxValidatorTest {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(TxValidatorTest.class);
|
|
||||||
|
|
||||||
private List<String> btcFeeReceivers = new ArrayList<>();
|
|
||||||
|
|
||||||
public TxValidatorTest() {
|
|
||||||
btcFeeReceivers.add("1EKXx73oUhHaUh8JBimtiPGgHfwNmxYKAj");
|
|
||||||
btcFeeReceivers.add("1HpvvMHcoXQsX85CjTsco5ZAAMoGu2Mze9");
|
|
||||||
btcFeeReceivers.add("3EfRGckBQQuk7cpU7SwatPv8kFD1vALkTU");
|
|
||||||
btcFeeReceivers.add("13sxMq8mTw7CTSqgGiMPfwo6ZDsVYrHLmR");
|
|
||||||
btcFeeReceivers.add("19qA2BVPoyXDfHKVMovKG7SoxGY7xrBV8c");
|
|
||||||
btcFeeReceivers.add("19BNi5EpZhgBBWAt5ka7xWpJpX2ZWJEYyq");
|
|
||||||
btcFeeReceivers.add("38bZBj5peYS3Husdz7AH3gEUiUbYRD951t");
|
|
||||||
btcFeeReceivers.add("3EtUWqsGThPtjwUczw27YCo6EWvQdaPUyp");
|
|
||||||
btcFeeReceivers.add("1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7");
|
|
||||||
btcFeeReceivers.add("3A8Zc1XioE2HRzYfbb5P8iemCS72M6vRJV");
|
|
||||||
btcFeeReceivers.add("34VLFgtFKAtwTdZ5rengTT2g2zC99sWQLC");
|
|
||||||
log.warn("Known BTC fee receivers: {}", btcFeeReceivers.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMakerTx() throws InterruptedException {
|
|
||||||
String mempoolData, offerData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTakerTx() throws InterruptedException {
|
|
||||||
String mempoolData, offerData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testOfferSet(Map<String, String> offers, Map<String, String> mempoolData, boolean expectedResult) {
|
|
||||||
Set<String> knownValuesList = new HashSet<>(offers.values());
|
|
||||||
knownValuesList.forEach(offerData -> {
|
|
||||||
TxValidator txValidator = createTxValidator(offerData);
|
|
||||||
log.warn("TESTING {}", txValidator.getTxId());
|
|
||||||
String jsonTxt = mempoolData.get(txValidator.getTxId());
|
|
||||||
if (jsonTxt == null || jsonTxt.isEmpty()) {
|
|
||||||
log.warn("{} was not found in the mempool", txValidator.getTxId());
|
|
||||||
assertFalse(expectedResult); // tx was not found in explorer
|
|
||||||
} else {
|
|
||||||
//txValidator.parseJsonValidateMakerFeeTx(jsonTxt, btcFeeReceivers);
|
|
||||||
log.warn("expectedResult {}", expectedResult );
|
|
||||||
log.warn("getResult {}", txValidator.getResult() );
|
|
||||||
assertTrue(expectedResult == txValidator.getResult());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> loadJsonTestData(String fileName) {
|
|
||||||
String json = "";
|
|
||||||
try {
|
|
||||||
json = IOUtils.toString(this.getClass().getResourceAsStream(fileName), "UTF-8");
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error(e.toString());
|
|
||||||
}
|
|
||||||
Map<String, String> map = new Gson().fromJson(json, Map.class);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize the TxValidator with offerData to be validated
|
|
||||||
private TxValidator createTxValidator(String offerData) {
|
|
||||||
try {
|
|
||||||
String[] y = offerData.split(",");
|
|
||||||
String txId = y[1];
|
|
||||||
long amount = Long.parseLong(y[2]);
|
|
||||||
TxValidator txValidator = new TxValidator(txId, Coin.valueOf(amount));
|
|
||||||
return txValidator;
|
|
||||||
} catch (RuntimeException ignore) {
|
|
||||||
// If input format is not as expected we ignore entry
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,7 +31,6 @@ import haveno.core.offer.OfferUtil;
|
|||||||
import haveno.core.payment.PaymentAccount;
|
import haveno.core.payment.PaymentAccount;
|
||||||
import haveno.core.payment.PaymentAccountUtil;
|
import haveno.core.payment.PaymentAccountUtil;
|
||||||
import haveno.core.payment.payload.PaymentMethod;
|
import haveno.core.payment.payload.PaymentMethod;
|
||||||
import haveno.core.provider.mempool.MempoolService;
|
|
||||||
import haveno.core.provider.price.PriceFeedService;
|
import haveno.core.provider.price.PriceFeedService;
|
||||||
import haveno.core.trade.HavenoUtils;
|
import haveno.core.trade.HavenoUtils;
|
||||||
import haveno.core.trade.TradeManager;
|
import haveno.core.trade.TradeManager;
|
||||||
@ -48,13 +47,10 @@ import haveno.desktop.main.offer.offerbook.OfferBook;
|
|||||||
import haveno.desktop.main.overlays.popups.Popup;
|
import haveno.desktop.main.overlays.popups.Popup;
|
||||||
import haveno.desktop.util.GUIUtil;
|
import haveno.desktop.util.GUIUtil;
|
||||||
import haveno.network.p2p.P2PService;
|
import haveno.network.p2p.P2PService;
|
||||||
import javafx.beans.property.IntegerProperty;
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import lombok.Getter;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -73,7 +69,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||||||
private final TradeManager tradeManager;
|
private final TradeManager tradeManager;
|
||||||
private final OfferBook offerBook;
|
private final OfferBook offerBook;
|
||||||
private final User user;
|
private final User user;
|
||||||
private final MempoolService mempoolService;
|
|
||||||
private final FilterManager filterManager;
|
private final FilterManager filterManager;
|
||||||
final Preferences preferences;
|
final Preferences preferences;
|
||||||
private final PriceFeedService priceFeedService;
|
private final PriceFeedService priceFeedService;
|
||||||
@ -94,10 +89,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||||||
private PaymentAccount paymentAccount;
|
private PaymentAccount paymentAccount;
|
||||||
private boolean isTabSelected;
|
private boolean isTabSelected;
|
||||||
Price tradePrice;
|
Price tradePrice;
|
||||||
@Getter
|
|
||||||
protected final IntegerProperty mempoolStatus = new SimpleIntegerProperty();
|
|
||||||
@Getter
|
|
||||||
protected String mempoolStatusText;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -111,7 +102,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||||||
OfferUtil offerUtil,
|
OfferUtil offerUtil,
|
||||||
XmrWalletService xmrWalletService,
|
XmrWalletService xmrWalletService,
|
||||||
User user,
|
User user,
|
||||||
MempoolService mempoolService,
|
|
||||||
FilterManager filterManager,
|
FilterManager filterManager,
|
||||||
Preferences preferences,
|
Preferences preferences,
|
||||||
PriceFeedService priceFeedService,
|
PriceFeedService priceFeedService,
|
||||||
@ -124,7 +114,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||||||
this.tradeManager = tradeManager;
|
this.tradeManager = tradeManager;
|
||||||
this.offerBook = offerBook;
|
this.offerBook = offerBook;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.mempoolService = mempoolService;
|
|
||||||
this.filterManager = filterManager;
|
this.filterManager = filterManager;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
this.priceFeedService = priceFeedService;
|
this.priceFeedService = priceFeedService;
|
||||||
@ -192,15 +181,6 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||||||
getBuyerSecurityDeposit() :
|
getBuyerSecurityDeposit() :
|
||||||
getSellerSecurityDeposit();
|
getSellerSecurityDeposit();
|
||||||
|
|
||||||
mempoolStatus.setValue(-1);
|
|
||||||
mempoolService.validateOfferMakerTx(offer.getOfferPayload(), (txValidator -> {
|
|
||||||
mempoolStatus.setValue(txValidator.isFail() ? 0 : 1);
|
|
||||||
if (txValidator.isFail()) {
|
|
||||||
mempoolStatusText = txValidator.toString();
|
|
||||||
log.info("Mempool check of OfferFeeTxId returned errors: [{}]", mempoolStatusText);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
calculateVolume();
|
calculateVolume();
|
||||||
calculateTotalToPay();
|
calculateTotalToPay();
|
||||||
|
|
||||||
|
@ -813,20 +813,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void nextStepCheckMakerTx() {
|
private void nextStepCheckMakerTx() {
|
||||||
// the tx validation check has had plenty of time to complete, but if for some reason it has not returned
|
// TODO: pre-check if open offer's reserve tx is failed or double spend seen?
|
||||||
// we continue anyway since the check is not crucial.
|
showNextStepAfterAmountIsSet();
|
||||||
// note, it would be great if there was a real tri-state boolean we could use here, instead of -1, 0, and 1
|
|
||||||
int result = model.dataModel.mempoolStatus.get();
|
|
||||||
if (result == 0) {
|
|
||||||
new Popup().warning(Res.get("popup.warning.makerTxInvalid") + model.dataModel.getMempoolStatusText())
|
|
||||||
.onClose(() -> cancelButton1.fire())
|
|
||||||
.show();
|
|
||||||
} else {
|
|
||||||
if (result == -1) {
|
|
||||||
log.warn("Fee check has not returned a result yet. We optimistically assume all is ok and continue.");
|
|
||||||
}
|
|
||||||
showNextStepAfterAmountIsSet();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showNextStepAfterAmountIsSet() {
|
private void showNextStepAfterAmountIsSet() {
|
||||||
|
@ -116,7 +116,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||||||
private ChangeListener<Boolean> isWalletFundedListener;
|
private ChangeListener<Boolean> isWalletFundedListener;
|
||||||
private ChangeListener<Trade.State> tradeStateListener;
|
private ChangeListener<Trade.State> tradeStateListener;
|
||||||
private ChangeListener<Offer.State> offerStateListener;
|
private ChangeListener<Offer.State> offerStateListener;
|
||||||
private ChangeListener<Number> getMempoolStatusListener;
|
|
||||||
private ConnectionListener connectionListener;
|
private ConnectionListener connectionListener;
|
||||||
// private Subscription isFeeSufficientSubscription;
|
// private Subscription isFeeSufficientSubscription;
|
||||||
private Runnable takeOfferResultHandler;
|
private Runnable takeOfferResultHandler;
|
||||||
@ -449,7 +448,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||||||
boolean inputDataValid = isBtcInputValid(amount.get()).isValid
|
boolean inputDataValid = isBtcInputValid(amount.get()).isValid
|
||||||
&& dataModel.isMinAmountLessOrEqualAmount()
|
&& dataModel.isMinAmountLessOrEqualAmount()
|
||||||
&& !dataModel.isAmountLargerThanOfferAmount()
|
&& !dataModel.isAmountLargerThanOfferAmount()
|
||||||
&& dataModel.mempoolStatus.get() >= 0 // TODO do we want to block in case response is slow (tor can be slow)?
|
|
||||||
&& isOfferAvailable.get()
|
&& isOfferAvailable.get()
|
||||||
&& !dataModel.wouldCreateDustForMaker();
|
&& !dataModel.wouldCreateDustForMaker();
|
||||||
isNextButtonDisabled.set(!inputDataValid);
|
isNextButtonDisabled.set(!inputDataValid);
|
||||||
@ -491,12 +489,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||||||
tradeStateListener = (ov, oldValue, newValue) -> applyTradeState();
|
tradeStateListener = (ov, oldValue, newValue) -> applyTradeState();
|
||||||
offerStateListener = (ov, oldValue, newValue) -> applyOfferState(newValue);
|
offerStateListener = (ov, oldValue, newValue) -> applyOfferState(newValue);
|
||||||
|
|
||||||
getMempoolStatusListener = (observable, oldValue, newValue) -> {
|
|
||||||
if (newValue.longValue() >= 0) {
|
|
||||||
updateButtonDisableState();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
connectionListener = new ConnectionListener() {
|
connectionListener = new ConnectionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) {
|
public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) {
|
||||||
@ -544,7 +536,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||||||
dataModel.getAmount().addListener(amountListener);
|
dataModel.getAmount().addListener(amountListener);
|
||||||
|
|
||||||
dataModel.getIsXmrWalletFunded().addListener(isWalletFundedListener);
|
dataModel.getIsXmrWalletFunded().addListener(isWalletFundedListener);
|
||||||
dataModel.getMempoolStatus().addListener(getMempoolStatusListener);
|
|
||||||
p2PService.getNetworkNode().addConnectionListener(connectionListener);
|
p2PService.getNetworkNode().addConnectionListener(connectionListener);
|
||||||
/* isFeeSufficientSubscription = EasyBind.subscribe(dataModel.isFeeFromFundingTxSufficient, newValue -> {
|
/* isFeeSufficientSubscription = EasyBind.subscribe(dataModel.isFeeFromFundingTxSufficient, newValue -> {
|
||||||
updateButtonDisableState();
|
updateButtonDisableState();
|
||||||
@ -557,7 +548,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||||||
|
|
||||||
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding
|
// Binding with Bindings.createObjectBinding does not work because of bi-directional binding
|
||||||
dataModel.getAmount().removeListener(amountListener);
|
dataModel.getAmount().removeListener(amountListener);
|
||||||
dataModel.getMempoolStatus().removeListener(getMempoolStatusListener);
|
|
||||||
|
|
||||||
dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener);
|
dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener);
|
||||||
if (offer != null) {
|
if (offer != null) {
|
||||||
@ -717,10 +707,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||||||
offer.setErrorMessage(null);
|
offer.setErrorMessage(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoinFormatter getFormatterForTakerFee() {
|
|
||||||
return xmrFormatter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Callback<ListView<PaymentAccount>, ListCell<PaymentAccount>> getPaymentAccountListCellFactory(
|
public Callback<ListView<PaymentAccount>, ListCell<PaymentAccount>> getPaymentAccountListCellFactory(
|
||||||
ComboBox<PaymentAccount> paymentAccountsComboBox) {
|
ComboBox<PaymentAccount> paymentAccountsComboBox) {
|
||||||
return GUIUtil.getPaymentAccountListCellFactory(paymentAccountsComboBox, accountAgeWitnessService);
|
return GUIUtil.getPaymentAccountListCellFactory(paymentAccountsComboBox, accountAgeWitnessService);
|
||||||
|
@ -24,7 +24,6 @@ import haveno.core.account.witness.AccountAgeWitnessService;
|
|||||||
import haveno.core.network.MessageState;
|
import haveno.core.network.MessageState;
|
||||||
import haveno.core.offer.Offer;
|
import haveno.core.offer.Offer;
|
||||||
import haveno.core.offer.OfferUtil;
|
import haveno.core.offer.OfferUtil;
|
||||||
import haveno.core.provider.mempool.MempoolService;
|
|
||||||
import haveno.core.trade.ArbitratorTrade;
|
import haveno.core.trade.ArbitratorTrade;
|
||||||
import haveno.core.trade.BuyerTrade;
|
import haveno.core.trade.BuyerTrade;
|
||||||
import haveno.core.trade.ClosedTradableManager;
|
import haveno.core.trade.ClosedTradableManager;
|
||||||
@ -91,7 +90,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||||||
public final BtcAddressValidator btcAddressValidator;
|
public final BtcAddressValidator btcAddressValidator;
|
||||||
final AccountAgeWitnessService accountAgeWitnessService;
|
final AccountAgeWitnessService accountAgeWitnessService;
|
||||||
public final P2PService p2PService;
|
public final P2PService p2PService;
|
||||||
private final MempoolService mempoolService;
|
|
||||||
private final ClosedTradableManager closedTradableManager;
|
private final ClosedTradableManager closedTradableManager;
|
||||||
private final OfferUtil offerUtil;
|
private final OfferUtil offerUtil;
|
||||||
private final TradeUtil tradeUtil;
|
private final TradeUtil tradeUtil;
|
||||||
@ -121,7 +119,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||||
BtcAddressValidator btcAddressValidator,
|
BtcAddressValidator btcAddressValidator,
|
||||||
P2PService p2PService,
|
P2PService p2PService,
|
||||||
MempoolService mempoolService,
|
|
||||||
ClosedTradableManager closedTradableManager,
|
ClosedTradableManager closedTradableManager,
|
||||||
OfferUtil offerUtil,
|
OfferUtil offerUtil,
|
||||||
TradeUtil tradeUtil,
|
TradeUtil tradeUtil,
|
||||||
@ -134,7 +131,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||||||
this.btcFormatter = btcFormatter;
|
this.btcFormatter = btcFormatter;
|
||||||
this.btcAddressValidator = btcAddressValidator;
|
this.btcAddressValidator = btcAddressValidator;
|
||||||
this.p2PService = p2PService;
|
this.p2PService = p2PService;
|
||||||
this.mempoolService = mempoolService;
|
|
||||||
this.closedTradableManager = closedTradableManager;
|
this.closedTradableManager = closedTradableManager;
|
||||||
this.offerUtil = offerUtil;
|
this.offerUtil = offerUtil;
|
||||||
this.tradeUtil = tradeUtil;
|
this.tradeUtil = tradeUtil;
|
||||||
|
Loading…
Reference in New Issue
Block a user