Commit e3d1af10 authored by Hamdi Allam's avatar Hamdi Allam

decouple finalization events from needing an rpc

parent a0acfebf
......@@ -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"`
......
......@@ -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.L1BridgeMessageByHash(*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.CrossDomainMessengerNonce)
require.Nil(t, deposit.CrossDomainMessageHash)
// (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.CrossDomainMessengerNonce)
require.Nil(t, withdrawal.CrossDomainMessageHash)
// (2) Test Withdrawal Proven/Finalized. Test the sql join queries to populate the right transaction
require.Empty(t, aliceWithdrawals[0].ProvenL1TransactionHash)
......
......@@ -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,
......
......@@ -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,
BridgeTransfer: database.BridgeTransfer{
Tx: transactionDeposits[i].Tx,
TokenPair: database.TokenPair{
// 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 {
......@@ -466,7 +462,8 @@ func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
deposits[i] = &database.L1BridgeDeposit{
TransactionSourceHash: depositTx.SourceHash,
CrossDomainMessengerNonce: &database.U256{Int: initiatedBridgeEvent.CrossDomainMessengerNonce},
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{
......@@ -476,6 +473,7 @@ func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
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.L2BridgeWithdrawalByCrossDomainMessengerNonce(finalizedWithdrawalEvent.CrossDomainMessengerNonce)
withdrawal, err := db.BridgeTransfers.L2BridgeWithdrawalWithFilter(database.BridgeTransfer{CrossDomainMessageHash: &finalizedWithdrawalEvent.CrossDomainMessageHash})
if err != nil {
return err
} else if withdrawal == nil {
processLog.Error("missing indexed L2StandardBridge withdrawal for finalization", "cross_domain_messenger_nonce", finalizedWithdrawalEvent.CrossDomainMessengerNonce)
processLog.Error("missing indexed L2StandardBridge withdrawal for finalization", "cross_domain_message_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)
}
}
......
......@@ -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,
BridgeTransfer: database.BridgeTransfer{
Tx: transactionWithdrawals[i].Tx,
TokenPair: database.TokenPair{
L1TokenAddress: predeploys.LegacyERC20ETHAddr,
L2TokenAddress: predeploys.LegacyERC20ETHAddr,
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,7 +353,8 @@ func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
withdrawals[i] = &database.L2BridgeWithdrawal{
TransactionWithdrawalHash: msgPassedEvent.WithdrawalHash,
CrossDomainMessengerNonce: &database.U256{Int: initiatedBridgeEvent.CrossDomainMessengerNonce},
BridgeTransfer: database.BridgeTransfer{
CrossDomainMessageHash: &initiatedBridgeEvent.CrossDomainMessageHash,
TokenPair: database.TokenPair{L1TokenAddress: initiatedBridgeEvent.LocalToken, L2TokenAddress: initiatedBridgeEvent.RemoteToken},
Tx: database.Transaction{
FromAddress: initiatedBridgeEvent.From,
......@@ -366,6 +363,7 @@ func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
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.L1BridgeDepositByCrossDomainMessengerNonce(finalizedDepositEvent.CrossDomainMessengerNonce)
deposit, err := db.BridgeTransfers.L1BridgeDepositWithFilter(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_messenger_nonce", finalizedDepositEvent.CrossDomainMessengerNonce)
processLog.Error("missing indexed L1StandardBridge deposit on finalization", "cross_domain_massage_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_messenger_nonce", deposit.CrossDomainMessengerNonce.Int)
processLog.Error("bridge finalization fields mismatch with initiated fields!", "tx_source_hash", deposit.TransactionSourceHash, "cross_domain_message_hash", deposit.CrossDomainMessageHash)
return errors.New("bridge tx mismatch")
}
}
......
......@@ -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,7 +16,7 @@ type StandardBridgeInitiatedEvent struct {
// the hardcoded ETH address
*bindings.StandardBridgeERC20BridgeInitiated
CrossDomainMessengerNonce *big.Int
CrossDomainMessageHash common.Hash
Event *database.ContractEvent
}
......@@ -28,7 +25,7 @@ type StandardBridgeFinalizedEvent struct {
// the hardcoded ETH address
*bindings.StandardBridgeERC20BridgeFinalized
CrossDomainMessengerNonce *big.Int
CrossDomainMessageHash common.Hash
Event *database.ContractEvent
}
......@@ -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) {
StandardBridgeABI, err := bindings.StandardBridgeMetaData.GetAbi()
standardBridgeABI, err := bindings.StandardBridgeMetaData.GetAbi()
if err != nil {
return nil, err
}
l1CrossDomainMessengerABI, err := bindings.L1CrossDomainMessengerMetaData.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[StandardBridgeABI.Events[eventName].ID]
processedInitiatedBridgeEvents := events.eventsBySignature[standardBridgeABI.Events[eventName].ID]
initiatedBridgeEvents := make([]StandardBridgeInitiatedEvent, len(processedInitiatedBridgeEvents))
for i, bridgeInitiatedEvent := range processedInitiatedBridgeEvents {
log := bridgeInitiatedEvent.RLPLog
var bridgeData BridgeEvent
err := UnpackLog(&bridgeData, log, eventName, StandardBridgeABI)
err := UnpackLog(&bridgeData, log, eventName, standardBridgeABI)
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.L1CrossDomainMessengerSentMessage
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 = StandardBridgeABI.Pack(finalizeMethodName, ethBridgeData.From, ethBridgeData.To, ethBridgeData.Amount, ethBridgeData.ExtraData)
expectedCrossDomainMessage, err = standardBridgeABI.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 = StandardBridgeABI.Pack(finalizeMethodName, erc20BridgeData.RemoteToken, erc20BridgeData.LocalToken, erc20BridgeData.From, erc20BridgeData.To, erc20BridgeData.Amount, erc20BridgeData.ExtraData)
expectedCrossDomainMessage, err = standardBridgeABI.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,
CrossDomainMessengerNonce: sentMsgData.MessageNonce,
CrossDomainMessageHash: 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) {
StandardBridgeABI, err := bindings.StandardBridgeMetaData.GetAbi()
if err != nil {
return nil, err
}
l1CrossDomainMessengerABI, err := bindings.L1CrossDomainMessengerMetaData.GetAbi()
standardBridgeABI, err := bindings.StandardBridgeMetaData.GetAbi()
if err != nil {
return nil, err
}
optimismPortalAbi, err := bindings.OptimismPortalMetaData.GetAbi()
crossDomainMessengerABI, err := bindings.CrossDomainMessengerMetaData.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,71 +203,28 @@ func _standardBridgeFinalizedEvents[BridgeEvent bindings.StandardBridgeETHBridge
panic("should not be here")
}
processedFinalizedBridgeEvents := events.eventsBySignature[StandardBridgeABI.Events[eventName].ID]
processedFinalizedBridgeEvents := events.eventsBySignature[standardBridgeABI.Events[eventName].ID]
finalizedBridgeEvents := make([]StandardBridgeFinalizedEvent, len(processedFinalizedBridgeEvents))
for i, bridgeFinalizedEvent := range processedFinalizedBridgeEvents {
log := bridgeFinalizedEvent.RLPLog
var bridgeData BridgeEvent
err := UnpackLog(&bridgeData, log, eventName, StandardBridgeABI)
err := UnpackLog(&bridgeData, log, eventName, standardBridgeABI)
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:])
err = UnpackLog(&relayedMsgData, relayedMsgLog, relayedMessageEventAbi.Name, crossDomainMessengerABI)
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)
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) {
case bindings.StandardBridgeETHBridgeFinalized:
......@@ -279,7 +245,7 @@ func _standardBridgeFinalizedEvents[BridgeEvent bindings.StandardBridgeETHBridge
finalizedBridgeEvents[i] = StandardBridgeFinalizedEvent{
StandardBridgeERC20BridgeFinalized: erc20BridgeData,
CrossDomainMessengerNonce: nonce,
CrossDomainMessageHash: relayedMsgData.MsgHash,
Event: bridgeFinalizedEvent,
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment