55 "encoding/hex"
66 "fmt"
77 "github.com/Layr-Labs/eigensdk-go/chainio/clients/wallet"
8- "github.com/Layr-Labs/eigensdk-go/chainio/txmgr"
8+ "github.com/Layr-Labs/eigensdk-go/chainio/txmgr/geometric "
99 "math/big"
1010 "time"
1111
@@ -27,8 +27,8 @@ type AvsWriter struct {
2727 * avsregistry.ChainWriter
2828 AvsContractBindings * AvsServiceBindings
2929 logger logging.Logger
30- TxManager txmgr. SimpleTxManager
31- TxManagerFallback txmgr. SimpleTxManager
30+ TxManager geometric. GeometricTxManager
31+ TxManagerFallback geometric. GeometricTxManager
3232 Client eth.InstrumentedClient
3333 ClientFallback eth.InstrumentedClient
3434 metrics * metrics.Metrics
@@ -46,29 +46,70 @@ func NewAvsWriterFromConfig(baseConfig *config.BaseConfig, ecdsaConfig *config.E
4646 ServiceManagerAddress : baseConfig .AlignedLayerDeploymentConfig .AlignedLayerServiceManagerAddr .String (),
4747 }
4848
49- clients , err := clients .BuildAll (buildAllConfig , ecdsaConfig .PrivateKey , baseConfig .Logger )
50-
49+ clients , err := clients .BuildAll (
50+ buildAllConfig ,
51+ ecdsaConfig .PrivateKey ,
52+ baseConfig .Logger ,
53+ )
5154 if err != nil {
5255 baseConfig .Logger .Error ("Cannot build signer config" , "err" , err )
5356 return nil , err
5457 }
5558
56- avsServiceBindings , err := NewAvsServiceBindings (baseConfig .AlignedLayerDeploymentConfig .AlignedLayerServiceManagerAddr , baseConfig .AlignedLayerDeploymentConfig .AlignedLayerOperatorStateRetrieverAddr , baseConfig .EthRpcClient , baseConfig .EthRpcClientFallback , baseConfig .Logger )
57-
59+ avsServiceBindings , err := NewAvsServiceBindings (
60+ baseConfig .AlignedLayerDeploymentConfig .AlignedLayerServiceManagerAddr ,
61+ baseConfig .AlignedLayerDeploymentConfig .AlignedLayerOperatorStateRetrieverAddr ,
62+ baseConfig .EthRpcClient ,
63+ baseConfig .EthRpcClientFallback ,
64+ baseConfig .Logger ,
65+ )
5866 if err != nil {
5967 baseConfig .Logger .Error ("Cannot create avs service bindings" , "err" , err )
6068 return nil , err
6169 }
6270
63- privateKeyWallet , err := wallet .NewPrivateKeyWallet (& baseConfig .EthRpcClient , ecdsaConfig .SignerFn , ecdsaConfig .Address , baseConfig .Logger )
71+ privateKeyWallet , err := wallet .NewPrivateKeyWallet (
72+ & baseConfig .EthRpcClient ,
73+ ecdsaConfig .SignerFn ,
74+ ecdsaConfig .Address ,
75+ baseConfig .Logger ,
76+ )
6477 if err != nil {
6578 baseConfig .Logger .Error ("Cannot create private key wallet" , "err" , err )
6679 return nil , err
6780 }
6881
69- txManager := txmgr .NewSimpleTxManager (privateKeyWallet , & baseConfig .EthRpcClient , baseConfig .Logger , ecdsaConfig .Address )
82+ privateKeyWalletFallback , err := wallet .NewPrivateKeyWallet (
83+ & baseConfig .EthRpcClientFallback ,
84+ ecdsaConfig .SignerFn ,
85+ ecdsaConfig .Address ,
86+ baseConfig .Logger ,
87+ )
88+ if err != nil {
89+ baseConfig .Logger .Error ("Cannot create private key wallet" , "err" , err )
90+ return nil , err
91+ }
7092
71- txManagerFallback := txmgr .NewSimpleTxManager (privateKeyWallet , & baseConfig .EthRpcClientFallback , baseConfig .Logger , ecdsaConfig .Address )
93+ geometricTxnManagerParams := geometric.GeometricTxnManagerParams {}
94+
95+ //txManager := txmgr.NewSimpleTxManager(privateKeyWallet, &baseConfig.EthRpcClient, baseConfig.Logger, ecdsaConfig.Address)
96+ //
97+ //txManagerFallback := txmgr.NewSimpleTxManager(privateKeyWallet, &baseConfig.EthRpcClientFallback, baseConfig.Logger, ecdsaConfig.Address)
98+ txManager := geometric .NewGeometricTxnManager (
99+ & baseConfig .EthRpcClient ,
100+ privateKeyWallet ,
101+ baseConfig .Logger ,
102+ geometric .NewNoopMetrics (), // TODO: Set a correct metrics instance
103+ geometricTxnManagerParams ,
104+ )
105+
106+ txManagerFallback := geometric .NewGeometricTxnManager (
107+ & baseConfig .EthRpcClientFallback ,
108+ privateKeyWalletFallback ,
109+ baseConfig .Logger ,
110+ geometric .NewNoopMetrics (), // TODO: Set a correct metrics instance
111+ geometricTxnManagerParams ,
112+ )
72113
73114 chainWriter := clients .AvsRegistryChainWriter
74115
@@ -99,122 +140,145 @@ func NewAvsWriterFromConfig(baseConfig *config.BaseConfig, ecdsaConfig *config.E
99140// - An error if the process encounters a fatal issue (e.g., permanent failure in verifying balances or state).
100141func (w * AvsWriter ) SendAggregatedResponse (batchIdentifierHash [32 ]byte , batchMerkleRoot [32 ]byte , senderAddress [20 ]byte , nonSignerStakesAndSignature servicemanager.IBLSSignatureCheckerNonSignerStakesAndSignature , gasBumpPercentage uint , gasBumpIncrementalPercentage uint , gasBumpPercentageLimit uint , timeToWaitBeforeBump time.Duration , metrics * metrics.Metrics , onSetGasPrice func (* big.Int )) (* types.Receipt , error ) {
101142 txOpts , err := w .TxManager .GetNoSendTxOpts ()
102- txOpts .NoSend = true // simulate the transaction
103- simTx , err := w .RespondToTaskV2Retryable (txOpts , batchMerkleRoot , senderAddress , nonSignerStakesAndSignature , retry .SendToChainRetryParams ())
104143 if err != nil {
105- w .logger .Errorf ("Failed to simulate transaction: %v" , err )
144+ w .logger .Errorf ("Failed to get transaction options : %v" , err )
106145 return nil , err
107146 }
108- w .logger .Infof ("Simulated transaction: %v" , simTx .Hash ().Hex ())
109-
110- // Set the nonce, as we might have to replace the transaction with a higher gas price
111- txNonce := big .NewInt (int64 (simTx .Nonce ()))
112- txOpts .Nonce = txNonce
113- txOpts .GasPrice = nil
114- txOpts .NoSend = false
115- i := 0
116-
117- var sentTxs []* types.Transaction
118147
119148 batchMerkleRootHashString := hex .EncodeToString (batchMerkleRoot [:])
120149
121- respondToTaskV2Func := func () (* types.Receipt , error ) {
122- gasPrice , err := utils .GetGasPriceRetryable (w .Client , w .ClientFallback , retry .NetworkRetryParams ())
123- if err != nil {
124- return nil , err
125- }
126-
127- // if txOpts.GasPrice wasn't previously set use the fetched gasPrice
128- // this should happen on the first iteration only
129- var previousTxGasPrice * big.Int
130- if txOpts .GasPrice == nil {
131- previousTxGasPrice = gasPrice
132- } else {
133- previousTxGasPrice = txOpts .GasPrice
134- }
135-
136- // in order to avoid replacement transaction underpriced
137- // the bumped gas price has to be at least 10% higher than the previous one.
138- minimumGasPriceBump := utils .CalculateGasPriceBumpBasedOnRetry (previousTxGasPrice , 10 , 0 , gasBumpPercentageLimit , 0 )
139- suggestedBumpedGasPrice := utils .CalculateGasPriceBumpBasedOnRetry (
140- gasPrice ,
141- gasBumpPercentage ,
142- gasBumpIncrementalPercentage ,
143- gasBumpPercentageLimit ,
144- i ,
145- )
146- // check the new gas price is sufficiently bumped.
147- // if the suggested bump does not meet the minimum threshold, use a fallback calculation to slightly increment the previous gas price.
148- if suggestedBumpedGasPrice .Cmp (minimumGasPriceBump ) > 0 {
149- txOpts .GasPrice = suggestedBumpedGasPrice
150- } else {
151- txOpts .GasPrice = minimumGasPriceBump
152- }
153-
154- onSetGasPrice (txOpts .GasPrice )
155-
156- if i > 0 {
157- w .logger .Infof ("Trying to get old sent transaction receipt before sending a new transaction" , "merkle root" , batchMerkleRootHashString )
158- for _ , tx := range sentTxs {
159- receipt , _ := w .Client .TransactionReceipt (context .Background (), tx .Hash ())
160- if receipt == nil {
161- receipt , _ = w .ClientFallback .TransactionReceipt (context .Background (), tx .Hash ())
162- if receipt != nil {
163- w .updateAggregatorGasCostMetrics (receipt , batchIdentifierHash )
164- return receipt , nil
165- }
166- }
167- }
168- w .logger .Infof ("Receipts for old transactions not found, will check if the batch state has been responded" , "merkle root" , batchMerkleRootHashString )
169- batchState , _ := w .BatchesStateRetryable (& bind.CallOpts {}, batchIdentifierHash , retry .NetworkRetryParams ())
170- if batchState .Responded {
171- w .logger .Infof ("Batch state has been already responded" , "merkle root" , batchMerkleRootHashString )
172- return nil , nil
173- }
174- w .logger .Infof ("Batch state has not been responded yet, will send a new tx" , "merkle root" , batchMerkleRootHashString )
175-
176- metrics .IncBumpedGasPriceForAggregatedResponse ()
177- }
178-
179- // We compare both Aggregator funds and Batcher balance in Aligned against respondToTaskFeeLimit
180- // Both are required to have some balance, more details inside the function
181- err = w .checkAggAndBatcherHaveEnoughBalance (simTx , * txOpts , batchIdentifierHash , senderAddress )
182- if err != nil {
183- w .logger .Errorf ("Permanent error when checking aggregator and batcher balances, err %v" , err , "merkle root" , batchMerkleRootHashString )
184- return nil , retry.PermanentError {Inner : err }
185- }
186-
187- w .logger .Infof ("Sending RespondToTask transaction with a gas price of %v" , txOpts .GasPrice , "merkle root" , batchMerkleRootHashString )
188- //realTx, err := w.RespondToTaskV2Retryable(txOpts, batchMerkleRoot, senderAddress, quorumNums, nonSignerStakesAndSignature, retry.SendToChainRetryParams())
189- receipt , err := w .SendTransactionRetryable (context .Background (), simTx , false , retry .SendToChainRetryParams ())
190- if err != nil {
191- w .logger .Errorf ("Respond to task transaction err, %v" , err , "merkle root" , batchMerkleRootHashString )
192- return nil , err
193- }
194- sentTxs = append (sentTxs , simTx )
195-
196- w .logger .Infof ("Transaction sent, waiting for receipt" , "merkle root" , batchMerkleRootHashString )
197- receipt , err = utils .WaitForTransactionReceiptRetryable (w .Client , w .ClientFallback , receipt .TxHash , retry .WaitForTxRetryParams (timeToWaitBeforeBump ))
198- if receipt != nil {
199- w .updateAggregatorGasCostMetrics (receipt , batchIdentifierHash )
200- return receipt , nil
201- }
202-
203- // if we are here, it means we have reached the receipt waiting timeout
204- // we increment the i here to add an incremental percentage to increase the odds of being included in the next blocks
205- i ++
206-
207- w .logger .Infof ("RespondToTask receipt waiting timeout has passed, will try again..." , "merkle_root" , batchMerkleRootHashString )
208- if err != nil {
209- return nil , err
210- }
211- return nil , fmt .Errorf ("transaction failed" )
150+ tx , err := w .RespondToTaskV2Retryable (txOpts , batchMerkleRoot , senderAddress , nonSignerStakesAndSignature , retry .SendToChainRetryParams ())
151+ if err != nil {
152+ w .logger .Errorf ("Failed to simulate transaction: %v" , err )
153+ return nil , err
212154 }
213155
214- // This just retries the bump of a fee in case of a timeout
215- // The wait is done before on WaitForTransactionReceiptRetryable, and all the functions are retriable,
216- // so this retry doesn't need to wait more time
217- return retry .RetryWithData (respondToTaskV2Func , retry .RespondToTaskV2 ())
156+ w .logger .Infof ("Sending RespondToTask transaction (%v) for MerkleRoot %v" , tx .Hash ().Hex (), batchMerkleRootHashString )
157+ receipt , err := w .SendTransactionRetryable (context .Background (), tx , retry .SendToChainRetryParams ())
158+ if err != nil {
159+ w .logger .Errorf ("RespondToTask transaction (%v) for MerkleRoot %v error: %v" , tx .Hash ().Hex (), batchMerkleRootHashString , err )
160+ return nil , err
161+ }
162+ w .logger .Infof ("RespondToTask transaction (%v) sent for MerkleRoot %v. %+v" , tx .Hash ().Hex (), batchMerkleRootHashString , receipt )
163+ return receipt , nil
164+ // TODO DELETE This commented code
165+ //txOpts, err := w.TxManager.GetNoSendTxOpts()
166+ //txOpts.NoSend = true // simulate the transaction
167+ //simTx, err := w.RespondToTaskV2Retryable(txOpts, batchMerkleRoot, senderAddress, nonSignerStakesAndSignature, retry.SendToChainRetryParams())
168+ //if err != nil {
169+ // w.logger.Errorf("Failed to simulate transaction: %v", err)
170+ // return nil, err
171+ //}
172+ //w.logger.Infof("Simulated transaction: %v", simTx.Hash().Hex())
173+ //
174+ //// Set the nonce, as we might have to replace the transaction with a higher gas price
175+ //txNonce := big.NewInt(int64(simTx.Nonce()))
176+ //txOpts.Nonce = txNonce
177+ //txOpts.GasPrice = nil
178+ //txOpts.NoSend = false
179+ //i := 0
180+ //
181+ //var sentTxs []*types.Transaction
182+ //
183+ //batchMerkleRootHashString := hex.EncodeToString(batchMerkleRoot[:])
184+ //
185+ //respondToTaskV2Func := func() (*types.Receipt, error) {
186+ // gasPrice, err := utils.GetGasPriceRetryable(w.Client, w.ClientFallback, retry.NetworkRetryParams())
187+ // if err != nil {
188+ // return nil, err
189+ // }
190+ //
191+ // // if txOpts.GasPrice wasn't previously set use the fetched gasPrice
192+ // // this should happen on the first iteration only
193+ // var previousTxGasPrice *big.Int
194+ // if txOpts.GasPrice == nil {
195+ // previousTxGasPrice = gasPrice
196+ // } else {
197+ // previousTxGasPrice = txOpts.GasPrice
198+ // }
199+ //
200+ // // in order to avoid replacement transaction underpriced
201+ // // the bumped gas price has to be at least 10% higher than the previous one.
202+ // minimumGasPriceBump := utils.CalculateGasPriceBumpBasedOnRetry(previousTxGasPrice, 10, 0, gasBumpPercentageLimit, 0)
203+ // suggestedBumpedGasPrice := utils.CalculateGasPriceBumpBasedOnRetry(
204+ // gasPrice,
205+ // gasBumpPercentage,
206+ // gasBumpIncrementalPercentage,
207+ // gasBumpPercentageLimit,
208+ // i,
209+ // )
210+ // // check the new gas price is sufficiently bumped.
211+ // // if the suggested bump does not meet the minimum threshold, use a fallback calculation to slightly increment the previous gas price.
212+ // if suggestedBumpedGasPrice.Cmp(minimumGasPriceBump) > 0 {
213+ // txOpts.GasPrice = suggestedBumpedGasPrice
214+ // } else {
215+ // txOpts.GasPrice = minimumGasPriceBump
216+ // }
217+ //
218+ // onSetGasPrice(txOpts.GasPrice)
219+ //
220+ // if i > 0 {
221+ // w.logger.Infof("Trying to get old sent transaction receipt before sending a new transaction", "merkle root", batchMerkleRootHashString)
222+ // for _, tx := range sentTxs {
223+ // receipt, _ := w.Client.TransactionReceipt(context.Background(), tx.Hash())
224+ // if receipt == nil {
225+ // receipt, _ = w.ClientFallback.TransactionReceipt(context.Background(), tx.Hash())
226+ // if receipt != nil {
227+ // w.updateAggregatorGasCostMetrics(receipt, batchIdentifierHash)
228+ // return receipt, nil
229+ // }
230+ // }
231+ // }
232+ // w.logger.Infof("Receipts for old transactions not found, will check if the batch state has been responded", "merkle root", batchMerkleRootHashString)
233+ // batchState, _ := w.BatchesStateRetryable(&bind.CallOpts{}, batchIdentifierHash, retry.NetworkRetryParams())
234+ // if batchState.Responded {
235+ // w.logger.Infof("Batch state has been already responded", "merkle root", batchMerkleRootHashString)
236+ // return nil, nil
237+ // }
238+ // w.logger.Infof("Batch state has not been responded yet, will send a new tx", "merkle root", batchMerkleRootHashString)
239+ //
240+ // metrics.IncBumpedGasPriceForAggregatedResponse()
241+ // }
242+ //
243+ // // We compare both Aggregator funds and Batcher balance in Aligned against respondToTaskFeeLimit
244+ // // Both are required to have some balance, more details inside the function
245+ // err = w.checkAggAndBatcherHaveEnoughBalance(simTx, *txOpts, batchIdentifierHash, senderAddress)
246+ // if err != nil {
247+ // w.logger.Errorf("Permanent error when checking aggregator and batcher balances, err %v", err, "merkle root", batchMerkleRootHashString)
248+ // return nil, retry.PermanentError{Inner: err}
249+ // }
250+ //
251+ // w.logger.Infof("Sending RespondToTask transaction with a gas price of %v", txOpts.GasPrice, "merkle root", batchMerkleRootHashString)
252+ // //realTx, err := w.RespondToTaskV2Retryable(txOpts, batchMerkleRoot, senderAddress, quorumNums, nonSignerStakesAndSignature, retry.SendToChainRetryParams())
253+ // receipt, err := w.SendTransactionRetryable(context.Background(), simTx, false, retry.SendToChainRetryParams())
254+ // if err != nil {
255+ // w.logger.Errorf("Respond to task transaction err, %v", err, "merkle root", batchMerkleRootHashString)
256+ // return nil, err
257+ // }
258+ // sentTxs = append(sentTxs, simTx)
259+ //
260+ // w.logger.Infof("Transaction sent, waiting for receipt", "merkle root", batchMerkleRootHashString)
261+ // receipt, err = utils.WaitForTransactionReceiptRetryable(w.Client, w.ClientFallback, receipt.TxHash, retry.WaitForTxRetryParams(timeToWaitBeforeBump))
262+ // if receipt != nil {
263+ // w.updateAggregatorGasCostMetrics(receipt, batchIdentifierHash)
264+ // return receipt, nil
265+ // }
266+ //
267+ // // if we are here, it means we have reached the receipt waiting timeout
268+ // // we increment the i here to add an incremental percentage to increase the odds of being included in the next blocks
269+ // i++
270+ //
271+ // w.logger.Infof("RespondToTask receipt waiting timeout has passed, will try again...", "merkle_root", batchMerkleRootHashString)
272+ // if err != nil {
273+ // return nil, err
274+ // }
275+ // return nil, fmt.Errorf("transaction failed")
276+ //}
277+ //
278+ //// This just retries the bump of a fee in case of a timeout
279+ //// The wait is done before on WaitForTransactionReceiptRetryable, and all the functions are retriable,
280+ //// so this retry doesn't need to wait more time
281+ //return retry.RetryWithData(respondToTaskV2Func, retry.RespondToTaskV2())
218282}
219283
220284// Calculates the transaction cost from the receipt and updates the total amount paid by the aggregator metric
0 commit comments