From 2e989aaa572b5ef30c7cf75c7c58290a82250661 Mon Sep 17 00:00:00 2001 From: crowetic Date: Tue, 3 Dec 2024 08:29:53 -0800 Subject: [PATCH 1/2] A merge of just alpha's validation changes, phil and quick's commits, and kenny's changes to test. --- src/main/java/org/qortal/account/Account.java | 20 ++- .../qortal/api/model/ApiOnlineAccount.java | 33 ++++ .../qortal/api/model/BlockMintingInfo.java | 2 +- .../qortal/api/resource/BlocksResource.java | 3 +- src/main/java/org/qortal/block/Block.java | 51 ++++-- .../java/org/qortal/data/block/BlockData.java | 29 +++- .../org/qortal/test/BlockArchiveV1Tests.java | 153 ++++++++++++++++- .../org/qortal/test/BlockArchiveV2Tests.java | 160 +++++++++++++++++- .../test-chain-v2-block-timestamps.json | 11 +- .../test-chain-v2-disable-reference.json | 11 +- .../test-chain-v2-founder-rewards.json | 11 +- .../test-chain-v2-leftover-reward.json | 11 +- src/test/resources/test-chain-v2-minting.json | 11 +- .../resources/test-chain-v2-penalty-fix.json | 14 +- .../test-chain-v2-qora-holder-extremes.json | 11 +- .../test-chain-v2-qora-holder-reduction.json | 11 +- .../resources/test-chain-v2-qora-holder.json | 11 +- .../test-chain-v2-reward-levels.json | 11 +- .../test-chain-v2-reward-scaling.json | 11 +- .../test-chain-v2-reward-shares.json | 11 +- ...est-chain-v2-self-sponsorship-algo-v1.json | 11 +- ...est-chain-v2-self-sponsorship-algo-v2.json | 11 +- ...est-chain-v2-self-sponsorship-algo-v3.json | 11 +- src/test/resources/test-chain-v2.json | 8 +- 24 files changed, 568 insertions(+), 59 deletions(-) diff --git a/src/main/java/org/qortal/account/Account.java b/src/main/java/org/qortal/account/Account.java index 537f07881..99fa52176 100644 --- a/src/main/java/org/qortal/account/Account.java +++ b/src/main/java/org/qortal/account/Account.java @@ -349,10 +349,28 @@ public int getEffectiveMintingLevel() throws DataException { } /** - * Returns 'effective' minting level, or zero if reward-share does not exist. + * Returns reward-share minting address, or unknown if reward-share does not exist. * * @param repository * @param rewardSharePublicKey + * @return address or unknown + * @throws DataException + */ + public static String getRewardShareMintingAddress(Repository repository, byte[] rewardSharePublicKey) throws DataException { + // Find actual minter address + RewardShareData rewardShareData = repository.getAccountRepository().getRewardShare(rewardSharePublicKey); + + if (rewardShareData == null) + return "Unknown"; + + return rewardShareData.getMinter(); + } + + /** + * Returns 'effective' minting level, or zero if reward-share does not exist. + * + * @param repository + * @param rewardSharePublicKey * @return 0+ * @throws DataException */ diff --git a/src/main/java/org/qortal/api/model/ApiOnlineAccount.java b/src/main/java/org/qortal/api/model/ApiOnlineAccount.java index 08b697aa5..e26eb8164 100644 --- a/src/main/java/org/qortal/api/model/ApiOnlineAccount.java +++ b/src/main/java/org/qortal/api/model/ApiOnlineAccount.java @@ -1,7 +1,13 @@ package org.qortal.api.model; +import org.qortal.account.Account; +import org.qortal.repository.DataException; +import org.qortal.repository.RepositoryManager; +import org.qortal.repository.Repository; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; // All properties to be converted to JSON via JAXB @XmlAccessorType(XmlAccessType.FIELD) @@ -47,4 +53,31 @@ public String getRecipientAddress() { return this.recipientAddress; } + public int getMinterLevelFromPublicKey() { + try (final Repository repository = RepositoryManager.getRepository()) { + return Account.getRewardShareEffectiveMintingLevel(repository, this.rewardSharePublicKey); + } catch (DataException e) { + return 0; + } + } + + public boolean getIsMember() { + try (final Repository repository = RepositoryManager.getRepository()) { + return repository.getGroupRepository().memberExists(694, getMinterAddress()); + } catch (DataException e) { + return false; + } + } + + // JAXB special + + @XmlElement(name = "minterLevel") + protected int getMinterLevel() { + return getMinterLevelFromPublicKey(); + } + + @XmlElement(name = "isMinterMember") + protected boolean getMinterMember() { + return getIsMember(); + } } diff --git a/src/main/java/org/qortal/api/model/BlockMintingInfo.java b/src/main/java/org/qortal/api/model/BlockMintingInfo.java index f84e179e1..02765a89b 100644 --- a/src/main/java/org/qortal/api/model/BlockMintingInfo.java +++ b/src/main/java/org/qortal/api/model/BlockMintingInfo.java @@ -9,6 +9,7 @@ public class BlockMintingInfo { public byte[] minterPublicKey; + public String minterAddress; public int minterLevel; public int onlineAccountsCount; public BigDecimal maxDistance; @@ -19,5 +20,4 @@ public class BlockMintingInfo { public BlockMintingInfo() { } - } diff --git a/src/main/java/org/qortal/api/resource/BlocksResource.java b/src/main/java/org/qortal/api/resource/BlocksResource.java index 01d8d2ab2..ff0bb9791 100644 --- a/src/main/java/org/qortal/api/resource/BlocksResource.java +++ b/src/main/java/org/qortal/api/resource/BlocksResource.java @@ -542,6 +542,7 @@ public BlockMintingInfo getBlockMintingInfoByHeight(@PathParam("height") int hei } } + String minterAddress = Account.getRewardShareMintingAddress(repository, blockData.getMinterPublicKey()); int minterLevel = Account.getRewardShareEffectiveMintingLevel(repository, blockData.getMinterPublicKey()); if (minterLevel == 0) // This may be unavailable when requesting a trimmed block @@ -554,6 +555,7 @@ public BlockMintingInfo getBlockMintingInfoByHeight(@PathParam("height") int hei BlockMintingInfo blockMintingInfo = new BlockMintingInfo(); blockMintingInfo.minterPublicKey = blockData.getMinterPublicKey(); + blockMintingInfo.minterAddress = minterAddress; blockMintingInfo.minterLevel = minterLevel; blockMintingInfo.onlineAccountsCount = blockData.getOnlineAccountsCount(); blockMintingInfo.maxDistance = new BigDecimal(block.MAX_DISTANCE); @@ -887,5 +889,4 @@ public List getBlockSummaries( throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } - } diff --git a/src/main/java/org/qortal/block/Block.java b/src/main/java/org/qortal/block/Block.java index 918a20ae9..c9353d700 100644 --- a/src/main/java/org/qortal/block/Block.java +++ b/src/main/java/org/qortal/block/Block.java @@ -145,7 +145,7 @@ public static class ExpandedAccount { private final Account recipientAccount; private final AccountData recipientAccountData; - + final BlockChain blockChain = BlockChain.getInstance(); ExpandedAccount(Repository repository, RewardShareData rewardShareData) throws DataException { @@ -414,6 +414,21 @@ else if (isOnlineAccountsBlock(height)) { }); } + // After feature trigger, remove any online accounts that are not minter group member + if (height >= BlockChain.getInstance().getGroupMemberCheckHeight()) { + onlineAccounts.removeIf(a -> { + try { + int groupId = BlockChain.getInstance().getMintingGroupId(); + String address = Account.getRewardShareMintingAddress(repository, a.getPublicKey()); + boolean isMinterGroupMember = repository.getGroupRepository().memberExists(groupId, address); + return !isMinterGroupMember; + } catch (DataException e) { + // Something went wrong, so remove the account + return true; + } + }); + } + if (onlineAccounts.isEmpty()) { LOGGER.debug("No online accounts - not even our own?"); return null; @@ -721,19 +736,19 @@ public List getExpandedAccounts() throws DataException { List expandedAccounts = new ArrayList<>(); for (RewardShareData rewardShare : this.cachedOnlineRewardShares) { - if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight()) { + int groupId = BlockChain.getInstance().getMintingGroupId(); + String address = rewardShare.getMinter(); + boolean isMinterGroupMember = repository.getGroupRepository().memberExists(groupId, address); + + if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight()) expandedAccounts.add(new ExpandedAccount(repository, rewardShare)); - } - if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight()) { - boolean isMinterGroupMember = repository.getGroupRepository().memberExists(BlockChain.getInstance().getMintingGroupId(), rewardShare.getMinter()); - if (isMinterGroupMember) { - expandedAccounts.add(new ExpandedAccount(repository, rewardShare)); - } - } - } + if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight() && isMinterGroupMember) + expandedAccounts.add(new ExpandedAccount(repository, rewardShare)); + } this.cachedExpandedAccounts = expandedAccounts; + LOGGER.trace(() -> String.format("Online reward-shares after expanded accounts %s", this.cachedOnlineRewardShares)); return this.cachedExpandedAccounts; } @@ -1143,8 +1158,17 @@ public ValidationResult areOnlineAccountsValid() throws DataException { if (this.getBlockData().getHeight() >= BlockChain.getInstance().getOnlineAccountMinterLevelValidationHeight()) { List expandedAccounts = this.getExpandedAccounts(); for (ExpandedAccount account : expandedAccounts) { + int groupId = BlockChain.getInstance().getMintingGroupId(); + String address = account.getMintingAccount().getAddress(); + boolean isMinterGroupMember = repository.getGroupRepository().memberExists(groupId, address); + if (account.getMintingAccount().getEffectiveMintingLevel() == 0) return ValidationResult.ONLINE_ACCOUNTS_INVALID; + + if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight()) { + if (!isMinterGroupMember) + return ValidationResult.ONLINE_ACCOUNTS_INVALID; + } } } @@ -1273,6 +1297,7 @@ public ValidationResult isValid() throws DataException { // Online Accounts ValidationResult onlineAccountsResult = this.areOnlineAccountsValid(); + LOGGER.trace("Accounts valid = {}", onlineAccountsResult); if (onlineAccountsResult != ValidationResult.OK) return onlineAccountsResult; @@ -1361,7 +1386,7 @@ private ValidationResult areTransactionsValid() throws DataException { // Check transaction can even be processed validationResult = transaction.isProcessable(); if (validationResult != Transaction.ValidationResult.OK) { - LOGGER.info(String.format("Error during transaction validation, tx %s: %s", Base58.encode(transactionData.getSignature()), validationResult.name())); + LOGGER.debug(String.format("Error during transaction validation, tx %s: %s", Base58.encode(transactionData.getSignature()), validationResult.name())); return ValidationResult.TRANSACTION_INVALID; } @@ -1562,6 +1587,7 @@ public void process() throws DataException { this.blockData.setHeight(blockchainHeight + 1); LOGGER.trace(() -> String.format("Processing block %d", this.blockData.getHeight())); + LOGGER.trace(() -> String.format("Online Reward Shares in process %s", this.cachedOnlineRewardShares)); if (this.blockData.getHeight() > 1) { @@ -2280,7 +2306,6 @@ protected List determineBlockRewardCandidates(boolean isPr // Select the correct set of share bins based on block height List accountLevelShareBinsForBlock = (this.blockData.getHeight() >= BlockChain.getInstance().getSharesByLevelV2Height()) ? BlockChain.getInstance().getAccountLevelShareBinsV2() : BlockChain.getInstance().getAccountLevelShareBinsV1(); - // Determine reward candidates based on account level // This needs a deep copy, so the shares can be modified when tiers aren't activated yet List accountLevelShareBins = new ArrayList<>(); @@ -2570,9 +2595,11 @@ private void logDebugInfo() { return; int minterLevel = Account.getRewardShareEffectiveMintingLevel(this.repository, this.getMinter().getPublicKey()); + String minterAddress = Account.getRewardShareMintingAddress(this.repository, this.getMinter().getPublicKey()); LOGGER.debug(String.format("======= BLOCK %d (%.8s) =======", this.getBlockData().getHeight(), Base58.encode(this.getSignature()))); LOGGER.debug(String.format("Timestamp: %d", this.getBlockData().getTimestamp())); + LOGGER.debug(String.format("Minter address: %s", minterAddress)); LOGGER.debug(String.format("Minter level: %d", minterLevel)); LOGGER.debug(String.format("Online accounts: %d", this.getBlockData().getOnlineAccountsCount())); LOGGER.debug(String.format("AT count: %d", this.getBlockData().getATCount())); diff --git a/src/main/java/org/qortal/data/block/BlockData.java b/src/main/java/org/qortal/data/block/BlockData.java index 34df0f9a4..7e2a18725 100644 --- a/src/main/java/org/qortal/data/block/BlockData.java +++ b/src/main/java/org/qortal/data/block/BlockData.java @@ -1,8 +1,11 @@ package org.qortal.data.block; import com.google.common.primitives.Bytes; +import org.qortal.account.Account; import org.qortal.block.BlockChain; -import org.qortal.crypto.Crypto; +import org.qortal.repository.DataException; +import org.qortal.repository.Repository; +import org.qortal.repository.RepositoryManager; import org.qortal.settings.Settings; import org.qortal.utils.NTP; @@ -224,7 +227,7 @@ public int getOnlineAccountsSignaturesCount() { } return 0; } - + public boolean isTrimmed() { long onlineAccountSignaturesTrimmedTimestamp = NTP.getTime() - BlockChain.getInstance().getOnlineAccountSignaturesMaxLifetime(); long currentTrimmableTimestamp = NTP.getTime() - Settings.getInstance().getAtStatesMaxLifetime(); @@ -232,11 +235,31 @@ public boolean isTrimmed() { return blockTimestamp < onlineAccountSignaturesTrimmedTimestamp && blockTimestamp < currentTrimmableTimestamp; } + public String getMinterAddressFromPublicKey() { + try (final Repository repository = RepositoryManager.getRepository()) { + return Account.getRewardShareMintingAddress(repository, this.minterPublicKey); + } catch (DataException e) { + return "Unknown"; + } + } + + public int getMinterLevelFromPublicKey() { + try (final Repository repository = RepositoryManager.getRepository()) { + return Account.getRewardShareEffectiveMintingLevel(repository, this.minterPublicKey); + } catch (DataException e) { + return 0; + } + } + // JAXB special @XmlElement(name = "minterAddress") protected String getMinterAddress() { - return Crypto.toAddress(this.minterPublicKey); + return getMinterAddressFromPublicKey(); } + @XmlElement(name = "minterLevel") + protected int getMinterLevel() { + return getMinterLevelFromPublicKey(); + } } diff --git a/src/test/java/org/qortal/test/BlockArchiveV1Tests.java b/src/test/java/org/qortal/test/BlockArchiveV1Tests.java index a28bd28d7..2cf8ef79d 100644 --- a/src/test/java/org/qortal/test/BlockArchiveV1Tests.java +++ b/src/test/java/org/qortal/test/BlockArchiveV1Tests.java @@ -54,26 +54,39 @@ public void afterTest() throws DataException { public void testWriter() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testWriter"); + // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // 900 blocks are trimmed (this specifies the first untrimmed height) repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getATRepository().setAtTrimHeight(901); + System.out.println("Set trim heights to 901."); // Check the max archive height - this should be one less than the first untrimmed height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight); assertEquals(900, maximumArchiveHeight); // Write blocks 2-900 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Archive contains " + writer.getWrittenCount() + " blocks. (Expected 899)"); assertEquals(900 - 1, writer.getWrittenCount()); // Increment block archive height @@ -84,6 +97,9 @@ public void testWriter() throws DataException, InterruptedException, Transformat // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); + + System.out.println("testWriter completed successfully."); } } @@ -91,26 +107,39 @@ public void testWriter() throws DataException, InterruptedException, Transformat public void testWriterAndReader() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testWriterAndReader"); + // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // 900 blocks are trimmed (this specifies the first untrimmed height) repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getATRepository().setAtTrimHeight(901); + System.out.println("Set trim heights to 901."); // Check the max archive height - this should be one less than the first untrimmed height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight); assertEquals(900, maximumArchiveHeight); // Write blocks 2-900 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Archive contains " + writer.getWrittenCount() + " blocks. (Expected 899)"); assertEquals(900 - 1, writer.getWrittenCount()); // Increment block archive height @@ -121,8 +150,10 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); // Read block 2 from the archive + System.out.println("Reading block 2 from the archive..."); BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockTransformation block2Info = reader.fetchBlockAtHeight(2); BlockData block2ArchiveData = block2Info.getBlockData(); @@ -131,6 +162,7 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr BlockData block2RepositoryData = repository.getBlockRepository().fromHeight(2); // Ensure the values match + System.out.println("Comparing block 2 data..."); assertEquals(block2ArchiveData.getHeight(), block2RepositoryData.getHeight()); assertArrayEquals(block2ArchiveData.getSignature(), block2RepositoryData.getSignature()); @@ -138,6 +170,7 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr assertEquals(1, block2ArchiveData.getOnlineAccountsCount()); // Read block 900 from the archive + System.out.println("Reading block 900 from the archive..."); BlockTransformation block900Info = reader.fetchBlockAtHeight(900); BlockData block900ArchiveData = block900Info.getBlockData(); @@ -145,12 +178,14 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr BlockData block900RepositoryData = repository.getBlockRepository().fromHeight(900); // Ensure the values match + System.out.println("Comparing block 900 data..."); assertEquals(block900ArchiveData.getHeight(), block900RepositoryData.getHeight()); assertArrayEquals(block900ArchiveData.getSignature(), block900RepositoryData.getSignature()); // Test some values in the archive assertEquals(1, block900ArchiveData.getOnlineAccountsCount()); + System.out.println("testWriterAndReader completed successfully."); } } @@ -158,33 +193,48 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr public void testArchivedAtStates() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testArchivedAtStates"); + // Deploy an AT so that we have AT state data + System.out.println("Deploying AT..."); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); byte[] creationBytes = AtUtils.buildSimpleAT(); long fundingAmount = 1_00000000L; DeployAtTransaction deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); String atAddress = deployAtTransaction.getATAccount().getAddress(); + System.out.println("AT deployed at address: " + atAddress); // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // 9 blocks are trimmed (this specifies the first untrimmed height) repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(10); repository.getATRepository().setAtTrimHeight(10); + System.out.println("Set trim heights to 10."); // Check the max archive height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height (Expected 9): " + maximumArchiveHeight); assertEquals(9, maximumArchiveHeight); // Write blocks 2-9 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Archive contains " + writer.getWrittenCount() + " blocks. (Expected 8)"); assertEquals(9 - 1, writer.getWrittenCount()); // Increment block archive height @@ -195,10 +245,13 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); // Check blocks 3-9 + System.out.println("Checking blocks 3 to 9..."); for (Integer testHeight = 2; testHeight <= 9; testHeight++) { + System.out.println("Reading block " + testHeight + " from the archive..."); // Read a block from the archive BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockTransformation blockInfo = reader.fetchBlockAtHeight(testHeight); @@ -216,6 +269,7 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T // Check the archived AT state if (testHeight == 2) { + System.out.println("Checking block " + testHeight + " AT state data (expected null)..."); // Block 2 won't have an AT state hash because it's initial (and has the DEPLOY_AT in the same block) assertNull(archivedAtStateData); @@ -223,6 +277,7 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T assertEquals(Transaction.TransactionType.DEPLOY_AT, archivedTransactions.get(0).getType()); } else { + System.out.println("Checking block " + testHeight + " AT state data..."); // For blocks 3+, ensure the archive has the AT state data, but not the hashes assertNotNull(archivedAtStateData.getStateHash()); assertNull(archivedAtStateData.getStateData()); @@ -255,10 +310,12 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T } // Check block 10 (unarchived) + System.out.println("Checking block 10 (should not be in archive)..."); BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockTransformation blockInfo = reader.fetchBlockAtHeight(10); assertNull(blockInfo); + System.out.println("testArchivedAtStates completed successfully."); } } @@ -267,32 +324,46 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T public void testArchiveAndPrune() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testArchiveAndPrune"); + // Deploy an AT so that we have AT state data + System.out.println("Deploying AT..."); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); byte[] creationBytes = AtUtils.buildSimpleAT(); long fundingAmount = 1_00000000L; AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // Assume 900 blocks are trimmed (this specifies the first untrimmed height) repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getATRepository().setAtTrimHeight(901); + System.out.println("Set trim heights to 901."); // Check the max archive height - this should be one less than the first untrimmed height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight); assertEquals(900, maximumArchiveHeight); // Write blocks 2-900 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Archive contains " + writer.getWrittenCount() + " blocks. (Expected 899)"); assertEquals(900 - 1, writer.getWrittenCount()); // Increment block archive height @@ -303,17 +374,21 @@ public void testArchiveAndPrune() throws DataException, InterruptedException, Tr // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); // Ensure the SQL repository contains blocks 2 and 900... assertNotNull(repository.getBlockRepository().fromHeight(2)); assertNotNull(repository.getBlockRepository().fromHeight(900)); + System.out.println("Blocks 2 and 900 exist in the repository."); // Prune all the archived blocks + System.out.println("Pruning blocks 2 to 900..."); int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 900); assertEquals(900-1, numBlocksPruned); repository.getBlockRepository().setBlockPruneHeight(901); // Prune the AT states for the archived blocks + System.out.println("Pruning AT states up to height 900..."); repository.getATRepository().rebuildLatestAtStates(900); repository.saveChanges(); int numATStatesPruned = repository.getATRepository().pruneAtStates(0, 900); @@ -323,14 +398,19 @@ public void testArchiveAndPrune() throws DataException, InterruptedException, Tr // Now ensure the SQL repository is missing blocks 2 and 900... assertNull(repository.getBlockRepository().fromHeight(2)); assertNull(repository.getBlockRepository().fromHeight(900)); + System.out.println("Blocks 2 and 900 have been pruned from the repository."); // ... but it's not missing blocks 1 and 901 (we don't prune the genesis block) assertNotNull(repository.getBlockRepository().fromHeight(1)); assertNotNull(repository.getBlockRepository().fromHeight(901)); + System.out.println("Blocks 1 and 901 still exist in the repository."); // Validate the latest block height in the repository - assertEquals(1002, (int) repository.getBlockRepository().getLastBlock().getHeight()); + int lastBlockHeight = repository.getBlockRepository().getLastBlock().getHeight(); + System.out.println("Latest block height in repository (Expected 1002): " + lastBlockHeight); + assertEquals(1002, lastBlockHeight); + System.out.println("testArchiveAndPrune completed successfully."); } } @@ -338,137 +418,190 @@ public void testArchiveAndPrune() throws DataException, InterruptedException, Tr public void testTrimArchivePruneAndOrphan() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testTrimArchivePruneAndOrphan"); + // Deploy an AT so that we have AT state data + System.out.println("Deploying AT..."); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); byte[] creationBytes = AtUtils.buildSimpleAT(); long fundingAmount = 1_00000000L; AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); + System.out.println("AT deployed successfully."); // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // Make sure that block 500 has full AT state data and data hash + System.out.println("Verifying block 500 AT state data..."); List block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500); ATStateData atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateData()); + System.out.println("Block 500 AT state data verified."); // Trim the first 500 blocks + System.out.println("Trimming first 500 blocks..."); repository.getBlockRepository().trimOldOnlineAccountsSignatures(0, 500); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(501); repository.getATRepository().rebuildLatestAtStates(500); repository.getATRepository().trimAtStates(0, 500, 1000); repository.getATRepository().setAtTrimHeight(501); + System.out.println("Trimming completed."); // Now block 499 should only have the AT state data hash + System.out.println("Checking block 499 AT state data..."); List block499AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(499); atStatesData = repository.getATRepository().getATStateAtHeight(block499AtStatesData.get(0).getATAddress(), 499); assertNotNull(atStatesData.getStateHash()); assertNull(atStatesData.getStateData()); + System.out.println("Block 499 AT state data contains only state hash as expected."); // ... but block 500 should have the full data (due to being retained as the "latest" AT state in the trimmed range + System.out.println("Verifying block 500 AT state data again..."); block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500); atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateData()); + System.out.println("Block 500 AT state data contains full data."); // ... and block 501 should also have the full data + System.out.println("Verifying block 501 AT state data..."); List block501AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(501); atStatesData = repository.getATRepository().getATStateAtHeight(block501AtStatesData.get(0).getATAddress(), 501); assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateData()); + System.out.println("Block 501 AT state data contains full data."); // Check the max archive height - this should be one less than the first untrimmed height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height determined (Expected 500): " + maximumArchiveHeight); assertEquals(500, maximumArchiveHeight); BlockData block3DataPreArchive = repository.getBlockRepository().fromHeight(3); // Write blocks 2-500 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Number of blocks written to archive (Expected 499): " + writer.getWrittenCount()); assertEquals(500 - 1, writer.getWrittenCount()); // -1 for the genesis block // Increment block archive height repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount()); repository.saveChanges(); assertEquals(500 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight()); + System.out.println("Block archive height updated to: " + (500 - 1)); // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); // Ensure the SQL repository contains blocks 2 and 500... + System.out.println("Verifying that blocks 2 and 500 exist in the repository..."); assertNotNull(repository.getBlockRepository().fromHeight(2)); assertNotNull(repository.getBlockRepository().fromHeight(500)); + System.out.println("Blocks 2 and 500 are present in the repository."); // Prune all the archived blocks + System.out.println("Pruning blocks 2 to 500..."); int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 500); + System.out.println("Number of blocks pruned (Expected 499): " + numBlocksPruned); assertEquals(500-1, numBlocksPruned); repository.getBlockRepository().setBlockPruneHeight(501); // Prune the AT states for the archived blocks + System.out.println("Pruning AT states up to height 500..."); repository.getATRepository().rebuildLatestAtStates(500); repository.saveChanges(); int numATStatesPruned = repository.getATRepository().pruneAtStates(2, 500); + System.out.println("Number of AT states pruned (Expected 498): " + numATStatesPruned); assertEquals(498, numATStatesPruned); // Minus 1 for genesis block, and another for the latest AT state repository.getATRepository().setAtPruneHeight(501); // Now ensure the SQL repository is missing blocks 2 and 500... + System.out.println("Verifying that blocks 2 and 500 have been pruned..."); assertNull(repository.getBlockRepository().fromHeight(2)); assertNull(repository.getBlockRepository().fromHeight(500)); + System.out.println("Blocks 2 and 500 have been successfully pruned."); // ... but it's not missing blocks 1 and 501 (we don't prune the genesis block) + System.out.println("Verifying that blocks 1 and 501 still exist..."); assertNotNull(repository.getBlockRepository().fromHeight(1)); assertNotNull(repository.getBlockRepository().fromHeight(501)); + System.out.println("Blocks 1 and 501 are present in the repository."); // Validate the latest block height in the repository - assertEquals(1002, (int) repository.getBlockRepository().getLastBlock().getHeight()); + int lastBlockHeight = repository.getBlockRepository().getLastBlock().getHeight(); + System.out.println("Latest block height in repository (Expected 1002): " + lastBlockHeight); + assertEquals(1002, lastBlockHeight); // Now orphan some unarchived blocks. + System.out.println("Orphaning 500 blocks..."); BlockUtils.orphanBlocks(repository, 500); - assertEquals(502, (int) repository.getBlockRepository().getLastBlock().getHeight()); + int currentLastBlockHeight = repository.getBlockRepository().getLastBlock().getHeight(); + System.out.println("New last block height after orphaning (Expected 502): " + currentLastBlockHeight); + assertEquals(502, currentLastBlockHeight); // We're close to the lower limit of the SQL database now, so // we need to import some blocks from the archive + System.out.println("Importing blocks 401 to 500 from the archive..."); BlockArchiveUtils.importFromArchive(401, 500, repository); // Ensure the SQL repository now contains block 401 but not 400... + System.out.println("Verifying that block 401 exists and block 400 does not..."); assertNotNull(repository.getBlockRepository().fromHeight(401)); assertNull(repository.getBlockRepository().fromHeight(400)); + System.out.println("Block 401 exists, block 400 does not."); // Import the remaining 399 blocks + System.out.println("Importing blocks 2 to 400 from the archive..."); BlockArchiveUtils.importFromArchive(2, 400, repository); // Verify that block 3 matches the original + System.out.println("Verifying that block 3 matches the original data..."); BlockData block3DataPostArchive = repository.getBlockRepository().fromHeight(3); assertArrayEquals(block3DataPreArchive.getSignature(), block3DataPostArchive.getSignature()); assertEquals(block3DataPreArchive.getHeight(), block3DataPostArchive.getHeight()); + System.out.println("Block 3 data matches the original."); // Orphan 1 more block, which should be the last one that is possible to be orphaned + System.out.println("Orphaning 1 more block..."); BlockUtils.orphanBlocks(repository, 1); + System.out.println("Orphaned 1 block successfully."); // Orphan another block, which should fail + System.out.println("Attempting to orphan another block, which should fail..."); Exception exception = null; try { BlockUtils.orphanBlocks(repository, 1); } catch (DataException e) { exception = e; + System.out.println("Caught expected DataException: " + e.getMessage()); } // Ensure that a DataException is thrown because there is no more AT states data available assertNotNull(exception); assertEquals(DataException.class, exception.getClass()); + System.out.println("DataException confirmed due to lack of AT states data."); // FUTURE: we may be able to retain unique AT states when trimming, to avoid this exception // and allow orphaning back through blocks with trimmed AT states. + System.out.println("testTrimArchivePruneAndOrphan completed successfully."); } } @@ -482,16 +615,26 @@ public void testTrimArchivePruneAndOrphan() throws DataException, InterruptedExc public void testMissingAtStatesHeightIndex() throws DataException, SQLException { try (final HSQLDBRepository repository = (HSQLDBRepository) RepositoryManager.getRepository()) { + System.out.println("Starting testMissingAtStatesHeightIndex"); + // Firstly check that we're able to prune or archive when the index exists + System.out.println("Checking existence of ATStatesHeightIndex..."); assertTrue(repository.getATRepository().hasAtStatesHeightIndex()); assertTrue(RepositoryManager.canArchiveOrPrune()); + System.out.println("ATStatesHeightIndex exists. Archiving and pruning are possible."); // Delete the index + System.out.println("Dropping ATStatesHeightIndex..."); repository.prepareStatement("DROP INDEX ATSTATESHEIGHTINDEX").execute(); + System.out.println("ATStatesHeightIndex dropped."); // Ensure check that we're unable to prune or archive when the index doesn't exist + System.out.println("Verifying that ATStatesHeightIndex no longer exists..."); assertFalse(repository.getATRepository().hasAtStatesHeightIndex()); assertFalse(RepositoryManager.canArchiveOrPrune()); + System.out.println("ATStatesHeightIndex does not exist. Archiving and pruning are disabled."); + + System.out.println("testMissingAtStatesHeightIndex completed successfully."); } } @@ -501,8 +644,10 @@ private void deleteArchiveDirectory() { Path archivePath = Paths.get(Settings.getInstance().getRepositoryPath(), "archive").toAbsolutePath(); try { FileUtils.deleteDirectory(archivePath.toFile()); + System.out.println("Deleted archive directory at: " + archivePath); } catch (IOException e) { - + + System.out.println("Failed to delete archive directory: " + e.getMessage()); } } diff --git a/src/test/java/org/qortal/test/BlockArchiveV2Tests.java b/src/test/java/org/qortal/test/BlockArchiveV2Tests.java index 3b1d12d3b..8ab02b407 100644 --- a/src/test/java/org/qortal/test/BlockArchiveV2Tests.java +++ b/src/test/java/org/qortal/test/BlockArchiveV2Tests.java @@ -54,26 +54,39 @@ public void afterTest() throws DataException { public void testWriter() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testWriter"); + // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // 900 blocks are trimmed (this specifies the first untrimmed height) repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getATRepository().setAtTrimHeight(901); + System.out.println("Set trim heights to 901."); // Check the max archive height - this should be one less than the first untrimmed height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight); assertEquals(900, maximumArchiveHeight); // Write blocks 2-900 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Archive contains " + writer.getWrittenCount() + " blocks. (Expected 899)"); assertEquals(900 - 1, writer.getWrittenCount()); // Increment block archive height @@ -84,6 +97,9 @@ public void testWriter() throws DataException, InterruptedException, Transformat // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); + + System.out.println("testWriter completed successfully."); } } @@ -91,26 +107,39 @@ public void testWriter() throws DataException, InterruptedException, Transformat public void testWriterAndReader() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testWriterAndReader"); + // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // 900 blocks are trimmed (this specifies the first untrimmed height) repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getATRepository().setAtTrimHeight(901); + System.out.println("Set trim heights to 901."); // Check the max archive height - this should be one less than the first untrimmed height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight); assertEquals(900, maximumArchiveHeight); // Write blocks 2-900 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Archive contains " + writer.getWrittenCount() + " blocks. (Expected 899)"); assertEquals(900 - 1, writer.getWrittenCount()); // Increment block archive height @@ -121,8 +150,10 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); // Read block 2 from the archive + System.out.println("Reading block 2 from the archive..."); BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockTransformation block2Info = reader.fetchBlockAtHeight(2); BlockData block2ArchiveData = block2Info.getBlockData(); @@ -131,6 +162,7 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr BlockData block2RepositoryData = repository.getBlockRepository().fromHeight(2); // Ensure the values match + System.out.println("Comparing block 2 data..."); assertEquals(block2ArchiveData.getHeight(), block2RepositoryData.getHeight()); assertArrayEquals(block2ArchiveData.getSignature(), block2RepositoryData.getSignature()); @@ -138,6 +170,7 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr assertEquals(1, block2ArchiveData.getOnlineAccountsCount()); // Read block 900 from the archive + System.out.println("Reading block 900 from the archive..."); BlockTransformation block900Info = reader.fetchBlockAtHeight(900); BlockData block900ArchiveData = block900Info.getBlockData(); @@ -145,12 +178,14 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr BlockData block900RepositoryData = repository.getBlockRepository().fromHeight(900); // Ensure the values match + System.out.println("Comparing block 900 data..."); assertEquals(block900ArchiveData.getHeight(), block900RepositoryData.getHeight()); assertArrayEquals(block900ArchiveData.getSignature(), block900RepositoryData.getSignature()); // Test some values in the archive assertEquals(1, block900ArchiveData.getOnlineAccountsCount()); + System.out.println("testWriterAndReader completed successfully."); } } @@ -158,47 +193,66 @@ public void testWriterAndReader() throws DataException, InterruptedException, Tr public void testArchivedAtStates() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testArchivedAtStates"); + // Deploy an AT so that we have AT state data + System.out.println("Deploying AT..."); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); byte[] creationBytes = AtUtils.buildSimpleAT(); long fundingAmount = 1_00000000L; DeployAtTransaction deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); String atAddress = deployAtTransaction.getATAccount().getAddress(); + System.out.println("AT deployed at address: " + atAddress); // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // 9 blocks are trimmed (this specifies the first untrimmed height) repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(10); repository.getATRepository().setAtTrimHeight(10); + System.out.println("Set trim heights to 10."); // Check the max archive height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height (Expected 9): " + maximumArchiveHeight); assertEquals(9, maximumArchiveHeight); // Write blocks 2-9 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Archive contains " + writer.getWrittenCount() + " blocks. (Expected 8)"); assertEquals(9 - 1, writer.getWrittenCount()); // Increment block archive height repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount()); repository.saveChanges(); assertEquals(9 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight()); + System.out.println("Block archive height updated to: " + (9 - 1)); // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); // Check blocks 3-9 + System.out.println("Checking blocks 2 to 9..."); for (Integer testHeight = 2; testHeight <= 9; testHeight++) { + System.out.println("Reading block " + testHeight + " from the archive..."); // Read a block from the archive BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockTransformation blockInfo = reader.fetchBlockAtHeight(testHeight); @@ -216,15 +270,18 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T // Check the archived AT state if (testHeight == 2) { + System.out.println("Checking block " + testHeight + " AT state data (expected transactions)..."); assertEquals(1, archivedTransactions.size()); assertEquals(Transaction.TransactionType.DEPLOY_AT, archivedTransactions.get(0).getType()); } else { + System.out.println("Checking block " + testHeight + " AT state data (no transactions expected)..."); // Blocks 3+ shouldn't have any transactions assertTrue(archivedTransactions.isEmpty()); } // Ensure the archive has the AT states hash + System.out.println("Checking block " + testHeight + " AT states hash..."); assertNotNull(archivedAtStateHash); // Also check the online accounts count and height @@ -232,6 +289,7 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T assertEquals(testHeight, archivedBlockData.getHeight()); // Ensure the values match + System.out.println("Comparing block " + testHeight + " data..."); assertEquals(archivedBlockData.getHeight(), repositoryBlockData.getHeight()); assertArrayEquals(archivedBlockData.getSignature(), repositoryBlockData.getSignature()); assertEquals(archivedBlockData.getOnlineAccountsCount(), repositoryBlockData.getOnlineAccountsCount()); @@ -249,10 +307,12 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T } // Check block 10 (unarchived) + System.out.println("Checking block 10 (should not be in archive)..."); BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockTransformation blockInfo = reader.fetchBlockAtHeight(10); assertNull(blockInfo); + System.out.println("testArchivedAtStates completed successfully."); } } @@ -261,32 +321,47 @@ public void testArchivedAtStates() throws DataException, InterruptedException, T public void testArchiveAndPrune() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testArchiveAndPrune"); + // Deploy an AT so that we have AT state data + System.out.println("Deploying AT..."); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); byte[] creationBytes = AtUtils.buildSimpleAT(); long fundingAmount = 1_00000000L; AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); + System.out.println("AT deployed successfully."); // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // Assume 900 blocks are trimmed (this specifies the first untrimmed height) repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getATRepository().setAtTrimHeight(901); + System.out.println("Set trim heights to 901."); // Check the max archive height - this should be one less than the first untrimmed height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight); assertEquals(900, maximumArchiveHeight); // Write blocks 2-900 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Archive contains " + writer.getWrittenCount() + " blocks. (Expected 899)"); assertEquals(900 - 1, writer.getWrittenCount()); // Increment block archive height @@ -297,34 +372,48 @@ public void testArchiveAndPrune() throws DataException, InterruptedException, Tr // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); // Ensure the SQL repository contains blocks 2 and 900... + System.out.println("Verifying that blocks 2 and 900 exist in the repository..."); assertNotNull(repository.getBlockRepository().fromHeight(2)); assertNotNull(repository.getBlockRepository().fromHeight(900)); + System.out.println("Blocks 2 and 900 are present in the repository."); // Prune all the archived blocks + System.out.println("Pruning blocks 2 to 900..."); int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 900); + System.out.println("Number of blocks pruned (Expected 899): " + numBlocksPruned); assertEquals(900-1, numBlocksPruned); repository.getBlockRepository().setBlockPruneHeight(901); // Prune the AT states for the archived blocks + System.out.println("Pruning AT states up to height 900..."); repository.getATRepository().rebuildLatestAtStates(900); repository.saveChanges(); int numATStatesPruned = repository.getATRepository().pruneAtStates(0, 900); + System.out.println("Number of AT states pruned (Expected 898): " + numATStatesPruned); assertEquals(900-2, numATStatesPruned); // Minus 1 for genesis block, and another for the latest AT state repository.getATRepository().setAtPruneHeight(901); // Now ensure the SQL repository is missing blocks 2 and 900... + System.out.println("Verifying that blocks 2 and 900 have been pruned..."); assertNull(repository.getBlockRepository().fromHeight(2)); assertNull(repository.getBlockRepository().fromHeight(900)); + System.out.println("Blocks 2 and 900 have been successfully pruned."); // ... but it's not missing blocks 1 and 901 (we don't prune the genesis block) + System.out.println("Verifying that blocks 1 and 901 still exist..."); assertNotNull(repository.getBlockRepository().fromHeight(1)); assertNotNull(repository.getBlockRepository().fromHeight(901)); + System.out.println("Blocks 1 and 901 are present in the repository."); // Validate the latest block height in the repository - assertEquals(1002, (int) repository.getBlockRepository().getLastBlock().getHeight()); + int lastBlockHeight = repository.getBlockRepository().getLastBlock().getHeight(); + System.out.println("Latest block height in repository (Expected 1002): " + lastBlockHeight); + assertEquals(1002, lastBlockHeight); + System.out.println("testArchiveAndPrune completed successfully."); } } @@ -332,138 +421,191 @@ public void testArchiveAndPrune() throws DataException, InterruptedException, Tr public void testTrimArchivePruneAndOrphan() throws DataException, InterruptedException, TransformationException, IOException { try (final Repository repository = RepositoryManager.getRepository()) { + System.out.println("Starting testTrimArchivePruneAndOrphan"); + // Deploy an AT so that we have AT state data + System.out.println("Deploying AT..."); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); byte[] creationBytes = AtUtils.buildSimpleAT(); long fundingAmount = 1_00000000L; AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); + System.out.println("AT deployed successfully."); // Mint some blocks so that we are able to archive them later + System.out.println("Minting 1000 blocks..."); for (int i = 0; i < 1000; i++) { BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); + // Log every 100 blocks + if ((i + 1) % 100 == 0) { + System.out.println("Minted block " + (i + 1)); + } } + System.out.println("Finished minting blocks."); // Make sure that block 500 has full AT state data and data hash + System.out.println("Verifying block 500 AT state data..."); List block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500); ATStateData atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateData()); + System.out.println("Block 500 AT state data verified."); // Trim the first 500 blocks + System.out.println("Trimming first 500 blocks..."); repository.getBlockRepository().trimOldOnlineAccountsSignatures(0, 500); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(501); repository.getATRepository().rebuildLatestAtStates(500); repository.getATRepository().trimAtStates(0, 500, 1000); repository.getATRepository().setAtTrimHeight(501); + System.out.println("Trimming completed."); // Now block 499 should only have the AT state data hash + System.out.println("Checking block 499 AT state data..."); List block499AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(499); atStatesData = repository.getATRepository().getATStateAtHeight(block499AtStatesData.get(0).getATAddress(), 499); assertNotNull(atStatesData.getStateHash()); assertNull(atStatesData.getStateData()); + System.out.println("Block 499 AT state data contains only state hash as expected."); // ... but block 500 should have the full data (due to being retained as the "latest" AT state in the trimmed range + System.out.println("Verifying block 500 AT state data again..."); block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500); atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateData()); + System.out.println("Block 500 AT state data contains full data."); // ... and block 501 should also have the full data + System.out.println("Verifying block 501 AT state data..."); List block501AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(501); atStatesData = repository.getATRepository().getATStateAtHeight(block501AtStatesData.get(0).getATAddress(), 501); assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateData()); + System.out.println("Block 501 AT state data contains full data."); // Check the max archive height - this should be one less than the first untrimmed height final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); + System.out.println("Maximum archive height determined (Expected 500): " + maximumArchiveHeight); assertEquals(500, maximumArchiveHeight); BlockData block3DataPreArchive = repository.getBlockRepository().fromHeight(3); // Write blocks 2-500 to the archive + System.out.println("Writing blocks 2 to " + maximumArchiveHeight + " to the archive..."); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository); writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); + System.out.println("Finished writing blocks to archive. Result: " + result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); // Make sure that the archive contains the correct number of blocks + System.out.println("Number of blocks written to archive (Expected 499): " + writer.getWrittenCount()); assertEquals(500 - 1, writer.getWrittenCount()); // -1 for the genesis block // Increment block archive height repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount()); repository.saveChanges(); assertEquals(500 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight()); + System.out.println("Block archive height updated to: " + (500 - 1)); // Ensure the file exists File outputFile = writer.getOutputPath().toFile(); assertTrue(outputFile.exists()); + System.out.println("Archive file exists at: " + outputFile.getAbsolutePath()); // Ensure the SQL repository contains blocks 2 and 500... + System.out.println("Verifying that blocks 2 and 500 exist in the repository..."); assertNotNull(repository.getBlockRepository().fromHeight(2)); assertNotNull(repository.getBlockRepository().fromHeight(500)); + System.out.println("Blocks 2 and 500 are present in the repository."); // Prune all the archived blocks + System.out.println("Pruning blocks 2 to 500..."); int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 500); + System.out.println("Number of blocks pruned (Expected 499): " + numBlocksPruned); assertEquals(500-1, numBlocksPruned); repository.getBlockRepository().setBlockPruneHeight(501); // Prune the AT states for the archived blocks + System.out.println("Pruning AT states up to height 500..."); repository.getATRepository().rebuildLatestAtStates(500); repository.saveChanges(); int numATStatesPruned = repository.getATRepository().pruneAtStates(2, 500); + System.out.println("Number of AT states pruned (Expected 498): " + numATStatesPruned); assertEquals(498, numATStatesPruned); // Minus 1 for genesis block, and another for the latest AT state repository.getATRepository().setAtPruneHeight(501); // Now ensure the SQL repository is missing blocks 2 and 500... + System.out.println("Verifying that blocks 2 and 500 have been pruned..."); assertNull(repository.getBlockRepository().fromHeight(2)); assertNull(repository.getBlockRepository().fromHeight(500)); + System.out.println("Blocks 2 and 500 have been successfully pruned."); // ... but it's not missing blocks 1 and 501 (we don't prune the genesis block) + System.out.println("Verifying that blocks 1 and 501 still exist..."); assertNotNull(repository.getBlockRepository().fromHeight(1)); assertNotNull(repository.getBlockRepository().fromHeight(501)); + System.out.println("Blocks 1 and 501 are present in the repository."); // Validate the latest block height in the repository - assertEquals(1002, (int) repository.getBlockRepository().getLastBlock().getHeight()); + int lastBlockHeight = repository.getBlockRepository().getLastBlock().getHeight(); + System.out.println("Latest block height in repository (Expected 1002): " + lastBlockHeight); + assertEquals(1002, lastBlockHeight); // Now orphan some unarchived blocks. + System.out.println("Orphaning 500 blocks..."); BlockUtils.orphanBlocks(repository, 500); - assertEquals(502, (int) repository.getBlockRepository().getLastBlock().getHeight()); + int currentLastBlockHeight = repository.getBlockRepository().getLastBlock().getHeight(); + System.out.println("New last block height after orphaning (Expected 502): " + currentLastBlockHeight); + assertEquals(502, currentLastBlockHeight); // We're close to the lower limit of the SQL database now, so // we need to import some blocks from the archive + System.out.println("Importing blocks 401 to 500 from the archive..."); BlockArchiveUtils.importFromArchive(401, 500, repository); // Ensure the SQL repository now contains block 401 but not 400... + System.out.println("Verifying that block 401 exists and block 400 does not..."); assertNotNull(repository.getBlockRepository().fromHeight(401)); assertNull(repository.getBlockRepository().fromHeight(400)); + System.out.println("Block 401 exists, block 400 does not."); // Import the remaining 399 blocks + System.out.println("Importing blocks 2 to 400 from the archive..."); BlockArchiveUtils.importFromArchive(2, 400, repository); // Verify that block 3 matches the original + System.out.println("Verifying that block 3 matches the original data..."); BlockData block3DataPostArchive = repository.getBlockRepository().fromHeight(3); assertArrayEquals(block3DataPreArchive.getSignature(), block3DataPostArchive.getSignature()); assertEquals(block3DataPreArchive.getHeight(), block3DataPostArchive.getHeight()); + System.out.println("Block 3 data matches the original."); // Orphan 2 more block, which should be the last one that is possible to be orphaned // TODO: figure out why this is 1 block more than in the equivalent block archive V1 test + System.out.println("Orphaning 2 more blocks..."); BlockUtils.orphanBlocks(repository, 2); + System.out.println("Orphaned 2 blocks successfully."); // Orphan another block, which should fail + System.out.println("Attempting to orphan another block, which should fail..."); Exception exception = null; try { BlockUtils.orphanBlocks(repository, 1); } catch (DataException e) { exception = e; + System.out.println("Caught expected DataException: " + e.getMessage()); } // Ensure that a DataException is thrown because there is no more AT states data available assertNotNull(exception); assertEquals(DataException.class, exception.getClass()); + System.out.println("DataException confirmed due to lack of AT states data."); // FUTURE: we may be able to retain unique AT states when trimming, to avoid this exception // and allow orphaning back through blocks with trimmed AT states. + System.out.println("testTrimArchivePruneAndOrphan completed successfully."); } } @@ -477,16 +619,26 @@ public void testTrimArchivePruneAndOrphan() throws DataException, InterruptedExc public void testMissingAtStatesHeightIndex() throws DataException, SQLException { try (final HSQLDBRepository repository = (HSQLDBRepository) RepositoryManager.getRepository()) { + System.out.println("Starting testMissingAtStatesHeightIndex"); + // Firstly check that we're able to prune or archive when the index exists + System.out.println("Checking existence of ATStatesHeightIndex..."); assertTrue(repository.getATRepository().hasAtStatesHeightIndex()); assertTrue(RepositoryManager.canArchiveOrPrune()); + System.out.println("ATStatesHeightIndex exists. Archiving and pruning are possible."); // Delete the index + System.out.println("Dropping ATStatesHeightIndex..."); repository.prepareStatement("DROP INDEX ATSTATESHEIGHTINDEX").execute(); + System.out.println("ATStatesHeightIndex dropped."); // Ensure check that we're unable to prune or archive when the index doesn't exist + System.out.println("Verifying that ATStatesHeightIndex no longer exists..."); assertFalse(repository.getATRepository().hasAtStatesHeightIndex()); assertFalse(RepositoryManager.canArchiveOrPrune()); + System.out.println("ATStatesHeightIndex does not exist. Archiving and pruning are disabled."); + + System.out.println("testMissingAtStatesHeightIndex completed successfully."); } } @@ -496,8 +648,10 @@ private void deleteArchiveDirectory() { Path archivePath = Paths.get(Settings.getInstance().getRepositoryPath(), "archive").toAbsolutePath(); try { FileUtils.deleteDirectory(archivePath.toFile()); + System.out.println("Deleted archive directory at: " + archivePath); } catch (IOException e) { + System.out.println("Failed to delete archive directory: " + e.getMessage()); } } diff --git a/src/test/resources/test-chain-v2-block-timestamps.json b/src/test/resources/test-chain-v2-block-timestamps.json index 17fc80c4b..4e49e86d8 100644 --- a/src/test/resources/test-chain-v2-block-timestamps.json +++ b/src/test/resources/test-chain-v2-block-timestamps.json @@ -81,7 +81,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -91,7 +91,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-disable-reference.json b/src/test/resources/test-chain-v2-disable-reference.json index 330547329..9ad59d792 100644 --- a/src/test/resources/test-chain-v2-disable-reference.json +++ b/src/test/resources/test-chain-v2-disable-reference.json @@ -84,7 +84,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 0, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -94,7 +94,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-founder-rewards.json b/src/test/resources/test-chain-v2-founder-rewards.json index 577a07f18..e4182d7d4 100644 --- a/src/test/resources/test-chain-v2-founder-rewards.json +++ b/src/test/resources/test-chain-v2-founder-rewards.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-leftover-reward.json b/src/test/resources/test-chain-v2-leftover-reward.json index 82e4ace7f..04005b2b1 100644 --- a/src/test/resources/test-chain-v2-leftover-reward.json +++ b/src/test/resources/test-chain-v2-leftover-reward.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-minting.json b/src/test/resources/test-chain-v2-minting.json index 16032a9c5..ddb29ca5c 100644 --- a/src/test/resources/test-chain-v2-minting.json +++ b/src/test/resources/test-chain-v2-minting.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 0, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 9999999999999, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-penalty-fix.json b/src/test/resources/test-chain-v2-penalty-fix.json index e62fc9f2d..cac92c160 100644 --- a/src/test/resources/test-chain-v2-penalty-fix.json +++ b/src/test/resources/test-chain-v2-penalty-fix.json @@ -83,16 +83,24 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, - "selfSponsorshipAlgoV1Height": 99999999, + "selfSponsorshipAlgoV1Height": 999999999, + "selfSponsorshipAlgoV2Height": 999999999, + "selfSponsorshipAlgoV3Height": 999999999, "feeValidationFixTimestamp": 0, "chatReferenceTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, - "selfSponsorshipAlgoV2Height": 9999999, "disableTransferPrivsTimestamp": 9999999999500, "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999, "penaltyFixHeight": 5 }, "genesisInfo": { diff --git a/src/test/resources/test-chain-v2-qora-holder-extremes.json b/src/test/resources/test-chain-v2-qora-holder-extremes.json index 3ec119420..566d85155 100644 --- a/src/test/resources/test-chain-v2-qora-holder-extremes.json +++ b/src/test/resources/test-chain-v2-qora-holder-extremes.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-qora-holder-reduction.json b/src/test/resources/test-chain-v2-qora-holder-reduction.json index 2b8834cec..c7ed22704 100644 --- a/src/test/resources/test-chain-v2-qora-holder-reduction.json +++ b/src/test/resources/test-chain-v2-qora-holder-reduction.json @@ -86,7 +86,7 @@ "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, "aggregateSignatureTimestamp": 0, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -96,7 +96,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-qora-holder.json b/src/test/resources/test-chain-v2-qora-holder.json index ab96a243b..1c4f0d93b 100644 --- a/src/test/resources/test-chain-v2-qora-holder.json +++ b/src/test/resources/test-chain-v2-qora-holder.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-reward-levels.json b/src/test/resources/test-chain-v2-reward-levels.json index 35535c752..30d952e14 100644 --- a/src/test/resources/test-chain-v2-reward-levels.json +++ b/src/test/resources/test-chain-v2-reward-levels.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-reward-scaling.json b/src/test/resources/test-chain-v2-reward-scaling.json index 616d0925c..612f02a53 100644 --- a/src/test/resources/test-chain-v2-reward-scaling.json +++ b/src/test/resources/test-chain-v2-reward-scaling.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 500, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-reward-shares.json b/src/test/resources/test-chain-v2-reward-shares.json index ec6ffd2e6..2f332233c 100644 --- a/src/test/resources/test-chain-v2-reward-shares.json +++ b/src/test/resources/test-chain-v2-reward-shares.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-self-sponsorship-algo-v1.json b/src/test/resources/test-chain-v2-self-sponsorship-algo-v1.json index d0d989cf2..3ea8bc70b 100644 --- a/src/test/resources/test-chain-v2-self-sponsorship-algo-v1.json +++ b/src/test/resources/test-chain-v2-self-sponsorship-algo-v1.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 20, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-self-sponsorship-algo-v2.json b/src/test/resources/test-chain-v2-self-sponsorship-algo-v2.json index 5f09cb472..ae424704b 100644 --- a/src/test/resources/test-chain-v2-self-sponsorship-algo-v2.json +++ b/src/test/resources/test-chain-v2-self-sponsorship-algo-v2.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 30, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-self-sponsorship-algo-v3.json b/src/test/resources/test-chain-v2-self-sponsorship-algo-v3.json index f7d1faa2c..2a24473bb 100644 --- a/src/test/resources/test-chain-v2-self-sponsorship-algo-v3.json +++ b/src/test/resources/test-chain-v2-self-sponsorship-algo-v3.json @@ -85,7 +85,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -95,7 +95,14 @@ "arbitraryOptionalFeeTimestamp": 0, "unconfirmableRewardSharesHeight": 99999999, "disableTransferPrivsTimestamp": 9999999999500, - "enableTransferPrivsTimestamp": 9999999999950 + "enableTransferPrivsTimestamp": 9999999999950, + "cancelSellNameValidationTimestamp": 9999999999999, + "disableRewardshareHeight": 9999999999990, + "enableRewardshareHeight": 9999999999999, + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2.json b/src/test/resources/test-chain-v2.json index 086c126eb..c829975b1 100644 --- a/src/test/resources/test-chain-v2.json +++ b/src/test/resources/test-chain-v2.json @@ -86,7 +86,7 @@ "transactionV5Timestamp": 0, "transactionV6Timestamp": 0, "disableReferenceTimestamp": 9999999999999, - "increaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "increaseOnlineAccountsDifficultyTimestamp": 9999999999990, "onlineAccountMinterLevelValidationHeight": 0, "selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999, @@ -100,8 +100,10 @@ "cancelSellNameValidationTimestamp": 9999999999999, "disableRewardshareHeight": 9999999999990, "enableRewardshareHeight": 9999999999999, - "onlyMintWithNameHeight": 9999999999999, - "groupMemberCheckHeight": 9999999999999 + "onlyMintWithNameHeight": 9999999999990, + "groupMemberCheckHeight": 9999999999999, + "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, + "removeOnlyMintWithNameHeight": 9999999999999 }, "genesisInfo": { "version": 4, From 448b536238c12e03a70abfee5339e9b308e42b5e Mon Sep 17 00:00:00 2001 From: crowetic Date: Tue, 3 Dec 2024 09:09:42 -0800 Subject: [PATCH 2/2] Modified start script to work with optimized Garbage Collection made available in version 4.6.6 and beyond. Suggestion to machines with 6GB of RAM or less, increase the percentage from 50 to 75. Qortal Core will only utilize the RAM it needs, up to the percentage set maximum. --- start.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/start.sh b/start.sh index cc80dceb6..889370262 100755 --- a/start.sh +++ b/start.sh @@ -33,8 +33,13 @@ fi # Limits Java JVM stack size and maximum heap usage. # Comment out for bigger systems, e.g. non-routers # or when API documentation is enabled -# Uncomment (remove '#' sign) line below if your system has less than 12GB of RAM for optimal RAM defaults -JVM_MEMORY_ARGS="-Xss256m -XX:+UseSerialGC" +# JAVA MEMORY SETTINGS BELOW - These settings are essentially optimized default settings. +# Combined with the latest changes on the Qortal Core in version 4.6.6 and beyond, +# should give a dramatic increase In performance due to optimized Garbage Collection. +# These memory arguments should work on machines with as little as 6GB of RAM. +# If you want to run on a machine with less than 6GB of RAM, it is suggested to increase the '50' below to '75' +# The Qortal Core will utilize only as much RAM as it needs, but up-to the amount set in percentage below. +JVM_MEMORY_ARGS="-XX:MaxRAMPercentage=50 -XX:+UseG1GC -Xss1024k" # Although java.net.preferIPv4Stack is supposed to be false # by default in Java 11, on some platforms (e.g. FreeBSD 12),