mirror of
https://github.com/Qortal/qortal.git
synced 2025-11-03 12:07:02 +00:00
Compare commits
36 Commits
chat-rate-
...
pruning-mo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2479f2d65d | ||
|
|
9056cb7026 | ||
|
|
cd9d9b31ef | ||
|
|
ff841c28e3 | ||
|
|
ca1379d9f8 | ||
|
|
5127f94423 | ||
|
|
f5910ab950 | ||
|
|
22efaccd4a | ||
|
|
c8466a2e7a | ||
|
|
209a9fa8c3 | ||
|
|
bc1af12655 | ||
|
|
e7e4cb7579 | ||
|
|
1b39db664c | ||
|
|
b4f980b349 | ||
|
|
673f23b6a0 | ||
|
|
8c325f3a8a | ||
|
|
f71516f36f | ||
|
|
1752386a6c | ||
|
|
112675c782 | ||
|
|
3b6ba7641d | ||
|
|
477a35a685 | ||
|
|
2a0a39a95a | ||
|
|
dfc77db51d | ||
|
|
c9596fd8c4 | ||
|
|
78373f3746 | ||
|
|
ebc3db8aed | ||
|
|
756601c1ce | ||
|
|
8bb5077e76 | ||
|
|
5b85f01427 | ||
|
|
a7d594e566 | ||
|
|
481e6671c2 | ||
|
|
b890e02a6a | ||
|
|
4772840b4c | ||
|
|
76ec3473d6 | ||
|
|
0b53de1bb6 | ||
|
|
746c68c9f6 |
BIN
WindowsInstaller/qortal.ico
Executable file → Normal file
BIN
WindowsInstaller/qortal.ico
Executable file → Normal file
Binary file not shown.
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 42 KiB |
@@ -553,13 +553,13 @@ public class AdminResource {
|
||||
@Path("/repository/data")
|
||||
@Operation(
|
||||
summary = "Import data into repository.",
|
||||
description = "Imports data from file on local machine. Filename is forced to 'import.json' if apiKey is not set.",
|
||||
description = "Imports data from file on local machine. Filename is forced to 'qortal-backup/TradeBotStates.json' if apiKey is not set.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "string", example = "MintingAccounts.script"
|
||||
type = "string", example = "qortal-backup/TradeBotStates.json"
|
||||
)
|
||||
)
|
||||
),
|
||||
@@ -577,7 +577,7 @@ public class AdminResource {
|
||||
|
||||
// Hard-coded because it's too dangerous to allow user-supplied filenames in weaker security contexts
|
||||
if (Settings.getInstance().getApiKey() == null)
|
||||
filename = "import.json";
|
||||
filename = "qortal-backup/TradeBotStates.json";
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
ReentrantLock blockchainLock = Controller.getInstance().getBlockchainLock();
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
@@ -173,7 +174,7 @@ public class CrossChainHtlcResource {
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@POST
|
||||
@Path("/redeem/{ataddress}")
|
||||
@Operation(
|
||||
summary = "Redeems HTLC associated with supplied AT",
|
||||
@@ -231,7 +232,7 @@ public class CrossChainHtlcResource {
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@POST
|
||||
@Path("/redeemAll")
|
||||
@Operation(
|
||||
summary = "Redeems HTLC for all applicable ATs in tradebot data",
|
||||
@@ -415,7 +416,7 @@ public class CrossChainHtlcResource {
|
||||
return false;
|
||||
}
|
||||
|
||||
@GET
|
||||
@POST
|
||||
@Path("/refund/{ataddress}")
|
||||
@Operation(
|
||||
summary = "Refunds HTLC associated with supplied AT",
|
||||
@@ -463,7 +464,7 @@ public class CrossChainHtlcResource {
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@POST
|
||||
@Path("/refundAll")
|
||||
@Operation(
|
||||
summary = "Refunds HTLC for all applicable ATs in tradebot data",
|
||||
@@ -478,8 +479,6 @@ public class CrossChainHtlcResource {
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_CRITERIA, ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN})
|
||||
public boolean refundAllHtlc() {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Security.checkApiCallAllowed(request);
|
||||
boolean success = false;
|
||||
|
||||
@@ -568,6 +567,13 @@ public class CrossChainHtlcResource {
|
||||
if (crossChainTradeData == null)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
|
||||
// If the AT is "finished" then it will have a zero balance
|
||||
// In these cases we should avoid HTLC refunds if tbe QORT haven't been returned to the seller
|
||||
if (atData.getIsFinished() && crossChainTradeData.mode != AcctMode.REFUNDED && crossChainTradeData.mode != AcctMode.CANCELLED) {
|
||||
LOGGER.info(String.format("Skipping AT %s because the QORT has already been redemed", atAddress));
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
|
||||
List<TradeBotData> allTradeBotData = repository.getCrossChainRepository().getAllTradeBotData();
|
||||
TradeBotData tradeBotData = allTradeBotData.stream().filter(tradeBotDataItem -> tradeBotDataItem.getAtAddress().equals(atAddress)).findFirst().orElse(null);
|
||||
if (tradeBotData == null)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.qortal.api.resource;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
@@ -42,6 +43,8 @@ public class ListsResource {
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
||||
public String addAddressToBlacklist(@PathParam("address") String address) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
if (!Crypto.isValidAddress(address))
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS);
|
||||
|
||||
@@ -84,6 +87,8 @@ public class ListsResource {
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
||||
public String addAddressesToBlacklist(AddressListRequest addressListRequest) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
if (addressListRequest == null || addressListRequest.addresses == null) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
@@ -146,6 +151,8 @@ public class ListsResource {
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
||||
public String removeAddressFromBlacklist(@PathParam("address") String address) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
if (!Crypto.isValidAddress(address))
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS);
|
||||
|
||||
@@ -188,6 +195,8 @@ public class ListsResource {
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
||||
public String removeAddressesFromBlacklist(AddressListRequest addressListRequest) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
if (addressListRequest == null || addressListRequest.addresses == null) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
@@ -237,6 +246,22 @@ public class ListsResource {
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/blacklist/addresses")
|
||||
@Operation(
|
||||
summary = "Fetch the list of blacklisted addresses",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
description = "A JSON array of addresses",
|
||||
content = @Content(mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema(schema = @Schema(implementation = String.class)))
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getAddressBlacklist() {
|
||||
Security.checkApiCallAllowed(request);
|
||||
return ResourceListManager.getInstance().getBlacklistJSONString();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/blacklist/address/{address}")
|
||||
@Operation(
|
||||
@@ -250,6 +275,8 @@ public class ListsResource {
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_ADDRESS, ApiError.ADDRESS_UNKNOWN, ApiError.REPOSITORY_ISSUE})
|
||||
public String checkAddressInBlacklist(@PathParam("address") String address) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
if (!Crypto.isValidAddress(address))
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS);
|
||||
|
||||
|
||||
@@ -506,28 +506,51 @@ public class BlockChain {
|
||||
* @throws SQLException
|
||||
*/
|
||||
public static void validate() throws DataException {
|
||||
// Check first block is Genesis Block
|
||||
if (!isGenesisBlockValid())
|
||||
rebuildBlockchain();
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
|
||||
boolean pruningEnabled = Settings.getInstance().isPruningEnabled();
|
||||
BlockData chainTip = repository.getBlockRepository().getLastBlock();
|
||||
boolean hasBlocks = (chainTip != null && chainTip.getHeight() > 1);
|
||||
|
||||
if (pruningEnabled && hasBlocks) {
|
||||
// Pruning is enabled and we have blocks, so it's possible that the genesis block has been pruned
|
||||
// It's best not to validate it, and there's no real need to
|
||||
}
|
||||
else {
|
||||
// Check first block is Genesis Block
|
||||
if (!isGenesisBlockValid()) {
|
||||
rebuildBlockchain();
|
||||
}
|
||||
}
|
||||
|
||||
repository.checkConsistency();
|
||||
|
||||
int startHeight = Math.max(repository.getBlockRepository().getBlockchainHeight() - 1440, 1);
|
||||
// Set the number of blocks to validate based on the pruned state of the chain
|
||||
// If pruned, subtract an extra 10 to allow room for error
|
||||
int blocksToValidate = pruningEnabled ? Settings.getInstance().getPruneBlockLimit() - 10 : 1440;
|
||||
|
||||
int startHeight = Math.max(repository.getBlockRepository().getBlockchainHeight() - blocksToValidate, 1);
|
||||
BlockData detachedBlockData = repository.getBlockRepository().getDetachedBlockSignature(startHeight);
|
||||
|
||||
if (detachedBlockData != null) {
|
||||
LOGGER.error(String.format("Block %d's reference does not match any block's signature", detachedBlockData.getHeight()));
|
||||
|
||||
// Wait for blockchain lock (whereas orphan() only tries to get lock)
|
||||
ReentrantLock blockchainLock = Controller.getInstance().getBlockchainLock();
|
||||
blockchainLock.lock();
|
||||
try {
|
||||
LOGGER.info(String.format("Orphaning back to block %d", detachedBlockData.getHeight() - 1));
|
||||
orphan(detachedBlockData.getHeight() - 1);
|
||||
} finally {
|
||||
blockchainLock.unlock();
|
||||
// Orphan if we aren't a pruning node
|
||||
if (!Settings.getInstance().isPruningEnabled()) {
|
||||
|
||||
// Wait for blockchain lock (whereas orphan() only tries to get lock)
|
||||
ReentrantLock blockchainLock = Controller.getInstance().getBlockchainLock();
|
||||
blockchainLock.lock();
|
||||
try {
|
||||
LOGGER.info(String.format("Orphaning back to block %d", detachedBlockData.getHeight() - 1));
|
||||
orphan(detachedBlockData.getHeight() - 1);
|
||||
} finally {
|
||||
blockchainLock.unlock();
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGGER.error(String.format("Not orphaning because we are in pruning mode. You may be on an " +
|
||||
"invalid chain and should consider bootstrapping or re-syncing from genesis."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
@@ -46,6 +45,7 @@ import org.qortal.block.Block;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.block.BlockChain.BlockTimingByHeight;
|
||||
import org.qortal.controller.Synchronizer.SynchronizationResult;
|
||||
import org.qortal.controller.repository.PruneManager;
|
||||
import org.qortal.controller.tradebot.TradeBot;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.account.MintingAccountData;
|
||||
@@ -95,7 +95,6 @@ import org.qortal.transaction.Transaction.TransactionType;
|
||||
import org.qortal.transaction.Transaction.ValidationResult;
|
||||
import org.qortal.utils.Base58;
|
||||
import org.qortal.utils.ByteArray;
|
||||
import org.qortal.utils.DaemonThreadFactory;
|
||||
import org.qortal.utils.NTP;
|
||||
import org.qortal.utils.Triple;
|
||||
|
||||
@@ -357,7 +356,7 @@ public class Controller extends Thread {
|
||||
return this.savedArgs;
|
||||
}
|
||||
|
||||
/* package */ static boolean isStopping() {
|
||||
public static boolean isStopping() {
|
||||
return isStopping;
|
||||
}
|
||||
|
||||
@@ -415,6 +414,7 @@ public class Controller extends Thread {
|
||||
try {
|
||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(getRepositoryUrl());
|
||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||
RepositoryManager.prune();
|
||||
} catch (DataException e) {
|
||||
// If exception has no cause then repository is in use by some other process.
|
||||
if (e.getCause() == null) {
|
||||
@@ -510,9 +510,8 @@ public class Controller extends Thread {
|
||||
final long repositoryBackupInterval = Settings.getInstance().getRepositoryBackupInterval();
|
||||
final long repositoryCheckpointInterval = Settings.getInstance().getRepositoryCheckpointInterval();
|
||||
|
||||
ExecutorService trimExecutor = Executors.newCachedThreadPool(new DaemonThreadFactory());
|
||||
trimExecutor.execute(new AtStatesTrimmer());
|
||||
trimExecutor.execute(new OnlineAccountsSignaturesTrimmer());
|
||||
// Start executor service for trimming or pruning
|
||||
PruneManager.getInstance().start();
|
||||
|
||||
try {
|
||||
while (!isStopping) {
|
||||
@@ -597,13 +596,7 @@ public class Controller extends Thread {
|
||||
Thread.interrupted();
|
||||
// Fall-through to exit
|
||||
} finally {
|
||||
trimExecutor.shutdownNow();
|
||||
|
||||
try {
|
||||
trimExecutor.awaitTermination(2L, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// We tried...
|
||||
}
|
||||
PruneManager.getInstance().stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -886,7 +879,7 @@ public class Controller extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
String tooltip = String.format("%s - %d %s - %s %d", actionText, numberOfPeers, connectionsText, heightText, height) + "\n" + String.format("Build version: %s", this.buildVersion);
|
||||
String tooltip = String.format("%s - %d %s - %s %d", actionText, numberOfPeers, connectionsText, heightText, height) + "\n" + String.format("%s: %s", Translator.INSTANCE.translate("SysTray", "BUILD_VERSION"), this.buildVersion);
|
||||
SysTray.getInstance().setToolTipText(tooltip);
|
||||
|
||||
this.callbackExecutor.execute(() -> {
|
||||
@@ -1286,6 +1279,13 @@ public class Controller extends Thread {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
BlockData blockData = repository.getBlockRepository().fromSignature(signature);
|
||||
|
||||
if (blockData != null) {
|
||||
if (PruneManager.getInstance().isBlockPruned(blockData.getHeight(), repository)) {
|
||||
// If this is a pruned block, we likely only have partial data, so best not to sent it
|
||||
blockData = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (blockData == null) {
|
||||
// We don't have this block
|
||||
this.stats.getBlockMessageStats.unknownBlocks.getAndIncrement();
|
||||
@@ -1407,6 +1407,14 @@ public class Controller extends Thread {
|
||||
|
||||
BlockData blockData = repository.getBlockRepository().fromReference(parentSignature);
|
||||
|
||||
if (blockData != null) {
|
||||
if (PruneManager.getInstance().isBlockPruned(blockData.getHeight(), repository)) {
|
||||
// If this request contains a pruned block, we likely only have partial data, so best not to sent anything
|
||||
// We always prune from the oldest first, so it's fine to just check the first block requested
|
||||
blockData = null;
|
||||
}
|
||||
}
|
||||
|
||||
while (blockData != null && blockSummaries.size() < numberRequested) {
|
||||
BlockSummaryData blockSummary = new BlockSummaryData(blockData);
|
||||
blockSummaries.add(blockSummary);
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.qortal.controller.repository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
import org.qortal.repository.RepositoryManager;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.utils.NTP;
|
||||
|
||||
public class AtStatesPruner implements Runnable {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(AtStatesPruner.class);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Thread.currentThread().setName("AT States pruner");
|
||||
|
||||
if (!Settings.getInstance().isPruningEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
int pruneStartHeight = repository.getATRepository().getAtPruneHeight();
|
||||
|
||||
repository.getATRepository().rebuildLatestAtStates();
|
||||
repository.saveChanges();
|
||||
|
||||
while (!Controller.isStopping()) {
|
||||
repository.discardChanges();
|
||||
|
||||
Thread.sleep(Settings.getInstance().getAtStatesPruneInterval());
|
||||
|
||||
BlockData chainTip = Controller.getInstance().getChainTip();
|
||||
if (chainTip == null || NTP.getTime() == null)
|
||||
continue;
|
||||
|
||||
// Don't even attempt if we're mid-sync as our repository requests will be delayed for ages
|
||||
if (Controller.getInstance().isSynchronizing())
|
||||
continue;
|
||||
|
||||
// Prune AT states for all blocks up until our latest minus pruneBlockLimit
|
||||
final int ourLatestHeight = chainTip.getHeight();
|
||||
final int upperPrunableHeight = ourLatestHeight - Settings.getInstance().getPruneBlockLimit();
|
||||
|
||||
int upperBatchHeight = pruneStartHeight + Settings.getInstance().getAtStatesPruneBatchSize();
|
||||
int upperPruneHeight = Math.min(upperBatchHeight, upperPrunableHeight);
|
||||
|
||||
if (pruneStartHeight >= upperPruneHeight)
|
||||
continue;
|
||||
|
||||
LOGGER.debug(String.format("Pruning AT states between blocks %d and %d...", pruneStartHeight, upperPruneHeight));
|
||||
|
||||
int numAtStatesPruned = repository.getATRepository().pruneAtStates(pruneStartHeight, upperPruneHeight);
|
||||
repository.saveChanges();
|
||||
int numAtStateDataRowsTrimmed = repository.getATRepository().trimAtStates(
|
||||
pruneStartHeight, upperPruneHeight, Settings.getInstance().getAtStatesTrimLimit());
|
||||
repository.saveChanges();
|
||||
|
||||
if (numAtStatesPruned > 0 || numAtStateDataRowsTrimmed > 0) {
|
||||
final int finalPruneStartHeight = pruneStartHeight;
|
||||
LOGGER.debug(() -> String.format("Pruned %d AT state%s between blocks %d and %d",
|
||||
numAtStatesPruned, (numAtStatesPruned != 1 ? "s" : ""),
|
||||
finalPruneStartHeight, upperPruneHeight));
|
||||
} else {
|
||||
// Can we move onto next batch?
|
||||
if (upperPrunableHeight > upperBatchHeight) {
|
||||
pruneStartHeight = upperBatchHeight;
|
||||
repository.getATRepository().setAtPruneHeight(pruneStartHeight);
|
||||
repository.getATRepository().rebuildLatestAtStates();
|
||||
repository.saveChanges();
|
||||
|
||||
final int finalPruneStartHeight = pruneStartHeight;
|
||||
LOGGER.debug(() -> String.format("Bumping AT state base prune height to %d", finalPruneStartHeight));
|
||||
}
|
||||
else {
|
||||
// We've pruned up to the upper prunable height
|
||||
// Back off for a while to save CPU for syncing
|
||||
Thread.sleep(5*60*1000L);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (DataException e) {
|
||||
LOGGER.warn(String.format("Repository issue trying to prune AT states: %s", e.getMessage()));
|
||||
} catch (InterruptedException e) {
|
||||
// Time to exit
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package org.qortal.controller;
|
||||
package org.qortal.controller.repository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
@@ -20,7 +21,7 @@ public class AtStatesTrimmer implements Runnable {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
int trimStartHeight = repository.getATRepository().getAtTrimHeight();
|
||||
|
||||
repository.getATRepository().prepareForAtStateTrimming();
|
||||
repository.getATRepository().rebuildLatestAtStates();
|
||||
repository.saveChanges();
|
||||
|
||||
while (!Controller.isStopping()) {
|
||||
@@ -62,7 +63,7 @@ public class AtStatesTrimmer implements Runnable {
|
||||
if (upperTrimmableHeight > upperBatchHeight) {
|
||||
trimStartHeight = upperBatchHeight;
|
||||
repository.getATRepository().setAtTrimHeight(trimStartHeight);
|
||||
repository.getATRepository().prepareForAtStateTrimming();
|
||||
repository.getATRepository().rebuildLatestAtStates();
|
||||
repository.saveChanges();
|
||||
|
||||
final int finalTrimStartHeight = trimStartHeight;
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.qortal.controller.repository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
import org.qortal.repository.RepositoryManager;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.utils.NTP;
|
||||
|
||||
public class BlockPruner implements Runnable {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(BlockPruner.class);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Thread.currentThread().setName("Block pruner");
|
||||
|
||||
if (!Settings.getInstance().isPruningEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
int pruneStartHeight = repository.getBlockRepository().getBlockPruneHeight();
|
||||
|
||||
while (!Controller.isStopping()) {
|
||||
repository.discardChanges();
|
||||
|
||||
Thread.sleep(Settings.getInstance().getBlockPruneInterval());
|
||||
|
||||
BlockData chainTip = Controller.getInstance().getChainTip();
|
||||
if (chainTip == null || NTP.getTime() == null)
|
||||
continue;
|
||||
|
||||
// Don't even attempt if we're mid-sync as our repository requests will be delayed for ages
|
||||
if (Controller.getInstance().isSynchronizing())
|
||||
continue;
|
||||
|
||||
// Prune all blocks up until our latest minus pruneBlockLimit
|
||||
final int ourLatestHeight = chainTip.getHeight();
|
||||
final int upperPrunableHeight = ourLatestHeight - Settings.getInstance().getPruneBlockLimit();
|
||||
|
||||
int upperBatchHeight = pruneStartHeight + Settings.getInstance().getBlockPruneBatchSize();
|
||||
int upperPruneHeight = Math.min(upperBatchHeight, upperPrunableHeight);
|
||||
|
||||
if (pruneStartHeight >= upperPruneHeight) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LOGGER.debug(String.format("Pruning blocks between %d and %d...", pruneStartHeight, upperPruneHeight));
|
||||
|
||||
int numBlocksPruned = repository.getBlockRepository().pruneBlocks(pruneStartHeight, upperPruneHeight);
|
||||
repository.saveChanges();
|
||||
|
||||
if (numBlocksPruned > 0) {
|
||||
final int finalPruneStartHeight = pruneStartHeight;
|
||||
LOGGER.debug(() -> String.format("Pruned %d block%s between %d and %d",
|
||||
numBlocksPruned, (numBlocksPruned != 1 ? "s" : ""),
|
||||
finalPruneStartHeight, upperPruneHeight));
|
||||
} else {
|
||||
// Can we move onto next batch?
|
||||
if (upperPrunableHeight > upperBatchHeight) {
|
||||
pruneStartHeight = upperBatchHeight;
|
||||
repository.getBlockRepository().setBlockPruneHeight(pruneStartHeight);
|
||||
repository.saveChanges();
|
||||
|
||||
final int finalPruneStartHeight = pruneStartHeight;
|
||||
LOGGER.debug(() -> String.format("Bumping block base prune height to %d", finalPruneStartHeight));
|
||||
}
|
||||
else {
|
||||
// We've pruned up to the upper prunable height
|
||||
// Back off for a while to save CPU for syncing
|
||||
Thread.sleep(10*60*1000L);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (DataException e) {
|
||||
LOGGER.warn(String.format("Repository issue trying to prune blocks: %s", e.getMessage()));
|
||||
} catch (InterruptedException e) {
|
||||
// Time to exit
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package org.qortal.controller;
|
||||
package org.qortal.controller.repository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
@@ -0,0 +1,87 @@
|
||||
package org.qortal.controller.repository;
|
||||
|
||||
import org.qortal.controller.Controller;
|
||||
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.utils.DaemonThreadFactory;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PruneManager {
|
||||
|
||||
private static PruneManager instance;
|
||||
|
||||
private boolean pruningEnabled = Settings.getInstance().isPruningEnabled();
|
||||
private int pruneBlockLimit = Settings.getInstance().getPruneBlockLimit();
|
||||
|
||||
private ExecutorService executorService;
|
||||
|
||||
private PruneManager() {
|
||||
|
||||
}
|
||||
|
||||
public static synchronized PruneManager getInstance() {
|
||||
if (instance == null)
|
||||
instance = new PruneManager();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
this.executorService = Executors.newCachedThreadPool(new DaemonThreadFactory());
|
||||
|
||||
// Don't allow both the pruner and the trimmer to run at the same time.
|
||||
// In pruning mode, we are already deleting far more than we would when trimming.
|
||||
// In non-pruning mode, we still need to trim to keep the non-essential data
|
||||
// out of the database. There isn't a case where both are needed at once.
|
||||
// If we ever do need to enable both at once, be very careful with the AT state
|
||||
// trimming, since both currently rely on having exclusive access to the
|
||||
// prepareForAtStateTrimming() method. For both trimming and pruning to take place
|
||||
// at once, we would need to synchronize this method in a way that both can't
|
||||
// call it at the same time, as otherwise active ATs would be pruned/trimmed when
|
||||
// they should have been kept.
|
||||
|
||||
if (Settings.getInstance().isPruningEnabled()) {
|
||||
// Pruning enabled - start the pruning processes
|
||||
this.executorService.execute(new AtStatesPruner());
|
||||
this.executorService.execute(new BlockPruner());
|
||||
}
|
||||
else {
|
||||
// Pruning disabled - use trimming instead
|
||||
this.executorService.execute(new AtStatesTrimmer());
|
||||
this.executorService.execute(new OnlineAccountsSignaturesTrimmer());
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
this.executorService.shutdownNow();
|
||||
|
||||
try {
|
||||
this.executorService.awaitTermination(2L, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// We tried...
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBlockPruned(int height, Repository repository) throws DataException {
|
||||
if (!this.pruningEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockData chainTip = Controller.getInstance().getChainTip();
|
||||
if (chainTip == null) {
|
||||
throw new DataException("Unable to determine chain tip when checking if a block is pruned");
|
||||
}
|
||||
|
||||
final int ourLatestHeight = chainTip.getHeight();
|
||||
final int latestUnprunedHeight = ourLatestHeight - this.pruneBlockLimit;
|
||||
|
||||
return (height < latestUnprunedHeight);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -653,18 +653,27 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
|
||||
|
||||
Object errorObj = responseJson.get("error");
|
||||
if (errorObj != null) {
|
||||
if (errorObj instanceof String)
|
||||
throw new ForeignBlockchainException.NetworkException(String.format("Unexpected error message from ElectrumX RPC %s: %s", method, (String) errorObj), this.currentServer);
|
||||
if (errorObj instanceof String) {
|
||||
LOGGER.debug(String.format("Unexpected error message from ElectrumX server %s for RPC method %s: %s", this.currentServer, method, (String) errorObj));
|
||||
// Try another server
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(errorObj instanceof JSONObject))
|
||||
throw new ForeignBlockchainException.NetworkException(String.format("Unexpected error response from ElectrumX RPC %s", method), this.currentServer);
|
||||
if (!(errorObj instanceof JSONObject)) {
|
||||
LOGGER.debug(String.format("Unexpected error response from ElectrumX server %s for RPC method %s", this.currentServer, method));
|
||||
// Try another server
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject errorJson = (JSONObject) errorObj;
|
||||
|
||||
Object messageObj = errorJson.get("message");
|
||||
|
||||
if (!(messageObj instanceof String))
|
||||
throw new ForeignBlockchainException.NetworkException(String.format("Missing/invalid message in error response from ElectrumX RPC %s", method), this.currentServer);
|
||||
if (!(messageObj instanceof String)) {
|
||||
LOGGER.debug(String.format("Missing/invalid message in error response from ElectrumX server %s for RPC method %s", this.currentServer, method));
|
||||
// Try another server
|
||||
return null;
|
||||
}
|
||||
|
||||
String message = (String) messageObj;
|
||||
|
||||
|
||||
@@ -23,17 +23,21 @@ public class Gui {
|
||||
private SysTray sysTray = null;
|
||||
|
||||
private Gui() {
|
||||
this.isHeadless = GraphicsEnvironment.isHeadless();
|
||||
try {
|
||||
this.isHeadless = GraphicsEnvironment.isHeadless();
|
||||
|
||||
if (!this.isHeadless) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||
| UnsupportedLookAndFeelException e) {
|
||||
// Use whatever look-and-feel comes by default then
|
||||
if (!this.isHeadless) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||
| UnsupportedLookAndFeelException e) {
|
||||
// Use whatever look-and-feel comes by default then
|
||||
}
|
||||
|
||||
showSplash();
|
||||
}
|
||||
|
||||
showSplash();
|
||||
} catch (Exception e) {
|
||||
LOGGER.info("Unable to initialize GUI: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -291,19 +291,23 @@ public class SysTray {
|
||||
|
||||
public void setTrayIcon(int iconid) {
|
||||
if (trayIcon != null) {
|
||||
switch (iconid) {
|
||||
case 1:
|
||||
this.trayIcon.setImage(Gui.loadImage("icons/qortal_ui_tray_syncing_time-alt.png"));
|
||||
break;
|
||||
case 2:
|
||||
this.trayIcon.setImage(Gui.loadImage("icons/qortal_ui_tray_minting.png"));
|
||||
break;
|
||||
case 3:
|
||||
this.trayIcon.setImage(Gui.loadImage("icons/qortal_ui_tray_syncing.png"));
|
||||
break;
|
||||
case 4:
|
||||
this.trayIcon.setImage(Gui.loadImage("icons/qortal_ui_tray_synced.png"));
|
||||
break;
|
||||
try {
|
||||
switch (iconid) {
|
||||
case 1:
|
||||
this.trayIcon.setImage(Gui.loadImage("icons/qortal_ui_tray_syncing_time-alt.png"));
|
||||
break;
|
||||
case 2:
|
||||
this.trayIcon.setImage(Gui.loadImage("icons/qortal_ui_tray_minting.png"));
|
||||
break;
|
||||
case 3:
|
||||
this.trayIcon.setImage(Gui.loadImage("icons/qortal_ui_tray_syncing.png"));
|
||||
break;
|
||||
case 4:
|
||||
this.trayIcon.setImage(Gui.loadImage("icons/qortal_ui_tray_synced.png"));
|
||||
break;
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
LOGGER.info("Unable to set tray icon");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public class ResourceList {
|
||||
public ResourceList(String category, String resourceName) throws IOException {
|
||||
this.category = category;
|
||||
this.resourceName = resourceName;
|
||||
this.list = new ArrayList<>();
|
||||
this.load();
|
||||
}
|
||||
|
||||
@@ -45,13 +46,7 @@ public class ResourceList {
|
||||
private Path getFilePath() {
|
||||
String pathString = String.format("%s%s%s_%s.json", Settings.getInstance().getListsPath(),
|
||||
File.separator, this.resourceName, this.category);
|
||||
Path outputFilePath = Paths.get(pathString);
|
||||
try {
|
||||
Files.createDirectories(outputFilePath.getParent());
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create lists directory");
|
||||
}
|
||||
return outputFilePath;
|
||||
return Paths.get(pathString);
|
||||
}
|
||||
|
||||
public void save() throws IOException {
|
||||
@@ -62,8 +57,15 @@ public class ResourceList {
|
||||
throw new IllegalStateException("Can't save list with missing category");
|
||||
}
|
||||
String jsonString = ResourceList.listToJSONString(this.list);
|
||||
|
||||
Path filePath = this.getFilePath();
|
||||
|
||||
// Create parent directory if needed
|
||||
try {
|
||||
Files.createDirectories(filePath.getParent());
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create lists directory");
|
||||
}
|
||||
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(filePath.toString()));
|
||||
writer.write(jsonString);
|
||||
writer.close();
|
||||
@@ -99,24 +101,35 @@ public class ResourceList {
|
||||
/* List management */
|
||||
|
||||
public void add(String resource) {
|
||||
if (resource == null || this.list == null) {
|
||||
return;
|
||||
}
|
||||
if (!this.contains(resource)) {
|
||||
this.list.add(resource);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(String resource) {
|
||||
if (resource == null || this.list == null) {
|
||||
return;
|
||||
}
|
||||
this.list.remove(resource);
|
||||
}
|
||||
|
||||
public boolean contains(String resource) {
|
||||
if (resource == null || this.list == null) {
|
||||
return false;
|
||||
}
|
||||
return this.list.contains(resource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Utils */
|
||||
|
||||
public static String listToJSONString(List<String> list) {
|
||||
if (list == null) {
|
||||
return null;
|
||||
}
|
||||
JSONArray items = new JSONArray();
|
||||
for (String item : list) {
|
||||
items.put(item);
|
||||
@@ -125,6 +138,9 @@ public class ResourceList {
|
||||
}
|
||||
|
||||
private static List<String> listFromJSONString(String jsonString) {
|
||||
if (jsonString == null) {
|
||||
return null;
|
||||
}
|
||||
JSONArray jsonList = new JSONArray(jsonString);
|
||||
List<String> resourceList = new ArrayList<>();
|
||||
for (int i=0; i<jsonList.length(); i++) {
|
||||
@@ -134,4 +150,8 @@ public class ResourceList {
|
||||
return resourceList;
|
||||
}
|
||||
|
||||
public String getJSONString() {
|
||||
return ResourceList.listToJSONString(this.list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class ResourceListManager {
|
||||
|
||||
@@ -84,4 +85,11 @@ public class ResourceListManager {
|
||||
this.addressBlacklist.revert();
|
||||
}
|
||||
|
||||
public String getBlacklistJSONString() {
|
||||
if (this.addressBlacklist == null) {
|
||||
return null;
|
||||
}
|
||||
return this.addressBlacklist.getJSONString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -112,6 +112,11 @@ public interface ATRepository {
|
||||
*/
|
||||
public List<ATStateData> getBlockATStatesAtHeight(int height) throws DataException;
|
||||
|
||||
|
||||
/** Rebuild the latest AT states cache, necessary for AT state trimming/pruning. */
|
||||
public void rebuildLatestAtStates() throws DataException;
|
||||
|
||||
|
||||
/** Returns height of first trimmable AT state. */
|
||||
public int getAtTrimHeight() throws DataException;
|
||||
|
||||
@@ -121,12 +126,23 @@ public interface ATRepository {
|
||||
*/
|
||||
public void setAtTrimHeight(int trimHeight) throws DataException;
|
||||
|
||||
/** Hook to allow repository to prepare/cache info for AT state trimming. */
|
||||
public void prepareForAtStateTrimming() throws DataException;
|
||||
|
||||
/** Trims full AT state data between passed heights. Returns number of trimmed rows. */
|
||||
public int trimAtStates(int minHeight, int maxHeight, int limit) throws DataException;
|
||||
|
||||
|
||||
/** Returns height of first prunable AT state. */
|
||||
public int getAtPruneHeight() throws DataException;
|
||||
|
||||
/** Sets new base height for AT state pruning.
|
||||
* <p>
|
||||
* NOTE: performs implicit <tt>repository.saveChanges()</tt>.
|
||||
*/
|
||||
public void setAtPruneHeight(int pruneHeight) throws DataException;
|
||||
|
||||
/** Prunes full AT state data between passed heights. Returns number of pruned rows. */
|
||||
public int pruneAtStates(int minHeight, int maxHeight) throws DataException;
|
||||
|
||||
|
||||
/**
|
||||
* Save ATStateData into repository.
|
||||
* <p>
|
||||
|
||||
@@ -166,6 +166,20 @@ public interface BlockRepository {
|
||||
*/
|
||||
public BlockData getDetachedBlockSignature(int startHeight) throws DataException;
|
||||
|
||||
|
||||
/** Returns height of first prunable block. */
|
||||
public int getBlockPruneHeight() throws DataException;
|
||||
|
||||
/** Sets new base height for block pruning.
|
||||
* <p>
|
||||
* NOTE: performs implicit <tt>repository.saveChanges()</tt>.
|
||||
*/
|
||||
public void setBlockPruneHeight(int pruneHeight) throws DataException;
|
||||
|
||||
/** Prunes full block data between passed heights. Returns number of pruned rows. */
|
||||
public int pruneBlocks(int minHeight, int maxHeight) throws DataException;
|
||||
|
||||
|
||||
/**
|
||||
* Saves block into repository.
|
||||
*
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
package org.qortal.repository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.repository.hsqldb.HSQLDBDatabasePruning;
|
||||
import org.qortal.settings.Settings;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public abstract class RepositoryManager {
|
||||
private static final Logger LOGGER = LogManager.getLogger(RepositoryManager.class);
|
||||
|
||||
private static RepositoryFactory repositoryFactory = null;
|
||||
|
||||
@@ -51,6 +57,24 @@ public abstract class RepositoryManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static void prune() {
|
||||
// Bulk prune the database the first time we use pruning mode
|
||||
if (Settings.getInstance().isPruningEnabled()) {
|
||||
try {
|
||||
boolean prunedATStates = HSQLDBDatabasePruning.pruneATStates();
|
||||
boolean prunedBlocks = HSQLDBDatabasePruning.pruneBlocks();
|
||||
|
||||
// Perform repository maintenance to shrink the db size down
|
||||
if (prunedATStates && prunedBlocks) {
|
||||
HSQLDBDatabasePruning.performMaintenance();
|
||||
}
|
||||
|
||||
} catch (SQLException | DataException e) {
|
||||
LOGGER.info("Unable to bulk prune AT states. The database may have been left in an inconsistent state.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setRequestedCheckpoint(Boolean quick) {
|
||||
quickCheckpointRequested = quick;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.Set;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.at.ATData;
|
||||
import org.qortal.data.at.ATStateData;
|
||||
import org.qortal.repository.ATRepository;
|
||||
@@ -600,6 +601,35 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
return atStates;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void rebuildLatestAtStates() throws DataException {
|
||||
// Rebuild cache of latest AT states that we can't trim
|
||||
String deleteSql = "DELETE FROM LatestATStates";
|
||||
try {
|
||||
this.repository.executeCheckedUpdate(deleteSql);
|
||||
} catch (SQLException e) {
|
||||
repository.examineException(e);
|
||||
throw new DataException("Unable to delete temporary latest AT states cache from repository", e);
|
||||
}
|
||||
|
||||
String insertSql = "INSERT INTO LatestATStates ("
|
||||
+ "SELECT AT_address, height FROM ATs "
|
||||
+ "CROSS JOIN LATERAL("
|
||||
+ "SELECT height FROM ATStates "
|
||||
+ "WHERE ATStates.AT_address = ATs.AT_address "
|
||||
+ "ORDER BY AT_address DESC, height DESC LIMIT 1"
|
||||
+ ") "
|
||||
+ ")";
|
||||
try {
|
||||
this.repository.executeCheckedUpdate(insertSql);
|
||||
} catch (SQLException e) {
|
||||
repository.examineException(e);
|
||||
throw new DataException("Unable to populate temporary latest AT states cache in repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getAtTrimHeight() throws DataException {
|
||||
String sql = "SELECT AT_trim_height FROM DatabaseInfo";
|
||||
@@ -631,33 +661,6 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareForAtStateTrimming() throws DataException {
|
||||
// Rebuild cache of latest AT states that we can't trim
|
||||
String deleteSql = "DELETE FROM LatestATStates";
|
||||
try {
|
||||
this.repository.executeCheckedUpdate(deleteSql);
|
||||
} catch (SQLException e) {
|
||||
repository.examineException(e);
|
||||
throw new DataException("Unable to delete temporary latest AT states cache from repository", e);
|
||||
}
|
||||
|
||||
String insertSql = "INSERT INTO LatestATStates ("
|
||||
+ "SELECT AT_address, height FROM ATs "
|
||||
+ "CROSS JOIN LATERAL("
|
||||
+ "SELECT height FROM ATStates "
|
||||
+ "WHERE ATStates.AT_address = ATs.AT_address "
|
||||
+ "ORDER BY AT_address DESC, height DESC LIMIT 1"
|
||||
+ ") "
|
||||
+ ")";
|
||||
try {
|
||||
this.repository.executeCheckedUpdate(insertSql);
|
||||
} catch (SQLException e) {
|
||||
repository.examineException(e);
|
||||
throw new DataException("Unable to populate temporary latest AT states cache in repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int trimAtStates(int minHeight, int maxHeight, int limit) throws DataException {
|
||||
if (minHeight >= maxHeight)
|
||||
@@ -682,6 +685,94 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getAtPruneHeight() throws DataException {
|
||||
String sql = "SELECT AT_prune_height FROM DatabaseInfo";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql)) {
|
||||
if (resultSet == null)
|
||||
return 0;
|
||||
|
||||
return resultSet.getInt(1);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch AT state prune height from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAtPruneHeight(int pruneHeight) throws DataException {
|
||||
// trimHeightsLock is to prevent concurrent update on DatabaseInfo
|
||||
// that could result in "transaction rollback: serialization failure"
|
||||
synchronized (this.repository.trimHeightsLock) {
|
||||
String updateSql = "UPDATE DatabaseInfo SET AT_prune_height = ?";
|
||||
|
||||
try {
|
||||
this.repository.executeCheckedUpdate(updateSql, pruneHeight);
|
||||
this.repository.saveChanges();
|
||||
} catch (SQLException e) {
|
||||
repository.examineException(e);
|
||||
throw new DataException("Unable to set AT state prune height in repository", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pruneAtStates(int minHeight, int maxHeight) throws DataException {
|
||||
int deletedCount = 0;
|
||||
|
||||
for (int height=minHeight; height<maxHeight; height++) {
|
||||
|
||||
// Give up if we're stopping
|
||||
if (Controller.isStopping()) {
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
// Get latest AT states for this height
|
||||
List<String> atAddresses = new ArrayList<>();
|
||||
String updateSql = "SELECT AT_address FROM LatestATStates WHERE height = ?";
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(updateSql, height)) {
|
||||
if (resultSet != null) {
|
||||
do {
|
||||
String atAddress = resultSet.getString(1);
|
||||
atAddresses.add(atAddress);
|
||||
|
||||
} while (resultSet.next());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch flagged accounts from repository", e);
|
||||
}
|
||||
|
||||
List<ATStateData> atStates = this.getBlockATStatesAtHeight(height);
|
||||
for (ATStateData atState : atStates) {
|
||||
//LOGGER.info("Found atState {} at height {}", atState.getATAddress(), atState.getHeight());
|
||||
|
||||
// Give up if we're stopping
|
||||
if (Controller.isStopping()) {
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
if (atAddresses.contains(atState.getATAddress())) {
|
||||
// We don't want to delete this AT state because it is still active
|
||||
LOGGER.info("Skipping atState {} at height {}", atState.getATAddress(), atState.getHeight());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Safe to delete everything else for this height
|
||||
try {
|
||||
this.repository.delete("ATStates", "AT_address = ? AND height = ?",
|
||||
atState.getATAddress(), atState.getHeight());
|
||||
deletedCount++;
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete AT state data from repository", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save(ATStateData atStateData) throws DataException {
|
||||
// We shouldn't ever save partial ATStateData
|
||||
|
||||
@@ -509,6 +509,53 @@ public class HSQLDBBlockRepository implements BlockRepository {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getBlockPruneHeight() throws DataException {
|
||||
String sql = "SELECT block_prune_height FROM DatabaseInfo";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql)) {
|
||||
if (resultSet == null)
|
||||
return 0;
|
||||
|
||||
return resultSet.getInt(1);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch block prune height from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockPruneHeight(int pruneHeight) throws DataException {
|
||||
// trimHeightsLock is to prevent concurrent update on DatabaseInfo
|
||||
// that could result in "transaction rollback: serialization failure"
|
||||
synchronized (this.repository.trimHeightsLock) {
|
||||
String updateSql = "UPDATE DatabaseInfo SET block_prune_height = ?";
|
||||
|
||||
try {
|
||||
this.repository.executeCheckedUpdate(updateSql, pruneHeight);
|
||||
this.repository.saveChanges();
|
||||
} catch (SQLException e) {
|
||||
repository.examineException(e);
|
||||
throw new DataException("Unable to set block prune height in repository", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pruneBlocks(int minHeight, int maxHeight) throws DataException {
|
||||
// Don't prune the genesis block
|
||||
if (minHeight <= 1) {
|
||||
minHeight = 2;
|
||||
}
|
||||
|
||||
try {
|
||||
return this.repository.delete("Blocks", "height BETWEEN ? AND ?", minHeight, maxHeight);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to prune blocks from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockData getDetachedBlockSignature(int startHeight) throws DataException {
|
||||
String sql = "SELECT " + BLOCK_DB_COLUMNS + " FROM Blocks "
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
package org.qortal.repository.hsqldb;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.RepositoryManager;
|
||||
import org.qortal.settings.Settings;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
*
|
||||
* When switching from a full node to a pruning node, we need to delete most of the database contents.
|
||||
* If we do this entirely as a background process, it is very slow and can interfere with syncing.
|
||||
* However, if we take the approach of transferring only the necessary rows to a new table and then
|
||||
* deleting the original table, this makes the process much faster. It was taking several days to
|
||||
* delete the AT states in the background, but only a couple of minutes to copy them to a new table.
|
||||
*
|
||||
* The trade off is that we have to go through a form of "reshape" when starting the app for the first
|
||||
* time after enabling pruning mode. But given that this is an opt-in mode, I don't think it will be
|
||||
* a problem.
|
||||
*
|
||||
* Once the pruning is complete, it automatically performs a CHECKPOINT DEFRAG in order to
|
||||
* shrink the database file size down to a fraction of what it was before.
|
||||
*
|
||||
* From this point, the original background process will run, but can be dialled right down so not
|
||||
* to interfere with syncing.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
public class HSQLDBDatabasePruning {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(HSQLDBDatabasePruning.class);
|
||||
|
||||
public static boolean pruneATStates() throws SQLException, DataException {
|
||||
try (final HSQLDBRepository repository = (HSQLDBRepository)RepositoryManager.getRepository()) {
|
||||
|
||||
// Only bulk prune AT states if we have never done so before
|
||||
int pruneHeight = repository.getATRepository().getAtPruneHeight();
|
||||
if (pruneHeight > 0) {
|
||||
// Already pruned AT states
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGGER.info("Starting bulk prune of AT states - this process could take a while... (approx. 2 mins on high spec)");
|
||||
|
||||
// Create new AT-states table to hold smaller dataset
|
||||
repository.executeCheckedUpdate("DROP TABLE IF EXISTS ATStatesNew");
|
||||
repository.executeCheckedUpdate("CREATE TABLE ATStatesNew ("
|
||||
+ "AT_address QortalAddress, height INTEGER NOT NULL, state_hash ATStateHash NOT NULL, "
|
||||
+ "fees QortalAmount NOT NULL, is_initial BOOLEAN NOT NULL, sleep_until_message_timestamp BIGINT, "
|
||||
+ "PRIMARY KEY (AT_address, height), "
|
||||
+ "FOREIGN KEY (AT_address) REFERENCES ATs (AT_address) ON DELETE CASCADE)");
|
||||
repository.executeCheckedUpdate("SET TABLE ATStatesNew NEW SPACE");
|
||||
repository.executeCheckedUpdate("CHECKPOINT");
|
||||
|
||||
|
||||
// Find our latest block
|
||||
BlockData latestBlock = repository.getBlockRepository().getLastBlock();
|
||||
if (latestBlock == null) {
|
||||
LOGGER.info("Unable to determine blockchain height, necessary for bulk block pruning");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate some constants for later use
|
||||
final int blockchainHeight = latestBlock.getHeight();
|
||||
final int maximumBlockToTrim = blockchainHeight - Settings.getInstance().getPruneBlockLimit();
|
||||
final int startHeight = maximumBlockToTrim;
|
||||
final int endHeight = blockchainHeight;
|
||||
final int blockStep = 10000;
|
||||
|
||||
// Loop through all the LatestATStates and copy them to the new table
|
||||
LOGGER.info("Copying AT states...");
|
||||
for (int height = 0; height < endHeight; height += blockStep) {
|
||||
//LOGGER.info(String.format("Copying AT states between %d and %d...", height, height + blockStep - 1));
|
||||
|
||||
String sql = "SELECT height, AT_address FROM LatestATStates WHERE height BETWEEN ? AND ?";
|
||||
try (ResultSet latestAtStatesResultSet = repository.checkedExecute(sql, height, height + blockStep - 1)) {
|
||||
if (latestAtStatesResultSet != null) {
|
||||
do {
|
||||
int latestAtHeight = latestAtStatesResultSet.getInt(1);
|
||||
String latestAtAddress = latestAtStatesResultSet.getString(2);
|
||||
|
||||
// Copy this latest ATState to the new table
|
||||
//LOGGER.info(String.format("Copying AT %s at height %d...", latestAtAddress, latestAtHeight));
|
||||
try {
|
||||
String updateSql = "INSERT INTO ATStatesNew ("
|
||||
+ "SELECT AT_address, height, state_hash, fees, is_initial, sleep_until_message_timestamp "
|
||||
+ "FROM ATStates "
|
||||
+ "WHERE height = ? AND AT_address = ?)";
|
||||
repository.executeCheckedUpdate(updateSql, latestAtHeight, latestAtAddress);
|
||||
} catch (SQLException e) {
|
||||
repository.examineException(e);
|
||||
throw new DataException("Unable to copy ATStates", e);
|
||||
}
|
||||
|
||||
if (height >= startHeight) {
|
||||
// Now copy this AT states for each recent block it is present in
|
||||
for (int i = startHeight; i < endHeight; i++) {
|
||||
if (latestAtHeight < i) {
|
||||
// This AT finished before this block so there is nothing to copy
|
||||
continue;
|
||||
}
|
||||
|
||||
//LOGGER.info(String.format("Copying recent AT %s at height %d...", latestAtAddress, i));
|
||||
try {
|
||||
// Copy each LatestATState to the new table
|
||||
String updateSql = "INSERT IGNORE INTO ATStatesNew ("
|
||||
+ "SELECT AT_address, height, state_hash, fees, is_initial, sleep_until_message_timestamp "
|
||||
+ "FROM ATStates "
|
||||
+ "WHERE height = ? AND AT_address = ?)";
|
||||
repository.executeCheckedUpdate(updateSql, i, latestAtAddress);
|
||||
} catch (SQLException e) {
|
||||
repository.examineException(e);
|
||||
throw new DataException("Unable to copy ATStates", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (latestAtStatesResultSet.next());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to copy AT states", e);
|
||||
}
|
||||
}
|
||||
|
||||
repository.saveChanges();
|
||||
|
||||
// Add a height index
|
||||
LOGGER.info("Rebuilding AT states height index in repository");
|
||||
repository.executeCheckedUpdate("CREATE INDEX IF NOT EXISTS ATStatesHeightIndex ON ATStatesNew (height)");
|
||||
repository.executeCheckedUpdate("CHECKPOINT");
|
||||
|
||||
// Finally, drop the original table and rename
|
||||
LOGGER.info("Deleting old AT states...");
|
||||
repository.executeCheckedUpdate("DROP TABLE ATStates");
|
||||
repository.executeCheckedUpdate("ALTER TABLE ATStatesNew RENAME TO ATStates");
|
||||
repository.executeCheckedUpdate("CHECKPOINT");
|
||||
|
||||
// Update the prune height
|
||||
repository.getATRepository().setAtPruneHeight(maximumBlockToTrim);
|
||||
repository.saveChanges();
|
||||
|
||||
repository.executeCheckedUpdate("CHECKPOINT");
|
||||
|
||||
// Now prune/trim the ATStatesData, as this currently goes back over a month
|
||||
return HSQLDBDatabasePruning.pruneATStateData();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Bulk prune ATStatesData to catch up with the now pruned ATStates table
|
||||
* This uses the existing AT States trimming code but with a much higher end block
|
||||
*/
|
||||
private static boolean pruneATStateData() throws SQLException, DataException {
|
||||
try (final HSQLDBRepository repository = (HSQLDBRepository) RepositoryManager.getRepository()) {
|
||||
|
||||
BlockData latestBlock = repository.getBlockRepository().getLastBlock();
|
||||
if (latestBlock == null) {
|
||||
LOGGER.info("Unable to determine blockchain height, necessary for bulk ATStatesData pruning");
|
||||
return false;
|
||||
}
|
||||
final int blockchainHeight = latestBlock.getHeight();
|
||||
final int upperPrunableHeight = blockchainHeight - Settings.getInstance().getPruneBlockLimit();
|
||||
// ATStateData is already trimmed - so carry on from where we left off in the past
|
||||
int pruneStartHeight = repository.getATRepository().getAtTrimHeight();
|
||||
|
||||
LOGGER.info("Starting bulk prune of AT states data - this process could take a while... (approx. 3 mins on high spec)");
|
||||
|
||||
while (pruneStartHeight < upperPrunableHeight) {
|
||||
// Prune all AT state data up until our latest minus pruneBlockLimit
|
||||
|
||||
if (Controller.isStopping()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Override batch size in the settings because this is a one-off process
|
||||
final int batchSize = 1000;
|
||||
final int rowLimitPerBatch = 50000;
|
||||
int upperBatchHeight = pruneStartHeight + batchSize;
|
||||
int upperPruneHeight = Math.min(upperBatchHeight, upperPrunableHeight);
|
||||
|
||||
LOGGER.trace(String.format("Pruning AT states data between %d and %d...", pruneStartHeight, upperPruneHeight));
|
||||
|
||||
int numATStatesPruned = repository.getATRepository().trimAtStates(pruneStartHeight, upperPruneHeight, rowLimitPerBatch);
|
||||
repository.saveChanges();
|
||||
|
||||
if (numATStatesPruned > 0) {
|
||||
final int finalPruneStartHeight = pruneStartHeight;
|
||||
LOGGER.trace(() -> String.format("Pruned %d AT states data rows between blocks %d and %d",
|
||||
numATStatesPruned, finalPruneStartHeight, upperPruneHeight));
|
||||
} else {
|
||||
// Can we move onto next batch?
|
||||
if (upperPrunableHeight > upperBatchHeight) {
|
||||
pruneStartHeight = upperBatchHeight;
|
||||
repository.getATRepository().setAtTrimHeight(pruneStartHeight);
|
||||
// No need to rebuild the latest AT states as we aren't currently synchronizing
|
||||
repository.saveChanges();
|
||||
|
||||
final int finalPruneStartHeight = pruneStartHeight;
|
||||
LOGGER.debug(() -> String.format("Bumping AT states trim height to %d", finalPruneStartHeight));
|
||||
}
|
||||
else {
|
||||
// We've finished pruning
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean pruneBlocks() throws SQLException, DataException {
|
||||
try (final HSQLDBRepository repository = (HSQLDBRepository) RepositoryManager.getRepository()) {
|
||||
|
||||
// Only bulk prune AT states if we have never done so before
|
||||
int pruneHeight = repository.getBlockRepository().getBlockPruneHeight();
|
||||
if (pruneHeight > 0) {
|
||||
// Already pruned blocks
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockData latestBlock = repository.getBlockRepository().getLastBlock();
|
||||
if (latestBlock == null) {
|
||||
LOGGER.info("Unable to determine blockchain height, necessary for bulk block pruning");
|
||||
return false;
|
||||
}
|
||||
final int blockchainHeight = latestBlock.getHeight();
|
||||
final int upperPrunableHeight = blockchainHeight - Settings.getInstance().getPruneBlockLimit();
|
||||
int pruneStartHeight = 0;
|
||||
|
||||
LOGGER.info("Starting bulk prune of blocks - this process could take a while... (approx. 5 mins on high spec)");
|
||||
|
||||
while (pruneStartHeight < upperPrunableHeight) {
|
||||
// Prune all blocks up until our latest minus pruneBlockLimit
|
||||
|
||||
int upperBatchHeight = pruneStartHeight + Settings.getInstance().getBlockPruneBatchSize();
|
||||
int upperPruneHeight = Math.min(upperBatchHeight, upperPrunableHeight);
|
||||
|
||||
LOGGER.info(String.format("Pruning blocks between %d and %d...", pruneStartHeight, upperPruneHeight));
|
||||
|
||||
int numBlocksPruned = repository.getBlockRepository().pruneBlocks(pruneStartHeight, upperPruneHeight);
|
||||
repository.saveChanges();
|
||||
|
||||
if (numBlocksPruned > 0) {
|
||||
final int finalPruneStartHeight = pruneStartHeight;
|
||||
LOGGER.info(() -> String.format("Pruned %d block%s between %d and %d",
|
||||
numBlocksPruned, (numBlocksPruned != 1 ? "s" : ""),
|
||||
finalPruneStartHeight, upperPruneHeight));
|
||||
} else {
|
||||
// Can we move onto next batch?
|
||||
if (upperPrunableHeight > upperBatchHeight) {
|
||||
pruneStartHeight = upperBatchHeight;
|
||||
repository.getBlockRepository().setBlockPruneHeight(pruneStartHeight);
|
||||
repository.saveChanges();
|
||||
|
||||
final int finalPruneStartHeight = pruneStartHeight;
|
||||
LOGGER.debug(() -> String.format("Bumping block base prune height to %d", finalPruneStartHeight));
|
||||
}
|
||||
else {
|
||||
// We've finished pruning
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void performMaintenance() throws SQLException, DataException {
|
||||
try (final HSQLDBRepository repository = (HSQLDBRepository) RepositoryManager.getRepository()) {
|
||||
repository.performPeriodicMaintenance();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -837,6 +837,11 @@ public class HSQLDBDatabaseUpdates {
|
||||
stmt.execute("SET TABLE ATStatesNew NEW SPACE");
|
||||
stmt.execute("CHECKPOINT");
|
||||
|
||||
// Add the height index
|
||||
LOGGER.info("Adding index to AT states table...");
|
||||
stmt.execute("CREATE INDEX ATStatesNewHeightIndex ON ATStatesNew (height)");
|
||||
stmt.execute("CHECKPOINT");
|
||||
|
||||
ResultSet resultSet = stmt.executeQuery("SELECT height FROM Blocks ORDER BY height DESC LIMIT 1");
|
||||
final int blockchainHeight = resultSet.next() ? resultSet.getInt(1) : 0;
|
||||
final int heightStep = 100;
|
||||
@@ -849,14 +854,24 @@ public class HSQLDBDatabaseUpdates {
|
||||
+ "WHERE height BETWEEN " + minHeight + " AND " + (minHeight + heightStep - 1)
|
||||
+ ")");
|
||||
stmt.execute("COMMIT");
|
||||
|
||||
int processed = Math.min(minHeight + heightStep - 1, blockchainHeight);
|
||||
double percentage = (double)processed / (double)blockchainHeight * 100.0f;
|
||||
LOGGER.info(String.format("Processed %d of %d blocks (%.1f%%)", processed, blockchainHeight, percentage));
|
||||
}
|
||||
stmt.execute("CHECKPOINT");
|
||||
|
||||
stmt.execute("DROP TABLE ATStates");
|
||||
stmt.execute("ALTER TABLE ATStatesNew RENAME TO ATStates");
|
||||
stmt.execute("ALTER INDEX ATStatesNewHeightIndex RENAME TO ATStatesHeightIndex");
|
||||
stmt.execute("CHECKPOINT");
|
||||
break;
|
||||
}
|
||||
case 35:
|
||||
// Support for pruning
|
||||
stmt.execute("ALTER TABLE DatabaseInfo ADD AT_prune_height INT NOT NULL DEFAULT 0");
|
||||
stmt.execute("ALTER TABLE DatabaseInfo ADD block_prune_height INT NOT NULL DEFAULT 0");
|
||||
break;
|
||||
|
||||
default:
|
||||
// nothing to do
|
||||
|
||||
@@ -109,6 +109,26 @@ public class Settings {
|
||||
* This has a significant effect on execution time. */
|
||||
private int onlineSignaturesTrimBatchSize = 100; // blocks
|
||||
|
||||
|
||||
/** Whether we should prune old data to reduce database size
|
||||
* This prevents the node from being able to serve older blocks */
|
||||
private boolean pruningEnabled = false;
|
||||
/** The amount of recent blocks we should keep when pruning */
|
||||
private int pruneBlockLimit = 1450;
|
||||
|
||||
/** How often to attempt AT state pruning (ms). */
|
||||
private long atStatesPruneInterval = 3219L; // milliseconds
|
||||
/** Block height range to scan for prunable AT states.<br>
|
||||
* This has a significant effect on execution time. */
|
||||
private int atStatesPruneBatchSize = 25; // blocks
|
||||
|
||||
/** How often to attempt block pruning (ms). */
|
||||
private long blockPruneInterval = 3219L; // milliseconds
|
||||
/** Block height range to scan for prunable blocks.<br>
|
||||
* This has a significant effect on execution time. */
|
||||
private int blockPruneBatchSize = 10000; // blocks
|
||||
|
||||
|
||||
// Peer-to-peer related
|
||||
private boolean isTestNet = false;
|
||||
/** Port number for inbound peer-to-peer connections. */
|
||||
@@ -529,4 +549,29 @@ public class Settings {
|
||||
return this.onlineSignaturesTrimBatchSize;
|
||||
}
|
||||
|
||||
|
||||
public boolean isPruningEnabled() {
|
||||
return this.pruningEnabled;
|
||||
}
|
||||
|
||||
public int getPruneBlockLimit() {
|
||||
return this.pruneBlockLimit;
|
||||
}
|
||||
|
||||
public long getAtStatesPruneInterval() {
|
||||
return this.atStatesPruneInterval;
|
||||
}
|
||||
|
||||
public int getAtStatesPruneBatchSize() {
|
||||
return this.atStatesPruneBatchSize;
|
||||
}
|
||||
|
||||
public long getBlockPruneInterval() {
|
||||
return this.blockPruneInterval;
|
||||
}
|
||||
|
||||
public int getBlockPruneBatchSize() {
|
||||
return this.blockPruneBatchSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,83 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# Keys are from api.ApiError enum
|
||||
|
||||
# "localeLang": "de",
|
||||
|
||||
### Common ###
|
||||
JSON = JSON nachricht konnte nicht geparsed werden
|
||||
|
||||
INSUFFICIENT_BALANCE = insufficient balance
|
||||
|
||||
UNAUTHORIZED = API call unauthorized
|
||||
|
||||
REPOSITORY_ISSUE = repository error
|
||||
|
||||
NON_PRODUCTION = this API call is not permitted for production systems
|
||||
|
||||
BLOCKCHAIN_NEEDS_SYNC = blockchain needs to synchronize first
|
||||
|
||||
NO_TIME_SYNC = no clock synchronization yet
|
||||
|
||||
### Validation ###
|
||||
INVALID_SIGNATURE = ungültige signatur
|
||||
|
||||
INVALID_ADDRESS = ungültige adresse
|
||||
|
||||
INVALID_ASSET_ID = ungültige asset ID
|
||||
INVALID_PUBLIC_KEY = ungültiger public key
|
||||
|
||||
INVALID_DATA = ungültige daten
|
||||
|
||||
INVALID_PUBLIC_KEY = ungültiger public key
|
||||
INVALID_NETWORK_ADDRESS = invalid network address
|
||||
|
||||
INVALID_SIGNATURE = ungültige signatur
|
||||
ADDRESS_UNKNOWN = account address unknown
|
||||
|
||||
JSON = JSON nachricht konnte nicht geparsed werden
|
||||
INVALID_CRITERIA = invalid search criteria
|
||||
|
||||
INVALID_REFERENCE = invalid reference
|
||||
|
||||
TRANSFORMATION_ERROR = could not transform JSON into transaction
|
||||
|
||||
INVALID_PRIVATE_KEY = invalid private key
|
||||
|
||||
INVALID_HEIGHT = invalid block height
|
||||
|
||||
CANNOT_MINT = account cannot mint
|
||||
|
||||
### Blocks ###
|
||||
BLOCK_UNKNOWN = block unknown
|
||||
|
||||
### Transactions ###
|
||||
TRANSACTION_UNKNOWN = transaction unknown
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = public key wurde nicht gefunden
|
||||
|
||||
# this one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = transaction invalid: %s (%s)
|
||||
|
||||
### Naming ###
|
||||
NAME_UNKNOWN = name unknown
|
||||
|
||||
### Asset ###
|
||||
INVALID_ASSET_ID = ungültige asset ID
|
||||
|
||||
INVALID_ORDER_ID = invalid asset order ID
|
||||
|
||||
ORDER_UNKNOWN = unknown asset order ID
|
||||
|
||||
### Groups ###
|
||||
GROUP_UNKNOWN = group unknown
|
||||
|
||||
### Foreign Blockchain ###
|
||||
FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = foreign blokchain or ElectrumX network issue
|
||||
|
||||
FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = insufficient balance on foreign blockchain
|
||||
|
||||
FOREIGN_BLOCKCHAIN_TOO_SOON = too soon to broadcast foreign blockchain transaction (LockTime/median block time)
|
||||
|
||||
### Trade Portal ###
|
||||
ORDER_SIZE_TOO_SMALL = order amount too low
|
||||
|
||||
### Data ###
|
||||
FILE_NOT_FOUND = file not found
|
||||
|
||||
NO_REPLY = peer did not reply with data
|
||||
@@ -1,68 +1,83 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# Keys are from api.ApiError enum
|
||||
|
||||
ADDRESS_UNKNOWN = account address unknown
|
||||
|
||||
BLOCKCHAIN_NEEDS_SYNC = blockchain needs to synchronize first
|
||||
|
||||
# Blocks
|
||||
BLOCK_UNKNOWN = block unknown
|
||||
|
||||
BTC_BALANCE_ISSUE = insufficient Bitcoin balance
|
||||
|
||||
BTC_NETWORK_ISSUE = Bitcoin/ElectrumX network issue
|
||||
|
||||
BTC_TOO_SOON = too soon to broadcast Bitcoin transaction (lockTime/median block time)
|
||||
|
||||
CANNOT_MINT = account cannot mint
|
||||
|
||||
GROUP_UNKNOWN = group unknown
|
||||
|
||||
INVALID_ADDRESS = invalid address
|
||||
|
||||
# Assets
|
||||
INVALID_ASSET_ID = invalid asset ID
|
||||
|
||||
INVALID_CRITERIA = invalid search criteria
|
||||
|
||||
INVALID_DATA = invalid data
|
||||
|
||||
INVALID_HEIGHT = invalid block height
|
||||
|
||||
INVALID_NETWORK_ADDRESS = invalid network address
|
||||
|
||||
INVALID_ORDER_ID = invalid asset order ID
|
||||
|
||||
INVALID_PRIVATE_KEY = invalid private key
|
||||
|
||||
INVALID_PUBLIC_KEY = invalid public key
|
||||
|
||||
INVALID_REFERENCE = invalid reference
|
||||
|
||||
# Validation
|
||||
INVALID_SIGNATURE = invalid signature
|
||||
# "localeLang": "en",
|
||||
|
||||
### Common ###
|
||||
JSON = failed to parse JSON message
|
||||
|
||||
NAME_UNKNOWN = name unknown
|
||||
|
||||
NON_PRODUCTION = this API call is not permitted for production systems
|
||||
|
||||
NO_TIME_SYNC = no clock synchronization yet
|
||||
|
||||
ORDER_UNKNOWN = unknown asset order ID
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = public key not found
|
||||
|
||||
REPOSITORY_ISSUE = repository error
|
||||
|
||||
# This one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = transaction invalid: %s (%s)
|
||||
|
||||
TRANSACTION_UNKNOWN = transaction unknown
|
||||
|
||||
TRANSFORMATION_ERROR = could not transform JSON into transaction
|
||||
INSUFFICIENT_BALANCE = insufficient balance
|
||||
|
||||
UNAUTHORIZED = API call unauthorized
|
||||
|
||||
ORDER_SIZE_TOO_SMALL = order size too small
|
||||
REPOSITORY_ISSUE = repository error
|
||||
|
||||
NON_PRODUCTION = this API call is not permitted for production systems
|
||||
|
||||
BLOCKCHAIN_NEEDS_SYNC = blockchain needs to synchronize first
|
||||
|
||||
NO_TIME_SYNC = no clock synchronization yet
|
||||
|
||||
### Validation ###
|
||||
INVALID_SIGNATURE = invalid signature
|
||||
|
||||
INVALID_ADDRESS = invalid address
|
||||
|
||||
INVALID_PUBLIC_KEY = invalid public key
|
||||
|
||||
INVALID_DATA = invalid data
|
||||
|
||||
INVALID_NETWORK_ADDRESS = invalid network address
|
||||
|
||||
ADDRESS_UNKNOWN = account address unknown
|
||||
|
||||
INVALID_CRITERIA = invalid search criteria
|
||||
|
||||
INVALID_REFERENCE = invalid reference
|
||||
|
||||
TRANSFORMATION_ERROR = could not transform JSON into transaction
|
||||
|
||||
INVALID_PRIVATE_KEY = invalid private key
|
||||
|
||||
INVALID_HEIGHT = invalid block height
|
||||
|
||||
CANNOT_MINT = account cannot mint
|
||||
|
||||
### Blocks ###
|
||||
BLOCK_UNKNOWN = block unknown
|
||||
|
||||
### Transactions ###
|
||||
TRANSACTION_UNKNOWN = transaction unknown
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = public key not found
|
||||
|
||||
# this one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = transaction invalid: %s (%s)
|
||||
|
||||
### Naming ###
|
||||
NAME_UNKNOWN = name unknown
|
||||
|
||||
### Asset ###
|
||||
INVALID_ASSET_ID = invalid asset ID
|
||||
|
||||
INVALID_ORDER_ID = invalid asset order ID
|
||||
|
||||
ORDER_UNKNOWN = unknown asset order ID
|
||||
|
||||
### Groups ###
|
||||
GROUP_UNKNOWN = group unknown
|
||||
|
||||
### Foreign Blockchain ###
|
||||
FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = foreign blokchain or ElectrumX network issue
|
||||
|
||||
FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = insufficient balance on foreign blockchain
|
||||
|
||||
FOREIGN_BLOCKCHAIN_TOO_SOON = too soon to broadcast foreign blockchain transaction (LockTime/median block time)
|
||||
|
||||
### Trade Portal ###
|
||||
ORDER_SIZE_TOO_SMALL = order amount too low
|
||||
|
||||
### Data ###
|
||||
FILE_NOT_FOUND = file not found
|
||||
|
||||
NO_REPLY = peer did not reply with data
|
||||
@@ -1,71 +1,86 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# Keys are from api.ApiError enum
|
||||
#
|
||||
|
||||
# Kielen muuttaminen suomeksi tapahtuu settings.json-tiedostossa
|
||||
#
|
||||
# "localeLang": "fi",
|
||||
# muista pilkku lopussa jos komento ei ole viimeisellä rivillä
|
||||
|
||||
ADDRESS_UNKNOWN = tilin osoite on tuntematon
|
||||
|
||||
BLOCKCHAIN_NEEDS_SYNC = lohkoketjun tarvitsee ensin synkronisoitua
|
||||
|
||||
# Blocks
|
||||
BLOCK_UNKNOWN = tuntematon lohko
|
||||
|
||||
BTC_BALANCE_ISSUE = riittämätön Bitcoin-saldo
|
||||
|
||||
BTC_NETWORK_ISSUE = Bitcoin/ElectrumX -verkon ongelma
|
||||
|
||||
BTC_TOO_SOON = liian aikaista julkistaa Bitcoin-tapahtumaa (lukitusaika/mediiaanilohkoaika)
|
||||
|
||||
CANNOT_MINT = tili ei voi lyödä rahaa
|
||||
|
||||
GROUP_UNKNOWN = tuntematon ryhmä
|
||||
|
||||
INVALID_ADDRESS = osoite on kelvoton
|
||||
|
||||
# Assets
|
||||
INVALID_ASSET_ID = kelvoton ID resurssille
|
||||
|
||||
INVALID_CRITERIA = kelvoton hakuehto
|
||||
|
||||
INVALID_DATA = kelvoton data
|
||||
|
||||
INVALID_HEIGHT = kelvoton lohkon korkeus
|
||||
|
||||
INVALID_NETWORK_ADDRESS = kelvoton verkko-osoite
|
||||
|
||||
INVALID_ORDER_ID = kelvoton resurssin tilaus-ID
|
||||
|
||||
INVALID_PRIVATE_KEY = kelvoton yksityinen avain
|
||||
|
||||
INVALID_PUBLIC_KEY = kelvoton julkinen avain
|
||||
|
||||
INVALID_REFERENCE = kelvoton viite
|
||||
|
||||
# Validation
|
||||
INVALID_SIGNATURE = kelvoton allekirjoitus
|
||||
|
||||
### Common ###
|
||||
JSON = JSON-viestin jaottelu epäonnistui
|
||||
|
||||
NAME_UNKNOWN = tuntematon nimi
|
||||
INSUFFICIENT_BALANCE = insufficient balance
|
||||
|
||||
NON_PRODUCTION = tämä API-kutsu on kielletty tuotantoversiossa
|
||||
|
||||
NO_TIME_SYNC = kello vielä synkronisoimatta
|
||||
|
||||
ORDER_UNKNOWN = tuntematon resurssin tilaus-ID
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = julkista avainta ei löytynyt
|
||||
UNAUTHORIZED = luvaton API-kutsu
|
||||
|
||||
REPOSITORY_ISSUE = tietovarantovirhe (repo)
|
||||
|
||||
# This one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = kelvoton transaktio: %s (%s)
|
||||
NON_PRODUCTION = tämä API-kutsu on kielletty tuotantoversiossa
|
||||
|
||||
TRANSACTION_UNKNOWN = tuntematon transaktio
|
||||
BLOCKCHAIN_NEEDS_SYNC = lohkoketjun tarvitsee ensin synkronisoitua
|
||||
|
||||
NO_TIME_SYNC = kello vielä synkronisoimatta
|
||||
|
||||
### Validation ###
|
||||
INVALID_SIGNATURE = kelvoton allekirjoitus
|
||||
|
||||
INVALID_ADDRESS = osoite on kelvoton
|
||||
|
||||
INVALID_PUBLIC_KEY = kelvoton julkinen avain
|
||||
|
||||
INVALID_DATA = kelvoton data
|
||||
|
||||
INVALID_NETWORK_ADDRESS = kelvoton verkko-osoite
|
||||
|
||||
ADDRESS_UNKNOWN = tilin osoite on tuntematon
|
||||
|
||||
INVALID_CRITERIA = kelvoton hakuehto
|
||||
|
||||
INVALID_REFERENCE = kelvoton viite
|
||||
|
||||
TRANSFORMATION_ERROR = JSON:in muuntaminen transaktioksi epäonnistui
|
||||
|
||||
UNAUTHORIZED = luvaton API-kutsu
|
||||
INVALID_PRIVATE_KEY = kelvoton yksityinen avain
|
||||
|
||||
INVALID_HEIGHT = kelvoton lohkon korkeus
|
||||
|
||||
CANNOT_MINT = tili ei voi lyödä rahaa
|
||||
|
||||
### Blocks ###
|
||||
BLOCK_UNKNOWN = tuntematon lohko
|
||||
|
||||
### Transactions ###
|
||||
TRANSACTION_UNKNOWN = tuntematon transaktio
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = julkista avainta ei löytynyt
|
||||
|
||||
# this one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = kelvoton transaktio: %s (%s)
|
||||
|
||||
### Naming ###
|
||||
NAME_UNKNOWN = tuntematon nimi
|
||||
|
||||
### Asset ###
|
||||
INVALID_ASSET_ID = kelvoton ID resurssille
|
||||
|
||||
INVALID_ORDER_ID = kelvoton resurssin tilaus-ID
|
||||
|
||||
ORDER_UNKNOWN = tuntematon resurssin tilaus-ID
|
||||
|
||||
### Groups ###
|
||||
GROUP_UNKNOWN = tuntematon ryhmä
|
||||
|
||||
### Foreign Blockchain ###
|
||||
FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = foreign blokchain or ElectrumX network issue
|
||||
|
||||
FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = insufficient balance on foreign blockchain
|
||||
|
||||
FOREIGN_BLOCKCHAIN_TOO_SOON = too soon to broadcast foreign blockchain transaction (LockTime/median block time)
|
||||
|
||||
### Trade Portal ###
|
||||
ORDER_SIZE_TOO_SMALL = order amount too low
|
||||
|
||||
### Data ###
|
||||
FILE_NOT_FOUND = file not found
|
||||
|
||||
NO_REPLY = peer did not reply with data
|
||||
86
src/main/resources/i18n/ApiError_hu.properties
Normal file
86
src/main/resources/i18n/ApiError_hu.properties
Normal file
@@ -0,0 +1,86 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# Keys are from api.ApiError enum
|
||||
|
||||
# Magyar myelvre forditotta: Szkíta (Scythian). 2021 Augusztus 7.
|
||||
# Az alkalmazás nyelvének magyarra való változtatása a settings.json oldalon történik.
|
||||
|
||||
# "localeLang": "hu",
|
||||
|
||||
### Common ###
|
||||
JSON = nem sikerült elemezni a JSON üzenetet
|
||||
|
||||
INSUFFICIENT_BALANCE = elégtelen egyenleg
|
||||
|
||||
UNAUTHORIZED = nem engedélyezett API-hívás
|
||||
|
||||
REPOSITORY_ISSUE = adattári hiba
|
||||
|
||||
NON_PRODUCTION = ez az API-hívás nem engedélyezett korlátozott rendszereken
|
||||
|
||||
BLOCKCHAIN_NEEDS_SYNC = a blokkláncnak még szinkronizálnia kell
|
||||
|
||||
NO_TIME_SYNC = az óraszinkronizálás még nem történt meg
|
||||
|
||||
### Validation ###
|
||||
INVALID_SIGNATURE = érvénytelen aláírás
|
||||
|
||||
INVALID_ADDRESS = érvénytelen fiók cím
|
||||
|
||||
INVALID_PUBLIC_KEY = érvénytelen nyilvános kulcs
|
||||
|
||||
INVALID_DATA = érvénytelen adat
|
||||
|
||||
INVALID_NETWORK_ADDRESS = érvénytelen hálózat cím
|
||||
|
||||
ADDRESS_UNKNOWN = ismeretlen fiók cím
|
||||
|
||||
INVALID_CRITERIA = érvénytelen keresési feltétel
|
||||
|
||||
INVALID_REFERENCE = érvénytelen hivatkozás
|
||||
|
||||
TRANSFORMATION_ERROR = nem sikerült tranzakcióvá alakítani a JSON-t
|
||||
|
||||
INVALID_PRIVATE_KEY = érvénytelen privát kulcs
|
||||
|
||||
INVALID_HEIGHT = érvénytelen blokkmagasság
|
||||
|
||||
CANNOT_MINT = ez a fiók még nem tud QORT-ot verni
|
||||
|
||||
### Blocks ###
|
||||
BLOCK_UNKNOWN = ismeretlen blokk
|
||||
|
||||
### Transactions ###
|
||||
TRANSACTION_UNKNOWN = ismeretlen tranzakció
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = nyilvános kulcs nem található
|
||||
|
||||
# this one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = érvénytelen tranzakció: %s (%s)
|
||||
|
||||
### Naming ###
|
||||
NAME_UNKNOWN = ismeretlen név
|
||||
|
||||
### Asset ###
|
||||
INVALID_ASSET_ID = érvénytelen eszközazonosító
|
||||
|
||||
INVALID_ORDER_ID = érvénytelen eszközrendelési azonosító
|
||||
|
||||
ORDER_UNKNOWN = ismeretlen eszközrendelési azonosító
|
||||
|
||||
### Groups ###
|
||||
GROUP_UNKNOWN = ismeretlen csoport
|
||||
|
||||
### Foreign Blockchain ###
|
||||
FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = idegen blokklánc vagy ElectrumX hálózati probléma
|
||||
|
||||
FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = elégtelen egyenleg az idegen blokkláncon
|
||||
|
||||
FOREIGN_BLOCKCHAIN_TOO_SOON = túl korai meghírdetni az idegen blokkláncon való tranzakciót (LockTime/medián blokkidő)
|
||||
|
||||
### Trade Portal ###
|
||||
ORDER_SIZE_TOO_SMALL = rendelési összeg túl alacsony
|
||||
|
||||
### Data ###
|
||||
FILE_NOT_FOUND = fájl nem található
|
||||
|
||||
NO_REPLY = a másik csomópont nem válaszolt
|
||||
@@ -7,66 +7,81 @@
|
||||
# "localeLang": "it",
|
||||
# Si prega ricordare la virgola alla fine, se questo comando non è sull'ultima riga
|
||||
|
||||
ADDRESS_UNKNOWN = indirizzo account sconosciuto
|
||||
|
||||
BLOCKCHAIN_NEEDS_SYNC = blockchain deve prima sincronizzarsi
|
||||
|
||||
# Blocks
|
||||
BLOCK_UNKNOWN = blocco sconosciuto
|
||||
|
||||
BTC_BALANCE_ISSUE = saldo Bitcoin insufficiente
|
||||
|
||||
BTC_NETWORK_ISSUE = Bitcoin/ElectrumX problema di rete
|
||||
|
||||
BTC_TOO_SOON = troppo presto per trasmettere transazione Bitcoin (tempo di blocco / tempo di blocco mediano)
|
||||
|
||||
CANNOT_MINT = l'account non può coniare
|
||||
|
||||
GROUP_UNKNOWN = gruppo sconosciuto
|
||||
|
||||
INVALID_ADDRESS = indirizzo non valido
|
||||
|
||||
# Assets
|
||||
INVALID_ASSET_ID = identificazione risorsa non valida
|
||||
|
||||
INVALID_CRITERIA = criteri di ricerca non validi
|
||||
|
||||
INVALID_DATA = dati non validi
|
||||
|
||||
INVALID_HEIGHT = altezza blocco non valida
|
||||
|
||||
INVALID_NETWORK_ADDRESS = indirizzo di rete non valido
|
||||
|
||||
INVALID_ORDER_ID = identificazione di ordine di risorsa non valida
|
||||
|
||||
INVALID_PRIVATE_KEY = chiave privata non valida
|
||||
|
||||
INVALID_PUBLIC_KEY = chiave pubblica non valida
|
||||
|
||||
INVALID_REFERENCE = riferimento non valido
|
||||
|
||||
# Validation
|
||||
INVALID_SIGNATURE = firma non valida
|
||||
|
||||
### Common ###
|
||||
JSON = Impossibile analizzare il messaggio JSON
|
||||
|
||||
NAME_UNKNOWN = nome sconosciuto
|
||||
INSUFFICIENT_BALANCE = insufficient balance
|
||||
|
||||
NON_PRODUCTION = questa chiamata API non è consentita per i sistemi di produzione
|
||||
|
||||
NO_TIME_SYNC = nessuna sincronizzazione dell'orologio ancora
|
||||
|
||||
ORDER_UNKNOWN = identificazione di ordine di risorsa sconosciuta
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = chiave pubblica non trovata
|
||||
UNAUTHORIZED = Chiamata API non autorizzata
|
||||
|
||||
REPOSITORY_ISSUE = errore del repositorio
|
||||
|
||||
# This one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = transazione non valida: %s (%s)
|
||||
NON_PRODUCTION = questa chiamata API non è consentita per i sistemi di produzione
|
||||
|
||||
TRANSACTION_UNKNOWN = transazione sconosciuta
|
||||
BLOCKCHAIN_NEEDS_SYNC = blockchain deve prima sincronizzarsi
|
||||
|
||||
NO_TIME_SYNC = nessuna sincronizzazione dell'orologio ancora
|
||||
|
||||
### Validation ###
|
||||
INVALID_SIGNATURE = firma non valida
|
||||
|
||||
INVALID_ADDRESS = indirizzo non valido
|
||||
|
||||
INVALID_PUBLIC_KEY = chiave pubblica non valida
|
||||
|
||||
INVALID_DATA = dati non validi
|
||||
|
||||
INVALID_NETWORK_ADDRESS = indirizzo di rete non valido
|
||||
|
||||
ADDRESS_UNKNOWN = indirizzo account sconosciuto
|
||||
|
||||
INVALID_CRITERIA = criteri di ricerca non validi
|
||||
|
||||
INVALID_REFERENCE = riferimento non valido
|
||||
|
||||
TRANSFORMATION_ERROR = non è stato possibile trasformare JSON in transazione
|
||||
|
||||
UNAUTHORIZED = Chiamata API non autorizzata
|
||||
INVALID_PRIVATE_KEY = chiave privata non valida
|
||||
|
||||
INVALID_HEIGHT = altezza blocco non valida
|
||||
|
||||
CANNOT_MINT = l'account non può coniare
|
||||
|
||||
### Blocks ###
|
||||
BLOCK_UNKNOWN = blocco sconosciuto
|
||||
|
||||
### Transactions ###
|
||||
TRANSACTION_UNKNOWN = transazione sconosciuta
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = chiave pubblica non trovata
|
||||
|
||||
# this one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = transazione non valida: %s (%s)
|
||||
|
||||
### Naming ###
|
||||
NAME_UNKNOWN = nome sconosciuto
|
||||
|
||||
### Asset ###
|
||||
INVALID_ASSET_ID = identificazione risorsa non valida
|
||||
|
||||
INVALID_ORDER_ID = identificazione di ordine di risorsa non valida
|
||||
|
||||
ORDER_UNKNOWN = identificazione di ordine di risorsa sconosciuta
|
||||
|
||||
### Groups ###
|
||||
GROUP_UNKNOWN = gruppo sconosciuto
|
||||
|
||||
### Foreign Blockchain ###
|
||||
FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = foreign blokchain or ElectrumX network issue
|
||||
|
||||
FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = insufficient balance on foreign blockchain
|
||||
|
||||
FOREIGN_BLOCKCHAIN_TOO_SOON = too soon to broadcast foreign blockchain transaction (LockTime/median block time)
|
||||
|
||||
### Trade Portal ###
|
||||
ORDER_SIZE_TOO_SMALL = order amount too low
|
||||
|
||||
### Data ###
|
||||
FILE_NOT_FOUND = file not found
|
||||
|
||||
NO_REPLY = peer did not reply with data
|
||||
@@ -1,66 +1,83 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# Keys are from api.ApiError enum
|
||||
|
||||
ADDRESS_UNKNOWN = account adres onbekend
|
||||
|
||||
BLOCKCHAIN_NEEDS_SYNC = blockchain dient eerst gesynchronizeerd te worden
|
||||
|
||||
# Blocks
|
||||
BLOCK_UNKNOWN = blok onbekend
|
||||
|
||||
BTC_BALANCE_ISSUE = onvoldoende Bitcoin balans
|
||||
|
||||
BTC_NETWORK_ISSUE = Bitcoin/ElectrumX netwerk probleem
|
||||
|
||||
BTC_TOO_SOON = te vroeg om Bitcoin transactie te versturen (vergrendelingstijd/gemiddelde bloktijd)
|
||||
|
||||
CANNOT_MINT = account kan niet munten
|
||||
|
||||
GROUP_UNKNOWN = onbekende groep
|
||||
|
||||
INVALID_ADDRESS = ongeldig adres
|
||||
|
||||
# Assets
|
||||
INVALID_ASSET_ID = ongeldige asset ID
|
||||
|
||||
INVALID_CRITERIA = ongeldige zoekcriteria
|
||||
|
||||
INVALID_DATA = ongeldige gegevens
|
||||
|
||||
INVALID_HEIGHT = ongeldige blokhoogte
|
||||
|
||||
INVALID_NETWORK_ADDRESS = ongeldig netwerkadres
|
||||
|
||||
INVALID_ORDER_ID = ongeldige asset order ID
|
||||
|
||||
INVALID_PRIVATE_KEY = ongeldige private key
|
||||
|
||||
INVALID_PUBLIC_KEY = ongeldige public key
|
||||
|
||||
INVALID_REFERENCE = ongeldige verwijzing
|
||||
|
||||
# Validation
|
||||
INVALID_SIGNATURE = ongeldige handtekening
|
||||
# "localeLang": "nl",
|
||||
|
||||
### Common ###
|
||||
JSON = lezen van JSON bericht gefaald
|
||||
|
||||
NAME_UNKNOWN = onbekende naam
|
||||
INSUFFICIENT_BALANCE = insufficient balance
|
||||
|
||||
NON_PRODUCTION = deze API call is niet toegestaan voor productiesystemen
|
||||
|
||||
NO_TIME_SYNC = klok nog niet gesynchronizeerd
|
||||
|
||||
ORDER_UNKNOWN = onbekende asset order ID
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = public key niet gevonden
|
||||
UNAUTHORIZED = ongeautoriseerde API call
|
||||
|
||||
REPOSITORY_ISSUE = repository fout
|
||||
|
||||
# This one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = ongeldige transactie: %s (%s)
|
||||
NON_PRODUCTION = deze API call is niet toegestaan voor productiesystemen
|
||||
|
||||
TRANSACTION_UNKNOWN = onbekende transactie
|
||||
BLOCKCHAIN_NEEDS_SYNC = blockchain dient eerst gesynchronizeerd te worden
|
||||
|
||||
NO_TIME_SYNC = klok nog niet gesynchronizeerd
|
||||
|
||||
### Validation ###
|
||||
INVALID_SIGNATURE = ongeldige handtekening
|
||||
|
||||
INVALID_ADDRESS = ongeldig adres
|
||||
|
||||
INVALID_PUBLIC_KEY = ongeldige public key
|
||||
|
||||
INVALID_DATA = ongeldige gegevens
|
||||
|
||||
INVALID_NETWORK_ADDRESS = ongeldig netwerkadres
|
||||
|
||||
ADDRESS_UNKNOWN = account adres onbekend
|
||||
|
||||
INVALID_CRITERIA = ongeldige zoekcriteria
|
||||
|
||||
INVALID_REFERENCE = ongeldige verwijzing
|
||||
|
||||
TRANSFORMATION_ERROR = JSON kon niet omgezet worden in transactie
|
||||
|
||||
UNAUTHORIZED = ongeautoriseerde API call
|
||||
INVALID_PRIVATE_KEY = ongeldige private key
|
||||
|
||||
INVALID_HEIGHT = ongeldige blokhoogte
|
||||
|
||||
CANNOT_MINT = account kan niet munten
|
||||
|
||||
### Blocks ###
|
||||
BLOCK_UNKNOWN = blok onbekend
|
||||
|
||||
### Transactions ###
|
||||
TRANSACTION_UNKNOWN = onbekende transactie
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = public key niet gevonden
|
||||
|
||||
# this one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = ongeldige transactie: %s (%s)
|
||||
|
||||
### Naming ###
|
||||
NAME_UNKNOWN = onbekende naam
|
||||
|
||||
### Asset ###
|
||||
INVALID_ASSET_ID = ongeldige asset ID
|
||||
|
||||
INVALID_ORDER_ID = ongeldige asset order ID
|
||||
|
||||
ORDER_UNKNOWN = onbekende asset order ID
|
||||
|
||||
### Groups ###
|
||||
GROUP_UNKNOWN = onbekende groep
|
||||
|
||||
### Foreign Blockchain ###
|
||||
FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = foreign blokchain or ElectrumX network issue
|
||||
|
||||
FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = insufficient balance on foreign blockchain
|
||||
|
||||
FOREIGN_BLOCKCHAIN_TOO_SOON = too soon to broadcast foreign blockchain transaction (LockTime/median block time)
|
||||
|
||||
### Trade Portal ###
|
||||
ORDER_SIZE_TOO_SMALL = order amount too low
|
||||
|
||||
### Data ###
|
||||
FILE_NOT_FOUND = file not found
|
||||
|
||||
NO_REPLY = peer did not reply with data
|
||||
@@ -1,57 +1,83 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# Keys are from api.ApiError enum
|
||||
|
||||
ADDRESS_UNKNOWN = неизвестная учетная запись
|
||||
|
||||
BLOCKCHAIN_NEEDS_SYNC = блокчейн должен сначала синхронизироваться
|
||||
|
||||
# Blocks
|
||||
BLOCK_UNKNOWN = неизвестный блок
|
||||
|
||||
CANNOT_MINT = аккаунт не может чеканить
|
||||
|
||||
GROUP_UNKNOWN = неизвестная группа
|
||||
|
||||
INVALID_ADDRESS = неизвестный адрес
|
||||
|
||||
# Assets
|
||||
INVALID_ASSET_ID = неверный идентификатор актива
|
||||
|
||||
INVALID_CRITERIA = неверные критерии поиска
|
||||
|
||||
INVALID_DATA = неверные данные
|
||||
|
||||
INVALID_HEIGHT = недопустимая высота блока
|
||||
|
||||
INVALID_NETWORK_ADDRESS = неверный сетевой адрес
|
||||
|
||||
INVALID_ORDER_ID = неверный идентификатор заказа актива
|
||||
|
||||
INVALID_PRIVATE_KEY = неверный приватный ключ
|
||||
|
||||
INVALID_PUBLIC_KEY = недействительный открытый ключ
|
||||
|
||||
INVALID_REFERENCE = неверная ссылка
|
||||
|
||||
# Validation
|
||||
INVALID_SIGNATURE = недействительная подпись
|
||||
# "localeLang": "ru",
|
||||
|
||||
### Common ###
|
||||
JSON = не удалось разобрать сообщение json
|
||||
|
||||
NAME_UNKNOWN = имя неизвестно
|
||||
INSUFFICIENT_BALANCE = insufficient balance
|
||||
|
||||
NON_PRODUCTION = этот вызов API не разрешен для производственных систем
|
||||
|
||||
ORDER_UNKNOWN = неизвестный идентификатор заказа актива
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = открытый ключ не найден
|
||||
UNAUTHORIZED = вызов API не авторизован
|
||||
|
||||
REPOSITORY_ISSUE = ошибка репозитория
|
||||
|
||||
TRANSACTION_INVALID = транзакция недействительна: %s (%s)
|
||||
NON_PRODUCTION = этот вызов API не разрешен для производственных систем
|
||||
|
||||
TRANSACTION_UNKNOWN = транзакция неизвестна
|
||||
BLOCKCHAIN_NEEDS_SYNC = блокчейн должен сначала синхронизироваться
|
||||
|
||||
NO_TIME_SYNC = no clock synchronization yet
|
||||
|
||||
### Validation ###
|
||||
INVALID_SIGNATURE = недействительная подпись
|
||||
|
||||
INVALID_ADDRESS = неизвестный адрес
|
||||
|
||||
INVALID_PUBLIC_KEY = недействительный открытый ключ
|
||||
|
||||
INVALID_DATA = неверные данные
|
||||
|
||||
INVALID_NETWORK_ADDRESS = неверный сетевой адрес
|
||||
|
||||
ADDRESS_UNKNOWN = неизвестная учетная запись
|
||||
|
||||
INVALID_CRITERIA = неверные критерии поиска
|
||||
|
||||
INVALID_REFERENCE = неверная ссылка
|
||||
|
||||
TRANSFORMATION_ERROR = не удалось преобразовать JSON в транзакцию
|
||||
|
||||
UNAUTHORIZED = вызов API не авторизован
|
||||
INVALID_PRIVATE_KEY = неверный приватный ключ
|
||||
|
||||
INVALID_HEIGHT = недопустимая высота блока
|
||||
|
||||
CANNOT_MINT = аккаунт не может чеканить
|
||||
|
||||
### Blocks ###
|
||||
BLOCK_UNKNOWN = неизвестный блок
|
||||
|
||||
### Transactions ###
|
||||
TRANSACTION_UNKNOWN = транзакция неизвестна
|
||||
|
||||
PUBLIC_KEY_NOT_FOUND = открытый ключ не найден
|
||||
|
||||
# this one is special in that caller expected to pass two additional strings, hence the two %s
|
||||
TRANSACTION_INVALID = транзакция недействительна: %s (%s)
|
||||
|
||||
### Naming ###
|
||||
NAME_UNKNOWN = имя неизвестно
|
||||
|
||||
### Asset ###
|
||||
INVALID_ASSET_ID = неверный идентификатор актива
|
||||
|
||||
INVALID_ORDER_ID = неверный идентификатор заказа актива
|
||||
|
||||
ORDER_UNKNOWN = неизвестный идентификатор заказа актива
|
||||
|
||||
### Groups ###
|
||||
GROUP_UNKNOWN = неизвестная группа
|
||||
|
||||
### Foreign Blockchain ###
|
||||
FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = foreign blokchain or ElectrumX network issue
|
||||
|
||||
FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = insufficient balance on foreign blockchain
|
||||
|
||||
FOREIGN_BLOCKCHAIN_TOO_SOON = too soon to broadcast foreign blockchain transaction (LockTime/median block time)
|
||||
|
||||
### Trade Portal ###
|
||||
ORDER_SIZE_TOO_SMALL = order amount too low
|
||||
|
||||
### Data ###
|
||||
FILE_NOT_FOUND = file not found
|
||||
|
||||
NO_REPLY = peer did not reply with data
|
||||
@@ -1,12 +1,14 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# SysTray pop-up menu
|
||||
|
||||
APPLYING_UPDATE_AND_RESTARTING = Applying automatic update and restarting...
|
||||
|
||||
AUTO_UPDATE = Auto Update
|
||||
|
||||
APPLYING_UPDATE_AND_RESTARTING = Applying automatic update and restarting...
|
||||
|
||||
BLOCK_HEIGHT = height
|
||||
|
||||
BUILD_VERSION = Build version
|
||||
|
||||
CHECK_TIME_ACCURACY = Check time accuracy
|
||||
|
||||
CONNECTING = Connecting
|
||||
@@ -27,13 +29,6 @@ MINTING_DISABLED = NOT minting
|
||||
|
||||
MINTING_ENABLED = \u2714 Minting
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION = Computer's clock is inaccurate!
|
||||
|
||||
NTP_NAG_TEXT_UNIX = Install NTP service to get an accurate clock.
|
||||
|
||||
NTP_NAG_TEXT_WINDOWS = Select "Synchronize clock" from menu to fix.
|
||||
|
||||
OPEN_UI = Open UI
|
||||
|
||||
PERFORMING_DB_CHECKPOINT = Saving uncommitted database changes...
|
||||
@@ -42,4 +37,4 @@ SYNCHRONIZE_CLOCK = Synchronize clock
|
||||
|
||||
SYNCHRONIZING_BLOCKCHAIN = Synchronizing
|
||||
|
||||
SYNCHRONIZING_CLOCK = Synchronizing clock
|
||||
SYNCHRONIZING_CLOCK = Synchronizing clock
|
||||
@@ -1,12 +1,14 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# SysTray pop-up menu
|
||||
|
||||
APPLYING_UPDATE_AND_RESTARTING = Automaattinen päivitys käynnissä, uudelleenkäynnistys seuraa...
|
||||
|
||||
AUTO_UPDATE = Automaattinen päivitys
|
||||
|
||||
APPLYING_UPDATE_AND_RESTARTING = Automaattinen päivitys käynnissä, uudelleenkäynnistys seuraa...
|
||||
|
||||
BLOCK_HEIGHT = korkeus
|
||||
|
||||
BUILD_VERSION = Versio
|
||||
|
||||
CHECK_TIME_ACCURACY = Tarkista ajan tarkkuus
|
||||
|
||||
CONNECTING = Yhdistää
|
||||
@@ -27,13 +29,6 @@ MINTING_DISABLED = EI lyö rahaa
|
||||
|
||||
MINTING_ENABLED = \u2714 Lyö rahaa
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION = Tietokoneen kello on epätarkka!
|
||||
|
||||
NTP_NAG_TEXT_UNIX = Asennathan NTP-palvelun, jotta saat kellon tarkkuuden oikeaksi.
|
||||
|
||||
NTP_NAG_TEXT_WINDOWS = Valitse "Kellon synkronisointi" valikosta korjataksesi.
|
||||
|
||||
OPEN_UI = Avaa UI
|
||||
|
||||
PERFORMING_DB_CHECKPOINT = Tallentaa kommittoidut tietokantamuutokset...
|
||||
@@ -42,4 +37,4 @@ SYNCHRONIZE_CLOCK = Synkronisoi kello
|
||||
|
||||
SYNCHRONIZING_BLOCKCHAIN = Synkronisoi
|
||||
|
||||
SYNCHRONIZING_CLOCK = Synkronisoi kelloa
|
||||
SYNCHRONIZING_CLOCK = Synkronisoi kelloa
|
||||
42
src/main/resources/i18n/SysTray_hu.properties
Normal file
42
src/main/resources/i18n/SysTray_hu.properties
Normal file
@@ -0,0 +1,42 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# SysTray pop-up menu
|
||||
|
||||
# Magyar myelvre forditotta: Szkíta (Scythian). 2021 Augusztus 7.
|
||||
|
||||
AUTO_UPDATE = Automatikus Frissítés
|
||||
|
||||
APPLYING_UPDATE_AND_RESTARTING = Automatikus frissítés és újraindítás alkalmazása...
|
||||
|
||||
BLOCK_HEIGHT = blokkmagasság
|
||||
|
||||
BUILD_VERSION = Verzió
|
||||
|
||||
CHECK_TIME_ACCURACY = Idő pontosság ellenőrzése
|
||||
|
||||
CONNECTING = Kapcsolódás
|
||||
|
||||
CONNECTION = kapcsolat
|
||||
|
||||
CONNECTIONS = kapcsolat
|
||||
|
||||
CREATING_BACKUP_OF_DB_FILES = Adatbázis fájlok biztonsági mentésének létrehozása...
|
||||
|
||||
DB_BACKUP = Adatbázis biztonsági mentése
|
||||
|
||||
DB_CHECKPOINT = Adatbázis-ellenőrzőpont
|
||||
|
||||
EXIT = Kilépés
|
||||
|
||||
MINTING_DISABLED = QORT-érmeverés jelenleg nincs folyamatban
|
||||
|
||||
MINTING_ENABLED = \u2714 QORT-érmeverés folyamatban
|
||||
|
||||
OPEN_UI = Felhasználói eszköz megnyitása
|
||||
|
||||
PERFORMING_DB_CHECKPOINT = Mentetlen adatbázis-módosítások mentése...
|
||||
|
||||
SYNCHRONIZE_CLOCK = Óra-szinkronizálás megkezdése
|
||||
|
||||
SYNCHRONIZING_BLOCKCHAIN = Szinkronizálás
|
||||
|
||||
SYNCHRONIZING_CLOCK = Óra-szinkronizálás folyamatban
|
||||
@@ -8,6 +8,8 @@ AUTO_UPDATE = Aggiornamento automatico
|
||||
|
||||
BLOCK_HEIGHT = altezza
|
||||
|
||||
BUILD_VERSION = Versione
|
||||
|
||||
CHECK_TIME_ACCURACY = Controlla la precisione dell'ora
|
||||
|
||||
CONNECTING = Collegando
|
||||
@@ -28,13 +30,6 @@ MINTING_DISABLED = NON coniando
|
||||
|
||||
MINTING_ENABLED = \u2714 Coniando
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION = L'orologio del computer è impreciso!
|
||||
|
||||
NTP_NAG_TEXT_UNIX = Installare servizio NTP per ottenere un orologio preciso.
|
||||
|
||||
NTP_NAG_TEXT_WINDOWS = Seleziona "Sincronizza orologio" dal menu per correggere.
|
||||
|
||||
OPEN_UI = Apri UI
|
||||
|
||||
PERFORMING_DB_CHECKPOINT = Salvataggio delle modifiche al database non salvate...
|
||||
@@ -43,4 +38,4 @@ SYNCHRONIZE_CLOCK = Sincronizza orologio
|
||||
|
||||
SYNCHRONIZING_BLOCKCHAIN = Sincronizzando
|
||||
|
||||
SYNCHRONIZING_CLOCK = Sincronizzando orologio
|
||||
SYNCHRONIZING_CLOCK = Sincronizzando orologio
|
||||
@@ -7,6 +7,8 @@ AUTO_UPDATE = Automatische Update
|
||||
|
||||
BLOCK_HEIGHT = hoogte
|
||||
|
||||
BUILD_VERSION = Versie
|
||||
|
||||
CHECK_TIME_ACCURACY = Controleer accuraatheid van de tijd
|
||||
|
||||
CONNECTING = Verbinden
|
||||
@@ -27,13 +29,6 @@ MINTING_DISABLED = NIET muntend
|
||||
|
||||
MINTING_ENABLED = \u2714 Muntend
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION = Klok van de computer is inaccuraat!
|
||||
|
||||
NTP_NAG_TEXT_UNIX = Installeer NTP service voor een accurate klok.
|
||||
|
||||
NTP_NAG_TEXT_WINDOWS = Selecteer "Synchronizeer klok" uit het menu om op te lossen.
|
||||
|
||||
OPEN_UI = Open UI
|
||||
|
||||
PERFORMING_DB_CHECKPOINT = Nieuwe veranderingen aan database worden opgeslagen...
|
||||
@@ -42,4 +37,4 @@ SYNCHRONIZE_CLOCK = Synchronizeer klok
|
||||
|
||||
SYNCHRONIZING_BLOCKCHAIN = Aan het synchronizeren
|
||||
|
||||
SYNCHRONIZING_CLOCK = Klok wordt gesynchronizeerd
|
||||
SYNCHRONIZING_CLOCK = Klok wordt gesynchronizeerd
|
||||
@@ -7,6 +7,8 @@ AUTO_UPDATE = Автоматическое обновление
|
||||
|
||||
BLOCK_HEIGHT = Высота блока
|
||||
|
||||
BUILD_VERSION = Build version
|
||||
|
||||
CHECK_TIME_ACCURACY = Проверка точного времени
|
||||
|
||||
CONNECTING = Подключение
|
||||
@@ -25,17 +27,12 @@ MINTING_DISABLED = Чеканка отключена
|
||||
|
||||
MINTING_ENABLED = Чеканка активна
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION = Часы компьютера неточны!
|
||||
|
||||
NTP_NAG_TEXT_UNIX = Установите службу NTP, чтобы получить точное время
|
||||
|
||||
NTP_NAG_TEXT_WINDOWS = Выберите "Синхронизация времени" из меню, чтобы исправить
|
||||
|
||||
OPEN_UI = Открыть пользовательский интерфейс
|
||||
|
||||
PERFORMING_DB_CHECKPOINT = Saving uncommitted database changes...
|
||||
|
||||
SYNCHRONIZE_CLOCK = Синхронизировать время
|
||||
|
||||
SYNCHRONIZING_BLOCKCHAIN = Синхронизация цепи
|
||||
|
||||
SYNCHRONIZING_CLOCK = Проверка времени
|
||||
SYNCHRONIZING_CLOCK = Проверка времени
|
||||
@@ -1,31 +1,40 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# SysTray pop-up menu
|
||||
|
||||
AUTO_UPDATE = Auto Update
|
||||
|
||||
APPLYING_UPDATE_AND_RESTARTING = Applying automatic update and restarting...
|
||||
|
||||
BLOCK_HEIGHT = 区块高度
|
||||
|
||||
BUILD_VERSION = Build version
|
||||
|
||||
CHECK_TIME_ACCURACY = 检查时间准确性
|
||||
|
||||
CONNECTING = Connecting
|
||||
|
||||
CONNECTION = 个链接
|
||||
|
||||
CONNECTIONS = 个链接
|
||||
|
||||
CREATING_BACKUP_OF_DB_FILES = Creating backup of database files...
|
||||
|
||||
DB_BACKUP = Database Backup
|
||||
|
||||
DB_CHECKPOINT = Database Checkpoint
|
||||
|
||||
EXIT = 退出核心
|
||||
|
||||
MINTING_DISABLED = 没有铸币
|
||||
|
||||
MINTING_ENABLED = ✔ 铸币
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION = 电脑的时间不准确!
|
||||
|
||||
NTP_NAG_TEXT_UNIX = 安装NTP服务以获取准确的时间。
|
||||
|
||||
NTP_NAG_TEXT_WINDOWS = 从菜单中选择“同步时钟”进行修复。
|
||||
|
||||
OPEN_UI = 开启Qortal界面
|
||||
|
||||
PERFORMING_DB_CHECKPOINT = Saving uncommitted database changes...
|
||||
|
||||
SYNCHRONIZE_CLOCK = 同步时钟
|
||||
|
||||
SYNCHRONIZING_BLOCKCHAIN = 正在同步区块链
|
||||
|
||||
SYNCHRONIZING_CLOCK = 正在同步时钟
|
||||
SYNCHRONIZING_CLOCK = 正在同步时钟
|
||||
@@ -1,31 +1,40 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
# SysTray pop-up menu
|
||||
|
||||
AUTO_UPDATE = Auto Update
|
||||
|
||||
APPLYING_UPDATE_AND_RESTARTING = Applying automatic update and restarting...
|
||||
|
||||
BLOCK_HEIGHT = 區塊高度
|
||||
|
||||
BUILD_VERSION = Build version
|
||||
|
||||
CHECK_TIME_ACCURACY = 檢查時間準確性
|
||||
|
||||
CONNECTING = Connecting
|
||||
|
||||
CONNECTION = 個鏈接
|
||||
|
||||
CONNECTIONS = 個鏈接
|
||||
|
||||
CREATING_BACKUP_OF_DB_FILES = Creating backup of database files...
|
||||
|
||||
DB_BACKUP = Database Backup
|
||||
|
||||
DB_CHECKPOINT = Database Checkpoint
|
||||
|
||||
EXIT = 退出核心
|
||||
|
||||
MINTING_DISABLED = 沒有鑄幣
|
||||
|
||||
MINTING_ENABLED = ✔ 鑄幣
|
||||
|
||||
# Nagging about lack of NTP time sync
|
||||
NTP_NAG_CAPTION = 電腦的時間不準確!
|
||||
|
||||
NTP_NAG_TEXT_UNIX = 安装NTP服務以獲取準確的時間。
|
||||
|
||||
NTP_NAG_TEXT_WINDOWS = 從菜單中選擇“同步時鐘”進行修復。
|
||||
|
||||
OPEN_UI = 開啓Qortal界面
|
||||
|
||||
PERFORMING_DB_CHECKPOINT = Saving uncommitted database changes...
|
||||
|
||||
SYNCHRONIZE_CLOCK = 同步時鐘
|
||||
|
||||
SYNCHRONIZING_BLOCKCHAIN = 正在同步區塊鏈
|
||||
|
||||
SYNCHRONIZING_CLOCK = 正在同步時鐘
|
||||
SYNCHRONIZING_CLOCK = 正在同步時鐘
|
||||
@@ -1,161 +1,44 @@
|
||||
|
||||
ACCOUNT_ALREADY_EXISTS = account already exists
|
||||
|
||||
ACCOUNT_CANNOT_REWARD_SHARE = account cannot reward-share
|
||||
|
||||
ALREADY_GROUP_ADMIN = already group admin
|
||||
|
||||
ALREADY_GROUP_MEMBER = already group member
|
||||
|
||||
ALREADY_VOTED_FOR_THAT_OPTION = already voted for that option
|
||||
|
||||
ASSET_ALREADY_EXISTS = asset already exists
|
||||
|
||||
ASSET_DOES_NOT_EXIST = asset does not exist
|
||||
|
||||
ASSET_DOES_NOT_MATCH_AT = asset does not match AT's asset
|
||||
|
||||
ASSET_NOT_SPENDABLE = asset is not spendable
|
||||
|
||||
AT_ALREADY_EXISTS = AT already exists
|
||||
|
||||
AT_IS_FINISHED = AT has finished
|
||||
|
||||
AT_UNKNOWN = AT unknown
|
||||
|
||||
BANNED_FROM_GROUP = banned from group
|
||||
|
||||
BAN_EXISTS = ban already exists
|
||||
|
||||
BAN_UNKNOWN = ban unknown
|
||||
|
||||
BUYER_ALREADY_OWNER = buyer is already owner
|
||||
|
||||
CHAT = CHAT transactions are never valid for inclusion into blocks
|
||||
|
||||
CLOCK_NOT_SYNCED = clock not synchronized
|
||||
|
||||
DUPLICATE_OPTION = duplicate option
|
||||
|
||||
GROUP_ALREADY_EXISTS = group already exists
|
||||
|
||||
GROUP_APPROVAL_DECIDED = group-approval already decided
|
||||
|
||||
GROUP_APPROVAL_NOT_REQUIRED = group-approval not required
|
||||
|
||||
GROUP_DOES_NOT_EXIST = group does not exist
|
||||
|
||||
GROUP_ID_MISMATCH = group ID mismatch
|
||||
|
||||
GROUP_OWNER_CANNOT_LEAVE = group owner cannot leave group
|
||||
|
||||
HAVE_EQUALS_WANT = have-asset is the same as want-asset
|
||||
|
||||
INCORRECT_NONCE = incorrect PoW nonce
|
||||
|
||||
INSUFFICIENT_FEE = insufficient fee
|
||||
OK = OK
|
||||
|
||||
INVALID_ADDRESS = invalid address
|
||||
|
||||
INVALID_AMOUNT = invalid amount
|
||||
|
||||
INVALID_ASSET_OWNER = invalid asset owner
|
||||
|
||||
INVALID_AT_TRANSACTION = invalid AT transaction
|
||||
|
||||
INVALID_AT_TYPE_LENGTH = invalid AT 'type' length
|
||||
|
||||
INVALID_CREATION_BYTES = invalid creation bytes
|
||||
|
||||
INVALID_DATA_LENGTH = invalid data length
|
||||
|
||||
INVALID_DESCRIPTION_LENGTH = invalid description length
|
||||
|
||||
INVALID_GROUP_APPROVAL_THRESHOLD = invalid group-approval threshold
|
||||
|
||||
INVALID_GROUP_BLOCK_DELAY = invalid group-approval block delay
|
||||
|
||||
INVALID_GROUP_ID = invalid group ID
|
||||
|
||||
INVALID_GROUP_OWNER = invalid group owner
|
||||
|
||||
INVALID_LIFETIME = invalid lifetime
|
||||
|
||||
INVALID_NAME_LENGTH = invalid name length
|
||||
|
||||
INVALID_NAME_OWNER = invalid name owner
|
||||
|
||||
INVALID_OPTIONS_COUNT = invalid options count
|
||||
|
||||
INVALID_OPTION_LENGTH = invalid options length
|
||||
|
||||
INVALID_ORDER_CREATOR = invalid order creator
|
||||
|
||||
INVALID_PAYMENTS_COUNT = invalid payments count
|
||||
|
||||
INVALID_PUBLIC_KEY = invalid public key
|
||||
|
||||
INVALID_QUANTITY = invalid quantity
|
||||
|
||||
INVALID_REFERENCE = invalid reference
|
||||
|
||||
INVALID_RETURN = invalid return
|
||||
|
||||
INVALID_REWARD_SHARE_PERCENT = invalid reward-share percent
|
||||
|
||||
INVALID_SELLER = invalid seller
|
||||
|
||||
INVALID_TAGS_LENGTH = invalid 'tags' length
|
||||
|
||||
INVALID_TX_GROUP_ID = invalid transaction group ID
|
||||
|
||||
INVALID_VALUE_LENGTH = invalid 'value' length
|
||||
|
||||
INVITE_UNKNOWN = group invite unknown
|
||||
|
||||
JOIN_REQUEST_EXISTS = group join request already exists
|
||||
|
||||
MAXIMUM_REWARD_SHARES = already at maximum number of reward-shares for this account
|
||||
|
||||
MISSING_CREATOR = missing creator
|
||||
|
||||
MULTIPLE_NAMES_FORBIDDEN = multiple registered names per account is forbidden
|
||||
|
||||
NAME_ALREADY_FOR_SALE = name already for sale
|
||||
|
||||
NAME_ALREADY_REGISTERED = name already registered
|
||||
|
||||
NAME_DOES_NOT_EXIST = name does not exist
|
||||
|
||||
NAME_NOT_FOR_SALE = name is not for sale
|
||||
|
||||
NAME_NOT_NORMALIZED = name not in Unicode 'normalized' form
|
||||
|
||||
NEGATIVE_AMOUNT = invalid/negative amount
|
||||
|
||||
NEGATIVE_FEE = invalid/negative fee
|
||||
|
||||
NEGATIVE_PRICE = invalid/negative price
|
||||
|
||||
NOT_GROUP_ADMIN = account is not a group admin
|
||||
|
||||
NOT_GROUP_MEMBER = account is not a group member
|
||||
|
||||
NOT_MINTING_ACCOUNT = account cannot mint
|
||||
|
||||
NOT_YET_RELEASED = feature not yet released
|
||||
|
||||
NO_BALANCE = insufficient balance
|
||||
|
||||
NO_BLOCKCHAIN_LOCK = node's blockchain currently busy
|
||||
INVALID_REFERENCE = invalid reference
|
||||
|
||||
NO_FLAG_PERMISSION = account does not have that permission
|
||||
INVALID_NAME_LENGTH = invalid name length
|
||||
|
||||
OK = OK
|
||||
INVALID_VALUE_LENGTH = invalid 'value' length
|
||||
|
||||
ORDER_ALREADY_CLOSED = asset trade order is already closed
|
||||
NAME_ALREADY_REGISTERED = name already registered
|
||||
|
||||
ORDER_DOES_NOT_EXIST = asset trade order does not exist
|
||||
NAME_DOES_NOT_EXIST = name does not exist
|
||||
|
||||
INVALID_NAME_OWNER = invalid name owner
|
||||
|
||||
NAME_ALREADY_FOR_SALE = name already for sale
|
||||
|
||||
NAME_NOT_FOR_SALE = name is not for sale
|
||||
|
||||
BUYER_ALREADY_OWNER = buyer is already owner
|
||||
|
||||
INVALID_AMOUNT = invalid amount
|
||||
|
||||
INVALID_SELLER = invalid seller
|
||||
|
||||
NAME_NOT_NORMALIZED = name not in Unicode 'normalized' form
|
||||
|
||||
INVALID_DESCRIPTION_LENGTH = invalid description length
|
||||
|
||||
INVALID_OPTIONS_COUNT = invalid options count
|
||||
|
||||
INVALID_OPTION_LENGTH = invalid options length
|
||||
|
||||
DUPLICATE_OPTION = duplicate option
|
||||
|
||||
POLL_ALREADY_EXISTS = poll already exists
|
||||
|
||||
@@ -163,22 +46,146 @@ POLL_DOES_NOT_EXIST = poll does not exist
|
||||
|
||||
POLL_OPTION_DOES_NOT_EXIST = poll option does not exist
|
||||
|
||||
PUBLIC_KEY_UNKNOWN = public key unknown
|
||||
ALREADY_VOTED_FOR_THAT_OPTION = already voted for that option
|
||||
|
||||
REWARD_SHARE_UNKNOWN = reward-share unknown
|
||||
INVALID_DATA_LENGTH = invalid data length
|
||||
|
||||
SELF_SHARE_EXISTS = self-share (reward-share) already exists
|
||||
INVALID_QUANTITY = invalid quantity
|
||||
|
||||
TIMESTAMP_TOO_NEW = timestamp too new
|
||||
ASSET_DOES_NOT_EXIST = asset does not exist
|
||||
|
||||
INVALID_RETURN = invalid return
|
||||
|
||||
HAVE_EQUALS_WANT = have-asset is the same as want-asset
|
||||
|
||||
ORDER_DOES_NOT_EXIST = asset trade order does not exist
|
||||
|
||||
INVALID_ORDER_CREATOR = invalid order creator
|
||||
|
||||
INVALID_PAYMENTS_COUNT = invalid payments count
|
||||
|
||||
NEGATIVE_PRICE = invalid/negative price
|
||||
|
||||
INVALID_CREATION_BYTES = invalid creation bytes
|
||||
|
||||
INVALID_TAGS_LENGTH = invalid 'tags' length
|
||||
|
||||
INVALID_AT_TYPE_LENGTH = invalid AT 'type' length
|
||||
|
||||
INVALID_AT_TRANSACTION = invalid AT transaction
|
||||
|
||||
INSUFFICIENT_FEE = insufficient fee
|
||||
|
||||
ASSET_DOES_NOT_MATCH_AT = asset does not match AT's asset
|
||||
|
||||
ASSET_ALREADY_EXISTS = asset already exists
|
||||
|
||||
MISSING_CREATOR = missing creator
|
||||
|
||||
TIMESTAMP_TOO_OLD = timestamp too old
|
||||
|
||||
TIMESTAMP_TOO_NEW = timestamp too new
|
||||
|
||||
TOO_MANY_UNCONFIRMED = account has too many unconfirmed transactions pending
|
||||
|
||||
TRANSACTION_ALREADY_CONFIRMED = transaction has already confirmed
|
||||
GROUP_ALREADY_EXISTS = group already exists
|
||||
|
||||
TRANSACTION_ALREADY_EXISTS = transaction already exists
|
||||
GROUP_DOES_NOT_EXIST = group does not exist
|
||||
|
||||
INVALID_GROUP_OWNER = invalid group owner
|
||||
|
||||
ALREADY_GROUP_MEMBER = already group member
|
||||
|
||||
GROUP_OWNER_CANNOT_LEAVE = group owner cannot leave group
|
||||
|
||||
NOT_GROUP_MEMBER = account is not a group member
|
||||
|
||||
ALREADY_GROUP_ADMIN = already group admin
|
||||
|
||||
NOT_GROUP_ADMIN = account is not a group admin
|
||||
|
||||
INVALID_LIFETIME = invalid lifetime
|
||||
|
||||
INVITE_UNKNOWN = group invite unknown
|
||||
|
||||
BAN_EXISTS = ban already exists
|
||||
|
||||
BAN_UNKNOWN = ban unknown
|
||||
|
||||
BANNED_FROM_GROUP = banned from group
|
||||
|
||||
JOIN_REQUEST_EXISTS = group join request already exists
|
||||
|
||||
INVALID_GROUP_APPROVAL_THRESHOLD = invalid group-approval threshold
|
||||
|
||||
GROUP_ID_MISMATCH = group ID mismatch
|
||||
|
||||
INVALID_GROUP_ID = invalid group ID
|
||||
|
||||
TRANSACTION_UNKNOWN = transaction unknown
|
||||
|
||||
TRANSACTION_ALREADY_CONFIRMED = transaction has already confirmed
|
||||
|
||||
INVALID_TX_GROUP_ID = invalid transaction group ID
|
||||
|
||||
TX_GROUP_ID_MISMATCH = transaction's group ID does not match
|
||||
|
||||
MULTIPLE_NAMES_FORBIDDEN = multiple registered names per account is forbidden
|
||||
|
||||
INVALID_ASSET_OWNER = invalid asset owner
|
||||
|
||||
AT_IS_FINISHED = AT has finished
|
||||
|
||||
NO_FLAG_PERMISSION = account does not have that permission
|
||||
|
||||
NOT_MINTING_ACCOUNT = account cannot mint
|
||||
|
||||
REWARD_SHARE_UNKNOWN = reward-share unknown
|
||||
|
||||
INVALID_REWARD_SHARE_PERCENT = invalid reward-share percent
|
||||
|
||||
PUBLIC_KEY_UNKNOWN = public key unknown
|
||||
|
||||
INVALID_PUBLIC_KEY = invalid public key
|
||||
|
||||
AT_UNKNOWN = AT unknown
|
||||
|
||||
AT_ALREADY_EXISTS = AT already exists
|
||||
|
||||
GROUP_APPROVAL_NOT_REQUIRED = group-approval not required
|
||||
|
||||
GROUP_APPROVAL_DECIDED = group-approval already decided
|
||||
|
||||
MAXIMUM_REWARD_SHARES = already at maximum number of reward-shares for this account
|
||||
|
||||
TRANSACTION_ALREADY_EXISTS = transaction already exists
|
||||
|
||||
NO_BLOCKCHAIN_LOCK = node's blockchain currently busy
|
||||
|
||||
ORDER_ALREADY_CLOSED = asset trade order is already closed
|
||||
|
||||
CLOCK_NOT_SYNCED = clock not synchronized
|
||||
|
||||
ASSET_NOT_SPENDABLE = asset is not spendable
|
||||
|
||||
ACCOUNT_CANNOT_REWARD_SHARE = account cannot reward-share
|
||||
|
||||
SELF_SHARE_EXISTS = self-share (reward-share) already exists
|
||||
|
||||
ACCOUNT_ALREADY_EXISTS = account already exists
|
||||
|
||||
INVALID_GROUP_BLOCK_DELAY = invalid group-approval block delay
|
||||
|
||||
INCORRECT_NONCE = incorrect PoW nonce
|
||||
|
||||
INVALID_TIMESTAMP_SIGNATURE = invalid timestamp signature
|
||||
|
||||
ADDRESS_IN_BLACKLIST = this address is in your blacklist
|
||||
|
||||
ADDRESS_ABOVE_RATE_LIMIT = address reached specified rate limit
|
||||
|
||||
DUPLICATE_MESSAGE = address sent duplicate message
|
||||
|
||||
INVALID_BUT_OK = invalid but OK
|
||||
|
||||
NOT_YET_RELEASED = feature not yet released
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
ACCOUNT_ALREADY_EXISTS = tili on jo olemassa
|
||||
|
||||
ACCOUNT_CANNOT_REWARD_SHARE = tili ei voi palkinto-jakaa
|
||||
@@ -31,8 +30,6 @@ BAN_UNKNOWN = tuntematon eväys
|
||||
|
||||
BUYER_ALREADY_OWNER = ostaja on jo omistaja
|
||||
|
||||
CHAT = CHATin transaktiot eivät koskaan ole kelvollisia sisällytettäväksi lohkoihin
|
||||
|
||||
CLOCK_NOT_SYNCED = kello on synkronisoimatta
|
||||
|
||||
DUPLICATE_OPTION = kahdennettu valinta
|
||||
@@ -182,3 +179,13 @@ TRANSACTION_ALREADY_EXISTS = transaktio on jo olemassa
|
||||
TRANSACTION_UNKNOWN = tuntematon transaktio
|
||||
|
||||
TX_GROUP_ID_MISMATCH = transaktion ryhmä-ID:n vastaavuusvirhe
|
||||
|
||||
ADDRESS_IN_BLACKLIST = this address is in your blacklist
|
||||
|
||||
ADDRESS_ABOVE_RATE_LIMIT = address reached specified rate limit
|
||||
|
||||
DUPLICATE_MESSAGE = address sent duplicate message
|
||||
|
||||
INVALID_TIMESTAMP_SIGNATURE = Invalid timestamp signature
|
||||
|
||||
INVALID_BUT_OK = Invalid but OK
|
||||
193
src/main/resources/i18n/TransactionValidity_hu.properties
Normal file
193
src/main/resources/i18n/TransactionValidity_hu.properties
Normal file
@@ -0,0 +1,193 @@
|
||||
# Magyar myelvre forditotta: Szkíta (Scythian). 2021 Augusztus 7.
|
||||
|
||||
OK = OK
|
||||
|
||||
INVALID_ADDRESS = érvénytelen név vagy cím
|
||||
|
||||
NEGATIVE_AMOUNT = negatív összeg
|
||||
|
||||
NEGATIVE_FEE = érvénytelen/negatív tranzakciós díj
|
||||
|
||||
NO_BALANCE = elégtelen egyenleg
|
||||
|
||||
INVALID_REFERENCE = érvénytelen hivatkozás
|
||||
|
||||
INVALID_NAME_LENGTH = érvénytelen névhossz
|
||||
|
||||
INVALID_VALUE_LENGTH = érvénytelen értékhossz
|
||||
|
||||
NAME_ALREADY_REGISTERED = ez a név már regisztrált
|
||||
|
||||
NAME_DOES_NOT_EXIST = ez a név nem létezik
|
||||
|
||||
INVALID_NAME_OWNER = érvénytelen név tulajdonos
|
||||
|
||||
NAME_ALREADY_FOR_SALE = ez a név már eladó
|
||||
|
||||
NAME_NOT_FOR_SALE = ez a név nem eladó
|
||||
|
||||
BUYER_ALREADY_OWNER = ez a vevő már a tulajdonos
|
||||
|
||||
INVALID_AMOUNT = érvénytelen összeg
|
||||
|
||||
INVALID_SELLER = érvénytelen eladó
|
||||
|
||||
NAME_NOT_NORMALIZED = ez a név nincs "normalizált" Unicode formátumban
|
||||
|
||||
INVALID_DESCRIPTION_LENGTH = érvénytelen leíráshossz
|
||||
|
||||
INVALID_OPTIONS_COUNT = invalid options count
|
||||
|
||||
INVALID_OPTION_LENGTH = érvénytelen opciókszám
|
||||
|
||||
DUPLICATE_OPTION = ez a lehetőség már létezik
|
||||
|
||||
POLL_ALREADY_EXISTS = ez a szavazás már létezik
|
||||
|
||||
POLL_DOES_NOT_EXIST = ez a szavazás nem létezik
|
||||
|
||||
POLL_OPTION_DOES_NOT_EXIST = ez a szavazási lehetőség nem létezik
|
||||
|
||||
ALREADY_VOTED_FOR_THAT_OPTION = erre a lehetőségre már szavaztál
|
||||
|
||||
INVALID_DATA_LENGTH = érvénytelen adathossz
|
||||
|
||||
INVALID_QUANTITY = érvénytelen mennyiség
|
||||
|
||||
ASSET_DOES_NOT_EXIST = tőke nem létezik
|
||||
|
||||
INVALID_RETURN = érvénytelen csere tőke
|
||||
|
||||
HAVE_EQUALS_WANT = saját tőke egyenlő a csere tőkével
|
||||
|
||||
ORDER_DOES_NOT_EXIST = tőke rendelés nem létezik
|
||||
|
||||
INVALID_ORDER_CREATOR = érvénytelen rendelés létrehozó
|
||||
|
||||
INVALID_PAYMENTS_COUNT = a kifizetések száma érvénytelen
|
||||
|
||||
NEGATIVE_PRICE = érvénytelen/negatív ár
|
||||
|
||||
INVALID_CREATION_BYTES = érvénytelen létrehozási bájtok
|
||||
|
||||
INVALID_TAGS_LENGTH = érvénytelen cimkehossz
|
||||
|
||||
INVALID_AT_TYPE_LENGTH = érvénytelen AT "típus" hossz
|
||||
|
||||
INVALID_AT_TRANSACTION = érvénytelen AT tranzakció
|
||||
|
||||
INSUFFICIENT_FEE = elégtelen díj
|
||||
|
||||
ASSET_DOES_NOT_MATCH_AT = a tőke nem egyezik az AT tőkéjével
|
||||
|
||||
ASSET_ALREADY_EXISTS = ez a tőke már létezik
|
||||
|
||||
MISSING_CREATOR = hiányzó létrehozó
|
||||
|
||||
TIMESTAMP_TOO_OLD = időbélyeg túl régi
|
||||
|
||||
TIMESTAMP_TOO_NEW = időbélyeg túl korai
|
||||
|
||||
TOO_MANY_UNCONFIRMED = ennek a fióknak túl sok meg nem erősített tranzakciója van folyamatban
|
||||
|
||||
GROUP_ALREADY_EXISTS = ez a csoport már létezik
|
||||
|
||||
GROUP_DOES_NOT_EXIST = ez a csoport nem létezik
|
||||
|
||||
INVALID_GROUP_OWNER = érvénytelen csoport tulajdonos
|
||||
|
||||
ALREADY_GROUP_MEMBER = már csoporttag
|
||||
|
||||
GROUP_OWNER_CANNOT_LEAVE = a csoport tulajdonos nem tudja elhagyni a csoportot
|
||||
|
||||
NOT_GROUP_MEMBER = ez a tag nem csoporttag
|
||||
|
||||
ALREADY_GROUP_ADMIN = már csoport adminisztrátor
|
||||
|
||||
NOT_GROUP_ADMIN = ez a tag nem csoport adminisztrátor
|
||||
|
||||
INVALID_LIFETIME = érvénytelen élettartam
|
||||
|
||||
INVITE_UNKNOWN = ismeretlen csoport meghívás
|
||||
|
||||
BAN_EXISTS = már ki van tiltva
|
||||
|
||||
BAN_UNKNOWN = kitiltás nem létezik
|
||||
|
||||
BANNED_FROM_GROUP = ki van tiltva a csoportból
|
||||
|
||||
JOIN_REQUEST_EXISTS = a csoporthoz való csatlakozási kérelem már megtöretént
|
||||
|
||||
INVALID_GROUP_APPROVAL_THRESHOLD = érvénytelen jóváhagyási küszöbérték
|
||||
|
||||
GROUP_ID_MISMATCH = csoportazonosító nem egyezik
|
||||
|
||||
INVALID_GROUP_ID = csoportazonosító érvénytelen
|
||||
|
||||
TRANSACTION_UNKNOWN = ismeretlen tranzakció
|
||||
|
||||
TRANSACTION_ALREADY_CONFIRMED = ez a tranzakció már meg van erősítve
|
||||
|
||||
INVALID_TX_GROUP_ID = a tranzakció csoportazonosítója érvénytelen
|
||||
|
||||
TX_GROUP_ID_MISMATCH = a tranzakció csoportazonosítója nem egyezik
|
||||
|
||||
MULTIPLE_NAMES_FORBIDDEN = fiókonként több név regisztrálása tilos
|
||||
|
||||
INVALID_ASSET_OWNER = érvénytelen tőke tulajdonos
|
||||
|
||||
AT_IS_FINISHED = az AT végzett
|
||||
|
||||
NO_FLAG_PERMISSION = ez a fiók nem rendelkezik ezzel az engedéllyel
|
||||
|
||||
NOT_MINTING_ACCOUNT = ez a fiók nem tud QORT-ot verni
|
||||
|
||||
REWARD_SHARE_UNKNOWN = ez a jutalék-megosztás ismeretlen
|
||||
|
||||
INVALID_REWARD_SHARE_PERCENT = ez a jutalék-megosztási arány érvénytelen
|
||||
|
||||
PUBLIC_KEY_UNKNOWN = ismeretlen nyilvános kulcs
|
||||
|
||||
INVALID_PUBLIC_KEY = érvénytelen nyilvános kulcs
|
||||
|
||||
AT_UNKNOWN = az AT ismeretlen
|
||||
|
||||
AT_ALREADY_EXISTS = az AT már létezik
|
||||
|
||||
GROUP_APPROVAL_NOT_REQUIRED = csoport általi jóváhagyás nem szükséges
|
||||
|
||||
GROUP_APPROVAL_DECIDED = csoport általi jóváhagyás el van döntve
|
||||
|
||||
MAXIMUM_REWARD_SHARES = ez a fiókcím már elérte a maximális lehetséges jutalék-megosztási részesedést
|
||||
|
||||
TRANSACTION_ALREADY_EXISTS = ez a tranzakció már létezik
|
||||
|
||||
NO_BLOCKCHAIN_LOCK = csomópont blokklánca jelenleg elfoglalt
|
||||
|
||||
ORDER_ALREADY_CLOSED = ez a tőke értékesítés már befejeződött
|
||||
|
||||
CLOCK_NOT_SYNCED = az óra nincs szinkronizálva
|
||||
|
||||
ASSET_NOT_SPENDABLE = ez a tőke nem értékesíthető
|
||||
|
||||
ACCOUNT_CANNOT_REWARD_SHARE = ez a fiók nem vehet részt jutalék-megosztásban
|
||||
|
||||
SELF_SHARE_EXISTS = önrészes jutalék-megosztás már létezik
|
||||
|
||||
ACCOUNT_ALREADY_EXISTS = ez a fiók már létezik
|
||||
|
||||
INVALID_GROUP_BLOCK_DELAY = invalid group-approval block delay
|
||||
|
||||
INCORRECT_NONCE = helytelen Proof-of-Work Nonce
|
||||
|
||||
INVALID_TIMESTAMP_SIGNATURE = érvénytelen időbélyeg aláírás
|
||||
|
||||
ADDRESS_IN_BLACKLIST = ez a fiókcím a fekete listádon van
|
||||
|
||||
ADDRESS_ABOVE_RATE_LIMIT = ez a cím elérte a megengedett mérték korlátot
|
||||
|
||||
DUPLICATE_MESSAGE = ez a cím duplikált üzenetet küldött
|
||||
|
||||
INVALID_BUT_OK = érvénytelen de elfogadva
|
||||
|
||||
NOT_YET_RELEASED = ez a funkció még nem került kiadásra
|
||||
@@ -32,8 +32,6 @@ BAN_UNKNOWN = divieto sconosciuto
|
||||
|
||||
BUYER_ALREADY_OWNER = l'acquirente è già proprietario
|
||||
|
||||
CHAT = Le transazioni CHAT non sono mai valide per l'inclusione nei blocchi
|
||||
|
||||
CLOCK_NOT_SYNCED = orologio non sincronizzato
|
||||
|
||||
DUPLICATE_OPTION = opzione duplicata
|
||||
@@ -183,3 +181,13 @@ TRANSACTION_ALREADY_EXISTS = la transazione già esiste
|
||||
TRANSACTION_UNKNOWN = transazione sconosciuta
|
||||
|
||||
TX_GROUP_ID_MISMATCH = identificazione di gruppo della transazione non corrisponde
|
||||
|
||||
ADDRESS_IN_BLACKLIST = this address is in your blacklist
|
||||
|
||||
ADDRESS_ABOVE_RATE_LIMIT = address reached specified rate limit
|
||||
|
||||
DUPLICATE_MESSAGE = address sent duplicate message
|
||||
|
||||
INVALID_TIMESTAMP_SIGNATURE = Invalid timestamp signature
|
||||
|
||||
INVALID_BUT_OK = Invalid but OK
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
ACCOUNT_ALREADY_EXISTS = account bestaat al
|
||||
|
||||
ACCOUNT_CANNOT_REWARD_SHARE = account kan geen beloningen delen
|
||||
@@ -31,8 +30,6 @@ BAN_UNKNOWN = ban onbekend
|
||||
|
||||
BUYER_ALREADY_OWNER = koper is al eigenaar
|
||||
|
||||
CHAT = CHAT transacties zijn nooit geldig voor opname in blokken
|
||||
|
||||
CLOCK_NOT_SYNCED = klok is niet gesynchronizeerd
|
||||
|
||||
DUPLICATE_OPTION = dubbele optie
|
||||
@@ -182,3 +179,13 @@ TRANSACTION_ALREADY_EXISTS = transactie bestaat al
|
||||
TRANSACTION_UNKNOWN = transactie onbekend
|
||||
|
||||
TX_GROUP_ID_MISMATCH = groep-ID van transactie matcht niet
|
||||
|
||||
ADDRESS_IN_BLACKLIST = this address is in your blacklist
|
||||
|
||||
ADDRESS_ABOVE_RATE_LIMIT = address reached specified rate limit
|
||||
|
||||
DUPLICATE_MESSAGE = address sent duplicate message
|
||||
|
||||
INVALID_TIMESTAMP_SIGNATURE = Invalid timestamp signature
|
||||
|
||||
INVALID_BUT_OK = Invalid but OK
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
ACCOUNT_ALREADY_EXISTS = аккаунт уже существует
|
||||
|
||||
ACCOUNT_CANNOT_REWARD_SHARE = аккаунт не может делиться вознаграждением
|
||||
@@ -174,3 +173,13 @@ TRANSACTION_ALREADY_EXISTS = транзакция существует
|
||||
TRANSACTION_UNKNOWN = неизвестная транзакция
|
||||
|
||||
TX_GROUP_ID_MISMATCH = не соответствие идентификатора группы c хэш транзации
|
||||
|
||||
ADDRESS_IN_BLACKLIST = this address is in your blacklist
|
||||
|
||||
ADDRESS_ABOVE_RATE_LIMIT = address reached specified rate limit
|
||||
|
||||
DUPLICATE_MESSAGE = address sent duplicate message
|
||||
|
||||
INVALID_TIMESTAMP_SIGNATURE = Invalid timestamp signature
|
||||
|
||||
INVALID_BUT_OK = Invalid but OK
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 187 KiB |
@@ -14,9 +14,9 @@ public class CheckTranslations {
|
||||
|
||||
private static final String[] SUPPORTED_LANGS = new String[] { "en", "de", "zh", "ru" };
|
||||
private static final Set<String> SYSTRAY_KEYS = Set.of("AUTO_UPDATE", "APPLYING_UPDATE_AND_RESTARTING", "BLOCK_HEIGHT",
|
||||
"CHECK_TIME_ACCURACY", "CONNECTING", "CONNECTION", "CONNECTIONS", "CREATING_BACKUP_OF_DB_FILES", "DB_BACKUP", "EXIT",
|
||||
"MINTING_DISABLED", "MINTING_ENABLED", "NTP_NAG_CAPTION", "NTP_NAG_TEXT_UNIX", "NTP_NAG_TEXT_WINDOWS",
|
||||
"OPEN_UI", "SYNCHRONIZE_CLOCK", "SYNCHRONIZING_BLOCKCHAIN", "SYNCHRONIZING_CLOCK");
|
||||
"BUILD_VERSION", "CHECK_TIME_ACCURACY", "CONNECTING", "CONNECTION", "CONNECTIONS", "CREATING_BACKUP_OF_DB_FILES",
|
||||
"DB_BACKUP", "DB_CHECKPOINT", "EXIT", "MINTING_DISABLED", "MINTING_ENABLED", "OPEN_UI", "PERFORMING_DB_CHECKPOINT",
|
||||
"SYNCHRONIZE_CLOCK", "SYNCHRONIZING_BLOCKCHAIN", "SYNCHRONIZING_CLOCK");
|
||||
|
||||
private static String failurePrefix;
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public class AtRepositoryTests extends Common {
|
||||
Integer testHeight = maxHeight - 2;
|
||||
|
||||
// Trim AT state data
|
||||
repository.getATRepository().prepareForAtStateTrimming();
|
||||
repository.getATRepository().rebuildLatestAtStates();
|
||||
repository.getATRepository().trimAtStates(2, maxHeight, 1000);
|
||||
|
||||
ATStateData atStateData = repository.getATRepository().getATStateAtHeight(atAddress, testHeight);
|
||||
@@ -129,7 +129,7 @@ public class AtRepositoryTests extends Common {
|
||||
Integer testHeight = blockchainHeight;
|
||||
|
||||
// Trim AT state data
|
||||
repository.getATRepository().prepareForAtStateTrimming();
|
||||
repository.getATRepository().rebuildLatestAtStates();
|
||||
// COMMIT to check latest AT states persist / TEMPORARY table interaction
|
||||
repository.saveChanges();
|
||||
|
||||
@@ -280,7 +280,7 @@ public class AtRepositoryTests extends Common {
|
||||
Integer testHeight = maxHeight - 2;
|
||||
|
||||
// Trim AT state data
|
||||
repository.getATRepository().prepareForAtStateTrimming();
|
||||
repository.getATRepository().rebuildLatestAtStates();
|
||||
repository.getATRepository().trimAtStates(2, maxHeight, 1000);
|
||||
|
||||
List<ATStateData> atStates = repository.getATRepository().getBlockATStatesAtHeight(testHeight);
|
||||
|
||||
Reference in New Issue
Block a user