|
1 | 1 | package io.iohk.ethereum.consensus
|
2 | 2 |
|
3 | 3 | import akka.util.ByteString
|
| 4 | +import cats.implicits._ |
4 | 5 | import io.iohk.ethereum.blockchain.sync.regular.{
|
5 | 6 | BlockEnqueued,
|
6 | 7 | BlockImportFailed,
|
7 | 8 | BlockImportFailedDueToMissingNode,
|
8 | 9 | BlockImportResult,
|
9 | 10 | BlockImportedToTop,
|
10 | 11 | ChainReorganised,
|
11 |
| - DuplicateBlock, |
12 |
| - UnknownParent |
| 12 | + DuplicateBlock |
13 | 13 | }
|
14 |
| -import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError |
15 | 14 | import io.iohk.ethereum.domain.{Block, BlockHeader, BlockchainImpl, BlockchainReader, BlockchainWriter, ChainWeight}
|
16 | 15 | import io.iohk.ethereum.ledger.BlockExecutionError.{MPTError, ValidationBeforeExecError}
|
17 | 16 | import io.iohk.ethereum.ledger.BlockQueue.Leaf
|
18 | 17 | import io.iohk.ethereum.ledger.{
|
19 | 18 | BlockData,
|
20 | 19 | BlockExecution,
|
21 | 20 | BlockExecutionError,
|
| 21 | + BlockExecutionSuccess, |
22 | 22 | BlockMetrics,
|
23 | 23 | BlockQueue,
|
24 | 24 | BlockValidation
|
@@ -63,22 +63,44 @@ class ConsensusImpl(
|
63 | 63 | log.debug("Ignoring duplicated block: {}", block.idTag)
|
64 | 64 | Task.now(DuplicateBlock)
|
65 | 65 | } else {
|
66 |
| - val hash = bestBlock.header.hash |
67 |
| - blockchain.getChainWeightByHash(hash) match { |
| 66 | + blockchain.getChainWeightByHash(bestBlock.header.hash) match { |
68 | 67 | 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) |
73 | 71 | }
|
74 |
| - importResult.foreach(measureBlockMetrics) |
75 |
| - importResult |
76 | 72 | case None => returnNoTotalDifficulty(bestBlock)
|
77 | 73 | }
|
78 | 74 | }
|
79 | 75 | case None => returnNoBestBlock()
|
80 | 76 | }
|
81 | 77 |
|
| 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 | + |
82 | 104 | private def returnNoTotalDifficulty(bestBlock: Block): Task[BlockImportFailed] = {
|
83 | 105 | log.error(
|
84 | 106 | "Getting total difficulty for current best block with hash: {} failed",
|
@@ -119,24 +141,10 @@ class ConsensusImpl(
|
119 | 141 | block: Block,
|
120 | 142 | currentBestBlock: Block,
|
121 | 143 | 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) |
140 | 148 |
|
141 | 149 | /** *
|
142 | 150 | * 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(
|
188 | 196 | }
|
189 | 197 | }
|
190 | 198 |
|
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 |
| - |
219 | 199 | private def reorganiseOrEnqueue(
|
220 | 200 | block: Block,
|
221 | 201 | currentBestBlock: Block,
|
222 | 202 | 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 | + }) |
239 | 211 |
|
240 | 212 | /** Once a better branch was found this attempts to reorganise the chain
|
241 | 213 | *
|
@@ -318,7 +290,6 @@ class ConsensusImpl(
|
318 | 290 | blockchainWriter.save(block, receipts, weight, saveAsBestBlock = false)
|
319 | 291 | }
|
320 | 292 |
|
321 |
| - import cats.implicits._ |
322 | 293 | val checkpointNumber = oldBranch.collect {
|
323 | 294 | case BlockData(block, _, _) if block.hasCheckpoint => block.number
|
324 | 295 | }.maximumOption
|
|
0 commit comments