From e25d24964cf1b1e643b0fd5aeba9da9d27a03a05 Mon Sep 17 00:00:00 2001 From: catbref Date: Wed, 15 Apr 2020 17:30:49 +0100 Subject: [PATCH] Make BlockMinter more aggressive about obtaining blockchain lock. Previously BlockMinter & Synchronizer would both try opportunistic locking, with no wait/timeout or fairness. This could lead to a situation where a majority of nodes are synchronizing, albeit only the top 1 or 2 blocks, but no node manages to mint within the 'recent' period, so the chain stalls. However, if a node is at/near the top of the chain then synchronization shouldn't take very long so we let BlockMinter wait until to 30s (approx. half typical block time) to obtain lock. This makes minting blocks more likely in a BlockMinter/Sync fight which helps keep the chain going. Detecting chain stalls, and allowing minting if we have plenty of peers, also produces blockchain 'islands' so isn't a simple fix at this point. --- .../java/org/qortal/block/BlockMinter.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/qortal/block/BlockMinter.java b/src/main/java/org/qortal/block/BlockMinter.java index 34c50556..3adbef3d 100644 --- a/src/main/java/org/qortal/block/BlockMinter.java +++ b/src/main/java/org/qortal/block/BlockMinter.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -75,20 +76,15 @@ public class BlockMinter extends Thread { boolean isMintingPossible = false; boolean wasMintingPossible = isMintingPossible; while (running) { + repository.discardChanges(); // Free repository locks, if any + + if (isMintingPossible != wasMintingPossible) + Controller.getInstance().onMintingPossibleChange(isMintingPossible); + + wasMintingPossible = isMintingPossible; + // Sleep for a while - try { - repository.discardChanges(); // Free repository locks, if any - - if (isMintingPossible != wasMintingPossible) - Controller.getInstance().onMintingPossibleChange(isMintingPossible); - - wasMintingPossible = isMintingPossible; - - Thread.sleep(1000); - } catch (InterruptedException e) { - // We've been interrupted - time to exit - return; - } + Thread.sleep(1000); isMintingPossible = false; @@ -181,7 +177,7 @@ public class BlockMinter extends Thread { // Make sure we're the only thread modifying the blockchain ReentrantLock blockchainLock = Controller.getInstance().getBlockchainLock(); - if (!blockchainLock.tryLock()) + if (!blockchainLock.tryLock(30, TimeUnit.SECONDS)) continue; boolean newBlockMinted = false; @@ -286,6 +282,9 @@ public class BlockMinter extends Thread { } } catch (DataException e) { LOGGER.warn("Repository issue while running block minter", e); + } catch (InterruptedException e) { + // We've been interrupted - time to exit + return; } }