diff --git a/src/test/java/org/qortal/test/SchnorrTests.java b/src/test/java/org/qortal/test/SchnorrTests.java index 03c92d2f..e0d1f1c9 100644 --- a/src/test/java/org/qortal/test/SchnorrTests.java +++ b/src/test/java/org/qortal/test/SchnorrTests.java @@ -8,6 +8,7 @@ import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.junit.Test; import org.qortal.crypto.Qortal25519Extras; import org.qortal.data.network.OnlineAccountData; +import org.qortal.test.common.AccountUtils; import org.qortal.transform.Transformer; import java.math.BigInteger; @@ -28,8 +29,6 @@ public class SchnorrTests extends Qortal25519Extras { Security.insertProviderAt(new BouncyCastleJsseProvider(), 1); } - private static final SecureRandom SECURE_RANDOM = new SecureRandom(); - @Test public void testConversion() { // Scalar form @@ -130,7 +129,7 @@ public class SchnorrTests extends Qortal25519Extras { @Test public void testSimpleAggregate() { - List onlineAccounts = generateOnlineAccounts(1); + List onlineAccounts = AccountUtils.generateOnlineAccounts(1); byte[] aggregatePublicKey = aggregatePublicKeys(onlineAccounts.stream().map(OnlineAccountData::getPublicKey).collect(Collectors.toUnmodifiableList())); System.out.printf("Aggregate public key: %s%n", HashCode.fromBytes(aggregatePublicKey)); @@ -151,7 +150,7 @@ public class SchnorrTests extends Qortal25519Extras { @Test public void testMultipleAggregate() { - List onlineAccounts = generateOnlineAccounts(5000); + List onlineAccounts = AccountUtils.generateOnlineAccounts(5000); byte[] aggregatePublicKey = aggregatePublicKeys(onlineAccounts.stream().map(OnlineAccountData::getPublicKey).collect(Collectors.toUnmodifiableList())); System.out.printf("Aggregate public key: %s%n", HashCode.fromBytes(aggregatePublicKey)); @@ -166,25 +165,4 @@ public class SchnorrTests extends Qortal25519Extras { byte[] timestampBytes = Longs.toByteArray(timestamp); assertTrue(verifyAggregated(aggregatePublicKey, aggregateSignature, timestampBytes)); } - - private List generateOnlineAccounts(int numAccounts) { - List onlineAccounts = new ArrayList<>(); - - long timestamp = System.currentTimeMillis(); - byte[] timestampBytes = Longs.toByteArray(timestamp); - - for (int a = 0; a < numAccounts; ++a) { - byte[] privateKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; - SECURE_RANDOM.nextBytes(privateKey); - - byte[] publicKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; - Qortal25519Extras.generatePublicKey(privateKey, 0, publicKey, 0); - - byte[] signature = signForAggregation(privateKey, timestampBytes); - - onlineAccounts.add(new OnlineAccountData(timestamp, signature, publicKey)); - } - - return onlineAccounts; - } } diff --git a/src/test/java/org/qortal/test/common/AccountUtils.java b/src/test/java/org/qortal/test/common/AccountUtils.java index ffc4a7a1..0d0b6d6a 100644 --- a/src/test/java/org/qortal/test/common/AccountUtils.java +++ b/src/test/java/org/qortal/test/common/AccountUtils.java @@ -1,12 +1,17 @@ package org.qortal.test.common; import static org.junit.Assert.assertEquals; +import static org.qortal.crypto.Qortal25519Extras.signForAggregation; -import java.util.HashMap; -import java.util.Map; +import java.security.SecureRandom; +import java.util.*; +import com.google.common.primitives.Longs; import org.qortal.account.PrivateKeyAccount; +import org.qortal.block.BlockChain; import org.qortal.crypto.Crypto; +import org.qortal.crypto.Qortal25519Extras; +import org.qortal.data.network.OnlineAccountData; import org.qortal.data.transaction.BaseTransactionData; import org.qortal.data.transaction.PaymentTransactionData; import org.qortal.data.transaction.RewardShareTransactionData; @@ -14,6 +19,7 @@ import org.qortal.data.transaction.TransactionData; import org.qortal.group.Group; import org.qortal.repository.DataException; import org.qortal.repository.Repository; +import org.qortal.transform.Transformer; import org.qortal.utils.Amounts; public class AccountUtils { @@ -21,6 +27,8 @@ public class AccountUtils { public static final int txGroupId = Group.NO_GROUP; public static final long fee = 1L * Amounts.MULTIPLIER; + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + public static void pay(Repository repository, String testSenderName, String testRecipientName, long amount) throws DataException { PrivateKeyAccount sendingAccount = Common.getTestAccount(repository, testSenderName); PrivateKeyAccount recipientAccount = Common.getTestAccount(repository, testRecipientName); @@ -109,4 +117,30 @@ public class AccountUtils { assertEquals(String.format("%s's %s [%d] balance incorrect", accountName, assetName, assetId), expectedBalance, actualBalance); } + + public static List generateOnlineAccounts(int numAccounts) { + List onlineAccounts = new ArrayList<>(); + + long timestamp = System.currentTimeMillis(); + byte[] timestampBytes = Longs.toByteArray(timestamp); + + final boolean mempowActive = timestamp >= BlockChain.getInstance().getOnlineAccountsMemoryPoWTimestamp(); + + for (int a = 0; a < numAccounts; ++a) { + byte[] privateKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; + SECURE_RANDOM.nextBytes(privateKey); + + byte[] publicKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; + Qortal25519Extras.generatePublicKey(privateKey, 0, publicKey, 0); + + byte[] signature = signForAggregation(privateKey, timestampBytes); + + Integer nonce = mempowActive ? new Random().nextInt(500000) : null; + + onlineAccounts.add(new OnlineAccountData(timestamp, signature, publicKey, nonce)); + } + + return onlineAccounts; + } + } diff --git a/src/test/java/org/qortal/test/network/OnlineAccountsTests.java b/src/test/java/org/qortal/test/network/OnlineAccountsTests.java index 0b554b6a..c5a3115b 100644 --- a/src/test/java/org/qortal/test/network/OnlineAccountsTests.java +++ b/src/test/java/org/qortal/test/network/OnlineAccountsTests.java @@ -1,26 +1,29 @@ package org.qortal.test.network; +import com.google.common.primitives.Ints; +import io.druid.extendedset.intset.ConciseSet; import org.apache.commons.lang3.reflect.FieldUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; -import org.qortal.account.PrivateKeyAccount; import org.qortal.block.Block; import org.qortal.block.BlockChain; import org.qortal.controller.BlockMinter; -import org.qortal.controller.OnlineAccountsManager; import org.qortal.data.network.OnlineAccountData; import org.qortal.network.message.*; import org.qortal.repository.DataException; import org.qortal.repository.Repository; import org.qortal.repository.RepositoryManager; import org.qortal.settings.Settings; +import org.qortal.test.common.AccountUtils; import org.qortal.test.common.Common; import org.qortal.transform.Transformer; import org.qortal.utils.Base58; import org.qortal.utils.NTP; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.security.Security; @@ -202,4 +205,31 @@ public class OnlineAccountsTests extends Common { assertTrue(onlineAccountSignatures.size() >= 1 && onlineAccountSignatures.size() <= 3); } } + + @Test + @Ignore(value = "For informational use") + public void testOnlineAccountNonceCompression() throws IOException { + List onlineAccounts = AccountUtils.generateOnlineAccounts(5000); + + // Build array of nonce values + List accountNonces = new ArrayList<>(); + for (OnlineAccountData onlineAccountData : onlineAccounts) { + accountNonces.add(onlineAccountData.getNonce()); + } + + // Write nonces into ConciseSet + ConciseSet nonceSet = new ConciseSet(); + nonceSet = nonceSet.convert(accountNonces); + byte[] conciseEncodedNonces = nonceSet.toByteBuffer().array(); + + // Also write to regular byte array of ints, for comparison + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + for (Integer nonce : accountNonces) { + bytes.write(Ints.toByteArray(nonce)); + } + byte[] standardEncodedNonces = bytes.toByteArray(); + + System.out.println(String.format("Standard: %d", standardEncodedNonces.length)); + System.out.println(String.format("Concise: %d", conciseEncodedNonces.length)); + } }