Fix issues with delayed mailbox messages, handle ui state when peer is offline

This commit is contained in:
Manfred Karrer 2016-03-11 16:44:25 +01:00
parent 4fc3b00fa4
commit 7c63e5ab00
11 changed files with 55 additions and 49 deletions

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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);
} }
} }

View file

@ -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);
} }
} }

View file

@ -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:

View file

@ -93,9 +93,13 @@ public class BuyerStep4View extends TradeStepView {
@Override @Override
protected void addContent() { protected void addContent() {
addTradeInfoBlock(); addTradeInfoBlock();
blockTextField = addLabelTextField(gridPane, gridRow, "Block(s) to wait until lock time elapsed:", "").second; if (model.getLockTime() > 0) {
timeTextField = addLabelTextField(gridPane, ++gridRow, "Approx. date when payout gets unlocked:").second; blockTextField = addLabelTextField(gridPane, gridRow, "Block(s) to wait until lock time elapsed:", "").second;
GridPane.setRowSpan(tradeInfoTitledGroupBg, 5); timeTextField = addLabelTextField(gridPane, ++gridRow, "Approx. date when payout gets unlocked:").second;
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() {
return "Wait until payout lock time is over"; if (model.getLockTime() > 0)
return "Wait until payout lock time is over";
else
return "Sending payout transaction to peer";
} }
@Override @Override
protected String getInfoText() { protected String getInfoText() {
return "The payout transaction is signed and finalized by both parties.\n" + if (model.getLockTime() > 0)
"For reducing bank chargeback risks the payout transaction is blocked by a lock time.\n" + return "The payout transaction is signed and finalized by both parties.\n" +
"After that lock time is over the payout transaction gets published and you receive " + "For reducing bank chargeback risks the payout transaction is blocked by a lock time.\n" +
"your bitcoin."; "After that lock time is over the payout transaction gets published and you receive " +
"your bitcoin.";
else
return "We are sending the payout transaction to the other peer.";
} }
@ -137,9 +147,12 @@ public class BuyerStep4View extends TradeStepView {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void updateDateFromBlockHeight(long bestBlocKHeight) { private void updateDateFromBlockHeight(long bestBlocKHeight) {
long missingBlocks = model.getLockTime() - bestBlocKHeight; if (model.getLockTime() > 0) {
blockTextField.setText(String.valueOf(missingBlocks)); long missingBlocks = model.getLockTime() - bestBlocKHeight;
timeTextField.setText(model.getOpenDisputeTimeAsFormattedDate());
blockTextField.setText(String.valueOf(missingBlocks));
timeTextField.setText(model.getOpenDisputeTimeAsFormattedDate());
}
} }

View file

@ -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")));

View file

@ -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();
} }

View file

@ -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);
} }

View file

@ -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();

View file

@ -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;
} }
} }