mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-22 11:39:29 +00:00
re-export multisig hex on create multisig tx or open dispute
This commit is contained in:
parent
d4a9838cd8
commit
79cd9f3e82
9 changed files with 120 additions and 104 deletions
|
@ -112,7 +112,7 @@ public class CoreDisputesService {
|
|||
|
||||
// Sends the openNewDisputeMessage to arbitrator, who will then create 2 disputes
|
||||
// one for the opener, the other for the peer, see sendPeerOpenedDisputeMessage.
|
||||
disputeManager.sendDisputeOpenedMessage(dispute, false, trade.getSelf().getUpdatedMultisigHex(), resultHandler, faultHandler);
|
||||
disputeManager.sendDisputeOpenedMessage(dispute, false, resultHandler, faultHandler);
|
||||
tradeManager.requestPersistence();
|
||||
}, trade.getId());
|
||||
}
|
||||
|
|
|
@ -157,6 +157,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
disputeListService.requestPersistence();
|
||||
}
|
||||
|
||||
protected void requestPersistence(Trade trade) {
|
||||
trade.requestPersistence();
|
||||
disputeListService.requestPersistence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeAddress getPeerNodeAddress(ChatMessage message) {
|
||||
Optional<Dispute> disputeOptional = findDispute(message);
|
||||
|
@ -322,7 +327,6 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
// trader sends message to arbitrator to open dispute
|
||||
public void sendDisputeOpenedMessage(Dispute dispute,
|
||||
boolean reOpen,
|
||||
String updatedMultisigHex,
|
||||
ResultHandler resultHandler,
|
||||
FaultHandler faultHandler) {
|
||||
|
||||
|
@ -372,12 +376,13 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
}
|
||||
|
||||
// create dispute opened message
|
||||
trade.exportMultisigHex();
|
||||
NodeAddress agentNodeAddress = getAgentNodeAddress(dispute);
|
||||
DisputeOpenedMessage disputeOpenedMessage = new DisputeOpenedMessage(dispute,
|
||||
p2PService.getAddress(),
|
||||
UUID.randomUUID().toString(),
|
||||
getSupportType(),
|
||||
updatedMultisigHex,
|
||||
trade.getSelf().getUpdatedMultisigHex(),
|
||||
trade.getArbitrator().getPaymentSentMessage());
|
||||
log.info("Send {} to peer {}. tradeId={}, openNewDisputeMessage.uid={}, " +
|
||||
"chatMessage.uid={}",
|
||||
|
@ -792,7 +797,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
disputeResult.getChatMessage().setArrived(true);
|
||||
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG);
|
||||
trade.pollWalletNormallyForMs(30000);
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
|
@ -811,7 +816,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
disputeResult.getChatMessage().setStoredInMailbox(true);
|
||||
Trade trade = tradeManager.getTrade(dispute.getTradeId());
|
||||
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_STORED_IN_MAILBOX_DISPUTE_CLOSED_MSG);
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
|
@ -828,13 +833,13 @@ 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().setSendMessageError(errorMessage);
|
||||
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SEND_FAILED_DISPUTE_CLOSED_MSG);
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
faultHandler.handleFault(errorMessage, new RuntimeException(errorMessage));
|
||||
}
|
||||
}
|
||||
);
|
||||
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG);
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
} catch (Exception e) {
|
||||
faultHandler.handleFault(e.getMessage(), e);
|
||||
}
|
||||
|
@ -900,11 +905,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
// update trade state
|
||||
if (updateState) {
|
||||
trade.getProcessModel().setUnsignedPayoutTx(payoutTx);
|
||||
trade.getSelf().setUpdatedMultisigHex(trade.getWallet().exportMultisigHex());
|
||||
trade.updatePayout(payoutTx);
|
||||
if (trade.getBuyer().getUpdatedMultisigHex() != null && trade.getBuyer().getUnsignedPayoutTxHex() == null) trade.getBuyer().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex());
|
||||
if (trade.getSeller().getUpdatedMultisigHex() != null && trade.getSeller().getUnsignedPayoutTxHex() == null) trade.getSeller().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex());
|
||||
}
|
||||
trade.requestPersistence();
|
||||
return payoutTx;
|
||||
} catch (Exception e) {
|
||||
trade.syncAndPollWallet();
|
||||
|
|
|
@ -252,7 +252,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
|
||||
// save dispute closed message for reprocessing
|
||||
trade.getArbitrator().setDisputeClosedMessage(disputeClosedMessage);
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
|
||||
// verify arbitrator does not receive DisputeClosedMessage
|
||||
if (keyRing.getPubKeyRing().equals(dispute.getAgentPubKeyRing())) {
|
||||
|
@ -326,17 +326,17 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
// We use the chatMessage as we only persist those not the DisputeClosedMessage.
|
||||
// If we would use the DisputeClosedMessage we could not lookup for the msg when we receive the AckMessage.
|
||||
sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), true, null);
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
} catch (Exception e) {
|
||||
log.warn("Error processing dispute closed message: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
|
||||
// nack bad message and do not reprocess
|
||||
if (e instanceof IllegalArgumentException) {
|
||||
trade.getArbitrator().setDisputeClosedMessage(null); // message is processed
|
||||
sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), false, e.getMessage());
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
@ -447,7 +447,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
String signedMultisigTxHex = result.getSignedMultisigTxHex();
|
||||
disputeTxSet.setMultisigTxHex(signedMultisigTxHex);
|
||||
trade.setPayoutTxHex(signedMultisigTxHex);
|
||||
requestPersistence();
|
||||
requestPersistence(trade);
|
||||
|
||||
// verify mining fee is within tolerance by recreating payout tx
|
||||
// TODO (monero-project): creating tx will require exchanging updated multisig hex if message needs reprocessed. provide weight with describe_transfer so fee can be estimated?
|
||||
|
@ -487,6 +487,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
trade.updatePayout(disputeTxSet.getTxs().get(0));
|
||||
trade.setPayoutState(Trade.PayoutState.PAYOUT_PUBLISHED);
|
||||
dispute.setDisputePayoutTxId(disputeTxSet.getTxs().get(0).getHash());
|
||||
requestPersistence(trade);
|
||||
return disputeTxSet;
|
||||
}
|
||||
|
||||
|
|
|
@ -1058,11 +1058,21 @@ public abstract class Trade implements Tradable, Model {
|
|||
public MoneroTxWallet createTx(MoneroTxConfig txConfig) {
|
||||
synchronized (walletLock) {
|
||||
synchronized (HavenoUtils.getWalletFunctionLock()) {
|
||||
return wallet.createTx(txConfig);
|
||||
MoneroTxWallet tx = wallet.createTx(txConfig);
|
||||
exportMultisigHex();
|
||||
requestSaveWallet();
|
||||
return tx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void exportMultisigHex() {
|
||||
synchronized (walletLock) {
|
||||
getSelf().setUpdatedMultisigHex(wallet.exportMultisigHex());
|
||||
requestPersistence();
|
||||
}
|
||||
}
|
||||
|
||||
public void importMultisigHex() {
|
||||
synchronized (walletLock) {
|
||||
synchronized (HavenoUtils.getDaemonLock()) { // lock on daemon because import calls full refresh
|
||||
|
@ -1220,13 +1230,11 @@ public abstract class Trade implements Tradable, Model {
|
|||
.setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY));
|
||||
|
||||
// update state
|
||||
saveWallet();
|
||||
BigInteger payoutTxFeeSplit = payoutTx.getFee().divide(BigInteger.valueOf(2));
|
||||
getBuyer().setPayoutTxFee(payoutTxFeeSplit);
|
||||
getBuyer().setPayoutAmount(HavenoUtils.getDestination(buyerPayoutAddress, payoutTx).getAmount());
|
||||
getSeller().setPayoutTxFee(payoutTxFeeSplit);
|
||||
getSeller().setPayoutAmount(HavenoUtils.getDestination(sellerPayoutAddress, payoutTx).getAmount());
|
||||
getSelf().setUpdatedMultisigHex(wallet.exportMultisigHex());
|
||||
return payoutTx;
|
||||
}
|
||||
|
||||
|
@ -1273,6 +1281,9 @@ public abstract class Trade implements Tradable, Model {
|
|||
if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
|
||||
if (xmrConnectionService.isConnected()) requestSwitchToNextBestConnection();
|
||||
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
|
||||
} finally {
|
||||
requestSaveWallet();
|
||||
requestPersistence();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,9 +64,9 @@ public class BuyerPreparePaymentSentMessage extends TradeTask {
|
|||
|
||||
// skip if payout tx already created
|
||||
if (trade.getSelf().getUnsignedPayoutTxHex() != null) {
|
||||
log.warn("Skipping preparation of payment sent message because payout tx is already created for {} {}", trade.getClass().getSimpleName(), trade.getShortId());
|
||||
complete();
|
||||
return;
|
||||
log.warn("Skipping preparation of payment sent message because payout tx is already created for {} {}", trade.getClass().getSimpleName(), trade.getShortId());
|
||||
complete();
|
||||
return;
|
||||
}
|
||||
|
||||
// validate state
|
||||
|
@ -87,6 +87,7 @@ public class BuyerPreparePaymentSentMessage extends TradeTask {
|
|||
MoneroTxWallet payoutTx = trade.createPayoutTx();
|
||||
trade.updatePayout(payoutTx);
|
||||
trade.getSelf().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex());
|
||||
trade.requestPersistence();
|
||||
}
|
||||
|
||||
complete();
|
||||
|
@ -107,101 +108,100 @@ public class BuyerPreparePaymentSentMessage extends TradeTask {
|
|||
*/
|
||||
public static class Pair<F, S> {
|
||||
|
||||
private F first;
|
||||
private S second;
|
||||
private F first;
|
||||
private S second;
|
||||
|
||||
public Pair(F first, S second) {
|
||||
super();
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
public Pair(F first, S second) {
|
||||
super();
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public F getFirst() {
|
||||
return first;
|
||||
}
|
||||
public F getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public void setFirst(F first) {
|
||||
this.first = first;
|
||||
}
|
||||
public void setFirst(F first) {
|
||||
this.first = first;
|
||||
}
|
||||
|
||||
public S getSecond() {
|
||||
return second;
|
||||
}
|
||||
public S getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
public void setSecond(S second) {
|
||||
this.second = second;
|
||||
}
|
||||
public void setSecond(S second) {
|
||||
this.second = second;
|
||||
}
|
||||
}
|
||||
|
||||
public static void printBalances(MoneroWallet wallet) {
|
||||
|
||||
// collect info about subaddresses
|
||||
List<Pair<String, List<Object>>> pairs = new ArrayList<Pair<String, List<Object>>>();
|
||||
//if (wallet == null) wallet = TestUtils.getWalletJni();
|
||||
BigInteger balance = wallet.getBalance();
|
||||
BigInteger unlockedBalance = wallet.getUnlockedBalance();
|
||||
List<MoneroAccount> accounts = wallet.getAccounts(true);
|
||||
System.out.println("Wallet balance: " + balance);
|
||||
System.out.println("Wallet unlocked balance: " + unlockedBalance);
|
||||
for (MoneroAccount account : accounts) {
|
||||
add(pairs, "ACCOUNT", account.getIndex());
|
||||
add(pairs, "SUBADDRESS", "");
|
||||
add(pairs, "LABEL", "");
|
||||
add(pairs, "ADDRESS", "");
|
||||
add(pairs, "BALANCE", account.getBalance());
|
||||
add(pairs, "UNLOCKED", account.getUnlockedBalance());
|
||||
for (MoneroSubaddress subaddress : account.getSubaddresses()) {
|
||||
add(pairs, "ACCOUNT", account.getIndex());
|
||||
add(pairs, "SUBADDRESS", subaddress.getIndex());
|
||||
add(pairs, "LABEL", subaddress.getLabel());
|
||||
add(pairs, "ADDRESS", subaddress.getAddress());
|
||||
add(pairs, "BALANCE", subaddress.getBalance());
|
||||
add(pairs, "UNLOCKED", subaddress.getUnlockedBalance());
|
||||
// collect info about subaddresses
|
||||
List<Pair<String, List<Object>>> pairs = new ArrayList<Pair<String, List<Object>>>();
|
||||
//if (wallet == null) wallet = TestUtils.getWalletJni();
|
||||
BigInteger balance = wallet.getBalance();
|
||||
BigInteger unlockedBalance = wallet.getUnlockedBalance();
|
||||
List<MoneroAccount> accounts = wallet.getAccounts(true);
|
||||
System.out.println("Wallet balance: " + balance);
|
||||
System.out.println("Wallet unlocked balance: " + unlockedBalance);
|
||||
for (MoneroAccount account : accounts) {
|
||||
add(pairs, "ACCOUNT", account.getIndex());
|
||||
add(pairs, "SUBADDRESS", "");
|
||||
add(pairs, "LABEL", "");
|
||||
add(pairs, "ADDRESS", "");
|
||||
add(pairs, "BALANCE", account.getBalance());
|
||||
add(pairs, "UNLOCKED", account.getUnlockedBalance());
|
||||
for (MoneroSubaddress subaddress : account.getSubaddresses()) {
|
||||
add(pairs, "ACCOUNT", account.getIndex());
|
||||
add(pairs, "SUBADDRESS", subaddress.getIndex());
|
||||
add(pairs, "LABEL", subaddress.getLabel());
|
||||
add(pairs, "ADDRESS", subaddress.getAddress());
|
||||
add(pairs, "BALANCE", subaddress.getBalance());
|
||||
add(pairs, "UNLOCKED", subaddress.getUnlockedBalance());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convert info to csv
|
||||
Integer length = null;
|
||||
for (Pair<String, List<Object>> pair : pairs) {
|
||||
if (length == null) length = pair.getSecond().size();
|
||||
}
|
||||
// convert info to csv
|
||||
Integer length = null;
|
||||
for (Pair<String, List<Object>> pair : pairs) {
|
||||
if (length == null)
|
||||
length = pair.getSecond().size();
|
||||
}
|
||||
|
||||
System.out.println(pairsToCsv(pairs));
|
||||
System.out.println(pairsToCsv(pairs));
|
||||
}
|
||||
|
||||
private static void add(List<Pair<String, List<Object>>> pairs, String header, Object value) {
|
||||
if (value == null) value = "";
|
||||
Pair<String, List<Object>> pair = null;
|
||||
for (Pair<String, List<Object>> aPair : pairs) {
|
||||
if (aPair.getFirst().equals(header)) {
|
||||
pair = aPair;
|
||||
break;
|
||||
if (value == null) value = "";
|
||||
Pair<String, List<Object>> pair = null;
|
||||
for (Pair<String, List<Object>> aPair : pairs) {
|
||||
if (aPair.getFirst().equals(header)) {
|
||||
pair = aPair;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pair == null) {
|
||||
List<Object> vals = new ArrayList<Object>();
|
||||
pair = new Pair<String, List<Object>>(header, vals);
|
||||
pairs.add(pair);
|
||||
}
|
||||
pair.getSecond().add(value);
|
||||
if (pair == null) {
|
||||
List<Object> vals = new ArrayList<Object>();
|
||||
pair = new Pair<String, List<Object>>(header, vals);
|
||||
pairs.add(pair);
|
||||
}
|
||||
pair.getSecond().add(value);
|
||||
}
|
||||
|
||||
private static String pairsToCsv(List<Pair<String, List<Object>>> pairs) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < pairs.size(); i++) {
|
||||
sb.append(pairs.get(i).getFirst());
|
||||
if (i < pairs.size() - 1) sb.append(',');
|
||||
else sb.append('\n');
|
||||
}
|
||||
for (int i = 0; i < pairs.get(0).getSecond().size(); i++) {
|
||||
for (int j = 0; j < pairs.size(); j++) {
|
||||
sb.append(pairs.get(j).getSecond().get(i));
|
||||
if (j < pairs.size() - 1) sb.append(',');
|
||||
else sb.append('\n');
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < pairs.size(); i++) {
|
||||
sb.append(pairs.get(i).getFirst());
|
||||
if (i < pairs.size() - 1) sb.append(',');
|
||||
else sb.append('\n');
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
for (int i = 0; i < pairs.get(0).getSecond().size(); i++) {
|
||||
for (int j = 0; j < pairs.size(); j++) {
|
||||
sb.append(pairs.get(j).getSecond().get(i));
|
||||
if (j < pairs.size() - 1) sb.append(',');
|
||||
else sb.append('\n');
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ public class ProcessPaymentSentMessage extends TradeTask {
|
|||
|
||||
// if seller, decrypt buyer's payment account payload
|
||||
if (trade.isSeller()) trade.decryptPeerPaymentAccountPayload(message.getPaymentAccountKey());
|
||||
trade.requestPersistence();
|
||||
|
||||
// update state
|
||||
trade.advanceState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG);
|
||||
|
|
|
@ -90,7 +90,7 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask {
|
|||
for (Dispute dispute : trade.getDisputes()) dispute.setIsClosed();
|
||||
}
|
||||
|
||||
processModel.getTradeManager().requestPersistence();
|
||||
trade.requestPersistence();
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
|
|
|
@ -76,8 +76,7 @@ public abstract class SendDepositsConfirmedMessage extends SendMailboxMessageTas
|
|||
|
||||
// export multisig hex once
|
||||
if (trade.getSelf().getUpdatedMultisigHex() == null) {
|
||||
trade.getSelf().setUpdatedMultisigHex(trade.getWallet().exportMultisigHex());
|
||||
processModel.getTradeManager().requestPersistence();
|
||||
trade.exportMultisigHex();
|
||||
}
|
||||
|
||||
// We do not use a real unique ID here as we want to be able to re-send the exact same message in case the
|
||||
|
|
|
@ -545,27 +545,28 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
dispute.setExtraData("counterCurrencyExtraData", trade.getCounterCurrencyExtraData());
|
||||
|
||||
trade.setDisputeState(Trade.DisputeState.MEDIATION_REQUESTED);
|
||||
sendDisputeOpenedMessage(dispute, false, disputeManager, trade.getSelf().getUpdatedMultisigHex());
|
||||
sendDisputeOpenedMessage(dispute, false, disputeManager);
|
||||
tradeManager.requestPersistence();
|
||||
} else if (useArbitration) {
|
||||
// Only if we have completed mediation we allow arbitration
|
||||
disputeManager = arbitrationManager;
|
||||
Dispute dispute = disputesService.createDisputeForTrade(trade, offer, pubKeyRingProvider.get(), isMaker, isSupportTicket);
|
||||
sendDisputeOpenedMessage(dispute, false, disputeManager, trade.getSelf().getUpdatedMultisigHex());
|
||||
trade.exportMultisigHex();
|
||||
sendDisputeOpenedMessage(dispute, false, disputeManager);
|
||||
tradeManager.requestPersistence();
|
||||
} else {
|
||||
log.warn("Invalid dispute state {}", disputeState.name());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendDisputeOpenedMessage(Dispute dispute, boolean reOpen, DisputeManager<? extends DisputeList<Dispute>> disputeManager, String senderMultisigHex) {
|
||||
disputeManager.sendDisputeOpenedMessage(dispute, reOpen, senderMultisigHex,
|
||||
private void sendDisputeOpenedMessage(Dispute dispute, boolean reOpen, DisputeManager<? extends DisputeList<Dispute>> disputeManager) {
|
||||
disputeManager.sendDisputeOpenedMessage(dispute, reOpen,
|
||||
() -> navigation.navigateTo(MainView.class, SupportView.class, ArbitrationClientView.class), (errorMessage, throwable) -> {
|
||||
if ((throwable instanceof DisputeAlreadyOpenException)) {
|
||||
errorMessage += "\n\n" + Res.get("portfolio.pending.openAgainDispute.msg");
|
||||
new Popup().warning(errorMessage)
|
||||
.actionButtonText(Res.get("portfolio.pending.openAgainDispute.button"))
|
||||
.onAction(() -> sendDisputeOpenedMessage(dispute, true, disputeManager, senderMultisigHex))
|
||||
.onAction(() -> sendDisputeOpenedMessage(dispute, true, disputeManager))
|
||||
.closeButtonText(Res.get("shared.cancel")).show();
|
||||
} else {
|
||||
new Popup().warning(errorMessage).show();
|
||||
|
|
Loading…
Reference in a new issue