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:
catbref 2022-03-19 15:08:20 +00:00
parent 44fc0f367d
commit 00996b047f
42 changed files with 527 additions and 696 deletions

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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,23 +76,24 @@ 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, MAX_PEER_ADDRESS_LENGTH); peerAddress = Serialization.deserializeSizedStringV2(bytes, PeerData.MAX_PEER_ADDRESS_SIZE);
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);
@ -124,9 +119,6 @@ public class ArbitraryDataFileListMessage extends Message {
bytes.write(Ints.toByteArray(this.isRelayPossible ? 1 : 0)); bytes.write(Ints.toByteArray(this.isRelayPossible ? 1 : 0));
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
public ArbitraryDataFileListMessage cloneWithNewId(int newId) { public ArbitraryDataFileListMessage cloneWithNewId(int newId) {

View File

@ -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,7 +69,6 @@ public class ArbitraryDataFileMessage extends Message {
return null; return null;
} }
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream(); ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bytes.write(signature); bytes.write(signature);
@ -82,9 +78,6 @@ public class ArbitraryDataFileMessage extends Message {
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) {

View File

@ -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,11 +49,10 @@ 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);
@ -65,9 +62,6 @@ public class ArbitraryDataMessage extends Message {
bytes.write(this.data); bytes.write(this.data);
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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,7 +68,6 @@ public class ArbitraryMetadataMessage extends Message {
return null; return null;
} }
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream(); ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bytes.write(signature); bytes.write(signature);
@ -81,9 +77,6 @@ public class ArbitraryMetadataMessage extends Message {
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) {

View File

@ -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,8 +73,7 @@ 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);
@ -84,9 +86,6 @@ public class ArbitrarySignaturesMessage extends Message {
bytes.write(signature); bytes.write(signature);
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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,16 +71,15 @@ 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));
@ -89,9 +87,6 @@ public class BlockMessage extends Message {
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) {

View File

@ -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,8 +59,7 @@ 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()));
@ -73,9 +72,6 @@ public class BlockSummariesMessage extends Message {
} }
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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,7 +42,6 @@ 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()));
@ -56,9 +54,6 @@ public class CachedBlockMessage extends Message {
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) {

View File

@ -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,15 +66,18 @@ 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);
@ -108,9 +102,6 @@ public class GetArbitraryDataFileListMessage extends Message {
} }
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
public long getRequestTime() { public long getRequestTime() {

View File

@ -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,22 +30,18 @@ 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);
@ -58,9 +49,6 @@ public class GetArbitraryDataFileMessage extends Message {
bytes.write(this.hash); bytes.write(this.hash);
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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;
}
} }
} }

View File

@ -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,8 +42,7 @@ 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);
@ -63,9 +52,6 @@ public class GetArbitraryMetadataMessage extends Message {
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() {

View File

@ -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;
}
} }
} }

View File

@ -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,8 +42,7 @@ 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);
@ -58,9 +50,6 @@ public class GetBlockSummariesMessage extends Message {
bytes.write(Ints.toByteArray(this.numberRequested)); bytes.write(Ints.toByteArray(this.numberRequested));
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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,7 +89,6 @@ 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()) {
@ -99,9 +96,7 @@ public class GetOnlineAccountsV2Message extends Message {
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) if (onlineAccountData.getTimestamp() == timestamp)
bytes.write(onlineAccountData.getPublicKey()); bytes.write(onlineAccountData.getPublicKey());
} }
@ -109,9 +104,6 @@ public class GetOnlineAccountsV2Message extends Message {
this.cachedData = bytes.toByteArray(); this.cachedData = bytes.toByteArray();
return this.cachedData; return this.cachedData;
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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);
} }

View File

@ -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,8 +42,7 @@ 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);
@ -59,9 +50,6 @@ public class GetSignaturesV2Message extends Message {
bytes.write(Ints.toByteArray(this.numberRequested)); bytes.write(Ints.toByteArray(this.numberRequested));
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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,7 +85,6 @@ 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()) {
@ -102,9 +100,6 @@ public class GetTradePresencesMessage extends Message {
this.cachedData = bytes.toByteArray(); this.cachedData = bytes.toByteArray();
return this.cachedData; return this.cachedData;
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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;
}
} }
} }

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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,8 +61,7 @@ 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));
@ -75,9 +73,6 @@ public class HeightV2Message extends Message {
bytes.write(this.minterPublicKey); bytes.write(this.minterPublicKey);
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -39,16 +39,21 @@ 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;
String senderPeerAddress = null;
try {
versionString = Serialization.deserializeSizedString(byteBuffer, 255);
// Sender peer address added in v3.0, so is an optional field. Older versions won't send it. // Sender peer address added in v3.0, so is an optional field. Older versions won't send it.
String senderPeerAddress = null;
if (byteBuffer.hasRemaining()) { if (byteBuffer.hasRemaining()) {
senderPeerAddress = Serialization.deserializeSizedString(byteBuffer, 255); 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);
} }

View File

@ -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;
} }

View File

@ -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);
}
}

View File

@ -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;
}

View 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);
}
}

View File

@ -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,15 +54,12 @@ 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());
@ -72,9 +68,6 @@ public class OnlineAccountsMessage extends Message {
} }
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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,7 +92,6 @@ 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()) {
@ -103,12 +99,9 @@ public class OnlineAccountsV2Message extends Message {
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) { if (onlineAccountData.getTimestamp() == timestamp) {
bytes.write(onlineAccountData.getSignature()); bytes.write(onlineAccountData.getSignature());
bytes.write(onlineAccountData.getPublicKey()); bytes.write(onlineAccountData.getPublicKey());
} }
} }
@ -116,9 +109,6 @@ public class OnlineAccountsV2Message extends Message {
this.cachedData = bytes.toByteArray(); this.cachedData = bytes.toByteArray();
return this.cachedData; return this.cachedData;
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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,8 +56,7 @@ 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<>();
@ -83,9 +81,6 @@ public class PeersV2Message extends Message {
} }
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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);
} }

View 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];
}
}

View File

@ -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,8 +46,7 @@ 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()));
@ -58,9 +55,6 @@ public class SignaturesMessage extends Message {
bytes.write(signature); bytes.write(signature);
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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,7 +93,6 @@ 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()) {
@ -115,9 +113,6 @@ public class TradePresencesMessage extends Message {
this.cachedData = bytes.toByteArray(); this.cachedData = bytes.toByteArray();
return this.cachedData; return this.cachedData;
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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 {
TransactionData transactionData;
try { try {
TransactionData transactionData = TransactionTransformer.fromByteBuffer(byteBuffer); transactionData = TransactionTransformer.fromByteBuffer(byteBuffer);
} catch (TransformationException e) {
throw new MessageException(e.getMessage(), e);
}
return new TransactionMessage(id, transactionData); return new TransactionMessage(id, transactionData);
} catch (TransformationException e) {
return null;
}
} }
@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;
}
} }
} }

View File

@ -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,8 +46,7 @@ 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()));
@ -58,9 +55,6 @@ public class TransactionSignaturesMessage extends Message {
bytes.write(signature); bytes.write(signature);
return bytes.toByteArray(); return bytes.toByteArray();
} catch (IOException e) {
return null;
}
} }
} }

View File

@ -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);