From 16ba4269327bc14bbe4129fab7a656a94da16390 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Mon, 30 May 2022 14:36:42 +0200 Subject: [PATCH] Added HEIGHT_V3 message with the following additions: - latest block's reference - latest block's online accounts count - latest blocks transaction count These are then retained locally in PeerChainTipData (as optional values, which will be null if peer doesn't support HEIGHT_V3 yet). --- .../org/qortal/controller/Controller.java | 25 ++++ .../qortal/data/network/PeerChainTipData.java | 31 ++++- src/main/java/org/qortal/network/Network.java | 16 +++ .../network/message/HeightV3Message.java | 113 ++++++++++++++++++ .../qortal/network/message/MessageType.java | 1 + 5 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/qortal/network/message/HeightV3Message.java diff --git a/src/main/java/org/qortal/controller/Controller.java b/src/main/java/org/qortal/controller/Controller.java index a5ada0c2..8d8939ba 100644 --- a/src/main/java/org/qortal/controller/Controller.java +++ b/src/main/java/org/qortal/controller/Controller.java @@ -1197,6 +1197,10 @@ public class Controller extends Thread { onNetworkHeightV2Message(peer, message); break; + case HEIGHT_V3: + onNetworkHeightV3Message(peer, message); + break; + case GET_TRANSACTION: TransactionImporter.getInstance().onNetworkGetTransactionMessage(peer, message); break; @@ -1537,6 +1541,27 @@ public class Controller extends Thread { Synchronizer.getInstance().requestSync(); } + private void onNetworkHeightV3Message(Peer peer, Message message) { + HeightV3Message heightV3Message = (HeightV3Message) message; + + if (!Settings.getInstance().isLite()) { + // If peer is inbound and we've not updated their height + // then this is probably their initial HEIGHT_V3 message + // so they need a corresponding HEIGHT_V3 message from us + if (!peer.isOutbound() && (peer.getChainTipData() == null || peer.getChainTipData().getLastHeight() == null)) + peer.sendMessage(Network.getInstance().buildHeightMessage(peer, getChainTip())); + } + + // Update peer chain tip data + PeerChainTipData newChainTipData = new PeerChainTipData(heightV3Message.getHeight(), heightV3Message.getSignature(), + heightV3Message.getReference(), heightV3Message.getTimestamp(), heightV3Message.getMinterPublicKey(), + heightV3Message.getOnlineAccountsCount(), heightV3Message.getTransactionCount()); + peer.setChainTipData(newChainTipData); + + // Potentially synchronize + Synchronizer.getInstance().requestSync(); + } + private void onNetworkGetAccountMessage(Peer peer, Message message) { GetAccountMessage getAccountMessage = (GetAccountMessage) message; String address = getAccountMessage.getAddress(); diff --git a/src/main/java/org/qortal/data/network/PeerChainTipData.java b/src/main/java/org/qortal/data/network/PeerChainTipData.java index d8dbbad4..3cec0a08 100644 --- a/src/main/java/org/qortal/data/network/PeerChainTipData.java +++ b/src/main/java/org/qortal/data/network/PeerChainTipData.java @@ -6,19 +6,34 @@ public class PeerChainTipData { private Integer lastHeight; /** Latest block signature as reported by peer. */ private byte[] lastBlockSignature; + /** Latest block reference as reported by peer. */ + private byte[] lastBlockReference; /** Latest block timestamp as reported by peer. */ private Long lastBlockTimestamp; /** Latest block minter public key as reported by peer. */ private byte[] lastBlockMinter; + /** Latest block's online accounts count as reported by peer. */ + private Integer lastBlockOnlineAccountsCount; + /** Latest block's transaction count as reported by peer. */ + private Integer lastBlockTransactionCount; - public PeerChainTipData(Integer lastHeight, byte[] lastBlockSignature, Long lastBlockTimestamp, byte[] lastBlockMinter) { + public PeerChainTipData(Integer lastHeight, byte[] lastBlockSignature, byte[] lastBlockReference, + Long lastBlockTimestamp, byte[] lastBlockMinter, Integer lastBlockOnlineAccountsCount, + Integer lastBlockTransactionCount) { this.lastHeight = lastHeight; this.lastBlockSignature = lastBlockSignature; + this.lastBlockReference = lastBlockReference; this.lastBlockTimestamp = lastBlockTimestamp; this.lastBlockMinter = lastBlockMinter; + this.lastBlockOnlineAccountsCount = lastBlockOnlineAccountsCount; + this.lastBlockTransactionCount = lastBlockTransactionCount; } - public Integer getLastHeight() { + public PeerChainTipData(Integer lastHeight, byte[] lastBlockSignature, Long lastBlockTimestamp, byte[] lastBlockMinter) { + this(lastHeight, lastBlockSignature, null, lastBlockTimestamp, lastBlockMinter, null, null); + } + + public Integer getLastHeight() { return this.lastHeight; } @@ -26,6 +41,10 @@ public class PeerChainTipData { return this.lastBlockSignature; } + public byte[] getLastBlockReference() { + return this.lastBlockReference; + } + public Long getLastBlockTimestamp() { return this.lastBlockTimestamp; } @@ -34,4 +53,12 @@ public class PeerChainTipData { return this.lastBlockMinter; } + public Integer getLastBlockOnlineAccountsCount() { + return this.lastBlockOnlineAccountsCount; + } + + public Integer getLastBlockTransactionCount() { + return this.lastBlockTransactionCount; + } + } diff --git a/src/main/java/org/qortal/network/Network.java b/src/main/java/org/qortal/network/Network.java index 6bc58bb4..37956a8c 100644 --- a/src/main/java/org/qortal/network/Network.java +++ b/src/main/java/org/qortal/network/Network.java @@ -1163,11 +1163,27 @@ public class Network { } public Message buildHeightMessage(Peer peer, BlockData blockData) { + final long HEIGHT_V3_PEER_VERSION = 0x0300030003L; + + if (peer.getPeersVersion() >= HEIGHT_V3_PEER_VERSION) { + return Network.getInstance().buildHeightV3Message(peer, blockData); + } else { + return Network.getInstance().buildHeightV2Message(peer, blockData); + } + } + private Message buildHeightV2Message(Peer peer, BlockData blockData) { // HEIGHT_V2 contains way more useful info return new HeightV2Message(blockData.getHeight(), blockData.getSignature(), blockData.getTimestamp(), blockData.getMinterPublicKey()); } + private Message buildHeightV3Message(Peer peer, BlockData blockData) { + // HEIGHT_V3 contains even more useful info + return new HeightV3Message(blockData.getHeight(), blockData.getSignature(), blockData.getReference(), + blockData.getTimestamp(), blockData.getMinterPublicKey(), blockData.getOnlineAccountsCount(), + blockData.getTransactionCount()); + } + public Message buildNewTransactionMessage(Peer peer, TransactionData transactionData) { // In V2 we send out transaction signature only and peers can decide whether to request the full transaction return new TransactionSignaturesMessage(Collections.singletonList(transactionData.getSignature())); diff --git a/src/main/java/org/qortal/network/message/HeightV3Message.java b/src/main/java/org/qortal/network/message/HeightV3Message.java new file mode 100644 index 00000000..004a1d9b --- /dev/null +++ b/src/main/java/org/qortal/network/message/HeightV3Message.java @@ -0,0 +1,113 @@ +package org.qortal.network.message; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import org.qortal.transform.Transformer; +import org.qortal.transform.block.BlockTransformer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +public class HeightV3Message extends Message { + + private int height; + private byte[] signature; + private byte[] reference; + private long timestamp; + private byte[] minterPublicKey; + private int onlineAccountsCount; + private int transactionCount; + + public HeightV3Message(int height, byte[] signature, byte[] reference, long timestamp, byte[] minterPublicKey, + int onlineAccountsCount, int transactionCount) { + super(MessageType.HEIGHT_V3); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + + try { + bytes.write(Ints.toByteArray(height)); + + bytes.write(signature); + + bytes.write(reference); + + bytes.write(Longs.toByteArray(timestamp)); + + bytes.write(minterPublicKey); + + bytes.write(Ints.toByteArray(onlineAccountsCount)); + + bytes.write(Ints.toByteArray(transactionCount)); + } catch (IOException e) { + throw new AssertionError("IOException shouldn't occur with ByteArrayOutputStream"); + } + + this.dataBytes = bytes.toByteArray(); + this.checksumBytes = Message.generateChecksum(this.dataBytes); + } + + private HeightV3Message(int id, int height, byte[] signature, byte[] reference, long timestamp, byte[] minterPublicKey, + int onlineAccountsCount, int transactionCount) { + super(id, MessageType.HEIGHT_V3); + + this.height = height; + this.signature = signature; + this.reference = reference; + this.timestamp = timestamp; + this.minterPublicKey = minterPublicKey; + this.onlineAccountsCount = onlineAccountsCount; + this.transactionCount = transactionCount; + } + + public int getHeight() { + return this.height; + } + + public byte[] getSignature() { + return this.signature; + } + + public byte[] getReference() { + return this.reference; + } + + public long getTimestamp() { + return this.timestamp; + } + + public byte[] getMinterPublicKey() { + return this.minterPublicKey; + } + + public int getOnlineAccountsCount() { + return this.onlineAccountsCount; + } + + public int getTransactionCount() { + return this.transactionCount; + } + + public static Message fromByteBuffer(int id, ByteBuffer bytes) { + int height = bytes.getInt(); + + byte[] signature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH]; + bytes.get(signature); + + byte[] reference = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH]; + bytes.get(reference); + + long timestamp = bytes.getLong(); + + byte[] minterPublicKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; + bytes.get(minterPublicKey); + + int onlineAccountsCount = bytes.getInt(); + + int transactionCount = bytes.getInt(); + + return new HeightV3Message(id, height, signature, reference, timestamp, minterPublicKey, onlineAccountsCount, + transactionCount); + } + +} diff --git a/src/main/java/org/qortal/network/message/MessageType.java b/src/main/java/org/qortal/network/message/MessageType.java index 8ad7a0da..08dd27be 100644 --- a/src/main/java/org/qortal/network/message/MessageType.java +++ b/src/main/java/org/qortal/network/message/MessageType.java @@ -18,6 +18,7 @@ public enum MessageType { HEIGHT_V2(10, HeightV2Message::fromByteBuffer), PING(11, PingMessage::fromByteBuffer), PONG(12, PongMessage::fromByteBuffer), + HEIGHT_V3(13, HeightV3Message::fromByteBuffer), // Requesting data PEERS_V2(20, PeersV2Message::fromByteBuffer),