Skip to content

Commit d5ada86

Browse files
author
Leonor Boga
committed
ETCM-1058 Extract duplicated code for block pre validation
1 parent 04d6529 commit d5ada86

File tree

2 files changed

+52
-79
lines changed

2 files changed

+52
-79
lines changed

src/main/scala/io/iohk/ethereum/consensus/ConsensusImpl.scala

Lines changed: 45 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
package io.iohk.ethereum.consensus
22

33
import akka.util.ByteString
4+
import cats.implicits._
45
import io.iohk.ethereum.blockchain.sync.regular.{
56
BlockEnqueued,
67
BlockImportFailed,
78
BlockImportFailedDueToMissingNode,
89
BlockImportResult,
910
BlockImportedToTop,
1011
ChainReorganised,
11-
DuplicateBlock,
12-
UnknownParent
12+
DuplicateBlock
1313
}
14-
import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError
1514
import io.iohk.ethereum.domain.{Block, BlockHeader, BlockchainImpl, BlockchainReader, BlockchainWriter, ChainWeight}
1615
import io.iohk.ethereum.ledger.BlockExecutionError.{MPTError, ValidationBeforeExecError}
1716
import io.iohk.ethereum.ledger.BlockQueue.Leaf
1817
import io.iohk.ethereum.ledger.{
1918
BlockData,
2019
BlockExecution,
2120
BlockExecutionError,
21+
BlockExecutionSuccess,
2222
BlockMetrics,
2323
BlockQueue,
2424
BlockValidation
@@ -63,22 +63,44 @@ class ConsensusImpl(
6363
log.debug("Ignoring duplicated block: {}", block.idTag)
6464
Task.now(DuplicateBlock)
6565
} else {
66-
val hash = bestBlock.header.hash
67-
blockchain.getChainWeightByHash(hash) match {
66+
blockchain.getChainWeightByHash(bestBlock.header.hash) match {
6867
case Some(weight) =>
69-
val importResult = if (isPossibleNewBestBlock(block.header, bestBlock.header)) {
70-
importToTop(block, bestBlock, weight)
71-
} else {
72-
reorganiseOrEnqueue(block, bestBlock, weight)
68+
doBlockPreValidation(block).flatMap {
69+
case Left(error) => Task.now(BlockImportFailed(error.reason.toString))
70+
case Right(_) => handleBlockImport(block, bestBlock, weight)
7371
}
74-
importResult.foreach(measureBlockMetrics)
75-
importResult
7672
case None => returnNoTotalDifficulty(bestBlock)
7773
}
7874
}
7975
case None => returnNoBestBlock()
8076
}
8177

78+
private def handleBlockImport(block: Block, bestBlock: Block, weight: ChainWeight)(implicit
79+
blockExecutionScheduler: Scheduler,
80+
blockchainConfig: BlockchainConfig
81+
): Task[BlockImportResult] = {
82+
val importResult = if (isPossibleNewBestBlock(block.header, bestBlock.header)) {
83+
importToTop(block, bestBlock, weight)
84+
} else {
85+
reorganiseOrEnqueue(block, bestBlock, weight)
86+
}
87+
importResult.foreach(measureBlockMetrics)
88+
importResult
89+
}
90+
91+
private def doBlockPreValidation(block: Block)(implicit
92+
blockchainConfig: BlockchainConfig
93+
): Task[Either[ValidationBeforeExecError, BlockExecutionSuccess]] =
94+
Task
95+
.evalOnce {
96+
val validationResult = blockValidation.validateBlockBeforeExecution(block)
97+
validationResult.left.foreach { error =>
98+
log.error("Error while validating block with hash {} before execution: {}", block.hash, error.reason)
99+
}
100+
validationResult
101+
}
102+
.executeOn(validationScheduler)
103+
82104
private def returnNoTotalDifficulty(bestBlock: Block): Task[BlockImportFailed] = {
83105
log.error(
84106
"Getting total difficulty for current best block with hash: {} failed",
@@ -119,24 +141,10 @@ class ConsensusImpl(
119141
block: Block,
120142
currentBestBlock: Block,
121143
currentWeight: ChainWeight
122-
)(implicit blockExecutionScheduler: Scheduler, blockchainConfig: BlockchainConfig): Task[BlockImportResult] = {
123-
val validationResult =
124-
Task.evalOnce(blockValidation.validateBlockBeforeExecution(block)).executeOn(validationScheduler)
125-
val importResult =
126-
Task
127-
.evalOnce(importBlockToTop(block, currentBestBlock.header.number, currentWeight))
128-
.executeOn(blockExecutionScheduler)
129-
130-
Task.map2(validationResult, importResult) { case (validationResult, importResult) =>
131-
validationResult.fold(
132-
error => {
133-
log.error("Error while validating block before execution: {}", error.reason)
134-
handleImportTopValidationError(error, block, importResult)
135-
},
136-
_ => importResult
137-
)
138-
}
139-
}
144+
)(implicit blockExecutionScheduler: Scheduler, blockchainConfig: BlockchainConfig): Task[BlockImportResult] =
145+
Task
146+
.evalOnce(importBlockToTop(block, currentBestBlock.header.number, currentWeight))
147+
.executeOn(blockExecutionScheduler)
140148

141149
/** *
142150
* Open for discussion: this is code that was in BlockImport. Even thought is tested (before) that only one block
@@ -188,54 +196,18 @@ class ConsensusImpl(
188196
}
189197
}
190198

191-
private def handleImportTopValidationError(
192-
error: ValidationBeforeExecError,
193-
block: Block,
194-
blockImportResult: BlockImportResult
195-
): BlockImportResult = {
196-
blockImportResult match {
197-
case BlockImportedToTop(blockImportData) =>
198-
blockImportData.foreach { blockData =>
199-
val hash = blockData.block.header.hash
200-
blockQueue.removeSubtree(hash)
201-
blockchain.removeBlock(hash, withState = true)
202-
}
203-
case _ => ()
204-
}
205-
handleBlockValidationError(error, block)
206-
}
207-
208-
private def handleBlockValidationError(error: ValidationBeforeExecError, block: Block): BlockImportResult =
209-
error match {
210-
case ValidationBeforeExecError(HeaderParentNotFoundError) =>
211-
log.debug(s"Block(${block.idTag}) has unknown parent")
212-
UnknownParent
213-
214-
case ValidationBeforeExecError(reason) =>
215-
log.debug(s"Block(${block.idTag}) failed pre-import validation")
216-
BlockImportFailed(reason.toString)
217-
}
218-
219199
private def reorganiseOrEnqueue(
220200
block: Block,
221201
currentBestBlock: Block,
222202
currentWeight: ChainWeight
223-
)(implicit blockExecutionScheduler: Scheduler, blockchainConfig: BlockchainConfig): Task[BlockImportResult] =
224-
Task.evalOnce {
225-
blockValidation
226-
.validateBlockBeforeExecution(block)
227-
.fold(
228-
error => handleBlockValidationError(error, block),
229-
_ =>
230-
blockQueue.enqueueBlock(block, currentBestBlock.header.number) match {
231-
case Some(Leaf(leafHash, leafWeight)) if leafWeight > currentWeight =>
232-
reorganiseChainFromQueue(leafHash)
233-
234-
case _ =>
235-
BlockEnqueued
236-
}
237-
)
238-
}
203+
)(implicit blockchainConfig: BlockchainConfig): Task[BlockImportResult] =
204+
Task.evalOnce(blockQueue.enqueueBlock(block, currentBestBlock.header.number) match {
205+
case Some(Leaf(leafHash, leafWeight)) if leafWeight > currentWeight =>
206+
reorganiseChainFromQueue(leafHash)
207+
208+
case _ =>
209+
BlockEnqueued
210+
})
239211

240212
/** Once a better branch was found this attempts to reorganise the chain
241213
*
@@ -318,7 +290,6 @@ class ConsensusImpl(
318290
blockchainWriter.save(block, receipts, weight, saveAsBestBlock = false)
319291
}
320292

321-
import cats.implicits._
322293
val checkpointNumber = oldBranch.collect {
323294
case BlockData(block, _, _) if block.hasCheckpoint => block.number
324295
}.maximumOption

src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import io.iohk.ethereum.blockchain.sync.regular.{
88
BlockImportFailed,
99
BlockImportedToTop,
1010
ChainReorganised,
11-
DuplicateBlock,
12-
UnknownParent
11+
DuplicateBlock
1312
}
1413
import io.iohk.ethereum.consensus.mining._
1514
import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderDifficultyError, HeaderParentNotFoundError}
@@ -26,7 +25,7 @@ import io.iohk.ethereum.ledger.{
2625
OmmersTestSetup,
2726
TestSetupWithVmAndValidators
2827
}
29-
import io.iohk.ethereum.mpt.{LeafNode, MerklePatriciaTrie, NullNode}
28+
import io.iohk.ethereum.mpt.{LeafNode, MerklePatriciaTrie}
3029
import io.iohk.ethereum.utils.BlockchainConfig
3130
import org.scalatest.concurrent.ScalaFutures
3231
import org.scalatest.flatspec.AnyFlatSpec
@@ -245,7 +244,8 @@ class ConsensusSpec extends AnyFlatSpec with Matchers with ScalaFutures {
245244
blockchainWriter.save(blockData2.block, blockData2.receipts, blockData2.weight, saveAsBestBlock = true)
246245
blockchainWriter.save(blockData3.block, blockData3.receipts, blockData3.weight, saveAsBestBlock = true)
247246

248-
//saving to cache the value of the best block from the initial chain. This recreates the bug ETCM-626, where (possibly) because of the thread of execution
247+
// saving to cache the value of the best block from the initial chain. This recreates the bug ETCM-626,
248+
// where (possibly) because of the thread of execution
249249
// dying before updating the storage but after updating the cache, inconsistency is created
250250
blockchain.saveBestKnownBlocks(oldBlock4.number)
251251

@@ -311,7 +311,9 @@ class ConsensusSpec extends AnyFlatSpec with Matchers with ScalaFutures {
311311
.expects(newBlock.header, *, *)
312312
.returning(Left(HeaderParentNotFoundError))
313313

314-
whenReady(consensus.evaluateBranchBlock(newBlock).runToFuture)(_ shouldEqual UnknownParent)
314+
whenReady(consensus.evaluateBranchBlock(newBlock).runToFuture)(
315+
_ shouldEqual BlockImportFailed("HeaderParentNotFoundError")
316+
)
315317
}
316318

317319
it should "validate blocks prior to import" in new ImportBlockTestSetup {

0 commit comments

Comments
 (0)