Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #105 from primevprotocol/evmclientmetrics
Browse files Browse the repository at this point in the history
feat: add metrics for evmclient
  • Loading branch information
kant777 authored Nov 28, 2023
2 parents 982bdb8 + 8818de6 commit 4a04985
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 10 deletions.
41 changes: 31 additions & 10 deletions pkg/evmclient/evmclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/prometheus/client_golang/prometheus"
)

type TxRequest struct {
Expand Down Expand Up @@ -44,37 +45,39 @@ type Interface interface {
CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error)
}

type evmClient struct {
type EvmClient struct {
mtx sync.Mutex
chainID *big.Int
ethClient *ethclient.Client
owner common.Address
signer *ecdsa.PrivateKey
logger *slog.Logger
nonce uint64
metrics *metrics
}

func New(
owner common.Address,
signer *ecdsa.PrivateKey,
ethClient *ethclient.Client,
logger *slog.Logger,
) (Interface, error) {
) (*EvmClient, error) {
chainID, err := ethClient.NetworkID(context.Background())
if err != nil {
return nil, fmt.Errorf("failed to get chain id: %w", err)
}

return &evmClient{
return &EvmClient{
chainID: chainID,
ethClient: ethClient,
owner: owner,
signer: signer,
logger: logger,
metrics: newMetrics(),
}, nil
}

func (c *evmClient) suggestMaxFeeAndTipCap(
func (c *EvmClient) suggestMaxFeeAndTipCap(
ctx context.Context,
gasPrice *big.Int,
) (*big.Int, *big.Int, error) {
Expand All @@ -95,7 +98,7 @@ func (c *evmClient) suggestMaxFeeAndTipCap(
return gasFeeCap, gasTipCap, nil
}

func (c *evmClient) newTx(ctx context.Context, req *TxRequest, nonce uint64) (*types.Transaction, error) {
func (c *EvmClient) newTx(ctx context.Context, req *TxRequest, nonce uint64) (*types.Transaction, error) {
var err error

if req.GasLimit == 0 {
Expand Down Expand Up @@ -128,7 +131,7 @@ func (c *evmClient) newTx(ctx context.Context, req *TxRequest, nonce uint64) (*t
}), nil
}

func (c *evmClient) getNonce(ctx context.Context) (uint64, error) {
func (c *EvmClient) getNonce(ctx context.Context) (uint64, error) {
accountNonce, err := c.ethClient.PendingNonceAt(ctx, c.owner)
if err != nil {
return 0, fmt.Errorf("failed to get nonce: %w", err)
Expand All @@ -152,10 +155,12 @@ func (c *evmClient) getNonce(ctx context.Context) (uint64, error) {
return c.nonce, nil
}

func (c *evmClient) Send(ctx context.Context, tx *TxRequest) (common.Hash, error) {
func (c *EvmClient) Send(ctx context.Context, tx *TxRequest) (common.Hash, error) {
c.mtx.Lock()
defer c.mtx.Unlock()

c.metrics.AttemptedTxCount.Inc()

nonce, err := c.getNonce(ctx)
if err != nil {
return common.Hash{}, fmt.Errorf("failed to get nonce: %w", err)
Expand All @@ -179,6 +184,7 @@ func (c *evmClient) Send(ctx context.Context, tx *TxRequest) (common.Hash, error
return common.Hash{}, err
}

c.metrics.SentTxCount.Inc()
c.nonce++
c.logger.Info("sent txn", "tx", txnString(txnData), "txHash", signedTx.Hash().Hex())

Expand All @@ -199,7 +205,7 @@ func txnString(tx *types.Transaction) string {
)
}

func (c *evmClient) WaitForReceipt(
func (c *EvmClient) WaitForReceipt(
ctx context.Context,
txHash common.Hash,
) (*types.Receipt, error) {
Expand All @@ -209,6 +215,12 @@ func (c *evmClient) WaitForReceipt(
for {
receipt, err := c.ethClient.TransactionReceipt(ctx, txHash)
if err == nil {
switch receipt.Status {
case types.ReceiptStatusSuccessful:
c.metrics.SuccessfulTxCount.Inc()
case types.ReceiptStatusFailed:
c.metrics.FailedTxCount.Inc()
}
c.logger.Info("tx receipt", "txHash", txHash.Hex(), "status", receipt.Status)
return receipt, nil
}
Expand All @@ -228,7 +240,7 @@ func (c *evmClient) WaitForReceipt(
}
}

func (c *evmClient) Call(
func (c *EvmClient) Call(
ctx context.Context,
tx *TxRequest,
) ([]byte, error) {
Expand All @@ -251,16 +263,20 @@ func (c *evmClient) Call(
return result, nil
}

func (c *evmClient) CancelTx(ctx context.Context, txnHash common.Hash) (common.Hash, error) {
func (c *EvmClient) CancelTx(ctx context.Context, txnHash common.Hash) (common.Hash, error) {
c.mtx.Lock()
defer c.mtx.Unlock()

txn, isPending, err := c.ethClient.TransactionByHash(ctx, txnHash)
if err != nil {
if errors.Is(err, ethereum.NotFound) {
c.metrics.NotFoundDuringCancelCount.Inc()
}
return common.Hash{}, fmt.Errorf("failed to get transaction: %w", err)
}

if !isPending {
c.metrics.NotFoundDuringCancelCount.Inc()
return common.Hash{}, ethereum.NotFound
}

Expand Down Expand Up @@ -304,6 +320,11 @@ func (c *evmClient) CancelTx(ctx context.Context, txnHash common.Hash) (common.H
return common.Hash{}, err
}

c.metrics.CancelledTxCount.Inc()
c.logger.Info("sent cancel txn", "txHash", signedTx.Hash().Hex())
return signedTx.Hash(), nil
}

func (e *EvmClient) Metrics() []prometheus.Collector {
return e.metrics.collectors()
}
64 changes: 64 additions & 0 deletions pkg/evmclient/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package evmclient

import "github.com/prometheus/client_golang/prometheus"

const (
defaultMetricsNamespace = "mev_commit"
)

type metrics struct {
AttemptedTxCount prometheus.Counter
SentTxCount prometheus.Counter
SuccessfulTxCount prometheus.Counter
CancelledTxCount prometheus.Counter
FailedTxCount prometheus.Counter
NotFoundDuringCancelCount prometheus.Counter
}

func newMetrics() *metrics {
m := &metrics{
AttemptedTxCount: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: defaultMetricsNamespace,
Name: "attempted_tx_count",
Help: "Number of attempted transactions",
}),
SentTxCount: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: defaultMetricsNamespace,
Name: "sent_tx_count",
Help: "Number of sent transactions",
}),
SuccessfulTxCount: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: defaultMetricsNamespace,
Name: "successful_tx_count",
Help: "Number of successful transactions",
}),
CancelledTxCount: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: defaultMetricsNamespace,
Name: "cancelled_tx_count",
Help: "Number of cancelled transactions",
}),
FailedTxCount: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: defaultMetricsNamespace,
Name: "failed_tx_count",
Help: "Number of failed transactions",
}),
NotFoundDuringCancelCount: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: defaultMetricsNamespace,
Name: "not_found_during_cancel_count",
Help: "Number of transactions not found during cancel",
}),
}

return m
}

func (m *metrics) collectors() []prometheus.Collector {
return []prometheus.Collector{
m.AttemptedTxCount,
m.SentTxCount,
m.SuccessfulTxCount,
m.CancelledTxCount,
m.FailedTxCount,
m.NotFoundDuringCancelCount,
}
}
2 changes: 2 additions & 0 deletions pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ func NewNode(opts *Options) (*Node, error) {
return nil, err
}

srv.MetricsRegistry().MustRegister(evmClient.Metrics()...)

userRegistryContractAddr := common.HexToAddress(opts.UserRegistryContract)

userRegistry := userregistrycontract.New(
Expand Down

0 comments on commit 4a04985

Please sign in to comment.