Skip to content

Commit a56bf06

Browse files
authored
test: add test for multiple rollups using the same namespace (#1613)
<!-- Please read and fill out this form before submitting your PR. Please make sure you have reviewed our contributors guide before submitting your first PR. --> ## Overview A new test has been added to `full_node_integration_test.go` to simulate multiple rollups within the same namespace. This helps validate the operation of the app in a more complex environment. Additional debugging information is also now logged in `manager.go` if a block from an unexpected sequencer is skipped. Resolves #883 <!-- Please provide an explanation of the PR, including the appropriate context, background, goal, and rationale. If there is an issue with this information, please provide a tl;dr and link the issue. --> ## Checklist <!-- Please complete the checklist to ensure that the PR is ready to be reviewed. IMPORTANT: PRs should be left in Draft until the below checklist is completed. --> - [x] New and updated code has appropriate documentation - [x] New and updated code has new and/or updated testing - [x] Required CI checks are passing - [x] Visual proof for any user facing features like CLI or documentation updates - [x] Linked issues closed with keywords <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new integration test for validating the functionality of two rollup networks within a single namespace. - **Bug Fixes** - Enhanced block processing logic to skip blocks from unexpected sequencers under specific conditions. - **Tests** - Added support for `chainID` parameter in test setup functions to facilitate more comprehensive testing scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent b5b58bc commit a56bf06

3 files changed

Lines changed: 136 additions & 14 deletions

File tree

block/manager.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,9 @@ func (m *Manager) processNextDABlock(ctx context.Context) error {
634634
for _, block := range blockResp.Blocks {
635635
// early validation to reject junk blocks
636636
if !m.isUsingExpectedCentralizedSequencer(block) {
637+
m.logger.Debug("skipping block from unexpected sequencer",
638+
"blockHeight", block.Height(),
639+
"blockHash", block.Hash().String())
637640
continue
638641
}
639642
blockHash := block.Hash().String()

node/full_node_integration_test.go

Lines changed: 131 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/stretchr/testify/require"
2727

2828
goDA "github.com/rollkit/go-da"
29+
"github.com/rollkit/rollkit/block"
2930
"github.com/rollkit/rollkit/config"
3031
"github.com/rollkit/rollkit/da"
3132
test "github.com/rollkit/rollkit/test/log"
@@ -93,7 +94,7 @@ func TestTxGossipingAndAggregation(t *testing.T) {
9394
clientNodes := 4
9495
aggCtx := context.Background()
9596
ctx := context.Background()
96-
nodes, apps := createNodes(aggCtx, ctx, clientNodes+1, getBMConfig(), t)
97+
nodes, apps := createNodes(aggCtx, ctx, clientNodes+1, getBMConfig(), types.TestChainID, t)
9798
startNodes(nodes, apps, t)
9899
defer func() {
99100
for _, n := range nodes {
@@ -235,7 +236,7 @@ func TestFastDASync(t *testing.T) {
235236
const numberOfBlocksToSyncTill = 5
236237

237238
// Create the 2 nodes
238-
nodes, _ := createNodes(aggCtx, ctx, clientNodes, bmConfig, t)
239+
nodes, _ := createNodes(aggCtx, ctx, clientNodes, bmConfig, types.TestChainID, t)
239240

240241
node1 := nodes[0]
241242
node2 := nodes[1]
@@ -328,7 +329,7 @@ func TestSingleAggregatorTwoFullNodesBlockSyncSpeed(t *testing.T) {
328329
return
329330
}
330331
}()
331-
nodes, _ := createNodes(aggCtx, ctx, clientNodes, bmConfig, t)
332+
nodes, _ := createNodes(aggCtx, ctx, clientNodes, bmConfig, types.TestChainID, t)
332333

333334
node1 := nodes[0]
334335
node2 := nodes[1]
@@ -386,6 +387,7 @@ func TestSubmitBlocksToDA(t *testing.T) {
386387
DABlockTime: 20 * time.Millisecond,
387388
BlockTime: 10 * time.Millisecond,
388389
},
390+
types.TestChainID,
389391
t,
390392
)
391393
seq := nodes[0]
@@ -408,6 +410,121 @@ func TestSubmitBlocksToDA(t *testing.T) {
408410
}
409411
}
410412

413+
func TestTwoRollupsInOneNamespace(t *testing.T) {
414+
cases := []struct {
415+
name string
416+
chainID1 string
417+
chainID2 string
418+
}{
419+
{
420+
name: "same chain ID",
421+
chainID1: "test-1",
422+
chainID2: "test-1",
423+
},
424+
{
425+
name: "different chain IDs",
426+
chainID1: "foo-1",
427+
chainID2: "bar-2",
428+
},
429+
}
430+
431+
for _, tc := range cases {
432+
t.Run(tc.name, func(t *testing.T) {
433+
doTestTwoRollupsInOneNamespace(t, tc.chainID1, tc.chainID1)
434+
})
435+
}
436+
}
437+
438+
func doTestTwoRollupsInOneNamespace(t *testing.T, chainID1, chainID2 string) {
439+
require := require.New(t)
440+
441+
const (
442+
n = 2
443+
daStartHeight = 1
444+
daMempoolTTL = 5
445+
blockTime1 = 100 * time.Millisecond
446+
blockTime2 = 50 * time.Millisecond
447+
)
448+
449+
mainCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
450+
defer cancel()
451+
452+
agg1Ctx := context.WithoutCancel(mainCtx)
453+
nodes1Ctx := context.WithoutCancel(mainCtx)
454+
455+
rollupNetwork1, apps1 := createNodes(agg1Ctx, nodes1Ctx, n, config.BlockManagerConfig{
456+
BlockTime: blockTime1,
457+
DABlockTime: blockTime1,
458+
DAStartHeight: daStartHeight,
459+
DAMempoolTTL: daMempoolTTL,
460+
}, chainID1, t)
461+
462+
require.Len(rollupNetwork1, n)
463+
require.Len(apps1, n)
464+
465+
agg2Ctx := context.WithoutCancel(mainCtx)
466+
nodes2Ctx := context.WithoutCancel(mainCtx)
467+
468+
rollupNetwork2, apps2 := createNodes(agg2Ctx, nodes2Ctx, n, config.BlockManagerConfig{
469+
BlockTime: blockTime2,
470+
DABlockTime: blockTime2,
471+
DAStartHeight: daStartHeight,
472+
DAMempoolTTL: daMempoolTTL,
473+
}, chainID2, t)
474+
475+
require.Len(rollupNetwork2, n)
476+
require.Len(apps2, n)
477+
478+
// same mock DA has to be used by all nodes to simulate posting to/retrieving from same namespace
479+
dalc := getMockDA(t)
480+
for _, node := range append(rollupNetwork1, rollupNetwork2...) {
481+
node.dalc = dalc
482+
node.blockManager.SetDALC(dalc)
483+
}
484+
485+
agg1 := rollupNetwork1[0]
486+
agg2 := rollupNetwork2[0]
487+
488+
node1 := rollupNetwork1[1]
489+
node2 := rollupNetwork2[1]
490+
491+
// start both aggregators and wait for 10 blocks
492+
require.NoError(agg1.Start())
493+
require.NoError(agg2.Start())
494+
495+
require.NoError(waitForAtLeastNBlocks(agg1, 10, Store))
496+
require.NoError(waitForAtLeastNBlocks(agg2, 10, Store))
497+
498+
// get the number of submitted blocks from aggregators before stopping (as it closes the store)
499+
lastSubmittedHeight1 := getLastSubmittedHeight(agg1Ctx, agg1, t)
500+
lastSubmittedHeight2 := getLastSubmittedHeight(agg2Ctx, agg2, t)
501+
502+
// make sure that there are any blocks for syncing
503+
require.Greater(lastSubmittedHeight1, 1)
504+
require.Greater(lastSubmittedHeight2, 1)
505+
506+
// now stop the aggregators and run the full nodes to ensure sync from D
507+
require.NoError(agg1.Stop())
508+
require.NoError(agg2.Stop())
509+
510+
startNodeWithCleanup(t, node1)
511+
startNodeWithCleanup(t, node2)
512+
513+
// check that full nodes are able to sync blocks from DA
514+
require.NoError(waitForAtLeastNBlocks(node1, lastSubmittedHeight1, Store))
515+
require.NoError(waitForAtLeastNBlocks(node2, lastSubmittedHeight2, Store))
516+
}
517+
518+
func getLastSubmittedHeight(ctx context.Context, node *FullNode, t *testing.T) int {
519+
raw, err := node.Store.GetMetadata(ctx, block.LastSubmittedHeightKey)
520+
require.NoError(t, err)
521+
require.NotEmpty(t, raw)
522+
523+
val, err := strconv.ParseUint(string(raw), 10, 64)
524+
require.NoError(t, err)
525+
return int(val)
526+
}
527+
411528
func TestMaxPending(t *testing.T) {
412529
cases := []struct {
413530
name string
@@ -449,6 +566,7 @@ func doTestMaxPending(maxPending uint64, t *testing.T) {
449566
BlockTime: 10 * time.Millisecond,
450567
MaxPendingBlocks: maxPending,
451568
},
569+
types.TestChainID,
452570
t,
453571
)
454572
seq := nodes[0]
@@ -499,7 +617,7 @@ func testSingleAggregatorSingleFullNode(t *testing.T, source Source) {
499617
ctx, cancel := context.WithCancel(context.Background())
500618
defer cancel()
501619
clientNodes := 2
502-
nodes, _ := createNodes(aggCtx, ctx, clientNodes, getBMConfig(), t)
620+
nodes, _ := createNodes(aggCtx, ctx, clientNodes, getBMConfig(), types.TestChainID, t)
503621

504622
node1 := nodes[0]
505623
node2 := nodes[1]
@@ -521,7 +639,7 @@ func testSingleAggregatorTwoFullNode(t *testing.T, source Source) {
521639
ctx, cancel := context.WithCancel(context.Background())
522640
defer cancel()
523641
clientNodes := 3
524-
nodes, _ := createNodes(aggCtx, ctx, clientNodes, getBMConfig(), t)
642+
nodes, _ := createNodes(aggCtx, ctx, clientNodes, getBMConfig(), types.TestChainID, t)
525643

526644
node1 := nodes[0]
527645
node2 := nodes[1]
@@ -548,7 +666,7 @@ func testSingleAggregatorSingleFullNodeTrustedHash(t *testing.T, source Source)
548666
ctx, cancel := context.WithCancel(context.Background())
549667
defer cancel()
550668
clientNodes := 2
551-
nodes, _ := createNodes(aggCtx, ctx, clientNodes, getBMConfig(), t)
669+
nodes, _ := createNodes(aggCtx, ctx, clientNodes, getBMConfig(), types.TestChainID, t)
552670

553671
node1 := nodes[0]
554672
node2 := nodes[1]
@@ -583,7 +701,7 @@ func testSingleAggregatorSingleFullNodeSingleLightNode(t *testing.T) {
583701
bmConfig := getBMConfig()
584702
sequencer, _ := createAndConfigureNode(aggCtx, 0, true, false, keys, bmConfig, dalc, t)
585703
fullNode, _ := createAndConfigureNode(ctx, 1, false, false, keys, bmConfig, dalc, t)
586-
lightNode, _ := createNode(ctx, 2, false, true, keys, bmConfig, t)
704+
lightNode, _ := createNode(ctx, 2, false, true, keys, bmConfig, types.TestChainID, t)
587705

588706
startNodeWithCleanup(t, sequencer)
589707
startNodeWithCleanup(t, fullNode)
@@ -654,7 +772,7 @@ func startNodes(nodes []*FullNode, apps []*mocks.Application, t *testing.T) {
654772
}
655773

656774
// Creates the given number of nodes the given nodes using the given wait group to synchornize them
657-
func createNodes(aggCtx, ctx context.Context, num int, bmConfig config.BlockManagerConfig, t *testing.T) ([]*FullNode, []*mocks.Application) {
775+
func createNodes(aggCtx, ctx context.Context, num int, bmConfig config.BlockManagerConfig, chainID string, t *testing.T) ([]*FullNode, []*mocks.Application) {
658776
t.Helper()
659777

660778
if aggCtx == nil {
@@ -673,14 +791,14 @@ func createNodes(aggCtx, ctx context.Context, num int, bmConfig config.BlockMana
673791
nodes := make([]*FullNode, num)
674792
apps := make([]*mocks.Application, num)
675793
dalc := getMockDA(t)
676-
node, app := createNode(aggCtx, 0, true, false, keys, bmConfig, t)
794+
node, app := createNode(aggCtx, 0, true, false, keys, bmConfig, chainID, t)
677795
apps[0] = app
678796
nodes[0] = node.(*FullNode)
679797
// use same, common DALC, so nodes can share data
680798
nodes[0].dalc = dalc
681799
nodes[0].blockManager.SetDALC(dalc)
682800
for i := 1; i < num; i++ {
683-
node, apps[i] = createNode(ctx, i, false, false, keys, bmConfig, t)
801+
node, apps[i] = createNode(ctx, i, false, false, keys, bmConfig, chainID, t)
684802
nodes[i] = node.(*FullNode)
685803
nodes[i].dalc = dalc
686804
nodes[i].blockManager.SetDALC(dalc)
@@ -689,7 +807,7 @@ func createNodes(aggCtx, ctx context.Context, num int, bmConfig config.BlockMana
689807
return nodes, apps
690808
}
691809

692-
func createNode(ctx context.Context, n int, aggregator bool, isLight bool, keys []crypto.PrivKey, bmConfig config.BlockManagerConfig, t *testing.T) (Node, *mocks.Application) {
810+
func createNode(ctx context.Context, n int, aggregator bool, isLight bool, keys []crypto.PrivKey, bmConfig config.BlockManagerConfig, chainID string, t *testing.T) (Node, *mocks.Application) {
693811
t.Helper()
694812
require := require.New(t)
695813
// nodes will listen on consecutive ports on local interface
@@ -727,7 +845,7 @@ func createNode(ctx context.Context, n int, aggregator bool, isLight bool, keys
727845
},
728846
}
729847

730-
genesis := &cmtypes.GenesisDoc{ChainID: "test", Validators: genesisValidators}
848+
genesis := &cmtypes.GenesisDoc{ChainID: chainID, Validators: genesisValidators}
731849
// TODO: need to investigate why this needs to be done for light nodes
732850
genesis.InitialHeight = 1
733851
node, err := NewNode(
@@ -754,7 +872,7 @@ func createNode(ctx context.Context, n int, aggregator bool, isLight bool, keys
754872

755873
func createAndConfigureNode(ctx context.Context, n int, aggregator bool, isLight bool, keys []crypto.PrivKey, bmConfig config.BlockManagerConfig, dalc *da.DAClient, t *testing.T) (Node, *mocks.Application) {
756874
t.Helper()
757-
node, app := createNode(ctx, n, aggregator, isLight, keys, bmConfig, t)
875+
node, app := createNode(ctx, n, aggregator, isLight, keys, bmConfig, types.TestChainID, t)
758876
node.(*FullNode).dalc = dalc
759877
node.(*FullNode).blockManager.SetDALC(dalc)
760878

node/helpers_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
goDATest "github.com/rollkit/go-da/test"
1717
"github.com/rollkit/rollkit/da"
18+
"github.com/rollkit/rollkit/types"
1819
)
1920

2021
func getMockDA(t *testing.T) *da.DAClient {
@@ -44,7 +45,7 @@ func TestGetNodeHeight(t *testing.T) {
4445
}
4546
bmConfig := getBMConfig()
4647
fullNode, _ := createAndConfigureNode(ctx, 0, true, false, keys, bmConfig, dalc, t)
47-
lightNode, _ := createNode(ctx, 1, true, true, keys, bmConfig, t)
48+
lightNode, _ := createNode(ctx, 1, true, true, keys, bmConfig, types.TestChainID, t)
4849

4950
startNodeWithCleanup(t, fullNode)
5051
startNodeWithCleanup(t, lightNode)

0 commit comments

Comments
 (0)