add trade init steps and reset timeout

This commit is contained in:
woodser 2024-05-05 19:32:07 -04:00
parent 6fb846d783
commit 78ec06b851
18 changed files with 63 additions and 36 deletions

View File

@ -1151,7 +1151,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
user,
keyRing,
filterManager,
accountAgeWitnessService);
accountAgeWitnessService,
this);
// create protocol
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(model,

View File

@ -23,6 +23,7 @@ import haveno.core.account.witness.AccountAgeWitnessService;
import haveno.core.filter.FilterManager;
import haveno.core.offer.OfferBookService;
import haveno.core.offer.OpenOffer;
import haveno.core.offer.OpenOfferManager;
import haveno.core.offer.messages.SignOfferResponse;
import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import haveno.core.support.dispute.mediation.mediator.MediatorManager;
@ -61,6 +62,8 @@ public class PlaceOfferModel implements Model {
private final FilterManager filterManager;
@Getter
private final AccountAgeWitnessService accountAgeWitnessService;
@Getter
private final OpenOfferManager openOfferManager;
// Mutable
@Setter
@ -89,7 +92,8 @@ public class PlaceOfferModel implements Model {
User user,
KeyRing keyRing,
FilterManager filterManager,
AccountAgeWitnessService accountAgeWitnessService) {
AccountAgeWitnessService accountAgeWitnessService,
OpenOfferManager openOfferManager) {
this.openOffer = openOffer;
this.reservedFundsForOffer = reservedFundsForOffer;
this.useSavingsWallet = useSavingsWallet;
@ -105,6 +109,7 @@ public class PlaceOfferModel implements Model {
this.keyRing = keyRing;
this.filterManager = filterManager;
this.accountAgeWitnessService = accountAgeWitnessService;
this.openOfferManager = openOfferManager;
}
@Override

View File

@ -58,6 +58,10 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
MoneroTxWallet reserveTx = null;
synchronized (XmrWalletService.WALLET_LOCK) {
// reset protocol timeout
verifyOpen();
model.getProtocol().startTimeoutTimer();
// collect relevant info
BigInteger penaltyFee = HavenoUtils.multiply(offer.getAmount(), offer.getPenaltyFeePct());
BigInteger makerFee = offer.getMaxMakerFee();
@ -71,6 +75,7 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
synchronized (HavenoUtils.getWalletFunctionLock()) {
for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) {
try {
//if (true) throw new RuntimeException("Pretend error");
reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, openOffer.isReserveExactAmount(), preferredSubaddressIndex);
} catch (Exception e) {
log.warn("Error creating reserve tx, attempt={}/{}, offerId={}, error={}", i + 1, TradeProtocol.MAX_ATTEMPTS, openOffer.getShortId(), e.getMessage());
@ -78,10 +83,8 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
}
// check for error in case creating reserve tx exceeded timeout // TODO: better way?
if (!model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).isPresent()) {
throw new RuntimeException("An error has occurred posting offer " + offer.getId() + " causing its subaddress entry to be deleted");
}
// verify still open
verifyOpen();
if (reserveTx != null) break;
}
}
@ -108,4 +111,12 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
failed(t);
}
}
public void verifyOpen() {
if (!isOpen()) throw new RuntimeException("Offer " + model.getOpenOffer().getOffer().getId() + " is no longer open");
}
public boolean isOpen() {
return model.getOpenOfferManager().getOpenOfferById(model.getOpenOffer().getId()).isPresent();
}
}

View File

@ -359,7 +359,7 @@ public abstract class Trade implements Tradable, Model {
private long takeOfferDate;
// Initialization
private static final int TOTAL_INIT_STEPS = 15; // total estimated steps
private static final int TOTAL_INIT_STEPS = 23; // total estimated steps
private int initStep = 0;
@Getter
private double initProgress = 0;
@ -1537,10 +1537,15 @@ public abstract class Trade implements Tradable, Model {
}
public void addInitProgressStep() {
startProtocolTimeout();
initProgress = Math.min(1.0, (double) ++initStep / TOTAL_INIT_STEPS);
UserThread.execute(() -> initProgressProperty.set(initProgress));
}
public void startProtocolTimeout() {
getProtocol().startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS);
}
public void setState(State state) {
if (isInitialized) {
// We don't want to log at startup the setState calls from all persisted trades

View File

@ -869,7 +869,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
trade.getMaker().setPubKeyRing(trade.getOffer().getPubKeyRing());
trade.getSelf().setPubKeyRing(model.getPubKeyRing());
trade.getSelf().setPaymentAccountId(paymentAccountId);
trade.addInitProgressStep();
// ensure trade is not already open
Optional<Trade> tradeOptional = getOpenTrade(offer.getId());
@ -880,6 +879,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
addTrade(trade);
initTradeAndProtocol(trade, tradeProtocol);
trade.addInitProgressStep();
// process with protocol
((TakerProtocol) tradeProtocol).onTakeOffer(result -> {

View File

@ -59,7 +59,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
ArbitratorSendInitTradeOrMultisigRequests.class)
.using(new TradeTaskRunner(trade,
() -> {
startTimeout(TRADE_STEP_TIMEOUT_SECONDS);
startTimeout();
handleTaskRunnerSuccess(peer, message);
},
errorMessage -> {

View File

@ -74,7 +74,7 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol
MakerSendInitTradeRequest.class)
.using(new TradeTaskRunner(trade,
() -> {
startTimeout(TRADE_STEP_TIMEOUT_SECONDS);
startTimeout();
handleTaskRunnerSuccess(peer, message);
},
errorMessage -> {

View File

@ -79,7 +79,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol
TakerSendInitTradeRequestToArbitrator.class)
.using(new TradeTaskRunner(trade,
() -> {
startTimeout(TRADE_STEP_TIMEOUT_SECONDS);
startTimeout();
unlatchTrade();
},
errorMessage -> {

View File

@ -79,7 +79,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc
MakerSendInitTradeRequest.class)
.using(new TradeTaskRunner(trade,
() -> {
startTimeout(TRADE_STEP_TIMEOUT_SECONDS);
startTimeout();
handleTaskRunnerSuccess(peer, message);
},
errorMessage -> {

View File

@ -80,7 +80,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc
TakerSendInitTradeRequestToArbitrator.class)
.using(new TradeTaskRunner(trade,
() -> {
startTimeout(TRADE_STEP_TIMEOUT_SECONDS);
startTimeout();
unlatchTrade();
},
errorMessage -> {

View File

@ -299,6 +299,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) {
System.out.println(getClass().getSimpleName() + ".handleInitMultisigRequest()");
trade.addInitProgressStep();
ThreadUtils.execute(() -> {
synchronized (trade) {
@ -320,7 +321,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
MaybeSendSignContractRequest.class)
.using(new TradeTaskRunner(trade,
() -> {
startTimeout(TRADE_STEP_TIMEOUT_SECONDS);
startTimeout();
handleTaskRunnerSuccess(sender, request);
},
errorMessage -> {
@ -335,6 +336,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) {
System.out.println(getClass().getSimpleName() + ".handleSignContractRequest() " + trade.getId());
trade.addInitProgressStep();
ThreadUtils.execute(() -> {
synchronized (trade) {
@ -358,7 +360,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
ProcessSignContractRequest.class)
.using(new TradeTaskRunner(trade,
() -> {
startTimeout(TRADE_STEP_TIMEOUT_SECONDS);
startTimeout();
handleTaskRunnerSuccess(sender, message);
},
errorMessage -> {
@ -380,6 +382,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) {
System.out.println(getClass().getSimpleName() + ".handleSignContractResponse() " + trade.getId());
trade.addInitProgressStep();
ThreadUtils.execute(() -> {
synchronized (trade) {
@ -403,7 +406,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
SendDepositRequest.class)
.using(new TradeTaskRunner(trade,
() -> {
startTimeout(TRADE_STEP_TIMEOUT_SECONDS);
startTimeout();
handleTaskRunnerSuccess(sender, message);
},
errorMessage -> {
@ -425,6 +428,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
public void handleDepositResponse(DepositResponse response, NodeAddress sender) {
System.out.println(getClass().getSimpleName() + ".handleDepositResponse()");
trade.addInitProgressStep();
ThreadUtils.execute(() -> {
synchronized (trade) {
Validator.checkTradeId(processModel.getOfferId(), response);
@ -716,6 +720,10 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
// Timeout
///////////////////////////////////////////////////////////////////////////////////////////
public synchronized void startTimeout() {
startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS);
}
public synchronized void startTimeout(long timeoutSec) {
synchronized (timeoutTimerLock) {
stopTimeout();

View File

@ -28,7 +28,6 @@ import haveno.core.trade.Trade;
import haveno.core.trade.messages.DepositRequest;
import haveno.core.trade.messages.DepositResponse;
import haveno.core.trade.protocol.TradePeer;
import haveno.core.trade.protocol.TradeProtocol;
import haveno.network.p2p.NodeAddress;
import haveno.network.p2p.SendDirectMessageListener;
import lombok.extern.slf4j.Slf4j;
@ -104,7 +103,7 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
// extend timeout
if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while verifying deposit tx for {} {}" + trade.getClass().getSimpleName() + " " + trade.getShortId());
trade.getProtocol().startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS);
trade.startProtocolTimeout();
// set deposit info
trader.setSecurityDeposit(securityDeposit.subtract(verifiedTx.getFee())); // subtract mining fee from security deposit

View File

@ -83,7 +83,8 @@ public class MaybeSendSignContractRequest extends TradeTask {
synchronized (XmrWalletService.WALLET_LOCK) {
// check for timeout
if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while creating deposit tx, tradeId=" + trade.getShortId());
if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while getting lock to create deposit tx, tradeId=" + trade.getShortId());
trade.startProtocolTimeout();
// collect relevant info
Integer subaddressIndex = null;
@ -126,7 +127,7 @@ public class MaybeSendSignContractRequest extends TradeTask {
}
// reset protocol timeout
trade.getProtocol().startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS);
trade.addInitProgressStep();
// collect reserved key images
List<String> reservedKeyImages = new ArrayList<String>();

View File

@ -23,7 +23,6 @@ import java.math.BigInteger;
import haveno.common.taskrunner.TaskRunner;
import haveno.core.trade.Trade;
import haveno.core.trade.messages.DepositResponse;
import haveno.core.trade.protocol.TradeProtocol;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@ -47,16 +46,12 @@ public class ProcessDepositResponse extends TradeTask {
throw new RuntimeException(message.getErrorMessage());
}
// reset protocol timeout
trade.getProtocol().startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS);
// record security deposits
trade.getBuyer().setSecurityDeposit(BigInteger.valueOf(message.getBuyerSecurityDeposit()));
trade.getSeller().setSecurityDeposit(BigInteger.valueOf(message.getSellerSecurityDeposit()));
// set success state
trade.setStateIfValidTransitionTo(Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS);
trade.addInitProgressStep();
processModel.getTradeManager().requestPersistence();
// update balances

View File

@ -81,7 +81,6 @@ public class ProcessInitMultisigRequest extends TradeTask {
// prepare multisig if applicable
boolean updateParticipants = false;
if (trade.getSelf().getPreparedMultisigHex() == null) {
trade.addInitProgressStep();
log.info("Preparing multisig wallet for {} {}", trade.getClass().getSimpleName(), trade.getId());
multisigWallet = trade.createWallet();
trade.getSelf().setPreparedMultisigHex(multisigWallet.prepareMultisig());

View File

@ -89,7 +89,6 @@ public class SendDepositRequest extends TradeTask {
// update trade state
trade.setState(Trade.State.SENT_PUBLISH_DEPOSIT_TX_REQUEST);
processModel.getTradeManager().requestPersistence();
trade.addInitProgressStep();
// send request to arbitrator
log.info("Sending {} to arbitrator {}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getArbitrator().getNodeAddress(), trade.getId(), request.getUid());
@ -99,6 +98,7 @@ public class SendDepositRequest extends TradeTask {
log.info("{} arrived: arbitrator={}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getArbitrator().getNodeAddress(), trade.getId(), request.getUid());
trade.setStateIfValidTransitionTo(Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST);
processModel.getTradeManager().requestPersistence();
trade.addInitProgressStep();
complete();
}
@Override

View File

@ -49,7 +49,8 @@ public class TakerReserveTradeFunds extends TradeTask {
synchronized (XmrWalletService.WALLET_LOCK) {
// check for timeout
if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while creating reserve tx, tradeId=" + trade.getShortId());
if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while getting lock to create reserve tx, tradeId=" + trade.getShortId());
trade.startProtocolTimeout();
// collect relevant info
BigInteger penaltyFee = HavenoUtils.multiply(trade.getAmount(), trade.getOffer().getPenaltyFeePct());
@ -76,7 +77,7 @@ public class TakerReserveTradeFunds extends TradeTask {
}
// reset protocol timeout
trade.getProtocol().startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS);
trade.startProtocolTimeout();
// collect reserved key images
List<String> reservedKeyImages = new ArrayList<String>();

View File

@ -372,12 +372,6 @@ public class XmrWalletService {
return useNativeXmrWallet && MoneroUtils.isNativeLibraryLoaded();
}
public MoneroSyncResult syncWallet() {
MoneroSyncResult result = syncWallet(wallet);
walletHeight.set(wallet.getHeight());
return result;
}
/**
* Sync the given wallet in a thread pool with other wallets.
*/
@ -1799,7 +1793,7 @@ public class XmrWalletService {
// sync wallet if behind daemon
if (walletHeight.get() < xmrConnectionService.getTargetHeight()) {
synchronized (WALLET_LOCK) { // avoid long sync from blocking other operations
syncWallet();
syncMainWallet();
}
}
@ -1833,6 +1827,14 @@ public class XmrWalletService {
}
}
private MoneroSyncResult syncMainWallet() {
synchronized (WALLET_LOCK) {
MoneroSyncResult result = syncWallet(wallet);
walletHeight.set(wallet.getHeight());
return result;
}
}
public boolean isWalletConnectedToDaemon() {
synchronized (WALLET_LOCK) {
try {