Compare commits

...

3 Commits

Author SHA1 Message Date
catbref
d8c5e557d8 Update uiLocalServers, autoUpdateRepos and bump to v1.2.1 2020-06-30 15:41:53 +01:00
catbref
984e8b5227 Network optimizations: if we're not up to date then don't request, or send, unconfirmed transaction lists 2020-06-30 14:26:12 +01:00
catbref
469bf2a63e Improve inbound peer handshaking
If a node accepts a connection from an inbound peer
then remote peer will send RESPONSE first
and local node would previously change handshaking state
to COMPLETED while computing their own RESPONSE.

This meant that the local node would sometimes also start
sending post-handshake messages to the remote peer,
e.g. TRANSACTION_SIGNATURES.

Remote peer is only expecting a RESPONSE message, so would
close connection.

So we introduce an extra handshaking state "RESPONDING" for use
by local node while they compute RESPONSE in a separate thread.
Once the RESPONSE has been sent, local node moves to COMPLETED
state and called onHandshakeCompleted() as per usual.

Note that the code path when connecting outbound to a remote peer
is not changed, and the RESPONDING state is not used.

Also in this commit:

Network.onPeerReady now bypasses call to onMessage and instead
calls onHandshakingMessage() directly to avoid race condition
where peer's handshake status could change between
onPeerReady's caller and onMessage() calling peer.getHandshakeStatus()
2020-06-30 13:37:14 +01:00
5 changed files with 45 additions and 11 deletions

View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.qortal</groupId>
<artifactId>qortal</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
<packaging>jar</packaging>
<properties>
<bitcoinj.version>0.15.5</bitcoinj.version>

View File

@@ -765,8 +765,10 @@ public class Controller extends Thread {
BlockData latestBlockData = getChainTip();
network.broadcast(peer -> network.buildHeightMessage(peer, latestBlockData));
// Send (if outbound) / Request unconfirmed transaction signatures
network.broadcast(network::buildGetUnconfirmedTransactionsMessage);
// Request unconfirmed transaction signatures, but only if we're up-to-date.
// If we're NOT up-to-date then priority is synchronizing first
if (isUpToDate())
network.broadcast(network::buildGetUnconfirmedTransactionsMessage);
}
public void onMintingPossibleChange(boolean isMintingPossible) {
@@ -1040,7 +1042,12 @@ public class Controller extends Thread {
private void onNetworkGetUnconfirmedTransactionsMessage(Peer peer, Message message) {
try (final Repository repository = RepositoryManager.getRepository()) {
List<byte[]> signatures = repository.getTransactionRepository().getUnconfirmedTransactionSignatures();
List<byte[]> signatures = Collections.emptyList();
// If we're NOT up-to-date then don't send out unconfirmed transactions
// as it's possible they are already included in a later block that we don't have.
if (isUpToDate())
signatures = repository.getTransactionRepository().getUnconfirmedTransactionSignatures();
Message transactionSignaturesMessage = new TransactionSignaturesMessage(signatures);
if (!peer.sendMessage(transactionSignaturesMessage))

View File

@@ -164,6 +164,11 @@ public enum Handshake {
peer.setPeersNodeId(Crypto.toNodeAddress(peersPublicKey));
// For inbound peers, we need to go into interim holding state while we compute RESPONSE
if (!peer.isOutbound())
return RESPONDING;
// Handshake completed!
return COMPLETED;
}
@@ -184,22 +189,42 @@ public enum Handshake {
Message responseMessage = new ResponseMessage(nonce, data);
if (!peer.sendMessage(responseMessage))
peer.disconnect("failed to send RESPONSE");
// For inbound peers, we should actually be in RESPONDING state.
// So we need to do the extra work to move to COMPLETED state.
if (!peer.isOutbound()) {
peer.setHandshakeStatus(COMPLETED);
Network.getInstance().onHandshakeCompleted(peer);
}
});
responseThread.setDaemon(true);
responseThread.start();
}
},
COMPLETED(null) {
// Interim holding state while we compute RESPONSE to send to inbound peer
RESPONDING(null) {
@Override
public Handshake onMessage(Peer peer, Message message) {
// Handshake completed
// Should never be called
return null;
}
@Override
public void action(Peer peer) {
// Note: this is only called when we've made outbound connection
// Should never be called
}
},
COMPLETED(null) {
@Override
public Handshake onMessage(Peer peer, Message message) {
// Should never be called
return null;
}
@Override
public void action(Peer peer) {
// Note: this is only called if we've made outbound connection
}
};

View File

@@ -635,7 +635,7 @@ public class Network {
/** Called when Peer's thread has setup and is ready to process messages */
public void onPeerReady(Peer peer) {
this.onMessage(peer, null);
onHandshakingMessage(peer, null, Handshake.STARTED);
}
public void onDisconnect(Peer peer) {
@@ -777,7 +777,7 @@ public class Network {
opportunisticMergePeers(peer.toString(), peerV2Addresses);
}
private void onHandshakeCompleted(Peer peer) {
/*pacakge*/ void onHandshakeCompleted(Peer peer) {
LOGGER.debug(String.format("Handshake completed with peer %s", peer));
// Are we already connected to this peer?

View File

@@ -47,7 +47,7 @@ public class Settings {
// UI servers
private int uiPort = 12388;
private String[] uiLocalServers = new String[] {
"localhost", "172.24.1.1", "qor.tal"
"localhost", "127.0.0.1", "172.24.1.1", "qor.tal"
};
private String[] uiRemoteServers = new String[] {
"node1.qortal.org", "node2.qortal.org", "node3.qortal.org", "node4.qortal.org", "node5.qortal.org",
@@ -106,7 +106,9 @@ public class Settings {
// Auto-update sources
private String[] autoUpdateRepos = new String[] {
"https://github.com/QORT/qortal/raw/%s/qortal.update",
"https://raw.githubusercontent.com@151.101.16.133/QORT/qortal/%s/qortal.update"
"https://raw.githubusercontent.com@151.101.16.133/QORT/qortal/%s/qortal.update",
"https://github.com/Qortal/qortal/raw/%s/qortal.update",
"https://raw.githubusercontent.com@151.101.16.133/Qortal/qortal/%s/qortal.update"
};
/** Array of NTP server hostnames. */