forked from Qortal/qortal
Self-reward-share tests and fixes.
Added Transaction.isFeeValid() to allow transaction subclasses to override and allow zero fees, etc. Added tests to cover self-reward-shares, including zero fee scenario. Set 'dilbert' test account to level 8 in test genesis block. Removed leftover mention of "previous_level" from HSQLDBAccountLevelTransactions, and AccountLevelTransactionData. (Previous level makes no sense as ACCOUNT_LEVEL transactions are genesis-block only). Fixed some incorrect uses of PrivateKeyAccount.getSharedSecret() to PrivateKeyAccount.getRewardSharePrivateKey() in tests.
This commit is contained in:
parent
491e79b8e6
commit
fef16e7620
@ -21,7 +21,6 @@ public class AccountLevelTransactionData extends TransactionData {
|
|||||||
|
|
||||||
private String target;
|
private String target;
|
||||||
private int level;
|
private int level;
|
||||||
private Integer previousLevel;
|
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
@ -40,20 +39,13 @@ public class AccountLevelTransactionData extends TransactionData {
|
|||||||
this.creatorPublicKey = GenesisAccount.PUBLIC_KEY;
|
this.creatorPublicKey = GenesisAccount.PUBLIC_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** From repository */
|
/** From repository, network/API */
|
||||||
public AccountLevelTransactionData(BaseTransactionData baseTransactionData,
|
public AccountLevelTransactionData(BaseTransactionData baseTransactionData,
|
||||||
String target, int level, Integer previousLevel) {
|
String target, int level) {
|
||||||
super(TransactionType.ACCOUNT_LEVEL, baseTransactionData);
|
super(TransactionType.ACCOUNT_LEVEL, baseTransactionData);
|
||||||
|
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
this.previousLevel = previousLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** From network/API */
|
|
||||||
public AccountLevelTransactionData(BaseTransactionData baseTransactionData,
|
|
||||||
String target, int level) {
|
|
||||||
this(baseTransactionData, target, level, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters / setters
|
// Getters / setters
|
||||||
@ -66,14 +58,6 @@ public class AccountLevelTransactionData extends TransactionData {
|
|||||||
return this.level;
|
return this.level;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getPreviousLevel() {
|
|
||||||
return this.previousLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPreviousLevel(Integer previousLevel) {
|
|
||||||
this.previousLevel = previousLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-expose to JAXB
|
// Re-expose to JAXB
|
||||||
|
|
||||||
@XmlElement(name = "creatorPublicKey")
|
@XmlElement(name = "creatorPublicKey")
|
||||||
|
@ -17,7 +17,7 @@ public class HSQLDBAccountLevelTransactionRepository extends HSQLDBTransactionRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
|
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
|
||||||
String sql = "SELECT target, level, previous_level FROM AccountLevelTransactions WHERE signature = ?";
|
String sql = "SELECT target, level FROM AccountLevelTransactions WHERE signature = ?";
|
||||||
|
|
||||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
|
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
|
||||||
if (resultSet == null)
|
if (resultSet == null)
|
||||||
@ -26,11 +26,7 @@ public class HSQLDBAccountLevelTransactionRepository extends HSQLDBTransactionRe
|
|||||||
String target = resultSet.getString(1);
|
String target = resultSet.getString(1);
|
||||||
int level = resultSet.getInt(2);
|
int level = resultSet.getInt(2);
|
||||||
|
|
||||||
Integer previousLevel = resultSet.getInt(3);
|
return new AccountLevelTransactionData(baseTransactionData, target, level);
|
||||||
if (previousLevel == 0 && resultSet.wasNull())
|
|
||||||
previousLevel = null;
|
|
||||||
|
|
||||||
return new AccountLevelTransactionData(baseTransactionData, target, level, previousLevel);
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DataException("Unable to fetch account level transaction from repository", e);
|
throw new DataException("Unable to fetch account level transaction from repository", e);
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,22 @@ public class RewardShareTransaction extends Transaction {
|
|||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RewardShareData getExistingRewardShare() throws DataException {
|
||||||
|
// Look up any existing reward-share (using transaction's reward-share public key)
|
||||||
|
RewardShareData existingRewardShareData = this.repository.getAccountRepository().getRewardShare(this.rewardShareTransactionData.getRewardSharePublicKey());
|
||||||
|
if (existingRewardShareData == null)
|
||||||
|
// No luck, try looking up existing reward-share using minting & recipient account info
|
||||||
|
existingRewardShareData = this.repository.getAccountRepository().getRewardShare(this.rewardShareTransactionData.getMinterPublicKey(), this.rewardShareTransactionData.getRecipient());
|
||||||
|
|
||||||
|
return existingRewardShareData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doesRewardShareMatch(RewardShareData rewardShareData) {
|
||||||
|
return rewardShareData.getRecipient().equals(this.rewardShareTransactionData.getRecipient())
|
||||||
|
&& Arrays.equals(rewardShareData.getMinterPublicKey(), this.rewardShareTransactionData.getMinterPublicKey())
|
||||||
|
&& Arrays.equals(rewardShareData.getRewardSharePublicKey(), this.rewardShareTransactionData.getRewardSharePublicKey());
|
||||||
|
}
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
|
|
||||||
public PublicKeyAccount getMintingAccount() {
|
public PublicKeyAccount getMintingAccount() {
|
||||||
@ -75,6 +91,25 @@ public class RewardShareTransaction extends Transaction {
|
|||||||
|
|
||||||
private static final BigDecimal MAX_SHARE = BigDecimal.valueOf(100).setScale(2);
|
private static final BigDecimal MAX_SHARE = BigDecimal.valueOf(100).setScale(2);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValidationResult isFeeValid() throws DataException {
|
||||||
|
// Look up any existing reward-share (using transaction's reward-share public key)
|
||||||
|
RewardShareData existingRewardShareData = this.getExistingRewardShare();
|
||||||
|
// If we have an existing reward-share then minter/recipient/reward-share-public-key should all match.
|
||||||
|
// This is to prevent malicious actors using multiple (fake) reward-share public keys for the same minter/recipient combo,
|
||||||
|
// or reusing the same reward-share public key for a different minter/recipient pair.
|
||||||
|
if (existingRewardShareData != null && !this.doesRewardShareMatch(existingRewardShareData))
|
||||||
|
return ValidationResult.INVALID_PUBLIC_KEY;
|
||||||
|
|
||||||
|
final boolean isRecipientAlsoMinter = getCreator().getAddress().equals(this.rewardShareTransactionData.getRecipient());
|
||||||
|
|
||||||
|
// Fee can be zero if setting up new self-share
|
||||||
|
if (isRecipientAlsoMinter && existingRewardShareData == null && this.transactionData.getFee().compareTo(BigDecimal.ZERO) >= 0)
|
||||||
|
return ValidationResult.OK;
|
||||||
|
|
||||||
|
return super.isFeeValid();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult isValid() throws DataException {
|
public ValidationResult isValid() throws DataException {
|
||||||
// Check reward share given to recipient
|
// Check reward share given to recipient
|
||||||
@ -102,34 +137,25 @@ public class RewardShareTransaction extends Transaction {
|
|||||||
return ValidationResult.ACCOUNT_CANNOT_REWARD_SHARE;
|
return ValidationResult.ACCOUNT_CANNOT_REWARD_SHARE;
|
||||||
|
|
||||||
// Look up any existing reward-share (using transaction's reward-share public key)
|
// Look up any existing reward-share (using transaction's reward-share public key)
|
||||||
RewardShareData rewardShareData = this.repository.getAccountRepository().getRewardShare(this.rewardShareTransactionData.getRewardSharePublicKey());
|
RewardShareData existingRewardShareData = this.getExistingRewardShare();
|
||||||
if (rewardShareData != null) {
|
// If we have an existing reward-share then minter/recipient/reward-share-public-key should all match.
|
||||||
// If reward-share public key already exists in repository, then it must be for the same minter-recipient combo
|
// This is to prevent malicious actors using multiple (fake) reward-share public keys for the same minter/recipient combo,
|
||||||
if (!rewardShareData.getRecipient().equals(recipient.getAddress()) || !Arrays.equals(rewardShareData.getMinterPublicKey(), creator.getPublicKey()))
|
// or reusing the same reward-share public key for a different minter/recipient pair.
|
||||||
|
if (existingRewardShareData != null && !this.doesRewardShareMatch(existingRewardShareData))
|
||||||
return ValidationResult.INVALID_PUBLIC_KEY;
|
return ValidationResult.INVALID_PUBLIC_KEY;
|
||||||
|
|
||||||
} else {
|
|
||||||
// No luck, try looking up existing reward-share using minting & recipient account info
|
|
||||||
rewardShareData = this.repository.getAccountRepository().getRewardShare(creator.getPublicKey(), recipient.getAddress());
|
|
||||||
|
|
||||||
if (rewardShareData != null)
|
|
||||||
// If reward-share between minter & recipient already exists in repository, then it must be have the same public key
|
|
||||||
if (!Arrays.equals(rewardShareData.getRewardSharePublicKey(), this.rewardShareTransactionData.getRewardSharePublicKey()))
|
|
||||||
return ValidationResult.INVALID_PUBLIC_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean isSharePercentZero = this.rewardShareTransactionData.getSharePercent().compareTo(BigDecimal.ZERO) == 0;
|
final boolean isSharePercentZero = this.rewardShareTransactionData.getSharePercent().compareTo(BigDecimal.ZERO) == 0;
|
||||||
|
|
||||||
if (rewardShareData == null) {
|
if (existingRewardShareData == null) {
|
||||||
// This is a new reward-share
|
// This is a new reward-share
|
||||||
|
|
||||||
// No point starting a new reward-share with 0% share (i.e. delete relationship)
|
// No point starting a new reward-share with 0% share (i.e. delete reward-share)
|
||||||
if (isSharePercentZero)
|
if (isSharePercentZero)
|
||||||
return ValidationResult.INVALID_REWARD_SHARE_PERCENT;
|
return ValidationResult.INVALID_REWARD_SHARE_PERCENT;
|
||||||
|
|
||||||
// Check the minting account hasn't reach maximum number of reward-shares
|
// Check the minting account hasn't reach maximum number of reward-shares
|
||||||
int relationshipCount = this.repository.getAccountRepository().countRewardShares(creator.getPublicKey());
|
int rewardShareCount = this.repository.getAccountRepository().countRewardShares(creator.getPublicKey());
|
||||||
if (relationshipCount >= BlockChain.getInstance().getMaxRewardSharesPerMintingAccount())
|
if (rewardShareCount >= BlockChain.getInstance().getMaxRewardSharesPerMintingAccount())
|
||||||
return ValidationResult.MAXIMUM_REWARD_SHARES;
|
return ValidationResult.MAXIMUM_REWARD_SHARES;
|
||||||
} else {
|
} else {
|
||||||
// This transaction intends to modify/terminate an existing reward-share
|
// This transaction intends to modify/terminate an existing reward-share
|
||||||
@ -140,15 +166,10 @@ public class RewardShareTransaction extends Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fee checking needed if not setting up new self-share
|
// Fee checking needed if not setting up new self-share
|
||||||
if (!(isRecipientAlsoMinter && rewardShareData == null)) {
|
if (!(isRecipientAlsoMinter && existingRewardShareData == null))
|
||||||
// Check fee is positive
|
|
||||||
if (rewardShareTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
|
||||||
return ValidationResult.NEGATIVE_FEE;
|
|
||||||
|
|
||||||
// Check creator has enough funds
|
// Check creator has enough funds
|
||||||
if (creator.getConfirmedBalance(Asset.QORT).compareTo(rewardShareTransactionData.getFee()) < 0)
|
if (creator.getConfirmedBalance(Asset.QORT).compareTo(rewardShareTransactionData.getFee()) < 0)
|
||||||
return ValidationResult.NO_BALANCE;
|
return ValidationResult.NO_BALANCE;
|
||||||
}
|
|
||||||
|
|
||||||
return ValidationResult.OK;
|
return ValidationResult.OK;
|
||||||
}
|
}
|
||||||
|
@ -314,6 +314,7 @@ public abstract class Transaction {
|
|||||||
return Transaction.getDeadline(transactionData);
|
return Transaction.getDeadline(transactionData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns whether transaction's fee is at least minimum unit fee as specified in blockchain config. */
|
||||||
public boolean hasMinimumFee() {
|
public boolean hasMinimumFee() {
|
||||||
return this.transactionData.getFee().compareTo(BlockChain.getInstance().getUnitFee()) >= 0;
|
return this.transactionData.getFee().compareTo(BlockChain.getInstance().getUnitFee()) >= 0;
|
||||||
}
|
}
|
||||||
@ -326,6 +327,7 @@ public abstract class Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns whether transaction's fee is at least amount needed to cover byte-length of transaction. */
|
||||||
public boolean hasMinimumFeePerByte() {
|
public boolean hasMinimumFeePerByte() {
|
||||||
return this.feePerByte().compareTo(BlockChain.getInstance().getMinFeePerByte()) >= 0;
|
return this.feePerByte().compareTo(BlockChain.getInstance().getMinFeePerByte()) >= 0;
|
||||||
}
|
}
|
||||||
@ -538,8 +540,9 @@ public abstract class Transaction {
|
|||||||
return ValidationResult.TIMESTAMP_TOO_NEW;
|
return ValidationResult.TIMESTAMP_TOO_NEW;
|
||||||
|
|
||||||
// Check fee is sufficient
|
// Check fee is sufficient
|
||||||
if (!hasMinimumFee() || !hasMinimumFeePerByte())
|
ValidationResult feeValidationResult = isFeeValid();
|
||||||
return ValidationResult.INSUFFICIENT_FEE;
|
if (feeValidationResult != ValidationResult.OK)
|
||||||
|
return feeValidationResult;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to grab the blockchain lock because we're updating
|
* We have to grab the blockchain lock because we're updating
|
||||||
@ -591,6 +594,14 @@ public abstract class Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns whether transaction's fee is valid. Might be overriden in transaction subclasses. */
|
||||||
|
protected ValidationResult isFeeValid() throws DataException {
|
||||||
|
if (!hasMinimumFee() || !hasMinimumFeePerByte())
|
||||||
|
return ValidationResult.INSUFFICIENT_FEE;
|
||||||
|
|
||||||
|
return ValidationResult.OK;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isValidTxGroupId() throws DataException {
|
private boolean isValidTxGroupId() throws DataException {
|
||||||
int txGroupId = this.transactionData.getTxGroupId();
|
int txGroupId = this.transactionData.getTxGroupId();
|
||||||
|
|
||||||
|
@ -38,11 +38,11 @@ public class AccountUtils {
|
|||||||
byte[] reference = mintingAccount.getLastReference();
|
byte[] reference = mintingAccount.getLastReference();
|
||||||
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
|
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
|
||||||
|
|
||||||
byte[] rewardSharePrivateKey = mintingAccount.getSharedSecret(recipientAccount.getPublicKey());
|
byte[] rewardSharePrivateKey = mintingAccount.getRewardSharePrivateKey(recipientAccount.getPublicKey());
|
||||||
PrivateKeyAccount rewardShareAccount = new PrivateKeyAccount(null, rewardSharePrivateKey);
|
byte[] rewardSharePublicKey = PrivateKeyAccount.toPublicKey(rewardSharePrivateKey);
|
||||||
|
|
||||||
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, mintingAccount.getPublicKey(), fee, null);
|
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, mintingAccount.getPublicKey(), fee, null);
|
||||||
TransactionData transactionData = new RewardShareTransactionData(baseTransactionData, recipientAccount.getAddress(), rewardShareAccount.getPublicKey(), sharePercent);
|
TransactionData transactionData = new RewardShareTransactionData(baseTransactionData, recipientAccount.getAddress(), rewardSharePublicKey, sharePercent);
|
||||||
|
|
||||||
return transactionData;
|
return transactionData;
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ public class AccountUtils {
|
|||||||
TransactionUtils.signAndMint(repository, transactionData, rewardShareAccount);
|
TransactionUtils.signAndMint(repository, transactionData, rewardShareAccount);
|
||||||
|
|
||||||
PrivateKeyAccount recipientAccount = Common.getTestAccount(repository, recipient);
|
PrivateKeyAccount recipientAccount = Common.getTestAccount(repository, recipient);
|
||||||
byte[] rewardSharePrivateKey = rewardShareAccount.getSharedSecret(recipientAccount.getPublicKey());
|
byte[] rewardSharePrivateKey = rewardShareAccount.getRewardSharePrivateKey(recipientAccount.getPublicKey());
|
||||||
|
|
||||||
return rewardSharePrivateKey;
|
return rewardSharePrivateKey;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public class TransactionUtils {
|
|||||||
assertEquals("Transaction invalid", ValidationResult.OK, result);
|
assertEquals("Transaction invalid", ValidationResult.OK, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Signs transaction using given account and forges a new block, using "alice" account. */
|
/** Signs transaction using given account and forges a new block, using "alice" self-reward-share key. */
|
||||||
public static void signAndMint(Repository repository, TransactionData transactionData, PrivateKeyAccount signingAccount) throws DataException {
|
public static void signAndMint(Repository repository, TransactionData transactionData, PrivateKeyAccount signingAccount) throws DataException {
|
||||||
signAsUnconfirmed(repository, transactionData, signingAccount);
|
signAsUnconfirmed(repository, transactionData, signingAccount);
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package org.qora.test.forging;
|
package org.qora.test.minting;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
@ -16,6 +16,7 @@ import org.qora.repository.RepositoryManager;
|
|||||||
import org.qora.test.common.AccountUtils;
|
import org.qora.test.common.AccountUtils;
|
||||||
import org.qora.test.common.BlockUtils;
|
import org.qora.test.common.BlockUtils;
|
||||||
import org.qora.test.common.Common;
|
import org.qora.test.common.Common;
|
||||||
|
import org.qora.test.common.TransactionUtils;
|
||||||
import org.qora.transaction.Transaction;
|
import org.qora.transaction.Transaction;
|
||||||
import org.qora.transaction.Transaction.ValidationResult;
|
import org.qora.transaction.Transaction.ValidationResult;
|
||||||
import org.qora.utils.Base58;
|
import org.qora.utils.Base58;
|
||||||
@ -124,4 +125,51 @@ public class RewardShareTests extends Common {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelfShare() throws DataException {
|
||||||
|
final String testAccountName = "dilbert";
|
||||||
|
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
PrivateKeyAccount signingAccount = Common.getTestAccount(repository, testAccountName);
|
||||||
|
// byte[] rewardSharePrivateKey = aliceAccount.getRewardSharePrivateKey(aliceAccount.getPublicKey());
|
||||||
|
// PrivateKeyAccount rewardShareAccount = new PrivateKeyAccount(repository, rewardSharePrivateKey);
|
||||||
|
|
||||||
|
// Create self-reward-share
|
||||||
|
TransactionData transactionData = AccountUtils.createRewardShare(repository, testAccountName, testAccountName, BigDecimal.valueOf(100L));
|
||||||
|
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||||
|
|
||||||
|
// Confirm self-share is valid
|
||||||
|
ValidationResult validationResult = transaction.isValidUnconfirmed();
|
||||||
|
assertEquals("Initial self-share should be valid", ValidationResult.OK, validationResult);
|
||||||
|
|
||||||
|
// Check zero fee is valid
|
||||||
|
transactionData.setFee(BigDecimal.ZERO);
|
||||||
|
validationResult = transaction.isValidUnconfirmed();
|
||||||
|
assertEquals("Zero-fee self-share should be valid", ValidationResult.OK, validationResult);
|
||||||
|
|
||||||
|
TransactionUtils.signAndMint(repository, transactionData, signingAccount);
|
||||||
|
|
||||||
|
// Subsequent non-terminating (0% share) self-reward-share should be invalid
|
||||||
|
TransactionData newTransactionData = AccountUtils.createRewardShare(repository, testAccountName, testAccountName, BigDecimal.valueOf(99L));
|
||||||
|
Transaction newTransaction = Transaction.fromData(repository, newTransactionData);
|
||||||
|
|
||||||
|
// Confirm subsequent self-reward-share is actually invalid
|
||||||
|
validationResult = newTransaction.isValidUnconfirmed();
|
||||||
|
assertNotSame("Subsequent self-share should be invalid", ValidationResult.OK, validationResult);
|
||||||
|
|
||||||
|
// Recheck with zero fee
|
||||||
|
newTransactionData.setFee(BigDecimal.ZERO);
|
||||||
|
validationResult = newTransaction.isValidUnconfirmed();
|
||||||
|
assertNotSame("Subsequent zero-fee self-share should be invalid", ValidationResult.OK, validationResult);
|
||||||
|
|
||||||
|
// Subsequent terminating (0% share) self-reward-share should be OK
|
||||||
|
newTransactionData = AccountUtils.createRewardShare(repository, testAccountName, testAccountName, BigDecimal.ZERO);
|
||||||
|
newTransaction = Transaction.fromData(repository, newTransactionData);
|
||||||
|
|
||||||
|
// Confirm terminating reward-share is valid
|
||||||
|
validationResult = newTransaction.isValidUnconfirmed();
|
||||||
|
assertEquals("Subsequent zero-fee self-share should be invalid", ValidationResult.OK, validationResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.qora.test.forging;
|
package org.qora.test.minting;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
@ -37,11 +37,11 @@ public class RewardTests extends Common {
|
|||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
Map<String, Map<Long, BigDecimal>> initialBalances = AccountUtils.getBalances(repository, Asset.QORT);
|
Map<String, Map<Long, BigDecimal>> initialBalances = AccountUtils.getBalances(repository, Asset.QORT);
|
||||||
|
|
||||||
PrivateKeyAccount forgingAccount = Common.getTestAccount(repository, "alice");
|
PrivateKeyAccount mintingAccount = Common.getTestAccount(repository, "alice");
|
||||||
|
|
||||||
BigDecimal blockReward = BlockUtils.getNextBlockReward(repository);
|
BigDecimal blockReward = BlockUtils.getNextBlockReward(repository);
|
||||||
|
|
||||||
BlockMinter.mintTestingBlock(repository, forgingAccount);
|
BlockMinter.mintTestingBlock(repository, mintingAccount);
|
||||||
|
|
||||||
BigDecimal expectedBalance = initialBalances.get("alice").get(Asset.QORT).add(blockReward);
|
BigDecimal expectedBalance = initialBalances.get("alice").get(Asset.QORT).add(blockReward);
|
||||||
AccountUtils.assertBalance(repository, "alice", Asset.QORT, expectedBalance);
|
AccountUtils.assertBalance(repository, "alice", Asset.QORT, expectedBalance);
|
||||||
@ -53,7 +53,7 @@ public class RewardTests extends Common {
|
|||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
Map<String, Map<Long, BigDecimal>> initialBalances = AccountUtils.getBalances(repository, Asset.QORT);
|
Map<String, Map<Long, BigDecimal>> initialBalances = AccountUtils.getBalances(repository, Asset.QORT);
|
||||||
|
|
||||||
PrivateKeyAccount forgingAccount = Common.getTestAccount(repository, "alice");
|
PrivateKeyAccount mintingAccount = Common.getTestAccount(repository, "alice");
|
||||||
|
|
||||||
List<RewardByHeight> rewards = BlockChain.getInstance().getBlockRewardsByHeight();
|
List<RewardByHeight> rewards = BlockChain.getInstance().getBlockRewardsByHeight();
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ public class RewardTests extends Common {
|
|||||||
rewardInfo = rewards.get(rewardIndex);
|
rewardInfo = rewards.get(rewardIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockMinter.mintTestingBlock(repository, forgingAccount);
|
BlockMinter.mintTestingBlock(repository, mintingAccount);
|
||||||
expectedBalance = expectedBalance.add(rewardInfo.reward);
|
expectedBalance = expectedBalance.add(rewardInfo.reward);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,16 +77,16 @@ public class RewardTests extends Common {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProxyReward() throws DataException {
|
public void testRewardSharing() throws DataException {
|
||||||
final BigDecimal share = new BigDecimal("12.8");
|
final BigDecimal share = new BigDecimal("12.8");
|
||||||
|
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
byte[] proxyPrivateKey = AccountUtils.rewardShare(repository, "alice", "bob", share);
|
byte[] rewardSharePrivateKey = AccountUtils.rewardShare(repository, "alice", "bob", share);
|
||||||
PrivateKeyAccount proxyAccount = new PrivateKeyAccount(repository, proxyPrivateKey);
|
PrivateKeyAccount rewardShareAccount = new PrivateKeyAccount(repository, rewardSharePrivateKey);
|
||||||
|
|
||||||
Map<String, Map<Long, BigDecimal>> initialBalances = AccountUtils.getBalances(repository, Asset.QORT);
|
Map<String, Map<Long, BigDecimal>> initialBalances = AccountUtils.getBalances(repository, Asset.QORT);
|
||||||
BigDecimal blockReward = BlockUtils.getNextBlockReward(repository);
|
BigDecimal blockReward = BlockUtils.getNextBlockReward(repository);
|
||||||
BlockMinter.mintTestingBlock(repository, proxyAccount);
|
BlockMinter.mintTestingBlock(repository, rewardShareAccount);
|
||||||
|
|
||||||
// We're expecting reward * 12.8% to Bob, the rest to Alice
|
// We're expecting reward * 12.8% to Bob, the rest to Alice
|
||||||
|
|
@ -52,6 +52,7 @@
|
|||||||
{ "type": "ISSUE_ASSET", "owner": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
|
{ "type": "ISSUE_ASSET", "owner": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
|
||||||
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
|
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "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": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 8 },
|
||||||
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": 100 }
|
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": 100 }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user