Some work on addresses and private keys that still doesn't work. As a side effect, sending objects now works basically.
This commit is contained in:
parent
8d1466f6f4
commit
a65907f13b
@ -16,18 +16,17 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.demo;
|
package ch.dissem.bitmessage.demo;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.BitmessageContext;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
import ch.dissem.bitmessage.inventory.JdbcAddressRepository;
|
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
import ch.dissem.bitmessage.inventory.JdbcInventory;
|
import ch.dissem.bitmessage.inventory.JdbcInventory;
|
||||||
import ch.dissem.bitmessage.inventory.JdbcNodeRegistry;
|
|
||||||
import ch.dissem.bitmessage.networking.NetworkNode;
|
|
||||||
import ch.dissem.bitmessage.ports.NetworkHandler;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Scanner;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by chris on 06.04.15.
|
* Created by chris on 06.04.15.
|
||||||
@ -36,26 +35,60 @@ public class Main {
|
|||||||
private final static Logger LOG = LoggerFactory.getLogger(Main.class);
|
private final static Logger LOG = LoggerFactory.getLogger(Main.class);
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
BitmessageContext ctx = new BitmessageContext.Builder()
|
final BitmessageAddress address = new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ");
|
||||||
.addressRepo(new JdbcAddressRepository())
|
|
||||||
.inventory(new JdbcInventory())
|
|
||||||
.nodeRegistry(new JdbcNodeRegistry())
|
|
||||||
.networkHandler(new NetworkNode())
|
|
||||||
.port(48444)
|
|
||||||
.streams(1)
|
|
||||||
.build();
|
|
||||||
ctx.getNetworkHandler().start(new NetworkHandler.MessageListener() {
|
|
||||||
@Override
|
|
||||||
public void receive(ObjectPayload payload) {
|
|
||||||
// LOG.info("message received: " + payload);
|
|
||||||
// System.out.print('.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
System.out.print("Press Enter to exit\n");
|
// BitmessageContext ctx = new BitmessageContext.Builder()
|
||||||
Scanner scanner = new Scanner(System.in);
|
// .addressRepo(new JdbcAddressRepository())
|
||||||
scanner.nextLine();
|
// .inventory(new JdbcInventory())
|
||||||
LOG.info("Shutting down client");
|
// .nodeRegistry(new JdbcNodeRegistry())
|
||||||
ctx.getNetworkHandler().stop();
|
// .networkHandler(new NetworkNode())
|
||||||
|
// .port(48444)
|
||||||
|
// .streams(1)
|
||||||
|
// .build();
|
||||||
|
//
|
||||||
|
// ctx.getNetworkHandler().start(new NetworkHandler.MessageListener() {
|
||||||
|
// @Override
|
||||||
|
// public void receive(ObjectPayload payload) {
|
||||||
|
//// LOG.info("message received: " + payload);
|
||||||
|
//// System.out.print('.');
|
||||||
|
// if (payload instanceof V3Pubkey) {
|
||||||
|
// V3Pubkey pubkey = (V3Pubkey) payload;
|
||||||
|
// try {
|
||||||
|
// address.setPubkey(pubkey);
|
||||||
|
// System.out.println(address);
|
||||||
|
// } catch (Exception ignore) {
|
||||||
|
// System.err.println("Received pubkey we didn't request.");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// Scanner scanner = new Scanner(System.in);
|
||||||
|
// System.out.println("Press Enter to request pubkey for address " + address);
|
||||||
|
// scanner.nextLine();
|
||||||
|
// ctx.send(1, address.getVersion(), new GetPubkey(address), 3000, 1000, 1000);
|
||||||
|
//
|
||||||
|
// System.out.println("Press Enter to exit");
|
||||||
|
// scanner.nextLine();
|
||||||
|
// LOG.info("Shutting down client");
|
||||||
|
// ctx.getNetworkHandler().stop();
|
||||||
|
|
||||||
|
List<ObjectMessage> objects = new JdbcInventory().getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY);
|
||||||
|
System.out.println("Address version: " + address.getVersion());
|
||||||
|
System.out.println("Address stream: " + address.getStream());
|
||||||
|
for (ObjectMessage o : objects) {
|
||||||
|
Pubkey pubkey = (Pubkey) o.getPayload();
|
||||||
|
if (Arrays.equals(address.getRipe(), pubkey.getRipe()))
|
||||||
|
System.out.println("Pubkey found!");
|
||||||
|
try {
|
||||||
|
address.setPubkey(pubkey);
|
||||||
|
System.out.println(address);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
System.out.println("But setPubkey failed? " + address.getRipe().length + "/" + pubkey.getRipe().length);
|
||||||
|
if (Arrays.equals(address.getRipe(), pubkey.getRipe())) {
|
||||||
|
ignore.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,15 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage;
|
package ch.dissem.bitmessage;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.ports.AddressRepository;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
import ch.dissem.bitmessage.ports.Inventory;
|
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
||||||
import ch.dissem.bitmessage.ports.NetworkHandler;
|
import ch.dissem.bitmessage.ports.*;
|
||||||
import ch.dissem.bitmessage.ports.NodeRegistry;
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
|
import ch.dissem.bitmessage.utils.UnixTime;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
@ -29,15 +33,16 @@ import java.util.TreeSet;
|
|||||||
*/
|
*/
|
||||||
public class BitmessageContext {
|
public class BitmessageContext {
|
||||||
public static final int CURRENT_VERSION = 3;
|
public static final int CURRENT_VERSION = 3;
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(BitmessageContext.class);
|
||||||
|
private final Inventory inventory;
|
||||||
|
private final NodeRegistry nodeRegistry;
|
||||||
|
private final NetworkHandler networkHandler;
|
||||||
|
private final AddressRepository addressRepo;
|
||||||
|
private final ProofOfWorkEngine proofOfWorkEngine;
|
||||||
|
|
||||||
private Inventory inventory;
|
private final TreeSet<Long> streams;
|
||||||
private NodeRegistry nodeRegistry;
|
|
||||||
private NetworkHandler networkHandler;
|
|
||||||
private AddressRepository addressRepo;
|
|
||||||
|
|
||||||
private Collection<Long> streams = new TreeSet<>();
|
private final int port;
|
||||||
|
|
||||||
private int port;
|
|
||||||
|
|
||||||
private long networkNonceTrialsPerByte = 1000;
|
private long networkNonceTrialsPerByte = 1000;
|
||||||
private long networkExtraBytes = 1000;
|
private long networkExtraBytes = 1000;
|
||||||
@ -48,9 +53,10 @@ public class BitmessageContext {
|
|||||||
nodeRegistry = builder.nodeRegistry;
|
nodeRegistry = builder.nodeRegistry;
|
||||||
networkHandler = builder.networkHandler;
|
networkHandler = builder.networkHandler;
|
||||||
addressRepo = builder.addressRepo;
|
addressRepo = builder.addressRepo;
|
||||||
|
proofOfWorkEngine = builder.proofOfWorkEngine;
|
||||||
streams = builder.streams;
|
streams = builder.streams;
|
||||||
|
|
||||||
init(inventory, nodeRegistry, networkHandler, addressRepo);
|
init(inventory, nodeRegistry, networkHandler, addressRepo, proofOfWorkEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(Object... objects) {
|
private void init(Object... objects) {
|
||||||
@ -61,6 +67,20 @@ public class BitmessageContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void send(long stream, long version, ObjectPayload payload, long timeToLive, long nonceTrialsPerByte, long extraBytes) throws IOException {
|
||||||
|
long expires = UnixTime.now(+timeToLive);
|
||||||
|
LOG.info("Expires at " + expires);
|
||||||
|
ObjectMessage object = new ObjectMessage.Builder()
|
||||||
|
.stream(stream)
|
||||||
|
.version(version)
|
||||||
|
.expiresTime(expires)
|
||||||
|
.payload(payload)
|
||||||
|
.build();
|
||||||
|
Security.doProofOfWork(object, proofOfWorkEngine, nonceTrialsPerByte, extraBytes);
|
||||||
|
inventory.storeObject(object);
|
||||||
|
networkHandler.offer(object.getInventoryVector());
|
||||||
|
}
|
||||||
|
|
||||||
public Inventory getInventory() {
|
public Inventory getInventory() {
|
||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
@ -113,7 +133,8 @@ public class BitmessageContext {
|
|||||||
private NodeRegistry nodeRegistry;
|
private NodeRegistry nodeRegistry;
|
||||||
private NetworkHandler networkHandler;
|
private NetworkHandler networkHandler;
|
||||||
private AddressRepository addressRepo;
|
private AddressRepository addressRepo;
|
||||||
private Collection<Long> streams;
|
private ProofOfWorkEngine proofOfWorkEngine;
|
||||||
|
private TreeSet<Long> streams;
|
||||||
|
|
||||||
public Builder() {
|
public Builder() {
|
||||||
}
|
}
|
||||||
@ -143,8 +164,13 @@ public class BitmessageContext {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder proofOfWorkEngine(ProofOfWorkEngine proofOfWorkEngine) {
|
||||||
|
this.proofOfWorkEngine = proofOfWorkEngine;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder streams(Collection<Long> streams) {
|
public Builder streams(Collection<Long> streams) {
|
||||||
this.streams = streams;
|
this.streams = new TreeSet<>(streams);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +190,9 @@ public class BitmessageContext {
|
|||||||
if (streams == null) {
|
if (streams == null) {
|
||||||
streams(1);
|
streams(1);
|
||||||
}
|
}
|
||||||
|
if (proofOfWorkEngine == null) {
|
||||||
|
proofOfWorkEngine = new MultiThreadedPOWEngine();
|
||||||
|
}
|
||||||
return new BitmessageContext(this);
|
return new BitmessageContext(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.utils.Decode.bytes;
|
||||||
|
import static ch.dissem.bitmessage.utils.Decode.varInt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Bitmessage address. Can be a user's private address, an address string without public keys or a recipient's address
|
* A Bitmessage address. Can be a user's private address, an address string without public keys or a recipient's address
|
||||||
* holding private keys.
|
* holding private keys.
|
||||||
@ -53,10 +56,10 @@ public class BitmessageAddress {
|
|||||||
byte[] bytes = Base58.decode(address.substring(3));
|
byte[] bytes = Base58.decode(address.substring(3));
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
|
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
|
||||||
AccessCounter counter = new AccessCounter();
|
AccessCounter counter = new AccessCounter();
|
||||||
this.version = Decode.varInt(in, counter);
|
this.version = varInt(in, counter);
|
||||||
this.stream = Decode.varInt(in, counter);
|
this.stream = varInt(in, counter);
|
||||||
this.ripe = Decode.bytes(in, bytes.length - counter.length() - 4);
|
this.ripe = Bytes.expand(bytes(in, bytes.length - counter.length() - 4), 20);
|
||||||
testChecksum(Decode.bytes(in, 4), bytes);
|
testChecksum(bytes(in, 4), bytes);
|
||||||
this.address = generateAddress();
|
this.address = generateAddress();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -108,10 +111,6 @@ public class BitmessageAddress {
|
|||||||
return privateKey;
|
return privateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAlias(String alias) {
|
|
||||||
this.alias = alias;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
@ -120,6 +119,10 @@ public class BitmessageAddress {
|
|||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAlias(String alias) {
|
||||||
|
this.alias = alias;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return alias != null ? alias : address;
|
return alias != null ? alias : address;
|
||||||
|
@ -89,20 +89,20 @@ public class ObjectMessage implements MessagePayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(OutputStream stream) throws IOException {
|
public void write(OutputStream out) throws IOException {
|
||||||
stream.write(nonce);
|
out.write(nonce);
|
||||||
stream.write(getPayloadBytesWithoutNonce());
|
out.write(getPayloadBytesWithoutNonce());
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getPayloadBytesWithoutNonce() throws IOException {
|
public byte[] getPayloadBytesWithoutNonce() throws IOException {
|
||||||
if (payloadBytes == null) {
|
if (payloadBytes == null) {
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
Encode.int64(expiresTime, stream);
|
Encode.int64(expiresTime, out);
|
||||||
Encode.int32(objectType, stream);
|
Encode.int32(objectType, out);
|
||||||
Encode.varInt(version, stream);
|
Encode.varInt(version, out);
|
||||||
Encode.varInt(this.stream, stream);
|
Encode.varInt(stream, out);
|
||||||
payload.write(stream);
|
payload.write(out);
|
||||||
payloadBytes = stream.toByteArray();
|
payloadBytes = out.toByteArray();
|
||||||
}
|
}
|
||||||
return payloadBytes;
|
return payloadBytes;
|
||||||
}
|
}
|
||||||
@ -110,8 +110,8 @@ public class ObjectMessage implements MessagePayload {
|
|||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
private byte[] nonce;
|
private byte[] nonce;
|
||||||
private long expiresTime;
|
private long expiresTime;
|
||||||
private long objectType;
|
private long objectType = -1;
|
||||||
private long version;
|
private long version = -1;
|
||||||
private long streamNumber;
|
private long streamNumber;
|
||||||
private ObjectPayload payload;
|
private ObjectPayload payload;
|
||||||
|
|
||||||
@ -138,13 +138,15 @@ public class ObjectMessage implements MessagePayload {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder streamNumber(long streamNumber) {
|
public Builder stream(long streamNumber) {
|
||||||
this.streamNumber = streamNumber;
|
this.streamNumber = streamNumber;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder payload(ObjectPayload payload) {
|
public Builder payload(ObjectPayload payload) {
|
||||||
this.payload = payload;
|
this.payload = payload;
|
||||||
|
if (this.objectType == -1)
|
||||||
|
this.objectType = payload.getType().getNumber();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,11 @@ public class GenericPayload implements ObjectPayload {
|
|||||||
return new GenericPayload(stream, Decode.bytes(is, length));
|
return new GenericPayload(stream, Decode.bytes(is, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectType getType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getStream() {
|
public long getStream() {
|
||||||
return stream;
|
return stream;
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload;
|
package ch.dissem.bitmessage.entity.payload;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
|
import ch.dissem.bitmessage.utils.Bytes;
|
||||||
import ch.dissem.bitmessage.utils.Decode;
|
import ch.dissem.bitmessage.utils.Decode;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -30,22 +32,30 @@ public class GetPubkey implements ObjectPayload {
|
|||||||
private byte[] ripe;
|
private byte[] ripe;
|
||||||
private byte[] tag;
|
private byte[] tag;
|
||||||
|
|
||||||
private GetPubkey(long stream, byte[] ripeOrTag) {
|
public GetPubkey(BitmessageAddress address) {
|
||||||
|
this.stream = address.getStream();
|
||||||
|
if (address.getVersion() < 4)
|
||||||
|
this.ripe = address.getRipe();
|
||||||
|
else
|
||||||
|
this.tag = ((V4Pubkey) address.getPubkey()).getTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
private GetPubkey(long stream, long version, byte[] ripeOrTag) {
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
switch (ripeOrTag.length) {
|
if (version < 4) {
|
||||||
case 20:
|
ripe = ripeOrTag;
|
||||||
ripe = ripeOrTag;
|
} else {
|
||||||
break;
|
tag = ripeOrTag;
|
||||||
case 32:
|
|
||||||
tag = ripeOrTag;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("ripe (20 bytes) or tag (32 bytes) expected, but pubkey was " + ripeOrTag.length + " bytes long.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GetPubkey read(InputStream is, long stream, int length) throws IOException {
|
public static GetPubkey read(InputStream is, long stream, int length, long version) throws IOException {
|
||||||
return new GetPubkey(stream, Decode.bytes(is, length));
|
return new GetPubkey(stream, version, Decode.bytes(is, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectType getType() {
|
||||||
|
return ObjectType.GET_PUBKEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,6 +44,11 @@ public class Msg implements ObjectPayload {
|
|||||||
return new Msg(stream, Decode.bytes(is, length));
|
return new Msg(stream, Decode.bytes(is, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectType getType() {
|
||||||
|
return ObjectType.MSG;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getStream() {
|
public long getStream() {
|
||||||
return stream;
|
return stream;
|
||||||
|
@ -22,5 +22,7 @@ import ch.dissem.bitmessage.entity.Streamable;
|
|||||||
* The payload of an 'object' command. This is shared by the network.
|
* The payload of an 'object' command. This is shared by the network.
|
||||||
*/
|
*/
|
||||||
public interface ObjectPayload extends Streamable {
|
public interface ObjectPayload extends Streamable {
|
||||||
|
ObjectType getType();
|
||||||
|
|
||||||
long getStream();
|
long getStream();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.payload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Known types for 'object' messages. Must not be used where an unknown type must be resent.
|
||||||
|
*/
|
||||||
|
public enum ObjectType {
|
||||||
|
GET_PUBKEY(0),
|
||||||
|
PUBKEY(1),
|
||||||
|
MSG(2),
|
||||||
|
BROADCAST(3);
|
||||||
|
|
||||||
|
int number;
|
||||||
|
|
||||||
|
ObjectType(int number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectType fromNumber(long number) {
|
||||||
|
for (ObjectType type : values()) {
|
||||||
|
if (type.number == number) return type;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
@ -56,6 +56,11 @@ public class V2Pubkey extends Pubkey {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectType getType() {
|
||||||
|
return ObjectType.PUBKEY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getStream() {
|
public long getStream() {
|
||||||
return stream;
|
return stream;
|
||||||
|
@ -40,6 +40,11 @@ public class V4Broadcast implements Broadcast {
|
|||||||
return new V4Broadcast(stream, Decode.bytes(is, length));
|
return new V4Broadcast(stream, Decode.bytes(is, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectType getType() {
|
||||||
|
return ObjectType.BROADCAST;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getStream() {
|
public long getStream() {
|
||||||
return stream;
|
return stream;
|
||||||
|
@ -62,6 +62,11 @@ public class V4Pubkey extends Pubkey {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectType getType() {
|
||||||
|
return ObjectType.PUBKEY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getStream() {
|
public long getStream() {
|
||||||
return stream;
|
return stream;
|
||||||
|
@ -103,7 +103,7 @@ public class NetworkAddress implements Streamable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return toInetAddress() + ":" + port;
|
return "[" + toInetAddress() + "]:" + port;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,27 +101,28 @@ public class Factory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ObjectPayload getObjectPayload(long objectType, long version, long streamNumber, InputStream stream, int length) throws IOException {
|
static ObjectPayload getObjectPayload(long objectType, long version, long streamNumber, InputStream stream, int length) throws IOException {
|
||||||
if (objectType < 4) {
|
ObjectType type = ObjectType.fromNumber(objectType);
|
||||||
switch ((int) objectType) {
|
if (type != null) {
|
||||||
case 0:
|
switch (type) {
|
||||||
|
case GET_PUBKEY:
|
||||||
return parseGetPubkey(version, streamNumber, stream, length);
|
return parseGetPubkey(version, streamNumber, stream, length);
|
||||||
case 1:
|
case PUBKEY:
|
||||||
return parsePubkey(version, streamNumber, stream, length);
|
return parsePubkey(version, streamNumber, stream, length);
|
||||||
case 2:
|
case MSG:
|
||||||
return parseMsg(version, streamNumber, stream, length);
|
return parseMsg(version, streamNumber, stream, length);
|
||||||
case 3:
|
case BROADCAST:
|
||||||
return parseBroadcast(version, streamNumber, stream, length);
|
return parseBroadcast(version, streamNumber, stream, length);
|
||||||
default:
|
default:
|
||||||
LOG.error("This should not happen, someone broke something in the code!");
|
LOG.error("This should not happen, someone broke something in the code!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fallback: just store the message - we don't really care what it is
|
// fallback: just store the message - we don't really care what it is
|
||||||
LOG.warn("Unexpected object type: " + objectType);
|
// LOG.info("Unexpected object type: " + objectType);
|
||||||
return GenericPayload.read(stream, streamNumber, length);
|
return GenericPayload.read(stream, streamNumber, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectPayload parseGetPubkey(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
private static ObjectPayload parseGetPubkey(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
||||||
return GetPubkey.read(stream, streamNumber, length);
|
return GetPubkey.read(stream, streamNumber, length, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pubkey readPubkey(long version, long stream, InputStream is, int length) throws IOException {
|
public static Pubkey readPubkey(long version, long stream, InputStream is, int length) throws IOException {
|
||||||
|
@ -46,7 +46,10 @@ class V3MessageFactory {
|
|||||||
|
|
||||||
if (testChecksum(checksum, payloadBytes)) {
|
if (testChecksum(checksum, payloadBytes)) {
|
||||||
MessagePayload payload = getPayload(command, new ByteArrayInputStream(payloadBytes), length);
|
MessagePayload payload = getPayload(command, new ByteArrayInputStream(payloadBytes), length);
|
||||||
return new NetworkMessage(payload);
|
if (payload != null)
|
||||||
|
return new NetworkMessage(payload);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
throw new IOException("Checksum failed for message '" + command + "'");
|
throw new IOException("Checksum failed for message '" + command + "'");
|
||||||
}
|
}
|
||||||
@ -84,14 +87,14 @@ class V3MessageFactory {
|
|||||||
long version = Decode.varInt(stream, counter);
|
long version = Decode.varInt(stream, counter);
|
||||||
long streamNumber = Decode.varInt(stream, counter);
|
long streamNumber = Decode.varInt(stream, counter);
|
||||||
|
|
||||||
ObjectPayload payload = Factory.getObjectPayload(objectType, version, streamNumber, stream, length-counter.length());
|
ObjectPayload payload = Factory.getObjectPayload(objectType, version, streamNumber, stream, length - counter.length());
|
||||||
|
|
||||||
return new ObjectMessage.Builder()
|
return new ObjectMessage.Builder()
|
||||||
.nonce(nonce)
|
.nonce(nonce)
|
||||||
.expiresTime(expiresTime)
|
.expiresTime(expiresTime)
|
||||||
.objectType(objectType)
|
.objectType(objectType)
|
||||||
.version(version)
|
.version(version)
|
||||||
.streamNumber(streamNumber)
|
.stream(streamNumber)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.ports;
|
package ch.dissem.bitmessage.ports;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -31,6 +32,8 @@ public interface Inventory {
|
|||||||
|
|
||||||
ObjectMessage getObject(InventoryVector vector);
|
ObjectMessage getObject(InventoryVector vector);
|
||||||
|
|
||||||
|
List<ObjectMessage> getObjects(long stream, long version, ObjectType type);
|
||||||
|
|
||||||
void storeObject(ObjectMessage object);
|
void storeObject(ObjectMessage object);
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
@ -18,6 +18,7 @@ package ch.dissem.bitmessage.ports;
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.BitmessageContext;
|
import ch.dissem.bitmessage.BitmessageContext;
|
||||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles incoming messages
|
* Handles incoming messages
|
||||||
@ -27,7 +28,7 @@ public interface NetworkHandler {
|
|||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void send(ObjectPayload payload);
|
void offer(InventoryVector iv);
|
||||||
|
|
||||||
interface MessageListener {
|
interface MessageListener {
|
||||||
void receive(ObjectPayload payload);
|
void receive(ObjectPayload payload);
|
||||||
|
@ -80,6 +80,9 @@ public class Security {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void doProofOfWork(ObjectMessage object, ProofOfWorkEngine worker, long nonceTrialsPerByte, long extraBytes) throws IOException {
|
public static void doProofOfWork(ObjectMessage object, ProofOfWorkEngine worker, long nonceTrialsPerByte, long extraBytes) throws IOException {
|
||||||
|
if (nonceTrialsPerByte < 1000) nonceTrialsPerByte = 1000;
|
||||||
|
if (extraBytes < 1000) extraBytes = 1000;
|
||||||
|
|
||||||
byte[] initialHash = getInitialHash(object);
|
byte[] initialHash = getInitialHash(object);
|
||||||
|
|
||||||
byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes);
|
byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes);
|
||||||
|
@ -20,7 +20,7 @@ package ch.dissem.bitmessage.utils;
|
|||||||
* Created by chris on 13.04.15.
|
* Created by chris on 13.04.15.
|
||||||
*/
|
*/
|
||||||
public class Strings {
|
public class Strings {
|
||||||
public static CharSequence join(byte[]... objects) {
|
public static StringBuilder join(byte[]... objects) {
|
||||||
StringBuilder streamList = new StringBuilder();
|
StringBuilder streamList = new StringBuilder();
|
||||||
for (int i = 0; i < objects.length; i++) {
|
for (int i = 0; i < objects.length; i++) {
|
||||||
if (i > 0) streamList.append(", ");
|
if (i > 0) streamList.append(", ");
|
||||||
@ -29,7 +29,7 @@ public class Strings {
|
|||||||
return streamList;
|
return streamList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CharSequence join(long... objects) {
|
public static StringBuilder join(long... objects) {
|
||||||
StringBuilder streamList = new StringBuilder();
|
StringBuilder streamList = new StringBuilder();
|
||||||
for (int i = 0; i < objects.length; i++) {
|
for (int i = 0; i < objects.length; i++) {
|
||||||
if (i > 0) streamList.append(", ");
|
if (i > 0) streamList.append(", ");
|
||||||
@ -38,7 +38,7 @@ public class Strings {
|
|||||||
return streamList;
|
return streamList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CharSequence join(Object... objects) {
|
public static StringBuilder join(Object... objects) {
|
||||||
StringBuilder streamList = new StringBuilder();
|
StringBuilder streamList = new StringBuilder();
|
||||||
for (int i = 0; i < objects.length; i++) {
|
for (int i = 0; i < objects.length; i++) {
|
||||||
if (i > 0) streamList.append(", ");
|
if (i > 0) streamList.append(", ");
|
||||||
@ -47,9 +47,8 @@ public class Strings {
|
|||||||
return streamList;
|
return streamList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CharSequence hex(byte[] bytes) {
|
public static StringBuilder hex(byte[] bytes) {
|
||||||
StringBuilder hex = new StringBuilder(bytes.length + 2);
|
StringBuilder hex = new StringBuilder(bytes.length + 2);
|
||||||
hex.append("0x");
|
|
||||||
for (byte b : bytes) {
|
for (byte b : bytes) {
|
||||||
hex.append(String.format("%02x", b));
|
hex.append(String.format("%02x", b));
|
||||||
}
|
}
|
||||||
|
@ -26,4 +26,8 @@ public class UnixTime {
|
|||||||
public static long now() {
|
public static long now() {
|
||||||
return System.currentTimeMillis() / 1000;
|
return System.currentTimeMillis() / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long now(long shiftSeconds) {
|
||||||
|
return (System.currentTimeMillis() / 1000) + shiftSeconds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity;
|
package ch.dissem.bitmessage.entity;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.utils.Base58;
|
import ch.dissem.bitmessage.utils.*;
|
||||||
import ch.dissem.bitmessage.utils.Bytes;
|
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import java.io.IOException;
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class BitmessageAddressTest {
|
public class BitmessageAddressTest {
|
||||||
@Test
|
@Test
|
||||||
@ -49,24 +49,59 @@ public class BitmessageAddressTest {
|
|||||||
assertNotNull(address.getPubkey());
|
assertNotNull(address.getPubkey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testV3() {
|
||||||
|
// ripe 007402be6e76c3cb87caa946d0c003a3d4d8e1d5
|
||||||
|
// publicSigningKey in hex: 0435e3f10f4884ec42f11f1a815ace8c7c4575cad455ca98db19a245c4c57baebdce990919b647f2657596b75aa939b858bd70c55a03492dd95119bef009cf9eea
|
||||||
|
// publicEncryptionKey in hex: 04bf30a7ee7854f9381332a6285659215a6a4b2ab3479fa87fe996f7cd11710367748371d8d2545f8466964dd3140ab80508b2b18e45616ef6cc4d8e54db923761
|
||||||
|
BitmessageAddress address = new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ");
|
||||||
|
V3Pubkey pubkey = new V3Pubkey.Builder()
|
||||||
|
.stream(1)
|
||||||
|
.publicSigningKey(Bytes.fromHex("0435e3f10f4884ec42f11f1a815ace8c7c4575cad455ca98db19a245c4c57baebdce990919b647f2657596b75aa939b858bd70c55a03492dd95119bef009cf9eea"))
|
||||||
|
.publicEncryptionKey(Bytes.fromHex("04bf30a7ee7854f9381332a6285659215a6a4b2ab3479fa87fe996f7cd11710367748371d8d2545f8466964dd3140ab80508b2b18e45616ef6cc4d8e54db923761"))
|
||||||
|
.build();
|
||||||
|
address.setPubkey(pubkey);
|
||||||
|
assertArrayEquals(Bytes.fromHex("007402be6e76c3cb87caa946d0c003a3d4d8e1d5"), address.getRipe());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testV3PubkeyImport() throws IOException {
|
||||||
|
ObjectMessage object = TestUtils.loadObjectMessage(3, "V3Pubkey.payload");
|
||||||
|
V3Pubkey pubkey = (V3Pubkey) object.getPayload();
|
||||||
|
BitmessageAddress address = new BitmessageAddress("BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn");
|
||||||
|
address.setPubkey(pubkey);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testV3Import() {
|
public void testV3Import() {
|
||||||
assertEquals(3, new BitmessageAddress("BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn").getVersion());
|
String address_string = "BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn";
|
||||||
assertEquals(1, new BitmessageAddress("BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn").getStream());
|
assertEquals(3, new BitmessageAddress(address_string).getVersion());
|
||||||
|
assertEquals(1, new BitmessageAddress(address_string).getStream());
|
||||||
|
|
||||||
byte[] privsigningkey = Base58.decode("5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9");
|
byte[] privsigningkey = getSecret("5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9");
|
||||||
byte[] privencryptionkey = Base58.decode("5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck");
|
byte[] privencryptionkey = getSecret("5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck");
|
||||||
assertEquals((byte) 0x80, privsigningkey[0]);
|
|
||||||
assertEquals((byte) 0x80, privencryptionkey[0]);
|
|
||||||
privsigningkey = Bytes.subArray(privsigningkey, 1, privsigningkey.length - 5);
|
|
||||||
privencryptionkey = Bytes.subArray(privencryptionkey, 1, privencryptionkey.length - 5);
|
|
||||||
|
|
||||||
privsigningkey = Bytes.expand(privsigningkey, 32);
|
System.out.println("\n\n" + Strings.hex(privsigningkey) + "\n\n");
|
||||||
privencryptionkey = Bytes.expand(privencryptionkey, 32);
|
|
||||||
|
// privsigningkey = Bytes.expand(privsigningkey, 32);
|
||||||
|
// privencryptionkey = Bytes.expand(privencryptionkey, 32);
|
||||||
|
|
||||||
BitmessageAddress address = new BitmessageAddress(new PrivateKey(privsigningkey, privencryptionkey,
|
BitmessageAddress address = new BitmessageAddress(new PrivateKey(privsigningkey, privencryptionkey,
|
||||||
Security.createPubkey(3, 1, privsigningkey, privencryptionkey, 320, 14000)));
|
Security.createPubkey(3, 1, privsigningkey, privencryptionkey, 320, 14000)));
|
||||||
assertEquals("BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn", address.getAddress());
|
assertEquals(address_string, address.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getSecret(String walletImportFormat) {
|
||||||
|
byte[] bytes = Base58.decode("5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9");
|
||||||
|
assertEquals(37, bytes.length);
|
||||||
|
assertEquals((byte) 0x80, bytes[0]);
|
||||||
|
byte[] checksum = Bytes.subArray(bytes, bytes.length - 4, 4);
|
||||||
|
byte[] secret = Bytes.subArray(bytes, 1, 32);
|
||||||
|
// assertArrayEquals("Checksum failed", checksum, Bytes.subArray(Security.doubleSha512(new byte[]{(byte) 0x80}, secret, new byte[]{0x01}), 0, 4));
|
||||||
|
byte[] result = new byte[33];
|
||||||
|
result[0] = 0x04;
|
||||||
|
System.arraycopy(secret, 0, result, 1, secret.length);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity;
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.payload.*;
|
import ch.dissem.bitmessage.entity.payload.*;
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
|
import ch.dissem.bitmessage.utils.TestUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@ -69,7 +70,7 @@ public class SerializationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doTest(String resourceName, int version, Class<?> expectedPayloadType) throws IOException {
|
private void doTest(String resourceName, int version, Class<?> expectedPayloadType) throws IOException {
|
||||||
byte[] data = getBytes(resourceName);
|
byte[] data = TestUtils.getBytes(resourceName);
|
||||||
InputStream in = new ByteArrayInputStream(data);
|
InputStream in = new ByteArrayInputStream(data);
|
||||||
ObjectMessage object = Factory.getObjectMessage(version, in, data.length);
|
ObjectMessage object = Factory.getObjectMessage(version, in, data.length);
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
@ -77,16 +78,4 @@ public class SerializationTest {
|
|||||||
assertArrayEquals(data, out.toByteArray());
|
assertArrayEquals(data, out.toByteArray());
|
||||||
assertEquals(expectedPayloadType.getCanonicalName(), object.getPayload().getClass().getCanonicalName());
|
assertEquals(expectedPayloadType.getCanonicalName(), object.getPayload().getClass().getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getBytes(String resourceName) throws IOException {
|
|
||||||
InputStream in = getClass().getClassLoader().getResourceAsStream(resourceName);
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int len = in.read(buffer);
|
|
||||||
while (len != -1) {
|
|
||||||
out.write(buffer, 0, len);
|
|
||||||
len = in.read(buffer);
|
|
||||||
}
|
|
||||||
return out.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,14 @@ public class BytesTest {
|
|||||||
public static final Random rnd = new Random();
|
public static final Random rnd = new Random();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncrement() throws IOException {
|
public void ensureExpandsCorrectly() {
|
||||||
|
byte[] source = {1};
|
||||||
|
byte[] expected = {0,1};
|
||||||
|
assertArrayEquals(expected, Bytes.expand(source, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ensureIncrementCarryWorks() throws IOException {
|
||||||
byte[] bytes = {0, -1};
|
byte[] bytes = {0, -1};
|
||||||
Bytes.inc(bytes);
|
Bytes.inc(bytes);
|
||||||
assertArrayEquals(TestUtils.int16(256), bytes);
|
assertArrayEquals(TestUtils.int16(256), bytes);
|
||||||
|
@ -29,6 +29,7 @@ public class StringsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHexString() {
|
public void testHexString() {
|
||||||
assertEquals("0x48656c6c6f21", Strings.hex("Hello!".getBytes()));
|
assertEquals("48656c6c6f21", Strings.hex("Hello!".getBytes()).toString());
|
||||||
|
assertEquals("0001", Strings.hex(new byte[]{0, 1}).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,13 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.utils;
|
package ch.dissem.bitmessage.utils;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there's ever a need for this in production code, it should be rewritten to be more efficient.
|
* If there's ever a need for this in production code, it should be rewritten to be more efficient.
|
||||||
@ -28,4 +33,22 @@ public class TestUtils {
|
|||||||
Encode.int16(number, out);
|
Encode.int16(number, out);
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ObjectMessage loadObjectMessage(int version, String resourceName) throws IOException {
|
||||||
|
byte[] data = getBytes(resourceName);
|
||||||
|
InputStream in = new ByteArrayInputStream(data);
|
||||||
|
return Factory.getObjectMessage(version, in, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] getBytes(String resourceName) throws IOException {
|
||||||
|
InputStream in = TestUtils.class.getClassLoader().getResourceAsStream(resourceName);
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int len = in.read(buffer);
|
||||||
|
while (len != -1) {
|
||||||
|
out.write(buffer, 0, len);
|
||||||
|
len = in.read(buffer);
|
||||||
|
}
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.inventory;
|
package ch.dissem.bitmessage.inventory;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.ports.Inventory;
|
import ch.dissem.bitmessage.ports.Inventory;
|
||||||
@ -62,9 +63,41 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
|
|||||||
public ObjectMessage getObject(InventoryVector vector) {
|
public ObjectMessage getObject(InventoryVector vector) {
|
||||||
try {
|
try {
|
||||||
Statement stmt = getConnection().createStatement();
|
Statement stmt = getConnection().createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT data, version FROM Inventory WHERE hash = " + vector);
|
ResultSet rs = stmt.executeQuery("SELECT data, version FROM Inventory WHERE hash = X'" + vector + "'");
|
||||||
Blob data = rs.getBlob("data");
|
if (rs.next()) {
|
||||||
return Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length());
|
Blob data = rs.getBlob("data");
|
||||||
|
return Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length());
|
||||||
|
} else {
|
||||||
|
LOG.info("Object requested that we don't have. IV: " + vector);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ObjectMessage> getObjects(long stream, long version, ObjectType type) {
|
||||||
|
try {
|
||||||
|
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 (type != null) {
|
||||||
|
query.append(" AND type = ").append(type.getNumber());
|
||||||
|
}
|
||||||
|
Statement stmt = getConnection().createStatement();
|
||||||
|
ResultSet rs = stmt.executeQuery(query.toString());
|
||||||
|
List<ObjectMessage> result = new LinkedList<>();
|
||||||
|
while (rs.next()) {
|
||||||
|
Blob data = rs.getBlob("data");
|
||||||
|
result.add(Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
LOG.error(e.getMessage(), e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.inventory;
|
package ch.dissem.bitmessage.inventory;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||||
import ch.dissem.bitmessage.ports.Inventory;
|
import ch.dissem.bitmessage.ports.Inventory;
|
||||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||||
@ -43,6 +44,11 @@ public class SimpleInventory implements Inventory {
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ObjectMessage> getObjects(long stream, long version, ObjectType type) {
|
||||||
|
return new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void storeObject(ObjectMessage object) {
|
public void storeObject(ObjectMessage object) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
@ -91,6 +91,7 @@ public class Connection implements Runnable {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case ACTIVE:
|
case ACTIVE:
|
||||||
receiveMessage(msg.getPayload());
|
receiveMessage(msg.getPayload());
|
||||||
|
sendQueue();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -121,14 +122,19 @@ public class Connection implements Runnable {
|
|||||||
}
|
}
|
||||||
} catch (SocketTimeoutException e) {
|
} catch (SocketTimeoutException e) {
|
||||||
if (state == ACTIVE) {
|
if (state == ACTIVE) {
|
||||||
for (MessagePayload msg = sendingQueue.poll(); msg != null; msg = sendingQueue.poll()) {
|
sendQueue();
|
||||||
send(msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendQueue() {
|
||||||
|
LOG.debug("Sending " + sendingQueue.size() + " messages to node " + node);
|
||||||
|
for (MessagePayload msg = sendingQueue.poll(); msg != null; msg = sendingQueue.poll()) {
|
||||||
|
send(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void receiveMessage(MessagePayload messagePayload) {
|
private void receiveMessage(MessagePayload messagePayload) {
|
||||||
switch (messagePayload.getCommand()) {
|
switch (messagePayload.getCommand()) {
|
||||||
case INV:
|
case INV:
|
||||||
@ -140,11 +146,10 @@ public class Connection implements Runnable {
|
|||||||
break;
|
break;
|
||||||
case GETDATA:
|
case GETDATA:
|
||||||
GetData getData = (GetData) messagePayload;
|
GetData getData = (GetData) messagePayload;
|
||||||
// for (InventoryVector iv : getData.getInventory()) {
|
for (InventoryVector iv : getData.getInventory()) {
|
||||||
// ObjectMessage om = ctx.getInventory().getObject(iv);
|
ObjectMessage om = ctx.getInventory().getObject(iv);
|
||||||
// sendingQueue.offer(om);
|
if (om != null) sendingQueue.offer(om);
|
||||||
// }
|
}
|
||||||
LOG.error("Node requests data!!!! This shouldn't happen, the hash is done wrong!!!");
|
|
||||||
break;
|
break;
|
||||||
case OBJECT:
|
case OBJECT:
|
||||||
ObjectMessage objectMessage = (ObjectMessage) messagePayload;
|
ObjectMessage objectMessage = (ObjectMessage) messagePayload;
|
||||||
@ -201,5 +206,12 @@ public class Connection implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void offer(InventoryVector iv) {
|
||||||
|
LOG.debug("Offering " + iv + " to node " + node.toString());
|
||||||
|
sendingQueue.offer(new Inv.Builder()
|
||||||
|
.addInventoryVector(iv)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
public enum State {SERVER, CLIENT, ACTIVE, DISCONNECTED}
|
public enum State {SERVER, CLIENT, ACTIVE, DISCONNECTED}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ package ch.dissem.bitmessage.networking;
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.BitmessageContext;
|
import ch.dissem.bitmessage.BitmessageContext;
|
||||||
import ch.dissem.bitmessage.BitmessageContext.ContextHolder;
|
import ch.dissem.bitmessage.BitmessageContext.ContextHolder;
|
||||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
||||||
import ch.dissem.bitmessage.ports.NetworkHandler;
|
import ch.dissem.bitmessage.ports.NetworkHandler;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -40,9 +40,9 @@ import static ch.dissem.bitmessage.networking.Connection.State.*;
|
|||||||
*/
|
*/
|
||||||
public class NetworkNode implements NetworkHandler, ContextHolder {
|
public class NetworkNode implements NetworkHandler, ContextHolder {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(NetworkNode.class);
|
private final static Logger LOG = LoggerFactory.getLogger(NetworkNode.class);
|
||||||
private BitmessageContext ctx;
|
|
||||||
private final ExecutorService pool;
|
private final ExecutorService pool;
|
||||||
private final List<Connection> connections = new LinkedList<>();
|
private final List<Connection> connections = new LinkedList<>();
|
||||||
|
private BitmessageContext ctx;
|
||||||
private ServerSocket serverSocket;
|
private ServerSocket serverSocket;
|
||||||
private Thread connectionManager;
|
private Thread connectionManager;
|
||||||
|
|
||||||
@ -137,7 +137,15 @@ public class NetworkNode implements NetworkHandler, ContextHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(final ObjectPayload payload) {
|
public void offer(final InventoryVector iv) {
|
||||||
// TODO: sendingQueue.add(message);
|
// TODO:
|
||||||
|
// - should offer to (random) 8 nodes during 8 seconds (if possible)
|
||||||
|
// - should probably offer later if no connection available at the moment?
|
||||||
|
synchronized (connections) {
|
||||||
|
LOG.debug(connections.size() + " connections available to offer " + iv);
|
||||||
|
for (Connection connection : connections) {
|
||||||
|
connection.offer(iv);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user