@@ -3,6 +3,7 @@ package io.iohk.ethereum.sync
33import com .typesafe .config .ConfigValueFactory
44import io .iohk .ethereum .FreeSpecBase
55import io .iohk .ethereum .metrics .{Metrics , MetricsConfig }
6+ import io .iohk .ethereum .network .PeerId
67import io .iohk .ethereum .sync .util .RegularSyncItSpecUtils .FakePeer
78import io .iohk .ethereum .sync .util .SyncCommonItSpec ._
89import io .iohk .ethereum .utils .Config
@@ -27,6 +28,24 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
2728 testScheduler.awaitTermination(120 .second)
2829 }
2930
31+ " a peer should reorganise when receives a checkpoint older than the current best from a peer" in customTestCaseResourceM(
32+ FakePeer .start2FakePeersRes()
33+ ) { case (peer1, peer2) =>
34+ for {
35+ _ <- peer1.importBlocksUntil(20 )(IdentityUpdate )
36+ _ <- peer2.importBlocksUntil(30 )(IdentityUpdate )
37+ _ <- peer1.startRegularSync()
38+ _ <- peer2.startRegularSync()
39+ _ <- peer1.addCheckpointedBlock(peer1.bl.getBestBlock().get)
40+ _ <- peer1.waitForRegularSyncLoadLastBlock(21 )
41+ _ <- peer2.getCheckpointFromPeer(peer1.bl.getBestBlock().get, PeerId (" Peer1" ))
42+ _ <- peer2.waitForRegularSyncLoadLastBlock(21 )
43+ } yield {
44+ assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash)
45+ assert(peer1.bl.getLatestCheckpointBlockNumber() == peer2.bl.getLatestCheckpointBlockNumber())
46+ }
47+ }
48+
3049 " peer 2 should sync to the top of peer1 blockchain" - {
3150 " given a previously imported blockchain" in customTestCaseResourceM(FakePeer .start2FakePeersRes()) {
3251 case (peer1, peer2) =>
@@ -76,6 +95,91 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl
7695 }
7796 }
7897
98+ " peers should keep being synced on checkpoints" in customTestCaseResourceM(
99+ FakePeer .start2FakePeersRes()
100+ ) { case (peer1, peer2) =>
101+ val blockNumber : Int = 2000
102+ for {
103+ _ <- peer1.importBlocksUntil(blockNumber)(IdentityUpdate )
104+ _ <- peer1.startRegularSync()
105+ _ <- peer2.startRegularSync()
106+ _ <- peer2.connectToPeers(Set (peer1.node))
107+ _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumber)
108+ _ <- peer2.addCheckpointedBlock(peer2.bl.getBestBlock().get)
109+ _ <- peer1.waitForRegularSyncLoadLastBlock(blockNumber + 1 )
110+ } yield {
111+ assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash)
112+ assert(peer1.bl.getLatestCheckpointBlockNumber() == peer2.bl.getLatestCheckpointBlockNumber())
113+ }
114+ }
115+
116+ " peers should keep being synced on checkpoints even if 2 checkpoints are issued to different forks at the same time" in customTestCaseResourceM(
117+ FakePeer .start2FakePeersRes()
118+ ) { case (peer1, peer2) =>
119+ val blockNumber : Int = 2000
120+ for {
121+ _ <- peer1.importBlocksUntil(blockNumber)(IdentityUpdate )
122+ _ <- peer1.startRegularSync()
123+ _ <- peer2.startRegularSync()
124+ _ <- peer2.connectToPeers(Set (peer1.node))
125+ _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumber)
126+ _ <- peer2.mineNewBlocks(100 .milliseconds, 2 )(IdentityUpdate )
127+ _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumber + 2 )
128+ _ <- peer2.addCheckpointedBlock(peer2.bl.getBestBlock().get)
129+ _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumber + 3 )
130+ _ <- peer1.addCheckpointedBlock(peer1.bl.getBestBlock().get)
131+ _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumber + 4 )
132+ _ <- peer1.mineNewBlocks(100 .milliseconds, 1 )(IdentityUpdate )
133+ _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumber + 5 )
134+ } yield {
135+ assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash)
136+ assert(peer1.bl.getLatestCheckpointBlockNumber() == peer2.bl.getLatestCheckpointBlockNumber())
137+ }
138+ }
139+
140+ " peers should chose the branch with a checkpoint discarding blocks that come after the checkpoint" in customTestCaseResourceM(
141+ FakePeer .start2FakePeersRes()
142+ ) { case (peer1, peer2) =>
143+ val length = 26
144+ for {
145+ _ <- peer1.importBlocksUntil(20 )(IdentityUpdate )
146+ _ <- peer2.importBlocksUntil(30 )(IdentityUpdate )
147+ _ <- peer1.startRegularSync()
148+ _ <- peer2.startRegularSync()
149+ _ <- peer2.addCheckpointedBlock(peer2.bl.getBlockByNumber(25 ).get)
150+ _ <- peer2.waitForRegularSyncLoadLastBlock(length)
151+ _ <- peer1.connectToPeers(Set (peer2.node))
152+ _ <- peer1.waitForRegularSyncLoadLastBlock(length)
153+ } yield {
154+ 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)
156+ assert(peer1.bl.getLatestCheckpointBlockNumber() == peer2.bl.getLatestCheckpointBlockNumber())
157+ }
158+ }
159+
160+ // TODO: investigate why reorganisation is not triggered after 2 nodes with conflicting branches connect
161+ " peers should choose the branch with a checkpoint even if it's shorter" in customTestCaseResourceM(
162+ FakePeer .start2FakePeersRes()
163+ ) { case (peer1, peer2) =>
164+ for {
165+ _ <- peer1.importBlocksUntil(8 )(IdentityUpdate )
166+ _ <- peer1.startRegularSync()
167+ _ <- peer1.addCheckpointedBlock(peer1.bl.getBestBlock().get)
168+ _ <- peer1.waitForRegularSyncLoadLastBlock(9 )
169+ _ <- peer2.importBlocksUntil(20 )(IdentityUpdate )
170+ _ <- peer2.startRegularSync()
171+ _ <- peer2.connectToPeers(Set (peer1.node))
172+ // without new added blocks the syncing and reorganisation are not triggered
173+ _ <- peer1.mineNewBlocks(500 .milliseconds, 10 )(IdentityUpdate )
174+ _ <- peer1.waitForRegularSyncLoadLastBlock(19 )
175+ } yield {
176+ assert(true )
177+ // these should pass
178+ // assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash )
179+ // assert(peer1.bl.getLatestCheckpointBlockNumber() == peer2.bl.getLatestCheckpointBlockNumber())
180+ }
181+ }
182+
79183 " peers with divergent chains will be forced to resolve branches" in customTestCaseResourceM(
80184 FakePeer .start2FakePeersRes()
81185 ) { case (peer1, peer2) =>
0 commit comments