mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-10-01 01:35:48 -04:00
refactor wallet poll loops to further minimize requests
This commit is contained in:
parent
5c0d9a1ae5
commit
9d9635ff50
@ -268,7 +268,7 @@ public final class XmrConnectionService {
|
||||
}
|
||||
|
||||
public Long getTargetHeight() {
|
||||
if (daemon == null || lastInfo == null) return null;
|
||||
if (lastInfo == null) return null;
|
||||
return lastInfo.getTargetHeight() == 0 ? chainHeight.get() : lastInfo.getTargetHeight(); // monerod sync_info's target_height returns 0 when node is fully synced
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ public abstract class SupportManager {
|
||||
for (Dispute dispute : trade.getDisputes()) {
|
||||
for (ChatMessage chatMessage : dispute.getChatMessages()) {
|
||||
if (chatMessage.getUid().equals(ackMessage.getSourceUid())) {
|
||||
if (dispute.isClosed()) trade.syncWalletNormallyForMs(30000); // sync to check for payout
|
||||
if (dispute.isClosed()) trade.pollWalletNormallyForMs(30000); // sync to check for payout
|
||||
else trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
||||
}
|
||||
}
|
||||
|
@ -792,7 +792,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||
// the state, as that is displayed to the user and we only persist that msg
|
||||
disputeResult.getChatMessage().setArrived(true);
|
||||
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG);
|
||||
trade.syncWalletNormallyForMs(30000);
|
||||
trade.pollWalletNormallyForMs(30000);
|
||||
requestPersistence();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ import com.google.protobuf.Message;
|
||||
import common.utils.GenUtils;
|
||||
import haveno.common.ThreadUtils;
|
||||
import haveno.common.UserThread;
|
||||
import haveno.common.config.Config;
|
||||
import haveno.common.crypto.Encryption;
|
||||
import haveno.common.crypto.PubKeyRing;
|
||||
import haveno.common.proto.ProtoUtil;
|
||||
@ -91,7 +90,6 @@ import monero.common.MoneroError;
|
||||
import monero.common.MoneroRpcConnection;
|
||||
import monero.common.TaskLooper;
|
||||
import monero.daemon.MoneroDaemon;
|
||||
import monero.daemon.model.MoneroDaemonInfo;
|
||||
import monero.daemon.model.MoneroKeyImage;
|
||||
import monero.daemon.model.MoneroTx;
|
||||
import monero.wallet.MoneroWallet;
|
||||
@ -137,6 +135,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
private static final String MONERO_TRADE_WALLET_PREFIX = "xmr_trade_";
|
||||
private static final long SHUTDOWN_TIMEOUT_MS = 60000;
|
||||
private static final long DELETE_BACKUPS_AFTER_NUM_BLOCKS = 3600; // ~5 days
|
||||
private static final long SYNC_EVERY_NUM_BLOCKS = 360; // ~1/2 day
|
||||
private final Object walletLock = new Object();
|
||||
private final Object pollLock = new Object();
|
||||
private MoneroWallet wallet;
|
||||
@ -414,8 +413,8 @@ public abstract class Trade implements Tradable, Model {
|
||||
transient private Subscription tradePhaseSubscription;
|
||||
transient private Subscription payoutStateSubscription;
|
||||
transient private TaskLooper pollLooper;
|
||||
transient private Long walletRefreshPeriodMs;
|
||||
transient private Long syncNormalStartTimeMs;
|
||||
transient private Long pollPeriodMs;
|
||||
transient private Long pollNormalStartTimeMs;
|
||||
|
||||
public static final long DEFER_PUBLISH_MS = 25000; // 25 seconds
|
||||
private static final long IDLE_SYNC_PERIOD_MS = 1680000; // 28 minutes (monero's default connection timeout is 30 minutes on a local connection, so beyond this the wallets will disconnect)
|
||||
@ -638,7 +637,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
if (!isInitialized || isShutDownStarted) return;
|
||||
ThreadUtils.execute(() -> {
|
||||
if (newValue == Trade.State.MULTISIG_COMPLETED) {
|
||||
updateWalletRefreshPeriod();
|
||||
updatePollPeriod();
|
||||
startPolling();
|
||||
}
|
||||
}, getId());
|
||||
@ -648,7 +647,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
tradePhaseSubscription = EasyBind.subscribe(phaseProperty, newValue -> {
|
||||
if (!isInitialized || isShutDownStarted) return;
|
||||
ThreadUtils.execute(() -> {
|
||||
if (isDepositsPublished() && !isPayoutUnlocked()) updateWalletRefreshPeriod();
|
||||
if (isDepositsPublished() && !isPayoutUnlocked()) updatePollPeriod();
|
||||
if (isPaymentReceived()) {
|
||||
UserThread.execute(() -> {
|
||||
if (tradePhaseSubscription != null) {
|
||||
@ -664,7 +663,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
payoutStateSubscription = EasyBind.subscribe(payoutStateProperty, newValue -> {
|
||||
if (!isInitialized || isShutDownStarted) return;
|
||||
ThreadUtils.execute(() -> {
|
||||
if (isPayoutPublished()) updateWalletRefreshPeriod();
|
||||
if (isPayoutPublished()) updatePollPeriod();
|
||||
|
||||
// handle when payout published
|
||||
if (newValue == Trade.PayoutState.PAYOUT_PUBLISHED) {
|
||||
@ -724,7 +723,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
if (walletExists()) getWallet();
|
||||
else {
|
||||
MoneroTx payoutTx = getPayoutTx();
|
||||
if (payoutTx != null && payoutTx.getNumConfirmations() >= 10) {
|
||||
if (payoutTx != null && payoutTx.getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK) {
|
||||
log.warn("Payout state for {} {} is {} but payout is unlocked, updating state", getClass().getSimpleName(), getId(), getPayoutState());
|
||||
setPayoutStateUnlocked();
|
||||
return;
|
||||
@ -734,7 +733,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
}
|
||||
|
||||
// initialize syncing and polling
|
||||
tryInitSyncing();
|
||||
tryInitPolling();
|
||||
}
|
||||
|
||||
public void requestPersistence() {
|
||||
@ -820,7 +819,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
}
|
||||
|
||||
public boolean isIdling() {
|
||||
return this instanceof ArbitratorTrade && isDepositsConfirmed() && walletExists() && syncNormalStartTimeMs == null; // arbitrator idles trade after deposits confirm unless overriden
|
||||
return this instanceof ArbitratorTrade && isDepositsConfirmed() && walletExists() && pollNormalStartTimeMs == null; // arbitrator idles trade after deposits confirm unless overriden
|
||||
}
|
||||
|
||||
public boolean isSyncedWithinTolerance() {
|
||||
@ -838,40 +837,38 @@ public abstract class Trade implements Tradable, Model {
|
||||
syncWallet(true);
|
||||
}
|
||||
|
||||
public void syncWalletNormallyForMs(long syncNormalDuration) {
|
||||
syncNormalStartTimeMs = System.currentTimeMillis();
|
||||
public void pollWalletNormallyForMs(long pollNormalDuration) {
|
||||
pollNormalStartTimeMs = System.currentTimeMillis();
|
||||
|
||||
// override wallet refresh period
|
||||
setWalletRefreshPeriod(xmrConnectionService.getRefreshPeriodMs());
|
||||
// override wallet poll period
|
||||
setPollPeriod(xmrConnectionService.getRefreshPeriodMs());
|
||||
|
||||
// reset wallet refresh period after duration
|
||||
// reset wallet poll period after duration
|
||||
new Thread(() -> {
|
||||
GenUtils.waitFor(syncNormalDuration);
|
||||
Long syncNormalStartTimeMsCopy = syncNormalStartTimeMs; // copy to avoid race condition
|
||||
if (syncNormalStartTimeMsCopy == null) return;
|
||||
if (!isShutDown && System.currentTimeMillis() >= syncNormalStartTimeMsCopy + syncNormalDuration) {
|
||||
syncNormalStartTimeMs = null;
|
||||
updateWalletRefreshPeriod();
|
||||
GenUtils.waitFor(pollNormalDuration);
|
||||
Long pollNormalStartTimeMsCopy = pollNormalStartTimeMs; // copy to avoid race condition
|
||||
if (pollNormalStartTimeMsCopy == null) return;
|
||||
if (!isShutDown && System.currentTimeMillis() >= pollNormalStartTimeMsCopy + pollNormalDuration) {
|
||||
pollNormalStartTimeMs = null;
|
||||
updatePollPeriod();
|
||||
}
|
||||
}).start();
|
||||
|
||||
// TODO: sync wallet because `auto_refresh` will not sync wallet until end of last sync period (which could be a long idle)
|
||||
new Thread(() -> {
|
||||
GenUtils.waitFor(1000);
|
||||
if (!isShutDownStarted) trySyncWallet(true);
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void importMultisigHex() {
|
||||
synchronized (walletLock) {
|
||||
|
||||
// ensure wallet sees deposits confirmed
|
||||
if (!isDepositsConfirmed()) syncAndPollWallet();
|
||||
|
||||
// import multisig hexes
|
||||
List<String> multisigHexes = new ArrayList<String>();
|
||||
if (getBuyer().getUpdatedMultisigHex() != null) multisigHexes.add(getBuyer().getUpdatedMultisigHex());
|
||||
if (getSeller().getUpdatedMultisigHex() != null) multisigHexes.add(getSeller().getUpdatedMultisigHex());
|
||||
if (getArbitrator().getUpdatedMultisigHex() != null) multisigHexes.add(getArbitrator().getUpdatedMultisigHex());
|
||||
for (TradePeer node : getAllTradeParties()) if (node.getUpdatedMultisigHex() != null) multisigHexes.add(node.getUpdatedMultisigHex());
|
||||
if (!multisigHexes.isEmpty()) {
|
||||
log.info("Importing multisig hex for {} {}", getClass().getSimpleName(), getId());
|
||||
long startTime = System.currentTimeMillis();
|
||||
getWallet().importMultisigHex(multisigHexes.toArray(new String[0]));
|
||||
log.info("Done importing multisig hex for {} {}", getClass().getSimpleName(), getId());
|
||||
log.info("Done importing multisig hex for {} {} in {} ms", getClass().getSimpleName(), getId(), System.currentTimeMillis() - startTime);
|
||||
}
|
||||
requestSaveWallet();
|
||||
}
|
||||
@ -917,7 +914,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
stopPolling();
|
||||
xmrWalletService.closeWallet(wallet, true);
|
||||
wallet = null;
|
||||
walletRefreshPeriodMs = null;
|
||||
pollPeriodMs = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2014,26 +2011,25 @@ public abstract class Trade implements Tradable, Model {
|
||||
|
||||
// sync and reprocess messages on new thread
|
||||
if (isInitialized && connection != null && !Boolean.FALSE.equals(connection.isConnected())) {
|
||||
ThreadUtils.execute(() -> tryInitSyncing(), getId());
|
||||
ThreadUtils.execute(() -> tryInitPolling(), getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void tryInitSyncing() {
|
||||
private void tryInitPolling() {
|
||||
if (isShutDownStarted) return;
|
||||
if (!isIdling()) {
|
||||
initSyncingAux();
|
||||
tryInitPollingAux();
|
||||
} else {
|
||||
long startSyncingInMs = ThreadLocalRandom.current().nextLong(0, getWalletRefreshPeriod()); // random time to start syncing
|
||||
long startSyncingInMs = ThreadLocalRandom.current().nextLong(0, getPollPeriod()); // random time to start polling
|
||||
UserThread.runAfter(() -> ThreadUtils.execute(() -> {
|
||||
if (!isShutDownStarted) initSyncingAux();
|
||||
if (!isShutDownStarted) tryInitPollingAux();
|
||||
}, getId()), startSyncingInMs / 1000l);
|
||||
}
|
||||
}
|
||||
|
||||
private void initSyncingAux() {
|
||||
private void tryInitPollingAux() {
|
||||
if (!wasWalletSynced) trySyncWallet(false);
|
||||
updateWalletRefreshPeriod();
|
||||
updatePollPeriod();
|
||||
|
||||
// reprocess pending payout messages
|
||||
this.getProtocol().maybeReprocessPaymentReceivedMessage(false);
|
||||
@ -2070,20 +2066,16 @@ public abstract class Trade implements Tradable, Model {
|
||||
if (pollWallet) pollWallet();
|
||||
}
|
||||
|
||||
public void updateWalletRefreshPeriod() {
|
||||
public void updatePollPeriod() {
|
||||
if (isShutDownStarted) return;
|
||||
setWalletRefreshPeriod(getWalletRefreshPeriod());
|
||||
setPollPeriod(getPollPeriod());
|
||||
}
|
||||
|
||||
private void setWalletRefreshPeriod(long walletRefreshPeriodMs) {
|
||||
private void setPollPeriod(long pollPeriodMs) {
|
||||
synchronized (walletLock) {
|
||||
if (this.isShutDownStarted) return;
|
||||
if (this.walletRefreshPeriodMs != null && this.walletRefreshPeriodMs == walletRefreshPeriodMs) return;
|
||||
this.walletRefreshPeriodMs = walletRefreshPeriodMs;
|
||||
if (getWallet() != null) {
|
||||
log.info("Setting wallet refresh rate for {} {} to {}", getClass().getSimpleName(), getId(), getWalletRefreshPeriod());
|
||||
getWallet().startSyncing(getWalletRefreshPeriod()); // TODO (monero-project): wallet rpc waits until last sync period finishes before starting new sync period
|
||||
}
|
||||
if (this.pollPeriodMs != null && this.pollPeriodMs == pollPeriodMs) return;
|
||||
this.pollPeriodMs = pollPeriodMs;
|
||||
if (isPollInProgress()) {
|
||||
stopPolling();
|
||||
startPolling();
|
||||
@ -2091,12 +2083,17 @@ public abstract class Trade implements Tradable, Model {
|
||||
}
|
||||
}
|
||||
|
||||
private long getPollPeriod() {
|
||||
if (isIdling()) return IDLE_SYNC_PERIOD_MS;
|
||||
return xmrConnectionService.getRefreshPeriodMs();
|
||||
}
|
||||
|
||||
private void startPolling() {
|
||||
synchronized (walletLock) {
|
||||
if (isShutDownStarted || isPollInProgress()) return;
|
||||
log.info("Starting to poll wallet for {} {}", getClass().getSimpleName(), getId());
|
||||
pollLooper = new TaskLooper(() -> pollWallet());
|
||||
pollLooper.start(walletRefreshPeriodMs);
|
||||
pollLooper.start(pollPeriodMs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2121,22 +2118,56 @@ public abstract class Trade implements Tradable, Model {
|
||||
pollInProgress = true;
|
||||
try {
|
||||
|
||||
// log warning if wallet is too far behind daemon
|
||||
MoneroDaemonInfo lastInfo = xmrConnectionService.getLastInfo();
|
||||
long walletHeight = wallet.getHeight();
|
||||
int maxBlocksBehindWarning = 10;
|
||||
if (wasWalletSynced && isDepositsPublished() && !isIdling() && lastInfo != null && walletHeight < lastInfo.getHeight() - maxBlocksBehindWarning && !Config.baseCurrencyNetwork().isTestnet()) {
|
||||
log.warn("Wallet is more than {} blocks behind monerod for {} {}, wallet height={}, monerod height={},", maxBlocksBehindWarning, getClass().getSimpleName(), getShortId(), walletHeight, lastInfo.getHeight());
|
||||
}
|
||||
// skip if payout unlocked
|
||||
if (isPayoutUnlocked()) return;
|
||||
|
||||
// skip if either deposit tx id is unknown
|
||||
if (processModel.getMaker().getDepositTxHash() == null || processModel.getTaker().getDepositTxHash() == null) return;
|
||||
|
||||
// skip if payout unlocked
|
||||
if (isPayoutUnlocked()) return;
|
||||
// sync if wallet too far behind daemon
|
||||
if (xmrConnectionService.getTargetHeight() == null) return;
|
||||
if (wallet.getHeight() < xmrConnectionService.getTargetHeight() - SYNC_EVERY_NUM_BLOCKS) syncWallet(false);
|
||||
|
||||
// rescan spent outputs to detect unconfirmed payout tx after payment received message
|
||||
if (!isPayoutPublished() && (hasPaymentReceivedMessage() || hasDisputeClosedMessage())) {
|
||||
// update deposit txs
|
||||
if (!isDepositsUnlocked()) {
|
||||
|
||||
// sync wallet if behind
|
||||
syncWalletIfBehind();
|
||||
|
||||
// get txs from trade wallet
|
||||
List<MoneroTxWallet> txs = wallet.getTxs(new MoneroTxQuery().setIncludeOutputs(true).setInTxPool(false)); // TODO (monero-wallet-rpc): cannot get pool txs without re-refetching from pool
|
||||
setDepositTxs(txs);
|
||||
if (txs.size() != 2) return; // skip if either tx not seen
|
||||
setStateDepositsSeen();
|
||||
|
||||
// set actual security deposits
|
||||
if (getBuyer().getSecurityDeposit().longValueExact() == 0) {
|
||||
BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount();
|
||||
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount());
|
||||
getBuyer().setSecurityDeposit(buyerSecurityDeposit);
|
||||
getSeller().setSecurityDeposit(sellerSecurityDeposit);
|
||||
}
|
||||
|
||||
// check for deposit txs confirmation
|
||||
if (getMaker().getDepositTx().isConfirmed() && getTaker().getDepositTx().isConfirmed()) setStateDepositsConfirmed();
|
||||
|
||||
// check for deposit txs unlocked
|
||||
if (getMaker().getDepositTx().getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK && getTaker().getDepositTx().getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK) {
|
||||
setStateDepositsUnlocked();
|
||||
}
|
||||
}
|
||||
|
||||
// check for payout tx
|
||||
if (isDepositsUnlocked()) {
|
||||
|
||||
// determine if payout tx expected
|
||||
boolean isPayoutExpected = isPaymentReceived() || hasPaymentReceivedMessage() || hasDisputeClosedMessage() || disputeState.ordinal() >= DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal();
|
||||
|
||||
// sync wallet if payout expected or payout is published
|
||||
if (isPayoutExpected || isPayoutPublished()) syncWalletIfBehind();
|
||||
|
||||
// rescan spent outputs to detect unconfirmed payout tx
|
||||
if (isPayoutExpected && !isPayoutPublished()) {
|
||||
try {
|
||||
wallet.rescanSpent();
|
||||
} catch (Exception e) {
|
||||
@ -2145,56 +2176,16 @@ public abstract class Trade implements Tradable, Model {
|
||||
}
|
||||
|
||||
// get txs from trade wallet
|
||||
boolean payoutExpected = isPaymentReceived() || getSeller().getPaymentReceivedMessage() != null || disputeState.ordinal() >= DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal() || getArbitrator().getDisputeClosedMessage() != null;
|
||||
boolean checkPool = !isDepositsConfirmed() || (!isPayoutConfirmed() && payoutExpected);
|
||||
boolean checkPool = isPayoutExpected && !isPayoutConfirmed();
|
||||
MoneroTxQuery query = new MoneroTxQuery().setIncludeOutputs(true);
|
||||
if (!checkPool) query.setInTxPool(false); // avoid pool check if possible
|
||||
List<MoneroTxWallet> txs = wallet.getTxs(query);
|
||||
|
||||
// warn on double spend // TODO: other handling?
|
||||
for (MoneroTxWallet tx : txs) {
|
||||
if (Boolean.TRUE.equals(tx.isDoubleSpendSeen())) log.warn("Double spend seen for tx {} for {} {}", tx.getHash(), getClass().getSimpleName(), getShortId());
|
||||
}
|
||||
|
||||
// check deposit txs
|
||||
if (!isDepositsUnlocked()) {
|
||||
|
||||
// update trader txs
|
||||
MoneroTxWallet makerDepositTx = null;
|
||||
MoneroTxWallet takerDepositTx = null;
|
||||
for (MoneroTxWallet tx : txs) {
|
||||
if (tx.getHash().equals(processModel.getMaker().getDepositTxHash())) makerDepositTx = tx;
|
||||
if (tx.getHash().equals(processModel.getTaker().getDepositTxHash())) takerDepositTx = tx;
|
||||
}
|
||||
if (makerDepositTx != null) getMaker().setDepositTx(makerDepositTx);
|
||||
if (takerDepositTx != null) getTaker().setDepositTx(takerDepositTx);
|
||||
|
||||
// skip if deposit txs not seen
|
||||
if (makerDepositTx == null || takerDepositTx == null) return;
|
||||
|
||||
// set security deposits
|
||||
if (getBuyer().getSecurityDeposit().longValueExact() == 0) {
|
||||
BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount();
|
||||
BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount());
|
||||
getBuyer().setSecurityDeposit(buyerSecurityDeposit);
|
||||
getSeller().setSecurityDeposit(sellerSecurityDeposit);
|
||||
}
|
||||
|
||||
// update state
|
||||
setStateDepositsPublished();
|
||||
if (makerDepositTx.isConfirmed() && takerDepositTx.isConfirmed()) setStateDepositsConfirmed();
|
||||
if (!makerDepositTx.isLocked() && !takerDepositTx.isLocked()) setStateDepositsUnlocked();
|
||||
}
|
||||
|
||||
// check payout tx
|
||||
if (isDepositsUnlocked()) {
|
||||
setDepositTxs(txs);
|
||||
|
||||
// check if any outputs spent (observed on payout published)
|
||||
for (MoneroTxWallet tx : txs) {
|
||||
for (MoneroOutputWallet output : tx.getOutputsWallet()) {
|
||||
if (Boolean.TRUE.equals(output.isSpent())) {
|
||||
setPayoutStatePublished();
|
||||
}
|
||||
if (Boolean.TRUE.equals(output.isSpent())) setPayoutStatePublished();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2224,6 +2215,17 @@ public abstract class Trade implements Tradable, Model {
|
||||
}
|
||||
}
|
||||
|
||||
private void syncWalletIfBehind() {
|
||||
if (wallet.getHeight() < xmrConnectionService.getTargetHeight()) syncWallet(false);
|
||||
}
|
||||
|
||||
private void setDepositTxs(List<? extends MoneroTx> txs) {
|
||||
for (MoneroTx tx : txs) {
|
||||
if (tx.getHash().equals(getMaker().getDepositTxHash())) getMaker().setDepositTx(tx);
|
||||
if (tx.getHash().equals(getTaker().getDepositTxHash())) getTaker().setDepositTx(tx);
|
||||
}
|
||||
}
|
||||
|
||||
private void forceRestartTradeWallet() {
|
||||
log.warn("Force restarting trade wallet for {} {}", getClass().getSimpleName(), getId());
|
||||
if (isShutDownStarted || restartInProgress) return;
|
||||
@ -2231,15 +2233,10 @@ public abstract class Trade implements Tradable, Model {
|
||||
forceCloseWallet();
|
||||
if (!isShutDownStarted) wallet = getWallet();
|
||||
restartInProgress = false;
|
||||
if (!isShutDownStarted) ThreadUtils.execute(() -> tryInitSyncing(), getId());
|
||||
if (!isShutDownStarted) ThreadUtils.execute(() -> tryInitPolling(), getId());
|
||||
}
|
||||
|
||||
private long getWalletRefreshPeriod() {
|
||||
if (isIdling()) return IDLE_SYNC_PERIOD_MS;
|
||||
return xmrConnectionService.getRefreshPeriodMs();
|
||||
}
|
||||
|
||||
private void setStateDepositsPublished() {
|
||||
private void setStateDepositsSeen() {
|
||||
if (!isDepositsPublished()) setState(State.DEPOSIT_TXS_SEEN_IN_NETWORK);
|
||||
}
|
||||
|
||||
|
@ -458,8 +458,8 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||
}, trade.getId());
|
||||
}
|
||||
|
||||
public void handle(DepositsConfirmedMessage response, NodeAddress sender) {
|
||||
System.out.println(getClass().getSimpleName() + ".handle(DepositsConfirmedMessage)");
|
||||
public void handle(DepositsConfirmedMessage message, NodeAddress sender) {
|
||||
System.out.println(getClass().getSimpleName() + ".handle(DepositsConfirmedMessage) from " + sender);
|
||||
if (!trade.isInitialized() || trade.isShutDown()) return;
|
||||
ThreadUtils.execute(() -> {
|
||||
synchronized (trade) {
|
||||
@ -467,7 +467,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||
latchTrade();
|
||||
this.errorMessageHandler = null;
|
||||
expect(new Condition(trade)
|
||||
.with(response)
|
||||
.with(message)
|
||||
.from(sender))
|
||||
.setup(tasks(
|
||||
ProcessDepositsConfirmedMessage.class,
|
||||
@ -475,10 +475,10 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||
MaybeResendDisputeClosedMessageWithPayout.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
handleTaskRunnerSuccess(sender, response);
|
||||
handleTaskRunnerSuccess(sender, message);
|
||||
},
|
||||
errorMessage -> {
|
||||
handleTaskRunnerFault(sender, response, errorMessage);
|
||||
handleTaskRunnerFault(sender, message, errorMessage);
|
||||
})))
|
||||
.executeTasks();
|
||||
awaitTradeLatch();
|
||||
|
@ -132,6 +132,7 @@ public class XmrWalletService {
|
||||
private static final boolean PRINT_STACK_TRACE = false;
|
||||
private static final String THREAD_ID = XmrWalletService.class.getSimpleName();
|
||||
private static final long SHUTDOWN_TIMEOUT_MS = 60000;
|
||||
private static final long NUM_BLOCKS_BEHIND_WARNING = 10;
|
||||
|
||||
private final User user;
|
||||
private final Preferences preferences;
|
||||
@ -165,7 +166,7 @@ public class XmrWalletService {
|
||||
// wallet polling and cache
|
||||
private TaskLooper pollLooper;
|
||||
private boolean pollInProgress;
|
||||
private Long walletRefreshPeriodMs;
|
||||
private Long pollPeriodMs;
|
||||
private final Object pollLock = new Object();
|
||||
private Long cachedHeight;
|
||||
private BigInteger cachedBalance;
|
||||
@ -1400,6 +1401,7 @@ public class XmrWalletService {
|
||||
});
|
||||
syncWithProgressLooper.start(1000);
|
||||
HavenoUtils.awaitLatch(syncWithProgressLatch);
|
||||
wallet.stopSyncing();
|
||||
if (!wasWalletSynced) throw new IllegalStateException("Failed to sync wallet with progress");
|
||||
}
|
||||
|
||||
@ -1441,7 +1443,7 @@ public class XmrWalletService {
|
||||
try {
|
||||
|
||||
// create wallet
|
||||
log.info("Creating full wallet " + config.getPath() + " connected to daemon " + connection.getUri());
|
||||
log.info("Creating full wallet " + config.getPath() + " connected to monerod=" + connection.getUri());
|
||||
long time = System.currentTimeMillis();
|
||||
config.setServer(connection);
|
||||
walletFull = MoneroWalletFull.createWallet(config);
|
||||
@ -1495,7 +1497,7 @@ public class XmrWalletService {
|
||||
walletRpc.stopSyncing();
|
||||
|
||||
// create wallet
|
||||
log.info("Creating RPC wallet " + config.getPath() + " connected to daemon " + connection.getUri());
|
||||
log.info("Creating RPC wallet " + config.getPath() + " connected to monerod=" + connection.getUri());
|
||||
long time = System.currentTimeMillis();
|
||||
config.setServer(connection);
|
||||
walletRpc.createWallet(config);
|
||||
@ -1602,9 +1604,8 @@ public class XmrWalletService {
|
||||
|
||||
// sync wallet on new thread
|
||||
if (connection != null && !isShutDownStarted) {
|
||||
updateWalletRefreshPeriod();
|
||||
wallet.getDaemonConnection().setPrintStackTrace(PRINT_STACK_TRACE);
|
||||
wallet.startSyncing(xmrConnectionService.getRefreshPeriodMs());
|
||||
updatePollPeriod();
|
||||
}
|
||||
|
||||
log.info("Done setting main wallet monerod=" + (wallet.getDaemonConnection() == null ? null : wallet.getDaemonConnection().getUri()));
|
||||
@ -1675,9 +1676,9 @@ public class XmrWalletService {
|
||||
synchronized (walletLock) {
|
||||
if (isShutDownStarted || isPollInProgress()) return;
|
||||
log.info("Starting to poll main wallet");
|
||||
updateWalletRefreshPeriod();
|
||||
updatePollPeriod();
|
||||
pollLooper = new TaskLooper(() -> pollWallet());
|
||||
pollLooper.start(walletRefreshPeriodMs);
|
||||
pollLooper.start(pollPeriodMs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1692,24 +1693,20 @@ public class XmrWalletService {
|
||||
return pollLooper != null;
|
||||
}
|
||||
|
||||
public void updateWalletRefreshPeriod() {
|
||||
public void updatePollPeriod() {
|
||||
if (isShutDownStarted) return;
|
||||
setWalletRefreshPeriod(getWalletRefreshPeriod());
|
||||
setPollPeriod(getPollPeriod());
|
||||
}
|
||||
|
||||
private long getWalletRefreshPeriod() {
|
||||
private long getPollPeriod() {
|
||||
return xmrConnectionService.getRefreshPeriodMs();
|
||||
}
|
||||
|
||||
private void setWalletRefreshPeriod(long walletRefreshPeriodMs) {
|
||||
private void setPollPeriod(long pollPeriodMs) {
|
||||
synchronized (walletLock) {
|
||||
if (this.isShutDownStarted) return;
|
||||
if (this.walletRefreshPeriodMs != null && this.walletRefreshPeriodMs == walletRefreshPeriodMs) return;
|
||||
this.walletRefreshPeriodMs = walletRefreshPeriodMs;
|
||||
if (getWallet() != null) {
|
||||
log.info("Setting main wallet refresh rate for to {}", getWalletRefreshPeriod());
|
||||
getWallet().startSyncing(getWalletRefreshPeriod()); // TODO (monero-project): wallet rpc waits until last sync period finishes before starting new sync period
|
||||
}
|
||||
if (this.pollPeriodMs != null && this.pollPeriodMs == pollPeriodMs) return;
|
||||
this.pollPeriodMs = pollPeriodMs;
|
||||
if (isPollInProgress()) {
|
||||
stopPolling();
|
||||
startPolling();
|
||||
@ -1718,24 +1715,31 @@ public class XmrWalletService {
|
||||
}
|
||||
|
||||
private void pollWallet() {
|
||||
if (pollInProgress) return;
|
||||
doPollWallet(true);
|
||||
}
|
||||
|
||||
private void doPollWallet(boolean updateTxs) {
|
||||
if (pollInProgress) return;
|
||||
synchronized (pollLock) {
|
||||
pollInProgress = true;
|
||||
try {
|
||||
|
||||
// log warning if wallet is too far behind daemon
|
||||
MoneroDaemonInfo lastInfo = xmrConnectionService.getLastInfo();
|
||||
if (lastInfo == null) {
|
||||
log.warn("Last daemon info is null");
|
||||
return;
|
||||
}
|
||||
long walletHeight = wallet.getHeight();
|
||||
int maxBlocksBehindWarning = 10;
|
||||
if (wasWalletSynced && lastInfo != null && walletHeight < lastInfo.getHeight() - maxBlocksBehindWarning && !Config.baseCurrencyNetwork().isTestnet()) {
|
||||
log.warn("Main wallet is more than {} blocks behind monerod, wallet height={}, monerod height={},", maxBlocksBehindWarning, walletHeight, lastInfo.getHeight());
|
||||
if (wasWalletSynced && walletHeight < xmrConnectionService.getTargetHeight() - NUM_BLOCKS_BEHIND_WARNING && !Config.baseCurrencyNetwork().isTestnet()) {
|
||||
log.warn("Main wallet is {} blocks behind monerod, wallet height={}, monerod height={},", xmrConnectionService.getTargetHeight() - walletHeight, walletHeight, lastInfo.getHeight());
|
||||
}
|
||||
|
||||
// fetch transactions from pool and cache
|
||||
// sync wallet if behind daemon
|
||||
if (wallet.getHeight() < xmrConnectionService.getTargetHeight()) wallet.sync();
|
||||
|
||||
// fetch transactions from pool and store to cache
|
||||
// TODO: ideally wallet should sync every poll and then avoid checking pool on fetching txs
|
||||
if (updateTxs) {
|
||||
try {
|
||||
cachedTxs = wallet.getTxs(new MoneroTxQuery().setIncludeOutputs(true));
|
||||
|
@ -131,7 +131,7 @@ public class TxIdTextField extends AnchorPane {
|
||||
txUpdater = new MoneroWalletListener() {
|
||||
@Override
|
||||
public void onNewBlock(long lastBlockHeight) {
|
||||
updateConfidence(txId, false, lastBlockHeight + 1);
|
||||
updateConfidence(txId, false, lastBlockHeight);
|
||||
}
|
||||
};
|
||||
xmrWalletService.addWalletListener(txUpdater);
|
||||
|
Loading…
Reference in New Issue
Block a user