github.com/celestiaorg/celestia-node@v0.15.0-beta.1/nodebuilder/tests/sync_test.go (about) 1 //go:build sync || integration 2 3 package tests 4 5 import ( 6 "context" 7 "testing" 8 "time" 9 10 ma "github.com/multiformats/go-multiaddr" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/celestiaorg/celestia-node/nodebuilder/tests/swamp" 15 ) 16 17 // Common consts for tests producing filled blocks 18 const ( 19 numBlocks = 20 20 bsize = 16 21 sbtime = time.Millisecond * 300 22 ) 23 24 /* 25 Test-Case: Header and block/sample sync against a Bridge Node of non-empty blocks. 26 27 Steps: 28 1. Create a Bridge Node(BN) 29 2. Start a BN 30 3. Check BN is synced to height 20 31 32 Light node: 33 4. Create a Light Node (LN) with bridge as a trusted peer 34 5. Start a LN with a defined connection to the BN 35 6. Check LN is header-synced to height 20 36 7. Wait until LN has sampled height 20 37 8. Wait for LN DASer to catch up to network head 38 39 Full node: 40 4. Create a Full Node (FN) with bridge as a trusted peer 41 5. Start a FN with a defined connection to the BN 42 6. Check FN is header-synced to height 20 43 7. Wait until FN has synced block at height 20 44 8. Wait for FN DASer to catch up to network head 45 */ 46 func TestSyncAgainstBridge_NonEmptyChain(t *testing.T) { 47 ctx, cancel := context.WithTimeout(context.Background(), swamp.DefaultTestTimeout) 48 t.Cleanup(cancel) 49 50 sw := swamp.NewSwamp(t, swamp.WithBlockTime(sbtime)) 51 // wait for core network to fill 20 blocks 52 fillDn := swamp.FillBlocks(ctx, sw.ClientContext, sw.Accounts, bsize, numBlocks) 53 sw.WaitTillHeight(ctx, numBlocks) 54 55 // create a bridge node and set it as the bootstrapper for the suite 56 bridge := sw.NewBridgeNode() 57 sw.SetBootstrapper(t, bridge) 58 // start bridge and wait for it to sync to 20 59 err := bridge.Start(ctx) 60 require.NoError(t, err) 61 bridgeClient := getAdminClient(ctx, bridge, t) 62 63 h, err := bridgeClient.Header.WaitForHeight(ctx, numBlocks) 64 require.NoError(t, err) 65 require.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 66 67 t.Run("light sync against bridge", func(t *testing.T) { 68 // create a light node that is connected to the bridge node as 69 // a bootstrapper 70 light := sw.NewLightNode() 71 // start light node and wait for it to sync 20 blocks 72 err = light.Start(ctx) 73 require.NoError(t, err) 74 lightClient := getAdminClient(ctx, light, t) 75 h, err = lightClient.Header.WaitForHeight(ctx, numBlocks) 76 require.NoError(t, err) 77 assert.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 78 79 // check that the light node has also sampled over the block at height 20 80 err = lightClient.Share.SharesAvailable(ctx, h) 81 assert.NoError(t, err) 82 83 // wait until the entire chain (up to network head) has been sampled 84 err = lightClient.DAS.WaitCatchUp(ctx) 85 require.NoError(t, err) 86 }) 87 88 t.Run("full sync against bridge", func(t *testing.T) { 89 // create a full node with bridge node as its bootstrapper 90 full := sw.NewFullNode() 91 // let full node sync 20 blocks 92 err = full.Start(ctx) 93 require.NoError(t, err) 94 fullClient := getAdminClient(ctx, full, t) 95 h, err = fullClient.Header.WaitForHeight(ctx, numBlocks) 96 require.NoError(t, err) 97 assert.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 98 99 // check to ensure the full node can sync the 20th block's data 100 err = fullClient.Share.SharesAvailable(ctx, h) 101 assert.NoError(t, err) 102 103 // wait for full node to sync up the blocks from genesis -> network head. 104 err = fullClient.DAS.WaitCatchUp(ctx) 105 require.NoError(t, err) 106 }) 107 108 // wait for the core block filling process to exit 109 select { 110 case <-ctx.Done(): 111 t.Fatal(ctx.Err()) 112 case err := <-fillDn: 113 require.NoError(t, err) 114 } 115 } 116 117 /* 118 Test-Case: Header and block/sample sync against a Bridge Node of empty blocks. 119 120 Steps: 121 1. Create a Bridge Node(BN) 122 2. Start a BN 123 3. Check BN is synced to height 20 124 125 Light node: 126 4. Create a Light Node (LN) with bridge as a trusted peer 127 5. Start a LN with a defined connection to the BN 128 6. Check LN is header-synced to height 20 129 7. Wait until LN has sampled height 20 130 8. Wait for LN DASer to catch up to network head 131 132 Full node: 133 4. Create a Full Node (FN) with bridge as a trusted peer 134 5. Start a FN with a defined connection to the BN 135 6. Check FN is header-synced to height 20 136 7. Wait until FN has synced block at height 20 137 8. Wait for FN DASer to catch up to network head 138 */ 139 func TestSyncAgainstBridge_EmptyChain(t *testing.T) { 140 ctx, cancel := context.WithTimeout(context.Background(), swamp.DefaultTestTimeout) 141 t.Cleanup(cancel) 142 143 sw := swamp.NewSwamp(t, swamp.WithBlockTime(sbtime)) 144 sw.WaitTillHeight(ctx, numBlocks) 145 146 // create bridge node and set it as the bootstrapper for the suite 147 bridge := sw.NewBridgeNode() 148 sw.SetBootstrapper(t, bridge) 149 // start bridge and wait for it to sync to 20 150 err := bridge.Start(ctx) 151 require.NoError(t, err) 152 bridgeClient := getAdminClient(ctx, bridge, t) 153 h, err := bridgeClient.Header.WaitForHeight(ctx, numBlocks) 154 require.NoError(t, err) 155 require.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 156 157 t.Run("light sync against bridge", func(t *testing.T) { 158 // create a light node that is connected to the bridge node as 159 // a bootstrapper 160 light := sw.NewLightNode() 161 // start light node and wait for it to sync 20 blocks 162 err = light.Start(ctx) 163 require.NoError(t, err) 164 lightClient := getAdminClient(ctx, light, t) 165 h, err = lightClient.Header.WaitForHeight(ctx, numBlocks) 166 require.NoError(t, err) 167 assert.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 168 169 // check that the light node has also sampled over the block at height 20 170 err = lightClient.Share.SharesAvailable(ctx, h) 171 assert.NoError(t, err) 172 173 // wait until the entire chain (up to network head) has been sampled 174 err = lightClient.DAS.WaitCatchUp(ctx) 175 require.NoError(t, err) 176 }) 177 178 t.Run("full sync against bridge", func(t *testing.T) { 179 // create a full node with bridge node as its bootstrapper 180 full := sw.NewFullNode() 181 // let full node sync 20 blocks 182 err = full.Start(ctx) 183 require.NoError(t, err) 184 fullClient := getAdminClient(ctx, full, t) 185 h, err = fullClient.Header.WaitForHeight(ctx, numBlocks) 186 require.NoError(t, err) 187 assert.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 188 189 // check to ensure the full node can sync the 20th block's data 190 err = fullClient.Share.SharesAvailable(ctx, h) 191 assert.NoError(t, err) 192 193 // wait for full node to sync up the blocks from genesis -> network head. 194 err = fullClient.DAS.WaitCatchUp(ctx) 195 require.NoError(t, err) 196 }) 197 } 198 199 /* 200 Test-Case: Light Node continues sync after abrupt stop/start 201 Pre-Requisites: 202 - CoreClient is started by swamp 203 - CoreClient has generated 50 blocks 204 Steps: 205 1. Create a Bridge Node(BN) 206 2. Start a BN 207 3. Check BN is synced to height 20 208 4. Create a Light Node(LN) with a trusted peer 209 5. Start a LN with a defined connection to the BN 210 6. Check LN is synced to height 20 211 7. Disconnect LN from BN for 3 seconds while BN continues broadcasting new blocks from core 212 8. Re-connect LN and let it sync up again 213 9. Check LN is synced to height 40 214 */ 215 func TestSyncStartStopLightWithBridge(t *testing.T) { 216 if testing.Short() { 217 t.Skip("skipping TestSyncStartStopLightWithBridge test in short mode.") 218 } 219 220 ctx, cancel := context.WithTimeout(context.Background(), swamp.DefaultTestTimeout) 221 defer cancel() 222 223 sw := swamp.NewSwamp(t) 224 // wait for core network to fill 20 blocks 225 fillDn := swamp.FillBlocks(ctx, sw.ClientContext, sw.Accounts, bsize, numBlocks) 226 sw.WaitTillHeight(ctx, numBlocks) 227 228 // create bridge and set it as a bootstrapper 229 bridge := sw.NewBridgeNode() 230 sw.SetBootstrapper(t, bridge) 231 // and let bridge node sync up 20 blocks 232 err := bridge.Start(ctx) 233 require.NoError(t, err) 234 bridgeClient := getAdminClient(ctx, bridge, t) 235 h, err := bridgeClient.Header.WaitForHeight(ctx, numBlocks) 236 require.NoError(t, err) 237 require.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 238 239 // create a light node and connect it to the bridge node as a bootstrapper 240 light := sw.NewLightNode() 241 // start light node and let it sync to 20 242 err = light.Start(ctx) 243 require.NoError(t, err) 244 lightClient := getAdminClient(ctx, light, t) 245 h, err = lightClient.Header.WaitForHeight(ctx, numBlocks) 246 require.NoError(t, err) 247 require.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 248 249 sw.StopNode(ctx, light) 250 251 light = sw.NewLightNode() 252 require.NoError(t, light.Start(ctx)) 253 254 // ensure when light node comes back up, it can sync the remainder of the chain it 255 // missed while sleeping 256 h, err = lightClient.Header.WaitForHeight(ctx, 40) 257 require.NoError(t, err) 258 assert.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, 40)) 259 260 // wait for the core block filling process to exit 261 select { 262 case <-ctx.Done(): 263 t.Fatal(ctx.Err()) 264 case err := <-fillDn: 265 require.NoError(t, err) 266 } 267 } 268 269 /* 270 Test-Case: Sync a Light Node from a Full Node 271 Pre-Requisites: 272 - CoreClient is started by swamp 273 - CoreClient has generated 20 blocks 274 Steps: 275 1. Create a Bridge Node(BN) 276 2. Start a BN 277 3. Check BN is synced to height 20 278 4. Create a Full Node(FN) with a connection to BN as a trusted peer 279 5. Start a FN 280 6. Check FN is synced to network head 281 7. Create a Light Node(LN) with a connection to FN as a trusted peer 282 8. Ensure LN is NOT connected to BN and only connected to FN 283 9. Start LN 284 10. Check LN is synced to network head 285 */ 286 func TestSyncLightAgainstFull(t *testing.T) { 287 ctx, cancel := context.WithTimeout(context.Background(), swamp.DefaultTestTimeout) 288 t.Cleanup(cancel) 289 290 sw := swamp.NewSwamp(t) 291 // wait for the core network to fill up 20 blocks 292 fillDn := swamp.FillBlocks(ctx, sw.ClientContext, sw.Accounts, bsize, numBlocks) 293 sw.WaitTillHeight(ctx, numBlocks) 294 295 // create bridge and set it as a bootstrapper 296 bridge := sw.NewBridgeNode() 297 sw.SetBootstrapper(t, bridge) 298 // start a bridge node and wait for it to sync up 20 blocks 299 err := bridge.Start(ctx) 300 require.NoError(t, err) 301 bridgeClient := getAdminClient(ctx, bridge, t) 302 h, err := bridgeClient.Header.WaitForHeight(ctx, numBlocks) 303 require.NoError(t, err) 304 assert.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 305 306 // create a FN with BN as a trusted peer 307 full := sw.NewFullNode() 308 // start FN and wait for it to sync up to head of BN 309 err = full.Start(ctx) 310 require.NoError(t, err) 311 fullClient := getAdminClient(ctx, full, t) 312 bridgeHead, err := bridgeClient.Header.LocalHead(ctx) 313 require.NoError(t, err) 314 _, err = fullClient.Header.WaitForHeight(ctx, bridgeHead.Height()) 315 require.NoError(t, err) 316 assert.EqualValues(t, h.Commit.BlockID.Hash, sw.GetCoreBlockHashByHeight(ctx, numBlocks)) 317 318 // reset suite bootstrapper list and set full node as a bootstrapper for 319 // LN to connect to 320 sw.Bootstrappers = make([]ma.Multiaddr, 0) 321 sw.SetBootstrapper(t, full) 322 323 // create an LN with FN as a trusted peer 324 light := sw.NewLightNode() 325 326 // ensure there is no direct connection between LN and BN so that 327 // LN relies only on FN for syncing 328 err = sw.Network.UnlinkPeers(bridge.Host.ID(), light.Host.ID()) 329 require.NoError(t, err) 330 331 // start LN and wait for it to sync up to network head against the head of the FN 332 err = light.Start(ctx) 333 require.NoError(t, err) 334 lightClient := getAdminClient(ctx, light, t) 335 fullHead, err := fullClient.Header.LocalHead(ctx) 336 require.NoError(t, err) 337 _, err = lightClient.Header.WaitForHeight(ctx, fullHead.Height()) 338 require.NoError(t, err) 339 340 // wait for the core block filling process to exit 341 select { 342 case <-ctx.Done(): 343 t.Fatal(ctx.Err()) 344 case err := <-fillDn: 345 require.NoError(t, err) 346 } 347 } 348 349 /* 350 Test-Case: Sync a Light Node with multiple trusted peers 351 Pre-Requisites: 352 - CoreClient is started by swamp 353 - CoreClient has generated 20 blocks 354 Steps: 355 1. Create a Bridge Node(BN) 356 2. Start a BN 357 3. Check BN is synced to height 20 358 4. Create a Full Node(FN) with a connection to BN as a trusted peer 359 5. Start a FN 360 6. Check FN is synced to network head 361 7. Create a Light Node(LN) with a connection to BN and FN as trusted peers 362 8. Start LN 363 9. Check LN is synced to network head. 364 */ 365 func TestSyncLightWithTrustedPeers(t *testing.T) { 366 ctx, cancel := context.WithTimeout(context.Background(), swamp.DefaultTestTimeout) 367 t.Cleanup(cancel) 368 369 sw := swamp.NewSwamp(t) 370 fillDn := swamp.FillBlocks(ctx, sw.ClientContext, sw.Accounts, bsize, numBlocks) 371 sw.WaitTillHeight(ctx, numBlocks) 372 373 // create a BN and set as a bootstrapper 374 bridge := sw.NewBridgeNode() 375 sw.SetBootstrapper(t, bridge) 376 // let it sync to network head 377 err := bridge.Start(ctx) 378 require.NoError(t, err) 379 bridgeClient := getAdminClient(ctx, bridge, t) 380 _, err = bridgeClient.Header.WaitForHeight(ctx, numBlocks) 381 require.NoError(t, err) 382 383 // create a FN with BN as trusted peer 384 full := sw.NewFullNode() 385 386 // let FN sync to network head 387 err = full.Start(ctx) 388 require.NoError(t, err) 389 fullClient := getAdminClient(ctx, full, t) 390 err = fullClient.Header.SyncWait(ctx) 391 require.NoError(t, err) 392 393 // add full node as a bootstrapper for the suite 394 sw.SetBootstrapper(t, full) 395 396 // create a LN with both FN and BN as trusted peers 397 light := sw.NewLightNode() 398 399 // let LN sync to network head 400 err = light.Start(ctx) 401 require.NoError(t, err) 402 lightClient := getAdminClient(ctx, light, t) 403 err = lightClient.Header.SyncWait(ctx) 404 require.NoError(t, err) 405 406 // wait for the core block filling process to exit 407 select { 408 case <-ctx.Done(): 409 t.Fatal(ctx.Err()) 410 case err := <-fillDn: 411 require.NoError(t, err) 412 } 413 }