Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix premature disconnections from seeds #5057

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f169cf1
Refactoring: Move PeerType outside of Connection
chimp1984 Jan 6, 2021
2c8c9ac
Add onMessageSent method to MessageListener
chimp1984 Jan 6, 2021
15cd42d
Add InitialDataRequest and InitialDataResponse marker interface for
chimp1984 Jan 6, 2021
809484e
Refactoring: Rename INITIAL_DATA_REQUEST to INITIAL_DATA_EXCHANGE
chimp1984 Jan 6, 2021
0f7a69d
Add ConnectionState class
chimp1984 Jan 6, 2021
86d0f96
Remove PeerType from Connection. Use ConnectionState instead.
chimp1984 Jan 6, 2021
0bb9d15
Fix null pointer
chimp1984 Jan 6, 2021
5f977ff
Use isSeedNode
chimp1984 Jan 6, 2021
e1b1781
Remove PeerType.SEED_NODE
chimp1984 Jan 6, 2021
3d55c16
Update display string and UI representation
chimp1984 Jan 6, 2021
acad31f
Do sorting at candidates stream.
chimp1984 Jan 6, 2021
4d64fac
Refactor: Rename lastInitialDataExchangeMessageTimeStamp to lastIniti…
chimp1984 Jan 6, 2021
cf4d89d
Behaviour change:
chimp1984 Jan 6, 2021
5628b7b
Refactor:
chimp1984 Jan 6, 2021
34230f4
Fix wrong return value for getMaxConnections
chimp1984 Jan 6, 2021
7414df0
Behaviour change: Remove removeSuperfluousSeedNodes method
chimp1984 Jan 6, 2021
769a78f
Behaviour change: Remove setAllowDisconnectSeedNodes method
chimp1984 Jan 6, 2021
c7bc772
Add safety filter to removeAnonymousPeers
chimp1984 Jan 6, 2021
3fa2242
Set expectedRequests to 5 in case of fullDaoNode as
chimp1984 Jan 6, 2021
347e680
Use OS independent double line breaks for better readability
chimp1984 Jan 6, 2021
a346db6
Handle BundleOfEnvelopes in ConnectionState
chimp1984 Jan 6, 2021
d13b7e7
Add seed node info, add line break
chimp1984 Jan 6, 2021
082cc33
Fix wrong param in addToMap
chimp1984 Jan 6, 2021
a996754
Improve log
chimp1984 Jan 6, 2021
8865d9b
Fix node display
chimp1984 Jan 6, 2021
14008a6
Add formatDurationAsWords to Utilities in common
chimp1984 Jan 6, 2021
379fec8
Fix translation string
chimp1984 Jan 6, 2021
63a87de
Add missing stub to mock
chimp1984 Jan 6, 2021
1dc71c9
Increase delay for reset
chimp1984 Jan 6, 2021
d8f9581
Ignore test
chimp1984 Jan 6, 2021
4aecd75
Add bytes sent/received to ConnectionStatistics
chimp1984 Jan 6, 2021
e0e1443
Add RRT for request / response
chimp1984 Jan 6, 2021
a1cb6d5
If duration is 0 we return "0.000 seconds" instead of empty string
chimp1984 Jan 6, 2021
bda9ebe
Change print statistics period to 5 min.
chimp1984 Jan 6, 2021
8ccfd65
Prevent calling shutdown at TorNetworkNode twice.
chimp1984 Jan 6, 2021
3f8972b
Call init after setting connectionState and connectionStatistics
chimp1984 Jan 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 10 additions & 15 deletions common/src/main/java/bisq/common/util/Utilities.java
Expand Up @@ -534,7 +534,7 @@ public static String readableFileSize(long size) {
}

// Substitute for FormattingUtils if there is no dependency to core
public static String formatDurationAsWords(long durationMillis, boolean showSeconds, boolean showZeroValues) {
public static String formatDurationAsWords(long durationMillis) {
String format = "";
String second = "second";
String minute = "minute";
Expand All @@ -549,11 +549,7 @@ public static String formatDurationAsWords(long durationMillis, boolean showSeco
format = "d\' " + days + ", \'";
}

if (showSeconds) {
format += "H\' " + hours + ", \'m\' " + minutes + ", \'s\' " + seconds + "\'";
} else {
format += "H\' " + hours + ", \'m\' " + minutes + "\'";
}
format += "H\' " + hours + ", \'m\' " + minutes + ", \'s\'.\'S\' " + seconds + "\'";

String duration = durationMillis > 0 ? DurationFormatUtils.formatDuration(durationMillis, format) : "";

Expand All @@ -562,15 +558,14 @@ public static String formatDurationAsWords(long durationMillis, boolean showSeco
duration = StringUtils.replacePattern(duration, "^1 " + hours + "|\\b1 " + hours, "1 " + hour);
duration = StringUtils.replacePattern(duration, "^1 " + days + "|\\b1 " + days, "1 " + day);

if (!showZeroValues) {
duration = duration.replace(", 0 seconds", "");
duration = duration.replace(", 0 minutes", "");
duration = duration.replace(", 0 hours", "");
duration = StringUtils.replacePattern(duration, "^0 days, ", "");
duration = StringUtils.replacePattern(duration, "^0 hours, ", "");
duration = StringUtils.replacePattern(duration, "^0 minutes, ", "");
duration = StringUtils.replacePattern(duration, "^0 seconds, ", "");
}
duration = duration.replace(", 0 seconds", "");
duration = duration.replace(", 0 minutes", "");
duration = duration.replace(", 0 hours", "");
duration = StringUtils.replacePattern(duration, "^0 days, ", "");
duration = StringUtils.replacePattern(duration, "^0 hours, ", "");
duration = StringUtils.replacePattern(duration, "^0 minutes, ", "");
duration = StringUtils.replacePattern(duration, "^0 seconds, ", "");

return duration.trim();
}
}
2 changes: 1 addition & 1 deletion core/src/main/resources/i18n/displayStrings.properties
Expand Up @@ -1300,7 +1300,7 @@ settings.net.chainHeight=Bisq: {0} | Peers: {1}
settings.net.ips=[IP address:port | host name:port | onion address:port] (comma separated). Port can be omitted if default is used (8333).
settings.net.seedNode=Seed node
settings.net.directPeer=Peer (direct)
settings.net.initialDataExchange=Initial data exchange with {0}
settings.net.initialDataExchange={0} [Bootstrapping]
settings.net.peer=Peer
settings.net.inbound=inbound
settings.net.outbound=outbound
Expand Down
Expand Up @@ -144,7 +144,7 @@
<PropertyValueFactory property="receivedBytes"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="peerTypeColumn" minWidth="100" maxWidth="100">
<TableColumn fx:id="peerTypeColumn" minWidth="170" maxWidth="170">
<cellValueFactory>
<PropertyValueFactory property="peerType"/>
</cellValueFactory>
Expand Down
Expand Up @@ -43,7 +43,7 @@ public class ConnectionState implements MessageListener {
// if it exceeds its limits the connectionCreationTimeStamp and lastInitialDataExchangeMessageTimeStamp can be
// used to set priorities for closing connections.
private static final long PEER_RESET_TIMER_DELAY_SEC = TimeUnit.MINUTES.toSeconds(4);
private static final long COMPLETED_TIMER_DELAY_SEC = 2;
private static final long COMPLETED_TIMER_DELAY_SEC = 10;

// Number of expected requests in standard case. Can be different according to network conditions.
// Is different for LiteDaoNodes and FullDaoNodes
Expand Down Expand Up @@ -126,7 +126,9 @@ private void onInitialDataExchange() {
private void maybeResetInitialDataExchangeType() {
if (numInitialDataResponses >= expectedRequests) {
// We have received the expected messages from initial data requests. We delay a bit the reset
// to give time for processing the response.
// to give time for processing the response and more tolerance to edge cases where we expect more responses.
// Reset to PEER does not mean disconnection as well, but just that this connection has lower priority and
// runs higher risk for getting disconnected.
if (initialDataExchangeCompletedTimer == null) {
initialDataExchangeCompletedTimer = UserThread.runAfter(this::resetInitialDataExchangeType, COMPLETED_TIMER_DELAY_SEC);
}
Expand Down
Expand Up @@ -23,7 +23,6 @@
import bisq.common.proto.network.NetworkEnvelope;
import bisq.common.util.Utilities;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -57,25 +56,32 @@ public void shutDown() {
public String getInfo() {
String ls = System.lineSeparator();
long now = System.currentTimeMillis();
String conInstance = connection instanceof InboundConnection ? "Inbound connection from" : "Outbound connection to";
String age = connectionCreationTimeStamp > 0 ? Utilities.formatDurationAsWords(now - connectionCreationTimeStamp, true, true) :
String conInstance = connection instanceof InboundConnection ? "Inbound" : "Outbound";
String age = connectionCreationTimeStamp > 0 ?
Utilities.formatDurationAsWords(now - connectionCreationTimeStamp) :
"N/A";
return String.format("%s %s%s " +
"of type %s " +
"was creation on %s " +
"with UID %s." + ls +
"Connection age: %s" + ls +
"Last message sent/received %s ms ago." + ls +
String lastMsg = lastMessageTimestamp > 0 ?
Utilities.formatDurationAsWords(now - lastMessageTimestamp) :
"N/A";
String peer = connection.getPeersNodeAddressOptional()
.map(NodeAddress::getFullAddress)
.orElse("[address not known yet]");
return String.format(
"Age: %s" + ls +
"Peer: %s%s " + ls +
"Type: %s " + ls +
"Direction: %s" + ls +
"UID: %s" + ls +
"Last message sent/received: %s" + ls +
"Sent data: %s;" + ls +
"Received data: %s;",
conInstance,
connectionState.isSeedNode() ? "seed node " : "",
connection.getPeersNodeAddressOptional().map(NodeAddress::getFullAddress).orElse("[address not known yet]"),
age,
connectionState.isSeedNode() ? "[Seed node] " : "",
peer,
connectionState.getPeerType().name(),
connectionCreationTimeStamp > 0 ? new Date(connectionCreationTimeStamp) : "N/A",
conInstance,
connection.getUid(),
age,
lastMessageTimestamp > 0 ? now - lastMessageTimestamp : "N/A",
lastMsg,
sentDataMap.toString(),
receivedDataMap.toString());
}
Expand Down
4 changes: 2 additions & 2 deletions p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java
Expand Up @@ -808,9 +808,9 @@ private void printStatistics() {
StringBuilder sb = new StringBuilder("Connection statistics: " + ls);
AtomicInteger counter = new AtomicInteger();
networkNode.getAllConnections().stream()
.sorted(Comparator.comparingLong(o -> o.getStatistic().getLastActivityTimestamp()))
.sorted(Comparator.comparingLong(o -> o.getConnectionStatistics().getConnectionCreationTimeStamp()))
.forEach(e -> sb.append(ls).append("Connection ")
.append(counter.incrementAndGet()).append(": ")
.append(counter.incrementAndGet()).append(ls)
.append(e.getConnectionStatistics().getInfo()).append(ls));
log.error(sb.toString());
}
Expand Down
13 changes: 13 additions & 0 deletions p2p/src/test/java/bisq/network/p2p/MockNode.java
Expand Up @@ -19,6 +19,7 @@

import bisq.network.p2p.network.Connection;
import bisq.network.p2p.network.ConnectionState;
import bisq.network.p2p.network.ConnectionStatistics;
import bisq.network.p2p.network.InboundConnection;
import bisq.network.p2p.network.NetworkNode;
import bisq.network.p2p.network.OutboundConnection;
Expand Down Expand Up @@ -71,9 +72,15 @@ public MockNode(int maxConnections) throws IOException {

public void addInboundConnection(PeerType peerType) {
InboundConnection inboundConnection = mock(InboundConnection.class);

ConnectionStatistics connectionStatistics = mock(ConnectionStatistics.class);
when(connectionStatistics.getConnectionCreationTimeStamp()).thenReturn(0L);
when(inboundConnection.getConnectionStatistics()).thenReturn(connectionStatistics);

ConnectionState connectionState = mock(ConnectionState.class);
when(connectionState.getPeerType()).thenReturn(peerType);
when(inboundConnection.getConnectionState()).thenReturn(connectionState);

Statistic statistic = mock(Statistic.class);
long lastActivityTimestamp = System.currentTimeMillis();
when(statistic.getLastActivityTimestamp()).thenReturn(lastActivityTimestamp);
Expand All @@ -84,9 +91,15 @@ public void addInboundConnection(PeerType peerType) {

public void addOutboundConnection(PeerType peerType) {
OutboundConnection outboundConnection = mock(OutboundConnection.class);

ConnectionStatistics connectionStatistics = mock(ConnectionStatistics.class);
when(connectionStatistics.getConnectionCreationTimeStamp()).thenReturn(0L);
when(outboundConnection.getConnectionStatistics()).thenReturn(connectionStatistics);

ConnectionState connectionState = mock(ConnectionState.class);
when(connectionState.getPeerType()).thenReturn(peerType);
when(outboundConnection.getConnectionState()).thenReturn(connectionState);

Statistic statistic = mock(Statistic.class);
long lastActivityTimestamp = System.currentTimeMillis();
when(statistic.getLastActivityTimestamp()).thenReturn(lastActivityTimestamp);
Expand Down