forked from Qortal-Forker/qortal
Compare commits
11 Commits
chain-weig
...
ignore-old
Author | SHA1 | Date | |
---|---|---|---|
|
26c1793d85 | ||
|
af9b536dd9 | ||
|
c4cbb64643 | ||
|
8260cec713 | ||
|
f4520e2752 | ||
|
475802afbc | ||
|
a170668d9d | ||
|
f8dac39076 | ||
|
fe4ae61552 | ||
|
0c3597f757 | ||
|
6109bdeafe |
File diff suppressed because it is too large
Load Diff
2
pom.xml
2
pom.xml
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.qortal</groupId>
|
||||
<artifactId>qortal</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.5.1</version>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<skipTests>true</skipTests>
|
||||
|
@@ -262,6 +262,7 @@ public class CrossChainResource {
|
||||
|
||||
// We want both a minimum of 5 trades and enough trades to span at least 4 hours
|
||||
int minimumCount = 5;
|
||||
int maximumCount = 10;
|
||||
long minimumPeriod = 4 * 60 * 60 * 1000L; // ms
|
||||
Boolean isFinished = Boolean.TRUE;
|
||||
|
||||
@@ -276,7 +277,7 @@ public class CrossChainResource {
|
||||
ACCT acct = acctInfo.getValue().get();
|
||||
|
||||
List<ATStateData> atStates = repository.getATRepository().getMatchingFinalATStatesQuorum(codeHash,
|
||||
isFinished, acct.getModeByteOffset(), (long) AcctMode.REDEEMED.value, minimumCount, minimumPeriod);
|
||||
isFinished, acct.getModeByteOffset(), (long) AcctMode.REDEEMED.value, minimumCount, maximumCount, minimumPeriod);
|
||||
|
||||
for (ATStateData atState : atStates) {
|
||||
CrossChainTradeData crossChainTradeData = acct.populateTradeData(repository, atState);
|
||||
|
@@ -1998,6 +1998,10 @@ public class Block {
|
||||
|
||||
private void logDebugInfo() {
|
||||
try {
|
||||
// Avoid calculations if possible. We have to check against INFO here, since Level.isMoreSpecificThan() confusingly uses <= rather than just <
|
||||
if (LOGGER.getLevel().isMoreSpecificThan(Level.INFO))
|
||||
return;
|
||||
|
||||
if (this.repository == null || this.getMinter() == null || this.getBlockData() == null)
|
||||
return;
|
||||
|
||||
@@ -2009,7 +2013,7 @@ public class Block {
|
||||
LOGGER.debug(String.format("Online accounts: %d", this.getBlockData().getOnlineAccountsCount()));
|
||||
|
||||
BlockSummaryData blockSummaryData = new BlockSummaryData(this.getBlockData());
|
||||
if (this.getParent() == null || this.getParent().getSignature() == null || blockSummaryData == null)
|
||||
if (this.getParent() == null || this.getParent().getSignature() == null || blockSummaryData == null || minterLevel == 0)
|
||||
return;
|
||||
|
||||
blockSummaryData.setMinterLevel(minterLevel);
|
||||
|
@@ -623,6 +623,11 @@ public class Controller extends Thread {
|
||||
return peerChainTipData == null || peerChainTipData.getLastBlockSignature() == null || inferiorChainTips.contains(new ByteArray(peerChainTipData.getLastBlockSignature()));
|
||||
};
|
||||
|
||||
public static final Predicate<Peer> hasOldVersion = peer -> {
|
||||
final String minPeerVersion = Settings.getInstance().getMinPeerVersion();
|
||||
return peer.isAtLeastVersion(minPeerVersion) == false;
|
||||
};
|
||||
|
||||
private void potentiallySynchronize() throws InterruptedException {
|
||||
// Already synchronizing via another thread?
|
||||
if (this.isSynchronizing)
|
||||
@@ -639,11 +644,15 @@ public class Controller extends Thread {
|
||||
// Disregard peers that don't have a recent block
|
||||
peers.removeIf(hasNoRecentBlock);
|
||||
|
||||
// Disregard peers that are on an old version
|
||||
peers.removeIf(hasOldVersion);
|
||||
|
||||
checkRecoveryModeForPeers(peers);
|
||||
if (recoveryMode) {
|
||||
peers = Network.getInstance().getHandshakedPeers();
|
||||
peers.removeIf(hasOnlyGenesisBlock);
|
||||
peers.removeIf(hasMisbehaved);
|
||||
peers.removeIf(hasOldVersion);
|
||||
}
|
||||
|
||||
// Check we have enough peers to potentially synchronize
|
||||
|
@@ -35,6 +35,7 @@ import org.qortal.network.message.Message.MessageType;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
import org.qortal.repository.RepositoryManager;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.transaction.Transaction;
|
||||
import org.qortal.utils.Base58;
|
||||
import org.qortal.utils.NTP;
|
||||
@@ -57,9 +58,6 @@ public class Synchronizer {
|
||||
/** Maximum number of block signatures we ask from peer in one go */
|
||||
private static final int MAXIMUM_REQUEST_SIZE = 200; // XXX move to Settings?
|
||||
|
||||
/** Number of retry attempts if a peer fails to respond with the requested data */
|
||||
private static final int MAXIMUM_RETRIES = 2; // XXX move to Settings?
|
||||
|
||||
|
||||
private static Synchronizer instance;
|
||||
|
||||
@@ -748,6 +746,7 @@ public class Synchronizer {
|
||||
|
||||
LOGGER.debug(() -> String.format("Fetching peer %s chain from height %d, sig %.8s", peer, commonBlockHeight, commonBlockSig58));
|
||||
|
||||
final int maxRetries = Settings.getInstance().getMaxRetries();
|
||||
|
||||
// Overall plan: fetch peer's blocks first, then orphan, then apply
|
||||
|
||||
@@ -837,7 +836,7 @@ public class Synchronizer {
|
||||
LOGGER.info(String.format("Peer %s failed to respond with block for height %d, sig %.8s", peer,
|
||||
nextHeight, Base58.encode(nextPeerSignature)));
|
||||
|
||||
if (retryCount >= MAXIMUM_RETRIES) {
|
||||
if (retryCount >= maxRetries) {
|
||||
|
||||
// If we have already received recent or newer blocks from this peer, go ahead and apply them
|
||||
if (peerBlocks.size() > 0) {
|
||||
@@ -875,9 +874,9 @@ public class Synchronizer {
|
||||
peerBlockSignatures.clear();
|
||||
numberSignaturesRequired = peerHeight - height;
|
||||
|
||||
// Retry until retryCount reaches MAXIMUM_RETRIES
|
||||
// Retry until retryCount reaches maxRetries
|
||||
retryCount++;
|
||||
int triesRemaining = MAXIMUM_RETRIES - retryCount;
|
||||
int triesRemaining = maxRetries - retryCount;
|
||||
LOGGER.info(String.format("Re-issuing request to peer %s (%d attempt%s remaining)", peer, triesRemaining, (triesRemaining != 1 ? "s" : "")));
|
||||
continue;
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ import java.util.Arrays;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -51,7 +50,7 @@ public enum Handshake {
|
||||
|
||||
String versionString = helloMessage.getVersionString();
|
||||
|
||||
Matcher matcher = VERSION_PATTERN.matcher(versionString);
|
||||
Matcher matcher = peer.VERSION_PATTERN.matcher(versionString);
|
||||
if (!matcher.lookingAt()) {
|
||||
LOGGER.debug(() -> String.format("Peer %s sent invalid HELLO version string '%s'", peer, versionString));
|
||||
return null;
|
||||
@@ -72,6 +71,15 @@ public enum Handshake {
|
||||
peer.setPeersConnectionTimestamp(peersConnectionTimestamp);
|
||||
peer.setPeersVersion(versionString, version);
|
||||
|
||||
if (Settings.getInstance().getAllowConnectionsWithOlderPeerVersions() == false) {
|
||||
// Ensure the peer is running at least the minimum version allowed for connections
|
||||
final String minPeerVersion = Settings.getInstance().getMinPeerVersion();
|
||||
if (peer.isAtLeastVersion(minPeerVersion) == false) {
|
||||
LOGGER.info(String.format("Ignoring peer %s because it is on an old version (%s)", peer, versionString));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return CHALLENGE;
|
||||
}
|
||||
|
||||
@@ -244,8 +252,6 @@ public enum Handshake {
|
||||
/** 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 Pattern VERSION_PATTERN = Pattern.compile(Controller.VERSION_PREFIX + "(\\d{1,3})\\.(\\d{1,5})\\.(\\d{1,5})");
|
||||
|
||||
private static final long PEER_VERSION_131 = 0x0100030001L;
|
||||
|
||||
private static final int POW_BUFFER_SIZE_PRE_131 = 8 * 1024 * 1024; // bytes
|
||||
|
@@ -20,9 +20,12 @@ import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.block.CommonBlockData;
|
||||
import org.qortal.data.network.PeerChainTipData;
|
||||
import org.qortal.data.network.PeerData;
|
||||
@@ -87,6 +90,9 @@ public class Peer {
|
||||
|
||||
byte[] ourChallenge;
|
||||
|
||||
// Versioning
|
||||
public static final Pattern VERSION_PATTERN = Pattern.compile(Controller.VERSION_PREFIX + "(\\d{1,3})\\.(\\d{1,5})\\.(\\d{1,5})");
|
||||
|
||||
// Peer info
|
||||
|
||||
private final Object peerInfoLock = new Object();
|
||||
@@ -634,6 +640,35 @@ public class Peer {
|
||||
}
|
||||
|
||||
|
||||
// Minimum version
|
||||
|
||||
public boolean isAtLeastVersion(String minVersionString) {
|
||||
if (minVersionString == null)
|
||||
return false;
|
||||
|
||||
// Add the version prefix
|
||||
minVersionString = Controller.VERSION_PREFIX + minVersionString;
|
||||
|
||||
Matcher matcher = VERSION_PATTERN.matcher(minVersionString);
|
||||
if (!matcher.lookingAt())
|
||||
return false;
|
||||
|
||||
// We're expecting 3 positive shorts, so we can convert 1.2.3 into 0x0100020003
|
||||
long minVersion = 0;
|
||||
for (int g = 1; g <= 3; ++g) {
|
||||
long value = Long.parseLong(matcher.group(g));
|
||||
|
||||
if (value < 0 || value > Short.MAX_VALUE)
|
||||
return false;
|
||||
|
||||
minVersion <<= 16;
|
||||
minVersion |= value;
|
||||
}
|
||||
|
||||
return this.getPeersVersion() >= minVersion;
|
||||
}
|
||||
|
||||
|
||||
// Common block data
|
||||
|
||||
public boolean canUseCachedCommonBlockData() {
|
||||
|
@@ -98,7 +98,7 @@ public interface ATRepository {
|
||||
*/
|
||||
public List<ATStateData> getMatchingFinalATStatesQuorum(byte[] codeHash, Boolean isFinished,
|
||||
Integer dataByteOffset, Long expectedValue,
|
||||
int minimumCount, long minimumPeriod) throws DataException;
|
||||
int minimumCount, int maximumCount, long minimumPeriod) throws DataException;
|
||||
|
||||
/**
|
||||
* Returns all ATStateData for a given block height.
|
||||
|
@@ -454,7 +454,7 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
@Override
|
||||
public List<ATStateData> getMatchingFinalATStatesQuorum(byte[] codeHash, Boolean isFinished,
|
||||
Integer dataByteOffset, Long expectedValue,
|
||||
int minimumCount, long minimumPeriod) throws DataException {
|
||||
int minimumCount, int maximumCount, long minimumPeriod) throws DataException {
|
||||
// We need most recent entry first so we can use its timestamp to slice further results
|
||||
List<ATStateData> mostRecentStates = this.getMatchingFinalATStates(codeHash, isFinished,
|
||||
dataByteOffset, expectedValue, null,
|
||||
@@ -510,7 +510,8 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
bindParams.add(minimumHeight);
|
||||
bindParams.add(minimumCount);
|
||||
|
||||
sql.append("ORDER BY FinalATStates.height DESC");
|
||||
sql.append("ORDER BY FinalATStates.height DESC LIMIT ?");
|
||||
bindParams.add(maximumCount);
|
||||
|
||||
List<ATStateData> atStates = new ArrayList<>();
|
||||
|
||||
|
@@ -122,6 +122,15 @@ public class Settings {
|
||||
private int maxNetworkThreadPoolSize = 20;
|
||||
/** Maximum number of threads for network proof-of-work compute, used during handshaking. */
|
||||
private int networkPoWComputePoolSize = 2;
|
||||
/** Maximum number of retry attempts if a peer fails to respond with the requested data */
|
||||
private int maxRetries = 2;
|
||||
|
||||
/** Minimum peer version number required in order to sync with them */
|
||||
private String minPeerVersion = "1.5.0";
|
||||
/** Whether to allow connections with peers below minPeerVersion
|
||||
* If true, we won't sync with them but they can still sync with us, and will show in the peers list
|
||||
* If false, sync will be blocked both ways, and they will not appear in the peers list */
|
||||
private boolean allowConnectionsWithOlderPeerVersions = true;
|
||||
|
||||
// Which blockchains this node is running
|
||||
private String blockchainConfig = null; // use default from resources
|
||||
@@ -408,6 +417,12 @@ public class Settings {
|
||||
return this.networkPoWComputePoolSize;
|
||||
}
|
||||
|
||||
public int getMaxRetries() { return this.maxRetries; }
|
||||
|
||||
public String getMinPeerVersion() { return this.minPeerVersion; }
|
||||
|
||||
public boolean getAllowConnectionsWithOlderPeerVersions() { return this.allowConnectionsWithOlderPeerVersions; }
|
||||
|
||||
public String getBlockchainConfig() {
|
||||
return this.blockchainConfig;
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@
|
||||
"atFindNextTransactionFix": 275000,
|
||||
"newBlockSigHeight": 320000,
|
||||
"shareBinFix": 399000,
|
||||
"calcChainWeightTimestamp": 1616000000000
|
||||
"calcChainWeightTimestamp": 1620579600000
|
||||
},
|
||||
"genesisInfo": {
|
||||
"version": 4,
|
||||
|
Reference in New Issue
Block a user