forked from Qortal/qortal
Added shareBinsByLevelV2.
This allows for different share bin distribution starting at an undecided future block height. This height will correspond with the QORA reduction. New values decided in recent community vote.
This commit is contained in:
parent
a9267760eb
commit
8b61247712
@ -10,7 +10,6 @@ import java.math.BigInteger;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@ -185,8 +184,11 @@ public class Block {
|
||||
if (accountLevel <= 0)
|
||||
return null; // level 0 isn't included in any share bins
|
||||
|
||||
// Select the correct set of share bins based on block height
|
||||
final BlockChain blockChain = BlockChain.getInstance();
|
||||
final AccountLevelShareBin[] shareBinsByLevel = blockChain.getShareBinsByAccountLevel();
|
||||
final AccountLevelShareBin[] shareBinsByLevel = (blockHeight >= blockChain.getSharesByLevelV2Height()) ?
|
||||
blockChain.getShareBinsByAccountLevelV2() : blockChain.getShareBinsByAccountLevelV1();
|
||||
|
||||
if (accountLevel > shareBinsByLevel.length)
|
||||
return null;
|
||||
|
||||
@ -1896,10 +1898,14 @@ public class Block {
|
||||
final List<ExpandedAccount> onlineFounderAccounts = expandedAccounts.stream().filter(expandedAccount -> expandedAccount.isMinterFounder).collect(Collectors.toList());
|
||||
final boolean haveFounders = !onlineFounderAccounts.isEmpty();
|
||||
|
||||
// Select the correct set of share bins based on block height
|
||||
List<AccountLevelShareBin> accountLevelShareBinsForBlock = (this.blockData.getHeight() >= BlockChain.getInstance().getSharesByLevelV2Height()) ?
|
||||
BlockChain.getInstance().getAccountLevelShareBinsV2() : BlockChain.getInstance().getAccountLevelShareBinsV1();
|
||||
|
||||
// Determine reward candidates based on account level
|
||||
// This needs a deep copy, so the shares can be modified when tiers aren't activated yet
|
||||
List<AccountLevelShareBin> accountLevelShareBins = new ArrayList<>();
|
||||
for (AccountLevelShareBin accountLevelShareBin : BlockChain.getInstance().getAccountLevelShareBins()) {
|
||||
for (AccountLevelShareBin accountLevelShareBin : accountLevelShareBinsForBlock) {
|
||||
accountLevelShareBins.add((AccountLevelShareBin) accountLevelShareBin.clone());
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,7 @@ public class BlockChain {
|
||||
atFindNextTransactionFix,
|
||||
newBlockSigHeight,
|
||||
shareBinFix,
|
||||
sharesByLevelV2Height,
|
||||
rewardShareLimitTimestamp,
|
||||
calcChainWeightTimestamp,
|
||||
transactionV5Timestamp,
|
||||
@ -122,9 +123,11 @@ public class BlockChain {
|
||||
return shareBinCopy;
|
||||
}
|
||||
}
|
||||
private List<AccountLevelShareBin> sharesByLevel;
|
||||
private List<AccountLevelShareBin> sharesByLevelV1;
|
||||
private List<AccountLevelShareBin> sharesByLevelV2;
|
||||
/** Generated lookup of share-bin by account level */
|
||||
private AccountLevelShareBin[] shareBinsByLevel;
|
||||
private AccountLevelShareBin[] shareBinsByLevelV1;
|
||||
private AccountLevelShareBin[] shareBinsByLevelV2;
|
||||
|
||||
/** Share of block reward/fees to legacy QORA coin holders, by block height */
|
||||
public static class ShareByHeight {
|
||||
@ -370,12 +373,20 @@ public class BlockChain {
|
||||
return this.rewardsByHeight;
|
||||
}
|
||||
|
||||
public List<AccountLevelShareBin> getAccountLevelShareBins() {
|
||||
return this.sharesByLevel;
|
||||
public List<AccountLevelShareBin> getAccountLevelShareBinsV1() {
|
||||
return this.sharesByLevelV1;
|
||||
}
|
||||
|
||||
public AccountLevelShareBin[] getShareBinsByAccountLevel() {
|
||||
return this.shareBinsByLevel;
|
||||
public List<AccountLevelShareBin> getAccountLevelShareBinsV2() {
|
||||
return this.sharesByLevelV2;
|
||||
}
|
||||
|
||||
public AccountLevelShareBin[] getShareBinsByAccountLevelV1() {
|
||||
return this.shareBinsByLevelV1;
|
||||
}
|
||||
|
||||
public AccountLevelShareBin[] getShareBinsByAccountLevelV2() {
|
||||
return this.shareBinsByLevelV2;
|
||||
}
|
||||
|
||||
public List<Integer> getBlocksNeededByLevel() {
|
||||
@ -444,6 +455,10 @@ public class BlockChain {
|
||||
return this.featureTriggers.get(FeatureTrigger.shareBinFix.name()).intValue();
|
||||
}
|
||||
|
||||
public int getSharesByLevelV2Height() {
|
||||
return this.featureTriggers.get(FeatureTrigger.sharesByLevelV2Height.name()).intValue();
|
||||
}
|
||||
|
||||
public long getRewardShareLimitTimestamp() {
|
||||
return this.featureTriggers.get(FeatureTrigger.rewardShareLimitTimestamp.name()).longValue();
|
||||
}
|
||||
@ -521,8 +536,11 @@ public class BlockChain {
|
||||
if (this.rewardsByHeight == null)
|
||||
Settings.throwValidationError("No \"rewardsByHeight\" entry found in blockchain config");
|
||||
|
||||
if (this.sharesByLevel == null)
|
||||
Settings.throwValidationError("No \"sharesByLevel\" entry found in blockchain config");
|
||||
if (this.sharesByLevelV1 == null)
|
||||
Settings.throwValidationError("No \"sharesByLevelV1\" entry found in blockchain config");
|
||||
|
||||
if (this.sharesByLevelV2 == null)
|
||||
Settings.throwValidationError("No \"sharesByLevelV2\" entry found in blockchain config");
|
||||
|
||||
if (this.qoraHoldersShareByHeight == null)
|
||||
Settings.throwValidationError("No \"qoraHoldersShareByHeight\" entry found in blockchain config");
|
||||
@ -562,13 +580,22 @@ public class BlockChain {
|
||||
if (!this.featureTriggers.containsKey(featureTrigger.name()))
|
||||
Settings.throwValidationError(String.format("Missing feature trigger \"%s\" in blockchain config", featureTrigger.name()));
|
||||
|
||||
// Check block reward share bounds
|
||||
long totalShare = this.getQoraHoldersShareAtHeight(1);
|
||||
// Check block reward share bounds (V1)
|
||||
long totalShareV1 = this.qoraHoldersShareByHeight.get(0).share;
|
||||
// Add share percents for account-level-based rewards
|
||||
for (AccountLevelShareBin accountLevelShareBin : this.sharesByLevel)
|
||||
totalShare += accountLevelShareBin.share;
|
||||
for (AccountLevelShareBin accountLevelShareBin : this.sharesByLevelV1)
|
||||
totalShareV1 += accountLevelShareBin.share;
|
||||
|
||||
if (totalShare < 0 || totalShare > 1_00000000L)
|
||||
if (totalShareV1 < 0 || totalShareV1 > 1_00000000L)
|
||||
Settings.throwValidationError("Total non-founder share out of bounds (0<x<1e8)");
|
||||
|
||||
// Check block reward share bounds (V2)
|
||||
long totalShareV2 = this.qoraHoldersShareByHeight.get(1).share;
|
||||
// Add share percents for account-level-based rewards
|
||||
for (AccountLevelShareBin accountLevelShareBin : this.sharesByLevelV2)
|
||||
totalShareV2 += accountLevelShareBin.share;
|
||||
|
||||
if (totalShareV2 < 0 || totalShareV2 > 1_00000000L)
|
||||
Settings.throwValidationError("Total non-founder share out of bounds (0<x<1e8)");
|
||||
}
|
||||
|
||||
@ -584,20 +611,30 @@ public class BlockChain {
|
||||
cumulativeBlocks += this.blocksNeededByLevel.get(level);
|
||||
}
|
||||
|
||||
// Generate lookup-array for account-level share bins
|
||||
AccountLevelShareBin lastAccountLevelShareBin = this.sharesByLevel.get(this.sharesByLevel.size() - 1);
|
||||
final int lastLevel = lastAccountLevelShareBin.levels.get(lastAccountLevelShareBin.levels.size() - 1);
|
||||
this.shareBinsByLevel = new AccountLevelShareBin[lastLevel];
|
||||
|
||||
for (AccountLevelShareBin accountLevelShareBin : this.sharesByLevel)
|
||||
// Generate lookup-array for account-level share bins (V1)
|
||||
AccountLevelShareBin lastAccountLevelShareBinV1 = this.sharesByLevelV1.get(this.sharesByLevelV1.size() - 1);
|
||||
final int lastLevelV1 = lastAccountLevelShareBinV1.levels.get(lastAccountLevelShareBinV1.levels.size() - 1);
|
||||
this.shareBinsByLevelV1 = new AccountLevelShareBin[lastLevelV1];
|
||||
for (AccountLevelShareBin accountLevelShareBin : this.sharesByLevelV1)
|
||||
for (int level : accountLevelShareBin.levels)
|
||||
// level 1 stored at index 0, level 2 stored at index 1, etc.
|
||||
// level 0 not allowed
|
||||
this.shareBinsByLevel[level - 1] = accountLevelShareBin;
|
||||
this.shareBinsByLevelV1[level - 1] = accountLevelShareBin;
|
||||
|
||||
// Generate lookup-array for account-level share bins (V2)
|
||||
AccountLevelShareBin lastAccountLevelShareBinV2 = this.sharesByLevelV2.get(this.sharesByLevelV2.size() - 1);
|
||||
final int lastLevelV2 = lastAccountLevelShareBinV2.levels.get(lastAccountLevelShareBinV2.levels.size() - 1);
|
||||
this.shareBinsByLevelV2 = new AccountLevelShareBin[lastLevelV2];
|
||||
for (AccountLevelShareBin accountLevelShareBin : this.sharesByLevelV2)
|
||||
for (int level : accountLevelShareBin.levels)
|
||||
// level 1 stored at index 0, level 2 stored at index 1, etc.
|
||||
// level 0 not allowed
|
||||
this.shareBinsByLevelV2[level - 1] = accountLevelShareBin;
|
||||
|
||||
// Convert collections to unmodifiable form
|
||||
this.rewardsByHeight = Collections.unmodifiableList(this.rewardsByHeight);
|
||||
this.sharesByLevel = Collections.unmodifiableList(this.sharesByLevel);
|
||||
this.sharesByLevelV1 = Collections.unmodifiableList(this.sharesByLevelV1);
|
||||
this.sharesByLevelV2 = Collections.unmodifiableList(this.sharesByLevelV2);
|
||||
this.blocksNeededByLevel = Collections.unmodifiableList(this.blocksNeededByLevel);
|
||||
this.cumulativeBlocksByLevel = Collections.unmodifiableList(this.cumulativeBlocksByLevel);
|
||||
this.blockTimingsByHeight = Collections.unmodifiableList(this.blockTimingsByHeight);
|
||||
|
@ -39,13 +39,20 @@
|
||||
{ "height": 2851201, "reward": 2.25 },
|
||||
{ "height": 3110401, "reward": 2.00 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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": 9999999, "share": 0.01 }
|
||||
@ -67,6 +74,7 @@
|
||||
"atFindNextTransactionFix": 275000,
|
||||
"newBlockSigHeight": 320000,
|
||||
"shareBinFix": 399000,
|
||||
"sharesByLevelV2Height": 9999999,
|
||||
"rewardShareLimitTimestamp": 1657382400000,
|
||||
"calcChainWeightTimestamp": 1620579600000,
|
||||
"transactionV5Timestamp": 1642176000000,
|
||||
|
@ -192,7 +192,7 @@ public class RewardTests extends Common {
|
||||
|
||||
@Test
|
||||
public void testLegacyQoraRewardReduction() throws DataException {
|
||||
Common.useSettings("test-settings-v2-qora-holder-extremes.json");
|
||||
Common.useSettings("test-settings-v2-qora-holder-reduction.json");
|
||||
|
||||
// Make sure that the QORA share reduces between blocks 4 and 5
|
||||
assertTrue(BlockChain.getInstance().getQoraHoldersShareAtHeight(5) < BlockChain.getInstance().getQoraHoldersShareAtHeight(4));
|
||||
@ -1182,6 +1182,250 @@ public class RewardTests extends Common {
|
||||
}
|
||||
}
|
||||
|
||||
/** Test rewards for level 1 and 2 accounts with V2 share-bin layout (post QORA reduction) */
|
||||
@Test
|
||||
public void testLevel1And2RewardsShareBinsV2() throws DataException {
|
||||
Common.useSettings("test-settings-v2-reward-levels.json");
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
|
||||
List<PrivateKeyAccount> mintingAndOnlineAccounts = new ArrayList<>();
|
||||
|
||||
// Alice self share online
|
||||
PrivateKeyAccount aliceSelfShare = Common.getTestAccount(repository, "alice-reward-share");
|
||||
mintingAndOnlineAccounts.add(aliceSelfShare);
|
||||
byte[] chloeRewardSharePrivateKey;
|
||||
// Bob self-share NOT online
|
||||
|
||||
// Mint some blocks, to get us close to the V2 activation, but with some room for Chloe and Dilbert to start minting some blocks
|
||||
for (int i=0; i<990; i++)
|
||||
BlockMinter.mintTestingBlock(repository, mintingAndOnlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||
|
||||
// Chloe self share comes online
|
||||
try {
|
||||
chloeRewardSharePrivateKey = AccountUtils.rewardShare(repository, "chloe", "chloe", 0);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.error("FAILED {}", ex.getLocalizedMessage(), ex);
|
||||
throw ex;
|
||||
}
|
||||
PrivateKeyAccount chloeRewardShareAccount = new PrivateKeyAccount(repository, chloeRewardSharePrivateKey);
|
||||
mintingAndOnlineAccounts.add(chloeRewardShareAccount);
|
||||
|
||||
// Dilbert self share comes online
|
||||
byte[] dilbertRewardSharePrivateKey = AccountUtils.rewardShare(repository, "dilbert", "dilbert", 0);
|
||||
PrivateKeyAccount dilbertRewardShareAccount = new PrivateKeyAccount(repository, dilbertRewardSharePrivateKey);
|
||||
mintingAndOnlineAccounts.add(dilbertRewardShareAccount);
|
||||
|
||||
// Mint 6 more blocks, so that V2 share bins are nearly activated
|
||||
for (int i=0; i<6; i++)
|
||||
BlockMinter.mintTestingBlock(repository, mintingAndOnlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||
|
||||
// Ensure that the levels are as we expect
|
||||
assertEquals(10, (int) Common.getTestAccount(repository, "alice").getLevel());
|
||||
assertEquals(1, (int) Common.getTestAccount(repository, "bob").getLevel());
|
||||
assertEquals(1, (int) Common.getTestAccount(repository, "chloe").getLevel());
|
||||
assertEquals(2, (int) Common.getTestAccount(repository, "dilbert").getLevel());
|
||||
|
||||
// Ensure that only Alice is a founder
|
||||
assertEquals(1, getFlags(repository, "alice"));
|
||||
assertEquals(0, getFlags(repository, "bob"));
|
||||
assertEquals(0, getFlags(repository, "chloe"));
|
||||
assertEquals(0, getFlags(repository, "dilbert"));
|
||||
|
||||
// Now that everyone is at level 1 or 2, we can capture initial balances
|
||||
Map<String, Map<Long, Long>> initialBalances = AccountUtils.getBalances(repository, Asset.QORT, Asset.LEGACY_QORA, Asset.QORT_FROM_QORA);
|
||||
final long aliceInitialBalance = initialBalances.get("alice").get(Asset.QORT);
|
||||
final long bobInitialBalance = initialBalances.get("bob").get(Asset.QORT);
|
||||
final long chloeInitialBalance = initialBalances.get("chloe").get(Asset.QORT);
|
||||
final long dilbertInitialBalance = initialBalances.get("dilbert").get(Asset.QORT);
|
||||
|
||||
// Mint a block
|
||||
final long blockReward = BlockUtils.getNextBlockReward(repository);
|
||||
BlockMinter.mintTestingBlock(repository, mintingAndOnlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||
|
||||
// Ensure we are at the correct height and block reward value
|
||||
assertEquals(1000, (int) repository.getBlockRepository().getLastBlock().getHeight());
|
||||
assertEquals(100000000L, blockReward);
|
||||
|
||||
// We are past the sharesByLevelV2Height feature trigger, so we expect level 1 and 2 to share the increased reward (6%)
|
||||
final int level1And2SharePercent = 6_00; // 6%
|
||||
final long level1And2ShareAmount = (blockReward * level1And2SharePercent) / 100L / 100L;
|
||||
final long expectedLevel1And2RewardV2 = level1And2ShareAmount / 2; // The reward is split between Chloe and Dilbert
|
||||
final long expectedFounderRewardV2 = blockReward - level1And2ShareAmount; // Alice should receive the remainder
|
||||
|
||||
// Validate the balances
|
||||
assertEquals(6000000, level1And2ShareAmount);
|
||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, aliceInitialBalance+expectedFounderRewardV2);
|
||||
AccountUtils.assertBalance(repository, "bob", Asset.QORT, bobInitialBalance); // Bob not online so his balance remains the same
|
||||
AccountUtils.assertBalance(repository, "chloe", Asset.QORT, chloeInitialBalance+expectedLevel1And2RewardV2);
|
||||
AccountUtils.assertBalance(repository, "dilbert", Asset.QORT, dilbertInitialBalance+expectedLevel1And2RewardV2);
|
||||
|
||||
// Now orphan the latest block. This brings us to the threshold of the sharesByLevelV2Height feature trigger
|
||||
BlockUtils.orphanBlocks(repository, 1);
|
||||
assertEquals(999, (int) repository.getBlockRepository().getLastBlock().getHeight());
|
||||
|
||||
// Ensure the latest block rewards have been subtracted and they have returned to their initial values
|
||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, aliceInitialBalance);
|
||||
AccountUtils.assertBalance(repository, "bob", Asset.QORT, bobInitialBalance); // Bob not online so his balance remains the same
|
||||
AccountUtils.assertBalance(repository, "chloe", Asset.QORT, chloeInitialBalance);
|
||||
AccountUtils.assertBalance(repository, "dilbert", Asset.QORT, dilbertInitialBalance);
|
||||
|
||||
// Orphan another block. This time, the block that was orphaned was prior to the sharesByLevelV2Height feature trigger.
|
||||
BlockUtils.orphanBlocks(repository, 1);
|
||||
assertEquals(998, (int) repository.getBlockRepository().getLastBlock().getHeight());
|
||||
|
||||
// In V1 of share-bins, level 1-2 pays out 5% instead of 6%
|
||||
final int level1And2SharePercentV1 = 5_00; // 5%
|
||||
final long level1And2ShareAmountV1 = (blockReward * level1And2SharePercentV1) / 100L / 100L;
|
||||
final long expectedLevel1And2RewardV1 = level1And2ShareAmountV1 / 2; // The reward is split between Chloe and Dilbert
|
||||
final long expectedFounderRewardV1 = blockReward - level1And2ShareAmountV1; // Alice should receive the remainder
|
||||
|
||||
// Validate the share amounts and balances
|
||||
assertEquals(5000000, level1And2ShareAmountV1);
|
||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, aliceInitialBalance-expectedFounderRewardV1);
|
||||
AccountUtils.assertBalance(repository, "bob", Asset.QORT, bobInitialBalance); // Bob not online so his balance remains the same
|
||||
AccountUtils.assertBalance(repository, "chloe", Asset.QORT, chloeInitialBalance-expectedLevel1And2RewardV1);
|
||||
AccountUtils.assertBalance(repository, "dilbert", Asset.QORT, dilbertInitialBalance-expectedLevel1And2RewardV1);
|
||||
|
||||
// Orphan the latest block one last time
|
||||
BlockUtils.orphanBlocks(repository, 1);
|
||||
assertEquals(997, (int) repository.getBlockRepository().getLastBlock().getHeight());
|
||||
|
||||
// Validate balances
|
||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, aliceInitialBalance-(expectedFounderRewardV1*2));
|
||||
AccountUtils.assertBalance(repository, "bob", Asset.QORT, bobInitialBalance); // Bob not online so his balance remains the same
|
||||
AccountUtils.assertBalance(repository, "chloe", Asset.QORT, chloeInitialBalance-(expectedLevel1And2RewardV1*2));
|
||||
AccountUtils.assertBalance(repository, "dilbert", Asset.QORT, dilbertInitialBalance-(expectedLevel1And2RewardV1*2));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** Test rewards for level 1 and 2 accounts with V2 share-bin layout (post QORA reduction)
|
||||
* plus some legacy QORA holders */
|
||||
@Test
|
||||
public void testLevel1And2RewardsShareBinsV2WithQoraHolders() throws DataException {
|
||||
Common.useSettings("test-settings-v2-qora-holder-extremes.json");
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
|
||||
List<PrivateKeyAccount> mintingAndOnlineAccounts = new ArrayList<>();
|
||||
|
||||
// Some legacy QORA holders exist (Bob and Chloe)
|
||||
|
||||
// Alice self share online
|
||||
PrivateKeyAccount aliceSelfShare = Common.getTestAccount(repository, "alice-reward-share");
|
||||
mintingAndOnlineAccounts.add(aliceSelfShare);
|
||||
byte[] chloeRewardSharePrivateKey;
|
||||
// Bob self-share NOT online
|
||||
|
||||
// Mint some blocks, to get us close to the V2 activation, but with some room for Chloe and Dilbert to start minting some blocks
|
||||
for (int i=0; i<990; i++)
|
||||
BlockMinter.mintTestingBlock(repository, mintingAndOnlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||
|
||||
// Chloe self share comes online
|
||||
try {
|
||||
chloeRewardSharePrivateKey = AccountUtils.rewardShare(repository, "chloe", "chloe", 0);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.error("FAILED {}", ex.getLocalizedMessage(), ex);
|
||||
throw ex;
|
||||
}
|
||||
PrivateKeyAccount chloeRewardShareAccount = new PrivateKeyAccount(repository, chloeRewardSharePrivateKey);
|
||||
mintingAndOnlineAccounts.add(chloeRewardShareAccount);
|
||||
|
||||
// Dilbert self share comes online
|
||||
byte[] dilbertRewardSharePrivateKey = AccountUtils.rewardShare(repository, "dilbert", "dilbert", 0);
|
||||
PrivateKeyAccount dilbertRewardShareAccount = new PrivateKeyAccount(repository, dilbertRewardSharePrivateKey);
|
||||
mintingAndOnlineAccounts.add(dilbertRewardShareAccount);
|
||||
|
||||
// Mint 6 more blocks, so that V2 share bins are nearly activated
|
||||
for (int i=0; i<6; i++)
|
||||
BlockMinter.mintTestingBlock(repository, mintingAndOnlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||
|
||||
// Ensure that the levels are as we expect
|
||||
assertEquals(10, (int) Common.getTestAccount(repository, "alice").getLevel());
|
||||
assertEquals(1, (int) Common.getTestAccount(repository, "bob").getLevel());
|
||||
assertEquals(1, (int) Common.getTestAccount(repository, "chloe").getLevel());
|
||||
assertEquals(2, (int) Common.getTestAccount(repository, "dilbert").getLevel());
|
||||
|
||||
// Ensure that only Alice is a founder
|
||||
assertEquals(1, getFlags(repository, "alice"));
|
||||
assertEquals(0, getFlags(repository, "bob"));
|
||||
assertEquals(0, getFlags(repository, "chloe"));
|
||||
assertEquals(0, getFlags(repository, "dilbert"));
|
||||
|
||||
// Now that everyone is at level 1 or 2, we can capture initial balances
|
||||
Map<String, Map<Long, Long>> initialBalances = AccountUtils.getBalances(repository, Asset.QORT, Asset.LEGACY_QORA, Asset.QORT_FROM_QORA);
|
||||
final long aliceInitialBalance = initialBalances.get("alice").get(Asset.QORT);
|
||||
final long bobInitialBalance = initialBalances.get("bob").get(Asset.QORT);
|
||||
final long chloeInitialBalance = initialBalances.get("chloe").get(Asset.QORT);
|
||||
final long dilbertInitialBalance = initialBalances.get("dilbert").get(Asset.QORT);
|
||||
|
||||
// Mint a block
|
||||
final long blockReward = BlockUtils.getNextBlockReward(repository);
|
||||
BlockMinter.mintTestingBlock(repository, mintingAndOnlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||
|
||||
// Ensure we are at the correct height and block reward value
|
||||
assertEquals(1000, (int) repository.getBlockRepository().getLastBlock().getHeight());
|
||||
assertEquals(100000000L, blockReward);
|
||||
|
||||
// We are past the sharesByLevelV2Height feature trigger, so we expect level 1 and 2 to share the increased reward (6%)
|
||||
// and the QORA share will be 1%
|
||||
final int level1And2SharePercent = 6_00; // 6%
|
||||
final int qoraSharePercentV2 = 1_00; // 1%
|
||||
final long qoraShareAmountV2 = (blockReward * qoraSharePercentV2) / 100L / 100L;
|
||||
final long level1And2ShareAmount = (blockReward * level1And2SharePercent) / 100L / 100L;
|
||||
final long expectedLevel1And2RewardV2 = level1And2ShareAmount / 2; // The reward is split between Chloe and Dilbert
|
||||
final long expectedFounderRewardV2 = blockReward - level1And2ShareAmount - qoraShareAmountV2; // Alice should receive the remainder
|
||||
|
||||
// Validate the balances
|
||||
assertEquals(6000000, level1And2ShareAmount);
|
||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, aliceInitialBalance+expectedFounderRewardV2);
|
||||
AccountUtils.assertBalance(repository, "bob", Asset.QORT, bobInitialBalance); // Bob not online so his balance remains the same
|
||||
// Chloe is a QORA holder and will receive additional QORT, so it's not easy to pre-calculate her balance
|
||||
AccountUtils.assertBalance(repository, "dilbert", Asset.QORT, dilbertInitialBalance+expectedLevel1And2RewardV2);
|
||||
|
||||
// Now orphan the latest block. This brings us to the threshold of the sharesByLevelV2Height feature trigger
|
||||
BlockUtils.orphanBlocks(repository, 1);
|
||||
assertEquals(999, (int) repository.getBlockRepository().getLastBlock().getHeight());
|
||||
|
||||
// Ensure the latest block rewards have been subtracted and they have returned to their initial values
|
||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, aliceInitialBalance);
|
||||
AccountUtils.assertBalance(repository, "bob", Asset.QORT, bobInitialBalance); // Bob not online so his balance remains the same
|
||||
AccountUtils.assertBalance(repository, "chloe", Asset.QORT, chloeInitialBalance);
|
||||
AccountUtils.assertBalance(repository, "dilbert", Asset.QORT, dilbertInitialBalance);
|
||||
|
||||
// Orphan another block. This time, the block that was orphaned was prior to the sharesByLevelV2Height feature trigger.
|
||||
BlockUtils.orphanBlocks(repository, 1);
|
||||
assertEquals(998, (int) repository.getBlockRepository().getLastBlock().getHeight());
|
||||
|
||||
// In V1 of share-bins, level 1-2 pays out 5% instead of 6%, and the QORA share is higher at 20%
|
||||
final int level1And2SharePercentV1 = 5_00; // 5%
|
||||
final int qoraSharePercentV1 = 20_00; // 20%
|
||||
final long qoraShareAmountV1 = (blockReward * qoraSharePercentV1) / 100L / 100L;
|
||||
final long level1And2ShareAmountV1 = (blockReward * level1And2SharePercentV1) / 100L / 100L;
|
||||
final long expectedLevel1And2RewardV1 = level1And2ShareAmountV1 / 2; // The reward is split between Chloe and Dilbert
|
||||
final long expectedFounderRewardV1 = blockReward - level1And2ShareAmountV1 - qoraShareAmountV1; // Alice should receive the remainder
|
||||
|
||||
// Validate the share amounts and balances
|
||||
assertEquals(5000000, level1And2ShareAmountV1);
|
||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, aliceInitialBalance-expectedFounderRewardV1);
|
||||
AccountUtils.assertBalance(repository, "bob", Asset.QORT, bobInitialBalance); // Bob not online so his balance remains the same
|
||||
// Chloe is a QORA holder and will receive additional QORT, so it's not easy to pre-calculate her balance
|
||||
AccountUtils.assertBalance(repository, "dilbert", Asset.QORT, dilbertInitialBalance-expectedLevel1And2RewardV1);
|
||||
|
||||
// Orphan the latest block one last time
|
||||
BlockUtils.orphanBlocks(repository, 1);
|
||||
assertEquals(997, (int) repository.getBlockRepository().getLastBlock().getHeight());
|
||||
|
||||
// Validate balances
|
||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, aliceInitialBalance-(expectedFounderRewardV1*2));
|
||||
AccountUtils.assertBalance(repository, "bob", Asset.QORT, bobInitialBalance); // Bob not online so his balance remains the same
|
||||
// Chloe is a QORA holder and will receive additional QORT, so it's not easy to pre-calculate her balance
|
||||
AccountUtils.assertBalance(repository, "dilbert", Asset.QORT, dilbertInitialBalance-(expectedLevel1And2RewardV1*2));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int getFlags(Repository repository, String name) throws DataException {
|
||||
TestAccount testAccount = Common.getTestAccount(repository, name);
|
||||
|
@ -19,13 +19,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -57,6 +64,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -23,13 +23,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -60,6 +67,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -24,13 +24,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -61,6 +68,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -24,13 +24,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -61,6 +68,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -24,13 +24,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -61,6 +68,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -20,12 +20,19 @@
|
||||
{ "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 }
|
||||
"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 }
|
||||
],
|
||||
"qoraHoldersShare": 0.20,
|
||||
"qoraPerQortReward": 250,
|
||||
@ -52,6 +59,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -24,16 +24,23 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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": 5, "share": 0.01 }
|
||||
{ "height": 1000, "share": 0.01 }
|
||||
],
|
||||
"qoraPerQortReward": 250,
|
||||
"minAccountsToActivateShareBin": 30,
|
||||
@ -60,7 +67,8 @@
|
||||
"groupApprovalTimestamp": 0,
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"shareBinFix": 0,
|
||||
"sharesByLevelV2Height": 1000,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
@ -93,7 +101,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": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "level": 1 },
|
||||
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 2 },
|
||||
{ "type": "ACCOUNT_LEVEL", "target": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "level": 1 },
|
||||
{ "type": "ACCOUNT_LEVEL", "target": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "level": 1 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
107
src/test/resources/test-chain-v2-qora-holder-reduction.json
Normal file
107
src/test/resources/test-chain-v2-qora-holder-reduction.json
Normal file
@ -0,0 +1,107 @@
|
||||
{
|
||||
"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": 9999999999999, "maxShares": 3 }
|
||||
],
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||
"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": 5, "share": 0.01 }
|
||||
],
|
||||
"qoraPerQortReward": 250,
|
||||
"minAccountsToActivateShareBin": 30,
|
||||
"shareBinActivationMinLevel": 7,
|
||||
"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,
|
||||
"sharesByLevelV2Height": 5,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 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": "GENESIS", "recipient": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "amount": "637557960.49687541", "assetId": 1 },
|
||||
{ "type": "GENESIS", "recipient": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "amount": "0.666", "assetId": 1 },
|
||||
|
||||
{ "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": 8 }
|
||||
]
|
||||
}
|
||||
}
|
@ -24,13 +24,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -61,6 +68,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 1000,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -24,16 +24,23 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
{ "height": 1000, "share": 0.01 }
|
||||
],
|
||||
"qoraPerQortReward": 250,
|
||||
"minAccountsToActivateShareBin": 1,
|
||||
@ -61,6 +68,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 6,
|
||||
"sharesByLevelV2Height": 1000,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -24,13 +24,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -61,6 +68,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -23,13 +23,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -60,6 +67,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 0,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"newConsensusTimestamp": 0,
|
||||
|
@ -24,13 +24,20 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
"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 }
|
||||
@ -61,6 +68,7 @@
|
||||
"atFindNextTransactionFix": 0,
|
||||
"newBlockSigHeight": 999999,
|
||||
"shareBinFix": 999999,
|
||||
"sharesByLevelV2Height": 999999,
|
||||
"rewardShareLimitTimestamp": 9999999999999,
|
||||
"calcChainWeightTimestamp": 0,
|
||||
"transactionV5Timestamp": 0,
|
||||
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"repositoryPath": "testdb",
|
||||
"restrictedApi": false,
|
||||
"blockchainConfig": "src/test/resources/test-chain-v2-qora-holder-reduction.json",
|
||||
"exportPath": "qortal-backup-test",
|
||||
"bootstrap": false,
|
||||
"wipeUnconfirmedOnStart": false,
|
||||
"testNtpOffset": 0,
|
||||
"minPeers": 0,
|
||||
"pruneBlockLimit": 100
|
||||
}
|
Loading…
Reference in New Issue
Block a user