From 3acc0babb7abe149f0d7c6d9aa28f8fd5a27ba47 Mon Sep 17 00:00:00 2001 From: catbref Date: Wed, 29 Jul 2020 14:25:00 +0100 Subject: [PATCH] More chain-weight tests --- .../org/qortal/test/ChainWeightTests.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/test/java/org/qortal/test/ChainWeightTests.java b/src/test/java/org/qortal/test/ChainWeightTests.java index b02c155e..d133dad1 100644 --- a/src/test/java/org/qortal/test/ChainWeightTests.java +++ b/src/test/java/org/qortal/test/ChainWeightTests.java @@ -3,6 +3,8 @@ package org.qortal.test; import static org.junit.Assert.*; import java.math.BigInteger; +import java.text.DecimalFormat; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -23,6 +25,7 @@ import org.junit.Test; public class ChainWeightTests extends Common { private static final Random RANDOM = new Random(); + private static final NumberFormat FORMATTER = new DecimalFormat("0.###E0"); @Before public void beforeTest() throws DataException { @@ -89,6 +92,96 @@ public class ChainWeightTests extends Common { } } + // Demonstrates that typical key distance ranges from roughly 1E75 to 1E77 + @Test + public void testKeyDistances() { + byte[] parentMinterKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; + byte[] testKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; + + for (int i = 0; i < 50; ++i) { + int parentHeight = RANDOM.nextInt(50000); + RANDOM.nextBytes(parentMinterKey); + RANDOM.nextBytes(testKey); + int minterLevel = RANDOM.nextInt(10) + 1; + + BigInteger keyDistance = Block.calcKeyDistance(parentHeight, parentMinterKey, testKey, minterLevel); + + System.out.println(String.format("Parent height: %d, minter level: %d, distance: %s", + parentHeight, + minterLevel, + FORMATTER.format(keyDistance))); + } + } + + // If typical key distance ranges from 1E75 to 1E77 + // then we want lots of online accounts to push a 1E75 distance + // towards 1E77 so that it competes with a 1E77 key that has hardly any online accounts + // 1E75 is approx. 2**249 so maybe that's a good value for Block.ACCOUNTS_COUNT_SHIFT + @Test + public void testMoreAccountsVersusKeyDistance() throws DataException { + BigInteger minimumBetterKeyDistance = BigInteger.TEN.pow(77); + BigInteger maximumWorseKeyDistance = BigInteger.TEN.pow(75); + + try (final Repository repository = RepositoryManager.getRepository()) { + final byte[] parentMinterKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; + + TestAccount betterAccount = Common.getTestAccount(repository, "bob-reward-share"); + byte[] betterKey = betterAccount.getPublicKey(); + int betterMinterLevel = Account.getRewardShareEffectiveMintingLevel(repository, betterKey); + + TestAccount worseAccount = Common.getTestAccount(repository, "dilbert-reward-share"); + byte[] worseKey = worseAccount.getPublicKey(); + int worseMinterLevel = Account.getRewardShareEffectiveMintingLevel(repository, worseKey); + + // This is to check that the hard-coded keys ARE actually better/worse as expected, before moving on testing more online accounts + BigInteger betterKeyDistance; + BigInteger worseKeyDistance; + + int parentHeight = 0; + do { + ++parentHeight; + betterKeyDistance = Block.calcKeyDistance(parentHeight, parentMinterKey, betterKey, betterMinterLevel); + worseKeyDistance = Block.calcKeyDistance(parentHeight, parentMinterKey, worseKey, worseMinterLevel); + } while (betterKeyDistance.compareTo(minimumBetterKeyDistance) < 0 || worseKeyDistance.compareTo(maximumWorseKeyDistance) > 0); + + System.out.println(String.format("Parent height: %d, better key distance: %s, worse key distance: %s", + parentHeight, + FORMATTER.format(betterKeyDistance), + FORMATTER.format(worseKeyDistance))); + + for (int accountsCountShift = 244; accountsCountShift <= 256; accountsCountShift += 2) { + for (int worseAccountsCount = 1; worseAccountsCount <= 101; worseAccountsCount += 25) { + for (int betterAccountsCount = 1; betterAccountsCount <= 1001; betterAccountsCount += 250) { + BlockSummaryData worseKeyBlockSummary = new BlockSummaryData(parentHeight + 1, null, worseKey, betterAccountsCount); + BlockSummaryData betterKeyBlockSummary = new BlockSummaryData(parentHeight + 1, null, betterKey, worseAccountsCount); + + populateBlockSummaryMinterLevel(repository, worseKeyBlockSummary); + populateBlockSummaryMinterLevel(repository, betterKeyBlockSummary); + + BigInteger worseKeyBlockWeight = calcBlockWeight(parentHeight, parentMinterKey, worseKeyBlockSummary, accountsCountShift); + BigInteger betterKeyBlockWeight = calcBlockWeight(parentHeight, parentMinterKey, betterKeyBlockSummary, accountsCountShift); + + System.out.println(String.format("Shift: %d, worse key: %d accounts, %s diff; better key: %d accounts: %s diff; winner: %s", + accountsCountShift, + betterAccountsCount, // used with worseKey + FORMATTER.format(worseKeyBlockWeight), + worseAccountsCount, // used with betterKey + FORMATTER.format(betterKeyBlockWeight), + worseKeyBlockWeight.compareTo(betterKeyBlockWeight) > 0 ? "worse key/better accounts" : "better key/worse accounts" + )); + } + } + + System.out.println(); + } + } + } + + private static BigInteger calcBlockWeight(int parentHeight, byte[] parentBlockSignature, BlockSummaryData blockSummaryData, int accountsCountShift) { + BigInteger keyDistance = Block.calcKeyDistance(parentHeight, parentBlockSignature, blockSummaryData.getMinterPublicKey(), blockSummaryData.getMinterLevel()); + return BigInteger.valueOf(blockSummaryData.getOnlineAccountsCount()).shiftLeft(accountsCountShift).add(keyDistance); + } + // Check that a longer chain beats a shorter chain @Test public void testLongerChain() throws DataException {