github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/core/04-channel/keeper/grpc_query.go (about)

     1  package keeper
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/prefix"
     9  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    10  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/query"
    12  	clienttypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/02-client/types"
    13  	connectiontypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/03-connection/types"
    14  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types"
    15  	host "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/24-host"
    16  
    17  	"google.golang.org/grpc/codes"
    18  	"google.golang.org/grpc/status"
    19  )
    20  
    21  var _ types.QueryServer = (*Keeper)(nil)
    22  
    23  // Channel implements the Query/Channel gRPC method
    24  func (q Keeper) Channel(c context.Context, req *types.QueryChannelRequest) (*types.QueryChannelResponse, error) {
    25  	if req == nil {
    26  		return nil, status.Error(codes.InvalidArgument, "empty request")
    27  	}
    28  
    29  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	ctx := sdk.UnwrapSDKContext(c)
    34  	channel, found := q.GetChannel(ctx, req.PortId, req.ChannelId)
    35  	if !found {
    36  		return nil, status.Error(
    37  			codes.NotFound,
    38  			sdkerrors.Wrapf(types.ErrChannelNotFound, "port-id: %s, channel-id %s", req.PortId, req.ChannelId).Error(),
    39  		)
    40  	}
    41  
    42  	selfHeight := clienttypes.GetSelfHeight(ctx)
    43  	return types.NewQueryChannelResponse(channel, nil, selfHeight), nil
    44  }
    45  
    46  // Channels implements the Query/Channels gRPC method
    47  func (q Keeper) Channels(c context.Context, req *types.QueryChannelsRequest) (*types.QueryChannelsResponse, error) {
    48  	if req == nil {
    49  		return nil, status.Error(codes.InvalidArgument, "empty request")
    50  	}
    51  
    52  	ctx := sdk.UnwrapSDKContext(c)
    53  
    54  	channels := []*types.IdentifiedChannel{}
    55  	store := prefix.NewStore(ctx.KVStore(q.storeKey), []byte(host.KeyChannelEndPrefix))
    56  
    57  	pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error {
    58  		var result types.Channel
    59  		if err := q.cdc.GetProtocMarshal().UnmarshalBinaryBare(value, &result); err != nil {
    60  			return err
    61  		}
    62  
    63  		portID, channelID, err := host.ParseChannelPath(string(key))
    64  		if err != nil {
    65  			return err
    66  		}
    67  
    68  		identifiedChannel := types.NewIdentifiedChannel(portID, channelID, result)
    69  		channels = append(channels, &identifiedChannel)
    70  		return nil
    71  	})
    72  
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	selfHeight := clienttypes.GetSelfHeight(ctx)
    78  	return &types.QueryChannelsResponse{
    79  		Channels:   channels,
    80  		Pagination: pageRes,
    81  		Height:     selfHeight,
    82  	}, nil
    83  }
    84  
    85  // ConnectionChannels implements the Query/ConnectionChannels gRPC method
    86  func (q Keeper) ConnectionChannels(c context.Context, req *types.QueryConnectionChannelsRequest) (*types.QueryConnectionChannelsResponse, error) {
    87  	if req == nil {
    88  		return nil, status.Error(codes.InvalidArgument, "empty request")
    89  	}
    90  
    91  	if err := host.ConnectionIdentifierValidator(req.Connection); err != nil {
    92  		return nil, status.Error(codes.InvalidArgument, err.Error())
    93  	}
    94  
    95  	ctx := sdk.UnwrapSDKContext(c)
    96  
    97  	channels := []*types.IdentifiedChannel{}
    98  	store := prefix.NewStore(ctx.KVStore(q.storeKey), []byte(host.KeyChannelEndPrefix))
    99  
   100  	pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error {
   101  		var result types.Channel
   102  		if err := q.cdc.GetProtocMarshal().UnmarshalBinaryBare(value, &result); err != nil {
   103  			return err
   104  		}
   105  
   106  		// ignore channel and continue to the next item if the connection is
   107  		// different than the requested one
   108  		if result.ConnectionHops[0] != req.Connection {
   109  			return nil
   110  		}
   111  
   112  		portID, channelID, err := host.ParseChannelPath(string(key))
   113  		if err != nil {
   114  			return err
   115  		}
   116  
   117  		identifiedChannel := types.NewIdentifiedChannel(portID, channelID, result)
   118  		channels = append(channels, &identifiedChannel)
   119  		return nil
   120  	})
   121  
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	selfHeight := clienttypes.GetSelfHeight(ctx)
   127  	return &types.QueryConnectionChannelsResponse{
   128  		Channels:   channels,
   129  		Pagination: pageRes,
   130  		Height:     selfHeight,
   131  	}, nil
   132  }
   133  
   134  // ChannelClientState implements the Query/ChannelClientState gRPC method
   135  func (q Keeper) ChannelClientState(c context.Context, req *types.QueryChannelClientStateRequest) (*types.QueryChannelClientStateResponse, error) {
   136  	if req == nil {
   137  		return nil, status.Error(codes.InvalidArgument, "empty request")
   138  	}
   139  
   140  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	ctx := sdk.UnwrapSDKContext(c)
   145  
   146  	clientID, clientState, err := q.GetChannelClientState(ctx, req.PortId, req.ChannelId)
   147  	if err != nil {
   148  		return nil, status.Error(codes.NotFound, err.Error())
   149  	}
   150  
   151  	identifiedClientState := clienttypes.NewIdentifiedClientState(clientID, clientState)
   152  
   153  	selfHeight := clienttypes.GetSelfHeight(ctx)
   154  	return types.NewQueryChannelClientStateResponse(identifiedClientState, nil, selfHeight), nil
   155  }
   156  
   157  // ChannelConsensusState implements the Query/ChannelConsensusState gRPC method
   158  func (q Keeper) ChannelConsensusState(c context.Context, req *types.QueryChannelConsensusStateRequest) (*types.QueryChannelConsensusStateResponse, error) {
   159  	if req == nil {
   160  		return nil, status.Error(codes.InvalidArgument, "empty request")
   161  	}
   162  
   163  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	ctx := sdk.UnwrapSDKContext(c)
   168  
   169  	channel, found := q.GetChannel(ctx, req.PortId, req.ChannelId)
   170  	if !found {
   171  		return nil, status.Error(
   172  			codes.NotFound,
   173  			sdkerrors.Wrapf(types.ErrChannelNotFound, "port-id: %s, channel-id %s", req.PortId, req.ChannelId).Error(),
   174  		)
   175  	}
   176  
   177  	connection, found := q.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
   178  	if !found {
   179  		return nil, status.Error(
   180  			codes.NotFound,
   181  			sdkerrors.Wrapf(connectiontypes.ErrConnectionNotFound, "connection-id: %s", channel.ConnectionHops[0]).Error(),
   182  		)
   183  	}
   184  
   185  	consHeight := clienttypes.NewHeight(req.RevisionNumber, req.RevisionHeight)
   186  	consensusState, found := q.clientKeeper.GetClientConsensusState(ctx, connection.ClientId, consHeight)
   187  	if !found {
   188  		return nil, status.Error(
   189  			codes.NotFound,
   190  			sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "client-id: %s", connection.ClientId).Error(),
   191  		)
   192  	}
   193  
   194  	anyConsensusState, err := clienttypes.PackConsensusState(consensusState)
   195  	if err != nil {
   196  		return nil, status.Error(codes.Internal, err.Error())
   197  	}
   198  
   199  	selfHeight := clienttypes.GetSelfHeight(ctx)
   200  	return types.NewQueryChannelConsensusStateResponse(connection.ClientId, anyConsensusState, consHeight, nil, selfHeight), nil
   201  }
   202  
   203  // PacketCommitment implements the Query/PacketCommitment gRPC method
   204  func (q Keeper) PacketCommitment(c context.Context, req *types.QueryPacketCommitmentRequest) (*types.QueryPacketCommitmentResponse, error) {
   205  	if req == nil {
   206  		return nil, status.Error(codes.InvalidArgument, "empty request")
   207  	}
   208  
   209  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   210  		return nil, err
   211  	}
   212  
   213  	if req.Sequence == 0 {
   214  		return nil, status.Error(codes.InvalidArgument, "packet sequence cannot be 0")
   215  	}
   216  
   217  	ctx := sdk.UnwrapSDKContext(c)
   218  
   219  	commitmentBz := q.GetPacketCommitment(ctx, req.PortId, req.ChannelId, req.Sequence)
   220  	if len(commitmentBz) == 0 {
   221  		return nil, status.Error(codes.NotFound, "packet commitment hash not found")
   222  	}
   223  
   224  	selfHeight := clienttypes.GetSelfHeight(ctx)
   225  	return types.NewQueryPacketCommitmentResponse(commitmentBz, nil, selfHeight), nil
   226  }
   227  
   228  // PacketCommitments implements the Query/PacketCommitments gRPC method
   229  func (q Keeper) PacketCommitments(c context.Context, req *types.QueryPacketCommitmentsRequest) (*types.QueryPacketCommitmentsResponse, error) {
   230  	if req == nil {
   231  		return nil, status.Error(codes.InvalidArgument, "empty request")
   232  	}
   233  
   234  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   235  		return nil, err
   236  	}
   237  
   238  	ctx := sdk.UnwrapSDKContext(c)
   239  
   240  	commitments := []*types.PacketState{}
   241  	store := prefix.NewStore(ctx.KVStore(q.storeKey), []byte(host.PacketCommitmentPrefixPath(req.PortId, req.ChannelId)))
   242  
   243  	pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error {
   244  		keySplit := strings.Split(string(key), "/")
   245  
   246  		sequence, err := strconv.ParseUint(keySplit[len(keySplit)-1], 10, 64)
   247  		if err != nil {
   248  			return err
   249  		}
   250  
   251  		commitment := types.NewPacketState(req.PortId, req.ChannelId, sequence, value)
   252  		commitments = append(commitments, &commitment)
   253  		return nil
   254  	})
   255  
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  
   260  	selfHeight := clienttypes.GetSelfHeight(ctx)
   261  	return &types.QueryPacketCommitmentsResponse{
   262  		Commitments: commitments,
   263  		Pagination:  pageRes,
   264  		Height:      selfHeight,
   265  	}, nil
   266  }
   267  
   268  // PacketReceipt implements the Query/PacketReceipt gRPC method
   269  func (q Keeper) PacketReceipt(c context.Context, req *types.QueryPacketReceiptRequest) (*types.QueryPacketReceiptResponse, error) {
   270  	if req == nil {
   271  		return nil, status.Error(codes.InvalidArgument, "empty request")
   272  	}
   273  
   274  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	if req.Sequence == 0 {
   279  		return nil, status.Error(codes.InvalidArgument, "packet sequence cannot be 0")
   280  	}
   281  
   282  	ctx := sdk.UnwrapSDKContext(c)
   283  
   284  	_, recvd := q.GetPacketReceipt(ctx, req.PortId, req.ChannelId, req.Sequence)
   285  
   286  	selfHeight := clienttypes.GetSelfHeight(ctx)
   287  	return types.NewQueryPacketReceiptResponse(recvd, nil, selfHeight), nil
   288  }
   289  
   290  // PacketAcknowledgement implements the Query/PacketAcknowledgement gRPC method
   291  func (q Keeper) PacketAcknowledgement(c context.Context, req *types.QueryPacketAcknowledgementRequest) (*types.QueryPacketAcknowledgementResponse, error) {
   292  	if req == nil {
   293  		return nil, status.Error(codes.InvalidArgument, "empty request")
   294  	}
   295  
   296  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   297  		return nil, err
   298  	}
   299  
   300  	if req.Sequence == 0 {
   301  		return nil, status.Error(codes.InvalidArgument, "packet sequence cannot be 0")
   302  	}
   303  
   304  	ctx := sdk.UnwrapSDKContext(c)
   305  
   306  	acknowledgementBz, found := q.GetPacketAcknowledgement(ctx, req.PortId, req.ChannelId, req.Sequence)
   307  	if !found || len(acknowledgementBz) == 0 {
   308  		return nil, status.Error(codes.NotFound, "packet acknowledgement hash not found")
   309  	}
   310  
   311  	selfHeight := clienttypes.GetSelfHeight(ctx)
   312  	return types.NewQueryPacketAcknowledgementResponse(acknowledgementBz, nil, selfHeight), nil
   313  }
   314  
   315  // PacketAcknowledgements implements the Query/PacketAcknowledgements gRPC method
   316  func (q Keeper) PacketAcknowledgements(c context.Context, req *types.QueryPacketAcknowledgementsRequest) (*types.QueryPacketAcknowledgementsResponse, error) {
   317  	if req == nil {
   318  		return nil, status.Error(codes.InvalidArgument, "empty request")
   319  	}
   320  
   321  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   322  		return nil, err
   323  	}
   324  
   325  	ctx := sdk.UnwrapSDKContext(c)
   326  
   327  	acks := []*types.PacketState{}
   328  	store := prefix.NewStore(ctx.KVStore(q.storeKey), []byte(host.PacketAcknowledgementPrefixPath(req.PortId, req.ChannelId)))
   329  
   330  	// if a list of packet sequences is provided then query for each specific ack and return a list <= len(req.PacketCommitmentSequences)
   331  	// otherwise, maintain previous behaviour and perform paginated query
   332  	for _, seq := range req.PacketCommitmentSequences {
   333  		acknowledgementBz, found := q.GetPacketAcknowledgement(ctx, req.PortId, req.ChannelId, seq)
   334  		if !found || len(acknowledgementBz) == 0 {
   335  			continue
   336  		}
   337  
   338  		ack := types.NewPacketState(req.PortId, req.ChannelId, seq, acknowledgementBz)
   339  		acks = append(acks, &ack)
   340  	}
   341  
   342  	if len(req.PacketCommitmentSequences) > 0 {
   343  		selfHeight := clienttypes.GetSelfHeight(ctx)
   344  		return &types.QueryPacketAcknowledgementsResponse{
   345  			Acknowledgements: acks,
   346  			Pagination:       nil,
   347  			Height:           selfHeight,
   348  		}, nil
   349  	}
   350  
   351  	pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error {
   352  		keySplit := strings.Split(string(key), "/")
   353  
   354  		sequence, err := strconv.ParseUint(keySplit[len(keySplit)-1], 10, 64)
   355  		if err != nil {
   356  			return err
   357  		}
   358  
   359  		ack := types.NewPacketState(req.PortId, req.ChannelId, sequence, value)
   360  		acks = append(acks, &ack)
   361  		return nil
   362  	})
   363  
   364  	if err != nil {
   365  		return nil, err
   366  	}
   367  
   368  	selfHeight := clienttypes.GetSelfHeight(ctx)
   369  	return &types.QueryPacketAcknowledgementsResponse{
   370  		Acknowledgements: acks,
   371  		Pagination:       pageRes,
   372  		Height:           selfHeight,
   373  	}, nil
   374  }
   375  
   376  // UnreceivedPackets implements the Query/UnreceivedPackets gRPC method. Given
   377  // a list of counterparty packet commitments, the querier checks if the packet
   378  // has already been received by checking if a receipt exists on this
   379  // chain for the packet sequence. All packets that haven't been received yet
   380  // are returned in the response
   381  // Usage: To use this method correctly, first query all packet commitments on
   382  // the sending chain using the Query/PacketCommitments gRPC method.
   383  // Then input the returned sequences into the QueryUnreceivedPacketsRequest
   384  // and send the request to this Query/UnreceivedPackets on the **receiving**
   385  // chain. This gRPC method will then return the list of packet sequences that
   386  // are yet to be received on the receiving chain.
   387  //
   388  // NOTE: The querier makes the assumption that the provided list of packet
   389  // commitments is correct and will not function properly if the list
   390  // is not up to date. Ideally the query height should equal the latest height
   391  // on the counterparty's client which represents this chain.
   392  func (q Keeper) UnreceivedPackets(c context.Context, req *types.QueryUnreceivedPacketsRequest) (*types.QueryUnreceivedPacketsResponse, error) {
   393  	if req == nil {
   394  		return nil, status.Error(codes.InvalidArgument, "empty request")
   395  	}
   396  
   397  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   398  		return nil, err
   399  	}
   400  
   401  	ctx := sdk.UnwrapSDKContext(c)
   402  
   403  	var unreceivedSequences = []uint64{}
   404  
   405  	for i, seq := range req.PacketCommitmentSequences {
   406  		if seq == 0 {
   407  			return nil, status.Errorf(codes.InvalidArgument, "packet sequence %d cannot be 0", i)
   408  		}
   409  
   410  		// if packet receipt exists on the receiving chain, then packet has already been received
   411  		if _, found := q.GetPacketReceipt(ctx, req.PortId, req.ChannelId, seq); !found {
   412  			unreceivedSequences = append(unreceivedSequences, seq)
   413  		}
   414  
   415  	}
   416  
   417  	selfHeight := clienttypes.GetSelfHeight(ctx)
   418  	return &types.QueryUnreceivedPacketsResponse{
   419  		Sequences: unreceivedSequences,
   420  		Height:    selfHeight,
   421  	}, nil
   422  }
   423  
   424  // UnreceivedAcks implements the Query/UnreceivedAcks gRPC method. Given
   425  // a list of counterparty packet acknowledgements, the querier checks if the packet
   426  // has already been received by checking if the packet commitment still exists on this
   427  // chain (original sender) for the packet sequence.
   428  // All acknowledgmeents that haven't been received yet are returned in the response.
   429  // Usage: To use this method correctly, first query all packet acknowledgements on
   430  // the original receiving chain (ie the chain that wrote the acks) using the Query/PacketAcknowledgements gRPC method.
   431  // Then input the returned sequences into the QueryUnreceivedAcksRequest
   432  // and send the request to this Query/UnreceivedAcks on the **original sending**
   433  // chain. This gRPC method will then return the list of packet sequences whose
   434  // acknowledgements are already written on the receiving chain but haven't yet
   435  // been received back to the sending chain.
   436  //
   437  // NOTE: The querier makes the assumption that the provided list of packet
   438  // acknowledgements is correct and will not function properly if the list
   439  // is not up to date. Ideally the query height should equal the latest height
   440  // on the counterparty's client which represents this chain.
   441  func (q Keeper) UnreceivedAcks(c context.Context, req *types.QueryUnreceivedAcksRequest) (*types.QueryUnreceivedAcksResponse, error) {
   442  	if req == nil {
   443  		return nil, status.Error(codes.InvalidArgument, "empty request")
   444  	}
   445  
   446  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   447  		return nil, err
   448  	}
   449  
   450  	ctx := sdk.UnwrapSDKContext(c)
   451  
   452  	var unreceivedSequences = []uint64{}
   453  
   454  	for i, seq := range req.PacketAckSequences {
   455  		if seq == 0 {
   456  			return nil, status.Errorf(codes.InvalidArgument, "packet sequence %d cannot be 0", i)
   457  		}
   458  
   459  		// if packet commitment still exists on the original sending chain, then packet ack has not been received
   460  		// since processing the ack will delete the packet commitment
   461  		if commitment := q.GetPacketCommitment(ctx, req.PortId, req.ChannelId, seq); len(commitment) != 0 {
   462  			unreceivedSequences = append(unreceivedSequences, seq)
   463  		}
   464  
   465  	}
   466  
   467  	selfHeight := clienttypes.GetSelfHeight(ctx)
   468  	return &types.QueryUnreceivedAcksResponse{
   469  		Sequences: unreceivedSequences,
   470  		Height:    selfHeight,
   471  	}, nil
   472  }
   473  
   474  // NextSequenceReceive implements the Query/NextSequenceReceive gRPC method
   475  func (q Keeper) NextSequenceReceive(c context.Context, req *types.QueryNextSequenceReceiveRequest) (*types.QueryNextSequenceReceiveResponse, error) {
   476  	if req == nil {
   477  		return nil, status.Error(codes.InvalidArgument, "empty request")
   478  	}
   479  
   480  	if err := validategRPCRequest(req.PortId, req.ChannelId); err != nil {
   481  		return nil, err
   482  	}
   483  
   484  	ctx := sdk.UnwrapSDKContext(c)
   485  	sequence, found := q.GetNextSequenceRecv(ctx, req.PortId, req.ChannelId)
   486  	if !found {
   487  		return nil, status.Error(
   488  			codes.NotFound,
   489  			sdkerrors.Wrapf(types.ErrSequenceReceiveNotFound, "port-id: %s, channel-id %s", req.PortId, req.ChannelId).Error(),
   490  		)
   491  	}
   492  
   493  	selfHeight := clienttypes.GetSelfHeight(ctx)
   494  	return types.NewQueryNextSequenceReceiveResponse(sequence, nil, selfHeight), nil
   495  }
   496  
   497  func validategRPCRequest(portID, channelID string) error {
   498  	if err := host.PortIdentifierValidator(portID); err != nil {
   499  		return status.Error(codes.InvalidArgument, err.Error())
   500  	}
   501  
   502  	if err := host.ChannelIdentifierValidator(channelID); err != nil {
   503  		return status.Error(codes.InvalidArgument, err.Error())
   504  	}
   505  
   506  	return nil
   507  }