Skip to content

Commit 6cea6c8

Browse files
committed
only produce 1 base block per da epoch (unless more needed)
1 parent 3062ac9 commit 6cea6c8

4 files changed

Lines changed: 37 additions & 13 deletions

File tree

block/public.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,13 @@ func NewDAClient(
6363
return base
6464
}
6565

66-
// ErrForceInclusionNotConfigured is returned when force inclusion is not configured.
67-
// It is exported because sequencers needs to check for this error.
68-
var ErrForceInclusionNotConfigured = da.ErrForceInclusionNotConfigured
66+
// Exported errors used by the sequencers
67+
var (
68+
// ErrForceInclusionNotConfigured is returned when force inclusion is not configured.
69+
ErrForceInclusionNotConfigured = da.ErrForceInclusionNotConfigured
70+
// ErrNoBatch is returned when a sequencer does not have a batch to return.
71+
ErrNoBatch = common.ErrNoBatch
72+
)
6973

7074
// ForcedInclusionEvent represents forced inclusion transactions retrieved from DA
7175
type ForcedInclusionEvent = da.ForcedInclusionEvent

pkg/sequencers/based/sequencer.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ doneProcessing:
219219
}
220220
s.lastTimestamp = timestamp
221221

222+
if len(validTxs) == 0 {
223+
return nil, block.ErrNoBatch
224+
}
225+
222226
return &coresequencer.GetNextBatchResponse{
223227
Batch: &coresequencer.Batch{Transactions: validTxs},
224228
Timestamp: timestamp,

pkg/sequencers/single/sequencer.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@ func (c *Sequencer) GetNextBatch(ctx context.Context, req coresequencer.GetNextB
372372
c.lastCatchUpTimestamp = timestamp
373373
}
374374

375+
if c.isCatchingUp() && len(batchTxs) == 0 {
376+
return nil, block.ErrNoBatch
377+
}
378+
375379
return &coresequencer.GetNextBatchResponse{
376380
Batch: &coresequencer.Batch{
377381
Transactions: batchTxs,
@@ -539,17 +543,17 @@ func (c *Sequencer) updateCatchUpState(ctx context.Context) {
539543
latestEpoch := types.CalculateEpochNumber(latestDAHeight, daStartHeight, epochSize)
540544
missedEpochs := latestEpoch - currentEpoch
541545

542-
if missedEpochs <= 1 {
546+
if missedEpochs == 0 {
543547
c.logger.Debug().
544548
Uint64("checkpoint_da_height", currentDAHeight).
545549
Uint64("latest_da_height", latestDAHeight).
546550
Uint64("current_epoch", currentEpoch).
547551
Uint64("latest_epoch", latestEpoch).
548-
Msg("sequencer within one epoch of DA head, no catch-up needed")
552+
Msg("sequencer at DA head, no catch-up needed")
549553
return
550554
}
551555

552-
// More than one epoch behind - enter catch-up mode.
556+
// At least one epoch behind - enter catch-up mode.
553557
// Read the last block time from the store so that catch-up timestamps
554558
// are guaranteed to be strictly after any previously produced block.
555559
s := store.New(store.NewEvNodeKVStore(c.db))

test/e2e/evm_force_inclusion_e2e_test.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,9 @@ func TestEvmSequencerCatchUpBasedSequencerE2E(t *testing.T) {
719719
seqFinalHeight := seqHeader.Number.Uint64()
720720
t.Logf("Sequencer at height: %d before shutdown", seqFinalHeight)
721721

722+
seqBlock, err := seqClient.BlockByNumber(ctx, new(big.Int).SetUint64(seqFinalHeight))
723+
require.NoError(t, err, "sequencer should have block %d", seqFinalHeight)
724+
722725
// Stop sequencer so it stops producing new blocks.
723726
err = seqProcess.Signal(syscall.SIGTERM)
724727
require.NoError(t, err, "failed to stop sequencer process")
@@ -740,6 +743,11 @@ func TestEvmSequencerCatchUpBasedSequencerE2E(t *testing.T) {
740743
require.NoError(t, err)
741744
t.Logf("Full node caught up to height: %d (sequencer was at %d)", fnHeader.Number.Uint64(), seqFinalHeight)
742745

746+
// Normal flow: last sequencer block equal last sync node block
747+
fnBlock, err := fnClient.BlockByNumber(ctx, new(big.Int).SetUint64(fnHeader.Number.Uint64()))
748+
require.NoError(t, err)
749+
require.Equal(t, seqBlock.Hash(), fnBlock.Hash())
750+
743751
// Stop sync node process
744752
err = fnProcess.Signal(syscall.SIGTERM)
745753
require.NoError(t, err, "failed to stop full node process")
@@ -775,6 +783,11 @@ func TestEvmSequencerCatchUpBasedSequencerE2E(t *testing.T) {
775783
require.NoError(t, err)
776784
defer basedSeqClient.Close()
777785

786+
// Normal flow: last sequencer block equal last based sequencer block
787+
baseSeqBlock, err := basedSeqClient.BlockByNumber(ctx, new(big.Int).SetUint64(fnHeader.Number.Uint64()))
788+
require.NoError(t, err)
789+
require.Equal(t, seqBlock.Hash(), baseSeqBlock.Hash(), "based sequencer block is not equal to last sequencer block")
790+
778791
t.Log("Phase 5: Submit Forced Inclusion Transactions to DA")
779792

780793
blobClient, err := blobrpc.NewClient(ctx, env.Endpoints.GetDAAddress(), "", "")
@@ -850,6 +863,7 @@ func TestEvmSequencerCatchUpBasedSequencerE2E(t *testing.T) {
850863
"--evnode.clear_cache",
851864
"--evm.engine-url", env.Endpoints.GetFullNodeEngineURL(),
852865
"--evm.eth-url", env.Endpoints.GetFullNodeEthURL(),
866+
"--evnode.log.level", "error",
853867
)
854868
sut.AwaitNodeLive(t, env.Endpoints.GetFullNodeRPCAddress(), NodeStartupTimeout)
855869
t.Log("Sync node restarted as normal full node")
@@ -924,10 +938,10 @@ func TestEvmSequencerCatchUpBasedSequencerE2E(t *testing.T) {
924938
for h := uint64(1); h <= basedSeqFinalHeight; h++ {
925939
height := new(big.Int).SetUint64(h)
926940

927-
seqBlock, err := seqClient.BlockByNumber(ctx, height)
941+
seqBlock, err = seqClient.BlockByNumber(ctx, height)
928942
require.NoError(t, err, "sequencer should have block %d", h)
929943

930-
fnBlock, err := fnClient.BlockByNumber(ctx, height)
944+
fnBlock, err = fnClient.BlockByNumber(ctx, height)
931945
require.NoError(t, err, "full node should have block %d", h)
932946

933947
seqTime := seqBlock.Time()
@@ -951,9 +965,6 @@ func TestEvmSequencerCatchUpBasedSequencerE2E(t *testing.T) {
951965
require.Equal(t, len(seqBlock.Transactions()), len(fnBlock.Transactions()),
952966
"tx count mismatch at height %d: sequencer=%d fullnode=%d",
953967
h, len(seqBlock.Transactions()), len(fnBlock.Transactions()))
954-
955-
t.Logf("✅ Block %d matches: hash=%s stateRoot=%s txs=%d",
956-
h, seqBlock.Hash().Hex(), seqBlock.Root().Hex(), len(seqBlock.Transactions()))
957968
}
958969
t.Logf("All %d blocks match between sequencer and full node", basedSeqFinalHeight)
959970

@@ -1048,7 +1059,8 @@ func TestEvmBasedSequencerBaselineE2E(t *testing.T) {
10481059
"--evm.eth-url", env.Endpoints.GetSequencerEthURL(),
10491060
"--evnode.log.level", "debug",
10501061
)
1051-
sut.AwaitNodeUp(t, env.Endpoints.GetRollkitRPCAddress(), NodeStartupTimeout)
1062+
// We cannot use AwaitNodeUp immediatly, as a base sequencer does not create blocks until getting txs from DA.
1063+
// sut.AwaitNodeUp(t, env.Endpoints.GetRollkitRPCAddress(), NodeStartupTimeout)
10521064
t.Log("Based sequencer is up")
10531065

10541066
// Connect to based sequencer
@@ -1094,7 +1106,6 @@ func TestEvmBasedSequencerBaselineE2E(t *testing.T) {
10941106
t.Log("Advancing DA past epoch boundary...")
10951107
time.Sleep(4 * time.Second)
10961108

1097-
// ===== VERIFY BASED SEQUENCER INCLUDES FORCED TXS =====
10981109
t.Log("Waiting for based sequencer to include forced inclusion txs")
10991110

11001111
for i, txHash := range forcedTxHashes {
@@ -1108,5 +1119,6 @@ func TestEvmBasedSequencerBaselineE2E(t *testing.T) {
11081119
// Verify blocks are being produced
11091120
header, err := basedSeqClient.HeaderByNumber(ctx, nil)
11101121
require.NoError(t, err)
1122+
require.GreaterOrEqual(t, header.Number.Uint64(), uint64(2))
11111123
t.Logf("Based sequencer height: %d", header.Number.Uint64())
11121124
}

0 commit comments

Comments
 (0)