Revert BlockMinter to using long-lifetime repository session.

Although BlockMinter could reattach a repository session to its cache of potential blocks,
and these blocks would in turn reattach that repository session to their transactions,
further transaction-specific fields (e.g. creator PublicKeyAccount) were not being updated.

This would lead to NPEs like the following:

Exception in thread "BlockMinter" java.lang.NullPointerException
        at org.qortal.repository.hsqldb.HSQLDBRepository.cachePreparedStatement(HSQLDBRepository.java:587)
        at org.qortal.repository.hsqldb.HSQLDBRepository.prepareStatement(HSQLDBRepository.java:569)
        at org.qortal.repository.hsqldb.HSQLDBRepository.checkedExecute(HSQLDBRepository.java:609)
        at org.qortal.repository.hsqldb.HSQLDBAccountRepository.getBalance(HSQLDBAccountRepository.java:327)
        at org.qortal.account.Account.getConfirmedBalance(Account.java:72)
        at org.qortal.transaction.MessageTransaction.isValid(MessageTransaction.java:200)
        at org.qortal.block.Block.areTransactionsValid(Block.java:1190)
        at org.qortal.block.Block.isValid(Block.java:1137)
        at org.qortal.controller.BlockMinter.run(BlockMinter.java:301)

where the Account has an associated repository session which is now obsolete.

This commit reverts BlockMinter back to obtaining a repository session before entering main loop.
This commit is contained in:
catbref 2022-07-17 13:53:07 +01:00
parent 57bd3c3459
commit 275bee62d9

View File

@ -90,37 +90,40 @@ public class BlockMinter extends Thread {
List<Block> newBlocks = new ArrayList<>(); List<Block> newBlocks = new ArrayList<>();
// Flags for tracking change in whether minting is possible, try (final Repository repository = RepositoryManager.getRepository()) {
// so we can notify Controller, and further update SysTray, etc. // Going to need this a lot...
boolean isMintingPossible = false; BlockRepository blockRepository = repository.getBlockRepository();
boolean wasMintingPossible = isMintingPossible;
while (running) {
if (isMintingPossible != wasMintingPossible)
Controller.getInstance().onMintingPossibleChange(isMintingPossible);
wasMintingPossible = isMintingPossible; // Flags for tracking change in whether minting is possible,
// so we can notify Controller, and further update SysTray, etc.
boolean isMintingPossible = false;
boolean wasMintingPossible = isMintingPossible;
while (running) {
if (isMintingPossible != wasMintingPossible)
Controller.getInstance().onMintingPossibleChange(isMintingPossible);
try { wasMintingPossible = isMintingPossible;
// Sleep for a while
Thread.sleep(1000);
isMintingPossible = false; try {
// Free up any repository locks
repository.discardChanges();
final Long now = NTP.getTime(); // Sleep for a while
if (now == null) Thread.sleep(1000);
continue;
final Long minLatestBlockTimestamp = Controller.getMinimumLatestBlockTimestamp(); isMintingPossible = false;
if (minLatestBlockTimestamp == null)
continue;
// No online accounts for current timestamp? (e.g. during startup) final Long now = NTP.getTime();
if (!OnlineAccountsManager.getInstance().hasOnlineAccounts()) if (now == null)
continue; continue;
try (final Repository repository = RepositoryManager.getRepository()) { final Long minLatestBlockTimestamp = Controller.getMinimumLatestBlockTimestamp();
// Going to need this a lot... if (minLatestBlockTimestamp == null)
BlockRepository blockRepository = repository.getBlockRepository(); continue;
// No online accounts for current timestamp? (e.g. during startup)
if (!OnlineAccountsManager.getInstance().hasOnlineAccounts())
continue;
List<MintingAccountData> mintingAccountsData = repository.getAccountRepository().getMintingAccounts(); List<MintingAccountData> mintingAccountsData = repository.getAccountRepository().getMintingAccounts();
// No minting accounts? // No minting accounts?
@ -198,10 +201,6 @@ public class BlockMinter extends Thread {
// so go ahead and mint a block if possible. // so go ahead and mint a block if possible.
isMintingPossible = true; isMintingPossible = true;
// Reattach newBlocks to new repository handle
for (Block newBlock : newBlocks)
newBlock.setRepository(repository);
// Check blockchain hasn't changed // Check blockchain hasn't changed
if (previousBlockData == null || !Arrays.equals(previousBlockData.getSignature(), lastBlockData.getSignature())) { if (previousBlockData == null || !Arrays.equals(previousBlockData.getSignature(), lastBlockData.getSignature())) {
previousBlockData = lastBlockData; previousBlockData = lastBlockData;
@ -439,13 +438,13 @@ public class BlockMinter extends Thread {
Network network = Network.getInstance(); Network network = Network.getInstance();
network.broadcast(broadcastPeer -> network.buildHeightMessage(broadcastPeer, newBlockData)); network.broadcast(broadcastPeer -> network.buildHeightMessage(broadcastPeer, newBlockData));
} }
} catch (DataException e) { } catch (InterruptedException e) {
LOGGER.warn("Repository issue while running block minter", e); // We've been interrupted - time to exit
return;
} }
} catch (InterruptedException e) {
// We've been interrupted - time to exit
return;
} }
} catch (DataException e) {
LOGGER.warn("Repository issue while running block minter - NO LONGER MINTING", e);
} }
} }