github.com/onflow/flow-go@v0.33.17/admin/commands/storage/read_blocks.go (about)

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/rs/zerolog/log"
     8  
     9  	"github.com/onflow/flow-go/admin"
    10  	"github.com/onflow/flow-go/admin/commands"
    11  	"github.com/onflow/flow-go/model/flow"
    12  	"github.com/onflow/flow-go/state/protocol"
    13  	"github.com/onflow/flow-go/storage"
    14  )
    15  
    16  var _ commands.AdminCommand = (*ReadBlocksCommand)(nil)
    17  
    18  type readBlocksRequest struct {
    19  	blocksRequest    *blocksRequest
    20  	numBlocksToQuery uint64
    21  }
    22  
    23  type ReadBlocksCommand struct {
    24  	state  protocol.State
    25  	blocks storage.Blocks
    26  }
    27  
    28  func (r *ReadBlocksCommand) Handler(ctx context.Context, req *admin.CommandRequest) (interface{}, error) {
    29  	data := req.ValidatorData.(*readBlocksRequest)
    30  	var result []*flow.Block
    31  	var blockID flow.Identifier
    32  
    33  	log.Info().Str("module", "admin-tool").Msgf("read blocks, data: %v", data)
    34  
    35  	if header, err := getBlockHeader(r.state, data.blocksRequest); err != nil {
    36  		return nil, fmt.Errorf("failed to get block header: %w", err)
    37  	} else {
    38  		blockID = header.ID()
    39  	}
    40  
    41  	for i := uint64(0); i < data.numBlocksToQuery; i++ {
    42  		block, err := r.blocks.ByID(blockID)
    43  		if err != nil {
    44  			return nil, fmt.Errorf("failed to get block by ID: %w", err)
    45  		}
    46  		result = append(result, block)
    47  		if block.Header.Height == 0 {
    48  			break
    49  		}
    50  		blockID = block.Header.ParentID
    51  	}
    52  
    53  	return commands.ConvertToInterfaceList(result)
    54  }
    55  
    56  // Validator validates the request.
    57  // Returns admin.InvalidAdminReqError for invalid/malformed requests.
    58  func (r *ReadBlocksCommand) Validator(req *admin.CommandRequest) error {
    59  	input, ok := req.Data.(map[string]interface{})
    60  	if !ok {
    61  		return admin.NewInvalidAdminReqFormatError("expected map[string]any")
    62  	}
    63  
    64  	block, ok := input["block"]
    65  	if !ok {
    66  		return admin.NewInvalidAdminReqErrorf("the \"block\" field is required")
    67  	}
    68  
    69  	data := &readBlocksRequest{}
    70  	if blocksRequest, err := parseBlocksRequest(block); err != nil {
    71  		return admin.NewInvalidAdminReqErrorf("invalid 'block' field: %w", err)
    72  	} else {
    73  		data.blocksRequest = blocksRequest
    74  	}
    75  
    76  	if n, ok := input["n"]; ok {
    77  		if n, err := parseN(n); err != nil {
    78  			return admin.NewInvalidAdminReqErrorf("invalid 'n' field: %w", err)
    79  		} else {
    80  			data.numBlocksToQuery = n
    81  		}
    82  	} else {
    83  		data.numBlocksToQuery = 1
    84  	}
    85  
    86  	req.ValidatorData = data
    87  
    88  	return nil
    89  
    90  }
    91  
    92  func NewReadBlocksCommand(state protocol.State, storage storage.Blocks) commands.AdminCommand {
    93  	return &ReadBlocksCommand{
    94  		state,
    95  		storage,
    96  	}
    97  }