mirror of
https://github.com/Qortal/qortal.git
synced 2025-02-11 17:55:50 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
2e3f97b51f
6
pom.xml
6
pom.xml
@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.qortal</groupId>
|
||||
<artifactId>qortal</artifactId>
|
||||
<version>4.6.3</version>
|
||||
<version>4.6.5</version>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@ -16,7 +16,7 @@
|
||||
<ciyam-at.version>1.4.2</ciyam-at.version>
|
||||
<commons-net.version>3.8.0</commons-net.version>
|
||||
<commons-text.version>1.12.0</commons-text.version>
|
||||
<commons-io.version>2.17.0</commons-io.version>
|
||||
<commons-io.version>2.18.0</commons-io.version>
|
||||
<commons-compress.version>1.27.1</commons-compress.version>
|
||||
<commons-lang3.version>3.17.0</commons-lang3.version>
|
||||
<dagger.version>1.2.2</dagger.version>
|
||||
@ -28,7 +28,7 @@
|
||||
<homoglyph.version>1.2.1</homoglyph.version>
|
||||
<hsqldb.version>2.7.4</hsqldb.version>
|
||||
<icu4j.version>76.1</icu4j.version>
|
||||
<java-diff-utils.version>4.12</java-diff-utils.version>
|
||||
<java-diff-utils.version>4.15</java-diff-utils.version>
|
||||
<javax.servlet-api.version>4.0.1</javax.servlet-api.version>
|
||||
<jaxb-runtime.version>2.3.9</jaxb-runtime.version>
|
||||
<jersey.version>2.42</jersey.version>
|
||||
|
@ -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 {
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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 {
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* <b>Note:</b> 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 {
|
||||
* <p>
|
||||
* Typically called as part of Block.process() or Block.orphan()
|
||||
* so ideally after any calls to Block.isValid().
|
||||
*
|
||||
*
|
||||
* @throws DataException
|
||||
*/
|
||||
public List<ExpandedAccount> getExpandedAccounts() throws DataException {
|
||||
@ -715,8 +720,18 @@ public class Block {
|
||||
|
||||
List<ExpandedAccount> 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* (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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Note: Block instance must have been constructed with a <tt>PrivateKeyAccount</tt> minter or this call will throw an <tt>IllegalStateException</tt>.
|
||||
*
|
||||
*
|
||||
* @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 {
|
||||
* <p>
|
||||
* 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 {
|
||||
* <p>
|
||||
* Checks block's transactions by testing their validity then processing them.<br>
|
||||
* 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 {
|
||||
* <p>
|
||||
* NOTE: will execute ATs locally if not already done.<br>
|
||||
* 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 <tt>process()</tt>.
|
||||
* <p>
|
||||
* 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.
|
||||
@ -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<AccountBalanceData> 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%
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,8 @@
|
||||
"enableRewardshareHeight": 1905100,
|
||||
"onlyMintWithNameHeight": 1900300,
|
||||
"removeOnlyMintWithNameHeight": 1935500,
|
||||
"groupMemberCheckHeight": 1902700
|
||||
"groupMemberCheckHeight": 1902700,
|
||||
"fixBatchRewardHeight": 1945900
|
||||
},
|
||||
"checkpoints": [
|
||||
{ "height": 1136300, "signature": "3BbwawEF2uN8Ni5ofpJXkukoU8ctAPxYoFB7whq9pKfBnjfZcpfEJT4R95NvBDoTP8WDyWvsUvbfHbcr9qSZuYpSKZjUQTvdFf6eqznHGEwhZApWfvXu6zjGCxYCp65F4jsVYYJjkzbjmkCg5WAwN5voudngA23kMK6PpTNygapCzXt" }
|
||||
|
Loading…
x
Reference in New Issue
Block a user