From ae64be4802a335511927a1ceef6cb277c4b3c1fa Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sat, 23 Apr 2022 12:31:15 +0100 Subject: [PATCH 01/14] Retry scheduled repository maintenance up to 5 times, as it's common for it to timeout waiting for the repository. Subsequent retries normally succeed. --- .../org/qortal/controller/Controller.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/qortal/controller/Controller.java b/src/main/java/org/qortal/controller/Controller.java index fcf6270f..ac0dc85d 100644 --- a/src/main/java/org/qortal/controller/Controller.java +++ b/src/main/java/org/qortal/controller/Controller.java @@ -573,15 +573,20 @@ public class Controller extends Thread { MessageType.INFO); LOGGER.info("Starting scheduled repository maintenance. This can take a while..."); - try (final Repository repository = RepositoryManager.getRepository()) { + int attempts = 0; + while (attempts <= 5) { + try (final Repository repository = RepositoryManager.getRepository()) { + attempts++; - // Timeout if the database isn't ready for maintenance after 60 seconds - long timeout = 60 * 1000L; - repository.performPeriodicMaintenance(timeout); + // Timeout if the database isn't ready for maintenance after 60 seconds + long timeout = 60 * 1000L; + repository.performPeriodicMaintenance(timeout); - LOGGER.info("Scheduled repository maintenance completed"); - } catch (DataException | TimeoutException e) { - LOGGER.error("Scheduled repository maintenance failed", e); + LOGGER.info("Scheduled repository maintenance completed"); + break; + } catch (DataException | TimeoutException e) { + LOGGER.info("Scheduled repository maintenance failed. Retrying up to 5 times...", e); + } } // Get a new random interval From df290950ea00dd9791721f5069f35c6c8f887f9a Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sat, 23 Apr 2022 12:32:06 +0100 Subject: [PATCH 02/14] Reduce log spam in BlockMinter --- src/main/java/org/qortal/controller/BlockMinter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/qortal/controller/BlockMinter.java b/src/main/java/org/qortal/controller/BlockMinter.java index de73adbe..04797314 100644 --- a/src/main/java/org/qortal/controller/BlockMinter.java +++ b/src/main/java/org/qortal/controller/BlockMinter.java @@ -219,7 +219,7 @@ public class BlockMinter extends Thread { // The last iteration found a higher weight block in the network, so sleep for a while // to allow is to sync the higher weight chain. We are sleeping here rather than when // detected as we don't want to hold the blockchain lock open. - LOGGER.info("Sleeping for 10 seconds..."); + LOGGER.debug("Sleeping for 10 seconds..."); Thread.sleep(10 * 1000L); } @@ -328,13 +328,13 @@ public class BlockMinter extends Thread { // If less than 30 seconds has passed since first detection the higher weight chain, // we should skip our block submission to give us the opportunity to sync to the better chain if (NTP.getTime() - timeOfLastLowWeightBlock < 30*1000L) { - LOGGER.info("Higher weight chain found in peers, so not signing a block this round"); - LOGGER.info("Time since detected: {}", NTP.getTime() - timeOfLastLowWeightBlock); + LOGGER.debug("Higher weight chain found in peers, so not signing a block this round"); + LOGGER.debug("Time since detected: {}ms", NTP.getTime() - timeOfLastLowWeightBlock); continue; } else { // More than 30 seconds have passed, so we should submit our block candidate anyway. - LOGGER.info("More than 30 seconds passed, so proceeding to submit block candidate..."); + LOGGER.debug("More than 30 seconds passed, so proceeding to submit block candidate..."); } } else { From 64e102a8c6bfd35b9cc4bf857184630e0eb11e93 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 24 Apr 2022 15:27:21 +0100 Subject: [PATCH 03/14] Name registration fee reduction to 1.25 QORT set to Sun, 01 May 2022 16:00:00 GMT --- src/main/resources/blockchain.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/blockchain.json b/src/main/resources/blockchain.json index be62aee4..1f20ccfe 100644 --- a/src/main/resources/blockchain.json +++ b/src/main/resources/blockchain.json @@ -5,7 +5,8 @@ "maxBytesPerUnitFee": 1024, "unitFee": "0.001", "nameRegistrationUnitFees": [ - { "timestamp": 1645372800000, "fee": "5" } + { "timestamp": 1645372800000, "fee": "5" }, + { "timestamp": 1651420800000, "fee": "1.25" } ], "useBrokenMD160ForAddresses": false, "requireGroupForApproval": false, From cca5bac30ae2e258827e8315f905aba4eaf40fcc Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 24 Apr 2022 15:36:36 +0100 Subject: [PATCH 04/14] Fixed logic bug in name registration fee calculation. --- src/main/java/org/qortal/block/BlockChain.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/qortal/block/BlockChain.java b/src/main/java/org/qortal/block/BlockChain.java index 86a00574..bc06fadf 100644 --- a/src/main/java/org/qortal/block/BlockChain.java +++ b/src/main/java/org/qortal/block/BlockChain.java @@ -425,9 +425,8 @@ public class BlockChain { } public long getNameRegistrationUnitFeeAtTimestamp(long ourTimestamp) { - // Scan through for reward at our height - for (int i = 0; i < nameRegistrationUnitFees.size(); ++i) - if (ourTimestamp >= nameRegistrationUnitFees.get(i).timestamp) + for (int i = nameRegistrationUnitFees.size() - 1; i >= 0; --i) + if (nameRegistrationUnitFees.get(i).timestamp <= ourTimestamp) return nameRegistrationUnitFees.get(i).fee; // Default to system-wide unit fee From 682a5fde94856bf868a794a047fcf9b836b800c8 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 24 Apr 2022 15:54:20 +0100 Subject: [PATCH 05/14] Revert "Attempt to fix core startup problems on some systems (GNOME Desktop?) by adding defensiveness to GUI elements." This reverts commit 311f41c610b7d3388cef714979d9653508fb0c55. --- src/main/java/org/qortal/gui/Gui.java | 4 +- src/main/java/org/qortal/gui/SplashFrame.java | 41 +++++++------------ src/main/java/org/qortal/gui/SysTray.java | 8 +--- 3 files changed, 18 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/qortal/gui/Gui.java b/src/main/java/org/qortal/gui/Gui.java index 12191349..4944db52 100644 --- a/src/main/java/org/qortal/gui/Gui.java +++ b/src/main/java/org/qortal/gui/Gui.java @@ -47,12 +47,12 @@ public class Gui { this.splashFrame = SplashFrame.getInstance(); } - protected static BufferedImage loadImage(String resourceName) throws IOException { + protected static BufferedImage loadImage(String resourceName) { try (InputStream in = Gui.class.getResourceAsStream("/images/" + resourceName)) { return ImageIO.read(in); } catch (IllegalArgumentException | IOException | ServiceConfigurationError e) { LOGGER.warn(String.format("Couldn't locate image resource \"images/%s\"", resourceName)); - throw new IOException(String.format("Couldn't locate image resource \"images/%s\"", resourceName)); + return null; } } diff --git a/src/main/java/org/qortal/gui/SplashFrame.java b/src/main/java/org/qortal/gui/SplashFrame.java index 3fd452fc..c4ea51d0 100644 --- a/src/main/java/org/qortal/gui/SplashFrame.java +++ b/src/main/java/org/qortal/gui/SplashFrame.java @@ -1,7 +1,6 @@ package org.qortal.gui; import java.awt.*; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.awt.image.BufferedImage; @@ -30,23 +29,18 @@ public class SplashFrame { private JLabel statusLabel; public SplashPanel() { - try { - image = Gui.loadImage(defaultSplash); - - // Add logo - JLabel imageLabel = new JLabel(new ImageIcon(image)); - imageLabel.setSize(new Dimension(300, 300)); - add(imageLabel); - } - catch (IOException e) { - LOGGER.warn("Unable to load splash panel image"); - } + image = Gui.loadImage(defaultSplash); setOpaque(true); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); setBorder(new EmptyBorder(10, 10, 10, 10)); setBackground(Color.BLACK); + // Add logo + JLabel imageLabel = new JLabel(new ImageIcon(image)); + imageLabel.setSize(new Dimension(300, 300)); + add(imageLabel); + // Add spacing add(Box.createRigidArea(new Dimension(0, 16))); @@ -81,20 +75,15 @@ public class SplashFrame { this.splashDialog = new JFrame(); - try { - List icons = new ArrayList<>(); - icons.add(Gui.loadImage("icons/icon16.png")); - icons.add(Gui.loadImage("icons/qortal_ui_tray_synced.png")); - icons.add(Gui.loadImage("icons/qortal_ui_tray_syncing_time-alt.png")); - icons.add(Gui.loadImage("icons/qortal_ui_tray_minting.png")); - icons.add(Gui.loadImage("icons/qortal_ui_tray_syncing.png")); - icons.add(Gui.loadImage("icons/icon64.png")); - icons.add(Gui.loadImage("icons/Qlogo_128.png")); - this.splashDialog.setIconImages(icons); - } - catch (IOException e) { - LOGGER.warn("Unable to load splash frame icons"); - } + List icons = new ArrayList<>(); + icons.add(Gui.loadImage("icons/icon16.png")); + icons.add(Gui.loadImage("icons/qortal_ui_tray_synced.png")); + icons.add(Gui.loadImage("icons/qortal_ui_tray_syncing_time-alt.png")); + icons.add(Gui.loadImage("icons/qortal_ui_tray_minting.png")); + icons.add(Gui.loadImage("icons/qortal_ui_tray_syncing.png")); + icons.add(Gui.loadImage("icons/icon64.png")); + icons.add(Gui.loadImage("icons/Qlogo_128.png")); + this.splashDialog.setIconImages(icons); this.splashPanel = new SplashPanel(); this.splashDialog.getContentPane().add(this.splashPanel); diff --git a/src/main/java/org/qortal/gui/SysTray.java b/src/main/java/org/qortal/gui/SysTray.java index 861c9ab0..7a24f825 100644 --- a/src/main/java/org/qortal/gui/SysTray.java +++ b/src/main/java/org/qortal/gui/SysTray.java @@ -61,13 +61,7 @@ public class SysTray { this.popupMenu = createJPopupMenu(); // Build TrayIcon without AWT PopupMenu (which doesn't support Unicode)... - try { - this.trayIcon = new TrayIcon(Gui.loadImage("icons/qortal_ui_tray_synced.png"), "qortal", null); - } - catch (IOException e) { - LOGGER.warn("Unable to load system tray icon"); - return; - } + this.trayIcon = new TrayIcon(Gui.loadImage("icons/qortal_ui_tray_synced.png"), "qortal", null); // ...and attach mouse listener instead so we can use JPopupMenu (which does support Unicode) this.trayIcon.addMouseListener(new MouseAdapter() { @Override From d03c1451892a7b4914ec72a6e165527b7a5663fd Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 24 Apr 2022 17:41:24 +0100 Subject: [PATCH 06/14] Added to testRegisterNameFeeIncrease() test to catch the recently detected bug. --- src/test/java/org/qortal/test/naming/MiscTests.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/qortal/test/naming/MiscTests.java b/src/test/java/org/qortal/test/naming/MiscTests.java index 8252453c..2bcd098d 100644 --- a/src/test/java/org/qortal/test/naming/MiscTests.java +++ b/src/test/java/org/qortal/test/naming/MiscTests.java @@ -356,8 +356,15 @@ public class MiscTests extends Common { UnitFeesByTimestamp pastFeeIncrease = new UnitFeesByTimestamp(); pastFeeIncrease.timestamp = now - 1000L; // 1 second ago pastFeeIncrease.fee = new AmountTypeAdapter().unmarshal("3"); - FieldUtils.writeField(BlockChain.getInstance(), "nameRegistrationUnitFees", Arrays.asList(pastFeeIncrease), true); + + // Set another increase in the future + futureFeeIncrease = new UnitFeesByTimestamp(); + futureFeeIncrease.timestamp = now + (60 * 60 * 1000L); // 1 hour in the future + futureFeeIncrease.fee = new AmountTypeAdapter().unmarshal("10"); + + FieldUtils.writeField(BlockChain.getInstance(), "nameRegistrationUnitFees", Arrays.asList(pastFeeIncrease, futureFeeIncrease), true); assertEquals(pastFeeIncrease.fee, BlockChain.getInstance().getNameRegistrationUnitFeeAtTimestamp(pastFeeIncrease.timestamp)); + assertEquals(futureFeeIncrease.fee, BlockChain.getInstance().getNameRegistrationUnitFeeAtTimestamp(futureFeeIncrease.timestamp)); // Register a different name // First try with the default unit fee From f3f8e0013dab52da8d05d2f515063bd2c4313942 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 24 Apr 2022 17:48:22 +0100 Subject: [PATCH 07/14] Bump version to 3.2.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4054ce71..12979e96 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.qortal qortal - 3.2.3 + 3.2.4 jar true From 568497e1c5019aa1660edd12026fb28723742d34 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Mon, 25 Apr 2022 09:03:57 +0100 Subject: [PATCH 08/14] Updated AdvancedInstaller project for v3.2.4 --- WindowsInstaller/Qortal.aip | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WindowsInstaller/Qortal.aip b/WindowsInstaller/Qortal.aip index 16b86fe2..7525aa1c 100755 --- a/WindowsInstaller/Qortal.aip +++ b/WindowsInstaller/Qortal.aip @@ -17,10 +17,10 @@ - + - + @@ -212,7 +212,7 @@ - + From 46701e4de75ac2bb569c1d56cab081b2d8e8a5a1 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Tue, 26 Apr 2022 19:52:08 +0100 Subject: [PATCH 09/14] Revert "Remove peers with unknown height, lower height or same height and same block signature (unless we don't have their block signature)" This reverts commit 895f02f17896c5ad78f7e8f26252d7530aae3a85. --- .../org/qortal/controller/Controller.java | 23 ------------------- .../org/qortal/controller/Synchronizer.java | 3 --- 2 files changed, 26 deletions(-) diff --git a/src/main/java/org/qortal/controller/Controller.java b/src/main/java/org/qortal/controller/Controller.java index ac0dc85d..e774ccf6 100644 --- a/src/main/java/org/qortal/controller/Controller.java +++ b/src/main/java/org/qortal/controller/Controller.java @@ -660,29 +660,6 @@ public class Controller extends Thread { return lastMisbehaved != null && lastMisbehaved > NTP.getTime() - MISBEHAVIOUR_COOLOFF; }; - /** True if peer has unknown height, lower height or same height and same block signature (unless we don't have their block signature). */ - public static Predicate hasShorterBlockchain = peer -> { - BlockData highestBlockData = getInstance().getChainTip(); - int ourHeight = highestBlockData.getHeight(); - final PeerChainTipData peerChainTipData = peer.getChainTipData(); - - // Ensure we have chain tip data for this peer - if (peerChainTipData == null) - return true; - - // Remove if peer is at a lower height than us - Integer peerHeight = peerChainTipData.getLastHeight(); - if (peerHeight == null || peerHeight < ourHeight) - return true; - - // Don't remove if peer is on a greater height chain than us, or if we don't have their block signature - if (peerHeight > ourHeight || peerChainTipData.getLastBlockSignature() == null) - return false; - - // Remove if signatures match - return Arrays.equals(peerChainTipData.getLastBlockSignature(), highestBlockData.getSignature()); - }; - public static final Predicate hasNoRecentBlock = peer -> { final Long minLatestBlockTimestamp = getMinimumLatestBlockTimestamp(); final PeerChainTipData peerChainTipData = peer.getChainTipData(); diff --git a/src/main/java/org/qortal/controller/Synchronizer.java b/src/main/java/org/qortal/controller/Synchronizer.java index d574ef87..63a48888 100644 --- a/src/main/java/org/qortal/controller/Synchronizer.java +++ b/src/main/java/org/qortal/controller/Synchronizer.java @@ -235,9 +235,6 @@ public class Synchronizer extends Thread { // Disregard peers that are on the same block as last sync attempt and we didn't like their chain peers.removeIf(Controller.hasInferiorChainTip); - // Remove peers with unknown height, lower height or same height and same block signature (unless we don't have their block signature) - peers.removeIf(Controller.hasShorterBlockchain); - final int peersBeforeComparison = peers.size(); // Request recent block summaries from the remaining peers, and locate our common block with each From 81ef1ae9647f628babe0e2a926c0e9ee964b2b8b Mon Sep 17 00:00:00 2001 From: CalDescent Date: Tue, 26 Apr 2022 20:17:57 +0100 Subject: [PATCH 10/14] Bump version to 3.2.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 12979e96..2b115f61 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.qortal qortal - 3.2.4 + 3.2.5 jar true From dd55dc277b308f755f6ec7bfb0e477d493d307c6 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Wed, 27 Apr 2022 08:50:40 +0100 Subject: [PATCH 11/14] Updated AdvancedInstaller project for v3.2.5 --- WindowsInstaller/Qortal.aip | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WindowsInstaller/Qortal.aip b/WindowsInstaller/Qortal.aip index 7525aa1c..722d881e 100755 --- a/WindowsInstaller/Qortal.aip +++ b/WindowsInstaller/Qortal.aip @@ -17,10 +17,10 @@ - + - + @@ -212,7 +212,7 @@ - + From e5b4b618323e95f1bd6f30e74e3415c474db40bd Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sat, 30 Apr 2022 11:26:05 +0100 Subject: [PATCH 12/14] Fixed bugs causing "Hash ... does not match file digest ..." errors --- src/main/java/org/qortal/arbitrary/ArbitraryDataFile.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/qortal/arbitrary/ArbitraryDataFile.java b/src/main/java/org/qortal/arbitrary/ArbitraryDataFile.java index 14504f37..9be4f145 100644 --- a/src/main/java/org/qortal/arbitrary/ArbitraryDataFile.java +++ b/src/main/java/org/qortal/arbitrary/ArbitraryDataFile.java @@ -93,10 +93,12 @@ public class ArbitraryDataFile { File outputFile = outputFilePath.toFile(); try (FileOutputStream outputStream = new FileOutputStream(outputFile)) { outputStream.write(fileContent); + outputStream.close(); this.filePath = outputFilePath; // Verify hash - if (!this.hash58.equals(this.digest58())) { - LOGGER.error("Hash {} does not match file digest {} for signature: {}", this.hash58, this.digest58(), Base58.encode(signature)); + String digest58 = this.digest58(); + if (!this.hash58.equals(digest58)) { + LOGGER.error("Hash {} does not match file digest {} for signature: {}", this.hash58, digest58, Base58.encode(signature)); this.delete(); throw new DataException("Data file digest validation failed"); } From a4bcd4451cefef10364bdd46677403e354177a86 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sat, 30 Apr 2022 12:07:47 +0100 Subject: [PATCH 13/14] Added "tail" parameter to GET /admin/logs to allow returning the last X (limit) lines. This should make it easy to display core logs in the UI. --- .../java/org/qortal/api/resource/AdminResource.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/org/qortal/api/resource/AdminResource.java b/src/main/java/org/qortal/api/resource/AdminResource.java index 277b5f00..b14d774f 100644 --- a/src/main/java/org/qortal/api/resource/AdminResource.java +++ b/src/main/java/org/qortal/api/resource/AdminResource.java @@ -381,6 +381,10 @@ public class AdminResource { ) @QueryParam("limit") Integer limit, @Parameter( ref = "offset" ) @QueryParam("offset") Integer offset, @Parameter( + name = "tail", + description = "Fetch most recent log lines", + schema = @Schema(type = "boolean") + ) @QueryParam("tail") Boolean tail, @Parameter( ref = "reverse" ) @QueryParam("reverse") Boolean reverse) { LoggerContext loggerContext = (LoggerContext) LogManager.getContext(); @@ -396,6 +400,13 @@ public class AdminResource { if (reverse != null && reverse) logLines = Lists.reverse(logLines); + // Tail mode - return the last X lines (where X = limit) + if (tail != null && tail) { + if (limit != null && limit > 0) { + offset = logLines.size() - limit; + } + } + // offset out of bounds? if (offset != null && (offset < 0 || offset >= logLines.size())) return ""; From 0695039ee3c904f7470875ac5c2be7e2462d8f5f Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sat, 30 Apr 2022 12:08:10 +0100 Subject: [PATCH 14/14] Fixed long term bug causing last line to be missed out. --- src/main/java/org/qortal/api/resource/AdminResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/qortal/api/resource/AdminResource.java b/src/main/java/org/qortal/api/resource/AdminResource.java index b14d774f..efb47acf 100644 --- a/src/main/java/org/qortal/api/resource/AdminResource.java +++ b/src/main/java/org/qortal/api/resource/AdminResource.java @@ -427,7 +427,7 @@ public class AdminResource { limit = Math.min(limit, logLines.size()); - logLines.subList(limit - 1, logLines.size()).clear(); + logLines.subList(limit, logLines.size()).clear(); return String.join("\n", logLines); } catch (IOException e) {