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:
		@@ -16,18 +16,17 @@
 | 
			
		||||
 | 
			
		||||
package ch.dissem.bitmessage.demo;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.BitmessageContext;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
 | 
			
		||||
import ch.dissem.bitmessage.inventory.JdbcAddressRepository;
 | 
			
		||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage;
 | 
			
		||||
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.JdbcNodeRegistry;
 | 
			
		||||
import ch.dissem.bitmessage.networking.NetworkNode;
 | 
			
		||||
import ch.dissem.bitmessage.ports.NetworkHandler;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Scanner;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by chris on 06.04.15.
 | 
			
		||||
@@ -36,26 +35,60 @@ public class Main {
 | 
			
		||||
    private final static Logger LOG = LoggerFactory.getLogger(Main.class);
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) throws IOException {
 | 
			
		||||
        BitmessageContext ctx = new BitmessageContext.Builder()
 | 
			
		||||
                .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('.');
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        final BitmessageAddress address = new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ");
 | 
			
		||||
 | 
			
		||||
        System.out.print("Press Enter to exit\n");
 | 
			
		||||
        Scanner scanner = new Scanner(System.in);
 | 
			
		||||
        scanner.nextLine();
 | 
			
		||||
        LOG.info("Shutting down client");
 | 
			
		||||
        ctx.getNetworkHandler().stop();
 | 
			
		||||
//        BitmessageContext ctx = new BitmessageContext.Builder()
 | 
			
		||||
//                .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('.');
 | 
			
		||||
//                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;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.ports.AddressRepository;
 | 
			
		||||
import ch.dissem.bitmessage.ports.Inventory;
 | 
			
		||||
import ch.dissem.bitmessage.ports.NetworkHandler;
 | 
			
		||||
import ch.dissem.bitmessage.ports.NodeRegistry;
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
 | 
			
		||||
import ch.dissem.bitmessage.ports.*;
 | 
			
		||||
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.TreeSet;
 | 
			
		||||
 | 
			
		||||
@@ -29,15 +33,16 @@ import java.util.TreeSet;
 | 
			
		||||
 */
 | 
			
		||||
public class BitmessageContext {
 | 
			
		||||
    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 NodeRegistry nodeRegistry;
 | 
			
		||||
    private NetworkHandler networkHandler;
 | 
			
		||||
    private AddressRepository addressRepo;
 | 
			
		||||
    private final TreeSet<Long> streams;
 | 
			
		||||
 | 
			
		||||
    private Collection<Long> streams = new TreeSet<>();
 | 
			
		||||
 | 
			
		||||
    private int port;
 | 
			
		||||
    private final int port;
 | 
			
		||||
 | 
			
		||||
    private long networkNonceTrialsPerByte = 1000;
 | 
			
		||||
    private long networkExtraBytes = 1000;
 | 
			
		||||
@@ -48,9 +53,10 @@ public class BitmessageContext {
 | 
			
		||||
        nodeRegistry = builder.nodeRegistry;
 | 
			
		||||
        networkHandler = builder.networkHandler;
 | 
			
		||||
        addressRepo = builder.addressRepo;
 | 
			
		||||
        proofOfWorkEngine = builder.proofOfWorkEngine;
 | 
			
		||||
        streams = builder.streams;
 | 
			
		||||
 | 
			
		||||
        init(inventory, nodeRegistry, networkHandler, addressRepo);
 | 
			
		||||
        init(inventory, nodeRegistry, networkHandler, addressRepo, proofOfWorkEngine);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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() {
 | 
			
		||||
        return inventory;
 | 
			
		||||
    }
 | 
			
		||||
@@ -113,7 +133,8 @@ public class BitmessageContext {
 | 
			
		||||
        private NodeRegistry nodeRegistry;
 | 
			
		||||
        private NetworkHandler networkHandler;
 | 
			
		||||
        private AddressRepository addressRepo;
 | 
			
		||||
        private Collection<Long> streams;
 | 
			
		||||
        private ProofOfWorkEngine proofOfWorkEngine;
 | 
			
		||||
        private TreeSet<Long> streams;
 | 
			
		||||
 | 
			
		||||
        public Builder() {
 | 
			
		||||
        }
 | 
			
		||||
@@ -143,8 +164,13 @@ public class BitmessageContext {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder proofOfWorkEngine(ProofOfWorkEngine proofOfWorkEngine) {
 | 
			
		||||
            this.proofOfWorkEngine = proofOfWorkEngine;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder streams(Collection<Long> streams) {
 | 
			
		||||
            this.streams = streams;
 | 
			
		||||
            this.streams = new TreeSet<>(streams);
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -164,6 +190,9 @@ public class BitmessageContext {
 | 
			
		||||
            if (streams == null) {
 | 
			
		||||
                streams(1);
 | 
			
		||||
            }
 | 
			
		||||
            if (proofOfWorkEngine == null) {
 | 
			
		||||
                proofOfWorkEngine = new MultiThreadedPOWEngine();
 | 
			
		||||
            }
 | 
			
		||||
            return new BitmessageContext(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,9 @@ import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
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
 | 
			
		||||
 * holding private keys.
 | 
			
		||||
@@ -53,10 +56,10 @@ public class BitmessageAddress {
 | 
			
		||||
            byte[] bytes = Base58.decode(address.substring(3));
 | 
			
		||||
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
 | 
			
		||||
            AccessCounter counter = new AccessCounter();
 | 
			
		||||
            this.version = Decode.varInt(in, counter);
 | 
			
		||||
            this.stream = Decode.varInt(in, counter);
 | 
			
		||||
            this.ripe = Decode.bytes(in, bytes.length - counter.length() - 4);
 | 
			
		||||
            testChecksum(Decode.bytes(in, 4), bytes);
 | 
			
		||||
            this.version = varInt(in, counter);
 | 
			
		||||
            this.stream = varInt(in, counter);
 | 
			
		||||
            this.ripe = Bytes.expand(bytes(in, bytes.length - counter.length() - 4), 20);
 | 
			
		||||
            testChecksum(bytes(in, 4), bytes);
 | 
			
		||||
            this.address = generateAddress();
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
@@ -108,10 +111,6 @@ public class BitmessageAddress {
 | 
			
		||||
        return privateKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setAlias(String alias) {
 | 
			
		||||
        this.alias = alias;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getAddress() {
 | 
			
		||||
        return address;
 | 
			
		||||
    }
 | 
			
		||||
@@ -120,6 +119,10 @@ public class BitmessageAddress {
 | 
			
		||||
        return alias;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setAlias(String alias) {
 | 
			
		||||
        this.alias = alias;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return alias != null ? alias : address;
 | 
			
		||||
 
 | 
			
		||||
@@ -89,20 +89,20 @@ public class ObjectMessage implements MessagePayload {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void write(OutputStream stream) throws IOException {
 | 
			
		||||
        stream.write(nonce);
 | 
			
		||||
        stream.write(getPayloadBytesWithoutNonce());
 | 
			
		||||
    public void write(OutputStream out) throws IOException {
 | 
			
		||||
        out.write(nonce);
 | 
			
		||||
        out.write(getPayloadBytesWithoutNonce());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public byte[] getPayloadBytesWithoutNonce() throws IOException {
 | 
			
		||||
        if (payloadBytes == null) {
 | 
			
		||||
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
 | 
			
		||||
            Encode.int64(expiresTime, stream);
 | 
			
		||||
            Encode.int32(objectType, stream);
 | 
			
		||||
            Encode.varInt(version, stream);
 | 
			
		||||
            Encode.varInt(this.stream, stream);
 | 
			
		||||
            payload.write(stream);
 | 
			
		||||
            payloadBytes = stream.toByteArray();
 | 
			
		||||
            ByteArrayOutputStream out = new ByteArrayOutputStream();
 | 
			
		||||
            Encode.int64(expiresTime, out);
 | 
			
		||||
            Encode.int32(objectType, out);
 | 
			
		||||
            Encode.varInt(version, out);
 | 
			
		||||
            Encode.varInt(stream, out);
 | 
			
		||||
            payload.write(out);
 | 
			
		||||
            payloadBytes = out.toByteArray();
 | 
			
		||||
        }
 | 
			
		||||
        return payloadBytes;
 | 
			
		||||
    }
 | 
			
		||||
@@ -110,8 +110,8 @@ public class ObjectMessage implements MessagePayload {
 | 
			
		||||
    public static final class Builder {
 | 
			
		||||
        private byte[] nonce;
 | 
			
		||||
        private long expiresTime;
 | 
			
		||||
        private long objectType;
 | 
			
		||||
        private long version;
 | 
			
		||||
        private long objectType = -1;
 | 
			
		||||
        private long version = -1;
 | 
			
		||||
        private long streamNumber;
 | 
			
		||||
        private ObjectPayload payload;
 | 
			
		||||
 | 
			
		||||
@@ -138,13 +138,15 @@ public class ObjectMessage implements MessagePayload {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder streamNumber(long streamNumber) {
 | 
			
		||||
        public Builder stream(long streamNumber) {
 | 
			
		||||
            this.streamNumber = streamNumber;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder payload(ObjectPayload payload) {
 | 
			
		||||
            this.payload = payload;
 | 
			
		||||
            if (this.objectType == -1)
 | 
			
		||||
                this.objectType = payload.getType().getNumber();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,11 @@ public class GenericPayload implements ObjectPayload {
 | 
			
		||||
        return new GenericPayload(stream, Decode.bytes(is, length));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ObjectType getType() {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getStream() {
 | 
			
		||||
        return stream;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,8 @@
 | 
			
		||||
 | 
			
		||||
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 java.io.IOException;
 | 
			
		||||
@@ -30,22 +32,30 @@ public class GetPubkey implements ObjectPayload {
 | 
			
		||||
    private byte[] ripe;
 | 
			
		||||
    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;
 | 
			
		||||
        switch (ripeOrTag.length) {
 | 
			
		||||
            case 20:
 | 
			
		||||
                ripe = ripeOrTag;
 | 
			
		||||
                break;
 | 
			
		||||
            case 32:
 | 
			
		||||
                tag = ripeOrTag;
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                throw new RuntimeException("ripe (20 bytes) or tag (32 bytes) expected, but pubkey was " + ripeOrTag.length + " bytes long.");
 | 
			
		||||
        if (version < 4) {
 | 
			
		||||
            ripe = ripeOrTag;
 | 
			
		||||
        } else {
 | 
			
		||||
            tag = ripeOrTag;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static GetPubkey read(InputStream is, long stream, int length) throws IOException {
 | 
			
		||||
        return new GetPubkey(stream, Decode.bytes(is, length));
 | 
			
		||||
    public static GetPubkey read(InputStream is, long stream, int length, long version) throws IOException {
 | 
			
		||||
        return new GetPubkey(stream, version, Decode.bytes(is, length));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ObjectType getType() {
 | 
			
		||||
        return ObjectType.GET_PUBKEY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,11 @@ public class Msg implements ObjectPayload {
 | 
			
		||||
        return new Msg(stream, Decode.bytes(is, length));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ObjectType getType() {
 | 
			
		||||
        return ObjectType.MSG;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getStream() {
 | 
			
		||||
        return stream;
 | 
			
		||||
 
 | 
			
		||||
@@ -22,5 +22,7 @@ import ch.dissem.bitmessage.entity.Streamable;
 | 
			
		||||
 * The payload of an 'object' command. This is shared by the network.
 | 
			
		||||
 */
 | 
			
		||||
public interface ObjectPayload extends Streamable {
 | 
			
		||||
    ObjectType getType();
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ObjectType getType() {
 | 
			
		||||
        return ObjectType.PUBKEY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getStream() {
 | 
			
		||||
        return stream;
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,11 @@ public class V4Broadcast implements Broadcast {
 | 
			
		||||
        return new V4Broadcast(stream, Decode.bytes(is, length));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ObjectType getType() {
 | 
			
		||||
        return ObjectType.BROADCAST;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getStream() {
 | 
			
		||||
        return stream;
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,11 @@ public class V4Pubkey extends Pubkey {
 | 
			
		||||
        return 4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ObjectType getType() {
 | 
			
		||||
        return ObjectType.PUBKEY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getStream() {
 | 
			
		||||
        return stream;
 | 
			
		||||
 
 | 
			
		||||
@@ -103,7 +103,7 @@ public class NetworkAddress implements Streamable {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return toInetAddress() + ":" + port;
 | 
			
		||||
        return "[" + toInetAddress() + "]:" + port;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -101,27 +101,28 @@ public class Factory {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static ObjectPayload getObjectPayload(long objectType, long version, long streamNumber, InputStream stream, int length) throws IOException {
 | 
			
		||||
        if (objectType < 4) {
 | 
			
		||||
            switch ((int) objectType) {
 | 
			
		||||
                case 0:
 | 
			
		||||
        ObjectType type = ObjectType.fromNumber(objectType);
 | 
			
		||||
        if (type != null) {
 | 
			
		||||
            switch (type) {
 | 
			
		||||
                case GET_PUBKEY:
 | 
			
		||||
                    return parseGetPubkey(version, streamNumber, stream, length);
 | 
			
		||||
                case 1:
 | 
			
		||||
                case PUBKEY:
 | 
			
		||||
                    return parsePubkey(version, streamNumber, stream, length);
 | 
			
		||||
                case 2:
 | 
			
		||||
                case MSG:
 | 
			
		||||
                    return parseMsg(version, streamNumber, stream, length);
 | 
			
		||||
                case 3:
 | 
			
		||||
                case BROADCAST:
 | 
			
		||||
                    return parseBroadcast(version, streamNumber, stream, length);
 | 
			
		||||
                default:
 | 
			
		||||
                    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
 | 
			
		||||
        LOG.warn("Unexpected object type: " + objectType);
 | 
			
		||||
//        LOG.info("Unexpected object type: " + objectType);
 | 
			
		||||
        return GenericPayload.read(stream, streamNumber, length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,10 @@ class V3MessageFactory {
 | 
			
		||||
 | 
			
		||||
            if (testChecksum(checksum, payloadBytes)) {
 | 
			
		||||
                MessagePayload payload = getPayload(command, new ByteArrayInputStream(payloadBytes), length);
 | 
			
		||||
                return new NetworkMessage(payload);
 | 
			
		||||
                if (payload != null)
 | 
			
		||||
                    return new NetworkMessage(payload);
 | 
			
		||||
                else
 | 
			
		||||
                    return null;
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new IOException("Checksum failed for message '" + command + "'");
 | 
			
		||||
            }
 | 
			
		||||
@@ -84,14 +87,14 @@ class V3MessageFactory {
 | 
			
		||||
        long version = 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()
 | 
			
		||||
                .nonce(nonce)
 | 
			
		||||
                .expiresTime(expiresTime)
 | 
			
		||||
                .objectType(objectType)
 | 
			
		||||
                .version(version)
 | 
			
		||||
                .streamNumber(streamNumber)
 | 
			
		||||
                .stream(streamNumber)
 | 
			
		||||
                .payload(payload)
 | 
			
		||||
                .build();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
package ch.dissem.bitmessage.ports;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.ObjectType;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -31,6 +32,8 @@ public interface Inventory {
 | 
			
		||||
 | 
			
		||||
    ObjectMessage getObject(InventoryVector vector);
 | 
			
		||||
 | 
			
		||||
    List<ObjectMessage> getObjects(long stream, long version, ObjectType type);
 | 
			
		||||
 | 
			
		||||
    void storeObject(ObjectMessage object);
 | 
			
		||||
 | 
			
		||||
    void cleanup();
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ package ch.dissem.bitmessage.ports;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.BitmessageContext;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handles incoming messages
 | 
			
		||||
@@ -27,7 +28,7 @@ public interface NetworkHandler {
 | 
			
		||||
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
    void send(ObjectPayload payload);
 | 
			
		||||
    void offer(InventoryVector iv);
 | 
			
		||||
 | 
			
		||||
    interface MessageListener {
 | 
			
		||||
        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 {
 | 
			
		||||
        if (nonceTrialsPerByte < 1000) nonceTrialsPerByte = 1000;
 | 
			
		||||
        if (extraBytes < 1000) extraBytes = 1000;
 | 
			
		||||
 | 
			
		||||
        byte[] initialHash = getInitialHash(object);
 | 
			
		||||
 | 
			
		||||
        byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes);
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ package ch.dissem.bitmessage.utils;
 | 
			
		||||
 * Created by chris on 13.04.15.
 | 
			
		||||
 */
 | 
			
		||||
public class Strings {
 | 
			
		||||
    public static CharSequence join(byte[]... objects) {
 | 
			
		||||
    public static StringBuilder join(byte[]... objects) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < objects.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
@@ -29,7 +29,7 @@ public class Strings {
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static CharSequence join(long... objects) {
 | 
			
		||||
    public static StringBuilder join(long... objects) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < objects.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
@@ -38,7 +38,7 @@ public class Strings {
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static CharSequence join(Object... objects) {
 | 
			
		||||
    public static StringBuilder join(Object... objects) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < objects.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
@@ -47,9 +47,8 @@ public class Strings {
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static CharSequence hex(byte[] bytes) {
 | 
			
		||||
    public static StringBuilder hex(byte[] bytes) {
 | 
			
		||||
        StringBuilder hex = new StringBuilder(bytes.length + 2);
 | 
			
		||||
        hex.append("0x");
 | 
			
		||||
        for (byte b : bytes) {
 | 
			
		||||
            hex.append(String.format("%02x", b));
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -26,4 +26,8 @@ public class UnixTime {
 | 
			
		||||
    public static long now() {
 | 
			
		||||
        return System.currentTimeMillis() / 1000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static long now(long shiftSeconds) {
 | 
			
		||||
        return (System.currentTimeMillis() / 1000) + shiftSeconds;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,14 +16,14 @@
 | 
			
		||||
 | 
			
		||||
package ch.dissem.bitmessage.entity;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
 | 
			
		||||
import ch.dissem.bitmessage.utils.Base58;
 | 
			
		||||
import ch.dissem.bitmessage.utils.Bytes;
 | 
			
		||||
import ch.dissem.bitmessage.utils.Security;
 | 
			
		||||
import ch.dissem.bitmessage.utils.*;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static org.junit.Assert.assertNotNull;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
public class BitmessageAddressTest {
 | 
			
		||||
    @Test
 | 
			
		||||
@@ -49,24 +49,59 @@ public class BitmessageAddressTest {
 | 
			
		||||
        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
 | 
			
		||||
    public void testV3Import() {
 | 
			
		||||
        assertEquals(3, new BitmessageAddress("BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn").getVersion());
 | 
			
		||||
        assertEquals(1, new BitmessageAddress("BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn").getStream());
 | 
			
		||||
        String address_string = "BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn";
 | 
			
		||||
        assertEquals(3, new BitmessageAddress(address_string).getVersion());
 | 
			
		||||
        assertEquals(1, new BitmessageAddress(address_string).getStream());
 | 
			
		||||
 | 
			
		||||
        byte[] privsigningkey = Base58.decode("5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9");
 | 
			
		||||
        byte[] privencryptionkey = Base58.decode("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);
 | 
			
		||||
        byte[] privsigningkey = getSecret("5KU2gbe9u4rKJ8PHYb1rvwMnZnAJj4gtV5GLwoYckeYzygWUzB9");
 | 
			
		||||
        byte[] privencryptionkey = getSecret("5KHd4c6cavd8xv4kzo3PwnVaYuBgEfg7voPQ5V97aZKgpYBXGck");
 | 
			
		||||
 | 
			
		||||
        privsigningkey = Bytes.expand(privsigningkey, 32);
 | 
			
		||||
        privencryptionkey = Bytes.expand(privencryptionkey, 32);
 | 
			
		||||
        System.out.println("\n\n" + Strings.hex(privsigningkey) + "\n\n");
 | 
			
		||||
 | 
			
		||||
//        privsigningkey = Bytes.expand(privsigningkey, 32);
 | 
			
		||||
//        privencryptionkey = Bytes.expand(privencryptionkey, 32);
 | 
			
		||||
 | 
			
		||||
        BitmessageAddress address = new BitmessageAddress(new PrivateKey(privsigningkey, privencryptionkey,
 | 
			
		||||
                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
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.*;
 | 
			
		||||
import ch.dissem.bitmessage.factory.Factory;
 | 
			
		||||
import ch.dissem.bitmessage.utils.TestUtils;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
@@ -69,7 +70,7 @@ public class SerializationTest {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        ObjectMessage object = Factory.getObjectMessage(version, in, data.length);
 | 
			
		||||
        ByteArrayOutputStream out = new ByteArrayOutputStream();
 | 
			
		||||
@@ -77,16 +78,4 @@ public class SerializationTest {
 | 
			
		||||
        assertArrayEquals(data, out.toByteArray());
 | 
			
		||||
        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();
 | 
			
		||||
 | 
			
		||||
    @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};
 | 
			
		||||
        Bytes.inc(bytes);
 | 
			
		||||
        assertArrayEquals(TestUtils.int16(256), bytes);
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ public class StringsTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage;
 | 
			
		||||
import ch.dissem.bitmessage.factory.Factory;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
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.
 | 
			
		||||
@@ -28,4 +33,22 @@ public class TestUtils {
 | 
			
		||||
        Encode.int16(number, out);
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.ObjectType;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
 | 
			
		||||
import ch.dissem.bitmessage.factory.Factory;
 | 
			
		||||
import ch.dissem.bitmessage.ports.Inventory;
 | 
			
		||||
@@ -62,9 +63,41 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
 | 
			
		||||
    public ObjectMessage getObject(InventoryVector vector) {
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT data, version FROM Inventory WHERE hash = " + vector);
 | 
			
		||||
            Blob data = rs.getBlob("data");
 | 
			
		||||
            return Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length());
 | 
			
		||||
            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());
 | 
			
		||||
            } 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) {
 | 
			
		||||
            LOG.error(e.getMessage(), e);
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
package ch.dissem.bitmessage.inventory;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.ObjectType;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
 | 
			
		||||
import ch.dissem.bitmessage.ports.Inventory;
 | 
			
		||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 | 
			
		||||
@@ -43,6 +44,11 @@ public class SimpleInventory implements Inventory {
 | 
			
		||||
        throw new NotImplementedException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<ObjectMessage> getObjects(long stream, long version, ObjectType type) {
 | 
			
		||||
        return new LinkedList<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void storeObject(ObjectMessage object) {
 | 
			
		||||
        throw new NotImplementedException();
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,7 @@ public class Connection implements Runnable {
 | 
			
		||||
                switch (state) {
 | 
			
		||||
                    case ACTIVE:
 | 
			
		||||
                        receiveMessage(msg.getPayload());
 | 
			
		||||
                        sendQueue();
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    default:
 | 
			
		||||
@@ -121,14 +122,19 @@ public class Connection implements Runnable {
 | 
			
		||||
                }
 | 
			
		||||
            } catch (SocketTimeoutException e) {
 | 
			
		||||
                if (state == ACTIVE) {
 | 
			
		||||
                    for (MessagePayload msg = sendingQueue.poll(); msg != null; msg = sendingQueue.poll()) {
 | 
			
		||||
                        send(msg);
 | 
			
		||||
                    }
 | 
			
		||||
                    sendQueue();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        switch (messagePayload.getCommand()) {
 | 
			
		||||
            case INV:
 | 
			
		||||
@@ -140,11 +146,10 @@ public class Connection implements Runnable {
 | 
			
		||||
                break;
 | 
			
		||||
            case GETDATA:
 | 
			
		||||
                GetData getData = (GetData) messagePayload;
 | 
			
		||||
//                for (InventoryVector iv : getData.getInventory()) {
 | 
			
		||||
//                    ObjectMessage om = ctx.getInventory().getObject(iv);
 | 
			
		||||
//                    sendingQueue.offer(om);
 | 
			
		||||
//                }
 | 
			
		||||
                LOG.error("Node requests data!!!! This shouldn't happen, the hash is done wrong!!!");
 | 
			
		||||
                for (InventoryVector iv : getData.getInventory()) {
 | 
			
		||||
                    ObjectMessage om = ctx.getInventory().getObject(iv);
 | 
			
		||||
                    if (om != null) sendingQueue.offer(om);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case OBJECT:
 | 
			
		||||
                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}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ package ch.dissem.bitmessage.networking;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.BitmessageContext;
 | 
			
		||||
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.ports.NetworkHandler;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
@@ -40,9 +40,9 @@ import static ch.dissem.bitmessage.networking.Connection.State.*;
 | 
			
		||||
 */
 | 
			
		||||
public class NetworkNode implements NetworkHandler, ContextHolder {
 | 
			
		||||
    private final static Logger LOG = LoggerFactory.getLogger(NetworkNode.class);
 | 
			
		||||
    private BitmessageContext ctx;
 | 
			
		||||
    private final ExecutorService pool;
 | 
			
		||||
    private final List<Connection> connections = new LinkedList<>();
 | 
			
		||||
    private BitmessageContext ctx;
 | 
			
		||||
    private ServerSocket serverSocket;
 | 
			
		||||
    private Thread connectionManager;
 | 
			
		||||
 | 
			
		||||
@@ -137,7 +137,15 @@ public class NetworkNode implements NetworkHandler, ContextHolder {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void send(final ObjectPayload payload) {
 | 
			
		||||
        // TODO: sendingQueue.add(message);
 | 
			
		||||
    public void offer(final InventoryVector iv) {
 | 
			
		||||
        // 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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user