@@ -134,38 +134,6 @@ class RegularSyncSpec extends RegularSyncFixtures with AnyWordSpecLike with Befo
134
134
}
135
135
136
136
" resolving branches" should {
137
- trait FakeLedger { self : Fixture =>
138
- class FakeLedgerImpl extends TestLedgerImpl {
139
- override def importBlock (block : Block )(
140
- implicit blockExecutionContext : ExecutionContext ): Future [BlockImportResult ] = {
141
- val result : BlockImportResult = if (didTryToImportBlock(block)) {
142
- DuplicateBlock
143
- } else {
144
- if (importedBlocks.isEmpty || bestBlock.isParentOf(block) || importedBlocks.exists(_.isParentOf(block))) {
145
- importedBlocks.add(block)
146
- BlockImportedToTop (List (BlockData (block, Nil , block.header.difficulty)))
147
- } else if (block.number > bestBlock.number) {
148
- importedBlocks.add(block)
149
- BlockEnqueued
150
- } else {
151
- BlockImportFailed (" foo" )
152
- }
153
- }
154
-
155
- Future .successful(result)
156
- }
157
-
158
- override def resolveBranch (headers : scala.Seq [BlockHeader ]): BranchResolutionResult = {
159
- val importedHashes = importedBlocks.map(_.hash).toSet
160
-
161
- if (importedBlocks.isEmpty || (importedHashes.contains(headers.head.parentHash) && headers.last.number > bestBlock.number)) {
162
- NewBetterBranch (Nil )
163
- } else {
164
- UnknownBranch
165
- }
166
- }
167
- }
168
- }
169
137
170
138
" go back to earlier block in order to find a common parent with new branch" in new Fixture (testSystem)
171
139
with FakeLedger {
@@ -216,6 +184,55 @@ class RegularSyncSpec extends RegularSyncFixtures with AnyWordSpecLike with Befo
216
184
}
217
185
}
218
186
187
+ " go back to earlier positive block in order to resolve a fork when branch smaller than branch resolution size" in new Fixture (testSystem)
188
+ with FakeLedger {
189
+ implicit val ec : ExecutionContext = system.dispatcher
190
+ override lazy val blockchain : BlockchainImpl = stub[BlockchainImpl ]
191
+ (blockchain.getBestBlockNumber _).when().onCall(() => ledger.bestBlock.number)
192
+ override lazy val ledger : TestLedgerImpl = new FakeLedgerImpl ()
193
+ override lazy val syncConfig = defaultSyncConfig.copy(
194
+ syncRetryInterval = 1 .second,
195
+ printStatusInterval = 0.5 .seconds,
196
+ branchResolutionRequestSize = 12 , // Over the original branch size
197
+
198
+ // Big so that they don't impact the test
199
+ blockHeadersPerRequest = 50 ,
200
+ blockBodiesPerRequest = 50 ,
201
+ blocksBatchSize = 50
202
+ )
203
+
204
+ val originalBranch = getBlocks(10 , genesis)
205
+ val betterBranch = getBlocks(originalBranch.size * 2 , genesis)
206
+
207
+ class ForkingAutoPilot (blocksToRespond : List [Block ], forkedBlocks : Option [List [Block ]])
208
+ extends PeersClientAutoPilot (blocksToRespond) {
209
+ override def overrides (sender : ActorRef ): PartialFunction [Any , Option [AutoPilot ]] = {
210
+ case req @ PeersClient .Request (GetBlockBodies (hashes), _, _) =>
211
+ val defaultResult = defaultHandlers(sender)(req)
212
+ if (forkedBlocks.nonEmpty && hashes.contains(blocksToRespond.last.hash)) {
213
+ Some (new ForkingAutoPilot (forkedBlocks.get, None ))
214
+ } else
215
+ defaultResult
216
+ }
217
+ }
218
+
219
+ peersClient.setAutoPilot(new ForkingAutoPilot (originalBranch, Some (betterBranch)))
220
+
221
+ Await .result(ledger.importBlock(genesis), remainingOrDefault)
222
+
223
+ regularSync ! RegularSync .Start
224
+
225
+ peerEventBus.expectMsgClass(classOf [Subscribe ])
226
+ val blockFetcher = peerEventBus.sender()
227
+ peerEventBus.reply(MessageFromPeer (NewBlock (originalBranch.last, originalBranch.last.number), defaultPeer.id))
228
+
229
+ awaitCond(ledger.bestBlock == originalBranch.last, 5 .seconds)
230
+
231
+ // As node will be on top, we have to re-trigger the fetching process by simulating a block from the fork being broadcasted
232
+ blockFetcher ! MessageFromPeer (NewBlock (betterBranch.last, betterBranch.last.number), defaultPeer.id)
233
+ awaitCond(ledger.bestBlock == betterBranch.last, 5 .seconds)
234
+ }
235
+
219
236
" fetching state node" should {
220
237
abstract class MissingStateNodeFixture (system : ActorSystem ) extends Fixture (system) {
221
238
val failingBlock : Block = testBlocksChunked.head.head
@@ -457,4 +474,36 @@ class RegularSyncSpec extends RegularSyncFixtures with AnyWordSpecLike with Befo
457
474
}
458
475
}
459
476
}
477
+
478
+ trait FakeLedger { self : Fixture =>
479
+ class FakeLedgerImpl extends TestLedgerImpl {
480
+ override def importBlock (block : Block )(
481
+ implicit blockExecutionContext : ExecutionContext ): Future [BlockImportResult ] = {
482
+ val result : BlockImportResult = if (didTryToImportBlock(block)) {
483
+ DuplicateBlock
484
+ } else {
485
+ if (importedBlocks.isEmpty || bestBlock.isParentOf(block) || importedBlocks.exists(_.isParentOf(block))) {
486
+ importedBlocks.add(block)
487
+ BlockImportedToTop (List (BlockData (block, Nil , block.header.difficulty)))
488
+ } else if (block.number > bestBlock.number) {
489
+ importedBlocks.add(block)
490
+ BlockEnqueued
491
+ } else {
492
+ BlockImportFailed (" foo" )
493
+ }
494
+ }
495
+
496
+ Future .successful(result)
497
+ }
498
+
499
+ override def resolveBranch (headers : Seq [BlockHeader ]): BranchResolutionResult = {
500
+ val importedHashes = importedBlocks.map(_.hash).toSet
501
+
502
+ if (importedBlocks.isEmpty || (importedHashes.contains(headers.head.parentHash) && headers.last.number > bestBlock.number))
503
+ NewBetterBranch (Nil )
504
+ else
505
+ UnknownBranch
506
+ }
507
+ }
508
+ }
460
509
}
0 commit comments