Skip to content

Commit 07bc1c8

Browse files
pslaskibsuieric
authored andcommitted
ETCM-670: handling checkpoint older than local best block
1 parent 6ff4db3 commit 07bc1c8

File tree

4 files changed

+31
-14
lines changed

4 files changed

+31
-14
lines changed

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ import cats.data.NonEmptyList
88
import cats.instances.option._
99
import cats.syntax.either._
1010
import io.iohk.ethereum.blockchain.sync.PeersClient._
11-
import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.{AwaitingBodiesToBeIgnored, AwaitingHeadersToBeIgnored}
12-
import io.iohk.ethereum.blockchain.sync.regular.BlockImporter.{ImportNewBlock, NewCheckpointBlock, NotOnTop, OnTop}
11+
import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.{
12+
AwaitingBodiesToBeIgnored,
13+
AwaitingHeadersToBeIgnored
14+
}
15+
import io.iohk.ethereum.blockchain.sync.regular.BlockImporter.{ImportNewBlock, NotOnTop, OnTop}
1316
import io.iohk.ethereum.blockchain.sync.regular.RegularSync.ProgressProtocol
1417
import io.iohk.ethereum.consensus.validators.BlockValidator
1518
import io.iohk.ethereum.crypto.kec256
@@ -238,12 +241,16 @@ class BlockFetcher(
238241
state.tryInsertBlock(block, peerId) match {
239242
case Left(_) if block.number <= state.lastBlock =>
240243
log.debug(
241-
s"Checkpoint block ${ByteStringUtils.hash2string(blockHash)} is older than current last block ${state.lastBlock}"
244+
s"Checkpoint block ${ByteStringUtils.hash2string(blockHash)} is older than current last block ${state.lastBlock}" +
245+
s" - clearing the queues and putting checkpoint to ready blocks queue"
242246
)
243-
state.importer ! NewCheckpointBlock(block, peerId)
247+
val newState = state
248+
.clearQueues()
249+
.enqueueReadyBlock(block, peerId)
250+
fetchBlocks(newState)
244251
case Left(_) if block.number <= state.knownTop =>
245252
log.debug(
246-
s"Checkpoint block ${ByteStringUtils.hash2string(blockHash)} not fit into queues - clearing the queues and setting new top"
253+
s"Checkpoint block ${ByteStringUtils.hash2string(blockHash)} not fit into queues - clearing the queues and setting possible new top"
247254
)
248255
val newState = state
249256
.clearQueues()

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,18 +190,21 @@ case class BlockFetcherState(
190190
def enqueueRequestedBlock(block: Block, fromPeer: PeerId): BlockFetcherState =
191191
waitingHeaders.dequeueOption
192192
.map { case (waitingHeader, waitingHeadersTail) =>
193-
if (waitingHeader.hash == block.hash)
194-
withPeerForBlocks(fromPeer, Seq(block.number))
193+
if (waitingHeader.hash == block.hash) {
194+
enqueueReadyBlock(block, fromPeer)
195195
.withPossibleNewTopAt(block.number)
196196
.copy(
197-
readyBlocks = readyBlocks.enqueue(block),
198197
waitingHeaders = waitingHeadersTail
199198
)
200-
else
199+
} else
201200
this
202201
}
203202
.getOrElse(this)
204203

204+
def enqueueReadyBlock(block: Block, fromPeer: PeerId): BlockFetcherState =
205+
withPeerForBlocks(fromPeer, Seq(block.number))
206+
.copy(readyBlocks = readyBlocks.enqueue(block))
207+
205208
def pickBlocks(amount: Int): Option[(NonEmptyList[Block], BlockFetcherState)] =
206209
if (readyBlocks.nonEmpty) {
207210
val (picked, rest) = readyBlocks.splitAt(amount)

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ class BlockImporter(
9191
}
9292
}
9393

94-
case NewCheckpointBlock(block, peerId) => importNewBlock(block, peerId, state)
95-
9694
case ImportNewBlock(block, peerId) if state.isOnTop && !state.importing => importNewBlock(block, peerId, state)
9795

9896
case ImportDone(newBehavior, importType) =>
@@ -389,7 +387,6 @@ object BlockImporter {
389387
case object NotOnTop extends ImporterMsg
390388
case class MinedBlock(block: Block) extends ImporterMsg
391389
case class NewCheckpoint(parentHash: ByteString, signatures: Seq[ECDSASignature]) extends ImporterMsg
392-
case class NewCheckpointBlock(block: Block, peerId: PeerId) extends ImporterMsg
393390
case class ImportNewBlock(block: Block, peerId: PeerId) extends ImporterMsg
394391
case class ImportDone(newBehavior: NewBehavior, blockImportType: BlockImportType) extends ImporterMsg
395392
case object PickBlocks extends ImporterMsg

src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ class BlockFetcherSpec
434434
}
435435
}
436436

437-
"should inform importer when checkpoint block is older than last block" in new TestSetup {
437+
"should put checkpoint to ready blocks when checkpoint block is older than last block" in new TestSetup {
438438
startFetcher()
439439

440440
triggerFetching(10)
@@ -469,7 +469,17 @@ class BlockFetcherSpec
469469

470470
importer.expectMsg(BlockImporter.OnTop)
471471

472-
importer.expectMsg(BlockImporter.NewCheckpointBlock(checkpointBlock, fakePeer.id))
472+
// We need to wait a while in order to allow fetcher to process all the blocks
473+
system.scheduler.scheduleOnce(Timeouts.shortTimeout) {
474+
importer.send(blockFetcher, PickBlocks(syncConfig.blocksBatchSize))
475+
}
476+
477+
importer.expectMsgPF() { case BlockFetcher.PickedBlocks(blocks) =>
478+
val headers = blocks.map(_.header).toList
479+
480+
assert(HeadersSeq.areChain(headers))
481+
assert(headers.contains(checkpointBlock.header))
482+
}
473483
}
474484

475485
"should properly handle a request timeout" in new TestSetup {

0 commit comments

Comments
 (0)