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
10c7f186
Unverified
Commit
10c7f186
authored
Nov 22, 2021
by
Conner Fromknecht
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: create batch params from L2 blocks
parent
5c5fcaa0
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
240 additions
and
0 deletions
+240
-0
batch.go
go/batch-submitter/drivers/sequencer/batch.go
+191
-0
batch_test.go
go/batch-submitter/drivers/sequencer/batch_test.go
+49
-0
No files found.
go/batch-submitter/drivers/sequencer/batch.go
0 → 100644
View file @
10c7f186
package
sequencer
import
(
"errors"
"fmt"
l2types
"github.com/ethereum-optimism/optimism/l2geth/core/types"
)
var
(
// ErrBlockWithInvalidContext signals an attempt to generate a
// BatchContext that specifies a total of zero txs.
ErrBlockWithInvalidContext
=
errors
.
New
(
"attempted to generate batch "
+
"context with 0 queued and 0 sequenced txs"
)
)
// BatchElement reflects the contents of an atomic update to the L2 state.
// Currently, each BatchElement is constructed from a single block containing
// exactly one tx.
type
BatchElement
struct
{
// Timestamp is the L1 timestamp of the batch.
Timestamp
uint64
// BlockNumber is the L1 BlockNumber of the batch.
BlockNumber
uint64
// Tx is the optional transaction that was applied in this batch.
//
// NOTE: This field will only be populated for sequencer txs.
Tx
*
l2types
.
Transaction
}
// IsSequencerTx returns true if this batch contains a tx that needs to be
// posted to the L1 CTC contract.
func
(
b
*
BatchElement
)
IsSequencerTx
()
bool
{
return
b
.
Tx
!=
nil
}
// BatchElementFromBlock constructs a BatchElement from a single L2 block. This
// method expects that there is exactly ONE tx per block. The returned
// BatchElement will reflect whether or not the lone tx is a sequencer tx or a
// queued tx.
func
BatchElementFromBlock
(
block
*
l2types
.
Block
)
BatchElement
{
txs
:=
block
.
Transactions
()
if
len
(
txs
)
!=
1
{
panic
(
fmt
.
Sprintf
(
"attempting to create batch element from block %d, "
+
"found %d txs instead of 1"
,
block
.
Number
(),
len
(
txs
)))
}
tx
:=
txs
[
0
]
// Extract L2 metadata.
l1BlockNumber
:=
tx
.
L1BlockNumber
()
.
Uint64
()
isSequencerTx
:=
tx
.
QueueOrigin
()
==
l2types
.
QueueOriginSequencer
// Only include sequencer txs in the returned BatchElement.
if
!
isSequencerTx
{
tx
=
nil
}
return
BatchElement
{
Timestamp
:
block
.
Time
(),
BlockNumber
:
l1BlockNumber
,
Tx
:
tx
,
}
}
type
groupedBlock
struct
{
sequenced
[]
BatchElement
queued
[]
BatchElement
}
// GenSequencerBatchParams generates a valid AppendSequencerBatchParams from a
// list of BatchElements. The BatchElements are assumed to be ordered in
// ascending order by L2 block height.
func
GenSequencerBatchParams
(
shouldStartAtElement
uint64
,
blockOffset
uint64
,
batch
[]
BatchElement
,
)
(
*
AppendSequencerBatchParams
,
error
)
{
var
(
contexts
[]
BatchContext
groupedBlocks
[]
groupedBlock
txs
[]
*
l2types
.
Transaction
lastBlockIsSequencerTx
bool
lastTimestamp
uint64
lastBlockNumber
uint64
)
// Iterate over the batch elements, grouping the elements according to
// the following critera:
// - All sequencer txs in the same group must have the same timestamp
// and block number.
// - If sequencer txs exist in a group, they must come before all
// queued txs.
// - A group should never split consecutive queued txs.
//
// Assuming the block and timestamp criteria for sequencer txs are
// respected within each group, the following are examples of groupings:
// - [s] // sequencer can exist by itself
// - [q] // ququed tx can exist by itself
// - [s] [s] // differing sequencer tx timestamp/blocknumber
// - [s q] [s] // sequencer tx must precede queued tx in group
// - [q] [q s] // INVALID: consecutive queued txs are split
// - [q q] [s] // correct split for preceding case
// - [s q] [s q] // alternating sequencer tx interleaved with queued
for
_
,
el
:=
range
batch
{
// To enforce the above groupings, the following condition is
// used to determine when to create a new batch:
// - On the first pass, or
// - Whenever a sequecer tx is observed, and:
// - The preceding tx was a queued tx, or
// - The preceding sequencer tx has a different
// block number/timestamp.
// Note that a sequencer tx is required to create a new group,
// so a queued tx may ONLY exist as the first element in a group
// if it is the very first element.
needsNewGroupOnSequencerTx
:=
!
lastBlockIsSequencerTx
||
el
.
Timestamp
!=
lastTimestamp
||
el
.
BlockNumber
!=
lastBlockNumber
if
len
(
groupedBlocks
)
==
0
||
(
el
.
IsSequencerTx
()
&&
needsNewGroupOnSequencerTx
)
{
groupedBlocks
=
append
(
groupedBlocks
,
groupedBlock
{})
}
// Append the tx to either the sequenced or queued txs,
// depending on its type.
cur
:=
len
(
groupedBlocks
)
-
1
if
el
.
IsSequencerTx
()
{
groupedBlocks
[
cur
]
.
sequenced
=
append
(
groupedBlocks
[
cur
]
.
sequenced
,
el
)
// Gather all sequencer txs, as these will be encoded in
// the calldata of the batch tx submitted to the L1 CTC
// contract.
txs
=
append
(
txs
,
el
.
Tx
)
}
else
{
groupedBlocks
[
cur
]
.
queued
=
append
(
groupedBlocks
[
cur
]
.
queued
,
el
)
}
lastBlockIsSequencerTx
=
el
.
IsSequencerTx
()
lastTimestamp
=
el
.
Timestamp
lastBlockNumber
=
el
.
BlockNumber
}
// For each group, construct the resulting BatchContext.
for
_
,
block
:=
range
groupedBlocks
{
numSequencedTxs
:=
uint64
(
len
(
block
.
sequenced
))
numSubsequentQueueTxs
:=
uint64
(
len
(
block
.
queued
))
// Ensure at least one tx was included in this group.
if
numSequencedTxs
==
0
&&
numSubsequentQueueTxs
==
0
{
return
nil
,
ErrBlockWithInvalidContext
}
// Compute the timestamp and block number from for the batch
// using either the earliest sequenced tx or the earliest queued
// tx. If a batch has a sequencer tx it is given preference,
// since it is guaranteed to be the earliest item in the group.
// Otherwise, we fallback to the earliest queued tx since it was
// the very first item.
var
(
timestamp
uint64
blockNumber
uint64
)
if
numSequencedTxs
>
0
{
timestamp
=
block
.
sequenced
[
0
]
.
Timestamp
blockNumber
=
block
.
sequenced
[
0
]
.
BlockNumber
}
else
{
timestamp
=
block
.
queued
[
0
]
.
Timestamp
blockNumber
=
block
.
queued
[
0
]
.
BlockNumber
}
contexts
=
append
(
contexts
,
BatchContext
{
NumSequencedTxs
:
numSequencedTxs
,
NumSubsequentQueueTxs
:
numSubsequentQueueTxs
,
Timestamp
:
timestamp
,
BlockNumber
:
blockNumber
,
})
}
return
&
AppendSequencerBatchParams
{
ShouldStartAtElement
:
shouldStartAtElement
-
blockOffset
,
TotalElementsToAppend
:
uint64
(
len
(
batch
)),
Contexts
:
contexts
,
Txs
:
txs
,
},
nil
}
go/batch-submitter/drivers/sequencer/batch_test.go
0 → 100644
View file @
10c7f186
package
sequencer_test
import
(
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/go/batch-submitter/drivers/sequencer"
l2common
"github.com/ethereum-optimism/optimism/l2geth/common"
l2types
"github.com/ethereum-optimism/optimism/l2geth/core/types"
"github.com/stretchr/testify/require"
)
func
TestBatchElementFromBlock
(
t
*
testing
.
T
)
{
expTime
:=
uint64
(
42
)
expBlockNumber
:=
uint64
(
43
)
header
:=
&
l2types
.
Header
{
Time
:
expTime
,
}
expTx
:=
l2types
.
NewTransaction
(
1
,
l2common
.
Address
{},
new
(
big
.
Int
)
.
SetUint64
(
2
),
3
,
new
(
big
.
Int
)
.
SetUint64
(
4
),
[]
byte
{},
)
expTx
.
SetL1BlockNumber
(
expBlockNumber
)
txs
:=
[]
*
l2types
.
Transaction
{
expTx
}
block
:=
l2types
.
NewBlock
(
header
,
txs
,
nil
,
nil
)
element
:=
sequencer
.
BatchElementFromBlock
(
block
)
require
.
Equal
(
t
,
element
.
Timestamp
,
expTime
)
require
.
Equal
(
t
,
element
.
BlockNumber
,
expBlockNumber
)
require
.
True
(
t
,
element
.
IsSequencerTx
())
require
.
Equal
(
t
,
element
.
Tx
,
expTx
)
queueMeta
:=
l2types
.
NewTransactionMeta
(
new
(
big
.
Int
)
.
SetUint64
(
expBlockNumber
),
0
,
nil
,
l2types
.
QueueOriginL1ToL2
,
nil
,
nil
,
nil
,
)
expTx
.
SetTransactionMeta
(
queueMeta
)
element
=
sequencer
.
BatchElementFromBlock
(
block
)
require
.
Equal
(
t
,
element
.
Timestamp
,
expTime
)
require
.
Equal
(
t
,
element
.
BlockNumber
,
expBlockNumber
)
require
.
False
(
t
,
element
.
IsSequencerTx
())
require
.
Nil
(
t
,
element
.
Tx
)
}
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