Skip to content

Commit

Permalink
Make ejector return the transaction hash of the ejection (#565)
Browse files Browse the repository at this point in the history
  • Loading branch information
jianoaix authored May 15, 2024
1 parent 9473b8a commit 4d5d8b5
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 27 deletions.
13 changes: 12 additions & 1 deletion disperser/dataapi/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ const docTemplate = `{
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"schema": {
"$ref": "#/definitions/dataapi.EjectionResponse"
}
},
"400": {
"description": "error: Bad request",
Expand Down Expand Up @@ -699,6 +702,14 @@ const docTemplate = `{
}
}
},
"dataapi.EjectionResponse": {
"type": "object",
"properties": {
"transaction_hash": {
"type": "string"
}
}
},
"dataapi.ErrorResponse": {
"type": "object",
"properties": {
Expand Down
13 changes: 12 additions & 1 deletion disperser/dataapi/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"schema": {
"$ref": "#/definitions/dataapi.EjectionResponse"
}
},
"400": {
"description": "error: Bad request",
Expand Down Expand Up @@ -695,6 +698,14 @@
}
}
},
"dataapi.EjectionResponse": {
"type": "object",
"properties": {
"transaction_hash": {
"type": "string"
}
}
},
"dataapi.ErrorResponse": {
"type": "object",
"properties": {
Expand Down
7 changes: 7 additions & 0 deletions disperser/dataapi/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ definitions:
meta:
$ref: '#/definitions/dataapi.Meta'
type: object
dataapi.EjectionResponse:
properties:
transaction_hash:
type: string
type: object
dataapi.ErrorResponse:
properties:
error:
Expand Down Expand Up @@ -261,6 +266,8 @@ paths:
responses:
"200":
description: OK
schema:
$ref: '#/definitions/dataapi.EjectionResponse'
"400":
description: 'error: Bad request'
schema:
Expand Down
23 changes: 13 additions & 10 deletions disperser/dataapi/ejector.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func NewEjector(wallet walletsdk.Wallet, ethClient common.EthClient, logger logg
}
}

func (e *Ejector) Eject(ctx context.Context, nonsigningRate *OperatorsNonsigningPercentage) error {
func (e *Ejector) Eject(ctx context.Context, nonsigningRate *OperatorsNonsigningPercentage) (*EjectionResponse, error) {
e.mu.Lock()
defer e.mu.Unlock()

Expand All @@ -103,26 +103,26 @@ func (e *Ejector) Eject(ctx context.Context, nonsigningRate *OperatorsNonsigning

operatorsByQuorum, err := e.convertOperators(nonsigners)
if err != nil {
return err
return nil, err
}

txn, err := e.transactor.BuildEjectOperatorsTxn(ctx, operatorsByQuorum)
if err != nil {
e.logger.Error("Failed to build ejection transaction", "err", err)
return err
return nil, err
}

var txID walletsdk.TxID
retryFromFailure := 0
for retryFromFailure < maxSendTransactionRetry {
gasTipCap, gasFeeCap, err := e.ethClient.GetLatestGasCaps(ctx)
if err != nil {
return fmt.Errorf("failed to get latest gas caps: %w", err)
return nil, fmt.Errorf("failed to get latest gas caps: %w", err)
}

txn, err = e.ethClient.UpdateGas(ctx, txn, big.NewInt(0), gasTipCap, gasFeeCap)
if err != nil {
return fmt.Errorf("failed to update gas price: %w", err)
return nil, fmt.Errorf("failed to update gas price: %w", err)
}
txID, err = e.wallet.SendTransaction(ctx, txn)
var urlErr *url.Error
Expand All @@ -135,7 +135,7 @@ func (e *Ejector) Eject(ctx context.Context, nonsigningRate *OperatorsNonsigning
retryFromFailure++
continue
} else if err != nil {
return fmt.Errorf("failed to send txn %s: %w", txn.Hash().Hex(), err)
return nil, fmt.Errorf("failed to send txn %s: %w", txn.Hash().Hex(), err)
} else {
e.logger.Debug("successfully sent txn", "txID", txID, "txHash", txn.Hash().Hex())
break
Expand All @@ -159,16 +159,16 @@ func (e *Ejector) Eject(ctx context.Context, nonsigningRate *OperatorsNonsigning
e.logger.Warn("Transaction has not been broadcasted to network but attempted to retrieve receipt", "err", err)
} else if errors.Is(err, walletsdk.ErrTransactionFailed) {
e.logger.Error("Transaction failed", "txID", txID, "txHash", txn.Hash().Hex(), "err", err)
return err
return nil, err
} else {
e.logger.Error("Transaction receipt retrieval failed", "err", err)
return err
return nil, err
}

// Wait for the next round.
select {
case <-ctxWithTimeout.Done():
return ctxWithTimeout.Err()
return nil, ctxWithTimeout.Err()
case <-queryTicker.C:
}
}
Expand All @@ -178,8 +178,11 @@ func (e *Ejector) Eject(ctx context.Context, nonsigningRate *OperatorsNonsigning
e.metrics.UpdateEjectionGasUsed(receipt.GasUsed)

// TODO: get the txn response and update the metrics.
ejectionResponse := &EjectionResponse{
TransactionHash: receipt.TxHash.Hex(),
}

return nil
return ejectionResponse, nil
}

func (e *Ejector) convertOperators(nonsigners []*OperatorNonsigningPercentageMetrics) ([][]core.OperatorID, error) {
Expand Down
25 changes: 15 additions & 10 deletions disperser/dataapi/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const (
// Cache control for responses.
// The time unit is second for max age.
maxOperatorsNonsigningPercentageAge = 10
maxOperatorPortCheckAge = 600
maxOperatorPortCheckAge = 60
maxNonSignerAge = 10
maxDeregisteredOperatorAage = 10
maxThroughputAge = 10
Expand Down Expand Up @@ -94,6 +94,10 @@ type (
Timestamp uint64 `json:"timestamp"`
}

EjectionResponse struct {
TransactionHash string `json:"transaction_hash"`
}

Meta struct {
Size int `json:"size"`
}
Expand Down Expand Up @@ -320,13 +324,13 @@ func (s *server) Shutdown() error {
// @Summary Eject operators who violate the SLAs during the given time interval
// @Tags Ejector
// @Produce json
// @Param interval query int false "Lookback window for operator ejection [default: 86400]"
// @Param end query int false "End time for evaluating operator ejection [default: now]"
// @Param mode query string false "Whether it's periodic or urgent ejection request [default: periodic]"
// @Success 200
// @Failure 400 {object} ErrorResponse "error: Bad request"
// @Failure 404 {object} ErrorResponse "error: Not found"
// @Failure 500 {object} ErrorResponse "error: Server error"
// @Param interval query int false "Lookback window for operator ejection [default: 86400]"
// @Param end query int false "End time for evaluating operator ejection [default: now]"
// @Param mode query string false "Whether it's periodic or urgent ejection request [default: periodic]"
// @Success 200 {object} EjectionResponse
// @Failure 400 {object} ErrorResponse "error: Bad request"
// @Failure 404 {object} ErrorResponse "error: Not found"
// @Failure 500 {object} ErrorResponse "error: Server error"
// @Router /ejector/operators [post]
func (s *server) EjectOperatorsHandler(c *gin.Context) {
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(f float64) {
Expand Down Expand Up @@ -363,8 +367,9 @@ func (s *server) EjectOperatorsHandler(c *gin.Context) {
}

nonSigningRate, err := s.getOperatorNonsigningRate(c.Request.Context(), endTime.Unix()-interval, endTime.Unix(), true)
var ejectionResponse *EjectionResponse
if err == nil {
err = s.ejector.Eject(c.Request.Context(), nonSigningRate)
ejectionResponse, err = s.ejector.Eject(c.Request.Context(), nonSigningRate)
}
if err != nil {
s.metrics.IncrementFailedRequestNum("EjectOperators")
Expand All @@ -374,7 +379,7 @@ func (s *server) EjectOperatorsHandler(c *gin.Context) {
}
s.metrics.IncrementSuccessfulRequestNum("EjectOperators")
s.metrics.IncrementEjectionRequest(mode, codes.OK)
c.Status(http.StatusOK)
c.JSON(http.StatusOK, ejectionResponse)
}

// FetchBlobHandler godoc
Expand Down
25 changes: 20 additions & 5 deletions disperser/dataapi/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,17 +350,20 @@ func TestEjectOperatorHandler(t *testing.T) {
ejectorComponents.ethClient.On("GetLatestGasCaps").Return(big.NewInt(0), big.NewInt(0), nil)
ejectorComponents.ethClient.On("UpdateGas").Return(types.NewTransaction(0, gethcommon.HexToAddress("0x1"), big.NewInt(0), 0, big.NewInt(0), []byte{}), nil)
txID := "1234"
receipt := &types.Receipt{
BlockNumber: new(big.Int).SetUint64(1),
TxHash: gethcommon.HexToHash("0xdf9c2506b0dbb107d5a35e262e2e94fe9ce91440dfbba2e7a919bd2e83aee29e"),
}
gomock.InOrder(
ejectorComponents.wallet.EXPECT().SendTransaction(gomock.Any(), gomock.Any()).Return(txID, nil),
ejectorComponents.wallet.EXPECT().GetTransactionReceipt(gomock.Any(), gomock.Any()).Return(&types.Receipt{
BlockNumber: new(big.Int).SetUint64(1),
}, nil),
ejectorComponents.wallet.EXPECT().GetTransactionReceipt(gomock.Any(), gomock.Any()).Return(receipt, nil),
)

r.GET("/v1/ejector/operator", testDataApiServer.EjectOperatorsHandler)

w := httptest.NewRecorder()
reqStr := fmt.Sprintf("/v1/ejector/operator?interval=%v&end=%s", interval, stopTime.Format("2006-01-02T15:04:05Z"))

w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, reqStr, nil)
ctxWithDeadline, cancel := context.WithTimeout(req.Context(), 500*time.Microsecond)
defer cancel()
Expand All @@ -374,8 +377,20 @@ func TestEjectOperatorHandler(t *testing.T) {
ctxWithDeadline2, cancel2 := context.WithTimeout(req2.Context(), 500*time.Microsecond)
defer cancel2()
req2 = req2.WithContext(ctxWithDeadline2)
r.ServeHTTP(w, req2)
r.ServeHTTP(w2, req2)
assert.Equal(t, w2.Code, http.StatusOK)

res := w2.Result()
defer res.Body.Close()

data, err := io.ReadAll(res.Body)
assert.NoError(t, err)

var response dataapi.EjectionResponse
err = json.Unmarshal(data, &response)
assert.NoError(t, err)
assert.NotNil(t, response)
assert.Equal(t, receipt.TxHash.Hex(), response.TransactionHash)
}

func TestFetchUnsignedBatchesHandler(t *testing.T) {
Expand Down

0 comments on commit 4d5d8b5

Please sign in to comment.