Skip to content

Commit

Permalink
feat(monitor/xfeemngr): tiered buffers (#2492)
Browse files Browse the repository at this point in the history
Use tiers instead of offset / tolerance.

issue: none
  • Loading branch information
kevinhalliday authored Nov 15, 2024
1 parent d73b69a commit fc989e4
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 107 deletions.
10 changes: 2 additions & 8 deletions lib/contracts/feeoraclev1/feeparams.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/omni-network/omni/lib/evmchain"
"github.com/omni-network/omni/lib/log"
"github.com/omni-network/omni/lib/tokens"
"github.com/omni-network/omni/monitor/xfeemngr"
"github.com/omni-network/omni/monitor/xfeemngr/gasprice"

"github.com/ethereum/go-ethereum/params"
)
Expand Down Expand Up @@ -86,7 +86,7 @@ func destFeeParams(ctx context.Context, srcChain evmchain.Metadata, destChain ev
ChainId: destChain.ChainID,
PostsTo: postsTo,
ToNativeRate: rateToNumerator(toNativeRate),
GasPrice: withGasPriceOffset(gasPrice),
GasPrice: new(big.Int).SetUint64(gasprice.Tier(gasPrice.Uint64())),
}, nil
}

Expand Down Expand Up @@ -132,12 +132,6 @@ func rateToNumerator(r float64) *big.Int {
return norm
}

// withGasPriceOffset returns the gas price with an added xfeemngr.GasPriceShield pct offset.
func withGasPriceOffset(gasPrice *big.Int) *big.Int {
gasPriceF := float64(gasPrice.Uint64())
return new(big.Int).SetUint64(uint64(gasPriceF + (xfeemngr.GasPriceBufferOffset * gasPriceF)))
}

func contains(params []bindings.IFeeOracleV1ChainFeeParams, chainID uint64) bool {
for _, param := range params {
if param.ChainId == chainID {
Expand Down
12 changes: 3 additions & 9 deletions lib/contracts/feeoraclev2/feeparams.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/omni-network/omni/lib/evmchain"
"github.com/omni-network/omni/lib/log"
"github.com/omni-network/omni/lib/tokens"
"github.com/omni-network/omni/monitor/xfeemngr"
"github.com/omni-network/omni/monitor/xfeemngr/gasprice"

"github.com/ethereum/go-ethereum/params"
)
Expand Down Expand Up @@ -78,8 +78,8 @@ func destFeeParams(ctx context.Context, srcChain evmchain.Metadata, destChain ev

return bindings.IFeeOracleV2FeeParams{
ChainId: destChain.ChainID,
ExecGasPrice: withGasPriceOffset(execGasPrice.Uint64()),
DataGasPrice: withGasPriceOffset(dataGasPrice.Uint64()),
ExecGasPrice: gasprice.Tier(execGasPrice.Uint64()),
DataGasPrice: gasprice.Tier(dataGasPrice.Uint64()),
ToNativeRate: rateToNumerator(toNativeRate),
}, nil
}
Expand Down Expand Up @@ -125,9 +125,3 @@ func rateToNumerator(r float64) uint64 {

return norm
}

// withGasPriceOffset returns the gas price with an added xfeemngr.GasPriceShield pct offset.
func withGasPriceOffset(gasPrice uint64) uint64 {
gasPriceF := float64(gasPrice)
return uint64(gasPriceF + (xfeemngr.GasPriceBufferOffset * gasPriceF))
}
70 changes: 11 additions & 59 deletions monitor/xfeemngr/gasprice/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"sync"

"github.com/omni-network/omni/lib/errors"
"github.com/omni-network/omni/lib/evmchain"
"github.com/omni-network/omni/lib/log"
"github.com/omni-network/omni/monitor/xfeemngr/ticker"
Expand All @@ -23,15 +22,6 @@ type buffer struct {

// map chainID to provider
pricers map[uint64]ethereum.GasPricer

// pct to offset live -> buffer
// ex. with offset 0.5, live=100, buffered=150 (50% higher)
// if live increases above 150, offset buffer will update to 225 (50% higher)
offset float64

// pct below the buffer the live value be to trigger a buffer decrease
// ex. with tolerance 0.5, buffered=150, live must be below 75 to decrease buffer
tolerance float64
}

type Buffer interface {
Expand All @@ -42,31 +32,13 @@ type Buffer interface {
var _ Buffer = (*buffer)(nil)

// NewBuffer creates a new gas price buffer.
//
// A gas price buffer maintains a buffered view of gas prices for multiple
// chains. Buffered gas prices exceed live prices by an offset. They decrease
// if live prices fall below tolerance.
func NewBuffer(pricers map[uint64]ethereum.GasPricer, offset, tolerance float64, ticker ticker.Ticker) (Buffer, error) {
if offset < 0 {
return nil, errors.New("offset must be >= 0")
}

if tolerance < 0 {
return nil, errors.New("tolerance must be >= 0")
}

if (1+offset)*(1-tolerance) >= 1 {
return nil, errors.New("applying offset would trigger tolerance")
}

func NewBuffer(pricers map[uint64]ethereum.GasPricer, ticker ticker.Ticker) (Buffer, error) {
return &buffer{
mu: sync.RWMutex{},
once: sync.Once{},
buffer: make(map[uint64]uint64),
pricers: pricers,
offset: offset,
tolerance: tolerance,
ticker: ticker,
mu: sync.RWMutex{},
once: sync.Once{},
buffer: make(map[uint64]uint64),
pricers: pricers,
ticker: ticker,
}, nil
}

Expand Down Expand Up @@ -112,35 +84,15 @@ func (b *buffer) streamOne(ctx context.Context, chainID uint64) {
live := liveBn.Uint64()
guageLive(chainID, live)

tiered := Tier(live)
buffed := b.GasPrice(chainID)
tooLow := live > buffed
tooHigh := live < uint64(float64(buffed)*(1-b.tolerance))

log.Debug(ctx, "Checking buffer",
"live", live,
"buffered", buffed,
"too_low", tooLow,
"too_high", tooHigh,
"offset", b.offset,
"tolerance", b.tolerance,
)

// do nothing
if !tooLow && !tooHigh {
log.Debug(ctx, "No update needed")

if tiered == buffed {
return
}

log.Info(ctx, "Updating buffer",
"live", live,
"buffered", buffed,
"too_low", tooLow,
"too_high", tooHigh,
)

corrected := uint64(float64(live) * (1 + b.offset))
b.setPrice(chainID, corrected)
guageBuffered(chainID, corrected)
b.setPrice(chainID, tiered)
guageBuffered(chainID, tiered)
}

tick.Go(ctx, callback)
Expand Down
31 changes: 8 additions & 23 deletions monitor/xfeemngr/gasprice/buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,10 @@ func TestBufferStream(t *testing.T) {
// mock gas pricers per chain
mocks := makeMockPricers(initials)

offset := 0.3 // 30% offset
tolerance := 0.5 // 50% tolerance
tick := ticker.NewMock()
ctx := context.Background()

withOffset := func(price uint64) uint64 {
return uint64(float64(price) * (1 + offset))
}

atTolerance := func(price uint64) uint64 {
return uint64(float64(price) * (1 - tolerance))
}

b, err := gasprice.NewBuffer(toEthGasPricers(mocks), offset, tolerance, tick)
b, err := gasprice.NewBuffer(toEthGasPricers(mocks), tick)
require.NoError(t, err)

b.Stream(ctx)
Expand All @@ -47,29 +37,24 @@ func TestBufferStream(t *testing.T) {

// buffered price should be initial live + offset
for chainID, price := range initials {
require.Equal(t, withOffset(price), b.GasPrice(chainID), "initial")
require.Equal(t, gasprice.Tier(price), b.GasPrice(chainID), "initial")
}

// 10 steps
buffed := make(map[uint64]uint64)
live := make(map[uint64]uint64)
for i := 0; i < 10; i++ {
for chainID, mock := range mocks {
buffed[chainID] = b.GasPrice(chainID)
mock.SetPrice(randGasPrice())
live[chainID] = randGasPrice()
mock.SetPrice(live[chainID])
}

tick.Tick()

// for each step, we check if buffer properly updates (or doesn't)
for chainID, mock := range mocks {
tooLow := mock.Price() > buffed[chainID]
tooHigh := mock.Price() < atTolerance(buffed[chainID])

if tooHigh || tooLow {
require.Equal(t, withOffset(mock.Price()), b.GasPrice(chainID), 0.01, "should change")
} else {
require.Equal(t, buffed[chainID], b.GasPrice(chainID), 0.01, "should not change")
}
tier := gasprice.Tier(mock.Price())
require.GreaterOrEqual(t, tier, live[chainID], "tier greater than live")
require.Equal(t, tier, b.GasPrice(chainID), "buffer equal to tier")
}
}
}
Expand Down
32 changes: 32 additions & 0 deletions monitor/xfeemngr/gasprice/tiers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package gasprice

// buffer will be the lowest tier that is higher than the live gas price.
var tiers = []uint64{
gwei(0.001),
gwei(0.1),
gwei(1),
gwei(5),
gwei(10),
gwei(25),
gwei(50),
gwei(100),
gwei(200),
}

func Tiers() []uint64 {
return tiers
}

func Tier(live uint64) uint64 {
for _, p := range tiers {
if p > live {
return p
}
}

return tiers[len(tiers)-1]
}

func gwei(p float64) uint64 {
return uint64(p * 1e9)
}
8 changes: 0 additions & 8 deletions monitor/xfeemngr/xfeemngr.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ const (
// Check live token prices every 30 seconds.
tokenPriceBufferSyncInterval = 30 * time.Second

// Buffer on-chain gas price by 50% of live price.
GasPriceBufferOffset = 0.5

// Only reduce on-chain gas price if live price is 50% of on-chain price.
gasPriceBufferTolerance = 0.5

// Check live gas prices every 30 seconds.
gasPriceBufferSyncInterval = 30 * time.Second

Expand Down Expand Up @@ -86,8 +80,6 @@ func Start(ctx context.Context, network netconf.Network, cfg Config, privKeyPath

gprice, err := gasprice.NewBuffer(
makeGasPricers(ethClients),
GasPriceBufferOffset,
gasPriceBufferTolerance,
ticker.New(gasPriceBufferSyncInterval))
if err != nil {
return errors.Wrap(err, "new gas price buffer")
Expand Down

0 comments on commit fc989e4

Please sign in to comment.