Skip to content

Commit 47dc924

Browse files
committed
Merge branch '311-aggregator-wait-for-receipt-for-1-minute-if-not-bump-the-fee-v2' into test-aggregator-bump-fee
2 parents 442345e + b1bc71f commit 47dc924

File tree

5 files changed

+88
-36
lines changed

5 files changed

+88
-36
lines changed

core/chainio/avs_writer.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ import (
2121
)
2222

2323
const (
24-
gasBumpPercentage int = 20
24+
// How much to bump every retry (constant)
25+
GasBaseBumpPercentage int = 20
26+
// An extra percentage to bump every retry i*5 (linear)
27+
GasBumpIncrementalBumpPercentage int = 5
28+
// Wait as much as 3 blocks time for the receipt
29+
SendAggregateResponseReceiptTimeout time.Duration = time.Second * 36
2530
)
2631

2732
type AvsWriter struct {
@@ -79,7 +84,10 @@ func NewAvsWriterFromConfig(baseConfig *config.BaseConfig, ecdsaConfig *config.E
7984
// Sends AggregatedResponse and waits for the receipt for three blocks, if not received
8085
// it will try again bumping the last tx gas price based on `CalculateGasPriceBump`
8186
// This process happens indefinitely until the transaction is included.
82-
// Note: If the rpc endpoints fail, the retry will stop, as it will infinitely try
87+
//
88+
// Note: If the rpc endpoints fail, the retry mechanism stops, returning a permanent error.
89+
// This is because retries are infinite and we want to prevent increasing the time between them too much as it is exponential.
90+
// And, if the rpc is down for a good period of time, we might fall into an infinite waiting.
8391
func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMerkleRoot [32]byte, senderAddress [20]byte, nonSignerStakesAndSignature servicemanager.IBLSSignatureCheckerNonSignerStakesAndSignature, onRetry func()) (*types.Receipt, error) {
8492
txOpts := *w.Signer.GetTxOpts()
8593
txOpts.NoSend = true // simulate the transaction
@@ -116,14 +124,13 @@ func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMe
116124
// Retry with fallback
117125
gasPrice, err = w.ClientFallback.SuggestGasPrice(context.Background())
118126
if err != nil {
119-
return nil, fmt.Errorf("transaction simulation failed: %v", err)
127+
return nil, connection.PermanentError{Inner: err}
120128
}
121129
}
122-
txOpts.GasPrice = utils.CalculateGasPriceBumpBasedOnRetry(gasPrice, gasBumpPercentage, i)
130+
txOpts.GasPrice = utils.CalculateGasPriceBumpBasedOnRetry(gasPrice, GasBaseBumpPercentage, GasBumpIncrementalBumpPercentage, i)
123131

124132
w.logger.Infof("Sending ResponseToTask transaction with a gas price of %v", txOpts.GasPrice)
125133
err = w.checkRespondToTaskFeeLimit(tx, txOpts, batchIdentifierHash, senderAddress)
126-
127134
if err != nil {
128135
return nil, connection.PermanentError{Inner: err}
129136
}

core/connection.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ func (e PermanentError) Is(err error) bool {
1919
return ok
2020
}
2121

22-
// Same as Retry only that the functionToRetry can return a value upon correct execution
22+
// Retries a given function in an exponential backoff manner and returns a value upon correct execution.
23+
// It will retry calling the function while it returns a non permanent error, until the max retries.
24+
// If maxTries == 0 then the retry function will run indefinitely until success or until a `PermanentError` is returned.
2325
func RetryWithData[T any](functionToRetry func() (*T, error), minDelay uint64, factor float64, maxTries uint64) (*T, error) {
2426
f := func() (*T, error) {
2527
val, err := functionToRetry()
26-
if perm, ok := err.(PermanentError); err != nil && ok {
28+
if perm, ok := err.(PermanentError); ok && err != nil {
2729
return nil, backoff.Permanent(perm.Inner)
2830
}
2931
return val, err
@@ -46,15 +48,12 @@ func RetryWithData[T any](functionToRetry func() (*T, error), minDelay uint64, f
4648
}
4749

4850
// Retries a given function in an exponential backoff manner.
49-
// It will retry calling the function while it returns an error, until the max retries.
50-
// If maxTries == 0 then the retry function will run indefinitely until success
51-
// from the configuration are reached, or until a `PermanentError` is returned.
52-
// The function to be retried should return `PermanentError` when the condition for stop retrying
53-
// is met.
51+
// It will retry calling the function while it returns a non permanent error, until the max retries.
52+
// If maxTries == 0 then the retry function will run indefinitely.
5453
func Retry(functionToRetry func() error, minDelay uint64, factor float64, maxTries uint64) error {
5554
f := func() error {
5655
err := functionToRetry()
57-
if perm, ok := err.(PermanentError); err != nil && ok {
56+
if perm, ok := err.(PermanentError); ok && err != nil {
5857
return backoff.Permanent(perm.Inner)
5958
}
6059
return err

core/connection_test.go

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,65 @@ func DummyFunction(x uint64) (uint64, error) {
1717
return x, nil
1818
}
1919

20+
// here we run the dummy function with the retry and check:
21+
// - The number of retries checks based on the `n`
22+
// - The returned valued matches based on the `n`
23+
// - The returned err matches based on the `n`
2024
func TestRetryWithData(t *testing.T) {
21-
function := func() (*uint64, error) {
22-
x, err := DummyFunction(43)
23-
return &x, err
25+
retries := -1
26+
testFun := func(n uint64) func() (*uint64, error) {
27+
return func() (*uint64, error) {
28+
retries++
29+
x, err := DummyFunction(n)
30+
return &x, err
31+
}
2432
}
25-
data, err := connection.RetryWithData(function, 1000, 2, 3)
26-
if err != nil {
27-
t.Errorf("Retry error!: %s", err)
28-
} else {
29-
fmt.Printf("DATA: %d\n", data)
33+
data, err := connection.RetryWithData(testFun(uint64(41)), 1000, 2, 3)
34+
if !(retries == 3 && *data == 0 && err != nil) {
35+
t.Error("Incorrect execution when n == 41")
36+
}
37+
//restart
38+
retries = -1
39+
data, err = connection.RetryWithData(testFun(42), 1000, 2, 3)
40+
if !(retries == 0 && data == nil) {
41+
if _, ok := err.(*connection.PermanentError); ok {
42+
t.Error("Incorrect execution when n == 42")
43+
}
44+
}
45+
//restart
46+
retries = -1
47+
data, err = connection.RetryWithData(testFun(43), 1000, 2, 3)
48+
if !(retries == 0 && *data == 43 && err == nil) {
49+
t.Error("Incorrect execution when n == 43")
3050
}
3151
}
3252

53+
// same as above but without checking returned data
3354
func TestRetry(t *testing.T) {
34-
function := func() error {
35-
_, err := DummyFunction(43)
36-
return err
55+
retries := -1
56+
testFun := func(n uint64) func() error {
57+
return func() error {
58+
retries++
59+
_, err := DummyFunction(n)
60+
return err
61+
}
62+
}
63+
err := connection.Retry(testFun(uint64(41)), 1000, 2, 3)
64+
if !(retries == 3 && err != nil) {
65+
t.Error("Incorrect execution when n == 41")
66+
}
67+
//restart
68+
retries = -1
69+
err = connection.Retry(testFun(42), 1000, 2, 3)
70+
if !(retries == 0) {
71+
if _, ok := err.(*connection.PermanentError); ok {
72+
t.Error("Incorrect execution when n == 42")
73+
}
3774
}
38-
err := connection.Retry(function, 1000, 2, 3)
39-
if err != nil {
40-
t.Errorf("Retry error!: %s", err)
75+
//restart
76+
retries = -1
77+
err = connection.Retry(testFun(43), 1000, 2, 3)
78+
if !(retries == 0 && err == nil) {
79+
t.Error("Incorrect execution when n == 43")
4180
}
4281
}

core/utils/eth_client_utils.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@ func WaitForTransactionReceipt(client eth.InstrumentedClient, ctx context.Contex
2525
// if context has timed out, return
2626
if ctx.Err() != nil {
2727
return nil, ctx.Err()
28-
} else {
29-
time.Sleep(sleepTime)
3028
}
29+
time.Sleep(sleepTime)
3130
}
3231
return nil, fmt.Errorf("transaction receipt not found for txHash: %s", txHash.String())
3332
}
@@ -48,13 +47,21 @@ func BytesToQuorumThresholdPercentages(quorumThresholdPercentagesBytes []byte) e
4847
return quorumThresholdPercentages
4948
}
5049

51-
// Very basic algorithm to calculate the gasPrice bump based on the currentGasPrice a constant percentage and the retry number.
52-
// It adds a the percentage to the current gas price and a 5% * i, where i is the iteration number. That is:
53-
func CalculateGasPriceBumpBasedOnRetry(currentGasPrice *big.Int, percentage int, i int) *big.Int {
54-
retryPercentage := new(big.Int).Mul(big.NewInt(5), big.NewInt(int64(i)))
55-
percentageBump := new(big.Int).Add(big.NewInt(int64(percentage)), retryPercentage)
56-
bumpAmount := new(big.Int).Mul(currentGasPrice, percentageBump)
50+
// Simple algorithm to calculate the gasPrice bump based on:
51+
// the currentGasPrice, a base bump percentage, a retry percentage, and the retry count.
52+
// Formula: currentGasPrice + (currentGasPrice * (baseBumpPercentage + retryCount * incrementalRetryPercentage) / 100)
53+
func CalculateGasPriceBumpBasedOnRetry(currentGasPrice *big.Int, baseBumpPercentage int, retryAttemptPercentage int, retryCount int) *big.Int {
54+
// Incremental percentage increase for each retry attempt (i*5%)
55+
incrementalRetryPercentage := new(big.Int).Mul(big.NewInt(int64(retryAttemptPercentage)), big.NewInt(int64(retryCount)))
56+
57+
// Total bump percentage: base bump + incremental retry percentage
58+
totalBumpPercentage := new(big.Int).Add(big.NewInt(int64(baseBumpPercentage)), incrementalRetryPercentage)
59+
60+
// Calculate the bump amount: currentGasPrice * totalBumpPercentage / 100
61+
bumpAmount := new(big.Int).Mul(currentGasPrice, totalBumpPercentage)
5762
bumpAmount = new(big.Int).Div(bumpAmount, big.NewInt(100))
63+
64+
// Final bumped gas price: currentGasPrice + bumpAmount
5865
bumpedGasPrice := new(big.Int).Add(currentGasPrice, bumpAmount)
5966

6067
return bumpedGasPrice

grafana/provisioning/dashboards/aligned/aggregator_batcher.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1425,4 +1425,4 @@
14251425
"uid": "aggregator",
14261426
"version": 15,
14271427
"weekStart": ""
1428-
}
1428+
}

0 commit comments

Comments
 (0)