github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/admin/commands/storage/read_results.go (about) 1 package storage 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/onflow/flow-go/admin" 8 "github.com/onflow/flow-go/admin/commands" 9 "github.com/onflow/flow-go/model/flow" 10 "github.com/onflow/flow-go/state/protocol" 11 "github.com/onflow/flow-go/storage" 12 ) 13 14 var _ commands.AdminCommand = (*ReadResultsCommand)(nil) 15 16 type readResultsRequestType int 17 18 const ( 19 readResultsRequestByID readResultsRequestType = iota 20 readResultsRequestByBlock 21 ) 22 23 type readResultsRequest struct { 24 requestType readResultsRequestType 25 value interface{} 26 numResultsToQuery uint64 27 } 28 29 type ReadResultsCommand struct { 30 state protocol.State 31 results storage.ExecutionResults 32 } 33 34 func (r *ReadResultsCommand) Handler(ctx context.Context, req *admin.CommandRequest) (interface{}, error) { 35 data := req.ValidatorData.(*readResultsRequest) 36 var results []*flow.ExecutionResult 37 var resultID flow.Identifier 38 n := data.numResultsToQuery 39 40 switch data.requestType { 41 case readResultsRequestByID: 42 resultID = data.value.(flow.Identifier) 43 case readResultsRequestByBlock: 44 if header, err := getBlockHeader(r.state, data.value.(*blocksRequest)); err != nil { 45 return nil, fmt.Errorf("failed to get block header: %w", err) 46 } else if result, err := r.results.ByBlockID(header.ID()); err != nil { 47 return nil, fmt.Errorf("failed to get result by block ID: %w", err) 48 } else { 49 results = append(results, result) 50 resultID = result.PreviousResultID 51 n -= 1 52 } 53 } 54 55 for i := uint64(0); i < n && resultID != flow.ZeroID; i++ { 56 result, err := r.results.ByID(resultID) 57 if err != nil { 58 return nil, fmt.Errorf("failed to get result by ID: %w", err) 59 } 60 results = append(results, result) 61 resultID = result.PreviousResultID 62 } 63 64 return commands.ConvertToInterfaceList(results) 65 } 66 67 // Validator validates the request. 68 // Returns admin.InvalidAdminReqError for invalid/malformed requests. 69 func (r *ReadResultsCommand) Validator(req *admin.CommandRequest) error { 70 input, ok := req.Data.(map[string]interface{}) 71 if !ok { 72 return admin.NewInvalidAdminReqFormatError("expected map[string]any") 73 } 74 75 data := &readResultsRequest{} 76 77 if resultIn, ok := input["result"]; ok { 78 errInvalidResultValue := admin.NewInvalidAdminReqParameterError("result", "expected a result ID represented as a 64 character long hex string", resultIn) 79 result, ok := resultIn.(string) 80 if !ok { 81 return errInvalidResultValue 82 } 83 resultID, err := flow.HexStringToIdentifier(result) 84 if err != nil { 85 return errInvalidResultValue 86 } 87 data.requestType = readResultsRequestByID 88 data.value = resultID 89 } else if block, ok := input["block"]; ok { 90 br, err := parseBlocksRequest(block) 91 if err != nil { 92 return admin.NewInvalidAdminReqErrorf("invalid 'block' field: %w", err) 93 } 94 data.requestType = readResultsRequestByBlock 95 data.value = br 96 } else { 97 return admin.NewInvalidAdminReqErrorf("either \"block\" or \"result\" field is required") 98 } 99 100 if n, ok := input["n"]; ok { 101 if n, err := parseN(n); err != nil { 102 return admin.NewInvalidAdminReqErrorf("invalid 'n' field: %w", err) 103 } else { 104 data.numResultsToQuery = n 105 } 106 } else { 107 data.numResultsToQuery = 1 108 } 109 110 req.ValidatorData = data 111 112 return nil 113 } 114 115 func NewReadResultsCommand(state protocol.State, storage storage.ExecutionResults) commands.AdminCommand { 116 return &ReadResultsCommand{ 117 state, 118 storage, 119 } 120 }