cache txs fetched from daemon

This commit is contained in:
woodser 2022-08-15 01:50:05 -04:00
parent 54eee73c04
commit f9d700074a
3 changed files with 58 additions and 8 deletions

View File

@ -94,6 +94,7 @@ public class XmrWalletService {
private TradeManager tradeManager; private TradeManager tradeManager;
private MoneroWalletRpc wallet; private MoneroWalletRpc wallet;
private Map<String, MoneroWallet> multisigWallets; private Map<String, MoneroWallet> multisigWallets;
private final Map<String, Optional<MoneroTx>> txCache = new HashMap<String, Optional<MoneroTx>>();
@Inject @Inject
XmrWalletService(CoreAccountService accountService, XmrWalletService(CoreAccountService accountService,
@ -325,7 +326,7 @@ public class XmrWalletService {
// submit tx to pool // submit tx to pool
MoneroSubmitTxResult result = daemon.submitTxHex(txHex, true); // TODO (woodser): invert doNotRelay flag to relay for library consistency? MoneroSubmitTxResult result = daemon.submitTxHex(txHex, true); // TODO (woodser): invert doNotRelay flag to relay for library consistency?
if (!result.isGood()) throw new RuntimeException("Failed to submit tx to daemon: " + JsonUtils.serialize(result)); if (!result.isGood()) throw new RuntimeException("Failed to submit tx to daemon: " + JsonUtils.serialize(result));
tx = daemon.getTx(txHash); tx = getTx(txHash);
// verify reserved key images // verify reserved key images
if (keyImages != null) { if (keyImages != null) {
@ -346,7 +347,6 @@ public class XmrWalletService {
// verify mining fee // verify mining fee
BigInteger feeEstimate = getFeeEstimate(txHex); BigInteger feeEstimate = getFeeEstimate(txHex);
BigInteger feeThreshold = feeEstimate.multiply(BigInteger.valueOf(1l)).divide(BigInteger.valueOf(2l)); // must be at least 50% of estimated fee BigInteger feeThreshold = feeEstimate.multiply(BigInteger.valueOf(1l)).divide(BigInteger.valueOf(2l)); // must be at least 50% of estimated fee
tx = daemon.getTx(txHash);
if (tx.getFee().compareTo(feeThreshold) < 0) { if (tx.getFee().compareTo(feeThreshold) < 0) {
throw new RuntimeException("Mining fee is not enough, needed " + feeThreshold + " but was " + tx.getFee()); throw new RuntimeException("Mining fee is not enough, needed " + feeThreshold + " but was " + tx.getFee());
} }
@ -372,6 +372,55 @@ public class XmrWalletService {
return getDaemon().getFeeEstimate().multiply(BigInteger.valueOf(txHex.length())); return getDaemon().getFeeEstimate().multiply(BigInteger.valueOf(txHex.length()));
} }
public MoneroTx getTx(String txHash) {
synchronized (txCache) {
List<MoneroTx> txs = getTxs(Arrays.asList(txHash));
return txs.isEmpty() ? null : txs.get(0);
}
}
public List<MoneroTx> getTxs(List<String> txHashes) {
synchronized (txCache) {
// fetch txs
List<MoneroTx> txs = getDaemon().getTxs(txHashes, true);
// store to cache
for (MoneroTx tx : txs) txCache.put(tx.getHash(), Optional.of(tx));
// schedule txs to be removed from cache
UserThread.runAfter(() -> {
synchronized (txCache) {
for (MoneroTx tx : txs) txCache.remove(tx.getHash());
}
}, connectionsService.getDefaultRefreshPeriodMs());
return txs;
}
}
public MoneroTx getTxWithCache(String txHash) {
synchronized (txCache) {
List<MoneroTx> cachedTxs = getTxsWithCache(Arrays.asList(txHash));
return cachedTxs.isEmpty() ? null : cachedTxs.get(0);
}
}
public List<MoneroTx> getTxsWithCache(List<String> txHashes) {
synchronized (txCache) {
// get cached txs
List<MoneroTx> cachedTxs = new ArrayList<MoneroTx>();
List<String> uncachedTxHashes = new ArrayList<String>();
for (int i = 0; i < txHashes.size(); i++) {
if (txCache.containsKey(txHashes.get(i))) cachedTxs.add(txCache.get(txHashes.get(i)).orElse(null));
else uncachedTxHashes.add(txHashes.get(i));
}
// return txs from cache if available, otherwise fetch
return uncachedTxHashes.isEmpty() ? cachedTxs : getTxs(txHashes);
}
}
public void shutDown() { public void shutDown() {
closeAllWallets(); closeAllWallets();
} }

View File

@ -446,6 +446,7 @@ public abstract class Trade implements Tradable, Model {
transient Boolean takerDepositLocked; transient Boolean takerDepositLocked;
transient private MoneroTx makerDepositTx; transient private MoneroTx makerDepositTx;
transient private MoneroTx takerDepositTx; transient private MoneroTx takerDepositTx;
private Long startTime; // cache
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, initialization // Constructor, initialization
@ -852,7 +853,7 @@ public abstract class Trade implements Tradable, Model {
MoneroWallet havenoWallet = processModel.getXmrWalletService().getWallet(); MoneroWallet havenoWallet = processModel.getXmrWalletService().getWallet();
// fetch deposit txs from daemon // fetch deposit txs from daemon
List<MoneroTx> txs = daemon.getTxs(Arrays.asList(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash()), true); List<MoneroTx> txs = xmrWalletService.getTxs(Arrays.asList(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash()));
// handle deposit txs seen // handle deposit txs seen
if (txs.size() == 2) { if (txs.size() == 2) {
@ -889,7 +890,7 @@ public abstract class Trade implements Tradable, Model {
if (unlockHeight != null && height < unlockHeight) return; if (unlockHeight != null && height < unlockHeight) return;
// fetch txs from daemon // fetch txs from daemon
List<MoneroTx> txs = daemon.getTxs(Arrays.asList(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash()), true); List<MoneroTx> txs = xmrWalletService.getTxs(Arrays.asList(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash()));
// ignore if deposit txs not seen // ignore if deposit txs not seen
if (txs.size() != 2) return; if (txs.size() != 2) return;
@ -924,7 +925,7 @@ public abstract class Trade implements Tradable, Model {
public MoneroTx getTakerDepositTx() { public MoneroTx getTakerDepositTx() {
String depositTxHash = getProcessModel().getTaker().getDepositTxHash(); String depositTxHash = getProcessModel().getTaker().getDepositTxHash();
try { try {
if (takerDepositTx == null) takerDepositTx = depositTxHash == null ? null : getXmrWalletService().getDaemon().getTx(depositTxHash); if (takerDepositTx == null) takerDepositTx = depositTxHash == null ? null : getXmrWalletService().getTxWithCache(depositTxHash);
return takerDepositTx; return takerDepositTx;
} catch (MoneroError e) { } catch (MoneroError e) {
log.error("Wallet is missing taker deposit tx " + depositTxHash); log.error("Wallet is missing taker deposit tx " + depositTxHash);
@ -936,7 +937,7 @@ public abstract class Trade implements Tradable, Model {
public MoneroTx getMakerDepositTx() { public MoneroTx getMakerDepositTx() {
String depositTxHash = getProcessModel().getMaker().getDepositTxHash(); String depositTxHash = getProcessModel().getMaker().getDepositTxHash();
try { try {
if (makerDepositTx == null) makerDepositTx = depositTxHash == null ? null : getXmrWalletService().getDaemon().getTx(depositTxHash); if (makerDepositTx == null) makerDepositTx = depositTxHash == null ? null : getXmrWalletService().getTxWithCache(depositTxHash);
return makerDepositTx; return makerDepositTx;
} catch (MoneroError e) { } catch (MoneroError e) {
log.error("Wallet is missing maker deposit tx " + depositTxHash); log.error("Wallet is missing maker deposit tx " + depositTxHash);
@ -1217,8 +1218,8 @@ public abstract class Trade implements Tradable, Model {
} }
private long getStartTime() { private long getStartTime() {
if (startTime != null) return startTime;
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long startTime;
final MoneroTx takerDepositTx = getTakerDepositTx(); final MoneroTx takerDepositTx = getTakerDepositTx();
final MoneroTx makerDepositTx = getMakerDepositTx(); final MoneroTx makerDepositTx = getMakerDepositTx();
if (makerDepositTx != null && takerDepositTx != null && getTakeOfferDate() != null) { if (makerDepositTx != null && takerDepositTx != null && getTakeOfferDate() != null) {

View File

@ -178,7 +178,7 @@ public class TxIdTextField extends AnchorPane {
private void updateConfidence(String txId) { private void updateConfidence(String txId) {
MoneroTx tx = null; MoneroTx tx = null;
try { try {
tx = xmrWalletService.getDaemon().getTx(txId); // TODO: cache results and don't re-fetch tx = xmrWalletService.getTxWithCache(txId);
tx.setNumConfirmations(tx.isConfirmed() ? xmrWalletService.getConnectionsService().getLastInfo().getHeight() - tx.getHeight() : 0l); // TODO: use tx.getNumConfirmations() when MoneroDaemonRpc supports it tx.setNumConfirmations(tx.isConfirmed() ? xmrWalletService.getConnectionsService().getLastInfo().getHeight() - tx.getHeight() : 0l); // TODO: use tx.getNumConfirmations() when MoneroDaemonRpc supports it
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing