Browse Source

Committed stashed code that is functional but probably too messy for production use.

Online account nonces are appended to the onlineAccountsSignatures to avoid the need for a new field, but it probably makes more sense to separate them.
online-accounts-mempow-v2-block-updates
CalDescent 2 years ago
parent
commit
46c40ca9ca
  1. 71
      src/main/java/org/qortal/block/Block.java
  2. 40
      src/main/java/org/qortal/transform/block/BlockTransformer.java
  3. 2
      src/main/resources/blockchain.json
  4. 4
      src/test/java/org/qortal/test/BlockArchiveTests.java

71
src/main/java/org/qortal/block/Block.java

@ -10,7 +10,6 @@ import java.math.BigInteger;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -90,7 +89,8 @@ public class Block {
ONLINE_ACCOUNT_UNKNOWN(71), ONLINE_ACCOUNT_UNKNOWN(71),
ONLINE_ACCOUNT_SIGNATURES_MISSING(72), ONLINE_ACCOUNT_SIGNATURES_MISSING(72),
ONLINE_ACCOUNT_SIGNATURES_MALFORMED(73), ONLINE_ACCOUNT_SIGNATURES_MALFORMED(73),
ONLINE_ACCOUNT_SIGNATURE_INCORRECT(74); ONLINE_ACCOUNT_SIGNATURE_INCORRECT(74),
ONLINE_ACCOUNT_NONCE_INCORRECT(75);
public final int value; public final int value;
@ -409,6 +409,31 @@ public class Block {
} }
} }
// Add nonces to the end of the online accounts signatures if mempow is active
if (timestamp >= BlockChain.getInstance().getOnlineAccountsMemoryPoWTimestamp()) {
try {
// Create ordered list of nonce values
List<Integer> nonces = new ArrayList<>();
for (int i = 0; i < onlineAccountsCount; ++i) {
Integer accountIndex = accountIndexes.get(i);
OnlineAccountData onlineAccountData = indexedOnlineAccounts.get(accountIndex);
nonces.add(onlineAccountData.getNonce());
}
// Encode the nonces to a byte array
byte[] encodedNonces = BlockTransformer.encodeOnlineAccountNonces(nonces);
// Append the encoded nonces to the encoded online account signatures
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(onlineAccountsSignatures);
outputStream.write(encodedNonces);
onlineAccountsSignatures = outputStream.toByteArray();
}
catch (TransformationException | IOException e) {
return null;
}
}
byte[] minterSignature = minter.sign(BlockTransformer.getBytesForMinterSignature(parentBlockData, byte[] minterSignature = minter.sign(BlockTransformer.getBytesForMinterSignature(parentBlockData,
minter.getPublicKey(), encodedOnlineAccounts)); minter.getPublicKey(), encodedOnlineAccounts));
@ -1016,12 +1041,15 @@ public class Block {
if (this.blockData.getOnlineAccountsSignatures() == null || this.blockData.getOnlineAccountsSignatures().length == 0) if (this.blockData.getOnlineAccountsSignatures() == null || this.blockData.getOnlineAccountsSignatures().length == 0)
return ValidationResult.ONLINE_ACCOUNT_SIGNATURES_MISSING; return ValidationResult.ONLINE_ACCOUNT_SIGNATURES_MISSING;
if (this.blockData.getTimestamp() >= BlockChain.getInstance().getAggregateSignatureTimestamp()) { final int signaturesLength = (this.blockData.getTimestamp() >= BlockChain.getInstance().getAggregateSignatureTimestamp()) ? Transformer.SIGNATURE_LENGTH : onlineRewardShares.size() * Transformer.SIGNATURE_LENGTH;
// We expect just the one, aggregated signature final int noncesLength = onlineRewardShares.size() * Transformer.INT_LENGTH;
if (this.blockData.getOnlineAccountsSignatures().length != Transformer.SIGNATURE_LENGTH)
if (this.blockData.getTimestamp() >= BlockChain.getInstance().getOnlineAccountsMemoryPoWTimestamp()) {
// We expect nonces to be appended to the online accounts signatures
if (this.blockData.getOnlineAccountsSignatures().length != signaturesLength + noncesLength)
return ValidationResult.ONLINE_ACCOUNT_SIGNATURES_MALFORMED; return ValidationResult.ONLINE_ACCOUNT_SIGNATURES_MALFORMED;
} else { } else {
if (this.blockData.getOnlineAccountsSignatures().length != onlineRewardShares.size() * Transformer.SIGNATURE_LENGTH) if (this.blockData.getOnlineAccountsSignatures().length != signaturesLength)
return ValidationResult.ONLINE_ACCOUNT_SIGNATURES_MALFORMED; return ValidationResult.ONLINE_ACCOUNT_SIGNATURES_MALFORMED;
} }
@ -1029,8 +1057,37 @@ public class Block {
long onlineTimestamp = this.blockData.getOnlineAccountsTimestamp(); long onlineTimestamp = this.blockData.getOnlineAccountsTimestamp();
byte[] onlineTimestampBytes = Longs.toByteArray(onlineTimestamp); byte[] onlineTimestampBytes = Longs.toByteArray(onlineTimestamp);
byte[] encodedOnlineAccountSignatures = this.blockData.getOnlineAccountsSignatures();
// Split online account signatures into signature(s) + nonces, then validate the nonces
if (this.blockData.getTimestamp() >= BlockChain.getInstance().getOnlineAccountsMemoryPoWTimestamp()) {
byte[] extractedSignatures = BlockTransformer.extract(encodedOnlineAccountSignatures, 0, signaturesLength);
byte[] extractedNonces = BlockTransformer.extract(encodedOnlineAccountSignatures, signaturesLength, onlineRewardShares.size() * Transformer.INT_LENGTH);
encodedOnlineAccountSignatures = extractedSignatures;
List<Integer> nonces = BlockTransformer.decodeOnlineAccountNonces(extractedNonces);
// Build block's view of online accounts (without signatures, as we don't need them here)
Set<OnlineAccountData> onlineAccounts = new HashSet<>();
for (int i = 0; i < onlineRewardShares.size(); ++i) {
Integer nonce = nonces.get(i);
byte[] publicKey = onlineRewardShares.get(i).getRewardSharePublicKey();
OnlineAccountData onlineAccountData = new OnlineAccountData(onlineTimestamp, null, publicKey, nonce);
onlineAccounts.add(onlineAccountData);
}
// Remove those already validated & cached by online accounts manager - no need to re-validate them
OnlineAccountsManager.getInstance().removeKnown(onlineAccounts, onlineTimestamp);
// Validate the rest
for (OnlineAccountData onlineAccount : onlineAccounts)
if (!OnlineAccountsManager.getInstance().verifyMemoryPoW(onlineAccount, this.blockData.getTimestamp()))
return ValidationResult.ONLINE_ACCOUNT_NONCE_INCORRECT;
}
// Extract online accounts' timestamp signatures from block data. Only one signature if aggregated. // Extract online accounts' timestamp signatures from block data. Only one signature if aggregated.
List<byte[]> onlineAccountsSignatures = BlockTransformer.decodeTimestampSignatures(this.blockData.getOnlineAccountsSignatures()); List<byte[]> onlineAccountsSignatures = BlockTransformer.decodeTimestampSignatures(encodedOnlineAccountSignatures);
if (this.blockData.getTimestamp() >= BlockChain.getInstance().getAggregateSignatureTimestamp()) { if (this.blockData.getTimestamp() >= BlockChain.getInstance().getAggregateSignatureTimestamp()) {
// Aggregate all public keys // Aggregate all public keys

40
src/main/java/org/qortal/transform/block/BlockTransformer.java

@ -478,4 +478,44 @@ public class BlockTransformer extends Transformer {
return signatures; return signatures;
} }
public static byte[] encodeOnlineAccountNonces(List<Integer> nonces) throws TransformationException {
try {
final int length = nonces.size() * Transformer.INT_LENGTH;
ByteArrayOutputStream bytes = new ByteArrayOutputStream(length);
for (int i = 0; i < nonces.size(); ++i) {
Integer nonce = nonces.get(i);
if (nonce == null || nonce < 0) {
throw new TransformationException("Unable to serialize online account nonces due to invalid value");
}
bytes.write(Ints.toByteArray(nonce));
}
return bytes.toByteArray();
} catch (IOException e) {
throw new TransformationException("Unable to serialize online account nonces", e);
}
}
public static List<Integer> decodeOnlineAccountNonces(byte[] encodedNonces) {
List<Integer> nonces = new ArrayList<>();
ByteBuffer bytes = ByteBuffer.wrap(encodedNonces);
final int count = encodedNonces.length / Transformer.INT_LENGTH;
for (int i = 0; i < count; i++) {
Integer nonce = bytes.getInt();
nonces.add(nonce);
}
return nonces;
}
public static byte[] extract(byte[] input, int pos, int length) {
byte[] output = new byte[length];
System.arraycopy(input, pos, output, 0, length);
return output;
}
} }

2
src/main/resources/blockchain.json

@ -72,7 +72,7 @@
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,
"timestamp": "1593450000000", "timestamp": "1656777099000",
"transactions": [ "transactions": [
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORTAL coin", "quantity": 0, "isDivisible": true, "data": "{}" }, { "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORTAL coin", "quantity": 0, "isDivisible": true, "data": "{}" },
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true }, { "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },

4
src/test/java/org/qortal/test/BlockArchiveTests.java

@ -361,7 +361,7 @@ public class BlockArchiveTests extends Common {
assertEquals(0, repository.getBlockArchiveRepository().getBlockArchiveHeight()); assertEquals(0, repository.getBlockArchiveRepository().getBlockArchiveHeight());
// Write blocks 2-900 to the archive (using bulk method) // Write blocks 2-900 to the archive (using bulk method)
int fileSizeTarget = 425000; // Pre-calculated size of 900 blocks int fileSizeTarget = 428600; // Pre-calculated size of 900 blocks
assertTrue(HSQLDBDatabaseArchiving.buildBlockArchive(repository, fileSizeTarget)); assertTrue(HSQLDBDatabaseArchiving.buildBlockArchive(repository, fileSizeTarget));
// Ensure the block archive height has increased // Ensure the block archive height has increased
@ -455,7 +455,7 @@ public class BlockArchiveTests extends Common {
assertEquals(0, repository.getBlockArchiveRepository().getBlockArchiveHeight()); assertEquals(0, repository.getBlockArchiveRepository().getBlockArchiveHeight());
// Write blocks 2-900 to the archive (using bulk method) // Write blocks 2-900 to the archive (using bulk method)
int fileSizeTarget = 42000; // Pre-calculated size of approx 90 blocks int fileSizeTarget = 42360; // Pre-calculated size of approx 90 blocks
assertTrue(HSQLDBDatabaseArchiving.buildBlockArchive(repository, fileSizeTarget)); assertTrue(HSQLDBDatabaseArchiving.buildBlockArchive(repository, fileSizeTarget));
// Ensure 10 archive files have been created // Ensure 10 archive files have been created

Loading…
Cancel
Save