mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-23 04:36:50 +00:00
Higher account levels more likely to win blocks
Also: RewardShareKeys app now supports only one arg (minter private key) in self-reward-share mode, where recipient public key is derived from minter private key. Added methods to Account for returning 'effective' minting level where minting level for founders is read from blockchain config. (Or returns zero if unable to mint). Changed two Block constructors into static methods that return a new Block as there was way too much work being done to really be called a constructor, especially with all the opportunities to throw an exception too. Main blockchain config updated to reflect near-launch version. Added/changed blockchain weight tests to check block winning based on higher account levels.
This commit is contained in:
@@ -4,131 +4,182 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.qora.crypto.Crypto;
|
||||
import org.qora.account.Account;
|
||||
import org.qora.block.Block;
|
||||
import org.qora.data.block.BlockSummaryData;
|
||||
import org.qora.repository.DataException;
|
||||
import org.qora.repository.Repository;
|
||||
import org.qora.repository.RepositoryManager;
|
||||
import org.qora.test.common.Common;
|
||||
import org.qora.test.common.TestAccount;
|
||||
import org.qora.transform.Transformer;
|
||||
import org.qora.transform.block.BlockTransformer;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.google.common.primitives.Longs;
|
||||
public class ChainWeightTests extends Common {
|
||||
|
||||
public class ChainWeightTests {
|
||||
|
||||
private static final int ACCOUNTS_COUNT_SHIFT = Transformer.PUBLIC_KEY_LENGTH * 8;
|
||||
private static final int CHAIN_WEIGHT_SHIFT = 8;
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private static final BigInteger MAX_DISTANCE;
|
||||
static {
|
||||
byte[] maxValue = new byte[Transformer.PUBLIC_KEY_LENGTH];
|
||||
Arrays.fill(maxValue, (byte) 0xFF);
|
||||
MAX_DISTANCE = new BigInteger(1, maxValue);
|
||||
@Before
|
||||
public void beforeTest() throws DataException {
|
||||
Common.useSettings("test-settings-v2-minting.json");
|
||||
}
|
||||
|
||||
|
||||
private static byte[] perturbPublicKey(int height, byte[] publicKey) {
|
||||
return Crypto.digest(Bytes.concat(Longs.toByteArray(height), publicKey));
|
||||
}
|
||||
|
||||
private static BigInteger calcKeyDistance(int parentHeight, byte[] parentGeneratorKey, byte[] publicKey) {
|
||||
byte[] idealKey = perturbPublicKey(parentHeight, parentGeneratorKey);
|
||||
byte[] perturbedKey = perturbPublicKey(parentHeight + 1, publicKey);
|
||||
|
||||
BigInteger keyDistance = MAX_DISTANCE.subtract(new BigInteger(idealKey).subtract(new BigInteger(perturbedKey)).abs());
|
||||
return keyDistance;
|
||||
}
|
||||
|
||||
private static BigInteger calcBlockWeight(int parentHeight, byte[] parentGeneratorKey, BlockSummaryData blockSummaryData) {
|
||||
BigInteger keyDistance = calcKeyDistance(parentHeight, parentGeneratorKey, blockSummaryData.getMinterPublicKey());
|
||||
BigInteger weight = BigInteger.valueOf(blockSummaryData.getOnlineAccountsCount()).shiftLeft(ACCOUNTS_COUNT_SHIFT).add(keyDistance);
|
||||
return weight;
|
||||
}
|
||||
|
||||
private static BigInteger calcChainWeight(int commonBlockHeight, byte[] commonBlockGeneratorKey, List<BlockSummaryData> blockSummaries) {
|
||||
BigInteger cumulativeWeight = BigInteger.ZERO;
|
||||
int parentHeight = commonBlockHeight;
|
||||
byte[] parentGeneratorKey = commonBlockGeneratorKey;
|
||||
|
||||
for (BlockSummaryData blockSummaryData : blockSummaries) {
|
||||
cumulativeWeight = cumulativeWeight.shiftLeft(CHAIN_WEIGHT_SHIFT).add(calcBlockWeight(parentHeight, parentGeneratorKey, blockSummaryData));
|
||||
parentHeight = blockSummaryData.getHeight();
|
||||
parentGeneratorKey = blockSummaryData.getMinterPublicKey();
|
||||
}
|
||||
|
||||
return cumulativeWeight;
|
||||
}
|
||||
|
||||
private static BlockSummaryData genBlockSummary(int height) {
|
||||
byte[] generatorPublicKey = new byte[Transformer.PUBLIC_KEY_LENGTH];
|
||||
RANDOM.nextBytes(generatorPublicKey);
|
||||
private static BlockSummaryData genBlockSummary(Repository repository, int height) {
|
||||
TestAccount testAccount = Common.getRandomTestAccount(repository, true);
|
||||
byte[] minterPublicKey = testAccount.getPublicKey();
|
||||
|
||||
byte[] signature = new byte[BlockTransformer.BLOCK_SIGNATURE_LENGTH];
|
||||
RANDOM.nextBytes(signature);
|
||||
|
||||
int onlineAccountsCount = RANDOM.nextInt(1000);
|
||||
|
||||
return new BlockSummaryData(height, signature, generatorPublicKey, onlineAccountsCount);
|
||||
return new BlockSummaryData(height, signature, minterPublicKey, onlineAccountsCount);
|
||||
}
|
||||
|
||||
private static List<BlockSummaryData> genBlockSummaries(int count, BlockSummaryData commonBlockSummary) {
|
||||
private static List<BlockSummaryData> genBlockSummaries(Repository repository, int count, BlockSummaryData commonBlockSummary) {
|
||||
List<BlockSummaryData> blockSummaries = new ArrayList<>();
|
||||
blockSummaries.add(commonBlockSummary);
|
||||
|
||||
final int commonBlockHeight = commonBlockSummary.getHeight();
|
||||
|
||||
for (int i = 1; i <= count; ++i)
|
||||
blockSummaries.add(genBlockSummary(commonBlockHeight + i));
|
||||
blockSummaries.add(genBlockSummary(repository, commonBlockHeight + i));
|
||||
|
||||
return blockSummaries;
|
||||
}
|
||||
|
||||
// Check that more online accounts beats a better key
|
||||
@Test
|
||||
public void testMoreAccountsBlock() {
|
||||
final int parentHeight = 1;
|
||||
final byte[] parentGeneratorKey = new byte[Transformer.PUBLIC_KEY_LENGTH];
|
||||
public void testMoreAccountsBlock() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
final int parentHeight = 1;
|
||||
final byte[] parentMinterKey = new byte[Transformer.PUBLIC_KEY_LENGTH];
|
||||
|
||||
int betterAccountsCount = 100;
|
||||
int worseAccountsCount = 20;
|
||||
int betterAccountsCount = 100;
|
||||
int worseAccountsCount = 20;
|
||||
|
||||
byte[] betterKey = new byte[Transformer.PUBLIC_KEY_LENGTH];
|
||||
betterKey[0] = 0x41;
|
||||
TestAccount betterAccount = Common.getTestAccount(repository, "bob-reward-share");
|
||||
byte[] betterKey = betterAccount.getPublicKey();
|
||||
int betterMinterLevel = Account.getRewardShareEffectiveMintingLevel(repository, betterKey);
|
||||
|
||||
byte[] worseKey = new byte[Transformer.PUBLIC_KEY_LENGTH];
|
||||
worseKey[0] = 0x23;
|
||||
TestAccount worseAccount = Common.getTestAccount(repository, "dilbert-reward-share");
|
||||
byte[] worseKey = worseAccount.getPublicKey();
|
||||
int worseMinterLevel = Account.getRewardShareEffectiveMintingLevel(repository, worseKey);
|
||||
|
||||
BigInteger betterKeyDistance = calcKeyDistance(parentHeight, parentGeneratorKey, betterKey);
|
||||
BigInteger worseKeyDistance = calcKeyDistance(parentHeight, parentGeneratorKey, worseKey);
|
||||
assertEquals("hard-coded keys are wrong", 1, betterKeyDistance.compareTo(worseKeyDistance));
|
||||
// This is to check that the hard-coded keys ARE actually better/worse as expected, before moving on testing more online accounts
|
||||
BigInteger betterKeyDistance = Block.calcKeyDistance(parentHeight, parentMinterKey, betterKey, betterMinterLevel);
|
||||
BigInteger worseKeyDistance = Block.calcKeyDistance(parentHeight, parentMinterKey, worseKey, worseMinterLevel);
|
||||
assertEquals("hard-coded keys are wrong", 1, betterKeyDistance.compareTo(worseKeyDistance));
|
||||
|
||||
BlockSummaryData betterBlockSummary = new BlockSummaryData(parentHeight + 1, null, worseKey, betterAccountsCount);
|
||||
BlockSummaryData worseBlockSummary = new BlockSummaryData(parentHeight + 1, null, betterKey, worseAccountsCount);
|
||||
BlockSummaryData betterBlockSummary = new BlockSummaryData(parentHeight + 1, null, worseKey, betterAccountsCount);
|
||||
BlockSummaryData worseBlockSummary = new BlockSummaryData(parentHeight + 1, null, betterKey, worseAccountsCount);
|
||||
|
||||
BigInteger betterBlockWeight = calcBlockWeight(parentHeight, parentGeneratorKey, betterBlockSummary);
|
||||
BigInteger worseBlockWeight = calcBlockWeight(parentHeight, parentGeneratorKey, worseBlockSummary);
|
||||
populateBlockSummaryMinterLevel(repository, betterBlockSummary);
|
||||
populateBlockSummaryMinterLevel(repository, worseBlockSummary);
|
||||
|
||||
assertEquals("block weights are wrong", 1, betterBlockWeight.compareTo(worseBlockWeight));
|
||||
BigInteger betterBlockWeight = Block.calcBlockWeight(parentHeight, parentMinterKey, betterBlockSummary);
|
||||
BigInteger worseBlockWeight = Block.calcBlockWeight(parentHeight, parentMinterKey, worseBlockSummary);
|
||||
|
||||
assertEquals("block weights are wrong", 1, betterBlockWeight.compareTo(worseBlockWeight));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that a longer chain beats a shorter chain
|
||||
@Test
|
||||
public void testLongerChain() {
|
||||
final int commonBlockHeight = 1;
|
||||
BlockSummaryData commonBlockSummary = genBlockSummary(commonBlockHeight);
|
||||
byte[] commonBlockGeneratorKey = commonBlockSummary.getMinterPublicKey();
|
||||
public void testLongerChain() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
final int commonBlockHeight = 1;
|
||||
BlockSummaryData commonBlockSummary = genBlockSummary(repository, commonBlockHeight);
|
||||
byte[] commonBlockGeneratorKey = commonBlockSummary.getMinterPublicKey();
|
||||
|
||||
List<BlockSummaryData> shorterChain = genBlockSummaries(3, commonBlockSummary);
|
||||
List<BlockSummaryData> longerChain = genBlockSummaries(shorterChain.size() + 1, commonBlockSummary);
|
||||
List<BlockSummaryData> shorterChain = genBlockSummaries(repository, 3, commonBlockSummary);
|
||||
List<BlockSummaryData> longerChain = genBlockSummaries(repository, shorterChain.size() + 1, commonBlockSummary);
|
||||
|
||||
BigInteger shorterChainWeight = calcChainWeight(commonBlockHeight, commonBlockGeneratorKey, shorterChain);
|
||||
BigInteger longerChainWeight = calcChainWeight(commonBlockHeight, commonBlockGeneratorKey, longerChain);
|
||||
populateBlockSummariesMinterLevels(repository, shorterChain);
|
||||
populateBlockSummariesMinterLevels(repository, longerChain);
|
||||
|
||||
assertEquals("longer chain should have greater weight", 1, longerChainWeight.compareTo(shorterChainWeight));
|
||||
BigInteger shorterChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockGeneratorKey, shorterChain);
|
||||
BigInteger longerChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockGeneratorKey, longerChain);
|
||||
|
||||
assertEquals("longer chain should have greater weight", 1, longerChainWeight.compareTo(shorterChainWeight));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that a higher level account wins more blocks
|
||||
@Test
|
||||
public void testMinterLevel() throws DataException {
|
||||
testMinterLevels("chloe-reward-share", "bob-reward-share");
|
||||
}
|
||||
|
||||
private void testMinterLevels(String betterMinterName, String worseMinterName) throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
TestAccount betterAccount = Common.getTestAccount(repository, betterMinterName);
|
||||
byte[] betterKey = betterAccount.getPublicKey();
|
||||
int betterMinterLevel = Account.getRewardShareEffectiveMintingLevel(repository, betterKey);
|
||||
|
||||
TestAccount worseAccount = Common.getTestAccount(repository, worseMinterName);
|
||||
byte[] worseKey = worseAccount.getPublicKey();
|
||||
int worseMinterLevel = Account.getRewardShareEffectiveMintingLevel(repository, worseKey);
|
||||
|
||||
// Check hard-coded accounts have expected better/worse levels
|
||||
assertTrue("hard-coded accounts have wrong relative minting levels", betterMinterLevel > worseMinterLevel);
|
||||
|
||||
Random random = new Random();
|
||||
final int onlineAccountsCount = 100;
|
||||
int betterAccountWins = 0;
|
||||
int worseAccountWins = 0;
|
||||
byte[] parentSignature = new byte[64];
|
||||
random.nextBytes(parentSignature);
|
||||
|
||||
for (int parentHeight = 1; parentHeight < 1000; ++parentHeight) {
|
||||
byte[] blockSignature = new byte[64];
|
||||
random.nextBytes(blockSignature);
|
||||
|
||||
BlockSummaryData betterBlockSummary = new BlockSummaryData(parentHeight + 1, blockSignature, worseKey, onlineAccountsCount);
|
||||
BlockSummaryData worseBlockSummary = new BlockSummaryData(parentHeight + 1, blockSignature, betterKey, onlineAccountsCount);
|
||||
|
||||
populateBlockSummaryMinterLevel(repository, betterBlockSummary);
|
||||
populateBlockSummaryMinterLevel(repository, worseBlockSummary);
|
||||
|
||||
BigInteger betterBlockWeight = Block.calcBlockWeight(parentHeight, parentSignature, betterBlockSummary);
|
||||
BigInteger worseBlockWeight = Block.calcBlockWeight(parentHeight, parentSignature, worseBlockSummary);
|
||||
|
||||
if (betterBlockWeight.compareTo(worseBlockWeight) >= 0)
|
||||
++betterAccountWins;
|
||||
else
|
||||
++worseAccountWins;
|
||||
|
||||
parentSignature = blockSignature;
|
||||
}
|
||||
|
||||
assertTrue("Account with better minting level didn't win more blocks", betterAccountWins > worseAccountWins);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that a higher level account wins more blocks
|
||||
@Test
|
||||
public void testFounderMinterLevel() throws DataException {
|
||||
testMinterLevels("alice-reward-share", "dilbert-reward-share");
|
||||
}
|
||||
|
||||
private void populateBlockSummariesMinterLevels(Repository repository, List<BlockSummaryData> blockSummaries) throws DataException {
|
||||
for (int i = 0; i < blockSummaries.size(); ++i) {
|
||||
BlockSummaryData blockSummary = blockSummaries.get(i);
|
||||
|
||||
populateBlockSummaryMinterLevel(repository, blockSummary);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateBlockSummaryMinterLevel(Repository repository, BlockSummaryData blockSummary) throws DataException {
|
||||
int minterLevel = Account.getRewardShareEffectiveMintingLevel(repository, blockSummary.getMinterPublicKey());
|
||||
assertNotSame("effective minter level should not be zero", 0, minterLevel);
|
||||
|
||||
blockSummary.setMinterLevel(minterLevel);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1155,7 +1155,7 @@ public class TransactionTests extends Common {
|
||||
}
|
||||
|
||||
private Block forgeBlock(TransactionData transactionData) throws DataException {
|
||||
Block block = new Block(repository, parentBlockData, generator);
|
||||
Block block = Block.mint(repository, parentBlockData, generator);
|
||||
block.addTransaction(transactionData);
|
||||
block.sign();
|
||||
return block;
|
||||
|
@@ -10,6 +10,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -71,12 +72,30 @@ public class Common {
|
||||
|
||||
// Alice reward-share with herself. Private key is reward-share private key, derived from Alice's private and public keys.
|
||||
testAccountsByName.put("alice-reward-share", new TestAccount(null, "alice-reward-share", "1CeDCg9TSdBwJNGVTGG7pCKsvsyyoEcaVXYvDT1Xb9f", true));
|
||||
// Bob self-share
|
||||
testAccountsByName.put("bob-reward-share", new TestAccount(null, "bob-reward-share", "975G6DJX2bhkq2dawxxDbNe5DcT33LbGto5tRueKVRDx", true));
|
||||
// Chloe self-share
|
||||
testAccountsByName.put("chloe-reward-share", new TestAccount(null, "chloe-reward-share", "2paayAXTbGmdLtJ7tNxY93bhPnWZwNYwk15KA37Sw5yS", true));
|
||||
// Dilbert self-share
|
||||
testAccountsByName.put("dilbert-reward-share", new TestAccount(null, "dilbert-reward-share", "C3DqD3K9bZDqxwLBroXc2NgL2SRJrif1mcAW7zNMUg9", true));
|
||||
}
|
||||
|
||||
public static TestAccount getTestAccount(Repository repository, String name) {
|
||||
return new TestAccount(repository, testAccountsByName.get(name));
|
||||
}
|
||||
|
||||
public static TestAccount getRandomTestAccount(Repository repository, Boolean includeRewardShare) {
|
||||
List<TestAccount> testAccounts = new ArrayList<>(testAccountsByName.values());
|
||||
|
||||
if (includeRewardShare != null)
|
||||
testAccounts.removeIf(account -> account.isRewardShare != includeRewardShare);
|
||||
|
||||
Random random = new Random();
|
||||
int index = random.nextInt(testAccounts.size());
|
||||
|
||||
return testAccounts.get(index);
|
||||
}
|
||||
|
||||
public static List<TestAccount> getTestAccounts(Repository repository) {
|
||||
return testAccountsByName.values().stream().map(account -> new TestAccount(repository, account)).collect(Collectors.toList());
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
"rewardsByHeight": [
|
||||
@@ -23,6 +24,7 @@
|
||||
{ "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 }
|
||||
|
69
src/test/resources/test-chain-v2-minting.json
Normal file
69
src/test/resources/test-chain-v2-minting.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"isTestChain": true,
|
||||
"blockTimestampMargin": 500,
|
||||
"transactionExpiryPeriod": 86400000,
|
||||
"maxBlockSize": 2097152,
|
||||
"maxBytesPerUnitFee": 1024,
|
||||
"unitFee": "0.1",
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"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 }
|
||||
],
|
||||
"featureTriggers": {
|
||||
"messageHeight": 0,
|
||||
"atHeight": 0,
|
||||
"assetsTimestamp": 0,
|
||||
"votingTimestamp": 0,
|
||||
"arbitraryTimestamp": 0,
|
||||
"powfixTimestamp": 0,
|
||||
"v2Timestamp": 0,
|
||||
"newAssetPricingTimestamp": 0,
|
||||
"groupApprovalTimestamp": 0
|
||||
},
|
||||
"genesisInfo": {
|
||||
"version": 4,
|
||||
"timestamp": 0,
|
||||
"transactions": [
|
||||
{ "type": "ISSUE_ASSET", "owner": "QcFmNxSArv5tWEzCtTKb2Lqc5QkKuQ7RNs", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0, "reference": "3Verk6ZKBJc3WTTVfxFC9icSjKdM8b92eeJEpJP8qNizG4ZszNFq8wdDYdSjJXq2iogDFR1njyhsBdVpbvDfjzU7" },
|
||||
{ "type": "ISSUE_ASSET", "owner": "QUwGVHPPxJNJ2dq95abQNe79EyBN2K26zM", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
||||
{ "type": "ISSUE_ASSET", "owner": "QUwGVHPPxJNJ2dq95abQNe79EyBN2K26zM", "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": "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": 1 },
|
||||
{ "type": "REWARD_SHARE", "minterPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "rewardSharePublicKey": "CcABzvk26TFEHG7Yok84jxyd4oBtLkx8RJdGFVz2csvp", "sharePercent": 100 },
|
||||
|
||||
{ "type": "ACCOUNT_LEVEL", "target": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "level": 8 },
|
||||
{ "type": "REWARD_SHARE", "minterPublicKey": "7KNBj2MnEb6zq1vvKY1q8G2Voctcc2Z1X4avFyEH2eJC", "recipient": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "rewardSharePublicKey": "6bnEKqZbsCSWryUQnbBT9Umufdu3CapFvxfAni6afhFb", "sharePercent": 100 },
|
||||
|
||||
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 5 },
|
||||
{ "type": "REWARD_SHARE", "minterPublicKey": "CGAedAQU91SR73iqoYtss6NAsra284SShXnDWvRXqR4G", "recipient": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "rewardSharePublicKey": "4QafENiQCCDCnbXgcZfiyCu9qWqZ6YEciXAyFb4TT8YQ", "sharePercent": 100 }
|
||||
]
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
"rewardsByHeight": [
|
||||
|
@@ -8,6 +8,7 @@
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
"rewardsByHeight": [
|
||||
|
6
src/test/resources/test-settings-v2-minting.json
Normal file
6
src/test/resources/test-settings-v2-minting.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"restrictedApi": false,
|
||||
"blockchainConfig": "src/test/resources/test-chain-v2-minting.json",
|
||||
"wipeUnconfirmedOnStart": false,
|
||||
"minPeers": 0
|
||||
}
|
Reference in New Issue
Block a user