Fix wrong penaties

This will set incorrectly penalized accounts from previous algo run back to previous state.
This commit is contained in:
AlphaX-Projects
2024-01-30 17:36:17 +01:00
parent 0ed27228b1
commit 2120490f4b
47 changed files with 5358 additions and 37 deletions

View File

@@ -2,7 +2,6 @@ package org.qortal.account;
import org.qortal.api.resource.TransactionsResource;
import org.qortal.asset.Asset;
import org.qortal.block.BlockChain;
import org.qortal.data.account.AccountData;
import org.qortal.data.naming.NameData;
import org.qortal.data.transaction.*;
@@ -27,7 +26,6 @@ public class SelfSponsorshipAlgoV1 {
private int consolidationCount = 0;
private int bulkIssuanceCount = 0;
private int recentSponsorshipCount = 0;
private int transferAssetsCount = 0;
private List<RewardShareTransactionData> sponsorshipRewardShares = new ArrayList<>();
private final Map<String, List<TransactionData>> paymentsByAddress = new HashMap<>();
@@ -35,7 +33,6 @@ public class SelfSponsorshipAlgoV1 {
private Set<String> consolidatedAddresses = new LinkedHashSet<>();
private final Set<String> zeroTransactionAddreses = new LinkedHashSet<>();
private final Set<String> penaltyAddresses = new LinkedHashSet<>();
private final Set<String> transferAssetsByAddress = new LinkedHashSet<>();
public SelfSponsorshipAlgoV1(Repository repository, String address, long snapshotTimestamp, boolean override) throws DataException {
this.repository = repository;
@@ -70,7 +67,6 @@ public class SelfSponsorshipAlgoV1 {
this.findBulkIssuance();
this.findRegisteredNameCount();
this.findRecentSponsorshipCount();
this.transferAssetsCount = this.transferAssetsByAddress.size();
int score = this.calculateScore();
if (score <= 0 && !override) {
@@ -225,9 +221,7 @@ public class SelfSponsorshipAlgoV1 {
}
private void findRecentSponsorshipCount() {
long snapshotTimestampBefore = BlockChain.getInstance().getSelfSponsorshipAlgoV1SnapshotTimestamp();
long diffTimeBetween = this.snapshotTimestamp - snapshotTimestampBefore;
final long referenceTimestamp = this.snapshotTimestamp - diffTimeBetween;
final long referenceTimestamp = this.snapshotTimestamp - (365 * 24 * 60 * 60 * 1000L);
int recentSponsorshipCount = 0;
for (RewardShareTransactionData rewardShare : sponsorshipRewardShares) {
if (rewardShare.getTimestamp() >= referenceTimestamp) {
@@ -238,13 +232,12 @@ public class SelfSponsorshipAlgoV1 {
}
private int calculateScore() {
final int transferAssetsMultiplier = (this.transferAssetsCount >= 5) ? 10 : 1;
final int suspiciousMultiplier = (this.suspiciousCount >= 100) ? this.suspiciousPercent : 1;
final int nameMultiplier = (this.sponsees.size() >= 50 && this.registeredNameCount == 0) ? 2 : 1;
final int consolidationMultiplier = Math.max(this.consolidationCount, 1);
final int bulkIssuanceMultiplier = Math.max(this.bulkIssuanceCount / 2, 1);
final int offset = 9;
return transferAssetsMultiplier * suspiciousMultiplier * nameMultiplier * consolidationMultiplier * bulkIssuanceMultiplier - offset;
return suspiciousMultiplier * nameMultiplier * consolidationMultiplier * bulkIssuanceMultiplier - offset;
}
private void fetchSponsorshipRewardShares() throws DataException {
@@ -329,7 +322,6 @@ public class SelfSponsorshipAlgoV1 {
if (!Objects.equals(transferAssetTransactionData.getRecipient(), address)) {
// Outgoing payment from this account
outgoingPaymentRecipients.add(transferAssetTransactionData.getRecipient());
this.transferAssetsByAddress.add(transferAssetTransactionData.getRecipient());
}
}
break;

View File

@@ -1553,9 +1553,14 @@ public class Block {
Block212937.processFix(this);
}
if (this.blockData.getHeight() == BlockChain.getInstance().getUnconfirmableRewardSharesHeight()) {
if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV1Height()) {
SelfSponsorshipAlgoV1Block.processAccountPenalties(this);
}
if (this.blockData.getHeight() == BlockChain.getInstance().getPenaltyFixHeight()) {
// Apply fix for penalties
PenaltyFix.processPenaltiesFix(this);
}
}
// We're about to (test-)process a batch of transactions,
@@ -1840,12 +1845,19 @@ public class Block {
// Invalidate expandedAccounts as they may have changed due to orphaning TRANSFER_PRIVS transactions, etc.
this.cachedExpandedAccounts = null;
if (this.blockData.getHeight() == 212937)
if (this.blockData.getHeight() == 212937) {
// Revert fix for block 212937
Block212937.orphanFix(this);
}
else if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV1Height())
if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV1Height()) {
SelfSponsorshipAlgoV1Block.orphanAccountPenalties(this);
}
if (this.blockData.getHeight() == BlockChain.getInstance().getPenaltyFixHeight()) {
// Revert fix for penalties
PenaltyFix.orphanPenaltiesFix(this);
}
// Account levels and block rewards are only processed/orphaned on block reward distribution blocks
if (this.isRewardDistributionBlock()) {

View File

@@ -73,10 +73,14 @@ public class BlockChain {
increaseOnlineAccountsDifficultyTimestamp,
onlineAccountMinterLevelValidationHeight,
selfSponsorshipAlgoV1Height,
selfSponsorshipAlgoV2Height,
feeValidationFixTimestamp,
chatReferenceTimestamp,
arbitraryOptionalFeeTimestamp,
unconfirmableRewardSharesHeight;
unconfirmableRewardSharesHeight,
disableTransferPrivsTimestamp,
enableTransferPrivsTimestamp,
penaltyFixHeight
}
// Custom transaction fees
@@ -199,6 +203,7 @@ public class BlockChain {
/** Minimum time to retain online account signatures (ms) for block validity checks. */
private long onlineAccountSignaturesMinLifetime;
/** Maximum time to retain online account signatures (ms) for block validity checks, to allow for clock variance. */
private long onlineAccountSignaturesMaxLifetime;
@@ -209,6 +214,9 @@ public class BlockChain {
/** Snapshot timestamp for self sponsorship algo V1 */
private long selfSponsorshipAlgoV1SnapshotTimestamp;
/** Snapshot timestamp for self sponsorship algo V2 */
private long selfSponsorshipAlgoV2SnapshotTimestamp;
/** Feature-trigger timestamp to modify behaviour of various transactions that support mempow */
private long mempowTransactionUpdatesTimestamp;
@@ -225,6 +233,8 @@ public class BlockChain {
* data and to base online accounts decisions on. */
private int blockRewardBatchAccountsBlockCount;
private String penaltyFixHash;
/** Max reward shares by block height */
public static class MaxRewardSharesByTimestamp {
public long timestamp;
@@ -267,7 +277,7 @@ public class BlockChain {
try {
// Create JAXB context aware of Settings
jc = JAXBContextFactory.createContext(new Class[] {
BlockChain.class, GenesisBlock.GenesisInfo.class
BlockChain.class, GenesisBlock.GenesisInfo.class
}, null);
// Create unmarshaller
@@ -395,12 +405,20 @@ public class BlockChain {
return this.blockRewardBatchAccountsBlockCount;
}
public String getPenaltyFixHash() {
return this.penaltyFixHash;
}
// Self sponsorship algo
// Self sponsorship algo V1
public long getSelfSponsorshipAlgoV1SnapshotTimestamp() {
return this.selfSponsorshipAlgoV1SnapshotTimestamp;
}
// Self sponsorship algo V2
public long getSelfSponsorshipAlgoV2SnapshotTimestamp() {
return this.selfSponsorshipAlgoV2SnapshotTimestamp;
}
// Feature-trigger timestamp to modify behaviour of various transactions that support mempow
public long getMemPoWTransactionUpdatesTimestamp() {
return this.mempowTransactionUpdatesTimestamp;
@@ -541,6 +559,10 @@ public class BlockChain {
return this.featureTriggers.get(FeatureTrigger.selfSponsorshipAlgoV1Height.name()).intValue();
}
public int getSelfSponsorshipAlgoV2Height() {
return this.featureTriggers.get(FeatureTrigger.selfSponsorshipAlgoV2Height.name()).intValue();
}
public long getOnlineAccountMinterLevelValidationHeight() {
return this.featureTriggers.get(FeatureTrigger.onlineAccountMinterLevelValidationHeight.name()).intValue();
}
@@ -561,6 +583,17 @@ public class BlockChain {
return this.featureTriggers.get(FeatureTrigger.unconfirmableRewardSharesHeight.name()).intValue();
}
public long getDisableTransferPrivsTimestamp() {
return this.featureTriggers.get(FeatureTrigger.disableTransferPrivsTimestamp.name()).longValue();
}
public long getEnableTransferPrivsTimestamp() {
return this.featureTriggers.get(FeatureTrigger.enableTransferPrivsTimestamp.name()).longValue();
}
public int getPenaltyFixHeight() {
return this.featureTriggers.get(FeatureTrigger.penaltyFixHeight.name()).intValue();
}
// More complex getters for aspects that change by height or timestamp
@@ -747,7 +780,7 @@ public class BlockChain {
/**
* Some sort of start-up/initialization/checking method.
*
*
* @throws SQLException
*/
public static void validate() throws DataException {

View File

@@ -0,0 +1,187 @@
package org.qortal.block;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
import org.qortal.api.model.AccountPenaltyStats;
import org.qortal.crypto.Crypto;
import org.qortal.data.account.AccountData;
import org.qortal.data.account.AccountPenaltyData;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
import org.qortal.utils.Base58;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
public final class PenaltyFix {
private static final Logger LOGGER = LogManager.getLogger(PenaltyFix.class);
private static final String PENALTY_FIX_SOURCE = "penalty-fix.json";
private static final String PENALTY_FIX_HASH = BlockChain.getInstance().getPenaltyFixHash();
private static final List<AccountPenaltyData> penalties = accountsPenaltyFix();
private PenaltyFix() {
/* Do not instantiate */
}
@SuppressWarnings("unchecked")
private static List<AccountPenaltyData> accountsPenaltyFix() {
Unmarshaller unmarshaller;
try {
// Create JAXB context aware of classes we need to unmarshal
JAXBContext pf = JAXBContextFactory.createContext(new Class[] {
AccountPenaltyData.class
}, null);
// Create unmarshaller
unmarshaller = pf.createUnmarshaller();
// Set the unmarshaller media type to JSON
unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
// Tell unmarshaller that there's no JSON root element in the JSON input
unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
} catch (JAXBException e) {
String message = "Failed to setup unmarshaller for penalty fix";
LOGGER.error(message, e);
throw new RuntimeException(message, e);
}
ClassLoader classLoader = BlockChain.class.getClassLoader();
InputStream pfIn = classLoader.getResourceAsStream(PENALTY_FIX_SOURCE);
StreamSource pfSource = new StreamSource(pfIn);
try {
// Attempt to unmarshal JSON stream to BlockChain config
return (List<AccountPenaltyData>) unmarshaller.unmarshal(pfSource, AccountPenaltyData.class).getValue();
} catch (UnmarshalException e) {
String message = "Failed to parse penalty fix";
LOGGER.error(message, e);
throw new RuntimeException(message, e);
} catch (JAXBException e) {
String message = "Unexpected JAXB issue while processing penalty fix";
LOGGER.error(message, e);
throw new RuntimeException(message, e);
}
}
public static void processPenaltiesFix(Block block) throws DataException {
// Create reverse penalties
List<AccountPenaltyData> reversePenalties = penalties.stream()
.map(penalty -> new AccountPenaltyData(penalty.getAddress(), 0 +5000000))
.collect(Collectors.toList());
Set<AccountPenaltyData> penaltiesFix = new HashSet<AccountPenaltyData>(reversePenalties);
final String PENALTY_FIX_HASH_VERIFY = getHash(penaltiesFix.stream().map(p -> p.getAddress()).collect(Collectors.toList()));
// Verify if we are on same penalty hash
if (PENALTY_FIX_HASH.equals(PENALTY_FIX_HASH_VERIFY)) {
LOGGER.info("Verify hash passed! Running process penalty fix - this will take a while...");
logPenaltyStats(block.repository);
long startTime = System.currentTimeMillis();
block.repository.getAccountRepository().updateBlocksMintedPenalties(penaltiesFix);
long totalTime = System.currentTimeMillis() - startTime;
LOGGER.info("{} penalty addresses processed. Total time taken: {} seconds", reversePenalties.size(), (int)(totalTime / 1000.0f));
logPenaltyStats(block.repository);
int updatedCount = updateAccountLevels(block.repository, penaltiesFix);
LOGGER.info("Account levels updated for {} penalty addresses", updatedCount);
} else {
LOGGER.info("Verify hash failed! Stopping process penalty fix!");
}
}
public static void orphanPenaltiesFix(Block block) throws DataException {
// Create inverse penalties
List<AccountPenaltyData> inversePenalties = penalties.stream()
.map(penalty -> new AccountPenaltyData(penalty.getAddress(), 0 -5000000))
.collect(Collectors.toList());
Set<AccountPenaltyData> penaltiesFix = new HashSet<AccountPenaltyData>(inversePenalties);
final String PENALTY_FIX_HASH_VERIFY = getHash(penaltiesFix.stream().map(p -> p.getAddress()).collect(Collectors.toList()));
// Verify if we are on same penalty hash
if (PENALTY_FIX_HASH.equals(PENALTY_FIX_HASH_VERIFY)) {
LOGGER.info("Verify hash passed! Running orphan penalty fix - this will take a while...");
logPenaltyStats(block.repository);
long startTime = System.currentTimeMillis();
block.repository.getAccountRepository().updateBlocksMintedPenalties(penaltiesFix);
long totalTime = System.currentTimeMillis() - startTime;
LOGGER.info("{} penalty addresses processed. Total time taken: {} seconds", inversePenalties.size(), (int)(totalTime / 1000.0f));
logPenaltyStats(block.repository);
int updatedCount = updateAccountLevels(block.repository, penaltiesFix);
LOGGER.info("Account levels updated for {} penalty addresses", updatedCount);
} else {
LOGGER.info("Verify hash failed! Stopping orphan penalty fix!");
}
}
private static int updateAccountLevels(Repository repository, Set<AccountPenaltyData> accountPenalties) throws DataException {
final List<Integer> cumulativeBlocksByLevel = BlockChain.getInstance().getCumulativeBlocksByLevel();
final int maximumLevel = cumulativeBlocksByLevel.size() - 1;
int updatedCount = 0;
for (AccountPenaltyData penaltyData : accountPenalties) {
AccountData accountData = repository.getAccountRepository().getAccount(penaltyData.getAddress());
final int effectiveBlocksMinted = accountData.getBlocksMinted() + accountData.getBlocksMintedAdjustment() + accountData.getBlocksMintedPenalty();
// Shortcut for penalties
if (effectiveBlocksMinted < 0) {
accountData.setLevel(0);
repository.getAccountRepository().setLevel(accountData);
updatedCount++;
LOGGER.trace(() -> String.format("Block minter %s dropped to level %d", accountData.getAddress(), accountData.getLevel()));
continue;
}
for (int newLevel = maximumLevel; newLevel >= 0; --newLevel) {
if (effectiveBlocksMinted >= cumulativeBlocksByLevel.get(newLevel)) {
accountData.setLevel(newLevel);
repository.getAccountRepository().setLevel(accountData);
updatedCount++;
LOGGER.trace(() -> String.format("Block minter %s increased to level %d", accountData.getAddress(), accountData.getLevel()));
break;
}
}
}
return updatedCount;
}
private static void logPenaltyStats(Repository repository) {
try {
LOGGER.info(getPenaltyStats(repository));
} catch (DataException e) {}
}
private static AccountPenaltyStats getPenaltyStats(Repository repository) throws DataException {
List<AccountData> accounts = repository.getAccountRepository().getPenaltyAccounts();
return AccountPenaltyStats.fromAccounts(accounts);
}
public static String getHash(List<String> penaltyAddresses) {
if (penaltyAddresses == null || penaltyAddresses.isEmpty()) {
return null;
}
Collections.sort(penaltyAddresses);
return Base58.encode(Crypto.digest(StringUtils.join(penaltyAddresses).getBytes(StandardCharsets.UTF_8)));
}
}

View File

@@ -28,7 +28,6 @@ public final class SelfSponsorshipAlgoV1Block {
private static final Logger LOGGER = LogManager.getLogger(SelfSponsorshipAlgoV1Block.class);
private SelfSponsorshipAlgoV1Block() {
/* Do not instantiate */
}
@@ -64,7 +63,7 @@ public final class SelfSponsorshipAlgoV1Block {
}
public static Set<AccountPenaltyData> getAccountPenalties(Repository repository, int penalty) throws DataException {
final long snapshotTimestamp = System.currentTimeMillis() - 10000;
final long snapshotTimestamp = BlockChain.getInstance().getSelfSponsorshipAlgoV1SnapshotTimestamp();
Set<AccountPenaltyData> penalties = new LinkedHashSet<>();
List<String> addresses = repository.getTransactionRepository().getConfirmedRewardShareCreatorsExcludingSelfShares();
for (String address : addresses) {
@@ -132,4 +131,5 @@ public final class SelfSponsorshipAlgoV1Block {
Collections.sort(penaltyAddresses);
return Base58.encode(Crypto.digest(StringUtils.join(penaltyAddresses).getBytes(StandardCharsets.UTF_8)));
}
}
}

View File

@@ -1047,6 +1047,11 @@ public class HSQLDBDatabaseUpdates {
stmt.execute("CREATE INDEX ArbitraryIdentifierIndex ON ArbitraryTransactions (identifier)");
break;
case 49:
// Update blocks minted penalty
stmt.execute("UPDATE Accounts SET blocks_minted_penalty = -5000000 WHERE blocks_minted_penalty < 0");
break;
default:
// nothing to do
return false;

View File

@@ -211,7 +211,7 @@ public class Settings {
public long recoveryModeTimeout = 9999999999999L;
/** Minimum peer version number required in order to sync with them */
private String minPeerVersion = "4.4.1";
private String minPeerVersion = "4.4.2";
/** Whether to allow connections with peers below minPeerVersion
* If true, we won't sync with them but they can still sync with us, and will show in the peers list
* If false, sync will be blocked both ways, and they will not appear in the peers list */

View File

@@ -183,12 +183,18 @@ public class RewardShareTransaction extends Transaction {
@Override
public boolean isConfirmableAtHeight(int height) {
final int min = BlockChain.getInstance().getPenaltyFixHeight() - 50;
final int max = BlockChain.getInstance().getPenaltyFixHeight() + 50;
if (height >= BlockChain.getInstance().getUnconfirmableRewardSharesHeight()) {
// Not confirmable in online accounts or distribution blocks
if (Block.isOnlineAccountsBlock(height) || Block.isBatchRewardDistributionBlock(height)) {
return false;
}
}
// Not confirmable on penalty fix
if (height > min && height < max) {
return false;
}
return true;
}

View File

@@ -246,6 +246,7 @@ public abstract class Transaction {
NAME_BLOCKED(97),
GROUP_APPROVAL_REQUIRED(98),
ACCOUNT_NOT_TRANSFERABLE(99),
TRANSFER_PRIVS_DISABLED(100),
INVALID_BUT_OK(999),
NOT_YET_RELEASED(1000),
NOT_SUPPORTED(1001);

View File

@@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.qortal.account.Account;
import org.qortal.asset.Asset;
import org.qortal.block.Block;
import org.qortal.block.BlockChain;
import org.qortal.crypto.Crypto;
import org.qortal.data.account.AccountData;
@@ -72,6 +73,13 @@ public class TransferPrivsTransaction extends Transaction {
if (senderAccountData == null || senderAccountData.getBlocksMintedPenalty() != 0)
return ValidationResult.ACCOUNT_NOT_TRANSFERABLE;
// Disable Transfer Privs (start - end) from feature trigger
long transactionTimestamp = this.transferPrivsTransactionData.getTimestamp();
final long startTimestamp = BlockChain.getInstance().getDisableTransferPrivsTimestamp();
final long endTimestamp = BlockChain.getInstance().getEnableTransferPrivsTimestamp();
if (transactionTimestamp > startTimestamp && transactionTimestamp < endTimestamp)
return ValidationResult.TRANSFER_PRIVS_DISABLED;
return ValidationResult.OK;
}
@@ -80,6 +88,17 @@ public class TransferPrivsTransaction extends Transaction {
// Nothing to do
}
@Override
public boolean isConfirmableAtHeight(int height) {
if (height >= BlockChain.getInstance().getUnconfirmableRewardSharesHeight()) {
// Not confirmable in online accounts or distribution blocks
if (Block.isOnlineAccountsBlock(height) || Block.isBatchRewardDistributionBlock(height)) {
return false;
}
}
return true;
}
@Override
public void process() throws DataException {
Account sender = this.getSender();

View File

@@ -30,10 +30,12 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 1659801600000,
"selfSponsorshipAlgoV1SnapshotTimestamp": 1670230000000,
"selfSponsorshipAlgoV2SnapshotTimestamp": 1706745600000,
"mempowTransactionUpdatesTimestamp": 1693558800000,
"blockRewardBatchStartHeight": 1508000,
"blockRewardBatchSize": 1000,
"blockRewardBatchAccountsBlockCount": 25,
"penaltyFixHash": "DG23E4Y63wC8FquG9FKAnfKwatvdJV3Z3iYnozMHn2A3",
"rewardsByHeight": [
{ "height": 1, "reward": 5.00 },
{ "height": 259201, "reward": 4.75 },
@@ -93,10 +95,15 @@
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"onlineAccountMinterLevelValidationHeight": 1092000,
"selfSponsorshipAlgoV1Height": 1092400,
"selfSponsorshipAlgoV2Height": 9999999,
"feeValidationFixTimestamp": 1671918000000,
"chatReferenceTimestamp": 1674316800000,
"arbitraryOptionalFeeTimestamp": 1680278400000,
"unconfirmableRewardSharesHeight": 1575500
"unconfirmableRewardSharesHeight": 1575500,
"disableTransferPrivsTimestamp": 1706745000000,
"enableTransferPrivsTimestamp": 1709251200000,
"penaltyFixHeight": 1589200
},
"checkpoints": [
{ "height": 1136300, "signature": "3BbwawEF2uN8Ni5ofpJXkukoU8ctAPxYoFB7whq9pKfBnjfZcpfEJT4R95NvBDoTP8WDyWvsUvbfHbcr9qSZuYpSKZjUQTvdFf6eqznHGEwhZApWfvXu6zjGCxYCp65F4jsVYYJjkzbjmkCg5WAwN5voudngA23kMK6PpTNygapCzXt" }

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = Transaktion existiert bereits
TRANSACTION_UNKNOWN = Transaktion unbekannt
TX_GROUP_ID_MISMATCH = die Gruppen-ID der Transaktion stimmt nicht überein
TRANSFER_PRIVS_DISABLED = Übertragungsberechtigungen deaktiviert

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = transaction already exists
TRANSACTION_UNKNOWN = transaction unknown
TX_GROUP_ID_MISMATCH = transaction's group ID does not match
TRANSFER_PRIVS_DISABLED = transfer privileges disabled

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = la transacción ya existe
TRANSACTION_UNKNOWN = transacción desconocida
TX_GROUP_ID_MISMATCH = el ID de grupo de la transacción no coincide
TRANSFER_PRIVS_DISABLED = privilegios de transferencia deshabilitados

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = transaktio on jo olemassa
TRANSACTION_UNKNOWN = tuntematon transaktio
TX_GROUP_ID_MISMATCH = transaktion ryhmä-ID:n vastaavuusvirhe
TRANSFER_PRIVS_DISABLED = siirtooikeudet poistettu käytöstä

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = la transaction existe déjà
TRANSACTION_UNKNOWN = transaction inconnue
TX_GROUP_ID_MISMATCH = l'identifiant du groupe de transaction ne correspond pas
TRANSFER_PRIVS_DISABLED = privilèges de transfert désactivés

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = עסקה כבר קיימת
TRANSACTION_UNKNOWN = עסקה לא ידועה
TX_GROUP_ID_MISMATCH = מזהה הקבוצה של העסקה אינו תואם
TRANSFER_PRIVS_DISABLED = הרשאות העברה מושבתות

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = ez a tranzakció már létezik
TRANSACTION_UNKNOWN = ismeretlen tranzakció
TX_GROUP_ID_MISMATCH = a tranzakció csoportazonosítója nem egyezik
TRANSFER_PRIVS_DISABLED = átviteli jogosultságok letiltva

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = la transazione già esiste
TRANSACTION_UNKNOWN = transazione sconosciuta
TX_GROUP_ID_MISMATCH = identificazione di gruppo della transazione non corrisponde
TRANSFER_PRIVS_DISABLED = privilegi di trasferimento disabilitati

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = 既にトランザクションは存在します
TRANSACTION_UNKNOWN = 不明なトランザクション
TX_GROUP_ID_MISMATCH = トランザクションのグループIDが一致しません
TRANSFER_PRIVS_DISABLED = 転送権限が無効になっています

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = 거래가 이미 존재합니다
TRANSACTION_UNKNOWN = 알 수 없는 거래
TX_GROUP_ID_MISMATCH = 트랜잭션의 그룹 ID가 일치하지 않습니다
TRANSFER_PRIVS_DISABLED = 권한 이전이 비활성화되었습니다.

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = transactie bestaat reeds
TRANSACTION_UNKNOWN = transactie onbekend
TX_GROUP_ID_MISMATCH = groep-ID komt niet overeen
TRANSFER_PRIVS_DISABLED = overdrachtsrechten uitgeschakeld

View File

@@ -194,3 +194,4 @@ TRANSACTION_UNKNOWN = transakcja nieznana
TX_GROUP_ID_MISMATCH = niezgodność ID grupy transakcji
TRANSFER_PRIVS_DISABLED = uprawnienia do przenoszenia wyłączone

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = tranzactia exista deja
TRANSACTION_UNKNOWN = tranzactie necunoscuta
TX_GROUP_ID_MISMATCH = ID-ul de grup al tranzactiei nu se potriveste
TRANSFER_PRIVS_DISABLED = privilegii de transfer dezactivate

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = транзакция существует
TRANSACTION_UNKNOWN = неизвестная транзакция
TX_GROUP_ID_MISMATCH = не соответствие идентификатора группы в хэш транзации
TRANSFER_PRIVS_DISABLED = права на передачу отключены

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = transaktionen finns redan
TRANSACTION_UNKNOWN = okänd transaktion
TX_GROUP_ID_MISMATCH = transaktionens grupp-ID matchar inte
TRANSFER_PRIVS_DISABLED = överföringsprivilegier inaktiverade

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = 此交易已存在
TRANSACTION_UNKNOWN = 未知的交易
TX_GROUP_ID_MISMATCH = 群组ID交易不吻合
TRANSFER_PRIVS_DISABLED = 传输权限已禁用

View File

@@ -193,3 +193,5 @@ TRANSACTION_ALREADY_EXISTS = 此交易已存在
TRANSACTION_UNKNOWN = 未知的交易
TX_GROUP_ID_MISMATCH = 群組ID交易不吻合
TRANSFER_PRIVS_DISABLED = 傳輸權限已停用

File diff suppressed because it is too large Load Diff