3
0
mirror of https://github.com/Qortal/qortal.git synced 2025-02-11 17:55:50 +00:00

Admin replace founders hardfork and online validation fail-safe hardfork.

This commit is contained in:
kennycud 2024-12-26 13:53:00 -08:00
parent 4f0aabfb36
commit 3952705edd
3 changed files with 154 additions and 27 deletions

View File

@ -23,6 +23,7 @@ import org.qortal.data.at.ATStateData;
import org.qortal.data.block.BlockData;
import org.qortal.data.block.BlockSummaryData;
import org.qortal.data.block.BlockTransactionData;
import org.qortal.data.group.GroupAdminData;
import org.qortal.data.network.OnlineAccountData;
import org.qortal.data.transaction.TransactionData;
import org.qortal.repository.*;
@ -170,6 +171,19 @@ public class Block {
}
}
/**
* Get Effective Minting Level
*
* @return the effective minting level, if a data exception is thrown, it catches the exception and returns a zero
*/
public int getEffectiveMintingLevel() {
try {
return this.mintingAccount.getEffectiveMintingLevel();
} catch (DataException e) {
return 0;
}
}
public Account getMintingAccount() {
return this.mintingAccount;
}
@ -186,7 +200,7 @@ public class Block {
* @return account-level share "bin" from blockchain config, or null if founder / none found
*/
public AccountLevelShareBin getShareBin(int blockHeight) {
if (this.isMinterFounder)
if (this.isMinterFounder && blockHeight < BlockChain.getInstance().getAdminsReplaceFoundersHeight())
return null;
final int accountLevel = this.mintingAccountData.getLevel();
@ -736,15 +750,7 @@ public class Block {
List<ExpandedAccount> expandedAccounts = new ArrayList<>();
for (RewardShareData rewardShare : this.cachedOnlineRewardShares) {
int groupId = BlockChain.getInstance().getMintingGroupId();
String address = rewardShare.getMinter();
boolean isMinterGroupMember = repository.getGroupRepository().memberExists(groupId, address);
if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight())
expandedAccounts.add(new ExpandedAccount(repository, rewardShare));
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight() && isMinterGroupMember)
expandedAccounts.add(new ExpandedAccount(repository, rewardShare));
expandedAccounts.add(new ExpandedAccount(repository, rewardShare));
}
this.cachedExpandedAccounts = expandedAccounts;
@ -1156,20 +1162,32 @@ public class Block {
// After feature trigger, require all online account minters to be greater than level 0
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getOnlineAccountMinterLevelValidationHeight()) {
List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
for (ExpandedAccount account : expandedAccounts) {
int groupId = BlockChain.getInstance().getMintingGroupId();
String address = account.getMintingAccount().getAddress();
boolean isMinterGroupMember = repository.getGroupRepository().memberExists(groupId, address);
if( this.blockData.getHeight() < BlockChain.getInstance().getOnlineValidationFailSafeHeight()) {
List<ExpandedAccount> expandedAccounts
= this.getExpandedAccounts().stream()
.filter(expandedAccount -> expandedAccount.isMinterMember)
.collect(Collectors.toList());
if (account.getMintingAccount().getEffectiveMintingLevel() == 0)
return ValidationResult.ONLINE_ACCOUNTS_INVALID;
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight()) {
if (!isMinterGroupMember)
for (ExpandedAccount account : expandedAccounts) {
if (account.getMintingAccount().getEffectiveMintingLevel() == 0)
return ValidationResult.ONLINE_ACCOUNTS_INVALID;
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight()) {
if (!account.isMinterMember)
return ValidationResult.ONLINE_ACCOUNTS_INVALID;
}
}
}
// this.blockData.getHeight() >= BlockChain.getInstance().getOnlineValidationFailSafeHeight()
else {
Optional<ExpandedAccount> anyInvalidAccount
= this.getExpandedAccounts().stream()
.filter(
account -> account.getEffectiveMintingLevel() == 0 ||
!account.isMinterMember)
.findAny();
if( anyInvalidAccount.isPresent() ) return ValidationResult.ONLINE_ACCOUNTS_INVALID;
}
}
// If block is past a certain age then we simply assume the signatures were correct
@ -1659,7 +1677,17 @@ public class Block {
final List<Integer> cumulativeBlocksByLevel = BlockChain.getInstance().getCumulativeBlocksByLevel();
final int maximumLevel = cumulativeBlocksByLevel.size() - 1;
final List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
final List<ExpandedAccount> expandedAccounts;
if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight()) {
expandedAccounts = this.getExpandedAccounts().stream().collect(Collectors.toList());
}
else {
expandedAccounts
= this.getExpandedAccounts().stream()
.filter(expandedAccount -> expandedAccount.isMinterMember)
.collect(Collectors.toList());
}
Set<AccountData> allUniqueExpandedAccounts = new HashSet<>();
for (ExpandedAccount expandedAccount : expandedAccounts) {
@ -2059,7 +2087,17 @@ public class Block {
final List<Integer> cumulativeBlocksByLevel = BlockChain.getInstance().getCumulativeBlocksByLevel();
final int maximumLevel = cumulativeBlocksByLevel.size() - 1;
final List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
final List<ExpandedAccount> expandedAccounts;
if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight()) {
expandedAccounts = this.getExpandedAccounts().stream().collect(Collectors.toList());
}
else {
expandedAccounts
= this.getExpandedAccounts().stream()
.filter(expandedAccount -> expandedAccount.isMinterMember)
.collect(Collectors.toList());
}
Set<AccountData> allUniqueExpandedAccounts = new HashSet<>();
for (ExpandedAccount expandedAccount : expandedAccounts) {
@ -2263,7 +2301,17 @@ public class Block {
List<BlockRewardCandidate> rewardCandidates = new ArrayList<>();
// All online accounts
final List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
final List<ExpandedAccount> expandedAccounts;
if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight()) {
expandedAccounts = this.getExpandedAccounts().stream().collect(Collectors.toList());
}
else {
expandedAccounts
= this.getExpandedAccounts().stream()
.filter(expandedAccount -> expandedAccount.isMinterMember)
.collect(Collectors.toList());
}
/*
* Distribution rules:
@ -2388,7 +2436,7 @@ public class Block {
final long qoraHoldersShare = BlockChain.getInstance().getQoraHoldersShareAtHeight(this.blockData.getHeight());
// Perform account-level-based reward scaling if appropriate
if (!haveFounders) {
if (!haveFounders && this.blockData.getHeight() < BlockChain.getInstance().getAdminsReplaceFoundersHeight() ) {
// Recalculate distribution ratios based on candidates
// Nothing shared? This shouldn't happen
@ -2424,7 +2472,7 @@ public class Block {
}
// Add founders as reward candidate if appropriate
if (haveFounders) {
if (haveFounders && this.blockData.getHeight() < BlockChain.getInstance().getAdminsReplaceFoundersHeight()) {
// Yes: add to reward candidates list
BlockRewardDistributor founderDistributor = (distributionAmount, balanceChanges) -> distributeBlockRewardShare(distributionAmount, onlineFounderAccounts, balanceChanges);
@ -2432,10 +2480,77 @@ public class Block {
BlockRewardCandidate rewardCandidate = new BlockRewardCandidate("Founders", foundersShare, founderDistributor);
rewardCandidates.add(rewardCandidate);
}
else if (this.blockData.getHeight() >= BlockChain.getInstance().getAdminsReplaceFoundersHeight()) {
try (final Repository repository = RepositoryManager.getRepository()) {
GroupRepository groupRepository = repository.getGroupRepository();
// all minter admins
List<String> minterAdmins
= groupRepository.getGroupAdmins(BlockChain.getInstance().getMintingGroupId()).stream()
.map(GroupAdminData::getAdmin)
.collect(Collectors.toList());
// all minter admins that are online
List<ExpandedAccount> onlineMinterAdminAccounts
= expandedAccounts.stream()
.filter(expandedAccount -> minterAdmins.contains(expandedAccount.getMintingAccount().getAddress()))
.collect(Collectors.toList());
BlockRewardDistributor minterAdminDistributor
= (distributionAmount, balanceChanges)
->
distributeBlockRewardShare(distributionAmount, onlineMinterAdminAccounts, balanceChanges);
long adminShare = 1_00000000 - totalShares;
long minterAdminShare = adminShare / 2;
BlockRewardCandidate minterAdminRewardCandidate
= new BlockRewardCandidate("Minter Admins", minterAdminShare, minterAdminDistributor);
rewardCandidates.add(minterAdminRewardCandidate);
totalShares -= adminShare;
// all dev admins
List<String> devAdminAddresses
= groupRepository.getGroupAdmins(1).stream()
.map(GroupAdminData::getAdmin)
.collect(Collectors.toList());
BlockRewardDistributor devAdminDistributor
= (distributionAmount, balanceChanges) -> distributeToAccounts(distributionAmount, devAdminAddresses, balanceChanges);
long devAdminShare = 1_00000000 - totalShares;
BlockRewardCandidate devAdminRewardCandidate
= new BlockRewardCandidate("Dev Admins", devAdminShare,devAdminDistributor);
rewardCandidates.add(devAdminRewardCandidate);
}
}
return rewardCandidates;
}
/**
* Distribute To Accounts
*
* Merges distribute shares to a map of distribution shares.
*
* @param distributionAmount the amount to distribute
* @param accountAddressess the addresses to distribute to
* @param balanceChanges the map of distribution shares, this gets appended to
*
* @return the total amount mapped to addresses for distribution
*/
public static long distributeToAccounts(long distributionAmount, List<String> accountAddressess, Map<String, Long> balanceChanges) {
long distibutionShare = distributionAmount / accountAddressess.size();
for(String accountAddress : accountAddressess ) {
balanceChanges.merge(accountAddress, distibutionShare, Long::sum);
}
return distibutionShare * accountAddressess.size();
}
private static long distributeBlockRewardShare(long distributionAmount, List<ExpandedAccount> accounts, Map<String, Long> balanceChanges) {
// Collate all expanded accounts by minting account
Map<String, List<ExpandedAccount>> accountsByMinter = new HashMap<>();

View File

@ -88,7 +88,9 @@ public class BlockChain {
onlyMintWithNameHeight,
removeOnlyMintWithNameHeight,
groupMemberCheckHeight,
fixBatchRewardHeight
fixBatchRewardHeight,
adminsReplaceFoundersHeight,
onlineValidationFailSafeHeight
}
// Custom transaction fees
@ -662,6 +664,14 @@ public class BlockChain {
return this.featureTriggers.get(FeatureTrigger.fixBatchRewardHeight.name()).intValue();
}
public int getAdminsReplaceFoundersHeight() {
return this.featureTriggers.get(FeatureTrigger.adminsReplaceFoundersHeight.name()).intValue();
}
public int getOnlineValidationFailSafeHeight() {
return this.featureTriggers.get(FeatureTrigger.onlineValidationFailSafeHeight.name()).intValue();
}
// More complex getters for aspects that change by height or timestamp
public long getRewardAtHeight(int ourHeight) {

View File

@ -113,7 +113,9 @@
"onlyMintWithNameHeight": 1900300,
"removeOnlyMintWithNameHeight": 1935500,
"groupMemberCheckHeight": 1902700,
"fixBatchRewardHeight": 1945900
"fixBatchRewardHeight": 1945900,
"adminsReplaceFoundersHeight": 9999999,
"onlineValidationFailSafeHeight": 9999999
},
"checkpoints": [
{ "height": 1136300, "signature": "3BbwawEF2uN8Ni5ofpJXkukoU8ctAPxYoFB7whq9pKfBnjfZcpfEJT4R95NvBDoTP8WDyWvsUvbfHbcr9qSZuYpSKZjUQTvdFf6eqznHGEwhZApWfvXu6zjGCxYCp65F4jsVYYJjkzbjmkCg5WAwN5voudngA23kMK6PpTNygapCzXt" }