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,6 +90,10 @@ public class BlockMinter extends Thread {
List<Block> newBlocks = new ArrayList<>();
try (final Repository repository = RepositoryManager.getRepository()) {
// Going to need this a lot...
BlockRepository blockRepository = repository.getBlockRepository();
// Flags for tracking change in whether minting is possible,
// so we can notify Controller, and further update SysTray, etc.
boolean isMintingPossible = false;
@ -101,6 +105,9 @@ public class BlockMinter extends Thread {
wasMintingPossible = isMintingPossible;
try {
// Free up any repository locks
repository.discardChanges();
// Sleep for a while
Thread.sleep(1000);
@ -118,10 +125,6 @@ public class BlockMinter extends Thread {
if (!OnlineAccountsManager.getInstance().hasOnlineAccounts())
continue;
try (final Repository repository = RepositoryManager.getRepository()) {
// Going to need this a lot...
BlockRepository blockRepository = repository.getBlockRepository();
List<MintingAccountData> mintingAccountsData = repository.getAccountRepository().getMintingAccounts();
// No minting accounts?
if (mintingAccountsData.isEmpty())
@ -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,14 +438,14 @@ 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 (DataException e) {
LOGGER.warn("Repository issue while running block minter - NO LONGER MINTING", e);
}
}
/**