github.com/okex/exchain@v1.8.0/libs/tendermint/rpc/jsonrpc/client/decode.go (about)

     1  package client
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/pkg/errors"
     7  
     8  	amino "github.com/tendermint/go-amino"
     9  
    10  	types "github.com/okex/exchain/libs/tendermint/rpc/jsonrpc/types"
    11  )
    12  
    13  func unmarshalResponseBytes(
    14  	cdc *amino.Codec,
    15  	responseBytes []byte,
    16  	expectedID types.JSONRPCIntID,
    17  	result interface{},
    18  ) (interface{}, error) {
    19  
    20  	// Read response.  If rpc/core/types is imported, the result will unmarshal
    21  	// into the correct type.
    22  	response := &types.RPCResponse{}
    23  	if err := json.Unmarshal(responseBytes, response); err != nil {
    24  		return nil, errors.Wrap(err, "error unmarshalling")
    25  	}
    26  
    27  	if response.Error != nil {
    28  		return nil, response.Error
    29  	}
    30  
    31  	if err := validateAndVerifyID(response, expectedID); err != nil {
    32  		return nil, errors.Wrap(err, "wrong ID")
    33  	}
    34  
    35  	// Unmarshal the RawMessage into the result.
    36  	if err := cdc.UnmarshalJSON(response.Result, result); err != nil {
    37  		return nil, errors.Wrap(err, "error unmarshalling result")
    38  	}
    39  
    40  	return result, nil
    41  }
    42  
    43  func unmarshalResponseBytesArray(
    44  	cdc *amino.Codec,
    45  	responseBytes []byte,
    46  	expectedIDs []types.JSONRPCIntID,
    47  	results []interface{},
    48  ) ([]interface{}, error) {
    49  
    50  	var (
    51  		responses []types.RPCResponse
    52  	)
    53  
    54  	if err := json.Unmarshal(responseBytes, &responses); err != nil {
    55  		return nil, errors.Wrap(err, "error unmarshalling")
    56  	}
    57  
    58  	// No response error checking here as there may be a mixture of successful
    59  	// and unsuccessful responses.
    60  
    61  	if len(results) != len(responses) {
    62  		return nil, errors.Errorf(
    63  			"expected %d result objects into which to inject responses, but got %d",
    64  			len(responses),
    65  			len(results),
    66  		)
    67  	}
    68  
    69  	// Intersect IDs from responses with expectedIDs.
    70  	ids := make([]types.JSONRPCIntID, len(responses))
    71  	var ok bool
    72  	for i, resp := range responses {
    73  		ids[i], ok = resp.ID.(types.JSONRPCIntID)
    74  		if !ok {
    75  			return nil, errors.Errorf("expected JSONRPCIntID, got %T", resp.ID)
    76  		}
    77  	}
    78  	if err := validateResponseIDs(ids, expectedIDs); err != nil {
    79  		return nil, errors.Wrap(err, "wrong IDs")
    80  	}
    81  
    82  	for i := 0; i < len(responses); i++ {
    83  		if err := cdc.UnmarshalJSON(responses[i].Result, results[i]); err != nil {
    84  			return nil, errors.Wrapf(err, "error unmarshalling #%d result", i)
    85  		}
    86  	}
    87  
    88  	return results, nil
    89  }
    90  
    91  func validateResponseIDs(ids, expectedIDs []types.JSONRPCIntID) error {
    92  	m := make(map[types.JSONRPCIntID]bool, len(expectedIDs))
    93  	for _, expectedID := range expectedIDs {
    94  		m[expectedID] = true
    95  	}
    96  
    97  	for i, id := range ids {
    98  		if m[id] {
    99  			delete(m, id)
   100  		} else {
   101  			return errors.Errorf("unsolicited ID #%d: %v", i, id)
   102  		}
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  // From the JSON-RPC 2.0 spec:
   109  // id: It MUST be the same as the value of the id member in the Request Object.
   110  func validateAndVerifyID(res *types.RPCResponse, expectedID types.JSONRPCIntID) error {
   111  	if err := validateResponseID(res.ID); err != nil {
   112  		return err
   113  	}
   114  	if expectedID != res.ID.(types.JSONRPCIntID) { // validateResponseID ensured res.ID has the right type
   115  		return errors.Errorf("response ID (%d) does not match request ID (%d)", res.ID, expectedID)
   116  	}
   117  	return nil
   118  }
   119  
   120  func validateResponseID(id interface{}) error {
   121  	if id == nil {
   122  		return errors.New("no ID")
   123  	}
   124  	_, ok := id.(types.JSONRPCIntID)
   125  	if !ok {
   126  		return errors.Errorf("expected JSONRPCIntID, but got: %T", id)
   127  	}
   128  	return nil
   129  }