From 671dc5995ad1c1d1b801ae1ce93a88dc3bb1d393 Mon Sep 17 00:00:00 2001 From: catbref Date: Thu, 25 Jul 2019 12:42:08 +0100 Subject: [PATCH] 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. --- .../java/org/qora/block/BlockGenerator.java | 14 +++--- .../java/org/qora/controller/Controller.java | 43 ++++++++++++++----- src/main/resources/i18n/SysTray_en.properties | 6 ++- src/main/resources/i18n/SysTray_zh.properties | 6 +++ src/test/java/org/qora/test/GuiTests.java | 4 +- 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/qora/block/BlockGenerator.java b/src/main/java/org/qora/block/BlockGenerator.java index 60da346c..710abe7a 100644 --- a/src/main/java/org/qora/block/BlockGenerator.java +++ b/src/main/java/org/qora/block/BlockGenerator.java @@ -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 forgingAccountsData = repository.getAccountRepository().getForgingAccounts(); + // No forging accounts? + if (forgingAccountsData.isEmpty()) + continue; + List 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 forgingAccountsData = repository.getAccountRepository().getForgingAccounts(); - // No forging accounts? - if (forgingAccountsData.isEmpty()) - continue; - List forgingAccounts = forgingAccountsData.stream().map(accountData -> new PrivateKeyAccount(repository, accountData.getSeed())).collect(Collectors.toList()); // Discard accounts we have blocks for diff --git a/src/main/java/org/qora/controller/Controller.java b/src/main/java/org/qora/controller/Controller.java index baacd1c3..39daccd6 100644 --- a/src/main/java/org/qora/controller/Controller.java +++ b/src/main/java/org/qora/controller/Controller.java @@ -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 true if clock is accurate, false if inaccurate, null 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); } diff --git a/src/main/resources/i18n/SysTray_en.properties b/src/main/resources/i18n/SysTray_en.properties index be493d1b..8b79dc85 100644 --- a/src/main/resources/i18n/SysTray_en.properties +++ b/src/main/resources/i18n/SysTray_en.properties @@ -5,12 +5,16 @@ BLOCK_HEIGHT = height CHECK_TIME_ACCURACY = Check time accuracy -CONNECTION = block +CONNECTION = connection CONNECTIONS = connections EXIT = Exit +GENERATING_DISABLED = NOT minting + +GENERATING_ENABLED = \u2714 Minting + # Nagging about lack of NTP time sync NTP_NAG_CAPTION = Computer's clock is inaccurate! diff --git a/src/main/resources/i18n/SysTray_zh.properties b/src/main/resources/i18n/SysTray_zh.properties index d3349242..369e434a 100644 --- a/src/main/resources/i18n/SysTray_zh.properties +++ b/src/main/resources/i18n/SysTray_zh.properties @@ -5,10 +5,16 @@ BLOCK_HEIGHT = \u5757\u9AD8\u5EA6 CHECK_TIME_ACCURACY = \u68C0\u67E5\u65F6\u95F4\u51C6\u786E\u6027 +CONNECTION = \u4E2A\u8FDE\u63A5 + CONNECTIONS = \u4E2A\u8FDE\u63A5 EXIT = \u9000\u51FA\u8F6F\u4EF6 +GENERATING_DISABLED = \u6CA1\u6709\u94F8\u5E01 + +GENERATING_ENABLED = \u2714 \u94F8\u5E01 + # Nagging about lack of NTP time sync NTP_NAG_CAPTION = \u7535\u8111\u7684\u65F6\u949F\u4E0D\u51C6\u786E\uFF01 diff --git a/src/test/java/org/qora/test/GuiTests.java b/src/test/java/org/qora/test/GuiTests.java index 27a9219a..5e8cdb26 100644 --- a/src/test/java/org/qora/test/GuiTests.java +++ b/src/test/java/org/qora/test/GuiTests.java @@ -19,9 +19,7 @@ public class GuiTests { public void testSysTray() throws InterruptedException { SysTray.getInstance(); - while(true) { - Thread.sleep(2000L); - } + Thread.sleep(10_000L); } }