From 275bee62d956212b0a6b6cefe7c36af7a9ca7d37 Mon Sep 17 00:00:00 2001 From: catbref Date: Sun, 17 Jul 2022 13:53:07 +0100 Subject: [PATCH] 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. --- .../org/qortal/controller/BlockMinter.java | 65 +++++++++---------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/qortal/controller/BlockMinter.java b/src/main/java/org/qortal/controller/BlockMinter.java index 2d736e76..343ab4af 100644 --- a/src/main/java/org/qortal/controller/BlockMinter.java +++ b/src/main/java/org/qortal/controller/BlockMinter.java @@ -90,37 +90,40 @@ public class BlockMinter extends Thread { List newBlocks = new ArrayList<>(); - // 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 (final Repository repository = RepositoryManager.getRepository()) { + // Going to need this a lot... + BlockRepository blockRepository = repository.getBlockRepository(); - 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 { - // Sleep for a while - Thread.sleep(1000); + wasMintingPossible = isMintingPossible; - isMintingPossible = false; + try { + // Free up any repository locks + repository.discardChanges(); - final Long now = NTP.getTime(); - if (now == null) - continue; + // Sleep for a while + Thread.sleep(1000); - final Long minLatestBlockTimestamp = Controller.getMinimumLatestBlockTimestamp(); - if (minLatestBlockTimestamp == null) - continue; + isMintingPossible = false; - // No online accounts for current timestamp? (e.g. during startup) - if (!OnlineAccountsManager.getInstance().hasOnlineAccounts()) - continue; + final Long now = NTP.getTime(); + if (now == null) + continue; - try (final Repository repository = RepositoryManager.getRepository()) { - // Going to need this a lot... - BlockRepository blockRepository = repository.getBlockRepository(); + final Long minLatestBlockTimestamp = Controller.getMinimumLatestBlockTimestamp(); + if (minLatestBlockTimestamp == null) + continue; + + // No online accounts for current timestamp? (e.g. during startup) + if (!OnlineAccountsManager.getInstance().hasOnlineAccounts()) + continue; List mintingAccountsData = repository.getAccountRepository().getMintingAccounts(); // No minting accounts? @@ -198,10 +201,6 @@ public class BlockMinter extends Thread { // so go ahead and mint a block if possible. isMintingPossible = true; - // Reattach newBlocks to new repository handle - for (Block newBlock : newBlocks) - newBlock.setRepository(repository); - // Check blockchain hasn't changed if (previousBlockData == null || !Arrays.equals(previousBlockData.getSignature(), lastBlockData.getSignature())) { previousBlockData = lastBlockData; @@ -439,13 +438,13 @@ public class BlockMinter extends Thread { Network network = Network.getInstance(); network.broadcast(broadcastPeer -> network.buildHeightMessage(broadcastPeer, newBlockData)); } - } catch (DataException e) { - LOGGER.warn("Repository issue while running block minter", e); + } catch (InterruptedException 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); } }