forked from Qortal/qortal
Reward share transaction modifications:
- Reduce concurrent reward share limit from 6 to 3 (or from 5 to 2 when including self share) - as per community vote. - Founders remain at 6 (5 when including self share) - also decided in community vote. - When all slots are being filled, require that at least one is a self share, so that not all can be used for sponsorship. - Activates at future undecided timestamp.
This commit is contained in:
parent
f499ada94c
commit
08f3351a7a
@ -68,6 +68,7 @@ public class BlockChain {
|
||||
atFindNextTransactionFix,
|
||||
newBlockSigHeight,
|
||||
shareBinFix,
|
||||
rewardShareLimitTimestamp,
|
||||
calcChainWeightTimestamp,
|
||||
transactionV5Timestamp,
|
||||
transactionV6Timestamp,
|
||||
@ -157,7 +158,7 @@ public class BlockChain {
|
||||
private int minAccountLevelToMint;
|
||||
private int minAccountLevelForBlockSubmissions;
|
||||
private int minAccountLevelToRewardShare;
|
||||
private int maxRewardSharesPerMintingAccount;
|
||||
private int maxRewardSharesPerFounderMintingAccount;
|
||||
private int founderEffectiveMintingLevel;
|
||||
|
||||
/** Minimum time to retain online account signatures (ms) for block validity checks. */
|
||||
@ -165,6 +166,13 @@ public class BlockChain {
|
||||
/** Maximum time to retain online account signatures (ms) for block validity checks, to allow for clock variance. */
|
||||
private long onlineAccountSignaturesMaxLifetime;
|
||||
|
||||
/** Max reward shares by block height */
|
||||
public static class MaxRewardSharesByTimestamp {
|
||||
public long timestamp;
|
||||
public int maxShares;
|
||||
}
|
||||
private List<MaxRewardSharesByTimestamp> maxRewardSharesByTimestamp;
|
||||
|
||||
/** Settings relating to CIYAM AT feature. */
|
||||
public static class CiyamAtSettings {
|
||||
/** Fee per step/op-code executed. */
|
||||
@ -366,8 +374,8 @@ public class BlockChain {
|
||||
return this.minAccountLevelToRewardShare;
|
||||
}
|
||||
|
||||
public int getMaxRewardSharesPerMintingAccount() {
|
||||
return this.maxRewardSharesPerMintingAccount;
|
||||
public int getMaxRewardSharesPerFounderMintingAccount() {
|
||||
return this.maxRewardSharesPerFounderMintingAccount;
|
||||
}
|
||||
|
||||
public int getFounderEffectiveMintingLevel() {
|
||||
@ -400,6 +408,10 @@ public class BlockChain {
|
||||
return this.featureTriggers.get(FeatureTrigger.shareBinFix.name()).intValue();
|
||||
}
|
||||
|
||||
public long getRewardShareLimitTimestamp() {
|
||||
return this.featureTriggers.get(FeatureTrigger.rewardShareLimitTimestamp.name()).longValue();
|
||||
}
|
||||
|
||||
public long getCalcChainWeightTimestamp() {
|
||||
return this.featureTriggers.get(FeatureTrigger.calcChainWeightTimestamp.name()).longValue();
|
||||
}
|
||||
@ -448,6 +460,14 @@ public class BlockChain {
|
||||
return this.getUnitFee();
|
||||
}
|
||||
|
||||
public int getMaxRewardSharesAtTimestamp(long ourTimestamp) {
|
||||
for (int i = maxRewardSharesByTimestamp.size() - 1; i >= 0; --i)
|
||||
if (maxRewardSharesByTimestamp.get(i).timestamp <= ourTimestamp)
|
||||
return maxRewardSharesByTimestamp.get(i).maxShares;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Validate blockchain config read from JSON */
|
||||
private void validateConfig() {
|
||||
if (this.genesisInfo == null)
|
||||
|
@ -159,6 +159,9 @@ public interface AccountRepository {
|
||||
/** Returns number of active reward-shares involving passed public key as the minting account only. */
|
||||
public int countRewardShares(byte[] mintingAccountPublicKey) throws DataException;
|
||||
|
||||
/** Returns number of active self-shares involving passed public key as the minting account only. */
|
||||
public int countSelfShares(byte[] mintingAccountPublicKey) throws DataException;
|
||||
|
||||
public List<RewardShareData> getRewardShares() throws DataException;
|
||||
|
||||
public List<RewardShareData> findRewardShares(List<String> mintingAccounts, List<String> recipientAccounts, List<String> involvedAddresses, Integer limit, Integer offset, Boolean reverse) throws DataException;
|
||||
|
@ -688,6 +688,17 @@ public class HSQLDBAccountRepository implements AccountRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countSelfShares(byte[] minterPublicKey) throws DataException {
|
||||
String sql = "SELECT COUNT(*) FROM RewardShares WHERE minter_public_key = ? AND minter = recipient";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, minterPublicKey)) {
|
||||
return resultSet.getInt(1);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to count self-shares in repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RewardShareData> getRewardShares() throws DataException {
|
||||
String sql = "SELECT minter_public_key, minter, recipient, share_percent, reward_share_public_key FROM RewardShares";
|
||||
|
@ -140,8 +140,21 @@ public class RewardShareTransaction extends Transaction {
|
||||
|
||||
// Check the minting account hasn't reach maximum number of reward-shares
|
||||
int rewardShareCount = this.repository.getAccountRepository().countRewardShares(creator.getPublicKey());
|
||||
if (rewardShareCount >= BlockChain.getInstance().getMaxRewardSharesPerMintingAccount())
|
||||
int selfShareCount = this.repository.getAccountRepository().countSelfShares(creator.getPublicKey());
|
||||
|
||||
int maxRewardShares = BlockChain.getInstance().getMaxRewardSharesAtTimestamp(this.rewardShareTransactionData.getTimestamp());
|
||||
if (creator.isFounder())
|
||||
// Founders have a different limit
|
||||
maxRewardShares = BlockChain.getInstance().getMaxRewardSharesPerFounderMintingAccount();
|
||||
|
||||
if (rewardShareCount >= maxRewardShares)
|
||||
return ValidationResult.MAXIMUM_REWARD_SHARES;
|
||||
|
||||
// When filling all reward share slots, one must be a self share (after feature trigger timestamp)
|
||||
if (this.rewardShareTransactionData.getTimestamp() >= BlockChain.getInstance().getRewardShareLimitTimestamp())
|
||||
if (!isRecipientAlsoMinter && rewardShareCount == maxRewardShares-1 && selfShareCount == 0)
|
||||
return ValidationResult.MAXIMUM_REWARD_SHARES;
|
||||
|
||||
} else {
|
||||
// This transaction intends to modify/terminate an existing reward-share
|
||||
|
||||
|
@ -15,7 +15,11 @@
|
||||
"minAccountLevelToMint": 1,
|
||||
"minAccountLevelForBlockSubmissions": 5,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 6,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 43200000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -57,6 +61,7 @@
|
||||
"atFindNextTransactionFix": 275000,
|
||||
"newBlockSigHeight": 320000,
|
||||
"shareBinFix": 399000,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 1620579600000,
|
||||
"transactionV5Timestamp": 1642176000000,
|
||||
"transactionV6Timestamp": 9999999999999,
|
||||
|
@ -41,7 +41,10 @@ public class AccountUtils {
|
||||
public static TransactionData createRewardShare(Repository repository, String minter, String recipient, int sharePercent) throws DataException {
|
||||
PrivateKeyAccount mintingAccount = Common.getTestAccount(repository, minter);
|
||||
PrivateKeyAccount recipientAccount = Common.getTestAccount(repository, recipient);
|
||||
return createRewardShare(repository, mintingAccount, recipientAccount, sharePercent);
|
||||
}
|
||||
|
||||
public static TransactionData createRewardShare(Repository repository, PrivateKeyAccount mintingAccount, PrivateKeyAccount recipientAccount, int sharePercent) throws DataException {
|
||||
byte[] reference = mintingAccount.getLastReference();
|
||||
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
|
||||
|
||||
@ -66,6 +69,15 @@ public class AccountUtils {
|
||||
return rewardSharePrivateKey;
|
||||
}
|
||||
|
||||
public static byte[] rewardShare(Repository repository, PrivateKeyAccount minterAccount, PrivateKeyAccount recipientAccount, int sharePercent) throws DataException {
|
||||
TransactionData transactionData = createRewardShare(repository, minterAccount, recipientAccount, sharePercent);
|
||||
|
||||
TransactionUtils.signAndMint(repository, transactionData, minterAccount);
|
||||
byte[] rewardSharePrivateKey = minterAccount.getRewardSharePrivateKey(recipientAccount.getPublicKey());
|
||||
|
||||
return rewardSharePrivateKey;
|
||||
}
|
||||
|
||||
public static Map<String, Map<Long, Long>> getBalances(Repository repository, long... assetIds) throws DataException {
|
||||
Map<String, Map<Long, Long>> balances = new HashMap<>();
|
||||
|
||||
|
@ -7,6 +7,7 @@ import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -25,6 +26,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.qortal.account.PrivateKeyAccount;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.account.AccountBalanceData;
|
||||
import org.qortal.data.asset.AssetData;
|
||||
@ -111,6 +113,12 @@ public class Common {
|
||||
return testAccountsByName.values().stream().map(account -> new TestAccount(repository, account)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static PrivateKeyAccount generateRandomSeedAccount(Repository repository) {
|
||||
byte[] seed = new byte[32];
|
||||
new SecureRandom().nextBytes(seed);
|
||||
return new PrivateKeyAccount(repository, seed);
|
||||
}
|
||||
|
||||
public static void useSettingsAndDb(String settingsFilename, boolean dbInMemory) throws DataException {
|
||||
closeRepository();
|
||||
|
||||
|
@ -177,4 +177,143 @@ public class RewardShareTests extends Common {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRewardSharesBeforeReduction() throws DataException {
|
||||
final int sharePercent = 0;
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
|
||||
|
||||
// Create 6 reward shares
|
||||
for (int i=0; i<6; i++) {
|
||||
AccountUtils.rewardShare(repository, dilbertAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
}
|
||||
|
||||
// 7th reward share should fail because we've reached the limit (and we're not yet requiring a self share)
|
||||
AssertionError assertionError = null;
|
||||
try {
|
||||
AccountUtils.rewardShare(repository, dilbertAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
} catch (AssertionError e) {
|
||||
assertionError = e;
|
||||
}
|
||||
assertNotNull("Transaction should be invalid", assertionError);
|
||||
assertTrue("Transaction should be invalid due to reaching maximum reward shares", assertionError.getMessage().contains("MAXIMUM_REWARD_SHARES"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRewardSharesAfterReduction() throws DataException {
|
||||
Common.useSettings("test-settings-v2-reward-shares.json");
|
||||
|
||||
final int sharePercent = 0;
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
|
||||
|
||||
// Create 2 reward shares
|
||||
for (int i=0; i<2; i++) {
|
||||
AccountUtils.rewardShare(repository, dilbertAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
}
|
||||
|
||||
// 3rd reward share should fail because we've reached the limit (and we haven't got a self share)
|
||||
AssertionError assertionError = null;
|
||||
try {
|
||||
AccountUtils.rewardShare(repository, dilbertAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
} catch (AssertionError e) {
|
||||
assertionError = e;
|
||||
}
|
||||
assertNotNull("Transaction should be invalid", assertionError);
|
||||
assertTrue("Transaction should be invalid due to reaching maximum reward shares", assertionError.getMessage().contains("MAXIMUM_REWARD_SHARES"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSelfAndRewardSharesAfterReduction() throws DataException {
|
||||
Common.useSettings("test-settings-v2-reward-shares.json");
|
||||
|
||||
final int sharePercent = 0;
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
|
||||
|
||||
// Create 2 reward shares
|
||||
for (int i=0; i<2; i++) {
|
||||
AccountUtils.rewardShare(repository, dilbertAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
}
|
||||
|
||||
// 3rd reward share should fail because we've reached the limit (and we haven't got a self share)
|
||||
AssertionError assertionError = null;
|
||||
try {
|
||||
AccountUtils.rewardShare(repository, dilbertAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
} catch (AssertionError e) {
|
||||
assertionError = e;
|
||||
}
|
||||
assertNotNull("Transaction should be invalid", assertionError);
|
||||
assertTrue("Transaction should be invalid due to reaching maximum reward shares", assertionError.getMessage().contains("MAXIMUM_REWARD_SHARES"));
|
||||
|
||||
// Now create a self share, which should succeed as we have space for it
|
||||
AccountUtils.rewardShare(repository, dilbertAccount, dilbertAccount, sharePercent);
|
||||
|
||||
// 4th reward share should fail because we've reached the limit (including the self share)
|
||||
assertionError = null;
|
||||
try {
|
||||
AccountUtils.rewardShare(repository, dilbertAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
} catch (AssertionError e) {
|
||||
assertionError = e;
|
||||
}
|
||||
assertNotNull("Transaction should be invalid", assertionError);
|
||||
assertTrue("Transaction should be invalid due to reaching maximum reward shares", assertionError.getMessage().contains("MAXIMUM_REWARD_SHARES"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFounderRewardSharesBeforeReduction() throws DataException {
|
||||
final int sharePercent = 0;
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount aliceFounderAccount = Common.getTestAccount(repository, "alice");
|
||||
|
||||
// Create 5 reward shares (not 6, because alice already starts with a self reward share in the genesis block)
|
||||
for (int i=0; i<5; i++) {
|
||||
AccountUtils.rewardShare(repository, aliceFounderAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
}
|
||||
|
||||
// 6th reward share should fail
|
||||
AssertionError assertionError = null;
|
||||
try {
|
||||
AccountUtils.rewardShare(repository, aliceFounderAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
} catch (AssertionError e) {
|
||||
assertionError = e;
|
||||
}
|
||||
assertNotNull("Transaction should be invalid", assertionError);
|
||||
assertTrue("Transaction should be invalid due to reaching maximum reward shares", assertionError.getMessage().contains("MAXIMUM_REWARD_SHARES"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFounderRewardSharesAfterReduction() throws DataException {
|
||||
Common.useSettings("test-settings-v2-reward-shares.json");
|
||||
|
||||
final int sharePercent = 0;
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount aliceFounderAccount = Common.getTestAccount(repository, "alice");
|
||||
|
||||
// Create 5 reward shares (not 6, because alice already starts with a self reward share in the genesis block)
|
||||
for (int i=0; i<5; i++) {
|
||||
AccountUtils.rewardShare(repository, aliceFounderAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
}
|
||||
|
||||
// 6th reward share should fail
|
||||
AssertionError assertionError = null;
|
||||
try {
|
||||
AccountUtils.rewardShare(repository, aliceFounderAccount, Common.generateRandomSeedAccount(repository), sharePercent);
|
||||
} catch (AssertionError e) {
|
||||
assertionError = e;
|
||||
}
|
||||
assertNotNull("Transaction should be invalid", assertionError);
|
||||
assertTrue("Transaction should be invalid due to reaching maximum reward shares", assertionError.getMessage().contains("MAXIMUM_REWARD_SHARES"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,6 +52,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 9999999999999,
|
||||
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 20 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 6,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 20 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
91
src/test/resources/test-chain-v2-reward-shares.json
Normal file
91
src/test/resources/test-chain-v2-reward-shares.json
Normal file
@ -0,0 +1,91 @@
|
||||
{
|
||||
"isTestChain": true,
|
||||
"blockTimestampMargin": 500,
|
||||
"transactionExpiryPeriod": 86400000,
|
||||
"maxBlockSize": 2097152,
|
||||
"maxBytesPerUnitFee": 1024,
|
||||
"unitFee": "0.1",
|
||||
"nameRegistrationUnitFees": [
|
||||
{ "timestamp": 1645372800000, "fee": "5" }
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 1655460000000, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
"rewardsByHeight": [
|
||||
{ "height": 1, "reward": 100 },
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
{ "levels": [ 1, 2 ], "share": 0.05 },
|
||||
{ "levels": [ 3, 4 ], "share": 0.10 },
|
||||
{ "levels": [ 5, 6 ], "share": 0.15 },
|
||||
{ "levels": [ 7, 8 ], "share": 0.20 },
|
||||
{ "levels": [ 9, 10 ], "share": 0.25 }
|
||||
],
|
||||
"qoraHoldersShare": 0.20,
|
||||
"qoraPerQortReward": 250,
|
||||
"blocksNeededByLevel": [ 10, 20, 30, 40, 50, 60, 70, 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,
|
||||
"rewardShareLimitTimestamp": 0,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"newConsensusTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
"disableReferenceTimestamp": 9999999999999,
|
||||
"aggregateSignatureTimestamp": 0
|
||||
},
|
||||
"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": "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": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 5 }
|
||||
]
|
||||
}
|
||||
}
|
@ -10,7 +10,11 @@
|
||||
],
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"maxRewardSharesPerFounderMintingAccount": 6,
|
||||
"maxRewardSharesByTimestamp": [
|
||||
{ "timestamp": 0, "maxShares": 6 },
|
||||
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
@ -51,6 +55,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
"transactionV6Timestamp": 0,
|
||||
|
19
src/test/resources/test-settings-v2-reward-shares.json
Normal file
19
src/test/resources/test-settings-v2-reward-shares.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"repositoryPath": "testdb",
|
||||
"bitcoinNet": "TEST3",
|
||||
"litecoinNet": "TEST3",
|
||||
"restrictedApi": false,
|
||||
"blockchainConfig": "src/test/resources/test-chain-v2-reward-shares.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
|
||||
}
|
Loading…
Reference in New Issue
Block a user