VersionMessage: move parse() to static constructor read()

This commit is contained in:
Andreas Schildbach 2023-04-14 21:01:55 +02:00
parent 14ba406298
commit e7ead0b3cb
3 changed files with 40 additions and 32 deletions

View file

@ -217,7 +217,7 @@ public class BitcoinSerializer extends MessageSerializer {
ByteBuffer payload = ByteBuffer.wrap(payloadBytes);
// We use an if ladder rather than reflection because reflection is very slow on Android.
if (command.equals("version")) {
return new VersionMessage(payload);
return VersionMessage.read(payload);
} else if (command.equals("inv")) {
return makeInventoryMessage(payload);
} else if (command.equals("block")) {

View file

@ -92,8 +92,38 @@ public class VersionMessage extends BaseMessage {
private static int NETADDR_BYTES = Services.BYTES + /* IPv6 */ 16 + /* port */ Short.BYTES;
public VersionMessage(ByteBuffer payload) throws ProtocolException {
super(payload);
/**
* Deserialize this message from a given payload.
*
* @param payload payload to deserialize from
* @return read message
* @throws BufferUnderflowException if the read message extends beyond the remaining bytes of the payload
*/
public static VersionMessage read(ByteBuffer payload) throws BufferUnderflowException, ProtocolException {
int clientVersion = (int) ByteUtils.readUint32(payload);
check(clientVersion >= ProtocolVersion.MINIMUM.intValue(),
ProtocolException::new);
Services localServices = Services.read(payload);
Instant time = Instant.ofEpochSecond(ByteUtils.readInt64(payload));
Services receivingServices = Services.read(payload);
InetAddress receivingInetAddress = PeerAddress.getByAddress(Buffers.readBytes(payload, 16));
int receivingPort = ByteUtils.readUint16BE(payload);
InetSocketAddress receivingAddr = new InetSocketAddress(receivingInetAddress, receivingPort);
Buffers.skipBytes(payload, NETADDR_BYTES); // addr_from
// uint64 localHostNonce (random data)
// We don't care about the localhost nonce. It's used to detect connecting back to yourself in cases where
// there are NATs and proxies in the way. However we don't listen for inbound connections so it's
// irrelevant.
Buffers.skipBytes(payload, 8);
// string subVer (currently "")
String subVer = Buffers.readLengthPrefixedString(payload);
// int bestHeight (size of known block chain).
long bestHeight = ByteUtils.readUint32(payload);
boolean relayTxesBeforeFilter = clientVersion >= ProtocolVersion.BLOOM_FILTER.intValue() ?
payload.get() != 0 :
true;
return new VersionMessage(clientVersion, localServices, time, receivingServices, receivingAddr, subVer,
bestHeight, relayTxesBeforeFilter);
}
/**
@ -147,29 +177,7 @@ public class VersionMessage extends BaseMessage {
@Override
protected void parse(ByteBuffer payload) throws BufferUnderflowException, ProtocolException {
clientVersion = (int) ByteUtils.readUint32(payload);
check(clientVersion >= ProtocolVersion.MINIMUM.intValue(),
ProtocolException::new);
localServices = Services.read(payload);
time = Instant.ofEpochSecond(ByteUtils.readInt64(payload));
receivingServices = Services.read(payload);
InetAddress receivingInetAddress = PeerAddress.getByAddress(Buffers.readBytes(payload, 16));
int receivingPort = ByteUtils.readUint16BE(payload);
receivingAddr = new InetSocketAddress(receivingInetAddress, receivingPort);
Buffers.skipBytes(payload, NETADDR_BYTES); // addr_from
// uint64 localHostNonce (random data)
// We don't care about the localhost nonce. It's used to detect connecting back to yourself in cases where
// there are NATs and proxies in the way. However we don't listen for inbound connections so it's
// irrelevant.
Buffers.skipBytes(payload, 8);
// string subVer (currently "")
subVer = Buffers.readLengthPrefixedString(payload);
// int bestHeight (size of known block chain).
bestHeight = ByteUtils.readUint32(payload);
relayTxesBeforeFilter =
clientVersion >= ProtocolVersion.BLOOM_FILTER.intValue() ?
payload.get() != 0 :
true;
throw new UnsupportedOperationException();
}
@Override

View file

@ -37,7 +37,7 @@ public class VersionMessageTest {
public void decode_noRelay_bestHeight_subVer() {
// Test that we can decode version messages which miss data which some old nodes may not include
String hex = "7111010000000000000000003334a85500000000000000000000000000000000000000000000ffff7f000001479d000000000000000000000000000000000000ffff7f000001479d00000000000000000f2f626974636f696e6a3a302e31332f0004000000";
VersionMessage ver = new VersionMessage(ByteBuffer.wrap(ByteUtils.parseHex(hex)));
VersionMessage ver = VersionMessage.read(ByteBuffer.wrap(ByteUtils.parseHex(hex)));
assertFalse(ver.relayTxesBeforeFilter);
assertEquals(1024, ver.bestHeight);
assertEquals("/bitcoinj:0.13/", ver.subVer);
@ -46,7 +46,7 @@ public class VersionMessageTest {
@Test
public void decode_relay_bestHeight_subVer() {
String hex = "711101000000000000000000a634a85500000000000000000000000000000000000000000000ffff7f000001479d000000000000000000000000000000000000ffff7f000001479d00000000000000000f2f626974636f696e6a3a302e31332f0004000001";
VersionMessage ver = new VersionMessage(ByteBuffer.wrap(ByteUtils.parseHex(hex)));
VersionMessage ver = VersionMessage.read(ByteBuffer.wrap(ByteUtils.parseHex(hex)));
assertTrue(ver.relayTxesBeforeFilter);
assertEquals(1024, ver.bestHeight);
assertEquals("/bitcoinj:0.13/", ver.subVer);
@ -55,7 +55,7 @@ public class VersionMessageTest {
@Test
public void decode_relay_noBestHeight_subVer() {
String hex = "711101000000000000000000c334a85500000000000000000000000000000000000000000000ffff7f000001479d000000000000000000000000000000000000ffff7f000001479d00000000000000000f2f626974636f696e6a3a302e31332f0000000001";
VersionMessage ver = new VersionMessage(ByteBuffer.wrap(ByteUtils.parseHex(hex)));
VersionMessage ver = VersionMessage.read(ByteBuffer.wrap(ByteUtils.parseHex(hex)));
assertTrue(ver.relayTxesBeforeFilter);
assertEquals(0, ver.bestHeight);
assertEquals("/bitcoinj:0.13/", ver.subVer);
@ -64,7 +64,7 @@ public class VersionMessageTest {
@Test(expected = ProtocolException.class)
public void decode_relay_noBestHeight_noSubVer() {
String hex = "00000000000000000000000048e5e95000000000000000000000000000000000000000000000ffff7f000001479d000000000000000000000000000000000000ffff7f000001479d0000000000000000";
VersionMessage ver = new VersionMessage(ByteBuffer.wrap(ByteUtils.parseHex(hex)));
VersionMessage ver = VersionMessage.read(ByteBuffer.wrap(ByteUtils.parseHex(hex)));
}
@Test
@ -75,7 +75,7 @@ public class VersionMessageTest {
ver.localServices = Services.of(1);
ver.receivingAddr = new InetSocketAddress(InetAddress.getByName("4.3.2.1"), 8333);
byte[] serialized = ver.bitcoinSerialize();
VersionMessage ver2 = new VersionMessage(ByteBuffer.wrap(serialized));
VersionMessage ver2 = VersionMessage.read(ByteBuffer.wrap(serialized));
assertEquals(1234, ver2.bestHeight);
assertEquals(Instant.ofEpochSecond(23456), ver2.time);
assertEquals("/bitcoinj/", ver2.subVer);
@ -93,7 +93,7 @@ public class VersionMessageTest {
ver.localServices = Services.of(1);
ver.receivingAddr = new InetSocketAddress(InetAddress.getByName("2002:db8:85a3:0:0:8a2e:370:7335"), 8333);
byte[] serialized = ver.bitcoinSerialize();
VersionMessage ver2 = new VersionMessage(ByteBuffer.wrap(serialized));
VersionMessage ver2 = VersionMessage.read(ByteBuffer.wrap(serialized));
assertEquals(1234, ver2.bestHeight);
assertEquals(Instant.ofEpochSecond(23456), ver2.time);
assertEquals("/bitcoinj/", ver2.subVer);