diff --git a/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java b/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java index dd3f4314db..e4011aa2d2 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java +++ b/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java @@ -17,15 +17,10 @@ package io.bitsquare.common.crypto; -import io.bitsquare.app.Version; - import java.io.Serializable; import java.security.PublicKey; public final class DecryptedPayloadWithPubKey implements Serializable { - // That object is sent over the wire, so we need to take care of version compatibility. - private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; - public final Serializable payload; public final PublicKey sigPublicKey; diff --git a/common/src/main/java/io/bitsquare/common/crypto/Encryption.java b/common/src/main/java/io/bitsquare/common/crypto/Encryption.java index b945430389..a8e7ce1d1d 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/Encryption.java +++ b/common/src/main/java/io/bitsquare/common/crypto/Encryption.java @@ -81,7 +81,6 @@ public class Encryption { return cipher.doFinal(encryptedPayload); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | NoSuchProviderException e) { - e.printStackTrace(); throw new CryptoException(e); } } diff --git a/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java b/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java index af9db573e7..b701ccd054 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java +++ b/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java @@ -34,7 +34,7 @@ import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.spec.*; -// TODO: use a password protection for storage? +// TODO: use a password protection for key storage public class KeyStorage { private static final Logger log = LoggerFactory.getLogger(KeyStorage.class); @@ -140,6 +140,7 @@ public class KeyStorage { if (!storageDir.exists()) storageDir.mkdir(); + PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded()); try (FileOutputStream fos = new FileOutputStream(storageDir + "/" + name + ".key")) { fos.write(pkcs8EncodedKeySpec.getEncoded()); diff --git a/core/pom.xml b/core/pom.xml index f2f31c4112..ca2122a6eb 100755 --- a/core/pom.xml +++ b/core/pom.xml @@ -49,29 +49,6 @@ ${project.parent.version} - - com.msopentech.thali - universal - 0.0.3-SNAPSHOT - - - org.slf4j - slf4j-simple - - - - - com.msopentech.thali - java - 0.0.3-SNAPSHOT - - - org.slf4j - slf4j-simple - - - - org.bitcoinj bitcoinj-core diff --git a/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java b/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java index fb1504bc11..d48a451bcf 100644 --- a/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java +++ b/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java @@ -173,18 +173,12 @@ public class ArbitratorManager { .collect(Collectors.toMap(Arbitrator::getArbitratorAddress, Function.identity())); arbitratorsObservableMap.putAll(filtered); - - log.debug("filtered arbitrators: " + arbitratorsObservableMap.values()); - log.trace("user.getAcceptedArbitrators(): " + user.getAcceptedArbitrators().toString()); - // we need to remove accepted arbitrators which are not available anymore if (user.getAcceptedArbitrators() != null) { List removeList = user.getAcceptedArbitrators().stream() .filter(e -> !arbitratorsObservableMap.containsValue(e)) .collect(Collectors.toList()); removeList.stream().forEach(user::removeAcceptedArbitrator); - log.trace("removeList arbitrators: " + removeList.toString()); - log.trace("user.getAcceptedArbitrators(): " + user.getAcceptedArbitrators().toString()); // if we don't have any arbitrator anymore we set all matching if (user.getAcceptedArbitrators().isEmpty()) { @@ -192,8 +186,6 @@ public class ArbitratorManager { .filter(arbitrator -> user.hasMatchingLanguage(arbitrator)) .forEach(arbitrator -> user.addAcceptedArbitrator(arbitrator)); } - - log.trace("user.getAcceptedArbitrators(): " + user.getAcceptedArbitrators().toString()); } } diff --git a/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java b/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java index a0d6aa5353..0e665c03ca 100644 --- a/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java +++ b/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java @@ -153,7 +153,8 @@ public class DisputeManager { log.debug("decryptedMessageWithPubKey.message " + message); if (message instanceof DisputeMessage) { dispatchMessage((DisputeMessage) message); - p2PService.removeEntryFromMailbox(decryptedMessageWithPubKey); + //TODO + //p2PService.removeEntryFromMailbox(decryptedMessageWithPubKey); } }); decryptedMailboxMessageWithPubKeys.clear(); diff --git a/core/src/main/java/io/bitsquare/btc/TradeWalletService.java b/core/src/main/java/io/bitsquare/btc/TradeWalletService.java index ae6f1f6b75..6773842008 100644 --- a/core/src/main/java/io/bitsquare/btc/TradeWalletService.java +++ b/core/src/main/java/io/bitsquare/btc/TradeWalletService.java @@ -987,7 +987,7 @@ public class TradeWalletService { private void verifyTransaction(Transaction transaction) throws TransactionVerificationException { try { - log.trace("Verify transaction"); + log.trace("Verify transaction " + transaction); transaction.verify(); } catch (Throwable t) { t.printStackTrace(); diff --git a/core/src/main/java/io/bitsquare/trade/TradeManager.java b/core/src/main/java/io/bitsquare/trade/TradeManager.java index 075b4b5f1c..29b873bd54 100644 --- a/core/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/core/src/main/java/io/bitsquare/trade/TradeManager.java @@ -205,6 +205,7 @@ public class TradeManager { // after we are authenticated we remove mailbox messages. DecryptedMsgWithPubKey mailboxMessage = trade.getMailboxMessage(); if (mailboxMessage != null) { + log.trace("initPendingTrades/removeEntryFromMailbox mailboxMessage = " + mailboxMessage); p2PService.removeEntryFromMailbox(mailboxMessage); trade.setMailboxMessage(null); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/disputes/DisputesView.java b/gui/src/main/java/io/bitsquare/gui/main/disputes/DisputesView.java index 3393326377..ca46631dae 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/disputes/DisputesView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/disputes/DisputesView.java @@ -82,8 +82,6 @@ public class DisputesView extends ActivatableViewAndModel boolean isArbitrator = arbitratorManager.getArbitratorsObservableMap().values().stream() .filter(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(keyRing.getPubKeyRing())) .findAny().isPresent(); - log.debug("arbitratorManager.getArbitratorsObservableMap() " + arbitratorManager.getArbitratorsObservableMap().size()); - log.debug("updateArbitratorsDisputesTabDisableState isArbitrator=" + isArbitrator); arbitratorsDisputesTab.setDisable(!isArbitrator); if (arbitratorsDisputesTab.getContent() != null) arbitratorsDisputesTab.getContent().setDisable(!isArbitrator); diff --git a/gui/src/main/java/io/bitsquare/gui/main/market/MarketViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/market/MarketViewModel.java index b1504f0b71..7e428ac21f 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/market/MarketViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/MarketViewModel.java @@ -68,7 +68,6 @@ class MarketViewModel extends ActivatableViewModel { protected void activate() { offerBookListItems.addListener(listChangeListener); offerBook.fillOfferBookListItems(); - //updateChartData(offerBookListItems); } @Override diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModel.java index d35b08c9d3..3f9985581c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModel.java @@ -122,8 +122,7 @@ class OfferBookViewModel extends ActivatableViewModel { public void onSetTradeCurrency(TradeCurrency tradeCurrency) { this.tradeCurrency = tradeCurrency; tradeCurrencyCode.set(tradeCurrency.getCode()); - /* if (!(tradeCurrency instanceof AllTradeCurrenciesEntry))*/ - //offerBook.getOffers(tradeCurrencyCode.get()); + filterList(); } public void onSetPaymentMethod(PaymentMethod paymentMethod) { @@ -273,11 +272,12 @@ class OfferBookViewModel extends ActivatableViewModel { filteredItems.setPredicate(offerBookListItem -> { Offer offer = offerBookListItem.getOffer(); boolean directionResult = offer.getDirection() != direction; + boolean currencyResult = offer.getCurrencyCode().equals(tradeCurrency.getCode()); boolean paymentMethodResult = true; - if (!(paymentMethod instanceof AllPaymentMethodsEntry)) + if (!(paymentMethod instanceof AllPaymentMethodsEntry)) paymentMethodResult = offer.getPaymentMethod().equals(paymentMethod); - return directionResult && paymentMethodResult; + return directionResult && currencyResult && paymentMethodResult; }); } diff --git a/network/libs/java-0.0.3-SNAPSHOT.jar b/network/libs/java-0.0.3-SNAPSHOT.jar new file mode 100644 index 0000000000..b28a30afce Binary files /dev/null and b/network/libs/java-0.0.3-SNAPSHOT.jar differ diff --git a/network/libs/universal-0.0.3-SNAPSHOT.jar b/network/libs/universal-0.0.3-SNAPSHOT.jar new file mode 100644 index 0000000000..3a2a7dbfa5 Binary files /dev/null and b/network/libs/universal-0.0.3-SNAPSHOT.jar differ diff --git a/network/pom.xml b/network/pom.xml index e4677ec39f..428b5dfae5 100644 --- a/network/pom.xml +++ b/network/pom.xml @@ -22,6 +22,8 @@ com.msopentech.thali universal 0.0.3-SNAPSHOT + system + ${basedir}/libs/universal-0.0.3-SNAPSHOT.jar org.slf4j @@ -33,6 +35,8 @@ com.msopentech.thali java 0.0.3-SNAPSHOT + system + ${basedir}/libs/java-0.0.3-SNAPSHOT.jar org.slf4j diff --git a/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java b/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java index 3a1d4d551f..7a5eaa14c7 100644 --- a/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java +++ b/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java @@ -1,10 +1,14 @@ package io.bitsquare.crypto; +import io.bitsquare.app.Version; import io.bitsquare.common.crypto.SealedAndSigned; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.messaging.MailboxMessage; -public class SealedAndSignedMessage implements MailboxMessage { +public final class SealedAndSignedMessage implements MailboxMessage { + // That object is sent over the wire, so we need to take care of version compatibility. + private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; + public final SealedAndSigned sealedAndSigned; public final Address peerAddress; diff --git a/network/src/main/java/io/bitsquare/p2p/P2PService.java b/network/src/main/java/io/bitsquare/p2p/P2PService.java index 658ab740aa..8df1e8d70f 100644 --- a/network/src/main/java/io/bitsquare/p2p/P2PService.java +++ b/network/src/main/java/io/bitsquare/p2p/P2PService.java @@ -141,24 +141,24 @@ public class P2PService { @Override public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) { + checkArgument(peerAddress.equals(connection.getPeerAddress())); authenticatedPeerAddresses.add(peerAddress); if (!authenticatedToFirstPeer) { authenticatedToFirstPeer = true; - Address address = connection.getPeerAddress(); - SettableFuture future = sendMessage(address, + SettableFuture future = sendMessage(peerAddress, new GetDataSetMessage(addToListAndGetNonce())); Futures.addCallback(future, new FutureCallback() { @Override public void onSuccess(@Nullable Connection connection) { - log.info("onPeerAddressAuthenticated Send GetAllDataMessage to " + address + " succeeded."); - connectedSeedNodes.add(address); + log.info("onPeerAddressAuthenticated Send GetAllDataMessage to " + peerAddress + " succeeded."); + connectedSeedNodes.add(peerAddress); } @Override public void onFailure(Throwable throwable) { - log.warn("onPeerAddressAuthenticated Send GetAllDataMessage to " + address + " failed. " + + log.warn("onPeerAddressAuthenticated Send GetAllDataMessage to " + peerAddress + " failed. " + "Exception:" + throwable.getMessage()); } }); @@ -171,9 +171,8 @@ public class P2PService { @Override public void onDisconnect(Reason reason, Connection connection) { - Address peerAddress = connection.getPeerAddress(); - if (peerAddress != null) - authenticatedPeerAddresses.remove(peerAddress); + if (connection.isAuthenticated()) + authenticatedPeerAddresses.remove(connection.getPeerAddress()); } @Override @@ -195,11 +194,15 @@ public class P2PService { }); } } else if (message instanceof DataSetMessage) { - log.trace("Received AllDataMessage: " + message); + DataSetMessage dataSetMessage = (DataSetMessage) message; + StringBuilder sb = new StringBuilder("Received DataSetMessage:\n\n"); + dataSetMessage.set.stream().forEach(e -> sb.append(e.toString() + "\n")); + sb.append("\n"); + log.trace(sb.toString()); // we keep that connection open as the bootstrapping peer will use that for the authentication // as we are not authenticated yet the data adding will not be broadcasted - HashSet set = ((DataSetMessage) message).set; + HashSet set = dataSetMessage.set; set.stream().forEach(e -> dataStorage.add(e, connection.getPeerAddress())); dataReceived(); @@ -664,7 +667,7 @@ public class P2PService { e -> e.onMailboxMessageAdded(decryptedMsgWithPubKey, senderAddress))); } } catch (CryptoException e) { - log.trace("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us."); + log.trace("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us. " + e.getMessage()); } } } diff --git a/network/src/main/java/io/bitsquare/p2p/network/Connection.java b/network/src/main/java/io/bitsquare/p2p/network/Connection.java index 96514c9de6..75fdfb97d0 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/Connection.java +++ b/network/src/main/java/io/bitsquare/p2p/network/Connection.java @@ -90,6 +90,7 @@ public class Connection { lastActivityDate = new Date(); + log.trace("\nNew connection created " + this.toString()); connectionListener.onConnection(this); } @@ -148,10 +149,6 @@ public class Connection { // Getters /////////////////////////////////////////////////////////////////////////////////////////// - public Socket getSocket() { - return socket; - } - @Nullable public Address getPeerAddress() { return peerAddress; @@ -170,14 +167,6 @@ public class Connection { } - /////////////////////////////////////////////////////////////////////////////////////////// - // Setters - /////////////////////////////////////////////////////////////////////////////////////////// - - public void setPeerAddress(Address peerAddress) { - this.peerAddress = peerAddress; - } - /////////////////////////////////////////////////////////////////////////////////////////// // ShutDown /////////////////////////////////////////////////////////////////////////////////////////// @@ -198,6 +187,7 @@ public class Connection { if (!shutDownInProgress) { log.info("\n\nShutDown connection:" + "\npeerAddress=" + peerAddress + + "\nobjectId=" + getObjectId() + "\nuid=" + getUid() + "\nisAuthenticated=" + isAuthenticated + "\nsocket.getPort()=" + socket.getPort() @@ -205,9 +195,12 @@ public class Connection { log.debug("ShutDown " + this.getObjectId()); log.debug("ShutDown connection requested. Connection=" + this.toString()); - shutDownInProgress = true; - inputHandlerStopped = true; if (!stopped) { + stopped = true; + shutDownInProgress = true; + inputHandlerStopped = true; + connectionListener.onDisconnect(ConnectionListener.Reason.SHUT_DOWN, Connection.this); + if (sendCloseConnectionMessage) { sendMessage(new CloseConnectionMessage()); try { @@ -217,8 +210,6 @@ public class Connection { Thread.currentThread().interrupt(); } } - stopped = true; - connectionListener.onDisconnect(ConnectionListener.Reason.SHUT_DOWN, Connection.this); try { socket.close(); @@ -282,7 +273,7 @@ public class Connection { @Override public String toString() { return "Connection{" + - "OBJECT ID=" + super.toString().split("@")[1] + + "objectId=" + getObjectId() + ", uid=" + uid + ", port=" + port + ", isAuthenticated=" + isAuthenticated + @@ -310,7 +301,7 @@ public class Connection { try { log.trace("InputHandler waiting for incoming messages connection=" + Connection.this.getObjectId()); Object rawInputObject = in.readObject(); - log.trace("New data arrived at inputHandler of connection=" + Connection.this.getObjectId() + log.trace("New data arrived at inputHandler of connection=" + Connection.this.toString() + " rawInputObject " + rawInputObject); int size = ByteArrayUtils.objectToByteArray(rawInputObject).length; @@ -339,10 +330,12 @@ public class Connection { if (serializable instanceof Message) { lastActivityDate = new Date(); Message message = (Message) serializable; - if (message instanceof CloseConnectionMessage) + if (message instanceof CloseConnectionMessage) { + inputHandlerStopped = true; shutDown(false); - else + } else { executorService.submit(() -> messageListener.onMessage(message, Connection.this)); + } } else { reportIllegalRequest(IllegalRequest.InvalidDataType); } @@ -355,6 +348,9 @@ public class Connection { reportIllegalRequest(IllegalRequest.MaxSizeExceeded); } } catch (IOException | ClassNotFoundException e) { + log.error("Exception at Connection.InputHandler. Connection=" + Connection.this.toString()); + log.error("Exception=" + e.getMessage()); + e.printStackTrace(); inputHandlerStopped = true; handleConnectionException(e); } diff --git a/network/src/main/java/io/bitsquare/p2p/network/LocalhostNetworkNode.java b/network/src/main/java/io/bitsquare/p2p/network/LocalhostNetworkNode.java index d4ce538d83..b2a22a1a7b 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/LocalhostNetworkNode.java +++ b/network/src/main/java/io/bitsquare/p2p/network/LocalhostNetworkNode.java @@ -24,8 +24,8 @@ import java.util.function.Consumer; public class LocalhostNetworkNode extends NetworkNode { private static final Logger log = LoggerFactory.getLogger(LocalhostNetworkNode.class); - private static int simulateTorDelayTorNode = 0; - private static int simulateTorDelayHiddenService = 0; + private static int simulateTorDelayTorNode = 2 * 1000; + private static int simulateTorDelayHiddenService = 2 * 1000; private Address address; public static void setSimulateTorDelayTorNode(int simulateTorDelayTorNode) { @@ -94,7 +94,10 @@ public class LocalhostNetworkNode extends NetworkNode { long ts = System.currentTimeMillis(); log.trace("[simulation] Create TorNode"); if (simulateTorDelayTorNode > 0) Thread.sleep(simulateTorDelayTorNode); - log.trace("\n\n##### TorNode created [simulation]. Took " + (System.currentTimeMillis() - ts) + " ms\n\n"); + log.info("\n\n############################################################\n" + + "TorNode created [simulation]:" + + "\nTook " + (System.currentTimeMillis() - ts) + " ms" + + "\n############################################################\n"); return null; }; ListenableFuture> future = executorService.submit(task); @@ -114,7 +117,10 @@ public class LocalhostNetworkNode extends NetworkNode { long ts = System.currentTimeMillis(); log.debug("[simulation] Create hidden service"); if (simulateTorDelayHiddenService > 0) Thread.sleep(simulateTorDelayHiddenService); - log.debug("\n\n##### Hidden service created [simulation]. Took " + (System.currentTimeMillis() - ts) + " ms\n\n"); + log.info("\n\n############################################################\n" + + "Hidden service created [simulation]:" + + "\nTook " + (System.currentTimeMillis() - ts) + " ms" + + "\n############################################################\n"); return null; }; ListenableFuture future = executorService.submit(task); diff --git a/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java b/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java index e97d63014a..8c0e5b2bf8 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java +++ b/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java @@ -11,9 +11,11 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; -import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import static com.google.common.base.Preconditions.checkNotNull; @@ -22,9 +24,8 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener private static final Logger log = LoggerFactory.getLogger(NetworkNode.class); protected final int port; - private final Map outBoundConnections = new ConcurrentHashMap<>(); - private final Map inBoundAuthenticatedConnections = new ConcurrentHashMap<>(); - private final List inBoundTempConnections = new CopyOnWriteArrayList<>(); + private final List outBoundConnections = new CopyOnWriteArrayList<>(); + private final List inBoundConnections = new CopyOnWriteArrayList<>(); private final List messageListeners = new CopyOnWriteArrayList<>(); private final List connectionListeners = new CopyOnWriteArrayList<>(); protected final List setupListeners = new CopyOnWriteArrayList<>(); @@ -58,32 +59,21 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener Callable task = () -> { Thread.currentThread().setName("Outgoing-connection-to-" + peerAddress); - Connection connection = outBoundConnections.get(peerAddress); + + Optional outboundConnectionOptional = getOutboundConnection(peerAddress); + Connection connection = outboundConnectionOptional.isPresent() ? outboundConnectionOptional.get() : null; if (connection != null && connection.isStopped()) { - // can happen because of threading... log.trace("We have a connection which is already stopped in outBoundConnections. Connection.uid=" + connection.getUid()); - outBoundConnections.remove(peerAddress); + outBoundConnections.remove(connection); connection = null; } if (connection == null) { - Optional connectionOptional = inBoundAuthenticatedConnections.values().stream() - .filter(e -> peerAddress.equals(e.getPeerAddress())) - .findAny(); - if (connectionOptional.isPresent()) - connection = connectionOptional.get(); + Optional inboundConnectionOptional = getInboundConnection(peerAddress); + if (inboundConnectionOptional.isPresent()) connection = inboundConnectionOptional.get(); if (connection != null) - log.trace("We have found a connection in inBoundAuthenticatedConnections. Connection.uid=" + connection.getUid()); - } - if (connection == null) { - Optional connectionOptional = inBoundTempConnections.stream() - .filter(e -> peerAddress.equals(e.getPeerAddress())) - .findAny(); - if (connectionOptional.isPresent()) - connection = connectionOptional.get(); - if (connection != null) - log.trace("We have found a connection in inBoundTempConnections. Connection.uid=" + connection.getUid()); + log.trace("We have found a connection in inBoundConnections. Connection.uid=" + connection.getUid()); } if (connection == null) { @@ -113,7 +103,11 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener NetworkNode.this.onError(throwable); } }); - outBoundConnections.put(peerAddress, connection); + if (!outBoundConnections.contains(connection)) + outBoundConnections.add(connection); + else + log.error("We have already that connection in our list. That must not happen. " + + outBoundConnections + " / connection=" + connection); log.info("\n\nNetworkNode created new outbound connection:" + "\npeerAddress=" + peerAddress.port @@ -144,6 +138,16 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener return resultFuture; } + private Optional getOutboundConnection(Address peerAddress) { + return outBoundConnections.stream() + .filter(e -> peerAddress.equals(e.getPeerAddress())).findAny(); + } + + private Optional getInboundConnection(Address peerAddress) { + return inBoundConnections.stream() + .filter(e -> peerAddress.equals(e.getPeerAddress())).findAny(); + } + public SettableFuture sendMessage(Connection connection, Message message) { final SettableFuture resultFuture = SettableFuture.create(); @@ -164,9 +168,8 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener } public Set getAllConnections() { - Set set = new HashSet<>(inBoundAuthenticatedConnections.values()); - set.addAll(outBoundConnections.values()); - set.addAll(inBoundTempConnections); + Set set = new HashSet<>(inBoundConnections); + set.addAll(outBoundConnections); return set; } @@ -226,22 +229,8 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener public void onDisconnect(Reason reason, Connection connection) { Address peerAddress = connection.getPeerAddress(); log.trace("onDisconnect connection " + connection + ", peerAddress= " + peerAddress); - if (peerAddress != null) { - inBoundAuthenticatedConnections.remove(peerAddress); - outBoundConnections.remove(peerAddress); - } else { - // try to find if we have connection - outBoundConnections.values().stream() - .filter(e -> e.equals(connection)) - .findAny() - .ifPresent(e -> outBoundConnections.remove(e.getPeerAddress())); - inBoundAuthenticatedConnections.values().stream() - .filter(e -> e.equals(connection)) - .findAny() - .ifPresent(e -> inBoundAuthenticatedConnections.remove(e.getPeerAddress())); - } - inBoundTempConnections.remove(connection); - + outBoundConnections.remove(connection); + inBoundConnections.remove(connection); connectionListeners.stream().forEach(e -> e.onDisconnect(reason, connection)); } @@ -280,28 +269,21 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener @Override public void onConnection(Connection connection) { // we still have not authenticated so put it to the temp list - inBoundTempConnections.add(connection); + if (!inBoundConnections.contains(connection)) + inBoundConnections.add(connection); NetworkNode.this.onConnection(connection); } @Override public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) { NetworkNode.this.onPeerAddressAuthenticated(peerAddress, connection); - // now we know the the peers address is correct and we add it to inBoundConnections and - // remove it from tempConnections - inBoundAuthenticatedConnections.put(peerAddress, connection); - inBoundTempConnections.remove(connection); } @Override public void onDisconnect(Reason reason, Connection connection) { Address peerAddress = connection.getPeerAddress(); log.trace("onDisconnect at incoming connection to peerAddress " + peerAddress); - if (peerAddress != null) - inBoundAuthenticatedConnections.remove(peerAddress); - - inBoundTempConnections.remove(connection); - + inBoundConnections.remove(connection); NetworkNode.this.onDisconnect(reason, connection); } diff --git a/network/src/main/java/io/bitsquare/p2p/network/TorNetworkNode.java b/network/src/main/java/io/bitsquare/p2p/network/TorNetworkNode.java index 40bbde28fd..4cf076aef3 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/TorNetworkNode.java +++ b/network/src/main/java/io/bitsquare/p2p/network/TorNetworkNode.java @@ -44,7 +44,7 @@ public class TorNetworkNode extends NetworkNode { private Timer shutDownTimeoutTimer, selfTestTimer, selfTestTimeoutTimer; private TimerTask selfTestTimeoutTask, selfTestTask; private AtomicBoolean selfTestRunning = new AtomicBoolean(false); - private int nonce; + private long nonce; private int errorCounter; private int restartCounter; private Runnable shutDownCompleteHandler; @@ -79,7 +79,7 @@ public class TorNetworkNode extends NetworkNode { selfTestTimeoutTimer.schedule(selfTestTimeoutTask, TIMEOUT); // might be interrupted by timeout task if (selfTestRunning.get()) { - nonce = random.nextInt(); + nonce = random.nextLong(); log.trace("send msg with nonce " + nonce); try { @@ -281,7 +281,10 @@ public class TorNetworkNode extends NetworkNode { TorNode torNode1 = new TorNode( torDir) { }; - log.trace("\n\n##### TorNode created. Took " + (System.currentTimeMillis() - ts) + " ms\n\n"); + log.info("\n\n############################################################\n" + + "TorNode created:" + + "\nTook " + (System.currentTimeMillis() - ts) + " ms" + + "\n############################################################\n"); return torNode1; }; ListenableFuture> future = executorService.submit(task); @@ -303,7 +306,11 @@ public class TorNetworkNode extends NetworkNode { long ts = System.currentTimeMillis(); log.debug("Create hidden service"); HiddenServiceDescriptor hiddenServiceDescriptor = torNode.createHiddenService(port); - log.debug("\n\n##### Hidden service created. Address = " + hiddenServiceDescriptor.getFullAddress() + ". Took " + (System.currentTimeMillis() - ts) + " ms\n\n"); + log.info("\n\n############################################################\n" + + "Hidden service created:" + + "\nAddress=" + hiddenServiceDescriptor.getFullAddress() + + "\nTook " + (System.currentTimeMillis() - ts) + " ms" + + "\n############################################################\n"); return hiddenServiceDescriptor; }; diff --git a/network/src/main/java/io/bitsquare/p2p/network/messages/SelfTestMessage.java b/network/src/main/java/io/bitsquare/p2p/network/messages/SelfTestMessage.java index d81d5fb722..792af1f3c6 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/messages/SelfTestMessage.java +++ b/network/src/main/java/io/bitsquare/p2p/network/messages/SelfTestMessage.java @@ -7,9 +7,9 @@ public final class SelfTestMessage implements Message { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; - public final Integer nonce; + public final long nonce; - public SelfTestMessage(Integer nonce) { + public SelfTestMessage(long nonce) { this.nonce = nonce; } } diff --git a/network/src/main/java/io/bitsquare/p2p/routing/Neighbor.java b/network/src/main/java/io/bitsquare/p2p/routing/Neighbor.java index 804710ea22..f1b07eccdf 100644 --- a/network/src/main/java/io/bitsquare/p2p/routing/Neighbor.java +++ b/network/src/main/java/io/bitsquare/p2p/routing/Neighbor.java @@ -1,26 +1,37 @@ package io.bitsquare.p2p.routing; import io.bitsquare.p2p.Address; +import io.bitsquare.p2p.network.Connection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.io.Serializable; +import java.util.Random; public class Neighbor implements Serializable { private static final Logger log = LoggerFactory.getLogger(Neighbor.class); + public final Connection connection; public final Address address; - private int pingNonce; + private long pingNonce; - public Neighbor(Address address) { - this.address = address; + public Neighbor(Connection connection) { + this.connection = connection; + this.address = connection.getPeerAddress(); + pingNonce = new Random().nextLong(); } - public void setPingNonce(int pingNonce) { - this.pingNonce = pingNonce; + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + try { + in.defaultReadObject(); + pingNonce = new Random().nextLong(); + } catch (Throwable t) { + log.trace("Cannot be deserialized." + t.getMessage()); + } } - public int getPingNonce() { + public long getPingNonce() { return pingNonce; } diff --git a/network/src/main/java/io/bitsquare/p2p/routing/Routing.java b/network/src/main/java/io/bitsquare/p2p/routing/Routing.java index 0f051790ba..c34b0e0dd4 100644 --- a/network/src/main/java/io/bitsquare/p2p/routing/Routing.java +++ b/network/src/main/java/io/bitsquare/p2p/routing/Routing.java @@ -24,7 +24,15 @@ import java.util.stream.Collectors; public class Routing { private static final Logger log = LoggerFactory.getLogger(Routing.class); + private static int simulateAuthTorNode = 2 * 1000; + + public static void setSimulateAuthTorNode(int simulateAuthTorNode) { + Routing.simulateAuthTorNode = simulateAuthTorNode; + } + private static int MAX_CONNECTIONS = 8; + private static int MAINTENANCE_INTERVAL = new Random().nextInt(15 * 60 * 1000) + 15 * 60 * 1000; // 15-30 min. + private static int PING_AFTER_CONNECTION_INACTIVITY = 5 * 60 * 1000; // 5 min private long startAuthTs; public static void setMaxConnections(int maxConnections) { @@ -33,10 +41,10 @@ public class Routing { private final NetworkNode networkNode; private final List
seedNodes; - private final Map nonceMap = new ConcurrentHashMap<>(); + private final Map nonceMap = new ConcurrentHashMap<>(); private final List routingListeners = new CopyOnWriteArrayList<>(); private final Map connectedNeighbors = new ConcurrentHashMap<>(); - private final Map reportedNeighbors = new ConcurrentHashMap<>(); + private final List
reportedNeighborAddresses = new CopyOnWriteArrayList<>(); private final Map authenticationCompleteHandlers = new ConcurrentHashMap<>(); private final Timer maintenanceTimer = new Timer(); private final ExecutorService executorService = Executors.newCachedThreadPool(); @@ -72,7 +80,7 @@ public class Routing { @Override public void onDisconnect(Reason reason, Connection connection) { // only removes authenticated nodes - if (connection.getPeerAddress() != null) + if (connection.isAuthenticated()) removeNeighbor(connection.getPeerAddress()); } @@ -99,14 +107,13 @@ public class Routing { } }); - int maintenanceInterval = new Random().nextInt(15 * 60 * 1000) + 15 * 60 * 1000; // 15-30 min. maintenanceTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { disconnectOldConnections(); pingNeighbors(); } - }, maintenanceInterval, maintenanceInterval); + }, MAINTENANCE_INTERVAL, MAINTENANCE_INTERVAL); } private void disconnectOldConnections() { @@ -128,7 +135,30 @@ public class Routing { } private void pingNeighbors() { + log.trace("pingNeighbors"); + List connectedNeighborsList = new ArrayList<>(connectedNeighbors.values()); + connectedNeighborsList.stream() + .filter(e -> (new Date().getTime() - e.connection.getLastActivityDate().getTime()) > PING_AFTER_CONNECTION_INACTIVITY) + .forEach(e -> { + SettableFuture future = networkNode.sendMessage(e.connection, new PingMessage(e.getPingNonce())); + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(Connection connection) { + log.trace("PingMessage sent successfully"); + } + @Override + public void onFailure(@NotNull Throwable throwable) { + log.info("PingMessage sending failed " + throwable.getMessage()); + removeNeighbor(e.address); + } + }); + try { + Thread.sleep(new Random().nextInt(5000) + 5000); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + }); } @@ -146,12 +176,13 @@ public class Routing { } } - public void broadcast(BroadcastMessage message, Address sender) { + public void broadcast(BroadcastMessage message, @Nullable Address sender) { log.trace("Broadcast message to " + connectedNeighbors.values().size() + " neighbors."); + log.trace("message = " + message); connectedNeighbors.values().parallelStream() .filter(e -> !e.address.equals(sender)) .forEach(neighbor -> { - log.trace("Broadcast message " + message + " from " + getAddress() + " to " + neighbor.address + "."); + log.trace("Broadcast message from " + getAddress() + " to " + neighbor.address + "."); SettableFuture future = networkNode.sendMessage(neighbor.address, message); Futures.addCallback(future, new FutureCallback() { @Override @@ -184,20 +215,18 @@ public class Routing { routingListeners.remove(routingListener); } - public Map getReportedNeighbors() { - return reportedNeighbors; - } - public Map getConnectedNeighbors() { return connectedNeighbors; } - public Map getAllNeighbors() { - Map hashMap = new ConcurrentHashMap<>(reportedNeighbors); - hashMap.putAll(connectedNeighbors); + // Use ArrayList not List as we need it serializable + public ArrayList
getAllNeighborAddresses() { + ArrayList
allNeighborAddresses = new ArrayList<>(reportedNeighborAddresses); + allNeighborAddresses.addAll(connectedNeighbors.values().stream() + .map(e -> e.address).collect(Collectors.toList())); // remove own address and seed nodes - hashMap.remove(getAddress()); - return hashMap; + allNeighborAddresses.remove(getAddress()); + return allNeighborAddresses; } @@ -239,7 +268,7 @@ public class Routing { alreadyConnected[0] = true; }); if (!alreadyConnected[0]) { - int nonce = addToMapAndGetNonce(address); + long nonce = addToMapAndGetNonce(address); SettableFuture future = networkNode.sendMessage(address, new RequestAuthenticationMessage(getAddress(), nonce)); Futures.addCallback(future, new FutureCallback() { @Override @@ -287,12 +316,17 @@ public class Routing { // inconsistent state (removal of connection from NetworkNode.authenticatedConnections) try { Thread.sleep(100); - } catch (InterruptedException ignored) { + } catch (InterruptedException e) { Thread.currentThread().interrupt(); } + try { + if (simulateAuthTorNode > 0) Thread.sleep(simulateAuthTorNode); + } catch (InterruptedException e1) { + Thread.currentThread().interrupt(); + } log.trace("processAuthenticationMessage: connection.shutDown complete. RequestAuthenticationMessage from " + peerAddress + " at " + getAddress()); - int nonce = addToMapAndGetNonce(peerAddress); + long nonce = addToMapAndGetNonce(peerAddress); SettableFuture future = networkNode.sendMessage(peerAddress, new ChallengeMessage(getAddress(), requestAuthenticationMessage.nonce, nonce)); Futures.addCallback(future, new FutureCallback() { @Override @@ -324,12 +358,12 @@ public class Routing { } else if (message instanceof ChallengeMessage) { ChallengeMessage challengeMessage = (ChallengeMessage) message; Address peerAddress = challengeMessage.address; - connection.setPeerAddress(peerAddress); log.trace("ChallengeMessage from " + peerAddress + " at " + getAddress()); + HashMap tempNonceMap = new HashMap<>(nonceMap); boolean verified = verifyNonceAndAuthenticatePeerAddress(challengeMessage.requesterNonce, peerAddress); if (verified) { - HashMap allNeighbors = new HashMap<>(getAllNeighbors()); - SettableFuture future = networkNode.sendMessage(peerAddress, new GetNeighborsMessage(getAddress(), challengeMessage.challengerNonce, allNeighbors)); + SettableFuture future = networkNode.sendMessage(peerAddress, + new GetNeighborsMessage(getAddress(), challengeMessage.challengerNonce, getAllNeighborAddresses())); Futures.addCallback(future, new FutureCallback() { @Override public void onSuccess(Connection connection) { @@ -346,6 +380,8 @@ public class Routing { removeNeighbor(peerAddress); } }); + } else { + log.warn("verifyNonceAndAuthenticatePeerAddress failed. challengeMessage=" + challengeMessage + " / nonceMap=" + tempNonceMap); } } else if (message instanceof GetNeighborsMessage) { GetNeighborsMessage getNeighborsMessage = (GetNeighborsMessage) message; @@ -355,9 +391,10 @@ public class Routing { if (verified) { setAuthenticated(connection, peerAddress); purgeReportedNeighbors(); - HashMap allNeighbors = new HashMap<>(getAllNeighbors()); - SettableFuture future = networkNode.sendMessage(peerAddress, new NeighborsMessage(allNeighbors)); - log.trace("sent NeighborsMessage to " + peerAddress + " from " + getAddress() + " with allNeighbors=" + allNeighbors.values()); + SettableFuture future = networkNode.sendMessage(peerAddress, + new NeighborsMessage(getAllNeighborAddresses())); + log.trace("sent NeighborsMessage to " + peerAddress + " from " + getAddress() + + " with allNeighbors=" + getAllNeighborAddresses()); Futures.addCallback(future, new FutureCallback() { @Override public void onSuccess(Connection connection) { @@ -372,19 +409,19 @@ public class Routing { }); // now we add the reported neighbors to our own set - final HashMap neighbors = ((GetNeighborsMessage) message).neighbors; - log.trace("Received neighbors: " + neighbors); + ArrayList
neighborAddresses = ((GetNeighborsMessage) message).neighborAddresses; + log.trace("Received neighbors: " + neighborAddresses); // remove ourselves - neighbors.remove(getAddress()); - addToReportedNeighbors(neighbors, connection); + neighborAddresses.remove(getAddress()); + addToReportedNeighbors(neighborAddresses, connection); } } else if (message instanceof NeighborsMessage) { log.trace("NeighborsMessage from " + connection.getPeerAddress() + " at " + getAddress()); - final HashMap neighbors = ((NeighborsMessage) message).neighbors; - log.trace("Received neighbors: " + neighbors); + ArrayList
neighborAddresses = ((NeighborsMessage) message).neighborAddresses; + log.trace("Received neighbors: " + neighborAddresses); // remove ourselves - neighbors.remove(getAddress()); - addToReportedNeighbors(neighbors, connection); + neighborAddresses.remove(getAddress()); + addToReportedNeighbors(neighborAddresses, connection); log.info("\n\nAuthenticationComplete\nPeer with address " + connection.getPeerAddress().toString() + " authenticated (" + connection.getObjectId() + "). Took " @@ -398,36 +435,42 @@ public class Routing { } } - private void addToReportedNeighbors(HashMap neighbors, Connection connection) { + private void addToReportedNeighbors(ArrayList
neighborAddresses, Connection connection) { // we disconnect misbehaving nodes trying to send too many neighbors // reported neighbors include the peers connected neighbors which is normally max. 8 but we give some headroom // for safety - if (neighbors.size() > 1100) { + if (neighborAddresses.size() > 1100) { connection.shutDown(); } else { - reportedNeighbors.putAll(neighbors); + reportedNeighborAddresses.addAll(neighborAddresses); purgeReportedNeighbors(); } } private void purgeReportedNeighbors() { - int all = getAllNeighbors().size(); + int all = getAllNeighborAddresses().size(); if (all > 1000) { int diff = all - 100; - ArrayList reportedNeighborsList = new ArrayList<>(reportedNeighbors.values()); + List
list = getNotConnectedNeighborAddresses(); for (int i = 0; i < diff; i++) { - Neighbor neighborToRemove = reportedNeighborsList.remove(new Random().nextInt(reportedNeighborsList.size())); - reportedNeighbors.remove(neighborToRemove.address); + Address neighborToRemove = list.remove(new Random().nextInt(list.size())); + reportedNeighborAddresses.remove(neighborToRemove); } } } + private List
getNotConnectedNeighborAddresses() { + ArrayList
reportedNeighborsList = new ArrayList<>(getAllNeighborAddresses()); + connectedNeighbors.values().stream().forEach(e -> reportedNeighborsList.remove(e.address)); + return reportedNeighborsList; + } + private void authenticateToNextRandomNeighbor() { if (getConnectedNeighbors().size() <= MAX_CONNECTIONS) { - Neighbor randomNotConnectedNeighbor = getRandomNotConnectedNeighbor(); - if (randomNotConnectedNeighbor != null) { - log.info("We try to build an authenticated connection to a random neighbor. " + randomNotConnectedNeighbor); - authenticateToPeer(randomNotConnectedNeighbor.address, null, () -> authenticateToNextRandomNeighbor()); + Address randomNotConnectedNeighborAddress = getRandomNotConnectedNeighborAddress(); + if (randomNotConnectedNeighborAddress != null) { + log.info("We try to build an authenticated connection to a random neighbor. " + randomNotConnectedNeighborAddress); + authenticateToPeer(randomNotConnectedNeighborAddress, null, () -> authenticateToNextRandomNeighbor()); } else { log.info("No more neighbors available for connecting."); } @@ -442,7 +485,7 @@ public class Routing { if (authenticationCompleteHandler != null) authenticationCompleteHandlers.put(address, authenticationCompleteHandler); - int nonce = addToMapAndGetNonce(address); + long nonce = addToMapAndGetNonce(address); SettableFuture future = networkNode.sendMessage(address, new RequestAuthenticationMessage(getAddress(), nonce)); Futures.addCallback(future, new FutureCallback() { @Override @@ -459,34 +502,43 @@ public class Routing { }); } - private int addToMapAndGetNonce(Address address) { - int nonce = new Random().nextInt(); + private long addToMapAndGetNonce(Address peerAddress) { + long nonce = new Random().nextLong(); while (nonce == 0) { - nonce = new Random().nextInt(); + nonce = new Random().nextLong(); } - nonceMap.put(address, nonce); + log.trace("addToMapAndGetNonce nonceMap=" + nonceMap + " / peerAddress=" + peerAddress); + nonceMap.put(peerAddress, nonce); return nonce; } - private boolean verifyNonceAndAuthenticatePeerAddress(int peersNonce, Address peerAddress) { - int nonce = nonceMap.remove(peerAddress); + private boolean verifyNonceAndAuthenticatePeerAddress(long peersNonce, Address peerAddress) { + log.trace("verifyNonceAndAuthenticatePeerAddress nonceMap=" + nonceMap + " / peerAddress=" + peerAddress); + long nonce = nonceMap.remove(peerAddress); boolean result = nonce == peersNonce; return result; } - private void setAuthenticated(Connection connection, Address address) { - log.info("We got the connection from " + getAddress() + " to " + address + " authenticated."); - Neighbor neighbor = new Neighbor(address); - addConnectedNeighbor(address, neighbor); + private void setAuthenticated(Connection connection, Address peerAddress) { + log.info("\n\n############################################################\n" + + "We are authenticated to:" + + "\nconnection=" + connection + + "\nmyAddress=" + getAddress() + + "\npeerAddress= " + peerAddress + + "\n############################################################\n"); + + connection.onAuthenticationComplete(peerAddress, connection); + + Neighbor neighbor = new Neighbor(connection); + addConnectedNeighbor(peerAddress, neighbor); - connection.onAuthenticationComplete(address, connection); routingListeners.stream().forEach(e -> e.onConnectionAuthenticated(connection)); + + log.debug("\n### setAuthenticated post connection " + connection); } - private Neighbor getRandomNotConnectedNeighbor() { - List list = reportedNeighbors.values().stream() - .filter(e -> !connectedNeighbors.values().contains(e)) - .collect(Collectors.toList()); + private Address getRandomNotConnectedNeighborAddress() { + List
list = getNotConnectedNeighborAddresses(); if (list.size() > 0) { Collections.shuffle(list); return list.get(0); @@ -532,16 +584,17 @@ public class Routing { // Neighbors /////////////////////////////////////////////////////////////////////////////////////////// - private void removeNeighbor(Address address) { - reportedNeighbors.remove(address); + private void removeNeighbor(@Nullable Address peerAddress) { + reportedNeighborAddresses.remove(peerAddress); Neighbor disconnectedNeighbor; - disconnectedNeighbor = connectedNeighbors.remove(address); + disconnectedNeighbor = connectedNeighbors.remove(peerAddress); if (disconnectedNeighbor != null) - UserThread.execute(() -> routingListeners.stream().forEach(e -> e.onNeighborRemoved(address))); + UserThread.execute(() -> routingListeners.stream().forEach(e -> e.onNeighborRemoved(peerAddress))); - nonceMap.remove(address); + log.trace("removeNeighbor nonceMap=" + nonceMap + " / peerAddress=" + peerAddress); + nonceMap.remove(peerAddress); } private void addConnectedNeighbor(Address address, Neighbor neighbor) { @@ -577,9 +630,9 @@ public class Routing { } public void printReportedNeighborsMap() { - StringBuilder result = new StringBuilder("\nReported neighbors for node " + getAddress() + ":"); - reportedNeighbors.values().stream().forEach(e -> { - result.append("\n\t" + e.address); + StringBuilder result = new StringBuilder("\nReported neighborAddresses for node " + getAddress() + ":"); + reportedNeighborAddresses.stream().forEach(e -> { + result.append("\n\t" + e); }); result.append("\n"); log.info(result.toString()); diff --git a/network/src/main/java/io/bitsquare/p2p/routing/messages/ChallengeMessage.java b/network/src/main/java/io/bitsquare/p2p/routing/messages/ChallengeMessage.java index ce161b732d..2de51fe625 100644 --- a/network/src/main/java/io/bitsquare/p2p/routing/messages/ChallengeMessage.java +++ b/network/src/main/java/io/bitsquare/p2p/routing/messages/ChallengeMessage.java @@ -8,10 +8,10 @@ public final class ChallengeMessage implements AuthenticationMessage { private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; public final Address address; - public final int requesterNonce; - public final int challengerNonce; + public final long requesterNonce; + public final long challengerNonce; - public ChallengeMessage(Address address, int requesterNonce, int challengerNonce) { + public ChallengeMessage(Address address, long requesterNonce, long challengerNonce) { this.address = address; this.requesterNonce = requesterNonce; this.challengerNonce = challengerNonce; diff --git a/network/src/main/java/io/bitsquare/p2p/routing/messages/GetNeighborsMessage.java b/network/src/main/java/io/bitsquare/p2p/routing/messages/GetNeighborsMessage.java index be41e03c2c..672f30dda6 100644 --- a/network/src/main/java/io/bitsquare/p2p/routing/messages/GetNeighborsMessage.java +++ b/network/src/main/java/io/bitsquare/p2p/routing/messages/GetNeighborsMessage.java @@ -2,22 +2,21 @@ package io.bitsquare.p2p.routing.messages; import io.bitsquare.app.Version; import io.bitsquare.p2p.Address; -import io.bitsquare.p2p.routing.Neighbor; -import java.util.HashMap; +import java.util.ArrayList; public final class GetNeighborsMessage implements AuthenticationMessage { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; public final Address address; - public final int challengerNonce; - public final HashMap neighbors; + public final long challengerNonce; + public final ArrayList
neighborAddresses; - public GetNeighborsMessage(Address address, int challengerNonce, HashMap neighbors) { + public GetNeighborsMessage(Address address, long challengerNonce, ArrayList
neighborAddresses) { this.address = address; this.challengerNonce = challengerNonce; - this.neighbors = neighbors; + this.neighborAddresses = neighborAddresses; } @Override @@ -25,7 +24,7 @@ public final class GetNeighborsMessage implements AuthenticationMessage { return "GetNeighborsMessage{" + "address=" + address + ", challengerNonce=" + challengerNonce + - ", neighbors=" + neighbors + + ", neighborAddresses=" + neighborAddresses + '}'; } } diff --git a/network/src/main/java/io/bitsquare/p2p/routing/messages/NeighborsMessage.java b/network/src/main/java/io/bitsquare/p2p/routing/messages/NeighborsMessage.java index 2fd3927ad8..19d563e17d 100644 --- a/network/src/main/java/io/bitsquare/p2p/routing/messages/NeighborsMessage.java +++ b/network/src/main/java/io/bitsquare/p2p/routing/messages/NeighborsMessage.java @@ -2,23 +2,22 @@ package io.bitsquare.p2p.routing.messages; import io.bitsquare.app.Version; import io.bitsquare.p2p.Address; -import io.bitsquare.p2p.routing.Neighbor; -import java.util.HashMap; +import java.util.ArrayList; public final class NeighborsMessage implements AuthenticationMessage { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; - public final HashMap neighbors; + public final ArrayList
neighborAddresses; - public NeighborsMessage(HashMap neighbors) { - this.neighbors = neighbors; + public NeighborsMessage(ArrayList
neighborAddresses) { + this.neighborAddresses = neighborAddresses; } @Override public String toString() { - return "NeighborsMessage{" + "neighbors=" + neighbors + '}'; + return "NeighborsMessage{" + "neighborAddresses=" + neighborAddresses + '}'; } } diff --git a/network/src/main/java/io/bitsquare/p2p/routing/messages/PingMessage.java b/network/src/main/java/io/bitsquare/p2p/routing/messages/PingMessage.java index 56d46b7b9f..e4143aa635 100644 --- a/network/src/main/java/io/bitsquare/p2p/routing/messages/PingMessage.java +++ b/network/src/main/java/io/bitsquare/p2p/routing/messages/PingMessage.java @@ -6,9 +6,9 @@ public final class PingMessage implements MaintenanceMessage { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; - public final int nonce; + public final long nonce; - public PingMessage(int nonce) { + public PingMessage(long nonce) { this.nonce = nonce; } diff --git a/network/src/main/java/io/bitsquare/p2p/routing/messages/PongMessage.java b/network/src/main/java/io/bitsquare/p2p/routing/messages/PongMessage.java index 628f15e50d..93a1181047 100644 --- a/network/src/main/java/io/bitsquare/p2p/routing/messages/PongMessage.java +++ b/network/src/main/java/io/bitsquare/p2p/routing/messages/PongMessage.java @@ -6,9 +6,9 @@ public final class PongMessage implements MaintenanceMessage { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; - public final int nonce; + public final long nonce; - public PongMessage(int nonce) { + public PongMessage(long nonce) { this.nonce = nonce; } diff --git a/network/src/main/java/io/bitsquare/p2p/routing/messages/RequestAuthenticationMessage.java b/network/src/main/java/io/bitsquare/p2p/routing/messages/RequestAuthenticationMessage.java index d299493787..8b7ec3b17b 100644 --- a/network/src/main/java/io/bitsquare/p2p/routing/messages/RequestAuthenticationMessage.java +++ b/network/src/main/java/io/bitsquare/p2p/routing/messages/RequestAuthenticationMessage.java @@ -8,9 +8,9 @@ public final class RequestAuthenticationMessage implements AuthenticationMessage private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; public final Address address; - public final int nonce; + public final long nonce; - public RequestAuthenticationMessage(Address address, int nonce) { + public RequestAuthenticationMessage(Address address, long nonce) { this.address = address; this.nonce = nonce; } diff --git a/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java b/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java index d5d176a5f5..0d386ae84d 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java @@ -15,6 +15,7 @@ import io.bitsquare.storage.Storage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; import java.io.File; import java.math.BigInteger; import java.security.KeyPair; @@ -69,6 +70,7 @@ public class ProtectedExpirableDataStorage { } } else { log.warn("Connection is not authenticated yet. We don't accept storage operations form non-authenticated nodes."); + log.warn("Connection = " + connection); connection.reportIllegalRequest(IllegalRequest.NotAuthenticated); } } @@ -103,7 +105,7 @@ public class ProtectedExpirableDataStorage { this.authenticated = authenticated; } - public boolean add(ProtectedData protectedData, Address sender) { + public boolean add(ProtectedData protectedData, @Nullable Address sender) { BigInteger hashOfPayload = getHashAsBigInteger(protectedData.expirablePayload); boolean containsKey = map.containsKey(hashOfPayload); boolean result = checkPublicKeys(protectedData, true) @@ -119,9 +121,10 @@ public class ProtectedExpirableDataStorage { log.trace("Data added to our map and it will be broadcasted to our neighbors."); UserThread.execute(() -> hashMapChangedListeners.stream().forEach(e -> e.onAdded(protectedData))); - StringBuilder sb = new StringBuilder("\n\nSet after addProtectedExpirableData:\n"); - map.values().stream().forEach(e -> sb.append(e.toString() + "\n\n")); - sb.append("\n\n"); + StringBuilder sb = new StringBuilder("\n\n----------------------------------------------------\n" + + "Data set after addProtectedExpirableData:"); + map.values().stream().forEach(e -> sb.append("\n\n").append(e.toString())); + sb.append("\n----------------------------------------------------\n\n"); log.trace(sb.toString()); if (!containsKey) @@ -130,12 +133,12 @@ public class ProtectedExpirableDataStorage { sequenceNumberMap.put(hashOfPayload, protectedData.sequenceNumber); storage.queueUpForSave(); } else { - log.debug("add failed"); + log.trace("add failed"); } return result; } - public boolean remove(ProtectedData protectedData, Address sender) { + public boolean remove(ProtectedData protectedData, @Nullable Address sender) { BigInteger hashOfPayload = getHashAsBigInteger(protectedData.expirablePayload); boolean containsKey = map.containsKey(hashOfPayload); if (!containsKey) log.debug("Remove data ignored as we don't have an entry for that data."); @@ -159,7 +162,7 @@ public class ProtectedExpirableDataStorage { return result; } - public boolean removeMailboxData(ProtectedMailboxData protectedMailboxData, Address sender) { + public boolean removeMailboxData(ProtectedMailboxData protectedMailboxData, @Nullable Address sender) { BigInteger hashOfData = getHashAsBigInteger(protectedMailboxData.expirablePayload); boolean containsKey = map.containsKey(hashOfData); if (!containsKey) log.debug("Remove data ignored as we don't have an entry for that data."); @@ -245,7 +248,7 @@ public class ProtectedExpirableDataStorage { int newSequenceNumber = data.sequenceNumber; Integer storedSequenceNumber = sequenceNumberMap.get(hashOfData); if (sequenceNumberMap.containsKey(hashOfData) && newSequenceNumber <= storedSequenceNumber) { - log.warn("Sequence number is invalid. newSequenceNumber=" + log.trace("Sequence number is invalid. newSequenceNumber=" + newSequenceNumber + " / storedSequenceNumber=" + storedSequenceNumber); return false; } else { @@ -313,7 +316,7 @@ public class ProtectedExpirableDataStorage { } - private void broadcast(BroadcastMessage message, Address sender) { + private void broadcast(BroadcastMessage message, @Nullable Address sender) { if (authenticated) { routing.broadcast(message, sender); log.trace("Broadcast message " + message); diff --git a/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java b/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java index 8113694236..d966cbb563 100644 --- a/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java +++ b/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java @@ -26,6 +26,7 @@ import io.bitsquare.common.util.Utilities; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey; import io.bitsquare.p2p.messaging.MailboxMessage; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -38,6 +39,7 @@ import java.io.File; import java.io.IOException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.Security; import java.security.cert.CertificateException; import static org.junit.Assert.assertEquals; @@ -50,10 +52,13 @@ public class EncryptionServiceTests { private PubKeyRing pubKeyRing; private KeyRing keyRing; - private File dir = new File("/tmp/bitsquare_tests"); + private File dir; @Before public void setup() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, CryptoException { + Security.addProvider(new BouncyCastleProvider()); + dir = File.createTempFile("temp_tests", ""); + dir.delete(); dir.mkdir(); KeyStorage keyStorage = new KeyStorage(dir); keyRing = new KeyRing(keyStorage); diff --git a/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java b/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java index 55445e627e..e85fd41b61 100644 --- a/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java +++ b/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java @@ -13,6 +13,7 @@ import io.bitsquare.p2p.seed.SeedNode; import io.bitsquare.p2p.storage.data.DataAndSeqNr; import io.bitsquare.p2p.storage.data.ProtectedData; import io.bitsquare.p2p.storage.mocks.MockData; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,16 +41,27 @@ public class P2PServiceTest { private EncryptionService encryptionService1, encryptionService2, encryptionService3; private P2PService p2PService1, p2PService2, p2PService3; private SeedNode seedNode1, seedNode2, seedNode3; - + private File dir1, dir2, dir3; @Before public void setup() throws InterruptedException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, CryptoException { + Security.addProvider(new BouncyCastleProvider()); + dir1 = File.createTempFile("temp_tests1", ""); + dir1.delete(); + dir1.mkdir(); + dir2 = File.createTempFile("temp_tests2", ""); + dir2.delete(); + dir2.mkdir(); + dir3 = File.createTempFile("temp_tests3", ""); + dir3.delete(); + dir3.mkdir(); + LocalhostNetworkNode.setSimulateTorDelayTorNode(10); LocalhostNetworkNode.setSimulateTorDelayHiddenService(100); Routing.setMaxConnections(8); - keyRing1 = new KeyRing(new KeyStorage(new File("temp_keyStorage1"))); - keyRing2 = new KeyRing(new KeyStorage(new File("temp_keyStorage2"))); - keyRing3 = new KeyRing(new KeyStorage(new File("temp_keyStorage3"))); + keyRing1 = new KeyRing(new KeyStorage(dir1)); + keyRing2 = new KeyRing(new KeyStorage(dir2)); + keyRing3 = new KeyRing(new KeyStorage(dir3)); encryptionService1 = new EncryptionService(keyRing1); encryptionService2 = new EncryptionService(keyRing2); encryptionService3 = new EncryptionService(keyRing3); diff --git a/network/src/test/java/io/bitsquare/p2p/network/LocalhostNetworkNodeTest.java b/network/src/test/java/io/bitsquare/p2p/network/LocalhostNetworkNodeTest.java index d2d0497e4e..8476d81df9 100644 --- a/network/src/test/java/io/bitsquare/p2p/network/LocalhostNetworkNodeTest.java +++ b/network/src/test/java/io/bitsquare/p2p/network/LocalhostNetworkNodeTest.java @@ -2,12 +2,15 @@ package io.bitsquare.p2p.network; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.routing.messages.RequestAuthenticationMessage; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.security.Security; import java.util.concurrent.CountDownLatch; // TorNode created. Took 6 sec. @@ -17,6 +20,12 @@ import java.util.concurrent.CountDownLatch; public class LocalhostNetworkNodeTest { private static final Logger log = LoggerFactory.getLogger(LocalhostNetworkNodeTest.class); + @Before + public void setup() { + Security.addProvider(new BouncyCastleProvider()); + } + + @Test public void testMessage() throws InterruptedException, IOException { CountDownLatch msgLatch = new CountDownLatch(2); diff --git a/network/src/test/java/io/bitsquare/p2p/network/TorNetworkNodeTest.java b/network/src/test/java/io/bitsquare/p2p/network/TorNetworkNodeTest.java index 127182db67..df7a909721 100644 --- a/network/src/test/java/io/bitsquare/p2p/network/TorNetworkNodeTest.java +++ b/network/src/test/java/io/bitsquare/p2p/network/TorNetworkNodeTest.java @@ -5,6 +5,8 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.SettableFuture; import io.bitsquare.p2p.Message; import io.bitsquare.p2p.mocks.MockMessage; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; @@ -12,6 +14,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; +import java.security.Security; import java.util.concurrent.CountDownLatch; // TorNode created. Took 6 sec. @@ -22,6 +25,11 @@ public class TorNetworkNodeTest { private static final Logger log = LoggerFactory.getLogger(TorNetworkNodeTest.class); private CountDownLatch latch; + @Before + public void setup() { + Security.addProvider(new BouncyCastleProvider()); + } + @Test public void testTorNodeBeforeSecondReady() throws InterruptedException, IOException { latch = new CountDownLatch(1); diff --git a/network/src/test/java/io/bitsquare/p2p/routing/RoutingTest.java b/network/src/test/java/io/bitsquare/p2p/routing/RoutingTest.java index 8c3a0148ab..7f3fadbcb3 100644 --- a/network/src/test/java/io/bitsquare/p2p/routing/RoutingTest.java +++ b/network/src/test/java/io/bitsquare/p2p/routing/RoutingTest.java @@ -107,7 +107,7 @@ public class RoutingTest { P2PService p2PService1 = seedNode1.getP2PService(); latch.await(); Thread.sleep(500); - Assert.assertEquals(0, p2PService1.getRouting().getAllNeighbors().size()); + Assert.assertEquals(0, p2PService1.getRouting().getAllNeighborAddresses().size()); } @Test @@ -180,8 +180,8 @@ public class RoutingTest { }); P2PService p2PService2 = seedNode2.getP2PService(); latch.await(); - Assert.assertEquals(1, p2PService1.getRouting().getAllNeighbors().size()); - Assert.assertEquals(1, p2PService2.getRouting().getAllNeighbors().size()); + Assert.assertEquals(1, p2PService1.getRouting().getAllNeighborAddresses().size()); + Assert.assertEquals(1, p2PService2.getRouting().getAllNeighborAddresses().size()); } // @Test diff --git a/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java b/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java index 995324d5d0..44453bf057 100644 --- a/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java +++ b/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java @@ -15,6 +15,7 @@ import io.bitsquare.p2p.storage.data.ExpirableMailboxPayload; import io.bitsquare.p2p.storage.data.ProtectedData; import io.bitsquare.p2p.storage.data.ProtectedMailboxData; import io.bitsquare.p2p.storage.mocks.MockData; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -44,13 +45,24 @@ public class ProtectedDataStorageTest { private KeyRing keyRing1, keyRing2; private MockData mockData; private int sleepTime = 100; + private File dir1; + private File dir2; @Before public void setup() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException { + Security.addProvider(new BouncyCastleProvider()); + dir1 = File.createTempFile("temp_tests1", ""); + dir1.delete(); + dir1.mkdir(); + dir2 = File.createTempFile("temp_tests2", ""); + dir2.delete(); + dir2.mkdir(); + UserThread.executor = Executors.newSingleThreadExecutor(); ProtectedExpirableDataStorage.CHECK_TTL_INTERVAL = 10 * 60 * 1000; - keyRing1 = new KeyRing(new KeyStorage(new File("temp_keyStorage1"))); + keyRing1 = new KeyRing(new KeyStorage(dir1)); + storageSignatureKeyPair1 = keyRing1.getSignatureKeyPair(); encryptionService1 = new EncryptionService(keyRing1); networkNode1 = TestUtils.getAndStartSeedNode(8001, encryptionService1, keyRing1, useClearNet, seedNodes).getP2PService().getNetworkNode(); @@ -58,7 +70,7 @@ public class ProtectedDataStorageTest { dataStorage1 = new ProtectedExpirableDataStorage(routing1, new File("dummy")); // for mailbox - keyRing2 = new KeyRing(new KeyStorage(new File("temp_keyStorage2"))); + keyRing2 = new KeyRing(new KeyStorage(dir2)); storageSignatureKeyPair2 = keyRing2.getSignatureKeyPair(); encryptionService2 = new EncryptionService(keyRing2); @@ -148,11 +160,18 @@ public class ProtectedDataStorageTest { dataToRemove = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertTrue(dataStorage1.remove(dataToRemove, null)); + // add to empty map, any seq nr. -> ok + newSequenceNumber = 2; + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + ProtectedData dataToAdd = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); + Assert.assertTrue(dataStorage1.add(dataToAdd, null)); + // add with updated seq nr below previous -> failure newSequenceNumber = 1; hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); - ProtectedData dataToAdd = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); + dataToAdd = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertFalse(dataStorage1.add(dataToAdd, null)); // add with updated seq nr over previous -> ok