Skip to content

Commit 9c34144

Browse files
dzajkowskidmitry-worker
andauthored
[FIX] Fixed concurrency issue that allowed multiple miners instantiation. (#909)
* Fixed concurrency issue to ensure that only one miner is created. * Add a comment explaining the proposed change Co-authored-by: dmitry-worker <[email protected]>
1 parent b003d6c commit 9c34144

File tree

1 file changed

+22
-18
lines changed

1 file changed

+22
-18
lines changed

src/main/scala/io/iohk/ethereum/consensus/ethash/EthashConsensus.scala

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package io.iohk.ethereum
22
package consensus
33
package ethash
44

5-
import java.util.concurrent.atomic.AtomicReference
65
import akka.actor.ActorRef
76
import akka.util.Timeout
87
import io.iohk.ethereum.consensus.Protocol._
@@ -48,34 +47,39 @@ class EthashConsensus private (
4847
blockchainConfig = blockchainConfig
4948
)
5049

51-
private[this] val atomicMiner = new AtomicReference[Option[ActorRef]](None)
50+
@volatile private[this] var minerRef: Option[ActorRef] = None
5251

5352
private implicit val timeout: Timeout = 5.seconds
5453

55-
override def sendMiner(msg: MinerProtocol): Unit = {
56-
atomicMiner
57-
.get()
58-
.foreach(_ ! msg)
59-
}
54+
override def sendMiner(msg: MinerProtocol): Unit =
55+
minerRef.foreach(_ ! msg)
6056

6157
override def askMiner(msg: MinerProtocol): Task[MinerResponse] = {
62-
atomicMiner
63-
.get()
58+
minerRef
6459
.map(_.askFor[MinerResponse](msg))
6560
.getOrElse(Task.now(MinerNotExist))
6661
}
6762

63+
private[this] val mutex = new Object
64+
65+
/*
66+
* guarantees one miner instance
67+
* this should not use a atomic* construct as it has side-effects
68+
*
69+
* TODO further refactors should focus on extracting two types - one with a miner, one without - based on the config
70+
*/
6871
private[this] def startMiningProcess(node: Node): Unit = {
69-
atomicMiner.get() match {
70-
case None =>
71-
val miner = config.generic.protocol match {
72-
case Ethash | RestrictedEthash => EthashMiner(node)
73-
case MockedPow => MockedMiner(node)
72+
if (minerRef.isEmpty) {
73+
mutex.synchronized {
74+
if (minerRef.isEmpty) {
75+
val miner = config.generic.protocol match {
76+
case Ethash | RestrictedEthash => EthashMiner(node)
77+
case MockedPow => MockedMiner(node)
78+
}
79+
minerRef = Some(miner)
80+
sendMiner(MinerProtocol.StartMining)
7481
}
75-
atomicMiner.set(Some(miner))
76-
sendMiner(MinerProtocol.StartMining)
77-
78-
case _ =>
82+
}
7983
}
8084
}
8185

0 commit comments

Comments
 (0)