github.com/okex/exchain@v1.8.0/libs/ibc-go/modules/core/03-connection/client/utils/utils.go (about)

     1  package utils
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	clictx "github.com/okex/exchain/libs/cosmos-sdk/client/context"
     7  	"github.com/okex/exchain/libs/cosmos-sdk/codec"
     8  	sdkerrors "github.com/okex/exchain/libs/cosmos-sdk/types/errors"
     9  	"github.com/okex/exchain/libs/ibc-go/modules/core/02-client/client/utils"
    10  	clienttypes "github.com/okex/exchain/libs/ibc-go/modules/core/02-client/types"
    11  	"github.com/okex/exchain/libs/ibc-go/modules/core/03-connection/types"
    12  	commitmenttypes "github.com/okex/exchain/libs/ibc-go/modules/core/23-commitment/types"
    13  	host "github.com/okex/exchain/libs/ibc-go/modules/core/24-host"
    14  	ibcclient "github.com/okex/exchain/libs/ibc-go/modules/core/client"
    15  	"github.com/okex/exchain/libs/ibc-go/modules/core/exported"
    16  	"io/ioutil"
    17  
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  // QueryConnection returns a connection end.
    22  // If prove is true, it performs an ABCI store query in order to retrieve the merkle proof. Otherwise,
    23  // it uses the gRPC query client.
    24  func QueryConnection(
    25  	clientCtx clictx.CLIContext, connectionID string, prove bool,
    26  ) (*types.QueryConnectionResponse, error) {
    27  	if prove {
    28  		return queryConnectionABCI(clientCtx, connectionID)
    29  	}
    30  	queryClient := types.NewQueryClient(clientCtx)
    31  	req := &types.QueryConnectionRequest{
    32  		ConnectionId: connectionID,
    33  	}
    34  
    35  	return queryClient.Connection(context.Background(), req)
    36  }
    37  
    38  func queryConnectionABCI(clientCtx clictx.CLIContext, connectionID string) (*types.QueryConnectionResponse, error) {
    39  	key := host.ConnectionKey(connectionID)
    40  
    41  	value, proofBz, proofHeight, err := ibcclient.QueryTendermintProof(clientCtx, key)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	// check if connection exists
    47  	if len(value) == 0 {
    48  		return nil, sdkerrors.Wrap(types.ErrConnectionNotFound, connectionID)
    49  	}
    50  
    51  	cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
    52  
    53  	var connection types.ConnectionEnd
    54  	if err := cdc.UnmarshalBinaryBare(value, &connection); err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	return types.NewQueryConnectionResponse(connection, proofBz, proofHeight), nil
    59  }
    60  
    61  // QueryClientConnections queries the connection paths registered for a particular client.
    62  // If prove is true, it performs an ABCI store query in order to retrieve the merkle proof. Otherwise,
    63  // it uses the gRPC query client.
    64  func QueryClientConnections(
    65  	clientCtx clictx.CLIContext, clientID string, prove bool,
    66  ) (*types.QueryClientConnectionsResponse, error) {
    67  	if prove {
    68  		return queryClientConnectionsABCI(clientCtx, clientID)
    69  	}
    70  
    71  	queryClient := types.NewQueryClient(clientCtx)
    72  	req := &types.QueryClientConnectionsRequest{
    73  		ClientId: clientID,
    74  	}
    75  
    76  	return queryClient.ClientConnections(context.Background(), req)
    77  }
    78  
    79  func queryClientConnectionsABCI(clientCtx clictx.CLIContext, clientID string) (*types.QueryClientConnectionsResponse, error) {
    80  	key := host.ClientConnectionsKey(clientID)
    81  
    82  	value, proofBz, proofHeight, err := ibcclient.QueryTendermintProof(clientCtx, key)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	// check if connection paths exist
    88  	if len(value) == 0 {
    89  		return nil, sdkerrors.Wrap(types.ErrClientConnectionPathsNotFound, clientID)
    90  	}
    91  
    92  	var paths []string
    93  	if err := clientCtx.CodecProy.GetCdc().UnmarshalBinaryBare(value, &paths); err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	return types.NewQueryClientConnectionsResponse(paths, proofBz, proofHeight), nil
    98  }
    99  
   100  // QueryConnectionClientState returns the ClientState of a connection end. If
   101  // prove is true, it performs an ABCI store query in order to retrieve the
   102  // merkle proof. Otherwise, it uses the gRPC query client.
   103  func QueryConnectionClientState(
   104  	clientCtx clictx.CLIContext, connectionID string, prove bool,
   105  ) (*types.QueryConnectionClientStateResponse, error) {
   106  
   107  	queryClient := types.NewQueryClient(clientCtx)
   108  	req := &types.QueryConnectionClientStateRequest{
   109  		ConnectionId: connectionID,
   110  	}
   111  
   112  	res, err := queryClient.ConnectionClientState(context.Background(), req)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	if prove {
   118  		clientStateRes, err := utils.QueryClientStateABCI(clientCtx, res.IdentifiedClientState.ClientId)
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  
   123  		// use client state returned from ABCI query in case query height differs
   124  		identifiedClientState := clienttypes.IdentifiedClientState{
   125  			ClientId:    res.IdentifiedClientState.ClientId,
   126  			ClientState: clientStateRes.ClientState,
   127  		}
   128  
   129  		res = types.NewQueryConnectionClientStateResponse(identifiedClientState, clientStateRes.Proof, clientStateRes.ProofHeight)
   130  	}
   131  
   132  	return res, nil
   133  }
   134  
   135  // QueryConnectionConsensusState returns the ConsensusState of a connection end. If
   136  // prove is true, it performs an ABCI store query in order to retrieve the
   137  // merkle proof. Otherwise, it uses the gRPC query client.
   138  func QueryConnectionConsensusState(
   139  	clientCtx clictx.CLIContext, connectionID string, height clienttypes.Height, prove bool,
   140  ) (*types.QueryConnectionConsensusStateResponse, error) {
   141  
   142  	queryClient := types.NewQueryClient(clientCtx)
   143  	req := &types.QueryConnectionConsensusStateRequest{
   144  		ConnectionId:   connectionID,
   145  		RevisionNumber: height.RevisionNumber,
   146  		RevisionHeight: height.RevisionHeight,
   147  	}
   148  
   149  	res, err := queryClient.ConnectionConsensusState(context.Background(), req)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	if prove {
   155  		consensusStateRes, err := utils.QueryConsensusStateABCI(clientCtx, res.ClientId, height)
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  
   160  		res = types.NewQueryConnectionConsensusStateResponse(res.ClientId, consensusStateRes.ConsensusState, height, consensusStateRes.Proof, consensusStateRes.ProofHeight)
   161  	}
   162  
   163  	return res, nil
   164  }
   165  
   166  // ParseClientState unmarshals a cmd input argument from a JSON string to a client state
   167  // If the input is not a JSON, it looks for a path to the JSON file
   168  func ParseClientState(cdc *codec.CodecProxy, arg string) (exported.ClientState, error) {
   169  	var clientState exported.ClientState
   170  	if err := cdc.GetCdc().UnmarshalJSON([]byte(arg), &clientState); err != nil {
   171  		// check for file path if JSON input is not provided
   172  		contents, err := ioutil.ReadFile(arg)
   173  		if err != nil {
   174  			return nil, errors.New("either JSON input nor path to .json file were provided")
   175  		}
   176  		if err := cdc.GetCdc().UnmarshalJSON(contents, &clientState); err != nil {
   177  			return nil, errors.Wrap(err, "error unmarshalling client state")
   178  		}
   179  	}
   180  	return clientState, nil
   181  }
   182  
   183  // ParsePrefix unmarshals an cmd input argument from a JSON string to a commitment
   184  // Prefix. If the input is not a JSON, it looks for a path to the JSON file.
   185  func ParsePrefix(cdc *codec.CodecProxy, arg string) (commitmenttypes.MerklePrefix, error) {
   186  	var prefix commitmenttypes.MerklePrefix
   187  	if err := cdc.GetCdc().UnmarshalJSON([]byte(arg), &prefix); err != nil {
   188  		// check for file path if JSON input is not provided
   189  		contents, err := ioutil.ReadFile(arg)
   190  		if err != nil {
   191  			return commitmenttypes.MerklePrefix{}, errors.New("neither JSON input nor path to .json file were provided")
   192  		}
   193  		if err := cdc.GetCdc().UnmarshalJSON(contents, &prefix); err != nil {
   194  			return commitmenttypes.MerklePrefix{}, errors.Wrap(err, "error unmarshalling commitment prefix")
   195  		}
   196  	}
   197  	return prefix, nil
   198  }
   199  
   200  // ParseProof unmarshals a cmd input argument from a JSON string to a commitment
   201  // Proof. If the input is not a JSON, it looks for a path to the JSON file. It
   202  // then marshals the commitment proof into a proto encoded byte array.
   203  func ParseProof(cdc *codec.CodecProxy, arg string) ([]byte, error) {
   204  	var merkleProof commitmenttypes.MerkleProof
   205  	if err := cdc.GetCdc().UnmarshalJSON([]byte(arg), &merkleProof); err != nil {
   206  		// check for file path if JSON input is not provided
   207  		contents, err := ioutil.ReadFile(arg)
   208  		if err != nil {
   209  			return nil, errors.New("neither JSON input nor path to .json file were provided")
   210  		}
   211  		if err := cdc.GetCdc().UnmarshalJSON(contents, &merkleProof); err != nil {
   212  			return nil, fmt.Errorf("error unmarshalling commitment proof: %w", err)
   213  		}
   214  	}
   215  
   216  	return cdc.GetCdc().MarshalJSON(&merkleProof)
   217  }