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
467e6f80
Unverified
Commit
467e6f80
authored
Sep 11, 2023
by
OptimismBot
Committed by
GitHub
Sep 11, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7119 from ethereum-optimism/indexer.legacy.blocks
feat(indexer): bridge process pre-bedrock blocks
parents
1ce16570
1adbe46d
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
700 additions
and
62 deletions
+700
-62
bigint.go
indexer/bigint/bigint.go
+0
-1
config.go
indexer/config/config.go
+20
-10
config_test.go
indexer/config/config_test.go
+3
-1
presets.go
indexer/config/presets.go
+16
-11
cross_domain_messages.go
indexer/e2e_tests/utils/cross_domain_messages.go
+7
-1
etl.go
indexer/etl/etl.go
+3
-2
l1_etl.go
indexer/etl/l1_etl.go
+2
-1
l2_etl.go
indexer/etl/l2_etl.go
+2
-1
indexer.toml
indexer/indexer.toml
+0
-1
20230523_create_schema.sql
indexer/migrations/20230523_create_schema.sql
+1
-1
client.go
indexer/node/client.go
+17
-0
mocks.go
indexer/node/mocks.go
+5
-0
bridge.go
indexer/processors/bridge.go
+65
-5
l1_bridge_processor.go
indexer/processors/bridge/l1_bridge_processor.go
+1
-1
l2_bridge_processor.go
indexer/processors/bridge/l2_bridge_processor.go
+1
-1
legacy_bridge_processor.go
indexer/processors/bridge/legacy_bridge_processor.go
+340
-0
cross_domain_messenger.go
indexer/processors/contracts/cross_domain_messenger.go
+40
-25
legacy_ctc.go
indexer/processors/contracts/legacy_ctc.go
+58
-0
legacy_standard_bridge.go
indexer/processors/contracts/legacy_standard_bridge.go
+119
-0
No files found.
indexer/bigint/bigint.go
View file @
467e6f80
...
...
@@ -37,7 +37,6 @@ func Grouped(start, end *big.Int, size uint64) []Range {
if
end
.
Cmp
(
start
)
<
0
||
size
==
0
{
return
nil
}
bigMaxDiff
:=
big
.
NewInt
(
int64
(
size
-
1
))
groups
:=
[]
Range
{}
...
...
indexer/config/config.go
View file @
467e6f80
...
...
@@ -7,7 +7,7 @@ import (
"github.com/BurntSushi/toml"
"github.com/ethereum/go-ethereum/common"
geth_log
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
)
const
(
...
...
@@ -34,6 +34,9 @@ type L1Contracts struct {
L1CrossDomainMessengerProxy
common
.
Address
`toml:"l1-cross-domain-messenger"`
L1StandardBridgeProxy
common
.
Address
`toml:"l1-standard-bridge"`
// Pre-Bedrock Legacy Contracts
LegacyCanonicalTransactionChain
common
.
Address
`toml:"l1-canonical-transaction-chain"`
// Some more contracts -- L1ERC721Bridge, ProxyAdmin, SystemConfig, etc
// Ignore the auxiliary contracts?
...
...
@@ -69,6 +72,10 @@ type ChainConfig struct {
L1Contracts
L1Contracts
`toml:"l1-contracts"`
L1StartingHeight
uint
`toml:"l1-starting-height"`
// Bedrock starting heights only applicable for OP-Mainnet & OP-Goerli
L1BedrockStartingHeight
uint
`toml:"-"`
L2BedrockStartingHeight
uint
`toml:"-"`
// These configuration options will be removed once
// native reorg handling is implemented
L1ConfirmationDepth
uint
`toml:"l1-confirmation-depth"`
...
...
@@ -103,8 +110,8 @@ type ServerConfig struct {
}
// LoadConfig loads the `indexer.toml` config file from a given path
func
LoadConfig
(
log
ger
geth_
log
.
Logger
,
path
string
)
(
Config
,
error
)
{
log
ger
.
Debug
(
"loading config"
,
"path"
,
path
)
func
LoadConfig
(
log
log
.
Logger
,
path
string
)
(
Config
,
error
)
{
log
.
Debug
(
"loading config"
,
"path"
,
path
)
var
conf
Config
data
,
err
:=
os
.
ReadFile
(
path
)
...
...
@@ -113,9 +120,9 @@ func LoadConfig(logger geth_log.Logger, path string) (Config, error) {
}
data
=
[]
byte
(
os
.
ExpandEnv
(
string
(
data
)))
log
ger
.
Debug
(
"parsed config file"
,
"data"
,
string
(
data
))
log
.
Debug
(
"parsed config file"
,
"data"
,
string
(
data
))
if
_
,
err
:=
toml
.
Decode
(
string
(
data
),
&
conf
);
err
!=
nil
{
log
ger
.
Info
(
"failed to decode config file"
,
"err"
,
err
)
log
.
Info
(
"failed to decode config file"
,
"err"
,
err
)
return
conf
,
err
}
...
...
@@ -124,31 +131,34 @@ func LoadConfig(logger geth_log.Logger, path string) (Config, error) {
if
!
ok
{
return
conf
,
fmt
.
Errorf
(
"unknown preset: %d"
,
conf
.
Chain
.
Preset
)
}
conf
.
Chain
.
L1Contracts
=
knownPreset
.
L1Contracts
conf
.
Chain
.
L1StartingHeight
=
knownPreset
.
L1StartingHeight
conf
.
Chain
.
L1BedrockStartingHeight
=
knownPreset
.
L1BedrockStartingHeight
conf
.
Chain
.
L2BedrockStartingHeight
=
knownPreset
.
L1BedrockStartingHeight
}
// Set polling defaults if not set
if
conf
.
Chain
.
L1PollingInterval
==
0
{
log
ger
.
Info
(
"setting default L1 polling interval"
,
"interval"
,
defaultLoopInterval
)
log
.
Info
(
"setting default L1 polling interval"
,
"interval"
,
defaultLoopInterval
)
conf
.
Chain
.
L1PollingInterval
=
defaultLoopInterval
}
if
conf
.
Chain
.
L2PollingInterval
==
0
{
log
ger
.
Info
(
"setting default L2 polling interval"
,
"interval"
,
defaultLoopInterval
)
log
.
Info
(
"setting default L2 polling interval"
,
"interval"
,
defaultLoopInterval
)
conf
.
Chain
.
L2PollingInterval
=
defaultLoopInterval
}
if
conf
.
Chain
.
L1HeaderBufferSize
==
0
{
log
ger
.
Info
(
"setting default L1 header buffer"
,
"size"
,
defaultHeaderBufferSize
)
log
.
Info
(
"setting default L1 header buffer"
,
"size"
,
defaultHeaderBufferSize
)
conf
.
Chain
.
L1HeaderBufferSize
=
defaultHeaderBufferSize
}
if
conf
.
Chain
.
L2HeaderBufferSize
==
0
{
log
ger
.
Info
(
"setting default L2 header buffer"
,
"size"
,
defaultHeaderBufferSize
)
log
.
Info
(
"setting default L2 header buffer"
,
"size"
,
defaultHeaderBufferSize
)
conf
.
Chain
.
L2HeaderBufferSize
=
defaultHeaderBufferSize
}
log
ger
.
Info
(
"loaded config"
)
log
.
Info
(
"loaded config"
)
return
conf
,
nil
}
indexer/config/config_test.go
View file @
467e6f80
...
...
@@ -192,9 +192,11 @@ func Test_AsSliceSuccess(t *testing.T) {
slice
,
err
:=
testCfg
.
AsSlice
()
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
len
(
slice
),
4
)
require
.
Equal
(
t
,
len
(
slice
),
5
)
require
.
Equal
(
t
,
slice
[
0
]
.
String
(),
testCfg
.
OptimismPortalProxy
.
String
())
require
.
Equal
(
t
,
slice
[
1
]
.
String
(),
testCfg
.
L2OutputOracleProxy
.
String
())
require
.
Equal
(
t
,
slice
[
2
]
.
String
(),
testCfg
.
L1CrossDomainMessengerProxy
.
String
())
require
.
Equal
(
t
,
slice
[
3
]
.
String
(),
testCfg
.
L1StandardBridgeProxy
.
String
())
// LegacyCanonicalTransactionChain is the 4th slot
}
indexer/config/presets.go
View file @
467e6f80
...
...
@@ -10,23 +10,28 @@ var presetConfigs = map[int]ChainConfig{
// OP Mainnet
10
:
{
L1Contracts
:
L1Contracts
{
OptimismPortalProxy
:
common
.
HexToAddress
(
"0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"
),
L2OutputOracleProxy
:
common
.
HexToAddress
(
"0xdfe97868233d1aa22e815a266982f2cf17685a27"
),
L1CrossDomainMessengerProxy
:
common
.
HexToAddress
(
"0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1"
),
L1StandardBridgeProxy
:
common
.
HexToAddress
(
"0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1"
),
//
LegacyCanonicalTransactionChain: common.HexToAddress("0x5e4e65926ba27467555eb562121fac00d24e9dd2"),
OptimismPortalProxy
:
common
.
HexToAddress
(
"0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"
),
L2OutputOracleProxy
:
common
.
HexToAddress
(
"0xdfe97868233d1aa22e815a266982f2cf17685a27"
),
L1CrossDomainMessengerProxy
:
common
.
HexToAddress
(
"0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1"
),
L1StandardBridgeProxy
:
common
.
HexToAddress
(
"0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1"
),
LegacyCanonicalTransactionChain
:
common
.
HexToAddress
(
"0x5e4e65926ba27467555eb562121fac00d24e9dd2"
),
},
L1StartingHeight
:
13596466
,
L1StartingHeight
:
13596466
,
L1BedrockStartingHeight
:
17422590
,
L2BedrockStartingHeight
:
105235063
,
},
// OP Goerli
420
:
{
L1Contracts
:
L1Contracts
{
OptimismPortalProxy
:
common
.
HexToAddress
(
"0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383"
),
L2OutputOracleProxy
:
common
.
HexToAddress
(
"0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0"
),
L1CrossDomainMessengerProxy
:
common
.
HexToAddress
(
"0x5086d1eEF304eb5284A0f6720f79403b4e9bE294"
),
L1StandardBridgeProxy
:
common
.
HexToAddress
(
"0x636Af16bf2f682dD3109e60102b8E1A089FedAa8"
),
OptimismPortalProxy
:
common
.
HexToAddress
(
"0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383"
),
L2OutputOracleProxy
:
common
.
HexToAddress
(
"0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0"
),
L1CrossDomainMessengerProxy
:
common
.
HexToAddress
(
"0x5086d1eEF304eb5284A0f6720f79403b4e9bE294"
),
L1StandardBridgeProxy
:
common
.
HexToAddress
(
"0x636Af16bf2f682dD3109e60102b8E1A089FedAa8"
),
LegacyCanonicalTransactionChain
:
common
.
HexToAddress
(
"0x607F755149cFEB3a14E1Dc3A4E2450Cde7dfb04D"
),
},
L1StartingHeight
:
7017096
,
L1StartingHeight
:
7017096
,
L1BedrockStartingHeight
:
8300214
,
L2BedrockStartingHeight
:
4061224
,
},
// Base Mainnet
8453
:
{
...
...
indexer/e2e_tests/utils/cross_domain_messages.go
View file @
467e6f80
...
...
@@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
)
type
CrossDomainMessengerSentMessage
struct
{
...
...
@@ -57,5 +58,10 @@ func CrossDomainMessengerSentMessageHash(sentMessage *bindings.CrossDomainMessen
return
common
.
Hash
{},
err
}
return
contracts
.
CrossDomainMessageHash
(
abi
,
sentMessage
,
value
)
calldata
,
err
:=
contracts
.
CrossDomainMessageCalldata
(
abi
,
sentMessage
,
value
)
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
return
crypto
.
Keccak256Hash
(
calldata
),
nil
}
indexer/etl/etl.go
View file @
467e6f80
...
...
@@ -29,9 +29,10 @@ type ETL struct {
headerBufferSize
uint64
headerTraversal
*
node
.
HeaderTraversal
ethClient
node
.
EthClient
contracts
[]
common
.
Address
etlBatches
chan
ETLBatch
EthClient
node
.
EthClient
}
type
ETLBatch
struct
{
...
...
@@ -104,7 +105,7 @@ func (etl *ETL) processBatch(headers []types.Header) error {
}
headersWithLog
:=
make
(
map
[
common
.
Hash
]
bool
,
len
(
headers
))
logs
,
err
:=
etl
.
e
thClient
.
FilterLogs
(
ethereum
.
FilterQuery
{
FromBlock
:
firstHeader
.
Number
,
ToBlock
:
lastHeader
.
Number
,
Addresses
:
etl
.
contracts
})
logs
,
err
:=
etl
.
E
thClient
.
FilterLogs
(
ethereum
.
FilterQuery
{
FromBlock
:
firstHeader
.
Number
,
ToBlock
:
lastHeader
.
Number
,
Addresses
:
etl
.
contracts
})
if
err
!=
nil
{
batchLog
.
Info
(
"unable to extract logs"
,
"err"
,
err
)
return
err
...
...
indexer/etl/l1_etl.go
View file @
467e6f80
...
...
@@ -66,9 +66,10 @@ func NewL1ETL(cfg Config, log log.Logger, db *database.DB, metrics Metricer, cli
log
:
log
,
metrics
:
metrics
,
headerTraversal
:
node
.
NewHeaderTraversal
(
client
,
fromHeader
,
cfg
.
ConfirmationDepth
),
ethClient
:
client
,
contracts
:
cSlice
,
etlBatches
:
etlBatches
,
EthClient
:
client
,
}
return
&
L1ETL
{
ETL
:
etl
,
db
:
db
,
mu
:
new
(
sync
.
Mutex
)},
nil
...
...
indexer/etl/l2_etl.go
View file @
467e6f80
...
...
@@ -50,9 +50,10 @@ func NewL2ETL(cfg Config, log log.Logger, db *database.DB, metrics Metricer, cli
log
:
log
,
metrics
:
metrics
,
headerTraversal
:
node
.
NewHeaderTraversal
(
client
,
fromHeader
,
cfg
.
ConfirmationDepth
),
ethClient
:
client
,
contracts
:
l2Contracts
,
etlBatches
:
etlBatches
,
EthClient
:
client
,
}
return
&
L2ETL
{
ETL
:
etl
,
db
:
db
},
nil
...
...
indexer/indexer.toml
View file @
467e6f80
...
...
@@ -2,7 +2,6 @@
# Can configure them manually or use a preset l2 ChainId for known chains including OP Mainnet, OP Goerli, Base, Base Goerli, Zora, and Zora goerli
[chain]
# OP Goerli
preset
=
$INDEXER_CHAIN_PRESET
# L1 Config
...
...
indexer/migrations/20230523_create_schema.sql
View file @
467e6f80
...
...
@@ -29,7 +29,7 @@ CREATE TABLE IF NOT EXISTS l2_block_headers (
hash
VARCHAR
PRIMARY
KEY
,
parent_hash
VARCHAR
NOT
NULL
UNIQUE
,
number
UINT256
NOT
NULL
UNIQUE
,
timestamp
INTEGER
NOT
NULL
UNIQUE
CHECK
(
timestamp
>
0
)
,
timestamp
INTEGER
NOT
NULL
,
-- Raw Data
rlp_bytes
VARCHAR
NOT
NULL
...
...
indexer/node/client.go
View file @
467e6f80
...
...
@@ -29,6 +29,8 @@ type EthClient interface {
BlockHeaderByHash
(
common
.
Hash
)
(
*
types
.
Header
,
error
)
BlockHeadersByRange
(
*
big
.
Int
,
*
big
.
Int
)
([]
types
.
Header
,
error
)
TxByHash
(
common
.
Hash
)
(
*
types
.
Transaction
,
error
)
StorageHash
(
common
.
Address
,
*
big
.
Int
)
(
common
.
Hash
,
error
)
FilterLogs
(
ethereum
.
FilterQuery
)
([]
types
.
Log
,
error
)
}
...
...
@@ -147,6 +149,21 @@ func (c *client) BlockHeadersByRange(startHeight, endHeight *big.Int) ([]types.H
return
headers
,
nil
}
func
(
c
*
client
)
TxByHash
(
hash
common
.
Hash
)
(
*
types
.
Transaction
,
error
)
{
ctxwt
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
defaultRequestTimeout
)
defer
cancel
()
var
tx
*
types
.
Transaction
err
:=
c
.
rpc
.
CallContext
(
ctxwt
,
&
tx
,
"eth_getTransactionByHash"
,
hash
)
if
err
!=
nil
{
return
nil
,
err
}
else
if
tx
==
nil
{
return
nil
,
ethereum
.
NotFound
}
return
tx
,
nil
}
// StorageHash returns the sha3 of the storage root for the specified account
func
(
c
*
client
)
StorageHash
(
address
common
.
Address
,
blockNumber
*
big
.
Int
)
(
common
.
Hash
,
error
)
{
ctxwt
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
defaultRequestTimeout
)
...
...
indexer/node/mocks.go
View file @
467e6f80
...
...
@@ -31,6 +31,11 @@ func (m *MockEthClient) BlockHeadersByRange(from, to *big.Int) ([]types.Header,
return
args
.
Get
(
0
)
.
([]
types
.
Header
),
args
.
Error
(
1
)
}
func
(
m
*
MockEthClient
)
TxByHash
(
hash
common
.
Hash
)
(
*
types
.
Transaction
,
error
)
{
args
:=
m
.
Called
(
hash
)
return
args
.
Get
(
0
)
.
(
*
types
.
Transaction
),
args
.
Error
(
1
)
}
func
(
m
*
MockEthClient
)
StorageHash
(
address
common
.
Address
,
blockNumber
*
big
.
Int
)
(
common
.
Hash
,
error
)
{
args
:=
m
.
Called
(
address
,
blockNumber
)
return
args
.
Get
(
0
)
.
(
common
.
Hash
),
args
.
Error
(
1
)
...
...
indexer/processors/bridge.go
View file @
467e6f80
...
...
@@ -124,19 +124,78 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
fromL2Height
=
new
(
big
.
Int
)
.
Add
(
b
.
LatestL2Header
.
Number
,
bigint
.
One
)
}
l1BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L1BedrockStartingHeight
))
l2BedrockStartingHeight
:=
big
.
NewInt
(
int64
(
b
.
chainConfig
.
L2BedrockStartingHeight
))
batchLog
:=
b
.
log
.
New
(
"epoch_start_number"
,
fromL1Height
,
"epoch_end_number"
,
toL1Height
)
batchLog
.
Info
(
"unobserved epochs"
)
err
=
b
.
db
.
Transaction
(
func
(
tx
*
database
.
DB
)
error
{
// In the event where we have a large number of un-observed blocks, group the block range
// on the order of 10k blocks at a time. If this turns out to be a bottleneck, we can
// parallelize these operations
maxBlockRange
:=
uint64
(
10
_000
)
l1BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l1"
)
l2BridgeLog
:=
b
.
log
.
New
(
"bridge"
,
"l2"
)
// In the event where we have a large number of un-observed blocks, group the block range
// on the order of 10k blocks at a time. If this turns out to be a bottleneck, we can
// parallelize these operations for significant improvements as well
l1BlockGroups
:=
bigint
.
Grouped
(
fromL1Height
,
toL1Height
,
10
_000
)
l2BlockGroups
:=
bigint
.
Grouped
(
fromL2Height
,
toL2Height
,
10
_000
)
// FOR OP-MAINNET, OP-GOERLI ONLY! Specially handle the existence of pre-bedrock blocks
if
l1BedrockStartingHeight
.
Cmp
(
fromL1Height
)
>
0
{
l1BridgeLog
:=
l1BridgeLog
.
New
(
"mode"
,
"legacy"
)
l2BridgeLog
:=
l2BridgeLog
.
New
(
"mode"
,
"legacy"
)
legacyFromL1Height
,
legacyToL1Height
:=
fromL1Height
,
toL1Height
legacyFromL2Height
,
legacyToL2Height
:=
fromL2Height
,
toL2Height
if
l1BedrockStartingHeight
.
Cmp
(
toL1Height
)
<=
0
{
legacyToL1Height
=
new
(
big
.
Int
)
.
Sub
(
l1BedrockStartingHeight
,
big
.
NewInt
(
1
))
legacyToL2Height
=
new
(
big
.
Int
)
.
Sub
(
l2BedrockStartingHeight
,
big
.
NewInt
(
1
))
}
// First, find all possible initiated bridge events
l1BlockGroups
:=
bigint
.
Grouped
(
legacyFromL1Height
,
legacyToL1Height
,
maxBlockRange
)
l2BlockGroups
:=
bigint
.
Grouped
(
legacyFromL2Height
,
legacyToL2Height
,
maxBlockRange
)
for
_
,
group
:=
range
l1BlockGroups
{
log
:=
l1BridgeLog
.
New
(
"from_l1_block_number"
,
group
.
Start
,
"to_l1_block_number"
,
group
.
End
)
log
.
Info
(
"scanning for initiated bridge events"
)
if
err
:=
bridge
.
LegacyL1ProcessInitiatedBridgeEvents
(
log
,
tx
,
b
.
chainConfig
,
group
.
Start
,
group
.
End
);
err
!=
nil
{
return
err
}
}
for
_
,
group
:=
range
l2BlockGroups
{
log
:=
l2BridgeLog
.
New
(
"from_l2_block_number"
,
group
.
Start
,
"to_l2_block_number"
,
group
.
End
)
log
.
Info
(
"scanning for initiated bridge events"
)
if
err
:=
bridge
.
LegacyL2ProcessInitiatedBridgeEvents
(
log
,
tx
,
group
.
Start
,
group
.
End
);
err
!=
nil
{
return
err
}
}
// Now that all initiated events have been indexed, it is ensured that all finalization can find their counterpart.
for
_
,
group
:=
range
l1BlockGroups
{
log
:=
l1BridgeLog
.
New
(
"from_l1_block_number"
,
group
.
Start
,
"to_l1_block_number"
,
group
.
End
)
log
.
Info
(
"scanning for finalized bridge events"
)
if
err
:=
bridge
.
LegacyL1ProcessFinalizedBridgeEvents
(
log
,
tx
,
b
.
l1Etl
.
EthClient
,
b
.
chainConfig
,
group
.
Start
,
group
.
End
);
err
!=
nil
{
return
err
}
}
for
_
,
group
:=
range
l2BlockGroups
{
log
:=
l2BridgeLog
.
New
(
"from_l2_block_number"
,
group
.
Start
,
"to_l2_block_number"
,
group
.
End
)
log
.
Info
(
"scanning for finalized bridge events"
)
if
err
:=
bridge
.
LegacyL2ProcessFinalizedBridgeEvents
(
log
,
tx
,
group
.
Start
,
group
.
End
);
err
!=
nil
{
return
err
}
}
if
legacyToL1Height
.
Cmp
(
toL1Height
)
==
0
{
// a-ok! entire batch was legacy blocks
return
nil
}
batchLog
.
Info
(
"detected switch to bedrock"
,
"l1_bedrock_starting_height"
,
l1BedrockStartingHeight
,
"l2_bedrock_starting_height"
,
l2BedrockStartingHeight
)
fromL1Height
=
l1BedrockStartingHeight
fromL2Height
=
l2BedrockStartingHeight
}
// First, find all possible initiated bridge events
l1BlockGroups
:=
bigint
.
Grouped
(
fromL1Height
,
toL1Height
,
maxBlockRange
)
l2BlockGroups
:=
bigint
.
Grouped
(
fromL2Height
,
toL2Height
,
maxBlockRange
)
for
_
,
group
:=
range
l1BlockGroups
{
log
:=
l1BridgeLog
.
New
(
"from_block_number"
,
group
.
Start
,
"to_block_number"
,
group
.
End
)
log
.
Info
(
"scanning for initiated bridge events"
)
...
...
@@ -181,4 +240,5 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
b
.
LatestL2Header
=
latestEpoch
.
L2BlockHeader
.
RLPHeader
.
Header
()
}
}
}
indexer/processors/bridge/l1_bridge_processor.go
View file @
467e6f80
...
...
@@ -12,7 +12,7 @@ import (
"github.com/ethereum/go-ethereum/log"
)
// L1ProcessInitiatedBridgeEvents will query the database for
new
bridge events that have been initiated between
// L1ProcessInitiatedBridgeEvents will query the database for bridge events that have been initiated between
// the specified block range. This covers every part of the multi-layered stack:
// 1. OptimismPortal
// 2. L1CrossDomainMessenger
...
...
indexer/processors/bridge/l2_bridge_processor.go
View file @
467e6f80
...
...
@@ -12,7 +12,7 @@ import (
"github.com/ethereum/go-ethereum/log"
)
// L2ProcessInitiatedBridgeEvents will query the database for
new
bridge events that have been initiated between
// L2ProcessInitiatedBridgeEvents will query the database for bridge events that have been initiated between
// the specified block range. This covers every part of the multi-layered stack:
// 1. OptimismPortal
// 2. L2CrossDomainMessenger
...
...
indexer/processors/bridge/legacy_bridge_processor.go
0 → 100644
View file @
467e6f80
package
bridge
import
(
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/indexer/config"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/indexer/processors/contracts"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
)
// Legacy Bridge Initiation
// LegacyL1ProcessInitiatedEvents will query the data for bridge events within the specified block range
// according the pre-bedrock protocol. This follows:
// 1. CanonicalTransactionChain
// 2. L1CrossDomainMessenger
// 3. L1StandardBridge
func
LegacyL1ProcessInitiatedBridgeEvents
(
log
log
.
Logger
,
db
*
database
.
DB
,
chainConfig
config
.
ChainConfig
,
fromHeight
*
big
.
Int
,
toHeight
*
big
.
Int
)
error
{
// (1) CanonicalTransactionChain
ctcTxDepositEvents
,
err
:=
contracts
.
LegacyCTCDepositEvents
(
chainConfig
.
L1Contracts
.
LegacyCanonicalTransactionChain
,
db
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
err
}
if
len
(
ctcTxDepositEvents
)
>
0
{
log
.
Info
(
"detected legacy transaction deposits"
,
"size"
,
len
(
ctcTxDepositEvents
))
}
ctcTxDeposits
:=
make
(
map
[
logKey
]
*
contracts
.
LegacyCTCDepositEvent
,
len
(
ctcTxDepositEvents
))
transactionDeposits
:=
make
([]
database
.
L1TransactionDeposit
,
len
(
ctcTxDepositEvents
))
for
i
:=
range
ctcTxDepositEvents
{
deposit
:=
ctcTxDepositEvents
[
i
]
ctcTxDeposits
[
logKey
{
deposit
.
Event
.
BlockHash
,
deposit
.
Event
.
LogIndex
}]
=
&
deposit
transactionDeposits
[
i
]
=
database
.
L1TransactionDeposit
{
// We re-use the L2 Transaction hash as the source hash
// to remain consistent in the schema.
SourceHash
:
deposit
.
TxHash
,
L2TransactionHash
:
deposit
.
TxHash
,
InitiatedL1EventGUID
:
deposit
.
Event
.
GUID
,
GasLimit
:
deposit
.
GasLimit
,
Tx
:
deposit
.
Tx
,
}
}
if
len
(
ctcTxDepositEvents
)
>
0
{
if
err
:=
db
.
BridgeTransactions
.
StoreL1TransactionDeposits
(
transactionDeposits
);
err
!=
nil
{
return
err
}
}
// (2) L1CrossDomainMessenger
crossDomainSentMessages
,
err
:=
contracts
.
CrossDomainMessengerSentMessageEvents
(
"l1"
,
chainConfig
.
L1Contracts
.
L1CrossDomainMessengerProxy
,
db
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
err
}
if
len
(
crossDomainSentMessages
)
>
0
{
log
.
Info
(
"detected legacy sent messages"
,
"size"
,
len
(
crossDomainSentMessages
))
}
sentMessages
:=
make
(
map
[
logKey
]
*
contracts
.
CrossDomainMessengerSentMessageEvent
,
len
(
crossDomainSentMessages
))
l1BridgeMessages
:=
make
([]
database
.
L1BridgeMessage
,
len
(
crossDomainSentMessages
))
for
i
:=
range
crossDomainSentMessages
{
sentMessage
:=
crossDomainSentMessages
[
i
]
sentMessages
[
logKey
{
sentMessage
.
Event
.
BlockHash
,
sentMessage
.
Event
.
LogIndex
}]
=
&
sentMessage
// extract the deposit hash from the previous TransactionDepositedEvent
ctcTxDeposit
,
ok
:=
ctcTxDeposits
[
logKey
{
sentMessage
.
Event
.
BlockHash
,
sentMessage
.
Event
.
LogIndex
-
1
}]
if
!
ok
{
log
.
Error
(
"missing transaction deposit for cross domain message"
,
"tx_hash"
,
sentMessage
.
Event
.
TransactionHash
.
String
())
return
fmt
.
Errorf
(
"missing preceding TransactionEnqueued for SentMessage event. tx_hash = %s"
,
sentMessage
.
Event
.
TransactionHash
.
String
())
}
l1BridgeMessages
[
i
]
=
database
.
L1BridgeMessage
{
TransactionSourceHash
:
ctcTxDeposit
.
TxHash
,
BridgeMessage
:
sentMessage
.
BridgeMessage
}
}
if
len
(
l1BridgeMessages
)
>
0
{
if
err
:=
db
.
BridgeMessages
.
StoreL1BridgeMessages
(
l1BridgeMessages
);
err
!=
nil
{
return
err
}
}
// (3) L1StandardBridge
initiatedBridges
,
err
:=
contracts
.
L1StandardBridgeLegacyDepositInitiatedEvents
(
chainConfig
.
L1Contracts
.
L1StandardBridgeProxy
,
db
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
err
}
if
len
(
initiatedBridges
)
>
0
{
log
.
Info
(
"detected iegacy bridge deposits"
,
"size"
,
len
(
initiatedBridges
))
}
l1BridgeDeposits
:=
make
([]
database
.
L1BridgeDeposit
,
len
(
initiatedBridges
))
for
i
:=
range
initiatedBridges
{
initiatedBridge
:=
initiatedBridges
[
i
]
// extract the cross domain message hash & deposit source hash from the following events
// Unlike bedrock, the bridge events are emitted AFTER sending the cross domain message
// - Event Flow: TransactionEnqueued -> SentMessage -> DepositInitiated
sentMessage
,
ok
:=
sentMessages
[
logKey
{
initiatedBridge
.
Event
.
BlockHash
,
initiatedBridge
.
Event
.
LogIndex
-
1
}]
if
!
ok
{
log
.
Error
(
"missing cross domain message for bridge transfer"
,
"tx_hash"
,
initiatedBridge
.
Event
.
TransactionHash
.
String
())
return
fmt
.
Errorf
(
"expected SentMessage preceding DepositInitiated event. tx_hash = %s"
,
initiatedBridge
.
Event
.
TransactionHash
.
String
())
}
ctcTxDeposit
,
ok
:=
ctcTxDeposits
[
logKey
{
initiatedBridge
.
Event
.
BlockHash
,
initiatedBridge
.
Event
.
LogIndex
-
2
}]
if
!
ok
{
log
.
Error
(
"missing transaction deposit for bridge transfer"
,
"tx_hash"
,
initiatedBridge
.
Event
.
TransactionHash
.
String
())
return
fmt
.
Errorf
(
"expected TransactionEnqueued preceding DepostInitiated event. tx_hash = %s"
,
initiatedBridge
.
Event
.
TransactionHash
.
String
())
}
initiatedBridge
.
BridgeTransfer
.
CrossDomainMessageHash
=
&
sentMessage
.
BridgeMessage
.
MessageHash
l1BridgeDeposits
[
i
]
=
database
.
L1BridgeDeposit
{
TransactionSourceHash
:
ctcTxDeposit
.
TxHash
,
BridgeTransfer
:
initiatedBridge
.
BridgeTransfer
,
}
}
if
len
(
l1BridgeDeposits
)
>
0
{
if
err
:=
db
.
BridgeTransfers
.
StoreL1BridgeDeposits
(
l1BridgeDeposits
);
err
!=
nil
{
return
err
}
}
// a-ok!
return
nil
}
// LegacyL2ProcessInitiatedEvents will query the data for bridge events within the specified block range
// according the pre-bedrock protocol. This follows:
// 1. L2CrossDomainMessenger - The LegacyMessagePasser contract cannot be used as entrypoint to bridge transactions from L2. The protocol
// only allows the L2CrossDomainMessenger as the sole sender when relaying a bridged message.
// 2. L2StandardBridge
func
LegacyL2ProcessInitiatedBridgeEvents
(
log
log
.
Logger
,
db
*
database
.
DB
,
fromHeight
*
big
.
Int
,
toHeight
*
big
.
Int
)
error
{
// (1) L2CrossDomainMessenger
crossDomainSentMessages
,
err
:=
contracts
.
CrossDomainMessengerSentMessageEvents
(
"l2"
,
predeploys
.
L2CrossDomainMessengerAddr
,
db
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
err
}
if
len
(
crossDomainSentMessages
)
>
0
{
log
.
Info
(
"detected legacy transaction withdrawals (via L2CrossDomainMessenger)"
,
"size"
,
len
(
crossDomainSentMessages
))
}
sentMessages
:=
make
(
map
[
logKey
]
*
contracts
.
CrossDomainMessengerSentMessageEvent
,
len
(
crossDomainSentMessages
))
l2BridgeMessages
:=
make
([]
database
.
L2BridgeMessage
,
len
(
crossDomainSentMessages
))
l2TransactionWithdrawals
:=
make
([]
database
.
L2TransactionWithdrawal
,
len
(
crossDomainSentMessages
))
for
i
:=
range
crossDomainSentMessages
{
sentMessage
:=
crossDomainSentMessages
[
i
]
sentMessages
[
logKey
{
sentMessage
.
Event
.
BlockHash
,
sentMessage
.
Event
.
LogIndex
}]
=
&
sentMessage
// To ensure consistency in the schema, we duplicate this as the "root" transaction withdrawal. The storage key in the message
// passer contract is sha3(calldata + sender). The sender always being the L2CrossDomainMessenger pre-bedrock.
withdrawalHash
:=
crypto
.
Keccak256Hash
(
append
(
sentMessage
.
MessageCalldata
,
predeploys
.
L2CrossDomainMessengerAddr
[
:
]
...
))
l2TransactionWithdrawals
[
i
]
=
database
.
L2TransactionWithdrawal
{
WithdrawalHash
:
withdrawalHash
,
InitiatedL2EventGUID
:
sentMessage
.
Event
.
GUID
,
Nonce
:
sentMessage
.
BridgeMessage
.
Nonce
,
GasLimit
:
sentMessage
.
BridgeMessage
.
GasLimit
,
Tx
:
database
.
Transaction
{
FromAddress
:
sentMessage
.
BridgeMessage
.
Tx
.
FromAddress
,
ToAddress
:
sentMessage
.
BridgeMessage
.
Tx
.
ToAddress
,
Amount
:
big
.
NewInt
(
0
),
Data
:
sentMessage
.
BridgeMessage
.
Tx
.
Data
,
Timestamp
:
sentMessage
.
Event
.
Timestamp
,
},
}
l2BridgeMessages
[
i
]
=
database
.
L2BridgeMessage
{
TransactionWithdrawalHash
:
withdrawalHash
,
BridgeMessage
:
sentMessage
.
BridgeMessage
,
}
}
if
len
(
l2BridgeMessages
)
>
0
{
if
err
:=
db
.
BridgeTransactions
.
StoreL2TransactionWithdrawals
(
l2TransactionWithdrawals
);
err
!=
nil
{
return
err
}
if
err
:=
db
.
BridgeMessages
.
StoreL2BridgeMessages
(
l2BridgeMessages
);
err
!=
nil
{
return
err
}
}
// (2) L2StandardBridge
initiatedBridges
,
err
:=
contracts
.
L2StandardBridgeLegacyWithdrawalInitiatedEvents
(
predeploys
.
L2StandardBridgeAddr
,
db
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
err
}
if
len
(
initiatedBridges
)
>
0
{
log
.
Info
(
"detected legacy bridge withdrawals"
,
"size"
,
len
(
initiatedBridges
))
}
l2BridgeWithdrawals
:=
make
([]
database
.
L2BridgeWithdrawal
,
len
(
initiatedBridges
))
for
i
:=
range
initiatedBridges
{
initiatedBridge
:=
initiatedBridges
[
i
]
// extract the cross domain message hash & deposit source hash from the following events
// Unlike bedrock, the bridge events are emitted AFTER sending the cross domain message
// - Event Flow: TransactionEnqueued -> SentMessage -> DepositInitiated
sentMessage
,
ok
:=
sentMessages
[
logKey
{
initiatedBridge
.
Event
.
BlockHash
,
initiatedBridge
.
Event
.
LogIndex
-
1
}]
if
!
ok
{
log
.
Error
(
"expected SentMessage preceding DepositInitiated event"
,
"tx_hash"
,
initiatedBridge
.
Event
.
TransactionHash
.
String
())
return
fmt
.
Errorf
(
"expected SentMessage preceding DepositInitiated event. tx_hash = %s"
,
initiatedBridge
.
Event
.
TransactionHash
)
}
initiatedBridge
.
BridgeTransfer
.
CrossDomainMessageHash
=
&
sentMessage
.
BridgeMessage
.
MessageHash
l2BridgeWithdrawals
[
i
]
=
database
.
L2BridgeWithdrawal
{
TransactionWithdrawalHash
:
sentMessage
.
BridgeMessage
.
MessageHash
,
BridgeTransfer
:
initiatedBridge
.
BridgeTransfer
,
}
}
if
len
(
l2BridgeWithdrawals
)
>
0
{
if
err
:=
db
.
BridgeTransfers
.
StoreL2BridgeWithdrawals
(
l2BridgeWithdrawals
);
err
!=
nil
{
return
err
}
}
// a-ok
return
nil
}
// Legacy Bridge Finalization
// LegacyL1ProcessFinalizedBridgeEvents will query for bridge events within the specified block range
// according to the pre-bedrock protocol. This follows:
// 1. L1CrossDomainMessenger
// 2. L1StandardBridge
func
LegacyL1ProcessFinalizedBridgeEvents
(
log
log
.
Logger
,
db
*
database
.
DB
,
l1Client
node
.
EthClient
,
chainConfig
config
.
ChainConfig
,
fromHeight
*
big
.
Int
,
toHeight
*
big
.
Int
)
error
{
// (1) L1CrossDomainMessenger -> This is the root-most contract from which bridge events are finalized since withdrawals must be initiated from the
// L2CrossDomainMessenger. Since there's no two-step withdrawal process, we mark the transaction as proven/finalized in the same step
crossDomainRelayedMessages
,
err
:=
contracts
.
CrossDomainMessengerRelayedMessageEvents
(
"l1"
,
chainConfig
.
L1Contracts
.
L1CrossDomainMessengerProxy
,
db
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
err
}
if
len
(
crossDomainRelayedMessages
)
>
0
{
log
.
Info
(
"detected relayed messages"
,
"size"
,
len
(
crossDomainRelayedMessages
))
}
skippedPreRegenesisMessages
:=
0
for
i
:=
range
crossDomainRelayedMessages
{
relayedMessage
:=
crossDomainRelayedMessages
[
i
]
message
,
err
:=
db
.
BridgeMessages
.
L2BridgeMessage
(
relayedMessage
.
MessageHash
)
if
err
!=
nil
{
return
err
}
else
if
message
==
nil
{
// Before surfacing an error about a missing withdrawal, we need to handle an edge case
// for OP-Mainnet pre-regensis withdrawals that no longer exist on L2.
tx
,
err
:=
l1Client
.
TxByHash
(
relayedMessage
.
Event
.
TransactionHash
)
if
err
!=
nil
{
return
err
}
else
if
tx
==
nil
{
log
.
Error
(
"missing tx for relayed message"
,
"tx_hash"
,
relayedMessage
.
Event
.
TransactionHash
.
String
())
return
fmt
.
Errorf
(
"missing tx for relayed message. tx_hash = %s"
,
relayedMessage
.
Event
.
TransactionHash
.
String
())
}
relayMessageData
:=
tx
.
Data
()[
4
:
]
inputs
,
err
:=
contracts
.
CrossDomainMessengerLegacyRelayMessageEncoding
.
Inputs
.
Unpack
(
relayMessageData
)
if
err
!=
nil
||
inputs
==
nil
{
log
.
Error
(
"failed to extract XDomainCallData from relayMessage transaction"
,
"err"
,
err
,
"tx_hash"
,
relayedMessage
.
Event
.
TransactionHash
.
String
())
return
fmt
.
Errorf
(
"unable to extract XDomainCallData from relayMessage transaction. err = %w. tx_hash = %s"
,
err
,
relayedMessage
.
Event
.
TransactionHash
.
String
())
}
// NOTE: Since OP-Mainnet is the only network to go through a regensis we can simply harcode the
// the starting message nonce at genesis (100k). Any relayed withdrawal on L1 with a lesser nonce
// is a clear indicator of a pre-regenesis withdrawal.
if
inputs
[
3
]
.
(
*
big
.
Int
)
.
Int64
()
<
100
_000
{
// skip pre-regenesis withdrawals
skippedPreRegenesisMessages
++
continue
}
else
{
log
.
Error
(
"missing indexed legacy L2CrossDomainMessenger message"
,
"tx_hash"
,
relayedMessage
.
Event
.
TransactionHash
.
String
())
return
fmt
.
Errorf
(
"missing indexed L2CrossDomainMessager message. tx_hash %s"
,
relayedMessage
.
Event
.
TransactionHash
.
String
())
}
}
// Mark the associated tx withdrawal as proven/finalized with the same event
if
err
:=
db
.
BridgeTransactions
.
MarkL2TransactionWithdrawalProvenEvent
(
relayedMessage
.
MessageHash
,
relayedMessage
.
Event
.
GUID
);
err
!=
nil
{
log
.
Error
(
"failed to mark withdrawal as proven"
,
"err"
,
err
)
return
err
}
if
err
:=
db
.
BridgeTransactions
.
MarkL2TransactionWithdrawalFinalizedEvent
(
relayedMessage
.
MessageHash
,
relayedMessage
.
Event
.
GUID
,
true
);
err
!=
nil
{
log
.
Error
(
"failed to mark withdrawal as finalzed"
,
"err"
,
err
)
return
err
}
if
err
:=
db
.
BridgeMessages
.
MarkRelayedL2BridgeMessage
(
relayedMessage
.
MessageHash
,
relayedMessage
.
Event
.
GUID
);
err
!=
nil
{
log
.
Error
(
"failed to relay cross domain message"
,
"err"
,
err
)
return
err
}
}
if
skippedPreRegenesisMessages
>
0
{
// Logged as a warning just for visibility
log
.
Warn
(
"skipped pre-regensis relayed L2CrossDomainMessenger withdrawals"
,
"size"
,
skippedPreRegenesisMessages
)
}
// (2) L2StandardBridge -- no-op for now as there's nothing actionable to do here besides
// santiy checks which is not important for legacy code. The message status is already tracked
// via the relayed bridge messed through the cross domain messenger.
// a-ok!
return
nil
}
// LegacyL2ProcessFinalizedBridgeEvents will query for bridge events within the specified block range
// according to the pre-bedrock protocol. This follows:
// 1. L2CrossDomainMessenger
// 2. L2StandardBridge
func
LegacyL2ProcessFinalizedBridgeEvents
(
log
log
.
Logger
,
db
*
database
.
DB
,
fromHeight
*
big
.
Int
,
toHeight
*
big
.
Int
)
error
{
// (1) L2CrossDomainMessenger
crossDomainRelayedMessages
,
err
:=
contracts
.
CrossDomainMessengerRelayedMessageEvents
(
"l2"
,
predeploys
.
L2CrossDomainMessengerAddr
,
db
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
err
}
if
len
(
crossDomainRelayedMessages
)
>
0
{
log
.
Info
(
"detected relayed legacy messages"
,
"size"
,
len
(
crossDomainRelayedMessages
))
}
for
i
:=
range
crossDomainRelayedMessages
{
relayedMessage
:=
crossDomainRelayedMessages
[
i
]
message
,
err
:=
db
.
BridgeMessages
.
L1BridgeMessage
(
relayedMessage
.
MessageHash
)
if
err
!=
nil
{
return
err
}
else
if
message
==
nil
{
log
.
Error
(
"missing indexed legacy L1CrossDomainMessenger message"
,
"tx_hash"
,
relayedMessage
.
Event
.
TransactionHash
.
String
())
return
fmt
.
Errorf
(
"missing indexed L1CrossDomainMessager message. tx_hash = %s"
,
relayedMessage
.
Event
.
TransactionHash
.
String
())
}
if
err
:=
db
.
BridgeMessages
.
MarkRelayedL1BridgeMessage
(
relayedMessage
.
MessageHash
,
relayedMessage
.
Event
.
GUID
);
err
!=
nil
{
log
.
Error
(
"failed to relay cross domain message"
,
"err"
,
err
)
return
err
}
}
// (2) L2StandardBridge -- no-op for now as there's nothing actionable to do here besides
// santiy checks which is not important for legacy code. The message status is already tracked
// via the relayed bridge messed through the cross domain messenger.
// a-ok!
return
nil
}
indexer/processors/contracts/cross_domain_messenger.go
View file @
467e6f80
...
...
@@ -18,7 +18,7 @@ var (
bytesType
,
_
=
abi
.
NewType
(
"bytes"
,
""
,
nil
)
addressType
,
_
=
abi
.
NewType
(
"address"
,
""
,
nil
)
legacyCrossDomainMessengerRelayMessageMethod
=
abi
.
NewMethod
(
CrossDomainMessengerLegacyRelayMessageEncoding
=
abi
.
NewMethod
(
"relayMessage"
,
"relayMessage"
,
abi
.
Function
,
...
...
@@ -26,18 +26,21 @@ var (
false
,
// isConst
true
,
// payable
abi
.
Arguments
{
// inputs
{
Name
:
"sender"
,
Type
:
addressType
},
{
Name
:
"target"
,
Type
:
addressType
},
{
Name
:
"sender"
,
Type
:
addressType
},
{
Name
:
"data"
,
Type
:
bytesType
},
{
Name
:
"nonce"
,
Type
:
uint256Type
},
// The actual transaction on the legacy L1CrossDomainMessenger has a trailing
// proof argument but is ignored for the `XDomainCallData` encoding
},
abi
.
Arguments
{},
// outputs
)
)
type
CrossDomainMessengerSentMessageEvent
struct
{
Event
*
database
.
ContractEvent
BridgeMessage
database
.
BridgeMessage
Event
*
database
.
ContractEvent
MessageCalldata
[]
byte
BridgeMessage
database
.
BridgeMessage
}
type
CrossDomainMessengerRelayedMessageEvent
struct
{
...
...
@@ -58,7 +61,6 @@ func CrossDomainMessengerSentMessageEvents(chainSelector string, contractAddress
return
nil
,
err
}
if
len
(
sentMessageEvents
)
==
0
{
// prevent the following db queries if we dont need them
return
nil
,
nil
}
...
...
@@ -68,10 +70,13 @@ func CrossDomainMessengerSentMessageEvents(chainSelector string, contractAddress
if
err
!=
nil
{
return
nil
,
err
}
if
len
(
sentMessageE
vents
)
!=
len
(
sentMessageExtension
Events
)
{
return
nil
,
fmt
.
Errorf
(
"mismatch
in SentMessage events
. %d sent messages & %d sent message extensions"
,
len
(
sentMessageEvents
),
len
(
sentMessageExtensionEvents
))
if
len
(
sentMessageE
xtensionEvents
)
>
len
(
sentMessage
Events
)
{
return
nil
,
fmt
.
Errorf
(
"mismatch. %d sent messages & %d sent message extensions"
,
len
(
sentMessageEvents
),
len
(
sentMessageExtensionEvents
))
}
// We handle version zero messages uniquely since the first version of cross domain messages
// do not have the SentMessageExtension1 event emitted, introduced in version 1.
numVersionZeroMessages
:=
len
(
sentMessageEvents
)
-
len
(
sentMessageExtensionEvents
)
crossDomainSentMessages
:=
make
([]
CrossDomainMessengerSentMessageEvent
,
len
(
sentMessageEvents
))
for
i
:=
range
sentMessageEvents
{
sentMessage
:=
bindings
.
CrossDomainMessengerSentMessage
{
Raw
:
*
sentMessageEvents
[
i
]
.
RLPLog
}
...
...
@@ -79,34 +84,45 @@ func CrossDomainMessengerSentMessageEvents(chainSelector string, contractAddress
if
err
!=
nil
{
return
nil
,
err
}
sentMessageExtension
:=
bindings
.
CrossDomainMessengerSentMessageExtension1
{
Raw
:
*
sentMessageExtensionEvents
[
i
]
.
RLPLog
}
err
=
UnpackLog
(
&
sentMessageExtension
,
sentMessageExtensionEvents
[
i
]
.
RLPLog
,
sentMessageExtensionEventAbi
.
Name
,
crossDomainMessengerAbi
)
if
err
!=
nil
{
return
nil
,
err
version
,
_
:=
DecodeVersionedNonce
(
sentMessage
.
MessageNonce
)
if
i
<
numVersionZeroMessages
&&
version
!=
0
{
return
nil
,
fmt
.
Errorf
(
"expected version zero nonce. nonce %d tx_hash %s"
,
sentMessage
.
MessageNonce
,
sentMessage
.
Raw
.
TxHash
)
}
messageHash
,
err
:=
CrossDomainMessageHash
(
crossDomainMessengerAbi
,
&
sentMessage
,
sentMessageExtension
.
Value
)
// In version zero, to value is bridged through the cross domain messenger.
value
:=
big
.
NewInt
(
0
)
if
version
>
0
{
sentMessageExtension
:=
bindings
.
CrossDomainMessengerSentMessageExtension1
{
Raw
:
*
sentMessageExtensionEvents
[
i
]
.
RLPLog
}
err
=
UnpackLog
(
&
sentMessageExtension
,
sentMessageExtensionEvents
[
i
]
.
RLPLog
,
sentMessageExtensionEventAbi
.
Name
,
crossDomainMessengerAbi
)
if
err
!=
nil
{
return
nil
,
err
}
value
=
sentMessageExtension
.
Value
}
messageCalldata
,
err
:=
CrossDomainMessageCalldata
(
crossDomainMessengerAbi
,
&
sentMessage
,
value
)
if
err
!=
nil
{
return
nil
,
err
}
crossDomainSentMessages
[
i
]
=
CrossDomainMessengerSentMessageEvent
{
Event
:
&
sentMessageEvents
[
i
],
Event
:
&
sentMessageEvents
[
i
],
MessageCalldata
:
messageCalldata
,
BridgeMessage
:
database
.
BridgeMessage
{
MessageHash
:
messageHash
,
MessageHash
:
crypto
.
Keccak256Hash
(
messageCalldata
)
,
Nonce
:
sentMessage
.
MessageNonce
,
SentMessageEventGUID
:
sentMessageEvents
[
i
]
.
GUID
,
GasLimit
:
sentMessage
.
GasLimit
,
Tx
:
database
.
Transaction
{
FromAddress
:
sentMessage
.
Sender
,
ToAddress
:
sentMessage
.
Target
,
Amount
:
sentMessageExtension
.
V
alue
,
Amount
:
v
alue
,
Data
:
sentMessage
.
Message
,
Timestamp
:
sentMessageEvents
[
i
]
.
Timestamp
,
},
},
}
}
return
crossDomainSentMessages
,
nil
...
...
@@ -142,26 +158,25 @@ func CrossDomainMessengerRelayedMessageEvents(chainSelector string, contractAddr
return
crossDomainRelayedMessages
,
nil
}
// Replica of `
Hashing.sol#hash
CrossDomainMessage` solidity implementation
func
CrossDomainMessage
Hash
(
abi
*
abi
.
ABI
,
sentMsg
*
bindings
.
CrossDomainMessengerSentMessage
,
value
*
big
.
Int
)
(
common
.
Hash
,
error
)
{
// Replica of `
Encoding.sol#encode
CrossDomainMessage` solidity implementation
func
CrossDomainMessage
Calldata
(
abi
*
abi
.
ABI
,
sentMsg
*
bindings
.
CrossDomainMessengerSentMessage
,
value
*
big
.
Int
)
([]
byte
,
error
)
{
version
,
_
:=
DecodeVersionedNonce
(
sentMsg
.
MessageNonce
)
switch
version
{
case
0
:
// Legacy Message
inputBytes
,
err
:=
legacyCrossDomainMessengerRelayMessageMethod
.
Inputs
.
Pack
(
sentMsg
.
Sender
,
sentMsg
.
Target
,
sentMsg
.
Message
,
sentMsg
.
MessageNonce
)
inputBytes
,
err
:=
CrossDomainMessengerLegacyRelayMessageEncoding
.
Inputs
.
Pack
(
sentMsg
.
Target
,
sentMsg
.
Sender
,
sentMsg
.
Message
,
sentMsg
.
MessageNonce
)
if
err
!=
nil
{
return
common
.
Hash
{}
,
err
return
nil
,
err
}
msgBytes
:=
append
(
legacyCrossDomainMessengerRelayMessageMethod
.
ID
,
inputBytes
...
)
return
crypto
.
Keccak256Hash
(
msgBytes
),
nil
return
append
(
CrossDomainMessengerLegacyRelayMessageEncoding
.
ID
,
inputBytes
...
),
nil
case
1
:
// Current Message
msgBytes
,
err
:=
abi
.
Pack
(
"relayMessage"
,
sentMsg
.
MessageNonce
,
sentMsg
.
Sender
,
sentMsg
.
Target
,
value
,
sentMsg
.
GasLimit
,
sentMsg
.
Message
)
if
err
!=
nil
{
return
common
.
Hash
{}
,
err
return
nil
,
err
}
return
crypto
.
Keccak256Hash
(
msgBytes
)
,
nil
return
msgBytes
,
nil
}
return
common
.
Hash
{}
,
fmt
.
Errorf
(
"unsupported cross domain messenger version: %d"
,
version
)
return
nil
,
fmt
.
Errorf
(
"unsupported cross domain messenger version: %d"
,
version
)
}
indexer/processors/contracts/legacy_ctc.go
0 → 100644
View file @
467e6f80
package
contracts
import
(
"math/big"
"github.com/ethereum-optimism/optimism/indexer/bigint"
"github.com/ethereum-optimism/optimism/indexer/database"
legacy_bindings
"github.com/ethereum-optimism/optimism/op-bindings/legacy-bindings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type
LegacyCTCDepositEvent
struct
{
Event
*
database
.
ContractEvent
Tx
database
.
Transaction
TxHash
common
.
Hash
GasLimit
*
big
.
Int
}
func
LegacyCTCDepositEvents
(
contractAddress
common
.
Address
,
db
*
database
.
DB
,
fromHeight
,
toHeight
*
big
.
Int
)
([]
LegacyCTCDepositEvent
,
error
)
{
ctcAbi
,
err
:=
legacy_bindings
.
CanonicalTransactionChainMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
transactionEnqueuedEventAbi
:=
ctcAbi
.
Events
[
"TransactionEnqueued"
]
contractEventFilter
:=
database
.
ContractEvent
{
ContractAddress
:
contractAddress
,
EventSignature
:
transactionEnqueuedEventAbi
.
ID
}
events
,
err
:=
db
.
ContractEvents
.
L1ContractEventsWithFilter
(
contractEventFilter
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
nil
,
err
}
ctcTxDeposits
:=
make
([]
LegacyCTCDepositEvent
,
len
(
events
))
for
i
:=
range
events
{
txEnqueued
:=
legacy_bindings
.
CanonicalTransactionChainTransactionEnqueued
{
Raw
:
*
events
[
i
]
.
RLPLog
}
err
=
UnpackLog
(
&
txEnqueued
,
events
[
i
]
.
RLPLog
,
transactionEnqueuedEventAbi
.
Name
,
ctcAbi
)
if
err
!=
nil
{
return
nil
,
err
}
// Enqueued Deposits do not carry a `msg.value` amount. ETH is only minted on L2 via the L1StandardBrige
ctcTxDeposits
[
i
]
=
LegacyCTCDepositEvent
{
Event
:
&
events
[
i
]
.
ContractEvent
,
GasLimit
:
txEnqueued
.
GasLimit
,
TxHash
:
types
.
NewTransaction
(
0
,
txEnqueued
.
Target
,
bigint
.
Zero
,
txEnqueued
.
GasLimit
.
Uint64
(),
nil
,
txEnqueued
.
Data
)
.
Hash
(),
Tx
:
database
.
Transaction
{
FromAddress
:
txEnqueued
.
L1TxOrigin
,
ToAddress
:
txEnqueued
.
Target
,
Amount
:
bigint
.
Zero
,
Data
:
txEnqueued
.
Data
,
Timestamp
:
events
[
i
]
.
Timestamp
,
},
}
}
return
ctcTxDeposits
,
nil
}
indexer/processors/contracts/legacy_standard_bridge.go
0 → 100644
View file @
467e6f80
package
contracts
import
(
"math/big"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/common"
)
type
LegacyBridgeEvent
struct
{
Event
*
database
.
ContractEvent
BridgeTransfer
database
.
BridgeTransfer
}
func
L1StandardBridgeLegacyDepositInitiatedEvents
(
contractAddress
common
.
Address
,
db
*
database
.
DB
,
fromHeight
,
toHeight
*
big
.
Int
)
([]
LegacyBridgeEvent
,
error
)
{
l1StandardBridgeAbi
,
err
:=
bindings
.
L1StandardBridgeMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
// The L1StandardBridge contains the legacy events
ethDepositEventAbi
:=
l1StandardBridgeAbi
.
Events
[
"ETHDepositInitiated"
]
erc20DepositEventAbi
:=
l1StandardBridgeAbi
.
Events
[
"ERC20DepositInitiated"
]
// Grab both ETH & ERC20 Events
ethDepositEvents
,
err
:=
db
.
ContractEvents
.
L1ContractEventsWithFilter
(
database
.
ContractEvent
{
ContractAddress
:
contractAddress
,
EventSignature
:
ethDepositEventAbi
.
ID
},
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
nil
,
err
}
erc20DepositEvents
,
err
:=
db
.
ContractEvents
.
L1ContractEventsWithFilter
(
database
.
ContractEvent
{
ContractAddress
:
contractAddress
,
EventSignature
:
erc20DepositEventAbi
.
ID
},
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
nil
,
err
}
// Represent the ETH deposits via the ETH ERC20 predeploy address
deposits
:=
make
([]
LegacyBridgeEvent
,
len
(
ethDepositEvents
)
+
len
(
erc20DepositEvents
))
for
i
:=
range
ethDepositEvents
{
bridgeEvent
:=
bindings
.
L1StandardBridgeETHDepositInitiated
{
Raw
:
*
ethDepositEvents
[
i
]
.
RLPLog
}
err
:=
UnpackLog
(
&
bridgeEvent
,
&
bridgeEvent
.
Raw
,
ethDepositEventAbi
.
Name
,
l1StandardBridgeAbi
)
if
err
!=
nil
{
return
nil
,
err
}
deposits
[
i
]
=
LegacyBridgeEvent
{
Event
:
&
ethDepositEvents
[
i
]
.
ContractEvent
,
BridgeTransfer
:
database
.
BridgeTransfer
{
TokenPair
:
database
.
ETHTokenPair
,
Tx
:
database
.
Transaction
{
FromAddress
:
bridgeEvent
.
From
,
ToAddress
:
bridgeEvent
.
To
,
Amount
:
bridgeEvent
.
Amount
,
Data
:
bridgeEvent
.
ExtraData
,
Timestamp
:
ethDepositEvents
[
i
]
.
Timestamp
,
},
},
}
}
for
i
:=
range
erc20DepositEvents
{
bridgeEvent
:=
bindings
.
L1StandardBridgeERC20DepositInitiated
{
Raw
:
*
erc20DepositEvents
[
i
]
.
RLPLog
}
err
:=
UnpackLog
(
&
bridgeEvent
,
&
bridgeEvent
.
Raw
,
erc20DepositEventAbi
.
Name
,
l1StandardBridgeAbi
)
if
err
!=
nil
{
return
nil
,
err
}
deposits
[
len
(
ethDepositEvents
)
+
i
]
=
LegacyBridgeEvent
{
Event
:
&
erc20DepositEvents
[
i
]
.
ContractEvent
,
BridgeTransfer
:
database
.
BridgeTransfer
{
TokenPair
:
database
.
TokenPair
{
LocalTokenAddress
:
bridgeEvent
.
L1Token
,
RemoteTokenAddress
:
bridgeEvent
.
L2Token
},
Tx
:
database
.
Transaction
{
FromAddress
:
bridgeEvent
.
From
,
ToAddress
:
bridgeEvent
.
To
,
Amount
:
bridgeEvent
.
Amount
,
Data
:
bridgeEvent
.
ExtraData
,
Timestamp
:
erc20DepositEvents
[
i
]
.
Timestamp
,
},
},
}
}
return
deposits
,
nil
}
func
L2StandardBridgeLegacyWithdrawalInitiatedEvents
(
contractAddress
common
.
Address
,
db
*
database
.
DB
,
fromHeight
,
toHeight
*
big
.
Int
)
([]
LegacyBridgeEvent
,
error
)
{
l2StandardBridgeAbi
,
err
:=
bindings
.
L2StandardBridgeMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
withdrawalInitiatedEventAbi
:=
l2StandardBridgeAbi
.
Events
[
"WithdrawalInitiated"
]
withdrawalEvents
,
err
:=
db
.
ContractEvents
.
L2ContractEventsWithFilter
(
database
.
ContractEvent
{
ContractAddress
:
contractAddress
,
EventSignature
:
withdrawalInitiatedEventAbi
.
ID
},
fromHeight
,
toHeight
)
if
err
!=
nil
{
return
nil
,
err
}
withdrawals
:=
make
([]
LegacyBridgeEvent
,
len
(
withdrawalEvents
))
for
i
:=
range
withdrawalEvents
{
bridgeEvent
:=
bindings
.
L2StandardBridgeWithdrawalInitiated
{
Raw
:
*
withdrawalEvents
[
i
]
.
RLPLog
}
err
:=
UnpackLog
(
&
bridgeEvent
,
&
bridgeEvent
.
Raw
,
withdrawalInitiatedEventAbi
.
Name
,
l2StandardBridgeAbi
)
if
err
!=
nil
{
return
nil
,
err
}
withdrawals
[
i
]
=
LegacyBridgeEvent
{
Event
:
&
withdrawalEvents
[
i
]
.
ContractEvent
,
BridgeTransfer
:
database
.
BridgeTransfer
{
TokenPair
:
database
.
ETHTokenPair
,
Tx
:
database
.
Transaction
{
FromAddress
:
bridgeEvent
.
From
,
ToAddress
:
bridgeEvent
.
To
,
Amount
:
bridgeEvent
.
Amount
,
Data
:
bridgeEvent
.
ExtraData
,
Timestamp
:
withdrawalEvents
[
i
]
.
Timestamp
,
},
},
}
}
return
withdrawals
,
nil
}
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