Commit 75cc25c4 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into dependabot/npm_and_yarn/chai-4.3.10

parents 28dd32be d8f1739d
...@@ -71,11 +71,11 @@ func (etl *ETL) Start(ctx context.Context) error { ...@@ -71,11 +71,11 @@ func (etl *ETL) Start(ctx context.Context) error {
etl.log.Error("error querying for headers", "err", err) etl.log.Error("error querying for headers", "err", err)
} else if len(newHeaders) == 0 { } else if len(newHeaders) == 0 {
etl.log.Warn("no new headers. processor unexpectedly at head...") etl.log.Warn("no new headers. processor unexpectedly at head...")
} } else {
headers = newHeaders headers = newHeaders
etl.metrics.RecordBatchHeaders(len(newHeaders)) etl.metrics.RecordBatchHeaders(len(newHeaders))
} }
}
// only clear the reference if we were able to process this batch // only clear the reference if we were able to process this batch
err := etl.processBatch(headers) err := etl.processBatch(headers)
...@@ -107,7 +107,7 @@ func (etl *ETL) processBatch(headers []types.Header) error { ...@@ -107,7 +107,7 @@ func (etl *ETL) processBatch(headers []types.Header) error {
headersWithLog := make(map[common.Hash]bool, len(headers)) headersWithLog := make(map[common.Hash]bool, len(headers))
logs, err := etl.EthClient.FilterLogs(ethereum.FilterQuery{FromBlock: firstHeader.Number, ToBlock: lastHeader.Number, Addresses: etl.contracts}) logs, err := etl.EthClient.FilterLogs(ethereum.FilterQuery{FromBlock: firstHeader.Number, ToBlock: lastHeader.Number, Addresses: etl.contracts})
if err != nil { if err != nil {
batchLog.Info("unable to extract logs", "err", err) batchLog.Info("failed to extract logs", "err", err)
return err return err
} }
if len(logs) > 0 { if len(logs) > 0 {
...@@ -118,7 +118,8 @@ func (etl *ETL) processBatch(headers []types.Header) error { ...@@ -118,7 +118,8 @@ func (etl *ETL) processBatch(headers []types.Header) error {
log := logs[i] log := logs[i]
if _, ok := headerMap[log.BlockHash]; !ok { if _, ok := headerMap[log.BlockHash]; !ok {
// NOTE. Definitely an error state if the none of the headers were re-orged out in between // NOTE. Definitely an error state if the none of the headers were re-orged out in between
// the blocks and logs retrieval operations. However, we need to gracefully handle reorgs // the blocks and logs retrieval operations. Unlikely as long as the confirmation depth has
// been appropriately set or when we get to natively handling reorgs.
batchLog.Error("log found with block hash not in the batch", "block_hash", logs[i].BlockHash, "log_index", logs[i].Index) batchLog.Error("log found with block hash not in the batch", "block_hash", logs[i].BlockHash, "log_index", logs[i].Index)
return errors.New("parsed log with a block hash not in the batch") return errors.New("parsed log with a block hash not in the batch")
} }
......
...@@ -16,7 +16,6 @@ type Metricer interface { ...@@ -16,7 +16,6 @@ type Metricer interface {
RecordInterval() (done func(err error)) RecordInterval() (done func(err error))
// Batch Extraction // Batch Extraction
RecordBatchFailure()
RecordBatchLatestHeight(height *big.Int) RecordBatchLatestHeight(height *big.Int)
RecordBatchHeaders(size int) RecordBatchHeaders(size int)
RecordBatchLog(contractAddress common.Address) RecordBatchLog(contractAddress common.Address)
...@@ -108,17 +107,13 @@ func (m *etlMetrics) RecordInterval() func(error) { ...@@ -108,17 +107,13 @@ func (m *etlMetrics) RecordInterval() func(error) {
timer := prometheus.NewTimer(m.intervalDuration) timer := prometheus.NewTimer(m.intervalDuration)
return func(err error) { return func(err error) {
if err != nil { if err != nil {
m.RecordBatchFailure() m.batchFailures.Inc()
} }
timer.ObserveDuration() timer.ObserveDuration()
} }
} }
func (m *etlMetrics) RecordBatchFailure() {
m.batchFailures.Inc()
}
func (m *etlMetrics) RecordBatchLatestHeight(height *big.Int) { func (m *etlMetrics) RecordBatchLatestHeight(height *big.Int) {
m.batchLatestHeight.Set(float64(height.Uint64())) m.batchLatestHeight.Set(float64(height.Uint64()))
} }
......
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
"github.com/ethereum-optimism/optimism/indexer/etl" "github.com/ethereum-optimism/optimism/indexer/etl"
"github.com/ethereum-optimism/optimism/indexer/node" "github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/indexer/processors" "github.com/ethereum-optimism/optimism/indexer/processors"
"github.com/ethereum-optimism/optimism/indexer/processors/bridge"
"github.com/ethereum-optimism/optimism/op-service/httputil" "github.com/ethereum-optimism/optimism/op-service/httputil"
"github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum-optimism/optimism/op-service/metrics"
) )
...@@ -82,7 +83,7 @@ func NewIndexer( ...@@ -82,7 +83,7 @@ func NewIndexer(
} }
// Bridge // Bridge
bridgeProcessor, err := processors.NewBridgeProcessor(log, db, l1Etl, chainConfig) bridgeProcessor, err := processors.NewBridgeProcessor(log, db, bridge.NewMetrics(metricsRegistry), l1Etl, chainConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum-optimism/optimism/op-service/metrics"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
......
...@@ -18,6 +18,8 @@ import ( ...@@ -18,6 +18,8 @@ import (
type BridgeProcessor struct { type BridgeProcessor struct {
log log.Logger log log.Logger
db *database.DB db *database.DB
metrics bridge.Metricer
l1Etl *etl.L1ETL l1Etl *etl.L1ETL
chainConfig config.ChainConfig chainConfig config.ChainConfig
...@@ -25,7 +27,7 @@ type BridgeProcessor struct { ...@@ -25,7 +27,7 @@ type BridgeProcessor struct {
LatestL2Header *types.Header LatestL2Header *types.Header
} }
func NewBridgeProcessor(log log.Logger, db *database.DB, l1Etl *etl.L1ETL, chainConfig config.ChainConfig) (*BridgeProcessor, error) { func NewBridgeProcessor(log log.Logger, db *database.DB, metrics bridge.Metricer, l1Etl *etl.L1ETL, chainConfig config.ChainConfig) (*BridgeProcessor, error) {
log = log.New("processor", "bridge") log = log.New("processor", "bridge")
latestL1Header, err := db.BridgeTransactions.L1LatestBlockHeader() latestL1Header, err := db.BridgeTransactions.L1LatestBlockHeader()
...@@ -45,28 +47,22 @@ func NewBridgeProcessor(log log.Logger, db *database.DB, l1Etl *etl.L1ETL, chain ...@@ -45,28 +47,22 @@ func NewBridgeProcessor(log log.Logger, db *database.DB, l1Etl *etl.L1ETL, chain
if latestL1Header != nil { if latestL1Header != nil {
l1Height = latestL1Header.Number l1Height = latestL1Header.Number
l1Header = latestL1Header.RLPHeader.Header() l1Header = latestL1Header.RLPHeader.Header()
metrics.RecordLatestIndexedL1Height(l1Height)
} }
if latestL2Header != nil { if latestL2Header != nil {
l2Height = latestL2Header.Number l2Height = latestL2Header.Number
l2Header = latestL2Header.RLPHeader.Header() l2Header = latestL2Header.RLPHeader.Header()
metrics.RecordLatestIndexedL2Height(l2Height)
} }
log.Info("detected latest indexed bridge state", "l1_block_number", l1Height, "l2_block_number", l2Height) log.Info("detected latest indexed bridge state", "l1_block_number", l1Height, "l2_block_number", l2Height)
} }
return &BridgeProcessor{log, db, l1Etl, chainConfig, l1Header, l2Header}, nil return &BridgeProcessor{log, db, metrics, l1Etl, chainConfig, l1Header, l2Header}, nil
} }
func (b *BridgeProcessor) Start(ctx context.Context) error { func (b *BridgeProcessor) Start(ctx context.Context) error {
done := ctx.Done() done := ctx.Done()
// In order to ensure all seen bridge finalization events correspond with seen
// bridge initiated events, we establish a shared marker between L1 and L2 when
// processing events.
//
// As L1 and L2 blocks are indexed, the highest indexed L2 block starting a new
// sequencing epoch and corresponding L1 origin that has also been indexed
// serves as this shared marker.
// Fire off independently on startup to check for // Fire off independently on startup to check for
// new data or if we've indexed new L1 data. // new data or if we've indexed new L1 data.
l1EtlUpdates := b.l1Etl.Notify() l1EtlUpdates := b.l1Etl.Notify()
...@@ -85,6 +81,16 @@ func (b *BridgeProcessor) Start(ctx context.Context) error { ...@@ -85,6 +81,16 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
case <-l1EtlUpdates: case <-l1EtlUpdates:
} }
done := b.metrics.RecordInterval()
done(b.run())
}
}
// Runs the processing loop. In order to ensure all seen bridge finalization events
// can be correlated with bridge initiated events, we establish a shared marker between
// L1 and L2 when processing events. The lastest shared indexed time (epochs) between
// L1 and L2 serves as this shared marker.
func (b *BridgeProcessor) run() error {
// In the event where we have a large number of un-observed epochs, we cap the search // In the event where we have a large number of un-observed epochs, we cap the search
// of epochs by 10k. If this turns out to be a bottleneck, we can parallelize the processing // of epochs by 10k. If this turns out to be a bottleneck, we can parallelize the processing
// of epochs to significantly speed up sync times. // of epochs to significantly speed up sync times.
...@@ -104,12 +110,12 @@ func (b *BridgeProcessor) Start(ctx context.Context) error { ...@@ -104,12 +110,12 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
return errors.New("bridge events indexed, but no observed epoch returned") return errors.New("bridge events indexed, but no observed epoch returned")
} }
b.log.Warn("no observed epochs available. waiting...") b.log.Warn("no observed epochs available. waiting...")
continue return nil
} }
if b.LatestL1Header != nil && latestEpoch.L1BlockHeader.Hash == b.LatestL1Header.Hash() { if b.LatestL1Header != nil && latestEpoch.L1BlockHeader.Hash == b.LatestL1Header.Hash() {
b.log.Warn("all available epochs indexed", "latest_bridge_l1_block_number", b.LatestL1Header.Number) b.log.Warn("all available epochs indexed", "latest_bridge_l1_block_number", b.LatestL1Header.Number)
continue return nil
} }
// Integrity Checks // Integrity Checks
...@@ -120,16 +126,14 @@ func (b *BridgeProcessor) Start(ctx context.Context) error { ...@@ -120,16 +126,14 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
return errors.New("L1 epoch less than starting L1 height observed") return errors.New("L1 epoch less than starting L1 height observed")
} }
if b.LatestL1Header != nil && latestEpoch.L1BlockHeader.Number.Cmp(b.LatestL1Header.Number) <= 0 { if b.LatestL1Header != nil && latestEpoch.L1BlockHeader.Number.Cmp(b.LatestL1Header.Number) <= 0 {
b.log.Error("decreasing l1 block height observed", "latest_bridge_l1_block_number", b.LatestL1Header.Number, "latest_epoch_number", latestEpoch.L1BlockHeader.Number) b.log.Error("non-increasing l1 block height observed", "latest_bridge_l1_block_number", b.LatestL1Header.Number, "latest_epoch_l1_block_number", latestEpoch.L1BlockHeader.Number)
return errors.New("decreasing l1 block heght observed") return errors.New("non-increasing l1 block heght observed")
} }
if b.LatestL2Header != nil && latestEpoch.L2BlockHeader.Number.Cmp(b.LatestL2Header.Number) <= 0 { if b.LatestL2Header != nil && latestEpoch.L2BlockHeader.Number.Cmp(b.LatestL2Header.Number) <= 0 {
b.log.Error("decreasing l2 block height observed", "latest_bridge_l2_block_number", b.LatestL2Header.Number, "latest_epoch_number", latestEpoch.L2BlockHeader.Number) b.log.Error("non-increasing l2 block height observed", "latest_bridge_l2_block_number", b.LatestL2Header.Number, "latest_epoch_l2_block_number", latestEpoch.L2BlockHeader.Number)
return errors.New("decreasing l2 block heght observed") return errors.New("non-increasing l2 block heght observed")
} }
// Process Bridge Events
toL1Height, toL2Height := latestEpoch.L1BlockHeader.Number, latestEpoch.L2BlockHeader.Number toL1Height, toL2Height := latestEpoch.L1BlockHeader.Number, latestEpoch.L2BlockHeader.Number
fromL1Height, fromL2Height := genesisL1Height, bigint.Zero fromL1Height, fromL2Height := genesisL1Height, bigint.Zero
if b.LatestL1Header != nil { if b.LatestL1Header != nil {
...@@ -164,18 +168,18 @@ func (b *BridgeProcessor) Start(ctx context.Context) error { ...@@ -164,18 +168,18 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
l2BridgeLog.Info("scanning for bridge events") l2BridgeLog.Info("scanning for bridge events")
// First, find all possible initiated bridge events // First, find all possible initiated bridge events
if err := bridge.LegacyL1ProcessInitiatedBridgeEvents(l1BridgeLog, tx, b.chainConfig.L1Contracts, legacyFromL1Height, legacyToL1Height); err != nil { if err := bridge.LegacyL1ProcessInitiatedBridgeEvents(l1BridgeLog, tx, b.metrics, b.chainConfig.L1Contracts, legacyFromL1Height, legacyToL1Height); err != nil {
return err return err
} }
if err := bridge.LegacyL2ProcessInitiatedBridgeEvents(l2BridgeLog, tx, b.chainConfig.L2Contracts, legacyFromL2Height, legacyToL2Height); err != nil { if err := bridge.LegacyL2ProcessInitiatedBridgeEvents(l2BridgeLog, tx, b.metrics, b.chainConfig.L2Contracts, legacyFromL2Height, legacyToL2Height); err != nil {
return err return err
} }
// Now that all initiated events have been indexed, it is ensured that all finalization can find their counterpart. // Now that all initiated events have been indexed, it is ensured that all finalization can find their counterpart.
if err := bridge.LegacyL1ProcessFinalizedBridgeEvents(l1BridgeLog, tx, b.l1Etl.EthClient, b.chainConfig.L1Contracts, legacyFromL1Height, legacyToL1Height); err != nil { if err := bridge.LegacyL1ProcessFinalizedBridgeEvents(l1BridgeLog, tx, b.metrics, b.l1Etl.EthClient, b.chainConfig.L1Contracts, legacyFromL1Height, legacyToL1Height); err != nil {
return err return err
} }
if err := bridge.LegacyL2ProcessFinalizedBridgeEvents(l2BridgeLog, tx, b.chainConfig.L2Contracts, legacyFromL2Height, legacyToL2Height); err != nil { if err := bridge.LegacyL2ProcessFinalizedBridgeEvents(l2BridgeLog, tx, b.metrics, b.chainConfig.L2Contracts, legacyFromL2Height, legacyToL2Height); err != nil {
return err return err
} }
...@@ -196,25 +200,24 @@ func (b *BridgeProcessor) Start(ctx context.Context) error { ...@@ -196,25 +200,24 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
l2BridgeLog.Info("scanning for bridge events") l2BridgeLog.Info("scanning for bridge events")
// First, find all possible initiated bridge events // First, find all possible initiated bridge events
if err := bridge.L1ProcessInitiatedBridgeEvents(l1BridgeLog, tx, b.chainConfig.L1Contracts, fromL1Height, toL1Height); err != nil { if err := bridge.L1ProcessInitiatedBridgeEvents(l1BridgeLog, tx, b.metrics, b.chainConfig.L1Contracts, fromL1Height, toL1Height); err != nil {
return err return err
} }
if err := bridge.L2ProcessInitiatedBridgeEvents(l2BridgeLog, tx, b.chainConfig.L2Contracts, fromL2Height, toL2Height); err != nil { if err := bridge.L2ProcessInitiatedBridgeEvents(l2BridgeLog, tx, b.metrics, b.chainConfig.L2Contracts, fromL2Height, toL2Height); err != nil {
return err return err
} }
// Now all finalization events can find their counterpart. // Now all finalization events can find their counterpart.
if err := bridge.L1ProcessFinalizedBridgeEvents(l1BridgeLog, tx, b.chainConfig.L1Contracts, fromL1Height, toL1Height); err != nil { if err := bridge.L1ProcessFinalizedBridgeEvents(l1BridgeLog, tx, b.metrics, b.chainConfig.L1Contracts, fromL1Height, toL1Height); err != nil {
return err return err
} }
if err := bridge.L2ProcessFinalizedBridgeEvents(l2BridgeLog, tx, b.chainConfig.L2Contracts, fromL2Height, toL2Height); err != nil { if err := bridge.L2ProcessFinalizedBridgeEvents(l2BridgeLog, tx, b.metrics, b.chainConfig.L2Contracts, fromL2Height, toL2Height); err != nil {
return err return err
} }
// a-ok // a-ok
return nil return nil
}); err != nil { }); err != nil {
// Try again on a subsequent interval
batchLog.Error("failed to index bridge events", "err", err) batchLog.Error("failed to index bridge events", "err", err)
return err return err
} }
...@@ -222,6 +225,5 @@ func (b *BridgeProcessor) Start(ctx context.Context) error { ...@@ -222,6 +225,5 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
batchLog.Info("indexed bridge events", "latest_l1_block_number", toL1Height, "latest_l2_block_number", toL2Height) batchLog.Info("indexed bridge events", "latest_l1_block_number", toL1Height, "latest_l2_block_number", toL2Height)
b.LatestL1Header = latestEpoch.L1BlockHeader.RLPHeader.Header() b.LatestL1Header = latestEpoch.L1BlockHeader.RLPHeader.Header()
b.LatestL2Header = latestEpoch.L2BlockHeader.RLPHeader.Header() b.LatestL2Header = latestEpoch.L2BlockHeader.RLPHeader.Header()
} return nil
} }
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum-optimism/optimism/indexer/database" "github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/processors/contracts" "github.com/ethereum-optimism/optimism/indexer/processors/contracts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -17,7 +18,7 @@ import ( ...@@ -17,7 +18,7 @@ import (
// 1. OptimismPortal // 1. OptimismPortal
// 2. L1CrossDomainMessenger // 2. L1CrossDomainMessenger
// 3. L1StandardBridge // 3. L1StandardBridge
func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts config.L1Contracts, fromHeight, toHeight *big.Int) error { func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metrics L1Metricer, l1Contracts config.L1Contracts, fromHeight, toHeight *big.Int) error {
// (1) OptimismPortal // (1) OptimismPortal
optimismPortalTxDeposits, err := contracts.OptimismPortalTransactionDepositEvents(l1Contracts.OptimismPortalProxy, db, fromHeight, toHeight) optimismPortalTxDeposits, err := contracts.OptimismPortalTransactionDepositEvents(l1Contracts.OptimismPortalProxy, db, fromHeight, toHeight)
if err != nil { if err != nil {
...@@ -44,6 +45,7 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -44,6 +45,7 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
if err := db.BridgeTransactions.StoreL1TransactionDeposits(transactionDeposits); err != nil { if err := db.BridgeTransactions.StoreL1TransactionDeposits(transactionDeposits); err != nil {
return err return err
} }
metrics.RecordL1TransactionDeposits(len(transactionDeposits))
} }
// (2) L1CrossDomainMessenger // (2) L1CrossDomainMessenger
...@@ -56,7 +58,7 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -56,7 +58,7 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
} }
sentMessages := make(map[logKey]*contracts.CrossDomainMessengerSentMessageEvent, len(crossDomainSentMessages)) sentMessages := make(map[logKey]*contracts.CrossDomainMessengerSentMessageEvent, len(crossDomainSentMessages))
l1BridgeMessages := make([]database.L1BridgeMessage, len(crossDomainSentMessages)) bridgeMessages := make([]database.L1BridgeMessage, len(crossDomainSentMessages))
for i := range crossDomainSentMessages { for i := range crossDomainSentMessages {
sentMessage := crossDomainSentMessages[i] sentMessage := crossDomainSentMessages[i]
sentMessages[logKey{sentMessage.Event.BlockHash, sentMessage.Event.LogIndex}] = &sentMessage sentMessages[logKey{sentMessage.Event.BlockHash, sentMessage.Event.LogIndex}] = &sentMessage
...@@ -68,12 +70,13 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -68,12 +70,13 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
return fmt.Errorf("expected TransactionDeposit preceding SentMessage event. tx_hash = %s", sentMessage.Event.TransactionHash.String()) return fmt.Errorf("expected TransactionDeposit preceding SentMessage event. tx_hash = %s", sentMessage.Event.TransactionHash.String())
} }
l1BridgeMessages[i] = database.L1BridgeMessage{TransactionSourceHash: portalDeposit.DepositTx.SourceHash, BridgeMessage: sentMessage.BridgeMessage} bridgeMessages[i] = database.L1BridgeMessage{TransactionSourceHash: portalDeposit.DepositTx.SourceHash, BridgeMessage: sentMessage.BridgeMessage}
} }
if len(l1BridgeMessages) > 0 { if len(bridgeMessages) > 0 {
if err := db.BridgeMessages.StoreL1BridgeMessages(l1BridgeMessages); err != nil { if err := db.BridgeMessages.StoreL1BridgeMessages(bridgeMessages); err != nil {
return err return err
} }
metrics.RecordL1CrossDomainSentMessages(len(bridgeMessages))
} }
// (3) L1StandardBridge // (3) L1StandardBridge
...@@ -85,7 +88,8 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -85,7 +88,8 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
log.Info("detected bridge deposits", "size", len(initiatedBridges)) log.Info("detected bridge deposits", "size", len(initiatedBridges))
} }
l1BridgeDeposits := make([]database.L1BridgeDeposit, len(initiatedBridges)) bridgedTokens := make(map[common.Address]int)
bridgeDeposits := make([]database.L1BridgeDeposit, len(initiatedBridges))
for i := range initiatedBridges { for i := range initiatedBridges {
initiatedBridge := initiatedBridges[i] initiatedBridge := initiatedBridges[i]
...@@ -102,15 +106,19 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -102,15 +106,19 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
} }
initiatedBridge.BridgeTransfer.CrossDomainMessageHash = &sentMessage.BridgeMessage.MessageHash initiatedBridge.BridgeTransfer.CrossDomainMessageHash = &sentMessage.BridgeMessage.MessageHash
l1BridgeDeposits[i] = database.L1BridgeDeposit{ bridgedTokens[initiatedBridge.BridgeTransfer.TokenPair.LocalTokenAddress]++
bridgeDeposits[i] = database.L1BridgeDeposit{
TransactionSourceHash: portalDeposit.DepositTx.SourceHash, TransactionSourceHash: portalDeposit.DepositTx.SourceHash,
BridgeTransfer: initiatedBridge.BridgeTransfer, BridgeTransfer: initiatedBridge.BridgeTransfer,
} }
} }
if len(l1BridgeDeposits) > 0 { if len(bridgeDeposits) > 0 {
if err := db.BridgeTransfers.StoreL1BridgeDeposits(l1BridgeDeposits); err != nil { if err := db.BridgeTransfers.StoreL1BridgeDeposits(bridgeDeposits); err != nil {
return err return err
} }
for tokenAddr, size := range bridgedTokens {
metrics.RecordL1InitiatedBridgeTransfers(tokenAddr, size)
}
} }
return nil return nil
...@@ -121,7 +129,7 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -121,7 +129,7 @@ func L1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
// 1. OptimismPortal (Bedrock prove & finalize steps) // 1. OptimismPortal (Bedrock prove & finalize steps)
// 2. L1CrossDomainMessenger (relayMessage marker) // 2. L1CrossDomainMessenger (relayMessage marker)
// 3. L1StandardBridge (no-op, since this is simply a wrapper over the L1CrossDomainMessenger) // 3. L1StandardBridge (no-op, since this is simply a wrapper over the L1CrossDomainMessenger)
func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts config.L1Contracts, fromHeight, toHeight *big.Int) error { func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metrics L1Metricer, l1Contracts config.L1Contracts, fromHeight, toHeight *big.Int) error {
// (1) OptimismPortal (proven withdrawals) // (1) OptimismPortal (proven withdrawals)
provenWithdrawals, err := contracts.OptimismPortalWithdrawalProvenEvents(l1Contracts.OptimismPortalProxy, db, fromHeight, toHeight) provenWithdrawals, err := contracts.OptimismPortalWithdrawalProvenEvents(l1Contracts.OptimismPortalProxy, db, fromHeight, toHeight)
if err != nil { if err != nil {
...@@ -146,6 +154,9 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -146,6 +154,9 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
return err return err
} }
} }
if len(provenWithdrawals) > 0 {
metrics.RecordL1ProvenWithdrawals(len(provenWithdrawals))
}
// (2) OptimismPortal (finalized withdrawals) // (2) OptimismPortal (finalized withdrawals)
finalizedWithdrawals, err := contracts.OptimismPortalWithdrawalFinalizedEvents(l1Contracts.OptimismPortalProxy, db, fromHeight, toHeight) finalizedWithdrawals, err := contracts.OptimismPortalWithdrawalFinalizedEvents(l1Contracts.OptimismPortalProxy, db, fromHeight, toHeight)
...@@ -171,6 +182,9 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -171,6 +182,9 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
return err return err
} }
} }
if len(finalizedWithdrawals) > 0 {
metrics.RecordL1FinalizedWithdrawals(len(finalizedWithdrawals))
}
// (3) L1CrossDomainMessenger // (3) L1CrossDomainMessenger
crossDomainRelayedMessages, err := contracts.CrossDomainMessengerRelayedMessageEvents("l1", l1Contracts.L1CrossDomainMessengerProxy, db, fromHeight, toHeight) crossDomainRelayedMessages, err := contracts.CrossDomainMessengerRelayedMessageEvents("l1", l1Contracts.L1CrossDomainMessengerProxy, db, fromHeight, toHeight)
...@@ -198,6 +212,9 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -198,6 +212,9 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
return err return err
} }
} }
if len(crossDomainRelayedMessages) > 0 {
metrics.RecordL1CrossDomainRelayedMessages(len(crossDomainRelayedMessages))
}
// (4) L1StandardBridge // (4) L1StandardBridge
finalizedBridges, err := contracts.StandardBridgeFinalizedEvents("l1", l1Contracts.L1StandardBridgeProxy, db, fromHeight, toHeight) finalizedBridges, err := contracts.StandardBridgeFinalizedEvents("l1", l1Contracts.L1StandardBridgeProxy, db, fromHeight, toHeight)
...@@ -208,6 +225,7 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -208,6 +225,7 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
log.Info("detected finalized bridge withdrawals", "size", len(finalizedBridges)) log.Info("detected finalized bridge withdrawals", "size", len(finalizedBridges))
} }
finalizedTokens := make(map[common.Address]int)
for i := range finalizedBridges { for i := range finalizedBridges {
// Nothing actionable on the database. However, we can treat the relayed message // Nothing actionable on the database. However, we can treat the relayed message
// as an invariant by ensuring we can query for a deposit by the same hash // as an invariant by ensuring we can query for a deposit by the same hash
...@@ -218,8 +236,7 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -218,8 +236,7 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
return fmt.Errorf("expected RelayedMessage following BridgeFinalized event. tx_hash = %s", finalizedBridge.Event.TransactionHash.String()) return fmt.Errorf("expected RelayedMessage following BridgeFinalized event. tx_hash = %s", finalizedBridge.Event.TransactionHash.String())
} }
// Since the message hash is computed from the relayed message, this ensures the deposit fields must match. For good measure, // Since the message hash is computed from the relayed message, this ensures the deposit fields must match
// we may choose to make sure `withdrawal.BridgeTransfer` matches with the finalized bridge
withdrawal, err := db.BridgeTransfers.L2BridgeWithdrawalWithFilter(database.BridgeTransfer{CrossDomainMessageHash: &relayedMessage.MessageHash}) withdrawal, err := db.BridgeTransfers.L2BridgeWithdrawalWithFilter(database.BridgeTransfer{CrossDomainMessageHash: &relayedMessage.MessageHash})
if err != nil { if err != nil {
return err return err
...@@ -227,6 +244,13 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts ...@@ -227,6 +244,13 @@ func L1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Contracts
log.Error("missing L2StandardBridge withdrawal on L1 finalization", "tx_hash", finalizedBridge.Event.TransactionHash.String()) log.Error("missing L2StandardBridge withdrawal on L1 finalization", "tx_hash", finalizedBridge.Event.TransactionHash.String())
return fmt.Errorf("missing L2StandardBridge withdrawal on L1 finalization. tx_hash: %s", finalizedBridge.Event.TransactionHash.String()) return fmt.Errorf("missing L2StandardBridge withdrawal on L1 finalization. tx_hash: %s", finalizedBridge.Event.TransactionHash.String())
} }
finalizedTokens[finalizedBridge.BridgeTransfer.TokenPair.LocalTokenAddress]++
}
if len(finalizedBridges) > 0 {
for tokenAddr, size := range finalizedTokens {
metrics.RecordL1FinalizedBridgeTransfers(tokenAddr, size)
}
} }
// a-ok! // a-ok!
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/indexer/database" "github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/processors/contracts" "github.com/ethereum-optimism/optimism/indexer/processors/contracts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -17,7 +18,7 @@ import ( ...@@ -17,7 +18,7 @@ import (
// 1. OptimismPortal // 1. OptimismPortal
// 2. L2CrossDomainMessenger // 2. L2CrossDomainMessenger
// 3. L2StandardBridge // 3. L2StandardBridge
func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts config.L2Contracts, fromHeight, toHeight *big.Int) error { func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metrics L2Metricer, l2Contracts config.L2Contracts, fromHeight, toHeight *big.Int) error {
// (1) L2ToL1MessagePasser // (1) L2ToL1MessagePasser
l2ToL1MPMessagesPassed, err := contracts.L2ToL1MessagePasserMessagePassedEvents(l2Contracts.L2ToL1MessagePasser, db, fromHeight, toHeight) l2ToL1MPMessagesPassed, err := contracts.L2ToL1MessagePasserMessagePassedEvents(l2Contracts.L2ToL1MessagePasser, db, fromHeight, toHeight)
if err != nil { if err != nil {
...@@ -44,6 +45,7 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -44,6 +45,7 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
if err := db.BridgeTransactions.StoreL2TransactionWithdrawals(transactionWithdrawals); err != nil { if err := db.BridgeTransactions.StoreL2TransactionWithdrawals(transactionWithdrawals); err != nil {
return err return err
} }
metrics.RecordL2TransactionWithdrawals(len(transactionWithdrawals))
} }
// (2) L2CrossDomainMessenger // (2) L2CrossDomainMessenger
...@@ -56,7 +58,7 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -56,7 +58,7 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
} }
sentMessages := make(map[logKey]*contracts.CrossDomainMessengerSentMessageEvent, len(crossDomainSentMessages)) sentMessages := make(map[logKey]*contracts.CrossDomainMessengerSentMessageEvent, len(crossDomainSentMessages))
l2BridgeMessages := make([]database.L2BridgeMessage, len(crossDomainSentMessages)) bridgeMessages := make([]database.L2BridgeMessage, len(crossDomainSentMessages))
for i := range crossDomainSentMessages { for i := range crossDomainSentMessages {
sentMessage := crossDomainSentMessages[i] sentMessage := crossDomainSentMessages[i]
sentMessages[logKey{sentMessage.Event.BlockHash, sentMessage.Event.LogIndex}] = &sentMessage sentMessages[logKey{sentMessage.Event.BlockHash, sentMessage.Event.LogIndex}] = &sentMessage
...@@ -68,13 +70,13 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -68,13 +70,13 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
return fmt.Errorf("expected MessagePassedEvent preceding SentMessage. tx_hash = %s", sentMessage.Event.TransactionHash.String()) return fmt.Errorf("expected MessagePassedEvent preceding SentMessage. tx_hash = %s", sentMessage.Event.TransactionHash.String())
} }
l2BridgeMessages[i] = database.L2BridgeMessage{TransactionWithdrawalHash: messagePassed.WithdrawalHash, BridgeMessage: sentMessage.BridgeMessage} bridgeMessages[i] = database.L2BridgeMessage{TransactionWithdrawalHash: messagePassed.WithdrawalHash, BridgeMessage: sentMessage.BridgeMessage}
} }
if len(bridgeMessages) > 0 {
if len(l2BridgeMessages) > 0 { if err := db.BridgeMessages.StoreL2BridgeMessages(bridgeMessages); err != nil {
if err := db.BridgeMessages.StoreL2BridgeMessages(l2BridgeMessages); err != nil {
return err return err
} }
metrics.RecordL2CrossDomainSentMessages(len(bridgeMessages))
} }
// (3) L2StandardBridge // (3) L2StandardBridge
...@@ -86,7 +88,8 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -86,7 +88,8 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
log.Info("detected bridge withdrawals", "size", len(initiatedBridges)) log.Info("detected bridge withdrawals", "size", len(initiatedBridges))
} }
l2BridgeWithdrawals := make([]database.L2BridgeWithdrawal, len(initiatedBridges)) bridgedTokens := make(map[common.Address]int)
bridgeWithdrawals := make([]database.L2BridgeWithdrawal, len(initiatedBridges))
for i := range initiatedBridges { for i := range initiatedBridges {
initiatedBridge := initiatedBridges[i] initiatedBridge := initiatedBridges[i]
...@@ -103,13 +106,19 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -103,13 +106,19 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
} }
initiatedBridge.BridgeTransfer.CrossDomainMessageHash = &sentMessage.BridgeMessage.MessageHash initiatedBridge.BridgeTransfer.CrossDomainMessageHash = &sentMessage.BridgeMessage.MessageHash
l2BridgeWithdrawals[i] = database.L2BridgeWithdrawal{TransactionWithdrawalHash: messagePassed.WithdrawalHash, BridgeTransfer: initiatedBridge.BridgeTransfer} bridgedTokens[initiatedBridge.BridgeTransfer.TokenPair.LocalTokenAddress]++
bridgeWithdrawals[i] = database.L2BridgeWithdrawal{
TransactionWithdrawalHash: messagePassed.WithdrawalHash,
BridgeTransfer: initiatedBridge.BridgeTransfer,
} }
}
if len(l2BridgeWithdrawals) > 0 { if len(bridgeWithdrawals) > 0 {
if err := db.BridgeTransfers.StoreL2BridgeWithdrawals(l2BridgeWithdrawals); err != nil { if err := db.BridgeTransfers.StoreL2BridgeWithdrawals(bridgeWithdrawals); err != nil {
return err return err
} }
for tokenAddr, size := range bridgedTokens {
metrics.RecordL2InitiatedBridgeTransfers(tokenAddr, size)
}
} }
// a-ok! // a-ok!
...@@ -122,7 +131,7 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -122,7 +131,7 @@ func L2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
// 2. L2StandardBridge (no-op, since this is simply a wrapper over the L2CrossDomainMEssenger) // 2. L2StandardBridge (no-op, since this is simply a wrapper over the L2CrossDomainMEssenger)
// //
// NOTE: Unlike L1, there's no L2ToL1MessagePasser stage since transaction deposits are apart of the block derivation process. // NOTE: Unlike L1, there's no L2ToL1MessagePasser stage since transaction deposits are apart of the block derivation process.
func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts config.L2Contracts, fromHeight, toHeight *big.Int) error { func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metrics L2Metricer, l2Contracts config.L2Contracts, fromHeight, toHeight *big.Int) error {
// (1) L2CrossDomainMessenger // (1) L2CrossDomainMessenger
crossDomainRelayedMessages, err := contracts.CrossDomainMessengerRelayedMessageEvents("l2", l2Contracts.L2CrossDomainMessenger, db, fromHeight, toHeight) crossDomainRelayedMessages, err := contracts.CrossDomainMessengerRelayedMessageEvents("l2", l2Contracts.L2CrossDomainMessenger, db, fromHeight, toHeight)
if err != nil { if err != nil {
...@@ -149,6 +158,9 @@ func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -149,6 +158,9 @@ func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
return err return err
} }
} }
if len(relayedMessages) > 0 {
metrics.RecordL2CrossDomainRelayedMessages(len(relayedMessages))
}
// (2) L2StandardBridge // (2) L2StandardBridge
finalizedBridges, err := contracts.StandardBridgeFinalizedEvents("l2", l2Contracts.L2StandardBridge, db, fromHeight, toHeight) finalizedBridges, err := contracts.StandardBridgeFinalizedEvents("l2", l2Contracts.L2StandardBridge, db, fromHeight, toHeight)
...@@ -159,6 +171,7 @@ func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -159,6 +171,7 @@ func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
log.Info("detected finalized bridge deposits", "size", len(finalizedBridges)) log.Info("detected finalized bridge deposits", "size", len(finalizedBridges))
} }
finalizedTokens := make(map[common.Address]int)
for i := range finalizedBridges { for i := range finalizedBridges {
// Nothing actionable on the database. However, we can treat the relayed message // Nothing actionable on the database. However, we can treat the relayed message
// as an invariant by ensuring we can query for a deposit by the same hash // as an invariant by ensuring we can query for a deposit by the same hash
...@@ -169,8 +182,7 @@ func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -169,8 +182,7 @@ func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
return fmt.Errorf("expected RelayedMessage following BridgeFinalized event. tx_hash = %s", finalizedBridge.Event.TransactionHash.String()) return fmt.Errorf("expected RelayedMessage following BridgeFinalized event. tx_hash = %s", finalizedBridge.Event.TransactionHash.String())
} }
// Since the message hash is computed from the relayed message, this ensures the withdrawal fields must match. For good measure, // Since the message hash is computed from the relayed message, this ensures the withdrawal fields must match
// we may choose to make sure `deposit.BridgeTransfer` matches with the finalized bridge
deposit, err := db.BridgeTransfers.L1BridgeDepositWithFilter(database.BridgeTransfer{CrossDomainMessageHash: &relayedMessage.MessageHash}) deposit, err := db.BridgeTransfers.L1BridgeDepositWithFilter(database.BridgeTransfer{CrossDomainMessageHash: &relayedMessage.MessageHash})
if err != nil { if err != nil {
return err return err
...@@ -178,6 +190,13 @@ func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts ...@@ -178,6 +190,13 @@ func L2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts
log.Error("missing L1StandardBridge deposit on L2 finalization", "tx_hash", finalizedBridge.Event.TransactionHash.String()) log.Error("missing L1StandardBridge deposit on L2 finalization", "tx_hash", finalizedBridge.Event.TransactionHash.String())
return errors.New("missing L1StandardBridge deposit on L2 finalization") return errors.New("missing L1StandardBridge deposit on L2 finalization")
} }
finalizedTokens[finalizedBridge.BridgeTransfer.TokenPair.LocalTokenAddress]++
}
if len(finalizedBridges) > 0 {
for tokenAddr, size := range finalizedTokens {
metrics.RecordL2FinalizedBridgeTransfers(tokenAddr, size)
}
} }
// a-ok! // a-ok!
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -20,7 +21,7 @@ import ( ...@@ -20,7 +21,7 @@ import (
// 1. CanonicalTransactionChain // 1. CanonicalTransactionChain
// 2. L1CrossDomainMessenger // 2. L1CrossDomainMessenger
// 3. L1StandardBridge // 3. L1StandardBridge
func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Contracts config.L1Contracts, fromHeight, toHeight *big.Int) error { func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metrics L1Metricer, l1Contracts config.L1Contracts, fromHeight, toHeight *big.Int) error {
// (1) CanonicalTransactionChain // (1) CanonicalTransactionChain
ctcTxDepositEvents, err := contracts.LegacyCTCDepositEvents(l1Contracts.LegacyCanonicalTransactionChain, db, fromHeight, toHeight) ctcTxDepositEvents, err := contracts.LegacyCTCDepositEvents(l1Contracts.LegacyCanonicalTransactionChain, db, fromHeight, toHeight)
if err != nil { if err != nil {
...@@ -50,6 +51,7 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con ...@@ -50,6 +51,7 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con
if err := db.BridgeTransactions.StoreL1TransactionDeposits(transactionDeposits); err != nil { if err := db.BridgeTransactions.StoreL1TransactionDeposits(transactionDeposits); err != nil {
return err return err
} }
metrics.RecordL1TransactionDeposits(len(transactionDeposits))
} }
// (2) L1CrossDomainMessenger // (2) L1CrossDomainMessenger
...@@ -62,7 +64,7 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con ...@@ -62,7 +64,7 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con
} }
sentMessages := make(map[logKey]*contracts.CrossDomainMessengerSentMessageEvent, len(crossDomainSentMessages)) sentMessages := make(map[logKey]*contracts.CrossDomainMessengerSentMessageEvent, len(crossDomainSentMessages))
l1BridgeMessages := make([]database.L1BridgeMessage, len(crossDomainSentMessages)) bridgeMessages := make([]database.L1BridgeMessage, len(crossDomainSentMessages))
for i := range crossDomainSentMessages { for i := range crossDomainSentMessages {
sentMessage := crossDomainSentMessages[i] sentMessage := crossDomainSentMessages[i]
sentMessages[logKey{sentMessage.Event.BlockHash, sentMessage.Event.LogIndex}] = &sentMessage sentMessages[logKey{sentMessage.Event.BlockHash, sentMessage.Event.LogIndex}] = &sentMessage
...@@ -74,12 +76,13 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con ...@@ -74,12 +76,13 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con
return fmt.Errorf("missing preceding TransactionEnqueued for SentMessage event. tx_hash = %s", 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} bridgeMessages[i] = database.L1BridgeMessage{TransactionSourceHash: ctcTxDeposit.TxHash, BridgeMessage: sentMessage.BridgeMessage}
} }
if len(l1BridgeMessages) > 0 { if len(bridgeMessages) > 0 {
if err := db.BridgeMessages.StoreL1BridgeMessages(l1BridgeMessages); err != nil { if err := db.BridgeMessages.StoreL1BridgeMessages(bridgeMessages); err != nil {
return err return err
} }
metrics.RecordL1CrossDomainSentMessages(len(bridgeMessages))
} }
// (3) L1StandardBridge // (3) L1StandardBridge
...@@ -91,7 +94,8 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con ...@@ -91,7 +94,8 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con
log.Info("detected iegacy bridge deposits", "size", len(initiatedBridges)) log.Info("detected iegacy bridge deposits", "size", len(initiatedBridges))
} }
l1BridgeDeposits := make([]database.L1BridgeDeposit, len(initiatedBridges)) bridgedTokens := make(map[common.Address]int)
bridgeDeposits := make([]database.L1BridgeDeposit, len(initiatedBridges))
for i := range initiatedBridges { for i := range initiatedBridges {
initiatedBridge := initiatedBridges[i] initiatedBridge := initiatedBridges[i]
...@@ -110,15 +114,19 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con ...@@ -110,15 +114,19 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con
} }
initiatedBridge.BridgeTransfer.CrossDomainMessageHash = &sentMessage.BridgeMessage.MessageHash initiatedBridge.BridgeTransfer.CrossDomainMessageHash = &sentMessage.BridgeMessage.MessageHash
l1BridgeDeposits[i] = database.L1BridgeDeposit{ bridgedTokens[initiatedBridge.BridgeTransfer.TokenPair.LocalTokenAddress]++
bridgeDeposits[i] = database.L1BridgeDeposit{
TransactionSourceHash: ctcTxDeposit.TxHash, TransactionSourceHash: ctcTxDeposit.TxHash,
BridgeTransfer: initiatedBridge.BridgeTransfer, BridgeTransfer: initiatedBridge.BridgeTransfer,
} }
} }
if len(l1BridgeDeposits) > 0 { if len(bridgeDeposits) > 0 {
if err := db.BridgeTransfers.StoreL1BridgeDeposits(l1BridgeDeposits); err != nil { if err := db.BridgeTransfers.StoreL1BridgeDeposits(bridgeDeposits); err != nil {
return err return err
} }
for tokenAddr, size := range bridgedTokens {
metrics.RecordL1InitiatedBridgeTransfers(tokenAddr, size)
}
} }
// a-ok! // a-ok!
...@@ -130,20 +138,19 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con ...@@ -130,20 +138,19 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l1Con
// 1. L2CrossDomainMessenger - The LegacyMessagePasser contract cannot be used as entrypoint to bridge transactions from L2. The protocol // 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. // only allows the L2CrossDomainMessenger as the sole sender when relaying a bridged message.
// 2. L2StandardBridge // 2. L2StandardBridge
func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Contracts config.L2Contracts, fromHeight, toHeight *big.Int) error { func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metrics L2Metricer, l2Contracts config.L2Contracts, fromHeight, toHeight *big.Int) error {
// (1) L2CrossDomainMessenger // (1) L2CrossDomainMessenger
crossDomainSentMessages, err := contracts.CrossDomainMessengerSentMessageEvents("l2", l2Contracts.L2CrossDomainMessenger, db, fromHeight, toHeight) crossDomainSentMessages, err := contracts.CrossDomainMessengerSentMessageEvents("l2", l2Contracts.L2CrossDomainMessenger, db, fromHeight, toHeight)
if err != nil { if err != nil {
return err return err
} }
if len(crossDomainSentMessages) > 0 { if len(crossDomainSentMessages) > 0 {
log.Info("detected legacy transaction withdrawals (via L2CrossDomainMessenger)", "size", len(crossDomainSentMessages)) log.Info("detected legacy transaction withdrawals (via L2CrossDomainMessenger)", "size", len(crossDomainSentMessages))
} }
sentMessages := make(map[logKey]*contracts.CrossDomainMessengerSentMessageEvent, len(crossDomainSentMessages)) sentMessages := make(map[logKey]*contracts.CrossDomainMessengerSentMessageEvent, len(crossDomainSentMessages))
l2BridgeMessages := make([]database.L2BridgeMessage, len(crossDomainSentMessages)) bridgeMessages := make([]database.L2BridgeMessage, len(crossDomainSentMessages))
l2TransactionWithdrawals := make([]database.L2TransactionWithdrawal, len(crossDomainSentMessages)) transactionWithdrawals := make([]database.L2TransactionWithdrawal, len(crossDomainSentMessages))
for i := range crossDomainSentMessages { for i := range crossDomainSentMessages {
sentMessage := crossDomainSentMessages[i] sentMessage := crossDomainSentMessages[i]
sentMessages[logKey{sentMessage.Event.BlockHash, sentMessage.Event.LogIndex}] = &sentMessage sentMessages[logKey{sentMessage.Event.BlockHash, sentMessage.Event.LogIndex}] = &sentMessage
...@@ -151,7 +158,7 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con ...@@ -151,7 +158,7 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con
// To ensure consistency in the schema, we duplicate this as the "root" transaction withdrawal. The storage key in the message // 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. // passer contract is sha3(calldata + sender). The sender always being the L2CrossDomainMessenger pre-bedrock.
withdrawalHash := crypto.Keccak256Hash(append(sentMessage.MessageCalldata, l2Contracts.L2CrossDomainMessenger[:]...)) withdrawalHash := crypto.Keccak256Hash(append(sentMessage.MessageCalldata, l2Contracts.L2CrossDomainMessenger[:]...))
l2TransactionWithdrawals[i] = database.L2TransactionWithdrawal{ transactionWithdrawals[i] = database.L2TransactionWithdrawal{
WithdrawalHash: withdrawalHash, WithdrawalHash: withdrawalHash,
InitiatedL2EventGUID: sentMessage.Event.GUID, InitiatedL2EventGUID: sentMessage.Event.GUID,
Nonce: sentMessage.BridgeMessage.Nonce, Nonce: sentMessage.BridgeMessage.Nonce,
...@@ -165,19 +172,20 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con ...@@ -165,19 +172,20 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con
}, },
} }
l2BridgeMessages[i] = database.L2BridgeMessage{ bridgeMessages[i] = database.L2BridgeMessage{
TransactionWithdrawalHash: withdrawalHash, TransactionWithdrawalHash: withdrawalHash,
BridgeMessage: sentMessage.BridgeMessage, BridgeMessage: sentMessage.BridgeMessage,
} }
} }
if len(bridgeMessages) > 0 {
if len(l2BridgeMessages) > 0 { if err := db.BridgeTransactions.StoreL2TransactionWithdrawals(transactionWithdrawals); err != nil {
if err := db.BridgeTransactions.StoreL2TransactionWithdrawals(l2TransactionWithdrawals); err != nil {
return err return err
} }
if err := db.BridgeMessages.StoreL2BridgeMessages(l2BridgeMessages); err != nil { if err := db.BridgeMessages.StoreL2BridgeMessages(bridgeMessages); err != nil {
return err return err
} }
metrics.RecordL2TransactionWithdrawals(len(transactionWithdrawals))
metrics.RecordL2CrossDomainSentMessages(len(bridgeMessages))
} }
// (2) L2StandardBridge // (2) L2StandardBridge
...@@ -189,6 +197,7 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con ...@@ -189,6 +197,7 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con
log.Info("detected legacy bridge withdrawals", "size", len(initiatedBridges)) log.Info("detected legacy bridge withdrawals", "size", len(initiatedBridges))
} }
bridgedTokens := make(map[common.Address]int)
l2BridgeWithdrawals := make([]database.L2BridgeWithdrawal, len(initiatedBridges)) l2BridgeWithdrawals := make([]database.L2BridgeWithdrawal, len(initiatedBridges))
for i := range initiatedBridges { for i := range initiatedBridges {
initiatedBridge := initiatedBridges[i] initiatedBridge := initiatedBridges[i]
...@@ -201,8 +210,9 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con ...@@ -201,8 +210,9 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con
log.Error("expected SentMessage preceding DepositInitiated event", "tx_hash", initiatedBridge.Event.TransactionHash.String()) 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) return fmt.Errorf("expected SentMessage preceding DepositInitiated event. tx_hash = %s", initiatedBridge.Event.TransactionHash)
} }
initiatedBridge.BridgeTransfer.CrossDomainMessageHash = &sentMessage.BridgeMessage.MessageHash initiatedBridge.BridgeTransfer.CrossDomainMessageHash = &sentMessage.BridgeMessage.MessageHash
bridgedTokens[initiatedBridge.BridgeTransfer.TokenPair.LocalTokenAddress]++
l2BridgeWithdrawals[i] = database.L2BridgeWithdrawal{ l2BridgeWithdrawals[i] = database.L2BridgeWithdrawal{
TransactionWithdrawalHash: sentMessage.BridgeMessage.MessageHash, TransactionWithdrawalHash: sentMessage.BridgeMessage.MessageHash,
BridgeTransfer: initiatedBridge.BridgeTransfer, BridgeTransfer: initiatedBridge.BridgeTransfer,
...@@ -212,6 +222,9 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con ...@@ -212,6 +222,9 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con
if err := db.BridgeTransfers.StoreL2BridgeWithdrawals(l2BridgeWithdrawals); err != nil { if err := db.BridgeTransfers.StoreL2BridgeWithdrawals(l2BridgeWithdrawals); err != nil {
return err return err
} }
for tokenAddr, size := range bridgedTokens {
metrics.RecordL2InitiatedBridgeTransfers(tokenAddr, size)
}
} }
// a-ok // a-ok
...@@ -224,7 +237,7 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con ...@@ -224,7 +237,7 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, l2Con
// according to the pre-bedrock protocol. This follows: // according to the pre-bedrock protocol. This follows:
// 1. L1CrossDomainMessenger // 1. L1CrossDomainMessenger
// 2. L1StandardBridge // 2. L1StandardBridge
func LegacyL1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Client node.EthClient, l1Contracts config.L1Contracts, fromHeight, toHeight *big.Int) error { func LegacyL1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metrics L1Metricer, l1Client node.EthClient, l1Contracts config.L1Contracts, fromHeight, 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 // (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 // 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", l1Contracts.L1CrossDomainMessengerProxy, db, fromHeight, toHeight) crossDomainRelayedMessages, err := contracts.CrossDomainMessengerRelayedMessageEvents("l1", l1Contracts.L1CrossDomainMessengerProxy, db, fromHeight, toHeight)
...@@ -286,15 +299,20 @@ func LegacyL1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Cli ...@@ -286,15 +299,20 @@ func LegacyL1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Cli
return err return err
} }
} }
if len(crossDomainRelayedMessages) > 0 {
metrics.RecordL1ProvenWithdrawals(len(crossDomainRelayedMessages))
metrics.RecordL1FinalizedWithdrawals(len(crossDomainRelayedMessages))
metrics.RecordL1CrossDomainRelayedMessages(len(crossDomainRelayedMessages))
}
if skippedPreRegenesisMessages > 0 { if skippedPreRegenesisMessages > 0 {
// Logged as a warning just for visibility // Logged as a warning just for visibility
log.Warn("skipped pre-regensis relayed L2CrossDomainMessenger withdrawals", "size", skippedPreRegenesisMessages) 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 // (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 // santiy checks which is not important for legacy code. Not worth extra code pre-bedrock.
// via the relayed bridge messed through the cross domain messenger. // The message status is already tracked via the relayed bridge messed through the cross domain messenger.
// - NOTE: This means we dont increment metrics for finalized bridge transfers
// a-ok! // a-ok!
return nil return nil
...@@ -304,7 +322,7 @@ func LegacyL1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Cli ...@@ -304,7 +322,7 @@ func LegacyL1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l1Cli
// according to the pre-bedrock protocol. This follows: // according to the pre-bedrock protocol. This follows:
// 1. L2CrossDomainMessenger // 1. L2CrossDomainMessenger
// 2. L2StandardBridge // 2. L2StandardBridge
func LegacyL2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Contracts config.L2Contracts, fromHeight, toHeight *big.Int) error { func LegacyL2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metrics L2Metricer, l2Contracts config.L2Contracts, fromHeight, toHeight *big.Int) error {
// (1) L2CrossDomainMessenger // (1) L2CrossDomainMessenger
crossDomainRelayedMessages, err := contracts.CrossDomainMessengerRelayedMessageEvents("l2", l2Contracts.L2CrossDomainMessenger, db, fromHeight, toHeight) crossDomainRelayedMessages, err := contracts.CrossDomainMessengerRelayedMessageEvents("l2", l2Contracts.L2CrossDomainMessenger, db, fromHeight, toHeight)
if err != nil { if err != nil {
...@@ -329,10 +347,14 @@ func LegacyL2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Con ...@@ -329,10 +347,14 @@ func LegacyL2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, l2Con
return err return err
} }
} }
if len(crossDomainRelayedMessages) > 0 {
metrics.RecordL2CrossDomainRelayedMessages(len(crossDomainRelayedMessages))
}
// (2) L2StandardBridge -- no-op for now as there's nothing actionable to do here besides // (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 // santiy checks which is not important for legacy code. Not worth the extra code pre-bedorck.
// via the relayed bridge messed through the cross domain messenger. // The message status is already tracked via the relayed bridge messed through the cross domain messenger.
// - NOTE: This means we dont increment metrics for finalized bridge transfers
// a-ok! // a-ok!
return nil return nil
......
package bridge
import (
"math/big"
"github.com/ethereum-optimism/optimism/op-service/metrics"
"github.com/ethereum/go-ethereum/common"
"github.com/prometheus/client_golang/prometheus"
)
var (
MetricsNamespace string = "bridge"
)
type L1Metricer interface {
RecordLatestIndexedL1Height(height *big.Int)
RecordL1TransactionDeposits(size int)
RecordL1ProvenWithdrawals(size int)
RecordL1FinalizedWithdrawals(size int)
RecordL1CrossDomainSentMessages(size int)
RecordL1CrossDomainRelayedMessages(size int)
RecordL1InitiatedBridgeTransfers(token common.Address, size int)
RecordL1FinalizedBridgeTransfers(token common.Address, size int)
}
type L2Metricer interface {
RecordLatestIndexedL2Height(height *big.Int)
RecordL2TransactionWithdrawals(size int)
RecordL2CrossDomainSentMessages(size int)
RecordL2CrossDomainRelayedMessages(size int)
RecordL2InitiatedBridgeTransfers(token common.Address, size int)
RecordL2FinalizedBridgeTransfers(token common.Address, size int)
}
type Metricer interface {
L1Metricer
L2Metricer
RecordInterval() (done func(err error))
}
type bridgeMetrics struct {
intervalTick prometheus.Counter
intervalDuration prometheus.Histogram
intervalFailures prometheus.Counter
latestL1Height prometheus.Gauge
latestL2Height prometheus.Gauge
txDeposits prometheus.Counter
txWithdrawals prometheus.Counter
provenWithdrawals prometheus.Counter
finalizedWithdrawals prometheus.Counter
sentMessages *prometheus.CounterVec
relayedMessages *prometheus.CounterVec
initiatedBridgeTransfers *prometheus.CounterVec
finalizedBridgeTransfers *prometheus.CounterVec
}
func NewMetrics(registry *prometheus.Registry) Metricer {
factory := metrics.With(registry)
return &bridgeMetrics{
intervalTick: factory.NewCounter(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "intervals_total",
Help: "number of times processing loop has run",
}),
intervalDuration: factory.NewHistogram(prometheus.HistogramOpts{
Namespace: MetricsNamespace,
Name: "interval_seconds",
Help: "duration elapsed in the processing loop",
}),
intervalFailures: factory.NewCounter(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "failures_total",
Help: "number of failures encountered",
}),
latestL1Height: factory.NewGauge(prometheus.GaugeOpts{
Namespace: MetricsNamespace,
Subsystem: "l1",
Name: "height",
Help: "the latest processed l1 block height",
}),
latestL2Height: factory.NewGauge(prometheus.GaugeOpts{
Namespace: MetricsNamespace,
Subsystem: "l2",
Name: "height",
Help: "the latest processed l2 block height",
}),
txDeposits: factory.NewCounter(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "tx_deposits",
Help: "number of processed transactions deposited from l1",
}),
txWithdrawals: factory.NewCounter(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "tx_withdrawals",
Help: "number of processed transactions withdrawn from l2",
}),
provenWithdrawals: factory.NewCounter(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "proven_withdrawals",
Help: "number of proven tx withdrawals on l1",
}),
finalizedWithdrawals: factory.NewCounter(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "finalized_withdrawals",
Help: "number of finalized tx withdrawals on l1",
}),
sentMessages: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "sent_messages",
Help: "number of bridged messages between l1 and l2",
}, []string{
"chain",
}),
relayedMessages: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "relayed_messages",
Help: "number of relayed messages between l1 and l2",
}, []string{
"chain",
}),
initiatedBridgeTransfers: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "initiated_token_transfers",
Help: "number of bridged tokens between l1 and l2",
}, []string{
"chain",
"token_address",
}),
finalizedBridgeTransfers: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: MetricsNamespace,
Name: "finalized_token_transfers",
Help: "number of finalized token transfers between l1 and l2",
}, []string{
"chain",
"token_address",
}),
}
}
func (m *bridgeMetrics) RecordInterval() func(error) {
m.intervalTick.Inc()
timer := prometheus.NewTimer(m.intervalDuration)
return func(err error) {
timer.ObserveDuration()
if err != nil {
m.intervalFailures.Inc()
}
}
}
// L1Metricer
func (m *bridgeMetrics) RecordLatestIndexedL1Height(height *big.Int) {
m.latestL1Height.Set(float64(height.Uint64()))
}
func (m *bridgeMetrics) RecordL1TransactionDeposits(size int) {
m.txDeposits.Add(float64(size))
}
func (m *bridgeMetrics) RecordL1ProvenWithdrawals(size int) {
m.provenWithdrawals.Add(float64(size))
}
func (m *bridgeMetrics) RecordL1FinalizedWithdrawals(size int) {
m.finalizedWithdrawals.Add(float64(size))
}
func (m *bridgeMetrics) RecordL1CrossDomainSentMessages(size int) {
m.sentMessages.WithLabelValues("l1").Add(float64(size))
}
func (m *bridgeMetrics) RecordL1CrossDomainRelayedMessages(size int) {
m.relayedMessages.WithLabelValues("l1").Add(float64(size))
}
func (m *bridgeMetrics) RecordL1InitiatedBridgeTransfers(tokenAddr common.Address, size int) {
m.initiatedBridgeTransfers.WithLabelValues("l1", tokenAddr.String()).Add(float64(size))
}
func (m *bridgeMetrics) RecordL1FinalizedBridgeTransfers(tokenAddr common.Address, size int) {
m.finalizedBridgeTransfers.WithLabelValues("l1", tokenAddr.String()).Add(float64(size))
}
// L2Metricer
func (m *bridgeMetrics) RecordLatestIndexedL2Height(height *big.Int) {
m.latestL2Height.Set(float64(height.Uint64()))
}
func (m *bridgeMetrics) RecordL2TransactionWithdrawals(size int) {
m.txWithdrawals.Add(float64(size))
}
func (m *bridgeMetrics) RecordL2CrossDomainSentMessages(size int) {
m.sentMessages.WithLabelValues("l2").Add(float64(size))
}
func (m *bridgeMetrics) RecordL2CrossDomainRelayedMessages(size int) {
m.relayedMessages.WithLabelValues("l2").Add(float64(size))
}
func (m *bridgeMetrics) RecordL2InitiatedBridgeTransfers(tokenAddr common.Address, size int) {
m.initiatedBridgeTransfers.WithLabelValues("l2", tokenAddr.String()).Add(float64(size))
}
func (m *bridgeMetrics) RecordL2FinalizedBridgeTransfers(tokenAddr common.Address, size int) {
m.finalizedBridgeTransfers.WithLabelValues("l2", tokenAddr.String()).Add(float64(size))
}
...@@ -15,21 +15,23 @@ type LegacyBridgeEvent struct { ...@@ -15,21 +15,23 @@ type LegacyBridgeEvent struct {
} }
func L1StandardBridgeLegacyDepositInitiatedEvents(contractAddress common.Address, db *database.DB, fromHeight, toHeight *big.Int) ([]LegacyBridgeEvent, error) { func L1StandardBridgeLegacyDepositInitiatedEvents(contractAddress common.Address, db *database.DB, fromHeight, toHeight *big.Int) ([]LegacyBridgeEvent, error) {
// The L1StandardBridge ABI contains the legacy events
l1StandardBridgeAbi, err := bindings.L1StandardBridgeMetaData.GetAbi() l1StandardBridgeAbi, err := bindings.L1StandardBridgeMetaData.GetAbi()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// The L1StandardBridge contains the legacy events
ethDepositEventAbi := l1StandardBridgeAbi.Events["ETHDepositInitiated"] ethDepositEventAbi := l1StandardBridgeAbi.Events["ETHDepositInitiated"]
erc20DepositEventAbi := l1StandardBridgeAbi.Events["ERC20DepositInitiated"] erc20DepositEventAbi := l1StandardBridgeAbi.Events["ERC20DepositInitiated"]
// Grab both ETH & ERC20 Events // Grab both ETH & ERC20 Events
ethDepositEvents, err := db.ContractEvents.L1ContractEventsWithFilter(database.ContractEvent{ContractAddress: contractAddress, EventSignature: ethDepositEventAbi.ID}, fromHeight, toHeight) contractEventFilter := database.ContractEvent{ContractAddress: contractAddress, EventSignature: ethDepositEventAbi.ID}
ethDepositEvents, err := db.ContractEvents.L1ContractEventsWithFilter(contractEventFilter, fromHeight, toHeight)
if err != nil { if err != nil {
return nil, err return nil, err
} }
erc20DepositEvents, err := db.ContractEvents.L1ContractEventsWithFilter(database.ContractEvent{ContractAddress: contractAddress, EventSignature: erc20DepositEventAbi.ID}, fromHeight, toHeight) contractEventFilter.EventSignature = erc20DepositEventAbi.ID
erc20DepositEvents, err := db.ContractEvents.L1ContractEventsWithFilter(contractEventFilter, fromHeight, toHeight)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -81,13 +83,15 @@ func L1StandardBridgeLegacyDepositInitiatedEvents(contractAddress common.Address ...@@ -81,13 +83,15 @@ func L1StandardBridgeLegacyDepositInitiatedEvents(contractAddress common.Address
} }
func L2StandardBridgeLegacyWithdrawalInitiatedEvents(contractAddress common.Address, db *database.DB, fromHeight, toHeight *big.Int) ([]LegacyBridgeEvent, error) { func L2StandardBridgeLegacyWithdrawalInitiatedEvents(contractAddress common.Address, db *database.DB, fromHeight, toHeight *big.Int) ([]LegacyBridgeEvent, error) {
// The L2StandardBridge ABI contains the legacy events
l2StandardBridgeAbi, err := bindings.L2StandardBridgeMetaData.GetAbi() l2StandardBridgeAbi, err := bindings.L2StandardBridgeMetaData.GetAbi()
if err != nil { if err != nil {
return nil, err return nil, err
} }
withdrawalInitiatedEventAbi := l2StandardBridgeAbi.Events["WithdrawalInitiated"] withdrawalInitiatedEventAbi := l2StandardBridgeAbi.Events["WithdrawalInitiated"]
withdrawalEvents, err := db.ContractEvents.L2ContractEventsWithFilter(database.ContractEvent{ContractAddress: contractAddress, EventSignature: withdrawalInitiatedEventAbi.ID}, fromHeight, toHeight) contractEventFilter := database.ContractEvent{ContractAddress: contractAddress, EventSignature: withdrawalInitiatedEventAbi.ID}
withdrawalEvents, err := db.ContractEvents.L2ContractEventsWithFilter(contractEventFilter, fromHeight, toHeight)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -144,7 +144,7 @@ func NewConfig( ...@@ -144,7 +144,7 @@ func NewConfig(
TraceType: traceType, TraceType: traceType,
TxMgrConfig: txmgr.NewCLIConfig(l1EthRpc), TxMgrConfig: txmgr.NewCLIConfig(l1EthRpc, txmgr.DefaultChallengerFlagValues),
MetricsConfig: opmetrics.DefaultCLIConfig(), MetricsConfig: opmetrics.DefaultCLIConfig(),
PprofConfig: oppprof.DefaultCLIConfig(), PprofConfig: oppprof.DefaultCLIConfig(),
......
...@@ -174,7 +174,7 @@ var optionalFlags = []cli.Flag{ ...@@ -174,7 +174,7 @@ var optionalFlags = []cli.Flag{
func init() { func init() {
optionalFlags = append(optionalFlags, oplog.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, oplog.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, txmgr.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, txmgr.CLIFlagsWithDefaults(envVarPrefix, txmgr.DefaultChallengerFlagValues)...)
optionalFlags = append(optionalFlags, opmetrics.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, opmetrics.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, oppprof.CLIFlags(envVarPrefix)...) optionalFlags = append(optionalFlags, oppprof.CLIFlags(envVarPrefix)...)
......
...@@ -152,10 +152,10 @@ func (a *Agent) tryResolveClaims(ctx context.Context) error { ...@@ -152,10 +152,10 @@ func (a *Agent) tryResolveClaims(ctx context.Context) error {
resolvableClaims = append(resolvableClaims, int64(claim.ContractIndex)) resolvableClaims = append(resolvableClaims, int64(claim.ContractIndex))
} }
} }
a.log.Info("Resolving claims", "numClaims", len(resolvableClaims))
if len(resolvableClaims) == 0 { if len(resolvableClaims) == 0 {
return errNoResolvableClaims return errNoResolvableClaims
} }
a.log.Info("Resolving claims", "numClaims", len(resolvableClaims))
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(len(resolvableClaims)) wg.Add(len(resolvableClaims))
......
...@@ -35,10 +35,6 @@ func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game type ...@@ -35,10 +35,6 @@ func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game type
if claim.Depth() == s.gameDepth { if claim.Depth() == s.gameDepth {
return nil, types.ErrGameDepthReached return nil, types.ErrGameDepthReached
} }
agree, err := s.agreeWithClaim(ctx, claim.ClaimData)
if err != nil {
return nil, err
}
// Before challenging this claim, first check that the move wasn't warranted. // Before challenging this claim, first check that the move wasn't warranted.
// If the parent claim is on a dishonest path, then we would have moved against it anyways. So we don't move. // If the parent claim is on a dishonest path, then we would have moved against it anyways. So we don't move.
...@@ -57,6 +53,10 @@ func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game type ...@@ -57,6 +53,10 @@ func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game type
} }
} }
agree, err := s.agreeWithClaim(ctx, claim.ClaimData)
if err != nil {
return nil, err
}
if agree { if agree {
return s.defend(ctx, claim) return s.defend(ctx, claim)
} else { } else {
......
...@@ -48,17 +48,42 @@ var ( ...@@ -48,17 +48,42 @@ var (
} }
) )
type DefaultFlagValues struct {
NumConfirmations uint64
SafeAbortNonceTooLowCount uint64
ResubmissionTimeout time.Duration
NetworkTimeout time.Duration
TxSendTimeout time.Duration
TxNotInMempoolTimeout time.Duration
ReceiptQueryInterval time.Duration
}
var ( var (
defaultNumConfirmations = uint64(10) DefaultBatcherFlagValues = DefaultFlagValues{
defaultSafeAbortNonceTooLowCount = uint64(3) NumConfirmations: uint64(10),
defaultResubmissionTimeout = 48 * time.Second SafeAbortNonceTooLowCount: uint64(3),
defaultNetworkTimeout = 10 * time.Second ResubmissionTimeout: 48 * time.Second,
defaultTxSendTimeout = 0 * time.Second NetworkTimeout: 10 * time.Second,
defaultTxNotInMempoolTimeout = 2 * time.Minute TxSendTimeout: 0 * time.Second,
defaultReceiptQueryInterval = 12 * time.Second TxNotInMempoolTimeout: 2 * time.Minute,
ReceiptQueryInterval: 12 * time.Second,
}
DefaultChallengerFlagValues = DefaultFlagValues{
NumConfirmations: uint64(3),
SafeAbortNonceTooLowCount: uint64(3),
ResubmissionTimeout: 24 * time.Second,
NetworkTimeout: 10 * time.Second,
TxSendTimeout: 2 * time.Minute,
TxNotInMempoolTimeout: 1 * time.Minute,
ReceiptQueryInterval: 12 * time.Second,
}
) )
func CLIFlags(envPrefix string) []cli.Flag { func CLIFlags(envPrefix string) []cli.Flag {
return CLIFlagsWithDefaults(envPrefix, DefaultBatcherFlagValues)
}
func CLIFlagsWithDefaults(envPrefix string, defaults DefaultFlagValues) []cli.Flag {
prefixEnvVars := func(name string) []string { prefixEnvVars := func(name string) []string {
return opservice.PrefixEnvVar(envPrefix, name) return opservice.PrefixEnvVar(envPrefix, name)
} }
...@@ -81,43 +106,43 @@ func CLIFlags(envPrefix string) []cli.Flag { ...@@ -81,43 +106,43 @@ func CLIFlags(envPrefix string) []cli.Flag {
&cli.Uint64Flag{ &cli.Uint64Flag{
Name: NumConfirmationsFlagName, Name: NumConfirmationsFlagName,
Usage: "Number of confirmations which we will wait after sending a transaction", Usage: "Number of confirmations which we will wait after sending a transaction",
Value: defaultNumConfirmations, Value: defaults.NumConfirmations,
EnvVars: prefixEnvVars("NUM_CONFIRMATIONS"), EnvVars: prefixEnvVars("NUM_CONFIRMATIONS"),
}, },
&cli.Uint64Flag{ &cli.Uint64Flag{
Name: SafeAbortNonceTooLowCountFlagName, Name: SafeAbortNonceTooLowCountFlagName,
Usage: "Number of ErrNonceTooLow observations required to give up on a tx at a particular nonce without receiving confirmation", Usage: "Number of ErrNonceTooLow observations required to give up on a tx at a particular nonce without receiving confirmation",
Value: defaultSafeAbortNonceTooLowCount, Value: defaults.SafeAbortNonceTooLowCount,
EnvVars: prefixEnvVars("SAFE_ABORT_NONCE_TOO_LOW_COUNT"), EnvVars: prefixEnvVars("SAFE_ABORT_NONCE_TOO_LOW_COUNT"),
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: ResubmissionTimeoutFlagName, Name: ResubmissionTimeoutFlagName,
Usage: "Duration we will wait before resubmitting a transaction to L1", Usage: "Duration we will wait before resubmitting a transaction to L1",
Value: defaultResubmissionTimeout, Value: defaults.ResubmissionTimeout,
EnvVars: prefixEnvVars("RESUBMISSION_TIMEOUT"), EnvVars: prefixEnvVars("RESUBMISSION_TIMEOUT"),
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: NetworkTimeoutFlagName, Name: NetworkTimeoutFlagName,
Usage: "Timeout for all network operations", Usage: "Timeout for all network operations",
Value: defaultNetworkTimeout, Value: defaults.NetworkTimeout,
EnvVars: prefixEnvVars("NETWORK_TIMEOUT"), EnvVars: prefixEnvVars("NETWORK_TIMEOUT"),
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: TxSendTimeoutFlagName, Name: TxSendTimeoutFlagName,
Usage: "Timeout for sending transactions. If 0 it is disabled.", Usage: "Timeout for sending transactions. If 0 it is disabled.",
Value: defaultTxSendTimeout, Value: defaults.TxSendTimeout,
EnvVars: prefixEnvVars("TXMGR_TX_SEND_TIMEOUT"), EnvVars: prefixEnvVars("TXMGR_TX_SEND_TIMEOUT"),
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: TxNotInMempoolTimeoutFlagName, Name: TxNotInMempoolTimeoutFlagName,
Usage: "Timeout for aborting a tx send if the tx does not make it to the mempool.", Usage: "Timeout for aborting a tx send if the tx does not make it to the mempool.",
Value: defaultTxNotInMempoolTimeout, Value: defaults.TxNotInMempoolTimeout,
EnvVars: prefixEnvVars("TXMGR_TX_NOT_IN_MEMPOOL_TIMEOUT"), EnvVars: prefixEnvVars("TXMGR_TX_NOT_IN_MEMPOOL_TIMEOUT"),
}, },
&cli.DurationFlag{ &cli.DurationFlag{
Name: ReceiptQueryIntervalFlagName, Name: ReceiptQueryIntervalFlagName,
Usage: "Frequency to poll for receipts", Usage: "Frequency to poll for receipts",
Value: defaultReceiptQueryInterval, Value: defaults.ReceiptQueryInterval,
EnvVars: prefixEnvVars("TXMGR_RECEIPT_QUERY_INTERVAL"), EnvVars: prefixEnvVars("TXMGR_RECEIPT_QUERY_INTERVAL"),
}, },
}, client.CLIFlags(envPrefix)...) }, client.CLIFlags(envPrefix)...)
...@@ -140,16 +165,16 @@ type CLIConfig struct { ...@@ -140,16 +165,16 @@ type CLIConfig struct {
TxNotInMempoolTimeout time.Duration TxNotInMempoolTimeout time.Duration
} }
func NewCLIConfig(l1RPCURL string) CLIConfig { func NewCLIConfig(l1RPCURL string, defaults DefaultFlagValues) CLIConfig {
return CLIConfig{ return CLIConfig{
L1RPCURL: l1RPCURL, L1RPCURL: l1RPCURL,
NumConfirmations: defaultNumConfirmations, NumConfirmations: defaults.NumConfirmations,
SafeAbortNonceTooLowCount: defaultSafeAbortNonceTooLowCount, SafeAbortNonceTooLowCount: defaults.SafeAbortNonceTooLowCount,
ResubmissionTimeout: defaultResubmissionTimeout, ResubmissionTimeout: defaults.ResubmissionTimeout,
NetworkTimeout: defaultNetworkTimeout, NetworkTimeout: defaults.NetworkTimeout,
TxSendTimeout: defaultTxSendTimeout, TxSendTimeout: defaults.TxSendTimeout,
TxNotInMempoolTimeout: defaultTxNotInMempoolTimeout, TxNotInMempoolTimeout: defaults.TxNotInMempoolTimeout,
ReceiptQueryInterval: defaultReceiptQueryInterval, ReceiptQueryInterval: defaults.ReceiptQueryInterval,
SignerCLIConfig: client.NewCLIConfig(), SignerCLIConfig: client.NewCLIConfig(),
} }
} }
......
...@@ -13,12 +13,12 @@ var ( ...@@ -13,12 +13,12 @@ var (
func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) { func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs() cfg := configForArgs()
defaultCfg := NewCLIConfig(l1EthRpcValue) defaultCfg := NewCLIConfig(l1EthRpcValue, DefaultBatcherFlagValues)
require.Equal(t, defaultCfg, cfg) require.Equal(t, defaultCfg, cfg)
} }
func TestDefaultConfigIsValid(t *testing.T) { func TestDefaultConfigIsValid(t *testing.T) {
cfg := NewCLIConfig(l1EthRpcValue) cfg := NewCLIConfig(l1EthRpcValue, DefaultBatcherFlagValues)
require.NoError(t, cfg.Check()) require.NoError(t, cfg.Check())
} }
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
"devDependencies": { "devDependencies": {
"@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0",
"@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0",
"@types/express": "^4.17.17", "@types/express": "^4.17.18",
"@types/morgan": "^1.9.6", "@types/morgan": "^1.9.6",
"@types/pino": "^7.0.5", "@types/pino": "^7.0.5",
"@types/pino-multi-stream": "^5.1.4", "@types/pino-multi-stream": "^5.1.4",
......
...@@ -247,8 +247,8 @@ importers: ...@@ -247,8 +247,8 @@ importers:
specifier: ^5.7.0 specifier: ^5.7.0
version: 5.7.0 version: 5.7.0
'@types/express': '@types/express':
specifier: ^4.17.17 specifier: ^4.17.18
version: 4.17.17 version: 4.17.18
'@types/morgan': '@types/morgan':
specifier: ^1.9.6 specifier: ^1.9.6
version: 1.9.6 version: 1.9.6
...@@ -3902,8 +3902,8 @@ packages: ...@@ -3902,8 +3902,8 @@ packages:
'@types/send': 0.17.1 '@types/send': 0.17.1
dev: true dev: true
/@types/express@4.17.17: /@types/express@4.17.18:
resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} resolution: {integrity: sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==}
dependencies: dependencies:
'@types/body-parser': 1.19.1 '@types/body-parser': 1.19.1
'@types/express-serve-static-core': 4.17.35 '@types/express-serve-static-core': 4.17.35
......
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