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
e9f8ae50
Unverified
Commit
e9f8ae50
authored
Mar 20, 2023
by
Brian Bland
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve select logic, avoid double-closure
parent
995e3e42
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
56 additions
and
49 deletions
+56
-49
channel_builder.go
op-batcher/batcher/channel_builder.go
+4
-5
channel_manager.go
op-batcher/batcher/channel_manager.go
+21
-14
channel_manager_test.go
op-batcher/batcher/channel_manager_test.go
+14
-22
driver.go
op-batcher/batcher/driver.go
+17
-8
No files found.
op-batcher/batcher/channel_builder.go
View file @
e9f8ae50
...
@@ -308,8 +308,8 @@ func (c *channelBuilder) IsFull() bool {
...
@@ -308,8 +308,8 @@ func (c *channelBuilder) IsFull() bool {
// FullErr returns the reason why the channel is full. If not full yet, it
// FullErr returns the reason why the channel is full. If not full yet, it
// returns nil.
// returns nil.
//
//
// It returns a ChannelFullError wrapping one of
six possible reasons for the
// It returns a ChannelFullError wrapping one of
the following possible reasons
// channel being full:
//
for the
channel being full:
// - ErrInputTargetReached if the target amount of input data has been reached,
// - ErrInputTargetReached if the target amount of input data has been reached,
// - derive.MaxRLPBytesPerChannel if the general maximum amount of input data
// - derive.MaxRLPBytesPerChannel if the general maximum amount of input data
// would have been exceeded by the latest AddBlock call,
// would have been exceeded by the latest AddBlock call,
...
@@ -405,12 +405,11 @@ func (c *channelBuilder) outputFrame() error {
...
@@ -405,12 +405,11 @@ func (c *channelBuilder) outputFrame() error {
}
}
// Close immediately marks the channel as full with an ErrTerminated
// Close immediately marks the channel as full with an ErrTerminated
// if the channel is not already full
, then outputs any remaining frames
.
// if the channel is not already full.
func
(
c
*
channelBuilder
)
Close
()
error
{
func
(
c
*
channelBuilder
)
Close
()
{
if
!
c
.
IsFull
()
{
if
!
c
.
IsFull
()
{
c
.
setFullErr
(
ErrTerminated
)
c
.
setFullErr
(
ErrTerminated
)
}
}
return
c
.
closeAndOutputAllFrames
()
}
}
// HasFrame returns whether there's any available frame. If true, it can be
// HasFrame returns whether there's any available frame. If true, it can be
...
...
op-batcher/batcher/channel_manager.go
View file @
e9f8ae50
...
@@ -81,12 +81,9 @@ func (s *channelManager) TxFailed(id txID) {
...
@@ -81,12 +81,9 @@ func (s *channelManager) TxFailed(id txID) {
}
}
s
.
metr
.
RecordBatchTxFailed
()
s
.
metr
.
RecordBatchTxFailed
()
// If this channel has no submitted transactions, put the pending blocks back into the
if
s
.
closed
&&
len
(
s
.
confirmedTransactions
)
==
0
&&
len
(
s
.
pendingTransactions
)
==
0
{
// local saved blocks and reset this state so it can try to build a new channel.
s
.
log
.
Info
(
"Channel has no submitted transactions, clearing for shutdown"
,
"chID"
,
s
.
pendingChannel
.
ID
())
if
len
(
s
.
confirmedTransactions
)
==
0
&&
len
(
s
.
pendingTransactions
)
==
0
{
s
.
Clear
()
s
.
log
.
Info
(
"Channel has no submitted transactions"
,
"chID"
,
s
.
pendingChannel
.
ID
())
s
.
blocks
=
append
(
s
.
pendingChannel
.
Blocks
(),
s
.
blocks
...
)
s
.
clearPendingChannel
()
}
}
}
}
...
@@ -194,11 +191,6 @@ func (s *channelManager) TxData(l1Head eth.BlockID) (txData, error) {
...
@@ -194,11 +191,6 @@ func (s *channelManager) TxData(l1Head eth.BlockID) (txData, error) {
return
s
.
nextTxData
()
return
s
.
nextTxData
()
}
}
// Avoid producing new frames if the channel has been explicitly closed.
if
s
.
closed
{
return
txData
{},
io
.
EOF
}
// No pending frame, so we have to add new blocks to the channel
// No pending frame, so we have to add new blocks to the channel
// If we have no saved blocks, we will not be able to create valid frames
// If we have no saved blocks, we will not be able to create valid frames
...
@@ -210,8 +202,11 @@ func (s *channelManager) TxData(l1Head eth.BlockID) (txData, error) {
...
@@ -210,8 +202,11 @@ func (s *channelManager) TxData(l1Head eth.BlockID) (txData, error) {
return
txData
{},
err
return
txData
{},
err
}
}
if
err
:=
s
.
processBlocks
();
err
!=
nil
{
// Avoid processing blocks if the channel manager has been explicitly closed.
return
txData
{},
err
if
!
s
.
closed
{
if
err
:=
s
.
processBlocks
();
err
!=
nil
{
return
txData
{},
err
}
}
}
// Register current L1 head only after all pending blocks have been
// Register current L1 head only after all pending blocks have been
...
@@ -365,9 +360,21 @@ func l2BlockRefFromBlockAndL1Info(block *types.Block, l1info derive.L1BlockInfo)
...
@@ -365,9 +360,21 @@ func l2BlockRefFromBlockAndL1Info(block *types.Block, l1info derive.L1BlockInfo)
// This ensures that no new frames will be produced, but there may be any number
// This ensures that no new frames will be produced, but there may be any number
// of pending frames produced before this call which should still be published.
// of pending frames produced before this call which should still be published.
func
(
s
*
channelManager
)
Close
()
error
{
func
(
s
*
channelManager
)
Close
()
error
{
if
s
.
closed
{
return
nil
}
s
.
closed
=
true
s
.
closed
=
true
// Any pending state can be proactively cleared if there are no submitted transactions
if
len
(
s
.
confirmedTransactions
)
==
0
&&
len
(
s
.
pendingTransactions
)
==
0
{
s
.
Clear
()
}
if
s
.
pendingChannel
==
nil
{
if
s
.
pendingChannel
==
nil
{
return
nil
return
nil
}
}
return
s
.
pendingChannel
.
Close
()
s
.
pendingChannel
.
Close
()
return
nil
}
}
op-batcher/batcher/channel_manager_test.go
View file @
e9f8ae50
...
@@ -332,11 +332,9 @@ func TestChannelManager_TxResend(t *testing.T) {
...
@@ -332,11 +332,9 @@ func TestChannelManager_TxResend(t *testing.T) {
log
:=
testlog
.
Logger
(
t
,
log
.
LvlError
)
log
:=
testlog
.
Logger
(
t
,
log
.
LvlError
)
m
:=
NewChannelManager
(
log
,
metrics
.
NoopMetrics
,
m
:=
NewChannelManager
(
log
,
metrics
.
NoopMetrics
,
ChannelConfig
{
ChannelConfig
{
TargetNumFrames
:
2
,
TargetFrameSize
:
0
,
TargetFrameSize
:
1000
,
MaxFrameSize
:
120
_000
,
MaxFrameSize
:
2000
,
ApproxComprRatio
:
1.0
,
ApproxComprRatio
:
1.0
,
ChannelTimeout
:
1000
,
})
})
a
,
_
:=
derivetest
.
RandomL2Block
(
rng
,
4
)
a
,
_
:=
derivetest
.
RandomL2Block
(
rng
,
4
)
...
@@ -345,30 +343,24 @@ func TestChannelManager_TxResend(t *testing.T) {
...
@@ -345,30 +343,24 @@ func TestChannelManager_TxResend(t *testing.T) {
txdata0
,
err
:=
m
.
TxData
(
eth
.
BlockID
{})
txdata0
,
err
:=
m
.
TxData
(
eth
.
BlockID
{})
require
.
NoError
(
err
)
require
.
NoError
(
err
)
txdata0bytes
:=
txdata0
.
Bytes
()
// confirm one frame to keep the channel open
data0
:=
make
([]
byte
,
len
(
txdata0bytes
))
m
.
TxConfirmed
(
txdata0
.
ID
(),
eth
.
BlockID
{})
txdata1
,
err
:=
m
.
TxData
(
eth
.
BlockID
{})
require
.
NoError
(
err
)
txdata1bytes
:=
txdata1
.
Bytes
()
data1
:=
make
([]
byte
,
len
(
txdata1bytes
))
// make sure we have a clone for later comparison
// make sure we have a clone for later comparison
copy
(
data
1
,
txdata1
bytes
)
copy
(
data
0
,
txdata0
bytes
)
// ensure channel is drained
// ensure channel is drained
_
,
err
=
m
.
TxData
(
eth
.
BlockID
{})
_
,
err
=
m
.
TxData
(
eth
.
BlockID
{})
require
.
ErrorIs
(
err
,
io
.
EOF
)
require
.
ErrorIs
(
err
,
io
.
EOF
)
// requeue frame
// requeue frame
m
.
TxFailed
(
txdata
1
.
ID
())
m
.
TxFailed
(
txdata
0
.
ID
())
txdata
2
,
err
:=
m
.
TxData
(
eth
.
BlockID
{})
txdata
1
,
err
:=
m
.
TxData
(
eth
.
BlockID
{})
require
.
NoError
(
err
)
require
.
NoError
(
err
)
data
2
:=
txdata2
.
Bytes
()
data
1
:=
txdata1
.
Bytes
()
require
.
Equal
(
data
2
,
data1
)
require
.
Equal
(
data
1
,
data0
)
fs
,
err
:=
derive
.
ParseFrames
(
data
2
)
fs
,
err
:=
derive
.
ParseFrames
(
data
1
)
require
.
NoError
(
err
)
require
.
NoError
(
err
)
require
.
Len
(
fs
,
1
)
require
.
Len
(
fs
,
1
)
}
}
...
@@ -457,13 +449,13 @@ func TestChannelManagerCloseNoPendingChannel(t *testing.T) {
...
@@ -457,13 +449,13 @@ func TestChannelManagerCloseNoPendingChannel(t *testing.T) {
// can gracefully close with a pending channel, and will not produce any
// can gracefully close with a pending channel, and will not produce any
// new channel frames after this point.
// new channel frames after this point.
func
TestChannelManagerClosePendingChannel
(
t
*
testing
.
T
)
{
func
TestChannelManagerClosePendingChannel
(
t
*
testing
.
T
)
{
rng
:=
rand
.
New
(
rand
.
NewSource
(
time
.
Now
()
.
UnixNano
()
))
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
log
:=
testlog
.
Logger
(
t
,
log
.
LvlCrit
)
log
:=
testlog
.
Logger
(
t
,
log
.
LvlCrit
)
m
:=
NewChannelManager
(
log
,
metrics
.
NoopMetrics
,
m
:=
NewChannelManager
(
log
,
metrics
.
NoopMetrics
,
ChannelConfig
{
ChannelConfig
{
TargetNumFrames
:
100
,
TargetNumFrames
:
100
,
TargetFrameSize
:
2
5
_000
,
TargetFrameSize
:
2
0
_000
,
MaxFrameSize
:
4
0
_000
,
MaxFrameSize
:
2
0
_000
,
ApproxComprRatio
:
1.0
,
ApproxComprRatio
:
1.0
,
ChannelTimeout
:
1000
,
ChannelTimeout
:
1000
,
})
})
...
@@ -505,7 +497,7 @@ func TestChannelManagerClosePendingChannel(t *testing.T) {
...
@@ -505,7 +497,7 @@ func TestChannelManagerClosePendingChannel(t *testing.T) {
// can gracefully close after producing transaction frames if none of these
// can gracefully close after producing transaction frames if none of these
// have successfully landed on chain.
// have successfully landed on chain.
func
TestChannelManagerCloseAllTxsFailed
(
t
*
testing
.
T
)
{
func
TestChannelManagerCloseAllTxsFailed
(
t
*
testing
.
T
)
{
rng
:=
rand
.
New
(
rand
.
NewSource
(
time
.
Now
()
.
UnixNano
()
))
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
log
:=
testlog
.
Logger
(
t
,
log
.
LvlCrit
)
log
:=
testlog
.
Logger
(
t
,
log
.
LvlCrit
)
m
:=
NewChannelManager
(
log
,
metrics
.
NoopMetrics
,
m
:=
NewChannelManager
(
log
,
metrics
.
NoopMetrics
,
ChannelConfig
{
ChannelConfig
{
...
...
op-batcher/batcher/driver.go
View file @
e9f8ae50
...
@@ -293,9 +293,18 @@ func (l *BatchSubmitter) loop() {
...
@@ -293,9 +293,18 @@ func (l *BatchSubmitter) loop() {
for
{
for
{
select
{
select
{
case
<-
ticker
.
C
:
case
<-
ticker
.
C
:
// prioritize the `done` condition over the ticker, even though select ordering is randomized
select
{
case
<-
l
.
done
:
l
.
publishStateToL1
(
ctx
)
return
default
:
}
l
.
loadBlocksIntoState
(
l
.
ctx
)
l
.
loadBlocksIntoState
(
l
.
ctx
)
l
.
publishStateToL1
(
ctx
)
l
.
publishStateToL1
(
ctx
)
case
<-
l
.
done
:
case
<-
l
.
done
:
l
.
publishStateToL1
(
ctx
)
return
return
}
}
}
}
...
@@ -305,6 +314,14 @@ func (l *BatchSubmitter) loop() {
...
@@ -305,6 +314,14 @@ func (l *BatchSubmitter) loop() {
// submits the associated data to the L1 in the form of channel frames.
// submits the associated data to the L1 in the form of channel frames.
func
(
l
*
BatchSubmitter
)
publishStateToL1
(
ctx
context
.
Context
)
{
func
(
l
*
BatchSubmitter
)
publishStateToL1
(
ctx
context
.
Context
)
{
for
{
for
{
// Attempt to gracefully terminate the current channel, ensuring that no new frames will be
// produced. Any remaining frames must still be published to the L1 to prevent stalling.
select
{
case
<-
l
.
done
:
l
.
state
.
Close
()
default
:
}
l1tip
,
err
:=
l
.
l1Tip
(
ctx
)
l1tip
,
err
:=
l
.
l1Tip
(
ctx
)
if
err
!=
nil
{
if
err
!=
nil
{
l
.
log
.
Error
(
"Failed to query L1 tip"
,
"error"
,
err
)
l
.
log
.
Error
(
"Failed to query L1 tip"
,
"error"
,
err
)
...
@@ -327,14 +344,6 @@ func (l *BatchSubmitter) publishStateToL1(ctx context.Context) {
...
@@ -327,14 +344,6 @@ func (l *BatchSubmitter) publishStateToL1(ctx context.Context) {
}
else
{
}
else
{
l
.
recordConfirmedTx
(
txdata
.
ID
(),
receipt
)
l
.
recordConfirmedTx
(
txdata
.
ID
(),
receipt
)
}
}
// Attempt to gracefully terminate the current channel, ensuring that no new frames will be
// produced. Any remaining frames must still be published to the L1 to prevent stalling.
select
{
case
<-
l
.
done
:
l
.
state
.
Close
()
default
:
}
}
}
}
}
...
...
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