forked from Qortal/qortal
Networking work-in-progress:
As per work done by szisti in PR#45: Extracted MessageException from inside Message into its own class. Extracted MessageType from inside Message into its own class. Converted reflection-based Message.fromByteBuffer method call to non-reflection, functional interface, method-reference. This should have minor performance improvement but stronger method signature and type enforcement, as well as better IDE integration. Message.fromByteBuffer method 'contract' tightened up to: 1. throw BufferUnderflowException if there are not enough bytes to deserialize message 2. throw MessageException if bytes contain invalid data 3. should not return null Message.toData method 'contract' tightened up to: 1. return null if the message has no payload to serialize 2. throw IOException directly - no need to try-catch in each subclass Several Message-subclass fields now marked 'final' as per IDE suggestion. Several Message-subclass fromByteBuffer() method signatures have changed 'throws' list. Several bytes.remaining() != some-value changed to bytes.remaining() < some-value as per new contract. Some bytes.remaining() checks removed for fixed-length messages because we can rely on ByteBuffer throwing BufferUnderflowException. Some bytes.remaining() checks retained for variable-length messages, or messages that read a large amount of data, to prevent wasted memory allocations. Other minor tidying up
This commit is contained in:
parent
44fc0f367d
commit
00996b047f
@ -33,7 +33,7 @@ import org.qortal.network.message.GetBlockSummariesMessage;
|
|||||||
import org.qortal.network.message.GetSignaturesV2Message;
|
import org.qortal.network.message.GetSignaturesV2Message;
|
||||||
import org.qortal.network.message.Message;
|
import org.qortal.network.message.Message;
|
||||||
import org.qortal.network.message.SignaturesMessage;
|
import org.qortal.network.message.SignaturesMessage;
|
||||||
import org.qortal.network.message.Message.MessageType;
|
import org.qortal.network.message.MessageType;
|
||||||
import org.qortal.repository.DataException;
|
import org.qortal.repository.DataException;
|
||||||
import org.qortal.repository.Repository;
|
import org.qortal.repository.Repository;
|
||||||
import org.qortal.repository.RepositoryManager;
|
import org.qortal.repository.RepositoryManager;
|
||||||
|
@ -7,7 +7,6 @@ import org.qortal.controller.Controller;
|
|||||||
import org.qortal.data.arbitrary.ArbitraryDirectConnectionInfo;
|
import org.qortal.data.arbitrary.ArbitraryDirectConnectionInfo;
|
||||||
import org.qortal.data.arbitrary.ArbitraryFileListResponseInfo;
|
import org.qortal.data.arbitrary.ArbitraryFileListResponseInfo;
|
||||||
import org.qortal.data.arbitrary.ArbitraryRelayInfo;
|
import org.qortal.data.arbitrary.ArbitraryRelayInfo;
|
||||||
import org.qortal.data.network.ArbitraryPeerData;
|
|
||||||
import org.qortal.data.network.PeerData;
|
import org.qortal.data.network.PeerData;
|
||||||
import org.qortal.data.transaction.ArbitraryTransactionData;
|
import org.qortal.data.transaction.ArbitraryTransactionData;
|
||||||
import org.qortal.network.Network;
|
import org.qortal.network.Network;
|
||||||
@ -210,7 +209,7 @@ public class ArbitraryDataFileManager extends Thread {
|
|||||||
LOGGER.debug("Received null message from peer {}", peer);
|
LOGGER.debug("Received null message from peer {}", peer);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (message.getType() != Message.MessageType.ARBITRARY_DATA_FILE) {
|
if (message.getType() != MessageType.ARBITRARY_DATA_FILE) {
|
||||||
LOGGER.debug("Received message with invalid type: {} from peer {}", message.getType(), peer);
|
LOGGER.debug("Received message with invalid type: {} from peer {}", message.getType(), peer);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import org.qortal.crypto.MemoryPoW;
|
|||||||
import org.qortal.network.message.ChallengeMessage;
|
import org.qortal.network.message.ChallengeMessage;
|
||||||
import org.qortal.network.message.HelloMessage;
|
import org.qortal.network.message.HelloMessage;
|
||||||
import org.qortal.network.message.Message;
|
import org.qortal.network.message.Message;
|
||||||
import org.qortal.network.message.Message.MessageType;
|
import org.qortal.network.message.MessageType;
|
||||||
import org.qortal.settings.Settings;
|
import org.qortal.settings.Settings;
|
||||||
import org.qortal.network.message.ResponseMessage;
|
import org.qortal.network.message.ResponseMessage;
|
||||||
import org.qortal.utils.DaemonThreadFactory;
|
import org.qortal.utils.DaemonThreadFactory;
|
||||||
|
@ -11,8 +11,8 @@ import org.qortal.data.network.PeerChainTipData;
|
|||||||
import org.qortal.data.network.PeerData;
|
import org.qortal.data.network.PeerData;
|
||||||
import org.qortal.network.message.ChallengeMessage;
|
import org.qortal.network.message.ChallengeMessage;
|
||||||
import org.qortal.network.message.Message;
|
import org.qortal.network.message.Message;
|
||||||
import org.qortal.network.message.Message.MessageException;
|
import org.qortal.network.message.MessageException;
|
||||||
import org.qortal.network.message.Message.MessageType;
|
import org.qortal.network.message.MessageType;
|
||||||
import org.qortal.network.message.PingMessage;
|
import org.qortal.network.message.PingMessage;
|
||||||
import org.qortal.settings.Settings;
|
import org.qortal.settings.Settings;
|
||||||
import org.qortal.utils.ExecuteProduceConsume;
|
import org.qortal.utils.ExecuteProduceConsume;
|
||||||
|
@ -9,17 +9,12 @@ import org.qortal.utils.Serialization;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ArbitraryDataFileListMessage extends Message {
|
public class ArbitraryDataFileListMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
|
||||||
private static final int HASH_LENGTH = Transformer.SHA256_LENGTH;
|
|
||||||
private static final int MAX_PEER_ADDRESS_LENGTH = PeerData.MAX_PEER_ADDRESS_SIZE;
|
|
||||||
|
|
||||||
private final byte[] signature;
|
private final byte[] signature;
|
||||||
private final List<byte[]> hashes;
|
private final List<byte[]> hashes;
|
||||||
private Long requestTime;
|
private Long requestTime;
|
||||||
@ -60,16 +55,15 @@ public class ArbitraryDataFileListMessage extends Message {
|
|||||||
return this.signature;
|
return this.signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException, TransformationException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws MessageException {
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
|
|
||||||
int count = bytes.getInt();
|
int count = bytes.getInt();
|
||||||
|
|
||||||
List<byte[]> hashes = new ArrayList<>();
|
List<byte[]> hashes = new ArrayList<>();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
|
byte[] hash = new byte[Transformer.SHA256_LENGTH];
|
||||||
byte[] hash = new byte[HASH_LENGTH];
|
|
||||||
bytes.get(hash);
|
bytes.get(hash);
|
||||||
hashes.add(hash);
|
hashes.add(hash);
|
||||||
}
|
}
|
||||||
@ -82,51 +76,49 @@ public class ArbitraryDataFileListMessage extends Message {
|
|||||||
// The remaining fields are optional
|
// The remaining fields are optional
|
||||||
|
|
||||||
if (bytes.hasRemaining()) {
|
if (bytes.hasRemaining()) {
|
||||||
|
try {
|
||||||
|
requestTime = bytes.getLong();
|
||||||
|
|
||||||
requestTime = bytes.getLong();
|
requestHops = bytes.getInt();
|
||||||
|
|
||||||
requestHops = bytes.getInt();
|
peerAddress = Serialization.deserializeSizedStringV2(bytes, PeerData.MAX_PEER_ADDRESS_SIZE);
|
||||||
|
|
||||||
peerAddress = Serialization.deserializeSizedStringV2(bytes, MAX_PEER_ADDRESS_LENGTH);
|
|
||||||
|
|
||||||
isRelayPossible = bytes.getInt() > 0;
|
|
||||||
|
|
||||||
|
isRelayPossible = bytes.getInt() > 0;
|
||||||
|
} catch (TransformationException e) {
|
||||||
|
throw new MessageException(e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ArbitraryDataFileListMessage(id, signature, hashes, requestTime, requestHops, peerAddress, isRelayPossible);
|
return new ArbitraryDataFileListMessage(id, signature, hashes, requestTime, requestHops, peerAddress, isRelayPossible);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.hashes.size()));
|
bytes.write(Ints.toByteArray(this.hashes.size()));
|
||||||
|
|
||||||
for (byte[] hash : this.hashes) {
|
for (byte[] hash : this.hashes) {
|
||||||
bytes.write(hash);
|
bytes.write(hash);
|
||||||
}
|
|
||||||
|
|
||||||
if (this.requestTime == null) { // To maintain backwards support
|
|
||||||
return bytes.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The remaining fields are optional
|
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(this.requestTime));
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.requestHops));
|
|
||||||
|
|
||||||
Serialization.serializeSizedStringV2(bytes, this.peerAddress);
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.isRelayPossible ? 1 : 0));
|
|
||||||
|
|
||||||
return bytes.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.requestTime == null) { // To maintain backwards support
|
||||||
|
return bytes.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The remaining fields are optional
|
||||||
|
|
||||||
|
bytes.write(Longs.toByteArray(this.requestTime));
|
||||||
|
|
||||||
|
bytes.write(Ints.toByteArray(this.requestHops));
|
||||||
|
|
||||||
|
Serialization.serializeSizedStringV2(bytes, this.peerAddress);
|
||||||
|
|
||||||
|
bytes.write(Ints.toByteArray(this.isRelayPossible ? 1 : 0));
|
||||||
|
|
||||||
|
return bytes.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArbitraryDataFileListMessage cloneWithNewId(int newId) {
|
public ArbitraryDataFileListMessage cloneWithNewId(int newId) {
|
||||||
|
@ -9,15 +9,13 @@ import org.qortal.transform.Transformer;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class ArbitraryDataFileMessage extends Message {
|
public class ArbitraryDataFileMessage extends Message {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(ArbitraryDataFileMessage.class);
|
private static final Logger LOGGER = LogManager.getLogger(ArbitraryDataFileMessage.class);
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
|
||||||
|
|
||||||
private final byte[] signature;
|
private final byte[] signature;
|
||||||
private final ArbitraryDataFile arbitraryDataFile;
|
private final ArbitraryDataFile arbitraryDataFile;
|
||||||
|
|
||||||
@ -39,14 +37,14 @@ public class ArbitraryDataFileMessage extends Message {
|
|||||||
return this.arbitraryDataFile;
|
return this.arbitraryDataFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
byteBuffer.get(signature);
|
byteBuffer.get(signature);
|
||||||
|
|
||||||
int dataLength = byteBuffer.getInt();
|
int dataLength = byteBuffer.getInt();
|
||||||
|
|
||||||
if (byteBuffer.remaining() != dataLength)
|
if (byteBuffer.remaining() < dataLength)
|
||||||
return null;
|
throw new BufferUnderflowException();
|
||||||
|
|
||||||
byte[] data = new byte[dataLength];
|
byte[] data = new byte[dataLength];
|
||||||
byteBuffer.get(data);
|
byteBuffer.get(data);
|
||||||
@ -54,15 +52,14 @@ public class ArbitraryDataFileMessage extends Message {
|
|||||||
try {
|
try {
|
||||||
ArbitraryDataFile arbitraryDataFile = new ArbitraryDataFile(data, signature);
|
ArbitraryDataFile arbitraryDataFile = new ArbitraryDataFile(data, signature);
|
||||||
return new ArbitraryDataFileMessage(id, signature, arbitraryDataFile);
|
return new ArbitraryDataFileMessage(id, signature, arbitraryDataFile);
|
||||||
}
|
} catch (DataException e) {
|
||||||
catch (DataException e) {
|
|
||||||
LOGGER.info("Unable to process received file: {}", e.getMessage());
|
LOGGER.info("Unable to process received file: {}", e.getMessage());
|
||||||
return null;
|
throw new MessageException("Unable to process received file: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
if (this.arbitraryDataFile == null) {
|
if (this.arbitraryDataFile == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -72,19 +69,15 @@ public class ArbitraryDataFileMessage extends Message {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(signature);
|
bytes.write(signature);
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(data.length));
|
bytes.write(Ints.toByteArray(data.length));
|
||||||
|
|
||||||
bytes.write(data);
|
bytes.write(data);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArbitraryDataFileMessage cloneWithNewId(int newId) {
|
public ArbitraryDataFileMessage cloneWithNewId(int newId) {
|
||||||
|
@ -2,7 +2,7 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.transform.Transformer;
|
import org.qortal.transform.Transformer;
|
||||||
@ -11,10 +11,8 @@ import com.google.common.primitives.Ints;
|
|||||||
|
|
||||||
public class ArbitraryDataMessage extends Message {
|
public class ArbitraryDataMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
private final byte[] signature;
|
||||||
|
private final byte[] data;
|
||||||
private byte[] signature;
|
|
||||||
private byte[] data;
|
|
||||||
|
|
||||||
public ArbitraryDataMessage(byte[] signature, byte[] data) {
|
public ArbitraryDataMessage(byte[] signature, byte[] data) {
|
||||||
this(-1, signature, data);
|
this(-1, signature, data);
|
||||||
@ -35,14 +33,14 @@ public class ArbitraryDataMessage extends Message {
|
|||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) {
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
byteBuffer.get(signature);
|
byteBuffer.get(signature);
|
||||||
|
|
||||||
int dataLength = byteBuffer.getInt();
|
int dataLength = byteBuffer.getInt();
|
||||||
|
|
||||||
if (byteBuffer.remaining() != dataLength)
|
if (byteBuffer.remaining() < dataLength)
|
||||||
return null;
|
throw new BufferUnderflowException();
|
||||||
|
|
||||||
byte[] data = new byte[dataLength];
|
byte[] data = new byte[dataLength];
|
||||||
byteBuffer.get(data);
|
byteBuffer.get(data);
|
||||||
@ -51,23 +49,19 @@ public class ArbitraryDataMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
if (this.data == null)
|
if (this.data == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.data.length));
|
bytes.write(Ints.toByteArray(this.data.length));
|
||||||
|
|
||||||
bytes.write(this.data);
|
bytes.write(this.data);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,11 @@ import org.qortal.transform.Transformer;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class ArbitraryMetadataMessage extends Message {
|
public class ArbitraryMetadataMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
|
||||||
|
|
||||||
private final byte[] signature;
|
private final byte[] signature;
|
||||||
private final ArbitraryDataFile arbitraryMetadataFile;
|
private final ArbitraryDataFile arbitraryMetadataFile;
|
||||||
|
|
||||||
@ -39,14 +37,14 @@ public class ArbitraryMetadataMessage extends Message {
|
|||||||
return this.arbitraryMetadataFile;
|
return this.arbitraryMetadataFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
byteBuffer.get(signature);
|
byteBuffer.get(signature);
|
||||||
|
|
||||||
int dataLength = byteBuffer.getInt();
|
int dataLength = byteBuffer.getInt();
|
||||||
|
|
||||||
if (byteBuffer.remaining() != dataLength)
|
if (byteBuffer.remaining() < dataLength)
|
||||||
return null;
|
throw new BufferUnderflowException();
|
||||||
|
|
||||||
byte[] data = new byte[dataLength];
|
byte[] data = new byte[dataLength];
|
||||||
byteBuffer.get(data);
|
byteBuffer.get(data);
|
||||||
@ -54,14 +52,13 @@ public class ArbitraryMetadataMessage extends Message {
|
|||||||
try {
|
try {
|
||||||
ArbitraryDataFile arbitraryMetadataFile = new ArbitraryDataFile(data, signature);
|
ArbitraryDataFile arbitraryMetadataFile = new ArbitraryDataFile(data, signature);
|
||||||
return new ArbitraryMetadataMessage(id, signature, arbitraryMetadataFile);
|
return new ArbitraryMetadataMessage(id, signature, arbitraryMetadataFile);
|
||||||
}
|
} catch (DataException e) {
|
||||||
catch (DataException e) {
|
throw new MessageException("Unable to process arbitrary metadata message: " + e.getMessage(), e);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
if (this.arbitraryMetadataFile == null) {
|
if (this.arbitraryMetadataFile == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -71,19 +68,15 @@ public class ArbitraryMetadataMessage extends Message {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(signature);
|
bytes.write(signature);
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(data.length));
|
bytes.write(Ints.toByteArray(data.length));
|
||||||
|
|
||||||
bytes.write(data);
|
bytes.write(data);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArbitraryMetadataMessage cloneWithNewId(int newId) {
|
public ArbitraryMetadataMessage cloneWithNewId(int newId) {
|
||||||
|
@ -8,15 +8,13 @@ import org.qortal.utils.Serialization;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ArbitrarySignaturesMessage extends Message {
|
public class ArbitrarySignaturesMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
|
||||||
|
|
||||||
private String peerAddress;
|
private String peerAddress;
|
||||||
private int requestHops;
|
private int requestHops;
|
||||||
private List<byte[]> signatures;
|
private List<byte[]> signatures;
|
||||||
@ -49,19 +47,24 @@ public class ArbitrarySignaturesMessage extends Message {
|
|||||||
this.requestHops = requestHops;
|
this.requestHops = requestHops;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException, TransformationException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws MessageException {
|
||||||
String peerAddress = Serialization.deserializeSizedStringV2(bytes, PeerData.MAX_PEER_ADDRESS_SIZE);
|
String peerAddress;
|
||||||
|
try {
|
||||||
|
peerAddress = Serialization.deserializeSizedStringV2(bytes, PeerData.MAX_PEER_ADDRESS_SIZE);
|
||||||
|
} catch (TransformationException e) {
|
||||||
|
throw new MessageException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
int requestHops = bytes.getInt();
|
int requestHops = bytes.getInt();
|
||||||
|
|
||||||
int signatureCount = bytes.getInt();
|
int signatureCount = bytes.getInt();
|
||||||
|
|
||||||
if (bytes.remaining() != signatureCount * SIGNATURE_LENGTH)
|
if (bytes.remaining() < signatureCount * Transformer.SIGNATURE_LENGTH)
|
||||||
return null;
|
throw new BufferUnderflowException();
|
||||||
|
|
||||||
List<byte[]> signatures = new ArrayList<>();
|
List<byte[]> signatures = new ArrayList<>();
|
||||||
for (int i = 0; i < signatureCount; ++i) {
|
for (int i = 0; i < signatureCount; ++i) {
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
signatures.add(signature);
|
signatures.add(signature);
|
||||||
}
|
}
|
||||||
@ -70,23 +73,19 @@ public class ArbitrarySignaturesMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
Serialization.serializeSizedStringV2(bytes, this.peerAddress);
|
Serialization.serializeSizedStringV2(bytes, this.peerAddress);
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.requestHops));
|
bytes.write(Ints.toByteArray(this.requestHops));
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.signatures.size()));
|
bytes.write(Ints.toByteArray(this.signatures.size()));
|
||||||
|
|
||||||
for (byte[] signature : this.signatures)
|
for (byte[] signature : this.signatures)
|
||||||
bytes.write(signature);
|
bytes.write(signature);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ public class BlockMessage extends Message {
|
|||||||
private List<TransactionData> transactions = null;
|
private List<TransactionData> transactions = null;
|
||||||
private List<ATStateData> atStates = null;
|
private List<ATStateData> atStates = null;
|
||||||
|
|
||||||
private int height;
|
private final int height;
|
||||||
|
|
||||||
public BlockMessage(Block block) {
|
public BlockMessage(Block block) {
|
||||||
super(MessageType.BLOCK);
|
super(MessageType.BLOCK);
|
||||||
@ -60,7 +59,7 @@ public class BlockMessage extends Message {
|
|||||||
return this.atStates;
|
return this.atStates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
||||||
try {
|
try {
|
||||||
int height = byteBuffer.getInt();
|
int height = byteBuffer.getInt();
|
||||||
|
|
||||||
@ -72,26 +71,22 @@ public class BlockMessage extends Message {
|
|||||||
return new BlockMessage(id, blockData, blockInfo.getB(), blockInfo.getC());
|
return new BlockMessage(id, blockData, blockInfo.getB(), blockInfo.getC());
|
||||||
} catch (TransformationException e) {
|
} catch (TransformationException e) {
|
||||||
LOGGER.info(String.format("Received garbled BLOCK message: %s", e.getMessage()));
|
LOGGER.info(String.format("Received garbled BLOCK message: %s", e.getMessage()));
|
||||||
return null;
|
throw new MessageException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException, TransformationException {
|
||||||
if (this.block == null)
|
if (this.block == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.height));
|
bytes.write(Ints.toByteArray(this.height));
|
||||||
|
|
||||||
bytes.write(BlockTransformer.toBytes(this.block));
|
bytes.write(BlockTransformer.toBytes(this.block));
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (TransformationException | IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockMessage cloneWithNewId(int newId) {
|
public BlockMessage cloneWithNewId(int newId) {
|
||||||
|
@ -2,7 +2,7 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -17,7 +17,7 @@ public class BlockSummariesMessage extends Message {
|
|||||||
|
|
||||||
private static final int BLOCK_SUMMARY_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH + Transformer.INT_LENGTH + Transformer.PUBLIC_KEY_LENGTH + Transformer.INT_LENGTH;
|
private static final int BLOCK_SUMMARY_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH + Transformer.INT_LENGTH + Transformer.PUBLIC_KEY_LENGTH + Transformer.INT_LENGTH;
|
||||||
|
|
||||||
private List<BlockSummaryData> blockSummaries;
|
private final List<BlockSummaryData> blockSummaries;
|
||||||
|
|
||||||
public BlockSummariesMessage(List<BlockSummaryData> blockSummaries) {
|
public BlockSummariesMessage(List<BlockSummaryData> blockSummaries) {
|
||||||
this(-1, blockSummaries);
|
this(-1, blockSummaries);
|
||||||
@ -33,11 +33,11 @@ public class BlockSummariesMessage extends Message {
|
|||||||
return this.blockSummaries;
|
return this.blockSummaries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
int count = bytes.getInt();
|
int count = bytes.getInt();
|
||||||
|
|
||||||
if (bytes.remaining() != count * BLOCK_SUMMARY_LENGTH)
|
if (bytes.remaining() < count * BLOCK_SUMMARY_LENGTH)
|
||||||
return null;
|
throw new BufferUnderflowException();
|
||||||
|
|
||||||
List<BlockSummaryData> blockSummaries = new ArrayList<>();
|
List<BlockSummaryData> blockSummaries = new ArrayList<>();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
@ -59,23 +59,19 @@ public class BlockSummariesMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.blockSummaries.size()));
|
bytes.write(Ints.toByteArray(this.blockSummaries.size()));
|
||||||
|
|
||||||
for (BlockSummaryData blockSummary : this.blockSummaries) {
|
for (BlockSummaryData blockSummary : this.blockSummaries) {
|
||||||
bytes.write(Ints.toByteArray(blockSummary.getHeight()));
|
bytes.write(Ints.toByteArray(blockSummary.getHeight()));
|
||||||
bytes.write(blockSummary.getSignature());
|
bytes.write(blockSummary.getSignature());
|
||||||
bytes.write(blockSummary.getMinterPublicKey());
|
bytes.write(blockSummary.getMinterPublicKey());
|
||||||
bytes.write(Ints.toByteArray(blockSummary.getOnlineAccountsCount()));
|
bytes.write(Ints.toByteArray(blockSummary.getOnlineAccountsCount()));
|
||||||
}
|
|
||||||
|
|
||||||
return bytes.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bytes.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.block.Block;
|
import org.qortal.block.Block;
|
||||||
@ -14,7 +13,7 @@ import com.google.common.primitives.Ints;
|
|||||||
// This is an OUTGOING-only Message which more readily lends itself to being cached
|
// This is an OUTGOING-only Message which more readily lends itself to being cached
|
||||||
public class CachedBlockMessage extends Message {
|
public class CachedBlockMessage extends Message {
|
||||||
|
|
||||||
private Block block = null;
|
private Block block;
|
||||||
private byte[] cachedBytes = null;
|
private byte[] cachedBytes = null;
|
||||||
|
|
||||||
public CachedBlockMessage(Block block) {
|
public CachedBlockMessage(Block block) {
|
||||||
@ -30,12 +29,12 @@ public class CachedBlockMessage extends Message {
|
|||||||
this.cachedBytes = cachedBytes;
|
this.cachedBytes = cachedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) {
|
||||||
throw new UnsupportedOperationException("CachedBlockMessage is for outgoing messages only");
|
throw new UnsupportedOperationException("CachedBlockMessage is for outgoing messages only");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException, TransformationException {
|
||||||
// Already serialized?
|
// Already serialized?
|
||||||
if (this.cachedBytes != null)
|
if (this.cachedBytes != null)
|
||||||
return cachedBytes;
|
return cachedBytes;
|
||||||
@ -43,22 +42,18 @@ public class CachedBlockMessage extends Message {
|
|||||||
if (this.block == null)
|
if (this.block == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.block.getBlockData().getHeight()));
|
bytes.write(Ints.toByteArray(this.block.getBlockData().getHeight()));
|
||||||
|
|
||||||
bytes.write(BlockTransformer.toBytes(this.block));
|
bytes.write(BlockTransformer.toBytes(this.block));
|
||||||
|
|
||||||
this.cachedBytes = bytes.toByteArray();
|
this.cachedBytes = bytes.toByteArray();
|
||||||
// We no longer need source Block
|
// We no longer need source Block
|
||||||
// and Block contains repository handle which is highly likely to be invalid after this call
|
// and Block contains repository handle which is highly likely to be invalid after this call
|
||||||
this.block = null;
|
this.block = null;
|
||||||
|
|
||||||
return this.cachedBytes;
|
return this.cachedBytes;
|
||||||
} catch (TransformationException | IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedBlockMessage cloneWithNewId(int newId) {
|
public CachedBlockMessage cloneWithNewId(int newId) {
|
||||||
|
@ -5,25 +5,16 @@ import com.google.common.primitives.Longs;
|
|||||||
import org.qortal.data.network.PeerData;
|
import org.qortal.data.network.PeerData;
|
||||||
import org.qortal.transform.TransformationException;
|
import org.qortal.transform.TransformationException;
|
||||||
import org.qortal.transform.Transformer;
|
import org.qortal.transform.Transformer;
|
||||||
import org.qortal.transform.transaction.TransactionTransformer;
|
|
||||||
import org.qortal.utils.Serialization;
|
import org.qortal.utils.Serialization;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.qortal.transform.Transformer.INT_LENGTH;
|
|
||||||
import static org.qortal.transform.Transformer.LONG_LENGTH;
|
|
||||||
|
|
||||||
public class GetArbitraryDataFileListMessage extends Message {
|
public class GetArbitraryDataFileListMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
|
||||||
private static final int HASH_LENGTH = TransactionTransformer.SHA256_LENGTH;
|
|
||||||
private static final int MAX_PEER_ADDRESS_LENGTH = PeerData.MAX_PEER_ADDRESS_SIZE;
|
|
||||||
|
|
||||||
private final byte[] signature;
|
private final byte[] signature;
|
||||||
private List<byte[]> hashes;
|
private List<byte[]> hashes;
|
||||||
private final long requestTime;
|
private final long requestTime;
|
||||||
@ -52,8 +43,8 @@ public class GetArbitraryDataFileListMessage extends Message {
|
|||||||
return this.hashes;
|
return this.hashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException, TransformationException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws MessageException {
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
|
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
|
|
||||||
@ -67,7 +58,7 @@ public class GetArbitraryDataFileListMessage extends Message {
|
|||||||
|
|
||||||
hashes = new ArrayList<>();
|
hashes = new ArrayList<>();
|
||||||
for (int i = 0; i < hashCount; ++i) {
|
for (int i = 0; i < hashCount; ++i) {
|
||||||
byte[] hash = new byte[HASH_LENGTH];
|
byte[] hash = new byte[Transformer.SHA256_LENGTH];
|
||||||
bytes.get(hash);
|
bytes.get(hash);
|
||||||
hashes.add(hash);
|
hashes.add(hash);
|
||||||
}
|
}
|
||||||
@ -75,42 +66,42 @@ public class GetArbitraryDataFileListMessage extends Message {
|
|||||||
|
|
||||||
String requestingPeer = null;
|
String requestingPeer = null;
|
||||||
if (bytes.hasRemaining()) {
|
if (bytes.hasRemaining()) {
|
||||||
requestingPeer = Serialization.deserializeSizedStringV2(bytes, MAX_PEER_ADDRESS_LENGTH);
|
try {
|
||||||
|
requestingPeer = Serialization.deserializeSizedStringV2(bytes, PeerData.MAX_PEER_ADDRESS_SIZE);
|
||||||
|
} catch (TransformationException e) {
|
||||||
|
throw new MessageException(e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GetArbitraryDataFileListMessage(id, signature, hashes, requestTime, requestHops, requestingPeer);
|
return new GetArbitraryDataFileListMessage(id, signature, hashes, requestTime, requestHops, requestingPeer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(this.requestTime));
|
bytes.write(Longs.toByteArray(this.requestTime));
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.requestHops));
|
bytes.write(Ints.toByteArray(this.requestHops));
|
||||||
|
|
||||||
if (this.hashes != null) {
|
if (this.hashes != null) {
|
||||||
bytes.write(Ints.toByteArray(this.hashes.size()));
|
bytes.write(Ints.toByteArray(this.hashes.size()));
|
||||||
|
|
||||||
for (byte[] hash : this.hashes) {
|
for (byte[] hash : this.hashes) {
|
||||||
bytes.write(hash);
|
bytes.write(hash);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
bytes.write(Ints.toByteArray(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.requestingPeer != null) {
|
|
||||||
Serialization.serializeSizedStringV2(bytes, this.requestingPeer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
bytes.write(Ints.toByteArray(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.requestingPeer != null) {
|
||||||
|
Serialization.serializeSizedStringV2(bytes, this.requestingPeer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRequestTime() {
|
public long getRequestTime() {
|
||||||
|
@ -1,18 +1,13 @@
|
|||||||
package org.qortal.network.message;
|
package org.qortal.network.message;
|
||||||
|
|
||||||
import org.qortal.transform.Transformer;
|
import org.qortal.transform.Transformer;
|
||||||
import org.qortal.transform.transaction.TransactionTransformer;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class GetArbitraryDataFileMessage extends Message {
|
public class GetArbitraryDataFileMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
|
||||||
private static final int HASH_LENGTH = TransactionTransformer.SHA256_LENGTH;
|
|
||||||
|
|
||||||
private final byte[] signature;
|
private final byte[] signature;
|
||||||
private final byte[] hash;
|
private final byte[] hash;
|
||||||
|
|
||||||
@ -35,32 +30,25 @@ public class GetArbitraryDataFileMessage extends Message {
|
|||||||
return this.hash;
|
return this.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
if (bytes.remaining() != HASH_LENGTH + SIGNATURE_LENGTH)
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
|
|
||||||
byte[] hash = new byte[HASH_LENGTH];
|
byte[] hash = new byte[Transformer.SHA256_LENGTH];
|
||||||
bytes.get(hash);
|
bytes.get(hash);
|
||||||
|
|
||||||
return new GetArbitraryDataFileMessage(id, signature, hash);
|
return new GetArbitraryDataFileMessage(id, signature, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
bytes.write(this.hash);
|
bytes.write(this.hash);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,13 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.transform.Transformer;
|
import org.qortal.transform.Transformer;
|
||||||
|
|
||||||
public class GetArbitraryDataMessage extends Message {
|
public class GetArbitraryDataMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
private final byte[] signature;
|
||||||
|
|
||||||
private byte[] signature;
|
|
||||||
|
|
||||||
public GetArbitraryDataMessage(byte[] signature) {
|
public GetArbitraryDataMessage(byte[] signature) {
|
||||||
this(-1, signature);
|
this(-1, signature);
|
||||||
@ -27,11 +24,8 @@ public class GetArbitraryDataMessage extends Message {
|
|||||||
return this.signature;
|
return this.signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
if (bytes.remaining() != SIGNATURE_LENGTH)
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
|
||||||
|
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
|
|
||||||
@ -39,16 +33,12 @@ public class GetArbitraryDataMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,10 @@ import org.qortal.transform.Transformer;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import static org.qortal.transform.Transformer.INT_LENGTH;
|
|
||||||
import static org.qortal.transform.Transformer.LONG_LENGTH;
|
|
||||||
|
|
||||||
public class GetArbitraryMetadataMessage extends Message {
|
public class GetArbitraryMetadataMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
|
||||||
|
|
||||||
private final byte[] signature;
|
private final byte[] signature;
|
||||||
private final long requestTime;
|
private final long requestTime;
|
||||||
private int requestHops;
|
private int requestHops;
|
||||||
@ -36,12 +30,8 @@ public class GetArbitraryMetadataMessage extends Message {
|
|||||||
return this.signature;
|
return this.signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
if (bytes.remaining() != SIGNATURE_LENGTH + LONG_LENGTH + INT_LENGTH)
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
|
||||||
|
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
|
|
||||||
long requestTime = bytes.getLong();
|
long requestTime = bytes.getLong();
|
||||||
@ -52,20 +42,16 @@ public class GetArbitraryMetadataMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(this.requestTime));
|
bytes.write(Longs.toByteArray(this.requestTime));
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.requestHops));
|
bytes.write(Ints.toByteArray(this.requestHops));
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRequestTime() {
|
public long getRequestTime() {
|
||||||
|
@ -2,16 +2,13 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.transform.block.BlockTransformer;
|
import org.qortal.transform.block.BlockTransformer;
|
||||||
|
|
||||||
public class GetBlockMessage extends Message {
|
public class GetBlockMessage extends Message {
|
||||||
|
|
||||||
private static final int BLOCK_SIGNATURE_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH;
|
private final byte[] signature;
|
||||||
|
|
||||||
private byte[] signature;
|
|
||||||
|
|
||||||
public GetBlockMessage(byte[] signature) {
|
public GetBlockMessage(byte[] signature) {
|
||||||
this(-1, signature);
|
this(-1, signature);
|
||||||
@ -27,28 +24,20 @@ public class GetBlockMessage extends Message {
|
|||||||
return this.signature;
|
return this.signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
if (bytes.remaining() != BLOCK_SIGNATURE_LENGTH)
|
byte[] signature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH];
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] signature = new byte[BLOCK_SIGNATURE_LENGTH];
|
|
||||||
|
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
|
|
||||||
return new GetBlockMessage(id, signature);
|
return new GetBlockMessage(id, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,16 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.transform.Transformer;
|
|
||||||
import org.qortal.transform.block.BlockTransformer;
|
import org.qortal.transform.block.BlockTransformer;
|
||||||
|
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
|
||||||
public class GetBlockSummariesMessage extends Message {
|
public class GetBlockSummariesMessage extends Message {
|
||||||
|
|
||||||
private static final int BLOCK_SIGNATURE_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH;
|
private final byte[] parentSignature;
|
||||||
|
private final int numberRequested;
|
||||||
private byte[] parentSignature;
|
|
||||||
private int numberRequested;
|
|
||||||
|
|
||||||
public GetBlockSummariesMessage(byte[] parentSignature, int numberRequested) {
|
public GetBlockSummariesMessage(byte[] parentSignature, int numberRequested) {
|
||||||
this(-1, parentSignature, numberRequested);
|
this(-1, parentSignature, numberRequested);
|
||||||
@ -36,11 +32,8 @@ public class GetBlockSummariesMessage extends Message {
|
|||||||
return this.numberRequested;
|
return this.numberRequested;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
if (bytes.remaining() != BLOCK_SIGNATURE_LENGTH + Transformer.INT_LENGTH)
|
byte[] parentSignature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH];
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] parentSignature = new byte[BLOCK_SIGNATURE_LENGTH];
|
|
||||||
bytes.get(parentSignature);
|
bytes.get(parentSignature);
|
||||||
|
|
||||||
int numberRequested = bytes.getInt();
|
int numberRequested = bytes.getInt();
|
||||||
@ -49,18 +42,14 @@ public class GetBlockSummariesMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.parentSignature);
|
bytes.write(this.parentSignature);
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.numberRequested));
|
bytes.write(Ints.toByteArray(this.numberRequested));
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -17,7 +16,7 @@ import com.google.common.primitives.Longs;
|
|||||||
public class GetOnlineAccountsMessage extends Message {
|
public class GetOnlineAccountsMessage extends Message {
|
||||||
private static final int MAX_ACCOUNT_COUNT = 5000;
|
private static final int MAX_ACCOUNT_COUNT = 5000;
|
||||||
|
|
||||||
private List<OnlineAccountData> onlineAccounts;
|
private final List<OnlineAccountData> onlineAccounts;
|
||||||
|
|
||||||
public GetOnlineAccountsMessage(List<OnlineAccountData> onlineAccounts) {
|
public GetOnlineAccountsMessage(List<OnlineAccountData> onlineAccounts) {
|
||||||
this(-1, onlineAccounts);
|
this(-1, onlineAccounts);
|
||||||
@ -33,7 +32,7 @@ public class GetOnlineAccountsMessage extends Message {
|
|||||||
return this.onlineAccounts;
|
return this.onlineAccounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
final int accountCount = bytes.getInt();
|
final int accountCount = bytes.getInt();
|
||||||
|
|
||||||
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount);
|
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount);
|
||||||
@ -51,23 +50,18 @@ public class GetOnlineAccountsMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.onlineAccounts.size()));
|
bytes.write(Ints.toByteArray(this.onlineAccounts.size()));
|
||||||
|
|
||||||
for (int i = 0; i < this.onlineAccounts.size(); ++i) {
|
for (OnlineAccountData onlineAccountData : this.onlineAccounts) {
|
||||||
OnlineAccountData onlineAccountData = this.onlineAccounts.get(i);
|
bytes.write(Longs.toByteArray(onlineAccountData.getTimestamp()));
|
||||||
bytes.write(Longs.toByteArray(onlineAccountData.getTimestamp()));
|
|
||||||
|
|
||||||
bytes.write(onlineAccountData.getPublicKey());
|
bytes.write(onlineAccountData.getPublicKey());
|
||||||
}
|
|
||||||
|
|
||||||
return bytes.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bytes.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import org.qortal.transform.Transformer;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -24,7 +23,7 @@ import java.util.Map;
|
|||||||
* Also V2 only builds online accounts message once!
|
* Also V2 only builds online accounts message once!
|
||||||
*/
|
*/
|
||||||
public class GetOnlineAccountsV2Message extends Message {
|
public class GetOnlineAccountsV2Message extends Message {
|
||||||
private List<OnlineAccountData> onlineAccounts;
|
private final List<OnlineAccountData> onlineAccounts;
|
||||||
private byte[] cachedData;
|
private byte[] cachedData;
|
||||||
|
|
||||||
public GetOnlineAccountsV2Message(List<OnlineAccountData> onlineAccounts) {
|
public GetOnlineAccountsV2Message(List<OnlineAccountData> onlineAccounts) {
|
||||||
@ -41,7 +40,7 @@ public class GetOnlineAccountsV2Message extends Message {
|
|||||||
return this.onlineAccounts;
|
return this.onlineAccounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
int accountCount = bytes.getInt();
|
int accountCount = bytes.getInt();
|
||||||
|
|
||||||
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount);
|
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount);
|
||||||
@ -68,7 +67,7 @@ public class GetOnlineAccountsV2Message extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected synchronized byte[] toData() {
|
protected synchronized byte[] toData() throws IOException {
|
||||||
if (this.cachedData != null)
|
if (this.cachedData != null)
|
||||||
return this.cachedData;
|
return this.cachedData;
|
||||||
|
|
||||||
@ -81,8 +80,7 @@ public class GetOnlineAccountsV2Message extends Message {
|
|||||||
// How many of each timestamp
|
// How many of each timestamp
|
||||||
Map<Long, Integer> countByTimestamp = new HashMap<>();
|
Map<Long, Integer> countByTimestamp = new HashMap<>();
|
||||||
|
|
||||||
for (int i = 0; i < this.onlineAccounts.size(); ++i) {
|
for (OnlineAccountData onlineAccountData : this.onlineAccounts) {
|
||||||
OnlineAccountData onlineAccountData = this.onlineAccounts.get(i);
|
|
||||||
Long timestamp = onlineAccountData.getTimestamp();
|
Long timestamp = onlineAccountData.getTimestamp();
|
||||||
countByTimestamp.compute(timestamp, (k, v) -> v == null ? 1 : ++v);
|
countByTimestamp.compute(timestamp, (k, v) -> v == null ? 1 : ++v);
|
||||||
}
|
}
|
||||||
@ -91,27 +89,21 @@ public class GetOnlineAccountsV2Message extends Message {
|
|||||||
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH)
|
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH)
|
||||||
+ this.onlineAccounts.size() * Transformer.PUBLIC_KEY_LENGTH;
|
+ this.onlineAccounts.size() * Transformer.PUBLIC_KEY_LENGTH;
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize);
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize);
|
|
||||||
|
|
||||||
for (long timestamp : countByTimestamp.keySet()) {
|
for (long timestamp : countByTimestamp.keySet()) {
|
||||||
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp)));
|
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp)));
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(timestamp));
|
bytes.write(Longs.toByteArray(timestamp));
|
||||||
|
|
||||||
for (int i = 0; i < this.onlineAccounts.size(); ++i) {
|
for (OnlineAccountData onlineAccountData : this.onlineAccounts) {
|
||||||
OnlineAccountData onlineAccountData = this.onlineAccounts.get(i);
|
if (onlineAccountData.getTimestamp() == timestamp)
|
||||||
|
bytes.write(onlineAccountData.getPublicKey());
|
||||||
if (onlineAccountData.getTimestamp() == timestamp)
|
|
||||||
bytes.write(onlineAccountData.getPublicKey());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cachedData = bytes.toByteArray();
|
|
||||||
return this.cachedData;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cachedData = bytes.toByteArray();
|
||||||
|
return this.cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.qortal.network.message;
|
package org.qortal.network.message;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class GetPeersMessage extends Message {
|
public class GetPeersMessage extends Message {
|
||||||
@ -13,7 +12,7 @@ public class GetPeersMessage extends Message {
|
|||||||
super(id, MessageType.GET_PEERS);
|
super(id, MessageType.GET_PEERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
return new GetPeersMessage(id);
|
return new GetPeersMessage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,21 +2,16 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.transform.Transformer;
|
|
||||||
import org.qortal.transform.block.BlockTransformer;
|
import org.qortal.transform.block.BlockTransformer;
|
||||||
|
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
|
||||||
public class GetSignaturesV2Message extends Message {
|
public class GetSignaturesV2Message extends Message {
|
||||||
|
|
||||||
private static final int BLOCK_SIGNATURE_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH;
|
private final byte[] parentSignature;
|
||||||
private static final int NUMBER_REQUESTED_LENGTH = Transformer.INT_LENGTH;
|
private final int numberRequested;
|
||||||
|
|
||||||
private byte[] parentSignature;
|
|
||||||
private int numberRequested;
|
|
||||||
|
|
||||||
public GetSignaturesV2Message(byte[] parentSignature, int numberRequested) {
|
public GetSignaturesV2Message(byte[] parentSignature, int numberRequested) {
|
||||||
this(-1, parentSignature, numberRequested);
|
this(-1, parentSignature, numberRequested);
|
||||||
@ -37,11 +32,8 @@ public class GetSignaturesV2Message extends Message {
|
|||||||
return this.numberRequested;
|
return this.numberRequested;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
if (bytes.remaining() != BLOCK_SIGNATURE_LENGTH + NUMBER_REQUESTED_LENGTH)
|
byte[] parentSignature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH];
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] parentSignature = new byte[BLOCK_SIGNATURE_LENGTH];
|
|
||||||
bytes.get(parentSignature);
|
bytes.get(parentSignature);
|
||||||
|
|
||||||
int numberRequested = bytes.getInt();
|
int numberRequested = bytes.getInt();
|
||||||
@ -50,18 +42,14 @@ public class GetSignaturesV2Message extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.parentSignature);
|
bytes.write(this.parentSignature);
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.numberRequested));
|
bytes.write(Ints.toByteArray(this.numberRequested));
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import org.qortal.transform.Transformer;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -20,7 +19,7 @@ import java.util.Map;
|
|||||||
* Groups of: number of entries, timestamp, then AT trade pubkey for each entry.
|
* Groups of: number of entries, timestamp, then AT trade pubkey for each entry.
|
||||||
*/
|
*/
|
||||||
public class GetTradePresencesMessage extends Message {
|
public class GetTradePresencesMessage extends Message {
|
||||||
private List<TradePresenceData> tradePresences;
|
private final List<TradePresenceData> tradePresences;
|
||||||
private byte[] cachedData;
|
private byte[] cachedData;
|
||||||
|
|
||||||
public GetTradePresencesMessage(List<TradePresenceData> tradePresences) {
|
public GetTradePresencesMessage(List<TradePresenceData> tradePresences) {
|
||||||
@ -37,7 +36,7 @@ public class GetTradePresencesMessage extends Message {
|
|||||||
return this.tradePresences;
|
return this.tradePresences;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
int groupedEntriesCount = bytes.getInt();
|
int groupedEntriesCount = bytes.getInt();
|
||||||
|
|
||||||
List<TradePresenceData> tradePresences = new ArrayList<>(groupedEntriesCount);
|
List<TradePresenceData> tradePresences = new ArrayList<>(groupedEntriesCount);
|
||||||
@ -64,7 +63,7 @@ public class GetTradePresencesMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected synchronized byte[] toData() {
|
protected synchronized byte[] toData() throws IOException {
|
||||||
if (this.cachedData != null)
|
if (this.cachedData != null)
|
||||||
return this.cachedData;
|
return this.cachedData;
|
||||||
|
|
||||||
@ -86,25 +85,21 @@ public class GetTradePresencesMessage extends Message {
|
|||||||
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH)
|
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH)
|
||||||
+ this.tradePresences.size() * Transformer.PUBLIC_KEY_LENGTH;
|
+ this.tradePresences.size() * Transformer.PUBLIC_KEY_LENGTH;
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize);
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize);
|
|
||||||
|
|
||||||
for (long timestamp : countByTimestamp.keySet()) {
|
for (long timestamp : countByTimestamp.keySet()) {
|
||||||
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp)));
|
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp)));
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(timestamp));
|
bytes.write(Longs.toByteArray(timestamp));
|
||||||
|
|
||||||
for (TradePresenceData tradePresenceData : this.tradePresences) {
|
for (TradePresenceData tradePresenceData : this.tradePresences) {
|
||||||
if (tradePresenceData.getTimestamp() == timestamp)
|
if (tradePresenceData.getTimestamp() == timestamp)
|
||||||
bytes.write(tradePresenceData.getPublicKey());
|
bytes.write(tradePresenceData.getPublicKey());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cachedData = bytes.toByteArray();
|
|
||||||
return this.cachedData;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cachedData = bytes.toByteArray();
|
||||||
|
return this.cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,13 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.transform.Transformer;
|
import org.qortal.transform.Transformer;
|
||||||
|
|
||||||
public class GetTransactionMessage extends Message {
|
public class GetTransactionMessage extends Message {
|
||||||
|
|
||||||
private static final int TRANSACTION_SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
private final byte[] signature;
|
||||||
|
|
||||||
private byte[] signature;
|
|
||||||
|
|
||||||
public GetTransactionMessage(byte[] signature) {
|
public GetTransactionMessage(byte[] signature) {
|
||||||
this(-1, signature);
|
this(-1, signature);
|
||||||
@ -27,11 +24,8 @@ public class GetTransactionMessage extends Message {
|
|||||||
return this.signature;
|
return this.signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
if (bytes.remaining() != TRANSACTION_SIGNATURE_LENGTH)
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] signature = new byte[TRANSACTION_SIGNATURE_LENGTH];
|
|
||||||
|
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
|
|
||||||
@ -39,16 +33,12 @@ public class GetTransactionMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.qortal.network.message;
|
package org.qortal.network.message;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class GetUnconfirmedTransactionsMessage extends Message {
|
public class GetUnconfirmedTransactionsMessage extends Message {
|
||||||
@ -13,7 +12,7 @@ public class GetUnconfirmedTransactionsMessage extends Message {
|
|||||||
super(id, MessageType.GET_UNCONFIRMED_TRANSACTIONS);
|
super(id, MessageType.GET_UNCONFIRMED_TRANSACTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
return new GetUnconfirmedTransactionsMessage(id);
|
return new GetUnconfirmedTransactionsMessage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ public class GoodbyeMessage extends Message {
|
|||||||
private static final Map<Integer, Reason> map = stream(Reason.values())
|
private static final Map<Integer, Reason> map = stream(Reason.values())
|
||||||
.collect(toMap(reason -> reason.value, reason -> reason));
|
.collect(toMap(reason -> reason.value, reason -> reason));
|
||||||
|
|
||||||
private Reason(int value) {
|
Reason(int value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,12 +47,12 @@ public class GoodbyeMessage extends Message {
|
|||||||
return this.reason;
|
return this.reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
||||||
int reasonValue = byteBuffer.getInt();
|
int reasonValue = byteBuffer.getInt();
|
||||||
|
|
||||||
Reason reason = Reason.valueOf(reasonValue);
|
Reason reason = Reason.valueOf(reasonValue);
|
||||||
if (reason == null)
|
if (reason == null)
|
||||||
return null;
|
throw new MessageException("Invalid reason " + reasonValue + " in GOODBYE message");
|
||||||
|
|
||||||
return new GoodbyeMessage(id, reason);
|
return new GoodbyeMessage(id, reason);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.transform.Transformer;
|
import org.qortal.transform.Transformer;
|
||||||
@ -13,10 +12,10 @@ import com.google.common.primitives.Longs;
|
|||||||
|
|
||||||
public class HeightV2Message extends Message {
|
public class HeightV2Message extends Message {
|
||||||
|
|
||||||
private int height;
|
private final int height;
|
||||||
private byte[] signature;
|
private final byte[] signature;
|
||||||
private long timestamp;
|
private final long timestamp;
|
||||||
private byte[] minterPublicKey;
|
private final byte[] minterPublicKey;
|
||||||
|
|
||||||
public HeightV2Message(int height, byte[] signature, long timestamp, byte[] minterPublicKey) {
|
public HeightV2Message(int height, byte[] signature, long timestamp, byte[] minterPublicKey) {
|
||||||
this(-1, height, signature, timestamp, minterPublicKey);
|
this(-1, height, signature, timestamp, minterPublicKey);
|
||||||
@ -47,7 +46,7 @@ public class HeightV2Message extends Message {
|
|||||||
return this.minterPublicKey;
|
return this.minterPublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
int height = bytes.getInt();
|
int height = bytes.getInt();
|
||||||
|
|
||||||
byte[] signature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH];
|
byte[] signature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH];
|
||||||
@ -62,22 +61,18 @@ public class HeightV2Message extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.height));
|
bytes.write(Ints.toByteArray(this.height));
|
||||||
|
|
||||||
bytes.write(this.signature);
|
bytes.write(this.signature);
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(this.timestamp));
|
bytes.write(Longs.toByteArray(this.timestamp));
|
||||||
|
|
||||||
bytes.write(this.minterPublicKey);
|
bytes.write(this.minterPublicKey);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -39,15 +39,20 @@ public class HelloMessage extends Message {
|
|||||||
return this.senderPeerAddress;
|
return this.senderPeerAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws TransformationException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
||||||
long timestamp = byteBuffer.getLong();
|
long timestamp = byteBuffer.getLong();
|
||||||
|
|
||||||
String versionString = Serialization.deserializeSizedString(byteBuffer, 255);
|
String versionString;
|
||||||
|
|
||||||
// Sender peer address added in v3.0, so is an optional field. Older versions won't send it.
|
|
||||||
String senderPeerAddress = null;
|
String senderPeerAddress = null;
|
||||||
if (byteBuffer.hasRemaining()) {
|
try {
|
||||||
senderPeerAddress = Serialization.deserializeSizedString(byteBuffer, 255);
|
versionString = Serialization.deserializeSizedString(byteBuffer, 255);
|
||||||
|
|
||||||
|
// Sender peer address added in v3.0, so is an optional field. Older versions won't send it.
|
||||||
|
if (byteBuffer.hasRemaining()) {
|
||||||
|
senderPeerAddress = Serialization.deserializeSizedString(byteBuffer, 255);
|
||||||
|
}
|
||||||
|
} catch (TransformationException e) {
|
||||||
|
throw new MessageException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HelloMessage(id, timestamp, versionString, senderPeerAddress);
|
return new HelloMessage(id, timestamp, versionString, senderPeerAddress);
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package org.qortal.network.message;
|
package org.qortal.network.message;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.qortal.crypto.Crypto;
|
import org.qortal.crypto.Crypto;
|
||||||
import org.qortal.network.Network;
|
import org.qortal.network.Network;
|
||||||
import org.qortal.transform.TransformationException;
|
import org.qortal.transform.TransformationException;
|
||||||
@ -13,8 +11,6 @@ import static java.util.stream.Collectors.toMap;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.nio.BufferUnderflowException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -27,127 +23,6 @@ public abstract class Message {
|
|||||||
|
|
||||||
private static final int MAX_DATA_SIZE = 10 * 1024 * 1024; // 10MB
|
private static final int MAX_DATA_SIZE = 10 * 1024 * 1024; // 10MB
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public static class MessageException extends Exception {
|
|
||||||
public MessageException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum MessageType {
|
|
||||||
// Handshaking
|
|
||||||
HELLO(0),
|
|
||||||
GOODBYE(1),
|
|
||||||
CHALLENGE(2),
|
|
||||||
RESPONSE(3),
|
|
||||||
|
|
||||||
// Status / notifications
|
|
||||||
HEIGHT_V2(10),
|
|
||||||
PING(11),
|
|
||||||
PONG(12),
|
|
||||||
|
|
||||||
// Requesting data
|
|
||||||
PEERS_V2(20),
|
|
||||||
GET_PEERS(21),
|
|
||||||
|
|
||||||
TRANSACTION(30),
|
|
||||||
GET_TRANSACTION(31),
|
|
||||||
|
|
||||||
TRANSACTION_SIGNATURES(40),
|
|
||||||
GET_UNCONFIRMED_TRANSACTIONS(41),
|
|
||||||
|
|
||||||
BLOCK(50),
|
|
||||||
GET_BLOCK(51),
|
|
||||||
|
|
||||||
SIGNATURES(60),
|
|
||||||
GET_SIGNATURES_V2(61),
|
|
||||||
|
|
||||||
BLOCK_SUMMARIES(70),
|
|
||||||
GET_BLOCK_SUMMARIES(71),
|
|
||||||
|
|
||||||
ONLINE_ACCOUNTS(80),
|
|
||||||
GET_ONLINE_ACCOUNTS(81),
|
|
||||||
ONLINE_ACCOUNTS_V2(82),
|
|
||||||
GET_ONLINE_ACCOUNTS_V2(83),
|
|
||||||
|
|
||||||
ARBITRARY_DATA(90),
|
|
||||||
GET_ARBITRARY_DATA(91),
|
|
||||||
|
|
||||||
BLOCKS(100),
|
|
||||||
GET_BLOCKS(101),
|
|
||||||
|
|
||||||
ARBITRARY_DATA_FILE(110),
|
|
||||||
GET_ARBITRARY_DATA_FILE(111),
|
|
||||||
|
|
||||||
ARBITRARY_DATA_FILE_LIST(120),
|
|
||||||
GET_ARBITRARY_DATA_FILE_LIST(121),
|
|
||||||
|
|
||||||
ARBITRARY_SIGNATURES(130),
|
|
||||||
|
|
||||||
TRADE_PRESENCES(140),
|
|
||||||
GET_TRADE_PRESENCES(141),
|
|
||||||
|
|
||||||
ARBITRARY_METADATA(150),
|
|
||||||
GET_ARBITRARY_METADATA(151);
|
|
||||||
|
|
||||||
public final int value;
|
|
||||||
public final Method fromByteBufferMethod;
|
|
||||||
|
|
||||||
private static final Map<Integer, MessageType> map = stream(MessageType.values())
|
|
||||||
.collect(toMap(messageType -> messageType.value, messageType -> messageType));
|
|
||||||
|
|
||||||
private MessageType(int value) {
|
|
||||||
this.value = value;
|
|
||||||
|
|
||||||
String[] classNameParts = this.name().toLowerCase().split("_");
|
|
||||||
|
|
||||||
for (int i = 0; i < classNameParts.length; ++i)
|
|
||||||
classNameParts[i] = classNameParts[i].substring(0, 1).toUpperCase().concat(classNameParts[i].substring(1));
|
|
||||||
|
|
||||||
String className = String.join("", classNameParts);
|
|
||||||
|
|
||||||
Method method;
|
|
||||||
try {
|
|
||||||
Class<?> subclass = Class.forName(String.join("", Message.class.getPackage().getName(), ".", className, "Message"));
|
|
||||||
|
|
||||||
method = subclass.getDeclaredMethod("fromByteBuffer", int.class, ByteBuffer.class);
|
|
||||||
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
|
|
||||||
method = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.fromByteBufferMethod = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MessageType valueOf(int value) {
|
|
||||||
return map.get(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
|
||||||
if (this.fromByteBufferMethod == null)
|
|
||||||
throw new MessageException("Unsupported message type [" + value + "] during conversion from bytes");
|
|
||||||
|
|
||||||
try {
|
|
||||||
return (Message) this.fromByteBufferMethod.invoke(null, id, byteBuffer);
|
|
||||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
|
||||||
if (e.getCause() instanceof BufferUnderflowException)
|
|
||||||
throw new MessageException("Byte data too short for " + name() + " message");
|
|
||||||
|
|
||||||
throw new MessageException("Internal error with " + name() + " message during conversion from bytes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int id;
|
private int id;
|
||||||
private MessageType type;
|
private MessageType type;
|
||||||
|
|
||||||
@ -181,7 +56,7 @@ public abstract class Message {
|
|||||||
*
|
*
|
||||||
* @param readOnlyBuffer
|
* @param readOnlyBuffer
|
||||||
* @return null if no complete message can be read
|
* @return null if no complete message can be read
|
||||||
* @throws MessageException
|
* @throws MessageException if message could not be decoded or is invalid
|
||||||
*/
|
*/
|
||||||
public static Message fromByteBuffer(ByteBuffer readOnlyBuffer) throws MessageException {
|
public static Message fromByteBuffer(ByteBuffer readOnlyBuffer) throws MessageException {
|
||||||
try {
|
try {
|
||||||
@ -293,6 +168,12 @@ public abstract class Message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Serialize message into bytes.
|
||||||
|
*
|
||||||
|
* @return message as byte array, or null if message is missing payload data / uninitialized somehow
|
||||||
|
* @throws IOException if unable / failed to serialize
|
||||||
|
* @throws TransformationException if unable / failed to serialize
|
||||||
|
*/
|
||||||
protected abstract byte[] toData() throws IOException, TransformationException;
|
protected abstract byte[] toData() throws IOException, TransformationException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package org.qortal.network.message;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class MessageException extends Exception {
|
||||||
|
public MessageException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.qortal.network.message;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MessageProducer {
|
||||||
|
Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException;
|
||||||
|
}
|
96
src/main/java/org/qortal/network/message/MessageType.java
Normal file
96
src/main/java/org/qortal/network/message/MessageType.java
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package org.qortal.network.message;
|
||||||
|
|
||||||
|
import java.nio.BufferUnderflowException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static java.util.Arrays.stream;
|
||||||
|
import static java.util.stream.Collectors.toMap;
|
||||||
|
|
||||||
|
public enum MessageType {
|
||||||
|
// Handshaking
|
||||||
|
HELLO(0, HelloMessage::fromByteBuffer),
|
||||||
|
GOODBYE(1, GoodbyeMessage::fromByteBuffer),
|
||||||
|
CHALLENGE(2, ChallengeMessage::fromByteBuffer),
|
||||||
|
RESPONSE(3, ResponseMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
// Status / notifications
|
||||||
|
HEIGHT_V2(10, HeightV2Message::fromByteBuffer),
|
||||||
|
PING(11, PingMessage::fromByteBuffer),
|
||||||
|
PONG(12, PongMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
// Requesting data
|
||||||
|
PEERS_V2(20, PeersV2Message::fromByteBuffer),
|
||||||
|
GET_PEERS(21, GetPeersMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
TRANSACTION(30, TransactionMessage::fromByteBuffer),
|
||||||
|
GET_TRANSACTION(31, GetTransactionMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
TRANSACTION_SIGNATURES(40, TransactionSignaturesMessage::fromByteBuffer),
|
||||||
|
GET_UNCONFIRMED_TRANSACTIONS(41, GetUnconfirmedTransactionsMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
BLOCK(50, BlockMessage::fromByteBuffer),
|
||||||
|
GET_BLOCK(51, GetBlockMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
SIGNATURES(60, SignaturesMessage::fromByteBuffer),
|
||||||
|
GET_SIGNATURES_V2(61, GetSignaturesV2Message::fromByteBuffer),
|
||||||
|
|
||||||
|
BLOCK_SUMMARIES(70, BlockSummariesMessage::fromByteBuffer),
|
||||||
|
GET_BLOCK_SUMMARIES(71, GetBlockSummariesMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
ONLINE_ACCOUNTS(80, OnlineAccountsMessage::fromByteBuffer),
|
||||||
|
GET_ONLINE_ACCOUNTS(81, GetOnlineAccountsMessage::fromByteBuffer),
|
||||||
|
ONLINE_ACCOUNTS_V2(82, OnlineAccountsV2Message::fromByteBuffer),
|
||||||
|
GET_ONLINE_ACCOUNTS_V2(83, GetOnlineAccountsV2Message::fromByteBuffer),
|
||||||
|
|
||||||
|
ARBITRARY_DATA(90, ArbitraryDataMessage::fromByteBuffer),
|
||||||
|
GET_ARBITRARY_DATA(91, GetArbitraryDataMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
BLOCKS(100, null), // unsupported
|
||||||
|
GET_BLOCKS(101, null), // unsupported
|
||||||
|
|
||||||
|
ARBITRARY_DATA_FILE(110, ArbitraryDataFileMessage::fromByteBuffer),
|
||||||
|
GET_ARBITRARY_DATA_FILE(111, GetArbitraryDataFileMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
ARBITRARY_DATA_FILE_LIST(120, ArbitraryDataFileListMessage::fromByteBuffer),
|
||||||
|
GET_ARBITRARY_DATA_FILE_LIST(121, GetArbitraryDataFileListMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
ARBITRARY_SIGNATURES(130, ArbitrarySignaturesMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
TRADE_PRESENCES(140, TradePresencesMessage::fromByteBuffer),
|
||||||
|
GET_TRADE_PRESENCES(141, GetTradePresencesMessage::fromByteBuffer),
|
||||||
|
|
||||||
|
ARBITRARY_METADATA(150, ArbitraryMetadataMessage::fromByteBuffer),
|
||||||
|
GET_ARBITRARY_METADATA(151, GetArbitraryMetadataMessage::fromByteBuffer);
|
||||||
|
|
||||||
|
public final int value;
|
||||||
|
public final MessageProducer fromByteBufferMethod;
|
||||||
|
|
||||||
|
private static final Map<Integer, MessageType> map = stream(MessageType.values())
|
||||||
|
.collect(toMap(messageType -> messageType.value, messageType -> messageType));
|
||||||
|
|
||||||
|
MessageType(int value, MessageProducer fromByteBufferMethod) {
|
||||||
|
this.value = value;
|
||||||
|
this.fromByteBufferMethod = fromByteBufferMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageType valueOf(int value) {
|
||||||
|
return map.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to read a message from byte buffer.
|
||||||
|
*
|
||||||
|
* @param id message ID or -1
|
||||||
|
* @param byteBuffer ByteBuffer source for message
|
||||||
|
* @return null if no complete message can be read
|
||||||
|
* @throws MessageException if message could not be decoded or is invalid
|
||||||
|
* @throws BufferUnderflowException if not enough bytes in buffer to read message
|
||||||
|
*/
|
||||||
|
public Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
||||||
|
if (this.fromByteBufferMethod == null)
|
||||||
|
throw new MessageException("Message type " + this.name() + " unsupported");
|
||||||
|
|
||||||
|
return this.fromByteBufferMethod.fromByteBuffer(id, byteBuffer);
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -17,7 +16,7 @@ import com.google.common.primitives.Longs;
|
|||||||
public class OnlineAccountsMessage extends Message {
|
public class OnlineAccountsMessage extends Message {
|
||||||
private static final int MAX_ACCOUNT_COUNT = 5000;
|
private static final int MAX_ACCOUNT_COUNT = 5000;
|
||||||
|
|
||||||
private List<OnlineAccountData> onlineAccounts;
|
private final List<OnlineAccountData> onlineAccounts;
|
||||||
|
|
||||||
public OnlineAccountsMessage(List<OnlineAccountData> onlineAccounts) {
|
public OnlineAccountsMessage(List<OnlineAccountData> onlineAccounts) {
|
||||||
this(-1, onlineAccounts);
|
this(-1, onlineAccounts);
|
||||||
@ -33,7 +32,7 @@ public class OnlineAccountsMessage extends Message {
|
|||||||
return this.onlineAccounts;
|
return this.onlineAccounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
final int accountCount = bytes.getInt();
|
final int accountCount = bytes.getInt();
|
||||||
|
|
||||||
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount);
|
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount);
|
||||||
@ -55,26 +54,20 @@ public class OnlineAccountsMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.onlineAccounts.size()));
|
bytes.write(Ints.toByteArray(this.onlineAccounts.size()));
|
||||||
|
|
||||||
for (int i = 0; i < this.onlineAccounts.size(); ++i) {
|
for (OnlineAccountData onlineAccountData : this.onlineAccounts) {
|
||||||
OnlineAccountData onlineAccountData = this.onlineAccounts.get(i);
|
bytes.write(Longs.toByteArray(onlineAccountData.getTimestamp()));
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(onlineAccountData.getTimestamp()));
|
bytes.write(onlineAccountData.getSignature());
|
||||||
|
|
||||||
bytes.write(onlineAccountData.getSignature());
|
bytes.write(onlineAccountData.getPublicKey());
|
||||||
|
|
||||||
bytes.write(onlineAccountData.getPublicKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bytes.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,11 @@ import org.qortal.transform.Transformer;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For sending online accounts info to remote peer.
|
* For sending online accounts info to remote peer.
|
||||||
@ -25,7 +23,7 @@ import java.util.stream.Collectors;
|
|||||||
* Also V2 only builds online accounts message once!
|
* Also V2 only builds online accounts message once!
|
||||||
*/
|
*/
|
||||||
public class OnlineAccountsV2Message extends Message {
|
public class OnlineAccountsV2Message extends Message {
|
||||||
private List<OnlineAccountData> onlineAccounts;
|
private final List<OnlineAccountData> onlineAccounts;
|
||||||
private byte[] cachedData;
|
private byte[] cachedData;
|
||||||
|
|
||||||
public OnlineAccountsV2Message(List<OnlineAccountData> onlineAccounts) {
|
public OnlineAccountsV2Message(List<OnlineAccountData> onlineAccounts) {
|
||||||
@ -42,7 +40,7 @@ public class OnlineAccountsV2Message extends Message {
|
|||||||
return this.onlineAccounts;
|
return this.onlineAccounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws MessageException {
|
||||||
int accountCount = bytes.getInt();
|
int accountCount = bytes.getInt();
|
||||||
|
|
||||||
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount);
|
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount);
|
||||||
@ -72,7 +70,7 @@ public class OnlineAccountsV2Message extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected synchronized byte[] toData() {
|
protected synchronized byte[] toData() throws IOException {
|
||||||
if (this.cachedData != null)
|
if (this.cachedData != null)
|
||||||
return this.cachedData;
|
return this.cachedData;
|
||||||
|
|
||||||
@ -85,8 +83,7 @@ public class OnlineAccountsV2Message extends Message {
|
|||||||
// How many of each timestamp
|
// How many of each timestamp
|
||||||
Map<Long, Integer> countByTimestamp = new HashMap<>();
|
Map<Long, Integer> countByTimestamp = new HashMap<>();
|
||||||
|
|
||||||
for (int i = 0; i < this.onlineAccounts.size(); ++i) {
|
for (OnlineAccountData onlineAccountData : this.onlineAccounts) {
|
||||||
OnlineAccountData onlineAccountData = this.onlineAccounts.get(i);
|
|
||||||
Long timestamp = onlineAccountData.getTimestamp();
|
Long timestamp = onlineAccountData.getTimestamp();
|
||||||
countByTimestamp.compute(timestamp, (k, v) -> v == null ? 1 : ++v);
|
countByTimestamp.compute(timestamp, (k, v) -> v == null ? 1 : ++v);
|
||||||
}
|
}
|
||||||
@ -95,30 +92,23 @@ public class OnlineAccountsV2Message extends Message {
|
|||||||
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH)
|
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH)
|
||||||
+ this.onlineAccounts.size() * (Transformer.SIGNATURE_LENGTH + Transformer.PUBLIC_KEY_LENGTH);
|
+ this.onlineAccounts.size() * (Transformer.SIGNATURE_LENGTH + Transformer.PUBLIC_KEY_LENGTH);
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize);
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize);
|
|
||||||
|
|
||||||
for (long timestamp : countByTimestamp.keySet()) {
|
for (long timestamp : countByTimestamp.keySet()) {
|
||||||
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp)));
|
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp)));
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(timestamp));
|
bytes.write(Longs.toByteArray(timestamp));
|
||||||
|
|
||||||
for (int i = 0; i < this.onlineAccounts.size(); ++i) {
|
for (OnlineAccountData onlineAccountData : this.onlineAccounts) {
|
||||||
OnlineAccountData onlineAccountData = this.onlineAccounts.get(i);
|
if (onlineAccountData.getTimestamp() == timestamp) {
|
||||||
|
bytes.write(onlineAccountData.getSignature());
|
||||||
if (onlineAccountData.getTimestamp() == timestamp) {
|
bytes.write(onlineAccountData.getPublicKey());
|
||||||
bytes.write(onlineAccountData.getSignature());
|
|
||||||
|
|
||||||
bytes.write(onlineAccountData.getPublicKey());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cachedData = bytes.toByteArray();
|
|
||||||
return this.cachedData;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cachedData = bytes.toByteArray();
|
||||||
|
return this.cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -16,7 +15,7 @@ import com.google.common.primitives.Ints;
|
|||||||
// NOTE: this message supports hostnames, literal IP addresses (IPv4 and IPv6) with port numbers
|
// NOTE: this message supports hostnames, literal IP addresses (IPv4 and IPv6) with port numbers
|
||||||
public class PeersV2Message extends Message {
|
public class PeersV2Message extends Message {
|
||||||
|
|
||||||
private List<PeerAddress> peerAddresses;
|
private final List<PeerAddress> peerAddresses;
|
||||||
|
|
||||||
public PeersV2Message(List<PeerAddress> peerAddresses) {
|
public PeersV2Message(List<PeerAddress> peerAddresses) {
|
||||||
this(-1, peerAddresses);
|
this(-1, peerAddresses);
|
||||||
@ -32,7 +31,7 @@ public class PeersV2Message extends Message {
|
|||||||
return this.peerAddresses;
|
return this.peerAddresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
||||||
// Read entry count
|
// Read entry count
|
||||||
int count = byteBuffer.getInt();
|
int count = byteBuffer.getInt();
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ public class PeersV2Message extends Message {
|
|||||||
PeerAddress peerAddress = PeerAddress.fromString(addressString);
|
PeerAddress peerAddress = PeerAddress.fromString(addressString);
|
||||||
peerAddresses.add(peerAddress);
|
peerAddresses.add(peerAddress);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
// Not valid - ignore
|
throw new MessageException("Invalid peer address in received PEERS_V2 message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,35 +56,31 @@ public class PeersV2Message extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
List<byte[]> addresses = new ArrayList<>();
|
List<byte[]> addresses = new ArrayList<>();
|
||||||
|
|
||||||
// First entry represents sending node but contains only port number with empty address.
|
// First entry represents sending node but contains only port number with empty address.
|
||||||
addresses.add(("0.0.0.0:" + Settings.getInstance().getListenPort()).getBytes(StandardCharsets.UTF_8));
|
addresses.add(("0.0.0.0:" + Settings.getInstance().getListenPort()).getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
for (PeerAddress peerAddress : this.peerAddresses)
|
for (PeerAddress peerAddress : this.peerAddresses)
|
||||||
addresses.add(peerAddress.toString().getBytes(StandardCharsets.UTF_8));
|
addresses.add(peerAddress.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
// We can't send addresses that are longer than 255 bytes as length itself is encoded in one byte.
|
// We can't send addresses that are longer than 255 bytes as length itself is encoded in one byte.
|
||||||
addresses.removeIf(addressString -> addressString.length > 255);
|
addresses.removeIf(addressString -> addressString.length > 255);
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
|
|
||||||
// Number of entries
|
// Number of entries
|
||||||
bytes.write(Ints.toByteArray(addresses.size()));
|
bytes.write(Ints.toByteArray(addresses.size()));
|
||||||
|
|
||||||
for (byte[] address : addresses) {
|
for (byte[] address : addresses) {
|
||||||
bytes.write(address.length);
|
bytes.write(address.length);
|
||||||
bytes.write(address);
|
bytes.write(address);
|
||||||
}
|
|
||||||
|
|
||||||
return bytes.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bytes.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.qortal.network.message;
|
package org.qortal.network.message;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class PingMessage extends Message {
|
public class PingMessage extends Message {
|
||||||
@ -13,7 +12,7 @@ public class PingMessage extends Message {
|
|||||||
super(id, MessageType.PING);
|
super(id, MessageType.PING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
return new PingMessage(id);
|
return new PingMessage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
src/main/java/org/qortal/network/message/PongMessage.java
Normal file
24
src/main/java/org/qortal/network/message/PongMessage.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package org.qortal.network.message;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class PongMessage extends Message {
|
||||||
|
|
||||||
|
public PongMessage() {
|
||||||
|
this(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PongMessage(int id) {
|
||||||
|
super(id, MessageType.PONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
|
return new PongMessage(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] toData() {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,7 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -13,9 +13,7 @@ import com.google.common.primitives.Ints;
|
|||||||
|
|
||||||
public class SignaturesMessage extends Message {
|
public class SignaturesMessage extends Message {
|
||||||
|
|
||||||
private static final int BLOCK_SIGNATURE_LENGTH = BlockTransformer.BLOCK_SIGNATURE_LENGTH;
|
private final List<byte[]> signatures;
|
||||||
|
|
||||||
private List<byte[]> signatures;
|
|
||||||
|
|
||||||
public SignaturesMessage(List<byte[]> signatures) {
|
public SignaturesMessage(List<byte[]> signatures) {
|
||||||
this(-1, signatures);
|
this(-1, signatures);
|
||||||
@ -31,15 +29,15 @@ public class SignaturesMessage extends Message {
|
|||||||
return this.signatures;
|
return this.signatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
int count = bytes.getInt();
|
int count = bytes.getInt();
|
||||||
|
|
||||||
if (bytes.remaining() != count * BLOCK_SIGNATURE_LENGTH)
|
if (bytes.remaining() < count * BlockTransformer.BLOCK_SIGNATURE_LENGTH)
|
||||||
return null;
|
throw new BufferUnderflowException();
|
||||||
|
|
||||||
List<byte[]> signatures = new ArrayList<>();
|
List<byte[]> signatures = new ArrayList<>();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
byte[] signature = new byte[BLOCK_SIGNATURE_LENGTH];
|
byte[] signature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH];
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
signatures.add(signature);
|
signatures.add(signature);
|
||||||
}
|
}
|
||||||
@ -48,19 +46,15 @@ public class SignaturesMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.signatures.size()));
|
bytes.write(Ints.toByteArray(this.signatures.size()));
|
||||||
|
|
||||||
for (byte[] signature : this.signatures)
|
for (byte[] signature : this.signatures)
|
||||||
bytes.write(signature);
|
bytes.write(signature);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import org.qortal.utils.Base58;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -21,7 +20,7 @@ import java.util.Map;
|
|||||||
* Groups of: number of entries, timestamp, then pubkey + sig + AT address for each entry.
|
* Groups of: number of entries, timestamp, then pubkey + sig + AT address for each entry.
|
||||||
*/
|
*/
|
||||||
public class TradePresencesMessage extends Message {
|
public class TradePresencesMessage extends Message {
|
||||||
private List<TradePresenceData> tradePresences;
|
private final List<TradePresenceData> tradePresences;
|
||||||
private byte[] cachedData;
|
private byte[] cachedData;
|
||||||
|
|
||||||
public TradePresencesMessage(List<TradePresenceData> tradePresences) {
|
public TradePresencesMessage(List<TradePresenceData> tradePresences) {
|
||||||
@ -38,7 +37,7 @@ public class TradePresencesMessage extends Message {
|
|||||||
return this.tradePresences;
|
return this.tradePresences;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
int groupedEntriesCount = bytes.getInt();
|
int groupedEntriesCount = bytes.getInt();
|
||||||
|
|
||||||
List<TradePresenceData> tradePresences = new ArrayList<>(groupedEntriesCount);
|
List<TradePresenceData> tradePresences = new ArrayList<>(groupedEntriesCount);
|
||||||
@ -72,7 +71,7 @@ public class TradePresencesMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected synchronized byte[] toData() {
|
protected synchronized byte[] toData() throws IOException {
|
||||||
if (this.cachedData != null)
|
if (this.cachedData != null)
|
||||||
return this.cachedData;
|
return this.cachedData;
|
||||||
|
|
||||||
@ -94,30 +93,26 @@ public class TradePresencesMessage extends Message {
|
|||||||
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH)
|
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH)
|
||||||
+ this.tradePresences.size() * (Transformer.PUBLIC_KEY_LENGTH + Transformer.SIGNATURE_LENGTH + Transformer.ADDRESS_LENGTH);
|
+ this.tradePresences.size() * (Transformer.PUBLIC_KEY_LENGTH + Transformer.SIGNATURE_LENGTH + Transformer.ADDRESS_LENGTH);
|
||||||
|
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize);
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize);
|
|
||||||
|
|
||||||
for (long timestamp : countByTimestamp.keySet()) {
|
for (long timestamp : countByTimestamp.keySet()) {
|
||||||
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp)));
|
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp)));
|
||||||
|
|
||||||
bytes.write(Longs.toByteArray(timestamp));
|
bytes.write(Longs.toByteArray(timestamp));
|
||||||
|
|
||||||
for (TradePresenceData tradePresenceData : this.tradePresences) {
|
for (TradePresenceData tradePresenceData : this.tradePresences) {
|
||||||
if (tradePresenceData.getTimestamp() == timestamp) {
|
if (tradePresenceData.getTimestamp() == timestamp) {
|
||||||
bytes.write(tradePresenceData.getPublicKey());
|
bytes.write(tradePresenceData.getPublicKey());
|
||||||
|
|
||||||
bytes.write(tradePresenceData.getSignature());
|
bytes.write(tradePresenceData.getSignature());
|
||||||
|
|
||||||
bytes.write(Base58.decode(tradePresenceData.getAtAddress()));
|
bytes.write(Base58.decode(tradePresenceData.getAtAddress()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cachedData = bytes.toByteArray();
|
|
||||||
return this.cachedData;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cachedData = bytes.toByteArray();
|
||||||
|
return this.cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.qortal.network.message;
|
package org.qortal.network.message;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.qortal.data.transaction.TransactionData;
|
import org.qortal.data.transaction.TransactionData;
|
||||||
@ -25,26 +24,24 @@ public class TransactionMessage extends Message {
|
|||||||
return this.transactionData;
|
return this.transactionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws MessageException {
|
||||||
try {
|
TransactionData transactionData;
|
||||||
TransactionData transactionData = TransactionTransformer.fromByteBuffer(byteBuffer);
|
|
||||||
|
|
||||||
return new TransactionMessage(id, transactionData);
|
try {
|
||||||
|
transactionData = TransactionTransformer.fromByteBuffer(byteBuffer);
|
||||||
} catch (TransformationException e) {
|
} catch (TransformationException e) {
|
||||||
return null;
|
throw new MessageException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new TransactionMessage(id, transactionData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws TransformationException {
|
||||||
if (this.transactionData == null)
|
if (this.transactionData == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try {
|
return TransactionTransformer.toBytes(this.transactionData);
|
||||||
return TransactionTransformer.toBytes(this.transactionData);
|
|
||||||
} catch (TransformationException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package org.qortal.network.message;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -13,9 +13,7 @@ import com.google.common.primitives.Ints;
|
|||||||
|
|
||||||
public class TransactionSignaturesMessage extends Message {
|
public class TransactionSignaturesMessage extends Message {
|
||||||
|
|
||||||
private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH;
|
private final List<byte[]> signatures;
|
||||||
|
|
||||||
private List<byte[]> signatures;
|
|
||||||
|
|
||||||
public TransactionSignaturesMessage(List<byte[]> signatures) {
|
public TransactionSignaturesMessage(List<byte[]> signatures) {
|
||||||
this(-1, signatures);
|
this(-1, signatures);
|
||||||
@ -31,15 +29,15 @@ public class TransactionSignaturesMessage extends Message {
|
|||||||
return this.signatures;
|
return this.signatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException {
|
public static Message fromByteBuffer(int id, ByteBuffer bytes) {
|
||||||
int count = bytes.getInt();
|
int count = bytes.getInt();
|
||||||
|
|
||||||
if (bytes.remaining() != count * SIGNATURE_LENGTH)
|
if (bytes.remaining() < count * Transformer.SIGNATURE_LENGTH)
|
||||||
return null;
|
throw new BufferUnderflowException();
|
||||||
|
|
||||||
List<byte[]> signatures = new ArrayList<>();
|
List<byte[]> signatures = new ArrayList<>();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
bytes.get(signature);
|
bytes.get(signature);
|
||||||
signatures.add(signature);
|
signatures.add(signature);
|
||||||
}
|
}
|
||||||
@ -48,19 +46,15 @@ public class TransactionSignaturesMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] toData() {
|
protected byte[] toData() throws IOException {
|
||||||
try {
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
bytes.write(Ints.toByteArray(this.signatures.size()));
|
bytes.write(Ints.toByteArray(this.signatures.size()));
|
||||||
|
|
||||||
for (byte[] signature : this.signatures)
|
for (byte[] signature : this.signatures)
|
||||||
bytes.write(signature);
|
bytes.write(signature);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ public class OnlineAccountsTests {
|
|||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOnlineAccountsV2() throws Message.MessageException {
|
public void testGetOnlineAccountsV2() throws MessageException {
|
||||||
List<OnlineAccountData> onlineAccountsOut = generateOnlineAccounts(false);
|
List<OnlineAccountData> onlineAccountsOut = generateOnlineAccounts(false);
|
||||||
|
|
||||||
Message messageOut = new GetOnlineAccountsV2Message(onlineAccountsOut);
|
Message messageOut = new GetOnlineAccountsV2Message(onlineAccountsOut);
|
||||||
@ -58,7 +58,7 @@ public class OnlineAccountsTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnlineAccountsV2() throws Message.MessageException {
|
public void testOnlineAccountsV2() throws MessageException {
|
||||||
List<OnlineAccountData> onlineAccountsOut = generateOnlineAccounts(true);
|
List<OnlineAccountData> onlineAccountsOut = generateOnlineAccounts(true);
|
||||||
|
|
||||||
Message messageOut = new OnlineAccountsV2Message(onlineAccountsOut);
|
Message messageOut = new OnlineAccountsV2Message(onlineAccountsOut);
|
||||||
|
Loading…
Reference in New Issue
Block a user