forked from Qortal/qortal
Browse Source
This could potentially be released ahead of the other mempow code, splitting the rollout into multiple smaller phases.online-accounts-mempow-v2
CalDescent
2 years ago
5 changed files with 164 additions and 6 deletions
@ -0,0 +1,121 @@
|
||||
package org.qortal.network.message; |
||||
|
||||
import com.google.common.primitives.Ints; |
||||
import com.google.common.primitives.Longs; |
||||
import org.qortal.data.network.OnlineAccountData; |
||||
import org.qortal.transform.Transformer; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.nio.ByteBuffer; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* For sending online accounts info to remote peer. |
||||
* |
||||
* Same format as V2, but with added support for a mempow nonce. |
||||
*/ |
||||
public class OnlineAccountsV3Message extends Message { |
||||
|
||||
public static final long MIN_PEER_VERSION = 0x300050000L; // 3.5.0
|
||||
|
||||
private List<OnlineAccountData> onlineAccounts; |
||||
|
||||
public OnlineAccountsV3Message(List<OnlineAccountData> onlineAccounts) { |
||||
super(MessageType.ONLINE_ACCOUNTS_V3); |
||||
|
||||
// Shortcut in case we have no online accounts
|
||||
if (onlineAccounts.isEmpty()) { |
||||
this.dataBytes = Ints.toByteArray(0); |
||||
this.checksumBytes = Message.generateChecksum(this.dataBytes); |
||||
return; |
||||
} |
||||
|
||||
// How many of each timestamp
|
||||
Map<Long, Integer> countByTimestamp = new HashMap<>(); |
||||
|
||||
for (OnlineAccountData onlineAccountData : onlineAccounts) { |
||||
Long timestamp = onlineAccountData.getTimestamp(); |
||||
countByTimestamp.compute(timestamp, (k, v) -> v == null ? 1 : ++v); |
||||
} |
||||
|
||||
// We should know exactly how many bytes to allocate now
|
||||
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH) |
||||
+ onlineAccounts.size() * (Transformer.SIGNATURE_LENGTH + Transformer.PUBLIC_KEY_LENGTH); |
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize); |
||||
|
||||
try { |
||||
for (long timestamp : countByTimestamp.keySet()) { |
||||
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp))); |
||||
|
||||
bytes.write(Longs.toByteArray(timestamp)); |
||||
|
||||
for (OnlineAccountData onlineAccountData : onlineAccounts) { |
||||
if (onlineAccountData.getTimestamp() == timestamp) { |
||||
bytes.write(onlineAccountData.getSignature()); |
||||
bytes.write(onlineAccountData.getPublicKey()); |
||||
|
||||
// Nonce is optional; use -1 as placeholder if missing
|
||||
int nonce = onlineAccountData.getNonce() != null ? onlineAccountData.getNonce() : -1; |
||||
bytes.write(Ints.toByteArray(nonce)); |
||||
} |
||||
} |
||||
} |
||||
} catch (IOException e) { |
||||
throw new AssertionError("IOException shouldn't occur with ByteArrayOutputStream"); |
||||
} |
||||
|
||||
this.dataBytes = bytes.toByteArray(); |
||||
this.checksumBytes = Message.generateChecksum(this.dataBytes); |
||||
} |
||||
|
||||
private OnlineAccountsV3Message(int id, List<OnlineAccountData> onlineAccounts) { |
||||
super(id, MessageType.ONLINE_ACCOUNTS_V3); |
||||
|
||||
this.onlineAccounts = onlineAccounts; |
||||
} |
||||
|
||||
public List<OnlineAccountData> getOnlineAccounts() { |
||||
return this.onlineAccounts; |
||||
} |
||||
|
||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws MessageException { |
||||
int accountCount = bytes.getInt(); |
||||
|
||||
List<OnlineAccountData> onlineAccounts = new ArrayList<>(accountCount); |
||||
|
||||
while (accountCount > 0) { |
||||
long timestamp = bytes.getLong(); |
||||
|
||||
for (int i = 0; i < accountCount; ++i) { |
||||
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH]; |
||||
bytes.get(signature); |
||||
|
||||
byte[] publicKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; |
||||
bytes.get(publicKey); |
||||
|
||||
// Nonce is optional - will be -1 if missing
|
||||
Integer nonce = bytes.getInt(); |
||||
if (nonce < 0) { |
||||
nonce = null; |
||||
} |
||||
|
||||
onlineAccounts.add(new OnlineAccountData(timestamp, signature, publicKey, nonce)); |
||||
} |
||||
|
||||
if (bytes.hasRemaining()) { |
||||
accountCount = bytes.getInt(); |
||||
} else { |
||||
// we've finished
|
||||
accountCount = 0; |
||||
} |
||||
} |
||||
|
||||
return new OnlineAccountsV3Message(id, onlineAccounts); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue