mirror of
https://github.com/Qortal/qortal.git
synced 2025-03-13 19:12:33 +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 {
|
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
|
// We need to do this for both forgers and recipients
|
||||||
this.increaseAccountLevels(expandedAccounts, cumulativeBlocksByLevel,
|
this.increaseAccountLevels(expandedAccount -> expandedAccount.isForgerFounder, expandedAccount -> expandedAccount.forgerAccountData);
|
||||||
expandedAccount -> expandedAccount.isForgerFounder,
|
this.increaseAccountLevels(expandedAccount -> expandedAccount.isRecipientFounder, expandedAccount -> expandedAccount.recipientAccountData);
|
||||||
expandedAccount -> expandedAccount.forgerAccountData);
|
|
||||||
|
|
||||||
this.increaseAccountLevels(expandedAccounts, cumulativeBlocksByLevel,
|
|
||||||
expandedAccount -> expandedAccount.isRecipientFounder,
|
|
||||||
expandedAccount -> expandedAccount.recipientAccountData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void increaseAccountLevels(List<ExpandedAccount> expandedAccounts, int[] cumulativeBlocksByLevel,
|
private void increaseAccountLevels(Predicate<ExpandedAccount> isFounder, Function<ExpandedAccount, AccountData> getAccountData) throws DataException {
|
||||||
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;
|
final boolean isProcessingRecipients = getAccountData.apply(expandedAccounts.get(0)) == expandedAccounts.get(0).recipientAccountData;
|
||||||
|
|
||||||
// Increase blocks generated count for all accounts
|
// Increase blocks generated count for all accounts
|
||||||
@ -1244,21 +1226,21 @@ public class Block {
|
|||||||
|
|
||||||
accountData.setBlocksGenerated(accountData.getBlocksGenerated() + 1);
|
accountData.setBlocksGenerated(accountData.getBlocksGenerated() + 1);
|
||||||
repository.getAccountRepository().setBlocksGenerated(accountData);
|
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
|
// 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());
|
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) {
|
for (int c = 0; c < candidateAccounts.size(); ++c) {
|
||||||
ExpandedAccount expandedAccount = candidateAccounts.get(c);
|
ExpandedAccount expandedAccount = candidateAccounts.get(c);
|
||||||
final AccountData accountData = getAccountData.apply(expandedAccount);
|
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)
|
for (int newLevel = maximumLevel; newLevel > 0; --newLevel)
|
||||||
if (effectiveBlocksGenerated >= cumulativeBlocksByLevel[newLevel]) {
|
if (effectiveBlocksGenerated >= cumulativeBlocksByLevel.get(newLevel)) {
|
||||||
if (newLevel > accountData.getLevel()) {
|
if (newLevel > accountData.getLevel()) {
|
||||||
// Account has increased in level!
|
// Account has increased in level!
|
||||||
accountData.setLevel(newLevel);
|
accountData.setLevel(newLevel);
|
||||||
@ -1530,7 +1512,53 @@ public class Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void decreaseAccountLevels() throws DataException {
|
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 {
|
protected void distributeByAccountLevel(BigDecimal totalAmount) throws DataException {
|
||||||
|
@ -6,7 +6,9 @@ import java.io.InputStream;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
@ -111,13 +113,22 @@ public class BlockChain {
|
|||||||
BigDecimal qoraHoldersShare;
|
BigDecimal qoraHoldersShare;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of generated blocks required to reach next level.
|
* Number of generated blocks required to reach next level from previous.
|
||||||
* <p>
|
* <p>
|
||||||
* Use account's current level as index.<br>
|
* 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.
|
* If account's level isn't valid as an index, then account's level is at maximum.
|
||||||
*/
|
*/
|
||||||
List<Integer> blocksNeededByLevel;
|
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 */
|
/** Block times by block height */
|
||||||
public static class BlockTimingByHeight {
|
public static class BlockTimingByHeight {
|
||||||
public int height;
|
public int height;
|
||||||
@ -221,9 +232,7 @@ public class BlockChain {
|
|||||||
blockchain.validateConfig();
|
blockchain.validateConfig();
|
||||||
|
|
||||||
// Minor fix-up
|
// Minor fix-up
|
||||||
blockchain.maxBytesPerUnitFee = blockchain.maxBytesPerUnitFee.setScale(8);
|
blockchain.fixUp();
|
||||||
blockchain.unitFee = blockchain.unitFee.setScale(8);
|
|
||||||
blockchain.minFeePerByte = blockchain.unitFee.divide(blockchain.maxBytesPerUnitFee, MathContext.DECIMAL32);
|
|
||||||
|
|
||||||
// Successfully read config now in effect
|
// Successfully read config now in effect
|
||||||
instance = blockchain;
|
instance = blockchain;
|
||||||
@ -291,6 +300,10 @@ public class BlockChain {
|
|||||||
return this.blocksNeededByLevel;
|
return this.blocksNeededByLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Integer> getCumulativeBlocksByLevel() {
|
||||||
|
return this.cumulativeBlocksByLevel;
|
||||||
|
}
|
||||||
|
|
||||||
public BigDecimal getQoraHoldersShare() {
|
public BigDecimal getQoraHoldersShare() {
|
||||||
return this.qoraHoldersShare;
|
return this.qoraHoldersShare;
|
||||||
}
|
}
|
||||||
@ -402,6 +415,30 @@ public class BlockChain {
|
|||||||
Settings.throwValidationError(String.format("Missing feature trigger \"%s\" in blockchain config", featureTrigger.name()));
|
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.
|
* Some sort start-up/initialization/checking method.
|
||||||
*
|
*
|
||||||
@ -412,7 +449,6 @@ public class BlockChain {
|
|||||||
if (!isGenesisBlockValid())
|
if (!isGenesisBlockValid())
|
||||||
rebuildBlockchain();
|
rebuildBlockchain();
|
||||||
|
|
||||||
// TODO: walk through blocks
|
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
Block parentBlock = GenesisBlock.getInstance(repository);
|
Block parentBlock = GenesisBlock.getInstance(repository);
|
||||||
BlockData parentBlockData = parentBlock.getBlockData();
|
BlockData parentBlockData = parentBlock.getBlockData();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user