Merge pull request #221 from kennycud/master

Minter Group Check Optimizations - Have been tested by 50+ nodes for multiple days. The only thing we have to verify prior to merging the upcoming changes from Alpha, is validate the additional boolean passed in to canMint on line 1521 in current block.java (isMinterValid)
This commit is contained in:
crowetic 2024-11-25 18:01:13 -08:00 committed by GitHub
commit 1f9a2edca4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 53 additions and 40 deletions

View File

@ -205,10 +205,11 @@ public class Account {
* <li>account's address is a member of the minter group</li> * <li>account's address is a member of the minter group</li>
* </ul> * </ul>
* *
* @param isGroupValidated true if this account has already been validated for MINTER Group membership
* @return true if account can be considered "minting account" * @return true if account can be considered "minting account"
* @throws DataException * @throws DataException
*/ */
public boolean canMint() throws DataException { public boolean canMint(boolean isGroupValidated) throws DataException {
AccountData accountData = this.repository.getAccountRepository().getAccount(this.address); AccountData accountData = this.repository.getAccountRepository().getAccount(this.address);
NameRepository nameRepository = this.repository.getNameRepository(); NameRepository nameRepository = this.repository.getNameRepository();
GroupRepository groupRepository = this.repository.getGroupRepository(); GroupRepository groupRepository = this.repository.getGroupRepository();
@ -251,9 +252,9 @@ public class Account {
if (blockchainHeight >= groupCheckHeight && blockchainHeight < removeNameCheckHeight) { if (blockchainHeight >= groupCheckHeight && blockchainHeight < removeNameCheckHeight) {
List<NameData> myName = nameRepository.getNamesByOwner(myAddress); List<NameData> myName = nameRepository.getNamesByOwner(myAddress);
if (Account.isFounder(accountData.getFlags())) { 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 { } 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 // Account's address is a member of the minter group
if (blockchainHeight >= removeNameCheckHeight) { if (blockchainHeight >= removeNameCheckHeight) {
if (Account.isFounder(accountData.getFlags())) { if (Account.isFounder(accountData.getFlags())) {
return accountData.getBlocksMintedPenalty() == 0 && groupRepository.memberExists(groupIdToMint, myAddress); return accountData.getBlocksMintedPenalty() == 0 && (isGroupValidated || groupRepository.memberExists(groupIdToMint, myAddress));
} else { } else {
return level >= levelToMint && groupRepository.memberExists(groupIdToMint, myAddress); return level >= levelToMint && (isGroupValidated || groupRepository.memberExists(groupIdToMint, myAddress));
} }
} }

View File

@ -459,7 +459,7 @@ public class AdminResource {
// Qortal: check reward-share's minting account is still allowed to mint // Qortal: check reward-share's minting account is still allowed to mint
Account rewardShareMintingAccount = new Account(repository, rewardShareData.getMinter()); Account rewardShareMintingAccount = new Account(repository, rewardShareData.getMinter());
if (!rewardShareMintingAccount.canMint()) if (!rewardShareMintingAccount.canMint(false))
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.CANNOT_MINT); throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.CANNOT_MINT);
MintingAccountData mintingAccountData = new MintingAccountData(mintingAccount.getPrivateKey(), mintingAccount.getPublicKey()); MintingAccountData mintingAccountData = new MintingAccountData(mintingAccount.getPrivateKey(), mintingAccount.getPublicKey());

View File

@ -1518,7 +1518,7 @@ public class Block {
return false; return false;
Account mintingAccount = new PublicKeyAccount(this.repository, rewardShareData.getMinterPublicKey()); Account mintingAccount = new PublicKeyAccount(this.repository, rewardShareData.getMinterPublicKey());
return mintingAccount.canMint(); return mintingAccount.canMint(false);
} }
/** /**

View File

@ -148,7 +148,7 @@ public class BlockMinter extends Thread {
} }
Account mintingAccount = new Account(repository, rewardShareData.getMinter()); 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 // Minting-account component of reward-share can no longer mint - disregard
madi.remove(); madi.remove();
continue; continue;

View File

@ -13,6 +13,7 @@ import org.qortal.crypto.MemoryPoW;
import org.qortal.crypto.Qortal25519Extras; import org.qortal.crypto.Qortal25519Extras;
import org.qortal.data.account.MintingAccountData; import org.qortal.data.account.MintingAccountData;
import org.qortal.data.account.RewardShareData; import org.qortal.data.account.RewardShareData;
import org.qortal.data.group.GroupMemberData;
import org.qortal.data.network.OnlineAccountData; import org.qortal.data.network.OnlineAccountData;
import org.qortal.network.Network; import org.qortal.network.Network;
import org.qortal.network.Peer; import org.qortal.network.Peer;
@ -224,6 +225,12 @@ public class OnlineAccountsManager {
Set<OnlineAccountData> onlineAccountsToAdd = new HashSet<>(); Set<OnlineAccountData> onlineAccountsToAdd = new HashSet<>();
Set<OnlineAccountData> onlineAccountsToRemove = new HashSet<>(); Set<OnlineAccountData> onlineAccountsToRemove = new HashSet<>();
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
List<String> mintingGroupMemberAddresses
= repository.getGroupRepository()
.getGroupMembers(BlockChain.getInstance().getMintingGroupId()).stream()
.map(GroupMemberData::getMember)
.collect(Collectors.toList());
for (OnlineAccountData onlineAccountData : this.onlineAccountsImportQueue) { for (OnlineAccountData onlineAccountData : this.onlineAccountsImportQueue) {
if (isStopping) if (isStopping)
return; return;
@ -236,7 +243,7 @@ public class OnlineAccountsManager {
continue; continue;
} }
boolean isValid = this.isValidCurrentAccount(repository, onlineAccountData); boolean isValid = this.isValidCurrentAccount(repository, mintingGroupMemberAddresses, onlineAccountData);
if (isValid) if (isValid)
onlineAccountsToAdd.add(onlineAccountData); onlineAccountsToAdd.add(onlineAccountData);
@ -315,7 +322,7 @@ public class OnlineAccountsManager {
return inplaceArray; return inplaceArray;
} }
private static boolean isValidCurrentAccount(Repository repository, OnlineAccountData onlineAccountData) throws DataException { private static boolean isValidCurrentAccount(Repository repository, List<String> mintingGroupMemberAddresses, OnlineAccountData onlineAccountData) throws DataException {
final Long now = NTP.getTime(); final Long now = NTP.getTime();
if (now == null) if (now == null)
return false; return false;
@ -350,9 +357,14 @@ public class OnlineAccountsManager {
LOGGER.trace(() -> String.format("Rejecting unknown online reward-share public key %s", Base58.encode(rewardSharePublicKey))); LOGGER.trace(() -> String.format("Rejecting unknown online reward-share public key %s", Base58.encode(rewardSharePublicKey)));
return false; 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()); 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 // 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())); LOGGER.trace(() -> String.format("Rejecting online reward-share with non-minting account %s", mintingAccount.getAddress()));
return false; return false;
@ -539,7 +551,7 @@ public class OnlineAccountsManager {
} }
Account mintingAccount = new Account(repository, rewardShareData.getMinter()); 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 // Minting-account component of reward-share can no longer mint - disregard
iterator.remove(); iterator.remove();
continue; continue;

View File

@ -123,7 +123,7 @@ public class RewardShareTransaction extends Transaction {
final boolean isCancellingSharePercent = this.rewardShareTransactionData.getSharePercent() < 0; final boolean isCancellingSharePercent = this.rewardShareTransactionData.getSharePercent() < 0;
// Creator themselves needs to be allowed to mint (unless cancelling) // Creator themselves needs to be allowed to mint (unless cancelling)
if (!isCancellingSharePercent && !creator.canMint()) if (!isCancellingSharePercent && !creator.canMint(false))
return ValidationResult.NOT_MINTING_ACCOUNT; return ValidationResult.NOT_MINTING_ACCOUNT;
// Qortal: special rules in play depending whether recipient is also minter // Qortal: special rules in play depending whether recipient is also minter

View File

@ -74,7 +74,7 @@ public class TransferPrivsTests extends Common {
public void testAliceIntoNewAccountTransferPrivs() throws DataException { public void testAliceIntoNewAccountTransferPrivs() throws DataException {
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
TestAccount alice = Common.getTestAccount(repository, "alice"); TestAccount alice = Common.getTestAccount(repository, "alice");
assertTrue(alice.canMint()); assertTrue(alice.canMint(false));
PrivateKeyAccount aliceMintingAccount = Common.getTestAccount(repository, "alice-reward-share"); PrivateKeyAccount aliceMintingAccount = Common.getTestAccount(repository, "alice-reward-share");
@ -86,8 +86,8 @@ public class TransferPrivsTests extends Common {
combineAccounts(repository, alice, randomAccount, aliceMintingAccount); combineAccounts(repository, alice, randomAccount, aliceMintingAccount);
assertFalse(alice.canMint()); assertFalse(alice.canMint(false));
assertTrue(randomAccount.canMint()); assertTrue(randomAccount.canMint(false));
} }
} }
@ -97,8 +97,8 @@ public class TransferPrivsTests extends Common {
TestAccount alice = Common.getTestAccount(repository, "alice"); TestAccount alice = Common.getTestAccount(repository, "alice");
TestAccount dilbert = Common.getTestAccount(repository, "dilbert"); TestAccount dilbert = Common.getTestAccount(repository, "dilbert");
assertTrue(alice.canMint()); assertTrue(alice.canMint(false));
assertTrue(dilbert.canMint()); 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 // 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; final int expectedPostCombineLevel = dilbert.getLevel() + 1;
@ -118,11 +118,11 @@ public class TransferPrivsTests extends Common {
// Post-combine sender checks // Post-combine sender checks
checkSenderPostTransfer(postCombineAliceData); checkSenderPostTransfer(postCombineAliceData);
assertFalse(alice.canMint()); assertFalse(alice.canMint(false));
// Post-combine recipient checks // Post-combine recipient checks
checkRecipientPostTransfer(preCombineAliceData, preCombineDilbertData, postCombineDilbertData, expectedPostCombineLevel); checkRecipientPostTransfer(preCombineAliceData, preCombineDilbertData, postCombineDilbertData, expectedPostCombineLevel);
assertTrue(dilbert.canMint()); assertTrue(dilbert.canMint(false));
// Orphan previous block // Orphan previous block
BlockUtils.orphanLastBlock(repository); BlockUtils.orphanLastBlock(repository);
@ -130,12 +130,12 @@ public class TransferPrivsTests extends Common {
// Sender checks // Sender checks
AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress()); AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress());
checkAccountDataRestored("sender", preCombineAliceData, orphanedAliceData); checkAccountDataRestored("sender", preCombineAliceData, orphanedAliceData);
assertTrue(alice.canMint()); assertTrue(alice.canMint(false));
// Recipient checks // Recipient checks
AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress()); AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress());
checkAccountDataRestored("recipient", preCombineDilbertData, orphanedDilbertData); 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 alice = Common.getTestAccount(repository, "alice");
TestAccount dilbert = Common.getTestAccount(repository, "dilbert"); TestAccount dilbert = Common.getTestAccount(repository, "dilbert");
assertTrue(dilbert.canMint()); assertTrue(dilbert.canMint(false));
assertTrue(alice.canMint()); 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 // 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; final int expectedPostCombineLevel = dilbert.getLevel() + 1;
@ -166,11 +166,11 @@ public class TransferPrivsTests extends Common {
// Post-combine sender checks // Post-combine sender checks
checkSenderPostTransfer(postCombineDilbertData); checkSenderPostTransfer(postCombineDilbertData);
assertFalse(dilbert.canMint()); assertFalse(dilbert.canMint(false));
// Post-combine recipient checks // Post-combine recipient checks
checkRecipientPostTransfer(preCombineDilbertData, preCombineAliceData, postCombineAliceData, expectedPostCombineLevel); checkRecipientPostTransfer(preCombineDilbertData, preCombineAliceData, postCombineAliceData, expectedPostCombineLevel);
assertTrue(alice.canMint()); assertTrue(alice.canMint(false));
// Orphan previous block // Orphan previous block
BlockUtils.orphanLastBlock(repository); BlockUtils.orphanLastBlock(repository);
@ -178,12 +178,12 @@ public class TransferPrivsTests extends Common {
// Sender checks // Sender checks
AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress()); AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress());
checkAccountDataRestored("sender", preCombineDilbertData, orphanedDilbertData); checkAccountDataRestored("sender", preCombineDilbertData, orphanedDilbertData);
assertTrue(dilbert.canMint()); assertTrue(dilbert.canMint(false));
// Recipient checks // Recipient checks
AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress()); AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress());
checkAccountDataRestored("recipient", preCombineAliceData, orphanedAliceData); 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 chloe = Common.getTestAccount(repository, "chloe");
TestAccount dilbert = Common.getTestAccount(repository, "dilbert"); TestAccount dilbert = Common.getTestAccount(repository, "dilbert");
assertTrue(dilbert.canMint()); assertTrue(dilbert.canMint(false));
assertFalse(chloe.canMint()); assertFalse(chloe.canMint(false));
// COMBINE DILBERT INTO CHLOE // COMBINE DILBERT INTO CHLOE
@ -225,16 +225,16 @@ public class TransferPrivsTests extends Common {
// Post-combine sender checks // Post-combine sender checks
checkSenderPostTransfer(post1stCombineDilbertData); checkSenderPostTransfer(post1stCombineDilbertData);
assertFalse(dilbert.canMint()); assertFalse(dilbert.canMint(false));
// Post-combine recipient checks // Post-combine recipient checks
checkRecipientPostTransfer(pre1stCombineDilbertData, pre1stCombineChloeData, post1stCombineChloeData, expectedPost1stCombineLevel); checkRecipientPostTransfer(pre1stCombineDilbertData, pre1stCombineChloeData, post1stCombineChloeData, expectedPost1stCombineLevel);
assertTrue(chloe.canMint()); assertTrue(chloe.canMint(false));
// COMBINE ALICE INTO CHLOE // COMBINE ALICE INTO CHLOE
assertTrue(alice.canMint()); assertTrue(alice.canMint(false));
assertTrue(chloe.canMint()); assertTrue(chloe.canMint(false));
// Alice needs to mint enough blocks to surpass Chloe's level post-combine // Alice needs to mint enough blocks to surpass Chloe's level post-combine
final int expectedPost2ndCombineLevel = chloe.getLevel() + 1; final int expectedPost2ndCombineLevel = chloe.getLevel() + 1;
@ -254,11 +254,11 @@ public class TransferPrivsTests extends Common {
// Post-combine sender checks // Post-combine sender checks
checkSenderPostTransfer(post2ndCombineAliceData); checkSenderPostTransfer(post2ndCombineAliceData);
assertFalse(alice.canMint()); assertFalse(alice.canMint(false));
// Post-combine recipient checks // Post-combine recipient checks
checkRecipientPostTransfer(pre2ndCombineAliceData, pre2ndCombineChloeData, post2ndCombineChloeData, expectedPost2ndCombineLevel); checkRecipientPostTransfer(pre2ndCombineAliceData, pre2ndCombineChloeData, post2ndCombineChloeData, expectedPost2ndCombineLevel);
assertTrue(chloe.canMint()); assertTrue(chloe.canMint(false));
// Orphan 2nd combine // Orphan 2nd combine
BlockUtils.orphanLastBlock(repository); BlockUtils.orphanLastBlock(repository);
@ -266,12 +266,12 @@ public class TransferPrivsTests extends Common {
// Sender checks // Sender checks
AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress()); AccountData orphanedAliceData = repository.getAccountRepository().getAccount(alice.getAddress());
checkAccountDataRestored("sender", pre2ndCombineAliceData, orphanedAliceData); checkAccountDataRestored("sender", pre2ndCombineAliceData, orphanedAliceData);
assertTrue(alice.canMint()); assertTrue(alice.canMint(false));
// Recipient checks // Recipient checks
AccountData orphanedChloeData = repository.getAccountRepository().getAccount(chloe.getAddress()); AccountData orphanedChloeData = repository.getAccountRepository().getAccount(chloe.getAddress());
checkAccountDataRestored("recipient", pre2ndCombineChloeData, orphanedChloeData); checkAccountDataRestored("recipient", pre2ndCombineChloeData, orphanedChloeData);
assertTrue(chloe.canMint()); assertTrue(chloe.canMint(false));
// Orphan 1nd combine // Orphan 1nd combine
BlockUtils.orphanToBlock(repository, pre1stCombineBlockHeight); BlockUtils.orphanToBlock(repository, pre1stCombineBlockHeight);
@ -279,7 +279,7 @@ public class TransferPrivsTests extends Common {
// Sender checks // Sender checks
AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress()); AccountData orphanedDilbertData = repository.getAccountRepository().getAccount(dilbert.getAddress());
checkAccountDataRestored("sender", pre1stCombineDilbertData, orphanedDilbertData); checkAccountDataRestored("sender", pre1stCombineDilbertData, orphanedDilbertData);
assertTrue(dilbert.canMint()); assertTrue(dilbert.canMint(false));
// Recipient checks // Recipient checks
orphanedChloeData = repository.getAccountRepository().getAccount(chloe.getAddress()); 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 // 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); BlockUtils.orphanToBlock(repository, 1);
assertFalse(chloe.canMint()); assertFalse(chloe.canMint(false));
} }
} }