mirror of
https://github.com/Qortal/qortal.git
synced 2025-03-13 11:12:31 +00:00
Improve code dealing with increase account level due to generated blocks & add orphan equivalent.
This commit is contained in:
parent
6ba24e1820
commit
a3751823eb
@ -1204,32 +1204,14 @@ public class Block {
|
||||
}
|
||||
|
||||
protected void increaseAccountLevels() throws DataException {
|
||||
List<Integer> blocksNeededByLevel = BlockChain.getInstance().getBlocksNeededByLevel();
|
||||
|
||||
// Pre-calculate cumulative blocks required for each level
|
||||
int cumulativeBlocks = 0;
|
||||
int[] cumulativeBlocksByLevel = new int[blocksNeededByLevel.size() + 1];
|
||||
for (int level = 0; level < cumulativeBlocksByLevel.length; ++level) {
|
||||
cumulativeBlocksByLevel[level] = cumulativeBlocks;
|
||||
|
||||
if (level < blocksNeededByLevel.size())
|
||||
cumulativeBlocks += blocksNeededByLevel.get(level);
|
||||
}
|
||||
|
||||
List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
|
||||
|
||||
// We need to do this for both forgers and recipients
|
||||
this.increaseAccountLevels(expandedAccounts, cumulativeBlocksByLevel,
|
||||
expandedAccount -> expandedAccount.isForgerFounder,
|
||||
expandedAccount -> expandedAccount.forgerAccountData);
|
||||
|
||||
this.increaseAccountLevels(expandedAccounts, cumulativeBlocksByLevel,
|
||||
expandedAccount -> expandedAccount.isRecipientFounder,
|
||||
expandedAccount -> expandedAccount.recipientAccountData);
|
||||
this.increaseAccountLevels(expandedAccount -> expandedAccount.isForgerFounder, expandedAccount -> expandedAccount.forgerAccountData);
|
||||
this.increaseAccountLevels(expandedAccount -> expandedAccount.isRecipientFounder, expandedAccount -> expandedAccount.recipientAccountData);
|
||||
}
|
||||
|
||||
private void increaseAccountLevels(List<ExpandedAccount> expandedAccounts, int[] cumulativeBlocksByLevel,
|
||||
Predicate<ExpandedAccount> isFounder, Function<ExpandedAccount, AccountData> getAccountData) throws DataException {
|
||||
private void increaseAccountLevels(Predicate<ExpandedAccount> isFounder, Function<ExpandedAccount, AccountData> getAccountData) throws DataException {
|
||||
final List<Integer> cumulativeBlocksByLevel = BlockChain.getInstance().getCumulativeBlocksByLevel();
|
||||
final List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
|
||||
final boolean isProcessingRecipients = getAccountData.apply(expandedAccounts.get(0)) == expandedAccounts.get(0).recipientAccountData;
|
||||
|
||||
// Increase blocks generated count for all accounts
|
||||
@ -1244,21 +1226,21 @@ public class Block {
|
||||
|
||||
accountData.setBlocksGenerated(accountData.getBlocksGenerated() + 1);
|
||||
repository.getAccountRepository().setBlocksGenerated(accountData);
|
||||
LOGGER.trace(() -> String.format("Block generator %s has generated %d block%s", accountData.getAddress(), accountData.getBlocksGenerated(), (accountData.getBlocksGenerated() != 1 ? "s" : "")));
|
||||
LOGGER.trace(() -> String.format("Block generator %s up to %d generated block%s", accountData.getAddress(), accountData.getBlocksGenerated(), (accountData.getBlocksGenerated() != 1 ? "s" : "")));
|
||||
}
|
||||
|
||||
// We are only interested in accounts that are NOT founders and NOT already highest level
|
||||
final int maximumLevel = cumulativeBlocksByLevel.length - 1;
|
||||
final int maximumLevel = cumulativeBlocksByLevel.size() - 1;
|
||||
List<ExpandedAccount> candidateAccounts = expandedAccounts.stream().filter(expandedAccount -> !isFounder.test(expandedAccount) && getAccountData.apply(expandedAccount).getLevel() < maximumLevel).collect(Collectors.toList());
|
||||
|
||||
for (int c = 0; c < candidateAccounts.size(); ++c) {
|
||||
ExpandedAccount expandedAccount = candidateAccounts.get(c);
|
||||
final AccountData accountData = getAccountData.apply(expandedAccount);
|
||||
|
||||
final int effectiveBlocksGenerated = cumulativeBlocksByLevel[accountData.getInitialLevel()] + accountData.getBlocksGenerated();
|
||||
final int effectiveBlocksGenerated = cumulativeBlocksByLevel.get(accountData.getInitialLevel()) + accountData.getBlocksGenerated();
|
||||
|
||||
for (int newLevel = cumulativeBlocksByLevel.length - 1; newLevel > 0; --newLevel)
|
||||
if (effectiveBlocksGenerated >= cumulativeBlocksByLevel[newLevel]) {
|
||||
for (int newLevel = maximumLevel; newLevel > 0; --newLevel)
|
||||
if (effectiveBlocksGenerated >= cumulativeBlocksByLevel.get(newLevel)) {
|
||||
if (newLevel > accountData.getLevel()) {
|
||||
// Account has increased in level!
|
||||
accountData.setLevel(newLevel);
|
||||
@ -1530,7 +1512,53 @@ public class Block {
|
||||
}
|
||||
|
||||
protected void decreaseAccountLevels() throws DataException {
|
||||
// TODO !
|
||||
// We need to do this for both forgers and recipients
|
||||
this.decreaseAccountLevels(expandedAccount -> expandedAccount.isForgerFounder, expandedAccount -> expandedAccount.forgerAccountData);
|
||||
this.decreaseAccountLevels(expandedAccount -> expandedAccount.isRecipientFounder, expandedAccount -> expandedAccount.recipientAccountData);
|
||||
}
|
||||
|
||||
private void decreaseAccountLevels(Predicate<ExpandedAccount> isFounder, Function<ExpandedAccount, AccountData> getAccountData) throws DataException {
|
||||
final List<Integer> cumulativeBlocksByLevel = BlockChain.getInstance().getCumulativeBlocksByLevel();
|
||||
final List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
|
||||
final boolean isProcessingRecipients = getAccountData.apply(expandedAccounts.get(0)) == expandedAccounts.get(0).recipientAccountData;
|
||||
|
||||
// Decrease blocks generated count for all accounts
|
||||
for (int a = 0; a < expandedAccounts.size(); ++a) {
|
||||
ExpandedAccount expandedAccount = expandedAccounts.get(a);
|
||||
|
||||
// Don't decrease twice if recipient is also forger.
|
||||
if (isProcessingRecipients && expandedAccount.isRecipientAlsoForger)
|
||||
continue;
|
||||
|
||||
AccountData accountData = getAccountData.apply(expandedAccount);
|
||||
|
||||
accountData.setBlocksGenerated(accountData.getBlocksGenerated() - 1);
|
||||
repository.getAccountRepository().setBlocksGenerated(accountData);
|
||||
LOGGER.trace(() -> String.format("Block generator %s down to %d generated block%s", accountData.getAddress(), accountData.getBlocksGenerated(), (accountData.getBlocksGenerated() != 1 ? "s" : "")));
|
||||
}
|
||||
|
||||
// We are only interested in accounts that are NOT founders and NOT already lowest level
|
||||
final int maximumLevel = cumulativeBlocksByLevel.size() - 1;
|
||||
List<ExpandedAccount> candidateAccounts = expandedAccounts.stream().filter(expandedAccount -> !isFounder.test(expandedAccount) && getAccountData.apply(expandedAccount).getLevel() > 0).collect(Collectors.toList());
|
||||
|
||||
for (int c = 0; c < candidateAccounts.size(); ++c) {
|
||||
ExpandedAccount expandedAccount = candidateAccounts.get(c);
|
||||
final AccountData accountData = getAccountData.apply(expandedAccount);
|
||||
|
||||
final int effectiveBlocksGenerated = cumulativeBlocksByLevel.get(accountData.getInitialLevel()) + accountData.getBlocksGenerated();
|
||||
|
||||
for (int newLevel = maximumLevel; newLevel > 0; --newLevel)
|
||||
if (effectiveBlocksGenerated >= cumulativeBlocksByLevel.get(newLevel)) {
|
||||
if (newLevel < accountData.getLevel()) {
|
||||
// Account has decreased in level!
|
||||
accountData.setLevel(newLevel);
|
||||
repository.getAccountRepository().setLevel(accountData);
|
||||
LOGGER.trace(() -> String.format("Block generator %s reduced to level %d", accountData.getAddress(), accountData.getLevel()));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void distributeByAccountLevel(BigDecimal totalAmount) throws DataException {
|
||||
|
@ -6,7 +6,9 @@ import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@ -111,13 +113,22 @@ public class BlockChain {
|
||||
BigDecimal qoraHoldersShare;
|
||||
|
||||
/**
|
||||
* Number of generated blocks required to reach next level.
|
||||
* Number of generated blocks required to reach next level from previous.
|
||||
* <p>
|
||||
* Use account's current level as index.<br>
|
||||
* If account's level isn't valid as an index, then account's level is at maximum.
|
||||
*/
|
||||
List<Integer> blocksNeededByLevel;
|
||||
|
||||
/**
|
||||
* Cumulative number of generated blocks required to reach level from scratch.
|
||||
* <p>
|
||||
* Generated just after blockchain config is parsed and validated.
|
||||
* <p>
|
||||
* Should NOT be present in blockchain config file!
|
||||
*/
|
||||
List<Integer> cumulativeBlocksByLevel;
|
||||
|
||||
/** Block times by block height */
|
||||
public static class BlockTimingByHeight {
|
||||
public int height;
|
||||
@ -221,9 +232,7 @@ public class BlockChain {
|
||||
blockchain.validateConfig();
|
||||
|
||||
// Minor fix-up
|
||||
blockchain.maxBytesPerUnitFee = blockchain.maxBytesPerUnitFee.setScale(8);
|
||||
blockchain.unitFee = blockchain.unitFee.setScale(8);
|
||||
blockchain.minFeePerByte = blockchain.unitFee.divide(blockchain.maxBytesPerUnitFee, MathContext.DECIMAL32);
|
||||
blockchain.fixUp();
|
||||
|
||||
// Successfully read config now in effect
|
||||
instance = blockchain;
|
||||
@ -291,6 +300,10 @@ public class BlockChain {
|
||||
return this.blocksNeededByLevel;
|
||||
}
|
||||
|
||||
public List<Integer> getCumulativeBlocksByLevel() {
|
||||
return this.cumulativeBlocksByLevel;
|
||||
}
|
||||
|
||||
public BigDecimal getQoraHoldersShare() {
|
||||
return this.qoraHoldersShare;
|
||||
}
|
||||
@ -402,6 +415,30 @@ public class BlockChain {
|
||||
Settings.throwValidationError(String.format("Missing feature trigger \"%s\" in blockchain config", featureTrigger.name()));
|
||||
}
|
||||
|
||||
/** Minor normalization, cached value generation, etc. */
|
||||
private void fixUp() {
|
||||
this.maxBytesPerUnitFee = this.maxBytesPerUnitFee.setScale(8);
|
||||
this.unitFee = this.unitFee.setScale(8);
|
||||
this.minFeePerByte = this.unitFee.divide(this.maxBytesPerUnitFee, MathContext.DECIMAL32);
|
||||
|
||||
// Pre-calculate cumulative blocks required for each level
|
||||
int cumulativeBlocks = 0;
|
||||
this.cumulativeBlocksByLevel = new ArrayList<>(this.blocksNeededByLevel.size() + 1);
|
||||
for (int level = 0; level <= this.blocksNeededByLevel.size(); ++level) {
|
||||
this.cumulativeBlocksByLevel.add(cumulativeBlocks);
|
||||
|
||||
if (level < this.blocksNeededByLevel.size())
|
||||
cumulativeBlocks += this.blocksNeededByLevel.get(level);
|
||||
}
|
||||
|
||||
// Convert collections to unmodifiable form
|
||||
this.rewardsByHeight = Collections.unmodifiableList(this.rewardsByHeight);
|
||||
this.sharesByLevel = Collections.unmodifiableList(this.sharesByLevel);
|
||||
this.blocksNeededByLevel = Collections.unmodifiableList(this.blocksNeededByLevel);
|
||||
this.cumulativeBlocksByLevel = Collections.unmodifiableList(this.cumulativeBlocksByLevel);
|
||||
this.blockTimingsByHeight = Collections.unmodifiableList(this.blockTimingsByHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some sort start-up/initialization/checking method.
|
||||
*
|
||||
@ -412,7 +449,6 @@ public class BlockChain {
|
||||
if (!isGenesisBlockValid())
|
||||
rebuildBlockchain();
|
||||
|
||||
// TODO: walk through blocks
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
Block parentBlock = GenesisBlock.getInstance(repository);
|
||||
BlockData parentBlockData = parentBlock.getBlockData();
|
||||
|
Loading…
x
Reference in New Issue
Block a user