github.com/koko1123/flow-go-1@v0.29.6/admin/commands/storage/helper.go (about)

     1  package storage
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"strings"
     7  
     8  	"github.com/koko1123/flow-go-1/model/flow"
     9  	"github.com/koko1123/flow-go-1/state/protocol"
    10  )
    11  
    12  type blocksRequestType int
    13  
    14  const (
    15  	blocksRequestByID blocksRequestType = iota
    16  	blocksRequestByHeight
    17  	blocksRequestFinal
    18  	blocksRequestSealed
    19  )
    20  
    21  const (
    22  	FINAL  = "final"
    23  	SEALED = "sealed"
    24  )
    25  
    26  type blocksRequest struct {
    27  	requestType blocksRequestType
    28  	value       interface{}
    29  }
    30  
    31  // parseN verifies that the input is an integral float64 value >=1.
    32  // All generic errors indicate a benign validation failure, and should be wrapped by the caller.
    33  func parseN(m interface{}) (uint64, error) {
    34  	n, ok := m.(float64)
    35  	if !ok {
    36  		return 0, fmt.Errorf("invalid value for \"n\": %v", n)
    37  	}
    38  	if math.Trunc(n) != n {
    39  		return 0, fmt.Errorf("\"n\" must be an integer, got: %v", n)
    40  	}
    41  	if n < 1 {
    42  		return 0, fmt.Errorf("\"n\" must be at least 1, got: %v", n)
    43  	}
    44  	return uint64(n), nil
    45  }
    46  
    47  // parseBlocksRequest parses the block field of an admin request.
    48  // All generic errors indicate a benign validation failure, and should be wrapped by the caller.
    49  func parseBlocksRequest(block interface{}) (*blocksRequest, error) {
    50  	errInvalidBlockValue := fmt.Errorf("invalid value for \"block\": expected %q, %q, block ID, or block height, but got: %v", FINAL, SEALED, block)
    51  	req := &blocksRequest{}
    52  
    53  	switch block := block.(type) {
    54  	case string:
    55  		block = strings.ToLower(strings.TrimSpace(block))
    56  		if block == FINAL {
    57  			req.requestType = blocksRequestFinal
    58  		} else if block == SEALED {
    59  			req.requestType = blocksRequestSealed
    60  		} else if id, err := flow.HexStringToIdentifier(block); err == nil {
    61  			req.requestType = blocksRequestByID
    62  			req.value = id
    63  		} else {
    64  			return nil, errInvalidBlockValue
    65  		}
    66  	case float64:
    67  		if block < 0 || math.Trunc(block) != block {
    68  			return nil, errInvalidBlockValue
    69  		}
    70  		req.requestType = blocksRequestByHeight
    71  		req.value = uint64(block)
    72  	default:
    73  		return nil, errInvalidBlockValue
    74  	}
    75  
    76  	return req, nil
    77  }
    78  
    79  func getBlockHeader(state protocol.State, req *blocksRequest) (*flow.Header, error) {
    80  	switch req.requestType {
    81  	case blocksRequestByID:
    82  		return state.AtBlockID(req.value.(flow.Identifier)).Head()
    83  	case blocksRequestByHeight:
    84  		return state.AtHeight(req.value.(uint64)).Head()
    85  	case blocksRequestFinal:
    86  		return state.Final().Head()
    87  	case blocksRequestSealed:
    88  		return state.Sealed().Head()
    89  	default:
    90  		return nil, fmt.Errorf("invalid request type: %v", req.requestType)
    91  	}
    92  }