diff --git a/op-batcher/batcher/driver.go b/op-batcher/batcher/driver.go index 5fe7a042c996f..e17e85d66ad07 100644 --- a/op-batcher/batcher/driver.go +++ b/op-batcher/batcher/driver.go @@ -73,7 +73,7 @@ func NewBatchSubmitterFromCLIConfig(cfg CLIConfig, l log.Logger, m metrics.Metri if err != nil { return nil, err } - txManager := txmgr.NewSimpleTxManager("batcher", l, txManagerConfig) + txManager := txmgr.NewSimpleTxManager("batcher", l, m, txManagerConfig) batcherCfg := Config{ L1Client: l1Client, diff --git a/op-batcher/metrics/metrics.go b/op-batcher/metrics/metrics.go index 31ba792cb63d3..6c92602ab85b9 100644 --- a/op-batcher/metrics/metrics.go +++ b/op-batcher/metrics/metrics.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" + txmetrics "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" ) const Namespace = "op_batcher" @@ -22,6 +23,9 @@ type Metricer interface { // Records all L1 and L2 block events opmetrics.RefMetricer + // Record Tx metrics + txmetrics.TxMetricer + RecordLatestL1Block(l1ref eth.L1BlockRef) RecordL2BlocksLoaded(l2ref eth.L2BlockRef) RecordChannelOpened(id derive.ChannelID, numPendingBlocks int) @@ -43,6 +47,7 @@ type Metrics struct { factory opmetrics.Factory opmetrics.RefMetrics + txmetrics.TxMetrics Info prometheus.GaugeVec Up prometheus.Gauge @@ -80,6 +85,7 @@ func NewMetrics(procName string) *Metrics { factory: factory, RefMetrics: opmetrics.MakeRefMetrics(ns, factory), + TxMetrics: txmetrics.MakeTxMetrics(ns, factory), Info: *factory.NewGaugeVec(prometheus.GaugeOpts{ Namespace: ns, diff --git a/op-batcher/metrics/noop.go b/op-batcher/metrics/noop.go index 80f993f0854a2..0873c722e5d00 100644 --- a/op-batcher/metrics/noop.go +++ b/op-batcher/metrics/noop.go @@ -4,9 +4,13 @@ import ( "github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" + txmetrics "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" ) -type noopMetrics struct{ opmetrics.NoopRefMetrics } +type noopMetrics struct { + opmetrics.NoopRefMetrics + txmetrics.NoopTxMetrics +} var NoopMetrics Metricer = new(noopMetrics) diff --git a/op-proposer/metrics/metrics.go b/op-proposer/metrics/metrics.go index a5296b637d55f..41767e8bc6caf 100644 --- a/op-proposer/metrics/metrics.go +++ b/op-proposer/metrics/metrics.go @@ -11,6 +11,7 @@ import ( "github.com/prometheus/client_golang/prometheus" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" + txmetrics "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" ) const Namespace = "op_proposer" @@ -22,6 +23,9 @@ type Metricer interface { // Records all L1 and L2 block events opmetrics.RefMetricer + // Record Tx metrics + txmetrics.TxMetricer + RecordL2BlocksProposed(l2ref eth.L2BlockRef) } @@ -31,6 +35,7 @@ type Metrics struct { factory opmetrics.Factory opmetrics.RefMetrics + txmetrics.TxMetrics Info prometheus.GaugeVec Up prometheus.Gauge @@ -53,6 +58,7 @@ func NewMetrics(procName string) *Metrics { factory: factory, RefMetrics: opmetrics.MakeRefMetrics(ns, factory), + TxMetrics: txmetrics.MakeTxMetrics(ns, factory), Info: *factory.NewGaugeVec(prometheus.GaugeOpts{ Namespace: ns, diff --git a/op-proposer/metrics/noop.go b/op-proposer/metrics/noop.go index d5cf33e58ea9d..14973bfd13c40 100644 --- a/op-proposer/metrics/noop.go +++ b/op-proposer/metrics/noop.go @@ -3,9 +3,13 @@ package metrics import ( "github.com/ethereum-optimism/optimism/op-node/eth" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" + txmetrics "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" ) -type noopMetrics struct{ opmetrics.NoopRefMetrics } +type noopMetrics struct { + opmetrics.NoopRefMetrics + txmetrics.NoopTxMetrics +} var NoopMetrics Metricer = new(noopMetrics) diff --git a/op-proposer/proposer/l2_output_submitter.go b/op-proposer/proposer/l2_output_submitter.go index 347a2e08b87a5..3434edb23cc15 100644 --- a/op-proposer/proposer/l2_output_submitter.go +++ b/op-proposer/proposer/l2_output_submitter.go @@ -42,7 +42,7 @@ func Main(version string, cliCtx *cli.Context) error { m := metrics.NewMetrics("default") l.Info("Initializing L2 Output Submitter") - proposerConfig, err := NewL2OutputSubmitterConfigFromCLIConfig(cfg, l) + proposerConfig, err := NewL2OutputSubmitterConfigFromCLIConfig(cfg, l, m) if err != nil { l.Error("Unable to create the L2 Output Submitter", "error", err) return err @@ -138,7 +138,7 @@ type L2OutputSubmitter struct { // NewL2OutputSubmitterFromCLIConfig creates a new L2 Output Submitter given the CLI Config func NewL2OutputSubmitterFromCLIConfig(cfg CLIConfig, l log.Logger, m metrics.Metricer) (*L2OutputSubmitter, error) { - proposerConfig, err := NewL2OutputSubmitterConfigFromCLIConfig(cfg, l) + proposerConfig, err := NewL2OutputSubmitterConfigFromCLIConfig(cfg, l, m) if err != nil { return nil, err } @@ -146,7 +146,7 @@ func NewL2OutputSubmitterFromCLIConfig(cfg CLIConfig, l log.Logger, m metrics.Me } // NewL2OutputSubmitterConfigFromCLIConfig creates the proposer config from the CLI config. -func NewL2OutputSubmitterConfigFromCLIConfig(cfg CLIConfig, l log.Logger) (*Config, error) { +func NewL2OutputSubmitterConfigFromCLIConfig(cfg CLIConfig, l log.Logger, m metrics.Metricer) (*Config, error) { l2ooAddress, err := parseAddress(cfg.L2OOAddress) if err != nil { return nil, err @@ -156,7 +156,7 @@ func NewL2OutputSubmitterConfigFromCLIConfig(cfg CLIConfig, l log.Logger) (*Conf if err != nil { return nil, err } - txManager := txmgr.NewSimpleTxManager("proposer", l, txManagerConfig) + txManager := txmgr.NewSimpleTxManager("proposer", l, m, txManagerConfig) // Connect to L1 and L2 providers. Perform these last since they are the most expensive. ctx := context.Background() diff --git a/op-service/txmgr/metrics/noop.go b/op-service/txmgr/metrics/noop.go new file mode 100644 index 0000000000000..b08e5f20bd438 --- /dev/null +++ b/op-service/txmgr/metrics/noop.go @@ -0,0 +1,7 @@ +package metrics + +import "github.com/ethereum/go-ethereum/core/types" + +type NoopTxMetrics struct{} + +func (*NoopTxMetrics) RecordL1GasFee(*types.Receipt) {} diff --git a/op-service/txmgr/metrics/tx_metrics.go b/op-service/txmgr/metrics/tx_metrics.go new file mode 100644 index 0000000000000..6201e13a9b3c5 --- /dev/null +++ b/op-service/txmgr/metrics/tx_metrics.go @@ -0,0 +1,34 @@ +package metrics + +import ( + "github.com/ethereum-optimism/optimism/op-service/metrics" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + + "github.com/prometheus/client_golang/prometheus" +) + +type TxMetricer interface { + RecordL1GasFee(receipt *types.Receipt) +} + +type TxMetrics struct { + TxL1GasFee prometheus.Gauge +} + +var _ TxMetricer = (*TxMetrics)(nil) + +func MakeTxMetrics(ns string, factory metrics.Factory) TxMetrics { + return TxMetrics{ + TxL1GasFee: factory.NewGauge(prometheus.GaugeOpts{ + Namespace: ns, + Name: "tx_fee_gwei", + Help: "L1 gas fee for transactions in GWEI", + Subsystem: "txmgr", + }), + } +} + +func (t *TxMetrics) RecordL1GasFee(receipt *types.Receipt) { + t.TxL1GasFee.Set(float64(receipt.EffectiveGasPrice.Uint64() * receipt.GasUsed / params.GWei)) +} diff --git a/op-service/txmgr/txmgr.go b/op-service/txmgr/txmgr.go index 088c22e04b3ff..96cd4f73c4d75 100644 --- a/op-service/txmgr/txmgr.go +++ b/op-service/txmgr/txmgr.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "math/big" "strings" "sync" @@ -15,6 +16,8 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" ) // Geth defaults the priceBump to 10 @@ -80,10 +83,11 @@ type SimpleTxManager struct { backend ETHBackend l log.Logger + metr metrics.TxMetricer } // NewSimpleTxManager initializes a new SimpleTxManager with the passed Config. -func NewSimpleTxManager(name string, l log.Logger, cfg Config) *SimpleTxManager { +func NewSimpleTxManager(name string, l log.Logger, m metrics.TxMetricer, cfg Config) *SimpleTxManager { if cfg.NumConfirmations == 0 { panic("txmgr: NumConfirmations cannot be zero") } @@ -97,6 +101,7 @@ func NewSimpleTxManager(name string, l log.Logger, cfg Config) *SimpleTxManager cfg: cfg, backend: cfg.Backend, l: l.New("service", name), + metr: m, } } @@ -281,6 +286,7 @@ func (m *SimpleTxManager) publishAndWaitForTx(ctx context.Context, tx *types.Tra } select { case receiptChan <- receipt: + m.metr.RecordL1GasFee(receipt) default: } } diff --git a/op-service/txmgr/txmgr_test.go b/op-service/txmgr/txmgr_test.go index d66cbe9ce3874..d913304899d9d 100644 --- a/op-service/txmgr/txmgr_test.go +++ b/op-service/txmgr/txmgr_test.go @@ -12,6 +12,8 @@ import ( "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/op-node/testlog" + "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -39,7 +41,7 @@ func newTestHarnessWithConfig(t *testing.T, cfg Config) *testHarness { g := newGasPricer(3) backend := newMockBackend(g) cfg.Backend = backend - mgr := NewSimpleTxManager("TEST", testlog.Logger(t, log.LvlCrit), cfg) + mgr := NewSimpleTxManager("TEST", testlog.Logger(t, log.LvlCrit), &metrics.NoopTxMetrics{}, cfg) return &testHarness{ cfg: cfg,