Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
2006da2e
Unverified
Commit
2006da2e
authored
Nov 02, 2023
by
protolambda
Committed by
GitHub
Nov 02, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7813 from testinprod-io/tip/span-batch-hard-fork-condition-spec-refactor
Span Batch Hard Fork Activation Rule Update
parents
fea98f4d
6646032d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
75 additions
and
18 deletions
+75
-18
batches.go
op-node/rollup/derive/batches.go
+14
-6
batches_test.go
op-node/rollup/derive/batches_test.go
+32
-4
channel_in_reader.go
op-node/rollup/derive/channel_in_reader.go
+3
-0
span-batches.md
specs/span-batches.md
+18
-0
superchain-upgrades.md
specs/superchain-upgrades.md
+8
-8
No files found.
op-node/rollup/derive/batches.go
View file @
2006da2e
...
@@ -47,10 +47,6 @@ func CheckBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1Block
...
@@ -47,10 +47,6 @@ func CheckBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1Block
log
.
Error
(
"failed type assertion to SpanBatch"
)
log
.
Error
(
"failed type assertion to SpanBatch"
)
return
BatchDrop
return
BatchDrop
}
}
if
!
cfg
.
IsSpanBatch
(
batch
.
Batch
.
GetTimestamp
())
{
log
.
Warn
(
"received SpanBatch before SpanBatch hard fork"
)
return
BatchDrop
}
return
checkSpanBatch
(
ctx
,
cfg
,
log
,
l1Blocks
,
l2SafeHead
,
spanBatch
,
batch
.
L1InclusionBlock
,
l2Fetcher
)
return
checkSpanBatch
(
ctx
,
cfg
,
log
,
l1Blocks
,
l2SafeHead
,
spanBatch
,
batch
.
L1InclusionBlock
,
l2Fetcher
)
default
:
default
:
log
.
Warn
(
"Unrecognized batch type: %d"
,
batch
.
Batch
.
GetBatchType
())
log
.
Warn
(
"Unrecognized batch type: %d"
,
batch
.
Batch
.
GetBatchType
())
...
@@ -181,6 +177,20 @@ func checkSpanBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1B
...
@@ -181,6 +177,20 @@ func checkSpanBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1B
}
}
epoch
:=
l1Blocks
[
0
]
epoch
:=
l1Blocks
[
0
]
startEpochNum
:=
uint64
(
batch
.
GetStartEpochNum
())
batchOrigin
:=
epoch
if
startEpochNum
==
batchOrigin
.
Number
+
1
{
if
len
(
l1Blocks
)
<
2
{
log
.
Info
(
"eager batch wants to advance epoch, but could not without more L1 blocks"
,
"current_epoch"
,
epoch
.
ID
())
return
BatchUndecided
}
batchOrigin
=
l1Blocks
[
1
]
}
if
!
cfg
.
IsSpanBatch
(
batchOrigin
.
Time
)
{
log
.
Warn
(
"received SpanBatch with L1 origin before SpanBatch hard fork"
)
return
BatchDrop
}
nextTimestamp
:=
l2SafeHead
.
Time
+
cfg
.
BlockTime
nextTimestamp
:=
l2SafeHead
.
Time
+
cfg
.
BlockTime
if
batch
.
GetTimestamp
()
>
nextTimestamp
{
if
batch
.
GetTimestamp
()
>
nextTimestamp
{
...
@@ -220,8 +230,6 @@ func checkSpanBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1B
...
@@ -220,8 +230,6 @@ func checkSpanBatch(ctx context.Context, cfg *rollup.Config, log log.Logger, l1B
return
BatchDrop
return
BatchDrop
}
}
startEpochNum
:=
uint64
(
batch
.
GetStartEpochNum
())
// Filter out batches that were included too late.
// Filter out batches that were included too late.
if
startEpochNum
+
cfg
.
SeqWindowSize
<
l1InclusionBlock
.
Number
{
if
startEpochNum
+
cfg
.
SeqWindowSize
<
l1InclusionBlock
.
Number
{
log
.
Warn
(
"batch was included too late, sequence window expired"
)
log
.
Warn
(
"batch was included too late, sequence window expired"
)
...
...
op-node/rollup/derive/batches_test.go
View file @
2006da2e
...
@@ -711,6 +711,33 @@ func TestValidBatch(t *testing.T) {
...
@@ -711,6 +711,33 @@ func TestValidBatch(t *testing.T) {
}),
}),
},
},
Expected
:
BatchUndecided
,
Expected
:
BatchUndecided
,
ExpectedLog
:
"eager batch wants to advance epoch, but could not without more L1 blocks"
,
SpanBatchTime
:
&
minTs
,
},
{
Name
:
"insufficient L1 info for eager derivation - long span"
,
L1Blocks
:
[]
eth
.
L1BlockRef
{
l1A
},
// don't know about l1B yet
L2SafeHead
:
l2A2
,
Batch
:
BatchWithL1InclusionBlock
{
L1InclusionBlock
:
l1C
,
Batch
:
NewSpanBatch
([]
*
SingularBatch
{
{
ParentHash
:
l2A3
.
ParentHash
,
EpochNum
:
rollup
.
Epoch
(
l2A3
.
L1Origin
.
Number
),
EpochHash
:
l2A3
.
L1Origin
.
Hash
,
Timestamp
:
l2A3
.
Time
,
Transactions
:
nil
,
},
{
ParentHash
:
l2B0
.
ParentHash
,
EpochNum
:
rollup
.
Epoch
(
l2B0
.
L1Origin
.
Number
),
EpochHash
:
l2B0
.
L1Origin
.
Hash
,
Timestamp
:
l2B0
.
Time
,
Transactions
:
nil
,
},
}),
},
Expected
:
BatchUndecided
,
ExpectedLog
:
"need more l1 blocks to check entire origins of span batch"
,
ExpectedLog
:
"need more l1 blocks to check entire origins of span batch"
,
SpanBatchTime
:
&
minTs
,
SpanBatchTime
:
&
minTs
,
},
},
...
@@ -1413,7 +1440,7 @@ func TestValidBatch(t *testing.T) {
...
@@ -1413,7 +1440,7 @@ func TestValidBatch(t *testing.T) {
Transactions
:
[]
hexutil
.
Bytes
{
randTxData
},
Transactions
:
[]
hexutil
.
Bytes
{
randTxData
},
},
},
},
},
SpanBatchTime
:
&
l
2A2
.
Time
,
SpanBatchTime
:
&
l
1B
.
Time
,
Expected
:
BatchAccept
,
Expected
:
BatchAccept
,
},
},
{
{
...
@@ -1432,8 +1459,9 @@ func TestValidBatch(t *testing.T) {
...
@@ -1432,8 +1459,9 @@ func TestValidBatch(t *testing.T) {
},
},
}),
}),
},
},
SpanBatchTime
:
&
l
2A2
.
Time
,
SpanBatchTime
:
&
l
1B
.
Time
,
Expected
:
BatchDrop
,
Expected
:
BatchDrop
,
ExpectedLog
:
"received SpanBatch with L1 origin before SpanBatch hard fork"
,
},
},
{
{
Name
:
"singular batch after hard fork"
,
Name
:
"singular batch after hard fork"
,
...
@@ -1449,7 +1477,7 @@ func TestValidBatch(t *testing.T) {
...
@@ -1449,7 +1477,7 @@ func TestValidBatch(t *testing.T) {
Transactions
:
[]
hexutil
.
Bytes
{
randTxData
},
Transactions
:
[]
hexutil
.
Bytes
{
randTxData
},
},
},
},
},
SpanBatchTime
:
&
l
2A0
.
Time
,
SpanBatchTime
:
&
l
1A
.
Time
,
Expected
:
BatchAccept
,
Expected
:
BatchAccept
,
},
},
{
{
...
@@ -1468,7 +1496,7 @@ func TestValidBatch(t *testing.T) {
...
@@ -1468,7 +1496,7 @@ func TestValidBatch(t *testing.T) {
},
},
}),
}),
},
},
SpanBatchTime
:
&
l
2A0
.
Time
,
SpanBatchTime
:
&
l
1A
.
Time
,
Expected
:
BatchAccept
,
Expected
:
BatchAccept
,
},
},
}
}
...
...
op-node/rollup/derive/channel_in_reader.go
View file @
2006da2e
...
@@ -99,6 +99,9 @@ func (cr *ChannelInReader) NextBatch(ctx context.Context) (Batch, error) {
...
@@ -99,6 +99,9 @@ func (cr *ChannelInReader) NextBatch(ctx context.Context) (Batch, error) {
return
singularBatch
,
nil
return
singularBatch
,
nil
case
SpanBatchType
:
case
SpanBatchType
:
if
origin
:=
cr
.
Origin
();
!
cr
.
cfg
.
IsSpanBatch
(
origin
.
Time
)
{
if
origin
:=
cr
.
Origin
();
!
cr
.
cfg
.
IsSpanBatch
(
origin
.
Time
)
{
// Check hard fork activation with the L1 inclusion block time instead of the L1 origin block time.
// Therefore, even if the batch passed this rule, it can be dropped in the batch queue.
// This is just for early dropping invalid batches as soon as possible.
return
nil
,
NewTemporaryError
(
fmt
.
Errorf
(
"cannot accept span batch in L1 block %s at time %d"
,
origin
,
origin
.
Time
))
return
nil
,
NewTemporaryError
(
fmt
.
Errorf
(
"cannot accept span batch in L1 block %s at time %d"
,
origin
,
origin
.
Time
))
}
}
rawSpanBatch
,
ok
:=
batchData
.
inner
.
(
*
RawSpanBatch
)
rawSpanBatch
,
ok
:=
batchData
.
inner
.
(
*
RawSpanBatch
)
...
...
specs/span-batches.md
View file @
2006da2e
...
@@ -9,6 +9,7 @@
...
@@ -9,6 +9,7 @@
-
[
Introduction
](
#introduction
)
-
[
Introduction
](
#introduction
)
-
[
Span batch format
](
#span-batch-format
)
-
[
Span batch format
](
#span-batch-format
)
-
[
Span batch Activation Rule
](
#span-batch-activation-rule
)
-
[
Optimization Strategies
](
#optimization-strategies
)
-
[
Optimization Strategies
](
#optimization-strategies
)
-
[
Truncating information and storing only necessary data
](
#truncating-information-and-storing-only-necessary-data
)
-
[
Truncating information and storing only necessary data
](
#truncating-information-and-storing-only-necessary-data
)
-
[
`tx_data_headers` removal from initial specs
](
#tx_data_headers-removal-from-initial-specs
)
-
[
`tx_data_headers` removal from initial specs
](
#tx_data_headers-removal-from-initial-specs
)
...
@@ -153,6 +154,16 @@ decoding. For example, lets say bad batcher wrote span batch which `block_count
...
@@ -153,6 +154,16 @@ decoding. For example, lets say bad batcher wrote span batch which `block_count
the explicit limit, not trying to consume data until EOF is reached. We can also safely preallocate memory for decoding
the explicit limit, not trying to consume data until EOF is reached. We can also safely preallocate memory for decoding
because we know the upper limit of memory usage.
because we know the upper limit of memory usage.
## Span batch Activation Rule
The span batch upgrade is activated based on timestamp.
Activation Rule:
`upgradeTime != null && span_start.l1_origin.timestamp >= upgradeTime`
`span_start.l1_origin.timestamp`
is the L1 origin block timestamp of the first block in the span batch.
This rule ensures that every chain activity regarding this span batch is done after the hard fork.
i.e. Every block in the span is created, submitted to the L1, and derived from the L1 after the hard fork.
## Optimization Strategies
## Optimization Strategies
### Truncating information and storing only necessary data
### Truncating information and storing only necessary data
...
@@ -261,6 +272,13 @@ Rules are enforced with the [contextual definitions](./derivation.md#batch-queue
...
@@ -261,6 +272,13 @@ Rules are enforced with the [contextual definitions](./derivation.md#batch-queue
Span-batch rules, in validation order:
Span-batch rules, in validation order:
-
`batch_origin`
is determined like with singular batches:
-
`batch.epoch_num == epoch.number+1`
:
-
If
`next_epoch`
is not known ->
`undecided`
:
i.e. a batch that changes the L1 origin cannot be processed until we have the L1 origin data.
-
If known, then define
`batch_origin`
as
`next_epoch`
-
`batch_origin.timestamp < span_batch_upgrade_timestamp`
->
`drop`
:
i.e. enforce the
[
span batch upgrade activation rule
](
#span-batch-activation-rule
)
.
-
`batch.start_timestamp > next_timestamp`
->
`future`
: i.e. the batch must be ready to process.
-
`batch.start_timestamp > next_timestamp`
->
`future`
: i.e. the batch must be ready to process.
-
`batch.start_timestamp < next_timestamp`
->
`drop`
: i.e. the batch must not be too old.
-
`batch.start_timestamp < next_timestamp`
->
`drop`
: i.e. the batch must not be too old.
-
`batch.parent_check != safe_l2_head.hash[:20]`
->
`drop`
: i.e. the checked part of the parent hash must be equal
-
`batch.parent_check != safe_l2_head.hash[:20]`
->
`drop`
: i.e. the checked part of the parent hash must be equal
...
...
specs/superchain-upgrades.md
View file @
2006da2e
...
@@ -199,7 +199,10 @@ and are then retrieved from the superchain target configuration.
...
@@ -199,7 +199,10 @@ and are then retrieved from the superchain target configuration.
### L2 Block-number based activation (deprecated)
### L2 Block-number based activation (deprecated)
Activation rule:
`x != null && x >= upgradeNumber`
Activation rule:
`upgradeNumber != null && block.number >= upgradeNumber`
Starting at, and including, the L2
`block`
with
`block.number >= upgradeNumber`
, the upgrade rules apply.
If the upgrade block-number
`upgradeNumber`
is not specified in the configuration, the upgrade is ignored.
This block number based method has commonly been used in L1 up until the Bellatrix/Paris upgrade, a.k.a. The Merge,
This block number based method has commonly been used in L1 up until the Bellatrix/Paris upgrade, a.k.a. The Merge,
which was upgraded through special rules.
which was upgraded through special rules.
...
@@ -207,22 +210,19 @@ which was upgraded through special rules.
...
@@ -207,22 +210,19 @@ which was upgraded through special rules.
This method is not superchain-compatible, as the activation-parameter is chain-specific
This method is not superchain-compatible, as the activation-parameter is chain-specific
(different chains may have different block-heights at the same moment in time).
(different chains may have different block-heights at the same moment in time).
Starting at, and including, the L2
`block`
with
`block.number == x`
, the upgrade rules apply.
If the upgrade block-number
`x`
is not specified in the configuration, the upgrade is ignored.
This applies to the L2 block number, not to the L1-origin block number.
This applies to the L2 block number, not to the L1-origin block number.
This means that an L2 upgrade may be inactive, and then active, without changing the L1-origin.
This means that an L2 upgrade may be inactive, and then active, without changing the L1-origin.
### L2 Block-timestamp based activation
### L2 Block-timestamp based activation
Activation rule:
`x != null && x >= upgradeTime`
Activation rule:
`upgradeTime != null && block.timestamp >= upgradeTime`
Starting at, and including, the L2
`block`
with
`block.timestamp >= upgradeTime`
, the upgrade rules apply.
If the upgrade block-timestamp
`upgradeTime`
is not specified in the configuration, the upgrade is ignored.
This is the preferred superchain upgrade activation-parameter type:
This is the preferred superchain upgrade activation-parameter type:
it is synchronous between all L2 chains and compatible with post-Merge timestamp-based chain upgrades in L1.
it is synchronous between all L2 chains and compatible with post-Merge timestamp-based chain upgrades in L1.
Starting at, and including, the L2
`block`
with
`block.timestamp == x`
, the upgrade rules apply.
If the upgrade block-timestamp
`x`
is not specified in the configuration, the upgrade is ignored.
This applies to the L2 block timestamp, not to the L1-origin block timestamp.
This applies to the L2 block timestamp, not to the L1-origin block timestamp.
This means that an L2 upgrade may be inactive, and then active, without changing the L1-origin.
This means that an L2 upgrade may be inactive, and then active, without changing the L1-origin.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment