Skip to content

Commit

Permalink
feat(aggregator): gas price bump percentage limit (#1445)
Browse files Browse the repository at this point in the history
Co-authored-by: Julian Arce <[email protected]>
  • Loading branch information
MarcosNicolau and JuArce authored Nov 22, 2024
1 parent 6887704 commit 8ab0376
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 4 deletions.
1 change: 1 addition & 0 deletions aggregator/pkg/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ func (agg *Aggregator) sendAggregatedResponse(batchIdentifierHash [32]byte, batc
nonSignerStakesAndSignature,
agg.AggregatorConfig.Aggregator.GasBaseBumpPercentage,
agg.AggregatorConfig.Aggregator.GasBumpIncrementalPercentage,
agg.AggregatorConfig.Aggregator.GasBumpPercentageLimit,
agg.AggregatorConfig.Aggregator.TimeToWaitBeforeBump,
onGasPriceBumped,
)
Expand Down
3 changes: 3 additions & 0 deletions config-files/config-aggregator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ aggregator:
gas_base_bump_percentage: 25 # Percentage to overestimate gas price when sending a task
gas_bump_incremental_percentage: 20 # An extra percentage to overestimate in each bump of respond to task. This is additive between tries
# Gas used formula = est_gas_by_node * (gas_base_bump_percentage + gas_bum_incremental_percentage * i) / 100, where i is the iteration number.
gas_bump_percentage_limit: 150 # The max percentage to bump the gas price.
# The Gas formula is percentage (gas_base_bump_percentage + gas_bump_incremental_percentage * i) / 100) is checked against this value
# If it is higher, it will default to `gas_bump_percentage_limit`
time_to_wait_before_bump: 72s # The time to wait for the receipt when responding to task. Suggested value 72 seconds (6 blocks)

## Operator Configurations
Expand Down
5 changes: 3 additions & 2 deletions core/chainio/avs_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func NewAvsWriterFromConfig(baseConfig *config.BaseConfig, ecdsaConfig *config.E
// - If no receipt is found, but the batch state indicates the response has already been processed, it exits
// without an error (returning `nil, nil`).
// - An error if the process encounters a fatal issue (e.g., permanent failure in verifying balances or state).
func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMerkleRoot [32]byte, senderAddress [20]byte, nonSignerStakesAndSignature servicemanager.IBLSSignatureCheckerNonSignerStakesAndSignature, gasBumpPercentage uint, gasBumpIncrementalPercentage uint, timeToWaitBeforeBump time.Duration, onGasPriceBumped func(*big.Int)) (*types.Receipt, error) {
func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMerkleRoot [32]byte, senderAddress [20]byte, nonSignerStakesAndSignature servicemanager.IBLSSignatureCheckerNonSignerStakesAndSignature, gasBumpPercentage uint, gasBumpIncrementalPercentage uint, gasBumpPercentageLimit uint, timeToWaitBeforeBump time.Duration, onGasPriceBumped func(*big.Int)) (*types.Receipt, error) {
txOpts := *w.Signer.GetTxOpts()
txOpts.NoSend = true // simulate the transaction
simTx, err := w.RespondToTaskV2Retryable(&txOpts, batchMerkleRoot, senderAddress, nonSignerStakesAndSignature, retry.SendToChainRetryParams())
Expand All @@ -116,11 +116,12 @@ func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMe
previousTxGasPrice := txOpts.GasPrice
// in order to avoid replacement transaction underpriced
// the bumped gas price has to be at least 10% higher than the previous one.
minimumGasPriceBump := utils.CalculateGasPriceBumpBasedOnRetry(previousTxGasPrice, 10, 0, 0)
minimumGasPriceBump := utils.CalculateGasPriceBumpBasedOnRetry(previousTxGasPrice, 10, 0, gasBumpPercentageLimit, 0)
suggestedBumpedGasPrice := utils.CalculateGasPriceBumpBasedOnRetry(
gasPrice,
gasBumpPercentage,
gasBumpIncrementalPercentage,
gasBumpPercentageLimit,
i,
)
// check the new gas price is sufficiently bumped.
Expand Down
3 changes: 3 additions & 0 deletions core/config/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type AggregatorConfig struct {
BlsServiceTaskTimeout time.Duration
GasBaseBumpPercentage uint
GasBumpIncrementalPercentage uint
GasBumpPercentageLimit uint
TimeToWaitBeforeBump time.Duration
}
}
Expand All @@ -45,6 +46,7 @@ type AggregatorConfigFromYaml struct {
BlsServiceTaskTimeout time.Duration `yaml:"bls_service_task_timeout"`
GasBaseBumpPercentage uint `yaml:"gas_base_bump_percentage"`
GasBumpIncrementalPercentage uint `yaml:"gas_bump_incremental_percentage"`
GasBumpPercentageLimit uint `yaml:"gas_bump_percentage_limit"`
TimeToWaitBeforeBump time.Duration `yaml:"time_to_wait_before_bump"`
} `yaml:"aggregator"`
}
Expand Down Expand Up @@ -93,6 +95,7 @@ func NewAggregatorConfig(configFilePath string) *AggregatorConfig {
BlsServiceTaskTimeout time.Duration
GasBaseBumpPercentage uint
GasBumpIncrementalPercentage uint
GasBumpPercentageLimit uint
TimeToWaitBeforeBump time.Duration
}(aggregatorConfigFromYaml.Aggregator),
}
Expand Down
8 changes: 7 additions & 1 deletion core/utils/eth_client_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,19 @@ func WeiToEth(wei *big.Int) float64 {
// Simple algorithm to calculate the gasPrice bump based on:
// the currentGasPrice, a base bump percentage, a retry percentage, and the retry count.
// Formula: currentGasPrice + (currentGasPrice * (baseBumpPercentage + retryCount * incrementalRetryPercentage) / 100)
func CalculateGasPriceBumpBasedOnRetry(currentGasPrice *big.Int, baseBumpPercentage uint, retryAttemptPercentage uint, retryCount int) *big.Int {
func CalculateGasPriceBumpBasedOnRetry(currentGasPrice *big.Int, baseBumpPercentage uint, retryAttemptPercentage uint, bumpPercentageLimit uint, retryCount int) *big.Int {
// Incremental percentage increase for each retry attempt (i*retryAttemptPercentage)
incrementalRetryPercentage := new(big.Int).Mul(big.NewInt(int64(retryAttemptPercentage)), big.NewInt(int64(retryCount)))

// Total bump percentage: base bump + incremental retry percentage
totalBumpPercentage := new(big.Int).Add(big.NewInt(int64(baseBumpPercentage)), incrementalRetryPercentage)

// Make sure the percentage to bump isn't higher than the limit
bumpPercentageLimitAsBigInt := big.NewInt(int64(bumpPercentageLimit))
if totalBumpPercentage.Cmp(bumpPercentageLimitAsBigInt) > 0 {
totalBumpPercentage = bumpPercentageLimitAsBigInt
}

// Calculate the bump amount: currentGasPrice * totalBumpPercentage / 100
bumpAmount := new(big.Int).Mul(currentGasPrice, totalBumpPercentage)
bumpAmount = new(big.Int).Div(bumpAmount, big.NewInt(100))
Expand Down
30 changes: 29 additions & 1 deletion core/utils/eth_client_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,40 @@ func TestCalculateGasPriceBumpBasedOnRetry(t *testing.T) {

for i := 0; i < len(gasPrices); i++ {
currentGasPrice := gasPrices[i]
bumpedGasPrice := utils.CalculateGasPriceBumpBasedOnRetry(currentGasPrice, baseBumpPercentage, incrementalRetryPercentage, i)
bumpedGasPrice := utils.CalculateGasPriceBumpBasedOnRetry(currentGasPrice, baseBumpPercentage, incrementalRetryPercentage, 100, i)
expectedGasPrice := expectedBumpedGasPrices[i]

if bumpedGasPrice.Cmp(expectedGasPrice) != 0 {
t.Errorf("Bumped gas price does not match expected gas price, expected value %v, got: %v", expectedGasPrice, bumpedGasPrice)
}
}
}

func TestCalculateGasPriceBumpBasedOnRetryPercentageLimit(t *testing.T) {
baseBumpPercentage := uint(20)
incrementalRetryPercentage := uint(5)

gasPrices := [5]*big.Int{
big.NewInt(3000000000),
big.NewInt(3000000000),
big.NewInt(4000000000),
big.NewInt(4000000000),
big.NewInt(5000000000)}

expectedBumpedGasPrices := [5]*big.Int{
big.NewInt(3600000000),
big.NewInt(3750000000),
big.NewInt(5200000000),
big.NewInt(5200000000),
big.NewInt(6500000000)}

for i := 0; i < len(gasPrices); i++ {
currentGasPrice := gasPrices[i]
bumpedGasPrice := utils.CalculateGasPriceBumpBasedOnRetry(currentGasPrice, baseBumpPercentage, incrementalRetryPercentage, 30, i)
expectedGasPrice := expectedBumpedGasPrices[i]

if bumpedGasPrice.Cmp(expectedGasPrice) != 0 {
t.Errorf("Bumped gas price does not match expected gas price, expected value %v, got: %v", expectedGasPrice, bumpedGasPrice)
}
}
}

0 comments on commit 8ab0376

Please sign in to comment.