Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fjord: Implement max sequencer drift change to a constant #10465

Merged
merged 8 commits into from
May 10, 2024
2 changes: 1 addition & 1 deletion op-e2e/actions/l2_sequencer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func TestL2Sequencer_SequencerDrift(gt *testing.T) {
sequencer.ActL1HeadSignal(t)

// Make blocks up till the sequencer drift is about to surpass, but keep the old L1 origin
for sequencer.SyncStatus().UnsafeL2.Time+sd.RollupCfg.BlockTime <= origin.Time+sd.RollupCfg.MaxSequencerDrift {
for sequencer.SyncStatus().UnsafeL2.Time+sd.RollupCfg.BlockTime <= origin.Time+sd.ChainSpec.MaxSequencerDrift(origin.Time) {
sequencer.ActL2KeepL1Origin(t)
makeL2BlockWithAliceTx()
require.Equal(t, uint64(1), sequencer.SyncStatus().UnsafeL2.L1Origin.Number, "expected to keep old L1 origin")
Expand Down
2 changes: 2 additions & 0 deletions op-e2e/e2eutils/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type SetupData struct {
L1Cfg *core.Genesis
L2Cfg *core.Genesis
RollupCfg *rollup.Config
ChainSpec *rollup.ChainSpec
DeploymentsL1 *genesis.L1Deployments
}

Expand Down Expand Up @@ -187,6 +188,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
L1Cfg: l1Genesis,
L2Cfg: l2Genesis,
RollupCfg: rollupCfg,
ChainSpec: rollup.NewChainSpec(rollupCfg),
DeploymentsL1: l1Deployments,
}
}
Expand Down
22 changes: 22 additions & 0 deletions op-node/rollup/chain_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const (
// TODO(#10428) Remove this parameter
const SafeMaxRLPBytesPerChannel = maxRLPBytesPerChannelBedrock

// Fjord changes the max sequencer drift to a protocol constant. It was previously configurable via
// the rollup config.
// From Fjord, the max sequencer drift for a given block timestamp should be learned via the
// ChainSpec instead of reading the rollup configuration field directly.
const maxSequencerDriftFjord = 1800

type ChainSpec struct {
config *Config
}
Expand Down Expand Up @@ -55,3 +61,19 @@ func (s *ChainSpec) MaxRLPBytesPerChannel(t uint64) uint64 {
}
return maxRLPBytesPerChannelBedrock
}

// IsFeatMaxSequencerDriftConstant specifies in which fork the max sequencer drift change to a
// constant will be performed.
func (s *ChainSpec) IsFeatMaxSequencerDriftConstant(t uint64) bool {
sebastianst marked this conversation as resolved.
Show resolved Hide resolved
return s.config.IsFjord(t)
}

// MaxSequencerDrift returns the maximum sequencer drift for the given block timestamp. Until Fjord,
// this was a rollup configuration parameter. Since Fjord, it is a constant, so its effective value
// should always be queried via the ChainSpec.
func (s *ChainSpec) MaxSequencerDrift(t uint64) uint64 {
if s.IsFeatMaxSequencerDriftConstant(t) {
return maxSequencerDriftFjord
}
return s.config.MaxSequencerDrift
}
29 changes: 26 additions & 3 deletions op-node/rollup/chain_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ var testConfig = Config{
UsePlasma: false,
}

func TestCanyonForkActivation(t *testing.T) {
func TestChainSpec_CanyonForkActivation(t *testing.T) {
c := NewChainSpec(&testConfig)
tests := []struct {
name string
Expand All @@ -74,7 +74,7 @@ func TestCanyonForkActivation(t *testing.T) {
}
}

func TestMaxChannelBankSize(t *testing.T) {
func TestChainSpec_MaxChannelBankSize(t *testing.T) {
c := NewChainSpec(&testConfig)
tests := []struct {
name string
Expand All @@ -97,7 +97,7 @@ func TestMaxChannelBankSize(t *testing.T) {
}
}

func TestMaxRLPBytesPerChannel(t *testing.T) {
func TestChainSpec_MaxRLPBytesPerChannel(t *testing.T) {
c := NewChainSpec(&testConfig)
tests := []struct {
name string
Expand All @@ -119,3 +119,26 @@ func TestMaxRLPBytesPerChannel(t *testing.T) {
})
}
}

func TestChainSpec_MaxSequencerDrift(t *testing.T) {
c := NewChainSpec(&testConfig)
tests := []struct {
name string
blockNum uint64
expected uint64
description string
}{
{"Genesis", 0, testConfig.MaxSequencerDrift, "Before Fjord activation, should use rollup config value"},
{"FjordTimeMinusOne", 49, testConfig.MaxSequencerDrift, "Just before Fjord, should still use rollup config value"},
{"FjordTime", 50, maxSequencerDriftFjord, "At Fjord activation, should switch to Fjord constant"},
{"FjordTimePlusOne", 51, maxSequencerDriftFjord, "After Fjord activation, should use Fjord constant"},
{"NextForkTime", 60, maxSequencerDriftFjord, "Well after Fjord, should continue to use Fjord constant"},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := c.MaxSequencerDrift(tt.blockNum)
require.Equal(t, tt.expected, result, tt.description)
})
}
}
18 changes: 9 additions & 9 deletions op-node/rollup/derive/batches.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const (
// The first entry of the l1Blocks should match the origin of the l2SafeHead. One or more consecutive l1Blocks should be provided.
// In case of only a single L1 block, the decision whether a batch is valid may have to stay undecided.
func CheckBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1Blocks []eth.L1BlockRef,
l2SafeHead eth.L2BlockRef, batch *BatchWithL1InclusionBlock, l2Fetcher SafeBlockFetcher) BatchValidity {
l2SafeHead eth.L2BlockRef, batch *BatchWithL1InclusionBlock, l2Fetcher SafeBlockFetcher,
) BatchValidity {
switch batch.Batch.GetBatchType() {
case SingularBatchType:
singularBatch, ok := batch.Batch.(*SingularBatch)
Expand Down Expand Up @@ -122,8 +123,9 @@ func checkSingularBatch(cfg *rollup.Config, log log.Logger, l1Blocks []eth.L1Blo
return BatchDrop
}

spec := rollup.NewChainSpec(cfg)
// Check if we ran out of sequencer time drift
if max := batchOrigin.Time + cfg.MaxSequencerDrift; batch.Timestamp > max {
if max := batchOrigin.Time + spec.MaxSequencerDrift(batchOrigin.Time); batch.Timestamp > max {
if len(batch.Transactions) == 0 {
// If the sequencer is co-operating by producing an empty batch,
// then allow the batch if it was the right thing to do to maintain the L2 time >= L1 time invariant.
Expand Down Expand Up @@ -166,7 +168,8 @@ func checkSingularBatch(cfg *rollup.Config, log log.Logger, l1Blocks []eth.L1Blo

// checkSpanBatch implements SpanBatch validation rule.
func checkSpanBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1Blocks []eth.L1BlockRef, l2SafeHead eth.L2BlockRef,
batch *SpanBatch, l1InclusionBlock eth.L1BlockRef, l2Fetcher SafeBlockFetcher) BatchValidity {
batch *SpanBatch, l1InclusionBlock eth.L1BlockRef, l2Fetcher SafeBlockFetcher,
) BatchValidity {
// add details to the log
log = batch.LogContext(log)

Expand Down Expand Up @@ -266,10 +269,7 @@ func checkSpanBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1B
}

originIdx := 0
originAdvanced := false
if startEpochNum == parentBlock.L1Origin.Number+1 {
originAdvanced = true
}
originAdvanced := startEpochNum == parentBlock.L1Origin.Number+1

for i := 0; i < batch.GetBlockCount(); i++ {
if batch.GetBlockTimestamp(i) <= l2SafeHead.Time {
Expand All @@ -282,7 +282,6 @@ func checkSpanBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1B
originIdx = j
break
}

}
if i > 0 {
originAdvanced = false
Expand All @@ -296,8 +295,9 @@ func checkSpanBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1B
return BatchDrop
}

spec := rollup.NewChainSpec(cfg)
// Check if we ran out of sequencer time drift
if max := l1Origin.Time + cfg.MaxSequencerDrift; blockTimestamp > max {
if max := l1Origin.Time + spec.MaxSequencerDrift(l1Origin.Time); blockTimestamp > max {
if len(batch.GetBlockTransactions(i)) == 0 {
// If the sequencer is co-operating by producing an empty batch,
// then allow the batch if it was the right thing to do to maintain the L2 time >= L1 time invariant.
Expand Down
Loading