Skip to content

Commit 047a65b

Browse files
uri-99taturosatitaturosatiglpecileJuArce
authored
feat: aggregator should check if gas is enough before respondToTask (#918)
Co-authored-by: Santos Rosati <[email protected]> Co-authored-by: taturosati <“[email protected]”> Co-authored-by: Gian <[email protected]> Co-authored-by: taturosati <[email protected]> Co-authored-by: Tatu <[email protected]> Co-authored-by: Julian Arce <[email protected]>
1 parent 7e64ee8 commit 047a65b

File tree

7 files changed

+134
-14
lines changed

7 files changed

+134
-14
lines changed

aggregator/internal/pkg/aggregator.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ func (agg *Aggregator) handleBlsAggServiceResponse(blsAggServiceResp blsagg.BlsA
277277
agg.logger.Info("Sending aggregated response onchain", "taskIndex", blsAggServiceResp.TaskIndex,
278278
"batchIdentifierHash", "0x"+hex.EncodeToString(batchIdentifierHash[:]))
279279
for i := 0; i < MaxSentTxRetries; i++ {
280-
_, err = agg.sendAggregatedResponse(batchData.BatchMerkleRoot, batchData.SenderAddress, nonSignerStakesAndSignature)
280+
_, err = agg.sendAggregatedResponse(batchIdentifierHash, batchData.BatchMerkleRoot, batchData.SenderAddress, nonSignerStakesAndSignature)
281281
if err == nil {
282282
agg.logger.Info("Aggregator successfully responded to task",
283283
"taskIndex", blsAggServiceResp.TaskIndex,
@@ -300,17 +300,15 @@ func (agg *Aggregator) handleBlsAggServiceResponse(blsAggServiceResp blsagg.BlsA
300300

301301
// / Sends response to contract and waits for transaction receipt
302302
// / Returns error if it fails to send tx or receipt is not found
303-
func (agg *Aggregator) sendAggregatedResponse(batchMerkleRoot [32]byte, senderAddress [20]byte, nonSignerStakesAndSignature servicemanager.IBLSSignatureCheckerNonSignerStakesAndSignature) (*gethtypes.Receipt, error) {
304-
batchIdentifier := append(batchMerkleRoot[:], senderAddress[:]...)
305-
var batchIdentifierHash = *(*[32]byte)(crypto.Keccak256(batchIdentifier))
303+
func (agg *Aggregator) sendAggregatedResponse(batchIdentifierHash [32]byte, batchMerkleRoot [32]byte, senderAddress [20]byte, nonSignerStakesAndSignature servicemanager.IBLSSignatureCheckerNonSignerStakesAndSignature) (*gethtypes.Receipt, error) {
306304

307305
agg.walletMutex.Lock()
308306
agg.logger.Infof("- Locked Wallet Resources: Sending aggregated response for batch",
309307
"merkleRoot", hex.EncodeToString(batchMerkleRoot[:]),
310308
"senderAddress", hex.EncodeToString(senderAddress[:]),
311309
"batchIdentifierHash", hex.EncodeToString(batchIdentifierHash[:]))
312310

313-
txHash, err := agg.avsWriter.SendAggregatedResponse(batchMerkleRoot, senderAddress, nonSignerStakesAndSignature)
311+
txHash, err := agg.avsWriter.SendAggregatedResponse(batchIdentifierHash, batchMerkleRoot, senderAddress, nonSignerStakesAndSignature)
314312
if err != nil {
315313
agg.walletMutex.Unlock()
316314
agg.logger.Infof("- Unlocked Wallet Resources: Error sending aggregated response for batch %s. Error: %s", hex.EncodeToString(batchIdentifierHash[:]), err)

batcher/aligned-sdk/abi/AlignedLayerServiceManager.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

contracts/bindings/AlignedLayerServiceManager/binding.go

Lines changed: 33 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/scripts/anvil/state/alignedlayer-deployed-anvil-state.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

contracts/src/core/AlignedLayerServiceManagerStorage.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ abstract contract AlignedLayerServiceManagerStorage {
1212
mapping(bytes32 => BatchState) public batchesState;
1313

1414
// Storage for batchers balances. Used by aggregator to pay for respondToTask
15-
mapping(address => uint256) internal batchersBalances;
15+
mapping(address => uint256) public batchersBalances;
1616

1717
address public alignedAggregator;
1818

core/chainio/avs_writer.go

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
package chainio
22

33
import (
4+
"context"
5+
"fmt"
6+
"math/big"
7+
"time"
48

59
"github.com/Layr-Labs/eigensdk-go/chainio/clients"
610
"github.com/Layr-Labs/eigensdk-go/chainio/clients/avsregistry"
711
"github.com/Layr-Labs/eigensdk-go/chainio/clients/eth"
812
"github.com/Layr-Labs/eigensdk-go/logging"
913
"github.com/Layr-Labs/eigensdk-go/signer"
14+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
1015
"github.com/ethereum/go-ethereum/common"
16+
"github.com/ethereum/go-ethereum/core/types"
1117
servicemanager "github.com/yetanotherco/aligned_layer/contracts/bindings/AlignedLayerServiceManager"
1218
"github.com/yetanotherco/aligned_layer/core/config"
1319
)
@@ -18,6 +24,7 @@ type AvsWriter struct {
1824
logger logging.Logger
1925
Signer signer.Signer
2026
Client eth.Client
27+
ClientFallback eth.Client
2128
}
2229

2330
func NewAvsWriterFromConfig(baseConfig *config.BaseConfig, ecdsaConfig *config.EcdsaConfig) (*AvsWriter, error) {
@@ -59,22 +66,27 @@ func NewAvsWriterFromConfig(baseConfig *config.BaseConfig, ecdsaConfig *config.E
5966
logger: baseConfig.Logger,
6067
Signer: privateKeySigner,
6168
Client: baseConfig.EthRpcClient,
69+
ClientFallback: baseConfig.EthRpcClientFallback,
6270
}, nil
6371
}
6472

65-
66-
func (w *AvsWriter) SendAggregatedResponse(batchMerkleRoot [32]byte, senderAddress [20]byte, nonSignerStakesAndSignature servicemanager.IBLSSignatureCheckerNonSignerStakesAndSignature) (*common.Hash, error) {
73+
func (w *AvsWriter) SendAggregatedResponse(batchIdentifierHash [32]byte, batchMerkleRoot [32]byte, senderAddress [20]byte, nonSignerStakesAndSignature servicemanager.IBLSSignatureCheckerNonSignerStakesAndSignature) (*common.Hash, error) {
6774
txOpts := *w.Signer.GetTxOpts()
6875
txOpts.NoSend = true // simulate the transaction
6976
tx, err := w.AvsContractBindings.ServiceManager.RespondToTaskV2(&txOpts, batchMerkleRoot, senderAddress, nonSignerStakesAndSignature)
7077
if err != nil {
7178
// Retry with fallback
7279
tx, err = w.AvsContractBindings.ServiceManagerFallback.RespondToTaskV2(&txOpts, batchMerkleRoot, senderAddress, nonSignerStakesAndSignature)
7380
if err != nil {
74-
return nil, err
81+
return nil, fmt.Errorf("transaction simulation failed: %v", err)
7582
}
7683
}
7784

85+
err = w.checkRespondToTaskFeeLimit(tx, txOpts, batchIdentifierHash, senderAddress)
86+
if err != nil {
87+
return nil, err
88+
}
89+
7890
// Send the transaction
7991
txOpts.NoSend = false
8092
txOpts.GasLimit = tx.Gas() * 110 / 100 // Add 10% to the gas limit
@@ -91,3 +103,82 @@ func (w *AvsWriter) SendAggregatedResponse(batchMerkleRoot [32]byte, senderAddre
91103

92104
return &txHash, nil
93105
}
106+
107+
func (w *AvsWriter) checkRespondToTaskFeeLimit(tx *types.Transaction, txOpts bind.TransactOpts, batchIdentifierHash [32]byte, senderAddress [20]byte) error {
108+
aggregatorAddress := txOpts.From
109+
simulatedCost := new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())
110+
w.logger.Info("Simulated cost", "cost", simulatedCost)
111+
112+
// Get RespondToTaskFeeLimit
113+
batchState, err := w.AvsContractBindings.ServiceManager.BatchesState(&bind.CallOpts{}, batchIdentifierHash)
114+
if err != nil {
115+
// Retry with fallback
116+
batchState, err = w.AvsContractBindings.ServiceManagerFallback.BatchesState(&bind.CallOpts{}, batchIdentifierHash)
117+
if err != nil {
118+
// Fallback also failed
119+
// Proceed to check values against simulated costs
120+
w.logger.Error("Failed to get batch state", "error", err)
121+
w.logger.Info("Proceeding with simulated cost checks")
122+
123+
return w.compareBalances(simulatedCost, aggregatorAddress, senderAddress)
124+
}
125+
}
126+
// At this point, batchState was successfully retrieved
127+
// Proceed to check values against RespondToTaskFeeLimit
128+
respondToTaskFeeLimit := batchState.RespondToTaskFeeLimit
129+
w.logger.Info("Batch RespondToTaskFeeLimit", "RespondToTaskFeeLimit", respondToTaskFeeLimit)
130+
131+
if respondToTaskFeeLimit.Cmp(simulatedCost) < 0 {
132+
return fmt.Errorf("cost of transaction is higher than Batch.RespondToTaskFeeLimit")
133+
}
134+
135+
return w.compareBalances(respondToTaskFeeLimit, aggregatorAddress, senderAddress)
136+
}
137+
138+
func (w *AvsWriter) compareBalances(amount *big.Int, aggregatorAddress common.Address, senderAddress [20]byte) error {
139+
if err := w.compareAggregatorBalance(amount, aggregatorAddress); err != nil {
140+
return err
141+
}
142+
if err := w.compareBatcherBalance(amount, senderAddress); err != nil {
143+
return err
144+
}
145+
return nil
146+
}
147+
148+
func (w *AvsWriter) compareAggregatorBalance(amount *big.Int, aggregatorAddress common.Address) error {
149+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
150+
defer cancel()
151+
// Get Agg wallet balance
152+
aggregatorBalance, err := w.Client.BalanceAt(ctx, aggregatorAddress, nil)
153+
if err != nil {
154+
aggregatorBalance, err = w.ClientFallback.BalanceAt(ctx, aggregatorAddress, nil)
155+
if err != nil {
156+
// Ignore and continue.
157+
w.logger.Error("failed to get aggregator balance: %v", err)
158+
return nil
159+
}
160+
}
161+
w.logger.Info("Aggregator balance", "balance", aggregatorBalance)
162+
if aggregatorBalance.Cmp(amount) < 0 {
163+
return fmt.Errorf("cost is higher than Aggregator balance")
164+
}
165+
return nil
166+
}
167+
168+
func (w *AvsWriter) compareBatcherBalance(amount *big.Int, senderAddress [20]byte) error {
169+
// Get batcher balance
170+
batcherBalance, err := w.AvsContractBindings.ServiceManager.BatchersBalances(&bind.CallOpts{}, senderAddress)
171+
if err != nil {
172+
batcherBalance, err = w.AvsContractBindings.ServiceManagerFallback.BatchersBalances(&bind.CallOpts{}, senderAddress)
173+
if err != nil {
174+
// Ignore and continue.
175+
w.logger.Error("Failed to get batcherBalance", "error", err)
176+
return nil
177+
}
178+
}
179+
w.logger.Info("Batcher balance", "balance", batcherBalance)
180+
if batcherBalance.Cmp(amount) < 0 {
181+
return fmt.Errorf("cost is higher than Batcher balance")
182+
}
183+
return nil
184+
}

explorer/lib/abi/AlignedLayerServiceManager.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)