From 99266712faeff0b392557512f73a751dd4fa7d7b Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Sat, 28 Nov 2015 20:27:05 +0100 Subject: [PATCH 01/54] Some extensions for server POW --- .../dissem/bitmessage/BitmessageContext.java | 18 ++- .../ch/dissem/bitmessage/InternalContext.java | 6 + .../bitmessage/entity/BitmessageAddress.java | 2 +- .../bitmessage/entity/CustomMessage.java | 68 +++++++++ .../bitmessage/entity/MessagePayload.java | 2 +- .../bitmessage/entity/payload/Broadcast.java | 1 - .../bitmessage/entity/payload/CryptoBox.java | 9 +- .../bitmessage/factory/V3MessageFactory.java | 6 + .../ports/CustomCommandHandler.java | 27 ++++ .../ch/dissem/bitmessage/utils/Encode.java | 16 +- extensions/build.gradle | 36 +++++ .../extensions/CryptoCustomMessage.java | 139 ++++++++++++++++++ .../extensions/pow/ProofOfWorkRequest.java | 86 +++++++++++ .../extensions/CryptoCustomMessageTest.java | 58 ++++++++ .../bitmessage/networking/Connection.java | 6 + .../bitmessage/repository/JdbcHelper.java | 2 +- settings.gradle | 2 + 17 files changed, 472 insertions(+), 12 deletions(-) create mode 100644 domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java create mode 100644 domain/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java create mode 100644 extensions/build.gradle create mode 100644 extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java create mode 100644 extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java create mode 100644 extensions/src/test/java/ch/dissem/bitmessage/extensions/CryptoCustomMessageTest.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 9f4d9a3..9d4abd7 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -16,9 +16,7 @@ package ch.dissem.bitmessage; -import ch.dissem.bitmessage.entity.BitmessageAddress; -import ch.dissem.bitmessage.entity.ObjectMessage; -import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.*; import ch.dissem.bitmessage.entity.payload.*; import ch.dissem.bitmessage.entity.payload.Pubkey.Feature; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; @@ -297,6 +295,7 @@ public class BitmessageContext { ProofOfWorkEngine proofOfWorkEngine; Security security; MessageCallback messageCallback; + CustomCommandHandler customCommandHandler; Listener listener; int connectionLimit = 150; long connectionTTL = 12 * HOUR; @@ -344,6 +343,11 @@ public class BitmessageContext { return this; } + public Builder customCommandHandler(CustomCommandHandler handler) { + this.customCommandHandler = handler; + return this; + } + public Builder proofOfWorkEngine(ProofOfWorkEngine proofOfWorkEngine) { this.proofOfWorkEngine = proofOfWorkEngine; return this; @@ -392,6 +396,14 @@ public class BitmessageContext { } }; } + if (customCommandHandler == null) { + customCommandHandler = new CustomCommandHandler() { + @Override + public MessagePayload handle(CustomMessage request) { + throw new RuntimeException("Received custom request, but no custom command handler configured."); + } + }; + } return new BitmessageContext(this); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java index 7a89978..95cd8d8 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -50,6 +50,7 @@ public class InternalContext { private final MessageRepository messageRepository; private final ProofOfWorkEngine proofOfWorkEngine; private final MessageCallback messageCallback; + private final CustomCommandHandler customCommandHandler; private final TreeSet streams = new TreeSet<>(); private final int port; @@ -69,6 +70,7 @@ public class InternalContext { this.proofOfWorkEngine = builder.proofOfWorkEngine; this.clientNonce = security.randomNonce(); this.messageCallback = builder.messageCallback; + this.customCommandHandler = builder.customCommandHandler; this.port = builder.port; this.connectionLimit = builder.connectionLimit; this.connectionTTL = builder.connectionTTL; @@ -263,6 +265,10 @@ public class InternalContext { return connectionLimit; } + public CustomCommandHandler getCustomCommandHandler() { + return customCommandHandler; + } + public interface ContextHolder { void setContext(InternalContext context); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index 0441e6e..931776c 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -87,7 +87,7 @@ public class BitmessageAddress implements Serializable { } } - BitmessageAddress(Pubkey publicKey) { + public BitmessageAddress(Pubkey publicKey) { this(publicKey.getVersion(), publicKey.getStream(), publicKey.getRipe()); this.pubkey = publicKey; } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java new file mode 100644 index 0000000..b31c9f5 --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.entity; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import static ch.dissem.bitmessage.utils.Decode.bytes; + +/** + * @author Christian Basler + */ +public class CustomMessage implements MessagePayload { + private final byte[] data; + + public CustomMessage() { + this.data = null; + } + + public CustomMessage(byte[] data) { + this.data = data; + } + + public static MessagePayload read(InputStream in, int length) throws IOException { + return new CustomMessage(bytes(in, length)); + } + + @Override + public Command getCommand() { + return Command.CUSTOM; + } + + public byte[] getData() throws IOException { + if (data != null) { + return data; + } else { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + write(out); + return out.toByteArray(); + } + } + + @Override + public void write(OutputStream out) throws IOException { + if (data != null) { + out.write(data); + } else { + throw new RuntimeException("Tried to write custom message without data. " + + "Programmer: did you forget to override #write()?"); + } + } +} diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java b/domain/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java index e6f6f0a..994952b 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java @@ -23,6 +23,6 @@ public interface MessagePayload extends Streamable { Command getCommand(); enum Command { - VERSION, VERACK, ADDR, INV, GETDATA, OBJECT + VERSION, VERACK, ADDR, INV, GETDATA, OBJECT, CUSTOM } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java index bf5ff7f..47bf539 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java @@ -21,7 +21,6 @@ import ch.dissem.bitmessage.entity.Encrypted; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.PlaintextHolder; import ch.dissem.bitmessage.exception.DecryptionFailedException; -import ch.dissem.bitmessage.ports.Security; import java.io.IOException; diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java index a870b32..fe45ac5 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java @@ -38,7 +38,14 @@ public class CryptoBox implements Streamable { private final byte[] mac; private byte[] encrypted; + private long addressVersion; + + public CryptoBox(Streamable data, byte[] K) throws IOException { + this(Encode.bytes(data), K); + } + + public CryptoBox(byte[] data, byte[] K) throws IOException { curveType = 0x02CA; // 1. The destination public key is called K. @@ -58,7 +65,7 @@ public class CryptoBox implements Streamable { byte[] key_m = Arrays.copyOfRange(H, 32, 64); // 7. Pad the input text to a multiple of 16 bytes, in accordance to PKCS7. // 8. Encrypt the data with AES-256-CBC, using IV as initialization vector, key_e as encryption key and the padded input text as payload. Call the output cipher text. - encrypted = security().crypt(true, Encode.bytes(data), key_e, initializationVector); + encrypted = security().crypt(true, data, key_e, initializationVector); // 9. Calculate a 32 byte MAC with HMACSHA256, using key_m as salt and IV + R + cipher text as data. Call the output MAC. mac = calculateMac(key_m); diff --git a/domain/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java b/domain/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java index 8dca6d2..9e15b3d 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java +++ b/domain/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java @@ -73,12 +73,18 @@ class V3MessageFactory { return parseGetData(stream); case "object": return readObject(stream, length); + case "custom": + return readCustom(stream, length); default: LOG.debug("Unknown command: " + command); return null; } } + private static MessagePayload readCustom(InputStream in, int length) throws IOException { + return CustomMessage.read(in, length); + } + public static ObjectMessage readObject(InputStream in, int length) throws IOException { AccessCounter counter = new AccessCounter(); byte nonce[] = Decode.bytes(in, 8, counter); diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java b/domain/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java new file mode 100644 index 0000000..8e49586 --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.ports; + +import ch.dissem.bitmessage.entity.CustomMessage; +import ch.dissem.bitmessage.entity.MessagePayload; + +/** + * @author Christian Basler + */ +public interface CustomCommandHandler { + MessagePayload handle(CustomMessage request); +} diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Encode.java b/domain/src/main/java/ch/dissem/bitmessage/utils/Encode.java index a78d03f..2cdc262 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/utils/Encode.java +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/Encode.java @@ -103,15 +103,23 @@ public class Encode { inc(counter, 8); } - public static void varString(String value, OutputStream stream) throws IOException { + public static void varString(String value, OutputStream out) throws IOException { byte[] bytes = value.getBytes("utf-8"); - // FIXME: technically, it says the length in characters, but I think this one might be correct + // Technically, it says the length in characters, but I think this one might be correct. + // It doesn't really matter, as only ASCII characters are being used. // see also Decode#varString() - varInt(bytes.length, stream); - stream.write(bytes); + varInt(bytes.length, out); + out.write(bytes); + } + + public static void varBytes(byte[] data, OutputStream out) throws IOException { + varInt(data.length, out); + out.write(data); } /** + * Serializes a {@link Streamable} object and returns the byte array. + * * @param streamable the object to be serialized * @return an array of bytes representing the given streamable object. * @throws IOException if an I/O error occurs. diff --git a/extensions/build.gradle b/extensions/build.gradle new file mode 100644 index 0000000..0ae9fd4 --- /dev/null +++ b/extensions/build.gradle @@ -0,0 +1,36 @@ +/* + * Copyright 2015 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +uploadArchives { + repositories { + mavenDeployer { + pom.project { + name 'Jabit Extensions' + artifactId = 'jabit-extensions' + description 'Protocol extensions used for some extended features, e.g. server and mobile client.' + } + } + } +} + +dependencies { + compile project(':domain') + testCompile 'junit:junit:4.11' + testCompile 'org.slf4j:slf4j-simple:1.7.12' + testCompile 'org.mockito:mockito-core:1.10.19' + testCompile project(path: ':domain', configuration: 'testArtifacts') + testCompile project(':security-bc') +} diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java new file mode 100644 index 0000000..5d82f4d --- /dev/null +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java @@ -0,0 +1,139 @@ +/* + * Copyright 2015 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.extensions; + +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.CustomMessage; +import ch.dissem.bitmessage.entity.Streamable; +import ch.dissem.bitmessage.entity.payload.CryptoBox; +import ch.dissem.bitmessage.entity.payload.Pubkey; +import ch.dissem.bitmessage.exception.DecryptionFailedException; +import ch.dissem.bitmessage.factory.Factory; +import ch.dissem.bitmessage.utils.Encode; + +import java.io.*; + +import static ch.dissem.bitmessage.utils.Decode.*; +import static ch.dissem.bitmessage.utils.Singleton.security; + +/** + * A {@link CustomMessage} implementation that contains signed and encrypted data. + * + * @author Christian Basler + */ +public class CryptoCustomMessage extends CustomMessage { + private final Reader dataReader; + private CryptoBox container; + private BitmessageAddress sender; + private T data; + + public CryptoCustomMessage(T data) throws IOException { + this.data = data; + this.dataReader = null; + } + + private CryptoCustomMessage(CryptoBox container, Reader dataReader) { + this.container = container; + this.dataReader = dataReader; + } + + public static CryptoCustomMessage read(byte[] data, Reader dataReader) throws IOException { + CryptoBox cryptoBox = CryptoBox.read(new ByteArrayInputStream(data), data.length); + return new CryptoCustomMessage<>(cryptoBox, dataReader); + } + + public BitmessageAddress getSender() { + return sender; + } + + public void signAndEncrypt(BitmessageAddress identity, byte[] publicKey) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + Encode.varInt(identity.getVersion(), out); + Encode.varInt(identity.getStream(), out); + Encode.int32(identity.getPubkey().getBehaviorBitfield(), out); + out.write(identity.getPubkey().getSigningKey(), 1, 64); + out.write(identity.getPubkey().getEncryptionKey(), 1, 64); + if (identity.getVersion() >= 3) { + Encode.varInt(identity.getPubkey().getNonceTrialsPerByte(), out); + Encode.varInt(identity.getPubkey().getExtraBytes(), out); + } + + data.write(out); + Encode.varBytes(security().getSignature(out.toByteArray(), identity.getPrivateKey()), out); + container = new CryptoBox(out.toByteArray(), publicKey); + } + + public T decrypt(byte[] privateKey) throws IOException, DecryptionFailedException { + SignatureCheckingInputStream in = new SignatureCheckingInputStream(container.decrypt(privateKey)); + + long addressVersion = varInt(in); + long stream = varInt(in); + int behaviorBitfield = int32(in); + byte[] publicSigningKey = bytes(in, 64); + byte[] publicEncryptionKey = bytes(in, 64); + long nonceTrialsPerByte = addressVersion >= 3 ? varInt(in) : 0; + long extraBytes = addressVersion >= 3 ? varInt(in) : 0; + + sender = new BitmessageAddress(Factory.createPubkey( + addressVersion, + stream, + publicSigningKey, + publicEncryptionKey, + nonceTrialsPerByte, + extraBytes, + behaviorBitfield + )); + + data = dataReader.read(sender, in); + + in.checkSignature(sender.getPubkey()); + + return data; + } + + @Override + public void write(OutputStream out) throws IOException { + container.write(out); + } + + public interface Reader { + T read(BitmessageAddress sender, InputStream in) throws IOException; + } + + private class SignatureCheckingInputStream extends InputStream { + private final ByteArrayOutputStream out = new ByteArrayOutputStream(); + private final InputStream wrapped; + + private SignatureCheckingInputStream(InputStream wrapped) { + this.wrapped = wrapped; + } + + @Override + public int read() throws IOException { + int read = wrapped.read(); + if (read >= 0) out.write(read); + return read; + } + + public void checkSignature(Pubkey pubkey) throws IOException, RuntimeException { + if (!security().isSignatureValid(out.toByteArray(), varBytes(wrapped), pubkey)) { + throw new RuntimeException("Signature check failed"); + } + } + } +} diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java new file mode 100644 index 0000000..b247b59 --- /dev/null +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2015 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.extensions.pow; + +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.Streamable; +import ch.dissem.bitmessage.utils.Encode; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import static ch.dissem.bitmessage.utils.Decode.*; + +/** + * @author Christian Basler + */ +public class ProofOfWorkRequest implements Streamable { + private final BitmessageAddress sender; + private final byte[] initialHash; + private final Request request; + private final byte[] data; + + private ProofOfWorkRequest(BitmessageAddress sender, byte[] initialHash, Request request, byte[] data) { + this.sender = sender; + this.initialHash = initialHash; + this.request = request; + this.data = data; + } + + public static ProofOfWorkRequest read(BitmessageAddress client, InputStream in) throws IOException { + return new ProofOfWorkRequest( + client, + bytes(in, 64), + Request.valueOf(varString(in)), + varBytes(in) + ); + } + + public BitmessageAddress getSender() { + return sender; + } + + public byte[] getInitialHash() { + return initialHash; + } + + public Request getRequest() { + return request; + } + + public byte[] getData() { + return data; + } + + @Override + public void write(OutputStream out) throws IOException { + out.write(initialHash); + Encode.varString(request.name(), out); + Encode.varBytes(data, out); + } + + public enum Request { + CALCULATE, + QUERY, + ERROR, + OK, + QUEUED, + CALCULATING, + COMPLETE + } +} diff --git a/extensions/src/test/java/ch/dissem/bitmessage/extensions/CryptoCustomMessageTest.java b/extensions/src/test/java/ch/dissem/bitmessage/extensions/CryptoCustomMessageTest.java new file mode 100644 index 0000000..98e97a1 --- /dev/null +++ b/extensions/src/test/java/ch/dissem/bitmessage/extensions/CryptoCustomMessageTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.extensions; + +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.payload.GenericPayload; +import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.utils.TestBase; +import ch.dissem.bitmessage.utils.TestUtils; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import static ch.dissem.bitmessage.utils.Singleton.security; +import static org.junit.Assert.assertEquals; + +public class CryptoCustomMessageTest extends TestBase { + @Test + public void testEncryptThenDecrypt() throws Exception { + PrivateKey privateKey = PrivateKey.read(TestUtils.getResource("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey")); + BitmessageAddress sendingIdentity = new BitmessageAddress(privateKey); + + GenericPayload payloadBefore = new GenericPayload(0, 1, security().randomBytes(100)); + CryptoCustomMessage messageBefore = new CryptoCustomMessage<>(payloadBefore); + messageBefore.signAndEncrypt(sendingIdentity, security().createPublicKey(sendingIdentity.getPublicDecryptionKey())); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + messageBefore.write(out); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + + CryptoCustomMessage messageAfter = CryptoCustomMessage.read(out.toByteArray(), new CryptoCustomMessage.Reader() { + @Override + public GenericPayload read(BitmessageAddress ignore, InputStream in) throws IOException { + return GenericPayload.read(0, in, 1, 100); + } + }); + GenericPayload payloadAfter = messageAfter.decrypt(sendingIdentity.getPublicDecryptionKey()); + + assertEquals(payloadBefore, payloadAfter); + } +} diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 8ed2fb4..a95adba 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -259,6 +259,12 @@ public class Connection { LOG.debug("Received " + addr.getAddresses().size() + " addresses."); ctx.getNodeRegistry().offerAddresses(addr.getAddresses()); break; + case CUSTOM: + MessagePayload response = ctx.getCustomCommandHandler().handle((CustomMessage) messagePayload); + if (response != null) { + send(response); + } + break; case VERACK: case VERSION: throw new RuntimeException("Unexpectedly received '" + messagePayload.getCommand() + "' command"); diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcHelper.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcHelper.java index 601ce29..d583a71 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcHelper.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcHelper.java @@ -31,7 +31,7 @@ import static ch.dissem.bitmessage.utils.Strings.hex; /** * Helper class that does Flyway migration, provides JDBC connections and some helper methods. */ -abstract class JdbcHelper { +public abstract class JdbcHelper { private static final Logger LOG = LoggerFactory.getLogger(JdbcHelper.class); protected final JdbcConfig config; diff --git a/settings.gradle b/settings.gradle index 2d3e1f6..adecd45 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,3 +13,5 @@ include 'wif' include 'security-sc' include 'security-bc' + +include 'extensions' \ No newline at end of file From 991a0e5f869a6c6087901ff405175e2039e69457 Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Wed, 2 Dec 2015 17:45:50 +0100 Subject: [PATCH 02/54] Some improvements for custom message handling --- .../bitmessage/entity/CustomMessage.java | 13 ++++++--- .../bitmessage/ports/NetworkHandler.java | 14 ++++++++- .../extensions/pow/ProofOfWorkRequest.java | 12 ++++---- gradle/wrapper/gradle-wrapper.properties | 2 +- .../bitmessage/networking/Connection.java | 12 ++++---- .../networking/DefaultNetworkHandler.java | 29 +++++++++++++++++-- .../bitmessage/wif/WifExporterTest.java | 16 +++++----- 7 files changed, 72 insertions(+), 26 deletions(-) diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java index b31c9f5..63f9663 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java @@ -16,10 +16,7 @@ package ch.dissem.bitmessage.entity; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import static ch.dissem.bitmessage.utils.Decode.bytes; @@ -65,4 +62,12 @@ public class CustomMessage implements MessagePayload { "Programmer: did you forget to override #write()?"); } } + + public static CustomMessage error(String message) { + try { + return new CustomMessage(("ERROR\n" + message).getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java b/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java index e2fd170..909d3dd 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java @@ -16,6 +16,7 @@ package ch.dissem.bitmessage.ports; +import ch.dissem.bitmessage.entity.CustomMessage; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.utils.Property; @@ -34,7 +35,18 @@ public interface NetworkHandler { * An implementation should disconnect if either the timeout is reached or the returned thread is interrupted. *

*/ - Future synchronize(InetAddress trustedHost, int port, MessageListener listener, long timeoutInSeconds); + Future synchronize(InetAddress server, int port, MessageListener listener, long timeoutInSeconds); + + /** + * Send a custom message to a specific node (that should implement handling for this message type) and returns + * the response, which in turn is expected to be a {@link CustomMessage}. + * + * @param server the node's address + * @param port the node's port + * @param request the request + * @return the response + */ + CustomMessage send(InetAddress server, int port, CustomMessage request); /** * Start a full network node, accepting incoming connections and relaying objects. diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java index b247b59..2ef2f9e 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import static ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest.Request.CALCULATE; import static ch.dissem.bitmessage.utils.Decode.*; /** @@ -35,7 +36,11 @@ public class ProofOfWorkRequest implements Streamable { private final Request request; private final byte[] data; - private ProofOfWorkRequest(BitmessageAddress sender, byte[] initialHash, Request request, byte[] data) { + public ProofOfWorkRequest(BitmessageAddress sender, byte[] initialHash, Request request) { + this(sender, initialHash, request, new byte[0]); + } + + public ProofOfWorkRequest(BitmessageAddress sender, byte[] initialHash, Request request, byte[] data) { this.sender = sender; this.initialHash = initialHash; this.request = request; @@ -76,11 +81,8 @@ public class ProofOfWorkRequest implements Streamable { public enum Request { CALCULATE, - QUERY, - ERROR, - OK, - QUEUED, CALCULATING, + QUERY, COMPLETE } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 66e6c70..94f382d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index a95adba..4d14fe2 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -260,11 +260,6 @@ public class Connection { ctx.getNodeRegistry().offerAddresses(addr.getAddresses()); break; case CUSTOM: - MessagePayload response = ctx.getCustomCommandHandler().handle((CustomMessage) messagePayload); - if (response != null) { - send(response); - } - break; case VERACK: case VERSION: throw new RuntimeException("Unexpectedly received '" + messagePayload.getCommand() + "' command"); @@ -400,6 +395,13 @@ public class Connection { break; } break; + case CUSTOM: + MessagePayload response = ctx.getCustomCommandHandler().handle((CustomMessage) msg.getPayload()); + if (response != null) { + send(response); + } + disconnect(); + break; default: throw new NodeException("Command 'version' or 'verack' expected, but was '" + msg.getPayload().getCommand() + "'"); diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java index 3944378..e934bdf 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java @@ -18,8 +18,12 @@ package ch.dissem.bitmessage.networking; import ch.dissem.bitmessage.InternalContext; import ch.dissem.bitmessage.InternalContext.ContextHolder; +import ch.dissem.bitmessage.entity.CustomMessage; +import ch.dissem.bitmessage.entity.NetworkMessage; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; +import ch.dissem.bitmessage.exception.NodeException; +import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.NetworkHandler; import ch.dissem.bitmessage.utils.Collections; import ch.dissem.bitmessage.utils.Property; @@ -71,9 +75,9 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { } @Override - public Future synchronize(InetAddress trustedHost, int port, MessageListener listener, long timeoutInSeconds) { + public Future synchronize(InetAddress server, int port, MessageListener listener, long timeoutInSeconds) { try { - Connection connection = Connection.sync(ctx, trustedHost, port, listener, timeoutInSeconds); + Connection connection = Connection.sync(ctx, server, port, listener, timeoutInSeconds); Future reader = pool.submit(connection.getReader()); pool.execute(connection.getWriter()); return reader; @@ -82,6 +86,27 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { } } + @Override + public CustomMessage send(InetAddress server, int port, CustomMessage request) { + try (Socket socket = new Socket(server, port)) { + socket.setSoTimeout(Connection.READ_TIMEOUT); + new NetworkMessage(request).write(socket.getOutputStream()); + NetworkMessage networkMessage = Factory.getNetworkMessage(3, socket.getInputStream()); + if (networkMessage != null && networkMessage.getPayload() instanceof CustomMessage) { + return (CustomMessage) networkMessage.getPayload(); + } else { + if (networkMessage == null) { + throw new NodeException("No response from node " + server); + } else { + throw new NodeException("Unexpected response from node " + + server + ": " + networkMessage.getPayload().getCommand()); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @Override public void start(final MessageListener listener) { if (listener == null) { diff --git a/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java b/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java index 5ed9025..a2ee560 100644 --- a/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java +++ b/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java @@ -72,14 +72,14 @@ public class WifExporterTest { @Test public void testAddIdentity() throws Exception { - String expected = "[BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn]\n" + - "label = Nuked Address\n" + - "enabled = true\n" + - "decoy = false\n" + - "noncetrialsperbyte = 320\n" + - "payloadlengthextrabytes = 14000\n" + - "privsigningkey = 5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9\n" + - "privencryptionkey = 5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck\n\n"; + String expected = "[BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn]" + System.lineSeparator() + + "label = Nuked Address" + System.lineSeparator() + + "enabled = true" + System.lineSeparator() + + "decoy = false" + System.lineSeparator() + + "noncetrialsperbyte = 320" + System.lineSeparator() + + "payloadlengthextrabytes = 14000" + System.lineSeparator() + + "privsigningkey = 5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9" + System.lineSeparator() + + "privencryptionkey = 5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck" + System.lineSeparator() + System.lineSeparator(); importer = new WifImporter(ctx, expected); exporter.addIdentity(importer.getIdentities().get(0)); assertEquals(expected, exporter.toString()); From ab6a3c56dd2a72d3cfc28bb5aeea3a573e7ab183 Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Tue, 8 Dec 2015 20:27:32 +0100 Subject: [PATCH 03/54] The POW callback is now a service and its state stored. The proof of work engine therefore just has to remember its initial hash making server based POW easier. --- .../dissem/bitmessage/demo/Application.java | 6 +- .../java/ch/dissem/bitmessage/demo/Main.java | 1 + .../dissem/bitmessage/BitmessageContext.java | 32 +++++---- .../bitmessage/DefaultMessageListener.java | 16 ++--- .../ch/dissem/bitmessage/InternalContext.java | 69 +++++-------------- .../dissem/bitmessage/ProofOfWorkService.java | 62 +++++++++++++++++ .../bitmessage/entity/CustomMessage.java | 23 +++++-- .../bitmessage/entity/ObjectMessage.java | 6 +- .../dissem/bitmessage/entity/Plaintext.java | 9 +++ .../bitmessage/ports/AbstractSecurity.java | 9 ++- .../bitmessage/ports/MessageRepository.java | 2 + .../ports/MultiThreadedPOWEngine.java | 6 +- .../bitmessage/ports/ProofOfWorkEngine.java | 2 +- .../ports/ProofOfWorkRepository.java | 16 +++++ .../ch/dissem/bitmessage/ports/Security.java | 2 + .../bitmessage/ports/SimplePOWEngine.java | 2 +- .../ch/dissem/bitmessage/utils/Decode.java | 8 ++- .../ch/dissem/bitmessage/utils/Numbers.java | 10 +++ .../ports/ProofOfWorkEngineTest.java | 4 +- .../extensions/CryptoCustomMessage.java | 3 + .../repository/JdbcMessageRepository.java | 26 +++++-- .../repository/JdbcProofOfWorkRepository.java | 69 +++++++++++++++++++ .../migration/V2.0__Update_table_message.sql | 2 + .../db/migration/V2.1__Create_table_POW.sql | 5 ++ .../bitmessage/security/SecurityTest.java | 2 +- 25 files changed, 289 insertions(+), 103 deletions(-) create mode 100644 domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java create mode 100644 domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java create mode 100644 domain/src/main/java/ch/dissem/bitmessage/utils/Numbers.java create mode 100644 repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java create mode 100644 repositories/src/main/resources/db/migration/V2.0__Update_table_message.sql create mode 100644 repositories/src/main/resources/db/migration/V2.1__Create_table_POW.sql diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java index a065de9..72da50d 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java @@ -22,10 +22,7 @@ import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.ports.MemoryNodeRegistry; -import ch.dissem.bitmessage.repository.JdbcAddressRepository; -import ch.dissem.bitmessage.repository.JdbcConfig; -import ch.dissem.bitmessage.repository.JdbcInventory; -import ch.dissem.bitmessage.repository.JdbcMessageRepository; +import ch.dissem.bitmessage.repository.*; import ch.dissem.bitmessage.security.bc.BouncySecurity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,6 +47,7 @@ public class Application { .inventory(new JdbcInventory(jdbcConfig)) .nodeRegistry(new MemoryNodeRegistry()) .messageRepo(new JdbcMessageRepository(jdbcConfig)) + .powRepo(new JdbcProofOfWorkRepository(jdbcConfig)) .networkHandler(new DefaultNetworkHandler()) .security(new BouncySecurity()) .port(48444) diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java index ac90e88..6dbfc14 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java @@ -51,6 +51,7 @@ public class Main { .inventory(new JdbcInventory(jdbcConfig)) .nodeRegistry(new MemoryNodeRegistry()) .messageRepo(new JdbcMessageRepository(jdbcConfig)) + .powRepo(new JdbcProofOfWorkRepository(jdbcConfig)) .networkHandler(new DefaultNetworkHandler()) .security(new BouncySecurity()) .port(48444) diff --git a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 9d4abd7..def0a4f 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -75,7 +75,7 @@ public class BitmessageContext { } public AddressRepository addresses() { - return ctx.getAddressRepo(); + return ctx.getAddressRepository(); } public MessageRepository messages() { @@ -90,7 +90,7 @@ public class BitmessageContext { ctx.getNetworkExtraBytes(), features )); - ctx.getAddressRepo().save(identity); + ctx.getAddressRepository().save(identity); pool.submit(new Runnable() { @Override public void run() { @@ -102,6 +102,7 @@ public class BitmessageContext { public void addDistributedMailingList(String address, String alias) { // TODO + throw new RuntimeException("not implemented"); } public void broadcast(final BitmessageAddress from, final String subject, final String message) { @@ -120,9 +121,7 @@ public class BitmessageContext { from, from, Factory.getBroadcast(from, msg), - +2 * DAY, - 0, - 0 + +2 * DAY ); msg.setStatus(SENT); msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.BROADCAST, Label.Type.SENT)); @@ -159,9 +158,7 @@ public class BitmessageContext { from, to, new Msg(msg), - +2 * DAY, - ctx.getNonceTrialsPerByte(to), - ctx.getExtraBytes(to) + +2 * DAY ); msg.setStatus(SENT); msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.SENT)); @@ -176,9 +173,7 @@ public class BitmessageContext { requestingIdentity, address, new GetPubkey(address), - +28 * DAY, - ctx.getNetworkNonceTrialsPerByte(), - ctx.getNetworkExtraBytes() + +28 * DAY ); } @@ -220,7 +215,7 @@ public class BitmessageContext { } public void addContact(BitmessageAddress contact) { - ctx.getAddressRepo().save(contact); + ctx.getAddressRepository().save(contact); tryToFindMatchingPubkey(contact); if (contact.getPubkey() == null) { ctx.requestPubkey(contact); @@ -237,7 +232,7 @@ public class BitmessageContext { v4Pubkey.decrypt(address.getPublicDecryptionKey()); if (object.isSignatureValid(v4Pubkey)) { address.setPubkey(v4Pubkey); - ctx.getAddressRepo().save(address); + ctx.getAddressRepository().save(address); break; } else { LOG.info("Found pubkey for " + address + " but signature is invalid"); @@ -246,7 +241,7 @@ public class BitmessageContext { } else { if (Arrays.equals(pubkey.getRipe(), address.getRipe())) { address.setPubkey(pubkey); - ctx.getAddressRepo().save(address); + ctx.getAddressRepository().save(address); break; } } @@ -258,7 +253,7 @@ public class BitmessageContext { public void addSubscribtion(BitmessageAddress address) { address.setSubscribed(true); - ctx.getAddressRepo().save(address); + ctx.getAddressRepository().save(address); tryToFindBroadcastsForAddress(address); } @@ -292,6 +287,7 @@ public class BitmessageContext { NetworkHandler networkHandler; AddressRepository addressRepo; MessageRepository messageRepo; + ProofOfWorkRepository proofOfWorkRepository; ProofOfWorkEngine proofOfWorkEngine; Security security; MessageCallback messageCallback; @@ -333,6 +329,11 @@ public class BitmessageContext { return this; } + public Builder powRepo(ProofOfWorkRepository proofOfWorkRepository) { + this.proofOfWorkRepository = proofOfWorkRepository; + return this; + } + public Builder security(Security security) { this.security = security; return this; @@ -374,6 +375,7 @@ public class BitmessageContext { nonNull("networkHandler", networkHandler); nonNull("addressRepo", addressRepo); nonNull("messageRepo", messageRepo); + nonNull("proofOfWorkRepo", proofOfWorkRepository); if (proofOfWorkEngine == null) { proofOfWorkEngine = new MultiThreadedPOWEngine(); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java index e069704..eb22f03 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java +++ b/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java @@ -69,7 +69,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { } protected void receive(ObjectMessage object, GetPubkey getPubkey) { - BitmessageAddress identity = ctx.getAddressRepo().findIdentity(getPubkey.getRipeTag()); + BitmessageAddress identity = ctx.getAddressRepository().findIdentity(getPubkey.getRipeTag()); if (identity != null && identity.getPrivateKey() != null) { LOG.info("Got pubkey request for identity " + identity); // FIXME: only send pubkey if it wasn't sent in the last 28 days @@ -82,17 +82,17 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { try { if (pubkey instanceof V4Pubkey) { V4Pubkey v4Pubkey = (V4Pubkey) pubkey; - address = ctx.getAddressRepo().findContact(v4Pubkey.getTag()); + address = ctx.getAddressRepository().findContact(v4Pubkey.getTag()); if (address != null) { v4Pubkey.decrypt(address.getPublicDecryptionKey()); } } else { - address = ctx.getAddressRepo().findContact(pubkey.getRipe()); + address = ctx.getAddressRepository().findContact(pubkey.getRipe()); } if (address != null) { address.setPubkey(pubkey); LOG.info("Got pubkey for contact " + address); - ctx.getAddressRepo().save(address); + ctx.getAddressRepository().save(address); List messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address); LOG.info("Sending " + messages.size() + " messages for contact " + address); for (Plaintext msg : messages) { @@ -102,9 +102,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { msg.getFrom(), msg.getTo(), new Msg(msg), - +2 * DAY, - ctx.getNonceTrialsPerByte(msg.getTo()), - ctx.getExtraBytes(msg.getTo()) + +2 * DAY ); msg.setStatus(SENT); ctx.getMessageRepository().save(msg); @@ -115,7 +113,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { } protected void receive(ObjectMessage object, Msg msg) throws IOException { - for (BitmessageAddress identity : ctx.getAddressRepo().getIdentities()) { + for (BitmessageAddress identity : ctx.getAddressRepository().getIdentities()) { try { msg.decrypt(identity.getPrivateKey().getPrivateEncryptionKey()); msg.getPlaintext().setTo(identity); @@ -136,7 +134,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { protected void receive(ObjectMessage object, Broadcast broadcast) throws IOException { byte[] tag = broadcast instanceof V5Broadcast ? ((V5Broadcast) broadcast).getTag() : null; - for (BitmessageAddress subscription : ctx.getAddressRepo().getSubscriptions(broadcast.getVersion())) { + for (BitmessageAddress subscription : ctx.getAddressRepository().getSubscriptions(broadcast.getVersion())) { if (tag != null && !Arrays.equals(tag, subscription.getTag())) { continue; } diff --git a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java index 95cd8d8..d139de5 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -48,9 +48,11 @@ public class InternalContext { private final NetworkHandler networkHandler; private final AddressRepository addressRepository; private final MessageRepository messageRepository; + private final ProofOfWorkRepository proofOfWorkRepository; private final ProofOfWorkEngine proofOfWorkEngine; private final MessageCallback messageCallback; private final CustomCommandHandler customCommandHandler; + private final ProofOfWorkService proofOfWorkService; private final TreeSet<Long> streams = new TreeSet<>(); private final int port; @@ -67,6 +69,8 @@ public class InternalContext { this.networkHandler = builder.networkHandler; this.addressRepository = builder.addressRepo; this.messageRepository = builder.messageRepo; + this.proofOfWorkRepository = builder.proofOfWorkRepository; + this.proofOfWorkService = new ProofOfWorkService(); this.proofOfWorkEngine = builder.proofOfWorkEngine; this.clientNonce = security.randomNonce(); this.messageCallback = builder.messageCallback; @@ -88,7 +92,9 @@ public class InternalContext { streams.add(1L); } - init(security, inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine); + init(security, inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, + proofOfWorkRepository, proofOfWorkService, proofOfWorkEngine, + messageCallback, customCommandHandler); for (BitmessageAddress identity : addressRepository.getIdentities()) { streams.add(identity.getStream()); } @@ -118,7 +124,7 @@ public class InternalContext { return networkHandler; } - public AddressRepository getAddressRepo() { + public AddressRepository getAddressRepository() { return addressRepository; } @@ -126,6 +132,10 @@ public class InternalContext { return messageRepository; } + public ProofOfWorkRepository getProofOfWorkRepository() { + return proofOfWorkRepository; + } + public ProofOfWorkEngine getProofOfWorkEngine() { return proofOfWorkEngine; } @@ -147,22 +157,12 @@ public class InternalContext { return networkNonceTrialsPerByte; } - public long getNonceTrialsPerByte(BitmessageAddress address) { - long nonceTrialsPerByte = address.getPubkey().getNonceTrialsPerByte(); - return networkNonceTrialsPerByte > nonceTrialsPerByte ? networkNonceTrialsPerByte : nonceTrialsPerByte; - } - public long getNetworkExtraBytes() { return networkExtraBytes; } - public long getExtraBytes(BitmessageAddress address) { - long extraBytes = address.getPubkey().getExtraBytes(); - return networkExtraBytes > extraBytes ? networkExtraBytes : extraBytes; - } - public void send(final BitmessageAddress from, BitmessageAddress to, final ObjectPayload payload, - final long timeToLive, final long nonceTrialsPerByte, final long extraBytes) { + final long timeToLive) { try { if (to == null) to = from; long expires = UnixTime.now(+timeToLive); @@ -181,22 +181,7 @@ public class InternalContext { object.encrypt(to.getPubkey()); } messageCallback.proofOfWorkStarted(payload); - security.doProofOfWork(object, nonceTrialsPerByte, extraBytes, - new ProofOfWorkEngine.Callback() { - @Override - public void onNonceCalculated(byte[] nonce) { - object.setNonce(nonce); - messageCallback.proofOfWorkCompleted(payload); - if (payload instanceof PlaintextHolder) { - Plaintext plaintext = ((PlaintextHolder) payload).getPlaintext(); - plaintext.setInventoryVector(object.getInventoryVector()); - messageRepository.save(plaintext); - } - inventory.storeObject(object); - networkHandler.offer(object.getInventoryVector()); - messageCallback.messageOffered(payload, object.getInventoryVector()); - } - }); + proofOfWorkService.doProofOfWork(to, object); } catch (IOException e) { throw new RuntimeException(e); } @@ -214,18 +199,8 @@ public class InternalContext { response.sign(identity.getPrivateKey()); response.encrypt(security.createPublicKey(identity.getPublicDecryptionKey())); messageCallback.proofOfWorkStarted(identity.getPubkey()); - security.doProofOfWork(response, networkNonceTrialsPerByte, networkExtraBytes, - new ProofOfWorkEngine.Callback() { - @Override - public void onNonceCalculated(byte[] nonce) { - response.setNonce(nonce); - messageCallback.proofOfWorkCompleted(identity.getPubkey()); - inventory.storeObject(response); - networkHandler.offer(response.getInventoryVector()); - // TODO: save that the pubkey was just sent, and on which stream! - messageCallback.messageOffered(identity.getPubkey(), response.getInventoryVector()); - } - }); + // TODO: remember that the pubkey is just about to be sent, and on which stream! + proofOfWorkService.doProofOfWork(response); } catch (IOException e) { throw new RuntimeException(e); } @@ -240,17 +215,7 @@ public class InternalContext { .payload(new GetPubkey(contact)) .build(); messageCallback.proofOfWorkStarted(response.getPayload()); - security.doProofOfWork(response, networkNonceTrialsPerByte, networkExtraBytes, - new ProofOfWorkEngine.Callback() { - @Override - public void onNonceCalculated(byte[] nonce) { - response.setNonce(nonce); - messageCallback.proofOfWorkCompleted(response.getPayload()); - inventory.storeObject(response); - networkHandler.offer(response.getInventoryVector()); - messageCallback.messageOffered(response.getPayload(), response.getInventoryVector()); - } - }); + proofOfWorkService.doProofOfWork(response); } public long getClientNonce() { diff --git a/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java new file mode 100644 index 0000000..3cf46ef --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java @@ -0,0 +1,62 @@ +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.ObjectMessage; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.PlaintextHolder; +import ch.dissem.bitmessage.ports.MessageRepository; +import ch.dissem.bitmessage.ports.ProofOfWorkEngine; +import ch.dissem.bitmessage.ports.ProofOfWorkRepository; +import ch.dissem.bitmessage.ports.Security; + +import static ch.dissem.bitmessage.utils.Singleton.security; + +/** + * @author Christian Basler + */ +public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalContext.ContextHolder { + private Security security; + private InternalContext ctx; + private ProofOfWorkRepository powRepo; + private MessageRepository messageRepo; + + public void doProofOfWork(ObjectMessage object) { + doProofOfWork(null, object); + } + + public void doProofOfWork(BitmessageAddress recipient, ObjectMessage object) { + long nonceTrialsPerByte = recipient == null ? 0 : recipient.getPubkey().getNonceTrialsPerByte(); + long extraBytes = recipient == null ? 0 : recipient.getPubkey().getExtraBytes(); + + powRepo.putObject(object, nonceTrialsPerByte, extraBytes); + if (object.getPayload() instanceof PlaintextHolder){ + Plaintext plaintext = ((PlaintextHolder) object.getPayload()).getPlaintext(); + plaintext.setInitialHash(security.getInitialHash(object)); + messageRepo.save(plaintext); + } + security.doProofOfWork(object, nonceTrialsPerByte, extraBytes, this); + } + + @Override + public void onNonceCalculated(byte[] initialHash, byte[] nonce) { + ObjectMessage object = powRepo.getObject(initialHash); + object.setNonce(nonce); +// messageCallback.proofOfWorkCompleted(payload); + Plaintext plaintext = messageRepo.getMessage(initialHash); + if (plaintext != null) { + plaintext.setInventoryVector(object.getInventoryVector()); + messageRepo.save(plaintext); + } + ctx.getInventory().storeObject(object); + ctx.getNetworkHandler().offer(object.getInventoryVector()); +// messageCallback.messageOffered(payload, object.getInventoryVector()); + } + + @Override + public void setContext(InternalContext ctx) { + this.ctx = ctx; + this.security = security(); + this.powRepo = ctx.getProofOfWorkRepository(); + this.messageRepo = ctx.getMessageRepository(); + } +} diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java index 63f9663..a5caf3a 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java @@ -16,26 +16,36 @@ package ch.dissem.bitmessage.entity; +import ch.dissem.bitmessage.utils.AccessCounter; +import ch.dissem.bitmessage.utils.Encode; + import java.io.*; import static ch.dissem.bitmessage.utils.Decode.bytes; +import static ch.dissem.bitmessage.utils.Decode.varString; /** * @author Christian Basler */ public class CustomMessage implements MessagePayload { + public static final String COMMAND_ERROR = "ERROR"; + + private final String command; private final byte[] data; - public CustomMessage() { + public CustomMessage(String command) { + this.command = command; this.data = null; } - public CustomMessage(byte[] data) { + public CustomMessage(String command, byte[] data) { + this.command = command; this.data = data; } public static MessagePayload read(InputStream in, int length) throws IOException { - return new CustomMessage(bytes(in, length)); + AccessCounter counter = new AccessCounter(); + return new CustomMessage(varString(in, counter), bytes(in, length - counter.length())); } @Override @@ -56,6 +66,7 @@ public class CustomMessage implements MessagePayload { @Override public void write(OutputStream out) throws IOException { if (data != null) { + Encode.varString(command, out); out.write(data); } else { throw new RuntimeException("Tried to write custom message without data. " + @@ -63,9 +74,13 @@ public class CustomMessage implements MessagePayload { } } + public boolean isError() { + return COMMAND_ERROR.equals(command); + } + public static CustomMessage error(String message) { try { - return new CustomMessage(("ERROR\n" + message).getBytes("UTF-8")); + return new CustomMessage(COMMAND_ERROR, message.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java index 128084e..9e89c42 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java @@ -156,7 +156,11 @@ public class ObjectMessage implements MessagePayload { @Override public void write(OutputStream out) throws IOException { - out.write(nonce); + if (nonce != null) { + out.write(nonce); + } else { + out.write(new byte[8]); + } out.write(getPayloadBytesWithoutNonce()); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java b/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java index eb0a60f..fbd5d48 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java @@ -44,6 +44,7 @@ public class Plaintext implements Streamable { private Long received; private Set<Label> labels; + private byte[] initialHash; private Plaintext(Builder builder) { id = builder.id; @@ -260,6 +261,14 @@ public class Plaintext implements Streamable { } } + public void setInitialHash(byte[] initialHash) { + this.initialHash = initialHash; + } + + public byte[] getInitialHash() { + return initialHash; + } + public enum Encoding { IGNORE(0), TRIVIAL(1), SIMPLE(2); diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java b/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java index bd55180..0dea04c 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java @@ -34,6 +34,8 @@ import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.SecureRandom; +import static ch.dissem.bitmessage.utils.Numbers.max; + /** * Implements everything that isn't directly dependent on either Spongy- or Bouncycastle. */ @@ -95,8 +97,8 @@ public abstract class AbstractSecurity implements Security, InternalContext.Cont public void doProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes, ProofOfWorkEngine.Callback callback) { try { - if (nonceTrialsPerByte < 1000) nonceTrialsPerByte = 1000; - if (extraBytes < 1000) extraBytes = 1000; + nonceTrialsPerByte = max(nonceTrialsPerByte, context.getNetworkNonceTrialsPerByte()); + extraBytes = max(extraBytes, context.getNetworkExtraBytes()); byte[] initialHash = getInitialHash(object); @@ -117,7 +119,8 @@ public abstract class AbstractSecurity implements Security, InternalContext.Cont } } - private byte[] getInitialHash(ObjectMessage object) throws IOException { + @Override + public byte[] getInitialHash(ObjectMessage object) { return sha512(object.getPayloadBytesWithoutNonce()); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java b/domain/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java index af7b2bc..9e949a7 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java @@ -30,6 +30,8 @@ public interface MessageRepository { int countUnread(Label label); + Plaintext getMessage(byte[] initialHash); + List<Plaintext> findMessages(Label label); List<Plaintext> findMessages(Status status); diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java b/domain/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java index ac65d3d..5e00e33 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java @@ -102,7 +102,7 @@ public class MultiThreadedPOWEngine implements ProofOfWorkEngine { synchronized (callback) { if (!Thread.interrupted()) { try { - callback.onNonceCalculated(nonce); + callback.onNonceCalculated(initialHash, nonce); } finally { semaphore.release(); for (Worker w : workers) { @@ -128,12 +128,12 @@ public class MultiThreadedPOWEngine implements ProofOfWorkEngine { } @Override - public void onNonceCalculated(byte[] nonce) { + public void onNonceCalculated(byte[] initialHash, byte[] nonce) { synchronized (this) { if (waiting) { LOG.info("Nonce calculated in " + ((System.currentTimeMillis() - startTime) / 1000) + " seconds"); waiting = false; - callback.onNonceCalculated(nonce); + callback.onNonceCalculated(initialHash, nonce); } } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java b/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java index 90513dc..fc7b4c2 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java @@ -35,6 +35,6 @@ public interface ProofOfWorkEngine { /** * @param nonce 8 bytes nonce */ - void onNonceCalculated(byte[] nonce); + void onNonceCalculated(byte[] initialHash, byte[] nonce); } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java b/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java new file mode 100644 index 0000000..9971ad5 --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java @@ -0,0 +1,16 @@ +package ch.dissem.bitmessage.ports; + +import ch.dissem.bitmessage.entity.ObjectMessage; + +/** + * Objects that proof of work is currently being done for. + * + * @author Christian Basler + */ +public interface ProofOfWorkRepository { + ObjectMessage getObject(byte[] initialHash); + + void putObject(ObjectMessage object, long nonceTrialsPerByte, long extraBytes); + + void removeObject(ObjectMessage object); +} diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java b/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java index c5fcb8f..8fc7e20 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java @@ -134,6 +134,8 @@ public interface Security { void checkProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) throws IOException; + byte[] getInitialHash(ObjectMessage object); + /** * Calculates the MAC for a message (data) * diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java b/domain/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java index 25d51aa..06d234b 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java @@ -40,6 +40,6 @@ public class SimplePOWEngine implements ProofOfWorkEngine { mda.update(nonce); mda.update(initialHash); } while (Bytes.lt(target, mda.digest(mda.digest()), 8)); - callback.onNonceCalculated(nonce); + callback.onNonceCalculated(initialHash, nonce); } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Decode.java b/domain/src/main/java/ch/dissem/bitmessage/utils/Decode.java index b539aa9..47b0ee3 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/utils/Decode.java +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/Decode.java @@ -130,9 +130,13 @@ public class Decode { } public static String varString(InputStream stream) throws IOException { - int length = (int) varInt(stream); + return varString(stream, null); + } + + public static String varString(InputStream stream, AccessCounter counter) throws IOException { + int length = (int) varInt(stream, counter); // FIXME: technically, it says the length in characters, but I think this one might be correct // otherwise it will get complicated, as we'll need to read UTF-8 char by char... - return new String(bytes(stream, length), "utf-8"); + return new String(bytes(stream, length, counter), "utf-8"); } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Numbers.java b/domain/src/main/java/ch/dissem/bitmessage/utils/Numbers.java new file mode 100644 index 0000000..b1ace02 --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/Numbers.java @@ -0,0 +1,10 @@ +package ch.dissem.bitmessage.utils; + +/** + * Created by chrig on 07.12.2015. + */ +public class Numbers { + public static long max(long a, long b) { + return a > b ? a : b; + } +} diff --git a/domain/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java b/domain/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java index ba5307d..1ed4aac 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java @@ -43,7 +43,7 @@ public class ProofOfWorkEngineTest extends TestBase { engine.calculateNonce(initialHash, target, new ProofOfWorkEngine.Callback() { @Override - public void onNonceCalculated(byte[] nonce) { + public void onNonceCalculated(byte[] initialHash, byte[] nonce) { waiter1.setValue(nonce); } }); @@ -59,7 +59,7 @@ public class ProofOfWorkEngineTest extends TestBase { engine.calculateNonce(initialHash2, target2, new ProofOfWorkEngine.Callback() { @Override - public void onNonceCalculated(byte[] nonce) { + public void onNonceCalculated(byte[] initialHash, byte[] nonce) { waiter2.setValue(nonce); } }); diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java index 5d82f4d..9a9e2dc 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java @@ -36,17 +36,20 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * @author Christian Basler */ public class CryptoCustomMessage<T extends Streamable> extends CustomMessage { + public static final String COMMAND = "ENCRYPTED"; private final Reader<T> dataReader; private CryptoBox container; private BitmessageAddress sender; private T data; public CryptoCustomMessage(T data) throws IOException { + super(COMMAND); this.data = data; this.dataReader = null; } private CryptoCustomMessage(CryptoBox container, Reader<T> dataReader) { + super(COMMAND); this.container = container; this.dataReader = dataReader; } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java index 4599b79..48b8df5 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java @@ -22,6 +22,7 @@ import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.ports.MessageRepository; +import ch.dissem.bitmessage.utils.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -108,6 +109,20 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito return 0; } + @Override + public Plaintext getMessage(byte[] initialHash) { + List<Plaintext> plaintexts = find("initial_hash=X'" + Strings.hex(initialHash) + "'"); + switch (plaintexts.size()) { + case 0: + return null; + case 1: + return plaintexts.get(0); + default: + throw new RuntimeException("This shouldn't happen, found " + plaintexts.size() + + " messages, one or none was expected"); + } + } + @Override public List<Plaintext> findMessages(Label label) { return find("id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ")"); @@ -141,8 +156,8 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito long id = rs.getLong("id"); builder.id(id); builder.IV(new InventoryVector(iv)); - builder.from(ctx.getAddressRepo().getAddress(rs.getString("sender"))); - builder.to(ctx.getAddressRepo().getAddress(rs.getString("recipient"))); + builder.from(ctx.getAddressRepository().getAddress(rs.getString("sender"))); + builder.to(ctx.getAddressRepository().getAddress(rs.getString("recipient"))); builder.sent(rs.getLong("sent")); builder.received(rs.getLong("received")); builder.status(Plaintext.Status.valueOf(rs.getString("status"))); @@ -173,12 +188,12 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito public void save(Plaintext message) { // save from address if necessary if (message.getId() == null) { - BitmessageAddress savedAddress = ctx.getAddressRepo().getAddress(message.getFrom().getAddress()); + BitmessageAddress savedAddress = ctx.getAddressRepository().getAddress(message.getFrom().getAddress()); if (savedAddress == null || savedAddress.getPrivateKey() == null) { if (savedAddress != null && savedAddress.getAlias() != null) { message.getFrom().setAlias(savedAddress.getAlias()); } - ctx.getAddressRepo().save(message.getFrom()); + ctx.getAddressRepository().save(message.getFrom()); } } @@ -219,7 +234,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito private void insert(Connection connection, Plaintext message) throws SQLException, IOException { PreparedStatement ps = connection.prepareStatement( - "INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + "INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status, initial_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); ps.setBytes(1, message.getInventoryVector() != null ? message.getInventoryVector().getHash() : null); ps.setString(2, message.getType().name()); @@ -229,6 +244,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito ps.setLong(6, message.getSent()); ps.setLong(7, message.getReceived()); ps.setString(8, message.getStatus() != null ? message.getStatus().name() : null); + ps.setBytes(9, message.getInitialHash()); ps.executeUpdate(); diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java new file mode 100644 index 0000000..aa8ca23 --- /dev/null +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java @@ -0,0 +1,69 @@ +package ch.dissem.bitmessage.repository; + +import ch.dissem.bitmessage.entity.ObjectMessage; +import ch.dissem.bitmessage.factory.Factory; +import ch.dissem.bitmessage.ports.ProofOfWorkRepository; +import ch.dissem.bitmessage.utils.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; + +import static ch.dissem.bitmessage.utils.Singleton.security; + +/** + * @author Christian Basler + */ +public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWorkRepository { + private static final Logger LOG = LoggerFactory.getLogger(JdbcProofOfWorkRepository.class); + + public JdbcProofOfWorkRepository(JdbcConfig config) { + super(config); + } + + @Override + public ObjectMessage getObject(byte[] initialHash) { + try (Connection connection = config.getConnection()) { + PreparedStatement ps = connection.prepareStatement("SELECT data, version FROM POW WHERE initial_hash=?"); + ps.setBytes(1, initialHash); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + Blob data = rs.getBlob("data"); + return Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length()); + } else { + throw new RuntimeException("Object requested that we don't have. Initial hash: " + Strings.hex(initialHash)); + } + } catch (Exception e) { + LOG.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } + + @Override + public void putObject(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) { + try (Connection connection = config.getConnection()) { + PreparedStatement ps = connection.prepareStatement("INSERT INTO POW (initial_hash, data, version) VALUES (?, ?, ?)"); + ps.setBytes(1, security().getInitialHash(object)); + writeBlob(ps, 2, object); + ps.setLong(3, object.getVersion()); + ps.executeUpdate(); + } catch (SQLException e) { + LOG.debug("Error storing object of type " + object.getPayload().getClass().getSimpleName(), e); + throw new RuntimeException(e); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } + + @Override + public void removeObject(ObjectMessage object) { + try (Connection connection = config.getConnection()) { + PreparedStatement ps = connection.prepareStatement("DELETE FROM POW WHERE initial_hash=?"); + ps.setBytes(1, security().getInitialHash(object)); + ps.executeUpdate(); + } catch (SQLException e) { + LOG.debug(e.getMessage(), e); + } + } +} diff --git a/repositories/src/main/resources/db/migration/V2.0__Update_table_message.sql b/repositories/src/main/resources/db/migration/V2.0__Update_table_message.sql new file mode 100644 index 0000000..0d81858 --- /dev/null +++ b/repositories/src/main/resources/db/migration/V2.0__Update_table_message.sql @@ -0,0 +1,2 @@ +ALTER TABLE Message ADD COLUMN initial_hash BINARY(64); +ALTER TABLE Message ADD CONSTRAINT initial_hash_unique UNIQUE(initial_hash); \ No newline at end of file diff --git a/repositories/src/main/resources/db/migration/V2.1__Create_table_POW.sql b/repositories/src/main/resources/db/migration/V2.1__Create_table_POW.sql new file mode 100644 index 0000000..4f54698 --- /dev/null +++ b/repositories/src/main/resources/db/migration/V2.1__Create_table_POW.sql @@ -0,0 +1,5 @@ +CREATE TABLE POW ( + initial_hash BINARY(64) PRIMARY KEY, + data BLOB NOT NULL, + version BIGINT NOT NULL +); diff --git a/security-bc/src/test/java/ch/dissem/bitmessage/security/SecurityTest.java b/security-bc/src/test/java/ch/dissem/bitmessage/security/SecurityTest.java index 46a8ae6..3aef7a8 100644 --- a/security-bc/src/test/java/ch/dissem/bitmessage/security/SecurityTest.java +++ b/security-bc/src/test/java/ch/dissem/bitmessage/security/SecurityTest.java @@ -91,7 +91,7 @@ public class SecurityTest { security.doProofOfWork(objectMessage, 1000, 1000, new ProofOfWorkEngine.Callback() { @Override - public void onNonceCalculated(byte[] nonce) { + public void onNonceCalculated(byte[] initialHash, byte[] nonce) { waiter.setValue(nonce); } }); From 51bf3b8bd2991b3455e36412995d3bdfc8e7904d Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sat, 12 Dec 2015 11:05:13 +0100 Subject: [PATCH 04/54] Fixed tests --- .../ch/dissem/bitmessage/networking/NetworkHandlerTest.java | 3 +++ .../test/java/ch/dissem/bitmessage/wif/WifExporterTest.java | 1 + .../test/java/ch/dissem/bitmessage/wif/WifImporterTest.java | 1 + 3 files changed, 5 insertions(+) diff --git a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java index 9fb2ea5..ccd2b67 100644 --- a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java +++ b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java @@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; import ch.dissem.bitmessage.ports.AddressRepository; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.NetworkHandler; +import ch.dissem.bitmessage.ports.ProofOfWorkRepository; import ch.dissem.bitmessage.security.bc.BouncySecurity; import ch.dissem.bitmessage.utils.Property; import org.junit.AfterClass; @@ -54,6 +55,7 @@ public class NetworkHandlerTest { .addressRepo(Mockito.mock(AddressRepository.class)) .inventory(peerInventory) .messageRepo(Mockito.mock(MessageRepository.class)) + .powRepo(Mockito.mock(ProofOfWorkRepository.class)) .port(6001) .nodeRegistry(new TestNodeRegistry()) .networkHandler(new DefaultNetworkHandler()) @@ -68,6 +70,7 @@ public class NetworkHandlerTest { .addressRepo(Mockito.mock(AddressRepository.class)) .inventory(nodeInventory) .messageRepo(Mockito.mock(MessageRepository.class)) + .powRepo(Mockito.mock(ProofOfWorkRepository.class)) .port(6002) .nodeRegistry(new TestNodeRegistry(localhost)) .networkHandler(networkHandler) diff --git a/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java b/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java index a2ee560..3e75a15 100644 --- a/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java +++ b/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java @@ -39,6 +39,7 @@ public class WifExporterTest { .networkHandler(mock(NetworkHandler.class)) .inventory(mock(Inventory.class)) .messageRepo(mock(MessageRepository.class)) + .powRepo(mock(ProofOfWorkRepository.class)) .nodeRegistry(mock(NodeRegistry.class)) .addressRepo(repo) .build(); diff --git a/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java b/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java index 862b3e3..d889523 100644 --- a/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java +++ b/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java @@ -42,6 +42,7 @@ public class WifImporterTest { .networkHandler(mock(NetworkHandler.class)) .inventory(mock(Inventory.class)) .messageRepo(mock(MessageRepository.class)) + .powRepo(mock(ProofOfWorkRepository.class)) .nodeRegistry(mock(NodeRegistry.class)) .addressRepo(repo) .build(); From 61788802c57a01d9d41932a5f5beb04e87f3b7c4 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Fri, 18 Dec 2015 16:42:17 +0100 Subject: [PATCH 05/54] Some POW improvements --- .../dissem/bitmessage/BitmessageContext.java | 30 ++++++++++++++++ .../ch/dissem/bitmessage/InternalContext.java | 4 +++ .../dissem/bitmessage/ProofOfWorkService.java | 12 +++++-- .../bitmessage/entity/CustomMessage.java | 16 ++++++--- .../ports/ProofOfWorkRepository.java | 20 +++++++++-- .../extensions/pow/ProofOfWorkRequest.java | 18 ++++++++-- .../repository/JdbcProofOfWorkRepository.java | 36 +++++++++++++++---- .../db/migration/V2.1__Create_table_POW.sql | 8 +++-- 8 files changed, 125 insertions(+), 19 deletions(-) diff --git a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index def0a4f..511aaea 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -31,6 +31,8 @@ import org.slf4j.LoggerFactory; import java.net.InetAddress; import java.util.Arrays; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.*; import static ch.dissem.bitmessage.entity.Plaintext.Status.*; @@ -72,6 +74,13 @@ public class BitmessageContext { // As this thread is used for parts that do POW, which itself uses parallel threads, only // one should be executed at any time. pool = Executors.newFixedThreadPool(1); + + new Timer().schedule(new TimerTask() { + @Override + public void run() { + ctx.getProofOfWorkService().doMissingProofOfWork(); + } + }, 30_000); // After 30 seconds } public AddressRepository addresses() { @@ -206,6 +215,19 @@ public class BitmessageContext { } } + /** + * Send a custom message to a specific node (that should implement handling for this message type) and returns + * the response, which in turn is expected to be a {@link CustomMessage}. + * + * @param server the node's address + * @param port the node's port + * @param request the request + * @return the response + */ + public CustomMessage send(InetAddress server, int port, CustomMessage request) { + return ctx.getNetworkHandler().send(server, port, request); + } + public void cleanup() { ctx.getInventory().cleanup(); } @@ -276,6 +298,14 @@ public class BitmessageContext { ); } + /** + * Returns the {@link InternalContext} - normally you wouldn't need it, + * unless you are doing something crazy with the protocol. + */ + public InternalContext internals() { + return ctx; + } + public interface Listener { void receive(Plaintext plaintext); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java index d139de5..89f3082 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -140,6 +140,10 @@ public class InternalContext { return proofOfWorkEngine; } + public ProofOfWorkService getProofOfWorkService() { + return proofOfWorkService; + } + public long[] getStreams() { long[] result = new long[streams.size()]; int i = 0; diff --git a/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java index 3cf46ef..da59105 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java @@ -20,6 +20,13 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC private ProofOfWorkRepository powRepo; private MessageRepository messageRepo; + public void doMissingProofOfWork() { + for (byte[] initialHash : powRepo.getItems()) { + ProofOfWorkRepository.Item item = powRepo.getItem(initialHash); + security.doProofOfWork(item.object, item.nonceTrialsPerByte, item.extraBytes, this); + } + } + public void doProofOfWork(ObjectMessage object) { doProofOfWork(null, object); } @@ -29,7 +36,7 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC long extraBytes = recipient == null ? 0 : recipient.getPubkey().getExtraBytes(); powRepo.putObject(object, nonceTrialsPerByte, extraBytes); - if (object.getPayload() instanceof PlaintextHolder){ + if (object.getPayload() instanceof PlaintextHolder) { Plaintext plaintext = ((PlaintextHolder) object.getPayload()).getPlaintext(); plaintext.setInitialHash(security.getInitialHash(object)); messageRepo.save(plaintext); @@ -39,7 +46,7 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC @Override public void onNonceCalculated(byte[] initialHash, byte[] nonce) { - ObjectMessage object = powRepo.getObject(initialHash); + ObjectMessage object = powRepo.getItem(initialHash).object; object.setNonce(nonce); // messageCallback.proofOfWorkCompleted(payload); Plaintext plaintext = messageRepo.getMessage(initialHash); @@ -48,6 +55,7 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC messageRepo.save(plaintext); } ctx.getInventory().storeObject(object); + ctx.getProofOfWorkRepository().removeObject(initialHash); ctx.getNetworkHandler().offer(object.getInventoryVector()); // messageCallback.messageOffered(payload, object.getInventoryVector()); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java index a5caf3a..126b808 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java @@ -53,13 +53,21 @@ public class CustomMessage implements MessagePayload { return Command.CUSTOM; } - public byte[] getData() throws IOException { + public String getCustomCommand() { + return command; + } + + public byte[] getData() { if (data != null) { return data; } else { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - write(out); - return out.toByteArray(); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + write(out); + return out.toByteArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java b/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java index 9971ad5..739c172 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java @@ -2,15 +2,31 @@ package ch.dissem.bitmessage.ports; import ch.dissem.bitmessage.entity.ObjectMessage; +import java.util.List; + /** * Objects that proof of work is currently being done for. * * @author Christian Basler */ public interface ProofOfWorkRepository { - ObjectMessage getObject(byte[] initialHash); + Item getItem(byte[] initialHash); + + List<byte[]> getItems(); void putObject(ObjectMessage object, long nonceTrialsPerByte, long extraBytes); - void removeObject(ObjectMessage object); + void removeObject(byte[] initialHash); + + class Item { + public final ObjectMessage object; + public final long nonceTrialsPerByte; + public final long extraBytes; + + public Item(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) { + this.object = object; + this.nonceTrialsPerByte = nonceTrialsPerByte; + this.extraBytes = extraBytes; + } + } } diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java index 2ef2f9e..196005d 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java @@ -18,13 +18,13 @@ package ch.dissem.bitmessage.extensions.pow; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Streamable; +import ch.dissem.bitmessage.extensions.CryptoCustomMessage; import ch.dissem.bitmessage.utils.Encode; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import static ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest.Request.CALCULATE; import static ch.dissem.bitmessage.utils.Decode.*; /** @@ -34,6 +34,7 @@ public class ProofOfWorkRequest implements Streamable { private final BitmessageAddress sender; private final byte[] initialHash; private final Request request; + private final byte[] data; public ProofOfWorkRequest(BitmessageAddress sender, byte[] initialHash, Request request) { @@ -79,10 +80,23 @@ public class ProofOfWorkRequest implements Streamable { Encode.varBytes(data, out); } + public static class Reader implements CryptoCustomMessage.Reader<ProofOfWorkRequest> { + private final BitmessageAddress identity; + + public Reader(BitmessageAddress identity) { + this.identity = identity; + } + + @Override + public ProofOfWorkRequest read(BitmessageAddress sender, InputStream in) throws IOException { + return ProofOfWorkRequest.read(identity, in); + } + } + + public enum Request { CALCULATE, CALCULATING, - QUERY, COMPLETE } } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java index aa8ca23..9268311 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java @@ -8,6 +8,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.*; +import java.util.LinkedList; +import java.util.List; import static ch.dissem.bitmessage.utils.Singleton.security; @@ -22,14 +24,18 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork } @Override - public ObjectMessage getObject(byte[] initialHash) { + public Item getItem(byte[] initialHash) { try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement("SELECT data, version FROM POW WHERE initial_hash=?"); + PreparedStatement ps = connection.prepareStatement("SELECT data, version, nonce_trials_per_byte, extra_bytes FROM POW WHERE initial_hash=?"); ps.setBytes(1, initialHash); ResultSet rs = ps.executeQuery(); if (rs.next()) { Blob data = rs.getBlob("data"); - return Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length()); + return new Item( + Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length()), + rs.getLong("nonce_trials_per_byte"), + rs.getLong("extra_bytes") + ); } else { throw new RuntimeException("Object requested that we don't have. Initial hash: " + Strings.hex(initialHash)); } @@ -39,13 +45,31 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork } } + @Override + public List<byte[]> getItems() { + try (Connection connection = config.getConnection()) { + List<byte[]> result = new LinkedList<>(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT initial_hash FROM POW"); + while (rs.next()) { + result.add(rs.getBytes("initial_hash")); + } + return result; + } catch (SQLException e) { + LOG.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } + @Override public void putObject(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) { try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement("INSERT INTO POW (initial_hash, data, version) VALUES (?, ?, ?)"); + PreparedStatement ps = connection.prepareStatement("INSERT INTO POW (initial_hash, data, version, nonce_trials_per_byte, extra_bytes) VALUES (?, ?, ?, ?, ?)"); ps.setBytes(1, security().getInitialHash(object)); writeBlob(ps, 2, object); ps.setLong(3, object.getVersion()); + ps.setLong(4, nonceTrialsPerByte); + ps.setLong(5, extraBytes); ps.executeUpdate(); } catch (SQLException e) { LOG.debug("Error storing object of type " + object.getPayload().getClass().getSimpleName(), e); @@ -57,10 +81,10 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork } @Override - public void removeObject(ObjectMessage object) { + public void removeObject(byte[] initialHash) { try (Connection connection = config.getConnection()) { PreparedStatement ps = connection.prepareStatement("DELETE FROM POW WHERE initial_hash=?"); - ps.setBytes(1, security().getInitialHash(object)); + ps.setBytes(1, initialHash); ps.executeUpdate(); } catch (SQLException e) { LOG.debug(e.getMessage(), e); diff --git a/repositories/src/main/resources/db/migration/V2.1__Create_table_POW.sql b/repositories/src/main/resources/db/migration/V2.1__Create_table_POW.sql index 4f54698..b39c6c5 100644 --- a/repositories/src/main/resources/db/migration/V2.1__Create_table_POW.sql +++ b/repositories/src/main/resources/db/migration/V2.1__Create_table_POW.sql @@ -1,5 +1,7 @@ CREATE TABLE POW ( - initial_hash BINARY(64) PRIMARY KEY, - data BLOB NOT NULL, - version BIGINT NOT NULL + initial_hash BINARY(64) PRIMARY KEY, + data BLOB NOT NULL, + version BIGINT NOT NULL, + nonce_trials_per_byte BIGINT NOT NULL, + extra_bytes BIGINT NOT NULL ); From fad3e07871e44cddad64ebe39ac85b34db37bfb5 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Mon, 21 Dec 2015 15:13:48 +0100 Subject: [PATCH 06/54] Some changes needed for POW server and some general improvements --- .../dissem/bitmessage/BitmessageContext.java | 44 ++++++++++++++++--- .../ch/dissem/bitmessage/InternalContext.java | 12 ++--- .../dissem/bitmessage/ProofOfWorkService.java | 18 ++++++-- .../bitmessage/entity/CustomMessage.java | 2 +- .../bitmessage/ports/AbstractSecurity.java | 31 ++++++++----- .../ch/dissem/bitmessage/ports/Security.java | 2 + .../extensions/CryptoCustomMessage.java | 5 ++- .../extensions/pow/ProofOfWorkRequest.java | 24 +++++++++- .../extensions/CryptoCustomMessageTest.java | 42 +++++++++++++++--- 9 files changed, 143 insertions(+), 37 deletions(-) diff --git a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 511aaea..1c4295e 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -66,6 +66,8 @@ public class BitmessageContext { private final Listener listener; private final NetworkHandler.MessageListener networkListener; + private final boolean sendPubkeyOnIdentityCreation; + private BitmessageContext(Builder builder) { ctx = new InternalContext(builder); listener = builder.listener; @@ -75,6 +77,8 @@ public class BitmessageContext { // one should be executed at any time. pool = Executors.newFixedThreadPool(1); + sendPubkeyOnIdentityCreation = builder.sendPubkeyOnIdentityCreation; + new Timer().schedule(new TimerTask() { @Override public void run() { @@ -100,12 +104,14 @@ public class BitmessageContext { features )); ctx.getAddressRepository().save(identity); - pool.submit(new Runnable() { - @Override - public void run() { - ctx.sendPubkey(identity, identity.getStream()); - } - }); + if (sendPubkeyOnIdentityCreation) { + pool.submit(new Runnable() { + @Override + public void run() { + ctx.sendPubkey(identity, identity.getStream()); + } + }); + } return identity; } @@ -325,6 +331,8 @@ public class BitmessageContext { Listener listener; int connectionLimit = 150; long connectionTTL = 12 * HOUR; + boolean sendPubkeyOnIdentityCreation = true; + long pubkeyTTL = 28; public Builder() { } @@ -399,6 +407,30 @@ public class BitmessageContext { return this; } + /** + * By default a client will send the public key when an identity is being created. On weaker devices + * this behaviour might not be desirable. + */ + public Builder doNotSendPubkeyOnIdentityCreation() { + this.sendPubkeyOnIdentityCreation = false; + return this; + } + + /** + * Time to live in seconds for public keys the client sends. Defaults to the maximum of 28 days, + * but on weak devices smaller values might be desirable. + * <p> + * Please be aware that this might cause some problems where you can't receive a message (the + * sender can't receive your public key) in some special situations. Also note that it's probably + * not a good idea to set it too low. + * </p> + */ + public Builder pubkeyTTL(long days) { + if (days < 0 || days > 28 * DAY) throw new IllegalArgumentException("TTL must be between 1 and 28 days"); + this.pubkeyTTL = days; + return this; + } + public BitmessageContext build() { nonNull("inventory", inventory); nonNull("nodeRegistry", nodeRegistry); diff --git a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java index 89f3082..1fe8007 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -16,7 +16,9 @@ package ch.dissem.bitmessage; -import ch.dissem.bitmessage.entity.*; +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.Encrypted; +import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.Broadcast; import ch.dissem.bitmessage.entity.payload.GetPubkey; import ch.dissem.bitmessage.entity.payload.ObjectPayload; @@ -29,8 +31,6 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.TreeSet; -import static ch.dissem.bitmessage.utils.UnixTime.DAY; - /** * The internal context should normally only be used for port implementations. If you need it in your client * implementation, you're either doing something wrong, something very weird, or the BitmessageContext should @@ -59,6 +59,7 @@ public class InternalContext { private final long clientNonce; private final long networkNonceTrialsPerByte = 1000; private final long networkExtraBytes = 1000; + private final long pubkeyTTL; private long connectionTTL; private int connectionLimit; @@ -78,6 +79,7 @@ public class InternalContext { this.port = builder.port; this.connectionLimit = builder.connectionLimit; this.connectionTTL = builder.connectionTTL; + this.pubkeyTTL = builder.pubkeyTTL; Singleton.initialize(security); @@ -193,7 +195,7 @@ public class InternalContext { public void sendPubkey(final BitmessageAddress identity, final long targetStream) { try { - long expires = UnixTime.now(+28 * DAY); + long expires = UnixTime.now(pubkeyTTL); LOG.info("Expires at " + expires); final ObjectMessage response = new ObjectMessage.Builder() .stream(targetStream) @@ -211,7 +213,7 @@ public class InternalContext { } public void requestPubkey(final BitmessageAddress contact) { - long expires = UnixTime.now(+2 * DAY); + long expires = UnixTime.now(+pubkeyTTL); LOG.info("Expires at " + expires); final ObjectMessage response = new ObjectMessage.Builder() .stream(contact.getStream()) diff --git a/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java index da59105..82c384c 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java @@ -8,6 +8,10 @@ import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; import ch.dissem.bitmessage.ports.Security; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; import static ch.dissem.bitmessage.utils.Singleton.security; @@ -15,13 +19,19 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * @author Christian Basler */ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalContext.ContextHolder { + private final static Logger LOG = LoggerFactory.getLogger(ProofOfWorkService.class); + private Security security; private InternalContext ctx; private ProofOfWorkRepository powRepo; private MessageRepository messageRepo; public void doMissingProofOfWork() { - for (byte[] initialHash : powRepo.getItems()) { + List<byte[]> items = powRepo.getItems(); + if (items.isEmpty()) return; + + LOG.info("Doing POW for " + items.size() + " tasks."); + for (byte[] initialHash : items) { ProofOfWorkRepository.Item item = powRepo.getItem(initialHash); security.doProofOfWork(item.object, item.nonceTrialsPerByte, item.extraBytes, this); } @@ -32,8 +42,10 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC } public void doProofOfWork(BitmessageAddress recipient, ObjectMessage object) { - long nonceTrialsPerByte = recipient == null ? 0 : recipient.getPubkey().getNonceTrialsPerByte(); - long extraBytes = recipient == null ? 0 : recipient.getPubkey().getExtraBytes(); + long nonceTrialsPerByte = recipient == null ? + ctx.getNetworkNonceTrialsPerByte() : recipient.getPubkey().getNonceTrialsPerByte(); + long extraBytes = recipient == null ? + ctx.getNetworkExtraBytes() : recipient.getPubkey().getExtraBytes(); powRepo.putObject(object, nonceTrialsPerByte, extraBytes); if (object.getPayload() instanceof PlaintextHolder) { diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java index 126b808..5702b6e 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java @@ -43,7 +43,7 @@ public class CustomMessage implements MessagePayload { this.data = data; } - public static MessagePayload read(InputStream in, int length) throws IOException { + public static CustomMessage read(InputStream in, int length) throws IOException { AccessCounter counter = new AccessCounter(); return new CustomMessage(varString(in, counter), bytes(in, length - counter.length())); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java b/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java index 0dea04c..053a776 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java @@ -43,6 +43,8 @@ public abstract class AbstractSecurity implements Security, InternalContext.Cont public static final Logger LOG = LoggerFactory.getLogger(Security.class); private static final SecureRandom RANDOM = new SecureRandom(); private static final BigInteger TWO = BigInteger.valueOf(2); + private static final BigInteger TWO_POW_64 = TWO.pow(64); + private static final BigInteger TWO_POW_16 = TWO.pow(16); private final String provider; private InternalContext context; @@ -96,18 +98,14 @@ public abstract class AbstractSecurity implements Security, InternalContext.Cont public void doProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes, ProofOfWorkEngine.Callback callback) { - try { - nonceTrialsPerByte = max(nonceTrialsPerByte, context.getNetworkNonceTrialsPerByte()); - extraBytes = max(extraBytes, context.getNetworkExtraBytes()); + nonceTrialsPerByte = max(nonceTrialsPerByte, context.getNetworkNonceTrialsPerByte()); + extraBytes = max(extraBytes, context.getNetworkExtraBytes()); - byte[] initialHash = getInitialHash(object); + byte[] initialHash = getInitialHash(object); - byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes); + byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes); - context.getProofOfWorkEngine().calculateNonce(initialHash, target, callback); - } catch (IOException e) { - throw new RuntimeException(e); - } + context.getProofOfWorkEngine().calculateNonce(initialHash, target, callback); } public void checkProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) @@ -124,11 +122,20 @@ public abstract class AbstractSecurity implements Security, InternalContext.Cont return sha512(object.getPayloadBytesWithoutNonce()); } - private byte[] getProofOfWorkTarget(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) throws IOException { + @Override + public byte[] getProofOfWorkTarget(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) { + if (nonceTrialsPerByte == 0) nonceTrialsPerByte = context.getNetworkNonceTrialsPerByte(); + if (extraBytes == 0) extraBytes = context.getNetworkExtraBytes(); + BigInteger TTL = BigInteger.valueOf(object.getExpiresTime() - UnixTime.now()); - BigInteger numerator = TWO.pow(64); + BigInteger numerator = TWO_POW_64; BigInteger powLength = BigInteger.valueOf(object.getPayloadBytesWithoutNonce().length + extraBytes); - BigInteger denominator = BigInteger.valueOf(nonceTrialsPerByte).multiply(powLength.add(powLength.multiply(TTL).divide(BigInteger.valueOf(2).pow(16)))); + BigInteger denominator = BigInteger.valueOf(nonceTrialsPerByte) + .multiply( + powLength.add( + powLength.multiply(TTL).divide(TWO_POW_16) + ) + ); return Bytes.expand(numerator.divide(denominator).toByteArray(), 8); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java b/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java index 8fc7e20..e76b21f 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java @@ -136,6 +136,8 @@ public interface Security { byte[] getInitialHash(ObjectMessage object); + byte[] getProofOfWorkTarget(ObjectMessage object, long nonceTrialsPerByte, long extraBytes); + /** * Calculates the MAC for a message (data) * diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java index 9a9e2dc..49c6f1b 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java @@ -54,8 +54,8 @@ public class CryptoCustomMessage<T extends Streamable> extends CustomMessage { this.dataReader = dataReader; } - public static <T extends Streamable> CryptoCustomMessage<T> read(byte[] data, Reader<T> dataReader) throws IOException { - CryptoBox cryptoBox = CryptoBox.read(new ByteArrayInputStream(data), data.length); + public static <T extends Streamable> CryptoCustomMessage<T> read(CustomMessage data, Reader<T> dataReader) throws IOException { + CryptoBox cryptoBox = CryptoBox.read(new ByteArrayInputStream(data.getData()), data.getData().length); return new CryptoCustomMessage<>(cryptoBox, dataReader); } @@ -111,6 +111,7 @@ public class CryptoCustomMessage<T extends Streamable> extends CustomMessage { @Override public void write(OutputStream out) throws IOException { + Encode.varString(COMMAND, out); container.write(out); } diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java index 196005d..0024aaa 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java @@ -24,6 +24,7 @@ import ch.dissem.bitmessage.utils.Encode; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Arrays; import static ch.dissem.bitmessage.utils.Decode.*; @@ -80,6 +81,28 @@ public class ProofOfWorkRequest implements Streamable { Encode.varBytes(data, out); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ProofOfWorkRequest other = (ProofOfWorkRequest) o; + + if (!sender.equals(other.sender)) return false; + if (!Arrays.equals(initialHash, other.initialHash)) return false; + if (request != other.request) return false; + return Arrays.equals(data, other.data); + } + + @Override + public int hashCode() { + int result = sender.hashCode(); + result = 31 * result + Arrays.hashCode(initialHash); + result = 31 * result + request.hashCode(); + result = 31 * result + Arrays.hashCode(data); + return result; + } + public static class Reader implements CryptoCustomMessage.Reader<ProofOfWorkRequest> { private final BitmessageAddress identity; @@ -93,7 +116,6 @@ public class ProofOfWorkRequest implements Streamable { } } - public enum Request { CALCULATE, CALCULATING, diff --git a/extensions/src/test/java/ch/dissem/bitmessage/extensions/CryptoCustomMessageTest.java b/extensions/src/test/java/ch/dissem/bitmessage/extensions/CryptoCustomMessageTest.java index 98e97a1..c1303e3 100644 --- a/extensions/src/test/java/ch/dissem/bitmessage/extensions/CryptoCustomMessageTest.java +++ b/extensions/src/test/java/ch/dissem/bitmessage/extensions/CryptoCustomMessageTest.java @@ -17,8 +17,10 @@ package ch.dissem.bitmessage.extensions; import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.CustomMessage; import ch.dissem.bitmessage.entity.payload.GenericPayload; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest; import ch.dissem.bitmessage.utils.TestBase; import ch.dissem.bitmessage.utils.TestUtils; import org.junit.Test; @@ -33,7 +35,7 @@ import static org.junit.Assert.assertEquals; public class CryptoCustomMessageTest extends TestBase { @Test - public void testEncryptThenDecrypt() throws Exception { + public void ensureEncryptThenDecryptYieldsSameObject() throws Exception { PrivateKey privateKey = PrivateKey.read(TestUtils.getResource("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey")); BitmessageAddress sendingIdentity = new BitmessageAddress(privateKey); @@ -45,14 +47,40 @@ public class CryptoCustomMessageTest extends TestBase { messageBefore.write(out); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - CryptoCustomMessage<GenericPayload> messageAfter = CryptoCustomMessage.read(out.toByteArray(), new CryptoCustomMessage.Reader<GenericPayload>() { - @Override - public GenericPayload read(BitmessageAddress ignore, InputStream in) throws IOException { - return GenericPayload.read(0, in, 1, 100); - } - }); + CustomMessage customMessage = CustomMessage.read(in, out.size()); + CryptoCustomMessage<GenericPayload> messageAfter = CryptoCustomMessage.read(customMessage, + new CryptoCustomMessage.Reader<GenericPayload>() { + @Override + public GenericPayload read(BitmessageAddress ignore, InputStream in) throws IOException { + return GenericPayload.read(0, in, 1, 100); + } + }); GenericPayload payloadAfter = messageAfter.decrypt(sendingIdentity.getPublicDecryptionKey()); assertEquals(payloadBefore, payloadAfter); } + + @Test + public void testWithActualRequest() throws Exception { + PrivateKey privateKey = PrivateKey.read(TestUtils.getResource("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey")); + final BitmessageAddress sendingIdentity = new BitmessageAddress(privateKey); + + ProofOfWorkRequest requestBefore = new ProofOfWorkRequest(sendingIdentity, security().randomBytes(64), + ProofOfWorkRequest.Request.CALCULATE); + + CryptoCustomMessage<ProofOfWorkRequest> messageBefore = new CryptoCustomMessage<>(requestBefore); + messageBefore.signAndEncrypt(sendingIdentity, security().createPublicKey(sendingIdentity.getPublicDecryptionKey())); + + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + messageBefore.write(out); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + + CustomMessage customMessage = CustomMessage.read(in, out.size()); + CryptoCustomMessage<ProofOfWorkRequest> messageAfter = CryptoCustomMessage.read(customMessage, + new ProofOfWorkRequest.Reader(sendingIdentity)); + ProofOfWorkRequest requestAfter = messageAfter.decrypt(sendingIdentity.getPublicDecryptionKey()); + + assertEquals(requestBefore, requestAfter); + } } From 549c8854ed7c8b5ec8319e8d174470483cf78327 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sun, 10 Jan 2016 13:38:32 +0100 Subject: [PATCH 07/54] Refactoring: renamed 'security' to 'cryptography' --- README.md | 1 + {security-bc => cryptography-bc}/build.gradle | 6 +++--- .../cryptography/bc/BouncyCryptography.java | 8 ++++---- .../bitmessage/security/CryptographyTest.java | 10 +++++----- {security-sc => cryptography-sc}/build.gradle | 6 +++--- .../cryptography/sc/SpongyCryptography.java | 8 ++++---- demo/build.gradle | 2 +- .../ch/dissem/bitmessage/demo/Application.java | 4 ++-- .../java/ch/dissem/bitmessage/demo/Main.java | 4 ++-- domain/build.gradle | 2 +- .../ch/dissem/bitmessage/BitmessageContext.java | 6 +++--- .../ch/dissem/bitmessage/InternalContext.java | 16 ++++++++-------- .../ch/dissem/bitmessage/ProofOfWorkService.java | 12 ++++++------ .../ch/dissem/bitmessage/entity/Encrypted.java | 1 - .../dissem/bitmessage/entity/ObjectMessage.java | 1 - .../bitmessage/entity/payload/V4Broadcast.java | 1 - ...ctSecurity.java => AbstractCryptography.java} | 6 +++--- .../ports/{Security.java => Cryptography.java} | 2 +- .../ch/dissem/bitmessage/utils/Singleton.java | 14 +++++++------- .../ch/dissem/bitmessage/utils/TestBase.java | 4 ++-- extensions/build.gradle | 2 +- networking/build.gradle | 2 +- .../networking/NetworkHandlerTest.java | 6 +++--- repositories/build.gradle | 2 +- .../repository/JdbcMessageRepositoryTest.java | 2 +- .../dissem/bitmessage/repository/TestBase.java | 4 ++-- settings.gradle | 4 ++-- wif/build.gradle | 2 +- .../dissem/bitmessage/wif/WifExporterTest.java | 4 ++-- .../dissem/bitmessage/wif/WifImporterTest.java | 4 ++-- 30 files changed, 72 insertions(+), 74 deletions(-) rename {security-bc => cryptography-bc}/build.gradle (61%) rename security-bc/src/main/java/ch/dissem/bitmessage/security/bc/BouncySecurity.java => cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java (96%) rename security-bc/src/test/java/ch/dissem/bitmessage/security/SecurityTest.java => cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java (94%) rename {security-sc => cryptography-sc}/build.gradle (54%) rename security-sc/src/main/java/ch/dissem/bitmessage/security/sc/SpongySecurity.java => cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java (96%) rename domain/src/main/java/ch/dissem/bitmessage/ports/{AbstractSecurity.java => AbstractCryptography.java} (96%) rename domain/src/main/java/ch/dissem/bitmessage/ports/{Security.java => Cryptography.java} (99%) diff --git a/README.md b/README.md index eb5cdfc..19ce171 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ BitmessageContext ctx = new BitmessageContext.Builder() .messageRepo(new JdbcMessageRepository(jdbcConfig)) .nodeRegistry(new MemoryNodeRegistry()) .networkHandler(new NetworkNode()) + .cryptography(new BouncyCryptography()) .build(); ``` This creates a simple context using a H2 database that will be created in the user's home directory. Next you'll need to diff --git a/security-bc/build.gradle b/cryptography-bc/build.gradle similarity index 61% rename from security-bc/build.gradle rename to cryptography-bc/build.gradle index ff37994..0634154 100644 --- a/security-bc/build.gradle +++ b/cryptography-bc/build.gradle @@ -2,9 +2,9 @@ uploadArchives { repositories { mavenDeployer { pom.project { - name 'Jabit Bouncy Security' - artifactId = 'jabit-security-bouncy' - description 'The Security implementation using bouncy castle' + name 'Jabit Bouncy Cryptography' + artifactId = 'jabit-cryptography-bouncy' + description 'The Cryptography implementation using bouncy castle' } } } diff --git a/security-bc/src/main/java/ch/dissem/bitmessage/security/bc/BouncySecurity.java b/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java similarity index 96% rename from security-bc/src/main/java/ch/dissem/bitmessage/security/bc/BouncySecurity.java rename to cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java index a125049..28be67a 100644 --- a/security-bc/src/main/java/ch/dissem/bitmessage/security/bc/BouncySecurity.java +++ b/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package ch.dissem.bitmessage.security.bc; +package ch.dissem.bitmessage.cryptography.bc; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; -import ch.dissem.bitmessage.ports.AbstractSecurity; +import ch.dissem.bitmessage.ports.AbstractCryptography; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; @@ -47,14 +47,14 @@ import java.util.Arrays; * As Spongycastle can't be used on the Oracle JVM, and Bouncycastle doesn't work properly on Android (thanks, Google), * this is the Bouncycastle implementation. */ -public class BouncySecurity extends AbstractSecurity { +public class BouncyCryptography extends AbstractCryptography { private static final X9ECParameters EC_CURVE_PARAMETERS = CustomNamedCurves.getByName("secp256k1"); static { java.security.Security.addProvider(new BouncyCastleProvider()); } - public BouncySecurity() { + public BouncyCryptography() { super("BC"); } diff --git a/security-bc/src/test/java/ch/dissem/bitmessage/security/SecurityTest.java b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java similarity index 94% rename from security-bc/src/test/java/ch/dissem/bitmessage/security/SecurityTest.java rename to cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java index 3aef7a8..3a68968 100644 --- a/security-bc/src/test/java/ch/dissem/bitmessage/security/SecurityTest.java +++ b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java @@ -5,7 +5,7 @@ import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.GenericPayload; import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; -import ch.dissem.bitmessage.security.bc.BouncySecurity; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.utils.CallbackWaiter; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.UnixTime; @@ -23,7 +23,7 @@ import static org.mockito.Mockito.when; /** * Created by chris on 19.07.15. */ -public class SecurityTest { +public class CryptographyTest { public static final byte[] TEST_VALUE = "teststring".getBytes(); public static final byte[] TEST_SHA1 = DatatypeConverter.parseHexBinary("" + "b8473b86d4c2072ca9b08bd28e373e8253e865c4"); @@ -33,10 +33,10 @@ public class SecurityTest { public static final byte[] TEST_RIPEMD160 = DatatypeConverter.parseHexBinary("" + "cd566972b5e50104011a92b59fa8e0b1234851ae"); - private static BouncySecurity security; + private static BouncyCryptography security; - public SecurityTest() { - security = new BouncySecurity(); + public CryptographyTest() { + security = new BouncyCryptography(); Singleton.initialize(security); InternalContext ctx = mock(InternalContext.class); when(ctx.getProofOfWorkEngine()).thenReturn(new MultiThreadedPOWEngine()); diff --git a/security-sc/build.gradle b/cryptography-sc/build.gradle similarity index 54% rename from security-sc/build.gradle rename to cryptography-sc/build.gradle index bfbdcab..2d4f82f 100644 --- a/security-sc/build.gradle +++ b/cryptography-sc/build.gradle @@ -2,9 +2,9 @@ uploadArchives { repositories { mavenDeployer { pom.project { - name 'Jabit Spongy Security' - artifactId = 'jabit-security-spongy' - description 'The Security implementation using spongy castle (needed for Android)' + name 'Jabit Spongy Cryptography' + artifactId = 'jabit-cryptography-spongy' + description 'The Cryptography implementation using spongy castle (needed for Android)' } } } diff --git a/security-sc/src/main/java/ch/dissem/bitmessage/security/sc/SpongySecurity.java b/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java similarity index 96% rename from security-sc/src/main/java/ch/dissem/bitmessage/security/sc/SpongySecurity.java rename to cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java index 70a0743..c9506fb 100644 --- a/security-sc/src/main/java/ch/dissem/bitmessage/security/sc/SpongySecurity.java +++ b/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package ch.dissem.bitmessage.security.sc; +package ch.dissem.bitmessage.cryptography.sc; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; -import ch.dissem.bitmessage.ports.AbstractSecurity; +import ch.dissem.bitmessage.ports.AbstractCryptography; import org.spongycastle.asn1.x9.X9ECParameters; import org.spongycastle.crypto.BufferedBlockCipher; import org.spongycastle.crypto.CipherParameters; @@ -47,14 +47,14 @@ import java.util.Arrays; * As Spongycastle can't be used on the Oracle JVM, and Bouncycastle doesn't work properly on Android (thanks, Google), * this is the Spongycastle implementation. */ -public class SpongySecurity extends AbstractSecurity { +public class SpongyCryptography extends AbstractCryptography { private static final X9ECParameters EC_CURVE_PARAMETERS = CustomNamedCurves.getByName("secp256k1"); static { java.security.Security.addProvider(new BouncyCastleProvider()); } - public SpongySecurity() { + public SpongyCryptography() { super("SC"); } diff --git a/demo/build.gradle b/demo/build.gradle index e4c51a7..e520157 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -24,7 +24,7 @@ dependencies { compile project(':domain') compile project(':networking') compile project(':repositories') - compile project(':security-bc') + compile project(':cryptography-bc') compile project(':wif') compile 'org.slf4j:slf4j-simple:1.7.12' compile 'args4j:args4j:2.32' diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java index 72da50d..f35bcc5 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java @@ -23,7 +23,7 @@ import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.ports.MemoryNodeRegistry; import ch.dissem.bitmessage.repository.*; -import ch.dissem.bitmessage.security.bc.BouncySecurity; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +49,7 @@ public class Application { .messageRepo(new JdbcMessageRepository(jdbcConfig)) .powRepo(new JdbcProofOfWorkRepository(jdbcConfig)) .networkHandler(new DefaultNetworkHandler()) - .security(new BouncySecurity()) + .cryptography(new BouncyCryptography()) .port(48444) .listener(new BitmessageContext.Listener() { @Override diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java index 6dbfc14..a7b63d1 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java @@ -20,7 +20,7 @@ import ch.dissem.bitmessage.BitmessageContext; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.ports.MemoryNodeRegistry; import ch.dissem.bitmessage.repository.*; -import ch.dissem.bitmessage.security.bc.BouncySecurity; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.wif.WifExporter; import ch.dissem.bitmessage.wif.WifImporter; import org.kohsuke.args4j.CmdLineException; @@ -53,7 +53,7 @@ public class Main { .messageRepo(new JdbcMessageRepository(jdbcConfig)) .powRepo(new JdbcProofOfWorkRepository(jdbcConfig)) .networkHandler(new DefaultNetworkHandler()) - .security(new BouncySecurity()) + .cryptography(new BouncyCryptography()) .port(48444) .build(); diff --git a/domain/build.gradle b/domain/build.gradle index 1880c6b..484abfd 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -27,5 +27,5 @@ dependencies { compile 'org.slf4j:slf4j-api:1.7.12' testCompile 'junit:junit:4.11' testCompile 'org.mockito:mockito-core:1.10.19' - testCompile project(':security-bc') + testCompile project(':cryptography-bc') } diff --git a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 1c4295e..1f34c9d 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -325,7 +325,7 @@ public class BitmessageContext { MessageRepository messageRepo; ProofOfWorkRepository proofOfWorkRepository; ProofOfWorkEngine proofOfWorkEngine; - Security security; + Cryptography cryptography; MessageCallback messageCallback; CustomCommandHandler customCommandHandler; Listener listener; @@ -372,8 +372,8 @@ public class BitmessageContext { return this; } - public Builder security(Security security) { - this.security = security; + public Builder cryptography(Cryptography cryptography) { + this.cryptography = cryptography; return this; } diff --git a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java index 1fe8007..9971b9b 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -42,7 +42,7 @@ import java.util.TreeSet; public class InternalContext { private final static Logger LOG = LoggerFactory.getLogger(InternalContext.class); - private final Security security; + private final Cryptography cryptography; private final Inventory inventory; private final NodeRegistry nodeRegistry; private final NetworkHandler networkHandler; @@ -64,7 +64,7 @@ public class InternalContext { private int connectionLimit; public InternalContext(BitmessageContext.Builder builder) { - this.security = builder.security; + this.cryptography = builder.cryptography; this.inventory = builder.inventory; this.nodeRegistry = builder.nodeRegistry; this.networkHandler = builder.networkHandler; @@ -73,7 +73,7 @@ public class InternalContext { this.proofOfWorkRepository = builder.proofOfWorkRepository; this.proofOfWorkService = new ProofOfWorkService(); this.proofOfWorkEngine = builder.proofOfWorkEngine; - this.clientNonce = security.randomNonce(); + this.clientNonce = cryptography.randomNonce(); this.messageCallback = builder.messageCallback; this.customCommandHandler = builder.customCommandHandler; this.port = builder.port; @@ -81,7 +81,7 @@ public class InternalContext { this.connectionTTL = builder.connectionTTL; this.pubkeyTTL = builder.pubkeyTTL; - Singleton.initialize(security); + Singleton.initialize(cryptography); // TODO: streams of new identities and subscriptions should also be added. This works only after a restart. for (BitmessageAddress address : addressRepository.getIdentities()) { @@ -94,7 +94,7 @@ public class InternalContext { streams.add(1L); } - init(security, inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, + init(cryptography, inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkRepository, proofOfWorkService, proofOfWorkEngine, messageCallback, customCommandHandler); for (BitmessageAddress identity : addressRepository.getIdentities()) { @@ -110,8 +110,8 @@ public class InternalContext { } } - public Security getSecurity() { - return security; + public Cryptography getCryptography() { + return cryptography; } public Inventory getInventory() { @@ -203,7 +203,7 @@ public class InternalContext { .payload(identity.getPubkey()) .build(); response.sign(identity.getPrivateKey()); - response.encrypt(security.createPublicKey(identity.getPublicDecryptionKey())); + response.encrypt(cryptography.createPublicKey(identity.getPublicDecryptionKey())); messageCallback.proofOfWorkStarted(identity.getPubkey()); // TODO: remember that the pubkey is just about to be sent, and on which stream! proofOfWorkService.doProofOfWork(response); diff --git a/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java index 82c384c..19e231f 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java @@ -7,7 +7,7 @@ import ch.dissem.bitmessage.entity.PlaintextHolder; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; -import ch.dissem.bitmessage.ports.Security; +import ch.dissem.bitmessage.ports.Cryptography; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +21,7 @@ import static ch.dissem.bitmessage.utils.Singleton.security; public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalContext.ContextHolder { private final static Logger LOG = LoggerFactory.getLogger(ProofOfWorkService.class); - private Security security; + private Cryptography cryptography; private InternalContext ctx; private ProofOfWorkRepository powRepo; private MessageRepository messageRepo; @@ -33,7 +33,7 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC LOG.info("Doing POW for " + items.size() + " tasks."); for (byte[] initialHash : items) { ProofOfWorkRepository.Item item = powRepo.getItem(initialHash); - security.doProofOfWork(item.object, item.nonceTrialsPerByte, item.extraBytes, this); + cryptography.doProofOfWork(item.object, item.nonceTrialsPerByte, item.extraBytes, this); } } @@ -50,10 +50,10 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC powRepo.putObject(object, nonceTrialsPerByte, extraBytes); if (object.getPayload() instanceof PlaintextHolder) { Plaintext plaintext = ((PlaintextHolder) object.getPayload()).getPlaintext(); - plaintext.setInitialHash(security.getInitialHash(object)); + plaintext.setInitialHash(cryptography.getInitialHash(object)); messageRepo.save(plaintext); } - security.doProofOfWork(object, nonceTrialsPerByte, extraBytes, this); + cryptography.doProofOfWork(object, nonceTrialsPerByte, extraBytes, this); } @Override @@ -75,7 +75,7 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC @Override public void setContext(InternalContext ctx) { this.ctx = ctx; - this.security = security(); + this.cryptography = security(); this.powRepo = ctx.getProofOfWorkRepository(); this.messageRepo = ctx.getMessageRepository(); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java b/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java index 9eaa2ab..8b15371 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java @@ -17,7 +17,6 @@ package ch.dissem.bitmessage.entity; import ch.dissem.bitmessage.exception.DecryptionFailedException; -import ch.dissem.bitmessage.ports.Security; import java.io.IOException; diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java index 9e89c42..99b3aec 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java @@ -22,7 +22,6 @@ import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.DecryptionFailedException; -import ch.dissem.bitmessage.ports.Security; import ch.dissem.bitmessage.utils.Bytes; import ch.dissem.bitmessage.utils.Encode; diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java index 03364d2..39127a8 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java @@ -18,7 +18,6 @@ package ch.dissem.bitmessage.entity.payload; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Plaintext; -import ch.dissem.bitmessage.ports.Security; import java.io.IOException; import java.io.InputStream; diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java b/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java similarity index 96% rename from domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java rename to domain/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java index 053a776..3cf3f0d 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractSecurity.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java @@ -39,8 +39,8 @@ import static ch.dissem.bitmessage.utils.Numbers.max; /** * Implements everything that isn't directly dependent on either Spongy- or Bouncycastle. */ -public abstract class AbstractSecurity implements Security, InternalContext.ContextHolder { - public static final Logger LOG = LoggerFactory.getLogger(Security.class); +public abstract class AbstractCryptography implements Cryptography, InternalContext.ContextHolder { + public static final Logger LOG = LoggerFactory.getLogger(Cryptography.class); private static final SecureRandom RANDOM = new SecureRandom(); private static final BigInteger TWO = BigInteger.valueOf(2); private static final BigInteger TWO_POW_64 = TWO.pow(64); @@ -49,7 +49,7 @@ public abstract class AbstractSecurity implements Security, InternalContext.Cont private final String provider; private InternalContext context; - protected AbstractSecurity(String provider) { + protected AbstractCryptography(String provider) { this.provider = provider; } diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java b/domain/src/main/java/ch/dissem/bitmessage/ports/Cryptography.java similarity index 99% rename from domain/src/main/java/ch/dissem/bitmessage/ports/Security.java rename to domain/src/main/java/ch/dissem/bitmessage/ports/Cryptography.java index e76b21f..48739ea 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/Security.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/Cryptography.java @@ -29,7 +29,7 @@ import java.security.SecureRandom; * Provides some methods to help with hashing and encryption. All randoms are created using {@link SecureRandom}, * which should be secure enough. */ -public interface Security { +public interface Cryptography { /** * A helper method to calculate SHA-512 hashes. Please note that a new {@link MessageDigest} object is created at * each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Singleton.java b/domain/src/main/java/ch/dissem/bitmessage/utils/Singleton.java index d272beb..0c7134b 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/utils/Singleton.java +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/Singleton.java @@ -16,23 +16,23 @@ package ch.dissem.bitmessage.utils; -import ch.dissem.bitmessage.ports.Security; +import ch.dissem.bitmessage.ports.Cryptography; /** * Created by chris on 20.07.15. */ public class Singleton { - private static Security security; + private static Cryptography cryptography; - public static void initialize(Security security) { + public static void initialize(Cryptography cryptography) { synchronized (Singleton.class) { - if (Singleton.security == null) { - Singleton.security = security; + if (Singleton.cryptography == null) { + Singleton.cryptography = cryptography; } } } - public static Security security() { - return security; + public static Cryptography security() { + return cryptography; } } diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/TestBase.java b/domain/src/test/java/ch/dissem/bitmessage/utils/TestBase.java index 1dd1335..e757d91 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/utils/TestBase.java +++ b/domain/src/test/java/ch/dissem/bitmessage/utils/TestBase.java @@ -16,13 +16,13 @@ package ch.dissem.bitmessage.utils; -import ch.dissem.bitmessage.security.bc.BouncySecurity; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; /** * Created by chris on 20.07.15. */ public class TestBase { static { - Singleton.initialize(new BouncySecurity()); + Singleton.initialize(new BouncyCryptography()); } } diff --git a/extensions/build.gradle b/extensions/build.gradle index 0ae9fd4..c92eb96 100644 --- a/extensions/build.gradle +++ b/extensions/build.gradle @@ -32,5 +32,5 @@ dependencies { testCompile 'org.slf4j:slf4j-simple:1.7.12' testCompile 'org.mockito:mockito-core:1.10.19' testCompile project(path: ':domain', configuration: 'testArtifacts') - testCompile project(':security-bc') + testCompile project(':cryptography-bc') } diff --git a/networking/build.gradle b/networking/build.gradle index 06bd5d0..788bc4d 100644 --- a/networking/build.gradle +++ b/networking/build.gradle @@ -16,5 +16,5 @@ dependencies { testCompile 'org.slf4j:slf4j-simple:1.7.12' testCompile 'org.mockito:mockito-core:1.10.19' testCompile project(path: ':domain', configuration: 'testArtifacts') - testCompile project(':security-bc') + testCompile project(':cryptography-bc') } \ No newline at end of file diff --git a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java index ccd2b67..499e377 100644 --- a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java +++ b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java @@ -22,7 +22,7 @@ import ch.dissem.bitmessage.ports.AddressRepository; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.NetworkHandler; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; -import ch.dissem.bitmessage.security.bc.BouncySecurity; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.utils.Property; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -59,7 +59,7 @@ public class NetworkHandlerTest { .port(6001) .nodeRegistry(new TestNodeRegistry()) .networkHandler(new DefaultNetworkHandler()) - .security(new BouncySecurity()) + .cryptography(new BouncyCryptography()) .listener(Mockito.mock(BitmessageContext.Listener.class)) .build(); peer.startup(); @@ -74,7 +74,7 @@ public class NetworkHandlerTest { .port(6002) .nodeRegistry(new TestNodeRegistry(localhost)) .networkHandler(networkHandler) - .security(new BouncySecurity()) + .cryptography(new BouncyCryptography()) .listener(Mockito.mock(BitmessageContext.Listener.class)) .build(); } diff --git a/repositories/build.gradle b/repositories/build.gradle index fecebce..cfbc9ea 100644 --- a/repositories/build.gradle +++ b/repositories/build.gradle @@ -18,5 +18,5 @@ dependencies { testCompile 'junit:junit:4.12' testCompile 'com.h2database:h2:1.4.190' testCompile 'org.mockito:mockito-core:1.10.19' - testCompile project(':security-bc') + testCompile project(':cryptography-bc') } \ No newline at end of file diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java index 3dceb24..c7c3614 100644 --- a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java @@ -55,7 +55,7 @@ public class JdbcMessageRepositoryTest extends TestBase { addressRepo = new JdbcAddressRepository(config); repo = new JdbcMessageRepository(config); new InternalContext(new BitmessageContext.Builder() - .security(security()) + .cryptography(security()) .addressRepo(addressRepo) .messageRepo(repo) ); diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/TestBase.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/TestBase.java index c6baaa2..be386cd 100644 --- a/repositories/src/test/java/ch/dissem/bitmessage/repository/TestBase.java +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/TestBase.java @@ -18,7 +18,7 @@ package ch.dissem.bitmessage.repository; import ch.dissem.bitmessage.InternalContext; import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; -import ch.dissem.bitmessage.security.bc.BouncySecurity; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.utils.Singleton; import static org.mockito.Mockito.mock; @@ -29,7 +29,7 @@ import static org.mockito.Mockito.when; */ public class TestBase { static { - BouncySecurity security = new BouncySecurity(); + BouncyCryptography security = new BouncyCryptography(); Singleton.initialize(security); InternalContext ctx = mock(InternalContext.class); when(ctx.getProofOfWorkEngine()).thenReturn(new MultiThreadedPOWEngine()); diff --git a/settings.gradle b/settings.gradle index adecd45..634c473 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,8 +10,8 @@ include 'demo' include 'wif' -include 'security-sc' +include 'cryptography-sc' -include 'security-bc' +include 'cryptography-bc' include 'extensions' \ No newline at end of file diff --git a/wif/build.gradle b/wif/build.gradle index 5b32a21..ef16682 100644 --- a/wif/build.gradle +++ b/wif/build.gradle @@ -15,5 +15,5 @@ dependencies { compile 'org.ini4j:ini4j:0.5.4' testCompile 'junit:junit:4.11' testCompile 'org.mockito:mockito-core:1.10.19' - testCompile project(':security-bc') + testCompile project(':cryptography-bc') } diff --git a/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java b/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java index 3e75a15..b930c0a 100644 --- a/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java +++ b/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java @@ -18,7 +18,7 @@ package ch.dissem.bitmessage.wif; import ch.dissem.bitmessage.BitmessageContext; import ch.dissem.bitmessage.ports.*; -import ch.dissem.bitmessage.security.bc.BouncySecurity; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import org.junit.Before; import org.junit.Test; @@ -35,7 +35,7 @@ public class WifExporterTest { @Before public void setUp() throws Exception { ctx = new BitmessageContext.Builder() - .security(new BouncySecurity()) + .cryptography(new BouncyCryptography()) .networkHandler(mock(NetworkHandler.class)) .inventory(mock(Inventory.class)) .messageRepo(mock(MessageRepository.class)) diff --git a/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java b/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java index d889523..fe8e15c 100644 --- a/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java +++ b/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java @@ -19,7 +19,7 @@ package ch.dissem.bitmessage.wif; import ch.dissem.bitmessage.BitmessageContext; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.ports.*; -import ch.dissem.bitmessage.security.bc.BouncySecurity; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import org.junit.Before; import org.junit.Test; @@ -38,7 +38,7 @@ public class WifImporterTest { @Before public void setUp() throws Exception { ctx = new BitmessageContext.Builder() - .security(new BouncySecurity()) + .cryptography(new BouncyCryptography()) .networkHandler(mock(NetworkHandler.class)) .inventory(mock(Inventory.class)) .messageRepo(mock(MessageRepository.class)) From 87646428780fdc34ed28dc2ffa8eb3d183027a46 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sat, 16 Jan 2016 08:47:50 +0100 Subject: [PATCH 08/54] Major fixes and improvements to the network module, fixing problems where objects where requested multiple times or not at all in some situations. --- .../dissem/bitmessage/BitmessageContext.java | 43 ++++++- .../ch/dissem/bitmessage/entity/GetData.java | 6 +- .../ch/dissem/bitmessage/utils/Property.java | 20 ++- .../bitmessage/networking/Connection.java | 117 ++++++++++-------- .../networking/DefaultNetworkHandler.java | 92 ++++++++++++-- .../networking/NetworkHandlerTest.java | 4 +- 6 files changed, 202 insertions(+), 80 deletions(-) diff --git a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 1f34c9d..46d76d7 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -40,6 +40,7 @@ import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; import static ch.dissem.bitmessage.utils.UnixTime.DAY; import static ch.dissem.bitmessage.utils.UnixTime.HOUR; +import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; /** * <p>Use this class if you want to create a Bitmessage client.</p> @@ -183,6 +184,40 @@ public class BitmessageContext { }); } + public void send(final Plaintext msg) { + if (msg.getFrom() == null || msg.getFrom().getPrivateKey() == null) { + throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key."); + } + pool.submit(new Runnable() { + @Override + public void run() { + BitmessageAddress to = msg.getTo(); + if (to.getPubkey() == null) { + tryToFindMatchingPubkey(to); + } + if (to.getPubkey() == null) { + LOG.info("Public key is missing from recipient. Requesting."); + requestPubkey(msg.getFrom(), to); + msg.setStatus(PUBKEY_REQUESTED); + ctx.getMessageRepository().save(msg); + } else { + LOG.info("Sending message."); + msg.setStatus(DOING_PROOF_OF_WORK); + ctx.getMessageRepository().save(msg); + ctx.send( + msg.getFrom(), + to, + new Msg(msg), + +2 * DAY + ); + msg.setStatus(SENT); + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.SENT)); + ctx.getMessageRepository().save(msg); + } + } + }); + } + private void requestPubkey(BitmessageAddress requestingIdentity, BitmessageAddress address) { ctx.send( requestingIdentity, @@ -330,7 +365,7 @@ public class BitmessageContext { CustomCommandHandler customCommandHandler; Listener listener; int connectionLimit = 150; - long connectionTTL = 12 * HOUR; + long connectionTTL = 30 * MINUTE; boolean sendPubkeyOnIdentityCreation = true; long pubkeyTTL = 28; @@ -420,9 +455,9 @@ public class BitmessageContext { * Time to live in seconds for public keys the client sends. Defaults to the maximum of 28 days, * but on weak devices smaller values might be desirable. * <p> - * Please be aware that this might cause some problems where you can't receive a message (the - * sender can't receive your public key) in some special situations. Also note that it's probably - * not a good idea to set it too low. + * Please be aware that this might cause some problems where you can't receive a message (the + * sender can't receive your public key) in some special situations. Also note that it's probably + * not a good idea to set it too low. * </p> */ public Builder pubkeyTTL(long days) { diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/GetData.java b/domain/src/main/java/ch/dissem/bitmessage/entity/GetData.java index b62e6e5..e272bbc 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/GetData.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/GetData.java @@ -44,10 +44,10 @@ public class GetData implements MessagePayload { } @Override - public void write(OutputStream stream) throws IOException { - Encode.varInt(inventory.size(), stream); + public void write(OutputStream out) throws IOException { + Encode.varInt(inventory.size(), out); for (InventoryVector iv : inventory) { - iv.write(stream); + iv.write(out); } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Property.java b/domain/src/main/java/ch/dissem/bitmessage/utils/Property.java index e00d193..b823eb5 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/utils/Property.java +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/Property.java @@ -16,6 +16,9 @@ package ch.dissem.bitmessage.utils; +import java.util.Arrays; +import java.util.Objects; + /** * Some property that has a name, a value and/or other properties. This can be used for any purpose, but is for now * used to contain different status information. It is by default displayed in some JSON inspired human readable @@ -43,12 +46,19 @@ public class Property { return value; } - public Property getProperty(String name) { + /** + * Returns the property if available or <code>null</code> otherwise. + * Subproperties can be requested by submitting the sequence of properties. + */ + public Property getProperty(String... name) { + if (name == null || name.length == 0) return null; + for (Property p : properties) { - if (name == null) { - if (p.name == null) return p; - } else { - if (name.equals(p.name)) return p; + if (Objects.equals(name[0], p.name)) { + if (name.length == 1) + return p; + else + return p.getProperty(Arrays.copyOfRange(name, 1, name.length)); } } return null; diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 4d14fe2..3155645 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -42,6 +42,7 @@ import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentMap; import static ch.dissem.bitmessage.networking.Connection.Mode.CLIENT; +import static ch.dissem.bitmessage.networking.Connection.Mode.SYNC; import static ch.dissem.bitmessage.networking.Connection.State.*; import static ch.dissem.bitmessage.utils.Singleton.security; import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; @@ -49,7 +50,7 @@ import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; /** * A connection to a specific node */ -public class Connection { +class Connection { public static final int READ_TIMEOUT = 2000; private static final Logger LOG = LoggerFactory.getLogger(Connection.class); private static final int CONNECT_TIMEOUT = 5000; @@ -63,10 +64,12 @@ public class Connection { private final NetworkAddress host; private final NetworkAddress node; private final Queue<MessagePayload> sendingQueue = new ConcurrentLinkedDeque<>(); - private final Map<InventoryVector, Long> requestedObjects; + private final Set<InventoryVector> commonRequestedObjects; + private final Set<InventoryVector> requestedObjects; private final long syncTimeout; private final ReaderRunnable reader = new ReaderRunnable(); private final WriterRunnable writer = new WriterRunnable(); + private final DefaultNetworkHandler networkHandler; private volatile State state; private InputStream in; @@ -75,39 +78,45 @@ public class Connection { private long[] streams; private int readTimeoutCounter; private boolean socketInitialized; + private long lastObjectTime; public Connection(InternalContext context, Mode mode, Socket socket, MessageListener listener, - ConcurrentMap<InventoryVector, Long> requestedObjectsMap) throws IOException { + Set<InventoryVector> requestedObjectsMap) throws IOException { this(context, mode, listener, socket, requestedObjectsMap, + Collections.newSetFromMap(new ConcurrentHashMap<InventoryVector, Boolean>(10_000)), new NetworkAddress.Builder().ip(socket.getInetAddress()).port(socket.getPort()).stream(1).build(), 0); } public Connection(InternalContext context, Mode mode, NetworkAddress node, MessageListener listener, - ConcurrentMap<InventoryVector, Long> requestedObjectsMap) { + Set<InventoryVector> requestedObjectsMap) { this(context, mode, listener, new Socket(), requestedObjectsMap, + Collections.newSetFromMap(new ConcurrentHashMap<InventoryVector, Boolean>(10_000)), node, 0); } private Connection(InternalContext context, Mode mode, MessageListener listener, Socket socket, - Map<InventoryVector, Long> requestedObjectsMap, NetworkAddress node, long syncTimeout) { + Set<InventoryVector> commonRequestedObjects, Set<InventoryVector> requestedObjects, NetworkAddress node, long syncTimeout) { this.startTime = UnixTime.now(); this.ctx = context; this.mode = mode; this.state = CONNECTING; this.listener = listener; this.socket = socket; - this.requestedObjects = requestedObjectsMap; + this.commonRequestedObjects = commonRequestedObjects; + this.requestedObjects = requestedObjects; this.host = new NetworkAddress.Builder().ipv6(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).port(0).build(); this.node = node; this.syncTimeout = (syncTimeout > 0 ? UnixTime.now(+syncTimeout) : 0); this.ivCache = new ConcurrentHashMap<>(); + this.networkHandler = (DefaultNetworkHandler) ctx.getNetworkHandler(); } public static Connection sync(InternalContext ctx, InetAddress address, int port, MessageListener listener, long timeoutInSeconds) throws IOException { - return new Connection(ctx, Mode.CLIENT, listener, new Socket(address, port), - new HashMap<InventoryVector, Long>(), + return new Connection(ctx, Mode.SYNC, listener, new Socket(address, port), + new HashSet<InventoryVector>(), + new HashSet<InventoryVector>(), new NetworkAddress.Builder().ip(address).port(port).stream(1).build(), timeoutInSeconds); } @@ -141,25 +150,26 @@ public class Connection { return true; } if (msg == null) { + if (requestedObjects.isEmpty() && sendingQueue.isEmpty()) + return true; + readTimeoutCounter++; return readTimeoutCounter > 1; + } else { + readTimeoutCounter = 0; + return false; } - readTimeoutCounter = 0; - if (!(msg.getPayload() instanceof Addr) && !(msg.getPayload() instanceof GetData) - && requestedObjects.isEmpty() && sendingQueue.isEmpty()) { - LOG.info("Synchronisation completed"); - return true; - } - return false; } private void activateConnection() { LOG.info("Successfully established connection with node " + node); state = ACTIVE; - sendAddresses(); + if (mode != SYNC) { + sendAddresses(); + ctx.getNodeRegistry().offerAddresses(Collections.singletonList(node)); + } sendInventory(); node.setTime(UnixTime.now()); - ctx.getNodeRegistry().offerAddresses(Collections.singletonList(node)); } private void cleanupIvCache() { @@ -187,41 +197,15 @@ public class Connection { } } - private void updateRequestedObjects(List<InventoryVector> missing) { - Long now = UnixTime.now(); - Long fiveMinutesAgo = now - 5 * MINUTE; - Long tenMinutesAgo = now - 10 * MINUTE; - List<InventoryVector> stillMissing = new LinkedList<>(); - for (Map.Entry<InventoryVector, Long> entry : requestedObjects.entrySet()) { - if (entry.getValue() < fiveMinutesAgo) { - stillMissing.add(entry.getKey()); - // If it's still not available after 10 minutes, we won't look for it - // any longer (except it's announced again) - if (entry.getValue() < tenMinutesAgo) { - requestedObjects.remove(entry.getKey()); - } - } - } - - for (InventoryVector iv : missing) { - requestedObjects.put(iv, now); - } - if (!stillMissing.isEmpty()) { - LOG.debug(stillMissing.size() + " items are still missing."); - missing.addAll(stillMissing); - } - } - private void receiveMessage(MessagePayload messagePayload) { switch (messagePayload.getCommand()) { case INV: Inv inv = (Inv) messagePayload; updateIvCache(inv.getInventory()); List<InventoryVector> missing = ctx.getInventory().getMissing(inv.getInventory(), streams); - missing.removeAll(requestedObjects.keySet()); + missing.removeAll(commonRequestedObjects); LOG.debug("Received inventory with " + inv.getInventory().size() + " elements, of which are " + missing.size() + " missing."); - updateRequestedObjects(missing); send(new GetData.Builder().inventory(missing).build()); break; case GETDATA: @@ -234,24 +218,33 @@ public class Connection { case OBJECT: ObjectMessage objectMessage = (ObjectMessage) messagePayload; try { + requestedObjects.remove(objectMessage.getInventoryVector()); if (ctx.getInventory().contains(objectMessage)) { LOG.trace("Received object " + objectMessage.getInventoryVector() + " - already in inventory"); break; } - security().checkProofOfWork(objectMessage, ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes()); listener.receive(objectMessage); + security().checkProofOfWork(objectMessage, ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes()); ctx.getInventory().storeObject(objectMessage); // offer object to some random nodes so it gets distributed throughout the network: // FIXME: don't do this while we catch up after initialising our first connection // (that might be a bit tricky to do) - ctx.getNetworkHandler().offer(objectMessage.getInventoryVector()); + networkHandler.offer(objectMessage.getInventoryVector()); + lastObjectTime = UnixTime.now(); } catch (InsufficientProofOfWorkException e) { LOG.warn(e.getMessage()); // DebugUtils.saveToFile(objectMessage); // this line must not be committed active } catch (IOException e) { LOG.error("Stream " + objectMessage.getStream() + ", object type " + objectMessage.getType() + ": " + e.getMessage(), e); } finally { - requestedObjects.remove(objectMessage.getInventoryVector()); + if (commonRequestedObjects.remove(objectMessage.getInventoryVector())) { + LOG.debug("Received object that wasn't requested."); +// if (!requestedObjects.isEmpty()) { +// DebugUtils.saveToFile(objectMessage); +// LOG.debug(objectMessage.getInventoryVector() + " was not in " +// + requestedObjects.toString()); +// } + } } break; case ADDR: @@ -282,10 +275,16 @@ public class Connection { public void disconnect() { state = DISCONNECTED; + + // Make sure objects that are still missing are requested from other nodes + networkHandler.request(requestedObjects); } - private void send(MessagePayload payload) { + void send(MessagePayload payload) { try { + if (payload instanceof GetData) { + requestedObjects.addAll(((GetData) payload).getInventory()); + } new NetworkMessage(payload).write(out); } catch (IOException e) { LOG.error(e.getMessage(), e); @@ -338,7 +337,7 @@ public class Connection { return writer; } - public enum Mode {SERVER, CLIENT} + public enum Mode {SERVER, CLIENT, SYNC} public enum State {CONNECTING, ACTIVE, DISCONNECTED} @@ -347,11 +346,15 @@ public class Connection { public void run() { try (Socket socket = Connection.this.socket) { initSocket(socket); - if (mode == CLIENT) { + if (mode == CLIENT || mode == SYNC) { send(new Version.Builder().defaults().addrFrom(host).addrRecv(node).build()); } while (state != DISCONNECTED) { - Thread.sleep(100); + if (requestedObjects.isEmpty()) { + Thread.sleep(1000); + } else { + Thread.sleep(100); + } try { NetworkMessage msg = Factory.getNetworkMessage(version, in); if (msg == null) @@ -377,6 +380,7 @@ public class Connection { send(new Version.Builder().defaults().addrFrom(host).addrRecv(node).build()); break; case CLIENT: + case SYNC: activateConnection(); break; } @@ -391,6 +395,7 @@ public class Connection { activateConnection(); break; case CLIENT: + case SYNC: // NO OP break; } @@ -407,7 +412,7 @@ public class Connection { + msg.getPayload().getCommand() + "'"); } } - if (socket.isClosed() || syncFinished(msg)) disconnect(); + if (socket.isClosed() || syncFinished(msg) || checkOpenRequests()) disconnect(); } catch (SocketTimeoutException ignore) { if (state == ACTIVE) { if (syncFinished(null)) disconnect(); @@ -429,16 +434,20 @@ public class Connection { } } + private boolean checkOpenRequests() { + return !requestedObjects.isEmpty() && lastObjectTime > 0 && (UnixTime.now() - lastObjectTime) > 2 * MINUTE; + } + public class WriterRunnable implements Runnable { @Override public void run() { try (Socket socket = Connection.this.socket) { initSocket(socket); while (state != DISCONNECTED) { - if (sendingQueue.size() > 0) { + if (!sendingQueue.isEmpty()) { send(sendingQueue.poll()); } else { - Thread.sleep(100); + Thread.sleep(1000); } } } catch (IOException | InterruptedException e) { diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java index e934bdf..bd58d8e 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java @@ -19,6 +19,7 @@ package ch.dissem.bitmessage.networking; import ch.dissem.bitmessage.InternalContext; import ch.dissem.bitmessage.InternalContext.ContextHolder; import ch.dissem.bitmessage.entity.CustomMessage; +import ch.dissem.bitmessage.entity.GetData; import ch.dissem.bitmessage.entity.NetworkMessage; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; @@ -41,8 +42,9 @@ import java.util.concurrent.*; import static ch.dissem.bitmessage.networking.Connection.Mode.CLIENT; import static ch.dissem.bitmessage.networking.Connection.Mode.SERVER; import static ch.dissem.bitmessage.networking.Connection.State.ACTIVE; -import static ch.dissem.bitmessage.networking.Connection.State.DISCONNECTED; import static ch.dissem.bitmessage.utils.DebugUtils.inc; +import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; +import static java.util.Collections.newSetFromMap; /** * Handles all the networky stuff. @@ -50,13 +52,14 @@ import static ch.dissem.bitmessage.utils.DebugUtils.inc; public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { public final static int NETWORK_MAGIC_NUMBER = 8; private final static Logger LOG = LoggerFactory.getLogger(DefaultNetworkHandler.class); - private final List<Connection> connections = new LinkedList<>(); + private static final Random RANDOM = new Random(); + private final Collection<Connection> connections = new ConcurrentLinkedQueue<>(); private final ExecutorService pool; private InternalContext ctx; private ServerSocket serverSocket; private volatile boolean running; - private ConcurrentMap<InventoryVector, Long> requestedObjects = new ConcurrentHashMap<>(); + private Set<InventoryVector> requestedObjects = newSetFromMap(new ConcurrentHashMap<InventoryVector, Boolean>(50_000)); public DefaultNetworkHandler() { pool = Executors.newCachedThreadPool(new ThreadFactory() { @@ -134,6 +137,8 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { } }); pool.execute(new Runnable() { + public Connection initialConnection; + @Override public void run() { try { @@ -152,25 +157,38 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { } for (Iterator<Connection> iterator = connections.iterator(); iterator.hasNext(); ) { Connection c = iterator.next(); - if (now - c.getStartTime() > ctx.getConnectionTTL()) { + // Just in case they were all created at the same time, don't disconnect + // all at once. + if (now - c.getStartTime() + RANDOM.nextInt(5 * MINUTE) > ctx.getConnectionTTL()) { c.disconnect(); } - if (c.getState() == DISCONNECTED) { - // Remove the current element from the iterator and the list. - iterator.remove(); - } - if (c.getState() == ACTIVE) { - active++; + switch (c.getState()) { + case DISCONNECTED: + iterator.remove(); + break; + case ACTIVE: + active++; + break; } } } if (active < NETWORK_MAGIC_NUMBER) { List<NetworkAddress> addresses = ctx.getNodeRegistry().getKnownAddresses( NETWORK_MAGIC_NUMBER - active, ctx.getStreams()); + boolean first = active == 0 && initialConnection == null; for (NetworkAddress address : addresses) { - startConnection(new Connection(ctx, CLIENT, address, listener, requestedObjects)); + Connection c = new Connection(ctx, CLIENT, address, listener, requestedObjects); + if (first) { + initialConnection = c; + first = false; + } + startConnection(c); } Thread.sleep(10000); + } else if (initialConnection != null) { + initialConnection.disconnect(); + initialConnection = null; + Thread.sleep(10000); } else { Thread.sleep(30000); } @@ -209,6 +227,7 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { c.disconnect(); } } + requestedObjects.clear(); } private void startConnection(Connection c) { @@ -272,7 +291,56 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { } return new Property("network", null, new Property("connectionManager", running ? "running" : "stopped"), - new Property("connections", null, streamProperties) + new Property("connections", null, streamProperties), + new Property("requestedObjects", requestedObjects.size()) ); } + + void request(Set<InventoryVector> inventoryVectors) { + if (!running || inventoryVectors.isEmpty()) return; + synchronized (connections) { + Map<Connection, List<InventoryVector>> distribution = new HashMap<>(); + for (Connection connection : connections) { + if (connection.getState() == ACTIVE) { + distribution.put(connection, new LinkedList<InventoryVector>()); + } + } + Iterator<InventoryVector> iterator = inventoryVectors.iterator(); + boolean firstRound = true; + InventoryVector next = iterator.next(); + while (firstRound || iterator.hasNext()) { + if (!firstRound) { + next = iterator.next(); + firstRound = true; + } else { + firstRound = false; + } + for (Connection connection : distribution.keySet()) { + if (connection.knowsOf(next)) { + List<InventoryVector> ivs = distribution.get(connection); + if (ivs.size() == 50_000) { + connection.send(new GetData.Builder().inventory(ivs).build()); + ivs.clear(); + } + ivs.add(next); + iterator.remove(); + + if (iterator.hasNext()) { + next = iterator.next(); + firstRound = true; + } else { + firstRound = false; + break; + } + } + } + } + for (Connection connection : distribution.keySet()) { + List<InventoryVector> ivs = distribution.get(connection); + if (!ivs.isEmpty()) { + connection.send(new GetData.Builder().inventory(ivs).build()); + } + } + } + } } diff --git a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java index 499e377..e850ffb 100644 --- a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java +++ b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java @@ -101,7 +101,7 @@ public class NetworkHandlerTest { Property status; do { Thread.yield(); - status = node.status().getProperty("network").getProperty("connections").getProperty("stream 0"); + status = node.status().getProperty("network", "connections", "stream 0"); } while (status == null); assertEquals(1, status.getProperty("outgoing").getValue()); } finally { @@ -109,7 +109,7 @@ public class NetworkHandlerTest { } } - @Test(timeout = 5_000) + @Test(timeout = 10_000) public void ensureObjectsAreSynchronizedIfBothHaveObjects() throws Exception { peerInventory.init( "V4Pubkey.payload", From ac6f291964c8ecd2bbb7a944af2b200d48a08878 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sun, 17 Jan 2016 05:42:48 +0100 Subject: [PATCH 09/54] Renamed module 'domain' to 'core' to make its purpose more clear --- README.md | 5 ++++- {domain => core}/build.gradle | 4 ++-- .../ch/dissem/bitmessage/BitmessageContext.java | 0 .../dissem/bitmessage/DefaultMessageListener.java | 0 .../java/ch/dissem/bitmessage/InternalContext.java | 0 .../java/ch/dissem/bitmessage/MessageCallback.java | 0 .../ch/dissem/bitmessage/ProofOfWorkService.java | 0 .../main/java/ch/dissem/bitmessage/entity/Addr.java | 0 .../dissem/bitmessage/entity/BitmessageAddress.java | 0 .../ch/dissem/bitmessage/entity/CustomMessage.java | 0 .../java/ch/dissem/bitmessage/entity/Encrypted.java | 0 .../java/ch/dissem/bitmessage/entity/GetData.java | 0 .../main/java/ch/dissem/bitmessage/entity/Inv.java | 0 .../ch/dissem/bitmessage/entity/MessagePayload.java | 0 .../ch/dissem/bitmessage/entity/NetworkMessage.java | 0 .../ch/dissem/bitmessage/entity/ObjectMessage.java | 0 .../java/ch/dissem/bitmessage/entity/Plaintext.java | 0 .../dissem/bitmessage/entity/PlaintextHolder.java | 0 .../ch/dissem/bitmessage/entity/Streamable.java | 0 .../java/ch/dissem/bitmessage/entity/VerAck.java | 0 .../java/ch/dissem/bitmessage/entity/Version.java | 0 .../dissem/bitmessage/entity/payload/Broadcast.java | 0 .../dissem/bitmessage/entity/payload/CryptoBox.java | 0 .../bitmessage/entity/payload/GenericPayload.java | 0 .../dissem/bitmessage/entity/payload/GetPubkey.java | 0 .../ch/dissem/bitmessage/entity/payload/Msg.java | 0 .../bitmessage/entity/payload/ObjectPayload.java | 0 .../bitmessage/entity/payload/ObjectType.java | 0 .../ch/dissem/bitmessage/entity/payload/Pubkey.java | 0 .../dissem/bitmessage/entity/payload/V2Pubkey.java | 0 .../dissem/bitmessage/entity/payload/V3Pubkey.java | 0 .../bitmessage/entity/payload/V4Broadcast.java | 0 .../dissem/bitmessage/entity/payload/V4Pubkey.java | 0 .../bitmessage/entity/payload/V5Broadcast.java | 0 .../entity/valueobject/InventoryVector.java | 0 .../dissem/bitmessage/entity/valueobject/Label.java | 0 .../entity/valueobject/NetworkAddress.java | 0 .../bitmessage/entity/valueobject/PrivateKey.java | 0 .../exception/AddressFormatException.java | 0 .../exception/DecryptionFailedException.java | 0 .../exception/InsufficientProofOfWorkException.java | 0 .../dissem/bitmessage/exception/NodeException.java | 0 .../java/ch/dissem/bitmessage/factory/Factory.java | 0 .../dissem/bitmessage/factory/V3MessageFactory.java | 0 .../bitmessage/ports/AbstractCryptography.java | 0 .../dissem/bitmessage/ports/AddressRepository.java | 0 .../ch/dissem/bitmessage/ports/Cryptography.java | 0 .../bitmessage/ports/CustomCommandHandler.java | 0 .../java/ch/dissem/bitmessage/ports/Inventory.java | 0 .../dissem/bitmessage/ports/MemoryNodeRegistry.java | 0 .../dissem/bitmessage/ports/MessageRepository.java | 0 .../bitmessage/ports/MultiThreadedPOWEngine.java | 0 .../ch/dissem/bitmessage/ports/NetworkHandler.java | 0 .../ch/dissem/bitmessage/ports/NodeRegistry.java | 0 .../dissem/bitmessage/ports/ProofOfWorkEngine.java | 0 .../bitmessage/ports/ProofOfWorkRepository.java | 0 .../ch/dissem/bitmessage/ports/SimplePOWEngine.java | 0 .../ch/dissem/bitmessage/utils/AccessCounter.java | 0 .../java/ch/dissem/bitmessage/utils/Base58.java | 0 .../main/java/ch/dissem/bitmessage/utils/Bytes.java | 0 .../ch/dissem/bitmessage/utils/CallbackWaiter.java | 0 .../ch/dissem/bitmessage/utils/Collections.java | 0 .../java/ch/dissem/bitmessage/utils/DebugUtils.java | 0 .../java/ch/dissem/bitmessage/utils/Decode.java | 0 .../java/ch/dissem/bitmessage/utils/Encode.java | 0 .../java/ch/dissem/bitmessage/utils/Numbers.java | 0 .../java/ch/dissem/bitmessage/utils/Points.java | 0 .../java/ch/dissem/bitmessage/utils/Property.java | 0 .../java/ch/dissem/bitmessage/utils/Singleton.java | 0 .../java/ch/dissem/bitmessage/utils/Strings.java | 0 .../java/ch/dissem/bitmessage/utils/UnixTime.java | 0 {domain => core}/src/main/resources/nodes.txt | 0 .../java/ch/dissem/bitmessage/DecryptionTest.java | 0 .../java/ch/dissem/bitmessage/EncryptionTest.java | 0 .../java/ch/dissem/bitmessage/SignatureTest.java | 0 .../bitmessage/entity/BitmessageAddressTest.java | 0 .../dissem/bitmessage/entity/SerializationTest.java | 0 .../bitmessage/ports/ProofOfWorkEngineTest.java | 0 .../java/ch/dissem/bitmessage/utils/BytesTest.java | 0 .../ch/dissem/bitmessage/utils/CollectionsTest.java | 0 .../java/ch/dissem/bitmessage/utils/DecodeTest.java | 0 .../java/ch/dissem/bitmessage/utils/EncodeTest.java | 0 .../ch/dissem/bitmessage/utils/StringsTest.java | 0 .../java/ch/dissem/bitmessage/utils/TestBase.java | 0 .../java/ch/dissem/bitmessage/utils/TestUtils.java | 0 .../BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ.pubkey | Bin .../BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey | Bin .../BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h.pubkey | Bin {domain => core}/src/test/resources/V1Msg.payload | Bin .../src/test/resources/V1MsgStrangeData.payload | Bin .../src/test/resources/V2GetPubkey.payload | Bin .../src/test/resources/V2Pubkey.payload | Bin .../src/test/resources/V3GetPubkey.payload | Bin .../src/test/resources/V3Pubkey.payload | Bin .../src/test/resources/V4Broadcast.payload | Bin .../src/test/resources/V4GetPubkey.payload | Bin .../src/test/resources/V4Pubkey.payload | Bin .../src/test/resources/V5Broadcast.payload | Bin cryptography-bc/build.gradle | 2 +- cryptography-sc/build.gradle | 2 +- demo/build.gradle | 2 +- extensions/build.gradle | 4 ++-- networking/build.gradle | 4 ++-- repositories/build.gradle | 4 ++-- settings.gradle | 2 +- wif/build.gradle | 2 +- 106 files changed, 17 insertions(+), 14 deletions(-) rename {domain => core}/build.gradle (89%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/BitmessageContext.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/InternalContext.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/MessageCallback.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/Addr.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/GetData.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/Inv.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/PlaintextHolder.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/Streamable.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/VerAck.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/Version.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectType.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/exception/NodeException.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/factory/Factory.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/Cryptography.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/Inventory.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/NodeRegistry.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/AccessCounter.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Base58.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Bytes.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/CallbackWaiter.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Collections.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/DebugUtils.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Decode.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Encode.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Numbers.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Points.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Property.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Singleton.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/Strings.java (100%) rename {domain => core}/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java (100%) rename {domain => core}/src/main/resources/nodes.txt (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/DecryptionTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/EncryptionTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/SignatureTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/utils/CollectionsTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/utils/DecodeTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/utils/StringsTest.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/utils/TestBase.java (100%) rename {domain => core}/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java (100%) rename {domain => core}/src/test/resources/BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ.pubkey (100%) rename {domain => core}/src/test/resources/BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey (100%) rename {domain => core}/src/test/resources/BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h.pubkey (100%) rename {domain => core}/src/test/resources/V1Msg.payload (100%) rename {domain => core}/src/test/resources/V1MsgStrangeData.payload (100%) rename {domain => core}/src/test/resources/V2GetPubkey.payload (100%) rename {domain => core}/src/test/resources/V2Pubkey.payload (100%) rename {domain => core}/src/test/resources/V3GetPubkey.payload (100%) rename {domain => core}/src/test/resources/V3Pubkey.payload (100%) rename {domain => core}/src/test/resources/V4Broadcast.payload (100%) rename {domain => core}/src/test/resources/V4GetPubkey.payload (100%) rename {domain => core}/src/test/resources/V4Pubkey.payload (100%) rename {domain => core}/src/test/resources/V5Broadcast.payload (100%) diff --git a/README.md b/README.md index 19ce171..fb45cc6 100644 --- a/README.md +++ b/README.md @@ -29,18 +29,21 @@ Setup Add Jabit as Gradle dependency: ```Gradle -compile 'ch.dissem.jabit:jabit-domain:0.2.0' +compile 'ch.dissem.jabit:jabit-core:0.2.0' ``` Unless you want to implement your own, also add the following: ```Gradle compile 'ch.dissem.jabit:jabit-networking:0.2.0' compile 'ch.dissem.jabit:jabit-repositories:0.2.0' +compile 'ch.dissem.jabit:jabit-cryptography-bc:0.2.0' ``` And if you want to import from or export to the Wallet Import Format (used by PyBitmessage) you might also want to add: ```Gradle compile 'ch.dissem.jabit:jabit-wif:0.2.0' ``` +For Android clients use `jabit-cryptography-sc` instead of `jabit-cryptography-bc`. + Usage ----- diff --git a/domain/build.gradle b/core/build.gradle similarity index 89% rename from domain/build.gradle rename to core/build.gradle index 484abfd..8754cb3 100644 --- a/domain/build.gradle +++ b/core/build.gradle @@ -2,8 +2,8 @@ uploadArchives { repositories { mavenDeployer { pom.project { - name 'Jabit Domain' - artifactId = 'jabit-domain' + name 'Jabit Core' + artifactId = 'jabit-core' description 'A Java implementation of the Bitmessage protocol. This is the core part. You\'ll either need the networking and repositories modules, too, or implement your own.' } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java rename to core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java rename to core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/InternalContext.java rename to core/src/main/java/ch/dissem/bitmessage/InternalContext.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/MessageCallback.java b/core/src/main/java/ch/dissem/bitmessage/MessageCallback.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/MessageCallback.java rename to core/src/main/java/ch/dissem/bitmessage/MessageCallback.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java rename to core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Addr.java b/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/Addr.java rename to core/src/main/java/ch/dissem/bitmessage/entity/Addr.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java rename to core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java rename to core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java b/core/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java rename to core/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/GetData.java b/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/GetData.java rename to core/src/main/java/ch/dissem/bitmessage/entity/GetData.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Inv.java b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/Inv.java rename to core/src/main/java/ch/dissem/bitmessage/entity/Inv.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java b/core/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java rename to core/src/main/java/ch/dissem/bitmessage/entity/MessagePayload.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java rename to core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java rename to core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java rename to core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/PlaintextHolder.java b/core/src/main/java/ch/dissem/bitmessage/entity/PlaintextHolder.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/PlaintextHolder.java rename to core/src/main/java/ch/dissem/bitmessage/entity/PlaintextHolder.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Streamable.java b/core/src/main/java/ch/dissem/bitmessage/entity/Streamable.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/Streamable.java rename to core/src/main/java/ch/dissem/bitmessage/entity/Streamable.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/VerAck.java b/core/src/main/java/ch/dissem/bitmessage/entity/VerAck.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/VerAck.java rename to core/src/main/java/ch/dissem/bitmessage/entity/VerAck.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Version.java b/core/src/main/java/ch/dissem/bitmessage/entity/Version.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/Version.java rename to core/src/main/java/ch/dissem/bitmessage/entity/Version.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectType.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectType.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectType.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectType.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java rename to core/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java rename to core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java rename to core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java rename to core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java rename to core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java b/core/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java rename to core/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java b/core/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java rename to core/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java b/core/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java rename to core/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/exception/NodeException.java b/core/src/main/java/ch/dissem/bitmessage/exception/NodeException.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/exception/NodeException.java rename to core/src/main/java/ch/dissem/bitmessage/exception/NodeException.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java b/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/factory/Factory.java rename to core/src/main/java/ch/dissem/bitmessage/factory/Factory.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java b/core/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java rename to core/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java b/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java rename to core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java b/core/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java rename to core/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/Cryptography.java b/core/src/main/java/ch/dissem/bitmessage/ports/Cryptography.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/Cryptography.java rename to core/src/main/java/ch/dissem/bitmessage/ports/Cryptography.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java b/core/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java rename to core/src/main/java/ch/dissem/bitmessage/ports/CustomCommandHandler.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/Inventory.java b/core/src/main/java/ch/dissem/bitmessage/ports/Inventory.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/Inventory.java rename to core/src/main/java/ch/dissem/bitmessage/ports/Inventory.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java b/core/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java rename to core/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java b/core/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java rename to core/src/main/java/ch/dissem/bitmessage/ports/MessageRepository.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java b/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java rename to core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java b/core/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java rename to core/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/NodeRegistry.java b/core/src/main/java/ch/dissem/bitmessage/ports/NodeRegistry.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/NodeRegistry.java rename to core/src/main/java/ch/dissem/bitmessage/ports/NodeRegistry.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java b/core/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java rename to core/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkEngine.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java b/core/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java rename to core/src/main/java/ch/dissem/bitmessage/ports/ProofOfWorkRepository.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java b/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java rename to core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/AccessCounter.java b/core/src/main/java/ch/dissem/bitmessage/utils/AccessCounter.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/AccessCounter.java rename to core/src/main/java/ch/dissem/bitmessage/utils/AccessCounter.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Base58.java b/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Base58.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Base58.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Bytes.java b/core/src/main/java/ch/dissem/bitmessage/utils/Bytes.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Bytes.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Bytes.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/CallbackWaiter.java b/core/src/main/java/ch/dissem/bitmessage/utils/CallbackWaiter.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/CallbackWaiter.java rename to core/src/main/java/ch/dissem/bitmessage/utils/CallbackWaiter.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Collections.java b/core/src/main/java/ch/dissem/bitmessage/utils/Collections.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Collections.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Collections.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/DebugUtils.java b/core/src/main/java/ch/dissem/bitmessage/utils/DebugUtils.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/DebugUtils.java rename to core/src/main/java/ch/dissem/bitmessage/utils/DebugUtils.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Decode.java b/core/src/main/java/ch/dissem/bitmessage/utils/Decode.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Decode.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Decode.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Encode.java b/core/src/main/java/ch/dissem/bitmessage/utils/Encode.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Encode.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Encode.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Numbers.java b/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Numbers.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Points.java b/core/src/main/java/ch/dissem/bitmessage/utils/Points.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Points.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Points.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Property.java b/core/src/main/java/ch/dissem/bitmessage/utils/Property.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Property.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Property.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Singleton.java b/core/src/main/java/ch/dissem/bitmessage/utils/Singleton.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Singleton.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Singleton.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Strings.java b/core/src/main/java/ch/dissem/bitmessage/utils/Strings.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/Strings.java rename to core/src/main/java/ch/dissem/bitmessage/utils/Strings.java diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java b/core/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java similarity index 100% rename from domain/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java rename to core/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java diff --git a/domain/src/main/resources/nodes.txt b/core/src/main/resources/nodes.txt similarity index 100% rename from domain/src/main/resources/nodes.txt rename to core/src/main/resources/nodes.txt diff --git a/domain/src/test/java/ch/dissem/bitmessage/DecryptionTest.java b/core/src/test/java/ch/dissem/bitmessage/DecryptionTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/DecryptionTest.java rename to core/src/test/java/ch/dissem/bitmessage/DecryptionTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java b/core/src/test/java/ch/dissem/bitmessage/EncryptionTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java rename to core/src/test/java/ch/dissem/bitmessage/EncryptionTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java b/core/src/test/java/ch/dissem/bitmessage/SignatureTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java rename to core/src/test/java/ch/dissem/bitmessage/SignatureTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java b/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java rename to core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java b/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java rename to core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java b/core/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java rename to core/src/test/java/ch/dissem/bitmessage/ports/ProofOfWorkEngineTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java b/core/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java rename to core/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/CollectionsTest.java b/core/src/test/java/ch/dissem/bitmessage/utils/CollectionsTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/utils/CollectionsTest.java rename to core/src/test/java/ch/dissem/bitmessage/utils/CollectionsTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/DecodeTest.java b/core/src/test/java/ch/dissem/bitmessage/utils/DecodeTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/utils/DecodeTest.java rename to core/src/test/java/ch/dissem/bitmessage/utils/DecodeTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java b/core/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java rename to core/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/StringsTest.java b/core/src/test/java/ch/dissem/bitmessage/utils/StringsTest.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/utils/StringsTest.java rename to core/src/test/java/ch/dissem/bitmessage/utils/StringsTest.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/TestBase.java b/core/src/test/java/ch/dissem/bitmessage/utils/TestBase.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/utils/TestBase.java rename to core/src/test/java/ch/dissem/bitmessage/utils/TestBase.java diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java b/core/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java similarity index 100% rename from domain/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java rename to core/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java diff --git a/domain/src/test/resources/BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ.pubkey b/core/src/test/resources/BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ.pubkey similarity index 100% rename from domain/src/test/resources/BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ.pubkey rename to core/src/test/resources/BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ.pubkey diff --git a/domain/src/test/resources/BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey b/core/src/test/resources/BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey similarity index 100% rename from domain/src/test/resources/BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey rename to core/src/test/resources/BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey diff --git a/domain/src/test/resources/BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h.pubkey b/core/src/test/resources/BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h.pubkey similarity index 100% rename from domain/src/test/resources/BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h.pubkey rename to core/src/test/resources/BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h.pubkey diff --git a/domain/src/test/resources/V1Msg.payload b/core/src/test/resources/V1Msg.payload similarity index 100% rename from domain/src/test/resources/V1Msg.payload rename to core/src/test/resources/V1Msg.payload diff --git a/domain/src/test/resources/V1MsgStrangeData.payload b/core/src/test/resources/V1MsgStrangeData.payload similarity index 100% rename from domain/src/test/resources/V1MsgStrangeData.payload rename to core/src/test/resources/V1MsgStrangeData.payload diff --git a/domain/src/test/resources/V2GetPubkey.payload b/core/src/test/resources/V2GetPubkey.payload similarity index 100% rename from domain/src/test/resources/V2GetPubkey.payload rename to core/src/test/resources/V2GetPubkey.payload diff --git a/domain/src/test/resources/V2Pubkey.payload b/core/src/test/resources/V2Pubkey.payload similarity index 100% rename from domain/src/test/resources/V2Pubkey.payload rename to core/src/test/resources/V2Pubkey.payload diff --git a/domain/src/test/resources/V3GetPubkey.payload b/core/src/test/resources/V3GetPubkey.payload similarity index 100% rename from domain/src/test/resources/V3GetPubkey.payload rename to core/src/test/resources/V3GetPubkey.payload diff --git a/domain/src/test/resources/V3Pubkey.payload b/core/src/test/resources/V3Pubkey.payload similarity index 100% rename from domain/src/test/resources/V3Pubkey.payload rename to core/src/test/resources/V3Pubkey.payload diff --git a/domain/src/test/resources/V4Broadcast.payload b/core/src/test/resources/V4Broadcast.payload similarity index 100% rename from domain/src/test/resources/V4Broadcast.payload rename to core/src/test/resources/V4Broadcast.payload diff --git a/domain/src/test/resources/V4GetPubkey.payload b/core/src/test/resources/V4GetPubkey.payload similarity index 100% rename from domain/src/test/resources/V4GetPubkey.payload rename to core/src/test/resources/V4GetPubkey.payload diff --git a/domain/src/test/resources/V4Pubkey.payload b/core/src/test/resources/V4Pubkey.payload similarity index 100% rename from domain/src/test/resources/V4Pubkey.payload rename to core/src/test/resources/V4Pubkey.payload diff --git a/domain/src/test/resources/V5Broadcast.payload b/core/src/test/resources/V5Broadcast.payload similarity index 100% rename from domain/src/test/resources/V5Broadcast.payload rename to core/src/test/resources/V5Broadcast.payload diff --git a/cryptography-bc/build.gradle b/cryptography-bc/build.gradle index 0634154..c09b0db 100644 --- a/cryptography-bc/build.gradle +++ b/cryptography-bc/build.gradle @@ -11,7 +11,7 @@ uploadArchives { } dependencies { - compile project(':domain') + compile project(':core') compile 'org.bouncycastle:bcprov-jdk15on:1.52' testCompile 'junit:junit:4.11' testCompile 'org.mockito:mockito-core:1.10.19' diff --git a/cryptography-sc/build.gradle b/cryptography-sc/build.gradle index 2d4f82f..16771fc 100644 --- a/cryptography-sc/build.gradle +++ b/cryptography-sc/build.gradle @@ -11,7 +11,7 @@ uploadArchives { } dependencies { - compile project(':domain') + compile project(':core') compile 'com.madgag.spongycastle:prov:1.52.0.0' testCompile 'junit:junit:4.11' } diff --git a/demo/build.gradle b/demo/build.gradle index e520157..84d5907 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -21,7 +21,7 @@ task fatCapsule(type: FatCapsule) { } dependencies { - compile project(':domain') + compile project(':core') compile project(':networking') compile project(':repositories') compile project(':cryptography-bc') diff --git a/extensions/build.gradle b/extensions/build.gradle index c92eb96..d44f900 100644 --- a/extensions/build.gradle +++ b/extensions/build.gradle @@ -27,10 +27,10 @@ uploadArchives { } dependencies { - compile project(':domain') + compile project(':core') testCompile 'junit:junit:4.11' testCompile 'org.slf4j:slf4j-simple:1.7.12' testCompile 'org.mockito:mockito-core:1.10.19' - testCompile project(path: ':domain', configuration: 'testArtifacts') + testCompile project(path: ':core', configuration: 'testArtifacts') testCompile project(':cryptography-bc') } diff --git a/networking/build.gradle b/networking/build.gradle index 788bc4d..984f585 100644 --- a/networking/build.gradle +++ b/networking/build.gradle @@ -11,10 +11,10 @@ uploadArchives { } dependencies { - compile project(':domain') + compile project(':core') testCompile 'junit:junit:4.11' testCompile 'org.slf4j:slf4j-simple:1.7.12' testCompile 'org.mockito:mockito-core:1.10.19' - testCompile project(path: ':domain', configuration: 'testArtifacts') + testCompile project(path: ':core', configuration: 'testArtifacts') testCompile project(':cryptography-bc') } \ No newline at end of file diff --git a/repositories/build.gradle b/repositories/build.gradle index cfbc9ea..abb8651 100644 --- a/repositories/build.gradle +++ b/repositories/build.gradle @@ -2,7 +2,7 @@ uploadArchives { repositories { mavenDeployer { pom.project { - name 'Jabit Domain' + name 'Jabit Repositories' artifactId = 'jabit-repositories' description 'A Java implementation of the Bitmessage protocol. This contains JDBC implementations of the repositories.' } @@ -13,7 +13,7 @@ uploadArchives { sourceCompatibility = 1.8 dependencies { - compile project(':domain') + compile project(':core') compile 'org.flywaydb:flyway-core:3.2.1' testCompile 'junit:junit:4.12' testCompile 'com.h2database:h2:1.4.190' diff --git a/settings.gradle b/settings.gradle index 634c473..4caa813 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,6 @@ rootProject.name = 'Jabit' -include 'domain' +include 'core' include 'networking' diff --git a/wif/build.gradle b/wif/build.gradle index ef16682..93a0248 100644 --- a/wif/build.gradle +++ b/wif/build.gradle @@ -11,7 +11,7 @@ uploadArchives { } dependencies { - compile project(':domain') + compile project(':core') compile 'org.ini4j:ini4j:0.5.4' testCompile 'junit:junit:4.11' testCompile 'org.mockito:mockito-core:1.10.19' From 35077243b0a8f8ad83f39667c1dd983069940c28 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sun, 17 Jan 2016 07:13:29 +0100 Subject: [PATCH 10/54] Fixed synchronization --- .../java/ch/dissem/bitmessage/networking/Connection.java | 2 +- .../dissem/bitmessage/networking/NetworkHandlerTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 3155645..176517b 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -350,7 +350,7 @@ class Connection { send(new Version.Builder().defaults().addrFrom(host).addrRecv(node).build()); } while (state != DISCONNECTED) { - if (requestedObjects.isEmpty()) { + if (mode != SYNC && state == ACTIVE && requestedObjects.isEmpty()) { Thread.sleep(1000); } else { Thread.sleep(100); diff --git a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java index e850ffb..77cad46 100644 --- a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java +++ b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java @@ -94,7 +94,7 @@ public class NetworkHandlerTest { } while (node.isRunning()); } - @Test(timeout = 20_000) + @Test(timeout = 5_000) public void ensureNodesAreConnecting() { try { node.startup(); @@ -109,7 +109,7 @@ public class NetworkHandlerTest { } } - @Test(timeout = 10_000) + @Test(timeout = 5_000) public void ensureObjectsAreSynchronizedIfBothHaveObjects() throws Exception { peerInventory.init( "V4Pubkey.payload", @@ -128,7 +128,7 @@ public class NetworkHandlerTest { assertInventorySize(3, peerInventory); } - @Test(timeout = 10_000) + @Test(timeout = 5_000) public void ensureObjectsAreSynchronizedIfOnlyPeerHasObjects() throws Exception { peerInventory.init( "V4Pubkey.payload", @@ -145,7 +145,7 @@ public class NetworkHandlerTest { assertInventorySize(2, peerInventory); } - @Test(timeout = 10_000) + @Test(timeout = 5_000) public void ensureObjectsAreSynchronizedIfOnlyNodeHasObjects() throws Exception { peerInventory.init(); From e29310102f7805893cd5d95e25d0214ef2419082 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Tue, 19 Jan 2016 21:07:26 +0100 Subject: [PATCH 11/54] Updated UML diagram --- Bitmessage.uml | 1541 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 1261 insertions(+), 280 deletions(-) diff --git a/Bitmessage.uml b/Bitmessage.uml index 997ab34..598f220 100644 --- a/Bitmessage.uml +++ b/Bitmessage.uml @@ -3,325 +3,1306 @@ <ID>JAVA</ID> <OriginalElement /> <nodes> - <node x="1022.2999999999998" y="1241.5">ch.dissem.bitmessage.entity.Encrypted</node> - <node x="3262.195225464191" y="1703.088063660477">ch.dissem.bitmessage.ports.Inventory</node> - <node x="953.8409281305113" y="1454.0">ch.dissem.bitmessage.entity.payload.V4Pubkey</node> - <node x="3639.070833333333" y="552.0">ch.dissem.bitmessage.entity.Addr</node> - <node x="61.3125" y="574.5">ch.dissem.bitmessage.entity.payload.Broadcast</node> - <node x="1759.485339506172" y="1777.0">ch.dissem.bitmessage.factory.Factory</node> - <node x="3809.027006172839" y="132.0">ch.dissem.bitmessage.entity.valueobject.NetworkAddress</node> - <node x="1252.7999999999997" y="840.5">ch.dissem.bitmessage.entity.payload.V2Pubkey</node> - <node x="2422.195225464191" y="1725.088063660477">ch.dissem.bitmessage.ports.AddressRepository</node> - <node x="1237.2999999999997" y="1174.5">ch.dissem.bitmessage.entity.payload.V3Pubkey</node> - <node x="950.1249999999999" y="198.0">ch.dissem.bitmessage.entity.payload.ObjectPayload</node> - <node x="3265.695833333333" y="242.5">ch.dissem.bitmessage.entity.MessagePayload</node> - <node x="2347.852579365079" y="540.5">ch.dissem.bitmessage.entity.NetworkMessage</node> - <node x="3910.070833333333" y="475.0">ch.dissem.bitmessage.entity.Version</node> - <node x="3278.195225464191" y="1915.0880636604768">ch.dissem.bitmessage.BitmessageContext</node> - <node x="3995.195225464191" y="1758.088063660477">ch.dissem.bitmessage.ports.ProofOfWorkEngine</node> - <node x="1602.2999999999997" y="1153.0">ch.dissem.bitmessage.entity.BitmessageAddress</node> - <node x="217.375" y="1205.3604060913706">ch.dissem.bitmessage.entity.payload.UnencryptedMessage</node> - <node x="2394.152006172839" y="907.5">ch.dissem.bitmessage.factory.V3MessageFactory</node> - <node x="703.2999999999997" y="1230.5">ch.dissem.bitmessage.entity.payload.CryptoBox</node> - <node x="2841.277006172839" y="530.0">ch.dissem.bitmessage.entity.valueobject.InventoryVector</node> - <node x="40.0" y="1821.0">ch.dissem.bitmessage.entity.payload.V5Broadcast</node> - <node x="2026.7485780423274" y="874.0">ch.dissem.bitmessage.entity.valueobject.PrivateKey</node> - <node x="4063.945225464191" y="2026.0880636604768">ch.dissem.bitmessage.ports.MultiThreadedPOWEngine</node> - <node x="3440.320833333333" y="896.0">ch.dissem.bitmessage.entity.Inv</node> - <node x="1508.9249999999997" y="518.5">ch.dissem.bitmessage.entity.payload.Pubkey</node> - <node x="236.3125" y="541.0">ch.dissem.bitmessage.entity.payload.GetPubkey</node> - <node x="2357.445833333333" y="0.0">ch.dissem.bitmessage.entity.Streamable</node> - <node x="4050.4279840848803" y="1283.5018567639252">ch.dissem.bitmessage.entity.payload.ObjectType</node> - <node x="2715.4985780423276" y="786.0">ch.dissem.bitmessage.entity.ObjectMessage</node> - <node x="1835.727579365079" y="519.0">ch.dissem.bitmessage.entity.payload.GenericPayload</node> - <node x="3709.195225464191" y="1736.088063660477">ch.dissem.bitmessage.ports.NetworkHandler</node> - <node x="2544.852579365079" y="563.0">ch.dissem.bitmessage.entity.VerAck</node> - <node x="3169.320833333333" y="896.0">ch.dissem.bitmessage.entity.GetData</node> - <node x="447.0" y="1487.0">ch.dissem.bitmessage.entity.payload.Msg</node> - <node x="2817.195225464191" y="1747.088063660477">ch.dissem.bitmessage.ports.NodeRegistry</node> - <node x="0.0" y="1498.0">ch.dissem.bitmessage.entity.payload.V4Broadcast</node> + <node x="1818.2000000000003" y="313.0">ch.dissem.bitmessage.entity.valueobject.Label.Type</node> + <node x="5324.841228070176" y="1368.0">ch.dissem.bitmessage.networking.Connection.WriterRunnable</node> + <node x="6921.341228070176" y="1368.0">ch.dissem.bitmessage.entity.valueobject.NetworkAddress</node> + <node x="6705.341228070176" y="1368.0">ch.dissem.bitmessage.factory.V3MessageFactory</node> + <node x="3281.2958333333336" y="695.0">ch.dissem.bitmessage.ProofOfWorkService</node> + <node x="4125.573772883003" y="1368.0">ch.dissem.bitmessage.cryptography.bc.BouncyCryptography</node> + <node x="5470.131996533652" y="1127.0">ch.dissem.bitmessage.entity.ObjectMessage</node> + <node x="3970.5737728830027" y="1368.0">ch.dissem.bitmessage.repository.JdbcHelper</node> + <node x="4642.726882897288" y="936.0">ch.dissem.bitmessage.exception.InsufficientProofOfWorkException</node> + <node x="1314.3071062163358" y="313.0">ch.dissem.bitmessage.utils.AccessCounter</node> + <node x="3075.4000000000005" y="695.0">ch.dissem.bitmessage.MessageCallback</node> + <node x="6475.841228070176" y="1368.0">ch.dissem.bitmessage.networking.Connection.ReaderRunnable</node> + <node x="700.8568660309461" y="313.0">ch.dissem.bitmessage.entity.payload.V2Pubkey</node> + <node x="793.4083333333338" y="1127.0">ch.dissem.bitmessage.extensions.CryptoCustomMessage.SignatureCheckingInputStream</node> + <node x="1647.183132897289" y="695.0">ch.dissem.bitmessage.entity.Plaintext</node> + <node x="3045.735216230623" y="936.0">ch.dissem.bitmessage.InternalContext</node> + <node x="10.5" y="695.0">ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest</node> + <node x="2730.8810495639564" y="936.0">ch.dissem.bitmessage.ports.NetworkHandler.MessageListener</node> + <node x="1183.8250000000003" y="936.0">ch.dissem.bitmessage.entity.payload.Msg</node> + <node x="5873.841228070176" y="1368.0">ch.dissem.bitmessage.networking.Connection.Mode</node> + <node x="3620.073772883002" y="695.0">ch.dissem.bitmessage.utils.Singleton</node> + <node x="3582.948772883002" y="444.0">ch.dissem.bitmessage.ports.Cryptography</node> + <node x="4962.31390446195" y="444.0">ch.dissem.bitmessage.ports.ProofOfWorkRepository</node> + <node x="3599.601882897289" y="1539.0">ch.dissem.bitmessage.repository.JdbcMessageRepository</node> + <node x="4301.179822446958" y="1539.0">ch.dissem.bitmessage.repository.JdbcInventory</node> + <node x="5719.653728070176" y="1127.0">ch.dissem.bitmessage.exception.NodeException</node> + <node x="2292.7333333333336" y="695.0">ch.dissem.bitmessage.entity.payload.GetPubkey</node> + <node x="6192.841228070176" y="1127.0">ch.dissem.bitmessage.entity.GetData</node> + <node x="7132.716228070176" y="1539.0">ch.dissem.bitmessage.entity.Addr</node> + <node x="3867.573772883002" y="444.0">ch.dissem.bitmessage.InternalContext.ContextHolder</node> + <node x="1294.4083333333338" y="1127.0">ch.dissem.bitmessage.entity.CustomMessage</node> + <node x="1592.8250000000003" y="1127.0">ch.dissem.bitmessage.DefaultMessageListener</node> + <node x="2645.7333333333336" y="695.0">ch.dissem.bitmessage.ports.MultiThreadedPOWEngine.Worker</node> + <node x="2444.7333333333336" y="695.0">ch.dissem.bitmessage.ports.MultiThreadedPOWEngine.CallbackWrapper</node> + <node x="2771.7333333333336" y="695.0">ch.dissem.bitmessage.ports.CustomCommandHandler</node> + <node x="4469.976882897288" y="1127.0">ch.dissem.bitmessage.utils.Property</node> + <node x="318.09979956395637" y="1539.0">ch.dissem.bitmessage.repository.JdbcAddressRepository</node> + <node x="1564.5750000000003" y="1368.0">ch.dissem.bitmessage.BitmessageContext</node> + <node x="6582.341228070176" y="1127.0">ch.dissem.bitmessage.entity.VerAck</node> + <node x="3970.0737728830027" y="1127.0">ch.dissem.bitmessage.repository.JdbcConfig</node> + <node x="6639.341228070176" y="1539.0">ch.dissem.bitmessage.ports.MemoryNodeRegistry</node> + <node x="5551.954714912281" y="444.0">ch.dissem.bitmessage.entity.valueobject.InventoryVector</node> + <node x="327.2000000000003" y="936.0">ch.dissem.bitmessage.entity.payload.V4Pubkey</node> + <node x="57.5" y="1368.0">ch.dissem.bitmessage.entity.payload.V5Broadcast</node> + <node x="6475.841228070176" y="1127.0">ch.dissem.bitmessage.entity.Inv</node> + <node x="2074.7333333333336" y="695.0">ch.dissem.bitmessage.ports.AddressRepository</node> + <node x="904.8568660309461" y="222.0">ch.dissem.bitmessage.entity.payload.Pubkey</node> + <node x="56.375" y="444.0">ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest.Request</node> + <node x="3168.5839493642798" y="444.0">ch.dissem.bitmessage.ports.MessageRepository</node> + <node x="1643.0750000000003" y="1539.0">ch.dissem.bitmessage.wif.WifExporter</node> + <node x="1063.731866030946" y="313.0">ch.dissem.bitmessage.entity.valueobject.PrivateKey</node> + <node x="2357.5893828972894" y="936.0">ch.dissem.bitmessage.ports.MultiThreadedPOWEngine</node> + <node x="671.4083333333338" y="1127.0">ch.dissem.bitmessage.extensions.CryptoCustomMessage.Reader</node> + <node x="249.5" y="444.0">ch.dissem.bitmessage.entity.payload.V3Pubkey</node> + <node x="846.8568660309461" y="313.0">ch.dissem.bitmessage.entity.payload.Pubkey.Feature</node> + <node x="3762.073772883002" y="695.0">ch.dissem.bitmessage.ports.NetworkHandler</node> + <node x="4604.976882897288" y="1127.0">ch.dissem.bitmessage.ports.AbstractCryptography</node> + <node x="4360.573772883003" y="1368.0">ch.dissem.bitmessage.cryptography.sc.SpongyCryptography</node> + <node x="4257.198772883003" y="444.0">ch.dissem.bitmessage.ports.SimplePOWEngine</node> + <node x="5279.360964912281" y="695.0">ch.dissem.bitmessage.ports.NodeRegistry</node> + <node x="1447.9083333333335" y="1539.0">ch.dissem.bitmessage.wif.WifImporter</node> + <node x="6323.841228070176" y="1127.0">ch.dissem.bitmessage.entity.MessagePayload.Command</node> + <node x="5988.841228070176" y="1127.0">ch.dissem.bitmessage.entity.NetworkMessage</node> + <node x="1722.7833333333335" y="936.0">ch.dissem.bitmessage.entity.Plaintext.Encoding</node> + <node x="1680.9187500000003" y="444.0">ch.dissem.bitmessage.entity.Plaintext.Type</node> + <node x="551.3250000000003" y="695.0">ch.dissem.bitmessage.entity.payload.CryptoBox</node> + <node x="50.59979956395637" y="1539.0">ch.dissem.bitmessage.factory.Factory</node> + <node x="5513.841228070176" y="1368.0">ch.dissem.bitmessage.networking.DefaultNetworkHandler</node> + <node x="4568.448772883003" y="1539.0">ch.dissem.bitmessage.repository.JdbcProofOfWorkRepository</node> + <node x="1007.5333333333338" y="444.0">ch.dissem.bitmessage.entity.BitmessageAddress</node> + <node x="5766.841228070176" y="1368.0">ch.dissem.bitmessage.networking.Connection.State</node> + <node x="10.5" y="1127.0">ch.dissem.bitmessage.entity.payload.V4Broadcast</node> + <node x="405.3250000000003" y="695.0">ch.dissem.bitmessage.entity.Encrypted</node> + <node x="5808.4446460551835" y="1539.0">ch.dissem.bitmessage.networking.Connection</node> + <node x="2882.840439549669" y="313.0">ch.dissem.bitmessage.ports.ProofOfWorkEngine</node> + <node x="6308.341228070176" y="936.0">ch.dissem.bitmessage.entity.MessagePayload</node> + <node x="2082.307106216336" y="0.0">ch.dissem.bitmessage.entity.Streamable</node> + <node x="1595.7833333333335" y="936.0">ch.dissem.bitmessage.BitmessageContext.Listener</node> + <node x="4182.420873082679" y="695.0">ch.dissem.bitmessage.ports.Inventory</node> + <node x="2507.2333333333336" y="444.0">ch.dissem.bitmessage.ports.ProofOfWorkEngine.Callback</node> + <node x="6757.674561403509" y="222.0">ch.dissem.bitmessage.entity.payload.GenericPayload</node> + <node x="7006.716228070176" y="1539.0">ch.dissem.bitmessage.entity.Version</node> + <node x="2140.6125397493456" y="121.0">ch.dissem.bitmessage.entity.payload.ObjectPayload</node> + <node x="480.5571062163358" y="936.0">ch.dissem.bitmessage.entity.payload.Broadcast</node> + <node x="693.4361111111111" y="1368.0">ch.dissem.bitmessage.extensions.CryptoCustomMessage</node> + <node x="531.8071062163353" y="444.0">ch.dissem.bitmessage.exception.DecryptionFailedException</node> + <node x="1551.1583333333335" y="444.0">ch.dissem.bitmessage.entity.Plaintext.Status</node> + <node x="1106.4083333333338" y="695.0">ch.dissem.bitmessage.entity.PlaintextHolder</node> + <node x="1817.4500000000003" y="444.0">ch.dissem.bitmessage.entity.valueobject.Label</node> + <node x="4736.948772883003" y="1368.0">ch.dissem.bitmessage.ports.ProofOfWorkRepository.Item</node> </nodes> <notes /> <edges> - <edge source="ch.dissem.bitmessage.entity.GetData" target="ch.dissem.bitmessage.entity.MessagePayload"> - <point x="62.75" y="-48.5" /> - <point x="0.0" y="26.0" /> + <edge source="ch.dissem.bitmessage.repository.JdbcProofOfWorkRepository" target="ch.dissem.bitmessage.ports.ProofOfWorkRepository"> + <point x="0.0" y="-20.5" /> + <point x="4706.448772883003" y="1519.0" /> + <point x="4726.448772883003" y="1519.0" /> + <point x="4726.448772883003" y="1298.0" /> + <point x="5247.735964912281" y="1298.0" /> + <point x="5247.735964912281" y="625.0" /> + <point x="5112.31390446195" y="625.0" /> + <point x="30.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.valueobject.PrivateKey" target="ch.dissem.bitmessage.entity.payload.Pubkey"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.NetworkHandler"> + <point x="55.666666666666515" y="-20.5" /> + <point x="3184.9018828972894" y="896.0" /> + <point x="3850.073772883002" y="896.0" /> + <point x="0.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.valueobject.NetworkAddress" target="ch.dissem.bitmessage.entity.Streamable"> - <point x="0.0" y="-136.5" /> - <point x="4023.527006172839" y="92.0" /> - <point x="2555.258333333333" y="92.0" /> - <point x="92.3125" y="26.0" /> + <edge source="ch.dissem.bitmessage.extensions.CryptoCustomMessage" target="ch.dissem.bitmessage.entity.BitmessageAddress"> + <point x="77.66666666666652" y="-20.5" /> + <point x="887.6027777777776" y="1338.0" /> + <point x="1283.9083333333338" y="1338.0" /> + <point x="1283.9083333333338" y="675.0" /> + <point x="1121.1583333333338" y="675.0" /> + <point x="12.625" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.repository.JdbcMessageRepository" target="ch.dissem.bitmessage.repository.JdbcHelper"> + <point x="99.58333333333348" y="-20.5" /> + <point x="3818.6852162306222" y="1519.0" /> + <point x="4021.1987728830027" y="1519.0" /> + <point x="-16.875" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.NetworkMessage" target="ch.dissem.bitmessage.entity.MessagePayload"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.MessageRepository"> + <point x="-33.40000000000009" y="-20.5" /> + <point x="3095.835216230623" y="826.0" /> + <point x="3064.9000000000005" y="826.0" /> + <point x="3064.9000000000005" y="625.0" /> + <point x="3202.417282697613" y="625.0" /> + <point x="-67.66666666666652" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.payload.Broadcast" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> - <point x="0.0" y="-26.0" /> - <point x="138.8125" y="435.0" /> - <point x="980.7083333333334" y="435.0" /> - <point x="-152.91666666666652" y="70.5" /> + <edge source="ch.dissem.bitmessage.cryptography.sc.SpongyCryptography" target="ch.dissem.bitmessage.ports.AbstractCryptography"> + <point x="0.0" y="-20.5" /> + <point x="4470.073772883003" y="1258.0" /> + <point x="4772.226882897288" y="1258.0" /> + <point x="55.75" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.payload.V5Broadcast" target="ch.dissem.bitmessage.entity.payload.V4Broadcast"> - <point x="0.0" y="-48.5" /> - <point x="0.0" y="92.5" /> - </edge> - <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.ports.NetworkHandler"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.Addr" target="ch.dissem.bitmessage.entity.MessagePayload"> - <point x="-62.75" y="-48.5" /> - <point x="3701.820833333333" y="445.0" /> - <point x="3410.2672619047617" y="445.0" /> - <point x="52.57142857142867" y="26.0" /> - </edge> - <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.entity.VerAck"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine"> - <point x="0.0" y="-26.0" /> - <point x="68.75" y="26.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.valueobject.PrivateKey" target="ch.dissem.bitmessage.entity.Streamable"> - <point x="78.25" y="-70.5" /> - <point x="2261.4985780423276" y="766.0" /> - <point x="2282.227579365079" y="766.0" /> - <point x="2282.227579365079" y="102.0" /> - <point x="2449.758333333333" y="102.0" /> - <point x="-13.1875" y="26.0" /> - </edge> - <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.entity.payload.V4Pubkey"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.VerAck" target="ch.dissem.bitmessage.entity.MessagePayload"> - <point x="0.0" y="-37.5" /> - <point x="2660.352579365079" y="445.0" /> - <point x="3305.1244047619048" y="445.0" /> - <point x="-52.571428571428555" y="26.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.V4Pubkey" target="ch.dissem.bitmessage.entity.payload.CryptoBox"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.Msg" target="ch.dissem.bitmessage.entity.payload.UnencryptedMessage"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.MessagePayload" target="ch.dissem.bitmessage.entity.Streamable"> - <point x="0.0" y="-26.0" /> - <point x="3357.695833333333" y="102.0" /> - <point x="2528.883333333333" y="102.0" /> - <point x="65.9375" y="26.0" /> - </edge> - <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.entity.BitmessageAddress"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.ports.Inventory"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.V4Broadcast" target="ch.dissem.bitmessage.entity.payload.UnencryptedMessage"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.valueobject.InventoryVector" target="ch.dissem.bitmessage.entity.Streamable"> - <point x="0.0" y="-70.5" /> - <point x="2980.277006172839" y="425.0" /> - <point x="2940.790244708994" y="425.0" /> - <point x="2940.790244708994" y="112.0" /> - <point x="2502.508333333333" y="112.0" /> - <point x="39.5625" y="26.0" /> - </edge> - <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.ports.AddressRepository"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.ObjectPayload" target="ch.dissem.bitmessage.entity.Streamable"> - <point x="0.0" y="-70.5" /> - <point x="1133.625" y="92.0" /> - <point x="2423.383333333333" y="92.0" /> - <point x="-39.5625" y="26.0" /> + <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.exception.NodeException"> + <point x="-81.66666666666697" y="-20.5" /> + <point x="6721.674561403509" y="1328.0" /> + <point x="5865.778728070176" y="1328.0" /> + <point x="62.625" y="20.5" /> </edge> <edge source="ch.dissem.bitmessage.entity.payload.V4Pubkey" target="ch.dissem.bitmessage.entity.payload.V3Pubkey"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.V2Pubkey" target="ch.dissem.bitmessage.entity.payload.Pubkey"> - <point x="0.0" y="-104.0" /> - <point x="1409.2999999999997" y="766.0" /> - <point x="1545.5499999999997" y="766.0" /> - <point x="-109.875" y="82.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.V3Pubkey" target="ch.dissem.bitmessage.entity.payload.V2Pubkey"> - <point x="0.0" y="-104.0" /> - <point x="0.0" y="104.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.V4Broadcast" target="ch.dissem.bitmessage.entity.payload.Broadcast"> - <point x="-106.75" y="-92.5" /> - <point x="106.75" y="1434.0" /> - <point x="138.8125" y="1434.0" /> - <point x="0.0" y="26.0" /> + <point x="-50.40000000000009" y="-20.5" /> + <point x="339.8000000000002" y="916.0" /> + <point x="312.5" y="916.0" /> + <point x="0.0" y="20.5" /> </edge> <edge source="ch.dissem.bitmessage.entity.payload.V4Pubkey" target="ch.dissem.bitmessage.entity.Encrypted"> - <point x="0.0" y="-136.5" /> - <point x="1199.3409281305112" y="1434.0" /> - <point x="1119.7999999999997" y="1434.0" /> - <point x="0.0" y="37.0" /> + <point x="0.0" y="-20.5" /> + <point x="390.2000000000003" y="816.0" /> + <point x="426.3250000000003" y="816.0" /> + <point x="-42.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.payload.CryptoBox" target="ch.dissem.bitmessage.entity.Streamable"> - <point x="0.0" y="-48.0" /> - <point x="852.7999999999997" y="1123.0" /> - <point x="50.8125" y="1123.0" /> - <point x="50.8125" y="82.0" /> - <point x="2397.008333333333" y="82.0" /> - <point x="-65.9375" y="26.0" /> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.entity.valueobject.NetworkAddress"> + <point x="64.89473684210498" y="-20.5" /> + <point x="5941.8393828972885" y="1509.0" /> + <point x="6943.716228070176" y="1509.0" /> + <point x="-67.125" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.entity.valueobject.PrivateKey"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.repository.JdbcInventory" target="ch.dissem.bitmessage.ports.Inventory"> + <point x="-19.75" y="-20.5" /> + <point x="4360.429822446958" y="1499.0" /> + <point x="4590.073772883003" y="1499.0" /> + <point x="4590.073772883003" y="1268.0" /> + <point x="5154.673464912281" y="1268.0" /> + <point x="5154.673464912281" y="906.0" /> + <point x="4273.920873082679" y="906.0" /> + <point x="30.5" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.BitmessageAddress" target="ch.dissem.bitmessage.entity.valueobject.PrivateKey"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.entity.MessagePayload" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="0.0" y="-20.5" /> + <point x="6398.341228070176" y="71.0" /> + <point x="2195.6404395496693" y="71.0" /> + <point x="45.333333333333485" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.AddressRepository"> + <point x="-77.9333333333334" y="-20.5" /> + <point x="3051.3018828972895" y="866.0" /> + <point x="2223.2333333333336" y="866.0" /> + <point x="49.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection.Mode" target="ch.dissem.bitmessage.networking.Connection"> + <point x="23.5" y="20.5" /> + <point x="5944.341228070176" y="1439.0" /> + <point x="5891.365698686763" y="1439.0" /> + <point x="14.421052631579187" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.utils.AccessCounter"> + <point x="49.0" y="-20.5" /> + <point x="6852.341228070176" y="1348.0" /> + <point x="6830.674561403509" y="1348.0" /> + <point x="6830.674561403509" y="384.0" /> + <point x="1456.9321062163358" y="384.0" /> + <point x="61.125" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.entity.payload.V4Broadcast"> + <point x="-26.25" y="-20.5" /> + <point x="76.84979956395637" y="1509.0" /> + <point x="47.0" y="1509.0" /> + <point x="-36.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcMessageRepository" target="ch.dissem.bitmessage.InternalContext"> + <point x="-59.75" y="-20.5" /> + <point x="3659.351882897289" y="1489.0" /> + <point x="3129.235216230623" y="1489.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.CustomCommandHandler"> + <point x="-55.666666666666515" y="-20.5" /> + <point x="3073.5685495639564" y="846.0" /> + <point x="2899.2333333333336" y="846.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine" target="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine.CallbackWrapper"> + <point x="-102.0" y="-20.5" /> + <point x="2383.0893828972894" y="876.0" /> + <point x="2489.9833333333336" y="876.0" /> + <point x="-45.25" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Msg" target="ch.dissem.bitmessage.entity.PlaintextHolder"> + <point x="6.8333333333332575" y="-20.5" /> + <point x="41.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection.WriterRunnable" target="ch.dissem.bitmessage.networking.Connection"> + <point x="56.33333333333303" y="20.5" /> + <point x="5465.674561403509" y="1479.0" /> + <point x="5840.892014476236" y="1479.0" /> + <point x="-36.05263157894751" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.InternalContext"> + <point x="54.0" y="-20.5" /> + <point x="1717.5750000000003" y="1218.0" /> + <point x="1859.3250000000003" y="1218.0" /> + <point x="1859.3250000000003" y="1057.0" /> + <point x="3081.520930516337" y="1057.0" /> + <point x="-47.71428571428578" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext" target="ch.dissem.bitmessage.entity.BitmessageAddress"> + <point x="-49.4375" y="-20.5" /> + <point x="1654.245632897289" y="645.0" /> + <point x="1196.9083333333338" y="645.0" /> + <point x="88.375" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.V5Broadcast" target="ch.dissem.bitmessage.entity.payload.V4Broadcast"> + <point x="0.0" y="-20.5" /> + <point x="130.5" y="1348.0" /> + <point x="120.0" y="1348.0" /> + <point x="36.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.CustomMessage" target="ch.dissem.bitmessage.entity.MessagePayload"> + <point x="44.75" y="-20.5" /> + <point x="1428.6583333333338" y="1077.0" /> + <point x="6317.341228070176" y="1077.0" /> + <point x="-81.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.Cryptography"> + <point x="-11.133333333333212" y="-20.5" /> + <point x="3118.1018828972897" y="826.0" /> + <point x="3270.7958333333336" y="826.0" /> + <point x="3270.7958333333336" y="575.0" /> + <point x="3602.573772883002" y="575.0" /> + <point x="-58.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.DefaultMessageListener" target="ch.dissem.bitmessage.ports.NetworkHandler.MessageListener"> + <point x="29.25" y="-20.5" /> + <point x="1739.0750000000003" y="1027.0" /> + <point x="2760.3810495639564" y="1027.0" /> + <point x="-59.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.valueobject.NetworkAddress" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="0.0" y="-20.5" /> + <point x="7010.841228070176" y="61.0" /> + <point x="2210.75155066078" y="61.0" /> + <point x="60.44444444444434" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Broadcast" target="ch.dissem.bitmessage.entity.PlaintextHolder"> + <point x="31.25" y="-20.5" /> + <point x="574.3071062163358" y="866.0" /> + <point x="1148.1583333333338" y="866.0" /> + <point x="-41.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.CryptoCustomMessage" target="ch.dissem.bitmessage.entity.payload.CryptoBox"> + <point x="-77.66666666666652" y="-20.5" /> + <point x="732.2694444444446" y="1338.0" /> + <point x="660.9083333333338" y="1338.0" /> + <point x="660.9083333333338" y="846.0" /> + <point x="640.7000000000003" y="846.0" /> + <point x="24.375" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcAddressRepository" target="ch.dissem.bitmessage.entity.payload.V4Pubkey"> + <point x="-29.25" y="-20.5" /> + <point x="405.84979956395637" y="1489.0" /> + <point x="421.7000000000003" y="1489.0" /> + <point x="31.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcProofOfWorkRepository" target="ch.dissem.bitmessage.repository.JdbcHelper"> + <point x="-92.0" y="-20.5" /> + <point x="4614.448772883003" y="1489.0" /> + <point x="4088.6987728830027" y="1489.0" /> + <point x="50.625" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.NodeRegistry"> + <point x="77.9333333333334" y="-20.5" /> + <point x="3207.1685495639563" y="916.0" /> + <point x="5318.110964912281" y="916.0" /> + <point x="-38.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection.ReaderRunnable" target="ch.dissem.bitmessage.entity.VerAck"> + <point x="44.0" y="-20.5" /> + <point x="-25.5" y="20.5" /> </edge> <edge source="ch.dissem.bitmessage.entity.ObjectMessage" target="ch.dissem.bitmessage.entity.MessagePayload"> - <point x="141.33333333333326" y="-158.5" /> - <point x="3068.8319113756606" y="766.0" /> - <point x="3242.277006172839" y="766.0" /> - <point x="3242.277006172839" y="455.0" /> - <point x="3331.410119047619" y="455.0" /> - <point x="-26.28571428571422" y="26.0" /> + <point x="56.33333333333303" y="-20.5" /> + <point x="5610.9653298669855" y="1087.0" /> + <point x="6335.341228070176" y="1087.0" /> + <point x="-63.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.payload.GetPubkey" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> - <point x="0.0" y="-59.5" /> - <point x="432.3125" y="445.0" /> - <point x="1041.875" y="445.0" /> - <point x="-91.75" y="70.5" /> + <edge source="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine.Worker" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine.Callback"> + <point x="0.0" y="-20.5" /> + <point x="2698.2333333333336" y="615.0" /> + <point x="2577.2333333333336" y="615.0" /> + <point x="14.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.entity.payload.GenericPayload"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.DefaultMessageListener"> + <point x="0.0" y="-20.5" /> + <point x="1663.5750000000003" y="1188.0" /> + <point x="1709.8250000000003" y="1188.0" /> + <point x="0.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.ObjectMessage" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.networking.Connection.Mode"> + <point x="7.210526315789139" y="-20.5" /> + <point x="5884.155172370973" y="1429.0" /> + <point x="5897.341228070176" y="1429.0" /> + <point x="-23.5" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.GetData" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.Inventory"> + <point x="66.80000000000018" y="-20.5" /> + <point x="3196.035216230623" y="906.0" /> + <point x="4212.920873082679" y="906.0" /> + <point x="-30.5" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.payload.Msg" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> - <point x="-49.5" y="-103.5" /> - <point x="595.5" y="1434.0" /> - <point x="638.8125" y="1434.0" /> - <point x="638.8125" y="455.0" /> - <point x="1103.0416666666665" y="455.0" /> - <point x="-30.583333333333485" y="70.5" /> + <edge source="ch.dissem.bitmessage.ProofOfWorkService" target="ch.dissem.bitmessage.ports.MessageRepository"> + <point x="-41.80000000000018" y="-20.5" /> + <point x="3343.9958333333334" y="555.0" /> + <point x="3270.0839493642798" y="555.0" /> + <point x="0.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.payload.Pubkey" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> - <point x="0.0" y="-82.0" /> - <point x="1655.4249999999997" y="455.0" /> - <point x="1164.2083333333335" y="455.0" /> - <point x="30.583333333333485" y="70.5" /> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.networking.Connection.WriterRunnable"> + <point x="-43.26315789473665" y="-20.5" /> + <point x="5833.681488160447" y="1489.0" /> + <point x="5409.341228070176" y="1489.0" /> + <point x="0.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.entity.Version" target="ch.dissem.bitmessage.entity.MessagePayload"> - <point x="-97.75" y="-125.5" /> - <point x="4007.820833333333" y="435.0" /> - <point x="3436.5529761904763" y="435.0" /> - <point x="78.85714285714289" y="26.0" /> - </edge> - <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.entity.NetworkMessage"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.ObjectMessage" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.UnencryptedMessage" target="ch.dissem.bitmessage.entity.Streamable"> - <point x="0.0" y="-70.5" /> - <point x="408.375" y="1133.0" /> - <point x="39.8125" y="1133.0" /> - <point x="39.8125" y="72.0" /> - <point x="2370.633333333333" y="72.0" /> - <point x="-92.3125" y="26.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.Addr" target="ch.dissem.bitmessage.entity.valueobject.NetworkAddress"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.Msg" target="ch.dissem.bitmessage.entity.payload.CryptoBox"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.GenericPayload" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> - <point x="0.0" y="-81.5" /> - <point x="2048.227579365079" y="445.0" /> - <point x="1225.375" y="445.0" /> - <point x="91.75" y="70.5" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.payload.V4Pubkey" target="ch.dissem.bitmessage.entity.payload.Pubkey"> - <point x="196.4000000000001" y="-136.5" /> - <point x="1395.7409281305113" y="1434.0" /> - <point x="1591.7999999999997" y="1434.0" /> - <point x="1591.7999999999997" y="766.0" /> - <point x="1618.7999999999997" y="766.0" /> - <point x="-36.625" y="82.0" /> - </edge> - <edge source="ch.dissem.bitmessage.entity.NetworkMessage" target="ch.dissem.bitmessage.entity.Streamable"> - <point x="-44.25" y="-60.0" /> - <point x="2392.102579365079" y="112.0" /> - <point x="2476.133333333333" y="112.0" /> - <point x="13.1875" y="26.0" /> + <edge source="ch.dissem.bitmessage.entity.payload.Broadcast" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> + <point x="-52.083333333333485" y="-20.5" /> + <point x="490.9737728830023" y="796.0" /> + <point x="239.0" y="796.0" /> + <point x="239.0" y="182.0" /> + <point x="2154.1125397493456" y="182.0" /> + <point x="-67.5" y="20.5" /> </edge> <edge source="ch.dissem.bitmessage.entity.Version" target="ch.dissem.bitmessage.entity.valueobject.NetworkAddress"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <point x="-26.5" y="-20.5" /> + <point x="22.375" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.valueobject.InventoryVector" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="0.0" y="-20.5" /> + <point x="5638.454714912281" y="91.0" /> + <point x="2165.418217327447" y="91.0" /> + <point x="15.111111111111313" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcAddressRepository" target="ch.dissem.bitmessage.repository.JdbcHelper"> + <point x="87.75" y="-20.5" /> + <point x="522.8497995639564" y="1509.0" /> + <point x="3987.4487728830027" y="1509.0" /> + <point x="-50.625" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.NetworkMessage" target="ch.dissem.bitmessage.entity.MessagePayload"> + <point x="46.0" y="-20.5" /> + <point x="6126.841228070176" y="1097.0" /> + <point x="6353.341228070176" y="1097.0" /> + <point x="-45.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext" target="ch.dissem.bitmessage.entity.Plaintext.Type"> + <point x="-7.0625" y="-20.5" /> + <point x="1696.620632897289" y="675.0" /> + <point x="1702.1687500000003" y="675.0" /> + <point x="-21.25" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> + <point x="16.33333333333303" y="-20.5" /> + <point x="6819.674561403509" y="505.0" /> + <point x="5717.091078548645" y="505.0" /> + <point x="78.63636363636397" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ProofOfWorkService" target="ch.dissem.bitmessage.ports.Cryptography"> + <point x="0.0" y="-20.5" /> + <point x="3385.7958333333336" y="585.0" /> + <point x="3641.823772883002" y="585.0" /> + <point x="-19.625" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest" target="ch.dissem.bitmessage.entity.BitmessageAddress"> + <point x="81.75" y="-20.5" /> + <point x="201.25" y="655.0" /> + <point x="1020.1583333333338" y="655.0" /> + <point x="-88.375" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.DefaultMessageListener" target="ch.dissem.bitmessage.BitmessageContext.Listener"> + <point x="-29.25" y="-20.5" /> + <point x="1680.5750000000003" y="1067.0" /> + <point x="1649.2833333333335" y="1067.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.utils.Property"> + <point x="90.0" y="-20.5" /> + <point x="1753.5750000000003" y="1238.0" /> + <point x="4498.726882897288" y="1238.0" /> + <point x="-28.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.utils.Singleton" target="ch.dissem.bitmessage.ports.Cryptography"> + <point x="0.0" y="-20.5" /> + <point x="19.625" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.ProofOfWorkRepository.Item" target="ch.dissem.bitmessage.ports.ProofOfWorkRepository"> + <point x="-20.75" y="-20.5" /> + <point x="4757.698772883003" y="1308.0" /> + <point x="5268.860964912281" y="1308.0" /> + <point x="5268.860964912281" y="615.0" /> + <point x="5172.31390446195" y="615.0" /> + <point x="90.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.MemoryNodeRegistry" target="ch.dissem.bitmessage.ports.NodeRegistry"> + <point x="-55.5" y="-20.5" /> + <point x="6694.841228070176" y="886.0" /> + <point x="5395.610964912281" y="886.0" /> + <point x="38.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ProofOfWorkService" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine.Callback"> + <point x="-83.59999999999991" y="-20.5" /> + <point x="3302.1958333333337" y="565.0" /> + <point x="2605.2333333333336" y="565.0" /> + <point x="42.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> + <point x="49.4375" y="-20.5" /> + <point x="1753.120632897289" y="635.0" /> + <point x="5559.818351275917" y="635.0" /> + <point x="-78.63636363636397" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.wif.WifImporter" target="ch.dissem.bitmessage.BitmessageContext"> + <point x="36.0" y="-20.5" /> + <point x="1555.9083333333335" y="1489.0" /> + <point x="1614.0750000000003" y="1489.0" /> + <point x="-49.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Addr" target="ch.dissem.bitmessage.entity.valueobject.NetworkAddress"> + <point x="-21.75" y="-20.5" /> + <point x="7154.466228070176" y="1509.0" /> + <point x="7077.966228070176" y="1509.0" /> + <point x="67.125" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcMessageRepository" target="ch.dissem.bitmessage.ports.MessageRepository"> + <point x="-19.916666666666515" y="-20.5" /> + <point x="3699.1852162306222" y="1479.0" /> + <point x="3609.573772883002" y="1479.0" /> + <point x="3609.573772883002" y="545.0" /> + <point x="3337.750616030946" y="545.0" /> + <point x="67.66666666666652" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Broadcast" target="ch.dissem.bitmessage.entity.Encrypted"> + <point x="-31.25" y="-20.5" /> + <point x="511.8071062163358" y="786.0" /> + <point x="468.3250000000003" y="786.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Msg" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> + <point x="34.166666666666515" y="-20.5" /> + <point x="1258.9916666666668" y="896.0" /> + <point x="1915.9500000000003" y="896.0" /> + <point x="1915.9500000000003" y="202.0" /> + <point x="2208.1125397493456" y="202.0" /> + <point x="-13.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection.ReaderRunnable" target="ch.dissem.bitmessage.networking.Connection"> + <point x="58.66666666666697" y="20.5" /> + <point x="6622.507894736843" y="1499.0" /> + <point x="5934.628856581499" y="1499.0" /> + <point x="57.68421052631584" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext" target="ch.dissem.bitmessage.entity.Plaintext.Status"> + <point x="-35.3125" y="-20.5" /> + <point x="1668.370632897289" y="635.0" /> + <point x="1575.1583333333335" y="635.0" /> + <point x="-24.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.DefaultNetworkHandler" target="ch.dissem.bitmessage.entity.NetworkMessage"> + <point x="101.9375" y="-20.5" /> + <point x="5732.278728070176" y="1348.0" /> + <point x="6019.507894736843" y="1348.0" /> + <point x="-61.33333333333303" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.valueobject.PrivateKey" target="ch.dissem.bitmessage.entity.payload.Pubkey"> + <point x="-32.0" y="-20.5" /> + <point x="1095.731866030946" y="283.0" /> + <point x="999.3568660309461" y="283.0" /> + <point x="42.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.cryptography.bc.BouncyCryptography" target="ch.dissem.bitmessage.ports.AbstractCryptography"> + <point x="0.0" y="-20.5" /> + <point x="4233.073772883003" y="1248.0" /> + <point x="4660.726882897288" y="1248.0" /> + <point x="-55.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.networking.DefaultNetworkHandler"> + <point x="-28.842105263158373" y="-20.5" /> + <point x="5848.102540792025" y="1469.0" /> + <point x="5552.674561403509" y="1469.0" /> + <point x="-77.66666666666697" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext.Encoding" target="ch.dissem.bitmessage.entity.Plaintext"> + <point x="0.0" y="-20.5" /> + <point x="1783.2833333333335" y="886.0" /> + <point x="1741.3497995639557" y="886.0" /> + <point x="37.66666666666674" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.DefaultMessageListener" target="ch.dissem.bitmessage.InternalContext"> + <point x="87.75" y="-20.5" /> + <point x="1797.5750000000003" y="1047.0" /> + <point x="3057.6637876591944" y="1047.0" /> + <point x="-71.57142857142844" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.AbstractCryptography" target="ch.dissem.bitmessage.exception.InsufficientProofOfWorkException"> + <point x="27.875" y="-20.5" /> + <point x="4744.351882897288" y="1057.0" /> + <point x="4800.726882897288" y="1057.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Broadcast" target="ch.dissem.bitmessage.entity.payload.CryptoBox"> + <point x="-10.416666666666629" y="-20.5" /> + <point x="532.6404395496693" y="846.0" /> + <point x="591.9500000000003" y="846.0" /> + <point x="-24.375" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcAddressRepository" target="ch.dissem.bitmessage.entity.BitmessageAddress"> + <point x="-87.75" y="-20.5" /> + <point x="347.34979956395637" y="1489.0" /> + <point x="272.0" y="1489.0" /> + <point x="272.0" y="675.0" /> + <point x="1070.6583333333338" y="675.0" /> + <point x="-37.875" y="20.5" /> </edge> <edge source="ch.dissem.bitmessage.entity.BitmessageAddress" target="ch.dissem.bitmessage.entity.payload.Pubkey"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <point x="-67.33333333333303" y="-20.5" /> + <point x="1041.2000000000007" y="384.0" /> + <point x="1053.231866030946" y="384.0" /> + <point x="1053.231866030946" y="293.0" /> + <point x="978.3568660309461" y="293.0" /> + <point x="21.0" y="20.5" /> </edge> - <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.ports.NodeRegistry"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <edge source="ch.dissem.bitmessage.entity.ObjectMessage" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> + <point x="0.0" y="-20.5" /> + <point x="5554.631996533652" y="1067.0" /> + <point x="5549.424411881978" y="1067.0" /> + <point x="5549.424411881978" y="675.0" /> + <point x="5622.727442185008" y="675.0" /> + <point x="-15.727272727272975" y="20.5" /> </edge> <edge source="ch.dissem.bitmessage.entity.Inv" target="ch.dissem.bitmessage.entity.MessagePayload"> - <point x="62.75" y="-48.5" /> - <point x="3628.570833333333" y="455.0" /> - <point x="3383.9815476190474" y="455.0" /> - <point x="26.28571428571422" y="26.0" /> + <point x="-17.75" y="-20.5" /> + <point x="6493.591228070176" y="1097.0" /> + <point x="6425.341228070176" y="1097.0" /> + <point x="27.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Pubkey.Feature" target="ch.dissem.bitmessage.entity.payload.Pubkey"> + <point x="0.0" y="-20.5" /> + <point x="899.3568660309461" y="293.0" /> + <point x="936.3568660309461" y="293.0" /> + <point x="-21.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest" target="ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest.Request"> + <point x="-27.25" y="-20.5" /> + <point x="92.25" y="675.0" /> + <point x="84.125" y="675.0" /> + <point x="-27.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext.Status" target="ch.dissem.bitmessage.entity.Plaintext"> + <point x="24.0" y="20.5" /> + <point x="1623.1583333333335" y="625.0" /> + <point x="1682.495632897289" y="625.0" /> + <point x="-21.1875" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.ports.NetworkHandler.MessageListener"> + <point x="36.0" y="-20.5" /> + <point x="1699.5750000000003" y="1208.0" /> + <point x="1848.3250000000003" y="1208.0" /> + <point x="1848.3250000000003" y="1037.0" /> + <point x="2819.3810495639564" y="1037.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcMessageRepository" target="ch.dissem.bitmessage.InternalContext.ContextHolder"> + <point x="19.916666666666515" y="-20.5" /> + <point x="3739.0185495639553" y="1489.0" /> + <point x="3948.573772883002" y="1489.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Version" target="ch.dissem.bitmessage.entity.MessagePayload"> + <point x="26.5" y="-20.5" /> + <point x="7086.216228070176" y="1519.0" /> + <point x="7110.841228070176" y="1519.0" /> + <point x="7110.841228070176" y="1077.0" /> + <point x="6461.341228070176" y="1077.0" /> + <point x="63.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.CustomMessage" target="ch.dissem.bitmessage.utils.AccessCounter"> + <point x="-44.75" y="-20.5" /> + <point x="1339.1583333333338" y="424.0" /> + <point x="1416.1821062163358" y="424.0" /> + <point x="20.375" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.valueobject.Label" target="ch.dissem.bitmessage.entity.valueobject.Label.Type"> + <point x="-22.0" y="-20.5" /> + <point x="-21.25" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcMessageRepository" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> + <point x="59.75" y="-20.5" /> + <point x="3778.851882897289" y="1499.0" /> + <point x="3959.573772883002" y="1499.0" /> + <point x="3959.573772883002" y="645.0" /> + <point x="5575.54562400319" y="645.0" /> + <point x="-62.90909090909099" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine.CallbackWrapper" target="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine"> + <point x="45.25" y="20.5" /> + <point x="2580.4833333333336" y="886.0" /> + <point x="2434.0893828972894" y="886.0" /> + <point x="-51.0" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Msg" target="ch.dissem.bitmessage.entity.Plaintext"> + <point x="20.5" y="-20.5" /> + <point x="1245.3250000000003" y="886.0" /> + <point x="1703.683132897289" y="886.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.entity.payload.GetPubkey"> + <point x="-36.0" y="-20.5" /> + <point x="1627.5750000000003" y="1318.0" /> + <point x="1562.6583333333335" y="1318.0" /> + <point x="1562.6583333333335" y="916.0" /> + <point x="2325.7333333333336" y="916.0" /> + <point x="-33.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.MemoryNodeRegistry" target="ch.dissem.bitmessage.entity.valueobject.NetworkAddress"> + <point x="55.5" y="-20.5" /> + <point x="6805.841228070176" y="1519.0" /> + <point x="6988.466228070176" y="1519.0" /> + <point x="-22.375" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext.Listener" target="ch.dissem.bitmessage.BitmessageContext"> + <point x="-35.66666666666674" y="20.5" /> + <point x="1613.6166666666668" y="1067.0" /> + <point x="1582.3250000000003" y="1067.0" /> + <point x="1582.3250000000003" y="1308.0" /> + <point x="1645.5750000000003" y="1308.0" /> + <point x="-18.0" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.VerAck" target="ch.dissem.bitmessage.entity.MessagePayload"> + <point x="0.0" y="-20.5" /> + <point x="6633.341228070176" y="1087.0" /> + <point x="6443.341228070176" y="1087.0" /> + <point x="45.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.entity.NetworkMessage"> + <point x="28.842105263157464" y="-20.5" /> + <point x="5905.786751318341" y="1459.0" /> + <point x="6080.841228070176" y="1459.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine.Worker" target="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine"> + <point x="26.25" y="20.5" /> + <point x="2724.4833333333336" y="906.0" /> + <point x="2536.0893828972894" y="906.0" /> + <point x="51.0" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcAddressRepository" target="ch.dissem.bitmessage.ports.AddressRepository"> + <point x="29.25" y="-20.5" /> + <point x="464.34979956395637" y="1489.0" /> + <point x="440.59979956395637" y="1489.0" /> + <point x="440.59979956395637" y="1067.0" /> + <point x="1551.6583333333335" y="1067.0" /> + <point x="1551.6583333333335" y="906.0" /> + <point x="2124.2333333333336" y="906.0" /> + <point x="-49.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext.Type" target="ch.dissem.bitmessage.entity.Plaintext"> + <point x="21.25" y="20.5" /> + <point x="1744.6687500000003" y="605.0" /> + <point x="1710.745632897289" y="605.0" /> + <point x="7.0625" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.AbstractCryptography" target="ch.dissem.bitmessage.InternalContext.ContextHolder"> + <point x="83.625" y="-20.5" /> + <point x="4800.101882897288" y="1067.0" /> + <point x="4969.226882897288" y="1067.0" /> + <point x="4969.226882897288" y="575.0" /> + <point x="3980.9737728830023" y="575.0" /> + <point x="32.40000000000009" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Msg" target="ch.dissem.bitmessage.entity.Encrypted"> + <point x="-34.16666666666674" y="-20.5" /> + <point x="1190.6583333333338" y="776.0" /> + <point x="510.3250000000003" y="776.0" /> + <point x="42.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.entity.valueobject.PrivateKey"> + <point x="-43.75" y="-20.5" /> + <point x="59.34979956395637" y="1519.0" /> + <point x="0.0" y="1519.0" /> + <point x="0.0" y="394.0" /> + <point x="1085.0651993642796" y="394.0" /> + <point x="-42.666666666666515" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.AbstractCryptography" target="ch.dissem.bitmessage.InternalContext"> + <point x="-83.625" y="-20.5" /> + <point x="4632.851882897288" y="1027.0" /> + <point x="3153.0923590877655" y="1027.0" /> + <point x="23.857142857142662" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.entity.BitmessageAddress"> + <point x="8.75" y="-20.5" /> + <point x="111.84979956395637" y="1479.0" /> + <point x="250.0" y="1479.0" /> + <point x="250.0" y="665.0" /> + <point x="1045.4083333333338" y="665.0" /> + <point x="-63.125" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.SimplePOWEngine" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine"> + <point x="0.0" y="-20.5" /> + <point x="4354.698772883003" y="424.0" /> + <point x="3063.965439549669" y="424.0" /> + <point x="77.625" y="20.5" /> </edge> <edge source="ch.dissem.bitmessage.entity.Inv" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> - <point x="0.0" y="0.0" /> - <point x="0.0" y="0.0" /> + <point x="17.75" y="-20.5" /> + <point x="6529.091228070176" y="515.0" /> + <point x="5701.363805821372" y="515.0" /> + <point x="62.90909090909099" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.GetData" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> + <point x="-27.75" y="-20.5" /> + <point x="6220.591228070176" y="525.0" /> + <point x="5685.636533094099" y="525.0" /> + <point x="47.18181818181802" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.DefaultNetworkHandler" target="ch.dissem.bitmessage.InternalContext"> + <point x="-72.8125" y="-20.5" /> + <point x="5557.528728070176" y="1208.0" /> + <point x="5423.9758960551835" y="1208.0" /> + <point x="5423.9758960551835" y="997.0" /> + <point x="3200.8066448020513" y="997.0" /> + <point x="71.57142857142844" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.MessagePayload.Command" target="ch.dissem.bitmessage.entity.MessagePayload"> + <point x="0.0" y="-20.5" /> + <point x="-9.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ProofOfWorkService" target="ch.dissem.bitmessage.InternalContext.ContextHolder"> + <point x="41.80000000000018" y="-20.5" /> + <point x="3427.5958333333338" y="595.0" /> + <point x="3883.773772883002" y="595.0" /> + <point x="-64.80000000000018" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcHelper" target="ch.dissem.bitmessage.repository.JdbcConfig"> + <point x="0.0" y="-20.5" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine.CallbackWrapper" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine.Callback"> + <point x="45.25" y="-20.5" /> + <point x="2580.4833333333336" y="625.0" /> + <point x="2549.2333333333336" y="625.0" /> + <point x="-14.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.ProofOfWorkEngine.Callback" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine"> + <point x="0.0" y="-20.5" /> + <point x="2563.2333333333336" y="414.0" /> + <point x="2908.715439549669" y="414.0" /> + <point x="-77.625" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.CryptoBox" target="ch.dissem.bitmessage.exception.DecryptionFailedException"> + <point x="0.0" y="-20.5" /> + <point x="616.3250000000003" y="635.0" /> + <point x="659.8071062163353" y="635.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="21.1875" y="-20.5" /> + <point x="1724.870632897289" y="615.0" /> + <point x="1776.4187500000003" y="615.0" /> + <point x="1776.4187500000003" y="101.0" /> + <point x="2135.1959951052245" y="101.0" /> + <point x="-15.111111111111313" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.networking.Connection.State"> + <point x="-7.210526315789139" y="-20.5" /> + <point x="5869.734119739394" y="1439.0" /> + <point x="5788.591228070176" y="1439.0" /> + <point x="-21.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcInventory" target="ch.dissem.bitmessage.repository.JdbcHelper"> + <point x="-59.25" y="-20.5" /> + <point x="4320.929822446958" y="1519.0" /> + <point x="4054.9487728830027" y="1519.0" /> + <point x="16.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine"> + <point x="102.0" y="-20.5" /> + <point x="2587.0893828972894" y="916.0" /> + <point x="2761.2333333333336" y="916.0" /> + <point x="2761.2333333333336" y="424.0" /> + <point x="2960.465439549669" y="424.0" /> + <point x="-25.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Addr" target="ch.dissem.bitmessage.entity.MessagePayload"> + <point x="21.75" y="-20.5" /> + <point x="7197.966228070176" y="1067.0" /> + <point x="6479.341228070176" y="1067.0" /> + <point x="81.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.DefaultNetworkHandler" target="ch.dissem.bitmessage.exception.NodeException"> + <point x="72.8125" y="-20.5" /> + <point x="5703.153728070176" y="1338.0" /> + <point x="5782.278728070176" y="1338.0" /> + <point x="-20.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.BitmessageAddress" target="ch.dissem.bitmessage.entity.valueobject.PrivateKey"> + <point x="0.0" y="-20.5" /> + <point x="1108.5333333333338" y="394.0" /> + <point x="1127.731866030946" y="394.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.GetData" target="ch.dissem.bitmessage.entity.MessagePayload"> + <point x="27.75" y="-20.5" /> + <point x="6276.091228070176" y="1107.0" /> + <point x="6371.341228070176" y="1107.0" /> + <point x="-27.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcInventory" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> + <point x="19.75" y="-20.5" /> + <point x="4399.929822446958" y="1509.0" /> + <point x="4601.073772883003" y="1509.0" /> + <point x="4601.073772883003" y="1278.0" /> + <point x="5165.673464912281" y="1278.0" /> + <point x="5165.673464912281" y="655.0" /> + <point x="5591.272896730463" y="655.0" /> + <point x="-47.18181818181802" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.ProofOfWorkRepository"> + <point x="44.5333333333333" y="-20.5" /> + <point x="3173.768549563956" y="876.0" /> + <point x="3579.340439549669" y="876.0" /> + <point x="3579.340439549669" y="625.0" /> + <point x="5052.31390446195" y="625.0" /> + <point x="-30.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.valueobject.PrivateKey" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="32.0" y="-20.5" /> + <point x="1159.731866030946" y="91.0" /> + <point x="2120.0848839941136" y="91.0" /> + <point x="-30.22222222222217" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.DefaultNetworkHandler" target="ch.dissem.bitmessage.networking.Connection"> + <point x="0.0" y="20.5" /> + <point x="5630.341228070176" y="1459.0" /> + <point x="5855.313067107815" y="1459.0" /> + <point x="-21.631578947368325" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.ObjectMessage" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> + <point x="-56.33333333333303" y="-20.5" /> + <point x="5498.298663200319" y="1067.0" /> + <point x="5503.288048245615" y="1067.0" /> + <point x="5503.288048245615" y="192.0" /> + <point x="2262.1125397493456" y="192.0" /> + <point x="40.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.entity.payload.GetPubkey"> + <point x="-66.80000000000018" y="-20.5" /> + <point x="3062.4352162306227" y="856.0" /> + <point x="2391.7333333333336" y="856.0" /> + <point x="33.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.NetworkHandler.MessageListener" target="ch.dissem.bitmessage.ports.NetworkHandler"> + <point x="0.0" y="-20.5" /> + <point x="2819.3810495639564" y="886.0" /> + <point x="3791.4071062163357" y="886.0" /> + <point x="-58.666666666666515" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.entity.MessagePayload"> + <point x="36.05263157894751" y="-20.5" /> + <point x="5912.997277634131" y="1469.0" /> + <point x="6465.341228070176" y="1469.0" /> + <point x="6465.341228070176" y="1107.0" /> + <point x="6407.341228070176" y="1107.0" /> + <point x="9.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.entity.payload.GenericPayload"> + <point x="81.66666666666697" y="-20.5" /> + <point x="6885.007894736843" y="1338.0" /> + <point x="6841.674561403509" y="1338.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ProofOfWorkService" target="ch.dissem.bitmessage.InternalContext"> + <point x="69.66666666666652" y="20.5" /> + <point x="3455.4625" y="856.0" /> + <point x="3151.5018828972898" y="856.0" /> + <point x="22.26666666666688" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.BitmessageAddress" target="ch.dissem.bitmessage.utils.AccessCounter"> + <point x="67.33333333333326" y="-20.5" /> + <point x="1175.8666666666668" y="414.0" /> + <point x="1375.4321062163358" y="414.0" /> + <point x="-20.375" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.V2Pubkey" target="ch.dissem.bitmessage.entity.payload.Pubkey"> + <point x="0.0" y="-20.5" /> + <point x="763.8568660309461" y="283.0" /> + <point x="915.3568660309461" y="283.0" /> + <point x="-42.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.NetworkMessage" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="-46.0" y="-20.5" /> + <point x="6034.841228070176" y="81.0" /> + <point x="2180.529328438558" y="81.0" /> + <point x="30.22222222222217" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcProofOfWorkRepository" target="ch.dissem.bitmessage.ports.ProofOfWorkRepository.Item"> + <point x="92.0" y="-20.5" /> + <point x="4798.448772883003" y="1519.0" /> + <point x="4778.448772883003" y="1519.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.ProofOfWorkRepository.Item" target="ch.dissem.bitmessage.entity.ObjectMessage"> + <point x="20.75" y="-20.5" /> + <point x="4799.198772883003" y="1318.0" /> + <point x="5554.631996533652" y="1318.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Msg" target="ch.dissem.bitmessage.entity.payload.CryptoBox"> + <point x="-20.5" y="-20.5" /> + <point x="1204.3250000000003" y="766.0" /> + <point x="656.9500000000003" y="766.0" /> + <point x="40.625" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.DefaultMessageListener" target="ch.dissem.bitmessage.entity.payload.Msg"> + <point x="-87.75" y="-20.5" /> + <point x="1622.0750000000003" y="1047.0" /> + <point x="1245.3250000000003" y="1047.0" /> + <point x="20.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.InternalContext"> + <point x="-57.68421052631584" y="-20.5" /> + <point x="5819.260435528868" y="1509.0" /> + <point x="5314.341228070176" y="1509.0" /> + <point x="5314.341228070176" y="1007.0" /> + <point x="3176.9495019449087" y="1007.0" /> + <point x="47.71428571428578" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest.Request" target="ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest"> + <point x="27.75" y="20.5" /> + <point x="139.625" y="675.0" /> + <point x="146.75" y="675.0" /> + <point x="27.25" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.repository.JdbcMessageRepository" target="ch.dissem.bitmessage.entity.valueobject.Label"> + <point x="-99.58333333333348" y="-20.5" /> + <point x="3619.5185495639553" y="1499.0" /> + <point x="1883.4500000000003" y="1499.0" /> + <point x="22.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.MessageCallback"> + <point x="-22.26666666666688" y="-20.5" /> + <point x="3106.968549563956" y="816.0" /> + <point x="3166.4000000000005" y="816.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.V4Broadcast" target="ch.dissem.bitmessage.entity.payload.Broadcast"> + <point x="0.0" y="-20.5" /> + <point x="83.5" y="1057.0" /> + <point x="543.0571062163358" y="1057.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.CryptoCustomMessage" target="ch.dissem.bitmessage.entity.CustomMessage"> + <point x="103.55555555555566" y="-20.5" /> + <point x="913.4916666666668" y="1348.0" /> + <point x="1383.9083333333338" y="1348.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.CryptoCustomMessage.SignatureCheckingInputStream" target="ch.dissem.bitmessage.extensions.CryptoCustomMessage"> + <point x="73.0" y="20.5" /> + <point x="1012.4083333333338" y="1318.0" /> + <point x="835.8249999999998" y="1318.0" /> + <point x="25.888888888888687" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.exception.NodeException"> + <point x="43.75" y="-20.5" /> + <point x="146.84979956395637" y="1499.0" /> + <point x="1808.339382897289" y="1499.0" /> + <point x="1808.339382897289" y="1328.0" /> + <point x="5740.528728070176" y="1328.0" /> + <point x="-62.625" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.CryptoBox" target="ch.dissem.bitmessage.utils.AccessCounter"> + <point x="43.333333333333485" y="-20.5" /> + <point x="659.6583333333338" y="645.0" /> + <point x="839.936072446958" y="645.0" /> + <point x="839.936072446958" y="404.0" /> + <point x="1334.6821062163358" y="404.0" /> + <point x="-61.125" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.CryptoBox" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="-43.333333333333485" y="-20.5" /> + <point x="572.9916666666668" y="645.0" /> + <point x="489.40833333333376" y="645.0" /> + <point x="489.40833333333376" y="81.0" /> + <point x="2104.9737728830023" y="81.0" /> + <point x="-45.333333333333485" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.ObjectPayload" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="0.0" y="-20.5" /> + <point x="2221.6125397493456" y="101.0" /> + <point x="2150.307106216336" y="101.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.BitmessageContext.Listener"> + <point x="18.0" y="-20.5" /> + <point x="1681.5750000000003" y="1198.0" /> + <point x="1837.3250000000003" y="1198.0" /> + <point x="1837.3250000000003" y="1017.0" /> + <point x="1684.9500000000003" y="1017.0" /> + <point x="35.66666666666674" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> + <point x="21.631578947368325" y="-20.5" /> + <point x="5898.576225002552" y="1449.0" /> + <point x="5978.341228070176" y="1449.0" /> + <point x="5978.341228070176" y="535.0" /> + <point x="5669.909260366826" y="535.0" /> + <point x="31.45454545454504" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.GetPubkey" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> + <point x="0.0" y="-20.5" /> + <point x="2358.7333333333336" y="202.0" /> + <point x="2235.1125397493456" y="202.0" /> + <point x="13.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.CryptoCustomMessage.Reader" target="ch.dissem.bitmessage.extensions.CryptoCustomMessage"> + <point x="25.5" y="20.5" /> + <point x="747.9083333333338" y="1318.0" /> + <point x="784.0472222222224" y="1318.0" /> + <point x="-25.888888888888687" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext.ContextHolder" target="ch.dissem.bitmessage.InternalContext"> + <point x="-32.40000000000009" y="20.5" /> + <point x="3916.173772883002" y="605.0" /> + <point x="3500.7958333333336" y="605.0" /> + <point x="3500.7958333333336" y="866.0" /> + <point x="3162.635216230623" y="866.0" /> + <point x="33.40000000000009" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.entity.payload.V4Pubkey"> + <point x="26.25" y="-20.5" /> + <point x="129.34979956395637" y="1489.0" /> + <point x="261.0" y="1489.0" /> + <point x="261.0" y="1047.0" /> + <point x="358.7000000000003" y="1047.0" /> + <point x="-31.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.DefaultNetworkHandler" target="ch.dissem.bitmessage.ports.NetworkHandler"> + <point x="-43.6875" y="-20.5" /> + <point x="5586.653728070176" y="1288.0" /> + <point x="5649.631996533652" y="1288.0" /> + <point x="5649.631996533652" y="896.0" /> + <point x="3908.7404395496687" y="896.0" /> + <point x="58.666666666666515" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Broadcast" target="ch.dissem.bitmessage.entity.Plaintext"> + <point x="52.08333333333337" y="-20.5" /> + <point x="595.1404395496693" y="876.0" /> + <point x="1666.0164662306222" y="876.0" /> + <point x="-37.66666666666674" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.entity.valueobject.PrivateKey"> + <point x="-54.0" y="-20.5" /> + <point x="1609.5750000000003" y="1328.0" /> + <point x="1540.6583333333335" y="1328.0" /> + <point x="1540.6583333333335" y="394.0" /> + <point x="1170.3985326976126" y="394.0" /> + <point x="42.666666666666515" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.entity.BitmessageAddress"> + <point x="-72.0" y="-20.5" /> + <point x="1591.5750000000003" y="1338.0" /> + <point x="1529.6583333333335" y="1338.0" /> + <point x="1529.6583333333335" y="655.0" /> + <point x="1171.6583333333338" y="655.0" /> + <point x="63.125" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.CryptoCustomMessage" target="ch.dissem.bitmessage.extensions.CryptoCustomMessage.SignatureCheckingInputStream"> + <point x="0.0" y="-20.5" /> + <point x="809.9361111111111" y="1308.0" /> + <point x="866.4083333333338" y="1308.0" /> + <point x="-73.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.entity.NetworkMessage"> + <point x="-49.0" y="-20.5" /> + <point x="6754.341228070176" y="1318.0" /> + <point x="6142.174561403509" y="1318.0" /> + <point x="61.33333333333303" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.GenericPayload" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> + <point x="0.0" y="-20.5" /> + <point x="6841.674561403509" y="182.0" /> + <point x="2289.1125397493456" y="182.0" /> + <point x="67.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.AbstractCryptography" target="ch.dissem.bitmessage.ports.Cryptography"> + <point x="-27.875" y="-20.5" /> + <point x="4688.601882897288" y="1017.0" /> + <point x="4632.226882897288" y="1017.0" /> + <point x="4632.226882897288" y="585.0" /> + <point x="3720.323772883002" y="585.0" /> + <point x="58.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.valueobject.Label.Type" target="ch.dissem.bitmessage.entity.valueobject.Label"> + <point x="21.25" y="20.5" /> + <point x="1881.9500000000003" y="424.0" /> + <point x="1883.4500000000003" y="424.0" /> + <point x="22.0" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection.State" target="ch.dissem.bitmessage.networking.Connection"> + <point x="21.75" y="20.5" /> + <point x="5832.091228070176" y="1429.0" /> + <point x="5876.9446460551835" y="1429.0" /> + <point x="0.0" y="-20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.V3Pubkey" target="ch.dissem.bitmessage.entity.payload.V2Pubkey"> + <point x="0.0" y="-20.5" /> + <point x="312.5" y="374.0" /> + <point x="763.8568660309461" y="374.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.Factory" target="ch.dissem.bitmessage.entity.payload.V5Broadcast"> + <point x="-8.75" y="-20.5" /> + <point x="94.34979956395637" y="1469.0" /> + <point x="130.5" y="1469.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ports.ProofOfWorkEngine"> + <point x="-44.5333333333333" y="-20.5" /> + <point x="3084.7018828972896" y="836.0" /> + <point x="3037.2333333333336" y="836.0" /> + <point x="3037.2333333333336" y="424.0" /> + <point x="3012.215439549669" y="424.0" /> + <point x="25.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.Plaintext" target="ch.dissem.bitmessage.entity.valueobject.Label"> + <point x="35.3125" y="-20.5" /> + <point x="1738.995632897289" y="625.0" /> + <point x="1839.4500000000003" y="625.0" /> + <point x="-22.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection.ReaderRunnable" target="ch.dissem.bitmessage.exception.NodeException"> + <point x="-44.0" y="-20.5" /> + <point x="6519.841228070176" y="1338.0" /> + <point x="5824.028728070176" y="1338.0" /> + <point x="20.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.wif.WifImporter" target="ch.dissem.bitmessage.entity.BitmessageAddress"> + <point x="-36.0" y="-20.5" /> + <point x="1483.9083333333335" y="665.0" /> + <point x="1146.4083333333338" y="665.0" /> + <point x="37.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.DefaultNetworkHandler" target="ch.dissem.bitmessage.InternalContext.ContextHolder"> + <point x="-14.5625" y="-20.5" /> + <point x="5615.778728070176" y="1298.0" /> + <point x="5669.6946460551835" y="1298.0" /> + <point x="5669.6946460551835" y="565.0" /> + <point x="4013.3737728830024" y="565.0" /> + <point x="64.80000000000018" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.Pubkey" target="ch.dissem.bitmessage.entity.payload.ObjectPayload"> + <point x="0.0" y="-20.5" /> + <point x="957.3568660309461" y="192.0" /> + <point x="2181.1125397493456" y="192.0" /> + <point x="-40.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest" target="ch.dissem.bitmessage.entity.Streamable"> + <point x="-81.75" y="-20.5" /> + <point x="37.75" y="675.0" /> + <point x="24.375" y="675.0" /> + <point x="24.375" y="71.0" /> + <point x="2089.8626617718915" y="71.0" /> + <point x="-60.44444444444434" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.wif.WifExporter" target="ch.dissem.bitmessage.BitmessageContext"> + <point x="0.0" y="-20.5" /> + <point x="49.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.DefaultNetworkHandler" target="ch.dissem.bitmessage.utils.Property"> + <point x="-101.9375" y="-20.5" /> + <point x="5528.403728070176" y="1218.0" /> + <point x="4556.226882897288" y="1218.0" /> + <point x="28.75" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine" target="ch.dissem.bitmessage.ports.MultiThreadedPOWEngine.Worker"> + <point x="0.0" y="-20.5" /> + <point x="2485.0893828972894" y="896.0" /> + <point x="2671.9833333333336" y="896.0" /> + <point x="-26.25" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.ports.NetworkHandler.MessageListener"> + <point x="-64.89473684210498" y="-20.5" /> + <point x="5812.0499092130785" y="1519.0" /> + <point x="4859.25140446195" y="1519.0" /> + <point x="4859.25140446195" y="1228.0" /> + <point x="4459.476882897288" y="1228.0" /> + <point x="4459.476882897288" y="1037.0" /> + <point x="2878.3810495639564" y="1037.0" /> + <point x="59.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.factory.V3MessageFactory" target="ch.dissem.bitmessage.entity.VerAck"> + <point x="-16.33333333333303" y="-20.5" /> + <point x="6787.007894736843" y="1308.0" /> + <point x="6658.841228070176" y="1308.0" /> + <point x="25.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.V4Pubkey" target="ch.dissem.bitmessage.entity.payload.Pubkey"> + <point x="-25.200000000000273" y="-20.5" /> + <point x="365.0" y="806.0" /> + <point x="386.0" y="806.0" /> + <point x="386.0" y="384.0" /> + <point x="962.3568660309461" y="384.0" /> + <point x="962.3568660309461" y="293.0" /> + <point x="957.3568660309461" y="293.0" /> + <point x="0.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.extensions.CryptoCustomMessage" target="ch.dissem.bitmessage.extensions.CryptoCustomMessage.Reader"> + <point x="-51.777777777777715" y="-20.5" /> + <point x="758.1583333333333" y="1328.0" /> + <point x="696.9083333333338" y="1328.0" /> + <point x="-25.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.InternalContext" target="ch.dissem.bitmessage.ProofOfWorkService"> + <point x="0.0" y="-20.5" /> + <point x="3129.235216230623" y="836.0" /> + <point x="3316.129166666667" y="836.0" /> + <point x="-69.66666666666652" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.entity.payload.V4Pubkey" target="ch.dissem.bitmessage.entity.payload.CryptoBox"> + <point x="25.19999999999999" y="-20.5" /> + <point x="415.4000000000001" y="826.0" /> + <point x="559.4500000000003" y="826.0" /> + <point x="-56.875" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.BitmessageContext" target="ch.dissem.bitmessage.entity.payload.Msg"> + <point x="-90.0" y="-20.5" /> + <point x="1573.5750000000003" y="1348.0" /> + <point x="1518.6583333333335" y="1348.0" /> + <point x="1518.6583333333335" y="1057.0" /> + <point x="1204.3250000000003" y="1057.0" /> + <point x="-20.5" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.DefaultNetworkHandler" target="ch.dissem.bitmessage.entity.valueobject.InventoryVector"> + <point x="43.6875" y="-20.5" /> + <point x="5674.028728070176" y="1318.0" /> + <point x="5709.153728070176" y="1318.0" /> + <point x="5709.153728070176" y="545.0" /> + <point x="5654.181987639554" y="545.0" /> + <point x="15.727272727272975" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.ProofOfWorkService" target="ch.dissem.bitmessage.ports.ProofOfWorkRepository"> + <point x="83.59999999999991" y="-20.5" /> + <point x="3469.3958333333335" y="615.0" /> + <point x="4992.31390446195" y="615.0" /> + <point x="-90.0" y="20.5" /> + </edge> + <edge source="ch.dissem.bitmessage.networking.Connection" target="ch.dissem.bitmessage.networking.Connection.ReaderRunnable"> + <point x="50.4736842105267" y="-20.5" /> + <point x="5927.41833026571" y="1489.0" /> + <point x="6563.841228070176" y="1489.0" /> + <point x="0.0" y="20.5" /> </edge> </edges> - <settings layout="Hierarchic Group" zoom="0.37884615384615383" x="630.736040609137" y="1186.0" /> + <settings layout="Hierarchic Group" zoom="0.25607734806629834" x="3610.0" y="790.0" /> <SelectedNodes /> <Categories> - <Category>Fields</Category> - <Category>Methods</Category> - <Category>Properties</Category> + <Category>Inner Classes</Category> </Categories> - <SCOPE>All</SCOPE> + <SCOPE>Production</SCOPE> <VISIBILITY>protected</VISIBILITY> </Diagram> From 733335ef4294b9ef76d0dfb91020a2566348666a Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Tue, 19 Jan 2016 21:09:46 +0100 Subject: [PATCH 12/54] Improved performance and network stability --- .../bitmessage/networking/Connection.java | 8 +++----- .../networking/DefaultNetworkHandler.java | 17 ++++++++++++----- .../bitmessage/repository/JdbcInventory.java | 5 ++++- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 176517b..76094ff 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -139,6 +139,9 @@ class Connection { @SuppressWarnings("RedundantIfStatement") private boolean syncFinished(NetworkMessage msg) { + if (mode != SYNC){ + return false; + } if (Thread.interrupted()) { return true; } @@ -239,11 +242,6 @@ class Connection { } finally { if (commonRequestedObjects.remove(objectMessage.getInventoryVector())) { LOG.debug("Received object that wasn't requested."); -// if (!requestedObjects.isEmpty()) { -// DebugUtils.saveToFile(objectMessage); -// LOG.debug(objectMessage.getInventoryVector() + " was not in " -// + requestedObjects.toString()); -// } } } break; diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java index bd58d8e..d3bec17 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java @@ -43,16 +43,16 @@ import static ch.dissem.bitmessage.networking.Connection.Mode.CLIENT; import static ch.dissem.bitmessage.networking.Connection.Mode.SERVER; import static ch.dissem.bitmessage.networking.Connection.State.ACTIVE; import static ch.dissem.bitmessage.utils.DebugUtils.inc; -import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; import static java.util.Collections.newSetFromMap; /** * Handles all the networky stuff. */ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { - public final static int NETWORK_MAGIC_NUMBER = 8; private final static Logger LOG = LoggerFactory.getLogger(DefaultNetworkHandler.class); - private static final Random RANDOM = new Random(); + + public final static int NETWORK_MAGIC_NUMBER = 8; + private final Collection<Connection> connections = new ConcurrentLinkedQueue<>(); private final ExecutorService pool; private InternalContext ctx; @@ -155,12 +155,14 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { if (diff == 0) break; } } + boolean forcedDisconnect = false; for (Iterator<Connection> iterator = connections.iterator(); iterator.hasNext(); ) { Connection c = iterator.next(); // Just in case they were all created at the same time, don't disconnect // all at once. - if (now - c.getStartTime() + RANDOM.nextInt(5 * MINUTE) > ctx.getConnectionTTL()) { + if (!forcedDisconnect && now - c.getStartTime() > ctx.getConnectionTTL()) { c.disconnect(); + forcedDisconnect = true; } switch (c.getState()) { case DISCONNECTED: @@ -306,8 +308,13 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { } } Iterator<InventoryVector> iterator = inventoryVectors.iterator(); + InventoryVector next; + if (iterator.hasNext()) { + next = iterator.next(); + } else { + return; + } boolean firstRound = true; - InventoryVector next = iterator.next(); while (firstRound || iterator.hasNext()) { if (!firstRound) { next = iterator.next(); diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java index 9c9c9e7..3336475 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java @@ -80,7 +80,7 @@ public class JdbcInventory extends JdbcHelper implements Inventory { @Override public List<InventoryVector> getMissing(List<InventoryVector> offer, long... streams) { for (long stream : streams) { - getCache(stream).forEach((iv, t) -> offer.remove(iv)); + offer.removeAll(getCache(stream).keySet()); } return offer; } @@ -132,6 +132,9 @@ public class JdbcInventory extends JdbcHelper implements Inventory { @Override public void storeObject(ObjectMessage object) { + if (getCache(object.getStream()).containsKey(object.getInventoryVector())) + return; + try (Connection connection = config.getConnection()) { PreparedStatement ps = connection.prepareStatement("INSERT INTO Inventory (hash, stream, expires, data, type, version) VALUES (?, ?, ?, ?, ?, ?)"); InventoryVector iv = object.getInventoryVector(); From 9f05af8bb7af3d87ce31e3a51535178cc439d9b0 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Thu, 21 Jan 2016 20:32:23 +0100 Subject: [PATCH 13/54] Finally fixed the bug that was haunting me for the last week. --- .../dissem/bitmessage/BitmessageContext.java | 1 + .../bitmessage/DefaultMessageListener.java | 40 +++++++++++-------- .../java/ch/dissem/bitmessage/entity/Inv.java | 6 +-- .../entity/valueobject/InventoryVector.java | 1 - .../bitmessage/factory/V3MessageFactory.java | 7 +++- .../bitmessage/entity/SerializationTest.java | 20 ++++++++++ .../dissem/bitmessage/demo/Application.java | 13 +++++- .../java/ch/dissem/bitmessage/demo/Main.java | 8 +++- .../bitmessage/networking/Connection.java | 24 ++++++----- .../networking/NetworkHandlerTest.java | 3 +- .../repository/JdbcMessageRepository.java | 5 ++- 11 files changed, 89 insertions(+), 39 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 46d76d7..28e8483 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -157,6 +157,7 @@ public class BitmessageContext { .from(from) .to(to) .message(subject, message) + .labels(messages().getLabels(Label.Type.SENT)) .build(); if (to.getPubkey() == null) { tryToFindMatchingPubkey(to); diff --git a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java index eb22f03..b2366e4 100644 --- a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java +++ b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java @@ -90,28 +90,32 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { address = ctx.getAddressRepository().findContact(pubkey.getRipe()); } if (address != null) { - address.setPubkey(pubkey); - LOG.info("Got pubkey for contact " + address); - ctx.getAddressRepository().save(address); - List<Plaintext> messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address); - LOG.info("Sending " + messages.size() + " messages for contact " + address); - for (Plaintext msg : messages) { - msg.setStatus(DOING_PROOF_OF_WORK); - ctx.getMessageRepository().save(msg); - ctx.send( - msg.getFrom(), - msg.getTo(), - new Msg(msg), - +2 * DAY - ); - msg.setStatus(SENT); - ctx.getMessageRepository().save(msg); - } + updatePubkey(address, pubkey); } } catch (DecryptionFailedException ignore) { } } + private void updatePubkey(BitmessageAddress address, Pubkey pubkey){ + address.setPubkey(pubkey); + LOG.info("Got pubkey for contact " + address); + ctx.getAddressRepository().save(address); + List<Plaintext> messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address); + LOG.info("Sending " + messages.size() + " messages for contact " + address); + for (Plaintext msg : messages) { + msg.setStatus(DOING_PROOF_OF_WORK); + ctx.getMessageRepository().save(msg); + ctx.send( + msg.getFrom(), + msg.getTo(), + new Msg(msg), + +2 * DAY + ); + msg.setStatus(SENT); + ctx.getMessageRepository().save(msg); + } + } + protected void receive(ObjectMessage object, Msg msg) throws IOException { for (BitmessageAddress identity : ctx.getAddressRepository().getIdentities()) { try { @@ -125,6 +129,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { msg.getPlaintext().setInventoryVector(object.getInventoryVector()); ctx.getMessageRepository().save(msg.getPlaintext()); listener.receive(msg.getPlaintext()); + updatePubkey(msg.getPlaintext().getFrom(), msg.getPlaintext().getFrom().getPubkey()); } break; } catch (DecryptionFailedException ignore) { @@ -148,6 +153,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { broadcast.getPlaintext().setInventoryVector(object.getInventoryVector()); ctx.getMessageRepository().save(broadcast.getPlaintext()); listener.receive(broadcast.getPlaintext()); + updatePubkey(broadcast.getPlaintext().getFrom(), broadcast.getPlaintext().getFrom().getPubkey()); } } catch (DecryptionFailedException ignore) { } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java index df1b380..0135ec0 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java @@ -44,10 +44,10 @@ public class Inv implements MessagePayload { } @Override - public void write(OutputStream stream) throws IOException { - Encode.varInt(inventory.size(), stream); + public void write(OutputStream out) throws IOException { + Encode.varInt(inventory.size(), out); for (InventoryVector iv : inventory) { - iv.write(stream); + iv.write(out); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java index f87dd13..fc67422 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java @@ -38,7 +38,6 @@ public class InventoryVector implements Streamable, Serializable { InventoryVector that = (InventoryVector) o; return Arrays.equals(hash, that.hash); - } @Override diff --git a/core/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java b/core/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java index 9e15b3d..d13e73e 100644 --- a/core/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java +++ b/core/src/main/java/ch/dissem/bitmessage/factory/V3MessageFactory.java @@ -44,6 +44,9 @@ class V3MessageFactory { findMagic(in); String command = getCommand(in); int length = (int) Decode.uint32(in); + if (length > 1600003) { + throw new NodeException("Payload of " + length + " bytes received, no more than 1600003 was expected."); + } byte[] checksum = Decode.bytes(in, 4); byte[] payloadBytes = Decode.bytes(in, length); @@ -191,10 +194,10 @@ class V3MessageFactory { private static String getCommand(InputStream stream) throws IOException { byte[] bytes = new byte[12]; - int end = -1; + int end = bytes.length; for (int i = 0; i < bytes.length; i++) { bytes[i] = (byte) stream.read(); - if (end == -1) { + if (end == bytes.length) { if (bytes[i] == 0) end = i; } else { if (bytes[i] != 0) throw new IOException("'\\0' padding expected for command"); diff --git a/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java b/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java index 03b7bc5..1bcb8e7 100644 --- a/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java @@ -17,6 +17,7 @@ package ch.dissem.bitmessage.entity; import ch.dissem.bitmessage.entity.payload.*; +import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.utils.TestBase; @@ -25,9 +26,11 @@ import org.junit.Test; import java.io.*; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Collections; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; +import static ch.dissem.bitmessage.utils.Singleton.security; import static org.junit.Assert.*; public class SerializationTest extends TestBase { @@ -95,6 +98,23 @@ public class SerializationTest extends TestBase { assertEquals(p1, p2); } + @Test + public void ensureNetworkMessageIsSerializedAndDeserializedCorrectly() throws Exception { + ArrayList<InventoryVector> ivs = new ArrayList<>(50000); + for (int i = 0; i < 50000; i++) { + ivs.add(new InventoryVector(security().randomBytes(32))); + } + + Inv inv = new Inv.Builder().inventory(ivs).build(); + NetworkMessage before = new NetworkMessage(inv); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + before.write(out); + + NetworkMessage after = Factory.getNetworkMessage(3, new ByteArrayInputStream(out.toByteArray())); + Inv invAfter = (Inv) after.getPayload(); + assertEquals(ivs, invAfter.getInventory()); + } + private void doTest(String resourceName, int version, Class<?> expectedPayloadType) throws IOException { byte[] data = TestUtils.getBytes(resourceName); InputStream in = new ByteArrayInputStream(data); diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java index f35bcc5..26d6652 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java @@ -28,6 +28,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; +import java.net.InetAddress; import java.util.List; import java.util.Scanner; @@ -40,7 +41,7 @@ public class Application { private BitmessageContext ctx; - public Application() { + public Application(String syncServer, int syncPort) { JdbcConfig jdbcConfig = new JdbcConfig(); ctx = new BitmessageContext.Builder() .addressRepo(new JdbcAddressRepository(jdbcConfig)) @@ -63,7 +64,9 @@ public class Application { }) .build(); - ctx.startup(); + if (syncServer == null) { + ctx.startup(); + } scanner = new Scanner(System.in); @@ -75,6 +78,9 @@ public class Application { System.out.println("c) contacts"); System.out.println("s) subscriptions"); System.out.println("m) messages"); + if (syncServer != null) { + System.out.println("y) sync"); + } System.out.println("?) info"); System.out.println("e) exit"); @@ -99,6 +105,9 @@ public class Application { break; case "e": break; + case "y": + ctx.synchronize(InetAddress.getByName(syncServer), syncPort, 120, true); + break; default: System.out.println("Unknown command. Please try again."); } diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java index a7b63d1..b0e114b 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java @@ -64,7 +64,7 @@ public class Main { new WifImporter(ctx, options.importWIF).importAll(); } } else { - new Application(); + new Application(options.syncServer, options.syncPort); } } @@ -74,5 +74,11 @@ public class Main { @Option(name = "-export", usage = "Export to WIF file.") private File exportWIF; + + @Option(name = "-syncServer", usage = "Use manual synchronization with the given server instead of starting a full node.") + private String syncServer; + + @Option(name = "-syncPort", usage = "Port to use for synchronisation") + private int syncPort = 8444; } } diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 76094ff..54bfee4 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -139,13 +139,13 @@ class Connection { @SuppressWarnings("RedundantIfStatement") private boolean syncFinished(NetworkMessage msg) { - if (mode != SYNC){ + if (mode != SYNC) { return false; } if (Thread.interrupted()) { return true; } - if (syncTimeout == 0 || state != ACTIVE) { + if (state != ACTIVE) { return false; } if (syncTimeout < UnixTime.now()) { @@ -204,10 +204,11 @@ class Connection { switch (messagePayload.getCommand()) { case INV: Inv inv = (Inv) messagePayload; + int originalSize = inv.getInventory().size(); updateIvCache(inv.getInventory()); List<InventoryVector> missing = ctx.getInventory().getMissing(inv.getInventory(), streams); missing.removeAll(commonRequestedObjects); - LOG.debug("Received inventory with " + inv.getInventory().size() + " elements, of which are " + LOG.debug("Received inventory with " + originalSize + " elements, of which are " + missing.size() + " missing."); send(new GetData.Builder().inventory(missing).build()); break; @@ -230,8 +231,6 @@ class Connection { security().checkProofOfWork(objectMessage, ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes()); ctx.getInventory().storeObject(objectMessage); // offer object to some random nodes so it gets distributed throughout the network: - // FIXME: don't do this while we catch up after initialising our first connection - // (that might be a bit tricky to do) networkHandler.offer(objectMessage.getInventoryVector()); lastObjectTime = UnixTime.now(); } catch (InsufficientProofOfWorkException e) { @@ -283,7 +282,9 @@ class Connection { if (payload instanceof GetData) { requestedObjects.addAll(((GetData) payload).getInventory()); } - new NetworkMessage(payload).write(out); + synchronized (this) { + new NetworkMessage(payload).write(out); + } } catch (IOException e) { LOG.error(e.getMessage(), e); disconnect(); @@ -342,16 +343,19 @@ class Connection { public class ReaderRunnable implements Runnable { @Override public void run() { + lastObjectTime = 0; try (Socket socket = Connection.this.socket) { initSocket(socket); if (mode == CLIENT || mode == SYNC) { send(new Version.Builder().defaults().addrFrom(host).addrRecv(node).build()); } while (state != DISCONNECTED) { - if (mode != SYNC && state == ACTIVE && requestedObjects.isEmpty()) { - Thread.sleep(1000); - } else { - Thread.sleep(100); + if (mode != SYNC) { + if (state == ACTIVE && requestedObjects.isEmpty() && sendingQueue.isEmpty()) { + Thread.sleep(1000); + } else { + Thread.sleep(100); + } } try { NetworkMessage msg = Factory.getNetworkMessage(version, in); diff --git a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java index 77cad46..a45ec47 100644 --- a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java +++ b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java @@ -117,7 +117,8 @@ public class NetworkHandlerTest { ); nodeInventory.init( - "V1Msg.payload" + "V1Msg.payload", + "V4Pubkey.payload" ); Future<?> future = networkHandler.synchronize(InetAddress.getLocalHost(), 6001, diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java index 48b8df5..69890c3 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java @@ -256,12 +256,13 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito private void update(Connection connection, Plaintext message) throws SQLException, IOException { PreparedStatement ps = connection.prepareStatement( - "UPDATE Message SET iv=?, sent=?, received=?, status=? WHERE id=?"); + "UPDATE Message SET iv=?, sent=?, received=?, status=?, initial_hash=? WHERE id=?"); ps.setBytes(1, message.getInventoryVector() != null ? message.getInventoryVector().getHash() : null); ps.setLong(2, message.getSent()); ps.setLong(3, message.getReceived()); ps.setString(4, message.getStatus() != null ? message.getStatus().name() : null); - ps.setLong(5, (Long) message.getId()); + ps.setBytes(5, message.getInitialHash()); + ps.setLong(6, (Long) message.getId()); ps.executeUpdate(); } From 07b349563ff02bc892227c66cef2cd64da973596 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sat, 23 Jan 2016 17:18:25 +0100 Subject: [PATCH 14/54] Fixed an issue in the POW engine --- .../bitmessage/ports/MultiThreadedPOWEngine.java | 14 +++++++------- .../dissem/bitmessage/ports/SimplePOWEngine.java | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java b/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java index 5e00e33..790e3b7 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java @@ -101,14 +101,12 @@ public class MultiThreadedPOWEngine implements ProofOfWorkEngine { if (!Bytes.lt(target, mda.digest(mda.digest()), 8)) { synchronized (callback) { if (!Thread.interrupted()) { - try { - callback.onNonceCalculated(initialHash, nonce); - } finally { - semaphore.release(); - for (Worker w : workers) { - w.interrupt(); - } + for (Worker w : workers) { + w.interrupt(); } + // Clear interrupted flag for callback + Thread.interrupted(); + callback.onNonceCalculated(initialHash, nonce); } } return; @@ -129,8 +127,10 @@ public class MultiThreadedPOWEngine implements ProofOfWorkEngine { @Override public void onNonceCalculated(byte[] initialHash, byte[] nonce) { + // Prevents the callback from being called twice if two nonces are found simultaneously synchronized (this) { if (waiting) { + semaphore.release(); LOG.info("Nonce calculated in " + ((System.currentTimeMillis() - startTime) / 1000) + " seconds"); waiting = false; callback.onNonceCalculated(initialHash, nonce); diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java b/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java index 06d234b..e8d649b 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java @@ -24,6 +24,10 @@ import static ch.dissem.bitmessage.utils.Bytes.inc; /** * You should really use the MultiThreadedPOWEngine, but this one might help you grok the other one. + * <p> + * <strong>Warning:</strong> implementations probably depend on POW being asynchronous, that's + * another reason not to use this one. + * </p> */ public class SimplePOWEngine implements ProofOfWorkEngine { @Override From 6c0eae59191e742b56918d5939acc143fcfba06f Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sat, 23 Jan 2016 17:19:36 +0100 Subject: [PATCH 15/54] Added CONTRIBUTING.md --- CONTRIBUTING.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..34c84ba --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing + +We love pull requests from everyone. Please be nice and forgive us +if we can't process your request right away. + +Fork, then clone the repo: + + git clone git@github.com:your-username/Jabit.git + +Make sure the tests pass: + + ./gradlew test + +Make your change. Add tests for your change. Make the tests pass: + + ./gradlew test + +Push to your fork and [submit a pull request][pr]. + +[pr]: https://github.com/Dissem/Jabit/compare/ + +Unfortunately we can't always answer right away, so we ask you to have +some patience. Then we may suggest some changes or improvements or +alternatives. From 9a91351091cd326e8e3118264fb9767de0337d21 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sat, 23 Jan 2016 17:21:33 +0100 Subject: [PATCH 16/54] Version 1.0.0 bump --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 02a3903..dc918be 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ subprojects { sourceCompatibility = 1.7 group = 'ch.dissem.jabit' - version = '0.2.1-SNAPSHOT' + version = '1.0.0' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") From 8bd7a245b0292e2d8f269f09f32986179b63a875 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sun, 24 Jan 2016 09:38:12 +0100 Subject: [PATCH 17/54] Updated README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fb45cc6..f9c7604 100644 --- a/README.md +++ b/README.md @@ -29,17 +29,17 @@ Setup Add Jabit as Gradle dependency: ```Gradle -compile 'ch.dissem.jabit:jabit-core:0.2.0' +compile 'ch.dissem.jabit:jabit-core:1.0.0' ``` Unless you want to implement your own, also add the following: ```Gradle -compile 'ch.dissem.jabit:jabit-networking:0.2.0' -compile 'ch.dissem.jabit:jabit-repositories:0.2.0' -compile 'ch.dissem.jabit:jabit-cryptography-bc:0.2.0' +compile 'ch.dissem.jabit:jabit-networking:1.0.0' +compile 'ch.dissem.jabit:jabit-repositories:1.0.0' +compile 'ch.dissem.jabit:jabit-cryptography-bc:1.0.0' ``` And if you want to import from or export to the Wallet Import Format (used by PyBitmessage) you might also want to add: ```Gradle -compile 'ch.dissem.jabit:jabit-wif:0.2.0' +compile 'ch.dissem.jabit:jabit-wif:1.0.0' ``` For Android clients use `jabit-cryptography-sc` instead of `jabit-cryptography-bc`. From 1a77396bdc978ff27b27b7ef94d8709002548ac3 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Fri, 29 Jan 2016 11:06:39 +0100 Subject: [PATCH 18/54] Update README.md Fixed error where bc and sc was used instead of bouncy and spongy --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f9c7604..db59adc 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,14 @@ Unless you want to implement your own, also add the following: ```Gradle compile 'ch.dissem.jabit:jabit-networking:1.0.0' compile 'ch.dissem.jabit:jabit-repositories:1.0.0' -compile 'ch.dissem.jabit:jabit-cryptography-bc:1.0.0' +compile 'ch.dissem.jabit:jabit-cryptography-bouncy:1.0.0' ``` And if you want to import from or export to the Wallet Import Format (used by PyBitmessage) you might also want to add: ```Gradle compile 'ch.dissem.jabit:jabit-wif:1.0.0' ``` -For Android clients use `jabit-cryptography-sc` instead of `jabit-cryptography-bc`. +For Android clients use `jabit-cryptography-spongy` instead of `jabit-cryptography-bouncy`. Usage ----- From 5f4dbfc98596fcdf565aadc4e3aec618196358e9 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sun, 31 Jan 2016 18:11:20 +0100 Subject: [PATCH 19/54] Version 1.0.1-SNAPSHOT - fixed issue with requesting pubkey, and problem where your keys are overwritten if you try to import a contact again or worse, your identity as a contact --- build.gradle | 4 +-- .../dissem/bitmessage/BitmessageContext.java | 3 ++- .../dissem/bitmessage/ProofOfWorkService.java | 9 ++++--- .../bitmessage/entity/valueobject/Label.java | 1 + .../repository/JdbcAddressRepository.java | 26 ++++++++++++++----- .../repository/JdbcAddressRepositoryTest.java | 11 ++++++++ 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index dc918be..b944a14 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ subprojects { sourceCompatibility = 1.7 group = 'ch.dissem.jabit' - version = '1.0.0' + version = '1.0.1-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") @@ -34,7 +34,7 @@ subprojects { } signing { - required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") } + required { isReleaseVersion } sign configurations.archives } diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 28e8483..dbc08d3 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -200,6 +200,7 @@ public class BitmessageContext { LOG.info("Public key is missing from recipient. Requesting."); requestPubkey(msg.getFrom(), to); msg.setStatus(PUBKEY_REQUESTED); + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.OUTBOX)); ctx.getMessageRepository().save(msg); } else { LOG.info("Sending message."); @@ -224,7 +225,7 @@ public class BitmessageContext { requestingIdentity, address, new GetPubkey(address), - +28 * DAY + +2 * DAY ); } diff --git a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java index 19e231f..ecd1099 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java +++ b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java @@ -4,6 +4,7 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.PlaintextHolder; +import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; @@ -42,10 +43,10 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC } public void doProofOfWork(BitmessageAddress recipient, ObjectMessage object) { - long nonceTrialsPerByte = recipient == null ? - ctx.getNetworkNonceTrialsPerByte() : recipient.getPubkey().getNonceTrialsPerByte(); - long extraBytes = recipient == null ? - ctx.getNetworkExtraBytes() : recipient.getPubkey().getExtraBytes(); + Pubkey pubkey = recipient == null ? null : recipient.getPubkey(); + + long nonceTrialsPerByte = pubkey == null ? ctx.getNetworkNonceTrialsPerByte() : pubkey.getNonceTrialsPerByte(); + long extraBytes = pubkey == null ? ctx.getNetworkExtraBytes() : pubkey.getExtraBytes(); powRepo.putObject(object, nonceTrialsPerByte, extraBytes); if (object.getPayload() instanceof PlaintextHolder) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java index 7c37973..02f0384 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java @@ -79,6 +79,7 @@ public class Label implements Serializable { INBOX, BROADCAST, DRAFT, + OUTBOX, SENT, UNREAD, TRASH diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java index 337d50a..bf15a6a 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java @@ -152,13 +152,25 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito private void update(BitmessageAddress address) throws IOException, SQLException { try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement( - "UPDATE Address SET alias=?, public_key=?, private_key=?, subscribed=? WHERE address=?"); - ps.setString(1, address.getAlias()); - writePubkey(ps, 2, address.getPubkey()); - writeBlob(ps, 3, address.getPrivateKey()); - ps.setBoolean(4, address.isSubscribed()); - ps.setString(5, address.getAddress()); + StringBuilder statement = new StringBuilder("UPDATE Address SET alias=?"); + if (address.getPubkey() != null) { + statement.append(", public_key=?"); + } + if (address.getPrivateKey() != null) { + statement.append(", private_key=?"); + } + statement.append(", subscribed=? WHERE address=?"); + PreparedStatement ps = connection.prepareStatement(statement.toString()); + int i = 0; + ps.setString(++i, address.getAlias()); + if (address.getPubkey() != null) { + writePubkey(ps, ++i, address.getPubkey()); + } + if (address.getPrivateKey() != null) { + writeBlob(ps, ++i, address.getPrivateKey()); + } + ps.setBoolean(++i, address.isSubscribed()); + ps.setString(++i, address.getAddress()); ps.executeUpdate(); } } diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java index 18fc83c..18e70b2 100644 --- a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java @@ -128,6 +128,17 @@ public class JdbcAddressRepositoryTest extends TestBase { assertEquals("Test-Alias", address.getAlias()); } + @Test + public void ensureExistingKeysAreNotDeleted() { + BitmessageAddress address = new BitmessageAddress(IDENTITY_A); + address.setAlias("Test"); + repo.save(address); + BitmessageAddress identityA = repo.getAddress(IDENTITY_A); + assertNotNull(identityA.getPubkey()); + assertNotNull(identityA.getPrivateKey()); + assertEquals("Test", identityA.getAlias()); + } + @Test public void testRemove() throws Exception { BitmessageAddress address = repo.getAddress(IDENTITY_A); From edd8045327bb4d13eae4aed7eff1cd730faf7d64 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Tue, 2 Feb 2016 20:40:01 +0100 Subject: [PATCH 20/54] Fixed / improved message sending and added a system test (it's a start) --- .../dissem/bitmessage/BitmessageContext.java | 137 ++++-------------- .../ch/dissem/bitmessage/InternalContext.java | 66 ++++++++- .../ch/dissem/bitmessage/utils/Numbers.java | 2 +- demo/build.gradle | 1 + .../java/ch/dissem/bitmessage/SystemTest.java | 79 ++++++++++ .../ch/dissem/bitmessage/TestListener.java | 26 ++++ .../dissem/bitmessage/TestNodeRegistry.java | 51 +++++++ 7 files changed, 246 insertions(+), 116 deletions(-) create mode 100644 demo/src/test/java/ch/dissem/bitmessage/SystemTest.java create mode 100644 demo/src/test/java/ch/dissem/bitmessage/TestListener.java create mode 100644 demo/src/test/java/ch/dissem/bitmessage/TestNodeRegistry.java diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index dbc08d3..dde6d2d 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -17,20 +17,21 @@ package ch.dissem.bitmessage; import ch.dissem.bitmessage.entity.*; -import ch.dissem.bitmessage.entity.payload.*; +import ch.dissem.bitmessage.entity.payload.Broadcast; +import ch.dissem.bitmessage.entity.payload.Msg; +import ch.dissem.bitmessage.entity.payload.ObjectPayload; +import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.payload.Pubkey.Feature; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.DecryptionFailedException; -import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Property; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetAddress; -import java.util.Arrays; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.*; @@ -38,9 +39,7 @@ import java.util.concurrent.*; import static ch.dissem.bitmessage.entity.Plaintext.Status.*; import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; -import static ch.dissem.bitmessage.utils.UnixTime.DAY; -import static ch.dissem.bitmessage.utils.UnixTime.HOUR; -import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; +import static ch.dissem.bitmessage.utils.UnixTime.*; /** * <p>Use this class if you want to create a Bitmessage client.</p> @@ -122,67 +121,24 @@ public class BitmessageContext { } public void broadcast(final BitmessageAddress from, final String subject, final String message) { - pool.submit(new Runnable() { - @Override - public void run() { - Plaintext msg = new Plaintext.Builder(BROADCAST) - .from(from) - .message(subject, message) - .build(); - - LOG.info("Sending message."); - msg.setStatus(DOING_PROOF_OF_WORK); - ctx.getMessageRepository().save(msg); - ctx.send( - from, - from, - Factory.getBroadcast(from, msg), - +2 * DAY - ); - msg.setStatus(SENT); - msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.BROADCAST, Label.Type.SENT)); - ctx.getMessageRepository().save(msg); - } - }); + Plaintext msg = new Plaintext.Builder(BROADCAST) + .from(from) + .message(subject, message) + .build(); + send(msg); } public void send(final BitmessageAddress from, final BitmessageAddress to, final String subject, final String message) { if (from.getPrivateKey() == null) { throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key."); } - pool.submit(new Runnable() { - @Override - public void run() { - Plaintext msg = new Plaintext.Builder(MSG) - .from(from) - .to(to) - .message(subject, message) - .labels(messages().getLabels(Label.Type.SENT)) - .build(); - if (to.getPubkey() == null) { - tryToFindMatchingPubkey(to); - } - if (to.getPubkey() == null) { - LOG.info("Public key is missing from recipient. Requesting."); - requestPubkey(from, to); - msg.setStatus(PUBKEY_REQUESTED); - ctx.getMessageRepository().save(msg); - } else { - LOG.info("Sending message."); - msg.setStatus(DOING_PROOF_OF_WORK); - ctx.getMessageRepository().save(msg); - ctx.send( - from, - to, - new Msg(msg), - +2 * DAY - ); - msg.setStatus(SENT); - msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.SENT)); - ctx.getMessageRepository().save(msg); - } - } - }); + Plaintext msg = new Plaintext.Builder(MSG) + .from(from) + .to(to) + .message(subject, message) + .labels(messages().getLabels(Label.Type.SENT)) + .build(); + send(msg); } public void send(final Plaintext msg) { @@ -193,16 +149,18 @@ public class BitmessageContext { @Override public void run() { BitmessageAddress to = msg.getTo(); - if (to.getPubkey() == null) { - tryToFindMatchingPubkey(to); + if (to != null) { + if (to.getPubkey() == null) { + LOG.info("Public key is missing from recipient. Requesting."); + ctx.requestPubkey(to); + } + if (to.getPubkey() == null) { + msg.setStatus(PUBKEY_REQUESTED); + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.OUTBOX)); + ctx.getMessageRepository().save(msg); + } } - if (to.getPubkey() == null) { - LOG.info("Public key is missing from recipient. Requesting."); - requestPubkey(msg.getFrom(), to); - msg.setStatus(PUBKEY_REQUESTED); - msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.OUTBOX)); - ctx.getMessageRepository().save(msg); - } else { + if (to == null || to.getPubkey() != null) { LOG.info("Sending message."); msg.setStatus(DOING_PROOF_OF_WORK); ctx.getMessageRepository().save(msg); @@ -220,15 +178,6 @@ public class BitmessageContext { }); } - private void requestPubkey(BitmessageAddress requestingIdentity, BitmessageAddress address) { - ctx.send( - requestingIdentity, - address, - new GetPubkey(address), - +2 * DAY - ); - } - public void startup() { ctx.getNetworkHandler().start(networkListener); } @@ -281,41 +230,11 @@ public class BitmessageContext { public void addContact(BitmessageAddress contact) { ctx.getAddressRepository().save(contact); - tryToFindMatchingPubkey(contact); if (contact.getPubkey() == null) { ctx.requestPubkey(contact); } } - private void tryToFindMatchingPubkey(BitmessageAddress address) { - for (ObjectMessage object : ctx.getInventory().getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY)) { - try { - Pubkey pubkey = (Pubkey) object.getPayload(); - if (address.getVersion() == 4) { - V4Pubkey v4Pubkey = (V4Pubkey) pubkey; - if (Arrays.equals(address.getTag(), v4Pubkey.getTag())) { - v4Pubkey.decrypt(address.getPublicDecryptionKey()); - if (object.isSignatureValid(v4Pubkey)) { - address.setPubkey(v4Pubkey); - ctx.getAddressRepository().save(address); - break; - } else { - LOG.info("Found pubkey for " + address + " but signature is invalid"); - } - } - } else { - if (Arrays.equals(pubkey.getRipe(), address.getRipe())) { - address.setPubkey(pubkey); - ctx.getAddressRepository().save(address); - break; - } - } - } catch (Exception e) { - LOG.debug(e.getMessage(), e); - } - } - } - public void addSubscribtion(BitmessageAddress address) { address.setSubscribed(true); ctx.getAddressRepository().save(address); diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java index 9971b9b..54e81a9 100644 --- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -19,9 +19,7 @@ package ch.dissem.bitmessage; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Encrypted; import ch.dissem.bitmessage.entity.ObjectMessage; -import ch.dissem.bitmessage.entity.payload.Broadcast; -import ch.dissem.bitmessage.entity.payload.GetPubkey; -import ch.dissem.bitmessage.entity.payload.ObjectPayload; +import ch.dissem.bitmessage.entity.payload.*; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.UnixTime; @@ -29,6 +27,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Arrays; import java.util.TreeSet; /** @@ -212,16 +211,71 @@ public class InternalContext { } } + /** + * Be aware that if the pubkey already exists in the inventory, the metods will not request it and the callback + * for freshly received pubkeys will not be called. Instead the pubkey is added to the contact and stored on DB. + */ public void requestPubkey(final BitmessageAddress contact) { + BitmessageAddress stored = addressRepository.getAddress(contact.getAddress()); + + tryToFindMatchingPubkey(contact); + if (contact.getPubkey() != null) { + if (stored != null) { + stored.setPubkey(contact.getPubkey()); + addressRepository.save(stored); + } else { + addressRepository.save(contact); + } + return; + } + + if (stored == null) { + addressRepository.save(contact); + } + long expires = UnixTime.now(+pubkeyTTL); LOG.info("Expires at " + expires); - final ObjectMessage response = new ObjectMessage.Builder() + final ObjectMessage request = new ObjectMessage.Builder() .stream(contact.getStream()) .expiresTime(expires) .payload(new GetPubkey(contact)) .build(); - messageCallback.proofOfWorkStarted(response.getPayload()); - proofOfWorkService.doProofOfWork(response); + messageCallback.proofOfWorkStarted(request.getPayload()); + proofOfWorkService.doProofOfWork(request); + } + + private void tryToFindMatchingPubkey(BitmessageAddress address) { + BitmessageAddress stored = addressRepository.getAddress(address.getAddress()); + if (stored != null) { + address.setAlias(stored.getAlias()); + address.setSubscribed(stored.isSubscribed()); + } + for (ObjectMessage object : inventory.getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY)) { + try { + Pubkey pubkey = (Pubkey) object.getPayload(); + if (address.getVersion() == 4) { + V4Pubkey v4Pubkey = (V4Pubkey) pubkey; + if (Arrays.equals(address.getTag(), v4Pubkey.getTag())) { + v4Pubkey.decrypt(address.getPublicDecryptionKey()); + if (object.isSignatureValid(v4Pubkey)) { + address.setPubkey(v4Pubkey); + addressRepository.save(address); + break; + } else { + LOG.info("Found pubkey for " + address + " but signature is invalid"); + } + } + } else { + if (Arrays.equals(pubkey.getRipe(), address.getRipe())) { + address.setPubkey(pubkey); + addressRepository.save(address); + break; + } + } + } catch (Exception e) { + LOG.debug(e.getMessage(), e); + } + } } public long getClientNonce() { diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java b/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java index b1ace02..9d0c078 100644 --- a/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java +++ b/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java @@ -1,7 +1,7 @@ package ch.dissem.bitmessage.utils; /** - * Created by chrig on 07.12.2015. + * @author Christian Basler */ public class Numbers { public static long max(long a, long b) { diff --git a/demo/build.gradle b/demo/build.gradle index 84d5907..2ab6363 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -30,4 +30,5 @@ dependencies { compile 'args4j:args4j:2.32' compile 'com.h2database:h2:1.4.190' testCompile 'junit:junit:4.11' + testCompile 'org.mockito:mockito-core:1.10.19' } diff --git a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java new file mode 100644 index 0000000..5bf2949 --- /dev/null +++ b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java @@ -0,0 +1,79 @@ +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.networking.DefaultNetworkHandler; +import ch.dissem.bitmessage.repository.*; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * @author Christian Basler + */ +public class SystemTest { + static BitmessageContext alice; + static TestListener aliceListener = new TestListener(); + static BitmessageAddress aliceIdentity; + + static BitmessageContext bob; + static TestListener bobListener = new TestListener(); + static BitmessageAddress bobIdentity; + + @BeforeClass + public static void setUp() { + JdbcConfig aliceDB = new JdbcConfig("jdbc:h2:mem:alice;DB_CLOSE_DELAY=-1", "sa", ""); + alice = new BitmessageContext.Builder() + .addressRepo(new JdbcAddressRepository(aliceDB)) + .inventory(new JdbcInventory(aliceDB)) + .messageRepo(new JdbcMessageRepository(aliceDB)) + .powRepo(new JdbcProofOfWorkRepository(aliceDB)) + .port(6001) + .nodeRegistry(new TestNodeRegistry(6002)) + .networkHandler(new DefaultNetworkHandler()) + .cryptography(new BouncyCryptography()) + .listener(aliceListener) + .build(); + alice.startup(); + aliceIdentity = alice.createIdentity(false); + + JdbcConfig bobDB = new JdbcConfig("jdbc:h2:mem:bob;DB_CLOSE_DELAY=-1", "sa", ""); + bob = new BitmessageContext.Builder() + .addressRepo(new JdbcAddressRepository(bobDB)) + .inventory(new JdbcInventory(bobDB)) + .messageRepo(new JdbcMessageRepository(bobDB)) + .powRepo(new JdbcProofOfWorkRepository(bobDB)) + .port(6002) + .nodeRegistry(new TestNodeRegistry(6001)) + .networkHandler(new DefaultNetworkHandler()) + .cryptography(new BouncyCryptography()) + .listener(bobListener) + .build(); + bob.startup(); + bobIdentity = bob.createIdentity(false); + } + + @AfterClass + public static void tearDown() { + alice.shutdown(); + bob.shutdown(); + } + + @Test + public void ensureAliceCanSendMessageToBob() throws Exception { + bobListener.reset(); + String originalMessage = UUID.randomUUID().toString(); + alice.send(aliceIdentity, new BitmessageAddress(bobIdentity.getAddress()), "Subject", originalMessage); + + Plaintext plaintext = bobListener.get(5, TimeUnit.MINUTES); + + assertThat(plaintext.getText(), equalTo(originalMessage)); + } +} diff --git a/demo/src/test/java/ch/dissem/bitmessage/TestListener.java b/demo/src/test/java/ch/dissem/bitmessage/TestListener.java new file mode 100644 index 0000000..9c00776 --- /dev/null +++ b/demo/src/test/java/ch/dissem/bitmessage/TestListener.java @@ -0,0 +1,26 @@ +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.entity.Plaintext; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +/** + * Created by chrig on 02.02.2016. + */ +public class TestListener implements BitmessageContext.Listener { + private CompletableFuture<Plaintext> future = new CompletableFuture<>(); + + @Override + public void receive(Plaintext plaintext) { + future.complete(plaintext); + } + + public void reset() { + future = new CompletableFuture<>(); + } + + public Plaintext get(long timeout, TimeUnit unit) throws Exception { + return future.get(timeout, unit); + } +} diff --git a/demo/src/test/java/ch/dissem/bitmessage/TestNodeRegistry.java b/demo/src/test/java/ch/dissem/bitmessage/TestNodeRegistry.java new file mode 100644 index 0000000..71750ed --- /dev/null +++ b/demo/src/test/java/ch/dissem/bitmessage/TestNodeRegistry.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; +import ch.dissem.bitmessage.ports.NodeRegistry; + +import java.util.LinkedList; +import java.util.List; + +/** + * Empty {@link NodeRegistry} that doesn't do anything, but shouldn't break things either. + */ +class TestNodeRegistry implements NodeRegistry { + private List<NetworkAddress> nodes = new LinkedList<>(); + + public TestNodeRegistry(int... ports) { + for (int port : ports) { + nodes.add( + new NetworkAddress.Builder() + .ipv4(127, 0, 0, 1) + .port(port) + .build() + ); + } + } + + @Override + public List<NetworkAddress> getKnownAddresses(int limit, long... streams) { + return nodes; + } + + @Override + public void offerAddresses(List<NetworkAddress> addresses) { + // Ignore + } +} From 985e830779a18990ca67b9e56ce49ec3bfc012dd Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Tue, 2 Feb 2016 21:05:14 +0100 Subject: [PATCH 21/54] Made TTLs easily changeable (albeit not for specific messages) This should make the system test run on Travis CI again --- .../dissem/bitmessage/BitmessageContext.java | 6 +-- .../ch/dissem/bitmessage/InternalContext.java | 7 ++-- .../java/ch/dissem/bitmessage/utils/TTL.java | 40 +++++++++++++++++++ .../bitmessage/security/CryptographyTest.java | 10 ++--- .../java/ch/dissem/bitmessage/SystemTest.java | 6 +++ 5 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/ch/dissem/bitmessage/utils/TTL.java diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index dde6d2d..c99acfb 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -28,6 +28,7 @@ import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Property; +import ch.dissem.bitmessage.utils.TTL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -168,7 +169,7 @@ public class BitmessageContext { msg.getFrom(), to, new Msg(msg), - +2 * DAY + TTL.msg() ); msg.setStatus(SENT); msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.SENT)); @@ -288,7 +289,6 @@ public class BitmessageContext { int connectionLimit = 150; long connectionTTL = 30 * MINUTE; boolean sendPubkeyOnIdentityCreation = true; - long pubkeyTTL = 28; public Builder() { } @@ -383,7 +383,7 @@ public class BitmessageContext { */ public Builder pubkeyTTL(long days) { if (days < 0 || days > 28 * DAY) throw new IllegalArgumentException("TTL must be between 1 and 28 days"); - this.pubkeyTTL = days; + TTL.pubkey(days); return this; } diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java index 54e81a9..bfd4f30 100644 --- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -22,6 +22,7 @@ import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.*; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Singleton; +import ch.dissem.bitmessage.utils.TTL; import ch.dissem.bitmessage.utils.UnixTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,7 +59,6 @@ public class InternalContext { private final long clientNonce; private final long networkNonceTrialsPerByte = 1000; private final long networkExtraBytes = 1000; - private final long pubkeyTTL; private long connectionTTL; private int connectionLimit; @@ -78,7 +78,6 @@ public class InternalContext { this.port = builder.port; this.connectionLimit = builder.connectionLimit; this.connectionTTL = builder.connectionTTL; - this.pubkeyTTL = builder.pubkeyTTL; Singleton.initialize(cryptography); @@ -194,7 +193,7 @@ public class InternalContext { public void sendPubkey(final BitmessageAddress identity, final long targetStream) { try { - long expires = UnixTime.now(pubkeyTTL); + long expires = UnixTime.now(TTL.pubkey()); LOG.info("Expires at " + expires); final ObjectMessage response = new ObjectMessage.Builder() .stream(targetStream) @@ -233,7 +232,7 @@ public class InternalContext { addressRepository.save(contact); } - long expires = UnixTime.now(+pubkeyTTL); + long expires = UnixTime.now(TTL.getpubkey()); LOG.info("Expires at " + expires); final ObjectMessage request = new ObjectMessage.Builder() .stream(contact.getStream()) diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/TTL.java b/core/src/main/java/ch/dissem/bitmessage/utils/TTL.java new file mode 100644 index 0000000..17e31e5 --- /dev/null +++ b/core/src/main/java/ch/dissem/bitmessage/utils/TTL.java @@ -0,0 +1,40 @@ +package ch.dissem.bitmessage.utils; + +import static ch.dissem.bitmessage.utils.UnixTime.DAY; + +/** + * Stores times to live for different object types. Usually this shouldn't be messed with, + * but for tests it might be a good idea to reduce it to a minimum, and on mobile clients + * you might want to optimize it as well. + * + * @author Christian Basler + */ +public class TTL { + private static long msg = 2 * DAY; + private static long getpubkey = 2 * DAY; + private static long pubkey = 28 * DAY; + + public static long msg() { + return msg; + } + + public static void msg(long msg) { + TTL.msg = msg; + } + + public static long getpubkey() { + return getpubkey; + } + + public static void getpubkey(long getpubkey) { + TTL.getpubkey = getpubkey; + } + + public static long pubkey() { + return pubkey; + } + + public static void pubkey(long pubkey) { + TTL.pubkey = pubkey; + } +} diff --git a/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java index 3a68968..d4ab2ad 100644 --- a/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java +++ b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java @@ -1,11 +1,11 @@ package ch.dissem.bitmessage.security; import ch.dissem.bitmessage.InternalContext; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.GenericPayload; import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; -import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.utils.CallbackWaiter; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.UnixTime; @@ -15,13 +15,13 @@ import javax.xml.bind.DatatypeConverter; import java.io.ByteArrayInputStream; import java.io.IOException; -import static ch.dissem.bitmessage.utils.UnixTime.DAY; +import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; import static org.junit.Assert.assertArrayEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** - * Created by chris on 19.07.15. + * @author Christian Basler */ public class CryptographyTest { public static final byte[] TEST_VALUE = "teststring".getBytes(); @@ -72,7 +72,7 @@ public class CryptographyTest { public void testProofOfWorkFails() throws IOException { ObjectMessage objectMessage = new ObjectMessage.Builder() .nonce(new byte[8]) - .expiresTime(UnixTime.now(+2 * DAY)) // 5 minutes + .expiresTime(UnixTime.now(+2 * MINUTE)) .objectType(0) .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) .build(); @@ -83,7 +83,7 @@ public class CryptographyTest { public void testDoProofOfWork() throws Exception { ObjectMessage objectMessage = new ObjectMessage.Builder() .nonce(new byte[8]) - .expiresTime(UnixTime.now(+2 * DAY)) + .expiresTime(UnixTime.now(+2 * MINUTE)) .objectType(0) .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) .build(); diff --git a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java index 5bf2949..fd73dcf 100644 --- a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java +++ b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java @@ -5,6 +5,8 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.repository.*; +import ch.dissem.bitmessage.utils.TTL; +import ch.dissem.bitmessage.utils.UnixTime; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -12,6 +14,7 @@ import org.junit.Test; import java.util.UUID; import java.util.concurrent.TimeUnit; +import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; @@ -29,6 +32,9 @@ public class SystemTest { @BeforeClass public static void setUp() { + TTL.msg(5 * MINUTE); + TTL.getpubkey(5 * MINUTE); + TTL.pubkey(5 * MINUTE); JdbcConfig aliceDB = new JdbcConfig("jdbc:h2:mem:alice;DB_CLOSE_DELAY=-1", "sa", ""); alice = new BitmessageContext.Builder() .addressRepo(new JdbcAddressRepository(aliceDB)) From 91c41fa3bd441214bfa537414a6ec010be6e1b3e Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Tue, 2 Feb 2016 21:23:15 +0100 Subject: [PATCH 22/54] Version 1.0.1 bump --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b944a14..68fb5bc 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ subprojects { sourceCompatibility = 1.7 group = 'ch.dissem.jabit' - version = '1.0.1-SNAPSHOT' + version = '1.0.1' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") From b1599cbd60d98d3067775dd97f459bcbcff053ab Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 3 Feb 2016 07:52:22 +0100 Subject: [PATCH 23/54] This should fix the build on Travis CI / machines that don't have signing configured --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 68fb5bc..0f6cf26 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ subprojects { } signing { - required { isReleaseVersion } + required { isReleaseVersion && project.getProperties().get("signing.keyId")?.length() > 0 } sign configurations.archives } From 5ab577f18a63bdbc310621a46e61c89cfe29b805 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 3 Feb 2016 17:09:26 +0100 Subject: [PATCH 24/54] Update .travis.yml to work with codecov.io --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9bcf999..36e370e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ language: java jdk: - oraclejdk8 +before_install: + - pip install codecov +after_success: + - codecov From ea700755b6efd7a76aba5896be16f5f4701e84c3 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 3 Feb 2016 17:17:31 +0100 Subject: [PATCH 25/54] Update .travis.yml Another try --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 36e370e..aacb38f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,10 @@ language: java +sudo: false # faster builds jdk: - oraclejdk8 + before_install: - - pip install codecov + - pip install --user codecov + after_success: - codecov From 2bfeedc7a95d8c74f8ff85c1d5d78aaa29745892 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 3 Feb 2016 17:32:04 +0100 Subject: [PATCH 26/54] Update build.gradle Another try for codecov.io --- build.gradle | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b944a14..040afda 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ subprojects { apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' + apply plugin: 'jacoco' sourceCompatibility = 1.7 group = 'ch.dissem.jabit' @@ -79,4 +80,13 @@ subprojects { } } } -} \ No newline at end of file + + jacocoTestReport { + reports { + xml.enabled = true + html.enabled = true + } + } + + check.dependsOn jacocoTestReport +} From 354f50687233aa2c4f60ecaf96a4d2aca37870cf Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 3 Feb 2016 19:28:41 +0100 Subject: [PATCH 27/54] Raised timeout for test so hopefully it doesn't fail anymore on Travis CI (otherwise there must be a different problem) --- demo/src/test/java/ch/dissem/bitmessage/SystemTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java index fd73dcf..1309336 100644 --- a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java +++ b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java @@ -6,7 +6,6 @@ import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.repository.*; import ch.dissem.bitmessage.utils.TTL; -import ch.dissem.bitmessage.utils.UnixTime; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -78,7 +77,7 @@ public class SystemTest { String originalMessage = UUID.randomUUID().toString(); alice.send(aliceIdentity, new BitmessageAddress(bobIdentity.getAddress()), "Subject", originalMessage); - Plaintext plaintext = bobListener.get(5, TimeUnit.MINUTES); + Plaintext plaintext = bobListener.get(15, TimeUnit.MINUTES); assertThat(plaintext.getText(), equalTo(originalMessage)); } From 9231cf5eaa9766a0b6bb3a48cb7fe36badeabea4 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Thu, 4 Feb 2016 10:12:43 +0100 Subject: [PATCH 28/54] Skip system tests by default as they don't work on Travis CI --- demo/build.gradle | 2 ++ gradle.properties | 1 + 2 files changed, 3 insertions(+) diff --git a/demo/build.gradle b/demo/build.gradle index 2ab6363..d87b0f3 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -16,6 +16,8 @@ uploadArchives { sourceCompatibility = 1.8 +test.enabled = Boolean.valueOf(systemTestsEnabled) + task fatCapsule(type: FatCapsule) { applicationClass 'ch.dissem.bitmessage.demo.Main' } diff --git a/gradle.properties b/gradle.properties index eb6ed30..bb8beb4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,3 +8,4 @@ signing.password= ossrhUsername= ossrhPassword= +systemTestsEnabled=false \ No newline at end of file From 06dbfbf64a4350e28b49eaedff4b7a4e761a2ad0 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Thu, 4 Feb 2016 13:01:03 +0100 Subject: [PATCH 29/54] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db59adc..9e7f9da 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Jabit [![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=master)](ht A Java implementation for the Bitmessage protocol. To build, use command `gradle build` or `./gradlew build`. -Please note that development is still heavily in progress, and I will break the database a lot until it's ready for prime time. +Please note that it still has its limitations, but the API should now be stable. Jabit uses Semantic Versioning, meaning as long as the major version doesn't change, nothing should break if you update. Security -------- From db64b555101f6c7088defcbc192fe03fb91cd9b8 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sat, 6 Feb 2016 15:47:13 +0100 Subject: [PATCH 30/54] Version 1.0.2-SNAPSHOT bump Fixed NPE if you create a Plaintext object without recipient --- build.gradle | 2 +- core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 09e7d61..917a0d4 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ subprojects { sourceCompatibility = 1.7 group = 'ch.dissem.jabit' - version = '1.0.1' + version = '1.0.2-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java index fbd5d48..fc38c65 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java @@ -455,7 +455,7 @@ public class Plaintext implements Streamable { behaviorBitfield )); } - if (to == null && type != Type.BROADCAST) { + if (to == null && type != Type.BROADCAST && destinationRipe != null) { to = new BitmessageAddress(0, 0, destinationRipe); } return new Plaintext(this); From 9c375d6608fe1d7f3e0da3db39f448125b055bde Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sat, 6 Feb 2016 17:27:12 +0100 Subject: [PATCH 31/54] Update README.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db59adc..8c5a006 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,16 @@ -Jabit [![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=master)](https://travis-ci.org/Dissem/Jabit) +Jabit [![Maven Central](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core) ===== A Java implementation for the Bitmessage protocol. To build, use command `gradle build` or `./gradlew build`. Please note that development is still heavily in progress, and I will break the database a lot until it's ready for prime time. +#### Master +[![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=master)](https://travis-ci.org/Dissem/Jabit) [![codecov.io](https://codecov.io/github/Dissem/Jabit/coverage.svg?branch=master)](https://codecov.io/github/Dissem/Jabit?branch=master) + +#### Develop +[![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=develop)](https://travis-ci.org/Dissem/Jabit?branch=develop) [![codecov.io](https://codecov.io/github/Dissem/Jabit/coverage.svg?branch=develop)](https://codecov.io/github/Dissem/Jabit?branch=develop) + Security -------- From 60adf73616aad41adaabfe663ab69f43a60bb638 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sun, 7 Feb 2016 23:36:35 +0100 Subject: [PATCH 32/54] Improved tests for repositories --- .../repository/JdbcMessageRepositoryTest.java | 39 +++++++-- .../JdbcProofOfWorkRepositoryTest.java | 84 +++++++++++++++++++ 2 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepositoryTest.java diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java index c7c3614..4c93271 100644 --- a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java @@ -30,11 +30,12 @@ import org.junit.Test; import java.util.Arrays; import java.util.List; +import java.util.Random; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; import static ch.dissem.bitmessage.utils.Singleton.security; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; public class JdbcMessageRepositoryTest extends TestBase { private BitmessageAddress contactA; @@ -47,6 +48,7 @@ public class JdbcMessageRepositoryTest extends TestBase { private Label inbox; private Label drafts; + private Label unread; @Before public void setUp() throws Exception { @@ -72,27 +74,28 @@ public class JdbcMessageRepositoryTest extends TestBase { inbox = repo.getLabels(Label.Type.INBOX).get(0); drafts = repo.getLabels(Label.Type.DRAFT).get(0); + unread = repo.getLabels(Label.Type.UNREAD).get(0); - addMessage(contactA, identity, Plaintext.Status.RECEIVED, inbox); + addMessage(contactA, identity, Plaintext.Status.RECEIVED, inbox, unread); addMessage(identity, contactA, Plaintext.Status.DRAFT, drafts); - addMessage(identity, contactB, Plaintext.Status.DRAFT); + addMessage(identity, contactB, Plaintext.Status.DRAFT, unread); } @Test - public void testGetLabels() throws Exception { + public void ensureLabelsAreRetrieved() throws Exception { List<Label> labels = repo.getLabels(); assertEquals(5, labels.size()); } @Test - public void testGetLabelsByType() throws Exception { + public void ensureLabelsCanBeRetrievedByType() throws Exception { List<Label> labels = repo.getLabels(Label.Type.INBOX); assertEquals(1, labels.size()); assertEquals("Inbox", labels.get(0).toString()); } @Test - public void testFindMessagesByLabel() throws Exception { + public void ensureMessagesCanBeFoundByLabel() throws Exception { List<Plaintext> messages = repo.findMessages(inbox); assertEquals(1, messages.size()); Plaintext m = messages.get(0); @@ -101,6 +104,28 @@ public class JdbcMessageRepositoryTest extends TestBase { assertEquals(Plaintext.Status.RECEIVED, m.getStatus()); } + @Test + public void ensureUnreadMessagesCanBeFoundForAllLabels() { + int unread = repo.countUnread(null); + assertThat(unread, is(2)); + } + + @Test + public void ensureUnreadMessagesCanBeFoundByLabel() { + int unread = repo.countUnread(inbox); + assertThat(unread, is(1)); + } + + @Test + public void ensureMessageCanBeRetrievedByInitialHash() { + byte[] initialHash = new byte[64]; + Plaintext message = repo.findMessages(contactA).get(0); + message.setInitialHash(initialHash); + repo.save(message); + Plaintext other = repo.getMessage(initialHash); + assertThat(other, is(message)); + } + @Test public void testFindMessagesByStatus() throws Exception { List<Plaintext> messages = repo.findMessages(Plaintext.Status.RECEIVED); diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepositoryTest.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepositoryTest.java new file mode 100644 index 0000000..c8fbaf0 --- /dev/null +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepositoryTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.repository; + +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.ObjectMessage; +import ch.dissem.bitmessage.entity.payload.GetPubkey; +import ch.dissem.bitmessage.ports.ProofOfWorkRepository; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * @author Christian Basler + */ +public class JdbcProofOfWorkRepositoryTest extends TestBase { + private TestJdbcConfig config; + private JdbcProofOfWorkRepository repo; + + @Before + public void setUp() throws Exception { + config = new TestJdbcConfig(); + config.reset(); + + repo = new JdbcProofOfWorkRepository(config); + + repo.putObject(new ObjectMessage.Builder() + .payload(new GetPubkey(new BitmessageAddress("BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn"))).build(), + 1000, 1000); + } + + @Test + public void ensureObjectIsStored() throws Exception { + int sizeBefore = repo.getItems().size(); + repo.putObject(new ObjectMessage.Builder() + .payload(new GetPubkey(new BitmessageAddress("BM-2D9U2hv3YBMHM1zERP32anKfVKohyPN9x2"))).build(), + 1000, 1000); + assertThat(repo.getItems().size(), is(sizeBefore + 1)); + } + + @Test + public void ensureItemCanBeRetrieved() { + byte[] initialHash = repo.getItems().get(0); + ProofOfWorkRepository.Item item = repo.getItem(initialHash); + assertThat(item, notNullValue()); + assertThat(item.object.getPayload(), instanceOf(GetPubkey.class)); + assertThat(item.nonceTrialsPerByte, is(1000L)); + assertThat(item.extraBytes, is(1000L)); + } + + @Test(expected = RuntimeException.class) + public void ensureRetrievingNonexistingItemThrowsException() { + repo.getItem(new byte[0]); + } + + @Test + public void ensureItemCanBeDeleted() { + byte[] initialHash = repo.getItems().get(0); + repo.removeObject(initialHash); + assertTrue(repo.getItems().isEmpty()); + } + + @Test + public void ensureDeletionOfNonexistingItemIsHandledSilently() { + repo.removeObject(new byte[0]); + } +} From af3e63f592bb076be15ba8715aa730b7dc11f9d0 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Tue, 9 Feb 2016 17:09:22 +0100 Subject: [PATCH 33/54] Improved tests for cryptography --- .../bitmessage/entity/payload/CryptoBox.java | 2 - .../bitmessage/security/CryptographyTest.java | 86 +++++++++++++++---- .../repository/JdbcMessageRepositoryTest.java | 7 +- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java index fe45ac5..3d1c926 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java @@ -38,8 +38,6 @@ public class CryptoBox implements Streamable { private final byte[] mac; private byte[] encrypted; - private long addressVersion; - public CryptoBox(Streamable data, byte[] K) throws IOException { this(Encode.bytes(data), K); diff --git a/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java index d4ab2ad..ef3fcbf 100644 --- a/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java +++ b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java @@ -4,19 +4,24 @@ import ch.dissem.bitmessage.InternalContext; import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.GenericPayload; +import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import ch.dissem.bitmessage.utils.CallbackWaiter; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.UnixTime; +import org.junit.BeforeClass; import org.junit.Test; import javax.xml.bind.DatatypeConverter; import java.io.ByteArrayInputStream; import java.io.IOException; +import static ch.dissem.bitmessage.utils.UnixTime.DAY; import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; +import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -33,50 +38,51 @@ public class CryptographyTest { public static final byte[] TEST_RIPEMD160 = DatatypeConverter.parseHexBinary("" + "cd566972b5e50104011a92b59fa8e0b1234851ae"); - private static BouncyCryptography security; + private static BouncyCryptography crypto; - public CryptographyTest() { - security = new BouncyCryptography(); - Singleton.initialize(security); + @BeforeClass + public static void setUp() { + crypto = new BouncyCryptography(); + Singleton.initialize(crypto); InternalContext ctx = mock(InternalContext.class); when(ctx.getProofOfWorkEngine()).thenReturn(new MultiThreadedPOWEngine()); - security.setContext(ctx); + crypto.setContext(ctx); } @Test public void testRipemd160() { - assertArrayEquals(TEST_RIPEMD160, security.ripemd160(TEST_VALUE)); + assertArrayEquals(TEST_RIPEMD160, crypto.ripemd160(TEST_VALUE)); } @Test public void testSha1() { - assertArrayEquals(TEST_SHA1, security.sha1(TEST_VALUE)); + assertArrayEquals(TEST_SHA1, crypto.sha1(TEST_VALUE)); } @Test public void testSha512() { - assertArrayEquals(TEST_SHA512, security.sha512(TEST_VALUE)); + assertArrayEquals(TEST_SHA512, crypto.sha512(TEST_VALUE)); } @Test public void testChaining() { - assertArrayEquals(TEST_SHA512, security.sha512("test".getBytes(), "string".getBytes())); + assertArrayEquals(TEST_SHA512, crypto.sha512("test".getBytes(), "string".getBytes())); } @Test - public void testDoubleHash() { - assertArrayEquals(security.sha512(TEST_SHA512), security.doubleSha512(TEST_VALUE)); + public void ensureDoubleHashYieldsSameResultAsHashOfHash() { + assertArrayEquals(crypto.sha512(TEST_SHA512), crypto.doubleSha512(TEST_VALUE)); } @Test(expected = IOException.class) - public void testProofOfWorkFails() throws IOException { + public void ensureExceptionForInsufficientProofOfWork() throws IOException { ObjectMessage objectMessage = new ObjectMessage.Builder() .nonce(new byte[8]) - .expiresTime(UnixTime.now(+2 * MINUTE)) + .expiresTime(UnixTime.now(+28 * DAY)) .objectType(0) .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) .build(); - security.checkProofOfWork(objectMessage, 1000, 1000); + crypto.checkProofOfWork(objectMessage, 1000, 1000); } @Test @@ -88,7 +94,7 @@ public class CryptographyTest { .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) .build(); final CallbackWaiter<byte[]> waiter = new CallbackWaiter<>(); - security.doProofOfWork(objectMessage, 1000, 1000, + crypto.doProofOfWork(objectMessage, 1000, 1000, new ProofOfWorkEngine.Callback() { @Override public void onNonceCalculated(byte[] initialHash, byte[] nonce) { @@ -96,6 +102,52 @@ public class CryptographyTest { } }); objectMessage.setNonce(waiter.waitForValue()); - security.checkProofOfWork(objectMessage, 1000, 1000); + crypto.checkProofOfWork(objectMessage, 1000, 1000); } -} \ No newline at end of file + + @Test + public void ensureEncryptionAndDecryptionWorks() { + byte[] data = crypto.randomBytes(100); + byte[] key_e = crypto.randomBytes(32); + byte[] iv = crypto.randomBytes(16); + byte[] encrypted = crypto.crypt(true, data, key_e, iv); + byte[] decrypted = crypto.crypt(false, encrypted, key_e, iv); + assertArrayEquals(data, decrypted); + } + + @Test(expected = IllegalArgumentException.class) + public void ensureDecryptionFailsWithInvalidCypherText() { + byte[] data = crypto.randomBytes(128); + byte[] key_e = crypto.randomBytes(32); + byte[] iv = crypto.randomBytes(16); + crypto.crypt(false, data, key_e, iv); + } + + @Test + public void testMultiplication() { + byte[] a = crypto.randomBytes(PrivateKey.PRIVATE_KEY_SIZE); + byte[] A = crypto.createPublicKey(a); + + byte[] b = crypto.randomBytes(PrivateKey.PRIVATE_KEY_SIZE); + byte[] B = crypto.createPublicKey(b); + + assertArrayEquals(crypto.multiply(A, b), crypto.multiply(B, a)); + } + + @Test + public void ensureSignatureIsValid() { + byte[] data = crypto.randomBytes(100); + PrivateKey privateKey = new PrivateKey(false, 1, 1000, 1000); + byte[] signature = crypto.getSignature(data, privateKey); + assertThat(crypto.isSignatureValid(data, signature, privateKey.getPubkey()), is(true)); + } + + @Test + public void ensureSignatureIsInvalidForTemperedData() { + byte[] data = crypto.randomBytes(100); + PrivateKey privateKey = new PrivateKey(false, 1, 1000, 1000); + byte[] signature = crypto.getSignature(data, privateKey); + data[0]++; + assertThat(crypto.isSignatureValid(data, signature, privateKey.getPubkey()), is(false)); + } +} diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java index 4c93271..816eafa 100644 --- a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcMessageRepositoryTest.java @@ -30,7 +30,6 @@ import org.junit.Test; import java.util.Arrays; import java.util.List; -import java.util.Random; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; import static ch.dissem.bitmessage.utils.Singleton.security; @@ -42,8 +41,6 @@ public class JdbcMessageRepositoryTest extends TestBase { private BitmessageAddress contactB; private BitmessageAddress identity; - private TestJdbcConfig config; - private AddressRepository addressRepo; private MessageRepository repo; private Label inbox; @@ -52,9 +49,9 @@ public class JdbcMessageRepositoryTest extends TestBase { @Before public void setUp() throws Exception { - config = new TestJdbcConfig(); + TestJdbcConfig config = new TestJdbcConfig(); config.reset(); - addressRepo = new JdbcAddressRepository(config); + AddressRepository addressRepo = new JdbcAddressRepository(config); repo = new JdbcMessageRepository(config); new InternalContext(new BitmessageContext.Builder() .cryptography(security()) From e4a69f42b09fe9a95a780f9185528104e830344b Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sat, 13 Feb 2016 08:03:05 +0100 Subject: [PATCH 34/54] Fixed problem with sending broadcasts (while adding some tests) --- .../dissem/bitmessage/BitmessageContext.java | 14 +- .../ch/dissem/bitmessage/factory/Factory.java | 3 +- .../bitmessage/BitmessageContextTest.java | 164 ++++++++++++++++++ .../bitmessage/utils/MessageMatchers.java | 58 +++++++ .../java/ch/dissem/bitmessage/SystemTest.java | 38 ++-- 5 files changed, 261 insertions(+), 16 deletions(-) create mode 100644 core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java create mode 100644 core/src/test/java/ch/dissem/bitmessage/utils/MessageMatchers.java diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index c99acfb..24a4aaf 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -26,6 +26,7 @@ import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.DecryptionFailedException; +import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Property; import ch.dissem.bitmessage.utils.TTL; @@ -168,7 +169,7 @@ public class BitmessageContext { ctx.send( msg.getFrom(), to, - new Msg(msg), + wrapInObjectPayload(msg), TTL.msg() ); msg.setStatus(SENT); @@ -179,6 +180,17 @@ public class BitmessageContext { }); } + private ObjectPayload wrapInObjectPayload(Plaintext msg) { + switch (msg.getType()) { + case MSG: + return new Msg(msg); + case BROADCAST: + return Factory.getBroadcast(msg); + default: + throw new RuntimeException("Unknown message type " + msg.getType()); + } + } + public void startup() { ctx.getNetworkHandler().start(networkListener); } diff --git a/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java b/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java index 33604ab..11d4330 100644 --- a/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java +++ b/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java @@ -196,7 +196,8 @@ public class Factory { } } - public static ObjectPayload getBroadcast(BitmessageAddress sendingAddress, Plaintext plaintext) { + public static ObjectPayload getBroadcast(Plaintext plaintext) { + BitmessageAddress sendingAddress = plaintext.getFrom(); if (sendingAddress.getVersion() < 4) { return new V4Broadcast(sendingAddress, plaintext); } else { diff --git a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java new file mode 100644 index 0000000..3eead03 --- /dev/null +++ b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java @@ -0,0 +1,164 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.ObjectMessage; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.payload.ObjectType; +import ch.dissem.bitmessage.entity.payload.Pubkey; +import ch.dissem.bitmessage.ports.*; +import ch.dissem.bitmessage.utils.MessageMatchers; +import ch.dissem.bitmessage.utils.Singleton; +import ch.dissem.bitmessage.utils.TestUtils; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.LinkedList; +import java.util.List; + +import static ch.dissem.bitmessage.entity.payload.ObjectType.*; +import static ch.dissem.bitmessage.utils.MessageMatchers.object; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +/** + * @author Christian Basler + */ +public class BitmessageContextTest { + private BitmessageContext ctx; + private BitmessageContext.Listener listener; + + @Before + public void setUp() throws Exception { + Field field = Singleton.class.getDeclaredField("cryptography"); + field.setAccessible(true); + field.set(null, null); + + listener = mock(BitmessageContext.Listener.class); + ctx = new BitmessageContext.Builder() + .addressRepo(mock(AddressRepository.class)) + .cryptography(new BouncyCryptography()) + .inventory(mock(Inventory.class)) + .listener(listener) + .messageCallback(mock(MessageCallback.class)) + .messageRepo(mock(MessageRepository.class)) + .networkHandler(mock(NetworkHandler.class)) + .nodeRegistry(mock(NodeRegistry.class)) + .powRepo(mock(ProofOfWorkRepository.class)) + .proofOfWorkEngine(mock(ProofOfWorkEngine.class)) + .build(); + } + + @Test + public void ensureContactIsSavedAndPubkeyRequested() { + BitmessageAddress contact = new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"); + ctx.addContact(contact); + + verify(ctx.addresses(), times(2)).save(contact); + verify(ctx.internals().getProofOfWorkEngine()) + .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class)); + } + + @Test + public void ensurePubkeyIsNotRequestedIfItExists() throws Exception { + ObjectMessage object = TestUtils.loadObjectMessage(2, "V2Pubkey.payload"); + Pubkey pubkey = (Pubkey) object.getPayload(); + BitmessageAddress contact = new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"); + contact.setPubkey(pubkey); + + ctx.addContact(contact); + + verify(ctx.addresses(), times(1)).save(contact); + verify(ctx.internals().getProofOfWorkEngine(), never()) + .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class)); + } + + @Test + public void ensureSubscriptionIsAddedAndExistingBroadcastsRetrieved() throws Exception { + BitmessageAddress address = new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ"); + + List<ObjectMessage> objects = new LinkedList<>(); + objects.add(TestUtils.loadObjectMessage(4, "V4Broadcast.payload")); + objects.add(TestUtils.loadObjectMessage(5, "V5Broadcast.payload")); + when(ctx.internals().getInventory().getObjects(eq(address.getStream()), anyLong(), any(ObjectType.class))) + .thenReturn(objects); + + ctx.addSubscribtion(address); + + verify(ctx.addresses(), times(1)).save(address); + assertThat(address.isSubscribed(), is(true)); + verify(ctx.internals().getInventory()).getObjects(eq(address.getStream()), anyLong(), any(ObjectType.class)); + verify(listener).receive(any(Plaintext.class)); + } + + @Test + public void ensureIdentityIsCreated() { + assertThat(ctx.createIdentity(false), notNullValue()); + } + + @Test + public void ensureMessageIsSent() throws Exception { + ctx.send(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"), TestUtils.loadContact(), + "Subject", "Message"); + verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce()) + .putObject(object(MSG), eq(1000L), eq(1000L)); + verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Plaintext.Type.MSG)); + } + + @Test + public void ensurePubkeyIsRequestedIfItIsMissing() throws Exception { + ctx.send(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"), + new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"), + "Subject", "Message"); + verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce()) + .putObject(object(GET_PUBKEY), eq(1000L), eq(1000L)); + verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Plaintext.Type.MSG)); + } + + @Test(expected = IllegalArgumentException.class) + public void ensureSenderMustBeIdentity() { + ctx.send(new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"), + new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"), + "Subject", "Message"); + } + + @Test + public void ensureBroadcastIsSent() throws Exception { + ctx.broadcast(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"), + "Subject", "Message"); + verify(ctx.internals().getProofOfWorkRepository(), timeout(10000).atLeastOnce()) + .putObject(object(BROADCAST), eq(1000L), eq(1000L)); + verify(ctx.internals().getProofOfWorkEngine()) + .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class)); + verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Plaintext.Type.BROADCAST)); + } + + @Test(expected = IllegalArgumentException.class) + public void ensureSenderWithoutPrivateKeyThrowsException() { + Plaintext msg = new Plaintext.Builder(Plaintext.Type.BROADCAST) + .from(new BitmessageAddress("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")) + .message("Subject", "Message") + .build(); + ctx.send(msg); + } +} diff --git a/core/src/test/java/ch/dissem/bitmessage/utils/MessageMatchers.java b/core/src/test/java/ch/dissem/bitmessage/utils/MessageMatchers.java new file mode 100644 index 0000000..8bb1e36 --- /dev/null +++ b/core/src/test/java/ch/dissem/bitmessage/utils/MessageMatchers.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.utils; + +import ch.dissem.bitmessage.entity.ObjectMessage; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.payload.ObjectType; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.mockito.Matchers; + +/** + * @author Christian Basler + */ +public class MessageMatchers { + public static Plaintext plaintext(final Plaintext.Type type) { + return Matchers.argThat(new BaseMatcher<Plaintext>() { + @Override + public boolean matches(Object item) { + return item instanceof Plaintext && ((Plaintext) item).getType() == type; + } + + @Override + public void describeTo(Description description) { + description.appendText("type should be ").appendValue(type); + } + }); + } + + public static ObjectMessage object(final ObjectType type) { + return Matchers.argThat(new BaseMatcher<ObjectMessage>() { + @Override + public boolean matches(Object item) { + return item instanceof ObjectMessage && ((ObjectMessage) item).getPayload().getType() == type; + } + + @Override + public void describeTo(Description description) { + description.appendText("payload type should be ").appendValue(type); + } + }); + } +} diff --git a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java index 1309336..a2e3da7 100644 --- a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java +++ b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java @@ -6,9 +6,7 @@ import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.repository.*; import ch.dissem.bitmessage.utils.TTL; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.*; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -21,16 +19,16 @@ import static org.junit.Assert.assertThat; * @author Christian Basler */ public class SystemTest { - static BitmessageContext alice; - static TestListener aliceListener = new TestListener(); - static BitmessageAddress aliceIdentity; + private BitmessageContext alice; + private TestListener aliceListener = new TestListener(); + private BitmessageAddress aliceIdentity; - static BitmessageContext bob; - static TestListener bobListener = new TestListener(); - static BitmessageAddress bobIdentity; + private BitmessageContext bob; + private TestListener bobListener = new TestListener(); + private BitmessageAddress bobIdentity; - @BeforeClass - public static void setUp() { + @Before + public void setUp() { TTL.msg(5 * MINUTE); TTL.getpubkey(5 * MINUTE); TTL.pubkey(5 * MINUTE); @@ -65,20 +63,32 @@ public class SystemTest { bobIdentity = bob.createIdentity(false); } - @AfterClass - public static void tearDown() { + @After + public void tearDown() { alice.shutdown(); bob.shutdown(); } @Test public void ensureAliceCanSendMessageToBob() throws Exception { - bobListener.reset(); String originalMessage = UUID.randomUUID().toString(); alice.send(aliceIdentity, new BitmessageAddress(bobIdentity.getAddress()), "Subject", originalMessage); Plaintext plaintext = bobListener.get(15, TimeUnit.MINUTES); + assertThat(plaintext.getType(), equalTo(Plaintext.Type.MSG)); + assertThat(plaintext.getText(), equalTo(originalMessage)); + } + + @Test + public void ensureBobCanReceiveBroadcastFromAlice() throws Exception { + String originalMessage = UUID.randomUUID().toString(); + bob.addSubscribtion(new BitmessageAddress(aliceIdentity.getAddress())); + alice.broadcast(aliceIdentity, "Subject", originalMessage); + + Plaintext plaintext = bobListener.get(15, TimeUnit.MINUTES); + + assertThat(plaintext.getType(), equalTo(Plaintext.Type.BROADCAST)); assertThat(plaintext.getText(), equalTo(originalMessage)); } } From f71671e04ad8c4c46e424878315e44c6ef4b5caa Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Mon, 15 Feb 2016 07:33:38 +0100 Subject: [PATCH 35/54] Added tests for DefaultMessageListener and ProofOfWorkService and some minor improvements --- .../dissem/bitmessage/ProofOfWorkService.java | 6 +- .../ch/dissem/bitmessage/factory/Factory.java | 2 +- .../ch/dissem/bitmessage/utils/Singleton.java | 6 +- .../bitmessage/BitmessageContextTest.java | 54 ++++++- .../DefaultMessageListenerTest.java | 150 ++++++++++++++++++ .../bitmessage/ProofOfWorkServiceTest.java | 113 +++++++++++++ .../ch/dissem/bitmessage/utils/TestBase.java | 6 +- 7 files changed, 321 insertions(+), 16 deletions(-) create mode 100644 core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java create mode 100644 core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java diff --git a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java index ecd1099..ad62dde 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java +++ b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java @@ -5,10 +5,10 @@ import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.PlaintextHolder; import ch.dissem.bitmessage.entity.payload.Pubkey; +import ch.dissem.bitmessage.ports.Cryptography; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; -import ch.dissem.bitmessage.ports.Cryptography; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,16 +61,14 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC public void onNonceCalculated(byte[] initialHash, byte[] nonce) { ObjectMessage object = powRepo.getItem(initialHash).object; object.setNonce(nonce); -// messageCallback.proofOfWorkCompleted(payload); Plaintext plaintext = messageRepo.getMessage(initialHash); if (plaintext != null) { plaintext.setInventoryVector(object.getInventoryVector()); messageRepo.save(plaintext); } ctx.getInventory().storeObject(object); - ctx.getProofOfWorkRepository().removeObject(initialHash); + powRepo.removeObject(initialHash); ctx.getNetworkHandler().offer(object.getInventoryVector()); -// messageCallback.messageOffered(payload, object.getInventoryVector()); } @Override diff --git a/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java b/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java index 11d4330..e0db3f4 100644 --- a/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java +++ b/core/src/main/java/ch/dissem/bitmessage/factory/Factory.java @@ -196,7 +196,7 @@ public class Factory { } } - public static ObjectPayload getBroadcast(Plaintext plaintext) { + public static Broadcast getBroadcast(Plaintext plaintext) { BitmessageAddress sendingAddress = plaintext.getFrom(); if (sendingAddress.getVersion() < 4) { return new V4Broadcast(sendingAddress, plaintext); diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/Singleton.java b/core/src/main/java/ch/dissem/bitmessage/utils/Singleton.java index 0c7134b..a751c65 100644 --- a/core/src/main/java/ch/dissem/bitmessage/utils/Singleton.java +++ b/core/src/main/java/ch/dissem/bitmessage/utils/Singleton.java @@ -19,16 +19,14 @@ package ch.dissem.bitmessage.utils; import ch.dissem.bitmessage.ports.Cryptography; /** - * Created by chris on 20.07.15. + * @author Christian Basler */ public class Singleton { private static Cryptography cryptography; public static void initialize(Cryptography cryptography) { synchronized (Singleton.class) { - if (Singleton.cryptography == null) { - Singleton.cryptography = cryptography; - } + Singleton.cryptography = cryptography; } } diff --git a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java index 3eead03..828e794 100644 --- a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java @@ -26,10 +26,12 @@ import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.MessageMatchers; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.TestUtils; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; import org.junit.Before; import org.junit.Test; -import java.lang.reflect.Field; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -50,10 +52,7 @@ public class BitmessageContextTest { @Before public void setUp() throws Exception { - Field field = Singleton.class.getDeclaredField("cryptography"); - field.setAccessible(true); - field.set(null, null); - + Singleton.initialize(null); listener = mock(BitmessageContext.Listener.class); ctx = new BitmessageContext.Builder() .addressRepo(mock(AddressRepository.class)) @@ -93,6 +92,51 @@ public class BitmessageContextTest { .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class)); } + @Test + public void ensureV2PubkeyIsNotRequestedIfItExistsInInventory() throws Exception { + BitmessageAddress contact = new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"); + when(ctx.internals().getInventory().getObjects(anyLong(), anyLong(), any(ObjectType.class))) + .thenReturn(Collections.singletonList( + TestUtils.loadObjectMessage(2, "V2Pubkey.payload") + )); + + ctx.addContact(contact); + + verify(ctx.addresses(), atLeastOnce()).save(contact); + verify(ctx.internals().getProofOfWorkEngine(), never()) + .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class)); + } + + @Test + public void ensureV4PubkeyIsNotRequestedIfItExistsInInventory() throws Exception { + BitmessageAddress contact = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h"); + when(ctx.internals().getInventory().getObjects(anyLong(), anyLong(), any(ObjectType.class))) + .thenReturn(Collections.singletonList( + TestUtils.loadObjectMessage(2, "V4Pubkey.payload") + )); + final BitmessageAddress stored = new BitmessageAddress(contact.getAddress()); + stored.setAlias("Test"); + when(ctx.addresses().getAddress(contact.getAddress())).thenReturn(stored); + + ctx.addContact(contact); + + verify(ctx.addresses(), atLeastOnce()).save(argThat(new BaseMatcher<BitmessageAddress>() { + @Override + public boolean matches(Object item) { + return item instanceof BitmessageAddress + && ((BitmessageAddress) item).getPubkey() != null + && stored.getAlias().equals(((BitmessageAddress) item).getAlias()); + } + + @Override + public void describeTo(Description description) { + description.appendText("pubkey must not be null and alias must be ").appendValue(stored.getAlias()); + } + })); + verify(ctx.internals().getProofOfWorkEngine(), never()) + .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class)); + } + @Test public void ensureSubscriptionIsAddedAndExistingBroadcastsRetrieved() throws Exception { BitmessageAddress address = new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ"); diff --git a/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java b/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java new file mode 100644 index 0000000..a6e6c53 --- /dev/null +++ b/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java @@ -0,0 +1,150 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.ObjectMessage; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.payload.Broadcast; +import ch.dissem.bitmessage.entity.payload.GetPubkey; +import ch.dissem.bitmessage.entity.payload.Msg; +import ch.dissem.bitmessage.factory.Factory; +import ch.dissem.bitmessage.ports.AddressRepository; +import ch.dissem.bitmessage.ports.MessageRepository; +import ch.dissem.bitmessage.utils.Singleton; +import ch.dissem.bitmessage.utils.TestBase; +import ch.dissem.bitmessage.utils.TestUtils; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; + +import static ch.dissem.bitmessage.entity.Plaintext.Status.PUBKEY_REQUESTED; +import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST; +import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; +import static ch.dissem.bitmessage.utils.MessageMatchers.plaintext; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.*; + +/** + * @author Christian Basler + */ +public class DefaultMessageListenerTest extends TestBase { + @Mock + private AddressRepository addressRepo; + @Mock + private MessageRepository messageRepo; + + private InternalContext ctx; + private DefaultMessageListener listener; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + ctx = mock(InternalContext.class); + Singleton.initialize(new BouncyCryptography()); + when(ctx.getAddressRepository()).thenReturn(addressRepo); + when(ctx.getMessageRepository()).thenReturn(messageRepo); + + listener = new DefaultMessageListener(ctx, mock(BitmessageContext.Listener.class)); + } + + @Test + public void ensurePubkeyIsSentOnRequest() throws Exception { + BitmessageAddress identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"); + when(addressRepo.findIdentity(any(byte[].class))) + .thenReturn(identity); + listener.receive(new ObjectMessage.Builder() + .stream(2) + .payload(new GetPubkey(new BitmessageAddress("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))) + .build()); + verify(ctx).sendPubkey(eq(identity), eq(2L)); + } + + @Test + public void ensureIncomingPubkeyIsAddedToContact() throws Exception { + BitmessageAddress identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"); + BitmessageAddress contact = new BitmessageAddress(identity.getAddress()); + when(addressRepo.findContact(any(byte[].class))) + .thenReturn(contact); + when(messageRepo.findMessages(eq(PUBKEY_REQUESTED), eq(contact))) + .thenReturn(Collections.singletonList( + new Plaintext.Builder(MSG).from(identity).to(contact).message("S", "T").build() + )); + + ObjectMessage objectMessage = new ObjectMessage.Builder() + .stream(2) + .payload(identity.getPubkey()) + .build(); + objectMessage.sign(identity.getPrivateKey()); + objectMessage.encrypt(Singleton.security().createPublicKey(identity.getPublicDecryptionKey())); + listener.receive(objectMessage); + + verify(addressRepo).save(any(BitmessageAddress.class)); + } + + @Test + public void ensureIncomingMessageIsSaved() throws Exception { + BitmessageAddress identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"); + BitmessageAddress contact = new BitmessageAddress(identity.getAddress()); + + when(addressRepo.getIdentities()).thenReturn(Collections.singletonList(identity)); + + ObjectMessage objectMessage = new ObjectMessage.Builder() + .stream(2) + .payload(new Msg(new Plaintext.Builder(MSG) + .from(identity) + .to(contact) + .message("S", "T") + .build())) + .nonce(new byte[8]) + .build(); + objectMessage.sign(identity.getPrivateKey()); + objectMessage.encrypt(identity.getPubkey()); + + listener.receive(objectMessage); + + verify(messageRepo, atLeastOnce()).save(plaintext(MSG)); + } + + @Test + public void ensureIncomingBroadcastIsSaved() throws Exception { + BitmessageAddress identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"); + + when(addressRepo.getSubscriptions(anyLong())).thenReturn(Collections.singletonList(identity)); + + Broadcast broadcast = Factory.getBroadcast(new Plaintext.Builder(BROADCAST) + .from(identity) + .message("S", "T") + .build()); + ObjectMessage objectMessage = new ObjectMessage.Builder() + .stream(2) + .payload(broadcast) + .nonce(new byte[8]) + .build(); + objectMessage.sign(identity.getPrivateKey()); + broadcast.encrypt(); + + listener.receive(objectMessage); + + verify(messageRepo, atLeastOnce()).save(plaintext(BROADCAST)); + } +} diff --git a/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java b/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java new file mode 100644 index 0000000..eb5d368 --- /dev/null +++ b/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.ObjectMessage; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.payload.GetPubkey; +import ch.dissem.bitmessage.entity.payload.Msg; +import ch.dissem.bitmessage.ports.*; +import ch.dissem.bitmessage.utils.Singleton; +import ch.dissem.bitmessage.utils.TestUtils; +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; + +import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.*; + +/** + * @author Christian Basler + */ +public class ProofOfWorkServiceTest { + private ProofOfWorkService proofOfWorkService; + + private Cryptography cryptography; + @Mock + private InternalContext ctx; + @Mock + private ProofOfWorkRepository proofOfWorkRepo; + @Mock + private Inventory inventory; + @Mock + private NetworkHandler networkHandler; + @Mock + private MessageRepository messageRepo; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + cryptography = spy(new BouncyCryptography()); + Singleton.initialize(cryptography); + + ctx = mock(InternalContext.class); + when(ctx.getProofOfWorkRepository()).thenReturn(proofOfWorkRepo); + when(ctx.getInventory()).thenReturn(inventory); + when(ctx.getNetworkHandler()).thenReturn(networkHandler); + when(ctx.getMessageRepository()).thenReturn(messageRepo); + + proofOfWorkService = new ProofOfWorkService(); + proofOfWorkService.setContext(ctx); + } + + @Test + public void ensureMissingProofOfWorkIsDone() { + when(proofOfWorkRepo.getItems()).thenReturn(Arrays.asList(new byte[64])); + when(proofOfWorkRepo.getItem(any(byte[].class))).thenReturn(new ProofOfWorkRepository.Item(null, 1001, 1002)); + doNothing().when(cryptography).doProofOfWork(any(ObjectMessage.class), anyLong(), anyLong(), any(ProofOfWorkEngine.Callback.class)); + + proofOfWorkService.doMissingProofOfWork(); + + verify(cryptography).doProofOfWork((ObjectMessage) isNull(), eq(1001L), eq(1002L), + any(ProofOfWorkEngine.Callback.class)); + } + + @Test + public void ensureCalculatedNonceIsStored() throws Exception { + BitmessageAddress identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"); + BitmessageAddress address = TestUtils.loadContact(); + Plaintext plaintext = new Plaintext.Builder(MSG).from(identity).to(address).message("", "").build(); + ObjectMessage object = new ObjectMessage.Builder() + .payload(new Msg(plaintext)) + .build(); + object.sign(identity.getPrivateKey()); + object.encrypt(address.getPubkey()); + byte[] initialHash = new byte[64]; + byte[] nonce = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; + + when(proofOfWorkRepo.getItem(initialHash)).thenReturn(new ProofOfWorkRepository.Item(object, 1001, 1002)); + when(messageRepo.getMessage(initialHash)).thenReturn(plaintext); + + proofOfWorkService.onNonceCalculated(initialHash, nonce); + + verify(proofOfWorkRepo).removeObject(eq(initialHash)); + verify(inventory).storeObject(eq(object)); + verify(networkHandler).offer(eq(object.getInventoryVector())); + assertThat(plaintext.getInventoryVector(), equalTo(object.getInventoryVector())); + } +} diff --git a/core/src/test/java/ch/dissem/bitmessage/utils/TestBase.java b/core/src/test/java/ch/dissem/bitmessage/utils/TestBase.java index e757d91..4c73fe3 100644 --- a/core/src/test/java/ch/dissem/bitmessage/utils/TestBase.java +++ b/core/src/test/java/ch/dissem/bitmessage/utils/TestBase.java @@ -17,12 +17,14 @@ package ch.dissem.bitmessage.utils; import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; +import org.junit.BeforeClass; /** - * Created by chris on 20.07.15. + * @author Christian Basler */ public class TestBase { - static { + @BeforeClass + public static void setUpClass() { Singleton.initialize(new BouncyCryptography()); } } From ccb102efd7869edd59ce282f1145b737db2a260e Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Mon, 15 Feb 2016 16:54:13 +0100 Subject: [PATCH 36/54] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c5a006..d112d3e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Jabit [![Maven Central](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core) +Jabit [![Maven Central](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core) [![Javadoc](https://javadoc-emblem.rhcloud.com/doc/ch.dissem.jabit/jabit-core/badge.svg)](http://www.javadoc.io/doc/ch.dissem.jabit/jabit-core) ===== A Java implementation for the Bitmessage protocol. To build, use command `gradle build` or `./gradlew build`. From 86accb94f21bddd47e46726a68de927888b9c29b Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 24 Feb 2016 14:34:14 +0100 Subject: [PATCH 37/54] Update README.md added link to IRC channel (thanks, kiwiirc!) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d112d3e..94d5419 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Jabit [![Maven Central](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core) [![Javadoc](https://javadoc-emblem.rhcloud.com/doc/ch.dissem.jabit/jabit-core/badge.svg)](http://www.javadoc.io/doc/ch.dissem.jabit/jabit-core) +Jabit [![Maven Central](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core) [![Javadoc](https://javadoc-emblem.rhcloud.com/doc/ch.dissem.jabit/jabit-core/badge.svg)](http://www.javadoc.io/doc/ch.dissem.jabit/jabit-core) [![Visit our IRC channel](https://img.shields.io/badge/irc-%23jabit-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/#jabit) ===== A Java implementation for the Bitmessage protocol. To build, use command `gradle build` or `./gradlew build`. From f17f26bf349c9ae343e6d629885756523cd630c7 Mon Sep 17 00:00:00 2001 From: Erkan Yilmaz <erkan77@gmail.com> Date: Wed, 24 Feb 2016 15:14:42 +0100 Subject: [PATCH 38/54] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e7f9da..16a3c03 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Project Status Basically, everything needed for a working Bitmessage client is there: * Creating new identities (private addresses) -* Adding contracts and subscriptions +* Adding contacts and subscriptions * Receiving broadcasts * Receiving messages * Sending messages and broadcasts From a72718d4e8c51722ab5db78902e23aa369eeec54 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 24 Feb 2016 16:53:11 +0100 Subject: [PATCH 39/54] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 94d5419..4d11060 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ -Jabit [![Maven Central](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core) [![Javadoc](https://javadoc-emblem.rhcloud.com/doc/ch.dissem.jabit/jabit-core/badge.svg)](http://www.javadoc.io/doc/ch.dissem.jabit/jabit-core) [![Visit our IRC channel](https://img.shields.io/badge/irc-%23jabit-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/#jabit) +Jabit ===== +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core) +[![Javadoc](https://javadoc-emblem.rhcloud.com/doc/ch.dissem.jabit/jabit-core/badge.svg)](http://www.javadoc.io/doc/ch.dissem.jabit/jabit-core) +[![GitHub license](https://img.shields.io/github/license/Dissem/Jabit.svg)](https://raw.githubusercontent.com/Dissem/Jabit/master/LICENSE) +[![Visit our IRC channel](https://img.shields.io/badge/irc-%23jabit-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/#jabit) A Java implementation for the Bitmessage protocol. To build, use command `gradle build` or `./gradlew build`. -Please note that development is still heavily in progress, and I will break the database a lot until it's ready for prime time. +There are still some features missing, most notably acknowledgements. The API however should be stable, and it should work well enough for most use cases. #### Master [![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=master)](https://travis-ci.org/Dissem/Jabit) [![codecov.io](https://codecov.io/github/Dissem/Jabit/coverage.svg?branch=master)](https://codecov.io/github/Dissem/Jabit?branch=master) From 4dd639e6515c41630a21dcbf8fe5289d4c33adea Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 24 Feb 2016 22:51:35 +0100 Subject: [PATCH 40/54] Code cleanup --- .../bitmessage/BaseMessageCallback.java | 47 +++++++++++++++++++ .../dissem/bitmessage/BitmessageContext.java | 18 +------ .../bitmessage/DefaultMessageListener.java | 5 +- .../ch/dissem/bitmessage/InternalContext.java | 5 +- .../bitmessage/entity/NetworkMessage.java | 3 +- .../bitmessage/entity/ObjectMessage.java | 3 -- .../entity/valueobject/NetworkAddress.java | 3 +- .../exception/ApplicationException.java | 26 ++++++++++ .../bitmessage/entity/SerializationTest.java | 1 + .../bitmessage/security/CryptographyTest.java | 8 +++- .../bitmessage/networking/Connection.java | 2 +- .../networking/DefaultNetworkHandler.java | 2 + .../networking/NetworkHandlerTest.java | 16 +++---- .../bitmessage/repository/JdbcInventory.java | 5 +- 14 files changed, 107 insertions(+), 37 deletions(-) create mode 100644 core/src/main/java/ch/dissem/bitmessage/BaseMessageCallback.java create mode 100644 core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java diff --git a/core/src/main/java/ch/dissem/bitmessage/BaseMessageCallback.java b/core/src/main/java/ch/dissem/bitmessage/BaseMessageCallback.java new file mode 100644 index 0000000..bf46b74 --- /dev/null +++ b/core/src/main/java/ch/dissem/bitmessage/BaseMessageCallback.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.entity.payload.ObjectPayload; +import ch.dissem.bitmessage.entity.valueobject.InventoryVector; + +/** + * Default implementation that doesn't do anything. + * + * @author Christian Basler + */ +public class BaseMessageCallback implements MessageCallback { + @Override + public void proofOfWorkStarted(ObjectPayload message) { + // No op + } + + @Override + public void proofOfWorkCompleted(ObjectPayload message) { + // No op + } + + @Override + public void messageOffered(ObjectPayload message, InventoryVector iv) { + // No op + } + + @Override + public void messageAcknowledged(InventoryVector iv) { + // No op + } +} diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 24a4aaf..94cf3c3 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -410,23 +410,7 @@ public class BitmessageContext { proofOfWorkEngine = new MultiThreadedPOWEngine(); } if (messageCallback == null) { - messageCallback = new MessageCallback() { - @Override - public void proofOfWorkStarted(ObjectPayload message) { - } - - @Override - public void proofOfWorkCompleted(ObjectPayload message) { - } - - @Override - public void messageOffered(ObjectPayload message, InventoryVector iv) { - } - - @Override - public void messageAcknowledged(InventoryVector iv) { - } - }; + messageCallback = new BaseMessageCallback(); } if (customCommandHandler == null) { customCommandHandler = new CustomCommandHandler() { diff --git a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java index b2366e4..dcc62b9 100644 --- a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java +++ b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java @@ -65,6 +65,9 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { receive(object, (Broadcast) payload); break; } + default: { + throw new IllegalArgumentException("Unknown payload type " + payload.getType()); + } } } @@ -96,7 +99,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { } } - private void updatePubkey(BitmessageAddress address, Pubkey pubkey){ + private void updatePubkey(BitmessageAddress address, Pubkey pubkey) { address.setPubkey(pubkey); LOG.info("Got pubkey for contact " + address); ctx.getAddressRepository().save(address); diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java index bfd4f30..33ee15b 100644 --- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -20,6 +20,7 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Encrypted; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.*; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.TTL; @@ -187,7 +188,7 @@ public class InternalContext { messageCallback.proofOfWorkStarted(payload); proofOfWorkService.doProofOfWork(to, object); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -206,7 +207,7 @@ public class InternalContext { // TODO: remember that the pubkey is just about to be sent, and on which stream! proofOfWorkService.doProofOfWork(response); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java index 8790d3a..5e8552e 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java @@ -16,6 +16,7 @@ package ch.dissem.bitmessage.entity; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.Encode; import java.io.ByteArrayOutputStream; @@ -84,7 +85,7 @@ public class NetworkMessage implements Streamable { try { out.write(getChecksum(payloadBytes)); } catch (GeneralSecurityException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } // message payload diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java index 99b3aec..3425c63 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java @@ -191,9 +191,6 @@ public class ObjectMessage implements MessagePayload { private long streamNumber; private ObjectPayload payload; - public Builder() { - } - public Builder nonce(byte[] nonce) { this.nonce = nonce; return this; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java index 794ae44..da99350 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java @@ -17,6 +17,7 @@ package ch.dissem.bitmessage.entity.valueobject; import ch.dissem.bitmessage.entity.Streamable; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.Encode; import ch.dissem.bitmessage.utils.UnixTime; @@ -85,7 +86,7 @@ public class NetworkAddress implements Streamable { try { return InetAddress.getByAddress(ipv6); } catch (UnknownHostException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java b/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java new file mode 100644 index 0000000..998284d --- /dev/null +++ b/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java @@ -0,0 +1,26 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.exception; + +/** + * @author Christian Basler + */ +public class ApplicationException extends RuntimeException { + public ApplicationException(Throwable cause) { + super(cause); + } +} diff --git a/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java b/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java index 1bcb8e7..5d8777a 100644 --- a/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java @@ -111,6 +111,7 @@ public class SerializationTest extends TestBase { before.write(out); NetworkMessage after = Factory.getNetworkMessage(3, new ByteArrayInputStream(out.toByteArray())); + assertNotNull(after); Inv invAfter = (Inv) after.getPayload(); assertEquals(ivs, invAfter.getInventory()); } diff --git a/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java index ef3fcbf..3e5695c 100644 --- a/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java +++ b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java @@ -5,6 +5,7 @@ import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.GenericPayload; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.InsufficientProofOfWorkException; import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import ch.dissem.bitmessage.utils.CallbackWaiter; @@ -22,6 +23,7 @@ import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -102,7 +104,11 @@ public class CryptographyTest { } }); objectMessage.setNonce(waiter.waitForValue()); - crypto.checkProofOfWork(objectMessage, 1000, 1000); + try { + crypto.checkProofOfWork(objectMessage, 1000, 1000); + } catch (InsufficientProofOfWorkException e) { + fail(e.getMessage()); + } } @Test diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 54bfee4..fef1d32 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -114,7 +114,7 @@ class Connection { public static Connection sync(InternalContext ctx, InetAddress address, int port, MessageListener listener, long timeoutInSeconds) throws IOException { - return new Connection(ctx, Mode.SYNC, listener, new Socket(address, port), + return new Connection(ctx, SYNC, listener, new Socket(address, port), new HashSet<InventoryVector>(), new HashSet<InventoryVector>(), new NetworkAddress.Builder().ip(address).port(port).stream(1).build(), diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java index d3bec17..f69af2c 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java @@ -171,6 +171,8 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { case ACTIVE: active++; break; + default: + // nothing to do } } } diff --git a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java index a45ec47..2e63e3a 100644 --- a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java +++ b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java @@ -52,30 +52,30 @@ public class NetworkHandlerTest { public static void setUp() { peerInventory = new TestInventory(); peer = new BitmessageContext.Builder() - .addressRepo(Mockito.mock(AddressRepository.class)) + .addressRepo(mock(AddressRepository.class)) .inventory(peerInventory) - .messageRepo(Mockito.mock(MessageRepository.class)) - .powRepo(Mockito.mock(ProofOfWorkRepository.class)) + .messageRepo(mock(MessageRepository.class)) + .powRepo(mock(ProofOfWorkRepository.class)) .port(6001) .nodeRegistry(new TestNodeRegistry()) .networkHandler(new DefaultNetworkHandler()) .cryptography(new BouncyCryptography()) - .listener(Mockito.mock(BitmessageContext.Listener.class)) + .listener(mock(BitmessageContext.Listener.class)) .build(); peer.startup(); nodeInventory = new TestInventory(); networkHandler = new DefaultNetworkHandler(); node = new BitmessageContext.Builder() - .addressRepo(Mockito.mock(AddressRepository.class)) + .addressRepo(mock(AddressRepository.class)) .inventory(nodeInventory) - .messageRepo(Mockito.mock(MessageRepository.class)) - .powRepo(Mockito.mock(ProofOfWorkRepository.class)) + .messageRepo(mock(MessageRepository.class)) + .powRepo(mock(ProofOfWorkRepository.class)) .port(6002) .nodeRegistry(new TestNodeRegistry(localhost)) .networkHandler(networkHandler) .cryptography(new BouncyCryptography()) - .listener(Mockito.mock(BitmessageContext.Listener.class)) + .listener(mock(BitmessageContext.Listener.class)) .build(); } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java index 3336475..aa41e5c 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java @@ -19,6 +19,7 @@ package ch.dissem.bitmessage.repository; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.Inventory; import org.slf4j.Logger; @@ -99,7 +100,7 @@ public class JdbcInventory extends JdbcHelper implements Inventory { } } catch (Exception e) { LOG.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -126,7 +127,7 @@ public class JdbcInventory extends JdbcHelper implements Inventory { return result; } catch (Exception e) { LOG.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new ApplicationException(e); } } From 9f1e0057c9666d39bd48654a5ed322e15d02f546 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 24 Feb 2016 23:10:04 +0100 Subject: [PATCH 41/54] Code cleanup --- .../java/ch/dissem/bitmessage/BitmessageContext.java | 5 +++-- .../ch/dissem/bitmessage/DefaultMessageListener.java | 2 +- .../java/ch/dissem/bitmessage/entity/CustomMessage.java | 7 ++++--- .../main/java/ch/dissem/bitmessage/entity/Plaintext.java | 9 +++++---- .../dissem/bitmessage/entity/valueobject/PrivateKey.java | 3 ++- .../bitmessage/exception/ApplicationException.java | 4 ++++ .../java/ch/dissem/bitmessage/ports/SimplePOWEngine.java | 3 ++- .../ch/dissem/bitmessage/ProofOfWorkServiceTest.java | 3 +-- .../bitmessage/extensions/CryptoCustomMessage.java | 5 +++-- .../java/ch/dissem/bitmessage/networking/Connection.java | 1 + .../bitmessage/repository/JdbcMessageRepository.java | 9 +++++---- .../main/java/ch/dissem/bitmessage/wif/WifExporter.java | 3 ++- 12 files changed, 33 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 94cf3c3..f54a8f9 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -25,6 +25,7 @@ import ch.dissem.bitmessage.entity.payload.Pubkey.Feature; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.*; @@ -119,7 +120,7 @@ public class BitmessageContext { public void addDistributedMailingList(String address, String alias) { // TODO - throw new RuntimeException("not implemented"); + throw new ApplicationException("not implemented"); } public void broadcast(final BitmessageAddress from, final String subject, final String message) { @@ -187,7 +188,7 @@ public class BitmessageContext { case BROADCAST: return Factory.getBroadcast(msg); default: - throw new RuntimeException("Unknown message type " + msg.getType()); + throw new ApplicationException("Unknown message type " + msg.getType()); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java index dcc62b9..d209974 100644 --- a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java +++ b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java @@ -103,7 +103,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { address.setPubkey(pubkey); LOG.info("Got pubkey for contact " + address); ctx.getAddressRepository().save(address); - List<Plaintext> messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address); + List<Plaintext> messages = ctx.getMessageRepository().findMessages(PUBKEY_REQUESTED, address); LOG.info("Sending " + messages.size() + " messages for contact " + address); for (Plaintext msg : messages) { msg.setStatus(DOING_PROOF_OF_WORK); diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java index 5702b6e..ffdb9b2 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java @@ -16,6 +16,7 @@ package ch.dissem.bitmessage.entity; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.AccessCounter; import ch.dissem.bitmessage.utils.Encode; @@ -66,7 +67,7 @@ public class CustomMessage implements MessagePayload { write(out); return out.toByteArray(); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } } @@ -77,7 +78,7 @@ public class CustomMessage implements MessagePayload { Encode.varString(command, out); out.write(data); } else { - throw new RuntimeException("Tried to write custom message without data. " + + throw new ApplicationException("Tried to write custom message without data. " + "Programmer: did you forget to override #write()?"); } } @@ -90,7 +91,7 @@ public class CustomMessage implements MessagePayload { try { return new CustomMessage(COMMAND_ERROR, message.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java index fc38c65..fe8b1d3 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.utils.Decode; import ch.dissem.bitmessage.utils.Encode; @@ -111,9 +112,9 @@ public class Plaintext implements Streamable { public void setTo(BitmessageAddress to) { if (this.to.getVersion() != 0) - throw new RuntimeException("Correct address already set"); + throw new IllegalStateException("Correct address already set"); if (!Arrays.equals(this.to.getRipe(), to.getRipe())) { - throw new RuntimeException("RIPEs don't match"); + throw new IllegalArgumentException("RIPEs don't match"); } this.to = to; } @@ -223,7 +224,7 @@ public class Plaintext implements Streamable { } return text; } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -402,7 +403,7 @@ public class Plaintext implements Streamable { this.encoding = Encoding.SIMPLE.getCode(); this.message = ("Subject:" + subject + '\n' + "Body:" + message).getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } return this; } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java index d07c859..e058308 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity.valueobject; import ch.dissem.bitmessage.entity.Streamable; import ch.dissem.bitmessage.entity.payload.Pubkey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.utils.Bytes; import ch.dissem.bitmessage.utils.Decode; @@ -71,7 +72,7 @@ public class PrivateKey implements Streamable { this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey, nonceTrialsPerByte, extraBytes, features); } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java b/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java index 998284d..c381410 100644 --- a/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java +++ b/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java @@ -23,4 +23,8 @@ public class ApplicationException extends RuntimeException { public ApplicationException(Throwable cause) { super(cause); } + + public ApplicationException(String message) { + super(message); + } } diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java b/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java index e8d649b..4fa1116 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java @@ -16,6 +16,7 @@ package ch.dissem.bitmessage.ports; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.Bytes; import java.security.MessageDigest; @@ -37,7 +38,7 @@ public class SimplePOWEngine implements ProofOfWorkEngine { try { mda = MessageDigest.getInstance("SHA-512"); } catch (Exception e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } do { inc(nonce); diff --git a/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java b/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java index eb5d368..e489e35 100644 --- a/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java @@ -20,12 +20,10 @@ import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.Plaintext; -import ch.dissem.bitmessage.entity.payload.GetPubkey; import ch.dissem.bitmessage.entity.payload.Msg; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.TestUtils; -import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -39,6 +37,7 @@ import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.*; /** diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java index 49c6f1b..eb2c4e7 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java @@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.CustomMessage; import ch.dissem.bitmessage.entity.Streamable; import ch.dissem.bitmessage.entity.payload.CryptoBox; import ch.dissem.bitmessage.entity.payload.Pubkey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.utils.Encode; @@ -134,9 +135,9 @@ public class CryptoCustomMessage<T extends Streamable> extends CustomMessage { return read; } - public void checkSignature(Pubkey pubkey) throws IOException, RuntimeException { + public void checkSignature(Pubkey pubkey) throws IOException, IllegalStateException { if (!security().isSignatureValid(out.toByteArray(), varBytes(wrapped), pubkey)) { - throw new RuntimeException("Signature check failed"); + throw new IllegalStateException("Signature check failed"); } } } diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index fef1d32..f24736f 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -252,6 +252,7 @@ class Connection { case CUSTOM: case VERACK: case VERSION: + default: throw new RuntimeException("Unexpectedly received '" + messagePayload.getCommand() + "' command"); } } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java index 69890c3..c01e147 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java @@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.utils.Strings; import org.slf4j.Logger; @@ -53,7 +54,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito result.add(getLabel(rs)); } } catch (SQLException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } return result; } @@ -118,7 +119,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito case 1: return plaintexts.get(0); default: - throw new RuntimeException("This shouldn't happen, found " + plaintexts.size() + + throw new ApplicationException("This shouldn't happen, found " + plaintexts.size() + " messages, one or none was expected"); } } @@ -225,10 +226,10 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito } catch (SQLException e1) { LOG.debug(e1.getMessage(), e); } - throw new RuntimeException(e); + throw new ApplicationException(e); } } catch (SQLException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/wif/src/main/java/ch/dissem/bitmessage/wif/WifExporter.java b/wif/src/main/java/ch/dissem/bitmessage/wif/WifExporter.java index b41d645..00f2790 100644 --- a/wif/src/main/java/ch/dissem/bitmessage/wif/WifExporter.java +++ b/wif/src/main/java/ch/dissem/bitmessage/wif/WifExporter.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.wif; import ch.dissem.bitmessage.BitmessageContext; import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.Base58; import org.ini4j.Ini; import org.ini4j.Profile; @@ -95,7 +96,7 @@ public class WifExporter { try { ini.store(writer); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } return writer.toString(); } From 0a00a0a1b444ea9a4d824edfaff6c03c7218fada Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 24 Feb 2016 23:25:55 +0100 Subject: [PATCH 42/54] Code cleanup --- .../dissem/bitmessage/BitmessageContext.java | 1 - .../bitmessage/entity/BitmessageAddress.java | 7 ++++--- .../bitmessage/entity/ObjectMessage.java | 7 ++++--- .../ports/AbstractCryptography.java | 5 +++-- .../bitmessage/ports/MemoryNodeRegistry.java | 3 ++- .../ports/MultiThreadedPOWEngine.java | 5 +++-- .../ch/dissem/bitmessage/utils/Base58.java | 20 +++++++++---------- .../extensions/CryptoCustomMessage.java | 1 - 8 files changed, 26 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index f54a8f9..9344b41 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -22,7 +22,6 @@ import ch.dissem.bitmessage.entity.payload.Msg; import ch.dissem.bitmessage.entity.payload.ObjectPayload; import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.payload.Pubkey.Feature; -import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.ApplicationException; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index 931776c..632bd70 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -19,6 +19,7 @@ package ch.dissem.bitmessage.entity; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.AccessCounter; import ch.dissem.bitmessage.utils.Base58; import ch.dissem.bitmessage.utils.Bytes; @@ -83,7 +84,7 @@ public class BitmessageAddress implements Serializable { os.write(checksum, 0, 4); this.address = "BM-" + Base58.encode(os.toByteArray()); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -124,7 +125,7 @@ public class BitmessageAddress implements Serializable { this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32); } } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -136,7 +137,7 @@ public class BitmessageAddress implements Serializable { out.write(ripe); return Arrays.copyOfRange(security().doubleSha512(out.toByteArray()), 32, 64); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java index 3425c63..a24bf6b 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java @@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.Bytes; import ch.dissem.bitmessage.utils.Encode; @@ -110,7 +111,7 @@ public class ObjectMessage implements MessagePayload { payload.writeBytesToSign(out); return out.toByteArray(); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -144,7 +145,7 @@ public class ObjectMessage implements MessagePayload { ((Encrypted) payload).encrypt(publicKey.getEncryptionKey()); } } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -180,7 +181,7 @@ public class ObjectMessage implements MessagePayload { } return payloadBytes; } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java b/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java index 3cf3f0d..81252d5 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java @@ -19,6 +19,7 @@ package ch.dissem.bitmessage.ports; import ch.dissem.bitmessage.InternalContext; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.Pubkey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.InsufficientProofOfWorkException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.utils.Bytes; @@ -151,7 +152,7 @@ public abstract class AbstractCryptography implements Cryptography, InternalCont try { return MessageDigest.getInstance(algorithm, provider); } catch (GeneralSecurityException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -161,7 +162,7 @@ public abstract class AbstractCryptography implements Cryptography, InternalCont mac.init(new SecretKeySpec(key_m, "HmacSHA256")); return mac.doFinal(data); } catch (GeneralSecurityException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java b/core/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java index 8d43423..c68a474 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/MemoryNodeRegistry.java @@ -17,6 +17,7 @@ package ch.dissem.bitmessage.ports; import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.UnixTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,7 +72,7 @@ public class MemoryNodeRegistry implements NodeRegistry { } } } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java b/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java index 790e3b7..50164a3 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/MultiThreadedPOWEngine.java @@ -16,6 +16,7 @@ package ch.dissem.bitmessage.ports; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +50,7 @@ public class MultiThreadedPOWEngine implements ProofOfWorkEngine { try { semaphore.acquire(); } catch (InterruptedException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } callback = new CallbackWrapper(callback); int cores = Runtime.getRuntime().availableProcessors(); @@ -88,7 +89,7 @@ public class MultiThreadedPOWEngine implements ProofOfWorkEngine { mda = MessageDigest.getInstance("SHA-512"); } catch (NoSuchAlgorithmException e) { LOG.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java b/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java index ec2476a..9f35fb7 100644 --- a/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java +++ b/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java @@ -44,27 +44,27 @@ public class Base58 { /** * Encodes the given bytes in base58. No checksum is appended. * - * @param input to encode + * @param data to encode * @return base58 encoded input */ - public static String encode(byte[] input) { - if (input.length == 0) { + public static String encode(byte[] data) { + if (data.length == 0) { return ""; } - input = copyOfRange(input, 0, input.length); + final byte[] bytes = copyOfRange(data, 0, data.length); // Count leading zeroes. int zeroCount = 0; - while (zeroCount < input.length && input[zeroCount] == 0) { + while (zeroCount < bytes.length && bytes[zeroCount] == 0) { ++zeroCount; } // The actual encoding. - byte[] temp = new byte[input.length * 2]; + byte[] temp = new byte[bytes.length * 2]; int j = temp.length; int startAt = zeroCount; - while (startAt < input.length) { - byte mod = divmod58(input, startAt); - if (input[startAt] == 0) { + while (startAt < bytes.length) { + byte mod = divmod58(bytes, startAt); + if (bytes[startAt] == 0) { ++startAt; } temp[--j] = (byte) ALPHABET[mod]; @@ -97,7 +97,7 @@ public class Base58 { char c = input.charAt(i); int digit58 = -1; - if (c >= 0 && c < 128) { + if (c < 128) { digit58 = INDEXES[c]; } if (digit58 < 0) { diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java index eb2c4e7..33c7524 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java @@ -21,7 +21,6 @@ import ch.dissem.bitmessage.entity.CustomMessage; import ch.dissem.bitmessage.entity.Streamable; import ch.dissem.bitmessage.entity.payload.CryptoBox; import ch.dissem.bitmessage.entity.payload.Pubkey; -import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.utils.Encode; From f6add5b2ea8e9168b1ef467b9a8af8896504d6ae Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Thu, 25 Feb 2016 16:36:43 +0100 Subject: [PATCH 43/54] Code cleanup --- .../dissem/bitmessage/BitmessageContext.java | 3 +- .../bitmessage/entity/payload/CryptoBox.java | 3 +- .../ch/dissem/bitmessage/utils/Base58.java | 3 +- .../bitmessage/BitmessageContextTest.java | 3 +- .../entity/BitmessageAddressTest.java | 56 ++++++++++--------- .../cryptography/bc/BouncyCryptography.java | 10 ++-- .../cryptography/sc/SpongyCryptography.java | 10 ++-- .../java/ch/dissem/bitmessage/SystemTest.java | 12 ++-- .../bitmessage/networking/Connection.java | 6 +- .../networking/DefaultNetworkHandler.java | 7 ++- .../repository/JdbcAddressRepository.java | 7 ++- .../repository/JdbcProofOfWorkRepository.java | 17 +++--- 12 files changed, 80 insertions(+), 57 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 9344b41..60b7267 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -416,7 +416,8 @@ public class BitmessageContext { customCommandHandler = new CustomCommandHandler() { @Override public MessagePayload handle(CustomMessage request) { - throw new RuntimeException("Received custom request, but no custom command handler configured."); + throw new IllegalStateException( + "Received custom request, but no custom command handler configured."); } }; } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java index 3d1c926..8887fea 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java @@ -17,6 +17,7 @@ package ch.dissem.bitmessage.entity.payload; import ch.dissem.bitmessage.entity.Streamable; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.*; import org.slf4j.Logger; @@ -123,7 +124,7 @@ public class CryptoBox implements Streamable { writeWithoutMAC(macData); return security().mac(key_m, macData.toByteArray()); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java b/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java index 9f35fb7..167d862 100644 --- a/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java +++ b/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.utils; import ch.dissem.bitmessage.exception.AddressFormatException; +import ch.dissem.bitmessage.exception.ApplicationException; import java.io.UnsupportedEncodingException; @@ -83,7 +84,7 @@ public class Base58 { try { return new String(output, "US-ASCII"); } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); // Cannot happen. + throw new ApplicationException(e); // Cannot happen. } } diff --git a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java index 828e794..890c2c3 100644 --- a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java @@ -194,7 +194,8 @@ public class BitmessageContextTest { .putObject(object(BROADCAST), eq(1000L), eq(1000L)); verify(ctx.internals().getProofOfWorkEngine()) .calculateNonce(any(byte[].class), any(byte[].class), any(ProofOfWorkEngine.Callback.class)); - verify(ctx.messages(), timeout(10000).atLeastOnce()).save(MessageMatchers.plaintext(Plaintext.Type.BROADCAST)); + verify(ctx.messages(), timeout(10000).atLeastOnce()) + .save(MessageMatchers.plaintext(Plaintext.Type.BROADCAST)); } @Test(expected = IllegalArgumentException.class) diff --git a/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java b/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java index e1fcc7f..495aea9 100644 --- a/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java @@ -55,44 +55,56 @@ public class BitmessageAddressTest { } @Test - public void testCreateAddress() { + public void ensureIdentityCanBeCreated() { BitmessageAddress address = new BitmessageAddress(new PrivateKey(false, 1, 1000, 1000, DOES_ACK)); assertNotNull(address.getPubkey()); } @Test - public void testV2PubkeyImport() throws IOException { + public void ensureV2PubkeyCanBeImported() throws IOException { ObjectMessage object = TestUtils.loadObjectMessage(2, "V2Pubkey.payload"); Pubkey pubkey = (Pubkey) object.getPayload(); BitmessageAddress address = new BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT"); - address.setPubkey(pubkey); + try { + address.setPubkey(pubkey); + } catch (Exception e) { + fail(e.getMessage()); + } } @Test - public void testV3PubkeyImport() throws IOException { + public void ensureV3PubkeyCanBeImported() throws IOException { BitmessageAddress address = new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ"); assertArrayEquals(Bytes.fromHex("007402be6e76c3cb87caa946d0c003a3d4d8e1d5"), address.getRipe()); ObjectMessage object = TestUtils.loadObjectMessage(3, "V3Pubkey.payload"); Pubkey pubkey = (Pubkey) object.getPayload(); assertTrue(object.isSignatureValid(pubkey)); - address.setPubkey(pubkey); + try { + address.setPubkey(pubkey); + } catch (Exception e) { + fail(e.getMessage()); + } assertArrayEquals(Bytes.fromHex("007402be6e76c3cb87caa946d0c003a3d4d8e1d5"), pubkey.getRipe()); } @Test - public void testV4PubkeyImport() throws IOException, DecryptionFailedException { + public void ensureV4PubkeyCanBeImported() throws IOException, DecryptionFailedException { BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h"); ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload"); object.decrypt(address.getPublicDecryptionKey()); V4Pubkey pubkey = (V4Pubkey) object.getPayload(); assertTrue(object.isSignatureValid(pubkey)); - address.setPubkey(pubkey); + try { + address.setPubkey(pubkey); + } catch (Exception e) { + fail(e.getMessage()); + } } @Test - public void testV3AddressImport() throws IOException { + public void ensureV3IdentityCanBeImported() throws IOException { String address_string = "BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn"; assertEquals(3, new BitmessageAddress(address_string).getVersion()); assertEquals(1, new BitmessageAddress(address_string).getStream()); @@ -108,9 +120,17 @@ public class BitmessageAddressTest { } @Test - public void testGetSecret() throws IOException { - assertHexEquals("0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D", - getSecret("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ")); + public void ensureV4IdentityCanBeImported() throws IOException { + assertEquals(4, new BitmessageAddress("BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke").getVersion()); + byte[] privsigningkey = getSecret("5KMWqfCyJZGFgW6QrnPJ6L9Gatz25B51y7ErgqNr1nXUVbtZbdU"); + byte[] privencryptionkey = getSecret("5JXXWEuhHQEPk414SzEZk1PHDRi8kCuZd895J7EnKeQSahJPxGz"); + BitmessageAddress address = new BitmessageAddress(new PrivateKey(privsigningkey, privencryptionkey, + security().createPubkey(4, 1, privsigningkey, privencryptionkey, 320, 14000))); + assertEquals("BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke", address.getAddress()); + } + + private void assertHexEquals(String hex, byte[] bytes) { + assertEquals(hex.toLowerCase(), Strings.hex(bytes).toString().toLowerCase()); } private byte[] getSecret(String walletImportFormat) throws IOException { @@ -126,18 +146,4 @@ public class BitmessageAddressTest { } return Arrays.copyOfRange(bytes, 1, 33); } - - @Test - public void testV4AddressImport() throws IOException { - assertEquals(4, new BitmessageAddress("BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke").getVersion()); - byte[] privsigningkey = getSecret("5KMWqfCyJZGFgW6QrnPJ6L9Gatz25B51y7ErgqNr1nXUVbtZbdU"); - byte[] privencryptionkey = getSecret("5JXXWEuhHQEPk414SzEZk1PHDRi8kCuZd895J7EnKeQSahJPxGz"); - BitmessageAddress address = new BitmessageAddress(new PrivateKey(privsigningkey, privencryptionkey, - security().createPubkey(4, 1, privsigningkey, privencryptionkey, 320, 14000))); - assertEquals("BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke", address.getAddress()); - } - - private void assertHexEquals(String hex, byte[] bytes) { - assertEquals(hex.toLowerCase(), Strings.hex(bytes).toString().toLowerCase()); - } } diff --git a/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java b/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java index 28be67a..41e2c37 100644 --- a/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java +++ b/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.cryptography.bc; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.ports.AbstractCryptography; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.BufferedBlockCipher; @@ -37,6 +38,7 @@ import org.bouncycastle.jce.spec.ECPublicKeySpec; import org.bouncycastle.math.ec.ECPoint; import java.math.BigInteger; +import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.PublicKey; import java.security.Signature; @@ -109,8 +111,8 @@ public class BouncyCryptography extends AbstractCryptography { sig.initVerify(publicKey); sig.update(data); return sig.verify(signature); - } catch (Exception e) { - throw new RuntimeException(e); + } catch (GeneralSecurityException e) { + throw new ApplicationException(e); } } @@ -133,8 +135,8 @@ public class BouncyCryptography extends AbstractCryptography { sig.initSign(privKey); sig.update(data); return sig.sign(); - } catch (Exception e) { - throw new RuntimeException(e); + } catch (GeneralSecurityException e) { + throw new ApplicationException(e); } } diff --git a/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java b/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java index c9506fb..066ca10 100644 --- a/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java +++ b/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.cryptography.sc; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.ports.AbstractCryptography; import org.spongycastle.asn1.x9.X9ECParameters; import org.spongycastle.crypto.BufferedBlockCipher; @@ -37,6 +38,7 @@ import org.spongycastle.jce.spec.ECPublicKeySpec; import org.spongycastle.math.ec.ECPoint; import java.math.BigInteger; +import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.PublicKey; import java.security.Signature; @@ -109,8 +111,8 @@ public class SpongyCryptography extends AbstractCryptography { sig.initVerify(publicKey); sig.update(data); return sig.verify(signature); - } catch (Exception e) { - throw new RuntimeException(e); + } catch (GeneralSecurityException e) { + throw new ApplicationException(e); } } @@ -133,8 +135,8 @@ public class SpongyCryptography extends AbstractCryptography { sig.initSign(privKey); sig.update(data); return sig.sign(); - } catch (Exception e) { - throw new RuntimeException(e); + } catch (GeneralSecurityException e) { + throw new ApplicationException(e); } } diff --git a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java index a2e3da7..06b6628 100644 --- a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java +++ b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java @@ -19,6 +19,8 @@ import static org.junit.Assert.assertThat; * @author Christian Basler */ public class SystemTest { + private static int port = 6000; + private BitmessageContext alice; private TestListener aliceListener = new TestListener(); private BitmessageAddress aliceIdentity; @@ -29,6 +31,8 @@ public class SystemTest { @Before public void setUp() { + int alicePort = port++; + int bobPort = port++; TTL.msg(5 * MINUTE); TTL.getpubkey(5 * MINUTE); TTL.pubkey(5 * MINUTE); @@ -38,8 +42,8 @@ public class SystemTest { .inventory(new JdbcInventory(aliceDB)) .messageRepo(new JdbcMessageRepository(aliceDB)) .powRepo(new JdbcProofOfWorkRepository(aliceDB)) - .port(6001) - .nodeRegistry(new TestNodeRegistry(6002)) + .port(alicePort) + .nodeRegistry(new TestNodeRegistry(bobPort)) .networkHandler(new DefaultNetworkHandler()) .cryptography(new BouncyCryptography()) .listener(aliceListener) @@ -53,8 +57,8 @@ public class SystemTest { .inventory(new JdbcInventory(bobDB)) .messageRepo(new JdbcMessageRepository(bobDB)) .powRepo(new JdbcProofOfWorkRepository(bobDB)) - .port(6002) - .nodeRegistry(new TestNodeRegistry(6001)) + .port(bobPort) + .nodeRegistry(new TestNodeRegistry(alicePort)) .networkHandler(new DefaultNetworkHandler()) .cryptography(new BouncyCryptography()) .listener(bobListener) diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index f24736f..4f99144 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -21,6 +21,7 @@ import ch.dissem.bitmessage.InternalContext; import ch.dissem.bitmessage.entity.*; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.InsufficientProofOfWorkException; import ch.dissem.bitmessage.exception.NodeException; import ch.dissem.bitmessage.factory.Factory; @@ -253,7 +254,7 @@ class Connection { case VERACK: case VERSION: default: - throw new RuntimeException("Unexpectedly received '" + messagePayload.getCommand() + "' command"); + throw new IllegalStateException("Unexpectedly received '" + messagePayload.getCommand() + "' command"); } } @@ -386,6 +387,8 @@ class Connection { case SYNC: activateConnection(); break; + default: + // NO OP } } else { LOG.info("Received unsupported version " + payload.getVersion() + ", disconnecting."); @@ -399,6 +402,7 @@ class Connection { break; case CLIENT: case SYNC: + default: // NO OP break; } diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java index f69af2c..44dd437 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java @@ -23,6 +23,7 @@ import ch.dissem.bitmessage.entity.GetData; import ch.dissem.bitmessage.entity.NetworkMessage; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.NodeException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.NetworkHandler; @@ -85,7 +86,7 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { pool.execute(connection.getWriter()); return reader; } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -106,7 +107,7 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { } } } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -209,7 +210,7 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { } }); } catch (IOException e) { - throw new RuntimeException(e); + throw new ApplicationException(e); } } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java index bf15a6a..6e58f09 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java @@ -21,12 +21,12 @@ import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.payload.V3Pubkey; import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.AddressRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -129,8 +129,9 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito try (Connection connection = config.getConnection()) { Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM Address WHERE address='" + address.getAddress() + "'"); - rs.next(); - return rs.getInt(1) > 0; + if (rs.next()) { + return rs.getInt(1) > 0; + } } catch (SQLException e) { LOG.error(e.getMessage(), e); } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java index 9268311..37628b5 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java @@ -1,12 +1,14 @@ package ch.dissem.bitmessage.repository; import ch.dissem.bitmessage.entity.ObjectMessage; +import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; import ch.dissem.bitmessage.utils.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.sql.*; import java.util.LinkedList; import java.util.List; @@ -37,11 +39,11 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork rs.getLong("extra_bytes") ); } else { - throw new RuntimeException("Object requested that we don't have. Initial hash: " + Strings.hex(initialHash)); + throw new IllegalArgumentException("Object requested that we don't have. Initial hash: " + Strings.hex(initialHash)); } - } catch (Exception e) { + } catch (SQLException e) { LOG.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -57,7 +59,7 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork return result; } catch (SQLException e) { LOG.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new ApplicationException(e); } } @@ -71,12 +73,9 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork ps.setLong(4, nonceTrialsPerByte); ps.setLong(5, extraBytes); ps.executeUpdate(); - } catch (SQLException e) { + } catch (IOException | SQLException e) { LOG.debug("Error storing object of type " + object.getPayload().getClass().getSimpleName(), e); - throw new RuntimeException(e); - } catch (Exception e) { - LOG.error(e.getMessage(), e); - throw new RuntimeException(e); + throw new ApplicationException(e); } } From 382cb80a87b7ad8e5864af78b59f0308ebf1f35f Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Fri, 26 Feb 2016 14:01:26 +0100 Subject: [PATCH 44/54] Updated badges --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c682e0b..6c44558 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Jabit ===== [![Maven Central](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/ch.dissem.jabit/jabit-core) [![Javadoc](https://javadoc-emblem.rhcloud.com/doc/ch.dissem.jabit/jabit-core/badge.svg)](http://www.javadoc.io/doc/ch.dissem.jabit/jabit-core) -[![GitHub license](https://img.shields.io/github/license/Dissem/Jabit.svg)](https://raw.githubusercontent.com/Dissem/Jabit/master/LICENSE) +[![Apache 2](https://img.shields.io/badge/license-Apache_2.0-blue.svg)](https://raw.githubusercontent.com/Dissem/Jabit/master/LICENSE) [![Visit our IRC channel](https://img.shields.io/badge/irc-%23jabit-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/#jabit) A Java implementation for the Bitmessage protocol. To build, use command `gradle build` or `./gradlew build`. @@ -11,10 +11,14 @@ Please note that it still has its limitations, but the API should now be stable. as long as the major version doesn't change, nothing should break if you update. #### Master -[![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=master)](https://travis-ci.org/Dissem/Jabit) [![codecov.io](https://codecov.io/github/Dissem/Jabit/coverage.svg?branch=master)](https://codecov.io/github/Dissem/Jabit?branch=master) +[![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=master)](https://travis-ci.org/Dissem/Jabit) +[![Code Quality](https://img.shields.io/codacy/e9938d2adbb74a0db553115bef692ff3/master.svg)](https://www.codacy.com/app/chrigu-meyer/Jabit/dashboard?bid=3144281) +[![Test Coverage](https://codecov.io/github/Dissem/Jabit/coverage.svg?branch=master)](https://codecov.io/github/Dissem/Jabit?branch=master) #### Develop -[![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=develop)](https://travis-ci.org/Dissem/Jabit?branch=develop) [![codecov.io](https://codecov.io/github/Dissem/Jabit/coverage.svg?branch=develop)](https://codecov.io/github/Dissem/Jabit?branch=develop) +[![Build Status](https://travis-ci.org/Dissem/Jabit.svg?branch=develop)](https://travis-ci.org/Dissem/Jabit?branch=develop) +[![Code Quality](https://img.shields.io/codacy/e9938d2adbb74a0db553115bef692ff3/develop.svg)](https://www.codacy.com/app/chrigu-meyer/Jabit/dashboard?bid=3144279) +[![Test Coverage](https://codecov.io/github/Dissem/Jabit/coverage.svg?branch=develop)](https://codecov.io/github/Dissem/Jabit?branch=develop) Security -------- From bc68a5d3ec89ee053afc123cca0decc264aba02c Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Fri, 26 Feb 2016 14:34:08 +0100 Subject: [PATCH 45/54] Code cleanup & improvements - most notably removed some unnecessary synchronize blocks in the DefaultNetworkHandler --- .../dissem/bitmessage/BitmessageContext.java | 3 - .../ch/dissem/bitmessage/entity/Addr.java | 3 - .../bitmessage/entity/BitmessageAddress.java | 2 +- .../ch/dissem/bitmessage/entity/GetData.java | 5 +- .../java/ch/dissem/bitmessage/entity/Inv.java | 3 - .../bitmessage/entity/ObjectMessage.java | 6 +- .../ch/dissem/bitmessage/entity/Version.java | 3 - .../bitmessage/entity/payload/V2Pubkey.java | 3 - .../bitmessage/entity/payload/V3Pubkey.java | 3 - .../entity/valueobject/NetworkAddress.java | 3 - .../bitmessage/ports/SimplePOWEngine.java | 20 +- .../dissem/bitmessage/demo/Application.java | 8 +- .../bitmessage/networking/Connection.java | 1 - .../networking/ConnectionOrganizer.java | 120 ++++++++++ .../networking/DefaultNetworkHandler.java | 220 +++++------------- .../bitmessage/networking/ServerRunnable.java | 70 ++++++ .../repository/JdbcAddressRepository.java | 8 +- .../bitmessage/repository/JdbcHelper.java | 6 +- .../repository/JdbcMessageRepository.java | 16 +- 19 files changed, 286 insertions(+), 217 deletions(-) create mode 100644 networking/src/main/java/ch/dissem/bitmessage/networking/ConnectionOrganizer.java create mode 100644 networking/src/main/java/ch/dissem/bitmessage/networking/ServerRunnable.java diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 60b7267..9f03926 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -302,9 +302,6 @@ public class BitmessageContext { long connectionTTL = 30 * MINUTE; boolean sendPubkeyOnIdentityCreation = true; - public Builder() { - } - public Builder port(int port) { this.port = port; return this; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java b/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java index d00623e..2c0eb3e 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java @@ -55,9 +55,6 @@ public class Addr implements MessagePayload { public static final class Builder { private List<NetworkAddress> addresses = new ArrayList<NetworkAddress>(); - public Builder() { - } - public Builder addresses(Collection<NetworkAddress> addresses){ this.addresses.addAll(addresses); return this; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index 632bd70..62fabc3 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -188,7 +188,7 @@ public class BitmessageAddress implements Serializable { @Override public String toString() { - return alias != null ? alias : address; + return alias == null ? address : alias; } public byte[] getRipe() { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java b/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java index e272bbc..9569929 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java @@ -28,6 +28,8 @@ import java.util.List; * The 'getdata' command is used to request objects from a node. */ public class GetData implements MessagePayload { + public static final int MAX_INVENTORY_SIZE = 50_000; + List<InventoryVector> inventory; private GetData(Builder builder) { @@ -54,9 +56,6 @@ public class GetData implements MessagePayload { public static final class Builder { private List<InventoryVector> inventory = new LinkedList<>(); - public Builder() { - } - public Builder addInventoryVector(InventoryVector inventoryVector) { this.inventory.add(inventoryVector); return this; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java index 0135ec0..7130fd7 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java @@ -54,9 +54,6 @@ public class Inv implements MessagePayload { public static final class Builder { private List<InventoryVector> inventory = new LinkedList<>(); - public Builder() { - } - public Builder addInventoryVector(InventoryVector inventoryVector) { this.inventory.add(inventoryVector); return this; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java index a24bf6b..89ddddb 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java @@ -156,10 +156,10 @@ public class ObjectMessage implements MessagePayload { @Override public void write(OutputStream out) throws IOException { - if (nonce != null) { - out.write(nonce); - } else { + if (nonce == null) { out.write(new byte[8]); + } else { + out.write(nonce); } out.write(getPayloadBytesWithoutNonce()); } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Version.java b/core/src/main/java/ch/dissem/bitmessage/entity/Version.java index 70c2ad2..6d24d92 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Version.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Version.java @@ -143,9 +143,6 @@ public class Version implements MessagePayload { private String userAgent; private long[] streamNumbers; - public Builder() { - } - public Builder defaults() { version = BitmessageContext.CURRENT_VERSION; services = 1; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java index da16929..d915941 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java @@ -96,9 +96,6 @@ public class V2Pubkey extends Pubkey { private byte[] publicSigningKey; private byte[] publicEncryptionKey; - public Builder() { - } - public Builder stream(long streamNumber) { this.streamNumber = streamNumber; return this; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java index bf91afe..a3b4da2 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java @@ -123,9 +123,6 @@ public class V3Pubkey extends V2Pubkey { private long extraBytes; private byte[] signature = new byte[0]; - public Builder() { - } - public Builder stream(long streamNumber) { this.streamNumber = streamNumber; return this; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java index da99350..0637da9 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java @@ -134,9 +134,6 @@ public class NetworkAddress implements Streamable { private byte[] ipv6; private int port; - public Builder() { - } - public Builder time(final long time) { this.time = time; return this; diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java b/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java index 4fa1116..a7d0d57 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/SimplePOWEngine.java @@ -20,6 +20,7 @@ import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.utils.Bytes; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import static ch.dissem.bitmessage.utils.Bytes.inc; @@ -33,18 +34,17 @@ import static ch.dissem.bitmessage.utils.Bytes.inc; public class SimplePOWEngine implements ProofOfWorkEngine { @Override public void calculateNonce(byte[] initialHash, byte[] target, Callback callback) { - byte[] nonce = new byte[8]; - MessageDigest mda; try { - mda = MessageDigest.getInstance("SHA-512"); - } catch (Exception e) { + MessageDigest mda = MessageDigest.getInstance("SHA-512"); + byte[] nonce = new byte[8]; + do { + inc(nonce); + mda.update(nonce); + mda.update(initialHash); + } while (Bytes.lt(target, mda.digest(mda.digest()), 8)); + callback.onNonceCalculated(initialHash, nonce); + } catch (NoSuchAlgorithmException e) { throw new ApplicationException(e); } - do { - inc(nonce); - mda.update(nonce); - mda.update(initialHash); - } while (Bytes.lt(target, mda.digest(mda.digest()), 8)); - callback.onNonceCalculated(initialHash, nonce); } } diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java index 26d6652..dab43f3 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java @@ -289,18 +289,18 @@ public class Application { System.out.println("Stream: " + address.getStream()); System.out.println("Version: " + address.getVersion()); if (address.getPrivateKey() == null) { - if (address.getPubkey() != null) { - System.out.println("Public key available"); - } else { + if (address.getPubkey() == null) { System.out.println("Public key still missing"); + } else { + System.out.println("Public key available"); } } } private void messages() { String command; - List<Plaintext> messages = ctx.messages().findMessages(Plaintext.Status.RECEIVED); do { + List<Plaintext> messages = ctx.messages().findMessages(Plaintext.Status.RECEIVED); System.out.println(); int i = 0; for (Plaintext message : messages) { diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 4f99144..43f1e30 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -21,7 +21,6 @@ import ch.dissem.bitmessage.InternalContext; import ch.dissem.bitmessage.entity.*; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; -import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.InsufficientProofOfWorkException; import ch.dissem.bitmessage.exception.NodeException; import ch.dissem.bitmessage.factory.Factory; diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/ConnectionOrganizer.java b/networking/src/main/java/ch/dissem/bitmessage/networking/ConnectionOrganizer.java new file mode 100644 index 0000000..3f667e6 --- /dev/null +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/ConnectionOrganizer.java @@ -0,0 +1,120 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.networking; + +import ch.dissem.bitmessage.InternalContext; +import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; +import ch.dissem.bitmessage.ports.NetworkHandler; +import ch.dissem.bitmessage.utils.UnixTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Iterator; +import java.util.List; + +import static ch.dissem.bitmessage.networking.Connection.Mode.CLIENT; +import static ch.dissem.bitmessage.networking.DefaultNetworkHandler.NETWORK_MAGIC_NUMBER; + +/** + * @author Christian Basler + */ +public class ConnectionOrganizer implements Runnable { + private static final Logger LOG = LoggerFactory.getLogger(ConnectionOrganizer.class); + + private final InternalContext ctx; + private final DefaultNetworkHandler networkHandler; + private final NetworkHandler.MessageListener listener; + + private Connection initialConnection; + + public ConnectionOrganizer(InternalContext ctx, + DefaultNetworkHandler networkHandler, + NetworkHandler.MessageListener listener) { + this.ctx = ctx; + this.networkHandler = networkHandler; + this.listener = listener; + } + + @Override + public void run() { + try { + while (networkHandler.isRunning()) { + try { + int active = 0; + long now = UnixTime.now(); + + int diff = networkHandler.connections.size() - ctx.getConnectionLimit(); + if (diff > 0) { + for (Connection c : networkHandler.connections) { + c.disconnect(); + diff--; + if (diff == 0) break; + } + } + boolean forcedDisconnect = false; + for (Iterator<Connection> iterator = networkHandler.connections.iterator(); iterator.hasNext(); ) { + Connection c = iterator.next(); + // Just in case they were all created at the same time, don't disconnect + // all at once. + if (!forcedDisconnect && now - c.getStartTime() > ctx.getConnectionTTL()) { + c.disconnect(); + forcedDisconnect = true; + } + switch (c.getState()) { + case DISCONNECTED: + iterator.remove(); + break; + case ACTIVE: + active++; + break; + default: + // nothing to do + } + } + + if (active < NETWORK_MAGIC_NUMBER) { + List<NetworkAddress> addresses = ctx.getNodeRegistry().getKnownAddresses( + NETWORK_MAGIC_NUMBER - active, ctx.getStreams()); + boolean first = active == 0 && initialConnection == null; + for (NetworkAddress address : addresses) { + Connection c = new Connection(ctx, CLIENT, address, listener, networkHandler.requestedObjects); + if (first) { + initialConnection = c; + first = false; + } + networkHandler.startConnection(c); + } + Thread.sleep(10000); + } else if (initialConnection != null) { + initialConnection.disconnect(); + initialConnection = null; + Thread.sleep(10000); + } else { + Thread.sleep(30000); + } + } catch (InterruptedException e) { + networkHandler.stop(); + } catch (Exception e) { + LOG.error("Error in connection manager. Ignored.", e); + } + } + } finally { + LOG.debug("Connection manager shutting down."); + networkHandler.stop(); + } + } +} diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java index 44dd437..43333ac 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/DefaultNetworkHandler.java @@ -22,25 +22,21 @@ import ch.dissem.bitmessage.entity.CustomMessage; import ch.dissem.bitmessage.entity.GetData; import ch.dissem.bitmessage.entity.NetworkMessage; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; -import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.NodeException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.NetworkHandler; import ch.dissem.bitmessage.utils.Collections; import ch.dissem.bitmessage.utils.Property; -import ch.dissem.bitmessage.utils.UnixTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.InetAddress; -import java.net.ServerSocket; import java.net.Socket; import java.util.*; import java.util.concurrent.*; -import static ch.dissem.bitmessage.networking.Connection.Mode.CLIENT; import static ch.dissem.bitmessage.networking.Connection.Mode.SERVER; import static ch.dissem.bitmessage.networking.Connection.State.ACTIVE; import static ch.dissem.bitmessage.utils.DebugUtils.inc; @@ -54,13 +50,13 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { public final static int NETWORK_MAGIC_NUMBER = 8; - private final Collection<Connection> connections = new ConcurrentLinkedQueue<>(); + final Collection<Connection> connections = new ConcurrentLinkedQueue<>(); private final ExecutorService pool; private InternalContext ctx; - private ServerSocket serverSocket; + private ServerRunnable server; private volatile boolean running; - private Set<InventoryVector> requestedObjects = newSetFromMap(new ConcurrentHashMap<InventoryVector, Boolean>(50_000)); + final Set<InventoryVector> requestedObjects = newSetFromMap(new ConcurrentHashMap<InventoryVector, Boolean>(50_000)); public DefaultNetworkHandler() { pool = Executors.newCachedThreadPool(new ThreadFactory() { @@ -122,93 +118,9 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { try { running = true; connections.clear(); - serverSocket = new ServerSocket(ctx.getPort()); - pool.execute(new Runnable() { - @Override - public void run() { - while (!serverSocket.isClosed()) { - try { - Socket socket = serverSocket.accept(); - socket.setSoTimeout(Connection.READ_TIMEOUT); - startConnection(new Connection(ctx, SERVER, socket, listener, requestedObjects)); - } catch (IOException e) { - LOG.debug(e.getMessage(), e); - } - } - } - }); - pool.execute(new Runnable() { - public Connection initialConnection; - - @Override - public void run() { - try { - while (running) { - try { - int active = 0; - long now = UnixTime.now(); - synchronized (connections) { - int diff = connections.size() - ctx.getConnectionLimit(); - if (diff > 0) { - for (Connection c : connections) { - c.disconnect(); - diff--; - if (diff == 0) break; - } - } - boolean forcedDisconnect = false; - for (Iterator<Connection> iterator = connections.iterator(); iterator.hasNext(); ) { - Connection c = iterator.next(); - // Just in case they were all created at the same time, don't disconnect - // all at once. - if (!forcedDisconnect && now - c.getStartTime() > ctx.getConnectionTTL()) { - c.disconnect(); - forcedDisconnect = true; - } - switch (c.getState()) { - case DISCONNECTED: - iterator.remove(); - break; - case ACTIVE: - active++; - break; - default: - // nothing to do - } - } - } - if (active < NETWORK_MAGIC_NUMBER) { - List<NetworkAddress> addresses = ctx.getNodeRegistry().getKnownAddresses( - NETWORK_MAGIC_NUMBER - active, ctx.getStreams()); - boolean first = active == 0 && initialConnection == null; - for (NetworkAddress address : addresses) { - Connection c = new Connection(ctx, CLIENT, address, listener, requestedObjects); - if (first) { - initialConnection = c; - first = false; - } - startConnection(c); - } - Thread.sleep(10000); - } else if (initialConnection != null) { - initialConnection.disconnect(); - initialConnection = null; - Thread.sleep(10000); - } else { - Thread.sleep(30000); - } - } catch (InterruptedException e) { - running = false; - } catch (Exception e) { - LOG.error("Error in connection manager. Ignored.", e); - } - } - } finally { - LOG.debug("Connection manager shutting down."); - running = false; - } - } - }); + server = new ServerRunnable(ctx, this, listener); + pool.execute(server); + pool.execute(new ConnectionOrganizer(ctx, this, listener)); } catch (IOException e) { throw new ApplicationException(e); } @@ -221,13 +133,9 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { @Override public void stop() { - running = false; - try { - serverSocket.close(); - } catch (IOException e) { - LOG.debug(e.getMessage(), e); - } + server.close(); synchronized (connections) { + running = false; for (Connection c : connections) { c.disconnect(); } @@ -235,8 +143,12 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { requestedObjects.clear(); } - private void startConnection(Connection c) { + void startConnection(Connection c) { + if (!running) return; + synchronized (connections) { + if (!running) return; + // prevent connecting twice to the same node if (connections.contains(c)) { return; @@ -250,11 +162,9 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { @Override public void offer(final InventoryVector iv) { List<Connection> target = new LinkedList<>(); - synchronized (connections) { - for (Connection connection : connections) { - if (connection.getState() == ACTIVE && !connection.knowsOf(iv)) { - target.add(connection); - } + for (Connection connection : connections) { + if (connection.getState() == ACTIVE && !connection.knowsOf(iv)) { + target.add(connection); } } List<Connection> randomSubset = Collections.selectRandom(NETWORK_MAGIC_NUMBER, target); @@ -269,16 +179,14 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { TreeMap<Long, Integer> incomingConnections = new TreeMap<>(); TreeMap<Long, Integer> outgoingConnections = new TreeMap<>(); - synchronized (connections) { - for (Connection connection : connections) { - if (connection.getState() == ACTIVE) { - long stream = connection.getNode().getStream(); - streams.add(stream); - if (connection.getMode() == SERVER) { - inc(incomingConnections, stream); - } else { - inc(outgoingConnections, stream); - } + for (Connection connection : connections) { + if (connection.getState() == ACTIVE) { + long stream = connection.getNode().getStream(); + streams.add(stream); + if (connection.getMode() == SERVER) { + inc(incomingConnections, stream); + } else { + inc(outgoingConnections, stream); } } } @@ -303,53 +211,47 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder { void request(Set<InventoryVector> inventoryVectors) { if (!running || inventoryVectors.isEmpty()) return; - synchronized (connections) { - Map<Connection, List<InventoryVector>> distribution = new HashMap<>(); - for (Connection connection : connections) { - if (connection.getState() == ACTIVE) { - distribution.put(connection, new LinkedList<InventoryVector>()); - } - } - Iterator<InventoryVector> iterator = inventoryVectors.iterator(); - InventoryVector next; - if (iterator.hasNext()) { - next = iterator.next(); - } else { - return; - } - boolean firstRound = true; - while (firstRound || iterator.hasNext()) { - if (!firstRound) { - next = iterator.next(); - firstRound = true; - } else { - firstRound = false; - } - for (Connection connection : distribution.keySet()) { - if (connection.knowsOf(next)) { - List<InventoryVector> ivs = distribution.get(connection); - if (ivs.size() == 50_000) { - connection.send(new GetData.Builder().inventory(ivs).build()); - ivs.clear(); - } - ivs.add(next); - iterator.remove(); - if (iterator.hasNext()) { - next = iterator.next(); - firstRound = true; - } else { - firstRound = false; - break; - } + Map<Connection, List<InventoryVector>> distribution = new HashMap<>(); + for (Connection connection : connections) { + if (connection.getState() == ACTIVE) { + distribution.put(connection, new LinkedList<InventoryVector>()); + } + } + Iterator<InventoryVector> iterator = inventoryVectors.iterator(); + if (!iterator.hasNext()) { + return; + } + InventoryVector next = iterator.next(); + Connection previous = null; + do { + for (Connection connection : distribution.keySet()) { + if (connection == previous) { + next = iterator.next(); + } + if (connection.knowsOf(next)) { + List<InventoryVector> ivs = distribution.get(connection); + if (ivs.size() == GetData.MAX_INVENTORY_SIZE) { + connection.send(new GetData.Builder().inventory(ivs).build()); + ivs.clear(); + } + ivs.add(next); + iterator.remove(); + + if (iterator.hasNext()) { + next = iterator.next(); + previous = connection; + } else { + break; } } } - for (Connection connection : distribution.keySet()) { - List<InventoryVector> ivs = distribution.get(connection); - if (!ivs.isEmpty()) { - connection.send(new GetData.Builder().inventory(ivs).build()); - } + } while (iterator.hasNext()); + + for (Connection connection : distribution.keySet()) { + List<InventoryVector> ivs = distribution.get(connection); + if (!ivs.isEmpty()) { + connection.send(new GetData.Builder().inventory(ivs).build()); } } } diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/ServerRunnable.java b/networking/src/main/java/ch/dissem/bitmessage/networking/ServerRunnable.java new file mode 100644 index 0000000..bf6d6f6 --- /dev/null +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/ServerRunnable.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.networking; + +import ch.dissem.bitmessage.InternalContext; +import ch.dissem.bitmessage.ports.NetworkHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Closeable; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +import static ch.dissem.bitmessage.networking.Connection.Mode.SERVER; + +/** + * @author Christian Basler + */ +public class ServerRunnable implements Runnable, Closeable { + private static final Logger LOG = LoggerFactory.getLogger(ServerRunnable.class); + private final InternalContext ctx; + private final ServerSocket serverSocket; + private final DefaultNetworkHandler networkHandler; + private final NetworkHandler.MessageListener listener; + + public ServerRunnable(InternalContext ctx, DefaultNetworkHandler networkHandler, NetworkHandler.MessageListener listener) throws IOException { + this.ctx = ctx; + this.networkHandler = networkHandler; + this.listener = listener; + this.serverSocket = new ServerSocket(ctx.getPort()); + } + + @Override + public void run() { + while (!serverSocket.isClosed()) { + try { + Socket socket = serverSocket.accept(); + socket.setSoTimeout(Connection.READ_TIMEOUT); + networkHandler.startConnection(new Connection(ctx, SERVER, socket, listener, + networkHandler.requestedObjects)); + } catch (IOException e) { + LOG.debug(e.getMessage(), e); + } + } + } + + @Override + public void close() { + try { + serverSocket.close(); + } catch (IOException e) { + LOG.debug(e.getMessage(), e); + } + } +} diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java index 6e58f09..97202d1 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java @@ -99,10 +99,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito BitmessageAddress address; InputStream privateKeyStream = rs.getBinaryStream("private_key"); - if (privateKeyStream != null) { - PrivateKey privateKey = PrivateKey.read(privateKeyStream); - address = new BitmessageAddress(privateKey); - } else { + if (privateKeyStream == null) { address = new BitmessageAddress(rs.getString("address")); Blob publicKeyBlob = rs.getBlob("public_key"); if (publicKeyBlob != null) { @@ -113,6 +110,9 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito } address.setPubkey(pubkey); } + } else { + PrivateKey privateKey = PrivateKey.read(privateKeyStream); + address = new BitmessageAddress(privateKey); } address.setAlias(rs.getString("alias")); address.setSubscribed(rs.getBoolean("subscribed")); diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcHelper.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcHelper.java index d583a71..1df12f6 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcHelper.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcHelper.java @@ -77,12 +77,12 @@ public abstract class JdbcHelper { } protected void writeBlob(PreparedStatement ps, int parameterIndex, Streamable data) throws SQLException, IOException { - if (data != null) { + if (data == null) { + ps.setBytes(parameterIndex, null); + } else { ByteArrayOutputStream os = new ByteArrayOutputStream(); data.write(os); ps.setBytes(parameterIndex, os.toByteArray()); - } else { - ps.setBytes(parameterIndex, null); } } } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java index c01e147..d77cdfb 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java @@ -90,10 +90,10 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito @Override public int countUnread(Label label) { String where; - if (label != null) { - where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ") AND "; - } else { + if (label == null) { where = ""; + } else { + where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ") AND "; } where += "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" + "SELECT id FROM Label WHERE type = '" + Label.Type.UNREAD.name() + "'))"; @@ -237,14 +237,14 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito PreparedStatement ps = connection.prepareStatement( "INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status, initial_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); - ps.setBytes(1, message.getInventoryVector() != null ? message.getInventoryVector().getHash() : null); + ps.setBytes(1, message.getInventoryVector() == null ? null : message.getInventoryVector().getHash()); ps.setString(2, message.getType().name()); ps.setString(3, message.getFrom().getAddress()); - ps.setString(4, message.getTo() != null ? message.getTo().getAddress() : null); + ps.setString(4, message.getTo() == null ? null : message.getTo().getAddress()); writeBlob(ps, 5, message); ps.setLong(6, message.getSent()); ps.setLong(7, message.getReceived()); - ps.setString(8, message.getStatus() != null ? message.getStatus().name() : null); + ps.setString(8, message.getStatus() == null ? null : message.getStatus().name()); ps.setBytes(9, message.getInitialHash()); ps.executeUpdate(); @@ -258,10 +258,10 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito private void update(Connection connection, Plaintext message) throws SQLException, IOException { PreparedStatement ps = connection.prepareStatement( "UPDATE Message SET iv=?, sent=?, received=?, status=?, initial_hash=? WHERE id=?"); - ps.setBytes(1, message.getInventoryVector() != null ? message.getInventoryVector().getHash() : null); + ps.setBytes(1, message.getInventoryVector() == null ? null : message.getInventoryVector().getHash()); ps.setLong(2, message.getSent()); ps.setLong(3, message.getReceived()); - ps.setString(4, message.getStatus() != null ? message.getStatus().name() : null); + ps.setString(4, message.getStatus() == null ? null : message.getStatus().name()); ps.setBytes(5, message.getInitialHash()); ps.setLong(6, (Long) message.getId()); ps.executeUpdate(); From 2a17e6024f34d7ab0a7d09c7ef072caab9b43c5d Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Fri, 26 Feb 2016 15:06:47 +0100 Subject: [PATCH 46/54] Code cleanup --- .../ch/dissem/bitmessage/utils/Strings.java | 2 - .../ch/dissem/bitmessage/SignatureTest.java | 2 - .../networking/ConnectionOrganizer.java | 6 +- .../repository/JdbcMessageRepository.java | 125 ++++++++++-------- .../ch/dissem/bitmessage/wif/WifImporter.java | 4 - 5 files changed, 73 insertions(+), 66 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/Strings.java b/core/src/main/java/ch/dissem/bitmessage/utils/Strings.java index 5c1aae9..7c9e13f 100644 --- a/core/src/main/java/ch/dissem/bitmessage/utils/Strings.java +++ b/core/src/main/java/ch/dissem/bitmessage/utils/Strings.java @@ -16,8 +16,6 @@ package ch.dissem.bitmessage.utils; -import ch.dissem.bitmessage.entity.payload.ObjectType; - /** * Some utilities to handle strings. * TODO: Probably this should be split in a GUI related and an SQL related utility class. diff --git a/core/src/test/java/ch/dissem/bitmessage/SignatureTest.java b/core/src/test/java/ch/dissem/bitmessage/SignatureTest.java index 71b7d2a..3566a5f 100644 --- a/core/src/test/java/ch/dissem/bitmessage/SignatureTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/SignatureTest.java @@ -22,7 +22,6 @@ import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.payload.Msg; import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.payload.Pubkey; -import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.TestBase; @@ -30,7 +29,6 @@ import ch.dissem.bitmessage.utils.TestUtils; import org.junit.Test; import java.io.IOException; -import java.util.Date; import static org.junit.Assert.*; diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/ConnectionOrganizer.java b/networking/src/main/java/ch/dissem/bitmessage/networking/ConnectionOrganizer.java index 3f667e6..1163d1c 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/ConnectionOrganizer.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/ConnectionOrganizer.java @@ -99,12 +99,12 @@ public class ConnectionOrganizer implements Runnable { networkHandler.startConnection(c); } Thread.sleep(10000); - } else if (initialConnection != null) { + } else if (initialConnection == null) { + Thread.sleep(30000); + } else { initialConnection.disconnect(); initialConnection = null; Thread.sleep(10000); - } else { - Thread.sleep(30000); } } catch (InterruptedException e) { networkHandler.stop(); diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java index d77cdfb..1d714d9 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java @@ -47,9 +47,11 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito @Override public List<Label> getLabels() { List<Label> result = new LinkedList<>(); - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label ORDER BY ord"); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label ORDER BY ord") + ) { while (rs.next()) { result.add(getLabel(rs)); } @@ -74,10 +76,12 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito @Override public List<Label> getLabels(Label.Type... types) { List<Label> result = new LinkedList<>(); - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label WHERE type IN (" + join(types) + - ") ORDER BY ord"); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label WHERE type IN (" + join(types) + + ") ORDER BY ord") + ) { while (rs.next()) { result.add(getLabel(rs)); } @@ -98,9 +102,11 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito where += "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" + "SELECT id FROM Label WHERE type = '" + Label.Type.UNREAD.name() + "'))"; - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT count(*) FROM Message WHERE " + where); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT count(*) FROM Message WHERE " + where) + ) { if (rs.next()) { return rs.getInt(1); } @@ -146,9 +152,12 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito private List<Plaintext> find(String where) { List<Plaintext> result = new LinkedList<>(); - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT id, iv, type, sender, recipient, data, sent, received, status FROM Message WHERE " + where); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT id, iv, type, sender, recipient, data, sent, received, status " + + "FROM Message WHERE " + where) + ) { while (rs.next()) { byte[] iv = rs.getBytes("iv"); InputStream data = rs.getBinaryStream("data"); @@ -173,9 +182,11 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito private Collection<Label> findLabels(Connection connection, long messageId) { List<Label> result = new ArrayList<>(); - try { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label WHERE id IN (SELECT label_id FROM Message_Label WHERE message_id=" + messageId + ")"); + try ( + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label " + + "WHERE id IN (SELECT label_id FROM Message_Label WHERE message_id=" + messageId + ")") + ) { while (rs.next()) { result.add(getLabel(rs)); } @@ -209,16 +220,17 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito } // remove existing labels - Statement stmt = connection.createStatement(); - stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id=" + message.getId()); - - // save labels - PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" + message.getId() + ", ?)"); - for (Label label : message.getLabels()) { - ps.setLong(1, (Long) label.getId()); - ps.executeUpdate(); + try (Statement stmt = connection.createStatement()) { + stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id=" + message.getId()); + } + // save labels + try (PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" + + message.getId() + ", ?)")) { + for (Label label : message.getLabels()) { + ps.setLong(1, (Long) label.getId()); + ps.executeUpdate(); + } } - connection.commit(); } catch (IOException | SQLException e) { try { @@ -234,45 +246,48 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito } private void insert(Connection connection, Plaintext message) throws SQLException, IOException { - PreparedStatement ps = connection.prepareStatement( - "INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status, initial_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", - Statement.RETURN_GENERATED_KEYS); - ps.setBytes(1, message.getInventoryVector() == null ? null : message.getInventoryVector().getHash()); - ps.setString(2, message.getType().name()); - ps.setString(3, message.getFrom().getAddress()); - ps.setString(4, message.getTo() == null ? null : message.getTo().getAddress()); - writeBlob(ps, 5, message); - ps.setLong(6, message.getSent()); - ps.setLong(7, message.getReceived()); - ps.setString(8, message.getStatus() == null ? null : message.getStatus().name()); - ps.setBytes(9, message.getInitialHash()); + try (PreparedStatement ps = connection.prepareStatement( + "INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status, initial_hash) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + Statement.RETURN_GENERATED_KEYS) + ) { + ps.setBytes(1, message.getInventoryVector() == null ? null : message.getInventoryVector().getHash()); + ps.setString(2, message.getType().name()); + ps.setString(3, message.getFrom().getAddress()); + ps.setString(4, message.getTo() == null ? null : message.getTo().getAddress()); + writeBlob(ps, 5, message); + ps.setLong(6, message.getSent()); + ps.setLong(7, message.getReceived()); + ps.setString(8, message.getStatus() == null ? null : message.getStatus().name()); + ps.setBytes(9, message.getInitialHash()); - ps.executeUpdate(); - - // get generated id - ResultSet rs = ps.getGeneratedKeys(); - rs.next(); - message.setId(rs.getLong(1)); + ps.executeUpdate(); + // get generated id + try (ResultSet rs = ps.getGeneratedKeys()) { + rs.next(); + message.setId(rs.getLong(1)); + } + } } private void update(Connection connection, Plaintext message) throws SQLException, IOException { - PreparedStatement ps = connection.prepareStatement( - "UPDATE Message SET iv=?, sent=?, received=?, status=?, initial_hash=? WHERE id=?"); - ps.setBytes(1, message.getInventoryVector() == null ? null : message.getInventoryVector().getHash()); - ps.setLong(2, message.getSent()); - ps.setLong(3, message.getReceived()); - ps.setString(4, message.getStatus() == null ? null : message.getStatus().name()); - ps.setBytes(5, message.getInitialHash()); - ps.setLong(6, (Long) message.getId()); - ps.executeUpdate(); + try (PreparedStatement ps = connection.prepareStatement( + "UPDATE Message SET iv=?, sent=?, received=?, status=?, initial_hash=? WHERE id=?")) { + ps.setBytes(1, message.getInventoryVector() == null ? null : message.getInventoryVector().getHash()); + ps.setLong(2, message.getSent()); + ps.setLong(3, message.getReceived()); + ps.setString(4, message.getStatus() == null ? null : message.getStatus().name()); + ps.setBytes(5, message.getInitialHash()); + ps.setLong(6, (Long) message.getId()); + ps.executeUpdate(); + } } @Override public void remove(Plaintext message) { try (Connection connection = config.getConnection()) { - try { - connection.setAutoCommit(false); - Statement stmt = connection.createStatement(); + connection.setAutoCommit(false); + try (Statement stmt = connection.createStatement()) { stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id = " + message.getId()); stmt.executeUpdate("DELETE FROM Message WHERE id = " + message.getId()); connection.commit(); diff --git a/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java b/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java index e88eaa4..a84e928 100644 --- a/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java +++ b/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java @@ -39,11 +39,7 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * @author Christian Basler */ public class WifImporter { - private final static Logger LOG = LoggerFactory.getLogger(WifImporter.class); - private final BitmessageContext ctx; - private final Ini ini = new Ini(); - private final List<BitmessageAddress> identities = new LinkedList<>(); public WifImporter(BitmessageContext ctx, File file) throws IOException { From 9ca28ead66a54ba2f1f499d64244f87dfa9ddc4a Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Fri, 26 Feb 2016 16:12:43 +0100 Subject: [PATCH 47/54] Code cleanup --- .../bitmessage/repository/JdbcInventory.java | 50 +++++++++------ .../repository/JdbcMessageRepository.java | 62 ++++++++++--------- 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java index aa41e5c..e70cabb 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java @@ -88,9 +88,11 @@ public class JdbcInventory extends JdbcHelper implements Inventory { @Override public ObjectMessage getObject(InventoryVector vector) { - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT data, version FROM Inventory WHERE hash = X'" + vector + "'"); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT data, version FROM Inventory WHERE hash = X'" + vector + "'") + ) { if (rs.next()) { Blob data = rs.getBlob("data"); return Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length()); @@ -106,19 +108,21 @@ public class JdbcInventory extends JdbcHelper implements Inventory { @Override public List<ObjectMessage> getObjects(long stream, long version, ObjectType... types) { - try (Connection connection = config.getConnection()) { - StringBuilder query = new StringBuilder("SELECT data, version FROM Inventory WHERE 1=1"); - if (stream > 0) { - query.append(" AND stream = ").append(stream); - } - if (version > 0) { - query.append(" AND version = ").append(version); - } - if (types.length > 0) { - query.append(" AND type IN (").append(join(types)).append(")"); - } - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery(query.toString()); + StringBuilder query = new StringBuilder("SELECT data, version FROM Inventory WHERE 1=1"); + if (stream > 0) { + query.append(" AND stream = ").append(stream); + } + if (version > 0) { + query.append(" AND version = ").append(version); + } + if (types.length > 0) { + query.append(" AND type IN (").append(join(types)).append(")"); + } + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery(query.toString()) + ) { List<ObjectMessage> result = new LinkedList<>(); while (rs.next()) { Blob data = rs.getBlob("data"); @@ -136,8 +140,11 @@ public class JdbcInventory extends JdbcHelper implements Inventory { if (getCache(object.getStream()).containsKey(object.getInventoryVector())) return; - try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement("INSERT INTO Inventory (hash, stream, expires, data, type, version) VALUES (?, ?, ?, ?, ?, ?)"); + try ( + Connection connection = config.getConnection(); + PreparedStatement ps = connection.prepareStatement("INSERT INTO Inventory " + + "(hash, stream, expires, data, type, version) VALUES (?, ?, ?, ?, ?, ?)") + ) { InventoryVector iv = object.getInventoryVector(); LOG.trace("Storing object " + iv); ps.setBytes(1, iv.getHash()); @@ -163,8 +170,11 @@ public class JdbcInventory extends JdbcHelper implements Inventory { @Override public void cleanup() { - try (Connection connection = config.getConnection()) { - connection.createStatement().executeUpdate("DELETE FROM Inventory WHERE expires < " + now(-5 * MINUTE)); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement() + ) { + stmt.executeUpdate("DELETE FROM Inventory WHERE expires < " + now(-5 * MINUTE)); } catch (SQLException e) { LOG.debug(e.getMessage(), e); } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java index 1d714d9..e043e7e 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java @@ -201,50 +201,52 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito // save from address if necessary if (message.getId() == null) { BitmessageAddress savedAddress = ctx.getAddressRepository().getAddress(message.getFrom().getAddress()); - if (savedAddress == null || savedAddress.getPrivateKey() == null) { - if (savedAddress != null && savedAddress.getAlias() != null) { - message.getFrom().setAlias(savedAddress.getAlias()); - } + if (savedAddress == null) { ctx.getAddressRepository().save(message.getFrom()); + } else if (savedAddress.getPubkey() == null && message.getFrom().getPubkey() != null) { + savedAddress.setPubkey(message.getFrom().getPubkey()); + ctx.getAddressRepository().save(savedAddress); } } try (Connection connection = config.getConnection()) { try { connection.setAutoCommit(false); - // save message - if (message.getId() == null) { - insert(connection, message); - } else { - update(connection, message); - } - - // remove existing labels - try (Statement stmt = connection.createStatement()) { - stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id=" + message.getId()); - } - // save labels - try (PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" + - message.getId() + ", ?)")) { - for (Label label : message.getLabels()) { - ps.setLong(1, (Long) label.getId()); - ps.executeUpdate(); - } - } + save(connection, message); + updateLabels(connection, message); connection.commit(); } catch (IOException | SQLException e) { - try { - connection.rollback(); - } catch (SQLException e1) { - LOG.debug(e1.getMessage(), e); - } - throw new ApplicationException(e); + connection.rollback(); + throw e; } - } catch (SQLException e) { + } catch (IOException | SQLException e) { throw new ApplicationException(e); } } + private void save(Connection connection, Plaintext message) throws IOException, SQLException { + if (message.getId() == null) { + insert(connection, message); + } else { + update(connection, message); + } + } + + private void updateLabels(Connection connection, Plaintext message) throws SQLException { + // remove existing labels + try (Statement stmt = connection.createStatement()) { + stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id=" + message.getId()); + } + // save new labels + try (PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" + + message.getId() + ", ?)")) { + for (Label label : message.getLabels()) { + ps.setLong(1, (Long) label.getId()); + ps.executeUpdate(); + } + } + } + private void insert(Connection connection, Plaintext message) throws SQLException, IOException { try (PreparedStatement ps = connection.prepareStatement( "INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status, initial_hash) " + From 57057298a1bf470701ff3953f9b701ac5e9d8756 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Fri, 26 Feb 2016 16:30:45 +0100 Subject: [PATCH 48/54] Code cleanup --- .../repository/JdbcAddressRepository.java | 56 +++++++++++-------- .../bitmessage/repository/JdbcInventory.java | 13 +++-- .../repository/JdbcProofOfWorkRepository.java | 49 +++++++++------- .../ch/dissem/bitmessage/wif/WifImporter.java | 15 +++-- 4 files changed, 80 insertions(+), 53 deletions(-) diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java index 97202d1..2cbd8c7 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java @@ -21,7 +21,6 @@ import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.payload.V3Pubkey; import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; -import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.AddressRepository; import org.slf4j.Logger; @@ -92,9 +91,12 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito private List<BitmessageAddress> find(String where) { List<BitmessageAddress> result = new LinkedList<>(); - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT address, alias, public_key, private_key, subscribed FROM Address WHERE " + where); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT address, alias, public_key, private_key, subscribed " + + "FROM Address WHERE " + where) + ) { while (rs.next()) { BitmessageAddress address; @@ -126,9 +128,12 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito } private boolean exists(BitmessageAddress address) { - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM Address WHERE address='" + address.getAddress() + "'"); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM Address " + + "WHERE address='" + address.getAddress() + "'") + ) { if (rs.next()) { return rs.getInt(1) > 0; } @@ -152,16 +157,18 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito } private void update(BitmessageAddress address) throws IOException, SQLException { - try (Connection connection = config.getConnection()) { - StringBuilder statement = new StringBuilder("UPDATE Address SET alias=?"); - if (address.getPubkey() != null) { - statement.append(", public_key=?"); - } - if (address.getPrivateKey() != null) { - statement.append(", private_key=?"); - } - statement.append(", subscribed=? WHERE address=?"); - PreparedStatement ps = connection.prepareStatement(statement.toString()); + StringBuilder statement = new StringBuilder("UPDATE Address SET alias=?"); + if (address.getPubkey() != null) { + statement.append(", public_key=?"); + } + if (address.getPrivateKey() != null) { + statement.append(", private_key=?"); + } + statement.append(", subscribed=? WHERE address=?"); + try ( + Connection connection = config.getConnection(); + PreparedStatement ps = connection.prepareStatement(statement.toString()) + ) { int i = 0; ps.setString(++i, address.getAlias()); if (address.getPubkey() != null) { @@ -177,9 +184,12 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito } private void insert(BitmessageAddress address) throws IOException, SQLException { - try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement( - "INSERT INTO Address (address, version, alias, public_key, private_key, subscribed) VALUES (?, ?, ?, ?, ?, ?)"); + try ( + Connection connection = config.getConnection(); + PreparedStatement ps = connection.prepareStatement( + "INSERT INTO Address (address, version, alias, public_key, private_key, subscribed) " + + "VALUES (?, ?, ?, ?, ?, ?)") + ) { ps.setString(1, address.getAddress()); ps.setLong(2, address.getVersion()); ps.setString(3, address.getAlias()); @@ -202,8 +212,10 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito @Override public void remove(BitmessageAddress address) { - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement() + ) { stmt.executeUpdate("DELETE FROM Address WHERE address = '" + address.getAddress() + "'"); } catch (SQLException e) { LOG.error(e.getMessage(), e); diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java index e70cabb..0cc9f3b 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcInventory.java @@ -61,11 +61,12 @@ public class JdbcInventory extends JdbcHelper implements Inventory { if (cache.get(stream) == null) { result = new ConcurrentHashMap<>(); cache.put(stream, result); - - try (Connection connection = config.getConnection()) { - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT hash, expires FROM Inventory WHERE expires > " - + now(-5 * MINUTE) + " AND stream = " + stream); + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT hash, expires FROM Inventory " + + "WHERE expires > " + now(-5 * MINUTE) + " AND stream = " + stream) + ) { while (rs.next()) { result.put(new InventoryVector(rs.getBytes("hash")), rs.getLong("expires")); } @@ -116,7 +117,7 @@ public class JdbcInventory extends JdbcHelper implements Inventory { query.append(" AND version = ").append(version); } if (types.length > 0) { - query.append(" AND type IN (").append(join(types)).append(")"); + query.append(" AND type IN (").append(join(types)).append(')'); } try ( Connection connection = config.getConnection(); diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java index 37628b5..0fbb2dc 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcProofOfWorkRepository.java @@ -27,19 +27,23 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork @Override public Item getItem(byte[] initialHash) { - try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement("SELECT data, version, nonce_trials_per_byte, extra_bytes FROM POW WHERE initial_hash=?"); + try ( + Connection connection = config.getConnection(); + PreparedStatement ps = connection.prepareStatement("SELECT data, version, nonce_trials_per_byte, " + + "extra_bytes FROM POW WHERE initial_hash=?") + ) { ps.setBytes(1, initialHash); - ResultSet rs = ps.executeQuery(); - if (rs.next()) { - Blob data = rs.getBlob("data"); - return new Item( - Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length()), - rs.getLong("nonce_trials_per_byte"), - rs.getLong("extra_bytes") - ); - } else { - throw new IllegalArgumentException("Object requested that we don't have. Initial hash: " + Strings.hex(initialHash)); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + Blob data = rs.getBlob("data"); + return new Item( + Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length()), + rs.getLong("nonce_trials_per_byte"), + rs.getLong("extra_bytes") + ); + } else { + throw new IllegalArgumentException("Object requested that we don't have. Initial hash: " + Strings.hex(initialHash)); + } } } catch (SQLException e) { LOG.error(e.getMessage(), e); @@ -49,10 +53,12 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork @Override public List<byte[]> getItems() { - try (Connection connection = config.getConnection()) { + try ( + Connection connection = config.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT initial_hash FROM POW") + ) { List<byte[]> result = new LinkedList<>(); - Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT initial_hash FROM POW"); while (rs.next()) { result.add(rs.getBytes("initial_hash")); } @@ -65,8 +71,11 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork @Override public void putObject(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) { - try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement("INSERT INTO POW (initial_hash, data, version, nonce_trials_per_byte, extra_bytes) VALUES (?, ?, ?, ?, ?)"); + try ( + Connection connection = config.getConnection(); + PreparedStatement ps = connection.prepareStatement("INSERT INTO POW (initial_hash, data, version, " + + "nonce_trials_per_byte, extra_bytes) VALUES (?, ?, ?, ?, ?)") + ) { ps.setBytes(1, security().getInitialHash(object)); writeBlob(ps, 2, object); ps.setLong(3, object.getVersion()); @@ -81,8 +90,10 @@ public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWork @Override public void removeObject(byte[] initialHash) { - try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement("DELETE FROM POW WHERE initial_hash=?"); + try ( + Connection connection = config.getConnection(); + PreparedStatement ps = connection.prepareStatement("DELETE FROM POW WHERE initial_hash=?") + ) { ps.setBytes(1, initialHash); ps.executeUpdate(); } catch (SQLException e) { diff --git a/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java b/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java index a84e928..3a45b44 100644 --- a/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java +++ b/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java @@ -23,8 +23,6 @@ import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.utils.Base58; import org.ini4j.Ini; import org.ini4j.Profile; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.*; import java.util.Arrays; @@ -39,6 +37,9 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * @author Christian Basler */ public class WifImporter { + private static final byte WIF_FIRST_BYTE = (byte) 0x80; + private static final int WIF_SECRET_LENGTH = 37; + private final BitmessageContext ctx; private final List<BitmessageAddress> identities = new LinkedList<>(); @@ -76,10 +77,12 @@ public class WifImporter { private byte[] getSecret(String walletImportFormat) throws IOException { byte[] bytes = Base58.decode(walletImportFormat); - if (bytes[0] != (byte) 0x80) - throw new IOException("Unknown format: 0x80 expected as first byte, but secret " + walletImportFormat + " was " + bytes[0]); - if (bytes.length != 37) - throw new IOException("Unknown format: 37 bytes expected, but secret " + walletImportFormat + " was " + bytes.length + " long"); + if (bytes[0] != WIF_FIRST_BYTE) + throw new IOException("Unknown format: 0x80 expected as first byte, but secret " + walletImportFormat + + " was " + bytes[0]); + if (bytes.length != WIF_SECRET_LENGTH) + throw new IOException("Unknown format: " + WIF_SECRET_LENGTH + + " bytes expected, but secret " + walletImportFormat + " was " + bytes.length + " long"); byte[] hash = security().doubleSha256(bytes, 33); for (int i = 0; i < 4; i++) { From 3e5e431d6f39fb8a7269b45c6a3bb0070cfbf13c Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Sun, 28 Feb 2016 23:03:00 +0100 Subject: [PATCH 49/54] Code cleanup --- .../cryptography/bc/BouncyCryptography.java | 19 +- .../cryptography/sc/SpongyCryptography.java | 19 +- .../dissem/bitmessage/demo/Application.java | 186 ++++---------- .../dissem/bitmessage/demo/CommandLine.java | 102 ++++++++ .../java/ch/dissem/bitmessage/demo/Main.java | 6 +- .../bitmessage/networking/Connection.java | 242 ++++++++++-------- 6 files changed, 313 insertions(+), 261 deletions(-) create mode 100644 demo/src/main/java/ch/dissem/bitmessage/demo/CommandLine.java diff --git a/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java b/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java index 41e2c37..377135c 100644 --- a/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java +++ b/cryptography-bc/src/main/java/ch/dissem/bitmessage/cryptography/bc/BouncyCryptography.java @@ -51,19 +51,23 @@ import java.util.Arrays; */ public class BouncyCryptography extends AbstractCryptography { private static final X9ECParameters EC_CURVE_PARAMETERS = CustomNamedCurves.getByName("secp256k1"); + private static final String ALGORITHM_ECDSA = "ECDSA"; + private static final String PROVIDER = "BC"; static { java.security.Security.addProvider(new BouncyCastleProvider()); } public BouncyCryptography() { - super("BC"); + super(PROVIDER); } @Override public byte[] crypt(boolean encrypt, byte[] data, byte[] key_e, byte[] initializationVector) { - BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding()); - + BufferedBlockCipher cipher = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new AESEngine()), + new PKCS7Padding() + ); CipherParameters params = new ParametersWithIV(new KeyParameter(key_e), initializationVector); cipher.init(encrypt, params); @@ -105,9 +109,9 @@ public class BouncyCryptography extends AbstractCryptography { ECPoint Q = keyToPoint(pubkey.getSigningKey()); KeySpec keySpec = new ECPublicKeySpec(Q, spec); - PublicKey publicKey = KeyFactory.getInstance("ECDSA", "BC").generatePublic(keySpec); + PublicKey publicKey = KeyFactory.getInstance(ALGORITHM_ECDSA, PROVIDER).generatePublic(keySpec); - Signature sig = Signature.getInstance("ECDSA", "BC"); + Signature sig = Signature.getInstance(ALGORITHM_ECDSA, PROVIDER); sig.initVerify(publicKey); sig.update(data); return sig.verify(signature); @@ -129,9 +133,10 @@ public class BouncyCryptography extends AbstractCryptography { BigInteger d = keyToBigInt(privateKey.getPrivateSigningKey()); KeySpec keySpec = new ECPrivateKeySpec(d, spec); - java.security.PrivateKey privKey = KeyFactory.getInstance("ECDSA", "BC").generatePrivate(keySpec); + java.security.PrivateKey privKey = KeyFactory.getInstance(ALGORITHM_ECDSA, PROVIDER) + .generatePrivate(keySpec); - Signature sig = Signature.getInstance("ECDSA", "BC"); + Signature sig = Signature.getInstance(ALGORITHM_ECDSA, PROVIDER); sig.initSign(privKey); sig.update(data); return sig.sign(); diff --git a/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java b/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java index 066ca10..b90e1c8 100644 --- a/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java +++ b/cryptography-sc/src/main/java/ch/dissem/bitmessage/cryptography/sc/SpongyCryptography.java @@ -51,19 +51,23 @@ import java.util.Arrays; */ public class SpongyCryptography extends AbstractCryptography { private static final X9ECParameters EC_CURVE_PARAMETERS = CustomNamedCurves.getByName("secp256k1"); + private static final String ALGORITHM_ECDSA = "ECDSA"; + private static final String PROVIDER = "SC"; static { java.security.Security.addProvider(new BouncyCastleProvider()); } public SpongyCryptography() { - super("SC"); + super(PROVIDER); } @Override public byte[] crypt(boolean encrypt, byte[] data, byte[] key_e, byte[] initializationVector) { - BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding()); - + BufferedBlockCipher cipher = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new AESEngine()), + new PKCS7Padding() + ); CipherParameters params = new ParametersWithIV(new KeyParameter(key_e), initializationVector); cipher.init(encrypt, params); @@ -105,9 +109,9 @@ public class SpongyCryptography extends AbstractCryptography { ECPoint Q = keyToPoint(pubkey.getSigningKey()); KeySpec keySpec = new ECPublicKeySpec(Q, spec); - PublicKey publicKey = KeyFactory.getInstance("ECDSA", "SC").generatePublic(keySpec); + PublicKey publicKey = KeyFactory.getInstance(ALGORITHM_ECDSA, PROVIDER).generatePublic(keySpec); - Signature sig = Signature.getInstance("ECDSA", "SC"); + Signature sig = Signature.getInstance(ALGORITHM_ECDSA, PROVIDER); sig.initVerify(publicKey); sig.update(data); return sig.verify(signature); @@ -129,9 +133,10 @@ public class SpongyCryptography extends AbstractCryptography { BigInteger d = keyToBigInt(privateKey.getPrivateSigningKey()); KeySpec keySpec = new ECPrivateKeySpec(d, spec); - java.security.PrivateKey privKey = KeyFactory.getInstance("ECDSA", "SC").generatePrivate(keySpec); + java.security.PrivateKey privKey = KeyFactory.getInstance(ALGORITHM_ECDSA, PROVIDER) + .generatePrivate(keySpec); - Signature sig = Signature.getInstance("ECDSA", "SC"); + Signature sig = Signature.getInstance(ALGORITHM_ECDSA, PROVIDER); sig.initSign(privKey); sig.update(data); return sig.sign(); diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java index dab43f3..a6a6e1f 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java @@ -17,31 +17,33 @@ package ch.dissem.bitmessage.demo; import ch.dissem.bitmessage.BitmessageContext; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.ports.MemoryNodeRegistry; import ch.dissem.bitmessage.repository.*; -import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.util.List; -import java.util.Scanner; + +import static ch.dissem.bitmessage.demo.CommandLine.COMMAND_BACK; +import static ch.dissem.bitmessage.demo.CommandLine.ERROR_UNKNOWN_COMMAND; /** * A simple command line Bitmessage application */ public class Application { private final static Logger LOG = LoggerFactory.getLogger(Application.class); - private final Scanner scanner; + private final CommandLine commandLine; private BitmessageContext ctx; - public Application(String syncServer, int syncPort) { + public Application(InetAddress syncServer, int syncPort) { JdbcConfig jdbcConfig = new JdbcConfig(); ctx = new BitmessageContext.Builder() .addressRepo(new JdbcAddressRepository(jdbcConfig)) @@ -68,7 +70,7 @@ public class Application { ctx.startup(); } - scanner = new Scanner(System.in); + commandLine = new CommandLine(); String command; do { @@ -84,7 +86,7 @@ public class Application { System.out.println("?) info"); System.out.println("e) exit"); - command = nextCommand(); + command = commandLine.nextCommand(); try { switch (command) { case "i": { @@ -106,10 +108,12 @@ public class Application { case "e": break; case "y": - ctx.synchronize(InetAddress.getByName(syncServer), syncPort, 120, true); + if (syncServer != null) { + ctx.synchronize(syncServer, syncPort, 120, true); + } break; default: - System.out.println("Unknown command. Please try again."); + System.out.println(ERROR_UNKNOWN_COMMAND); } } catch (Exception e) { LOG.debug(e.getMessage()); @@ -125,32 +129,16 @@ public class Application { System.out.println(ctx.status()); } - private String nextCommand() { - return scanner.nextLine().trim().toLowerCase(); - } - private void identities() { String command; List<BitmessageAddress> identities = ctx.addresses().getIdentities(); do { System.out.println(); - int i = 0; - for (BitmessageAddress identity : identities) { - i++; - System.out.print(i + ") "); - if (identity.getAlias() != null) { - System.out.println(identity.getAlias() + " (" + identity.getAddress() + ")"); - } else { - System.out.println(identity.getAddress()); - } - } - if (i == 0) { - System.out.println("You have no identities yet."); - } + commandLine.listAddresses(identities, "identities"); System.out.println("a) create identity"); - System.out.println("b) back"); + System.out.println(COMMAND_BACK); - command = nextCommand(); + command = commandLine.nextCommand(); switch (command) { case "a": addIdentity(); @@ -163,7 +151,7 @@ public class Application { int index = Integer.parseInt(command) - 1; address(identities.get(index)); } catch (NumberFormatException e) { - System.out.println("Unknown command. Please try again."); + System.out.println(ERROR_UNKNOWN_COMMAND); } } } while (!"b".equals(command)); @@ -171,9 +159,9 @@ public class Application { private void addIdentity() { System.out.println(); - BitmessageAddress identity = ctx.createIdentity(yesNo("would you like a shorter address? This will take some time to calculate."), Pubkey.Feature.DOES_ACK); + BitmessageAddress identity = ctx.createIdentity(commandLine.yesNo("would you like a shorter address? This will take some time to calculate."), Pubkey.Feature.DOES_ACK); System.out.println("Please enter an alias for this identity, or an empty string for none"); - String alias = scanner.nextLine().trim(); + String alias = commandLine.nextLineTrimmed(); if (alias.length() > 0) { identity.setAlias(alias); } @@ -185,24 +173,12 @@ public class Application { List<BitmessageAddress> contacts = ctx.addresses().getContacts(); do { System.out.println(); - int i = 0; - for (BitmessageAddress contact : contacts) { - i++; - System.out.print(i + ") "); - if (contact.getAlias() != null) { - System.out.println(contact.getAlias() + " (" + contact.getAddress() + ")"); - } else { - System.out.println(contact.getAddress()); - } - } - if (i == 0) { - System.out.println("You have no contacts yet."); - } + commandLine.listAddresses(contacts, "contacts"); System.out.println(); System.out.println("a) add contact"); - System.out.println("b) back"); + System.out.println(COMMAND_BACK); - command = nextCommand(); + command = commandLine.nextCommand(); switch (command) { case "a": addContact(false); @@ -215,7 +191,7 @@ public class Application { int index = Integer.parseInt(command) - 1; address(contacts.get(index)); } catch (NumberFormatException e) { - System.out.println("Unknown command. Please try again."); + System.out.println(ERROR_UNKNOWN_COMMAND); } } } while (!"b".equals(command)); @@ -225,9 +201,9 @@ public class Application { System.out.println(); System.out.println("Please enter the Bitmessage address you want to add"); try { - BitmessageAddress address = new BitmessageAddress(scanner.nextLine().trim()); + BitmessageAddress address = new BitmessageAddress(commandLine.nextLineTrimmed()); System.out.println("Please enter an alias for this address, or an empty string for none"); - String alias = scanner.nextLine().trim(); + String alias = commandLine.nextLineTrimmed(); if (alias.length() > 0) { address.setAlias(alias); } @@ -245,24 +221,12 @@ public class Application { List<BitmessageAddress> subscriptions = ctx.addresses().getSubscriptions(); do { System.out.println(); - int i = 0; - for (BitmessageAddress contact : subscriptions) { - i++; - System.out.print(i + ") "); - if (contact.getAlias() != null) { - System.out.println(contact.getAlias() + " (" + contact.getAddress() + ")"); - } else { - System.out.println(contact.getAddress()); - } - } - if (i == 0) { - System.out.println("You have no subscriptions yet."); - } + commandLine.listAddresses(subscriptions, "subscriptions"); System.out.println(); System.out.println("a) add subscription"); - System.out.println("b) back"); + System.out.println(COMMAND_BACK); - command = nextCommand(); + command = commandLine.nextCommand(); switch (command) { case "a": addContact(true); @@ -275,7 +239,7 @@ public class Application { int index = Integer.parseInt(command) - 1; address(subscriptions.get(index)); } catch (NumberFormatException e) { - System.out.println("Unknown command. Please try again."); + System.out.println(ERROR_UNKNOWN_COMMAND); } } } while (!"b".equals(command)); @@ -313,9 +277,9 @@ public class Application { System.out.println(); System.out.println("c) compose message"); System.out.println("s) compose broadcast"); - System.out.println("b) back"); + System.out.println(COMMAND_BACK); - command = scanner.nextLine().trim(); + command = commandLine.nextCommand(); switch (command) { case "c": compose(false); @@ -330,7 +294,7 @@ public class Application { int index = Integer.parseInt(command) - 1; show(messages.get(index)); } catch (NumberFormatException | IndexOutOfBoundsException e) { - System.out.println("Unknown command. Please try again."); + System.out.println(ERROR_UNKNOWN_COMMAND); } } } while (!"b".equalsIgnoreCase(command)); @@ -350,8 +314,8 @@ public class Application { do { System.out.println("r) reply"); System.out.println("d) delete"); - System.out.println("b) back"); - command = nextCommand(); + System.out.println(COMMAND_BACK); + command = commandLine.nextCommand(); switch (command) { case "r": compose(message.getTo(), message.getFrom(), "RE: " + message.getSubject()); @@ -361,18 +325,18 @@ public class Application { case "b": return; default: - System.out.println("Unknown command. Please try again."); + System.out.println(ERROR_UNKNOWN_COMMAND); } } while (!"b".equalsIgnoreCase(command)); } private void compose(boolean broadcast) { System.out.println(); - BitmessageAddress from = selectAddress(true); + BitmessageAddress from = selectIdentity(); if (from == null) { return; } - BitmessageAddress to = (broadcast ? null : selectAddress(false)); + BitmessageAddress to = (broadcast ? null : selectContact()); if (!broadcast && to == null) { return; } @@ -380,58 +344,22 @@ public class Application { compose(from, to, null); } - private BitmessageAddress selectAddress(boolean id) { - List<BitmessageAddress> addresses = (id ? ctx.addresses().getIdentities() : ctx.addresses().getContacts()); + private BitmessageAddress selectIdentity() { + List<BitmessageAddress> addresses = ctx.addresses().getIdentities(); while (addresses.size() == 0) { - if (id) { - addIdentity(); - addresses = ctx.addresses().getIdentities(); - } else { - addContact(false); - addresses = ctx.addresses().getContacts(); - } + addIdentity(); + addresses = ctx.addresses().getIdentities(); } - if (addresses.size() == 1) { - return addresses.get(0); + return commandLine.selectAddress(addresses, "From:"); + } + + private BitmessageAddress selectContact() { + List<BitmessageAddress> addresses = ctx.addresses().getContacts(); + while (addresses.size() == 0) { + addContact(false); + addresses = ctx.addresses().getContacts(); } - - String command; - do { - System.out.println(); - if (id) { - System.out.println("From:"); - } else { - System.out.println("To:"); - } - - int i = 0; - for (BitmessageAddress identity : addresses) { - i++; - System.out.print(i + ") "); - if (identity.getAlias() != null) { - System.out.println(identity.getAlias() + " (" + identity.getAddress() + ")"); - } else { - System.out.println(identity.getAddress()); - } - } - System.out.println("b) back"); - - command = nextCommand(); - switch (command) { - case "b": - return null; - default: - try { - int index = Integer.parseInt(command) - 1; - if (addresses.get(index) != null) { - return addresses.get(index); - } - } catch (NumberFormatException e) { - System.out.println("Unknown command. Please try again."); - } - } - } while (!"b".equals(command)); - return null; + return commandLine.selectAddress(addresses, "To:"); } private void compose(BitmessageAddress from, BitmessageAddress to, String subject) { @@ -445,29 +373,19 @@ public class Application { System.out.println("Subject: " + subject); } else { System.out.print("Subject: "); - subject = scanner.nextLine().trim(); + subject = commandLine.nextLineTrimmed(); } System.out.println("Message:"); StringBuilder message = new StringBuilder(); String line; do { - line = scanner.nextLine(); + line = commandLine.nextLine(); message.append(line).append('\n'); - } while (line.length() > 0 || !yesNo("Send message?")); + } while (line.length() > 0 || !commandLine.yesNo("Send message?")); if (broadcast) { ctx.broadcast(from, subject, message.toString()); } else { ctx.send(from, to, subject, message.toString()); } } - - private boolean yesNo(String question) { - String answer; - do { - System.out.println(question + " (y/n)"); - answer = scanner.nextLine(); - if ("y".equalsIgnoreCase(answer)) return true; - if ("n".equalsIgnoreCase(answer)) return false; - } while (true); - } } diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/CommandLine.java b/demo/src/main/java/ch/dissem/bitmessage/demo/CommandLine.java new file mode 100644 index 0000000..f04196a --- /dev/null +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/CommandLine.java @@ -0,0 +1,102 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.demo; + +import ch.dissem.bitmessage.entity.BitmessageAddress; + +import java.util.List; +import java.util.Scanner; + + +/** + * @author Christian Basler + */ +public class CommandLine { + public static final String COMMAND_BACK = "b) back"; + public static final String ERROR_UNKNOWN_COMMAND = "Unknown command. Please try again."; + + private Scanner scanner = new Scanner(System.in); + + public String nextCommand() { + return scanner.nextLine().trim().toLowerCase(); + } + + public String nextLine() { + return scanner.nextLine(); + } + + public String nextLineTrimmed() { + return scanner.nextLine(); + } + + public boolean yesNo(String question) { + String answer; + do { + System.out.println(question + " (y/n)"); + answer = scanner.nextLine(); + if ("y".equalsIgnoreCase(answer)) return true; + if ("n".equalsIgnoreCase(answer)) return false; + } while (true); + } + + public BitmessageAddress selectAddress(List<BitmessageAddress> addresses, String label) { + if (addresses.size() == 1) { + return addresses.get(0); + } + + String command; + do { + System.out.println(); + System.out.println(label); + + listAddresses(addresses, "contacts"); + System.out.println(COMMAND_BACK); + + command = nextCommand(); + switch (command) { + case "b": + return null; + default: + try { + int index = Integer.parseInt(command) - 1; + if (addresses.get(index) != null) { + return addresses.get(index); + } + } catch (NumberFormatException e) { + System.out.println(ERROR_UNKNOWN_COMMAND); + } + } + } while (!"b".equals(command)); + return null; + } + + public void listAddresses(List<BitmessageAddress> addresses, String kind) { + int i = 0; + for (BitmessageAddress address : addresses) { + i++; + System.out.print(i + ") "); + if (address.getAlias() == null) { + System.out.println(address.getAddress()); + } else { + System.out.println(address.getAlias() + " (" + address.getAddress() + ")"); + } + } + if (i == 0) { + System.out.println("You have no " + kind + " yet."); + } + } +} diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java index b0e114b..2532796 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Main.java @@ -17,10 +17,10 @@ package ch.dissem.bitmessage.demo; import ch.dissem.bitmessage.BitmessageContext; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.ports.MemoryNodeRegistry; import ch.dissem.bitmessage.repository.*; -import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.wif.WifExporter; import ch.dissem.bitmessage.wif.WifImporter; import org.kohsuke.args4j.CmdLineException; @@ -29,6 +29,7 @@ import org.kohsuke.args4j.Option; import java.io.File; import java.io.IOException; +import java.net.InetAddress; public class Main { public static void main(String[] args) throws IOException { @@ -64,7 +65,8 @@ public class Main { new WifImporter(ctx, options.importWIF).importAll(); } } else { - new Application(options.syncServer, options.syncPort); + InetAddress syncServer = options.syncServer == null ? null : InetAddress.getByName(options.syncServer); + new Application(syncServer, options.syncPort); } } diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 43f1e30..5781bc3 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -203,51 +203,16 @@ class Connection { private void receiveMessage(MessagePayload messagePayload) { switch (messagePayload.getCommand()) { case INV: - Inv inv = (Inv) messagePayload; - int originalSize = inv.getInventory().size(); - updateIvCache(inv.getInventory()); - List<InventoryVector> missing = ctx.getInventory().getMissing(inv.getInventory(), streams); - missing.removeAll(commonRequestedObjects); - LOG.debug("Received inventory with " + originalSize + " elements, of which are " - + missing.size() + " missing."); - send(new GetData.Builder().inventory(missing).build()); + receiveMessage((Inv) messagePayload); break; case GETDATA: - GetData getData = (GetData) messagePayload; - for (InventoryVector iv : getData.getInventory()) { - ObjectMessage om = ctx.getInventory().getObject(iv); - if (om != null) sendingQueue.offer(om); - } + receiveMessage((GetData) messagePayload); break; case OBJECT: - ObjectMessage objectMessage = (ObjectMessage) messagePayload; - try { - requestedObjects.remove(objectMessage.getInventoryVector()); - if (ctx.getInventory().contains(objectMessage)) { - LOG.trace("Received object " + objectMessage.getInventoryVector() + " - already in inventory"); - break; - } - listener.receive(objectMessage); - security().checkProofOfWork(objectMessage, ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes()); - ctx.getInventory().storeObject(objectMessage); - // offer object to some random nodes so it gets distributed throughout the network: - networkHandler.offer(objectMessage.getInventoryVector()); - lastObjectTime = UnixTime.now(); - } catch (InsufficientProofOfWorkException e) { - LOG.warn(e.getMessage()); - // DebugUtils.saveToFile(objectMessage); // this line must not be committed active - } catch (IOException e) { - LOG.error("Stream " + objectMessage.getStream() + ", object type " + objectMessage.getType() + ": " + e.getMessage(), e); - } finally { - if (commonRequestedObjects.remove(objectMessage.getInventoryVector())) { - LOG.debug("Received object that wasn't requested."); - } - } + receiveMessage((ObjectMessage) messagePayload); break; case ADDR: - Addr addr = (Addr) messagePayload; - LOG.debug("Received " + addr.getAddresses().size() + " addresses."); - ctx.getNodeRegistry().offerAddresses(addr.getAddresses()); + receiveMessage((Addr) messagePayload); break; case CUSTOM: case VERACK: @@ -257,6 +222,53 @@ class Connection { } } + private void receiveMessage(Inv inv) { + int originalSize = inv.getInventory().size(); + updateIvCache(inv.getInventory()); + List<InventoryVector> missing = ctx.getInventory().getMissing(inv.getInventory(), streams); + missing.removeAll(commonRequestedObjects); + LOG.debug("Received inventory with " + originalSize + " elements, of which are " + + missing.size() + " missing."); + send(new GetData.Builder().inventory(missing).build()); + } + + private void receiveMessage(GetData getData) { + for (InventoryVector iv : getData.getInventory()) { + ObjectMessage om = ctx.getInventory().getObject(iv); + if (om != null) sendingQueue.offer(om); + } + } + + private void receiveMessage(ObjectMessage objectMessage) { + requestedObjects.remove(objectMessage.getInventoryVector()); + if (ctx.getInventory().contains(objectMessage)) { + LOG.trace("Received object " + objectMessage.getInventoryVector() + " - already in inventory"); + return; + } + try { + listener.receive(objectMessage); + security().checkProofOfWork(objectMessage, ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes()); + ctx.getInventory().storeObject(objectMessage); + // offer object to some random nodes so it gets distributed throughout the network: + networkHandler.offer(objectMessage.getInventoryVector()); + lastObjectTime = UnixTime.now(); + } catch (InsufficientProofOfWorkException e) { + LOG.warn(e.getMessage()); + // DebugUtils.saveToFile(objectMessage); // this line must not be committed active + } catch (IOException e) { + LOG.error("Stream " + objectMessage.getStream() + ", object type " + objectMessage.getType() + ": " + e.getMessage(), e); + } finally { + if (commonRequestedObjects.remove(objectMessage.getInventoryVector())) { + LOG.debug("Received object that wasn't requested."); + } + } + } + + private void receiveMessage(Addr addr) { + LOG.debug("Received " + addr.getAddresses().size() + " addresses."); + ctx.getNodeRegistry().offerAddresses(addr.getAddresses()); + } + private void sendAddresses() { List<NetworkAddress> addresses = ctx.getNodeRegistry().getKnownAddresses(1000, streams); sendingQueue.offer(new Addr.Builder().addresses(addresses).build()); @@ -358,77 +370,10 @@ class Connection { Thread.sleep(100); } } - try { - NetworkMessage msg = Factory.getNetworkMessage(version, in); - if (msg == null) - continue; - switch (state) { - case ACTIVE: - receiveMessage(msg.getPayload()); - break; - - default: - switch (msg.getPayload().getCommand()) { - case VERSION: - Version payload = (Version) msg.getPayload(); - if (payload.getNonce() == ctx.getClientNonce()) { - LOG.info("Tried to connect to self, disconnecting."); - disconnect(); - } else if (payload.getVersion() >= BitmessageContext.CURRENT_VERSION) { - version = payload.getVersion(); - streams = payload.getStreams(); - send(new VerAck()); - switch (mode) { - case SERVER: - send(new Version.Builder().defaults().addrFrom(host).addrRecv(node).build()); - break; - case CLIENT: - case SYNC: - activateConnection(); - break; - default: - // NO OP - } - } else { - LOG.info("Received unsupported version " + payload.getVersion() + ", disconnecting."); - disconnect(); - } - break; - case VERACK: - switch (mode) { - case SERVER: - activateConnection(); - break; - case CLIENT: - case SYNC: - default: - // NO OP - break; - } - break; - case CUSTOM: - MessagePayload response = ctx.getCustomCommandHandler().handle((CustomMessage) msg.getPayload()); - if (response != null) { - send(response); - } - disconnect(); - break; - default: - throw new NodeException("Command 'version' or 'verack' expected, but was '" - + msg.getPayload().getCommand() + "'"); - } - } - if (socket.isClosed() || syncFinished(msg) || checkOpenRequests()) disconnect(); - } catch (SocketTimeoutException ignore) { - if (state == ACTIVE) { - if (syncFinished(null)) disconnect(); - } - } + receive(); } - } catch (InterruptedException | IOException | NodeException e) { + } catch (Exception e) { LOG.trace("Reader disconnected from node " + node + ": " + e.getMessage()); - } catch (RuntimeException e) { - LOG.trace("Reader disconnecting from node " + node + " due to error: " + e.getMessage(), e); } finally { disconnect(); try { @@ -438,6 +383,81 @@ class Connection { } } } + + private void receive() throws InterruptedException { + try { + NetworkMessage msg = Factory.getNetworkMessage(version, in); + if (msg == null) + return; + switch (state) { + case ACTIVE: + receiveMessage(msg.getPayload()); + break; + + default: + handleCommand(msg.getPayload()); + break; + } + if (socket.isClosed() || syncFinished(msg) || checkOpenRequests()) disconnect(); + } catch (SocketTimeoutException ignore) { + if (state == ACTIVE && syncFinished(null)) disconnect(); + } + } + + private void handleCommand(MessagePayload payload) { + switch (payload.getCommand()) { + case VERSION: + handleVersion((Version) payload); + break; + case VERACK: + switch (mode) { + case SERVER: + activateConnection(); + break; + case CLIENT: + case SYNC: + default: + // NO OP + break; + } + break; + case CUSTOM: + MessagePayload response = ctx.getCustomCommandHandler().handle((CustomMessage) payload); + if (response != null) { + send(response); + } + disconnect(); + break; + default: + throw new NodeException("Command 'version' or 'verack' expected, but was '" + + payload.getCommand() + "'"); + } + } + + private void handleVersion(Version version) { + if (version.getNonce() == ctx.getClientNonce()) { + LOG.info("Tried to connect to self, disconnecting."); + disconnect(); + } else if (version.getVersion() >= BitmessageContext.CURRENT_VERSION) { + Connection.this.version = version.getVersion(); + streams = version.getStreams(); + send(new VerAck()); + switch (mode) { + case SERVER: + send(new Version.Builder().defaults().addrFrom(host).addrRecv(node).build()); + break; + case CLIENT: + case SYNC: + activateConnection(); + break; + default: + // NO OP + } + } else { + LOG.info("Received unsupported version " + version.getVersion() + ", disconnecting."); + disconnect(); + } + } } private boolean checkOpenRequests() { @@ -450,10 +470,10 @@ class Connection { try (Socket socket = Connection.this.socket) { initSocket(socket); while (state != DISCONNECTED) { - if (!sendingQueue.isEmpty()) { - send(sendingQueue.poll()); - } else { + if (sendingQueue.isEmpty()) { Thread.sleep(1000); + } else { + send(sendingQueue.poll()); } } } catch (IOException | InterruptedException e) { From ead5341b2e24d20eb305c36408efcaa5c678ccf8 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Thu, 31 Mar 2016 20:04:23 +0200 Subject: [PATCH 50/54] Some code for supporting chans --- .../dissem/bitmessage/BitmessageContext.java | 19 +++++++---- .../bitmessage/entity/BitmessageAddress.java | 26 +++++++++++++++ .../entity/valueobject/PrivateKey.java | 33 +++++++++++++++---- .../ch/dissem/bitmessage/utils/Encode.java | 30 ++++++++++++++++- .../bitmessage/BitmessageContextTest.java | 19 ++++++++++- .../entity/BitmessageAddressTest.java | 5 ++- 6 files changed, 115 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 9f03926..2b68f57 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -17,10 +17,7 @@ package ch.dissem.bitmessage; import ch.dissem.bitmessage.entity.*; -import ch.dissem.bitmessage.entity.payload.Broadcast; -import ch.dissem.bitmessage.entity.payload.Msg; -import ch.dissem.bitmessage.entity.payload.ObjectPayload; -import ch.dissem.bitmessage.entity.payload.ObjectType; +import ch.dissem.bitmessage.entity.payload.*; import ch.dissem.bitmessage.entity.payload.Pubkey.Feature; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; @@ -117,9 +114,17 @@ public class BitmessageContext { return identity; } - public void addDistributedMailingList(String address, String alias) { - // TODO - throw new ApplicationException("not implemented"); + public BitmessageAddress joinChan(String passphrase, String address) { + BitmessageAddress chan = BitmessageAddress.chan(address, passphrase); + ctx.getAddressRepository().save(chan); + return chan; + } + + public BitmessageAddress createChan(String passphrase) { + // FIXME: hardcoded stream number + BitmessageAddress chan = BitmessageAddress.chan(1, passphrase); + ctx.getAddressRepository().save(chan); + return chan; } public void broadcast(final BitmessageAddress from, final String subject, final String message) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index 62fabc3..ff44d0f 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -57,6 +57,7 @@ public class BitmessageAddress implements Serializable { private String alias; private boolean subscribed; + private boolean chan; BitmessageAddress(long version, long stream, byte[] ripe) { try { @@ -93,6 +94,27 @@ public class BitmessageAddress implements Serializable { this.pubkey = publicKey; } + public BitmessageAddress(String address, String passphrase) { + this(address); + this.privateKey = new PrivateKey(this, passphrase); + if (!Arrays.equals(ripe, privateKey.getPubkey().getRipe())) { + throw new IllegalArgumentException("Wrong address or passphrase"); + } + } + + public static BitmessageAddress chan(String address, String passphrase) { + BitmessageAddress result = new BitmessageAddress(address, passphrase); + result.chan = true; + return result; + } + + public static BitmessageAddress chan(long stream, String passphrase) { + PrivateKey privateKey = new PrivateKey(Pubkey.LATEST_VERSION, stream, passphrase); + BitmessageAddress result = new BitmessageAddress(privateKey); + result.chan = true; + return result; + } + public BitmessageAddress(PrivateKey privateKey) { this(privateKey.getPubkey()); this.privateKey = privateKey; @@ -221,4 +243,8 @@ public class BitmessageAddress implements Serializable { public void setSubscribed(boolean subscribed) { this.subscribed = subscribed; } + + public boolean isChan() { + return chan; + } } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java index e058308..6348add 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java @@ -16,6 +16,7 @@ package ch.dissem.bitmessage.entity.valueobject; +import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Streamable; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.exception.ApplicationException; @@ -64,14 +65,32 @@ public class PrivateKey implements Streamable { this.pubkey = pubkey; } - public PrivateKey(long version, long stream, String passphrase, long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) { + public PrivateKey(BitmessageAddress address, String passphrase) { + this(address.getVersion(), address.getStream(), passphrase); + } + + public PrivateKey(long version, long stream, String passphrase) { try { - // FIXME: this is most definitely wrong - this.privateSigningKey = Bytes.truncate(security().sha512(passphrase.getBytes("UTF-8"), new byte[]{0}), 32); - this.privateEncryptionKey = Bytes.truncate(security().sha512(passphrase.getBytes("UTF-8"), new byte[]{1}), 32); - this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey, - nonceTrialsPerByte, extraBytes, features); - } catch (UnsupportedEncodingException e) { + byte[] signingKey; + int signingKeyNonce = 0; + byte[] encryptionKey; + int encryptionKeyNonce = 1; + byte[] passPhraseBytes = passphrase.getBytes("UTF-8"); + byte[] ripe; + do { + signingKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(signingKeyNonce)), 32); + encryptionKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(encryptionKeyNonce)), 32); + byte[] publicSigningKey = security().createPublicKey(signingKey); + byte[] publicEncryptionKey = security().createPublicKey(encryptionKey); + ripe = security().ripemd160(security().sha512(publicSigningKey, publicEncryptionKey)); + + signingKeyNonce += 2; + encryptionKeyNonce += 2; + } while (ripe[0] != 0); + this.privateSigningKey = signingKey; + this.privateEncryptionKey = encryptionKey; + this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey, 0, 0); + } catch (IOException e) { throw new ApplicationException(e); } } diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/Encode.java b/core/src/main/java/ch/dissem/bitmessage/utils/Encode.java index 2cdc262..f5eac43 100644 --- a/core/src/main/java/ch/dissem/bitmessage/utils/Encode.java +++ b/core/src/main/java/ch/dissem/bitmessage/utils/Encode.java @@ -41,6 +41,34 @@ public class Encode { varInt(value, stream, null); } + public static byte[] varInt(long value) throws IOException { + final byte[] result; + if (value < 0) { + // This is due to the fact that Java doesn't really support unsigned values. + // Please be aware that this might be an error due to a smaller negative value being cast to long. + // Normally, negative values shouldn't occur within the protocol, and I large enough longs + // to being recognized as negatives aren't realistic. + ByteBuffer buffer = ByteBuffer.allocate(9); + buffer.put((byte) 0xff); + result = buffer.putLong(value).array(); + } else if (value < 0xfd) { + result = new byte[]{(byte) value}; + } else if (value <= 0xffffL) { + ByteBuffer buffer = ByteBuffer.allocate(3); + buffer.put((byte) 0xfd); + result = buffer.putShort((short) value).array(); + } else if (value <= 0xffffffffL) { + ByteBuffer buffer = ByteBuffer.allocate(5); + buffer.put((byte) 0xfe); + result = buffer.putInt((int) value).array(); + } else { + ByteBuffer buffer = ByteBuffer.allocate(9); + buffer.put((byte) 0xff); + result = buffer.putLong(value).array(); + } + return result; + } + public static void varInt(long value, OutputStream stream, AccessCounter counter) throws IOException { if (value < 0) { // This is due to the fact that Java doesn't really support unsigned values. @@ -81,7 +109,7 @@ public class Encode { } public static void int16(long value, OutputStream stream, AccessCounter counter) throws IOException { - stream.write(ByteBuffer.allocate(4).putInt((int) value).array(), 2, 2); + stream.write(ByteBuffer.allocate(2).putShort((short) value).array()); inc(counter, 2); } diff --git a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java index 890c2c3..a1991f8 100644 --- a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java @@ -39,7 +39,7 @@ import static ch.dissem.bitmessage.entity.payload.ObjectType.*; import static ch.dissem.bitmessage.utils.MessageMatchers.object; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; @@ -206,4 +206,21 @@ public class BitmessageContextTest { .build(); ctx.send(msg); } + + @Test + public void ensureChanIsJoined() { + String chanAddress = "BM-2cW67GEKkHGonXKZLCzouLLxnLym3azS8r"; + BitmessageAddress chan = ctx.joinChan("general", chanAddress); + assertNotNull(chan); + assertEquals(chan.getAddress(), chanAddress); + assertTrue(chan.isChan()); + } + + @Test + public void ensureChanIsCreated() { + BitmessageAddress chan = ctx.createChan("test"); + assertNotNull(chan); + assertEquals(chan.getVersion(), Pubkey.LATEST_VERSION); + assertTrue(chan.isChan()); + } } diff --git a/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java b/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java index 495aea9..9b22589 100644 --- a/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java @@ -20,7 +20,10 @@ import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.DecryptionFailedException; -import ch.dissem.bitmessage.utils.*; +import ch.dissem.bitmessage.utils.Base58; +import ch.dissem.bitmessage.utils.Bytes; +import ch.dissem.bitmessage.utils.Strings; +import ch.dissem.bitmessage.utils.TestUtils; import org.junit.Test; import java.io.IOException; From 32ea3517fe7a9f34caa8cb57ae214cea04b3baa2 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Thu, 7 Apr 2016 17:24:56 +0200 Subject: [PATCH 51/54] Chans should now work. Other deterministic addresses should be easy to implement, but aren't done yet --- .../dissem/bitmessage/BitmessageContext.java | 1 + .../bitmessage/DefaultMessageListener.java | 2 +- .../bitmessage/entity/BitmessageAddress.java | 4 +++ .../bitmessage/ports/AddressRepository.java | 7 +++- .../dissem/bitmessage/demo/Application.java | 33 ++++++++++++++----- .../repository/JdbcAddressRepository.java | 18 +++++++--- .../migration/V3.0__Update_table_address.sql | 1 + .../repository/JdbcAddressRepositoryTest.java | 20 ++++++++++- 8 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 repositories/src/main/resources/db/migration/V3.0__Update_table_address.sql diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 2b68f57..6348bcc 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -116,6 +116,7 @@ public class BitmessageContext { public BitmessageAddress joinChan(String passphrase, String address) { BitmessageAddress chan = BitmessageAddress.chan(address, passphrase); + chan.setAlias(passphrase); ctx.getAddressRepository().save(chan); return chan; } diff --git a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java index d209974..c2c2f64 100644 --- a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java +++ b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java @@ -73,7 +73,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { protected void receive(ObjectMessage object, GetPubkey getPubkey) { BitmessageAddress identity = ctx.getAddressRepository().findIdentity(getPubkey.getRipeTag()); - if (identity != null && identity.getPrivateKey() != null) { + if (identity != null && identity.getPrivateKey() != null && !identity.isChan()) { LOG.info("Got pubkey request for identity " + identity); // FIXME: only send pubkey if it wasn't sent in the last 28 days ctx.sendPubkey(identity, object.getStream()); diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index ff44d0f..229da14 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -247,4 +247,8 @@ public class BitmessageAddress implements Serializable { public boolean isChan() { return chan; } + + public void setChan(boolean chan) { + this.chan = chan; + } } diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java b/core/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java index 2770997..ff397ba 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java @@ -30,12 +30,17 @@ public interface AddressRepository { */ List<BitmessageAddress> getIdentities(); + /** + * @return all subscribed chans. + */ + List<BitmessageAddress> getChans(); + List<BitmessageAddress> getSubscriptions(); List<BitmessageAddress> getSubscriptions(long broadcastVersion); /** - * @return all Bitmessage addresses that have no private key. + * @return all Bitmessage addresses that have no private key or are chans. */ List<BitmessageAddress> getContacts(); diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java index a6a6e1f..f480785 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java @@ -54,14 +54,11 @@ public class Application { .networkHandler(new DefaultNetworkHandler()) .cryptography(new BouncyCryptography()) .port(48444) - .listener(new BitmessageContext.Listener() { - @Override - public void receive(Plaintext plaintext) { - try { - System.out.println(new String(plaintext.getMessage(), "UTF-8")); - } catch (UnsupportedEncodingException e) { - LOG.error(e.getMessage(), e); - } + .listener(plaintext -> { + try { + System.out.println(new String(plaintext.getMessage(), "UTF-8")); + } catch (UnsupportedEncodingException e) { + LOG.error(e.getMessage(), e); } }) .build(); @@ -136,6 +133,7 @@ public class Application { System.out.println(); commandLine.listAddresses(identities, "identities"); System.out.println("a) create identity"); + System.out.println("c) join chan"); System.out.println(COMMAND_BACK); command = commandLine.nextCommand(); @@ -144,6 +142,10 @@ public class Application { addIdentity(); identities = ctx.addresses().getIdentities(); break; + case "c": + joinChan(); + identities = ctx.addresses().getIdentities(); + break; case "b": return; default: @@ -168,6 +170,15 @@ public class Application { ctx.addresses().save(identity); } + private void joinChan() { + System.out.println(); + System.out.print("Passphrase: "); + String passphrase = commandLine.nextLine(); + System.out.print("Address: "); + String address = commandLine.nextLineTrimmed(); + ctx.joinChan(passphrase, address); + } + private void contacts() { String command; List<BitmessageAddress> contacts = ctx.addresses().getContacts(); @@ -258,6 +269,12 @@ public class Application { } else { System.out.println("Public key available"); } + } else { + if (address.isChan()) { + System.out.println("Chan"); + } else { + System.out.println("Identity"); + } } } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java index 2cbd8c7..5422997 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java @@ -70,6 +70,11 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito return find("private_key IS NOT NULL"); } + @Override + public List<BitmessageAddress> getChans() { + return find("chan = '1'"); + } + @Override public List<BitmessageAddress> getSubscriptions() { return find("subscribed = '1'"); @@ -86,7 +91,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito @Override public List<BitmessageAddress> getContacts() { - return find("private_key IS NULL"); + return find("private_key IS NULL OR chan = '1'"); } private List<BitmessageAddress> find(String where) { @@ -94,7 +99,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito try ( Connection connection = config.getConnection(); Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT address, alias, public_key, private_key, subscribed " + + ResultSet rs = stmt.executeQuery("SELECT address, alias, public_key, private_key, subscribed, chan " + "FROM Address WHERE " + where) ) { while (rs.next()) { @@ -118,6 +123,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito } address.setAlias(rs.getString("alias")); address.setSubscribed(rs.getBoolean("subscribed")); + address.setChan(rs.getBoolean("chan")); result.add(address); } @@ -164,7 +170,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito if (address.getPrivateKey() != null) { statement.append(", private_key=?"); } - statement.append(", subscribed=? WHERE address=?"); + statement.append(", subscribed=?, chan=? WHERE address=?"); try ( Connection connection = config.getConnection(); PreparedStatement ps = connection.prepareStatement(statement.toString()) @@ -178,6 +184,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito writeBlob(ps, ++i, address.getPrivateKey()); } ps.setBoolean(++i, address.isSubscribed()); + ps.setBoolean(++i, address.isChan()); ps.setString(++i, address.getAddress()); ps.executeUpdate(); } @@ -187,8 +194,8 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito try ( Connection connection = config.getConnection(); PreparedStatement ps = connection.prepareStatement( - "INSERT INTO Address (address, version, alias, public_key, private_key, subscribed) " + - "VALUES (?, ?, ?, ?, ?, ?)") + "INSERT INTO Address (address, version, alias, public_key, private_key, subscribed, chan) " + + "VALUES (?, ?, ?, ?, ?, ?, ?)") ) { ps.setString(1, address.getAddress()); ps.setLong(2, address.getVersion()); @@ -196,6 +203,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito writePubkey(ps, 4, address.getPubkey()); writeBlob(ps, 5, address.getPrivateKey()); ps.setBoolean(6, address.isSubscribed()); + ps.setBoolean(7, address.isChan()); ps.executeUpdate(); } } diff --git a/repositories/src/main/resources/db/migration/V3.0__Update_table_address.sql b/repositories/src/main/resources/db/migration/V3.0__Update_table_address.sql new file mode 100644 index 0000000..01e036b --- /dev/null +++ b/repositories/src/main/resources/db/migration/V3.0__Update_table_address.sql @@ -0,0 +1 @@ +ALTER TABLE Address ADD COLUMN chan BIT NOT NULL DEFAULT '0'; diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java index 18e70b2..bd91329 100644 --- a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java @@ -95,7 +95,7 @@ public class JdbcAddressRepositoryTest extends TestBase { addSubscription("BM-2D9QKN4teYRvoq2fyzpiftPh9WP9qggtzh"); List<BitmessageAddress> subscriptions; - + subscriptions = repo.getSubscriptions(5); assertEquals(1, subscriptions.size()); @@ -137,6 +137,24 @@ public class JdbcAddressRepositoryTest extends TestBase { assertNotNull(identityA.getPubkey()); assertNotNull(identityA.getPrivateKey()); assertEquals("Test", identityA.getAlias()); + assertFalse(identityA.isChan()); + } + + @Test + public void ensureNewChanIsSavedAndUpdated() { + BitmessageAddress chan = BitmessageAddress.chan(1, "test"); + repo.save(chan); + BitmessageAddress address = repo.getAddress(chan.getAddress()); + assertNotNull(address); + assertTrue(address.isChan()); + + address.setAlias("Test"); + repo.save(address); + + address = repo.getAddress(chan.getAddress()); + assertNotNull(address); + assertTrue(address.isChan()); + assertEquals("Test", address.getAlias()); } @Test From f70c15da382294e2e5ce46704d5e179bde26a881 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Thu, 7 Apr 2016 23:01:16 +0200 Subject: [PATCH 52/54] Some code for deterministic addresses - needs tests --- .../dissem/bitmessage/BitmessageContext.java | 13 +++ .../bitmessage/entity/BitmessageAddress.java | 14 +++ .../entity/valueobject/InventoryVector.java | 4 +- .../bitmessage/entity/valueobject/Label.java | 2 + .../entity/valueobject/NetworkAddress.java | 2 + .../entity/valueobject/PrivateKey.java | 90 ++++++++++++++----- .../ch/dissem/bitmessage/utils/Base58.java | 2 +- 7 files changed, 104 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 6348bcc..8377e22 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -31,6 +31,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetAddress; +import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.*; @@ -128,6 +129,18 @@ public class BitmessageContext { return chan; } + public List<BitmessageAddress> createDeterministicAddresses( + String passphrase, int numberOfAddresses, int version, int stream, boolean shorter) { + List<BitmessageAddress> result = BitmessageAddress.deterministic( + passphrase, numberOfAddresses, version, stream, shorter); + for (int i = 0; i < result.size(); i++) { + BitmessageAddress address = result.get(i); + address.setAlias(passphrase + " (" + (i + 1) + ")"); + ctx.getAddressRepository().save(address); + } + return result; + } + public void broadcast(final BitmessageAddress from, final String subject, final String message) { Plaintext msg = new Plaintext.Builder(BROADCAST) .from(from) diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index 229da14..2458854 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -29,7 +29,9 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Serializable; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Objects; import static ch.dissem.bitmessage.utils.Decode.bytes; @@ -41,6 +43,8 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * holding private keys. */ public class BitmessageAddress implements Serializable { + private static final long serialVersionUID = 2386328540805994064L; + private final long version; private final long stream; private final byte[] ripe; @@ -115,6 +119,16 @@ public class BitmessageAddress implements Serializable { return result; } + public static List<BitmessageAddress> deterministic(String passphrase, int numberOfAddresses, + int version, int stream, boolean shorter) { + List<BitmessageAddress> result = new ArrayList<>(numberOfAddresses); + List<PrivateKey> privateKeys = PrivateKey.deterministic(passphrase, numberOfAddresses, version, stream, shorter); + for (PrivateKey pk : privateKeys) { + result.add(new BitmessageAddress(pk)); + } + return result; + } + public BitmessageAddress(PrivateKey privateKey) { this(privateKey.getPubkey()); this.privateKey = privateKey; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java index fc67422..127b90a 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java @@ -25,6 +25,8 @@ import java.io.Serializable; import java.util.Arrays; public class InventoryVector implements Streamable, Serializable { + private static final long serialVersionUID = -7349009673063348719L; + /** * Hash of the object */ @@ -42,7 +44,7 @@ public class InventoryVector implements Streamable, Serializable { @Override public int hashCode() { - return hash != null ? Arrays.hashCode(hash) : 0; + return hash == null ? 0 : Arrays.hashCode(hash); } public byte[] getHash() { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java index 02f0384..facbe55 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java @@ -20,6 +20,8 @@ import java.io.Serializable; import java.util.Objects; public class Label implements Serializable { + private static final long serialVersionUID = 831782893630994914L; + private Object id; private String label; private Type type; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java index 0637da9..d0324a4 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/NetworkAddress.java @@ -31,6 +31,8 @@ import java.util.Arrays; * A node's address. It's written in IPv6 format. */ public class NetworkAddress implements Streamable { + private static final long serialVersionUID = 2500120578167100300L; + private long time; /** diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java index 6348add..73594ff 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java @@ -26,6 +26,8 @@ import ch.dissem.bitmessage.utils.Decode; import ch.dissem.bitmessage.utils.Encode; import java.io.*; +import java.util.ArrayList; +import java.util.List; import static ch.dissem.bitmessage.utils.Singleton.security; @@ -34,7 +36,10 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * {@link Pubkey} object. */ public class PrivateKey implements Streamable { + private static final long serialVersionUID = 8562555470709110558L; + public static final int PRIVATE_KEY_SIZE = 32; + private final byte[] privateSigningKey; private final byte[] privateEncryptionKey; @@ -70,29 +75,72 @@ public class PrivateKey implements Streamable { } public PrivateKey(long version, long stream, String passphrase) { - try { - byte[] signingKey; - int signingKeyNonce = 0; - byte[] encryptionKey; - int encryptionKeyNonce = 1; - byte[] passPhraseBytes = passphrase.getBytes("UTF-8"); - byte[] ripe; - do { - signingKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(signingKeyNonce)), 32); - encryptionKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(encryptionKeyNonce)), 32); - byte[] publicSigningKey = security().createPublicKey(signingKey); - byte[] publicEncryptionKey = security().createPublicKey(encryptionKey); - ripe = security().ripemd160(security().sha512(publicSigningKey, publicEncryptionKey)); + this(new Builder(version, stream, false).seed(passphrase).generate()); + } - signingKeyNonce += 2; - encryptionKeyNonce += 2; - } while (ripe[0] != 0); - this.privateSigningKey = signingKey; - this.privateEncryptionKey = encryptionKey; - this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey, 0, 0); - } catch (IOException e) { - throw new ApplicationException(e); + private PrivateKey(Builder builder) { + this.privateSigningKey = builder.privSK; + this.privateEncryptionKey = builder.privEK; + this.pubkey = Factory.createPubkey(builder.version, builder.stream, builder.pubSK, builder.pubEK, 0, 0); + } + + private static class Builder { + final long version; + final long stream; + final boolean shorter; + + byte[] seed; + long nextNonce; + + byte[] privSK, privEK; + byte[] pubSK, pubEK; + + private Builder(long version, long stream, boolean shorter) { + this.version = version; + this.stream = stream; + this.shorter = shorter; } + + Builder seed(String passphrase) { + try { + seed = passphrase.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new ApplicationException(e); + } + return this; + } + + Builder generate() { + try { + long signingKeyNonce = nextNonce; + long encryptionKeyNonce = nextNonce + 1; + byte[] ripe; + do { + privEK = Bytes.truncate(security().sha512(seed, Encode.varInt(encryptionKeyNonce)), 32); + privSK = Bytes.truncate(security().sha512(seed, Encode.varInt(signingKeyNonce)), 32); + pubSK = security().createPublicKey(privSK); + pubEK = security().createPublicKey(privEK); + ripe = security().ripemd160(security().sha512(pubSK, pubEK)); + + signingKeyNonce += 2; + encryptionKeyNonce += 2; + } while (ripe[0] != 0 || (shorter && ripe[1] != 0)); + nextNonce = signingKeyNonce; + } catch (IOException e) { + throw new ApplicationException(e); + } + return this; + } + } + + public static List<PrivateKey> deterministic(String passphrase, int numberOfAddresses, long version, long stream, boolean shorter) { + List<PrivateKey> result = new ArrayList<>(numberOfAddresses); + Builder builder = new Builder(version, stream, shorter).seed(passphrase); + for (int i = 0; i < numberOfAddresses; i++) { + builder.generate(); + result.add(new PrivateKey(builder)); + } + return result; } public static PrivateKey read(InputStream is) throws IOException { diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java b/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java index 167d862..a67e344 100644 --- a/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java +++ b/core/src/main/java/ch/dissem/bitmessage/utils/Base58.java @@ -31,7 +31,7 @@ import static java.util.Arrays.copyOfRange; */ public class Base58 { private static final int[] INDEXES = new int[128]; - private static char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); + private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); static { for (int i = 0; i < INDEXES.length; i++) { From 4f7f80c12a9b1cb2717f1a536da554e918a352e0 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Fri, 8 Apr 2016 19:22:40 +0200 Subject: [PATCH 53/54] Added tests and code improvements --- .../dissem/bitmessage/BitmessageContext.java | 10 +++-- .../ch/dissem/bitmessage/InternalContext.java | 13 ++----- .../dissem/bitmessage/ProofOfWorkService.java | 6 ++- .../ch/dissem/bitmessage/entity/Addr.java | 4 +- .../bitmessage/entity/BitmessageAddress.java | 3 +- .../bitmessage/entity/CustomMessage.java | 2 + .../ch/dissem/bitmessage/entity/GetData.java | 2 + .../java/ch/dissem/bitmessage/entity/Inv.java | 2 + .../bitmessage/entity/NetworkMessage.java | 2 + .../bitmessage/entity/ObjectMessage.java | 2 + .../dissem/bitmessage/entity/Plaintext.java | 2 + .../ch/dissem/bitmessage/entity/VerAck.java | 2 + .../ch/dissem/bitmessage/entity/Version.java | 2 + .../bitmessage/entity/payload/Broadcast.java | 2 + .../bitmessage/entity/payload/CryptoBox.java | 1 + .../entity/payload/GenericPayload.java | 2 + .../bitmessage/entity/payload/GetPubkey.java | 2 + .../dissem/bitmessage/entity/payload/Msg.java | 2 + .../entity/payload/ObjectPayload.java | 3 +- .../bitmessage/entity/payload/Pubkey.java | 2 + .../bitmessage/entity/payload/V2Pubkey.java | 2 + .../bitmessage/entity/payload/V3Pubkey.java | 2 + .../entity/payload/V4Broadcast.java | 2 + .../bitmessage/entity/payload/V4Pubkey.java | 2 + .../entity/payload/V5Broadcast.java | 2 + .../entity/valueobject/PrivateKey.java | 4 +- .../exception/AddressFormatException.java | 2 + .../exception/ApplicationException.java | 2 + .../exception/DecryptionFailedException.java | 1 + .../InsufficientProofOfWorkException.java | 2 + .../bitmessage/exception/NodeException.java | 2 + .../ports/AbstractCryptography.java | 10 +++-- .../bitmessage/BitmessageContextTest.java | 37 +++++++++++++++++-- .../DefaultMessageListenerTest.java | 2 - .../bitmessage/ProofOfWorkServiceTest.java | 4 -- .../dissem/bitmessage/utils/EncodeTest.java | 2 +- .../bitmessage/utils/MessageMatchers.java | 1 - .../extensions/CryptoCustomMessage.java | 3 ++ .../extensions/pow/ProofOfWorkRequest.java | 2 + .../bitmessage/networking/Connection.java | 4 +- .../networking/NetworkHandlerTest.java | 1 - .../repository/JdbcNodeRegistryTest.java | 3 +- .../ch/dissem/bitmessage/wif/WifExporter.java | 3 ++ .../ch/dissem/bitmessage/wif/WifImporter.java | 3 ++ .../bitmessage/wif/WifExporterTest.java | 21 ++++++++++- .../bitmessage/wif/WifImporterTest.java | 21 +++++++++-- 46 files changed, 163 insertions(+), 43 deletions(-) diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 8377e22..51243ab 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -36,6 +36,8 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.*; +import static ch.dissem.bitmessage.InternalContext.NETWORK_EXTRA_BYTES; +import static ch.dissem.bitmessage.InternalContext.NETWORK_NONCE_TRIALS_PER_BYTE; import static ch.dissem.bitmessage.entity.Plaintext.Status.*; import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; @@ -99,8 +101,8 @@ public class BitmessageContext { final BitmessageAddress identity = new BitmessageAddress(new PrivateKey( shorter, ctx.getStreams()[0], - ctx.getNetworkNonceTrialsPerByte(), - ctx.getNetworkExtraBytes(), + NETWORK_NONCE_TRIALS_PER_BYTE, + NETWORK_EXTRA_BYTES, features )); ctx.getAddressRepository().save(identity); @@ -130,12 +132,12 @@ public class BitmessageContext { } public List<BitmessageAddress> createDeterministicAddresses( - String passphrase, int numberOfAddresses, int version, int stream, boolean shorter) { + String passphrase, int numberOfAddresses, long version, long stream, boolean shorter) { List<BitmessageAddress> result = BitmessageAddress.deterministic( passphrase, numberOfAddresses, version, stream, shorter); for (int i = 0; i < result.size(); i++) { BitmessageAddress address = result.get(i); - address.setAlias(passphrase + " (" + (i + 1) + ")"); + address.setAlias("deterministic (" + (i + 1) + ")"); ctx.getAddressRepository().save(address); } return result; diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java index 33ee15b..00ec40e 100644 --- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -43,6 +43,9 @@ import java.util.TreeSet; public class InternalContext { private final static Logger LOG = LoggerFactory.getLogger(InternalContext.class); + public final static long NETWORK_NONCE_TRIALS_PER_BYTE = 1000; + public final static long NETWORK_EXTRA_BYTES = 1000; + private final Cryptography cryptography; private final Inventory inventory; private final NodeRegistry nodeRegistry; @@ -58,8 +61,6 @@ public class InternalContext { private final TreeSet<Long> streams = new TreeSet<>(); private final int port; private final long clientNonce; - private final long networkNonceTrialsPerByte = 1000; - private final long networkExtraBytes = 1000; private long connectionTTL; private int connectionLimit; @@ -158,14 +159,6 @@ public class InternalContext { return port; } - public long getNetworkNonceTrialsPerByte() { - return networkNonceTrialsPerByte; - } - - public long getNetworkExtraBytes() { - return networkExtraBytes; - } - public void send(final BitmessageAddress from, BitmessageAddress to, final ObjectPayload payload, final long timeToLive) { try { diff --git a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java index ad62dde..93e461f 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java +++ b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java @@ -14,6 +14,8 @@ import org.slf4j.LoggerFactory; import java.util.List; +import static ch.dissem.bitmessage.InternalContext.NETWORK_EXTRA_BYTES; +import static ch.dissem.bitmessage.InternalContext.NETWORK_NONCE_TRIALS_PER_BYTE; import static ch.dissem.bitmessage.utils.Singleton.security; /** @@ -45,8 +47,8 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC public void doProofOfWork(BitmessageAddress recipient, ObjectMessage object) { Pubkey pubkey = recipient == null ? null : recipient.getPubkey(); - long nonceTrialsPerByte = pubkey == null ? ctx.getNetworkNonceTrialsPerByte() : pubkey.getNonceTrialsPerByte(); - long extraBytes = pubkey == null ? ctx.getNetworkExtraBytes() : pubkey.getExtraBytes(); + long nonceTrialsPerByte = pubkey == null ? NETWORK_NONCE_TRIALS_PER_BYTE : pubkey.getNonceTrialsPerByte(); + long extraBytes = pubkey == null ? NETWORK_EXTRA_BYTES : pubkey.getExtraBytes(); powRepo.putObject(object, nonceTrialsPerByte, extraBytes); if (object.getPayload() instanceof PlaintextHolder) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java b/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java index 2c0eb3e..6125910 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java @@ -29,6 +29,8 @@ import java.util.List; * The 'addr' command holds a list of known active Bitmessage nodes. */ public class Addr implements MessagePayload { + private static final long serialVersionUID = -5117688017050138720L; + private final List<NetworkAddress> addresses; private Addr(Builder builder) { @@ -53,7 +55,7 @@ public class Addr implements MessagePayload { } public static final class Builder { - private List<NetworkAddress> addresses = new ArrayList<NetworkAddress>(); + private List<NetworkAddress> addresses = new ArrayList<>(); public Builder addresses(Collection<NetworkAddress> addresses){ this.addresses.addAll(addresses); diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index 2458854..7868efd 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -101,6 +101,7 @@ public class BitmessageAddress implements Serializable { public BitmessageAddress(String address, String passphrase) { this(address); this.privateKey = new PrivateKey(this, passphrase); + this.pubkey = this.privateKey.getPubkey(); if (!Arrays.equals(ripe, privateKey.getPubkey().getRipe())) { throw new IllegalArgumentException("Wrong address or passphrase"); } @@ -120,7 +121,7 @@ public class BitmessageAddress implements Serializable { } public static List<BitmessageAddress> deterministic(String passphrase, int numberOfAddresses, - int version, int stream, boolean shorter) { + long version, long stream, boolean shorter) { List<BitmessageAddress> result = new ArrayList<>(numberOfAddresses); List<PrivateKey> privateKeys = PrivateKey.deterministic(passphrase, numberOfAddresses, version, stream, shorter); for (PrivateKey pk : privateKeys) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java index ffdb9b2..e43f56d 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java @@ -29,6 +29,8 @@ import static ch.dissem.bitmessage.utils.Decode.varString; * @author Christian Basler */ public class CustomMessage implements MessagePayload { + private static final long serialVersionUID = -8932056829480326011L; + public static final String COMMAND_ERROR = "ERROR"; private final String command; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java b/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java index 9569929..44fab5b 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java @@ -28,6 +28,8 @@ import java.util.List; * The 'getdata' command is used to request objects from a node. */ public class GetData implements MessagePayload { + private static final long serialVersionUID = 1433878785969631061L; + public static final int MAX_INVENTORY_SIZE = 50_000; List<InventoryVector> inventory; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java index 7130fd7..fd2d40d 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java @@ -28,6 +28,8 @@ import java.util.List; * The 'inv' command holds up to 50000 inventory vectors, i.e. hashes of inventory items. */ public class Inv implements MessagePayload { + private static final long serialVersionUID = 3662992522956947145L; + private List<InventoryVector> inventory; private Inv(Builder builder) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java index 5e8552e..347af6c 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java @@ -33,6 +33,8 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * A network message is exchanged between two nodes. */ public class NetworkMessage implements Streamable { + private static final long serialVersionUID = 702708857104464809L; + /** * Magic value indicating message origin network, and used to seek to next message when stream state is unknown */ diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java index 89ddddb..68aa5ac 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java @@ -36,6 +36,8 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * The 'object' command sends an object that is shared throughout the network. */ public class ObjectMessage implements MessagePayload { + private static final long serialVersionUID = 2495752480120659139L; + private byte[] nonce; private long expiresTime; private long objectType; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java index fe8b1d3..034f2da 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java @@ -31,6 +31,8 @@ import java.util.*; * The unencrypted message to be sent by 'msg' or 'broadcast'. */ public class Plaintext implements Streamable { + private static final long serialVersionUID = -5325729856394951079L; + private final Type type; private final BitmessageAddress from; private final long encoding; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/VerAck.java b/core/src/main/java/ch/dissem/bitmessage/entity/VerAck.java index 1aad501..815a20f 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/VerAck.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/VerAck.java @@ -23,6 +23,8 @@ import java.io.OutputStream; * The 'verack' command answers a 'version' command, accepting the other node's version. */ public class VerAck implements MessagePayload { + private static final long serialVersionUID = -4302074845199181687L; + @Override public Command getCommand() { return Command.VERACK; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Version.java b/core/src/main/java/ch/dissem/bitmessage/entity/Version.java index 6d24d92..3722528 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Version.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Version.java @@ -29,6 +29,8 @@ import java.util.Random; * The 'version' command advertises this node's latest supported protocol version upon initiation. */ public class Version implements MessagePayload { + private static final long serialVersionUID = 7219240857343176567L; + /** * Identifies protocol version being used by the node. Should equal 3. Nodes should disconnect if the remote node's * version is lower but continue with the connection if it is higher. diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java index 47bf539..7e19e8f 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java @@ -32,6 +32,8 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * Broadcasts are version 4 or 5. */ public abstract class Broadcast extends ObjectPayload implements Encrypted, PlaintextHolder { + private static final long serialVersionUID = 4064521827582239069L; + protected final long stream; protected CryptoBox encrypted; protected Plaintext plaintext; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java index 8887fea..6609070 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java @@ -31,6 +31,7 @@ import static ch.dissem.bitmessage.utils.Singleton.security; public class CryptoBox implements Streamable { + private static final long serialVersionUID = 7217659539975573852L; private static final Logger LOG = LoggerFactory.getLogger(CryptoBox.class); private final byte[] initializationVector; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java index 7051814..66cc296 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/GenericPayload.java @@ -28,6 +28,8 @@ import java.util.Arrays; * have to know what it is. */ public class GenericPayload extends ObjectPayload { + private static final long serialVersionUID = -912314085064185940L; + private long stream; private byte[] data; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java index e31dbe3..06e623a 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java @@ -27,6 +27,8 @@ import java.io.OutputStream; * Request for a public key. */ public class GetPubkey extends ObjectPayload { + private static final long serialVersionUID = -3634516646972610180L; + private long stream; private byte[] ripeTag; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java index 52c36e7..8974ce3 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java @@ -31,6 +31,8 @@ import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; * Used for person-to-person messages. */ public class Msg extends ObjectPayload implements Encrypted, PlaintextHolder { + private static final long serialVersionUID = 4327495048296365733L; + private long stream; private CryptoBox encrypted; private Plaintext plaintext; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java index 0ca45cd..33da28d 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java @@ -21,12 +21,13 @@ import ch.dissem.bitmessage.entity.Streamable; import java.io.IOException; import java.io.OutputStream; -import java.io.Serializable; /** * The payload of an 'object' command. This is shared by the network. */ public abstract class ObjectPayload implements Streamable { + private static final long serialVersionUID = -5034977402902364482L; + private final long version; protected ObjectPayload(long version) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java index 1243b32..dec339d 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/Pubkey.java @@ -26,6 +26,8 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * Public keys for signing and encryption, the answer to a 'getpubkey' request. */ public abstract class Pubkey extends ObjectPayload { + private static final long serialVersionUID = -6634533361454999619L; + public final static long LATEST_VERSION = 4; protected Pubkey(long version) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java index d915941..0eceb91 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V2Pubkey.java @@ -27,6 +27,8 @@ import java.io.OutputStream; * A version 2 public key. */ public class V2Pubkey extends Pubkey { + private static final long serialVersionUID = -257598690676510460L; + protected long stream; protected int behaviorBitfield; protected byte[] publicSigningKey; // 64 Bytes diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java index a3b4da2..72358d0 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V3Pubkey.java @@ -29,6 +29,8 @@ import java.util.Objects; * A version 3 public key. */ public class V3Pubkey extends V2Pubkey { + private static final long serialVersionUID = 6958853116648528319L; + long nonceTrialsPerByte; long extraBytes; byte[] signature; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java index 39127a8..7781455 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Broadcast.java @@ -28,6 +28,8 @@ import java.io.OutputStream; * Broadcasts are version 4 or 5. */ public class V4Broadcast extends Broadcast { + private static final long serialVersionUID = 195663108282762711L; + protected V4Broadcast(long version, long stream, CryptoBox encrypted, Plaintext plaintext) { super(version, stream, encrypted, plaintext); } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java index 048e7a6..8aa0ee4 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java @@ -33,6 +33,8 @@ import java.util.Arrays; * to create messages to be used in spam or in flooding attacks. */ public class V4Pubkey extends Pubkey implements Encrypted { + private static final long serialVersionUID = 1556710353694033093L; + private long stream; private byte[] tag; private CryptoBox encrypted; diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java index c12aae0..8f07a30 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/payload/V5Broadcast.java @@ -28,6 +28,8 @@ import java.io.OutputStream; * Users who are subscribed to the sending address will see the message appear in their inbox. */ public class V5Broadcast extends V4Broadcast { + private static final long serialVersionUID = 920649721626968644L; + private byte[] tag; private V5Broadcast(long stream, byte[] tag, CryptoBox encrypted) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java index 73594ff..b9c3afb 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/PrivateKey.java @@ -16,6 +16,7 @@ package ch.dissem.bitmessage.entity.valueobject; +import ch.dissem.bitmessage.InternalContext; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Streamable; import ch.dissem.bitmessage.entity.payload.Pubkey; @@ -81,7 +82,8 @@ public class PrivateKey implements Streamable { private PrivateKey(Builder builder) { this.privateSigningKey = builder.privSK; this.privateEncryptionKey = builder.privEK; - this.pubkey = Factory.createPubkey(builder.version, builder.stream, builder.pubSK, builder.pubEK, 0, 0); + this.pubkey = Factory.createPubkey(builder.version, builder.stream, builder.pubSK, builder.pubEK, + InternalContext.NETWORK_NONCE_TRIALS_PER_BYTE, InternalContext.NETWORK_EXTRA_BYTES); } private static class Builder { diff --git a/core/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java b/core/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java index 7da990a..9f6674d 100644 --- a/core/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java +++ b/core/src/main/java/ch/dissem/bitmessage/exception/AddressFormatException.java @@ -20,6 +20,8 @@ package ch.dissem.bitmessage.exception; * Indicates an illegal Bitmessage address */ public class AddressFormatException extends RuntimeException { + private static final long serialVersionUID = 6943764578672021573L; + public AddressFormatException(String message) { super(message); } diff --git a/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java b/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java index c381410..e688cb1 100644 --- a/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java +++ b/core/src/main/java/ch/dissem/bitmessage/exception/ApplicationException.java @@ -20,6 +20,8 @@ package ch.dissem.bitmessage.exception; * @author Christian Basler */ public class ApplicationException extends RuntimeException { + private static final long serialVersionUID = 1796776684126759324L; + public ApplicationException(Throwable cause) { super(cause); } diff --git a/core/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java b/core/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java index c68a050..c9e3efd 100644 --- a/core/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java +++ b/core/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java @@ -17,4 +17,5 @@ package ch.dissem.bitmessage.exception; public class DecryptionFailedException extends Exception { + private static final long serialVersionUID = 3241116253113872731L; } diff --git a/core/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java b/core/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java index 685e710..94a5d84 100644 --- a/core/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java +++ b/core/src/main/java/ch/dissem/bitmessage/exception/InsufficientProofOfWorkException.java @@ -22,6 +22,8 @@ import java.io.IOException; import java.util.Arrays; public class InsufficientProofOfWorkException extends IOException { + private static final long serialVersionUID = 9105580366564571318L; + public InsufficientProofOfWorkException(byte[] target, byte[] hash) { super("Insufficient proof of work: " + Strings.hex(target) + " required, " + Strings.hex(Arrays.copyOfRange(hash, 0, 8)) + " achieved."); } diff --git a/core/src/main/java/ch/dissem/bitmessage/exception/NodeException.java b/core/src/main/java/ch/dissem/bitmessage/exception/NodeException.java index 9ab2b7f..cecd950 100644 --- a/core/src/main/java/ch/dissem/bitmessage/exception/NodeException.java +++ b/core/src/main/java/ch/dissem/bitmessage/exception/NodeException.java @@ -22,6 +22,8 @@ package ch.dissem.bitmessage.exception; * @author Ch. Basler */ public class NodeException extends RuntimeException { + private static final long serialVersionUID = 2965325796118227802L; + public NodeException(String message) { super(message); } diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java b/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java index 81252d5..3b08377 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java +++ b/core/src/main/java/ch/dissem/bitmessage/ports/AbstractCryptography.java @@ -35,6 +35,8 @@ import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.SecureRandom; +import static ch.dissem.bitmessage.InternalContext.NETWORK_EXTRA_BYTES; +import static ch.dissem.bitmessage.InternalContext.NETWORK_NONCE_TRIALS_PER_BYTE; import static ch.dissem.bitmessage.utils.Numbers.max; /** @@ -99,8 +101,8 @@ public abstract class AbstractCryptography implements Cryptography, InternalCont public void doProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes, ProofOfWorkEngine.Callback callback) { - nonceTrialsPerByte = max(nonceTrialsPerByte, context.getNetworkNonceTrialsPerByte()); - extraBytes = max(extraBytes, context.getNetworkExtraBytes()); + nonceTrialsPerByte = max(nonceTrialsPerByte, NETWORK_NONCE_TRIALS_PER_BYTE); + extraBytes = max(extraBytes, NETWORK_EXTRA_BYTES); byte[] initialHash = getInitialHash(object); @@ -125,8 +127,8 @@ public abstract class AbstractCryptography implements Cryptography, InternalCont @Override public byte[] getProofOfWorkTarget(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) { - if (nonceTrialsPerByte == 0) nonceTrialsPerByte = context.getNetworkNonceTrialsPerByte(); - if (extraBytes == 0) extraBytes = context.getNetworkExtraBytes(); + if (nonceTrialsPerByte == 0) nonceTrialsPerByte = NETWORK_NONCE_TRIALS_PER_BYTE; + if (extraBytes == 0) extraBytes = NETWORK_EXTRA_BYTES; BigInteger TTL = BigInteger.valueOf(object.getExpiresTime() - UnixTime.now()); BigInteger numerator = TWO_POW_64; diff --git a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java index a1991f8..530ece0 100644 --- a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java @@ -31,16 +31,13 @@ import org.hamcrest.Description; import org.junit.Before; import org.junit.Test; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; +import java.util.*; import static ch.dissem.bitmessage.entity.payload.ObjectType.*; import static ch.dissem.bitmessage.utils.MessageMatchers.object; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.junit.Assert.*; -import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; /** @@ -216,6 +213,38 @@ public class BitmessageContextTest { assertTrue(chan.isChan()); } + @Test + public void ensureDeterministicAddressesAreCreated() { + final int expected_size = 8; + List<BitmessageAddress> addresses = ctx.createDeterministicAddresses("test", expected_size, 4, 1, false); + assertEquals(expected_size, addresses.size()); + Set<String> expected = new HashSet<>(expected_size); + expected.add("BM-2cWFkyuXXFw6d393RGnin2RpSXj8wxtt6F"); + expected.add("BM-2cX8TF9vuQZEWvT7UrEeq1HN9dgiSUPLEN"); + expected.add("BM-2cUzX8f9CKUU7L8NeB8GExZvf54PrcXq1S"); + expected.add("BM-2cU7MAoQd7KE8SPF7AKFPpoEZKjk86KRqE"); + expected.add("BM-2cVm8ByVBacc2DVhdTNs6rmy5ZQK6DUsrt"); + expected.add("BM-2cW2af1vB6kWon2WkygDHqGwfcpfAFm2Jk"); + expected.add("BM-2cWdWD7UtUN4gWChgNX9pvyvNPjUZvU8BT"); + expected.add("BM-2cXkYgYcUrv4fGxSHzyEScW955Cc8sDteo"); + for (BitmessageAddress a : addresses) { + assertTrue(expected.contains(a.getAddress())); + expected.remove(a.getAddress()); + } + } + @Test + public void ensureShortDeterministicAddressesAreCreated() { + final int expected_size = 1; + List<BitmessageAddress> addresses = ctx.createDeterministicAddresses("test", expected_size, 4, 1, true); + assertEquals(expected_size, addresses.size()); + Set<String> expected = new HashSet<>(expected_size); + expected.add("BM-NBGyBAEp6VnBkFWKpzUSgxuTqVdWPi78"); + for (BitmessageAddress a : addresses) { + assertTrue(expected.contains(a.getAddress())); + expected.remove(a.getAddress()); + } + } + @Test public void ensureChanIsCreated() { BitmessageAddress chan = ctx.createChan("test"); diff --git a/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java b/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java index a6e6c53..976e464 100644 --- a/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java @@ -40,8 +40,6 @@ import static ch.dissem.bitmessage.entity.Plaintext.Status.PUBKEY_REQUESTED; import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; import static ch.dissem.bitmessage.utils.MessageMatchers.plaintext; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; /** diff --git a/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java b/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java index e489e35..e66beb1 100644 --- a/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/ProofOfWorkServiceTest.java @@ -34,10 +34,6 @@ import java.util.Arrays; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.*; /** diff --git a/core/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java b/core/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java index aaba5bf..23d602c 100644 --- a/core/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/utils/EncodeTest.java @@ -57,7 +57,7 @@ public class EncodeTest { checkBytes(stream, 4, 3, 2, 1); stream = new ByteArrayOutputStream(); - Encode.int32(3355443201l, stream); + Encode.int32(3355443201L, stream); checkBytes(stream, 200, 0, 0, 1); } diff --git a/core/src/test/java/ch/dissem/bitmessage/utils/MessageMatchers.java b/core/src/test/java/ch/dissem/bitmessage/utils/MessageMatchers.java index 8bb1e36..e423d02 100644 --- a/core/src/test/java/ch/dissem/bitmessage/utils/MessageMatchers.java +++ b/core/src/test/java/ch/dissem/bitmessage/utils/MessageMatchers.java @@ -21,7 +21,6 @@ import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.payload.ObjectType; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; -import org.hamcrest.Matcher; import org.mockito.Matchers; /** diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java index 33c7524..0b5b142 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/CryptoCustomMessage.java @@ -36,7 +36,10 @@ import static ch.dissem.bitmessage.utils.Singleton.security; * @author Christian Basler */ public class CryptoCustomMessage<T extends Streamable> extends CustomMessage { + private static final long serialVersionUID = 7395193565986284426L; + public static final String COMMAND = "ENCRYPTED"; + private final Reader<T> dataReader; private CryptoBox container; private BitmessageAddress sender; diff --git a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java index 0024aaa..d661c50 100644 --- a/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java +++ b/extensions/src/main/java/ch/dissem/bitmessage/extensions/pow/ProofOfWorkRequest.java @@ -32,6 +32,8 @@ import static ch.dissem.bitmessage.utils.Decode.*; * @author Christian Basler */ public class ProofOfWorkRequest implements Streamable { + private static final long serialVersionUID = 4729003751499662713L; + private final BitmessageAddress sender; private final byte[] initialHash; private final Request request; diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 5781bc3..54c8acf 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -41,6 +41,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentMap; +import static ch.dissem.bitmessage.InternalContext.NETWORK_EXTRA_BYTES; +import static ch.dissem.bitmessage.InternalContext.NETWORK_NONCE_TRIALS_PER_BYTE; import static ch.dissem.bitmessage.networking.Connection.Mode.CLIENT; import static ch.dissem.bitmessage.networking.Connection.Mode.SYNC; import static ch.dissem.bitmessage.networking.Connection.State.*; @@ -247,7 +249,7 @@ class Connection { } try { listener.receive(objectMessage); - security().checkProofOfWork(objectMessage, ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes()); + security().checkProofOfWork(objectMessage, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES); ctx.getInventory().storeObject(objectMessage); // offer object to some random nodes so it gets distributed throughout the network: networkHandler.offer(objectMessage.getInventoryVector()); diff --git a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java index 2e63e3a..accb4c5 100644 --- a/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java +++ b/networking/src/test/java/ch/dissem/bitmessage/networking/NetworkHandlerTest.java @@ -27,7 +27,6 @@ import ch.dissem.bitmessage.utils.Property; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import org.mockito.Mockito; import java.net.InetAddress; import java.util.concurrent.Future; diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcNodeRegistryTest.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcNodeRegistryTest.java index 044c44c..f56d973 100644 --- a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcNodeRegistryTest.java +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcNodeRegistryTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Test; import java.util.Arrays; +import java.util.Collections; import java.util.List; import static ch.dissem.bitmessage.utils.UnixTime.now; @@ -73,7 +74,7 @@ public class JdbcNodeRegistryTest extends TestBase { List<NetworkAddress> knownAddresses = registry.getKnownAddresses(1000, 1); assertEquals(5, knownAddresses.size()); - registry.offerAddresses(Arrays.asList( + registry.offerAddresses(Collections.singletonList( createAddress(1, 8445, 1, now()) )); diff --git a/wif/src/main/java/ch/dissem/bitmessage/wif/WifExporter.java b/wif/src/main/java/ch/dissem/bitmessage/wif/WifExporter.java index 00f2790..ad6098e 100644 --- a/wif/src/main/java/ch/dissem/bitmessage/wif/WifExporter.java +++ b/wif/src/main/java/ch/dissem/bitmessage/wif/WifExporter.java @@ -60,6 +60,9 @@ public class WifExporter { section.add("label", identity.getAlias()); section.add("enabled", true); section.add("decoy", false); + if (identity.isChan()) { + section.add("chan", identity.isChan()); + } section.add("noncetrialsperbyte", identity.getPubkey().getNonceTrialsPerByte()); section.add("payloadlengthextrabytes", identity.getPubkey().getExtraBytes()); section.add("privsigningkey", exportSecret(identity.getPrivateKey().getPrivateSigningKey())); diff --git a/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java b/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java index 3a45b44..1bd6bcd 100644 --- a/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java +++ b/wif/src/main/java/ch/dissem/bitmessage/wif/WifImporter.java @@ -70,6 +70,9 @@ public class WifImporter { section.get("payloadlengthextrabytes", long.class), Pubkey.Feature.bitfield(features) ); + if (section.containsKey("chan")) { + address.setChan(section.get("chan", boolean.class)); + } address.setAlias(section.get("label")); identities.add(address); } diff --git a/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java b/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java index b930c0a..225f2f9 100644 --- a/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java +++ b/wif/src/test/java/ch/dissem/bitmessage/wif/WifExporterTest.java @@ -17,6 +17,7 @@ package ch.dissem.bitmessage.wif; import ch.dissem.bitmessage.BitmessageContext; +import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import org.junit.Before; @@ -80,9 +81,27 @@ public class WifExporterTest { "noncetrialsperbyte = 320" + System.lineSeparator() + "payloadlengthextrabytes = 14000" + System.lineSeparator() + "privsigningkey = 5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9" + System.lineSeparator() + - "privencryptionkey = 5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck" + System.lineSeparator() + System.lineSeparator(); + "privencryptionkey = 5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck" + System.lineSeparator() + + System.lineSeparator(); importer = new WifImporter(ctx, expected); exporter.addIdentity(importer.getIdentities().get(0)); assertEquals(expected, exporter.toString()); } + + @Test + public void ensureChanIsAdded() throws Exception { + String expected = "[BM-2cW67GEKkHGonXKZLCzouLLxnLym3azS8r]" + System.lineSeparator() + + "label = general" + System.lineSeparator() + + "enabled = true" + System.lineSeparator() + + "decoy = false" + System.lineSeparator() + + "chan = true" + System.lineSeparator() + + "noncetrialsperbyte = 1000" + System.lineSeparator() + + "payloadlengthextrabytes = 1000" + System.lineSeparator() + + "privsigningkey = 5Jnbdwc4u4DG9ipJxYLznXSvemkRFueQJNHujAQamtDDoX3N1eQ" + System.lineSeparator() + + "privencryptionkey = 5JrDcFtQDv5ydcHRW6dfGUEvThoxCCLNEUaxQfy8LXXgTJzVAcq" + System.lineSeparator() + + System.lineSeparator(); + BitmessageAddress chan = ctx.joinChan("general", "BM-2cW67GEKkHGonXKZLCzouLLxnLym3azS8r"); + exporter.addIdentity(chan); + assertEquals(expected, exporter.toString()); + } } \ No newline at end of file diff --git a/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java b/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java index fe8e15c..398ff20 100644 --- a/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java +++ b/wif/src/test/java/ch/dissem/bitmessage/wif/WifImporterTest.java @@ -25,9 +25,7 @@ import org.junit.Test; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.any; +import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class WifImporterTest { @@ -69,6 +67,7 @@ public class WifImporterTest { assertNotNull("Private key", identity.getPrivateKey()); assertEquals(32, identity.getPrivateKey().getPrivateEncryptionKey().length); assertEquals(32, identity.getPrivateKey().getPrivateSigningKey().length); + assertFalse(identity.isChan()); } @Test @@ -98,4 +97,20 @@ public class WifImporterTest { importer.importIdentity(identities.get(0)); verify(repo, times(1)).save(identities.get(0)); } + + @Test + public void ensureChanIsImported() throws Exception { + importer = new WifImporter(ctx, "[BM-2cW67GEKkHGonXKZLCzouLLxnLym3azS8r]\n" + + "label = [chan] general\n" + + "enabled = true\n" + + "decoy = false\n" + + "chan = true\n" + + "noncetrialsperbyte = 1000\n" + + "payloadlengthextrabytes = 1000\n" + + "privsigningkey = 5Jnbdwc4u4DG9ipJxYLznXSvemkRFueQJNHujAQamtDDoX3N1eQ\n" + + "privencryptionkey = 5JrDcFtQDv5ydcHRW6dfGUEvThoxCCLNEUaxQfy8LXXgTJzVAcq\n"); + assertEquals(1, importer.getIdentities().size()); + BitmessageAddress chan = importer.getIdentities().get(0); + assertTrue(chan.isChan()); + } } \ No newline at end of file From e8ddf90363b84d01c5091f54552011197c2a1ed8 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Mon, 11 Apr 2016 15:10:59 +0200 Subject: [PATCH 54/54] Provide a more flexible way to label messages. I'm not quite sure about chans yet --- build.gradle | 2 +- .../dissem/bitmessage/BitmessageContext.java | 26 ++++++- .../bitmessage/DefaultMessageListener.java | 30 ++++---- .../ch/dissem/bitmessage/InternalContext.java | 2 +- .../bitmessage/ports/DefaultLabeler.java | 68 +++++++++++++++++++ .../ch/dissem/bitmessage/ports/Labeler.java | 39 +++++++++++ .../bitmessage/BitmessageContextTest.java | 4 +- .../DefaultMessageListenerTest.java | 3 +- .../dissem/bitmessage/demo/Application.java | 6 +- 9 files changed, 158 insertions(+), 22 deletions(-) create mode 100644 core/src/main/java/ch/dissem/bitmessage/ports/DefaultLabeler.java create mode 100644 core/src/main/java/ch/dissem/bitmessage/ports/Labeler.java diff --git a/build.gradle b/build.gradle index 917a0d4..0e96284 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ subprojects { sourceCompatibility = 1.7 group = 'ch.dissem.jabit' - version = '1.0.2-SNAPSHOT' + version = '1.1.0-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 51243ab..f33b26c 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -17,7 +17,10 @@ package ch.dissem.bitmessage; import ch.dissem.bitmessage.entity.*; -import ch.dissem.bitmessage.entity.payload.*; +import ch.dissem.bitmessage.entity.payload.Broadcast; +import ch.dissem.bitmessage.entity.payload.Msg; +import ch.dissem.bitmessage.entity.payload.ObjectPayload; +import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.payload.Pubkey.Feature; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; @@ -65,6 +68,7 @@ public class BitmessageContext { private final InternalContext ctx; + private final Labeler labeler; private final Listener listener; private final NetworkHandler.MessageListener networkListener; @@ -72,8 +76,9 @@ public class BitmessageContext { private BitmessageContext(Builder builder) { ctx = new InternalContext(builder); + labeler = builder.labeler; listener = builder.listener; - networkListener = new DefaultMessageListener(ctx, listener); + networkListener = new DefaultMessageListener(ctx, labeler, listener); // As this thread is used for parts that do POW, which itself uses parallel threads, only // one should be executed at any time. @@ -97,6 +102,10 @@ public class BitmessageContext { return ctx.getMessageRepository(); } + public Labeler labeler() { + return labeler; + } + public BitmessageAddress createIdentity(boolean shorter, Feature... features) { final BitmessageAddress identity = new BitmessageAddress(new PrivateKey( shorter, @@ -280,7 +289,9 @@ public class BitmessageContext { try { Broadcast broadcast = (Broadcast) object.getPayload(); broadcast.decrypt(address); - listener.receive(broadcast.getPlaintext()); + // This decrypts it twice, but on the other hand it doesn't try to decrypt the objects with + // other subscriptions and the interface stays as simple as possible. + networkListener.receive(object); } catch (DecryptionFailedException ignore) { } catch (Exception e) { LOG.debug(e.getMessage(), e); @@ -318,6 +329,7 @@ public class BitmessageContext { Cryptography cryptography; MessageCallback messageCallback; CustomCommandHandler customCommandHandler; + Labeler labeler; Listener listener; int connectionLimit = 150; long connectionTTL = 30 * MINUTE; @@ -378,6 +390,11 @@ public class BitmessageContext { return this; } + public Builder labeler(Labeler labeler) { + this.labeler = labeler; + return this; + } + public Builder listener(Listener listener) { this.listener = listener; return this; @@ -430,6 +447,9 @@ public class BitmessageContext { if (messageCallback == null) { messageCallback = new BaseMessageCallback(); } + if (labeler == null) { + labeler = new DefaultLabeler(); + } if (customCommandHandler == null) { customCommandHandler = new CustomCommandHandler() { @Override diff --git a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java index c2c2f64..74a6560 100644 --- a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java +++ b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java @@ -20,8 +20,9 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.payload.*; -import ch.dissem.bitmessage.entity.valueobject.Label; +import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.exception.DecryptionFailedException; +import ch.dissem.bitmessage.ports.Labeler; import ch.dissem.bitmessage.ports.NetworkHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,10 +37,12 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY; class DefaultMessageListener implements NetworkHandler.MessageListener { private final static Logger LOG = LoggerFactory.getLogger(DefaultMessageListener.class); private final InternalContext ctx; + private final Labeler labeler; private final BitmessageContext.Listener listener; - public DefaultMessageListener(InternalContext context, BitmessageContext.Listener listener) { + public DefaultMessageListener(InternalContext context, Labeler labeler, BitmessageContext.Listener listener) { this.ctx = context; + this.labeler = labeler; this.listener = listener; } @@ -127,12 +130,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { if (!object.isSignatureValid(msg.getPlaintext().getFrom().getPubkey())) { LOG.warn("Msg with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring."); } else { - msg.getPlaintext().setStatus(RECEIVED); - msg.getPlaintext().addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.UNREAD)); - msg.getPlaintext().setInventoryVector(object.getInventoryVector()); - ctx.getMessageRepository().save(msg.getPlaintext()); - listener.receive(msg.getPlaintext()); - updatePubkey(msg.getPlaintext().getFrom(), msg.getPlaintext().getFrom().getPubkey()); + receive(object.getInventoryVector(), msg.getPlaintext()); } break; } catch (DecryptionFailedException ignore) { @@ -151,15 +149,19 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { if (!object.isSignatureValid(broadcast.getPlaintext().getFrom().getPubkey())) { LOG.warn("Broadcast with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring."); } else { - broadcast.getPlaintext().setStatus(RECEIVED); - broadcast.getPlaintext().addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.BROADCAST, Label.Type.UNREAD)); - broadcast.getPlaintext().setInventoryVector(object.getInventoryVector()); - ctx.getMessageRepository().save(broadcast.getPlaintext()); - listener.receive(broadcast.getPlaintext()); - updatePubkey(broadcast.getPlaintext().getFrom(), broadcast.getPlaintext().getFrom().getPubkey()); + receive(object.getInventoryVector(), broadcast.getPlaintext()); } } catch (DecryptionFailedException ignore) { } } } + + protected void receive(InventoryVector iv, Plaintext msg) { + msg.setStatus(RECEIVED); + msg.setInventoryVector(iv); + labeler.setLabels(msg); + ctx.getMessageRepository().save(msg); + listener.receive(msg); + updatePubkey(msg.getFrom(), msg.getFrom().getPubkey()); + } } diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java index 00ec40e..56dd9e9 100644 --- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -96,7 +96,7 @@ public class InternalContext { init(cryptography, inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkRepository, proofOfWorkService, proofOfWorkEngine, - messageCallback, customCommandHandler); + messageCallback, customCommandHandler, builder.labeler); for (BitmessageAddress identity : addressRepository.getIdentities()) { streams.add(identity.getStream()); } diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/DefaultLabeler.java b/core/src/main/java/ch/dissem/bitmessage/ports/DefaultLabeler.java new file mode 100644 index 0000000..1598ce1 --- /dev/null +++ b/core/src/main/java/ch/dissem/bitmessage/ports/DefaultLabeler.java @@ -0,0 +1,68 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.ports; + +import ch.dissem.bitmessage.InternalContext; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.valueobject.Label; + +import java.util.Iterator; + +public class DefaultLabeler implements Labeler, InternalContext.ContextHolder { + private InternalContext ctx; + + @Override + public void setLabels(Plaintext msg) { + if (msg.getType() == Plaintext.Type.BROADCAST) { + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.BROADCAST, Label.Type.UNREAD)); + } else { + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.UNREAD)); + } + } + + @Override + public void markAsRead(Plaintext msg) { + Iterator<Label> iterator = msg.getLabels().iterator(); + while (iterator.hasNext()) { + Label label = iterator.next(); + if (label.getType() == Label.Type.UNREAD) { + iterator.remove(); + } + } + } + + @Override + public void markAsUnread(Plaintext msg) { + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.UNREAD)); + } + + @Override + public void delete(Plaintext msg) { + msg.getLabels().clear(); + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.TRASH)); + } + + @Override + public void archive(Plaintext msg) { + msg.getLabels().clear(); + } + + @Override + public void setContext(InternalContext ctx) { + this.ctx = ctx; + } +} diff --git a/core/src/main/java/ch/dissem/bitmessage/ports/Labeler.java b/core/src/main/java/ch/dissem/bitmessage/ports/Labeler.java new file mode 100644 index 0000000..95febaf --- /dev/null +++ b/core/src/main/java/ch/dissem/bitmessage/ports/Labeler.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage.ports; + +import ch.dissem.bitmessage.entity.Plaintext; + +/** + * Defines and sets labels + */ +public interface Labeler { + /** + * Sets the labels of a newly received message. + * + * @param msg an unlabeled message or broadcast + */ + void setLabels(Plaintext msg); + + void markAsRead(Plaintext msg); + + void markAsUnread(Plaintext msg); + + void delete(Plaintext msg); + + void archive(Plaintext msg); +} diff --git a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java index 530ece0..7ca0d87 100644 --- a/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/BitmessageContextTest.java @@ -143,10 +143,11 @@ public class BitmessageContextTest { objects.add(TestUtils.loadObjectMessage(5, "V5Broadcast.payload")); when(ctx.internals().getInventory().getObjects(eq(address.getStream()), anyLong(), any(ObjectType.class))) .thenReturn(objects); + when(ctx.addresses().getSubscriptions(anyLong())).thenReturn(Collections.singletonList(address)); ctx.addSubscribtion(address); - verify(ctx.addresses(), times(1)).save(address); + verify(ctx.addresses(), atLeastOnce()).save(address); assertThat(address.isSubscribed(), is(true)); verify(ctx.internals().getInventory()).getObjects(eq(address.getStream()), anyLong(), any(ObjectType.class)); verify(listener).receive(any(Plaintext.class)); @@ -232,6 +233,7 @@ public class BitmessageContextTest { expected.remove(a.getAddress()); } } + @Test public void ensureShortDeterministicAddressesAreCreated() { final int expected_size = 1; diff --git a/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java b/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java index 976e464..710bf98 100644 --- a/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java +++ b/core/src/test/java/ch/dissem/bitmessage/DefaultMessageListenerTest.java @@ -25,6 +25,7 @@ import ch.dissem.bitmessage.entity.payload.GetPubkey; import ch.dissem.bitmessage.entity.payload.Msg; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.AddressRepository; +import ch.dissem.bitmessage.ports.Labeler; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.TestBase; @@ -62,7 +63,7 @@ public class DefaultMessageListenerTest extends TestBase { when(ctx.getAddressRepository()).thenReturn(addressRepo); when(ctx.getMessageRepository()).thenReturn(messageRepo); - listener = new DefaultMessageListener(ctx, mock(BitmessageContext.Listener.class)); + listener = new DefaultMessageListener(ctx, mock(Labeler.class), mock(BitmessageContext.Listener.class)); } @Test diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java index f480785..f3d9579 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java @@ -21,6 +21,7 @@ import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.payload.Pubkey; +import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.ports.MemoryNodeRegistry; import ch.dissem.bitmessage.repository.*; @@ -30,6 +31,7 @@ import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.util.List; +import java.util.stream.Collectors; import static ch.dissem.bitmessage.demo.CommandLine.COMMAND_BACK; import static ch.dissem.bitmessage.demo.CommandLine.ERROR_UNKNOWN_COMMAND; @@ -325,8 +327,10 @@ public class Application { System.out.println(); System.out.println(message.getText()); System.out.println(); - System.out.println("Labels: " + message.getLabels()); + System.out.println(message.getLabels().stream().map(Label::toString).collect( + Collectors.joining("Labels: ", ", ", ""))); System.out.println(); + ctx.labeler().markAsRead(message); String command; do { System.out.println("r) reply");