mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-23 04:36:50 +00:00
Modifications to support a single node testnet:
- Added "singleNodeTestnet" setting, allowing for fast and consecutive block minting, and no requirement for a minimum number of peers. - Added "recoveryModeTimeout" setting (previously hardcoded in Synchronizer). - Updated testnets documentation to include new settings and a quick start guide. - Added "generic" minting account that can be used in testnets (not functional on mainnet), to simplify the process for new devs.
This commit is contained in:
@@ -93,6 +93,8 @@ public class BlockMinter extends Thread {
|
||||
|
||||
List<Block> newBlocks = new ArrayList<>();
|
||||
|
||||
final boolean isSingleNodeTestnet = Settings.getInstance().isSingleNodeTestnet();
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
// Going to need this a lot...
|
||||
BlockRepository blockRepository = repository.getBlockRepository();
|
||||
@@ -111,8 +113,9 @@ public class BlockMinter extends Thread {
|
||||
// Free up any repository locks
|
||||
repository.discardChanges();
|
||||
|
||||
// Sleep for a while
|
||||
Thread.sleep(1000);
|
||||
// Sleep for a while.
|
||||
// It's faster on single node testnets, to allow lots of blocks to be minted quickly.
|
||||
Thread.sleep(isSingleNodeTestnet ? 50 : 1000);
|
||||
|
||||
isMintingPossible = false;
|
||||
|
||||
@@ -223,9 +226,10 @@ public class BlockMinter extends Thread {
|
||||
List<PrivateKeyAccount> newBlocksMintingAccounts = mintingAccountsData.stream().map(accountData -> new PrivateKeyAccount(repository, accountData.getPrivateKey())).collect(Collectors.toList());
|
||||
|
||||
// We might need to sit the next block out, if one of our minting accounts signed the previous one
|
||||
// Skip this check for single node testnets, since they definitely need to mint every block
|
||||
byte[] previousBlockMinter = previousBlockData.getMinterPublicKey();
|
||||
boolean mintedLastBlock = mintingAccountsData.stream().anyMatch(mintingAccount -> Arrays.equals(mintingAccount.getPublicKey(), previousBlockMinter));
|
||||
if (mintedLastBlock) {
|
||||
if (mintedLastBlock && !isSingleNodeTestnet) {
|
||||
LOGGER.trace(String.format("One of our keys signed the last block, so we won't sign the next one"));
|
||||
continue;
|
||||
}
|
||||
|
@@ -1872,6 +1872,10 @@ public class Controller extends Thread {
|
||||
if (latestBlockData == null || latestBlockData.getTimestamp() < minLatestBlockTimestamp)
|
||||
return false;
|
||||
|
||||
if (Settings.getInstance().isSingleNodeTestnet())
|
||||
// Single node testnets won't have peers, so we can assume up to date from this point
|
||||
return true;
|
||||
|
||||
// Needs a mutable copy of the unmodifiableList
|
||||
List<Peer> peers = new ArrayList<>(Network.getInstance().getImmutableHandshakedPeers());
|
||||
if (peers == null)
|
||||
|
@@ -56,8 +56,6 @@ public class Synchronizer extends Thread {
|
||||
/** Maximum number of consecutive failed sync attempts before marking peer as misbehaved */
|
||||
private static final int MAX_CONSECUTIVE_FAILED_SYNC_ATTEMPTS = 3;
|
||||
|
||||
private static final long RECOVERY_MODE_TIMEOUT = 10 * 60 * 1000L; // ms
|
||||
|
||||
|
||||
private boolean running;
|
||||
|
||||
@@ -399,9 +397,10 @@ public class Synchronizer extends Thread {
|
||||
timePeersLastAvailable = NTP.getTime();
|
||||
|
||||
// If enough time has passed, enter recovery mode, which lifts some restrictions on who we can sync with and when we can mint
|
||||
if (NTP.getTime() - timePeersLastAvailable > RECOVERY_MODE_TIMEOUT) {
|
||||
long recoveryModeTimeout = Settings.getInstance().getRecoveryModeTimeout();
|
||||
if (NTP.getTime() - timePeersLastAvailable > recoveryModeTimeout) {
|
||||
if (recoveryMode == false) {
|
||||
LOGGER.info(String.format("Peers have been unavailable for %d minutes. Entering recovery mode...", RECOVERY_MODE_TIMEOUT/60/1000));
|
||||
LOGGER.info(String.format("Peers have been unavailable for %d minutes. Entering recovery mode...", recoveryModeTimeout/60/1000));
|
||||
recoveryMode = true;
|
||||
}
|
||||
}
|
||||
|
@@ -184,6 +184,8 @@ public class Settings {
|
||||
|
||||
// Peer-to-peer related
|
||||
private boolean isTestNet = false;
|
||||
/** Single node testnet mode */
|
||||
private boolean singleNodeTestnet = false;
|
||||
/** Port number for inbound peer-to-peer connections. */
|
||||
private Integer listenPort;
|
||||
/** Whether to attempt to open the listen port via UPnP */
|
||||
@@ -203,6 +205,9 @@ public class Settings {
|
||||
/** Maximum number of retry attempts if a peer fails to respond with the requested data */
|
||||
private int maxRetries = 2;
|
||||
|
||||
/** The number of seconds of no activity before recovery mode begins */
|
||||
public long recoveryModeTimeout = 10 * 60 * 1000L;
|
||||
|
||||
/** Minimum peer version number required in order to sync with them */
|
||||
private String minPeerVersion = "3.6.3";
|
||||
/** Whether to allow connections with peers below minPeerVersion
|
||||
@@ -486,7 +491,7 @@ public class Settings {
|
||||
|
||||
private void validate() {
|
||||
// Validation goes here
|
||||
if (this.minBlockchainPeers < 1)
|
||||
if (this.minBlockchainPeers < 1 && !singleNodeTestnet)
|
||||
throwValidationError("minBlockchainPeers must be at least 1");
|
||||
|
||||
if (this.apiKey != null && this.apiKey.trim().length() < 8)
|
||||
@@ -643,6 +648,10 @@ public class Settings {
|
||||
return this.isTestNet;
|
||||
}
|
||||
|
||||
public boolean isSingleNodeTestnet() {
|
||||
return this.singleNodeTestnet;
|
||||
}
|
||||
|
||||
public int getListenPort() {
|
||||
if (this.listenPort != null)
|
||||
return this.listenPort;
|
||||
@@ -663,6 +672,9 @@ public class Settings {
|
||||
}
|
||||
|
||||
public int getMinBlockchainPeers() {
|
||||
if (singleNodeTestnet)
|
||||
return 0;
|
||||
|
||||
return this.minBlockchainPeers;
|
||||
}
|
||||
|
||||
@@ -688,6 +700,10 @@ public class Settings {
|
||||
|
||||
public int getMaxRetries() { return this.maxRetries; }
|
||||
|
||||
public long getRecoveryModeTimeout() {
|
||||
return recoveryModeTimeout;
|
||||
}
|
||||
|
||||
public String getMinPeerVersion() { return this.minPeerVersion; }
|
||||
|
||||
public boolean getAllowConnectionsWithOlderPeerVersions() { return this.allowConnectionsWithOlderPeerVersions; }
|
||||
|
Reference in New Issue
Block a user