diff --git a/src/main/java/org/qora/account/Account.java b/src/main/java/org/qora/account/Account.java index 27ef27fb..40ccf5ab 100644 --- a/src/main/java/org/qora/account/Account.java +++ b/src/main/java/org/qora/account/Account.java @@ -192,6 +192,17 @@ public class Account { // Minting blocks + /** Returns whether account can be considered a "minting account". + *

+ * To be considered a "minting account", the account needs to pass at least one of these tests:
+ *

+ * + * @return true if account can be considered "minting account" + * @throws DataException + */ public boolean canMint() throws DataException { Integer level = this.getLevel(); if (level != null && level >= BlockChain.getInstance().getMinAccountLevelToMint()) @@ -203,6 +214,17 @@ public class Account { return false; } + /** Returns whether account can build reward-shares. + *

+ * To be able to create reward-shares, the account needs to pass at least one of these tests:
+ *

+ * + * @return true if account can be considered "minting account" + * @throws DataException + */ public boolean canRewardShare() throws DataException { Integer level = this.getLevel(); if (level != null && level >= BlockChain.getInstance().getMinAccountLevelToRewardShare()) diff --git a/src/main/java/org/qora/block/Block.java b/src/main/java/org/qora/block/Block.java index c3653131..29126f3e 100644 --- a/src/main/java/org/qora/block/Block.java +++ b/src/main/java/org/qora/block/Block.java @@ -1584,7 +1584,7 @@ public class Block { final int effectiveBlocksMinted = cumulativeBlocksByLevel.get(accountData.getInitialLevel()) + accountData.getBlocksMinted(); - for (int newLevel = maximumLevel; newLevel > 0; --newLevel) + for (int newLevel = maximumLevel; newLevel >= 0; --newLevel) if (effectiveBlocksMinted >= cumulativeBlocksByLevel.get(newLevel)) { if (newLevel < accountData.getLevel()) { // Account has decreased in level! diff --git a/src/test/java/org/qora/test/common/BlockUtils.java b/src/test/java/org/qora/test/common/BlockUtils.java index a2507349..12f2b2c3 100644 --- a/src/test/java/org/qora/test/common/BlockUtils.java +++ b/src/test/java/org/qora/test/common/BlockUtils.java @@ -46,4 +46,21 @@ public class BlockUtils { orphanLastBlock(repository); } + public static void orphanToBlock(Repository repository, int targetHeight) throws DataException { + do { + BlockData blockData = repository.getBlockRepository().getLastBlock(); + final int height = blockData.getHeight(); + + if (height <= targetHeight) + return; + + Block block = new Block(repository, blockData); + block.orphan(); + + LOGGER.info(String.format("Orphaned block: %d", height)); + + repository.saveChanges(); + } while (true); + } + } diff --git a/src/test/java/org/qora/test/minting/RewardTests.java b/src/test/java/org/qora/test/minting/RewardTests.java index 9edb6720..0b5861c9 100644 --- a/src/test/java/org/qora/test/minting/RewardTests.java +++ b/src/test/java/org/qora/test/minting/RewardTests.java @@ -22,6 +22,7 @@ import org.qora.repository.RepositoryManager; import org.qora.test.common.AccountUtils; import org.qora.test.common.BlockUtils; import org.qora.test.common.Common; +import org.qora.test.common.TestAccount; public class RewardTests extends Common { @@ -175,4 +176,32 @@ public class RewardTests extends Common { } } + /** Use Alice-Chloe reward-share to bump Chloe from level 0 to level 1, then check orphaning works as expected. */ + @Test + public void testLevel1() throws DataException { + List cumulativeBlocksByLevel = BlockChain.getInstance().getCumulativeBlocksByLevel(); + + try (final Repository repository = RepositoryManager.getRepository()) { + TestAccount chloe = Common.getTestAccount(repository, "chloe"); + + assertEquals(0, (int) chloe.getLevel()); + + // Alice needs to mint block containing REWARD_SHARE BEFORE Alice loses minting privs + byte[] aliceChloeRewardSharePrivateKey = AccountUtils.rewardShare(repository, "alice", "chloe", BigDecimal.ZERO); // Block minted by Alice + PrivateKeyAccount aliceChloeRewardShareAccount = new PrivateKeyAccount(repository, aliceChloeRewardSharePrivateKey); + + final int minterBlocksNeeded = cumulativeBlocksByLevel.get(1); + // Mint enough blocks to bump testAccount level + for (int bc = 0; bc < minterBlocksNeeded; ++bc) + BlockMinter.mintTestingBlock(repository, aliceChloeRewardShareAccount); + + assertEquals(1, (int) chloe.getLevel()); + + // Orphan back to genesis block + BlockUtils.orphanToBlock(repository, 1); + + assertEquals(0, (int) chloe.getLevel()); + } + } + } \ No newline at end of file diff --git a/src/test/resources/test-chain-v2.json b/src/test/resources/test-chain-v2.json index 498365d3..bb0e882b 100644 --- a/src/test/resources/test-chain-v2.json +++ b/src/test/resources/test-chain-v2.json @@ -62,7 +62,7 @@ { "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": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 5 } ] } }