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

Merge pull request #238 from AlphaX-Qortal/master

Added real address to API results - Currently the address shown in the API results when querying blocks, shows an address formed by the 'reward share public key', this address is not useful for viewing, as it is not the address utilized for QORT. This change makes it so the 'real' Qortal address is displayed instead of this useless address. Thanks @AlphaX-Qortal

Added group member check to validations - validation fixes.

Network changes - Moved unnecessary 'we already have connection' messages from info logging to debug. Updated minPeerVersion default to current release version. (4.6.5). Updated default peer list. Updated syntax. Updated formatting.

Updated dependencies

Thanks @AlphaX-Qortal
This commit is contained in:
crowetic 2024-12-02 14:42:34 -08:00 committed by GitHub
commit a8d73926b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 182 additions and 84 deletions

View File

@ -22,7 +22,7 @@
<dagger.version>1.2.2</dagger.version> <dagger.version>1.2.2</dagger.version>
<extendedset.version>0.12.3</extendedset.version> <extendedset.version>0.12.3</extendedset.version>
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version> <git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
<grpc.version>1.68.1</grpc.version> <grpc.version>1.68.2</grpc.version>
<guava.version>33.3.1-jre</guava.version> <guava.version>33.3.1-jre</guava.version>
<hamcrest-library.version>2.2</hamcrest-library.version> <hamcrest-library.version>2.2</hamcrest-library.version>
<homoglyph.version>1.2.1</homoglyph.version> <homoglyph.version>1.2.1</homoglyph.version>
@ -35,7 +35,7 @@
<jetty.version>9.4.56.v20240826</jetty.version> <jetty.version>9.4.56.v20240826</jetty.version>
<json-simple.version>1.1.1</json-simple.version> <json-simple.version>1.1.1</json-simple.version>
<json.version>20240303</json.version> <json.version>20240303</json.version>
<jsoup.version>1.18.1</jsoup.version> <jsoup.version>1.18.3</jsoup.version>
<junit-jupiter-engine.version>5.11.0-M2</junit-jupiter-engine.version> <junit-jupiter-engine.version>5.11.0-M2</junit-jupiter-engine.version>
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version> <lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
<log4j.version>2.23.1</log4j.version> <log4j.version>2.23.1</log4j.version>

View File

@ -349,10 +349,28 @@ public class Account {
} }
/** /**
* Returns 'effective' minting level, or zero if reward-share does not exist. * Returns reward-share minting address, or unknown if reward-share does not exist.
* *
* @param repository * @param repository
* @param rewardSharePublicKey * @param rewardSharePublicKey
* @return address or unknown
* @throws DataException
*/
public static String getRewardShareMintingAddress(Repository repository, byte[] rewardSharePublicKey) throws DataException {
// Find actual minter address
RewardShareData rewardShareData = repository.getAccountRepository().getRewardShare(rewardSharePublicKey);
if (rewardShareData == null)
return "Unknown";
return rewardShareData.getMinter();
}
/**
* Returns 'effective' minting level, or zero if reward-share does not exist.
*
* @param repository
* @param rewardSharePublicKey
* @return 0+ * @return 0+
* @throws DataException * @throws DataException
*/ */

View File

@ -1,7 +1,13 @@
package org.qortal.api.model; package org.qortal.api.model;
import org.qortal.account.Account;
import org.qortal.repository.DataException;
import org.qortal.repository.RepositoryManager;
import org.qortal.repository.Repository;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
// All properties to be converted to JSON via JAXB // All properties to be converted to JSON via JAXB
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
@ -47,4 +53,31 @@ public class ApiOnlineAccount {
return this.recipientAddress; return this.recipientAddress;
} }
public int getMinterLevelFromPublicKey() {
try (final Repository repository = RepositoryManager.getRepository()) {
return Account.getRewardShareEffectiveMintingLevel(repository, this.rewardSharePublicKey);
} catch (DataException e) {
return 0;
}
}
public boolean getIsMember() {
try (final Repository repository = RepositoryManager.getRepository()) {
return repository.getGroupRepository().memberExists(694, getMinterAddress());
} catch (DataException e) {
return false;
}
}
// JAXB special
@XmlElement(name = "minterLevel")
protected int getMinterLevel() {
return getMinterLevelFromPublicKey();
}
@XmlElement(name = "isMinterMember")
protected boolean getMinterMember() {
return getIsMember();
}
} }

View File

@ -9,6 +9,7 @@ import java.math.BigInteger;
public class BlockMintingInfo { public class BlockMintingInfo {
public byte[] minterPublicKey; public byte[] minterPublicKey;
public String minterAddress;
public int minterLevel; public int minterLevel;
public int onlineAccountsCount; public int onlineAccountsCount;
public BigDecimal maxDistance; public BigDecimal maxDistance;
@ -19,5 +20,4 @@ public class BlockMintingInfo {
public BlockMintingInfo() { public BlockMintingInfo() {
} }
} }

View File

@ -542,6 +542,7 @@ public class BlocksResource {
} }
} }
String minterAddress = Account.getRewardShareMintingAddress(repository, blockData.getMinterPublicKey());
int minterLevel = Account.getRewardShareEffectiveMintingLevel(repository, blockData.getMinterPublicKey()); int minterLevel = Account.getRewardShareEffectiveMintingLevel(repository, blockData.getMinterPublicKey());
if (minterLevel == 0) if (minterLevel == 0)
// This may be unavailable when requesting a trimmed block // This may be unavailable when requesting a trimmed block
@ -554,6 +555,7 @@ public class BlocksResource {
BlockMintingInfo blockMintingInfo = new BlockMintingInfo(); BlockMintingInfo blockMintingInfo = new BlockMintingInfo();
blockMintingInfo.minterPublicKey = blockData.getMinterPublicKey(); blockMintingInfo.minterPublicKey = blockData.getMinterPublicKey();
blockMintingInfo.minterAddress = minterAddress;
blockMintingInfo.minterLevel = minterLevel; blockMintingInfo.minterLevel = minterLevel;
blockMintingInfo.onlineAccountsCount = blockData.getOnlineAccountsCount(); blockMintingInfo.onlineAccountsCount = blockData.getOnlineAccountsCount();
blockMintingInfo.maxDistance = new BigDecimal(block.MAX_DISTANCE); blockMintingInfo.maxDistance = new BigDecimal(block.MAX_DISTANCE);
@ -887,5 +889,4 @@ public class BlocksResource {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
} }
} }
} }

View File

@ -145,7 +145,7 @@ public class Block {
private final Account recipientAccount; private final Account recipientAccount;
private final AccountData recipientAccountData; private final AccountData recipientAccountData;
final BlockChain blockChain = BlockChain.getInstance(); final BlockChain blockChain = BlockChain.getInstance();
ExpandedAccount(Repository repository, RewardShareData rewardShareData) throws DataException { ExpandedAccount(Repository repository, RewardShareData rewardShareData) throws DataException {
@ -414,6 +414,21 @@ public class Block {
}); });
} }
// After feature trigger, remove any online accounts that are not minter group member
if (height >= BlockChain.getInstance().getGroupMemberCheckHeight()) {
onlineAccounts.removeIf(a -> {
try {
int groupId = BlockChain.getInstance().getMintingGroupId();
String address = Account.getRewardShareMintingAddress(repository, a.getPublicKey());
boolean isMinterGroupMember = repository.getGroupRepository().memberExists(groupId, address);
return !isMinterGroupMember;
} catch (DataException e) {
// Something went wrong, so remove the account
return true;
}
});
}
if (onlineAccounts.isEmpty()) { if (onlineAccounts.isEmpty()) {
LOGGER.debug("No online accounts - not even our own?"); LOGGER.debug("No online accounts - not even our own?");
return null; return null;
@ -721,19 +736,19 @@ public class Block {
List<ExpandedAccount> expandedAccounts = new ArrayList<>(); List<ExpandedAccount> expandedAccounts = new ArrayList<>();
for (RewardShareData rewardShare : this.cachedOnlineRewardShares) { for (RewardShareData rewardShare : this.cachedOnlineRewardShares) {
if (this.getBlockData().getHeight() < BlockChain.getInstance().getFixBatchRewardHeight()) { 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));
}
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; this.cachedExpandedAccounts = expandedAccounts;
LOGGER.trace(() -> String.format("Online reward-shares after expanded accounts %s", this.cachedOnlineRewardShares));
return this.cachedExpandedAccounts; return this.cachedExpandedAccounts;
} }
@ -1143,8 +1158,17 @@ public class Block {
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getOnlineAccountMinterLevelValidationHeight()) { if (this.getBlockData().getHeight() >= BlockChain.getInstance().getOnlineAccountMinterLevelValidationHeight()) {
List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts(); List<ExpandedAccount> expandedAccounts = this.getExpandedAccounts();
for (ExpandedAccount account : expandedAccounts) { for (ExpandedAccount account : expandedAccounts) {
int groupId = BlockChain.getInstance().getMintingGroupId();
String address = account.getMintingAccount().getAddress();
boolean isMinterGroupMember = repository.getGroupRepository().memberExists(groupId, address);
if (account.getMintingAccount().getEffectiveMintingLevel() == 0) if (account.getMintingAccount().getEffectiveMintingLevel() == 0)
return ValidationResult.ONLINE_ACCOUNTS_INVALID; return ValidationResult.ONLINE_ACCOUNTS_INVALID;
if (this.getBlockData().getHeight() >= BlockChain.getInstance().getFixBatchRewardHeight()) {
if (!isMinterGroupMember)
return ValidationResult.ONLINE_ACCOUNTS_INVALID;
}
} }
} }
@ -1273,6 +1297,7 @@ public class Block {
// Online Accounts // Online Accounts
ValidationResult onlineAccountsResult = this.areOnlineAccountsValid(); ValidationResult onlineAccountsResult = this.areOnlineAccountsValid();
LOGGER.trace("Accounts valid = {}", onlineAccountsResult);
if (onlineAccountsResult != ValidationResult.OK) if (onlineAccountsResult != ValidationResult.OK)
return onlineAccountsResult; return onlineAccountsResult;
@ -1361,7 +1386,7 @@ public class Block {
// Check transaction can even be processed // Check transaction can even be processed
validationResult = transaction.isProcessable(); validationResult = transaction.isProcessable();
if (validationResult != Transaction.ValidationResult.OK) { if (validationResult != Transaction.ValidationResult.OK) {
LOGGER.info(String.format("Error during transaction validation, tx %s: %s", Base58.encode(transactionData.getSignature()), validationResult.name())); LOGGER.debug(String.format("Error during transaction validation, tx %s: %s", Base58.encode(transactionData.getSignature()), validationResult.name()));
return ValidationResult.TRANSACTION_INVALID; return ValidationResult.TRANSACTION_INVALID;
} }
@ -1562,6 +1587,7 @@ public class Block {
this.blockData.setHeight(blockchainHeight + 1); this.blockData.setHeight(blockchainHeight + 1);
LOGGER.trace(() -> String.format("Processing block %d", this.blockData.getHeight())); LOGGER.trace(() -> String.format("Processing block %d", this.blockData.getHeight()));
LOGGER.trace(() -> String.format("Online Reward Shares in process %s", this.cachedOnlineRewardShares));
if (this.blockData.getHeight() > 1) { if (this.blockData.getHeight() > 1) {
@ -2280,7 +2306,6 @@ public class Block {
// Select the correct set of share bins based on block height // Select the correct set of share bins based on block height
List<AccountLevelShareBin> accountLevelShareBinsForBlock = (this.blockData.getHeight() >= BlockChain.getInstance().getSharesByLevelV2Height()) ? List<AccountLevelShareBin> accountLevelShareBinsForBlock = (this.blockData.getHeight() >= BlockChain.getInstance().getSharesByLevelV2Height()) ?
BlockChain.getInstance().getAccountLevelShareBinsV2() : BlockChain.getInstance().getAccountLevelShareBinsV1(); BlockChain.getInstance().getAccountLevelShareBinsV2() : BlockChain.getInstance().getAccountLevelShareBinsV1();
// Determine reward candidates based on account level // Determine reward candidates based on account level
// This needs a deep copy, so the shares can be modified when tiers aren't activated yet // This needs a deep copy, so the shares can be modified when tiers aren't activated yet
List<AccountLevelShareBin> accountLevelShareBins = new ArrayList<>(); List<AccountLevelShareBin> accountLevelShareBins = new ArrayList<>();
@ -2570,9 +2595,11 @@ public class Block {
return; return;
int minterLevel = Account.getRewardShareEffectiveMintingLevel(this.repository, this.getMinter().getPublicKey()); int minterLevel = Account.getRewardShareEffectiveMintingLevel(this.repository, this.getMinter().getPublicKey());
String minterAddress = Account.getRewardShareMintingAddress(this.repository, this.getMinter().getPublicKey());
LOGGER.debug(String.format("======= BLOCK %d (%.8s) =======", this.getBlockData().getHeight(), Base58.encode(this.getSignature()))); LOGGER.debug(String.format("======= BLOCK %d (%.8s) =======", this.getBlockData().getHeight(), Base58.encode(this.getSignature())));
LOGGER.debug(String.format("Timestamp: %d", this.getBlockData().getTimestamp())); LOGGER.debug(String.format("Timestamp: %d", this.getBlockData().getTimestamp()));
LOGGER.debug(String.format("Minter address: %s", minterAddress));
LOGGER.debug(String.format("Minter level: %d", minterLevel)); LOGGER.debug(String.format("Minter level: %d", minterLevel));
LOGGER.debug(String.format("Online accounts: %d", this.getBlockData().getOnlineAccountsCount())); LOGGER.debug(String.format("Online accounts: %d", this.getBlockData().getOnlineAccountsCount()));
LOGGER.debug(String.format("AT count: %d", this.getBlockData().getATCount())); LOGGER.debug(String.format("AT count: %d", this.getBlockData().getATCount()));

View File

@ -1,8 +1,11 @@
package org.qortal.data.block; package org.qortal.data.block;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import org.qortal.account.Account;
import org.qortal.block.BlockChain; import org.qortal.block.BlockChain;
import org.qortal.crypto.Crypto; import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager;
import org.qortal.settings.Settings; import org.qortal.settings.Settings;
import org.qortal.utils.NTP; import org.qortal.utils.NTP;
@ -224,7 +227,7 @@ public class BlockData implements Serializable {
} }
return 0; return 0;
} }
public boolean isTrimmed() { public boolean isTrimmed() {
long onlineAccountSignaturesTrimmedTimestamp = NTP.getTime() - BlockChain.getInstance().getOnlineAccountSignaturesMaxLifetime(); long onlineAccountSignaturesTrimmedTimestamp = NTP.getTime() - BlockChain.getInstance().getOnlineAccountSignaturesMaxLifetime();
long currentTrimmableTimestamp = NTP.getTime() - Settings.getInstance().getAtStatesMaxLifetime(); long currentTrimmableTimestamp = NTP.getTime() - Settings.getInstance().getAtStatesMaxLifetime();
@ -232,11 +235,31 @@ public class BlockData implements Serializable {
return blockTimestamp < onlineAccountSignaturesTrimmedTimestamp && blockTimestamp < currentTrimmableTimestamp; return blockTimestamp < onlineAccountSignaturesTrimmedTimestamp && blockTimestamp < currentTrimmableTimestamp;
} }
public String getMinterAddressFromPublicKey() {
try (final Repository repository = RepositoryManager.getRepository()) {
return Account.getRewardShareMintingAddress(repository, this.minterPublicKey);
} catch (DataException e) {
return "Unknown";
}
}
public int getMinterLevelFromPublicKey() {
try (final Repository repository = RepositoryManager.getRepository()) {
return Account.getRewardShareEffectiveMintingLevel(repository, this.minterPublicKey);
} catch (DataException e) {
return 0;
}
}
// JAXB special // JAXB special
@XmlElement(name = "minterAddress") @XmlElement(name = "minterAddress")
protected String getMinterAddress() { protected String getMinterAddress() {
return Crypto.toAddress(this.minterPublicKey); return getMinterAddressFromPublicKey();
} }
@XmlElement(name = "minterLevel")
protected int getMinterLevel() {
return getMinterLevelFromPublicKey();
}
} }

View File

@ -48,7 +48,7 @@ public enum Handshake {
String versionString = helloMessage.getVersionString(); String versionString = helloMessage.getVersionString();
Matcher matcher = peer.VERSION_PATTERN.matcher(versionString); Matcher matcher = Peer.VERSION_PATTERN.matcher(versionString);
if (!matcher.lookingAt()) { if (!matcher.lookingAt()) {
LOGGER.debug(() -> String.format("Peer %s sent invalid HELLO version string '%s'", peer, versionString)); LOGGER.debug(() -> String.format("Peer %s sent invalid HELLO version string '%s'", peer, versionString));
return null; return null;
@ -71,7 +71,7 @@ public enum Handshake {
// Ensure the peer is running at least the version specified in MIN_PEER_VERSION // Ensure the peer is running at least the version specified in MIN_PEER_VERSION
if (!peer.isAtLeastVersion(MIN_PEER_VERSION)) { if (!peer.isAtLeastVersion(MIN_PEER_VERSION)) {
LOGGER.debug(String.format("Ignoring peer %s because it is on an old version (%s)", peer, versionString)); LOGGER.debug("Ignoring peer {} because it is on an old version ({})", peer, versionString);
return null; return null;
} }
@ -79,7 +79,7 @@ public enum Handshake {
// Ensure the peer is running at least the minimum version allowed for connections // Ensure the peer is running at least the minimum version allowed for connections
final String minPeerVersion = Settings.getInstance().getMinPeerVersion(); final String minPeerVersion = Settings.getInstance().getMinPeerVersion();
if (!peer.isAtLeastVersion(minPeerVersion)) { if (!peer.isAtLeastVersion(minPeerVersion)) {
LOGGER.debug(String.format("Ignoring peer %s because it is on an old version (%s)", peer, versionString)); LOGGER.debug("Ignoring peer {} because it is on an old version ({})", peer, versionString);
return null; return null;
} }
} }
@ -106,7 +106,7 @@ public enum Handshake {
byte[] peersPublicKey = challengeMessage.getPublicKey(); byte[] peersPublicKey = challengeMessage.getPublicKey();
byte[] peersChallenge = challengeMessage.getChallenge(); byte[] peersChallenge = challengeMessage.getChallenge();
// If public key matches our public key then we've connected to self // If public key matches our public key, then we've connected to self
byte[] ourPublicKey = Network.getInstance().getOurPublicKey(); byte[] ourPublicKey = Network.getInstance().getOurPublicKey();
if (Arrays.equals(ourPublicKey, peersPublicKey)) { if (Arrays.equals(ourPublicKey, peersPublicKey)) {
// If outgoing connection then record destination as self so we don't try again // If outgoing connection then record destination as self so we don't try again
@ -121,11 +121,11 @@ public enum Handshake {
peer.disconnect("failed to send CHALLENGE to self"); peer.disconnect("failed to send CHALLENGE to self");
/* /*
* We return CHALLENGE here to prevent us from closing connection. Closing * We return the CHALLENGE here to prevent us from closing the connection.
* connection currently preempts remote end from reading any pending messages, * Closing the connection currently preempts the remote end from reading any pending messages,
* specifically the CHALLENGE message we just sent above. When our 'remote' * specifically the CHALLENGE message we just sent above. When our 'remote'
* outbound counterpart reads our message, they will close both connections. * outbound counterpart reads our message, they will close both connections.
* Failing that, our connection will timeout or a future handshake error will * Failing that, our connection will time out or a future handshake error will
* occur. * occur.
*/ */
return CHALLENGE; return CHALLENGE;
@ -135,7 +135,7 @@ public enum Handshake {
// Are we already connected to this peer? // Are we already connected to this peer?
Peer existingPeer = Network.getInstance().getHandshakedPeerWithPublicKey(peersPublicKey); Peer existingPeer = Network.getInstance().getHandshakedPeerWithPublicKey(peersPublicKey);
if (existingPeer != null) { if (existingPeer != null) {
LOGGER.info(() -> String.format("We already have a connection with peer %s - discarding", peer)); LOGGER.debug(() -> String.format("We already have a connection with peer %s - discarding", peer));
// Handshake failure - caller will deal with disconnect // Handshake failure - caller will deal with disconnect
return null; return null;
} }
@ -148,7 +148,7 @@ public enum Handshake {
@Override @Override
public void action(Peer peer) { public void action(Peer peer) {
// Send challenge // Send a challenge
byte[] publicKey = Network.getInstance().getOurPublicKey(); byte[] publicKey = Network.getInstance().getOurPublicKey();
byte[] challenge = peer.getOurChallenge(); byte[] challenge = peer.getOurChallenge();
@ -254,16 +254,17 @@ public enum Handshake {
private static final Logger LOGGER = LogManager.getLogger(Handshake.class); private static final Logger LOGGER = LogManager.getLogger(Handshake.class);
/** Maximum allowed difference between peer's reported timestamp and when they connected, in milliseconds. */ /** The Maximum allowed difference between peer's reported timestamp and when they connected, in milliseconds. */
private static final long MAX_TIMESTAMP_DELTA = 30 * 1000L; // ms private static final long MAX_TIMESTAMP_DELTA = 30 * 1000L; // ms
private static final long PEER_VERSION_131 = 0x0100030001L; private static final long PEER_VERSION_131 = 0x0100030001L;
/** Minimum peer version that we are allowed to communicate with */ /** Minimum peer version that we are allowed to communicate with */
private static final String MIN_PEER_VERSION = "4.1.1"; private static final String MIN_PEER_VERSION = "4.6.5";
private static final int POW_BUFFER_SIZE_PRE_131 = 8 * 1024 * 1024; // bytes private static final int POW_BUFFER_SIZE_PRE_131 = 8 * 1024 * 1024; // bytes
private static final int POW_DIFFICULTY_PRE_131 = 8; // leading zero bits private static final int POW_DIFFICULTY_PRE_131 = 8; // leading zero bits
// Can always be made harder in the future... // Can always be made harder in the future...
private static final int POW_BUFFER_SIZE_POST_131 = 2 * 1024 * 1024; // bytes private static final int POW_BUFFER_SIZE_POST_131 = 2 * 1024 * 1024; // bytes
private static final int POW_DIFFICULTY_POST_131 = 2; // leading zero bits private static final int POW_DIFFICULTY_POST_131 = 2; // leading zero bits
@ -275,12 +276,11 @@ public enum Handshake {
public final MessageType expectedMessageType; public final MessageType expectedMessageType;
private Handshake(MessageType expectedMessageType) { Handshake(MessageType expectedMessageType) {
this.expectedMessageType = expectedMessageType; this.expectedMessageType = expectedMessageType;
} }
public abstract Handshake onMessage(Peer peer, Message message); public abstract Handshake onMessage(Peer peer, Message message);
public abstract void action(Peer peer); public abstract void action(Peer peer);
} }

View File

@ -80,7 +80,7 @@ public class Network {
"node.qortal.ru", "node2.qortal.ru", "node3.qortal.ru", "node.qortal.uk", "node22.qortal.org", "node.qortal.ru", "node2.qortal.ru", "node3.qortal.ru", "node.qortal.uk", "node22.qortal.org",
"cinfu1.crowetic.com", "node.cwd.systems", "bootstrap.cwd.systems", "node1.qortalnodes.live", "cinfu1.crowetic.com", "node.cwd.systems", "bootstrap.cwd.systems", "node1.qortalnodes.live",
"node2.qortalnodes.live", "node3.qortalnodes.live", "node4.qortalnodes.live", "node5.qortalnodes.live", "node2.qortalnodes.live", "node3.qortalnodes.live", "node4.qortalnodes.live", "node5.qortalnodes.live",
"node6.qortalnodes.live", "node7.qortalnodes.live", "node8.qortalnodes.live" "node.qortalnodes.live", "qortex.live",
}; };
private static final long NETWORK_EPC_KEEPALIVE = 5L; // seconds private static final long NETWORK_EPC_KEEPALIVE = 5L; // seconds
@ -149,7 +149,7 @@ public class Network {
private final Lock mergePeersLock = new ReentrantLock(); private final Lock mergePeersLock = new ReentrantLock();
private List<String> ourExternalIpAddressHistory = new ArrayList<>(); private final List<String> ourExternalIpAddressHistory = new ArrayList<>();
private String ourExternalIpAddress = null; private String ourExternalIpAddress = null;
private int ourExternalPort = Settings.getInstance().getListenPort(); private int ourExternalPort = Settings.getInstance().getListenPort();
@ -167,7 +167,7 @@ public class Network {
ExecutorService networkExecutor = new ThreadPoolExecutor(2, ExecutorService networkExecutor = new ThreadPoolExecutor(2,
Settings.getInstance().getMaxNetworkThreadPoolSize(), Settings.getInstance().getMaxNetworkThreadPoolSize(),
NETWORK_EPC_KEEPALIVE, TimeUnit.SECONDS, NETWORK_EPC_KEEPALIVE, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), new SynchronousQueue<>(),
new NamedThreadFactory("Network-EPC", Settings.getInstance().getNetworkThreadPriority())); new NamedThreadFactory("Network-EPC", Settings.getInstance().getNetworkThreadPriority()));
networkEPC = new NetworkProcessor(networkExecutor); networkEPC = new NetworkProcessor(networkExecutor);
} }
@ -314,7 +314,7 @@ public class Network {
public List<Peer> getImmutableConnectedDataPeers() { public List<Peer> getImmutableConnectedDataPeers() {
return this.getImmutableConnectedPeers().stream() return this.getImmutableConnectedPeers().stream()
.filter(p -> p.isDataPeer()) .filter(Peer::isDataPeer)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -346,7 +346,7 @@ public class Network {
public boolean requestDataFromPeer(String peerAddressString, byte[] signature) { public boolean requestDataFromPeer(String peerAddressString, byte[] signature) {
if (peerAddressString != null) { if (peerAddressString != null) {
PeerAddress peerAddress = PeerAddress.fromString(peerAddressString); PeerAddress peerAddress = PeerAddress.fromString(peerAddressString);
PeerData peerData = null; PeerData peerData;
// Reuse an existing PeerData instance if it's already in the known peers list // Reuse an existing PeerData instance if it's already in the known peers list
synchronized (this.allKnownPeers) { synchronized (this.allKnownPeers) {
@ -370,9 +370,9 @@ public class Network {
// Check if we're already connected to and handshaked with this peer // Check if we're already connected to and handshaked with this peer
Peer connectedPeer = this.getImmutableConnectedPeers().stream() Peer connectedPeer = this.getImmutableConnectedPeers().stream()
.filter(p -> p.getPeerData().getAddress().equals(peerAddress)) .filter(p -> p.getPeerData().getAddress().equals(peerAddress))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
boolean isConnected = (connectedPeer != null); boolean isConnected = (connectedPeer != null);
@ -710,7 +710,7 @@ public class Network {
return true; return true;
} }
private Peer getConnectablePeer(final Long now) throws InterruptedException { private Peer getConnectablePeer(final Long now) {
// We can't block here so use tryRepository(). We don't NEED to connect a new peer. // We can't block here so use tryRepository(). We don't NEED to connect a new peer.
try (Repository repository = RepositoryManager.tryRepository()) { try (Repository repository = RepositoryManager.tryRepository()) {
if (repository == null) { if (repository == null) {
@ -807,7 +807,7 @@ public class Network {
// Find peers that have reached their maximum connection age, and disconnect them // Find peers that have reached their maximum connection age, and disconnect them
List<Peer> peersToDisconnect = this.getImmutableConnectedPeers().stream() List<Peer> peersToDisconnect = this.getImmutableConnectedPeers().stream()
.filter(peer -> !peer.isSyncInProgress()) .filter(peer -> !peer.isSyncInProgress())
.filter(peer -> peer.hasReachedMaxConnectionAge()) .filter(Peer::hasReachedMaxConnectionAge)
.collect(Collectors.toList()); .collect(Collectors.toList());
if (peersToDisconnect != null && !peersToDisconnect.isEmpty()) { if (peersToDisconnect != null && !peersToDisconnect.isEmpty()) {
@ -996,9 +996,9 @@ public class Network {
} }
// Add to per-message thread count (first initializing to 0 if not already present) // Add to per-message thread count (first initializing to 0 if not already present)
threadsPerMessageType.computeIfAbsent(message.getType(), key -> 0); threadsPerMessageType.putIfAbsent(message.getType(), 0);
threadsPerMessageType.computeIfPresent(message.getType(), (key, value) -> value + 1); threadsPerMessageType.computeIfPresent(message.getType(), (key, value) -> value + 1);
// Add to total thread count // Add to total thread count
synchronized (this) { synchronized (this) {
totalThreadCount++; totalThreadCount++;
@ -1037,7 +1037,7 @@ public class Network {
} }
// Remove from per-message thread count (first initializing to 0 if not already present) // Remove from per-message thread count (first initializing to 0 if not already present)
threadsPerMessageType.computeIfAbsent(message.getType(), key -> 0); threadsPerMessageType.putIfAbsent(message.getType(), 0);
threadsPerMessageType.computeIfPresent(message.getType(), (key, value) -> value - 1); threadsPerMessageType.computeIfPresent(message.getType(), (key, value) -> value - 1);
// Remove from total thread count // Remove from total thread count
@ -1135,7 +1135,7 @@ public class Network {
Peer existingPeer = getHandshakedPeerWithPublicKey(peer.getPeersPublicKey()); Peer existingPeer = getHandshakedPeerWithPublicKey(peer.getPeersPublicKey());
// NOTE: actual object reference compare, not Peer.equals() // NOTE: actual object reference compare, not Peer.equals()
if (existingPeer != peer) { if (existingPeer != peer) {
LOGGER.info("[{}] We already have a connection with peer {} - discarding", LOGGER.debug("[{}] We already have a connection with peer {} - discarding",
peer.getPeerConnectionId(), peer); peer.getPeerConnectionId(), peer);
peer.disconnect("existing connection"); peer.disconnect("existing connection");
return; return;
@ -1216,29 +1216,7 @@ public class Network {
* Returns PEERS message made from peers we've connected to recently, and this node's details * Returns PEERS message made from peers we've connected to recently, and this node's details
*/ */
public Message buildPeersMessage(Peer peer) { public Message buildPeersMessage(Peer peer) {
List<PeerData> knownPeers = this.getAllKnownPeers(); final var knownPeers = getPeerData();
// Filter out peers that we've not connected to ever or within X milliseconds
final long connectionThreshold = NTP.getTime() - RECENT_CONNECTION_THRESHOLD;
Predicate<PeerData> notRecentlyConnected = peerData -> {
final Long lastAttempted = peerData.getLastAttempted();
final Long lastConnected = peerData.getLastConnected();
if (lastAttempted == null || lastConnected == null) {
return true;
}
if (lastConnected < lastAttempted) {
return true;
}
if (lastConnected < connectionThreshold) {
return true;
}
return false;
};
knownPeers.removeIf(notRecentlyConnected);
List<PeerAddress> peerAddresses = new ArrayList<>(); List<PeerAddress> peerAddresses = new ArrayList<>();
@ -1262,6 +1240,29 @@ public class Network {
return new PeersV2Message(peerAddresses); return new PeersV2Message(peerAddresses);
} }
private List<PeerData> getPeerData() {
List<PeerData> knownPeers = this.getAllKnownPeers();
// Filter out peers that we've not connected to ever or within X milliseconds
final long connectionThreshold = NTP.getTime() - RECENT_CONNECTION_THRESHOLD;
Predicate<PeerData> notRecentlyConnected = peerData -> {
final Long lastAttempted = peerData.getLastAttempted();
final Long lastConnected = peerData.getLastConnected();
if (lastAttempted == null || lastConnected == null) {
return true;
}
if (lastConnected < lastAttempted) {
return true;
}
return lastConnected < connectionThreshold;
};
knownPeers.removeIf(notRecentlyConnected);
return knownPeers;
}
/** Builds either (legacy) HeightV2Message or (newer) BlockSummariesV2Message, depending on peer version. /** Builds either (legacy) HeightV2Message or (newer) BlockSummariesV2Message, depending on peer version.
* *
* @return Message, or null if DataException was thrown. * @return Message, or null if DataException was thrown.
@ -1328,7 +1329,7 @@ public class Network {
return; return;
} }
String host = parts[0]; String host = parts[0];
try { try {
InetAddress addr = InetAddress.getByName(host); InetAddress addr = InetAddress.getByName(host);
if (addr.isAnyLocalAddress() || addr.isSiteLocalAddress()) { if (addr.isAnyLocalAddress() || addr.isSiteLocalAddress()) {
@ -1369,12 +1370,12 @@ public class Network {
for (int i = size-1; i >= 0; i--) { for (int i = size-1; i >= 0; i--) {
String reading = ipAddressHistory.get(i); String reading = ipAddressHistory.get(i);
if (lastReading != null) { if (lastReading != null) {
if (Objects.equals(reading, lastReading)) { if (Objects.equals(reading, lastReading)) {
consecutiveReadings++; consecutiveReadings++;
} }
else { else {
consecutiveReadings = 0; consecutiveReadings = 0;
} }
} }
lastReading = reading; lastReading = reading;
} }
@ -1515,12 +1516,8 @@ public class Network {
return true; return true;
} }
if (peerData.getLastConnected() == null return peerData.getLastConnected() == null
|| peerData.getLastConnected() > now - OLD_PEER_CONNECTION_PERIOD) { || peerData.getLastConnected() > now - OLD_PEER_CONNECTION_PERIOD;
return true;
}
return false;
}; };
// Disregard peers that are NOT 'old' // Disregard peers that are NOT 'old'
@ -1655,7 +1652,7 @@ public class Network {
// Stop processing threads // Stop processing threads
try { try {
if (!this.networkEPC.shutdown(5000)) { if (!this.networkEPC.shutdown(10000)) {
LOGGER.warn("Network threads failed to terminate"); LOGGER.warn("Network threads failed to terminate");
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -1667,5 +1664,4 @@ public class Network {
peer.shutdown(); peer.shutdown();
} }
} }
} }