mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-23 04:36:50 +00:00
Work on granting forging rights
Move hard-coded forging tiers to blockchain config. Tests for granting forging rights. Added API call to list top block forgers. Fixed typo with Reward[s]ByHeight class name.
This commit is contained in:
@@ -5,6 +5,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.qora.account.PrivateKeyAccount;
|
||||
import org.qora.crypto.Crypto;
|
||||
import org.qora.data.transaction.EnableForgingTransactionData;
|
||||
import org.qora.data.transaction.PaymentTransactionData;
|
||||
import org.qora.data.transaction.ProxyForgingTransactionData;
|
||||
import org.qora.data.transaction.TransactionData;
|
||||
@@ -46,6 +48,30 @@ public class AccountUtils {
|
||||
return proxyPrivateKey;
|
||||
}
|
||||
|
||||
public static TransactionData createEnableForging(Repository repository, String forger, byte[] recipientPublicKey) throws DataException {
|
||||
PrivateKeyAccount forgingAccount = Common.getTestAccount(repository, forger);
|
||||
|
||||
byte[] reference = forgingAccount.getLastReference();
|
||||
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1000;
|
||||
|
||||
return new EnableForgingTransactionData(timestamp, txGroupId, reference, forgingAccount.getPublicKey(), Crypto.toAddress(recipientPublicKey), fee);
|
||||
}
|
||||
|
||||
public static TransactionData createEnableForging(Repository repository, String forger, String recipient) throws DataException {
|
||||
PrivateKeyAccount recipientAccount = Common.getTestAccount(repository, recipient);
|
||||
|
||||
return createEnableForging(repository, forger, recipientAccount.getPublicKey());
|
||||
}
|
||||
|
||||
public static TransactionData enableForging(Repository repository, String forger, String recipient) throws DataException {
|
||||
TransactionData transactionData = createEnableForging(repository, forger, recipient);
|
||||
|
||||
PrivateKeyAccount forgingAccount = Common.getTestAccount(repository, forger);
|
||||
TransactionUtils.signAndForge(repository, transactionData, forgingAccount);
|
||||
|
||||
return transactionData;
|
||||
}
|
||||
|
||||
public static Map<String, Map<Long, BigDecimal>> getBalances(Repository repository, long... assetIds) throws DataException {
|
||||
Map<String, Map<Long, BigDecimal>> balances = new HashMap<>();
|
||||
|
||||
|
163
src/test/java/org/qora/test/forging/GrantForgingTests.java
Normal file
163
src/test/java/org/qora/test/forging/GrantForgingTests.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package org.qora.test.forging;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.qora.account.PrivateKeyAccount;
|
||||
import org.qora.block.BlockChain;
|
||||
import org.qora.block.BlockGenerator;
|
||||
import org.qora.data.transaction.TransactionData;
|
||||
import org.qora.repository.DataException;
|
||||
import org.qora.repository.Repository;
|
||||
import org.qora.repository.RepositoryManager;
|
||||
import org.qora.test.common.AccountUtils;
|
||||
import org.qora.test.common.Common;
|
||||
import org.qora.test.common.TransactionUtils;
|
||||
import org.qora.transaction.Transaction;
|
||||
import org.qora.transaction.Transaction.ValidationResult;
|
||||
|
||||
public class GrantForgingTests extends Common {
|
||||
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws DataException {
|
||||
Common.useDefaultSettings();
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws DataException {
|
||||
Common.orphanCheck();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleGrant() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount forgingAccount = Common.getTestAccount(repository, "alice");
|
||||
|
||||
TransactionData transactionData = AccountUtils.createEnableForging(repository, "alice", "bob");
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.sign(forgingAccount);
|
||||
|
||||
ValidationResult result = transaction.isValidUnconfirmed();
|
||||
// Alice can't grant without forging minimum number of blocks
|
||||
assertEquals(ValidationResult.FORGE_MORE_BLOCKS, result);
|
||||
|
||||
// Forge a load of blocks
|
||||
int blocksNeeded = BlockChain.getInstance().getForgingTiers().get(0).minBlocks;
|
||||
for (int i = 0; i < blocksNeeded; ++i)
|
||||
BlockGenerator.generateTestingBlock(repository, forgingAccount);
|
||||
|
||||
// Alice should be able to grant now
|
||||
result = transaction.isValidUnconfirmed();
|
||||
assertEquals(ValidationResult.OK, result);
|
||||
|
||||
TransactionUtils.signAndForge(repository, transactionData, forgingAccount);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxGrant() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount forgingAccount = Common.getTestAccount(repository, "alice");
|
||||
|
||||
TransactionData transactionData = AccountUtils.createEnableForging(repository, "alice", "bob");
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.sign(forgingAccount);
|
||||
|
||||
ValidationResult result = transaction.isValidUnconfirmed();
|
||||
// Alice can't grant without forging minimum number of blocks
|
||||
assertEquals(ValidationResult.FORGE_MORE_BLOCKS, result);
|
||||
|
||||
// Forge a load of blocks
|
||||
int blocksNeeded = BlockChain.getInstance().getForgingTiers().get(0).minBlocks;
|
||||
for (int i = 0; i < blocksNeeded; ++i)
|
||||
BlockGenerator.generateTestingBlock(repository, forgingAccount);
|
||||
|
||||
// Alice should be able to grant up to 5 now
|
||||
|
||||
// Gift to random accounts
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
byte[] publicKey = new byte[32];
|
||||
random.nextBytes(publicKey);
|
||||
|
||||
transactionData = AccountUtils.createEnableForging(repository, "alice", publicKey);
|
||||
transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.sign(forgingAccount);
|
||||
|
||||
result = transaction.isValidUnconfirmed();
|
||||
assertEquals("Couldn't enable account #" + i, ValidationResult.OK, result);
|
||||
|
||||
TransactionUtils.signAndForge(repository, transactionData, forgingAccount);
|
||||
}
|
||||
|
||||
// Alice's allocation used up
|
||||
byte[] publicKey = new byte[32];
|
||||
random.nextBytes(publicKey);
|
||||
|
||||
transactionData = AccountUtils.createEnableForging(repository, "alice", publicKey);
|
||||
transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.sign(forgingAccount);
|
||||
|
||||
result = transaction.isValidUnconfirmed();
|
||||
assertEquals(ValidationResult.FORGING_ENABLE_LIMIT, result);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinalTier() throws DataException {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
PrivateKeyAccount aliceAccount = Common.getTestAccount(repository, "alice");
|
||||
|
||||
TransactionData transactionData = AccountUtils.createEnableForging(repository, "alice", "bob");
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.sign(aliceAccount);
|
||||
|
||||
ValidationResult result = transaction.isValidUnconfirmed();
|
||||
// Alice can't grant without forging minimum number of blocks
|
||||
assertEquals(ValidationResult.FORGE_MORE_BLOCKS, result);
|
||||
|
||||
// Forge a load of blocks
|
||||
int blocksNeeded = BlockChain.getInstance().getForgingTiers().get(0).minBlocks;
|
||||
for (int i = 0; i < blocksNeeded; ++i)
|
||||
BlockGenerator.generateTestingBlock(repository, aliceAccount);
|
||||
|
||||
// Alice should be able to grant now
|
||||
AccountUtils.enableForging(repository, "alice", "bob");
|
||||
|
||||
// Bob can't grant without forging minimum number of blocks
|
||||
transactionData = AccountUtils.createEnableForging(repository, "bob", "chloe");
|
||||
transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.sign(aliceAccount);
|
||||
|
||||
result = transaction.isValidUnconfirmed();
|
||||
assertEquals(ValidationResult.FORGE_MORE_BLOCKS, result);
|
||||
|
||||
// Bob needs to forge a load of blocks
|
||||
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
|
||||
blocksNeeded = BlockChain.getInstance().getForgingTiers().get(1).minBlocks;
|
||||
for (int i = 0; i < blocksNeeded; ++i)
|
||||
BlockGenerator.generateTestingBlock(repository, bobAccount);
|
||||
|
||||
// Bob should be able to grant now
|
||||
AccountUtils.enableForging(repository, "bob", "chloe");
|
||||
|
||||
// Chloe is final tier so shouldn't be able to grant
|
||||
Random random = new Random();
|
||||
byte[] publicKey = new byte[32];
|
||||
random.nextBytes(publicKey);
|
||||
|
||||
transactionData = AccountUtils.createEnableForging(repository, "chloe", publicKey);
|
||||
transaction = Transaction.fromData(repository, transactionData);
|
||||
transaction.sign(aliceAccount);
|
||||
|
||||
result = transaction.isValidUnconfirmed();
|
||||
assertEquals(ValidationResult.FORGING_ENABLE_LIMIT, result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -11,7 +11,7 @@ import org.junit.Test;
|
||||
import org.qora.account.PrivateKeyAccount;
|
||||
import org.qora.asset.Asset;
|
||||
import org.qora.block.BlockChain;
|
||||
import org.qora.block.BlockChain.RewardsByHeight;
|
||||
import org.qora.block.BlockChain.RewardByHeight;
|
||||
import org.qora.block.BlockGenerator;
|
||||
import org.qora.repository.DataException;
|
||||
import org.qora.repository.Repository;
|
||||
@@ -54,11 +54,11 @@ public class RewardTests extends Common {
|
||||
|
||||
PrivateKeyAccount forgingAccount = Common.getTestAccount(repository, "alice");
|
||||
|
||||
List<RewardsByHeight> rewards = BlockChain.getInstance().getBlockRewardsByHeight();
|
||||
List<RewardByHeight> rewards = BlockChain.getInstance().getBlockRewardsByHeight();
|
||||
|
||||
int rewardIndex = rewards.size() - 1;
|
||||
|
||||
RewardsByHeight rewardInfo = rewards.get(rewardIndex);
|
||||
RewardByHeight rewardInfo = rewards.get(rewardIndex);
|
||||
BigDecimal expectedBalance = initialBalances.get("alice").get(Asset.QORA);
|
||||
|
||||
for (int height = rewardInfo.height; height > 1; --height) {
|
||||
|
@@ -30,6 +30,11 @@
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"forgingTiers": [
|
||||
{ "minBlocks": 5, "maxSubAccounts": 5 },
|
||||
{ "minBlocks": 4, "maxSubAccounts": 3 },
|
||||
{ "minBlocks": 0, "maxSubAccounts": 0 }
|
||||
],
|
||||
"featureTriggers": {
|
||||
"messageHeight": 0,
|
||||
"atHeight": 0,
|
||||
|
Reference in New Issue
Block a user