Skip to content

Commit c340728

Browse files
authored
Etcm 175 sync reporting issues (#735)
1 parent 635f002 commit c340728

38 files changed

+1316
-574
lines changed

build.sbt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,10 @@ addCommandAlias(
158158
addCommandAlias(
159159
"pp",
160160
""";compile-all
161-
|;test
161+
|;scalafmtAll
162162
|;scalastyle
163163
|;test:scalastyle
164+
|;test
165+
|;it:test
164166
|""".stripMargin
165167
)

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package io.iohk.ethereum.sync.util
33
import akka.util.ByteString
44
import cats.effect.Resource
55
import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed
6-
import io.iohk.ethereum.blockchain.sync.FastSync
6+
import io.iohk.ethereum.blockchain.sync.{FastSync, SyncProtocol}
77
import io.iohk.ethereum.blockchain.sync.FastSync.SyncState
88
import io.iohk.ethereum.crypto.kec256
99
import io.iohk.ethereum.domain.Address
@@ -37,7 +37,7 @@ object FastSyncItSpecUtils {
3737
)
3838

3939
def startFastSync(): Task[Unit] = Task {
40-
fastSync ! FastSync.Start
40+
fastSync ! SyncProtocol.Start
4141
}
4242

4343
def waitForFastSyncFinish(): Task[Boolean] = {
@@ -96,7 +96,18 @@ object FastSyncItSpecUtils {
9696
val currentBest = bl.getBestBlock().header
9797
val safeTarget = currentBest.number + syncConfig.fastSyncBlockValidationX
9898
val nextToValidate = currentBest.number + 1
99-
val syncState = SyncState(currentBest, safeTarget, Seq(), Seq(), 0, 0, currentBest.number, nextToValidate)
99+
val syncState =
100+
SyncState(
101+
pivotBlock = currentBest,
102+
lastFullBlockNumber = currentBest.number,
103+
safeDownloadTarget = safeTarget,
104+
blockBodiesQueue = Seq(),
105+
receiptsQueue = Seq(),
106+
downloadedNodesCount = 0,
107+
totalNodesCount = 0,
108+
bestBlockHeaderNumber = currentBest.number,
109+
nextBlockToFullyValidate = nextToValidate
110+
)
100111
storagesInstance.storages.fastSyncStateStorage.putSyncState(syncState)
101112
}.map(_ => ())
102113
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import akka.actor.ActorRef
44
import akka.util.ByteString
55
import cats.effect.Resource
66
import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed
7-
import io.iohk.ethereum.blockchain.sync.PeersClient
7+
import io.iohk.ethereum.blockchain.sync.{PeersClient, SyncProtocol}
88
import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcasterActor.BroadcastBlock
99
import io.iohk.ethereum.blockchain.sync.regular.RegularSync
1010
import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator
@@ -80,7 +80,7 @@ object RegularSyncItSpecUtils {
8080
)
8181

8282
def startRegularSync(): Task[Unit] = Task {
83-
regularSync ! RegularSync.Start
83+
regularSync ! SyncProtocol.Start
8484
}
8585

8686
def broadcastBlock(
@@ -116,7 +116,7 @@ object RegularSyncItSpecUtils {
116116
val currentWolrd = getMptForBlock(block)
117117
val (newBlock, newTd, newWorld) =
118118
createChildBlock(block, currentTd, currentWolrd, plusDifficulty)(updateWorldForBlock)
119-
regularSync ! RegularSync.MinedBlock(newBlock)
119+
regularSync ! SyncProtocol.MinedBlock(newBlock)
120120
}
121121

122122
def mineNewBlocks(delay: FiniteDuration, nBlocks: Int)(

src/main/resources/application.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,8 @@ mantis {
543543
}
544544

545545
async {
546+
ask-timeout = 100.millis
547+
546548
dispatchers {
547549
block-forger {
548550
type = Dispatcher

src/main/scala/io/iohk/ethereum/blockchain/sync/FastSync.scala

Lines changed: 79 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import cats.data.NonEmptyList
77
import io.iohk.ethereum.blockchain.sync.FastSyncReceiptsValidator.ReceiptsValidationResult
88
import io.iohk.ethereum.blockchain.sync.PeerRequestHandler.ResponseReceived
99
import io.iohk.ethereum.blockchain.sync.SyncBlocksValidator.BlockBodyValidationResult
10+
import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress
1011
import io.iohk.ethereum.blockchain.sync.SyncStateSchedulerActor.{
1112
RestartRequested,
1213
StartSyncingTo,
@@ -26,7 +27,7 @@ import io.iohk.ethereum.utils.Config.SyncConfig
2627
import org.bouncycastle.util.encoders.Hex
2728
import scala.annotation.tailrec
2829
import scala.concurrent.ExecutionContext.Implicits.global
29-
import scala.concurrent.duration.{FiniteDuration, _}
30+
import scala.concurrent.duration._
3031
import scala.util.Random
3132

3233
// scalastyle:off file.size.limit
@@ -55,8 +56,10 @@ class FastSync(
5556

5657
def handleCommonMessages: Receive = handlePeerListMessages orElse handleBlacklistMessages
5758

58-
def idle: Receive = handleCommonMessages orElse { case Start =>
59-
start()
59+
def idle: Receive = handleCommonMessages orElse {
60+
case SyncProtocol.Start =>
61+
start()
62+
case SyncProtocol.GetStatus => sender() ! SyncProtocol.Status.NotSyncing
6063
}
6164

6265
def start(): Unit = {
@@ -82,22 +85,24 @@ class FastSync(
8285
context become waitingForPivotBlock
8386
}
8487

85-
def waitingForPivotBlock: Receive = handleCommonMessages orElse { case PivotBlockSelector.Result(pivotBlockHeader) =>
86-
if (pivotBlockHeader.number < 1) {
87-
log.info("Unable to start block synchronization in fast mode: pivot block is less than 1")
88-
appStateStorage.fastSyncDone().commit()
89-
context become idle
90-
syncController ! Done
91-
} else {
92-
val initialSyncState =
93-
SyncState(
94-
pivotBlockHeader,
95-
safeDownloadTarget = pivotBlockHeader.number + syncConfig.fastSyncBlockValidationX
96-
)
97-
val syncingHandler = new SyncingHandler(initialSyncState)
98-
context.become(syncingHandler.receive)
99-
syncingHandler.processSyncing()
100-
}
88+
def waitingForPivotBlock: Receive = handleCommonMessages orElse {
89+
case SyncProtocol.GetStatus => sender() ! SyncProtocol.Status.NotSyncing
90+
case PivotBlockSelector.Result(pivotBlockHeader) =>
91+
if (pivotBlockHeader.number < 1) {
92+
log.info("Unable to start block synchronization in fast mode: pivot block is less than 1")
93+
appStateStorage.fastSyncDone().commit()
94+
context become idle
95+
syncController ! Done
96+
} else {
97+
val initialSyncState =
98+
SyncState(
99+
pivotBlockHeader,
100+
safeDownloadTarget = pivotBlockHeader.number + syncConfig.fastSyncBlockValidationX
101+
)
102+
val syncingHandler = new SyncingHandler(initialSyncState)
103+
context.become(syncingHandler.receive)
104+
syncingHandler.processSyncing()
105+
}
101106
}
102107

103108
// scalastyle:off number.of.methods
@@ -140,8 +145,14 @@ class FastSync(
140145
private val heartBeat =
141146
scheduler.scheduleWithFixedDelay(syncRetryInterval, syncRetryInterval * 2, self, ProcessSyncing)
142147

143-
def receive: Receive = handleCommonMessages orElse {
144-
case UpdatePivotBlock(state) => updatePivotBlock(state)
148+
def handleStatus: Receive = {
149+
case SyncProtocol.GetStatus => sender() ! currentSyncingStatus
150+
case SyncStateSchedulerActor.StateSyncStats(saved, missing) =>
151+
syncState = syncState.copy(downloadedNodesCount = saved, totalNodesCount = (saved + missing))
152+
}
153+
154+
def receive: Receive = handleCommonMessages orElse handleStatus orElse {
155+
case UpdatePivotBlock(reason) => updatePivotBlock(reason)
145156
case WaitingForNewTargetBlock =>
146157
log.info("State sync stopped until receiving new pivot block")
147158
updatePivotBlock(ImportedLastBlock)
@@ -200,7 +211,8 @@ class FastSync(
200211

201212
def reScheduleAskForNewPivot(updateReason: PivotBlockUpdateReason): Unit = {
202213
syncState = syncState.copy(pivotBlockUpdateFailures = syncState.pivotBlockUpdateFailures + 1)
203-
scheduler.scheduleOnce(syncConfig.pivotBlockReScheduleInterval, self, UpdatePivotBlock(updateReason))
214+
scheduler
215+
.scheduleOnce(syncConfig.pivotBlockReScheduleInterval, self, UpdatePivotBlock(updateReason))
204216
}
205217

206218
private def stalePivotAfterRestart(
@@ -219,23 +231,33 @@ class FastSync(
219231
newPivot.number >= currentState.pivotBlock.number && !stalePivotAfterRestart(newPivot, currentState, updateReason)
220232
}
221233

222-
def waitingForPivotBlockUpdate(updateReason: PivotBlockUpdateReason): Receive = handleCommonMessages orElse {
223-
case PivotBlockSelector.Result(pivotBlockHeader)
224-
if newPivotIsGoodEnough(pivotBlockHeader, syncState, updateReason) =>
225-
log.info(s"New pivot block with number ${pivotBlockHeader.number} received")
226-
updatePivotSyncState(updateReason, pivotBlockHeader)
227-
context become this.receive
228-
processSyncing()
234+
def waitingForPivotBlockUpdate(updateReason: PivotBlockUpdateReason): Receive =
235+
handleCommonMessages orElse handleStatus orElse {
236+
case PivotBlockSelector.Result(pivotBlockHeader)
237+
if newPivotIsGoodEnough(pivotBlockHeader, syncState, updateReason) =>
238+
log.info(s"New pivot block with number ${pivotBlockHeader.number} received")
239+
updatePivotSyncState(updateReason, pivotBlockHeader)
240+
context become this.receive
241+
processSyncing()
229242

230-
case PivotBlockSelector.Result(pivotBlockHeader)
231-
if !newPivotIsGoodEnough(pivotBlockHeader, syncState, updateReason) =>
232-
log.info("Received pivot block is older than old one, re-scheduling asking for new one")
233-
reScheduleAskForNewPivot(updateReason)
243+
case PivotBlockSelector.Result(pivotBlockHeader)
244+
if !newPivotIsGoodEnough(pivotBlockHeader, syncState, updateReason) =>
245+
log.info("Received pivot block is older than old one, re-scheduling asking for new one")
246+
reScheduleAskForNewPivot(updateReason)
234247

235-
case PersistSyncState => persistSyncState()
248+
case PersistSyncState => persistSyncState()
236249

237-
case UpdatePivotBlock(state) => updatePivotBlock(state)
238-
}
250+
case UpdatePivotBlock(state) => updatePivotBlock(state)
251+
}
252+
253+
def currentSyncingStatus: SyncProtocol.Status =
254+
SyncProtocol.Status.Syncing(
255+
initialSyncState.lastFullBlockNumber,
256+
Progress(syncState.lastFullBlockNumber, syncState.pivotBlock.number),
257+
Some(
258+
Progress(syncState.downloadedNodesCount, syncState.totalNodesCount.max(1))
259+
) //There's always at least one state root to fetch
260+
)
239261

240262
private def updatePivotBlock(updateReason: PivotBlockUpdateReason): Unit = {
241263
if (syncState.pivotBlockUpdateFailures <= syncConfig.maximumTargetUpdateFailures) {
@@ -745,24 +767,26 @@ class FastSync(
745767
def fullySynced: Boolean = {
746768
syncState.isBlockchainWorkFinished && assignedHandlers.isEmpty && syncState.stateSyncFinished
747769
}
748-
}
749770

750-
private def updateBestBlockIfNeeded(receivedHashes: Seq[ByteString]): Unit = {
751-
val fullBlocks = receivedHashes.flatMap { hash =>
752-
for {
753-
header <- blockchain.getBlockHeaderByHash(hash)
754-
_ <- blockchain.getBlockBodyByHash(hash)
755-
_ <- blockchain.getReceiptsByHash(hash)
756-
} yield header
757-
}
771+
private def updateBestBlockIfNeeded(receivedHashes: Seq[ByteString]): Unit = {
772+
val fullBlocks = receivedHashes.flatMap { hash =>
773+
for {
774+
header <- blockchain.getBlockHeaderByHash(hash)
775+
_ <- blockchain.getBlockBodyByHash(hash)
776+
_ <- blockchain.getReceiptsByHash(hash)
777+
} yield header
778+
}
758779

759-
if (fullBlocks.nonEmpty) {
760-
val bestReceivedBlock = fullBlocks.maxBy(_.number)
761-
if (appStateStorage.getBestBlockNumber() < bestReceivedBlock.number) {
762-
appStateStorage.putBestBlockNumber(bestReceivedBlock.number).commit()
780+
if (fullBlocks.nonEmpty) {
781+
val bestReceivedBlock = fullBlocks.maxBy(_.number)
782+
val lastStoredBestBlockNumber = appStateStorage.getBestBlockNumber()
783+
if (lastStoredBestBlockNumber < bestReceivedBlock.number) {
784+
appStateStorage.putBestBlockNumber(bestReceivedBlock.number).commit()
785+
}
786+
syncState = syncState.copy(lastFullBlockNumber = bestReceivedBlock.number.max(lastStoredBestBlockNumber))
763787
}
764-
}
765788

789+
}
766790
}
767791
}
768792

@@ -794,7 +818,7 @@ object FastSync {
794818
)
795819
)
796820

797-
private case class UpdatePivotBlock(state: PivotBlockUpdateReason)
821+
private case class UpdatePivotBlock(reason: PivotBlockUpdateReason)
798822
private case object ProcessSyncing
799823

800824
private[sync] case object PersistSyncState
@@ -803,11 +827,12 @@ object FastSync {
803827

804828
case class SyncState(
805829
pivotBlock: BlockHeader,
830+
lastFullBlockNumber: BigInt = 0,
806831
safeDownloadTarget: BigInt = 0,
807832
blockBodiesQueue: Seq[ByteString] = Nil,
808833
receiptsQueue: Seq[ByteString] = Nil,
809-
downloadedNodesCount: Int = 0,
810-
totalNodesCount: Int = 0,
834+
downloadedNodesCount: Long = 0,
835+
totalNodesCount: Long = 0,
811836
bestBlockHeaderNumber: BigInt = 0,
812837
nextBlockToFullyValidate: BigInt = 1,
813838
pivotBlockUpdateFailures: Int = 0,
@@ -846,9 +871,8 @@ object FastSync {
846871
updatingPivotBlock = false
847872
)
848873

849-
def isBlockchainWorkFinished: Boolean = {
874+
def isBlockchainWorkFinished: Boolean =
850875
bestBlockHeaderNumber >= safeDownloadTarget && !blockChainWorkQueued
851-
}
852876
}
853877

854878
sealed trait HashType {
@@ -860,17 +884,12 @@ object FastSync {
860884
case class EvmCodeHash(v: ByteString) extends HashType
861885
case class StorageRootHash(v: ByteString) extends HashType
862886

863-
case object Start
864887
case object Done
865888

866889
sealed abstract class HeaderProcessingResult
867-
868890
case object HeadersProcessingFinished extends HeaderProcessingResult
869-
870891
case class ParentDifficultyNotFound(header: BlockHeader) extends HeaderProcessingResult
871-
872892
case class ValidationFailed(header: BlockHeader, peer: Peer) extends HeaderProcessingResult
873-
874893
case object ImportedPivotBlock extends HeaderProcessingResult
875894

876895
sealed abstract class PivotBlockUpdateReason {

src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,11 @@ class SyncController(
2727
) extends Actor
2828
with ActorLogging {
2929

30-
import SyncController._
31-
3230
def scheduler: Scheduler = externalSchedulerOpt getOrElse context.system.scheduler
3331

3432
override def receive: Receive = idle
3533

36-
def idle: Receive = { case Start =>
34+
def idle: Receive = { case SyncProtocol.Start =>
3735
start()
3836
}
3937

@@ -89,7 +87,7 @@ class SyncController(
8987
),
9088
"fast-sync"
9189
)
92-
fastSync ! FastSync.Start
90+
fastSync ! SyncProtocol.Start
9391
context become runningFastSync(fastSync)
9492
}
9593

@@ -112,7 +110,7 @@ class SyncController(
112110
),
113111
"regular-sync"
114112
)
115-
regularSync ! RegularSync.Start
113+
regularSync ! SyncProtocol.Start
116114
context become runningRegularSync(regularSync)
117115
}
118116

@@ -150,6 +148,4 @@ object SyncController {
150148
syncConfig
151149
)
152150
)
153-
154-
case object Start
155151
}

0 commit comments

Comments
 (0)