use network gas

This commit is contained in:
Felipe Andrade 2023-09-06 15:14:26 -07:00
parent 9c56cde783
commit 51dc1f0e84
3 changed files with 112 additions and 20 deletions

@ -2,6 +2,7 @@ package clients
import ( import (
"context" "context"
"math/big"
"time" "time"
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics" "github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
@ -79,6 +80,39 @@ func (i *InstrumentedEthClient) SendTransaction(ctx context.Context, tx *types.T
return err return err
} }
func (i *InstrumentedEthClient) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
start := time.Now()
gas, err := i.c.EstimateGas(ctx, msg)
if err != nil {
metrics.RecordErrorDetails(i.providerName, "ethclient.EstimateGas", err)
return 0, err
}
metrics.RecordRPCLatency(i.providerName, "ethclient", "EstimateGas", time.Since(start))
return gas, err
}
func (i *InstrumentedEthClient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
start := time.Now()
gasTipCap, err := i.c.SuggestGasTipCap(ctx)
if err != nil {
metrics.RecordErrorDetails(i.providerName, "ethclient.SuggestGasTipCap", err)
return nil, err
}
metrics.RecordRPCLatency(i.providerName, "ethclient", "SuggestGasTipCap", time.Since(start))
return gasTipCap, err
}
func (i *InstrumentedEthClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
start := time.Now()
header, err := i.c.HeaderByNumber(ctx, number)
if err != nil {
metrics.RecordErrorDetails(i.providerName, "ethclient.HeaderByNumber", err)
return nil, err
}
metrics.RecordRPCLatency(i.providerName, "ethclient", "HeaderByNumber", time.Since(start))
return header, err
}
func (i *InstrumentedEthClient) ignorableErrors(err error) bool { func (i *InstrumentedEthClient) ignorableErrors(err error) bool {
msg := err.Error() msg := err.Error()
// we dont use errors.Is because eth client actually uses errors.New, // we dont use errors.Is because eth client actually uses errors.New,

@ -2,6 +2,7 @@ package provider
import ( import (
"context" "context"
"math/big"
"time" "time"
"github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics" "github.com/ethereum-optimism/optimism/op-ufm/pkg/metrics"
@ -21,7 +22,7 @@ import (
// RoundTrip send a new transaction to measure round trip latency // RoundTrip send a new transaction to measure round trip latency
func (p *Provider) RoundTrip(ctx context.Context) { func (p *Provider) RoundTrip(ctx context.Context) {
log.Debug("roundTripLatency", log.Debug("RoundTrip",
"provider", p.name) "provider", p.name)
client, err := iclients.Dial(p.name, p.config.URL) client, err := iclients.Dial(p.name, p.config.URL)
@ -40,8 +41,9 @@ func (p *Provider) RoundTrip(ctx context.Context) {
// used for timeout // used for timeout
firstAttemptAt := time.Now() firstAttemptAt := time.Now()
// used for actual round trip time (disregard retry time) // used for actual round trip time (disregard retry time)
roundTripStartedAt := time.Now() var roundTripStartedAt time.Time
for { for {
// sleep until we get a clear to send // sleep until we get a clear to send
for { for {
coolDown := time.Duration(p.config.SendTransactionCoolDown) - time.Since(p.txPool.LastSend) coolDown := time.Duration(p.config.SendTransactionCoolDown) - time.Since(p.txPool.LastSend)
@ -52,17 +54,16 @@ func (p *Provider) RoundTrip(ctx context.Context) {
} }
} }
nonce, err = client.PendingNonceAt(ctx, p.walletConfig.Address) tx, err := p.createTx(ctx, client, nonce)
nonce = tx.Nonce()
if err != nil { if err != nil {
log.Error("cant get nounce", log.Error("cant create tx",
"provider", p.name, "provider", p.name,
"nonce", nonce,
"err", err) "err", err)
return return
} }
tx := p.createTx(nonce)
txHash = tx.Hash()
signedTx, err := p.sign(ctx, tx) signedTx, err := p.sign(ctx, tx)
if err != nil { if err != nil {
log.Error("cant sign tx", log.Error("cant sign tx",
@ -90,15 +91,13 @@ func (p *Provider) RoundTrip(ctx context.Context) {
metrics.RecordErrorDetails(p.name, "ethclient.SendTransaction", err) metrics.RecordErrorDetails(p.name, "ethclient.SendTransaction", err)
return return
} }
log.Warn("tx already known, incrementing nonce and trying again", log.Warn("tx already known, incrementing nonce and trying again",
"provider", p.name, "provider", p.name,
"nonce", nonce) "nonce", nonce)
time.Sleep(time.Duration(p.config.SendTransactionRetryInterval)) time.Sleep(time.Duration(p.config.SendTransactionRetryInterval))
p.txPool.M.Lock() nonce++
p.txPool.Nonce++
nonce = p.txPool.Nonce
p.txPool.M.Unlock()
attempt++ attempt++
if attempt%10 == 0 { if attempt%10 == 0 {
log.Debug("retrying send transaction...", log.Debug("retrying send transaction...",
@ -184,20 +183,80 @@ func (p *Provider) RoundTrip(ctx context.Context) {
"gasUsed", receipt.GasUsed) "gasUsed", receipt.GasUsed)
} }
func (p *Provider) createTx(nonce uint64) *types.Transaction { func (p *Provider) createTx(ctx context.Context, client *iclients.InstrumentedEthClient, nonce uint64) (*types.Transaction, error) {
toAddress := common.HexToAddress(p.walletConfig.Address) var err error
if nonce == 0 {
nonce, err = client.PendingNonceAt(ctx, p.walletConfig.Address)
if err != nil {
log.Error("cant get nounce",
"provider", p.name,
"nonce", nonce,
"err", err)
return nil, err
}
}
gasTipCap, err := client.SuggestGasTipCap(ctx)
if err != nil {
log.Error("cant get gas tip cap",
"provider", p.name,
"err", err)
return nil, err
}
gasTipCap = new(big.Int).Mul(gasTipCap, big.NewInt(110))
gasTipCap = new(big.Int).Div(gasTipCap, big.NewInt(100))
head, err := client.HeaderByNumber(ctx, nil)
if err != nil {
log.Error("cant get base fee from head",
"provider", p.name,
"err", err)
return nil, err
}
baseFee := head.BaseFee
gasFeeCap := new(big.Int).Add(
gasTipCap,
new(big.Int).Mul(baseFee, big.NewInt(2)))
addr := common.HexToAddress(p.walletConfig.Address)
var data []byte var data []byte
tx := types.NewTx(&types.DynamicFeeTx{ dynamicTx := &types.DynamicFeeTx{
ChainID: &p.walletConfig.ChainID, ChainID: &p.walletConfig.ChainID,
Nonce: nonce, Nonce: nonce,
GasFeeCap: &p.walletConfig.GasFeeCap, GasFeeCap: gasFeeCap,
GasTipCap: &p.walletConfig.GasTipCap, GasTipCap: gasTipCap,
Gas: p.walletConfig.GasLimit, To: &addr,
To: &toAddress,
Value: &p.walletConfig.TxValue, Value: &p.walletConfig.TxValue,
Data: data, Data: data,
}
gas, err := client.EstimateGas(ctx, ethereum.CallMsg{
From: addr,
To: &addr,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
Data: dynamicTx.Data,
Value: dynamicTx.Value,
}) })
return tx if err != nil {
log.Error("cant estimate gas",
"provider", p.name,
"err", err)
return nil, err
}
dynamicTx.Gas = gas
tx := types.NewTx(dynamicTx)
log.Debug("tx created",
"provider", p.name,
"nonce", nonce,
"gas", dynamicTx.Gas,
"gasTipCap", dynamicTx.GasTipCap,
"gasFeeCap", dynamicTx.GasFeeCap,
)
return tx, nil
} }
func (p *Provider) sign(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) { func (p *Provider) sign(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) {

@ -15,7 +15,6 @@ type NetworkTransactionPool struct {
M sync.Mutex M sync.Mutex
Transactions map[string]*TransactionState Transactions map[string]*TransactionState
Expected int Expected int
Nonce uint64
// Last time a transaction was sent // Last time a transaction was sent
LastSend time.Time LastSend time.Time