mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-08-20 20:28:57 -04:00
Fix issues with delayed mailbox messages, handle ui state when peer is offline
This commit is contained in:
parent
4fc3b00fa4
commit
7c63e5ab00
11 changed files with 55 additions and 49 deletions
|
@ -63,7 +63,7 @@ public class Log {
|
||||||
|
|
||||||
logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
|
logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
|
||||||
//TODO for now use always trace
|
//TODO for now use always trace
|
||||||
logbackLogger.setLevel(useDetailedLogging ? Level.TRACE : Level.INFO);
|
logbackLogger.setLevel(useDetailedLogging ? Level.TRACE : Level.TRACE);
|
||||||
// logbackLogger.setLevel(useDetailedLogging ? Level.TRACE : Level.DEBUG);
|
// logbackLogger.setLevel(useDetailedLogging ? Level.TRACE : Level.DEBUG);
|
||||||
logbackLogger.addAppender(appender);
|
logbackLogger.addAppender(appender);
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,7 @@ public abstract class Trade implements Tradable, Model {
|
||||||
OpenOfferManager openOfferManager,
|
OpenOfferManager openOfferManager,
|
||||||
User user,
|
User user,
|
||||||
KeyRing keyRing) {
|
KeyRing keyRing) {
|
||||||
|
Log.traceCall();
|
||||||
processModel.onAllServicesInitialized(offer,
|
processModel.onAllServicesInitialized(offer,
|
||||||
tradeManager,
|
tradeManager,
|
||||||
openOfferManager,
|
openOfferManager,
|
||||||
|
@ -234,6 +234,7 @@ public abstract class Trade implements Tradable, Model {
|
||||||
|
|
||||||
createProtocol();
|
createProtocol();
|
||||||
|
|
||||||
|
log.trace("decryptedMsgWithPubKey = " + decryptedMsgWithPubKey);
|
||||||
if (decryptedMsgWithPubKey != null) {
|
if (decryptedMsgWithPubKey != null) {
|
||||||
tradeProtocol.applyMailboxMessage(decryptedMsgWithPubKey, this);
|
tradeProtocol.applyMailboxMessage(decryptedMsgWithPubKey, this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
isSpinnerVisible.set(false);
|
isSpinnerVisible.set(false);
|
||||||
spinnerInfoText.set("");
|
spinnerInfoText.set("");
|
||||||
} else if (showPayFundsScreenDisplayed) {
|
} else if (showPayFundsScreenDisplayed) {
|
||||||
spinnerInfoText.set("Waiting for funds...");
|
spinnerInfoText.set("Waiting for receiving funds...");
|
||||||
isSpinnerVisible.set(true);
|
isSpinnerVisible.set(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,7 +453,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
isSpinnerVisible.set(false);
|
isSpinnerVisible.set(false);
|
||||||
spinnerInfoText.set("");
|
spinnerInfoText.set("");
|
||||||
} else if (showPayFundsScreenDisplayed) {
|
} else if (showPayFundsScreenDisplayed) {
|
||||||
spinnerInfoText.set("Waiting for funds...");
|
spinnerInfoText.set("Waiting for receiving funds...");
|
||||||
isSpinnerVisible.set(true);
|
isSpinnerVisible.set(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,6 +301,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
case BUYER_RECEIVED_FIAT_PAYMENT_RECEIPT_MSG:
|
case BUYER_RECEIVED_FIAT_PAYMENT_RECEIPT_MSG:
|
||||||
case BUYER_COMMITTED_PAYOUT_TX:
|
case BUYER_COMMITTED_PAYOUT_TX:
|
||||||
case BUYER_STARTED_SEND_PAYOUT_TX:
|
case BUYER_STARTED_SEND_PAYOUT_TX:
|
||||||
|
// TODO would need extra state for wait until msg arrived and PAYOUT_BROAD_CASTED gets called.
|
||||||
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_BROADCAST_AFTER_UNLOCK);
|
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_BROADCAST_AFTER_UNLOCK);
|
||||||
break;
|
break;
|
||||||
case SELLER_RECEIVED_AND_COMMITTED_PAYOUT_TX:
|
case SELLER_RECEIVED_AND_COMMITTED_PAYOUT_TX:
|
||||||
|
|
|
@ -93,9 +93,13 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
@Override
|
@Override
|
||||||
protected void addContent() {
|
protected void addContent() {
|
||||||
addTradeInfoBlock();
|
addTradeInfoBlock();
|
||||||
|
if (model.getLockTime() > 0) {
|
||||||
blockTextField = addLabelTextField(gridPane, gridRow, "Block(s) to wait until lock time elapsed:", "").second;
|
blockTextField = addLabelTextField(gridPane, gridRow, "Block(s) to wait until lock time elapsed:", "").second;
|
||||||
timeTextField = addLabelTextField(gridPane, ++gridRow, "Approx. date when payout gets unlocked:").second;
|
timeTextField = addLabelTextField(gridPane, ++gridRow, "Approx. date when payout gets unlocked:").second;
|
||||||
GridPane.setRowSpan(tradeInfoTitledGroupBg, 5);
|
GridPane.setRowSpan(tradeInfoTitledGroupBg, 5);
|
||||||
|
} else {
|
||||||
|
GridPane.setRowSpan(tradeInfoTitledGroupBg, 3); //TODO should never reach
|
||||||
|
}
|
||||||
|
|
||||||
addInfoBlock();
|
addInfoBlock();
|
||||||
}
|
}
|
||||||
|
@ -107,15 +111,21 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getInfoBlockTitle() {
|
protected String getInfoBlockTitle() {
|
||||||
|
if (model.getLockTime() > 0)
|
||||||
return "Wait until payout lock time is over";
|
return "Wait until payout lock time is over";
|
||||||
|
else
|
||||||
|
return "Sending payout transaction to peer";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getInfoText() {
|
protected String getInfoText() {
|
||||||
|
if (model.getLockTime() > 0)
|
||||||
return "The payout transaction is signed and finalized by both parties.\n" +
|
return "The payout transaction is signed and finalized by both parties.\n" +
|
||||||
"For reducing bank chargeback risks the payout transaction is blocked by a lock time.\n" +
|
"For reducing bank chargeback risks the payout transaction is blocked by a lock time.\n" +
|
||||||
"After that lock time is over the payout transaction gets published and you receive " +
|
"After that lock time is over the payout transaction gets published and you receive " +
|
||||||
"your bitcoin.";
|
"your bitcoin.";
|
||||||
|
else
|
||||||
|
return "We are sending the payout transaction to the other peer.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,10 +147,13 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void updateDateFromBlockHeight(long bestBlocKHeight) {
|
private void updateDateFromBlockHeight(long bestBlocKHeight) {
|
||||||
|
if (model.getLockTime() > 0) {
|
||||||
long missingBlocks = model.getLockTime() - bestBlocKHeight;
|
long missingBlocks = model.getLockTime() - bestBlocKHeight;
|
||||||
|
|
||||||
blockTextField.setText(String.valueOf(missingBlocks));
|
blockTextField.setText(String.valueOf(missingBlocks));
|
||||||
timeTextField.setText(model.getOpenDisputeTimeAsFormattedDate());
|
timeTextField.setText(model.getOpenDisputeTimeAsFormattedDate());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,10 @@ public class OfferBookViewModelTest {
|
||||||
Offer offer;
|
Offer offer;
|
||||||
Collection<PaymentAccount> paymentAccounts;
|
Collection<PaymentAccount> paymentAccounts;
|
||||||
|
|
||||||
|
paymentAccounts = new ArrayList<>(Arrays.asList(getSepaAccount("EUR", "DE", "1212324", new ArrayList<>(Arrays.asList("AT", "DE")))));
|
||||||
|
assertTrue(OfferBookViewModel.isAnyPaymentAccountValidForOffer(
|
||||||
|
getSEPAPaymentMethod("EUR", "AT", new ArrayList(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts));
|
||||||
|
|
||||||
|
|
||||||
// empty paymentAccounts
|
// empty paymentAccounts
|
||||||
paymentAccounts = new ArrayList<>();
|
paymentAccounts = new ArrayList<>();
|
||||||
|
@ -56,15 +60,20 @@ public class OfferBookViewModelTest {
|
||||||
assertTrue(OfferBookViewModel.isAnyPaymentAccountValidForOffer(
|
assertTrue(OfferBookViewModel.isAnyPaymentAccountValidForOffer(
|
||||||
getSameBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts));
|
getSameBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts));
|
||||||
|
|
||||||
// offer: SpecificBanks paymentAccount: SpecificBanks - same country, same currency
|
// offer: sepa paymentAccount: sepa - diff. country, same currency
|
||||||
paymentAccounts = new ArrayList<>(Arrays.asList(getSpecificBanksAccount("EUR", "AT", "PSK",
|
paymentAccounts = new ArrayList<>(Arrays.asList(getSepaAccount("EUR", "DE", "1212324", new ArrayList<>(Arrays.asList("AT", "DE")))));
|
||||||
new ArrayList<>(Arrays.asList("PSK", "Raika")))));
|
|
||||||
assertTrue(OfferBookViewModel.isAnyPaymentAccountValidForOffer(
|
assertTrue(OfferBookViewModel.isAnyPaymentAccountValidForOffer(
|
||||||
getSpecificBanksPaymentMethod("EUR", "AT", "PSK",
|
getSEPAPaymentMethod("EUR", "AT", new ArrayList(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts));
|
||||||
new ArrayList<>(Arrays.asList("PSK", "Raika"))), paymentAccounts));
|
|
||||||
|
|
||||||
//////
|
//////
|
||||||
|
|
||||||
|
// offer: sepa paymentAccount: sepa - same country, same currency
|
||||||
|
paymentAccounts = new ArrayList<>(Arrays.asList(getSepaAccount("EUR", "AT", "1212324", new ArrayList<>(Arrays.asList("AT", "DE")))));
|
||||||
|
assertTrue(OfferBookViewModel.isAnyPaymentAccountValidForOffer(
|
||||||
|
getSEPAPaymentMethod("EUR", "AT", new ArrayList(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts));
|
||||||
|
|
||||||
|
|
||||||
// offer: sepa paymentAccount: nationalBank - same country, same currency
|
// offer: sepa paymentAccount: nationalBank - same country, same currency
|
||||||
// wrong method
|
// wrong method
|
||||||
paymentAccounts = new ArrayList<>(Arrays.asList(getNationalBankAccount("EUR", "AT", "PSK")));
|
paymentAccounts = new ArrayList<>(Arrays.asList(getNationalBankAccount("EUR", "AT", "PSK")));
|
||||||
|
|
|
@ -407,7 +407,7 @@ public class Connection implements MessageListener {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//TODO find out why we get called that
|
//TODO find out why we get called that
|
||||||
log.warn("stopped was already true at shutDown call");
|
log.debug("stopped was already at shutDown call");
|
||||||
UserThread.execute(() -> doShutDown(closeConnectionReason, shutDownCompleteHandler));
|
UserThread.execute(() -> doShutDown(closeConnectionReason, shutDownCompleteHandler));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -536,20 +536,13 @@ public class Connection implements MessageListener {
|
||||||
closeConnectionReason = CloseConnectionReason.RESET;
|
closeConnectionReason = CloseConnectionReason.RESET;
|
||||||
} else if (e instanceof SocketTimeoutException || e instanceof TimeoutException) {
|
} else if (e instanceof SocketTimeoutException || e instanceof TimeoutException) {
|
||||||
closeConnectionReason = CloseConnectionReason.SOCKET_TIMEOUT;
|
closeConnectionReason = CloseConnectionReason.SOCKET_TIMEOUT;
|
||||||
log.warn("SocketTimeoutException at socket " + socket.toString() + "\n\tconnection={}" + this);
|
log.debug("SocketTimeoutException at socket " + socket.toString() + "\n\tconnection={}" + this);
|
||||||
} else if (e instanceof EOFException || e instanceof StreamCorruptedException) {
|
} else if (e instanceof EOFException || e instanceof StreamCorruptedException) {
|
||||||
closeConnectionReason = CloseConnectionReason.TERMINATED;
|
closeConnectionReason = CloseConnectionReason.TERMINATED;
|
||||||
} else {
|
} else {
|
||||||
closeConnectionReason = CloseConnectionReason.UNKNOWN_EXCEPTION;
|
closeConnectionReason = CloseConnectionReason.UNKNOWN_EXCEPTION;
|
||||||
|
|
||||||
String message;
|
|
||||||
if (e.getMessage() != null)
|
|
||||||
message = e.getMessage();
|
|
||||||
else
|
|
||||||
message = e.toString();
|
|
||||||
|
|
||||||
log.warn("Unknown reason for exception at socket {}\n\tconnection={}\n\tException=",
|
log.warn("Unknown reason for exception at socket {}\n\tconnection={}\n\tException=",
|
||||||
socket.toString(), this, message);
|
socket.toString(), this, e.toString());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,14 +112,14 @@ public class BroadcastHandler implements PeerManager.Listener {
|
||||||
numOfPeers = connectedPeersList.size();
|
numOfPeers = connectedPeersList.size();
|
||||||
int factor = 1;
|
int factor = 1;
|
||||||
if (!isDataOwner) {
|
if (!isDataOwner) {
|
||||||
// for not data owner (relay nodes) we send to max. 4 nodes and use a longer delay
|
// for not data owner (relay nodes) we send to max. 5 nodes and use a longer delay
|
||||||
numOfPeers = Math.min(4, connectedPeersList.size());
|
numOfPeers = Math.min(5, connectedPeersList.size());
|
||||||
factor = 2;
|
factor = 2;
|
||||||
}
|
}
|
||||||
log.info("Broadcast message to {} peers out of {} total connected peers.", numOfPeers, connectedPeersSet.size());
|
log.info("Broadcast message to {} peers out of {} total connected peers.", numOfPeers, connectedPeersSet.size());
|
||||||
for (int i = 0; i < numOfPeers; i++) {
|
for (int i = 0; i < numOfPeers; i++) {
|
||||||
final long minDelay = i * 50 * factor + 1;
|
final long minDelay = i * 30 * factor + 1;
|
||||||
final long maxDelay = minDelay * 2 + 50 * factor;
|
final long maxDelay = minDelay * 2 + 30 * factor;
|
||||||
final Connection connection = connectedPeersList.get(i);
|
final Connection connection = connectedPeersList.get(i);
|
||||||
UserThread.runAfterRandomDelay(() -> sendToPeer(connection, message), minDelay, maxDelay, TimeUnit.MILLISECONDS);
|
UserThread.runAfterRandomDelay(() -> sendToPeer(connection, message), minDelay, maxDelay, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,16 +18,12 @@ import io.bitsquare.p2p.peers.getdata.messages.GetDataResponse;
|
||||||
import io.bitsquare.p2p.peers.getdata.messages.GetUpdatedDataRequest;
|
import io.bitsquare.p2p.peers.getdata.messages.GetUpdatedDataRequest;
|
||||||
import io.bitsquare.p2p.peers.getdata.messages.PreliminaryGetDataRequest;
|
import io.bitsquare.p2p.peers.getdata.messages.PreliminaryGetDataRequest;
|
||||||
import io.bitsquare.p2p.storage.P2PDataStorage;
|
import io.bitsquare.p2p.storage.P2PDataStorage;
|
||||||
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
|
||||||
|
@ -160,17 +156,10 @@ public class RequestDataHandler implements MessageListener {
|
||||||
"RequestDataHandler.onMessage: connection.getPeersNodeAddressOptional() must be present " +
|
"RequestDataHandler.onMessage: connection.getPeersNodeAddressOptional() must be present " +
|
||||||
"at that moment");
|
"at that moment");
|
||||||
|
|
||||||
final List<ProtectedStorageEntry> dataList = new ArrayList<>(((GetDataResponse) message).dataSet);
|
|
||||||
final NodeAddress sender = connection.getPeersNodeAddressOptional().get();
|
final NodeAddress sender = connection.getPeersNodeAddressOptional().get();
|
||||||
for (int i = 0; i < dataList.size(); i++) {
|
((GetDataResponse) message).dataSet.stream().forEach(protectedStorageEntry -> {
|
||||||
// roughly 3-6 sec for 100 entries
|
dataStorage.add(protectedStorageEntry, sender, null, false);
|
||||||
final long minDelay = i * 30 + 1;
|
});
|
||||||
final long maxDelay = minDelay * 2 + 30;
|
|
||||||
final ProtectedStorageEntry protectedData = dataList.get(i);
|
|
||||||
// TODO questionable if it is needed to relay the data to our peers
|
|
||||||
UserThread.runAfterRandomDelay(() -> dataStorage.add(protectedData, sender, null, false),
|
|
||||||
minDelay, maxDelay, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
listener.onComplete();
|
listener.onComplete();
|
||||||
|
|
|
@ -254,7 +254,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn("We don't have data for that refresh message in our map.");
|
log.debug("We don't have data for that refresh message in our map. That is expected if we missed the data publishing.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue