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
e3d1af10
Commit
e3d1af10
authored
Aug 15, 2023
by
Hamdi Allam
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
decouple finalization events from needing an rpc
parent
a0acfebf
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
113 additions
and
143 deletions
+113
-143
bridge_transfers.go
indexer/database/bridge_transfers.go
+6
-1
bridge_transfers_e2e_test.go
indexer/e2e_tests/bridge_transfers_e2e_test.go
+14
-10
20230523_create_schema.sql
indexer/migrations/20230523_create_schema.sql
+6
-6
l1_processor.go
indexer/processor/l1_processor.go
+21
-24
l2_processor.go
indexer/processor/l2_processor.go
+19
-21
standard_bridge.go
indexer/processor/standard_bridge.go
+47
-81
No files found.
indexer/database/bridge_transfers.go
View file @
e3d1af10
...
...
@@ -5,9 +5,14 @@ import (
"gorm.io/gorm"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common"
)
var
(
ETHTokenPair
=
TokenPair
{
L1TokenAddress
:
predeploys
.
LegacyERC20ETHAddr
,
L2TokenAddress
:
predeploys
.
LegacyERC20ETHAddr
}
)
/**
* Types
*/
...
...
@@ -18,7 +23,7 @@ type TokenPair struct {
}
type
BridgeTransfer
struct
{
CrossDomainMessageHash
*
common
.
Hash
CrossDomainMessageHash
*
common
.
Hash
`gorm:"serializer:json"`
Tx
Transaction
`gorm:"embedded"`
TokenPair
TokenPair
`gorm:"embedded"`
...
...
indexer/e2e_tests/bridge_transfers_e2e_test.go
View file @
e3d1af10
...
...
@@ -7,7 +7,6 @@ import (
"time"
e2etest_utils
"github.com/ethereum-optimism/optimism/indexer/e2e_tests/utils"
"github.com/ethereum-optimism/optimism/indexer/processor"
op_e2e
"github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
...
...
@@ -65,9 +64,7 @@ func TestE2EBridgeTransfersStandardBridgeETHDeposit(t *testing.T) {
// StandardBridge flows through the messenger. We remove the first two significant
// bytes of the nonce dedicated to the version. nonce == 0 (first message)
require
.
NotNil
(
t
,
deposit
.
CrossDomainMessengerNonce
)
_
,
nonce
:=
processor
.
DecodeVersionedNonce
(
deposit
.
CrossDomainMessengerNonce
.
Int
)
require
.
Zero
(
t
,
nonce
.
Uint64
())
require
.
NotNil
(
t
,
deposit
.
CrossDomainMessageHash
)
// (2) Test Deposit Finalization via CrossDomainMessenger relayed message
depositReceipt
,
err
=
wait
.
ForReceiptOK
(
context
.
Background
(),
testSuite
.
L2Client
,
types
.
NewTx
(
depositInfo
.
DepositTx
)
.
Hash
())
...
...
@@ -77,7 +74,7 @@ func TestE2EBridgeTransfersStandardBridgeETHDeposit(t *testing.T) {
return
l2Header
!=
nil
&&
l2Header
.
Number
.
Uint64
()
>=
depositReceipt
.
BlockNumber
.
Uint64
(),
nil
}))
crossDomainBridgeMessage
,
err
:=
testSuite
.
DB
.
BridgeMessages
.
L1BridgeMessage
(
deposit
.
CrossDomainMessengerNonce
.
Int
)
crossDomainBridgeMessage
,
err
:=
testSuite
.
DB
.
BridgeMessages
.
L1BridgeMessage
ByHash
(
*
deposit
.
CrossDomainMessageHash
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
crossDomainBridgeMessage
)
require
.
NotNil
(
t
,
crossDomainBridgeMessage
.
RelayedMessageEventGUID
)
...
...
@@ -125,7 +122,7 @@ func TestE2EBridgeTransfersOptimismPortalETHReceive(t *testing.T) {
require
.
Len
(
t
,
deposit
.
Tx
.
Data
,
0
)
// deposit was not sent through the cross domain messenger
require
.
Nil
(
t
,
deposit
.
CrossDomainMess
engerNonce
)
require
.
Nil
(
t
,
deposit
.
CrossDomainMess
ageHash
)
// (2) Test Deposit Finalization
// Nothing to do as we rely on the derivation process to include the deposit
...
...
@@ -187,9 +184,11 @@ func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
// StandardBridge flows through the messenger. We remove the first two
// bytes of the nonce dedicated to the version. nonce == 0 (first message)
require
.
NotNil
(
t
,
withdrawal
.
CrossDomainMessengerNonce
)
_
,
nonce
:=
processor
.
DecodeVersionedNonce
(
withdrawal
.
CrossDomainMessengerNonce
.
Int
)
require
.
Zero
(
t
,
nonce
.
Uint64
())
require
.
NotNil
(
t
,
withdrawal
.
CrossDomainMessageHash
)
crossDomainBridgeMessage
,
err
:=
testSuite
.
DB
.
BridgeMessages
.
L2BridgeMessageByHash
(
*
withdrawal
.
CrossDomainMessageHash
)
require
.
NoError
(
t
,
err
)
require
.
Nil
(
t
,
crossDomainBridgeMessage
.
RelayedMessageEventGUID
)
// (2) Test Withdrawal Proven/Finalized. Test the sql join queries to populate the right transaction
require
.
Empty
(
t
,
aliceWithdrawals
[
0
]
.
ProvenL1TransactionHash
)
...
...
@@ -206,6 +205,11 @@ func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
proveReceipt
.
TxHash
,
aliceWithdrawals
[
0
]
.
ProvenL1TransactionHash
)
require
.
Equal
(
t
,
finalizeReceipt
.
TxHash
,
aliceWithdrawals
[
0
]
.
FinalizedL1TransactionHash
)
crossDomainBridgeMessage
,
err
=
testSuite
.
DB
.
BridgeMessages
.
L2BridgeMessageByHash
(
*
withdrawal
.
CrossDomainMessageHash
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
crossDomainBridgeMessage
)
require
.
NotNil
(
t
,
crossDomainBridgeMessage
.
RelayedMessageEventGUID
)
}
func
TestE2EBridgeTransfersL2ToL1MessagePasserReceive
(
t
*
testing
.
T
)
{
...
...
@@ -262,7 +266,7 @@ func TestE2EBridgeTransfersL2ToL1MessagePasserReceive(t *testing.T) {
require
.
Len
(
t
,
withdrawal
.
Tx
.
Data
,
0
)
// withdrawal was not sent through the cross domain messenger
require
.
Nil
(
t
,
withdrawal
.
CrossDomainMess
engerNonce
)
require
.
Nil
(
t
,
withdrawal
.
CrossDomainMess
ageHash
)
// (2) Test Withdrawal Proven/Finalized. Test the sql join queries to populate the right transaction
require
.
Empty
(
t
,
aliceWithdrawals
[
0
]
.
ProvenL1TransactionHash
)
...
...
indexer/migrations/20230523_create_schema.sql
View file @
e3d1af10
...
...
@@ -153,8 +153,8 @@ CREATE TABLE IF NOT EXISTS l2_transaction_withdrawals (
-- CrossDomainMessenger
CREATE
TABLE
IF
NOT
EXISTS
l1_bridge_messages
(
nonce
UINT256
NOT
NULL
PRIMARY
KEY
,
message_hash
VARCHAR
NOT
NULL
,
transaction_source_hash
VARCHAR
NOT
NULL
REFERENCES
l1_transaction_deposits
(
source_hash
),
message_hash
VARCHAR
UNIQUE
NOT
NULL
,
transaction_source_hash
VARCHAR
UNIQUE
NOT
NULL
REFERENCES
l1_transaction_deposits
(
source_hash
),
sent_message_event_guid
VARCHAR
NOT
NULL
UNIQUE
REFERENCES
l1_contract_events
(
guid
),
relayed_message_event_guid
VARCHAR
UNIQUE
REFERENCES
l2_contract_events
(
guid
),
...
...
@@ -169,8 +169,8 @@ CREATE TABLE IF NOT EXISTS l1_bridge_messages(
);
CREATE
TABLE
IF
NOT
EXISTS
l2_bridge_messages
(
nonce
UINT256
NOT
NULL
PRIMARY
KEY
,
message_hash
VARCHAR
NOT
NULL
,
transaction_withdrawal_hash
VARCHAR
NOT
NULL
REFERENCES
l2_transaction_withdrawals
(
withdrawal_hash
),
message_hash
VARCHAR
UNIQUE
NOT
NULL
,
transaction_withdrawal_hash
VARCHAR
UNIQUE
NOT
NULL
REFERENCES
l2_transaction_withdrawals
(
withdrawal_hash
),
sent_message_event_guid
VARCHAR
NOT
NULL
UNIQUE
REFERENCES
l2_contract_events
(
guid
),
relayed_message_event_guid
VARCHAR
UNIQUE
REFERENCES
l1_contract_events
(
guid
),
...
...
@@ -190,7 +190,7 @@ CREATE TABLE IF NOT EXISTS l1_bridge_deposits (
-- We allow the cross_domain_message_hash to be NULL-able to account
-- for scenarios where ETH is simply sent to the OptimismPortal contract
cross_domain_message_hash
VARCHAR
UNIQUE
REFERENCES
l1_bridge_messages
(
nonce
),
cross_domain_message_hash
VARCHAR
UNIQUE
REFERENCES
l1_bridge_messages
(
message_hash
),
-- Deposit information
from_address
VARCHAR
NOT
NULL
,
...
...
@@ -206,7 +206,7 @@ CREATE TABLE IF NOT EXISTS l2_bridge_withdrawals (
-- We allow the cross_domain_message_hash to be NULL-able to account for
-- scenarios where ETH is simply sent to the L2ToL1MessagePasser contract
cross_domain_message_hash
VARCHAR
UNIQUE
REFERENCES
l2_bridge_messages
(
nonce
),
cross_domain_message_hash
VARCHAR
UNIQUE
REFERENCES
l2_bridge_messages
(
message_hash
),
-- Withdrawal information
from_address
VARCHAR
NOT
NULL
,
...
...
indexer/processor/l1_processor.go
View file @
e3d1af10
...
...
@@ -12,7 +12,6 @@ import (
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
legacy_bindings
"github.com/ethereum-optimism/optimism/op-bindings/legacy-bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum"
...
...
@@ -222,7 +221,7 @@ func l1ProcessFn(processLog log.Logger, ethClient node.EthClient, l1Contracts co
}
// forward along contract events to standard bridge processor
err
=
l1ProcessContractEventsStandardBridge
(
processLog
,
db
,
ethClient
,
processedContractEvents
)
err
=
l1ProcessContractEventsStandardBridge
(
processLog
,
db
,
processedContractEvents
)
if
err
!=
nil
{
return
err
}
...
...
@@ -266,11 +265,10 @@ func l1ProcessContractEventsBridgeTransactions(processLog log.Logger, db *databa
if
len
(
depositTx
.
Data
)
==
0
&&
depositTx
.
Value
.
BitLen
()
>
0
{
ethDeposits
=
append
(
ethDeposits
,
&
database
.
L1BridgeDeposit
{
TransactionSourceHash
:
depositTx
.
SourceHash
,
Tx
:
transactionDeposits
[
i
]
.
Tx
,
TokenPair
:
database
.
TokenPair
{
BridgeTransfer
:
database
.
BridgeTransfer
{
Tx
:
transactionDeposits
[
i
]
.
Tx
,
// TODO index eth token if it doesn't exist
L1TokenAddress
:
predeploys
.
LegacyERC20ETHAddr
,
L2TokenAddress
:
predeploys
.
LegacyERC20ETHAddr
,
TokenPair
:
database
.
ETHTokenPair
,
},
})
}
...
...
@@ -443,9 +441,7 @@ func l1ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
return
nil
}
func
l1ProcessContractEventsStandardBridge
(
processLog
log
.
Logger
,
db
*
database
.
DB
,
ethClient
node
.
EthClient
,
events
*
ProcessedContractEvents
)
error
{
rawEthClient
:=
ethclient
.
NewClient
(
ethClient
.
RawRpcClient
())
func
l1ProcessContractEventsStandardBridge
(
processLog
log
.
Logger
,
db
*
database
.
DB
,
events
*
ProcessedContractEvents
)
error
{
// (1) Process New Deposits
initiatedDepositEvents
,
err
:=
StandardBridgeInitiatedEvents
(
events
)
if
err
!=
nil
{
...
...
@@ -465,16 +461,18 @@ func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
}
deposits
[
i
]
=
&
database
.
L1BridgeDeposit
{
TransactionSourceHash
:
depositTx
.
SourceHash
,
CrossDomainMessengerNonce
:
&
database
.
U256
{
Int
:
initiatedBridgeEvent
.
CrossDomainMessengerNonce
},
// TODO index the tokens pairs if they don't exist
TokenPair
:
database
.
TokenPair
{
L1TokenAddress
:
initiatedBridgeEvent
.
LocalToken
,
L2TokenAddress
:
initiatedBridgeEvent
.
RemoteToken
},
Tx
:
database
.
Transaction
{
FromAddress
:
initiatedBridgeEvent
.
From
,
ToAddress
:
initiatedBridgeEvent
.
To
,
Amount
:
database
.
U256
{
Int
:
initiatedBridgeEvent
.
Amount
},
Data
:
initiatedBridgeEvent
.
ExtraData
,
Timestamp
:
initiatedBridgeEvent
.
Event
.
Timestamp
,
TransactionSourceHash
:
depositTx
.
SourceHash
,
BridgeTransfer
:
database
.
BridgeTransfer
{
CrossDomainMessageHash
:
&
initiatedBridgeEvent
.
CrossDomainMessageHash
,
// TODO index the tokens pairs if they don't exist
TokenPair
:
database
.
TokenPair
{
L1TokenAddress
:
initiatedBridgeEvent
.
LocalToken
,
L2TokenAddress
:
initiatedBridgeEvent
.
RemoteToken
},
Tx
:
database
.
Transaction
{
FromAddress
:
initiatedBridgeEvent
.
From
,
ToAddress
:
initiatedBridgeEvent
.
To
,
Amount
:
database
.
U256
{
Int
:
initiatedBridgeEvent
.
Amount
},
Data
:
initiatedBridgeEvent
.
ExtraData
,
Timestamp
:
initiatedBridgeEvent
.
Event
.
Timestamp
,
},
},
}
}
...
...
@@ -491,17 +489,17 @@ func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
// - We dont need do anything actionable on the database here as this is layered on top of the
// bridge transaction & messages that have a tracked lifecyle. We simply walk through and ensure
// that the corresponding initiated withdrawals exist and match as an integrity check
finalizedWithdrawalEvents
,
err
:=
StandardBridgeFinalizedEvents
(
rawEthClient
,
events
)
finalizedWithdrawalEvents
,
err
:=
StandardBridgeFinalizedEvents
(
events
)
if
err
!=
nil
{
return
err
}
for
_
,
finalizedWithdrawalEvent
:=
range
finalizedWithdrawalEvents
{
withdrawal
,
err
:=
db
.
BridgeTransfers
.
L2BridgeWithdrawal
ByCrossDomainMessengerNonce
(
finalizedWithdrawalEvent
.
CrossDomainMessengerNonce
)
withdrawal
,
err
:=
db
.
BridgeTransfers
.
L2BridgeWithdrawal
WithFilter
(
database
.
BridgeTransfer
{
CrossDomainMessageHash
:
&
finalizedWithdrawalEvent
.
CrossDomainMessageHash
}
)
if
err
!=
nil
{
return
err
}
else
if
withdrawal
==
nil
{
processLog
.
Error
(
"missing indexed L2StandardBridge withdrawal for finalization"
,
"cross_domain_mess
enger_nonce"
,
finalizedWithdrawalEvent
.
CrossDomainMessengerNonce
)
processLog
.
Error
(
"missing indexed L2StandardBridge withdrawal for finalization"
,
"cross_domain_mess
age_hash"
,
finalizedWithdrawalEvent
.
CrossDomainMessageHash
)
return
errors
.
New
(
"missing indexed L2StandardBridge withdrawal for finalization event"
)
}
...
...
@@ -509,8 +507,7 @@ func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
if
finalizedWithdrawalEvent
.
From
!=
withdrawal
.
Tx
.
FromAddress
||
finalizedWithdrawalEvent
.
To
!=
withdrawal
.
Tx
.
ToAddress
||
finalizedWithdrawalEvent
.
Amount
.
Cmp
(
withdrawal
.
Tx
.
Amount
.
Int
)
!=
0
||
!
bytes
.
Equal
(
finalizedWithdrawalEvent
.
ExtraData
,
withdrawal
.
Tx
.
Data
)
||
finalizedWithdrawalEvent
.
LocalToken
!=
withdrawal
.
TokenPair
.
L1TokenAddress
||
finalizedWithdrawalEvent
.
RemoteToken
!=
withdrawal
.
TokenPair
.
L2TokenAddress
{
processLog
.
Crit
(
"bridge finalization fields mismatch with initiated fields!"
,
"tx_withdrawal_hash"
,
withdrawal
.
TransactionWithdrawalHash
,
"cross_domain_messenger_nonce"
,
withdrawal
.
CrossDomainMessengerNonce
.
Int
)
return
errors
.
New
(
"bridge tx mismatch!"
)
processLog
.
Crit
(
"bridge finalization fields mismatch with initiated fields!"
,
"tx_withdrawal_hash"
,
withdrawal
.
TransactionWithdrawalHash
,
"cross_domain_message_hash"
,
withdrawal
.
CrossDomainMessageHash
)
}
}
...
...
indexer/processor/l2_processor.go
View file @
e3d1af10
...
...
@@ -10,7 +10,6 @@ import (
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -160,7 +159,7 @@ func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2
}
// forward along contract events to standard bridge processor
err
=
l2ProcessContractEventsStandardBridge
(
processLog
,
db
,
ethClient
,
processedContractEvents
)
err
=
l2ProcessContractEventsStandardBridge
(
processLog
,
db
,
processedContractEvents
)
if
err
!=
nil
{
return
err
}
...
...
@@ -198,10 +197,9 @@ func l2ProcessContractEventsBridgeTransactions(processLog log.Logger, db *databa
if
len
(
withdrawalEvent
.
Data
)
==
0
&&
withdrawalEvent
.
Value
.
BitLen
()
>
0
{
ethWithdrawals
=
append
(
ethWithdrawals
,
&
database
.
L2BridgeWithdrawal
{
TransactionWithdrawalHash
:
withdrawalEvent
.
WithdrawalHash
,
Tx
:
transactionWithdrawals
[
i
]
.
Tx
,
TokenPair
:
database
.
TokenPair
{
L1TokenAddress
:
predeploys
.
LegacyERC20ETHAddr
,
L2TokenAddress
:
predeploys
.
LegacyERC20ETHAddr
,
BridgeTransfer
:
database
.
BridgeTransfer
{
Tx
:
transactionWithdrawals
[
i
]
.
Tx
,
TokenPair
:
database
.
ETHTokenPair
,
},
})
}
...
...
@@ -330,9 +328,7 @@ func l2ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
return
nil
}
func
l2ProcessContractEventsStandardBridge
(
processLog
log
.
Logger
,
db
*
database
.
DB
,
ethClient
node
.
EthClient
,
events
*
ProcessedContractEvents
)
error
{
rawEthClient
:=
ethclient
.
NewClient
(
ethClient
.
RawRpcClient
())
func
l2ProcessContractEventsStandardBridge
(
processLog
log
.
Logger
,
db
*
database
.
DB
,
events
*
ProcessedContractEvents
)
error
{
l2ToL1MessagePasserABI
,
err
:=
bindings
.
NewL2ToL1MessagePasser
(
common
.
Address
{},
nil
)
if
err
!=
nil
{
return
err
...
...
@@ -357,14 +353,16 @@ func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
withdrawals
[
i
]
=
&
database
.
L2BridgeWithdrawal
{
TransactionWithdrawalHash
:
msgPassedEvent
.
WithdrawalHash
,
CrossDomainMessengerNonce
:
&
database
.
U256
{
Int
:
initiatedBridgeEvent
.
CrossDomainMessengerNonce
},
TokenPair
:
database
.
TokenPair
{
L1TokenAddress
:
initiatedBridgeEvent
.
LocalToken
,
L2TokenAddress
:
initiatedBridgeEvent
.
RemoteToken
},
Tx
:
database
.
Transaction
{
FromAddress
:
initiatedBridgeEvent
.
From
,
ToAddress
:
initiatedBridgeEvent
.
To
,
Amount
:
database
.
U256
{
Int
:
initiatedBridgeEvent
.
Amount
},
Data
:
initiatedBridgeEvent
.
ExtraData
,
Timestamp
:
initiatedBridgeEvent
.
Event
.
Timestamp
,
BridgeTransfer
:
database
.
BridgeTransfer
{
CrossDomainMessageHash
:
&
initiatedBridgeEvent
.
CrossDomainMessageHash
,
TokenPair
:
database
.
TokenPair
{
L1TokenAddress
:
initiatedBridgeEvent
.
LocalToken
,
L2TokenAddress
:
initiatedBridgeEvent
.
RemoteToken
},
Tx
:
database
.
Transaction
{
FromAddress
:
initiatedBridgeEvent
.
From
,
ToAddress
:
initiatedBridgeEvent
.
To
,
Amount
:
database
.
U256
{
Int
:
initiatedBridgeEvent
.
Amount
},
Data
:
initiatedBridgeEvent
.
ExtraData
,
Timestamp
:
initiatedBridgeEvent
.
Event
.
Timestamp
,
},
},
}
}
...
...
@@ -382,18 +380,18 @@ func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
// bridge transaction & messages that have a tracked lifecyle. We simply walk through and ensure
// that the corresponding initiated deposits exist as an integrity check
finalizedDepositEvents
,
err
:=
StandardBridgeFinalizedEvents
(
rawEthClient
,
events
)
finalizedDepositEvents
,
err
:=
StandardBridgeFinalizedEvents
(
events
)
if
err
!=
nil
{
return
err
}
for
_
,
finalizedDepositEvent
:=
range
finalizedDepositEvents
{
deposit
,
err
:=
db
.
BridgeTransfers
.
L1BridgeDeposit
ByCrossDomainMessengerNonce
(
finalizedDepositEvent
.
CrossDomainMessengerNonce
)
deposit
,
err
:=
db
.
BridgeTransfers
.
L1BridgeDeposit
WithFilter
(
database
.
BridgeTransfer
{
CrossDomainMessageHash
:
&
finalizedDepositEvent
.
CrossDomainMessageHash
}
)
if
err
!=
nil
{
return
err
}
else
if
deposit
==
nil
{
// Indexed CrossDomainMessenger messages ensure we're in a caught up state here
processLog
.
Error
(
"missing indexed L1StandardBridge deposit on finalization"
,
"cross_domain_m
essenger_nonce"
,
finalizedDepositEvent
.
CrossDomainMessengerNonce
)
processLog
.
Error
(
"missing indexed L1StandardBridge deposit on finalization"
,
"cross_domain_m
assage_hash"
,
finalizedDepositEvent
.
CrossDomainMessageHash
)
return
errors
.
New
(
"missing indexed L1StandardBridge deposit on finalization"
)
}
...
...
@@ -401,7 +399,7 @@ func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
if
finalizedDepositEvent
.
From
!=
deposit
.
Tx
.
FromAddress
||
finalizedDepositEvent
.
To
!=
deposit
.
Tx
.
ToAddress
||
finalizedDepositEvent
.
Amount
.
Cmp
(
deposit
.
Tx
.
Amount
.
Int
)
!=
0
||
!
bytes
.
Equal
(
finalizedDepositEvent
.
ExtraData
,
deposit
.
Tx
.
Data
)
||
finalizedDepositEvent
.
LocalToken
!=
deposit
.
TokenPair
.
L1TokenAddress
||
finalizedDepositEvent
.
RemoteToken
!=
deposit
.
TokenPair
.
L2TokenAddress
{
processLog
.
Error
(
"bridge finalization fields mismatch with initiated fields!"
,
"tx_source_hash"
,
deposit
.
TransactionSourceHash
,
"cross_domain_mess
enger_nonce"
,
deposit
.
CrossDomainMessengerNonce
.
Int
)
processLog
.
Error
(
"bridge finalization fields mismatch with initiated fields!"
,
"tx_source_hash"
,
deposit
.
TransactionSourceHash
,
"cross_domain_mess
age_hash"
,
deposit
.
CrossDomainMessageHash
)
return
errors
.
New
(
"bridge tx mismatch"
)
}
}
...
...
indexer/processor/standard_bridge.go
View file @
e3d1af10
...
...
@@ -2,16 +2,13 @@ package processor
import
(
"bytes"
"context"
"errors"
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/
ethclient
"
"github.com/ethereum/go-ethereum/
common
"
)
type
StandardBridgeInitiatedEvent
struct
{
...
...
@@ -19,8 +16,8 @@ type StandardBridgeInitiatedEvent struct {
// the hardcoded ETH address
*
bindings
.
StandardBridgeERC20BridgeInitiated
CrossDomainMess
engerNonce
*
big
.
Int
Event
*
database
.
ContractEvent
CrossDomainMess
ageHash
common
.
Hash
Event
*
database
.
ContractEvent
}
type
StandardBridgeFinalizedEvent
struct
{
...
...
@@ -28,8 +25,8 @@ type StandardBridgeFinalizedEvent struct {
// the hardcoded ETH address
*
bindings
.
StandardBridgeERC20BridgeFinalized
CrossDomainMess
engerNonce
*
big
.
Int
Event
*
database
.
ContractEvent
CrossDomainMess
ageHash
common
.
Hash
Event
*
database
.
ContractEvent
}
// StandardBridgeInitiatedEvents extracts all initiated bridge events from the contracts that follow the StandardBridge ABI. The
...
...
@@ -50,13 +47,13 @@ func StandardBridgeInitiatedEvents(events *ProcessedContractEvents) ([]StandardB
// StandardBridgeFinalizedEvents extracts all finalization bridge events from the contracts that follow the StandardBridge ABI. The
// correlated CrossDomainMessenger nonce is also parsed by looking at the parameters of the corresponding relayMessage transaction data.
func
StandardBridgeFinalizedEvents
(
rawEthClient
*
ethclient
.
Client
,
events
*
ProcessedContractEvents
)
([]
StandardBridgeFinalizedEvent
,
error
)
{
ethBridgeFinalizedEvents
,
err
:=
_standardBridgeFinalizedEvents
[
bindings
.
StandardBridgeETHBridgeFinalized
](
rawEthClient
,
events
)
func
StandardBridgeFinalizedEvents
(
events
*
ProcessedContractEvents
)
([]
StandardBridgeFinalizedEvent
,
error
)
{
ethBridgeFinalizedEvents
,
err
:=
_standardBridgeFinalizedEvents
[
bindings
.
StandardBridgeETHBridgeFinalized
](
events
)
if
err
!=
nil
{
return
nil
,
err
}
erc20BridgeFinalizedEvents
,
err
:=
_standardBridgeFinalizedEvents
[
bindings
.
StandardBridgeERC20BridgeFinalized
](
rawEthClient
,
events
)
erc20BridgeFinalizedEvents
,
err
:=
_standardBridgeFinalizedEvents
[
bindings
.
StandardBridgeERC20BridgeFinalized
](
events
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -68,17 +65,18 @@ func StandardBridgeFinalizedEvents(rawEthClient *ethclient.Client, events *Proce
func
_standardBridgeInitiatedEvents
[
BridgeEvent
bindings
.
StandardBridgeETHBridgeInitiated
|
bindings
.
StandardBridgeERC20BridgeInitiated
](
events
*
ProcessedContractEvents
,
)
([]
StandardBridgeInitiatedEvent
,
error
)
{
S
tandardBridgeABI
,
err
:=
bindings
.
StandardBridgeMetaData
.
GetAbi
()
s
tandardBridgeABI
,
err
:=
bindings
.
StandardBridgeMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
l1CrossDomainMessengerABI
,
err
:=
bindings
.
L1
CrossDomainMessengerMetaData
.
GetAbi
()
crossDomainMessengerABI
,
err
:=
bindings
.
CrossDomainMessengerMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
sentMessageEventAbi
:=
l1CrossDomainMessengerABI
.
Events
[
"SentMessage"
]
sentMessageEventAbi
:=
crossDomainMessengerABI
.
Events
[
"SentMessage"
]
sentMessageExtensionEventAbi
:=
crossDomainMessengerABI
.
Events
[
"SentMessageExtension1"
]
var
tmp
BridgeEvent
var
eventName
string
...
...
@@ -94,24 +92,43 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
panic
(
"should not be here"
)
}
processedInitiatedBridgeEvents
:=
events
.
eventsBySignature
[
S
tandardBridgeABI
.
Events
[
eventName
]
.
ID
]
processedInitiatedBridgeEvents
:=
events
.
eventsBySignature
[
s
tandardBridgeABI
.
Events
[
eventName
]
.
ID
]
initiatedBridgeEvents
:=
make
([]
StandardBridgeInitiatedEvent
,
len
(
processedInitiatedBridgeEvents
))
for
i
,
bridgeInitiatedEvent
:=
range
processedInitiatedBridgeEvents
{
log
:=
bridgeInitiatedEvent
.
RLPLog
var
bridgeData
BridgeEvent
err
:=
UnpackLog
(
&
bridgeData
,
log
,
eventName
,
S
tandardBridgeABI
)
err
:=
UnpackLog
(
&
bridgeData
,
log
,
eventName
,
s
tandardBridgeABI
)
if
err
!=
nil
{
return
nil
,
err
}
// Look for the sent message event to
extract the associated messager nonce
// Look for the sent message event to
compute the message hash of the relayed tx
// - L1: BridgeInitiated -> Portal#DepositTransaction -> SentMessage ...
// - L1: BridgeInitiated -> L2ToL1MessagePasser#MessagePassed -> SentMessage ...
var
sentMsgData
bindings
.
L1
CrossDomainMessengerSentMessage
var
sentMsgData
bindings
.
CrossDomainMessengerSentMessage
sentMsgLog
:=
events
.
eventByLogIndex
[
ProcessedContractEventLogIndexKey
{
log
.
BlockHash
,
log
.
Index
+
2
}]
.
RLPLog
if
sentMsgLog
.
Topics
[
0
]
!=
sentMessageEventAbi
.
ID
{
return
nil
,
errors
.
New
(
"unexpected bridge event ordering"
)
}
sentMsgData
.
Raw
=
*
sentMsgLog
err
=
UnpackLog
(
&
sentMsgData
,
sentMsgLog
,
sentMessageEventAbi
.
Name
,
l1CrossDomainMessengerABI
)
err
=
UnpackLog
(
&
sentMsgData
,
sentMsgLog
,
sentMessageEventAbi
.
Name
,
crossDomainMessengerABI
)
if
err
!=
nil
{
return
nil
,
err
}
var
sentMsgExtensionData
bindings
.
CrossDomainMessengerSentMessageExtension1
sentMsgExtensionLog
:=
events
.
eventByLogIndex
[
ProcessedContractEventLogIndexKey
{
log
.
BlockHash
,
log
.
Index
+
3
}]
.
RLPLog
if
sentMsgExtensionLog
.
Topics
[
0
]
!=
sentMessageExtensionEventAbi
.
ID
{
return
nil
,
errors
.
New
(
"unexpected bridge event ordering"
)
}
sentMsgData
.
Raw
=
*
sentMsgLog
err
=
UnpackLog
(
&
sentMsgExtensionData
,
sentMsgExtensionLog
,
sentMessageExtensionEventAbi
.
Name
,
crossDomainMessengerABI
)
if
err
!=
nil
{
return
nil
,
err
}
msgHash
,
err
:=
CrossDomainMessageHash
(
crossDomainMessengerABI
,
&
sentMsgData
,
sentMsgExtensionData
.
Value
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -121,7 +138,7 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
switch
any
(
bridgeData
)
.
(
type
)
{
case
bindings
.
StandardBridgeETHBridgeInitiated
:
ethBridgeData
:=
any
(
bridgeData
)
.
(
bindings
.
StandardBridgeETHBridgeInitiated
)
expectedCrossDomainMessage
,
err
=
S
tandardBridgeABI
.
Pack
(
finalizeMethodName
,
ethBridgeData
.
From
,
ethBridgeData
.
To
,
ethBridgeData
.
Amount
,
ethBridgeData
.
ExtraData
)
expectedCrossDomainMessage
,
err
=
s
tandardBridgeABI
.
Pack
(
finalizeMethodName
,
ethBridgeData
.
From
,
ethBridgeData
.
To
,
ethBridgeData
.
Amount
,
ethBridgeData
.
ExtraData
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -139,7 +156,7 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
_temp
:=
any
(
bridgeData
)
.
(
bindings
.
StandardBridgeERC20BridgeInitiated
)
erc20BridgeData
=
&
_temp
erc20BridgeData
.
Raw
=
*
log
expectedCrossDomainMessage
,
err
=
S
tandardBridgeABI
.
Pack
(
finalizeMethodName
,
erc20BridgeData
.
RemoteToken
,
erc20BridgeData
.
LocalToken
,
erc20BridgeData
.
From
,
erc20BridgeData
.
To
,
erc20BridgeData
.
Amount
,
erc20BridgeData
.
ExtraData
)
expectedCrossDomainMessage
,
err
=
s
tandardBridgeABI
.
Pack
(
finalizeMethodName
,
erc20BridgeData
.
RemoteToken
,
erc20BridgeData
.
LocalToken
,
erc20BridgeData
.
From
,
erc20BridgeData
.
To
,
erc20BridgeData
.
Amount
,
erc20BridgeData
.
ExtraData
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -151,7 +168,7 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
initiatedBridgeEvents
[
i
]
=
StandardBridgeInitiatedEvent
{
StandardBridgeERC20BridgeInitiated
:
erc20BridgeData
,
CrossDomainMess
engerNonce
:
sentMsgData
.
MessageNonce
,
CrossDomainMess
ageHash
:
msgHash
,
Event
:
bridgeInitiatedEvent
,
}
}
...
...
@@ -161,27 +178,19 @@ func _standardBridgeInitiatedEvents[BridgeEvent bindings.StandardBridgeETHBridge
// parse out eth or erc20 bridge finalization events
func
_standardBridgeFinalizedEvents
[
BridgeEvent
bindings
.
StandardBridgeETHBridgeFinalized
|
bindings
.
StandardBridgeERC20BridgeFinalized
](
rawEthClient
*
ethclient
.
Client
,
events
*
ProcessedContractEvents
,
)
([]
StandardBridgeFinalizedEvent
,
error
)
{
S
tandardBridgeABI
,
err
:=
bindings
.
StandardBridgeMetaData
.
GetAbi
()
s
tandardBridgeABI
,
err
:=
bindings
.
StandardBridgeMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
l1CrossDomainMessengerABI
,
err
:=
bindings
.
L1
CrossDomainMessengerMetaData
.
GetAbi
()
crossDomainMessengerABI
,
err
:=
bindings
.
CrossDomainMessengerMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
optimismPortalAbi
,
err
:=
bindings
.
OptimismPortalMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
relayedMessageEventAbi
:=
l1CrossDomainMessengerABI
.
Events
[
"RelayedMessage"
]
relayMessageMethodAbi
:=
l1CrossDomainMessengerABI
.
Methods
[
"relayMessage"
]
finalizeWithdrawalTransactionMethodAbi
:=
optimismPortalAbi
.
Methods
[
"finalizeWithdrawalTransaction"
]
relayedMessageEventAbi
:=
crossDomainMessengerABI
.
Events
[
"RelayedMessage"
]
var
bridgeData
BridgeEvent
var
eventName
string
...
...
@@ -194,70 +203,27 @@ func _standardBridgeFinalizedEvents[BridgeEvent bindings.StandardBridgeETHBridge
panic
(
"should not be here"
)
}
processedFinalizedBridgeEvents
:=
events
.
eventsBySignature
[
S
tandardBridgeABI
.
Events
[
eventName
]
.
ID
]
processedFinalizedBridgeEvents
:=
events
.
eventsBySignature
[
s
tandardBridgeABI
.
Events
[
eventName
]
.
ID
]
finalizedBridgeEvents
:=
make
([]
StandardBridgeFinalizedEvent
,
len
(
processedFinalizedBridgeEvents
))
for
i
,
bridgeFinalizedEvent
:=
range
processedFinalizedBridgeEvents
{
log
:=
bridgeFinalizedEvent
.
RLPLog
var
bridgeData
BridgeEvent
err
:=
UnpackLog
(
&
bridgeData
,
log
,
eventName
,
S
tandardBridgeABI
)
err
:=
UnpackLog
(
&
bridgeData
,
log
,
eventName
,
s
tandardBridgeABI
)
if
err
!=
nil
{
return
nil
,
err
}
// Look for the RelayedMessage event that follows right after the BridgeFinalized Event
var
relayedMsgData
bindings
.
CrossDomainMessengerRelayedMessage
relayedMsgLog
:=
events
.
eventByLogIndex
[
ProcessedContractEventLogIndexKey
{
log
.
BlockHash
,
log
.
Index
+
1
}]
.
RLPLog
if
relayedMsgLog
.
Topics
[
0
]
!=
relayedMessageEventAbi
.
ID
{
return
nil
,
errors
.
New
(
"unexpected bridge event ordering"
)
}
// There's no way to extract the nonce on the relayed message event. we can extract the nonce by
// by unpacking the transaction input for the `relayMessage` transaction. Since bedrock has OptimismPortal
// as on L1 as an intermediary for finalization, we have to check both scenarios
tx
,
isPending
,
err
:=
rawEthClient
.
TransactionByHash
(
context
.
Background
(),
relayedMsgLog
.
TxHash
)
if
err
!=
nil
||
isPending
{
return
nil
,
errors
.
New
(
"unable to query relayMessage tx for bridge finalization event"
)
}
// If this is a finalization step with the optimism portal, the calldata for relayMessage invocation can be
// extracted from the withdrawal transaction.
// NOTE: the L2CrossDomainMessenger nonce may not match the L2ToL1MessagePasser nonce, hence the additional
// layer of decoding vs reading the nocne of the withdrawal transaction. Both nonces have a similar but
// different lifeycle that might not match (i.e L2ToL1MessagePasser can be invoced directly)
var
relayMsgCallData
[]
byte
switch
{
case
bytes
.
Equal
(
tx
.
Data
()[
:
4
],
relayMessageMethodAbi
.
ID
)
:
relayMsgCallData
=
tx
.
Data
()[
4
:
]
case
bytes
.
Equal
(
tx
.
Data
()[
:
4
],
finalizeWithdrawalTransactionMethodAbi
.
ID
)
:
data
,
err
:=
finalizeWithdrawalTransactionMethodAbi
.
Inputs
.
Unpack
(
tx
.
Data
()[
4
:
])
if
err
!=
nil
{
return
nil
,
err
}
finalizeWithdrawTransactionInput
:=
new
(
struct
{
Tx
bindings
.
TypesWithdrawalTransaction
})
err
=
finalizeWithdrawalTransactionMethodAbi
.
Inputs
.
Copy
(
finalizeWithdrawTransactionInput
,
data
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"unable extract withdrawal tx input from finalizeWithdrawalTransaction calldata: %w"
,
err
)
}
else
if
!
bytes
.
Equal
(
finalizeWithdrawTransactionInput
.
Tx
.
Data
[
:
4
],
relayMessageMethodAbi
.
ID
)
{
return
nil
,
errors
.
New
(
"finalizeWithdrawalTransaction calldata does not match relayMessage invocation"
)
}
relayMsgCallData
=
finalizeWithdrawTransactionInput
.
Tx
.
Data
[
4
:
]
default
:
return
nil
,
errors
.
New
(
"bridge finalization event does not correlate with a relayMessage tx invocation"
)
}
inputsMap
:=
make
(
map
[
string
]
interface
{})
err
=
relayMessageMethodAbi
.
Inputs
.
UnpackIntoMap
(
inputsMap
,
relayMsgCallData
)
err
=
UnpackLog
(
&
relayedMsgData
,
relayedMsgLog
,
relayedMessageEventAbi
.
Name
,
crossDomainMessengerABI
)
if
err
!=
nil
{
return
nil
,
err
}
nonce
,
ok
:=
inputsMap
[
"_nonce"
]
.
(
*
big
.
Int
)
if
!
ok
{
return
nil
,
errors
.
New
(
"unable to extract `_nonce` parameter from relayMessage calldata"
)
}
var
erc20BridgeData
*
bindings
.
StandardBridgeERC20BridgeFinalized
switch
any
(
bridgeData
)
.
(
type
)
{
...
...
@@ -279,7 +245,7 @@ func _standardBridgeFinalizedEvents[BridgeEvent bindings.StandardBridgeETHBridge
finalizedBridgeEvents
[
i
]
=
StandardBridgeFinalizedEvent
{
StandardBridgeERC20BridgeFinalized
:
erc20BridgeData
,
CrossDomainMess
engerNonce
:
nonce
,
CrossDomainMess
ageHash
:
relayedMsgData
.
MsgHash
,
Event
:
bridgeFinalizedEvent
,
}
}
...
...
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