Skip to content

Commit 25c3966

Browse files
author
Leonor Boga
authored
[ETCM-709] Improve ommers validations (#948)
Replaced OmmersAncestorsError by more specific OmmerIsAncestorError and OmmerParentIsNotAncestorError. Renamed OmmersNotValidError to OmmersHeaderError and added the underlying reason for failure Refactored validateOmmersAncestors method. Refactored validateOmmersHeaders method to not hide the underlying failing reason. Reorganized some packages because some classes were not in the correct package and/or the Spec was not in the correct package. Renamed some specs to better reflect the class being tested
1 parent 219b958 commit 25c3966

33 files changed

+238
-123
lines changed

src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package io.iohk.ethereum.ets.blockchain
22

33
import akka.util.ByteString
44
import io.iohk.ethereum.consensus.Protocol
5-
import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor
5+
import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor
66
import io.iohk.ethereum.domain.{Address, UInt256}
77
import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, MonetaryPolicyConfig}
88
import org.bouncycastle.util.encoders.Hex

src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package io.iohk.ethereum.ets.blockchain
33
import akka.util.ByteString
44
import io.iohk.ethereum.consensus.Protocol.NoAdditionalEthashData
55
import io.iohk.ethereum.consensus.ethash.EthashConsensus
6-
import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor
6+
import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor
77
import io.iohk.ethereum.consensus.{ConsensusConfig, FullConsensusConfig, TestConsensus, ethash}
88
import io.iohk.ethereum.db.components.Storages.PruningModeComponent
99
import io.iohk.ethereum.db.components.{EphemDataSourceComponent, Storages}
@@ -18,6 +18,7 @@ import io.iohk.ethereum.utils.BigIntExtensionMethods._
1818
import io.iohk.ethereum.utils.{BlockchainConfig, Config}
1919
import monix.execution.Scheduler
2020
import org.bouncycastle.util.encoders.Hex
21+
2122
import scala.util.{Failure, Success, Try}
2223

2324
object ScenarioSetup {

src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import io.iohk.ethereum.blockchain.sync.regular.{BlockFetcher, BlockImporter}
88
import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers
99
import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack}
1010
import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator
11-
import io.iohk.ethereum.consensus.ethash.validators.{OmmersValidator, StdOmmersValidator}
11+
import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator
1212
import io.iohk.ethereum.consensus.validators.Validators
13+
import io.iohk.ethereum.consensus.validators.std.StdOmmersValidator
1314
import io.iohk.ethereum.domain._
1415
import io.iohk.ethereum.mpt.MerklePatriciaTrie
1516
import io.iohk.ethereum.utils.Config.SyncConfig
@@ -74,7 +75,7 @@ class BlockImporterItSpec
7475
getBlockHeaderByHash: GetBlockHeaderByHash,
7576
getNBlocksBack: GetNBlocksBack
7677
) =>
77-
new StdOmmersValidator(blockchainConfig, blockHeaderValidator)
78+
new StdOmmersValidator(blockHeaderValidator)
7879
.validate(parentHash, blockNumber, ommers, getBlockHeaderByHash, getNBlocksBack)
7980
}
8081

src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,12 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
152152
_ <- peer1.waitForRegularSyncLoadLastBlock(length)
153153
} yield {
154154
assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash)
155-
assert(peer1.bl.getBestBlock().get.number == peer2.bl.getBestBlock().get.number && peer1.bl.getBestBlock().get.number == length)
155+
assert(
156+
peer1.bl.getBestBlock().get.number == peer2.bl.getBestBlock().get.number && peer1.bl
157+
.getBestBlock()
158+
.get
159+
.number == length
160+
)
156161
assert(peer1.bl.getLatestCheckpointBlockNumber() == peer2.bl.getLatestCheckpointBlockNumber())
157162
}
158163
}

src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed
77
import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast.BlockToBroadcast
88
import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcasterActor.BroadcastBlock
99
import io.iohk.ethereum.blockchain.sync.regular.BlockImporter.Start
10-
import io.iohk.ethereum.blockchain.sync.regular.{BlockBroadcast, BlockBroadcasterActor, BlockFetcher, BlockImporter, RegularSync}
10+
import io.iohk.ethereum.blockchain.sync.regular.{
11+
BlockBroadcast,
12+
BlockBroadcasterActor,
13+
BlockFetcher,
14+
BlockImporter,
15+
RegularSync
16+
}
1117
import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint
1218
import io.iohk.ethereum.blockchain.sync.{PeersClient, SyncProtocol}
1319
import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers
@@ -96,7 +102,8 @@ object RegularSyncItSpecUtils {
96102
broadcasterRef,
97103
pendingTransactionsManager,
98104
regularSync
99-
))
105+
)
106+
)
100107

101108
lazy val regularSync = system.actorOf(
102109
RegularSync.props(

src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class BlockFetcher(
9898

9999
private def handleCommands(state: BlockFetcherState): Receive = {
100100
case PickBlocks(amount) => state.pickBlocks(amount) |> handlePickedBlocks(state) |> fetchBlocks
101+
101102
case StrictPickBlocks(from, atLeastWith) =>
102103
// FIXME: Consider having StrictPickBlocks calls guaranteeing this
103104
// from parameter could be negative or 0 so we should cap it to 1 if that's the case
@@ -113,6 +114,7 @@ class BlockFetcher(
113114
}
114115

115116
fetchBlocks(newState)
117+
116118
case InvalidateBlocksFrom(blockNr, reason, withBlacklist) =>
117119
val (blockProvider, newState) = state.invalidateBlocksFrom(blockNr, withBlacklist)
118120
log.debug("Invalidate blocks from {}", blockNr)
@@ -157,7 +159,7 @@ class BlockFetcher(
157159

158160
private def handleBodiesMessages(state: BlockFetcherState): Receive = {
159161
case Response(peer, BlockBodies(bodies)) if state.isFetchingBodies =>
160-
log.debug(s"Received ${bodies.size} block bodies")
162+
log.debug("Received {} block bodies", bodies.size)
161163
if (state.fetchingBodiesState == AwaitingBodiesToBeIgnored) {
162164
log.debug("Block bodies will be ignored due to an invalidation was requested for them")
163165
fetchBlocks(state.withBodiesFetchReceived)
@@ -171,9 +173,10 @@ class BlockFetcher(
171173
state.withBodiesFetchReceived.handleRequestedBlocks(newBlocks, peer.id)
172174
}
173175
val waitingHeadersDequeued = state.waitingHeaders.size - newState.waitingHeaders.size
174-
log.debug(s"Processed $waitingHeadersDequeued new blocks from received block bodies")
176+
log.debug("Processed {} new blocks from received block bodies", waitingHeadersDequeued)
175177
fetchBlocks(newState)
176178
}
179+
177180
case RetryBodiesRequest if state.isFetchingBodies =>
178181
log.debug("Something failed on a bodies request, cancelling the request and re-fetching")
179182
val newState = state.withBodiesFetchReceived
@@ -182,8 +185,10 @@ class BlockFetcher(
182185

183186
private def handleStateNodeMessages(state: BlockFetcherState): Receive = {
184187
case FetchStateNode(hash) => fetchStateNode(hash, sender(), state)
188+
185189
case RetryFetchStateNode if state.isFetchingStateNode =>
186190
state.stateNodeFetcher.foreach(fetcher => fetchStateNode(fetcher.hash, fetcher.replyTo, state))
191+
187192
case Response(peer, NodeData(values)) if state.isFetchingStateNode =>
188193
log.debug("Received state node response from peer {}", peer)
189194
state.stateNodeFetcher.foreach(fetcher => {
@@ -215,10 +220,13 @@ class BlockFetcher(
215220
}
216221
supervisor ! ProgressProtocol.GotNewBlock(newState.knownTop)
217222
fetchBlocks(newState)
223+
218224
case MessageFromPeer(CommonMessages.NewBlock(block, _), peerId) =>
219225
handleNewBlock(block, peerId, state)
226+
220227
case MessageFromPeer(PV64.NewBlock(block, _), peerId) =>
221228
handleNewBlock(block, peerId, state)
229+
222230
case BlockImportFailed(blockNr, reason) =>
223231
val (peerId, newState) = state.invalidateBlocksFrom(blockNr)
224232
peerId.foreach(id => peersClient ! BlacklistPeer(id, reason))
@@ -259,8 +267,9 @@ class BlockFetcher(
259267
state.tryInsertBlock(block, peerId) match {
260268
case Left(_) if block.number <= state.lastBlock =>
261269
log.debug(
262-
s"Checkpoint block ${ByteStringUtils.hash2string(blockHash)} is older than current last block ${state.lastBlock}" +
263-
s" - clearing the queues and putting checkpoint to ready blocks queue"
270+
"Checkpoint block {} is older than current last block {} - clearing the queues and putting checkpoint to ready blocks queue",
271+
ByteStringUtils.hash2string(blockHash),
272+
state.lastBlock
264273
)
265274
val newState = state
266275
.clearQueues()
@@ -279,7 +288,7 @@ class BlockFetcher(
279288
log.debug(error)
280289
handleFutureBlock(block, state)
281290
case Right(state) =>
282-
log.debug(s"Checkpoint block [${ByteStringUtils.hash2string(blockHash)}] fit into queues")
291+
log.debug("Checkpoint block [{}] fit into queues", ByteStringUtils.hash2string(blockHash))
283292
fetchBlocks(state)
284293
}
285294
}
@@ -289,20 +298,20 @@ class BlockFetcher(
289298
//ex. After a successful handshake, fetcher will receive the info about the header of the peer best block
290299
case MessageFromPeer(BlockHeaders(headers), _) =>
291300
headers.lastOption.map { bh =>
292-
log.debug(s"Candidate for new top at block ${bh.number}, current known top ${state.knownTop}")
301+
log.debug("Candidate for new top at block {}, current known top {}", bh.number, state.knownTop)
293302
val newState = state.withPossibleNewTopAt(bh.number)
294303
fetchBlocks(newState)
295304
}
296305
//keep fetcher state updated in case new mined block was imported
297306
case InternalLastBlockImport(blockNr) =>
298-
log.debug(s"New mined block $blockNr imported from the inside")
307+
log.debug("New mined block {} imported from the inside", blockNr)
299308
val newState = state.withLastBlock(blockNr).withPossibleNewTopAt(blockNr)
300309

301310
fetchBlocks(newState)
302311

303312
//keep fetcher state updated in case new checkpoint block was imported
304313
case InternalCheckpointImport(blockNr) =>
305-
log.debug(s"New checkpoint block $blockNr imported from the inside")
314+
log.debug("New checkpoint block {} imported from the inside", blockNr)
306315

307316
val newState = state
308317
.clearQueues()
@@ -414,13 +423,16 @@ class BlockFetcher(
414423

415424
private def handleRequestResult(fallback: FetchMsg)(msg: Any): Task[Any] = msg match {
416425
case failed: RequestFailed =>
417-
log.debug("Request failed due to {}", failed)
426+
log.warning("Request failed due to {}", failed)
418427
Task.now(fallback)
428+
419429
case NoSuitablePeer =>
420430
Task.now(fallback).delayExecution(syncConfig.syncRetryInterval)
431+
421432
case Failure(cause) =>
422433
log.error(cause, "Unexpected error on the request result")
423434
Task.now(fallback)
435+
424436
case m =>
425437
Task.now(m)
426438
}

src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ import io.iohk.ethereum.network.PeerId
1515
import io.iohk.ethereum.ommers.OmmersPool.AddOmmers
1616
import io.iohk.ethereum.transactions.PendingTransactionsManager
1717
import io.iohk.ethereum.transactions.PendingTransactionsManager.{AddUncheckedTransactions, RemoveTransactions}
18+
import io.iohk.ethereum.utils.ByteStringUtils
1819
import io.iohk.ethereum.utils.Config.SyncConfig
1920
import io.iohk.ethereum.utils.FunctorOps._
2021
import monix.eval.Task
2122
import monix.execution.Scheduler
23+
import org.bouncycastle.util.encoders.Hex
2224

2325
import scala.concurrent.duration._
2426

@@ -207,7 +209,12 @@ class BlockImporter(
207209
tryImportBlocks(restOfBlocks, importedBlocks)
208210

209211
case err @ (UnknownParent | BlockImportFailed(_)) =>
210-
log.error("Block {} import failed", blocks.head.number)
212+
log.error(
213+
"Block {} import failed, with hash {} and parent hash {}",
214+
blocks.head.number,
215+
blocks.head.header.hashAsHexString,
216+
ByteStringUtils.hash2string(blocks.head.header.parentHash)
217+
)
211218
Task.now((importedBlocks, Some(err)))
212219
}
213220
.onErrorHandle {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package io.iohk.ethereum.consensus
22

33
import io.iohk.ethereum.consensus.Protocol.{NoAdditionalEthashData, RestrictedEthashMinerData}
44
import io.iohk.ethereum.consensus.ethash.EthashConsensus
5-
import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor
5+
import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor
66
import io.iohk.ethereum.nodebuilder._
77
import io.iohk.ethereum.utils.{Config, Logger}
88

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@ import io.iohk.ethereum.consensus.ethash.blocks.{
1313
EthashBlockGeneratorImpl,
1414
RestrictedEthashBlockGeneratorImpl
1515
}
16-
import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor
1716
import io.iohk.ethereum.consensus.validators.Validators
17+
import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor
1818
import io.iohk.ethereum.domain.BlockchainImpl
1919
import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps
2020
import io.iohk.ethereum.ledger.BlockPreparator
2121
import io.iohk.ethereum.ledger.Ledger.VMImpl
2222
import io.iohk.ethereum.nodebuilder.Node
2323
import io.iohk.ethereum.utils.{BlockchainConfig, Logger}
2424
import monix.eval.Task
25+
2526
import scala.concurrent.duration._
2627

2728
/**

src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/EthashBlockGenerator.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import akka.util.ByteString
55
import io.iohk.ethereum.consensus.ConsensusConfig
66
import io.iohk.ethereum.consensus.blocks._
77
import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator
8-
import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor
98
import io.iohk.ethereum.crypto.kec256
109
import io.iohk.ethereum.domain._
1110
import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy}
1211
import io.iohk.ethereum.utils.BlockchainConfig
1312
import io.iohk.ethereum.consensus.ConsensusMetrics
13+
import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor
1414

1515
/** Internal API, used for testing (especially mocks) */
1616
trait EthashBlockGenerator extends TestBlockGenerator {

src/main/scala/io/iohk/ethereum/consensus/ethash/blocks/RestrictedEthashBlockGeneratorImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import io.iohk.ethereum.consensus.ConsensusConfig
44
import io.iohk.ethereum.consensus.blocks.{BlockTimestampProvider, DefaultBlockTimestampProvider, PendingBlockAndState}
55
import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator
66
import io.iohk.ethereum.consensus.ethash.RestrictedEthashSigner
7-
import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor
87
import io.iohk.ethereum.domain.{Address, Block, Blockchain, SignedTransaction}
98
import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy}
109
import io.iohk.ethereum.utils.BlockchainConfig
1110
import org.bouncycastle.crypto.AsymmetricCipherKeyPair
1211
import io.iohk.ethereum.consensus.ConsensusMetrics
12+
import io.iohk.ethereum.consensus.validators.std.ValidatorsExecutor
1313

1414
class RestrictedEthashBlockGeneratorImpl(
1515
validators: ValidatorsExecutor,

src/main/scala/io/iohk/ethereum/consensus/ethash/validators/OmmersValidator.scala

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

33
import akka.util.ByteString
44
import io.iohk.ethereum.consensus.ethash.validators.OmmersValidator.{OmmersError, OmmersValid}
5+
import io.iohk.ethereum.consensus.validators.BlockHeaderError
56
import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack}
67
import io.iohk.ethereum.domain.{Block, BlockHeader, Blockchain}
78

@@ -36,9 +37,10 @@ object OmmersValidator {
3637

3738
object OmmersError {
3839
case object OmmersLengthError extends OmmersError
39-
case object OmmersNotValidError extends OmmersError
40+
case class OmmersHeaderError(errors: List[BlockHeaderError]) extends OmmersError
4041
case object OmmersUsedBeforeError extends OmmersError
41-
case object OmmersAncestorsError extends OmmersError
42+
case object OmmerIsAncestorError extends OmmersError
43+
case object OmmerParentIsNotAncestorError extends OmmersError
4244
case object OmmersDuplicatedError extends OmmersError
4345
}
4446

0 commit comments

Comments
 (0)