Commit e85caec3 authored by Hamdi Allam's avatar Hamdi Allam

bridge events

parent 256ab17b
This diff is collapsed.
package processor
import (
"bytes"
"context"
"errors"
"math/big"
"reflect"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/google/uuid"
"github.com/ethereum/go-ethereum"
......@@ -125,7 +128,10 @@ func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2
}
numLogs := len(logs)
logsByIndex := make(map[uint]*types.Log, numLogs)
l2ContractEvents := make([]*database.L2ContractEvent, numLogs)
l2ContractEventLogs := make(map[uuid.UUID]*types.Log)
for i, log := range logs {
header, ok := l2HeaderMap[log.BlockHash]
if !ok {
......@@ -133,16 +139,11 @@ func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2
return errors.New("parsed log with a block hash not in this batch")
}
l2ContractEvents[i] = &database.L2ContractEvent{
ContractEvent: database.ContractEvent{
GUID: uuid.New(),
BlockHash: log.BlockHash,
TransactionHash: log.TxHash,
EventSignature: log.Topics[0],
LogIndex: uint64(log.Index),
Timestamp: header.Time,
},
}
logsByIndex[log.Index] = &logs[i]
contractEvent := &database.L2ContractEvent{ContractEvent: database.ContractEventFromLog(&log, header.Time)}
l2ContractEvents[i] = contractEvent
l2ContractEventLogs[contractEvent.GUID] = &logs[i]
}
/** Update Database **/
......@@ -159,9 +160,125 @@ func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2
if err != nil {
return err
}
// forward along contract events to the bridge processor
err = l2BridgeProcessContractEvents(processLog, db, ethClient, l2ContractEvents, l2ContractEventLogs, logsByIndex)
if err != nil {
return err
}
}
// a-ok!
return nil
}
}
func l2BridgeProcessContractEvents(
processLog log.Logger,
db *database.DB,
ethClient node.EthClient,
events []*database.L2ContractEvent,
eventLogs map[uuid.UUID]*types.Log,
logsByIndex map[uint]*types.Log,
) error {
rawEthClient := ethclient.NewClient(ethClient.RawRpcClient())
l2StandardBridgeABI, err := bindings.L2StandardBridgeMetaData.GetAbi()
if err != nil {
return err
}
l2CrossDomainMessengerABI, err := bindings.L2CrossDomainMessengerMetaData.GetAbi()
if err != nil {
return err
}
type BridgeData struct {
From common.Address
To common.Address
Amount *big.Int
ExtraData []byte
}
numFinalizedDeposits := 0
ethBridgeFinalizedEventSig := l2StandardBridgeABI.Events["ETHBridgeFinalized"].ID
relayedMessageEventSig := l2CrossDomainMessengerABI.Events["RelayedMessage"].ID
relayMessageMethod := l2CrossDomainMessengerABI.Methods["relayMessage"]
for _, contractEvent := range events {
eventSig := contractEvent.EventSignature
log := eventLogs[contractEvent.GUID]
if eventSig == ethBridgeFinalizedEventSig {
// (1) Ensure the RelayedMessage follows the log right after the bridge event
relayedMsgLog := logsByIndex[log.Index+1]
if relayedMsgLog.Topics[0] != relayedMessageEventSig {
processLog.Crit("expected CrossDomainMessenger#RelayedMessage following StandardBridge#EthBridgeFinalized event", "event_sig", relayedMsgLog.Topics[0], "relayed_message_sig", relayedMessageEventSig)
return errors.New("unexpected bridge event ordering")
}
// unfortunately there's no way to extract the nonce on the relayed message event. we can
// extract the nonce by unpacking the transaction input for the `relayMessage` transaction
tx, isPending, err := rawEthClient.TransactionByHash(context.Background(), relayedMsgLog.TxHash)
if err != nil || isPending {
processLog.Crit("CrossDomainMessager#relayeMessage transaction query err or found pending", err, "err", "isPending", isPending)
return errors.New("unable to query relayMessage tx")
}
txData := tx.Data()
fnSelector := txData[:4]
if !bytes.Equal(fnSelector, relayMessageMethod.ID) {
processLog.Crit("expected relayMessage function selector")
return errors.New("RelayMessage log does not match relayMessage transaction")
}
fnData := txData[4:]
inputsMap := make(map[string]interface{})
err = relayMessageMethod.Inputs.UnpackIntoMap(inputsMap, fnData)
if err != nil {
processLog.Crit("unable to unpack CrossDomainMessenger#relayMessage function data", "err", err)
return err
}
nonce, ok := inputsMap["_nonce"].(*big.Int)
if !ok {
processLog.Crit("unable to extract _nonce from CrossDomainMessenger#relayMessage function call")
return errors.New("unable to extract relayMessage nonce")
}
// (2) Mark initiated L1 deposit as finalized
deposit, err := db.Bridge.DepositByMessageNonce(nonce)
if err != nil {
processLog.Error("error querying initiated deposit messsage using nonce", "nonce", nonce)
return err
} else if deposit == nil {
latestNonce, err := db.Bridge.LatestDepositMessageNonce()
if err != nil {
return err
}
// check if the the L1Processor is behind or really has missed an event
if latestNonce == nil || nonce.Cmp(latestNonce) > 0 {
processLog.Warn("behind on indexed L1 deposits", "deposit_message_nonce", nonce, "latest_deposit_message_nonce", latestNonce)
return errors.New("waiting for L1Processor to catch up")
} else {
processLog.Crit("missing indexed deposit for this finalization event", "deposit_message_nonce", nonce, "tx_hash", log.TxHash, "log_index", log.Index)
return errors.New("missing deposit message")
}
}
err = db.Bridge.MarkFinalizedDepositEvent(deposit.GUID, contractEvent.GUID)
if err != nil {
processLog.Error("error finalizing deposit", "err", err)
return err
}
numFinalizedDeposits++
}
}
// a-ok!
if numFinalizedDeposits > 0 {
processLog.Info("finalized deposits", "num", numFinalizedDeposits)
}
return nil
}
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