Compare commits

...

12 Commits

Author SHA1 Message Date
AlphaX-Projects
070f14b3dd Bump version to 4.5.0 2024-01-30 17:38:34 +01:00
AlphaX-Projects
2120490f4b Fix wrong penaties
This will set incorrectly penalized accounts from previous algo run back to previous state.
2024-01-30 17:36:17 +01:00
AlphaX-Projects
0ed27228b1 Merge pull request #173 from AlphaX-Projects/master
Out of Service
2024-01-21 14:24:40 +01:00
AlphaX-Projects
b75c2029ac Out of Service 2024-01-21 14:23:46 +01:00
AlphaX-Projects
867fe764ca Bump version to 4.4.2 2024-01-17 17:50:22 +01:00
AlphaX-Projects
140f14f2f4 Set exclude reward share transactions blockheight 2024-01-17 17:49:05 +01:00
AlphaX-Projects
9dd61f0e7a Merge pull request #170 from AlphaX-Projects/master
Update dependencies
2024-01-17 17:45:42 +01:00
AlphaX-Projects
747b1a4f9d Update dependencies 2024-01-17 17:28:27 +01:00
AlphaX-Projects
425152657a Merge pull request #166 from AlphaX-Projects/master
Exclude reward share transactions from the online accounts blocks
2024-01-14 20:36:46 +01:00
AlphaX-Projects
41645ac7b4 Exclude reward share transactions from the online accounts blocks 2024-01-14 18:40:40 +01:00
AlphaX-Projects
83e324c4ad Fix file ending 2024-01-07 14:34:20 +01:00
AlphaX-Projects
d7f44376be Default minPeerVersion set to 4.4.1 2024-01-07 14:32:12 +01:00
56 changed files with 5538 additions and 62 deletions

View File

@@ -8,7 +8,7 @@
* Build auto-update download: `tools/build-auto-update.sh` - uploads auto-update file into new git branch
* Restart local node
* Publish auto-update transaction using *private key* for **non-admin** member of "dev" group:
`tools/publish-auto-update.sh non-admin-dev-member-private-key-in-base58`
`tools/publish-auto-update.pl non-admin-dev-member-private-key-in-base58`
* Wait for auto-update `ARBITRARY` transaction to be confirmed into a block
* Have "dev" group admins 'approve' auto-update using `tools/approve-auto-update.sh`
This tool will prompt for *private key* of **admin** of "dev" group

10
pom.xml
View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.qortal</groupId>
<artifactId>qortal</artifactId>
<version>4.4.1</version>
<version>4.5.0</version>
<packaging>jar</packaging>
<properties>
<skipTests>true</skipTests>
@@ -21,7 +21,7 @@
<dagger.version>1.2.2</dagger.version>
<extendedset.version>0.12.3</extendedset.version>
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
<grpc.version>1.60.1</grpc.version>
<grpc.version>1.61.0</grpc.version>
<guava.version>33.0.0-jre</guava.version>
<hamcrest-library.version>2.2</hamcrest-library.version>
<homoglyph.version>1.2.1</homoglyph.version>
@@ -34,16 +34,16 @@
<jetty.version>9.4.53.v20231009</jetty.version>
<json-simple.version>1.1.1</json-simple.version>
<json.version>20231013</json.version>
<jsoup.version>1.17.1</jsoup.version>
<jsoup.version>1.17.2</jsoup.version>
<junit-jupiter-engine.version>5.10.0</junit-jupiter-engine.version>
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
<log4j.version>2.22.0</log4j.version>
<log4j.version>2.22.1</log4j.version>
<mail.version>1.5.0-b01</mail.version>
<maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version>
<maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>
<maven-resources-plugin.version>3.3.1</maven-resources-plugin.version>
<maven-shade-plugin.version>3.5.1</maven-shade-plugin.version>
<maven-surefire-plugin.version>3.2.3</maven-surefire-plugin.version>
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
<package-info-maven-plugin.version>1.1.0</package-info-maven-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<protobuf.version>3.25.1</protobuf.version>

View File

@@ -363,5 +363,4 @@ public class SelfSponsorshipAlgoV1 {
return transactionDataList;
}
}
}

View File

@@ -1309,6 +1309,9 @@ public class Block {
if (!transaction.isConfirmable()) {
return ValidationResult.TRANSACTION_NOT_CONFIRMABLE;
}
if (!transaction.isConfirmableAtHeight(this.blockData.getHeight())) {
return ValidationResult.TRANSACTION_NOT_CONFIRMABLE;
}
}
// Check transaction isn't already included in a block
@@ -1545,12 +1548,19 @@ public class Block {
processBlockRewards();
}
if (this.blockData.getHeight() == 212937)
if (this.blockData.getHeight() == 212937) {
// Apply fix for block 212937
Block212937.processFix(this);
}
else if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV1Height())
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,
@@ -1835,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()) {
@@ -2088,7 +2105,7 @@ public class Block {
return Block.isOnlineAccountsBlock(this.getBlockData().getHeight());
}
private static boolean isOnlineAccountsBlock(int height) {
public static boolean isOnlineAccountsBlock(int height) {
// After feature trigger, only certain blocks contain online accounts
if (height >= BlockChain.getInstance().getBlockRewardBatchStartHeight()) {
final int leadingBlockCount = BlockChain.getInstance().getBlockRewardBatchAccountsBlockCount();
@@ -2539,5 +2556,4 @@ public class Block {
LOGGER.info(() -> String.format("Unable to log block debugging info: %s", e.getMessage()));
}
}
}
}

View File

@@ -73,9 +73,14 @@ public class BlockChain {
increaseOnlineAccountsDifficultyTimestamp,
onlineAccountMinterLevelValidationHeight,
selfSponsorshipAlgoV1Height,
selfSponsorshipAlgoV2Height,
feeValidationFixTimestamp,
chatReferenceTimestamp,
arbitraryOptionalFeeTimestamp;
arbitraryOptionalFeeTimestamp,
unconfirmableRewardSharesHeight,
disableTransferPrivsTimestamp,
enableTransferPrivsTimestamp,
penaltyFixHeight
}
// Custom transaction fees
@@ -198,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;
@@ -208,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;
@@ -224,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;
@@ -266,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
@@ -394,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;
@@ -540,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();
}
@@ -556,6 +579,21 @@ public class BlockChain {
return this.featureTriggers.get(FeatureTrigger.arbitraryOptionalFeeTimestamp.name()).longValue();
}
public int getUnconfirmableRewardSharesHeight() {
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
@@ -742,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 */
}
@@ -133,4 +132,4 @@ public final class SelfSponsorshipAlgoV1Block {
return Base58.encode(Crypto.digest(StringUtils.join(penaltyAddresses).getBytes(StandardCharsets.UTF_8)));
}
}
}

View File

@@ -474,6 +474,7 @@ public class BlockMinter extends Thread {
Iterator<TransactionData> unconfirmedTransactionsIterator = unconfirmedTransactions.iterator();
final long newBlockTimestamp = newBlock.getBlockData().getTimestamp();
final int newBlockHeight = newBlock.getBlockData().getHeight();
while (unconfirmedTransactionsIterator.hasNext()) {
TransactionData transactionData = unconfirmedTransactionsIterator.next();
@@ -481,6 +482,12 @@ public class BlockMinter extends Thread {
// Ignore transactions that have expired before this block - they will be cleaned up later
if (transactionData.getTimestamp() > newBlockTimestamp || Transaction.getDeadline(transactionData) <= newBlockTimestamp)
unconfirmedTransactionsIterator.remove();
// Ignore transactions that are unconfirmable at this block height
Transaction transaction = Transaction.fromData(repository, transactionData);
if (!transaction.isConfirmableAtHeight(newBlockHeight)) {
unconfirmedTransactionsIterator.remove();
}
}
// Sign to create block's signature, needed by Block.isValid()

View File

@@ -46,10 +46,6 @@ public class Digibyte extends Bitcoiny {
// Servers chosen on NO BASIS WHATSOEVER from various sources!
// Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=dgb
new Server("electrum.qortal.link", Server.ConnectionType.SSL, 55002),
new Server("electrum1-dgb.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum2-dgb.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum3-dgb.qortal.online", Server.ConnectionType.SSL, 40002),
new Server("electrum4-dgb.qortal.online", Server.ConnectionType.SSL, 40002),
new Server("electrum1.cipig.net", Server.ConnectionType.SSL, 20059),
new Server("electrum2.cipig.net", Server.ConnectionType.SSL, 20059),
new Server("electrum3.cipig.net", Server.ConnectionType.SSL, 20059)

View File

@@ -46,10 +46,6 @@ public class Dogecoin extends Bitcoiny {
// Servers chosen on NO BASIS WHATSOEVER from various sources!
// Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=doge
new Server("electrum.qortal.link", Server.ConnectionType.SSL, 54002),
new Server("electrum1-doge.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum2-doge.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum3-doge.qortal.online", Server.ConnectionType.SSL, 30002),
new Server("electrum4-doge.qortal.online", Server.ConnectionType.SSL, 30002),
new Server("electrum1.cipig.net", Server.ConnectionType.SSL, 20060),
new Server("electrum2.cipig.net", Server.ConnectionType.SSL, 20060),
new Server("electrum3.cipig.net", Server.ConnectionType.SSL, 20060)

View File

@@ -46,10 +46,6 @@ public class Litecoin extends Bitcoiny {
// Servers chosen on NO BASIS WHATSOEVER from various sources!
// Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=ltc
new Server("electrum.qortal.link", Server.ConnectionType.SSL, 50002),
new Server("electrum1-ltc.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum2-ltc.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum3-ltc.qortal.online", Server.ConnectionType.SSL, 20002),
new Server("electrum4-ltc.qortal.online", Server.ConnectionType.SSL, 20002),
new Server("backup.electrum-ltc.org", Server.ConnectionType.SSL, 443),
new Server("electrum.ltc.xurious.com", Server.ConnectionType.SSL, 50002),
new Server("electrum-ltc.petrkr.net", Server.ConnectionType.SSL, 60002),

View File

@@ -51,11 +51,6 @@ public class PirateChain extends Bitcoiny {
public Collection<Server> getServers() {
return Arrays.asList(
// Servers chosen on NO BASIS WHATSOEVER from various sources!
new Server("wallet-arrr1.qortal.online", Server.ConnectionType.SSL, 443),
new Server("wallet-arrr2.qortal.online", Server.ConnectionType.SSL, 443),
new Server("wallet-arrr3.qortal.online", Server.ConnectionType.SSL, 443),
new Server("wallet-arrr4.qortal.online", Server.ConnectionType.SSL, 443),
new Server("wallet-arrr5.qortal.online", Server.ConnectionType.SSL, 443),
new Server("lightd.pirate.black", Server.ConnectionType.SSL, 443)
);
}

View File

@@ -46,10 +46,6 @@ public class Ravencoin extends Bitcoiny {
// Servers chosen on NO BASIS WHATSOEVER from various sources!
// Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=rvn
new Server("electrum.qortal.link", Server.ConnectionType.SSL, 56002),
new Server("electrum1-rvn.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum2-rvn.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum3-rvn.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum4-rvn.qortal.online", Server.ConnectionType.SSL, 50002),
new Server("electrum1.cipig.net", Server.ConnectionType.SSL, 20051),
new Server("electrum2.cipig.net", Server.ConnectionType.SSL, 20051),
new Server("electrum3.cipig.net", Server.ConnectionType.SSL, 20051),

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.0";
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 */
@@ -272,8 +272,7 @@ public class Settings {
private String[] bootstrapHosts = new String[] {
"http://bootstrap.qortal.org",
"http://bootstrap2.qortal.org",
"http://bootstrap3.qortal.org",
"http://bootstrap.qortal.online"
"http://bootstrap3.qortal.org"
};
// Auto-update sources

View File

@@ -3,6 +3,7 @@ package org.qortal.transaction;
import org.qortal.account.Account;
import org.qortal.account.PublicKeyAccount;
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.RewardShareData;
@@ -180,6 +181,23 @@ public class RewardShareTransaction extends Transaction {
// Nothing to do
}
@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;
}
@Override
public void process() throws DataException {
PublicKeyAccount mintingAccount = getMintingAccount();

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);
@@ -904,6 +905,15 @@ public abstract class Transaction {
return true;
}
/**
* Returns whether transaction is confirmable in a block at a given height.
* @return
*/
public boolean isConfirmableAtHeight(int height) {
/* To be optionally overridden */
return true;
}
/**
* Returns whether transaction can be added to the blockchain.
* <p>

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,9 +95,15 @@
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"onlineAccountMinterLevelValidationHeight": 1092000,
"selfSponsorshipAlgoV1Height": 1092400,
"selfSponsorshipAlgoV2Height": 9999999,
"feeValidationFixTimestamp": 1671918000000,
"chatReferenceTimestamp": 1674316800000,
"arbitraryOptionalFeeTimestamp": 1680278400000
"arbitraryOptionalFeeTimestamp": 1680278400000,
"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

View File

@@ -0,0 +1,82 @@
package org.qortal.test;
import org.junit.Before;
import org.junit.Test;
import org.qortal.account.Account;
import org.qortal.account.PrivateKeyAccount;
import org.qortal.block.Block;
import org.qortal.controller.BlockMinter;
import org.qortal.data.transaction.PaymentTransactionData;
import org.qortal.data.transaction.TransactionData;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager;
import org.qortal.settings.Settings;
import org.qortal.test.common.BlockUtils;
import org.qortal.test.common.Common;
import org.qortal.test.common.TransactionUtils;
import org.qortal.test.common.transaction.TestTransaction;
import org.qortal.utils.NTP;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
public class PenaltyFixTests extends Common {
@Before
public void beforeTest() throws DataException {
Common.useSettings("test-settings-v2-penalty-fix.json");
NTP.setFixedOffset(Settings.getInstance().getTestNtpOffset());
}
@Test
public void testSingleSponsor() throws DataException {
try (final Repository repository = RepositoryManager.getRepository()) {
// Alice self share online, and will be used to mint the blocks
PrivateKeyAccount aliceSelfShare = Common.getTestAccount(repository, "alice-reward-share");
List<PrivateKeyAccount> onlineAccounts = new ArrayList<>();
onlineAccounts.add(aliceSelfShare);
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Test account from real penalty data (pen-revert.json)
Account penaltyAccount = new Account(repository, "QLcAQpko5egwNjifueCAeAsT8CAj2Sr5qJ");
// Bob sends a payment to the penalty account, so that it gets a row in the Accounts table
TransactionData paymentData = new PaymentTransactionData(TestTransaction.generateBase(bobAccount), penaltyAccount.getAddress(), 1);
TransactionUtils.signAndImportValid(repository, paymentData, bobAccount); // updates paymentData's signature
// Mint blocks up to height 4
Block block = null;
for (int i = 2; i <= 4; i++)
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
assertEquals(4, (int)block.getBlockData().getHeight());
// Check blocks minted penalty of penalty account
assertEquals(0, (int) penaltyAccount.getBlocksMintedPenalty());
// Penalty revert code runs at block 5
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
assertEquals(5, (int)block.getBlockData().getHeight());
// +5000000 blocks minted penalty should be applied
assertEquals(5000000, (int) penaltyAccount.getBlocksMintedPenalty());
// Orphan the last block, to simulate a re-org
BlockUtils.orphanLastBlock(repository);
assertEquals(0, (int) penaltyAccount.getBlocksMintedPenalty());
// Penalty revert code runs again
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
assertEquals(5, (int)block.getBlockData().getHeight());
// Penalty should still be 5000000, rather than doubled up to 10000000
assertEquals(5000000, (int) penaltyAccount.getBlocksMintedPenalty());
}
}
}

View File

@@ -38,7 +38,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
@Before
public void beforeTest() throws DataException {
Common.useSettings("test-settings-v2-self-sponsorship-algo.json");
Common.useSettings("test-settings-v2-self-sponsorship-algo-v1.json");
NTP.setFixedOffset(Settings.getInstance().getTestNtpOffset());
}

View File

@@ -20,6 +20,7 @@ import org.qortal.settings.Settings;
import org.qortal.test.common.*;
import org.qortal.test.common.transaction.TestTransaction;
import org.qortal.transaction.DeployAtTransaction;
import org.qortal.transaction.Transaction;
import org.qortal.transform.TransformationException;
import org.qortal.transform.block.BlockTransformer;
import org.qortal.utils.NTP;
@@ -679,4 +680,120 @@ public class BatchRewardTests extends Common {
}
}
@Test
public void testUnconfirmableRewardShares() throws DataException, IllegalAccessException {
// test-settings-v2-reward-scaling.json has unconfirmable reward share feature trigger enabled from block 500
Common.useSettings("test-settings-v2-reward-scaling.json");
// Set reward batching to every 1000 blocks, starting at block 0, looking back the last 25 blocks for online accounts
FieldUtils.writeField(BlockChain.getInstance(), "blockRewardBatchStartHeight", 0, true);
FieldUtils.writeField(BlockChain.getInstance(), "blockRewardBatchSize", 1000, true);
FieldUtils.writeField(BlockChain.getInstance(), "blockRewardBatchAccountsBlockCount", 25, true);
try (final Repository repository = RepositoryManager.getRepository()) {
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
PrivateKeyAccount chloe = Common.getTestAccount(repository, "chloe");
PrivateKeyAccount dilbert = Common.getTestAccount(repository, "dilbert");
PrivateKeyAccount aliceSelfShare = Common.getTestAccount(repository, "alice-reward-share");
PrivateKeyAccount bobSelfShare = Common.getTestAccount(repository, "bob-reward-share");
PrivateKeyAccount chloeSelfShare = Common.getTestAccount(repository, "chloe-reward-share");
// Create self shares for bob, chloe and dilbert
AccountUtils.generateSelfShares(repository, List.of(bob, chloe, dilbert));
// Mint blocks 1-974 - these should have no online accounts or rewards
for (int i=1; i<974; i++) {
Block block = BlockUtils.mintBlockWithReorgs(repository, 2);
assertTrue(block.isBatchRewardDistributionActive());
assertFalse(block.isRewardDistributionBlock());
assertFalse(block.isBatchRewardDistributionBlock());
assertFalse(block.isOnlineAccountsBlock());
assertEquals(0, block.getBlockData().getOnlineAccountsCount());
}
// Mint blocks 975-998 - these should have online accounts but no rewards
for (int i=975; i<=998; i++) {
List<PrivateKeyAccount> onlineAccounts = Arrays.asList(aliceSelfShare, bobSelfShare, chloeSelfShare);
Block block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
assertTrue(block.isBatchRewardDistributionActive());
assertFalse(block.isRewardDistributionBlock());
assertFalse(block.isBatchRewardDistributionBlock());
assertTrue(block.isOnlineAccountsBlock());
assertEquals(3, block.getBlockData().getOnlineAccountsCount());
}
// Cancel Chloe's reward share
TransactionData transactionData = AccountUtils.createRewardShare(repository, chloe, chloe, -100, 10000000L);
TransactionUtils.signAndImportValid(repository, transactionData, chloe);
// Mint block 999 - Chloe's account should still be included as the reward share cancellation is delayed
List<PrivateKeyAccount> onlineAccounts = Arrays.asList(aliceSelfShare, bobSelfShare, chloeSelfShare);
Block block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
assertTrue(block.isBatchRewardDistributionActive());
assertFalse(block.isRewardDistributionBlock());
assertFalse(block.isBatchRewardDistributionBlock());
assertTrue(block.isOnlineAccountsBlock());
assertEquals(3, block.getBlockData().getOnlineAccountsCount());
// Mint block 1000
Block block1000 = BlockUtils.mintBlockWithReorgs(repository, 12);
// Online accounts should be included from block 999
assertEquals(3, block1000.getBlockData().getOnlineAccountsCount());
assertEquals(repository.getBlockRepository().getBlockchainHeight(), 1000);
// It's a distribution block (which is technically also an online accounts block)
assertTrue(block1000.isBatchRewardDistributionBlock());
assertTrue(block1000.isRewardDistributionBlock());
assertTrue(block1000.isBatchRewardDistributionActive());
assertTrue(block1000.isOnlineAccountsBlock());
}
}
@Test
public void testUnconfirmableRewardShareBlocks() throws DataException, IllegalAccessException {
// test-settings-v2-reward-scaling.json has unconfirmable reward share feature trigger enabled from block 500
Common.useSettings("test-settings-v2-reward-scaling.json");
// Set reward batching to every 1000 blocks, starting at block 0, looking back the last 25 blocks for online accounts
FieldUtils.writeField(BlockChain.getInstance(), "blockRewardBatchStartHeight", 0, true);
FieldUtils.writeField(BlockChain.getInstance(), "blockRewardBatchSize", 1000, true);
FieldUtils.writeField(BlockChain.getInstance(), "blockRewardBatchAccountsBlockCount", 25, true);
try (final Repository repository = RepositoryManager.getRepository()) {
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
PrivateKeyAccount chloe = Common.getTestAccount(repository, "chloe");
PrivateKeyAccount dilbert = Common.getTestAccount(repository, "dilbert");
// Create self shares for bob, chloe and dilbert
AccountUtils.generateSelfShares(repository, List.of(bob, chloe, dilbert));
// Create transaction to cancel chloe's reward share
TransactionData rewardShareTransactionData = AccountUtils.createRewardShare(repository, chloe, chloe, -100, 10000000L);
Transaction rewardShareTransaction = Transaction.fromData(repository, rewardShareTransactionData);
// Mint a block
BlockUtils.mintBlock(repository);
// Check block heights up to 974 - transaction should be confirmable
for (int height=2; height<974; height++) {
assertEquals(true, rewardShareTransaction.isConfirmableAtHeight(height));
}
// Check block heights 975-1000 - transaction should not be confirmable
for (int height=975; height<1000; height++) {
assertEquals(false, rewardShareTransaction.isConfirmableAtHeight(height));
}
// Check block heights 1001-1974 - transaction should be confirmable again
for (int height=1001; height<1974; height++) {
assertEquals(true, rewardShareTransaction.isConfirmableAtHeight(height));
}
}
}
}

View File

@@ -18,6 +18,7 @@
"onlineAccountSignaturesMinLifetime": 3600000,
"onlineAccountSignaturesMaxLifetime": 86400000,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -83,7 +84,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -22,6 +22,7 @@
"onlineAccountSignaturesMinLifetime": 3600000,
"onlineAccountSignaturesMaxLifetime": 86400000,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -86,7 +87,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 9999999999999,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 9999999999999
"arbitraryOptionalFeeTimestamp": 9999999999999,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -0,0 +1,130 @@
{
"isTestChain": true,
"blockTimestampMargin": 500,
"transactionExpiryPeriod": 86400000,
"maxBlockSize": 2097152,
"maxBytesPerUnitFee": 0,
"unitFees": [
{ "timestamp": 0, "fee": "0.00000001" }
],
"nameRegistrationUnitFees": [
{ "timestamp": 0, "fee": "0.00000001" },
{ "timestamp": 1645372800000, "fee": "5" }
],
"requireGroupForApproval": false,
"minAccountLevelToRewardShare": 5,
"maxRewardSharesPerFounderMintingAccount": 20,
"maxRewardSharesByTimestamp": [
{ "timestamp": 0, "maxShares": 20 },
{ "timestamp": 9999999999999, "maxShares": 3 }
],
"founderEffectiveMintingLevel": 10,
"onlineAccountSignaturesMinLifetime": 3600000,
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3,
"rewardsByHeight": [
{ "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 },
{ "height": 21, "reward": 1 }
],
"sharesByLevelV1": [
{ "id": 1, "levels": [ 1, 2 ], "share": 0.05 },
{ "id": 2, "levels": [ 3, 4 ], "share": 0.10 },
{ "id": 3, "levels": [ 5, 6 ], "share": 0.15 },
{ "id": 4, "levels": [ 7, 8 ], "share": 0.20 },
{ "id": 5, "levels": [ 9, 10 ], "share": 0.25 }
],
"sharesByLevelV2": [
{ "id": 1, "levels": [ 1, 2 ], "share": 0.06 },
{ "id": 2, "levels": [ 3, 4 ], "share": 0.13 },
{ "id": 3, "levels": [ 5, 6 ], "share": 0.19 },
{ "id": 4, "levels": [ 7, 8 ], "share": 0.26 },
{ "id": 5, "levels": [ 9, 10 ], "share": 0.32 }
],
"qoraHoldersShareByHeight": [
{ "height": 1, "share": 0.20 },
{ "height": 1000000, "share": 0.01 }
],
"qoraPerQortReward": 250,
"minAccountsToActivateShareBin": 0,
"shareBinActivationMinLevel": 7,
"blocksNeededByLevel": [ 5, 20, 30, 40, 50, 60, 18, 80, 90, 100 ],
"blockTimingsByHeight": [
{ "height": 1, "target": 60000, "deviation": 30000, "power": 0.2 }
],
"ciyamAtSettings": {
"feePerStep": "0.0001",
"maxStepsPerRound": 500,
"stepsPerFunctionCall": 10,
"minutesPerBlock": 1
},
"featureTriggers": {
"messageHeight": 0,
"atHeight": 0,
"assetsTimestamp": 0,
"votingTimestamp": 0,
"arbitraryTimestamp": 0,
"powfixTimestamp": 0,
"qortalTimestamp": 0,
"newAssetPricingTimestamp": 0,
"groupApprovalTimestamp": 0,
"atFindNextTransactionFix": 0,
"newBlockSigHeight": 999999,
"shareBinFix": 999999,
"sharesByLevelV2Height": 999999,
"rewardShareLimitTimestamp": 9999999999999,
"calcChainWeightTimestamp": 0,
"transactionV5Timestamp": 0,
"transactionV6Timestamp": 0,
"disableReferenceTimestamp": 9999999999999,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"onlineAccountMinterLevelValidationHeight": 0,
"selfSponsorshipAlgoV1Height": 99999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 5
},
"genesisInfo": {
"version": 4,
"timestamp": 0,
"transactions": [
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000" },
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000" },
{ "type": "GENESIS", "recipient": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "amount": "1000000" },
{ "type": "GENESIS", "recipient": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "amount": "1000000" },
{ "type": "CREATE_GROUP", "creatorPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupName": "dev-group", "description": "developer group", "isOpen": false, "approvalThreshold": "PCT100", "minimumBlockDelay": 0, "maximumBlockDelay": 1440 },
{ "type": "UPDATE_GROUP", "ownerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupId": 1, "newOwner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "newDescription": "developer group", "newIsOpen": false, "newApprovalThreshold": "PCT40", "minimumBlockDelay": 10, "maximumBlockDelay": 1440 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "TEST", "description": "test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": "100" },
{ "type": "ACCOUNT_LEVEL", "target": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "level": 5 },
{ "type": "REWARD_SHARE", "minterPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "rewardSharePublicKey": "CcABzvk26TFEHG7Yok84jxyd4oBtLkx8RJdGFVz2csvp", "sharePercent": 100 },
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 5 },
{ "type": "ACCOUNT_LEVEL", "target": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "level": 5 },
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 6 }
]
}
}

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -88,7 +89,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 500,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,
@@ -107,7 +113,10 @@
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": 100 },
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 8 }
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 8 },
{ "type": "ACCOUNT_LEVEL", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "level": 1 },
{ "type": "ACCOUNT_LEVEL", "target": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "level": 1 },
{ "type": "ACCOUNT_LEVEL", "target": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "level": 1 }
]
}
}

View File

@@ -22,6 +22,7 @@
"onlineAccountSignaturesMinLifetime": 3600000,
"onlineAccountSignaturesMaxLifetime": 86400000,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -23,6 +23,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -87,7 +88,12 @@
"selfSponsorshipAlgoV1Height": 20,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -24,6 +24,7 @@
"onlineAccountSignaturesMaxLifetime": 86400000,
"onlineAccountsModulusV2Timestamp": 9999999999999,
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
"mempowTransactionUpdatesTimestamp": 0,
"blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10,
@@ -88,7 +89,12 @@
"selfSponsorshipAlgoV1Height": 999999999,
"feeValidationFixTimestamp": 0,
"chatReferenceTimestamp": 0,
"arbitraryOptionalFeeTimestamp": 0
"arbitraryOptionalFeeTimestamp": 0,
"unconfirmableRewardSharesHeight": 99999999,
"selfSponsorshipAlgoV2Height": 9999999,
"disableTransferPrivsTimestamp": 9999999999500,
"enableTransferPrivsTimestamp": 9999999999950,
"penaltyFixHeight": 9999999
},
"genesisInfo": {
"version": 4,

View File

@@ -0,0 +1,20 @@
{
"repositoryPath": "testdb",
"bitcoinNet": "TEST3",
"litecoinNet": "TEST3",
"restrictedApi": false,
"blockchainConfig": "src/test/resources/test-chain-v2-penalty-fix.json",
"exportPath": "qortal-backup-test",
"bootstrap": false,
"wipeUnconfirmedOnStart": false,
"testNtpOffset": 0,
"minPeers": 0,
"pruneBlockLimit": 100,
"bootstrapFilenamePrefix": "test-",
"dataPath": "data-test",
"tempDataPath": "data-test/_temp",
"listsPath": "lists-test",
"storagePolicy": "FOLLOWED_OR_VIEWED",
"maxStorageCapacity": 104857600,
"arrrDefaultBirthday": 1900000
}

View File

@@ -3,7 +3,7 @@
"bitcoinNet": "TEST3",
"litecoinNet": "TEST3",
"restrictedApi": false,
"blockchainConfig": "src/test/resources/test-chain-v2-self-sponsorship-algo.json",
"blockchainConfig": "src/test/resources/test-chain-v2-self-sponsorship-algo-v1.json",
"exportPath": "qortal-backup-test",
"bootstrap": false,
"wipeUnconfirmedOnStart": false,