improve stability on tor, refactor startup and shut down

refactor startup sequence to improve message reliability
refactor shut down sequence to finish processing messages
reduce monerod requests to improve slow tor connections
refactor trade wallet polling
monero node service uses default data directory unless local
connections service checks connection by polling daemon
connections service supports getRefreshPeriodMs and shutting down
add make config: monerod-stagenet-custom
fix bugs in key image polling
force stop wallet on deletion
trade manager initializes persisted trades on data received
support hardcoding monero log level and request stack traces
remove xmrAddress from Arbitrator model
fix formatting of MoneroWalletRpcManager
This commit is contained in:
woodser 2023-04-17 08:54:10 -04:00
parent 5e364f7e7e
commit 2afa5d761d
51 changed files with 1058 additions and 644 deletions

View file

@ -70,7 +70,7 @@ public class MakerSendInitTradeRequest extends TradeTask {
trade.getSelf().getReserveTxHash(),
trade.getSelf().getReserveTxHex(),
trade.getSelf().getReserveTxKey(),
model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).get().getAddressString(),
model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.RESERVED_FOR_TRADE).get().getAddressString(),
null);
// send request to arbitrator

View file

@ -32,10 +32,10 @@ import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j
public class ResendDisputeClosedMessageWithPayout extends TradeTask {
public class MaybeResendDisputeClosedMessageWithPayout extends TradeTask {
@SuppressWarnings({"unused"})
public ResendDisputeClosedMessageWithPayout(TaskRunner taskHandler, Trade trade) {
public MaybeResendDisputeClosedMessageWithPayout(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}

View file

@ -83,7 +83,7 @@ public class MaybeSendSignContractRequest extends TradeTask {
trade.getSelf().setDepositTx(depositTx);
trade.getSelf().setDepositTxHash(depositTx.getHash());
trade.getSelf().setReserveTxKeyImages(reservedKeyImages);
trade.getSelf().setPayoutAddressString(trade.getXmrWalletService().getAddressEntry(processModel.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).get().getAddressString()); // TODO (woodser): allow custom payout address?
trade.getSelf().setPayoutAddressString(trade.getXmrWalletService().getOrCreateAddressEntry(processModel.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString()); // TODO (woodser): allow custom payout address?
trade.getSelf().setPaymentAccountPayload(trade.getProcessModel().getPaymentAccountPayload(trade.getSelf().getPaymentAccountId()));
// maker signs deposit hash nonce to avoid challenge protocol

View file

@ -53,14 +53,21 @@ public class ProcessDepositsConfirmedMessage extends TradeTask {
if (sender.getNodeAddress().equals(trade.getSeller().getNodeAddress()) && sender != trade.getSeller()) trade.getSeller().setNodeAddress(null);
if (sender.getNodeAddress().equals(trade.getArbitrator().getNodeAddress()) && sender != trade.getArbitrator()) trade.getArbitrator().setNodeAddress(null);
// update multisig hex
sender.setUpdatedMultisigHex(request.getUpdatedMultisigHex());
// decrypt seller payment account payload if key given
if (request.getSellerPaymentAccountKey() != null && trade.getTradePeer().getPaymentAccountPayload() == null) {
log.info(trade.getClass().getSimpleName() + " decrypting using seller payment account key");
trade.decryptPeerPaymentAccountPayload(request.getSellerPaymentAccountKey());
}
processModel.getTradeManager().requestPersistence(); // in case importing multisig hex fails
// update multisig hex
sender.setUpdatedMultisigHex(request.getUpdatedMultisigHex());
try {
trade.importMultisigHex();
} catch (Exception e) {
log.warn("Error importing multisig hex for {} {}: {}", trade.getClass().getSimpleName(), trade.getId(), e.getMessage());
e.printStackTrace();
}
// persist and complete
processModel.getTradeManager().requestPersistence();

View file

@ -111,6 +111,7 @@ public class ProcessInitMultisigRequest extends TradeTask {
processModel.setMultisigAddress(result.getAddress());
trade.saveWallet(); // save multisig wallet on completion
trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_COMPLETED);
trade.updateWalletRefreshPeriod(); // starts syncing
}
// update multisig participants if new state to communicate

View file

@ -113,7 +113,8 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
// wait to sign and publish payout tx if defer flag set (seller recently saw payout tx arrive at buyer)
boolean isSigned = message.getSignedPayoutTxHex() != null;
if (trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout()) {
boolean deferSignAndPublish = trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout();
if (deferSignAndPublish) {
log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
GenUtils.waitFor(Trade.DEFER_PUBLISH_MS);
if (!trade.isPayoutUnlocked()) trade.syncWallet();
@ -135,6 +136,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
trade.verifyPayoutTx(trade.getPayoutTxHex(), false, true);
}
} catch (Exception e) {
trade.syncWallet();
if (trade.isPayoutPublished()) log.info("Payout tx already published for {} {}", trade.getClass().getName(), trade.getId());
else throw e;
}

View file

@ -47,10 +47,7 @@ public class ProcessPaymentSentMessage extends TradeTask {
// update latest peer address
trade.getBuyer().setNodeAddress(processModel.getTempTradePeerNodeAddress());
// if seller, decrypt buyer's payment account payload
if (trade.isSeller()) trade.decryptPeerPaymentAccountPayload(message.getPaymentAccountKey());
// update state
// update state from message
processModel.setPaymentSentMessage(message);
trade.setPayoutTxHex(message.getPayoutTxHex());
trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex());
@ -59,6 +56,20 @@ public class ProcessPaymentSentMessage extends TradeTask {
if (counterCurrencyTxId != null && counterCurrencyTxId.length() < 100) trade.setCounterCurrencyTxId(counterCurrencyTxId);
String counterCurrencyExtraData = message.getCounterCurrencyExtraData();
if (counterCurrencyExtraData != null && counterCurrencyExtraData.length() < 100) trade.setCounterCurrencyExtraData(counterCurrencyExtraData);
// if seller, decrypt buyer's payment account payload
if (trade.isSeller()) trade.decryptPeerPaymentAccountPayload(message.getPaymentAccountKey());
trade.requestPersistence();
// import multisig hex
try {
trade.importMultisigHex();
} catch (Exception e) {
log.warn("Error importing multisig hex for {} {}: {}", trade.getClass().getSimpleName(), trade.getId(), e.getMessage());
e.printStackTrace();
}
// update state
trade.advanceState(trade.isSeller() ? Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG : Trade.State.BUYER_SENT_PAYMENT_SENT_MSG);
trade.requestPersistence();
complete();

View file

@ -58,8 +58,8 @@ public abstract class SendMailboxMessageTask extends TradeTask {
TradeMailboxMessage message = getTradeMailboxMessage(id);
setStateSent();
NodeAddress peersNodeAddress = getReceiverNodeAddress();
log.info("Send {} to peer {} for {} {}", trade.getClass().getSimpleName(), trade.getId(),
message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid());
log.info("Send {} to peer {} for {} {}, uid={}",
message.getClass().getSimpleName(), peersNodeAddress, trade.getClass().getSimpleName(), trade.getId(), message.getUid());
TradeTask task = this;
processModel.getP2PService().getMailboxMessageService().sendEncryptedMailboxMessage(

View file

@ -43,7 +43,7 @@ public class TakerReserveTradeFunds extends TradeTask {
BigInteger takerFee = trade.getTakerFee();
BigInteger sendAmount = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getAmount() : BigInteger.valueOf(0);
BigInteger securityDeposit = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getSellerSecurityDeposit() : trade.getOffer().getBuyerSecurityDeposit();
String returnAddress = model.getXmrWalletService().getAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).get().getAddressString();
String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString();
MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(takerFee, sendAmount, securityDeposit, returnAddress);
// collect reserved key images