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:
+ *
+ * - account's level is at least minAccountLevelToMint from blockchain config
+ * - account has 'founder' flag set
+ *
+ *
+ * @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:
+ *
+ * - account's level is at least minAccountLevelToRewardShare from blockchain config
+ * - account has 'founder' flag set
+ *
+ *
+ * @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 }
]
}
}