github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/admin/commands/execution/stop_at_height.go (about)

     1  package execution
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/rs/zerolog/log"
     7  
     8  	"github.com/onflow/flow-go/admin"
     9  	"github.com/onflow/flow-go/admin/commands"
    10  	"github.com/onflow/flow-go/engine/execution/ingestion/stop"
    11  )
    12  
    13  var _ commands.AdminCommand = (*StopAtHeightCommand)(nil)
    14  
    15  // StopAtHeightCommand will send a signal to engine to stop/crash EN
    16  // at given height
    17  type StopAtHeightCommand struct {
    18  	stopControl *stop.StopControl
    19  }
    20  
    21  // NewStopAtHeightCommand creates a new StopAtHeightCommand object
    22  func NewStopAtHeightCommand(sah *stop.StopControl) *StopAtHeightCommand {
    23  	return &StopAtHeightCommand{
    24  		stopControl: sah,
    25  	}
    26  }
    27  
    28  type StopAtHeightReq struct {
    29  	height uint64
    30  	crash  bool
    31  }
    32  
    33  // Handler method sets the stop height parameters.
    34  // Errors only if setting of stop height parameters fails.
    35  // Returns "ok" if successful.
    36  func (s *StopAtHeightCommand) Handler(_ context.Context, req *admin.CommandRequest) (interface{}, error) {
    37  	sah := req.ValidatorData.(StopAtHeightReq)
    38  
    39  	oldParams := s.stopControl.GetStopParameters()
    40  	newParams := stop.StopParameters{
    41  		StopBeforeHeight: sah.height,
    42  		ShouldCrash:      sah.crash,
    43  	}
    44  
    45  	err := s.stopControl.SetStopParameters(newParams)
    46  
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	log.Info().
    52  		Interface("newParams", newParams).
    53  		Interface("oldParams", oldParams).
    54  		Msgf("admintool: New En stop parameters set")
    55  
    56  	return "ok", nil
    57  }
    58  
    59  // Validator checks the inputs for StopAtHeight command.
    60  // It expects the following fields in the Data field of the req object:
    61  //   - height in a numeric format
    62  //   - crash, a boolean
    63  //
    64  // Additionally, height must be a positive integer. If a float value is provided, only the integer part is used.
    65  // The following sentinel errors are expected during normal operations:
    66  // * `admin.InvalidAdminReqError` if any required field is missing or in a wrong format
    67  func (s *StopAtHeightCommand) Validator(req *admin.CommandRequest) error {
    68  
    69  	input, ok := req.Data.(map[string]interface{})
    70  	if !ok {
    71  		return admin.NewInvalidAdminReqFormatError("expected map[string]any")
    72  	}
    73  	result, ok := input["height"]
    74  	if !ok {
    75  		return admin.NewInvalidAdminReqErrorf("missing required field: 'height'")
    76  	}
    77  	height, ok := result.(float64)
    78  	if !ok || height <= 0 {
    79  		return admin.NewInvalidAdminReqParameterError("height", "must be number >=0", result)
    80  	}
    81  
    82  	result, ok = input["crash"]
    83  	if !ok {
    84  		return admin.NewInvalidAdminReqErrorf("missing required field: 'crash'")
    85  	}
    86  	crash, ok := result.(bool)
    87  	if !ok {
    88  		return admin.NewInvalidAdminReqParameterError("crash", "must be bool", result)
    89  	}
    90  
    91  	req.ValidatorData = StopAtHeightReq{
    92  		height: uint64(height),
    93  		crash:  crash,
    94  	}
    95  
    96  	return nil
    97  }