diff --git a/pom.xml b/pom.xml index 288442a9..44bb10da 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.qortal qortal - 4.6.3 + 4.6.5 jar UTF-8 @@ -16,7 +16,7 @@ 1.4.2 3.8.0 1.12.0 - 2.17.0 + 2.18.0 1.27.1 3.17.0 1.2.2 @@ -28,7 +28,7 @@ 1.2.1 2.7.4 76.1 - 4.12 + 4.15 4.0.1 2.3.9 2.42 diff --git a/src/main/java/org/qortal/account/Account.java b/src/main/java/org/qortal/account/Account.java index 1aaceffb..537f0788 100644 --- a/src/main/java/org/qortal/account/Account.java +++ b/src/main/java/org/qortal/account/Account.java @@ -205,10 +205,11 @@ public class Account { *
  • account's address is a member of the minter group
  • * * + * @param isGroupValidated true if this account has already been validated for MINTER Group membership * @return true if account can be considered "minting account" * @throws DataException */ - public boolean canMint() throws DataException { + public boolean canMint(boolean isGroupValidated) throws DataException { AccountData accountData = this.repository.getAccountRepository().getAccount(this.address); NameRepository nameRepository = this.repository.getNameRepository(); GroupRepository groupRepository = this.repository.getGroupRepository(); @@ -251,9 +252,9 @@ public class Account { if (blockchainHeight >= groupCheckHeight && blockchainHeight < removeNameCheckHeight) { List myName = nameRepository.getNamesByOwner(myAddress); if (Account.isFounder(accountData.getFlags())) { - return accountData.getBlocksMintedPenalty() == 0 && !myName.isEmpty() && groupRepository.memberExists(groupIdToMint, myAddress); + return accountData.getBlocksMintedPenalty() == 0 && !myName.isEmpty() && (isGroupValidated || groupRepository.memberExists(groupIdToMint, myAddress)); } else { - return level >= levelToMint && !myName.isEmpty() && groupRepository.memberExists(groupIdToMint, myAddress); + return level >= levelToMint && !myName.isEmpty() && (isGroupValidated || groupRepository.memberExists(groupIdToMint, myAddress)); } } @@ -262,9 +263,9 @@ public class Account { // Account's address is a member of the minter group if (blockchainHeight >= removeNameCheckHeight) { if (Account.isFounder(accountData.getFlags())) { - return accountData.getBlocksMintedPenalty() == 0 && groupRepository.memberExists(groupIdToMint, myAddress); + return accountData.getBlocksMintedPenalty() == 0 && (isGroupValidated || groupRepository.memberExists(groupIdToMint, myAddress)); } else { - return level >= levelToMint && groupRepository.memberExists(groupIdToMint, myAddress); + return level >= levelToMint && (isGroupValidated || groupRepository.memberExists(groupIdToMint, myAddress)); } } diff --git a/src/main/java/org/qortal/api/restricted/resource/AdminResource.java b/src/main/java/org/qortal/api/restricted/resource/AdminResource.java index 9a61a21b..279485bc 100644 --- a/src/main/java/org/qortal/api/restricted/resource/AdminResource.java +++ b/src/main/java/org/qortal/api/restricted/resource/AdminResource.java @@ -459,7 +459,7 @@ public class AdminResource { // Qortal: check reward-share's minting account is still allowed to mint Account rewardShareMintingAccount = new Account(repository, rewardShareData.getMinter()); - if (!rewardShareMintingAccount.canMint()) + if (!rewardShareMintingAccount.canMint(false)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.CANNOT_MINT); MintingAccountData mintingAccountData = new MintingAccountData(mintingAccount.getPrivateKey(), mintingAccount.getPublicKey()); diff --git a/src/main/java/org/qortal/block/Block.java b/src/main/java/org/qortal/block/Block.java index eba55069..918a20ae 100644 --- a/src/main/java/org/qortal/block/Block.java +++ b/src/main/java/org/qortal/block/Block.java @@ -25,10 +25,7 @@ import org.qortal.data.block.BlockSummaryData; import org.qortal.data.block.BlockTransactionData; import org.qortal.data.network.OnlineAccountData; import org.qortal.data.transaction.TransactionData; -import org.qortal.repository.ATRepository; -import org.qortal.repository.DataException; -import org.qortal.repository.Repository; -import org.qortal.repository.TransactionRepository; +import org.qortal.repository.*; import org.qortal.settings.Settings; import org.qortal.transaction.AtTransaction; import org.qortal.transaction.Transaction; @@ -144,9 +141,12 @@ public class Block { private final Account mintingAccount; private final AccountData mintingAccountData; private final boolean isMinterFounder; + private final boolean isMinterMember; private final Account recipientAccount; private final AccountData recipientAccountData; + + final BlockChain blockChain = BlockChain.getInstance(); ExpandedAccount(Repository repository, RewardShareData rewardShareData) throws DataException { this.rewardShareData = rewardShareData; @@ -157,6 +157,7 @@ public class Block { this.isMinterFounder = Account.isFounder(mintingAccountData.getFlags()); this.isRecipientAlsoMinter = this.rewardShareData.getRecipient().equals(this.mintingAccount.getAddress()); + this.isMinterMember = repository.getGroupRepository().memberExists(BlockChain.getInstance().getMintingGroupId(), this.mintingAccount.getAddress()); if (this.isRecipientAlsoMinter) { // Self-share: minter is also recipient @@ -181,7 +182,7 @@ public class Block { *

    * This is a method, not a final variable, because account's level can change between construction and call, * e.g. during Block.process() where account levels are bumped right before Block.distributeBlockReward(). - * + * * @return account-level share "bin" from blockchain config, or null if founder / none found */ public AccountLevelShareBin getShareBin(int blockHeight) { @@ -192,8 +193,12 @@ public class Block { if (accountLevel <= 0) return null; // level 0 isn't included in any share bins + if (blockHeight >= blockChain.getFixBatchRewardHeight()) { + if (!this.isMinterMember) + return null; // not member of minter group isn't included in any share bins + } + // Select the correct set of share bins based on block height - final BlockChain blockChain = BlockChain.getInstance(); final AccountLevelShareBin[] shareBinsByLevel = (blockHeight >= blockChain.getSharesByLevelV2Height()) ? blockChain.getShareBinsByAccountLevelV2() : blockChain.getShareBinsByAccountLevelV1(); @@ -262,7 +267,7 @@ public class Block { * Constructs new Block without loading transactions and AT states. *

    * Transactions and AT states are loaded on first call to getTransactions() or getATStates() respectively. - * + * * @param repository * @param blockData */ @@ -333,7 +338,7 @@ public class Block { /** * Constructs new Block with empty transaction list, using passed minter account. - * + * * @param repository * @param blockData * @param minter @@ -351,7 +356,7 @@ public class Block { * This constructor typically used when minting a new block. *

    * Note that CIYAM ATs will be executed and AT-Transactions prepended to this block, along with AT state data and fees. - * + * * @param repository * @param parentBlockData * @param minter @@ -377,7 +382,7 @@ public class Block { byte[] encodedOnlineAccounts = new byte[0]; int onlineAccountsCount = 0; byte[] onlineAccountsSignatures = null; - + if (isBatchRewardDistributionBlock(height)) { // Batch reward distribution block - copy online accounts from recent block with highest online accounts count @@ -512,7 +517,7 @@ public class Block { * Mints new block using this block as template, but with different minting account. *

    * NOTE: uses the same transactions list, AT states, etc. - * + * * @param minter * @return * @throws DataException @@ -598,7 +603,7 @@ public class Block { /** * Return composite block signature (minterSignature + transactionsSignature). - * + * * @return byte[], or null if either component signature is null. */ public byte[] getSignature() { @@ -613,7 +618,7 @@ public class Block { *

    * We're starting with version 4 as a nod to being newer than successor Qora, * whose latest block version was 3. - * + * * @return 1, 2, 3 or 4 */ public int getNextBlockVersion() { @@ -627,7 +632,7 @@ public class Block { * Return block's transactions. *

    * If the block was loaded from repository then it's possible this method will call the repository to fetch the transactions if not done already. - * + * * @return * @throws DataException */ @@ -661,7 +666,7 @@ public class Block { * If the block was loaded from repository then it's possible this method will call the repository to fetch the AT states if not done already. *

    * Note: AT states fetched from repository only contain summary info, not actual data like serialized state data or AT creation timestamps! - * + * * @return * @throws DataException */ @@ -697,7 +702,7 @@ public class Block { *

    * Typically called as part of Block.process() or Block.orphan() * so ideally after any calls to Block.isValid(). - * + * * @throws DataException */ public List getExpandedAccounts() throws DataException { @@ -715,8 +720,18 @@ public class Block { List expandedAccounts = new ArrayList<>(); - for (RewardShareData rewardShare : this.cachedOnlineRewardShares) - expandedAccounts.add(new ExpandedAccount(repository, rewardShare)); + for (RewardShareData rewardShare : this.cachedOnlineRewardShares) { + if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight()) { + expandedAccounts.add(new ExpandedAccount(repository, rewardShare)); + } + if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight()) { + boolean isMinterGroupMember = repository.getGroupRepository().memberExists(BlockChain.getInstance().getMintingGroupId(), rewardShare.getMinter()); + if (isMinterGroupMember) { + expandedAccounts.add(new ExpandedAccount(repository, rewardShare)); + } + } + } + this.cachedExpandedAccounts = expandedAccounts; @@ -727,7 +742,7 @@ public class Block { /** * Load parent block's data from repository via this block's reference. - * + * * @return parent's BlockData, or null if no parent found * @throws DataException */ @@ -741,7 +756,7 @@ public class Block { /** * Load child block's data from repository via this block's signature. - * + * * @return child's BlockData, or null if no parent found * @throws DataException */ @@ -761,7 +776,7 @@ public class Block { * Used when constructing a new block during minting. *

    * Requires block's {@code minter} being a {@code PrivateKeyAccount} so block's transactions signature can be recalculated. - * + * * @param transactionData * @return true if transaction successfully added to block, false otherwise * @throws IllegalStateException @@ -814,7 +829,7 @@ public class Block { * Used when constructing a new block during minting. *

    * Requires block's {@code minter} being a {@code PrivateKeyAccount} so block's transactions signature can be recalculated. - * + * * @param transactionData * @throws IllegalStateException * if block's {@code minter} is not a {@code PrivateKeyAccount}. @@ -859,7 +874,7 @@ public class Block { * previous block's minter signature + minter's public key + (encoded) online-accounts data *

    * (Previous block's minter signature is extracted from this block's reference). - * + * * @throws IllegalStateException * if block's {@code minter} is not a {@code PrivateKeyAccount}. * @throws RuntimeException @@ -876,7 +891,7 @@ public class Block { * Recalculate block's transactions signature. *

    * Requires block's {@code minter} being a {@code PrivateKeyAccount}. - * + * * @throws IllegalStateException * if block's {@code minter} is not a {@code PrivateKeyAccount}. * @throws RuntimeException @@ -998,7 +1013,7 @@ public class Block { * Recalculate block's minter and transactions signatures, thus giving block full signature. *

    * Note: Block instance must have been constructed with a PrivateKeyAccount minter or this call will throw an IllegalStateException. - * + * * @throws IllegalStateException * if block's {@code minter} is not a {@code PrivateKeyAccount}. */ @@ -1011,7 +1026,7 @@ public class Block { /** * Returns whether this block's signatures are valid. - * + * * @return true if both minter and transaction signatures are valid, false otherwise */ public boolean isSignatureValid() { @@ -1035,7 +1050,7 @@ public class Block { *

    * Used by BlockMinter to check whether it's time to mint a new block, * and also used by Block.isValid for checks (if not a testchain). - * + * * @return ValidationResult.OK if timestamp valid, or some other ValidationResult otherwise. * @throws DataException */ @@ -1215,7 +1230,7 @@ public class Block { *

    * Checks block's transactions by testing their validity then processing them.
    * Hence uses a repository savepoint during execution. - * + * * @return ValidationResult.OK if block is valid, or some other ValidationResult otherwise. * @throws DataException */ @@ -1386,7 +1401,7 @@ public class Block { *

    * NOTE: will execute ATs locally if not already done.
    * This is so we have locally-generated AT states for comparison. - * + * * @return OK, or some AT-related validation result * @throws DataException */ @@ -1462,11 +1477,11 @@ public class Block { * Note: this method does not store new AT state data into repository - that is handled by process(). *

    * This method is not needed if fetching an existing block from the repository as AT state data will be loaded from repository as well. - * + * * @see #isValid() - * + * * @throws DataException - * + * */ private void executeATs() throws DataException { // We're expecting a lack of AT state data at this point. @@ -1518,7 +1533,7 @@ public class Block { return false; Account mintingAccount = new PublicKeyAccount(this.repository, rewardShareData.getMinterPublicKey()); - return mintingAccount.canMint(); + return mintingAccount.canMint(false); } /** @@ -1538,7 +1553,7 @@ public class Block { /** * Process block, and its transactions, adding them to the blockchain. - * + * * @throws DataException */ public void process() throws DataException { @@ -1839,7 +1854,7 @@ public class Block { /** * Removes block from blockchain undoing transactions and adding them to unconfirmed pile. - * + * * @throws DataException */ public void orphan() throws DataException { @@ -1879,7 +1894,7 @@ public class Block { SelfSponsorshipAlgoV3Block.orphanAccountPenalties(this); } } - + // Account levels and block rewards are only processed/orphaned on block reward distribution blocks if (this.isRewardDistributionBlock()) { // Block rewards, including transaction fees, removed after transactions undone @@ -2213,6 +2228,7 @@ public class Block { List accountBalanceDeltas = balanceChanges.entrySet().stream() .map(entry -> new AccountBalanceData(entry.getKey(), Asset.QORT, entry.getValue())) .collect(Collectors.toList()); + LOGGER.trace("Account Balance Deltas: {}", accountBalanceDeltas); this.repository.getAccountRepository().modifyAssetBalances(accountBalanceDeltas); } @@ -2225,30 +2241,30 @@ public class Block { /* * Distribution rules: - * + * * Distribution is based on the minting account of 'online' reward-shares. - * + * * If ANY founders are online, then they receive the leftover non-distributed reward. * If NO founders are online, then account-level-based rewards are scaled up so 100% of reward is allocated. - * + * * If ANY non-maxxed legacy QORA holders exist then they are always allocated their fixed share (e.g. 20%). - * + * * There has to be either at least one 'online' account for blocks to be minted * so there is always either one account-level-based or founder reward candidate. - * + * * Examples: - * + * * With at least one founder online: * Level 1/2 accounts: 5% * Legacy QORA holders: 20% * Founders: ~75% - * + * * No online founders: * Level 1/2 accounts: 5% * Level 5/6 accounts: 15% * Legacy QORA holders: 20% * Total: 40% - * + * * After scaling account-level-based shares to fill 100%: * Level 1/2 accounts: 20% * Level 5/6 accounts: 60% diff --git a/src/main/java/org/qortal/block/BlockChain.java b/src/main/java/org/qortal/block/BlockChain.java index 34097f0f..3e98d4a0 100644 --- a/src/main/java/org/qortal/block/BlockChain.java +++ b/src/main/java/org/qortal/block/BlockChain.java @@ -87,7 +87,8 @@ public class BlockChain { enableRewardshareHeight, onlyMintWithNameHeight, removeOnlyMintWithNameHeight, - groupMemberCheckHeight + groupMemberCheckHeight, + fixBatchRewardHeight } // Custom transaction fees @@ -657,6 +658,10 @@ public class BlockChain { return this.featureTriggers.get(FeatureTrigger.groupMemberCheckHeight.name()).intValue(); } + public int getFixBatchRewardHeight() { + return this.featureTriggers.get(FeatureTrigger.fixBatchRewardHeight.name()).intValue(); + } + // More complex getters for aspects that change by height or timestamp public long getRewardAtHeight(int ourHeight) { diff --git a/src/main/java/org/qortal/controller/BlockMinter.java b/src/main/java/org/qortal/controller/BlockMinter.java index 7ea2242c..a1fb9769 100644 --- a/src/main/java/org/qortal/controller/BlockMinter.java +++ b/src/main/java/org/qortal/controller/BlockMinter.java @@ -148,7 +148,7 @@ public class BlockMinter extends Thread { } Account mintingAccount = new Account(repository, rewardShareData.getMinter()); - if (!mintingAccount.canMint()) { + if (!mintingAccount.canMint(true)) { // Minting-account component of reward-share can no longer mint - disregard madi.remove(); continue; diff --git a/src/main/java/org/qortal/controller/OnlineAccountsManager.java b/src/main/java/org/qortal/controller/OnlineAccountsManager.java index 5572dee1..332bf867 100644 --- a/src/main/java/org/qortal/controller/OnlineAccountsManager.java +++ b/src/main/java/org/qortal/controller/OnlineAccountsManager.java @@ -13,6 +13,7 @@ import org.qortal.crypto.MemoryPoW; import org.qortal.crypto.Qortal25519Extras; import org.qortal.data.account.MintingAccountData; import org.qortal.data.account.RewardShareData; +import org.qortal.data.group.GroupMemberData; import org.qortal.data.network.OnlineAccountData; import org.qortal.network.Network; import org.qortal.network.Peer; @@ -224,6 +225,12 @@ public class OnlineAccountsManager { Set onlineAccountsToAdd = new HashSet<>(); Set onlineAccountsToRemove = new HashSet<>(); try (final Repository repository = RepositoryManager.getRepository()) { + List mintingGroupMemberAddresses + = repository.getGroupRepository() + .getGroupMembers(BlockChain.getInstance().getMintingGroupId()).stream() + .map(GroupMemberData::getMember) + .collect(Collectors.toList()); + for (OnlineAccountData onlineAccountData : this.onlineAccountsImportQueue) { if (isStopping) return; @@ -236,7 +243,7 @@ public class OnlineAccountsManager { continue; } - boolean isValid = this.isValidCurrentAccount(repository, onlineAccountData); + boolean isValid = this.isValidCurrentAccount(repository, mintingGroupMemberAddresses, onlineAccountData); if (isValid) onlineAccountsToAdd.add(onlineAccountData); @@ -315,7 +322,7 @@ public class OnlineAccountsManager { return inplaceArray; } - private static boolean isValidCurrentAccount(Repository repository, OnlineAccountData onlineAccountData) throws DataException { + private static boolean isValidCurrentAccount(Repository repository, List mintingGroupMemberAddresses, OnlineAccountData onlineAccountData) throws DataException { final Long now = NTP.getTime(); if (now == null) return false; @@ -350,9 +357,14 @@ public class OnlineAccountsManager { LOGGER.trace(() -> String.format("Rejecting unknown online reward-share public key %s", Base58.encode(rewardSharePublicKey))); return false; } + // reject account address that are not in the MINTER Group + else if( !mintingGroupMemberAddresses.contains(rewardShareData.getMinter())) { + LOGGER.trace(() -> String.format("Rejecting online reward-share that is not in MINTER Group, account %s", rewardShareData.getMinter())); + return false; + } Account mintingAccount = new Account(repository, rewardShareData.getMinter()); - if (!mintingAccount.canMint()) { + if (!mintingAccount.canMint(true)) { // group validation is a few lines above // Minting-account component of reward-share can no longer mint - disregard LOGGER.trace(() -> String.format("Rejecting online reward-share with non-minting account %s", mintingAccount.getAddress())); return false; @@ -539,7 +551,7 @@ public class OnlineAccountsManager { } Account mintingAccount = new Account(repository, rewardShareData.getMinter()); - if (!mintingAccount.canMint()) { + if (!mintingAccount.canMint(true)) { // Minting-account component of reward-share can no longer mint - disregard iterator.remove(); continue; diff --git a/src/main/java/org/qortal/network/task/PeerConnectTask.java b/src/main/java/org/qortal/network/task/PeerConnectTask.java index 7eec4e6b..3ae1b640 100644 --- a/src/main/java/org/qortal/network/task/PeerConnectTask.java +++ b/src/main/java/org/qortal/network/task/PeerConnectTask.java @@ -4,10 +4,15 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qortal.network.Network; import org.qortal.network.Peer; +import org.qortal.utils.DaemonThreadFactory; import org.qortal.utils.ExecuteProduceConsume.Task; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + public class PeerConnectTask implements Task { private static final Logger LOGGER = LogManager.getLogger(PeerConnectTask.class); + private static final ExecutorService connectionExecutor = Executors.newCachedThreadPool(new DaemonThreadFactory(8)); private final Peer peer; private final String name; @@ -24,6 +29,24 @@ public class PeerConnectTask implements Task { @Override public void perform() throws InterruptedException { - Network.getInstance().connectPeer(peer); + // Submit connection task to a dedicated thread pool for non-blocking I/O + connectionExecutor.submit(() -> { + try { + connectPeerAsync(peer); + } catch (InterruptedException e) { + LOGGER.error("Connection attempt interrupted for peer {}", peer, e); + Thread.currentThread().interrupt(); // Reset interrupt flag + } + }); + } + + private void connectPeerAsync(Peer peer) throws InterruptedException { + // Perform peer connection in a separate thread to avoid blocking main task execution + try { + Network.getInstance().connectPeer(peer); + LOGGER.trace("Successfully connected to peer {}", peer); + } catch (Exception e) { + LOGGER.error("Error connecting to peer {}", peer, e); + } } } diff --git a/src/main/java/org/qortal/settings/Settings.java b/src/main/java/org/qortal/settings/Settings.java index 937d352a..305021d5 100644 --- a/src/main/java/org/qortal/settings/Settings.java +++ b/src/main/java/org/qortal/settings/Settings.java @@ -213,7 +213,7 @@ public class Settings { public long recoveryModeTimeout = 9999999999999L; /** Minimum peer version number required in order to sync with them */ - private String minPeerVersion = "4.6.2"; + private String minPeerVersion = "4.6.3"; /** Whether to allow connections with peers below minPeerVersion * If true, we won't sync with them but they can still sync with us, and will show in the peers list * If false, sync will be blocked both ways, and they will not appear in the peers list */ diff --git a/src/main/java/org/qortal/transaction/RewardShareTransaction.java b/src/main/java/org/qortal/transaction/RewardShareTransaction.java index 50eead31..31734204 100644 --- a/src/main/java/org/qortal/transaction/RewardShareTransaction.java +++ b/src/main/java/org/qortal/transaction/RewardShareTransaction.java @@ -123,7 +123,7 @@ public class RewardShareTransaction extends Transaction { final boolean isCancellingSharePercent = this.rewardShareTransactionData.getSharePercent() < 0; // Creator themselves needs to be allowed to mint (unless cancelling) - if (!isCancellingSharePercent && !creator.canMint()) + if (!isCancellingSharePercent && !creator.canMint(false)) return ValidationResult.NOT_MINTING_ACCOUNT; // Qortal: special rules in play depending whether recipient is also minter diff --git a/src/main/resources/blockchain.json b/src/main/resources/blockchain.json index 1dcd9e46..762a5708 100644 --- a/src/main/resources/blockchain.json +++ b/src/main/resources/blockchain.json @@ -112,7 +112,8 @@ "enableRewardshareHeight": 1905100, "onlyMintWithNameHeight": 1900300, "removeOnlyMintWithNameHeight": 1935500, - "groupMemberCheckHeight": 1902700 + "groupMemberCheckHeight": 1902700, + "fixBatchRewardHeight": 1945900 }, "checkpoints": [ { "height": 1136300, "signature": "3BbwawEF2uN8Ni5ofpJXkukoU8ctAPxYoFB7whq9pKfBnjfZcpfEJT4R95NvBDoTP8WDyWvsUvbfHbcr9qSZuYpSKZjUQTvdFf6eqznHGEwhZApWfvXu6zjGCxYCp65F4jsVYYJjkzbjmkCg5WAwN5voudngA23kMK6PpTNygapCzXt" } diff --git a/src/test/java/org/qortal/test/TransferPrivsTests.java b/src/test/java/org/qortal/test/TransferPrivsTests.java index 86a0e743..ad1d2a2a 100644 --- a/src/test/java/org/qortal/test/TransferPrivsTests.java +++ b/src/test/java/org/qortal/test/TransferPrivsTests.java @@ -74,7 +74,7 @@ public class TransferPrivsTests extends Common { public void testAliceIntoNewAccountTransferPrivs() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { TestAccount alice = Common.getTestAccount(repository, "alice"); - assertTrue(alice.canMint()); + assertTrue(alice.canMint(false)); PrivateKeyAccount aliceMintingAccount = Common.getTestAccount(repository, "alice-reward-share"); @@ -86,8 +86,8 @@ public class TransferPrivsTests extends Common { combineAccounts(repository, alice, randomAccount, aliceMintingAccount); - assertFalse(alice.canMint()); - assertTrue(randomAccount.canMint()); + assertFalse(alice.canMint(false)); + assertTrue(randomAccount.canMint(false)); } } @@ -97,8 +97,8 @@ public class TransferPrivsTests extends Common { TestAccount alice = Common.getTestAccount(repository, "alice"); TestAccount dilbert = Common.getTestAccount(repository, "dilbert"); - assertTrue(alice.canMint()); - assertTrue(dilbert.canMint()); + assertTrue(alice.canMint(false)); + assertTrue(dilbert.canMint(false)); // Dilbert has level, Alice does not so we need Alice to mint enough blocks to bump Dilbert's level post-combine final int expectedPostCombineLevel = dilbert.getLevel() + 1; @@ -118,11 +118,11 @@ public class TransferPrivsTests extends Common { // Post-combine sender checks checkSenderPostTransfer(postCombineAliceData); - assertFalse(alice.canMint()); + assertFalse(alice.canMint(false)); // Post-combine recipient checks checkRecipientPostTransfer(preCombineAliceData, preCombineDilbertData, postCombineDilbertData, expectedPostCombineLevel); - assertTrue(dilbert.canMint()); + assertTrue(dilbert.canMint(false)); // Orphan previous block BlockUtils.orphanLastBlock(repository); @@ -130,12 +130,12 @@ public class TransferPrivsTests extends Common { // Sender checks AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress()); checkAccountDataRestored("sender", preCombineAliceData, orphanedAliceData); - assertTrue(alice.canMint()); + assertTrue(alice.canMint(false)); // Recipient checks AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress()); checkAccountDataRestored("recipient", preCombineDilbertData, orphanedDilbertData); - assertTrue(dilbert.canMint()); + assertTrue(dilbert.canMint(false)); } } @@ -145,8 +145,8 @@ public class TransferPrivsTests extends Common { TestAccount alice = Common.getTestAccount(repository, "alice"); TestAccount dilbert = Common.getTestAccount(repository, "dilbert"); - assertTrue(dilbert.canMint()); - assertTrue(alice.canMint()); + assertTrue(dilbert.canMint(false)); + assertTrue(alice.canMint(false)); // Dilbert has level, Alice does not so we need Alice to mint enough blocks to surpass Dilbert's level post-combine final int expectedPostCombineLevel = dilbert.getLevel() + 1; @@ -166,11 +166,11 @@ public class TransferPrivsTests extends Common { // Post-combine sender checks checkSenderPostTransfer(postCombineDilbertData); - assertFalse(dilbert.canMint()); + assertFalse(dilbert.canMint(false)); // Post-combine recipient checks checkRecipientPostTransfer(preCombineDilbertData, preCombineAliceData, postCombineAliceData, expectedPostCombineLevel); - assertTrue(alice.canMint()); + assertTrue(alice.canMint(false)); // Orphan previous block BlockUtils.orphanLastBlock(repository); @@ -178,12 +178,12 @@ public class TransferPrivsTests extends Common { // Sender checks AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress()); checkAccountDataRestored("sender", preCombineDilbertData, orphanedDilbertData); - assertTrue(dilbert.canMint()); + assertTrue(dilbert.canMint(false)); // Recipient checks AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress()); checkAccountDataRestored("recipient", preCombineAliceData, orphanedAliceData); - assertTrue(alice.canMint()); + assertTrue(alice.canMint(false)); } } @@ -202,8 +202,8 @@ public class TransferPrivsTests extends Common { TestAccount chloe = Common.getTestAccount(repository, "chloe"); TestAccount dilbert = Common.getTestAccount(repository, "dilbert"); - assertTrue(dilbert.canMint()); - assertFalse(chloe.canMint()); + assertTrue(dilbert.canMint(false)); + assertFalse(chloe.canMint(false)); // COMBINE DILBERT INTO CHLOE @@ -225,16 +225,16 @@ public class TransferPrivsTests extends Common { // Post-combine sender checks checkSenderPostTransfer(post1stCombineDilbertData); - assertFalse(dilbert.canMint()); + assertFalse(dilbert.canMint(false)); // Post-combine recipient checks checkRecipientPostTransfer(pre1stCombineDilbertData, pre1stCombineChloeData, post1stCombineChloeData, expectedPost1stCombineLevel); - assertTrue(chloe.canMint()); + assertTrue(chloe.canMint(false)); // COMBINE ALICE INTO CHLOE - assertTrue(alice.canMint()); - assertTrue(chloe.canMint()); + assertTrue(alice.canMint(false)); + assertTrue(chloe.canMint(false)); // Alice needs to mint enough blocks to surpass Chloe's level post-combine final int expectedPost2ndCombineLevel = chloe.getLevel() + 1; @@ -254,11 +254,11 @@ public class TransferPrivsTests extends Common { // Post-combine sender checks checkSenderPostTransfer(post2ndCombineAliceData); - assertFalse(alice.canMint()); + assertFalse(alice.canMint(false)); // Post-combine recipient checks checkRecipientPostTransfer(pre2ndCombineAliceData, pre2ndCombineChloeData, post2ndCombineChloeData, expectedPost2ndCombineLevel); - assertTrue(chloe.canMint()); + assertTrue(chloe.canMint(false)); // Orphan 2nd combine BlockUtils.orphanLastBlock(repository); @@ -266,12 +266,12 @@ public class TransferPrivsTests extends Common { // Sender checks AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress()); checkAccountDataRestored("sender", pre2ndCombineAliceData, orphanedAliceData); - assertTrue(alice.canMint()); + assertTrue(alice.canMint(false)); // Recipient checks AccountData orphanedChloeData = repository.getAccountRepository().getAccount(chloe.getAddress()); checkAccountDataRestored("recipient", pre2ndCombineChloeData, orphanedChloeData); - assertTrue(chloe.canMint()); + assertTrue(chloe.canMint(false)); // Orphan 1nd combine BlockUtils.orphanToBlock(repository, pre1stCombineBlockHeight); @@ -279,7 +279,7 @@ public class TransferPrivsTests extends Common { // Sender checks AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress()); checkAccountDataRestored("sender", pre1stCombineDilbertData, orphanedDilbertData); - assertTrue(dilbert.canMint()); + assertTrue(dilbert.canMint(false)); // Recipient checks orphanedChloeData = repository.getAccountRepository().getAccount(chloe.getAddress()); @@ -287,7 +287,7 @@ public class TransferPrivsTests extends Common { // Chloe canMint() would return true here due to Alice-Chloe reward-share minting at top of method, so undo that minting by orphaning back to block 1 BlockUtils.orphanToBlock(repository, 1); - assertFalse(chloe.canMint()); + assertFalse(chloe.canMint(false)); } }