3
0
mirror of https://github.com/Qortal/qortal.git synced 2025-02-11 17:55:50 +00:00

Merge remote-tracking branch 'origin/master'

This commit is contained in:
kennycud 2024-12-10 14:07:32 -08:00
commit 543d0a7d22
38 changed files with 1561 additions and 1038 deletions

View File

@ -1,3 +1,4 @@
{ {
"apiDocumentationEnabled": true "apiDocumentationEnabled": true,
"apiWhitelistEnabled": false
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,9 @@
## Prerequisites ## Prerequisites
* AdvancedInstaller v19.4 or better, and enterprise licence if translations are required * AdvancedInstaller v19.4 or better, and enterprise licence.
* Qortal has an open source license, however it currently (as of December 2024) only supports up to version 19. (We may need to reach out to Advanced Installer again to obtain a new license at some point, if needed.
* Reach out to @crowetic for links to the installer install files, and license.
* Installed AdoptOpenJDK v17 64bit, full JDK *not* JRE * Installed AdoptOpenJDK v17 64bit, full JDK *not* JRE
## General build instructions ## General build instructions
@ -10,6 +12,12 @@
If this is your first time opening the `qortal.aip` file then you might need to adjust If this is your first time opening the `qortal.aip` file then you might need to adjust
configured paths, or create a dummy `D:` drive with the expected layout. configured paths, or create a dummy `D:` drive with the expected layout.
Opening the aip file from within a clone of the qortal repo also works, if you have a separate windows machine setup to do the build.
You May need to change the location of the 'jre64' files inside Advanced Installer, if it is set to a path that your build machine doesn't have.
The Java Memory Arguments can be set manually, but as of December 2024 they have been reset back to system defaults. This should include G1GC Garbage Collector.
Typical build procedure: Typical build procedure:
* Place the `qortal.jar` file in `Install-Files\` * Place the `qortal.jar` file in `Install-Files\`

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.qortal</groupId> <groupId>org.qortal</groupId>
<artifactId>qortal</artifactId> <artifactId>qortal</artifactId>
<version>4.6.5</version> <version>4.6.6</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

View File

@ -348,6 +348,24 @@ public class Account {
return accountData.getLevel(); return accountData.getLevel();
} }
/**
* 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. * Returns 'effective' minting level, or zero if reward-share does not exist.
* *

View File

@ -1,7 +1,13 @@
package org.qortal.api.model; 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.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
// All properties to be converted to JSON via JAXB // All properties to be converted to JSON via JAXB
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
@ -47,4 +53,31 @@ public class ApiOnlineAccount {
return this.recipientAddress; 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();
}
} }

View File

@ -9,6 +9,7 @@ import java.math.BigInteger;
public class BlockMintingInfo { public class BlockMintingInfo {
public byte[] minterPublicKey; public byte[] minterPublicKey;
public String minterAddress;
public int minterLevel; public int minterLevel;
public int onlineAccountsCount; public int onlineAccountsCount;
public BigDecimal maxDistance; public BigDecimal maxDistance;
@ -19,5 +20,4 @@ public class BlockMintingInfo {
public BlockMintingInfo() { public BlockMintingInfo() {
} }
} }

View File

@ -542,6 +542,7 @@ public class BlocksResource {
} }
} }
String minterAddress = Account.getRewardShareMintingAddress(repository, blockData.getMinterPublicKey());
int minterLevel = Account.getRewardShareEffectiveMintingLevel(repository, blockData.getMinterPublicKey()); int minterLevel = Account.getRewardShareEffectiveMintingLevel(repository, blockData.getMinterPublicKey());
if (minterLevel == 0) if (minterLevel == 0)
// This may be unavailable when requesting a trimmed block // This may be unavailable when requesting a trimmed block
@ -554,6 +555,7 @@ public class BlocksResource {
BlockMintingInfo blockMintingInfo = new BlockMintingInfo(); BlockMintingInfo blockMintingInfo = new BlockMintingInfo();
blockMintingInfo.minterPublicKey = blockData.getMinterPublicKey(); blockMintingInfo.minterPublicKey = blockData.getMinterPublicKey();
blockMintingInfo.minterAddress = minterAddress;
blockMintingInfo.minterLevel = minterLevel; blockMintingInfo.minterLevel = minterLevel;
blockMintingInfo.onlineAccountsCount = blockData.getOnlineAccountsCount(); blockMintingInfo.onlineAccountsCount = blockData.getOnlineAccountsCount();
blockMintingInfo.maxDistance = new BigDecimal(block.MAX_DISTANCE); blockMintingInfo.maxDistance = new BigDecimal(block.MAX_DISTANCE);
@ -887,5 +889,4 @@ public class BlocksResource {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
} }
} }
} }

View File

@ -234,12 +234,16 @@ public class ChatResource {
} }
) )
@ApiErrors({ApiError.INVALID_CRITERIA, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) @ApiErrors({ApiError.INVALID_CRITERIA, ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE})
public ActiveChats getActiveChats(@PathParam("address") String address, @QueryParam("encoding") Encoding encoding) { public ActiveChats getActiveChats(
@PathParam("address") String address,
@QueryParam("encoding") Encoding encoding,
@QueryParam("haschatreference") Boolean hasChatReference
) {
if (address == null || !Crypto.isValidAddress(address)) if (address == null || !Crypto.isValidAddress(address))
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS);
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
return repository.getChatRepository().getActiveChats(address, encoding); return repository.getChatRepository().getActiveChats(address, encoding, hasChatReference);
} catch (DataException e) { } catch (DataException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
} }

View File

@ -77,7 +77,9 @@ public class ActiveChatsWebSocket extends ApiWebSocket {
} }
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
ActiveChats activeChats = repository.getChatRepository().getActiveChats(ourAddress, getTargetEncoding(session)); Boolean hasChatReference = getHasChatReference(session);
ActiveChats activeChats = repository.getChatRepository().getActiveChats(ourAddress, getTargetEncoding(session), hasChatReference);
StringWriter stringWriter = new StringWriter(); StringWriter stringWriter = new StringWriter();
@ -103,4 +105,20 @@ public class ActiveChatsWebSocket extends ApiWebSocket {
return Encoding.valueOf(encoding); return Encoding.valueOf(encoding);
} }
private Boolean getHasChatReference(Session session) {
Map<String, List<String>> queryParams = session.getUpgradeRequest().getParameterMap();
List<String> hasChatReferenceList = queryParams.get("haschatreference");
// Return null if not specified
if (hasChatReferenceList != null && hasChatReferenceList.size() == 1) {
String value = hasChatReferenceList.get(0).toLowerCase();
if (value.equals("true")) {
return true;
} else if (value.equals("false")) {
return false;
}
}
return null; // Ignored if not present
}
} }

View File

@ -414,6 +414,21 @@ public class Block {
}); });
} }
// 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()) { if (onlineAccounts.isEmpty()) {
LOGGER.debug("No online accounts - not even our own?"); LOGGER.debug("No online accounts - not even our own?");
return null; return null;
@ -721,19 +736,19 @@ public class Block {
List<ExpandedAccount> expandedAccounts = new ArrayList<>(); List<ExpandedAccount> expandedAccounts = new ArrayList<>();
for (RewardShareData rewardShare : this.cachedOnlineRewardShares) { for (RewardShareData rewardShare : this.cachedOnlineRewardShares) {
if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight()) { int groupId = BlockChain.getInstance().getMintingGroupId();
expandedAccounts.add(new ExpandedAccount(repository, rewardShare)); String address = rewardShare.getMinter();
} boolean isMinterGroupMember = repository.getGroupRepository().memberExists(groupId, address);
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())
expandedAccounts.add(new ExpandedAccount(repository, rewardShare));
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight() && isMinterGroupMember)
expandedAccounts.add(new ExpandedAccount(repository, rewardShare));
}
this.cachedExpandedAccounts = expandedAccounts; this.cachedExpandedAccounts = expandedAccounts;
LOGGER.trace(() -> String.format("Online reward-shares after expanded accounts %s", this.cachedOnlineRewardShares));
return this.cachedExpandedAccounts; return this.cachedExpandedAccounts;
} }
@ -1143,8 +1158,17 @@ public class Block {
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getOnlineAccountMinterLevelValidationHeight()) { if (this.getBlockData().getHeight() >= BlockChain.getInstance().getOnlineAccountMinterLevelValidationHeight()) {
List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts(); List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
for (ExpandedAccount account : expandedAccounts) { 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) if (account.getMintingAccount().getEffectiveMintingLevel() == 0)
return ValidationResult.ONLINE_ACCOUNTS_INVALID; return ValidationResult.ONLINE_ACCOUNTS_INVALID;
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight()) {
if (!isMinterGroupMember)
return ValidationResult.ONLINE_ACCOUNTS_INVALID;
}
} }
} }
@ -1273,6 +1297,7 @@ public class Block {
// Online Accounts // Online Accounts
ValidationResult onlineAccountsResult = this.areOnlineAccountsValid(); ValidationResult onlineAccountsResult = this.areOnlineAccountsValid();
LOGGER.trace("Accounts valid = {}", onlineAccountsResult);
if (onlineAccountsResult != ValidationResult.OK) if (onlineAccountsResult != ValidationResult.OK)
return onlineAccountsResult; return onlineAccountsResult;
@ -1361,7 +1386,7 @@ public class Block {
// Check transaction can even be processed // Check transaction can even be processed
validationResult = transaction.isProcessable(); validationResult = transaction.isProcessable();
if (validationResult != Transaction.ValidationResult.OK) { 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; return ValidationResult.TRANSACTION_INVALID;
} }
@ -1562,6 +1587,7 @@ public class Block {
this.blockData.setHeight(blockchainHeight + 1); this.blockData.setHeight(blockchainHeight + 1);
LOGGER.trace(() -> String.format("Processing block %d", this.blockData.getHeight())); 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) { if (this.blockData.getHeight() > 1) {
@ -2280,7 +2306,6 @@ public class Block {
// Select the correct set of share bins based on block height // Select the correct set of share bins based on block height
List<AccountLevelShareBin> accountLevelShareBinsForBlock = (this.blockData.getHeight() >= BlockChain.getInstance().getSharesByLevelV2Height()) ? List<AccountLevelShareBin> accountLevelShareBinsForBlock = (this.blockData.getHeight() >= BlockChain.getInstance().getSharesByLevelV2Height()) ?
BlockChain.getInstance().getAccountLevelShareBinsV2() : BlockChain.getInstance().getAccountLevelShareBinsV1(); BlockChain.getInstance().getAccountLevelShareBinsV2() : BlockChain.getInstance().getAccountLevelShareBinsV1();
// Determine reward candidates based on account level // Determine reward candidates based on account level
// This needs a deep copy, so the shares can be modified when tiers aren't activated yet // This needs a deep copy, so the shares can be modified when tiers aren't activated yet
List<AccountLevelShareBin> accountLevelShareBins = new ArrayList<>(); List<AccountLevelShareBin> accountLevelShareBins = new ArrayList<>();
@ -2570,9 +2595,11 @@ public class Block {
return; return;
int minterLevel = Account.getRewardShareEffectiveMintingLevel(this.repository, this.getMinter().getPublicKey()); 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("======= BLOCK %d (%.8s) =======", this.getBlockData().getHeight(), Base58.encode(this.getSignature())));
LOGGER.debug(String.format("Timestamp: %d", this.getBlockData().getTimestamp())); 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("Minter level: %d", minterLevel));
LOGGER.debug(String.format("Online accounts: %d", this.getBlockData().getOnlineAccountsCount())); LOGGER.debug(String.format("Online accounts: %d", this.getBlockData().getOnlineAccountsCount()));
LOGGER.debug(String.format("AT count: %d", this.getBlockData().getATCount())); LOGGER.debug(String.format("AT count: %d", this.getBlockData().getATCount()));

View File

@ -1,8 +1,11 @@
package org.qortal.data.block; package org.qortal.data.block;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import org.qortal.account.Account;
import org.qortal.block.BlockChain; 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.settings.Settings;
import org.qortal.utils.NTP; import org.qortal.utils.NTP;
@ -232,11 +235,31 @@ public class BlockData implements Serializable {
return blockTimestamp < onlineAccountSignaturesTrimmedTimestamp && blockTimestamp < currentTrimmableTimestamp; 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 // JAXB special
@XmlElement(name = "minterAddress") @XmlElement(name = "minterAddress")
protected String getMinterAddress() { protected String getMinterAddress() {
return Crypto.toAddress(this.minterPublicKey); return getMinterAddressFromPublicKey();
} }
@XmlElement(name = "minterLevel")
protected int getMinterLevel() {
return getMinterLevelFromPublicKey();
}
} }

View File

@ -22,6 +22,6 @@ public interface ChatRepository {
public ChatMessage toChatMessage(ChatTransactionData chatTransactionData, Encoding encoding) throws DataException; public ChatMessage toChatMessage(ChatTransactionData chatTransactionData, Encoding encoding) throws DataException;
public ActiveChats getActiveChats(String address, Encoding encoding) throws DataException; public ActiveChats getActiveChats(String address, Encoding encoding, Boolean hasChatReference) throws DataException;
} }

View File

@ -176,14 +176,14 @@ public class HSQLDBChatRepository implements ChatRepository {
} }
@Override @Override
public ActiveChats getActiveChats(String address, Encoding encoding) throws DataException { public ActiveChats getActiveChats(String address, Encoding encoding, Boolean hasChatReference) throws DataException {
List<GroupChat> groupChats = getActiveGroupChats(address, encoding); List<GroupChat> groupChats = getActiveGroupChats(address, encoding, hasChatReference);
List<DirectChat> directChats = getActiveDirectChats(address); List<DirectChat> directChats = getActiveDirectChats(address, hasChatReference);
return new ActiveChats(groupChats, directChats); return new ActiveChats(groupChats, directChats);
} }
private List<GroupChat> getActiveGroupChats(String address, Encoding encoding) throws DataException { private List<GroupChat> getActiveGroupChats(String address, Encoding encoding, Boolean hasChatReference) throws DataException {
// Find groups where address is a member and potential latest message details // Find groups where address is a member and potential latest message details
String groupsSql = "SELECT group_id, group_name, latest_timestamp, sender, sender_name, signature, data " String groupsSql = "SELECT group_id, group_name, latest_timestamp, sender, sender_name, signature, data "
+ "FROM GroupMembers " + "FROM GroupMembers "
@ -194,8 +194,16 @@ public class HSQLDBChatRepository implements ChatRepository {
+ "JOIN Transactions USING (signature) " + "JOIN Transactions USING (signature) "
+ "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender " + "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender "
// NOTE: We need to qualify "Groups.group_id" here to avoid "General error" bug in HSQLDB v2.5.0 // NOTE: We need to qualify "Groups.group_id" here to avoid "General error" bug in HSQLDB v2.5.0
+ "WHERE tx_group_id = Groups.group_id AND type = " + TransactionType.CHAT.value + " " + "WHERE tx_group_id = Groups.group_id AND type = " + TransactionType.CHAT.value + " ";
+ "ORDER BY created_when DESC "
if (hasChatReference != null) {
if (hasChatReference) {
groupsSql += "AND chat_reference IS NOT NULL ";
} else {
groupsSql += "AND chat_reference IS NULL ";
}
}
groupsSql += "ORDER BY created_when DESC "
+ "LIMIT 1" + "LIMIT 1"
+ ") AS LatestMessages ON TRUE " + ") AS LatestMessages ON TRUE "
+ "WHERE address = ?"; + "WHERE address = ?";
@ -230,8 +238,16 @@ public class HSQLDBChatRepository implements ChatRepository {
+ "JOIN Transactions USING (signature) " + "JOIN Transactions USING (signature) "
+ "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender " + "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender "
+ "WHERE tx_group_id = 0 " + "WHERE tx_group_id = 0 "
+ "AND recipient IS NULL " + "AND recipient IS NULL ";
+ "ORDER BY created_when DESC "
if (hasChatReference != null) {
if (hasChatReference) {
grouplessSql += "AND chat_reference IS NOT NULL ";
} else {
grouplessSql += "AND chat_reference IS NULL ";
}
}
grouplessSql += "ORDER BY created_when DESC "
+ "LIMIT 1"; + "LIMIT 1";
try (ResultSet resultSet = this.repository.checkedExecute(grouplessSql)) { try (ResultSet resultSet = this.repository.checkedExecute(grouplessSql)) {
@ -259,7 +275,7 @@ public class HSQLDBChatRepository implements ChatRepository {
return groupChats; return groupChats;
} }
private List<DirectChat> getActiveDirectChats(String address) throws DataException { private List<DirectChat> getActiveDirectChats(String address, Boolean hasChatReference) throws DataException {
// Find chat messages involving address // Find chat messages involving address
String directSql = "SELECT other_address, name, latest_timestamp, sender, sender_name " String directSql = "SELECT other_address, name, latest_timestamp, sender, sender_name "
+ "FROM (" + "FROM ("
@ -275,8 +291,18 @@ public class HSQLDBChatRepository implements ChatRepository {
+ "NATURAL JOIN Transactions " + "NATURAL JOIN Transactions "
+ "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender " + "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender "
+ "WHERE (sender = other_address AND recipient = ?) " + "WHERE (sender = other_address AND recipient = ?) "
+ "OR (sender = ? AND recipient = other_address) " + "OR (sender = ? AND recipient = other_address) ";
+ "ORDER BY created_when DESC "
// Apply hasChatReference filter
if (hasChatReference != null) {
if (hasChatReference) {
directSql += "AND chat_reference IS NOT NULL ";
} else {
directSql += "AND chat_reference IS NULL ";
}
}
directSql += "ORDER BY created_when DESC "
+ "LIMIT 1" + "LIMIT 1"
+ ") AS LatestMessages " + ") AS LatestMessages "
+ "LEFT OUTER JOIN Names ON owner = other_address"; + "LEFT OUTER JOIN Names ON owner = other_address";

View File

@ -213,7 +213,7 @@ public class Settings {
public long recoveryModeTimeout = 9999999999999L; public long recoveryModeTimeout = 9999999999999L;
/** Minimum peer version number required in order to sync with them */ /** Minimum peer version number required in order to sync with them */
private String minPeerVersion = "4.6.3"; private String minPeerVersion = "4.6.5";
/** Whether to allow connections with peers below minPeerVersion /** Whether to allow connections with peers below minPeerVersion
* If true, we won't sync with them but they can still sync with us, and will show in the peers list * If true, we won't sync with them but they can still sync with us, and will show in the peers list
* If false, sync will be blocked both ways, and they will not appear in the peers list */ * If false, sync will be blocked both ways, and they will not appear in the peers list */
@ -222,7 +222,7 @@ public class Settings {
/** Minimum time (in seconds) that we should attempt to remain connected to a peer for */ /** Minimum time (in seconds) that we should attempt to remain connected to a peer for */
private int minPeerConnectionTime = 2 * 60 * 60; // seconds private int minPeerConnectionTime = 2 * 60 * 60; // seconds
/** Maximum time (in seconds) that we should attempt to remain connected to a peer for */ /** Maximum time (in seconds) that we should attempt to remain connected to a peer for */
private int maxPeerConnectionTime = 4 * 60 * 60; // seconds private int maxPeerConnectionTime = 6 * 60 * 60; // seconds
/** Maximum time (in seconds) that a peer should remain connected when requesting QDN data */ /** Maximum time (in seconds) that a peer should remain connected when requesting QDN data */
private int maxDataPeerConnectionTime = 30 * 60; // seconds private int maxDataPeerConnectionTime = 30 * 60; // seconds
@ -281,7 +281,10 @@ public class Settings {
// Auto-update sources // Auto-update sources
private String[] autoUpdateRepos = new String[] { private String[] autoUpdateRepos = new String[] {
"https://github.com/Qortal/qortal/raw/%s/qortal.update", "https://github.com/Qortal/qortal/raw/%s/qortal.update",
"https://raw.githubusercontent.com@151.101.16.133/Qortal/qortal/%s/qortal.update" "https://raw.githubusercontent.com@151.101.16.133/Qortal/qortal/%s/qortal.update",
"https://qortal.link/Auto-Update/%s/qortal.update",
"https://qortal.name/Auto-Update/%s/qortal.update",
"https://update.qortal.org/Auto-Update/%s/qortal.update"
}; };
// Lists // Lists

View File

@ -614,6 +614,7 @@ function getDefaultTimeout(action) {
switch (action) { switch (action) {
case "GET_USER_ACCOUNT": case "GET_USER_ACCOUNT":
case "SAVE_FILE": case "SAVE_FILE":
case "SIGN_TRANSACTION":
case "DECRYPT_DATA": case "DECRYPT_DATA":
// User may take a long time to accept/deny the popup // User may take a long time to accept/deny the popup
return 60 * 60 * 1000; return 60 * 60 * 1000;
@ -635,6 +636,11 @@ function getDefaultTimeout(action) {
// Chat messages rely on PoW computations, so allow extra time // Chat messages rely on PoW computations, so allow extra time
return 60 * 1000; return 60 * 1000;
case "CREATE_TRADE_BUY_ORDER":
case "CREATE_TRADE_SELL_ORDER":
case "CANCEL_TRADE_SELL_ORDER":
case "VOTE_ON_POLL":
case "CREATE_POLL":
case "JOIN_GROUP": case "JOIN_GROUP":
case "DEPLOY_AT": case "DEPLOY_AT":
case "SEND_COIN": case "SEND_COIN":
@ -649,7 +655,7 @@ function getDefaultTimeout(action) {
break; break;
} }
} }
return 10 * 1000; return 30 * 1000;
} }
/** /**

View File

@ -54,26 +54,39 @@ public class BlockArchiveV1Tests extends Common {
public void testWriter() throws DataException, InterruptedException, TransformationException, IOException { public void testWriter() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testWriter");
// Mint some blocks so that we are able to archive them later // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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) // 900 blocks are trimmed (this specifies the first untrimmed height)
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901);
repository.getATRepository().setAtTrimHeight(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 // Check the max archive height - this should be one less than the first untrimmed height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight);
assertEquals(900, maximumArchiveHeight); assertEquals(900, maximumArchiveHeight);
// Write blocks 2-900 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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()); assertEquals(900 - 1, writer.getWrittenCount());
// Increment block archive height // Increment block archive height
@ -84,6 +97,9 @@ public class BlockArchiveV1Tests extends Common {
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
System.out.println("testWriter completed successfully.");
} }
} }
@ -91,26 +107,39 @@ public class BlockArchiveV1Tests extends Common {
public void testWriterAndReader() throws DataException, InterruptedException, TransformationException, IOException { public void testWriterAndReader() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testWriterAndReader");
// Mint some blocks so that we are able to archive them later // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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) // 900 blocks are trimmed (this specifies the first untrimmed height)
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901);
repository.getATRepository().setAtTrimHeight(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 // Check the max archive height - this should be one less than the first untrimmed height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight);
assertEquals(900, maximumArchiveHeight); assertEquals(900, maximumArchiveHeight);
// Write blocks 2-900 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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()); assertEquals(900 - 1, writer.getWrittenCount());
// Increment block archive height // Increment block archive height
@ -121,8 +150,10 @@ public class BlockArchiveV1Tests extends Common {
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
// Read block 2 from the archive // Read block 2 from the archive
System.out.println("Reading block 2 from the archive...");
BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockArchiveReader reader = BlockArchiveReader.getInstance();
BlockTransformation block2Info = reader.fetchBlockAtHeight(2); BlockTransformation block2Info = reader.fetchBlockAtHeight(2);
BlockData block2ArchiveData = block2Info.getBlockData(); BlockData block2ArchiveData = block2Info.getBlockData();
@ -131,6 +162,7 @@ public class BlockArchiveV1Tests extends Common {
BlockData block2RepositoryData = repository.getBlockRepository().fromHeight(2); BlockData block2RepositoryData = repository.getBlockRepository().fromHeight(2);
// Ensure the values match // Ensure the values match
System.out.println("Comparing block 2 data...");
assertEquals(block2ArchiveData.getHeight(), block2RepositoryData.getHeight()); assertEquals(block2ArchiveData.getHeight(), block2RepositoryData.getHeight());
assertArrayEquals(block2ArchiveData.getSignature(), block2RepositoryData.getSignature()); assertArrayEquals(block2ArchiveData.getSignature(), block2RepositoryData.getSignature());
@ -138,6 +170,7 @@ public class BlockArchiveV1Tests extends Common {
assertEquals(1, block2ArchiveData.getOnlineAccountsCount()); assertEquals(1, block2ArchiveData.getOnlineAccountsCount());
// Read block 900 from the archive // Read block 900 from the archive
System.out.println("Reading block 900 from the archive...");
BlockTransformation block900Info = reader.fetchBlockAtHeight(900); BlockTransformation block900Info = reader.fetchBlockAtHeight(900);
BlockData block900ArchiveData = block900Info.getBlockData(); BlockData block900ArchiveData = block900Info.getBlockData();
@ -145,12 +178,14 @@ public class BlockArchiveV1Tests extends Common {
BlockData block900RepositoryData = repository.getBlockRepository().fromHeight(900); BlockData block900RepositoryData = repository.getBlockRepository().fromHeight(900);
// Ensure the values match // Ensure the values match
System.out.println("Comparing block 900 data...");
assertEquals(block900ArchiveData.getHeight(), block900RepositoryData.getHeight()); assertEquals(block900ArchiveData.getHeight(), block900RepositoryData.getHeight());
assertArrayEquals(block900ArchiveData.getSignature(), block900RepositoryData.getSignature()); assertArrayEquals(block900ArchiveData.getSignature(), block900RepositoryData.getSignature());
// Test some values in the archive // Test some values in the archive
assertEquals(1, block900ArchiveData.getOnlineAccountsCount()); assertEquals(1, block900ArchiveData.getOnlineAccountsCount());
System.out.println("testWriterAndReader completed successfully.");
} }
} }
@ -158,33 +193,48 @@ public class BlockArchiveV1Tests extends Common {
public void testArchivedAtStates() throws DataException, InterruptedException, TransformationException, IOException { public void testArchivedAtStates() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testArchivedAtStates");
// Deploy an AT so that we have AT state data // Deploy an AT so that we have AT state data
System.out.println("Deploying AT...");
PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice");
byte[] creationBytes = AtUtils.buildSimpleAT(); byte[] creationBytes = AtUtils.buildSimpleAT();
long fundingAmount = 1_00000000L; long fundingAmount = 1_00000000L;
DeployAtTransaction deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); DeployAtTransaction deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
String atAddress = deployAtTransaction.getATAccount().getAddress(); 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 // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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) // 9 blocks are trimmed (this specifies the first untrimmed height)
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(10); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(10);
repository.getATRepository().setAtTrimHeight(10); repository.getATRepository().setAtTrimHeight(10);
System.out.println("Set trim heights to 10.");
// Check the max archive height // Check the max archive height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height (Expected 9): " + maximumArchiveHeight);
assertEquals(9, maximumArchiveHeight); assertEquals(9, maximumArchiveHeight);
// Write blocks 2-9 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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()); assertEquals(9 - 1, writer.getWrittenCount());
// Increment block archive height // Increment block archive height
@ -195,10 +245,13 @@ public class BlockArchiveV1Tests extends Common {
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
// Check blocks 3-9 // Check blocks 3-9
System.out.println("Checking blocks 3 to 9...");
for (Integer testHeight = 2; testHeight <= 9; testHeight++) { for (Integer testHeight = 2; testHeight <= 9; testHeight++) {
System.out.println("Reading block " + testHeight + " from the archive...");
// Read a block from the archive // Read a block from the archive
BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockArchiveReader reader = BlockArchiveReader.getInstance();
BlockTransformation blockInfo = reader.fetchBlockAtHeight(testHeight); BlockTransformation blockInfo = reader.fetchBlockAtHeight(testHeight);
@ -216,6 +269,7 @@ public class BlockArchiveV1Tests extends Common {
// Check the archived AT state // Check the archived AT state
if (testHeight == 2) { 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) // Block 2 won't have an AT state hash because it's initial (and has the DEPLOY_AT in the same block)
assertNull(archivedAtStateData); assertNull(archivedAtStateData);
@ -223,6 +277,7 @@ public class BlockArchiveV1Tests extends Common {
assertEquals(Transaction.TransactionType.DEPLOY_AT, archivedTransactions.get(0).getType()); assertEquals(Transaction.TransactionType.DEPLOY_AT, archivedTransactions.get(0).getType());
} }
else { 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 // For blocks 3+, ensure the archive has the AT state data, but not the hashes
assertNotNull(archivedAtStateData.getStateHash()); assertNotNull(archivedAtStateData.getStateHash());
assertNull(archivedAtStateData.getStateData()); assertNull(archivedAtStateData.getStateData());
@ -255,10 +310,12 @@ public class BlockArchiveV1Tests extends Common {
} }
// Check block 10 (unarchived) // Check block 10 (unarchived)
System.out.println("Checking block 10 (should not be in archive)...");
BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockArchiveReader reader = BlockArchiveReader.getInstance();
BlockTransformation blockInfo = reader.fetchBlockAtHeight(10); BlockTransformation blockInfo = reader.fetchBlockAtHeight(10);
assertNull(blockInfo); assertNull(blockInfo);
System.out.println("testArchivedAtStates completed successfully.");
} }
} }
@ -267,32 +324,46 @@ public class BlockArchiveV1Tests extends Common {
public void testArchiveAndPrune() throws DataException, InterruptedException, TransformationException, IOException { public void testArchiveAndPrune() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testArchiveAndPrune");
// Deploy an AT so that we have AT state data // Deploy an AT so that we have AT state data
System.out.println("Deploying AT...");
PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice");
byte[] creationBytes = AtUtils.buildSimpleAT(); byte[] creationBytes = AtUtils.buildSimpleAT();
long fundingAmount = 1_00000000L; long fundingAmount = 1_00000000L;
AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
// Mint some blocks so that we are able to archive them later // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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) // Assume 900 blocks are trimmed (this specifies the first untrimmed height)
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901);
repository.getATRepository().setAtTrimHeight(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 // Check the max archive height - this should be one less than the first untrimmed height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight);
assertEquals(900, maximumArchiveHeight); assertEquals(900, maximumArchiveHeight);
// Write blocks 2-900 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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()); assertEquals(900 - 1, writer.getWrittenCount());
// Increment block archive height // Increment block archive height
@ -303,17 +374,21 @@ public class BlockArchiveV1Tests extends Common {
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
// Ensure the SQL repository contains blocks 2 and 900... // Ensure the SQL repository contains blocks 2 and 900...
assertNotNull(repository.getBlockRepository().fromHeight(2)); assertNotNull(repository.getBlockRepository().fromHeight(2));
assertNotNull(repository.getBlockRepository().fromHeight(900)); assertNotNull(repository.getBlockRepository().fromHeight(900));
System.out.println("Blocks 2 and 900 exist in the repository.");
// Prune all the archived blocks // Prune all the archived blocks
System.out.println("Pruning blocks 2 to 900...");
int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 900); int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 900);
assertEquals(900-1, numBlocksPruned); assertEquals(900-1, numBlocksPruned);
repository.getBlockRepository().setBlockPruneHeight(901); repository.getBlockRepository().setBlockPruneHeight(901);
// Prune the AT states for the archived blocks // Prune the AT states for the archived blocks
System.out.println("Pruning AT states up to height 900...");
repository.getATRepository().rebuildLatestAtStates(900); repository.getATRepository().rebuildLatestAtStates(900);
repository.saveChanges(); repository.saveChanges();
int numATStatesPruned = repository.getATRepository().pruneAtStates(0, 900); int numATStatesPruned = repository.getATRepository().pruneAtStates(0, 900);
@ -323,14 +398,19 @@ public class BlockArchiveV1Tests extends Common {
// Now ensure the SQL repository is missing blocks 2 and 900... // Now ensure the SQL repository is missing blocks 2 and 900...
assertNull(repository.getBlockRepository().fromHeight(2)); assertNull(repository.getBlockRepository().fromHeight(2));
assertNull(repository.getBlockRepository().fromHeight(900)); 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) // ... 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(1));
assertNotNull(repository.getBlockRepository().fromHeight(901)); 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 // 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 class BlockArchiveV1Tests extends Common {
public void testTrimArchivePruneAndOrphan() throws DataException, InterruptedException, TransformationException, IOException { public void testTrimArchivePruneAndOrphan() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testTrimArchivePruneAndOrphan");
// Deploy an AT so that we have AT state data // Deploy an AT so that we have AT state data
System.out.println("Deploying AT...");
PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice");
byte[] creationBytes = AtUtils.buildSimpleAT(); byte[] creationBytes = AtUtils.buildSimpleAT();
long fundingAmount = 1_00000000L; long fundingAmount = 1_00000000L;
AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
System.out.println("AT deployed successfully.");
// Mint some blocks so that we are able to archive them later // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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 // Make sure that block 500 has full AT state data and data hash
System.out.println("Verifying block 500 AT state data...");
List<ATStateData> block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500); List<ATStateData> block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500);
ATStateData atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); ATStateData atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500);
assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateHash());
assertNotNull(atStatesData.getStateData()); assertNotNull(atStatesData.getStateData());
System.out.println("Block 500 AT state data verified.");
// Trim the first 500 blocks // Trim the first 500 blocks
System.out.println("Trimming first 500 blocks...");
repository.getBlockRepository().trimOldOnlineAccountsSignatures(0, 500); repository.getBlockRepository().trimOldOnlineAccountsSignatures(0, 500);
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(501); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(501);
repository.getATRepository().rebuildLatestAtStates(500); repository.getATRepository().rebuildLatestAtStates(500);
repository.getATRepository().trimAtStates(0, 500, 1000); repository.getATRepository().trimAtStates(0, 500, 1000);
repository.getATRepository().setAtTrimHeight(501); repository.getATRepository().setAtTrimHeight(501);
System.out.println("Trimming completed.");
// Now block 499 should only have the AT state data hash // Now block 499 should only have the AT state data hash
System.out.println("Checking block 499 AT state data...");
List<ATStateData> block499AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(499); List<ATStateData> block499AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(499);
atStatesData = repository.getATRepository().getATStateAtHeight(block499AtStatesData.get(0).getATAddress(), 499); atStatesData = repository.getATRepository().getATStateAtHeight(block499AtStatesData.get(0).getATAddress(), 499);
assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateHash());
assertNull(atStatesData.getStateData()); 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 // ... 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); block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500);
atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500);
assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateHash());
assertNotNull(atStatesData.getStateData()); assertNotNull(atStatesData.getStateData());
System.out.println("Block 500 AT state data contains full data.");
// ... and block 501 should also have the full data // ... and block 501 should also have the full data
System.out.println("Verifying block 501 AT state data...");
List<ATStateData> block501AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(501); List<ATStateData> block501AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(501);
atStatesData = repository.getATRepository().getATStateAtHeight(block501AtStatesData.get(0).getATAddress(), 501); atStatesData = repository.getATRepository().getATStateAtHeight(block501AtStatesData.get(0).getATAddress(), 501);
assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateHash());
assertNotNull(atStatesData.getStateData()); 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 // Check the max archive height - this should be one less than the first untrimmed height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height determined (Expected 500): " + maximumArchiveHeight);
assertEquals(500, maximumArchiveHeight); assertEquals(500, maximumArchiveHeight);
BlockData block3DataPreArchive = repository.getBlockRepository().fromHeight(3); BlockData block3DataPreArchive = repository.getBlockRepository().fromHeight(3);
// Write blocks 2-500 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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 assertEquals(500 - 1, writer.getWrittenCount()); // -1 for the genesis block
// Increment block archive height // Increment block archive height
repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount()); repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount());
repository.saveChanges(); repository.saveChanges();
assertEquals(500 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight()); assertEquals(500 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight());
System.out.println("Block archive height updated to: " + (500 - 1));
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
// Ensure the SQL repository contains blocks 2 and 500... // 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(2));
assertNotNull(repository.getBlockRepository().fromHeight(500)); assertNotNull(repository.getBlockRepository().fromHeight(500));
System.out.println("Blocks 2 and 500 are present in the repository.");
// Prune all the archived blocks // Prune all the archived blocks
System.out.println("Pruning blocks 2 to 500...");
int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 500); int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 500);
System.out.println("Number of blocks pruned (Expected 499): " + numBlocksPruned);
assertEquals(500-1, numBlocksPruned); assertEquals(500-1, numBlocksPruned);
repository.getBlockRepository().setBlockPruneHeight(501); repository.getBlockRepository().setBlockPruneHeight(501);
// Prune the AT states for the archived blocks // Prune the AT states for the archived blocks
System.out.println("Pruning AT states up to height 500...");
repository.getATRepository().rebuildLatestAtStates(500); repository.getATRepository().rebuildLatestAtStates(500);
repository.saveChanges(); repository.saveChanges();
int numATStatesPruned = repository.getATRepository().pruneAtStates(2, 500); 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 assertEquals(498, numATStatesPruned); // Minus 1 for genesis block, and another for the latest AT state
repository.getATRepository().setAtPruneHeight(501); repository.getATRepository().setAtPruneHeight(501);
// Now ensure the SQL repository is missing blocks 2 and 500... // 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(2));
assertNull(repository.getBlockRepository().fromHeight(500)); 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) // ... 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(1));
assertNotNull(repository.getBlockRepository().fromHeight(501)); 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 // 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. // Now orphan some unarchived blocks.
System.out.println("Orphaning 500 blocks...");
BlockUtils.orphanBlocks(repository, 500); 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're close to the lower limit of the SQL database now, so
// we need to import some blocks from the archive // 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); BlockArchiveUtils.importFromArchive(401, 500, repository);
// Ensure the SQL repository now contains block 401 but not 400... // 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)); assertNotNull(repository.getBlockRepository().fromHeight(401));
assertNull(repository.getBlockRepository().fromHeight(400)); assertNull(repository.getBlockRepository().fromHeight(400));
System.out.println("Block 401 exists, block 400 does not.");
// Import the remaining 399 blocks // Import the remaining 399 blocks
System.out.println("Importing blocks 2 to 400 from the archive...");
BlockArchiveUtils.importFromArchive(2, 400, repository); BlockArchiveUtils.importFromArchive(2, 400, repository);
// Verify that block 3 matches the original // Verify that block 3 matches the original
System.out.println("Verifying that block 3 matches the original data...");
BlockData block3DataPostArchive = repository.getBlockRepository().fromHeight(3); BlockData block3DataPostArchive = repository.getBlockRepository().fromHeight(3);
assertArrayEquals(block3DataPreArchive.getSignature(), block3DataPostArchive.getSignature()); assertArrayEquals(block3DataPreArchive.getSignature(), block3DataPostArchive.getSignature());
assertEquals(block3DataPreArchive.getHeight(), block3DataPostArchive.getHeight()); 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 // 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); BlockUtils.orphanBlocks(repository, 1);
System.out.println("Orphaned 1 block successfully.");
// Orphan another block, which should fail // Orphan another block, which should fail
System.out.println("Attempting to orphan another block, which should fail...");
Exception exception = null; Exception exception = null;
try { try {
BlockUtils.orphanBlocks(repository, 1); BlockUtils.orphanBlocks(repository, 1);
} catch (DataException e) { } catch (DataException e) {
exception = 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 // Ensure that a DataException is thrown because there is no more AT states data available
assertNotNull(exception); assertNotNull(exception);
assertEquals(DataException.class, exception.getClass()); 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 // 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. // and allow orphaning back through blocks with trimmed AT states.
System.out.println("testTrimArchivePruneAndOrphan completed successfully.");
} }
} }
@ -482,16 +615,26 @@ public class BlockArchiveV1Tests extends Common {
public void testMissingAtStatesHeightIndex() throws DataException, SQLException { public void testMissingAtStatesHeightIndex() throws DataException, SQLException {
try (final HSQLDBRepository repository = (HSQLDBRepository) RepositoryManager.getRepository()) { 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 // 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(repository.getATRepository().hasAtStatesHeightIndex());
assertTrue(RepositoryManager.canArchiveOrPrune()); assertTrue(RepositoryManager.canArchiveOrPrune());
System.out.println("ATStatesHeightIndex exists. Archiving and pruning are possible.");
// Delete the index // Delete the index
System.out.println("Dropping ATStatesHeightIndex...");
repository.prepareStatement("DROP INDEX ATSTATESHEIGHTINDEX").execute(); 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 // 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(repository.getATRepository().hasAtStatesHeightIndex());
assertFalse(RepositoryManager.canArchiveOrPrune()); 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 @@ public class BlockArchiveV1Tests extends Common {
Path archivePath = Paths.get(Settings.getInstance().getRepositoryPath(), "archive").toAbsolutePath(); Path archivePath = Paths.get(Settings.getInstance().getRepositoryPath(), "archive").toAbsolutePath();
try { try {
FileUtils.deleteDirectory(archivePath.toFile()); FileUtils.deleteDirectory(archivePath.toFile());
System.out.println("Deleted archive directory at: " + archivePath);
} catch (IOException e) { } catch (IOException e) {
System.out.println("Failed to delete archive directory: " + e.getMessage());
} }
} }

View File

@ -54,26 +54,39 @@ public class BlockArchiveV2Tests extends Common {
public void testWriter() throws DataException, InterruptedException, TransformationException, IOException { public void testWriter() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testWriter");
// Mint some blocks so that we are able to archive them later // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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) // 900 blocks are trimmed (this specifies the first untrimmed height)
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901);
repository.getATRepository().setAtTrimHeight(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 // Check the max archive height - this should be one less than the first untrimmed height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight);
assertEquals(900, maximumArchiveHeight); assertEquals(900, maximumArchiveHeight);
// Write blocks 2-900 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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()); assertEquals(900 - 1, writer.getWrittenCount());
// Increment block archive height // Increment block archive height
@ -84,6 +97,9 @@ public class BlockArchiveV2Tests extends Common {
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
System.out.println("testWriter completed successfully.");
} }
} }
@ -91,26 +107,39 @@ public class BlockArchiveV2Tests extends Common {
public void testWriterAndReader() throws DataException, InterruptedException, TransformationException, IOException { public void testWriterAndReader() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testWriterAndReader");
// Mint some blocks so that we are able to archive them later // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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) // 900 blocks are trimmed (this specifies the first untrimmed height)
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901);
repository.getATRepository().setAtTrimHeight(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 // Check the max archive height - this should be one less than the first untrimmed height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight);
assertEquals(900, maximumArchiveHeight); assertEquals(900, maximumArchiveHeight);
// Write blocks 2-900 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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()); assertEquals(900 - 1, writer.getWrittenCount());
// Increment block archive height // Increment block archive height
@ -121,8 +150,10 @@ public class BlockArchiveV2Tests extends Common {
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
// Read block 2 from the archive // Read block 2 from the archive
System.out.println("Reading block 2 from the archive...");
BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockArchiveReader reader = BlockArchiveReader.getInstance();
BlockTransformation block2Info = reader.fetchBlockAtHeight(2); BlockTransformation block2Info = reader.fetchBlockAtHeight(2);
BlockData block2ArchiveData = block2Info.getBlockData(); BlockData block2ArchiveData = block2Info.getBlockData();
@ -131,6 +162,7 @@ public class BlockArchiveV2Tests extends Common {
BlockData block2RepositoryData = repository.getBlockRepository().fromHeight(2); BlockData block2RepositoryData = repository.getBlockRepository().fromHeight(2);
// Ensure the values match // Ensure the values match
System.out.println("Comparing block 2 data...");
assertEquals(block2ArchiveData.getHeight(), block2RepositoryData.getHeight()); assertEquals(block2ArchiveData.getHeight(), block2RepositoryData.getHeight());
assertArrayEquals(block2ArchiveData.getSignature(), block2RepositoryData.getSignature()); assertArrayEquals(block2ArchiveData.getSignature(), block2RepositoryData.getSignature());
@ -138,6 +170,7 @@ public class BlockArchiveV2Tests extends Common {
assertEquals(1, block2ArchiveData.getOnlineAccountsCount()); assertEquals(1, block2ArchiveData.getOnlineAccountsCount());
// Read block 900 from the archive // Read block 900 from the archive
System.out.println("Reading block 900 from the archive...");
BlockTransformation block900Info = reader.fetchBlockAtHeight(900); BlockTransformation block900Info = reader.fetchBlockAtHeight(900);
BlockData block900ArchiveData = block900Info.getBlockData(); BlockData block900ArchiveData = block900Info.getBlockData();
@ -145,12 +178,14 @@ public class BlockArchiveV2Tests extends Common {
BlockData block900RepositoryData = repository.getBlockRepository().fromHeight(900); BlockData block900RepositoryData = repository.getBlockRepository().fromHeight(900);
// Ensure the values match // Ensure the values match
System.out.println("Comparing block 900 data...");
assertEquals(block900ArchiveData.getHeight(), block900RepositoryData.getHeight()); assertEquals(block900ArchiveData.getHeight(), block900RepositoryData.getHeight());
assertArrayEquals(block900ArchiveData.getSignature(), block900RepositoryData.getSignature()); assertArrayEquals(block900ArchiveData.getSignature(), block900RepositoryData.getSignature());
// Test some values in the archive // Test some values in the archive
assertEquals(1, block900ArchiveData.getOnlineAccountsCount()); assertEquals(1, block900ArchiveData.getOnlineAccountsCount());
System.out.println("testWriterAndReader completed successfully.");
} }
} }
@ -158,47 +193,66 @@ public class BlockArchiveV2Tests extends Common {
public void testArchivedAtStates() throws DataException, InterruptedException, TransformationException, IOException { public void testArchivedAtStates() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testArchivedAtStates");
// Deploy an AT so that we have AT state data // Deploy an AT so that we have AT state data
System.out.println("Deploying AT...");
PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice");
byte[] creationBytes = AtUtils.buildSimpleAT(); byte[] creationBytes = AtUtils.buildSimpleAT();
long fundingAmount = 1_00000000L; long fundingAmount = 1_00000000L;
DeployAtTransaction deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); DeployAtTransaction deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
String atAddress = deployAtTransaction.getATAccount().getAddress(); 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 // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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) // 9 blocks are trimmed (this specifies the first untrimmed height)
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(10); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(10);
repository.getATRepository().setAtTrimHeight(10); repository.getATRepository().setAtTrimHeight(10);
System.out.println("Set trim heights to 10.");
// Check the max archive height // Check the max archive height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height (Expected 9): " + maximumArchiveHeight);
assertEquals(9, maximumArchiveHeight); assertEquals(9, maximumArchiveHeight);
// Write blocks 2-9 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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()); assertEquals(9 - 1, writer.getWrittenCount());
// Increment block archive height // Increment block archive height
repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount()); repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount());
repository.saveChanges(); repository.saveChanges();
assertEquals(9 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight()); assertEquals(9 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight());
System.out.println("Block archive height updated to: " + (9 - 1));
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
// Check blocks 3-9 // Check blocks 3-9
System.out.println("Checking blocks 2 to 9...");
for (Integer testHeight = 2; testHeight <= 9; testHeight++) { for (Integer testHeight = 2; testHeight <= 9; testHeight++) {
System.out.println("Reading block " + testHeight + " from the archive...");
// Read a block from the archive // Read a block from the archive
BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockArchiveReader reader = BlockArchiveReader.getInstance();
BlockTransformation blockInfo = reader.fetchBlockAtHeight(testHeight); BlockTransformation blockInfo = reader.fetchBlockAtHeight(testHeight);
@ -216,15 +270,18 @@ public class BlockArchiveV2Tests extends Common {
// Check the archived AT state // Check the archived AT state
if (testHeight == 2) { if (testHeight == 2) {
System.out.println("Checking block " + testHeight + " AT state data (expected transactions)...");
assertEquals(1, archivedTransactions.size()); assertEquals(1, archivedTransactions.size());
assertEquals(Transaction.TransactionType.DEPLOY_AT, archivedTransactions.get(0).getType()); assertEquals(Transaction.TransactionType.DEPLOY_AT, archivedTransactions.get(0).getType());
} }
else { else {
System.out.println("Checking block " + testHeight + " AT state data (no transactions expected)...");
// Blocks 3+ shouldn't have any transactions // Blocks 3+ shouldn't have any transactions
assertTrue(archivedTransactions.isEmpty()); assertTrue(archivedTransactions.isEmpty());
} }
// Ensure the archive has the AT states hash // Ensure the archive has the AT states hash
System.out.println("Checking block " + testHeight + " AT states hash...");
assertNotNull(archivedAtStateHash); assertNotNull(archivedAtStateHash);
// Also check the online accounts count and height // Also check the online accounts count and height
@ -232,6 +289,7 @@ public class BlockArchiveV2Tests extends Common {
assertEquals(testHeight, archivedBlockData.getHeight()); assertEquals(testHeight, archivedBlockData.getHeight());
// Ensure the values match // Ensure the values match
System.out.println("Comparing block " + testHeight + " data...");
assertEquals(archivedBlockData.getHeight(), repositoryBlockData.getHeight()); assertEquals(archivedBlockData.getHeight(), repositoryBlockData.getHeight());
assertArrayEquals(archivedBlockData.getSignature(), repositoryBlockData.getSignature()); assertArrayEquals(archivedBlockData.getSignature(), repositoryBlockData.getSignature());
assertEquals(archivedBlockData.getOnlineAccountsCount(), repositoryBlockData.getOnlineAccountsCount()); assertEquals(archivedBlockData.getOnlineAccountsCount(), repositoryBlockData.getOnlineAccountsCount());
@ -249,10 +307,12 @@ public class BlockArchiveV2Tests extends Common {
} }
// Check block 10 (unarchived) // Check block 10 (unarchived)
System.out.println("Checking block 10 (should not be in archive)...");
BlockArchiveReader reader = BlockArchiveReader.getInstance(); BlockArchiveReader reader = BlockArchiveReader.getInstance();
BlockTransformation blockInfo = reader.fetchBlockAtHeight(10); BlockTransformation blockInfo = reader.fetchBlockAtHeight(10);
assertNull(blockInfo); assertNull(blockInfo);
System.out.println("testArchivedAtStates completed successfully.");
} }
} }
@ -261,32 +321,47 @@ public class BlockArchiveV2Tests extends Common {
public void testArchiveAndPrune() throws DataException, InterruptedException, TransformationException, IOException { public void testArchiveAndPrune() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testArchiveAndPrune");
// Deploy an AT so that we have AT state data // Deploy an AT so that we have AT state data
System.out.println("Deploying AT...");
PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice");
byte[] creationBytes = AtUtils.buildSimpleAT(); byte[] creationBytes = AtUtils.buildSimpleAT();
long fundingAmount = 1_00000000L; long fundingAmount = 1_00000000L;
AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
System.out.println("AT deployed successfully.");
// Mint some blocks so that we are able to archive them later // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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) // Assume 900 blocks are trimmed (this specifies the first untrimmed height)
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(901);
repository.getATRepository().setAtTrimHeight(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 // Check the max archive height - this should be one less than the first untrimmed height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height (Expected 900): " + maximumArchiveHeight);
assertEquals(900, maximumArchiveHeight); assertEquals(900, maximumArchiveHeight);
// Write blocks 2-900 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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()); assertEquals(900 - 1, writer.getWrittenCount());
// Increment block archive height // Increment block archive height
@ -297,34 +372,48 @@ public class BlockArchiveV2Tests extends Common {
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
// Ensure the SQL repository contains blocks 2 and 900... // 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(2));
assertNotNull(repository.getBlockRepository().fromHeight(900)); assertNotNull(repository.getBlockRepository().fromHeight(900));
System.out.println("Blocks 2 and 900 are present in the repository.");
// Prune all the archived blocks // Prune all the archived blocks
System.out.println("Pruning blocks 2 to 900...");
int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 900); int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 900);
System.out.println("Number of blocks pruned (Expected 899): " + numBlocksPruned);
assertEquals(900-1, numBlocksPruned); assertEquals(900-1, numBlocksPruned);
repository.getBlockRepository().setBlockPruneHeight(901); repository.getBlockRepository().setBlockPruneHeight(901);
// Prune the AT states for the archived blocks // Prune the AT states for the archived blocks
System.out.println("Pruning AT states up to height 900...");
repository.getATRepository().rebuildLatestAtStates(900); repository.getATRepository().rebuildLatestAtStates(900);
repository.saveChanges(); repository.saveChanges();
int numATStatesPruned = repository.getATRepository().pruneAtStates(0, 900); 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 assertEquals(900-2, numATStatesPruned); // Minus 1 for genesis block, and another for the latest AT state
repository.getATRepository().setAtPruneHeight(901); repository.getATRepository().setAtPruneHeight(901);
// Now ensure the SQL repository is missing blocks 2 and 900... // 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(2));
assertNull(repository.getBlockRepository().fromHeight(900)); 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) // ... 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(1));
assertNotNull(repository.getBlockRepository().fromHeight(901)); 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 // 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 class BlockArchiveV2Tests extends Common {
public void testTrimArchivePruneAndOrphan() throws DataException, InterruptedException, TransformationException, IOException { public void testTrimArchivePruneAndOrphan() throws DataException, InterruptedException, TransformationException, IOException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
System.out.println("Starting testTrimArchivePruneAndOrphan");
// Deploy an AT so that we have AT state data // Deploy an AT so that we have AT state data
System.out.println("Deploying AT...");
PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice"); PrivateKeyAccount deployer = Common.getTestAccount(repository, "alice");
byte[] creationBytes = AtUtils.buildSimpleAT(); byte[] creationBytes = AtUtils.buildSimpleAT();
long fundingAmount = 1_00000000L; long fundingAmount = 1_00000000L;
AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount); AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
System.out.println("AT deployed successfully.");
// Mint some blocks so that we are able to archive them later // 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++) { for (int i = 0; i < 1000; i++) {
BlockMinter.mintTestingBlock(repository, Common.getTestAccount(repository, "alice-reward-share")); 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 // Make sure that block 500 has full AT state data and data hash
System.out.println("Verifying block 500 AT state data...");
List<ATStateData> block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500); List<ATStateData> block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500);
ATStateData atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); ATStateData atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500);
assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateHash());
assertNotNull(atStatesData.getStateData()); assertNotNull(atStatesData.getStateData());
System.out.println("Block 500 AT state data verified.");
// Trim the first 500 blocks // Trim the first 500 blocks
System.out.println("Trimming first 500 blocks...");
repository.getBlockRepository().trimOldOnlineAccountsSignatures(0, 500); repository.getBlockRepository().trimOldOnlineAccountsSignatures(0, 500);
repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(501); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(501);
repository.getATRepository().rebuildLatestAtStates(500); repository.getATRepository().rebuildLatestAtStates(500);
repository.getATRepository().trimAtStates(0, 500, 1000); repository.getATRepository().trimAtStates(0, 500, 1000);
repository.getATRepository().setAtTrimHeight(501); repository.getATRepository().setAtTrimHeight(501);
System.out.println("Trimming completed.");
// Now block 499 should only have the AT state data hash // Now block 499 should only have the AT state data hash
System.out.println("Checking block 499 AT state data...");
List<ATStateData> block499AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(499); List<ATStateData> block499AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(499);
atStatesData = repository.getATRepository().getATStateAtHeight(block499AtStatesData.get(0).getATAddress(), 499); atStatesData = repository.getATRepository().getATStateAtHeight(block499AtStatesData.get(0).getATAddress(), 499);
assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateHash());
assertNull(atStatesData.getStateData()); 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 // ... 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); block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500);
atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500);
assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateHash());
assertNotNull(atStatesData.getStateData()); assertNotNull(atStatesData.getStateData());
System.out.println("Block 500 AT state data contains full data.");
// ... and block 501 should also have the full data // ... and block 501 should also have the full data
System.out.println("Verifying block 501 AT state data...");
List<ATStateData> block501AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(501); List<ATStateData> block501AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(501);
atStatesData = repository.getATRepository().getATStateAtHeight(block501AtStatesData.get(0).getATAddress(), 501); atStatesData = repository.getATRepository().getATStateAtHeight(block501AtStatesData.get(0).getATAddress(), 501);
assertNotNull(atStatesData.getStateHash()); assertNotNull(atStatesData.getStateHash());
assertNotNull(atStatesData.getStateData()); 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 // Check the max archive height - this should be one less than the first untrimmed height
final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository); final int maximumArchiveHeight = BlockArchiveWriter.getMaxArchiveHeight(repository);
System.out.println("Maximum archive height determined (Expected 500): " + maximumArchiveHeight);
assertEquals(500, maximumArchiveHeight); assertEquals(500, maximumArchiveHeight);
BlockData block3DataPreArchive = repository.getBlockRepository().fromHeight(3); BlockData block3DataPreArchive = repository.getBlockRepository().fromHeight(3);
// Write blocks 2-500 to the archive // 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); BlockArchiveWriter writer = new BlockArchiveWriter(0, maximumArchiveHeight, repository);
writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes writer.setShouldEnforceFileSizeTarget(false); // To avoid the need to pre-calculate file sizes
BlockArchiveWriter.BlockArchiveWriteResult result = writer.write(); BlockArchiveWriter.BlockArchiveWriteResult result = writer.write();
System.out.println("Finished writing blocks to archive. Result: " + result);
assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result); assertEquals(BlockArchiveWriter.BlockArchiveWriteResult.OK, result);
// Make sure that the archive contains the correct number of blocks // 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 assertEquals(500 - 1, writer.getWrittenCount()); // -1 for the genesis block
// Increment block archive height // Increment block archive height
repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount()); repository.getBlockArchiveRepository().setBlockArchiveHeight(writer.getWrittenCount());
repository.saveChanges(); repository.saveChanges();
assertEquals(500 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight()); assertEquals(500 - 1, repository.getBlockArchiveRepository().getBlockArchiveHeight());
System.out.println("Block archive height updated to: " + (500 - 1));
// Ensure the file exists // Ensure the file exists
File outputFile = writer.getOutputPath().toFile(); File outputFile = writer.getOutputPath().toFile();
assertTrue(outputFile.exists()); assertTrue(outputFile.exists());
System.out.println("Archive file exists at: " + outputFile.getAbsolutePath());
// Ensure the SQL repository contains blocks 2 and 500... // 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(2));
assertNotNull(repository.getBlockRepository().fromHeight(500)); assertNotNull(repository.getBlockRepository().fromHeight(500));
System.out.println("Blocks 2 and 500 are present in the repository.");
// Prune all the archived blocks // Prune all the archived blocks
System.out.println("Pruning blocks 2 to 500...");
int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 500); int numBlocksPruned = repository.getBlockRepository().pruneBlocks(0, 500);
System.out.println("Number of blocks pruned (Expected 499): " + numBlocksPruned);
assertEquals(500-1, numBlocksPruned); assertEquals(500-1, numBlocksPruned);
repository.getBlockRepository().setBlockPruneHeight(501); repository.getBlockRepository().setBlockPruneHeight(501);
// Prune the AT states for the archived blocks // Prune the AT states for the archived blocks
System.out.println("Pruning AT states up to height 500...");
repository.getATRepository().rebuildLatestAtStates(500); repository.getATRepository().rebuildLatestAtStates(500);
repository.saveChanges(); repository.saveChanges();
int numATStatesPruned = repository.getATRepository().pruneAtStates(2, 500); 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 assertEquals(498, numATStatesPruned); // Minus 1 for genesis block, and another for the latest AT state
repository.getATRepository().setAtPruneHeight(501); repository.getATRepository().setAtPruneHeight(501);
// Now ensure the SQL repository is missing blocks 2 and 500... // 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(2));
assertNull(repository.getBlockRepository().fromHeight(500)); 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) // ... 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(1));
assertNotNull(repository.getBlockRepository().fromHeight(501)); 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 // 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. // Now orphan some unarchived blocks.
System.out.println("Orphaning 500 blocks...");
BlockUtils.orphanBlocks(repository, 500); 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're close to the lower limit of the SQL database now, so
// we need to import some blocks from the archive // 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); BlockArchiveUtils.importFromArchive(401, 500, repository);
// Ensure the SQL repository now contains block 401 but not 400... // 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)); assertNotNull(repository.getBlockRepository().fromHeight(401));
assertNull(repository.getBlockRepository().fromHeight(400)); assertNull(repository.getBlockRepository().fromHeight(400));
System.out.println("Block 401 exists, block 400 does not.");
// Import the remaining 399 blocks // Import the remaining 399 blocks
System.out.println("Importing blocks 2 to 400 from the archive...");
BlockArchiveUtils.importFromArchive(2, 400, repository); BlockArchiveUtils.importFromArchive(2, 400, repository);
// Verify that block 3 matches the original // Verify that block 3 matches the original
System.out.println("Verifying that block 3 matches the original data...");
BlockData block3DataPostArchive = repository.getBlockRepository().fromHeight(3); BlockData block3DataPostArchive = repository.getBlockRepository().fromHeight(3);
assertArrayEquals(block3DataPreArchive.getSignature(), block3DataPostArchive.getSignature()); assertArrayEquals(block3DataPreArchive.getSignature(), block3DataPostArchive.getSignature());
assertEquals(block3DataPreArchive.getHeight(), block3DataPostArchive.getHeight()); 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 // 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 // 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); BlockUtils.orphanBlocks(repository, 2);
System.out.println("Orphaned 2 blocks successfully.");
// Orphan another block, which should fail // Orphan another block, which should fail
System.out.println("Attempting to orphan another block, which should fail...");
Exception exception = null; Exception exception = null;
try { try {
BlockUtils.orphanBlocks(repository, 1); BlockUtils.orphanBlocks(repository, 1);
} catch (DataException e) { } catch (DataException e) {
exception = 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 // Ensure that a DataException is thrown because there is no more AT states data available
assertNotNull(exception); assertNotNull(exception);
assertEquals(DataException.class, exception.getClass()); 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 // 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. // and allow orphaning back through blocks with trimmed AT states.
System.out.println("testTrimArchivePruneAndOrphan completed successfully.");
} }
} }
@ -477,16 +619,26 @@ public class BlockArchiveV2Tests extends Common {
public void testMissingAtStatesHeightIndex() throws DataException, SQLException { public void testMissingAtStatesHeightIndex() throws DataException, SQLException {
try (final HSQLDBRepository repository = (HSQLDBRepository) RepositoryManager.getRepository()) { 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 // 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(repository.getATRepository().hasAtStatesHeightIndex());
assertTrue(RepositoryManager.canArchiveOrPrune()); assertTrue(RepositoryManager.canArchiveOrPrune());
System.out.println("ATStatesHeightIndex exists. Archiving and pruning are possible.");
// Delete the index // Delete the index
System.out.println("Dropping ATStatesHeightIndex...");
repository.prepareStatement("DROP INDEX ATSTATESHEIGHTINDEX").execute(); 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 // 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(repository.getATRepository().hasAtStatesHeightIndex());
assertFalse(RepositoryManager.canArchiveOrPrune()); 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 @@ public class BlockArchiveV2Tests extends Common {
Path archivePath = Paths.get(Settings.getInstance().getRepositoryPath(), "archive").toAbsolutePath(); Path archivePath = Paths.get(Settings.getInstance().getRepositoryPath(), "archive").toAbsolutePath();
try { try {
FileUtils.deleteDirectory(archivePath.toFile()); FileUtils.deleteDirectory(archivePath.toFile());
System.out.println("Deleted archive directory at: " + archivePath);
} catch (IOException e) { } catch (IOException e) {
System.out.println("Failed to delete archive directory: " + e.getMessage());
} }
} }

View File

@ -411,13 +411,20 @@ public class RepositoryTests extends Common {
} }
} }
/** Specifically test LATERAL() usage in Chat repository */ /** Specifically test LATERAL() usage in Chat repository with hasChatReference */
@Test @Test
public void testChatLateral() { public void testChatLateral() {
try (final HSQLDBRepository hsqldb = (HSQLDBRepository) RepositoryManager.getRepository()) { try (final HSQLDBRepository hsqldb = (HSQLDBRepository) RepositoryManager.getRepository()) {
String address = Crypto.toAddress(new byte[32]); String address = Crypto.toAddress(new byte[32]);
hsqldb.getChatRepository().getActiveChats(address, ChatMessage.Encoding.BASE58); // Test without hasChatReference
hsqldb.getChatRepository().getActiveChats(address, ChatMessage.Encoding.BASE58, null);
// Test with hasChatReference = true
hsqldb.getChatRepository().getActiveChats(address, ChatMessage.Encoding.BASE58, true);
// Test with hasChatReference = false
hsqldb.getChatRepository().getActiveChats(address, ChatMessage.Encoding.BASE58, false);
} catch (DataException e) { } catch (DataException e) {
fail("HSQLDB bug #1580"); fail("HSQLDB bug #1580");
} }

View File

@ -81,7 +81,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 9999999999999, "transactionV6Timestamp": 9999999999999,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -91,7 +91,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -84,7 +84,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 0, "disableReferenceTimestamp": 0,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -94,7 +94,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 0, "disableReferenceTimestamp": 0,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 9999999999999, "arbitraryOptionalFeeTimestamp": 9999999999999,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -83,16 +83,24 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 99999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999,
"selfSponsorshipAlgoV3Height": 999999999,
"feeValidationFixTimestamp": 0, "feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0, "chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950, "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999,
"penaltyFixHeight": 5 "penaltyFixHeight": 5
}, },
"genesisInfo": { "genesisInfo": {

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -86,7 +86,7 @@
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"aggregateSignatureTimestamp": 0, "aggregateSignatureTimestamp": 0,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -96,7 +96,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 500, "unconfirmableRewardSharesHeight": 500,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 20, "selfSponsorshipAlgoV1Height": 20,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 30, "selfSponsorshipAlgoV2Height": 30,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -85,7 +85,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -95,7 +95,14 @@
"arbitraryOptionalFeeTimestamp": 0, "arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999, "unconfirmableRewardSharesHeight": 99999999,
"disableTransferPrivsTimestamp": 9999999999500, "disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950 "enableTransferPrivsTimestamp": 9999999999950,
"cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -86,7 +86,7 @@
"transactionV5Timestamp": 0, "transactionV5Timestamp": 0,
"transactionV6Timestamp": 0, "transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999, "disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999, "increaseOnlineAccountsDifficultyTimestamp": 9999999999990,
"onlineAccountMinterLevelValidationHeight": 0, "onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 999999999, "selfSponsorshipAlgoV1Height": 999999999,
"selfSponsorshipAlgoV2Height": 999999999, "selfSponsorshipAlgoV2Height": 999999999,
@ -100,8 +100,10 @@
"cancelSellNameValidationTimestamp": 9999999999999, "cancelSellNameValidationTimestamp": 9999999999999,
"disableRewardshareHeight": 9999999999990, "disableRewardshareHeight": 9999999999990,
"enableRewardshareHeight": 9999999999999, "enableRewardshareHeight": 9999999999999,
"onlyMintWithNameHeight": 9999999999999, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999 "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -33,8 +33,13 @@ fi
# Limits Java JVM stack size and maximum heap usage. # Limits Java JVM stack size and maximum heap usage.
# Comment out for bigger systems, e.g. non-routers # Comment out for bigger systems, e.g. non-routers
# or when API documentation is enabled # or when API documentation is enabled
# Uncomment (remove '#' sign) line below if your system has less than 12GB of RAM for optimal RAM defaults # JAVA MEMORY SETTINGS BELOW - These settings are essentially optimized default settings.
JVM_MEMORY_ARGS="-Xss256m -XX:+UseSerialGC" # 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 # Although java.net.preferIPv4Stack is supposed to be false
# by default in Java 11, on some platforms (e.g. FreeBSD 12), # by default in Java 11, on some platforms (e.g. FreeBSD 12),