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.
This commit is contained in:
catbref 2020-04-15 17:30:49 +01:00
parent d90d84ab06
commit e25d24964c

View File

@ -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;
}
}