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
2aa13672
Unverified
Commit
2aa13672
authored
Dec 25, 2023
by
Hamdi Allam
Committed by
GitHub
Dec 26, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(indexer) bridge fast sync (#8607)
* bridge fast sync * updates * more conservative blocks limit
parent
54305b4e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
144 additions
and
79 deletions
+144
-79
bridge.go
indexer/processors/bridge.go
+102
-73
legacy_bridge_processor.go
indexer/processors/bridge/legacy_bridge_processor.go
+4
-4
legacy_bridge_processor_test.go
indexer/processors/bridge/legacy_bridge_processor_test.go
+38
-2
No files found.
indexer/processors/bridge.go
View file @
2aa13672
...
@@ -8,6 +8,7 @@ import (
...
@@ -8,6 +8,7 @@ import (
"gorm.io/gorm"
"gorm.io/gorm"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/indexer/bigint"
"github.com/ethereum-optimism/optimism/indexer/bigint"
...
@@ -18,7 +19,7 @@ import (
...
@@ -18,7 +19,7 @@ import (
"github.com/ethereum-optimism/optimism/op-service/tasks"
"github.com/ethereum-optimism/optimism/op-service/tasks"
)
)
var
blocksLimit
=
10
_0
00
var
blocksLimit
=
5
00
type
BridgeProcessor
struct
{
type
BridgeProcessor
struct
{
log
log
.
Logger
log
log
.
Logger
...
@@ -88,13 +89,14 @@ func NewBridgeProcessor(log log.Logger, db *database.DB, metrics bridge.Metricer
...
@@ -88,13 +89,14 @@ func NewBridgeProcessor(log log.Logger, db *database.DB, metrics bridge.Metricer
func
(
b
*
BridgeProcessor
)
Start
()
error
{
func
(
b
*
BridgeProcessor
)
Start
()
error
{
b
.
log
.
Info
(
"starting bridge processor..."
)
b
.
log
.
Info
(
"starting bridge processor..."
)
// start L1 worker
// start L1 worker
b
.
tasks
.
Go
(
func
()
error
{
b
.
tasks
.
Go
(
func
()
error
{
l1EtlUpdates
:=
b
.
l1Etl
.
Notify
()
l1EtlUpdates
:=
b
.
l1Etl
.
Notify
()
for
range
l1EtlUpdates
{
for
range
l1EtlUpdates
{
done
:=
b
.
metrics
.
RecordL1Interval
()
b
.
log
.
Info
(
"notified of traversed L1 state"
,
"l1_etl_block_number"
,
b
.
l1Etl
.
LatestHeader
.
Number
)
done
(
b
.
onL1Data
())
if
err
:=
b
.
onL1Data
(
b
.
l1Etl
.
LatestHeader
);
err
!=
nil
{
b
.
log
.
Error
(
"failed l1 bridge processing interval"
,
"err"
,
err
)
}
}
}
b
.
log
.
Info
(
"no more l1 etl updates. shutting down l1 task"
)
b
.
log
.
Info
(
"no more l1 etl updates. shutting down l1 task"
)
return
nil
return
nil
...
@@ -103,8 +105,10 @@ func (b *BridgeProcessor) Start() error {
...
@@ -103,8 +105,10 @@ func (b *BridgeProcessor) Start() error {
b
.
tasks
.
Go
(
func
()
error
{
b
.
tasks
.
Go
(
func
()
error
{
l2EtlUpdates
:=
b
.
l2Etl
.
Notify
()
l2EtlUpdates
:=
b
.
l2Etl
.
Notify
()
for
range
l2EtlUpdates
{
for
range
l2EtlUpdates
{
done
:=
b
.
metrics
.
RecordL2Interval
()
b
.
log
.
Info
(
"notified of traversed L2 state"
,
"l2_etl_block_number"
,
b
.
l2Etl
.
LatestHeader
.
Number
)
done
(
b
.
onL2Data
())
if
err
:=
b
.
onL2Data
(
b
.
l2Etl
.
LatestHeader
);
err
!=
nil
{
b
.
log
.
Error
(
"failed l2 bridge processing interval"
,
"err"
,
err
)
}
}
}
b
.
log
.
Info
(
"no more l2 etl updates. shutting down l2 task"
)
b
.
log
.
Info
(
"no more l2 etl updates. shutting down l2 task"
)
return
nil
return
nil
...
@@ -121,23 +125,35 @@ func (b *BridgeProcessor) Close() error {
...
@@ -121,23 +125,35 @@ func (b *BridgeProcessor) Close() error {
// onL1Data will index new bridge events for the unvisited L1 state. As new L1 bridge events
// onL1Data will index new bridge events for the unvisited L1 state. As new L1 bridge events
// are processed, bridge finalization events can be processed on L2 in this same window.
// are processed, bridge finalization events can be processed on L2 in this same window.
func
(
b
*
BridgeProcessor
)
onL1Data
()
error
{
func
(
b
*
BridgeProcessor
)
onL1Data
(
latestL1Header
*
types
.
Header
)
(
errs
error
)
{
latestL1Header
:=
b
.
l1Etl
.
LatestHeader
b
.
log
.
Info
(
"notified of new L1 state"
,
"l1_etl_block_number"
,
latestL1Header
.
Number
)
// Continue while unvisited state is available to process
for
errs
==
nil
{
var
errs
error
done
:=
b
.
metrics
.
RecordL1Interval
()
if
err
:=
b
.
processInitiatedL1Events
();
err
!=
nil
{
b
.
log
.
Error
(
"failed to process initiated L1 events"
,
"err"
,
err
)
lastL1Header
:=
b
.
LastL1Header
errs
=
errors
.
Join
(
errs
,
err
)
lastFinalizedL2Header
:=
b
.
LastFinalizedL2Header
}
// Initiated L1 Events
if
b
.
LastL1Header
==
nil
||
b
.
LastL1Header
.
Timestamp
<
latestL1Header
.
Time
{
if
err
:=
b
.
processInitiatedL1Events
(
latestL1Header
);
err
!=
nil
{
errs
=
errors
.
Join
(
errs
,
fmt
.
Errorf
(
"failed processing initiated l1 events: %w"
,
err
))
}
}
// Finalized L1 Events (on L2)
// - Not every L1 block is indexed so check against a false interval on start.
if
b
.
LastL1Header
!=
nil
&&
(
b
.
LastFinalizedL2Header
==
nil
||
b
.
LastFinalizedL2Header
.
Timestamp
<
latestL1Header
.
Time
)
{
if
err
:=
b
.
processFinalizedL2Events
(
latestL1Header
);
err
!=
nil
{
errs
=
errors
.
Join
(
errs
,
fmt
.
Errorf
(
"failed processing finalized l2 events: %w"
,
err
))
}
}
done
(
errs
)
// `LastFinalizedL2Header` and `LastL1Header` are mutated by the same routine and can
// Break if there has been no change in processed events.
// safely be read without needing any sync primitives. Not every L1 block is indexed
if
lastL1Header
==
b
.
LastL1Header
&&
lastFinalizedL2Header
==
b
.
LastFinalizedL2Header
{
// so check against a false interval on start.
break
if
b
.
LastL1Header
!=
nil
&&
(
b
.
LastFinalizedL2Header
==
nil
||
b
.
LastFinalizedL2Header
.
Timestamp
<
b
.
LastL1Header
.
Timestamp
)
{
if
err
:=
b
.
processFinalizedL2Events
();
err
!=
nil
{
b
.
log
.
Error
(
"failed to process finalized L2 events"
,
"err"
,
err
)
errs
=
errors
.
Join
(
errs
,
err
)
}
}
}
}
...
@@ -146,24 +162,37 @@ func (b *BridgeProcessor) onL1Data() error {
...
@@ -146,24 +162,37 @@ func (b *BridgeProcessor) onL1Data() error {
// onL2Data will index new bridge events for the unvisited L2 state. As new L2 bridge events
// onL2Data will index new bridge events for the unvisited L2 state. As new L2 bridge events
// are processed, bridge finalization events can be processed on L1 in this same window.
// are processed, bridge finalization events can be processed on L1 in this same window.
func
(
b
*
BridgeProcessor
)
onL2Data
(
)
error
{
func
(
b
*
BridgeProcessor
)
onL2Data
(
latestL2Header
*
types
.
Header
)
(
errs
error
)
{
if
b
.
l2Etl
.
Latest
Header
.
Number
.
Cmp
(
bigint
.
Zero
)
==
0
{
if
latestL2
Header
.
Number
.
Cmp
(
bigint
.
Zero
)
==
0
{
return
nil
// skip genesis
return
nil
// skip genesis
}
}
b
.
log
.
Info
(
"notified of new L2 state"
,
"l2_etl_block_number"
,
b
.
l2Etl
.
LatestHeader
.
Number
)
var
errs
error
// Continue while unvisited state is available to process
if
err
:=
b
.
processInitiatedL2Events
();
err
!=
nil
{
for
errs
==
nil
{
b
.
log
.
Error
(
"failed to process initiated L2 events"
,
"err"
,
err
)
done
:=
b
.
metrics
.
RecordL2Interval
()
errs
=
errors
.
Join
(
errs
,
err
)
}
lastL2Header
:=
b
.
LastL2Header
lastFinalizedL1Header
:=
b
.
LastFinalizedL1Header
// Initiated L2 Events
if
b
.
LastL2Header
==
nil
||
b
.
LastL2Header
.
Timestamp
<
latestL2Header
.
Time
{
if
err
:=
b
.
processInitiatedL2Events
(
latestL2Header
);
err
!=
nil
{
errs
=
errors
.
Join
(
errs
,
fmt
.
Errorf
(
"failed processing initiated l2 events: %w"
,
err
))
}
}
// Finalized L2 Events (on L1)
if
b
.
LastFinalizedL1Header
==
nil
||
b
.
LastFinalizedL1Header
.
Timestamp
<
latestL2Header
.
Time
{
if
err
:=
b
.
processFinalizedL1Events
(
latestL2Header
);
err
!=
nil
{
errs
=
errors
.
Join
(
errs
,
fmt
.
Errorf
(
"failed processing finalized l1 events: %w"
,
err
))
}
}
done
(
errs
)
// `LastFinalizedL1Header` and `LastL2Header` are mutated by the same routine and can
// Break if there has been no change in processed events.
// safely be read without needing any sync primitives
if
lastL2Header
==
b
.
LastL2Header
&&
lastFinalizedL1Header
==
b
.
LastFinalizedL1Header
{
if
b
.
LastFinalizedL1Header
==
nil
||
b
.
LastFinalizedL1Header
.
Timestamp
<
b
.
LastL2Header
.
Timestamp
{
break
if
err
:=
b
.
processFinalizedL1Events
();
err
!=
nil
{
b
.
log
.
Error
(
"failed to process finalized L1 events"
,
"err"
,
err
)
errs
=
errors
.
Join
(
errs
,
err
)
}
}
}
}
...
@@ -172,29 +201,29 @@ func (b *BridgeProcessor) onL2Data() error {
...
@@ -172,29 +201,29 @@ func (b *BridgeProcessor) onL2Data() error {
// Process Initiated Bridge Events
// Process Initiated Bridge Events
func
(
b
*
BridgeProcessor
)
processInitiatedL1Events
()
error
{
func
(
b
*
BridgeProcessor
)
processInitiatedL1Events
(
latestL1Header
*
types
.
Header
)
error
{
l1BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l1"
,
"kind"
,
"initiated"
)
l1BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l1"
,
"kind"
,
"initiated"
)
lastL1BlockNumber
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1StartingHeight
)
-
1
)
lastL1BlockNumber
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1StartingHeight
-
1
)
)
if
b
.
LastL1Header
!=
nil
{
if
b
.
LastL1Header
!=
nil
{
lastL1BlockNumber
=
b
.
LastL1Header
.
Number
lastL1BlockNumber
=
b
.
LastL1Header
.
Number
}
}
// Latest unobserved L1 state bounded by `blockLimits` blocks. Since
// Latest unobserved L1 state bounded by `blockLimits` blocks. Since
// not every L1 block is indexed, we may have nothing to process.
// not every L1 block is indexed, we may have nothing to process.
latest
L1HeaderScope
:=
func
(
db
*
gorm
.
DB
)
*
gorm
.
DB
{
to
L1HeaderScope
:=
func
(
db
*
gorm
.
DB
)
*
gorm
.
DB
{
newQuery
:=
db
.
Session
(
&
gorm
.
Session
{
NewDB
:
true
})
// fresh subquery
newQuery
:=
db
.
Session
(
&
gorm
.
Session
{
NewDB
:
true
})
// fresh subquery
headers
:=
newQuery
.
Model
(
database
.
L1BlockHeader
{})
.
Where
(
"number > ?
"
,
lastL1Block
Number
)
headers
:=
newQuery
.
Model
(
database
.
L1BlockHeader
{})
.
Where
(
"number > ?
AND number <= ?"
,
lastL1BlockNumber
,
latestL1Header
.
Number
)
return
db
.
Where
(
"number = (?)"
,
newQuery
.
Table
(
"(?)
as
block_numbers"
,
headers
.
Order
(
"number ASC"
)
.
Limit
(
blocksLimit
))
.
Select
(
"MAX(number)"
))
return
db
.
Where
(
"number = (?)"
,
newQuery
.
Table
(
"(?)
AS
block_numbers"
,
headers
.
Order
(
"number ASC"
)
.
Limit
(
blocksLimit
))
.
Select
(
"MAX(number)"
))
}
}
latestL1Header
,
err
:=
b
.
db
.
Blocks
.
L1BlockHeaderWithScope
(
latest
L1HeaderScope
)
toL1Header
,
err
:=
b
.
db
.
Blocks
.
L1BlockHeaderWithScope
(
to
L1HeaderScope
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to query new L1 state: %w"
,
err
)
return
fmt
.
Errorf
(
"failed to query new L1 state: %w"
,
err
)
}
else
if
latest
L1Header
==
nil
{
}
else
if
to
L1Header
==
nil
{
l1BridgeLog
.
Debug
(
"no new L1 state found"
)
l1BridgeLog
.
Debug
(
"no new L1 state found"
)
return
nil
return
nil
}
}
fromL1Height
,
toL1Height
:=
new
(
big
.
Int
)
.
Add
(
lastL1BlockNumber
,
bigint
.
One
),
latest
L1Header
.
Number
fromL1Height
,
toL1Height
:=
new
(
big
.
Int
)
.
Add
(
lastL1BlockNumber
,
bigint
.
One
),
to
L1Header
.
Number
if
err
:=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
if
err
:=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
l1BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1BedrockStartingHeight
))
l1BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1BedrockStartingHeight
))
if
l1BedrockStartingHeight
.
Cmp
(
fromL1Height
)
>
0
{
// OP Mainnet & OP Goerli Only.
if
l1BedrockStartingHeight
.
Cmp
(
fromL1Height
)
>
0
{
// OP Mainnet & OP Goerli Only.
...
@@ -221,12 +250,12 @@ func (b *BridgeProcessor) processInitiatedL1Events() error {
...
@@ -221,12 +250,12 @@ func (b *BridgeProcessor) processInitiatedL1Events() error {
return
err
return
err
}
}
b
.
LastL1Header
=
latest
L1Header
b
.
LastL1Header
=
to
L1Header
b
.
metrics
.
RecordL1LatestHeight
(
latest
L1Header
.
Number
)
b
.
metrics
.
RecordL1LatestHeight
(
to
L1Header
.
Number
)
return
nil
return
nil
}
}
func
(
b
*
BridgeProcessor
)
processInitiatedL2Events
()
error
{
func
(
b
*
BridgeProcessor
)
processInitiatedL2Events
(
latestL2Header
*
types
.
Header
)
error
{
l2BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l2"
,
"kind"
,
"initiated"
)
l2BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l2"
,
"kind"
,
"initiated"
)
lastL2BlockNumber
:=
bigint
.
Zero
lastL2BlockNumber
:=
bigint
.
Zero
if
b
.
LastL2Header
!=
nil
{
if
b
.
LastL2Header
!=
nil
{
...
@@ -235,19 +264,19 @@ func (b *BridgeProcessor) processInitiatedL2Events() error {
...
@@ -235,19 +264,19 @@ func (b *BridgeProcessor) processInitiatedL2Events() error {
// Latest unobserved L2 state bounded by `blockLimits` blocks.
// Latest unobserved L2 state bounded by `blockLimits` blocks.
// Since every L2 block is indexed, we always expect new state.
// Since every L2 block is indexed, we always expect new state.
latest
L2HeaderScope
:=
func
(
db
*
gorm
.
DB
)
*
gorm
.
DB
{
to
L2HeaderScope
:=
func
(
db
*
gorm
.
DB
)
*
gorm
.
DB
{
newQuery
:=
db
.
Session
(
&
gorm
.
Session
{
NewDB
:
true
})
// fresh subquery
newQuery
:=
db
.
Session
(
&
gorm
.
Session
{
NewDB
:
true
})
// fresh subquery
headers
:=
newQuery
.
Model
(
database
.
L2BlockHeader
{})
.
Where
(
"number > ?
"
,
lastL2Block
Number
)
headers
:=
newQuery
.
Model
(
database
.
L2BlockHeader
{})
.
Where
(
"number > ?
AND number <= ?"
,
lastL2BlockNumber
,
latestL2Header
.
Number
)
return
db
.
Where
(
"number = (?)"
,
newQuery
.
Table
(
"(?)
as
block_numbers"
,
headers
.
Order
(
"number ASC"
)
.
Limit
(
blocksLimit
))
.
Select
(
"MAX(number)"
))
return
db
.
Where
(
"number = (?)"
,
newQuery
.
Table
(
"(?)
AS
block_numbers"
,
headers
.
Order
(
"number ASC"
)
.
Limit
(
blocksLimit
))
.
Select
(
"MAX(number)"
))
}
}
latestL2Header
,
err
:=
b
.
db
.
Blocks
.
L2BlockHeaderWithScope
(
latest
L2HeaderScope
)
toL2Header
,
err
:=
b
.
db
.
Blocks
.
L2BlockHeaderWithScope
(
to
L2HeaderScope
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to query new L2 state: %w"
,
err
)
return
fmt
.
Errorf
(
"failed to query new L2 state: %w"
,
err
)
}
else
if
latest
L2Header
==
nil
{
}
else
if
to
L2Header
==
nil
{
return
fmt
.
Errorf
(
"no new L2 state found"
)
return
fmt
.
Errorf
(
"no new L2 state found"
)
}
}
fromL2Height
,
toL2Height
:=
new
(
big
.
Int
)
.
Add
(
lastL2BlockNumber
,
bigint
.
One
),
latest
L2Header
.
Number
fromL2Height
,
toL2Height
:=
new
(
big
.
Int
)
.
Add
(
lastL2BlockNumber
,
bigint
.
One
),
to
L2Header
.
Number
if
err
:=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
if
err
:=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
l2BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L2BedrockStartingHeight
))
l2BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L2BedrockStartingHeight
))
if
l2BedrockStartingHeight
.
Cmp
(
fromL2Height
)
>
0
{
// OP Mainnet & OP Goerli Only
if
l2BedrockStartingHeight
.
Cmp
(
fromL2Height
)
>
0
{
// OP Mainnet & OP Goerli Only
...
@@ -274,14 +303,14 @@ func (b *BridgeProcessor) processInitiatedL2Events() error {
...
@@ -274,14 +303,14 @@ func (b *BridgeProcessor) processInitiatedL2Events() error {
return
err
return
err
}
}
b
.
LastL2Header
=
latest
L2Header
b
.
LastL2Header
=
to
L2Header
b
.
metrics
.
RecordL2LatestHeight
(
latest
L2Header
.
Number
)
b
.
metrics
.
RecordL2LatestHeight
(
to
L2Header
.
Number
)
return
nil
return
nil
}
}
// Process Finalized Bridge Events
// Process Finalized Bridge Events
func
(
b
*
BridgeProcessor
)
processFinalizedL1Events
()
error
{
func
(
b
*
BridgeProcessor
)
processFinalizedL1Events
(
latestL2Header
*
types
.
Header
)
error
{
l1BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l1"
,
"kind"
,
"finalization"
)
l1BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l1"
,
"kind"
,
"finalization"
)
lastFinalizedL1BlockNumber
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1StartingHeight
)
-
1
)
lastFinalizedL1BlockNumber
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1StartingHeight
)
-
1
)
if
b
.
LastFinalizedL1Header
!=
nil
{
if
b
.
LastFinalizedL1Header
!=
nil
{
...
@@ -290,20 +319,20 @@ func (b *BridgeProcessor) processFinalizedL1Events() error {
...
@@ -290,20 +319,20 @@ func (b *BridgeProcessor) processFinalizedL1Events() error {
// Latest unfinalized L1 state bounded by `blockLimit` blocks that have had L2 bridge events
// Latest unfinalized L1 state bounded by `blockLimit` blocks that have had L2 bridge events
// indexed. Since L1 data is indexed independently, there may not be new L1 state to finalize
// indexed. Since L1 data is indexed independently, there may not be new L1 state to finalize
latest
L1HeaderScope
:=
func
(
db
*
gorm
.
DB
)
*
gorm
.
DB
{
to
L1HeaderScope
:=
func
(
db
*
gorm
.
DB
)
*
gorm
.
DB
{
newQuery
:=
db
.
Session
(
&
gorm
.
Session
{
NewDB
:
true
})
// fresh subquery
newQuery
:=
db
.
Session
(
&
gorm
.
Session
{
NewDB
:
true
})
// fresh subquery
headers
:=
newQuery
.
Model
(
database
.
L1BlockHeader
{})
.
Where
(
"number > ? AND timestamp <= ?"
,
lastFinalizedL1BlockNumber
,
b
.
LastL2Header
.
Timestamp
)
headers
:=
newQuery
.
Model
(
database
.
L1BlockHeader
{})
.
Where
(
"number > ? AND timestamp <= ?"
,
lastFinalizedL1BlockNumber
,
latestL2Header
.
Time
)
return
db
.
Where
(
"number = (?)"
,
newQuery
.
Table
(
"(?)
as
block_numbers"
,
headers
.
Order
(
"number ASC"
)
.
Limit
(
blocksLimit
))
.
Select
(
"MAX(number)"
))
return
db
.
Where
(
"number = (?)"
,
newQuery
.
Table
(
"(?)
AS
block_numbers"
,
headers
.
Order
(
"number ASC"
)
.
Limit
(
blocksLimit
))
.
Select
(
"MAX(number)"
))
}
}
latestL1Header
,
err
:=
b
.
db
.
Blocks
.
L1BlockHeaderWithScope
(
latest
L1HeaderScope
)
toL1Header
,
err
:=
b
.
db
.
Blocks
.
L1BlockHeaderWithScope
(
to
L1HeaderScope
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to query for latest unfinalized L1 state: %w"
,
err
)
return
fmt
.
Errorf
(
"failed to query for latest unfinalized L1 state: %w"
,
err
)
}
else
if
latest
L1Header
==
nil
{
}
else
if
to
L1Header
==
nil
{
l1BridgeLog
.
Debug
(
"no new l1 state to finalize"
,
"last_finalized_block_number"
,
lastFinalizedL1BlockNumber
)
l1BridgeLog
.
Debug
(
"no new l1 state to finalize"
,
"last_finalized_block_number"
,
lastFinalizedL1BlockNumber
)
return
nil
return
nil
}
}
fromL1Height
,
toL1Height
:=
new
(
big
.
Int
)
.
Add
(
lastFinalizedL1BlockNumber
,
bigint
.
One
),
latest
L1Header
.
Number
fromL1Height
,
toL1Height
:=
new
(
big
.
Int
)
.
Add
(
lastFinalizedL1BlockNumber
,
bigint
.
One
),
to
L1Header
.
Number
if
err
:=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
if
err
:=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
l1BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1BedrockStartingHeight
))
l1BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1BedrockStartingHeight
))
if
l1BedrockStartingHeight
.
Cmp
(
fromL1Height
)
>
0
{
if
l1BedrockStartingHeight
.
Cmp
(
fromL1Height
)
>
0
{
...
@@ -330,12 +359,12 @@ func (b *BridgeProcessor) processFinalizedL1Events() error {
...
@@ -330,12 +359,12 @@ func (b *BridgeProcessor) processFinalizedL1Events() error {
return
err
return
err
}
}
b
.
LastFinalizedL1Header
=
latest
L1Header
b
.
LastFinalizedL1Header
=
to
L1Header
b
.
metrics
.
RecordL1LatestFinalizedHeight
(
latest
L1Header
.
Number
)
b
.
metrics
.
RecordL1LatestFinalizedHeight
(
to
L1Header
.
Number
)
return
nil
return
nil
}
}
func
(
b
*
BridgeProcessor
)
processFinalizedL2Events
()
error
{
func
(
b
*
BridgeProcessor
)
processFinalizedL2Events
(
latestL1Header
*
types
.
Header
)
error
{
l2BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l2"
,
"kind"
,
"finalization"
)
l2BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l2"
,
"kind"
,
"finalization"
)
lastFinalizedL2BlockNumber
:=
bigint
.
Zero
lastFinalizedL2BlockNumber
:=
bigint
.
Zero
if
b
.
LastFinalizedL2Header
!=
nil
{
if
b
.
LastFinalizedL2Header
!=
nil
{
...
@@ -344,20 +373,20 @@ func (b *BridgeProcessor) processFinalizedL2Events() error {
...
@@ -344,20 +373,20 @@ func (b *BridgeProcessor) processFinalizedL2Events() error {
// Latest unfinalized L2 state bounded by `blockLimit` blocks that have had L1 bridge events
// Latest unfinalized L2 state bounded by `blockLimit` blocks that have had L1 bridge events
// indexed. Since L2 data is indexed independently, there may not be new L2 state to finalize
// indexed. Since L2 data is indexed independently, there may not be new L2 state to finalize
latest
L2HeaderScope
:=
func
(
db
*
gorm
.
DB
)
*
gorm
.
DB
{
to
L2HeaderScope
:=
func
(
db
*
gorm
.
DB
)
*
gorm
.
DB
{
newQuery
:=
db
.
Session
(
&
gorm
.
Session
{
NewDB
:
true
})
// fresh subquery
newQuery
:=
db
.
Session
(
&
gorm
.
Session
{
NewDB
:
true
})
// fresh subquery
headers
:=
newQuery
.
Model
(
database
.
L2BlockHeader
{})
.
Where
(
"number > ? AND timestamp <= ?"
,
lastFinalizedL2BlockNumber
,
b
.
LastL1Header
.
Timestamp
)
headers
:=
newQuery
.
Model
(
database
.
L2BlockHeader
{})
.
Where
(
"number > ? AND timestamp <= ?"
,
lastFinalizedL2BlockNumber
,
latestL1Header
.
Time
)
return
db
.
Where
(
"number = (?)"
,
newQuery
.
Table
(
"(?)
as
block_numbers"
,
headers
.
Order
(
"number ASC"
)
.
Limit
(
blocksLimit
))
.
Select
(
"MAX(number)"
))
return
db
.
Where
(
"number = (?)"
,
newQuery
.
Table
(
"(?)
AS
block_numbers"
,
headers
.
Order
(
"number ASC"
)
.
Limit
(
blocksLimit
))
.
Select
(
"MAX(number)"
))
}
}
latestL2Header
,
err
:=
b
.
db
.
Blocks
.
L2BlockHeaderWithScope
(
latest
L2HeaderScope
)
toL2Header
,
err
:=
b
.
db
.
Blocks
.
L2BlockHeaderWithScope
(
to
L2HeaderScope
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to query for latest unfinalized L2 state: %w"
,
err
)
return
fmt
.
Errorf
(
"failed to query for latest unfinalized L2 state: %w"
,
err
)
}
else
if
latest
L2Header
==
nil
{
}
else
if
to
L2Header
==
nil
{
l2BridgeLog
.
Debug
(
"no new l2 state to finalize"
,
"last_finalized_block_number"
,
lastFinalizedL2BlockNumber
)
l2BridgeLog
.
Debug
(
"no new l2 state to finalize"
,
"last_finalized_block_number"
,
lastFinalizedL2BlockNumber
)
return
nil
return
nil
}
}
fromL2Height
,
toL2Height
:=
new
(
big
.
Int
)
.
Add
(
lastFinalizedL2BlockNumber
,
bigint
.
One
),
latest
L2Header
.
Number
fromL2Height
,
toL2Height
:=
new
(
big
.
Int
)
.
Add
(
lastFinalizedL2BlockNumber
,
bigint
.
One
),
to
L2Header
.
Number
if
err
:=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
if
err
:=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
l2BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L2BedrockStartingHeight
))
l2BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L2BedrockStartingHeight
))
if
l2BedrockStartingHeight
.
Cmp
(
fromL2Height
)
>
0
{
if
l2BedrockStartingHeight
.
Cmp
(
fromL2Height
)
>
0
{
...
@@ -384,7 +413,7 @@ func (b *BridgeProcessor) processFinalizedL2Events() error {
...
@@ -384,7 +413,7 @@ func (b *BridgeProcessor) processFinalizedL2Events() error {
return
err
return
err
}
}
b
.
LastFinalizedL2Header
=
latest
L2Header
b
.
LastFinalizedL2Header
=
to
L2Header
b
.
metrics
.
RecordL2LatestFinalizedHeight
(
latest
L2Header
.
Number
)
b
.
metrics
.
RecordL2LatestFinalizedHeight
(
to
L2Header
.
Number
)
return
nil
return
nil
}
}
indexer/processors/bridge/legacy_bridge_processor.go
View file @
2aa13672
...
@@ -178,12 +178,12 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metri
...
@@ -178,12 +178,12 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metri
// require the entry but we'll store it anyways as a large % of these withdrawals are not relayed
// require the entry but we'll store it anyways as a large % of these withdrawals are not relayed
// pre-bedrock.
// pre-bedrock.
v1MessageHash
,
err
:=
l
egacyBridgeMessageV1MessageHash
(
&
sentMessage
.
BridgeMessage
)
v1MessageHash
,
err
:=
L
egacyBridgeMessageV1MessageHash
(
&
sentMessage
.
BridgeMessage
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to compute versioned message hash: %w"
,
err
)
return
fmt
.
Errorf
(
"failed to compute versioned message hash: %w"
,
err
)
}
}
withdrawalHash
,
err
:=
l
egacyBridgeMessageWithdrawalHash
(
preset
,
&
sentMessage
.
BridgeMessage
)
withdrawalHash
,
err
:=
L
egacyBridgeMessageWithdrawalHash
(
preset
,
&
sentMessage
.
BridgeMessage
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to construct migrated withdrawal hash: %w"
,
err
)
return
fmt
.
Errorf
(
"failed to construct migrated withdrawal hash: %w"
,
err
)
}
}
...
@@ -373,7 +373,7 @@ func LegacyL2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metri
...
@@ -373,7 +373,7 @@ func LegacyL2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metri
// Utils
// Utils
func
l
egacyBridgeMessageWithdrawalHash
(
preset
int
,
msg
*
database
.
BridgeMessage
)
(
common
.
Hash
,
error
)
{
func
L
egacyBridgeMessageWithdrawalHash
(
preset
int
,
msg
*
database
.
BridgeMessage
)
(
common
.
Hash
,
error
)
{
l1Cdm
:=
config
.
Presets
[
preset
]
.
ChainConfig
.
L1Contracts
.
L1CrossDomainMessengerProxy
l1Cdm
:=
config
.
Presets
[
preset
]
.
ChainConfig
.
L1Contracts
.
L1CrossDomainMessengerProxy
legacyWithdrawal
:=
crossdomain
.
NewLegacyWithdrawal
(
predeploys
.
L2CrossDomainMessengerAddr
,
msg
.
Tx
.
ToAddress
,
msg
.
Tx
.
FromAddress
,
msg
.
Tx
.
Data
,
msg
.
Nonce
)
legacyWithdrawal
:=
crossdomain
.
NewLegacyWithdrawal
(
predeploys
.
L2CrossDomainMessengerAddr
,
msg
.
Tx
.
ToAddress
,
msg
.
Tx
.
FromAddress
,
msg
.
Tx
.
Data
,
msg
.
Nonce
)
migratedWithdrawal
,
err
:=
crossdomain
.
MigrateWithdrawal
(
legacyWithdrawal
,
&
l1Cdm
,
big
.
NewInt
(
int64
(
preset
)))
migratedWithdrawal
,
err
:=
crossdomain
.
MigrateWithdrawal
(
legacyWithdrawal
,
&
l1Cdm
,
big
.
NewInt
(
int64
(
preset
)))
...
@@ -384,7 +384,7 @@ func legacyBridgeMessageWithdrawalHash(preset int, msg *database.BridgeMessage)
...
@@ -384,7 +384,7 @@ func legacyBridgeMessageWithdrawalHash(preset int, msg *database.BridgeMessage)
return
migratedWithdrawal
.
Hash
()
return
migratedWithdrawal
.
Hash
()
}
}
func
l
egacyBridgeMessageV1MessageHash
(
msg
*
database
.
BridgeMessage
)
(
common
.
Hash
,
error
)
{
func
L
egacyBridgeMessageV1MessageHash
(
msg
*
database
.
BridgeMessage
)
(
common
.
Hash
,
error
)
{
legacyWithdrawal
:=
crossdomain
.
NewLegacyWithdrawal
(
predeploys
.
L2CrossDomainMessengerAddr
,
msg
.
Tx
.
ToAddress
,
msg
.
Tx
.
FromAddress
,
msg
.
Tx
.
Data
,
msg
.
Nonce
)
legacyWithdrawal
:=
crossdomain
.
NewLegacyWithdrawal
(
predeploys
.
L2CrossDomainMessengerAddr
,
msg
.
Tx
.
ToAddress
,
msg
.
Tx
.
FromAddress
,
msg
.
Tx
.
Data
,
msg
.
Nonce
)
value
,
err
:=
legacyWithdrawal
.
Value
()
value
,
err
:=
legacyWithdrawal
.
Value
()
if
err
!=
nil
{
if
err
!=
nil
{
...
...
indexer/processors/bridge/legacy_bridge_processor_test.go
View file @
2aa13672
package
bridge
package
bridge
import
(
import
(
"math/big"
"testing"
"testing"
"github.com/ethereum-optimism/optimism/indexer/bigint"
"github.com/ethereum-optimism/optimism/indexer/bigint"
...
@@ -37,13 +38,48 @@ func TestLegacyWithdrawalAndMessageHash(t *testing.T) {
...
@@ -37,13 +38,48 @@ func TestLegacyWithdrawalAndMessageHash(t *testing.T) {
Tx
:
database
.
Transaction
{
FromAddress
:
sentMessage
.
Sender
,
ToAddress
:
sentMessage
.
Target
,
Amount
:
value
,
Data
:
sentMessage
.
Message
},
Tx
:
database
.
Transaction
{
FromAddress
:
sentMessage
.
Sender
,
ToAddress
:
sentMessage
.
Target
,
Amount
:
value
,
Data
:
sentMessage
.
Message
},
}
}
hash
,
err
:=
l
egacyBridgeMessageWithdrawalHash
(
420
,
&
msg
)
hash
,
err
:=
L
egacyBridgeMessageWithdrawalHash
(
420
,
&
msg
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expectedWithdrawalHash
,
hash
)
require
.
Equal
(
t
,
expectedWithdrawalHash
,
hash
)
// Ensure the relayed message hash (v1) matches
// Ensure the relayed message hash (v1) matches
expectedMessageHash
:=
common
.
HexToHash
(
"0xcb16ecc1967f5d7aed909349a4351d28fbb396429ef7faf1c9d2a670e3ca906f"
)
expectedMessageHash
:=
common
.
HexToHash
(
"0xcb16ecc1967f5d7aed909349a4351d28fbb396429ef7faf1c9d2a670e3ca906f"
)
v1MessageHash
,
err
:=
l
egacyBridgeMessageV1MessageHash
(
&
msg
)
v1MessageHash
,
err
:=
L
egacyBridgeMessageV1MessageHash
(
&
msg
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expectedMessageHash
,
v1MessageHash
)
require
.
Equal
(
t
,
expectedMessageHash
,
v1MessageHash
)
// OP Mainnet hashes to also check for
// - since the message hash doesn't depend on the preset, we only need to check for the withdrawal hash
expectedWithdrawalHash
=
common
.
HexToHash
(
"0x9c0bc28a77328a405f21d51a32d32f038ebf7ce70e377ca48b2cd194ec024f15"
)
msg
=
database
.
BridgeMessage
{
Nonce
:
big
.
NewInt
(
100180
),
GasLimit
:
bigint
.
Zero
,
Tx
:
database
.
Transaction
{
FromAddress
:
common
.
HexToAddress
(
"0x4200000000000000000000000000000000000010"
),
ToAddress
:
common
.
HexToAddress
(
"0x99c9fc46f92e8a1c0dec1b1747d010903e884be1"
),
Amount
:
bigint
.
Zero
,
Data
:
common
.
FromHex
(
"0x1532ec34000000000000000000000000094a9009fe93a85658e4b49604fd8177620f8cd8000000000000000000000000094a9009fe93a85658e4b49604fd8177620f8cd8000000000000000000000000000000000000000000000000013abb2a2774ab0000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
),
},
}
hash
,
err
=
LegacyBridgeMessageWithdrawalHash
(
10
,
&
msg
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expectedWithdrawalHash
,
hash
)
expectedWithdrawalHash
=
common
.
HexToHash
(
"0xeb1dd5ead967ad6860d64407413f86e50330ab123ca9adf2768145524c3f5323"
)
msg
=
database
.
BridgeMessage
{
Nonce
:
big
.
NewInt
(
100618
),
GasLimit
:
bigint
.
Zero
,
Tx
:
database
.
Transaction
{
FromAddress
:
common
.
HexToAddress
(
"0x4200000000000000000000000000000000000010"
),
ToAddress
:
common
.
HexToAddress
(
"0x99c9fc46f92e8a1c0dec1b1747d010903e884be1"
),
Amount
:
bigint
.
Zero
,
Data
:
common
.
FromHex
(
"0xa9f9e67500000000000000000000000028e1de268616a6ba0de59717ac5547589e6bb1180000000000000000000000003ef241d9ae02f2253d8a1bf0b35d68eab9925b400000000000000000000000003e579180cf01f0e2abf6ff4d566b7891fbf9b8680000000000000000000000003e579180cf01f0e2abf6ff4d566b7891fbf9b868000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000"
),
},
}
hash
,
err
=
LegacyBridgeMessageWithdrawalHash
(
10
,
&
msg
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expectedWithdrawalHash
,
hash
)
}
}
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