forked from Qortal/qortal
Fix off-by-one error when reducing account level during block orphaning.
Added test to cover above. Modified test-chain-v2.json so Dilbert starts with level 5, not 8, to reduce number of blocks minted during tests.
This commit is contained in:
parent
c3a6e0d9fd
commit
5cd35e07d0
@ -192,6 +192,17 @@ public class Account {
|
||||
|
||||
// Minting blocks
|
||||
|
||||
/** Returns whether account can be considered a "minting account".
|
||||
* <p>
|
||||
* To be considered a "minting account", the account needs to pass at least one of these tests:<br>
|
||||
* <ul>
|
||||
* <li>account's level is at least <tt>minAccountLevelToMint</tt> from blockchain config</li>
|
||||
* <li>account has 'founder' flag set</li>
|
||||
* </ul>
|
||||
*
|
||||
* @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.
|
||||
* <p>
|
||||
* To be able to create reward-shares, the account needs to pass at least one of these tests:<br>
|
||||
* <ul>
|
||||
* <li>account's level is at least <tt>minAccountLevelToRewardShare</tt> from blockchain config</li>
|
||||
* <li>account has 'founder' flag set</li>
|
||||
* </ul>
|
||||
*
|
||||
* @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())
|
||||
|
@ -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!
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<Integer> 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user