Don't allow block generation unless system clock is accurate.

Controller performs NTP check on startup (and every 5 minutes)
which determines whether block generation is allowed.

System Tray tooltip updated to reflect generating status.
Plus new translations.

Improved GuiTests.

BlockGenerator fetches forging accounts first, and sleeps
if none configured, which is less work than processing peer lists.
This commit is contained in:
catbref
2019-07-25 12:42:08 +01:00
parent 73e53120a9
commit 671dc5995a
5 changed files with 54 additions and 19 deletions

View File

@@ -79,6 +79,15 @@ public class BlockGenerator extends Thread {
return;
}
// If Controller says we can't generate, then don't...
if (!Controller.getInstance().isGenerationAllowed())
continue;
List<ForgingAccountData> forgingAccountsData = repository.getAccountRepository().getForgingAccounts();
// No forging accounts?
if (forgingAccountsData.isEmpty())
continue;
List<Peer> peers = Network.getInstance().getUniqueHandshakedPeers();
BlockData lastBlockData = blockRepository.getLastBlock();
@@ -109,11 +118,6 @@ public class BlockGenerator extends Thread {
}
// Do we need to build any potential new blocks?
List<ForgingAccountData> forgingAccountsData = repository.getAccountRepository().getForgingAccounts();
// No forging accounts?
if (forgingAccountsData.isEmpty())
continue;
List<PrivateKeyAccount> forgingAccounts = forgingAccountsData.stream().map(accountData -> new PrivateKeyAccount(repository, accountData.getSeed())).collect(Collectors.toList());
// Discard accounts we have blocks for

View File

@@ -91,7 +91,7 @@ public class Controller extends Thread {
private static final String repositoryUrlTemplate = "jdbc:hsqldb:file:%s/blockchain;create=true;hsqldb.full_log_replay=true";
private static final long ARBITRARY_REQUEST_TIMEOUT = 5 * 1000; // ms
private static final long REPOSITORY_BACKUP_PERIOD = 123 * 60 * 1000; // ms
private static final long NTP_NAG_PERIOD = 5 * 60 * 1000; // ms
private static final long NTP_CHECK_PERIOD = 5 * 60 * 1000; // ms
private static final long MAX_NTP_OFFSET = 500; // ms
private static volatile boolean isStopping = false;
@@ -103,7 +103,9 @@ public class Controller extends Thread {
private final long buildTimestamp; // seconds
private long repositoryBackupTimestamp = startTime + REPOSITORY_BACKUP_PERIOD;
private long ntpNagTimestamp = startTime + NTP_NAG_PERIOD;
private long ntpCheckTimestamp = startTime; // ms
/** Whether BlockGenerator is allowed to generate blocks. Mostly determined by system clock accuracy. */
private boolean isGenerationAllowed = false;
/** Signature of peer's latest block when we tried to sync but peer had inferior chain. */
private byte[] inferiorChainPeerBlockSignature = null;
@@ -202,6 +204,10 @@ public class Controller extends Thread {
return this.blockchainLock;
}
public boolean isGenerationAllowed() {
return this.isGenerationAllowed;
}
// Entry point
public static void main(String args[]) {
@@ -321,9 +327,13 @@ public class Controller extends Thread {
}
// Potentially nag end-user about NTP
if (System.currentTimeMillis() >= ntpNagTimestamp) {
ntpNagTimestamp += NTP_NAG_PERIOD;
ntpNag();
if (System.currentTimeMillis() >= ntpCheckTimestamp) {
ntpCheckTimestamp += NTP_CHECK_PERIOD;
Boolean isClockAccurate = ntpCheck();
if (isClockAccurate != null) {
isGenerationAllowed = isClockAccurate;
updateSysTray();
}
}
// Prune stuck/slow/old peers
@@ -422,8 +432,12 @@ public class Controller extends Thread {
}
}
/** Nag if we detect system clock is too far from internet time. */
private void ntpNag() {
/**
* Nag if we detect system clock is too far from internet time.
*
* @return <tt>true</tt> if clock is accurate, <tt>false</tt> if inaccurate, <tt>null</tt> if we don't know.
*/
private Boolean ntpCheck() {
// Fetch mean offset from internet time (ms).
Long meanOffset = NTP.getOffset();
@@ -459,13 +473,20 @@ public class Controller extends Thread {
}
// If offset is good and ntp is active then we're good
if (Math.abs(meanOffset) < MAX_NTP_OFFSET && isNtpActive == true)
return;
if (meanOffset != null && Math.abs(meanOffset) < MAX_NTP_OFFSET && isNtpActive == true)
return true;
// Time to nag
String caption = Translator.INSTANCE.translate("SysTray", "NTP_NAG_CAPTION");
String text = Translator.INSTANCE.translate("SysTray", isWindows ? "NTP_NAG_TEXT_WINDOWS" : "NTP_NAG_TEXT_UNIX");
SysTray.getInstance().showMessage(caption, text, MessageType.WARNING);
if (meanOffset == null)
// We don't know if we're inaccurate
return null;
// Return whether we're accurate (disregarding whether NTP service is active)
return Math.abs(meanOffset) < MAX_NTP_OFFSET;
}
public void updateSysTray() {
@@ -475,7 +496,9 @@ public class Controller extends Thread {
String connectionsText = Translator.INSTANCE.translate("SysTray", numberOfPeers != 1 ? "CONNECTIONS" : "CONNECTION");
String heightText = Translator.INSTANCE.translate("SysTray", "BLOCK_HEIGHT");
String tooltip = String.format("qora-core - %d %s - %s %d", numberOfPeers, connectionsText, heightText, height);
String generatingText = Translator.INSTANCE.translate("SysTray", isGenerationAllowed ? "GENERATING_ENABLED" : "GENERATING_DISABLED");
String tooltip = String.format("%s - %d %s - %s %d", generatingText, numberOfPeers, connectionsText, heightText, height);
SysTray.getInstance().setToolTipText(tooltip);
}