I'm creating a simple blockchain application, I have a method for mining new blocks and a method where I can submit mining tasks.
Here is the method that I use for submitting new tasks using ExecutorService#submit
:
public void executeCommand(int noOfStartingZero) throws ExecutionException, InterruptedException {
for (int i = 0; i < NO_OF_BLOCKS; i ) {
executor.submit(() -> {
Block prevBlock = this.blockchain.getBlocks().peekLast();
Block block = this.minerCommand.mine(prevBlock, noOfStartingZero);
System.out.println("block: " block);
String minedBy = Thread.currentThread().getName();
block.setMinedBy(minedBy);
try {
this.blockchain.addNewBlock(block);
} catch (InvalidBlockException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
}
The problem is, on this line, it always returns the same block: Block block = this.minerCommand.mine(prevBlock, noOfStartingZero);
Here is my mine()
method, each time it gets called it will create a new block:
public Block mine(Block prevBlock, int noOfStartingZero) {
if (prevBlock == null) {
return getGenesisBlock(noOfStartingZero);
}
long startTime = System.currentTimeMillis();
var block = new Block();
block.setId(prevBlock.id() 1);
block.setTimestamp(new Date().getTime());
block.setPrevHash(prevBlock.hash());
BlockHashContainer hashContainer = generateHash(block, noOfStartingZero);
block.setMagicNumber(hashContainer.getMagicNumber());
block.setHash(hashContainer.getHash());
block.setTimeGenerated((new Date().getTime() - startTime) / 1000);
return block;
}
I tried to print out the block for each iteration, and here is what I got, it always returns the first block, and no other block is added to the blockchain:
block: Block[id=1, timestamp=1632128365538, prevHash=0, hash=818b72956bdb163b5b51b848c2988378cb03bd58649511186ac9a5339d9e392c]
block: Block[id=1, timestamp=1632128365538, prevHash=0, hash=818b72956bdb163b5b51b848c2988378cb03bd58649511186ac9a5339d9e392c]
block: Block[id=1, timestamp=1632128365537, prevHash=0, hash=a840f8f7922fae5b974e1a4e286dbd7247ed19efb12629ba8b0533b117c9451d]
block: Block[id=1, timestamp=1632128365538, prevHash=0, hash=818b72956bdb163b5b51b848c2988378cb03bd58649511186ac9a5339d9e392c]
block: Block[id=1, timestamp=1632128365516, prevHash=0, hash=336385001bb8a9f7b16800fd94e09347dac1a2566bd0edfd0ea6c941b722dd4d]
Why it behaves like this? Any help would be much appreciated.
CodePudding user response:
Using an ExecutorService
to run this operation has the potential to run each iteration concurrently. This means that they can all see prevBlock
as null
before any task has the opportunity to set it. If each iteration depends on the result of the previous operation, there’s no reason to use an ExecutorService
at all. Instead, run each mining operation synchronously within the loop.