Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: wire new handlers to grpc #22333

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open

feat: wire new handlers to grpc #22333

wants to merge 14 commits into from

Conversation

randygrok
Copy link
Collaborator

@randygrok randygrok commented Oct 22, 2024

Description

Closes: #XXXX


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • included the correct type prefix in the PR title, you can find examples of the prefixes below:
  • confirmed ! in the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • reviewed "Files changed" and left comments if necessary
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • updated the relevant documentation or specification, including comments for documenting Go code
  • confirmed all CI checks have passed

Reviewers Checklist

All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.

Please see Pull Request Reviewer section in the contributing guide for more information on how to review a pull request.

I have...

  • confirmed the correct type prefix in the PR title
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic, API design and naming, documentation is accurate, tests and test coverage

Summary by CodeRabbit

  • New Features

    • Introduced a gRPC service for handling queries in the Cosmos ecosystem, including methods for querying and listing query handlers.
    • Added flexible message types for requests and responses, enhancing data handling capabilities.
  • Bug Fixes

    • Improved error handling in the service registration process to ensure robust communication.
  • Tests

    • Implemented unit tests for the new gRPC service, validating the functionality of query and handler listing methods.
  • Chores

    • Updated Go module dependencies and versioning for improved compatibility and functionality.

@github-actions github-actions bot added C:server/v2 Issues related to server/v2 C:server/v2 api labels Oct 22, 2024
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
anypb "google.golang.org/protobuf/types/known/anypb"
io "io"
reflect "reflect"

Check notice

Code scanning / CodeQL

Sensitive package import Note

Certain system packages contain functions which may be a possible source of non-determinism
x.Request = value.Message().Interface().(*anypb.Any)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.QueryRequest"))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.QueryRequest"))
}
panic(fmt.Errorf("message cosmos.base.grpc.v2.QueryRequest does not contain field %s", fd.FullName()))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
x.Response = value.Message().Interface().(*anypb.Any)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.QueryResponse"))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.QueryResponse"))
}
panic(fmt.Errorf("message cosmos.base.grpc.v2.QueryResponse does not contain field %s", fd.FullName()))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.ListQueryHandlersRequest"))
}
panic(fmt.Errorf("message cosmos.base.grpc.v2.ListQueryHandlersRequest does not contain field %s", fd.FullName()))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
x.Handlers = *clv.list
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.ListQueryHandlersResponse"))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.ListQueryHandlersResponse"))
}
panic(fmt.Errorf("message cosmos.base.grpc.v2.ListQueryHandlersResponse does not contain field %s", fd.FullName()))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
x.ResponseName = value.Interface().(string)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.Handler"))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.Handler"))
}
panic(fmt.Errorf("message cosmos.base.grpc.v2.Handler does not contain field %s", fd.FullName()))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
Copy link
Contributor

coderabbitai bot commented Oct 25, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

This pull request introduces a new gRPC service for the Cosmos ecosystem, defining several message types and service methods for handling queries. Key additions include QueryRequest, QueryResponse, ListQueryHandlersRequest, and ListQueryHandlersResponse, along with a Handler type. The service is registered in the gRPC server, and unit tests have been added to validate the functionality of the new service methods. Additionally, the Go module file has been updated to reflect changes in dependencies and Go versioning.

Changes

File Path Change Summary
api/cosmos/base/grpc/v2/service.pulsar.go Added types: QueryRequest, QueryResponse, ListQueryHandlersRequest, ListQueryHandlersResponse, Handler; added ProtoReflect methods for each type.
proto/cosmos/base/grpc/v2/service.proto Added service Service with RPC methods Query and ListQueryHandlers; defined message types for requests and responses.
server/v2/api/grpc/server.go Added RegisterV2Service(grpcSrv, appI) method to register the new service with the gRPC server.
server/v2/api/grpc/service.go Introduced V2Service struct and methods Query and ListQueryHandlers; added service registration logic.
server/v2/api/grpc/service_test.go Added unit tests for Query and ListQueryHandlers methods; created mock request/response types and application interface.
server/v2/go.mod Updated Go version to 1.23.1, added and updated several dependencies.

Possibly related PRs

Suggested labels

C:server/v2 cometbft, C:x/accounts, C:x/authz, C:x/bank, C:x/consensus, C:x/distribution, C:x/epochs, C:x/feegrant, C:x/gov, C:x/group, C:x/mint, C:x/nft, C:x/slashing, C:collections, C:core/testing, C:Store, C:x/protocolpool, C:x/accounts/lockup, C:x/accounts/multisig, C:server/v2 stf, backport/v0.52.x, C:x/accounts/base

Suggested reviewers

  • julienrbrt
  • sontrinh16
  • kocubinski
  • tac0turtle
  • testinginprod

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@randygrok randygrok marked this pull request as ready for review October 25, 2024 19:49
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (9)
proto/cosmos/base/grpc/v2/service.proto (2)

8-12: Consider adding service and RPC method documentation

While the service design is solid, adding documentation comments would help developers understand:

  • The purpose of the Service
  • When to use Query vs ListQueryHandlers
  • The expected types that can be passed in the Any message

Add proto comments like this:

 // Service provides a generic query interface for cosmos-sdk applications
 service Service {
   // Query handles dynamic querying of application state
   rpc Query(QueryRequest) returns (QueryResponse) {}

   // ListQueryHandlers returns all available query handlers supported by this service
   rpc ListQueryHandlers(ListQueryHandlersRequest) returns (ListQueryHandlersResponse) {}
 }

28-31: Enhance Handler message field naming and documentation

The Handler message fields could be more descriptive:

Consider this improvement:

 message Handler {
-  string request_name  = 1;
-  string response_name = 2;
   // fully_qualified_request_type is the protobuf message type URL of the request
   string fully_qualified_request_type  = 1;
   // fully_qualified_response_type is the protobuf message type URL of the response
   string fully_qualified_response_type = 2;
 }
server/v2/api/grpc/service_test.go (4)

27-29: Enhance ValidateBasic implementation.

The ValidateBasic method should validate the Data field to ensure it's not empty or malformed.

func (m *MockRequestMessage) ValidateBasic() error {
-	return nil
 	if m.Data == "" {
 		return fmt.Errorf("data field cannot be empty")
 	}
 	return nil
}

25-25: Improve String() implementation for better debugging.

The String() method returns an empty string, which isn't helpful for debugging. Consider implementing a meaningful string representation.

-func (m *MockRequestMessage) String() string { return "" }
 func (m *MockRequestMessage) String() string {
 	return fmt.Sprintf("MockRequestMessage{Data: %s}", m.Data)
}

Also applies to: 36-36


61-158: Enhance test coverage and readability.

Consider the following improvements:

  1. Add test case for invalid request message (malformed protobuf)
  2. Use a named constant for the height parameter instead of magic number 0
  3. Make test data more descriptive (e.g., "request" -> "test_query_data")

Example additional test case:

{
    name: "invalid request message",
    setupMock: func(app *mockApp[transaction.Tx]) {
        app.On("QueryHandlers").Return(map[string]appmodulev2.Handler{})
    },
    request: &QueryRequest{
        Request: &gogoproto.Any{
            TypeUrl: "/MockRequestMessage",
            Value:   []byte("invalid protobuf"),
        },
    },
    expectError:   true,
    expectedError: "rpc error: code = InvalidArgument desc = failed to unmarshal request",
},

160-209: Add more test cases for ListQueryHandlers.

The current test suite only covers the success scenario. Consider adding test cases for:

  1. Empty handlers map
  2. Multiple handlers
  3. Error scenarios (if applicable)

Example additional test case:

{
    name: "empty handlers",
    setupMock: func(app *mockApp[transaction.Tx]) {
        app.On("QueryHandlers").Return(map[string]appmodulev2.Handler{})
    },
},
server/v2/api/grpc/service.go (1)

76-85: Ensure deterministic ordering when listing query handlers

Iterating over maps in Go does not guarantee order, which may lead to non-deterministic responses. If the order of handlers in ListQueryHandlersResponse matters, consider sorting the handler names.

Apply this diff to sort the handler names:

 import (
     "sort"
 )

 var handlerDescriptors []*Handler
 handlerNames := make([]string, 0, len(handlersMap))
 for handlerName := range handlersMap {
     handlerNames = append(handlerNames, handlerName)
 }
 sort.Strings(handlerNames)

-for handlerName := range handlersMap {
 for _, handlerName := range handlerNames {
     msg := handlersMap[handlerName].MakeMsg()
     resp := handlersMap[handlerName].MakeMsgResp()

     handlerDescriptors = append(handlerDescriptors, &Handler{
         RequestName:  proto.MessageName(msg),
         ResponseName: proto.MessageName(resp),
     })
 }
api/cosmos/base/grpc/v2/service.pulsar.go (2)

5-5: Unnecessary alias for standard library import

On line 5, the standard library package fmt is imported with an alias, which is unnecessary:

import (
	fmt "fmt"

Per the Uber Go Style Guide, standard library packages should be imported without aliases unless there's a naming conflict. Removing the alias improves code clarity.

Apply this diff to remove the unnecessary alias:

 import (
-	fmt "fmt"
 	"fmt"

11-13: Unnecessary aliases for standard library imports

Lines 11-13 import standard library packages with aliases, which is unnecessary:

	io "io"
	reflect "reflect"
	sync "sync"

According to the Uber Go Style Guide, standard library packages should be imported without aliases unless there's a naming conflict. Removing these aliases enhances readability.

Apply this diff to remove the unnecessary aliases:

 import (
 	// other imports
-	io "io"
-	reflect "reflect"
-	sync "sync"
 	"io"
 	"reflect"
 	"sync"
 )
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between cd3ce0c and f08976a.

⛔ Files ignored due to path filters (3)
  • api/cosmos/base/grpc/v2/service_grpc.pb.go is excluded by !**/*.pb.go
  • server/v2/api/grpc/service.pb.go is excluded by !**/*.pb.go
  • server/v2/go.sum is excluded by !**/*.sum
📒 Files selected for processing (6)
  • api/cosmos/base/grpc/v2/service.pulsar.go (1 hunks)
  • proto/cosmos/base/grpc/v2/service.proto (1 hunks)
  • server/v2/api/grpc/server.go (1 hunks)
  • server/v2/api/grpc/service.go (1 hunks)
  • server/v2/api/grpc/service_test.go (1 hunks)
  • server/v2/go.mod (5 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
api/cosmos/base/grpc/v2/service.pulsar.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/api/grpc/server.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/api/grpc/service.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/api/grpc/service_test.go (2)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.


Pattern **/*_test.go: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"

🪛 buf
proto/cosmos/base/grpc/v2/service.proto

2-2: Files with package "cosmos.base.grpc.v2" must be within a directory "cosmos/base/grpc/v2" relative to root but were in directory "proto/cosmos/base/grpc/v2".

(PACKAGE_DIRECTORY_MATCH)

🔇 Additional comments (6)
proto/cosmos/base/grpc/v2/service.proto (1)

14-20: Consider adding validation for Any messages

The QueryRequest and QueryResponse messages use Any type without apparent validation. Consider:

  1. Adding comments describing valid message types
  2. Implementing runtime validation in the service implementation

Let's check if there are any validation mechanisms in place:

server/v2/api/grpc/server.go (1)

74-75: Verify service implementation and integration.

Let's verify that the service implementation exists and is properly integrated with the query handling system.

✅ Verification successful

Service implementation is properly integrated and functional

The verification shows that:

  1. The V2Service implementation exists in server/v2/api/grpc/service.go with proper query handling
  2. The service registration function is correctly implemented with type safety checks
  3. The service provides core functionality for:
    • Query handling with proper error management
    • Query handler listing capability
    • Integration with the app interface through serverv2.AppI[T]
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the V2Service implementation and its integration

# Test 1: Check if the service implementation exists
echo "Checking for V2Service implementation..."
rg -l "type V2Service" .

# Test 2: Check the service registration function
echo "Checking service registration implementation..."
rg -l "func RegisterV2Service"

# Test 3: Check for protobuf service definition
echo "Checking for protobuf service definition..."
fd -e proto | xargs rg "service.*V2"

Length of output: 453


Script:

#!/bin/bash
# Let's examine the service implementation and registration in detail

# Check the content of the service implementation file
echo "=== Service Implementation ==="
cat ./server/v2/api/grpc/service.go

# Look for any V2-related interfaces or types in the codebase
echo -e "\n=== V2-related Types and Interfaces ==="
rg "type.*V2" -A 3

# Check for any proto files that might contain the service definition
echo -e "\n=== Proto Files in the Repository ==="
fd -e proto

Length of output: 23175

server/v2/api/grpc/service_test.go (1)

42-59: LGTM! Well-structured mock implementation.

The mock app implementation is well-structured with proper error handling and type assertions.

server/v2/go.mod (3)

3-5: Verify Go toolchain compatibility.

The toolchain version (1.23.2) is ahead of the specified Go version (1.23.1). While this usually works, it's recommended to keep them in sync to avoid potential compatibility issues.


37-37: Review dependency version updates.

The updates to key dependencies appear to be minor version bumps:

  • go-toml/v2: v2.2.2 -> v2.2.3
  • cockroachdb/errors: v1.11.1 -> v1.11.3
  • cockroachdb/pebble: v1.1.2

These are patch version updates and should not introduce breaking changes. However, please ensure that the changes in these dependencies, particularly in cockroachdb packages, don't affect the performance or behavior of your database operations.

Also applies to: 67-70


27-27: Verify dependency compatibility with new gRPC handlers.

The addition of bank module and numerous indirect dependencies aligns with the PR's objective of wiring new gRPC handlers. However, let's verify the compatibility of these dependencies.

Also applies to: 51-157

✅ Verification successful

Based on the search results, I can see that the bank module is extensively integrated into the codebase with proper gRPC handlers and dependencies. The key findings show:

  1. The bank module has proper gRPC service definitions and handlers in both v1beta1 and v2 versions
  2. The module is properly integrated with protobuf/gRPC infrastructure
  3. The handlers are properly wired up in the keeper layer
  4. The module is used extensively across tests and other modules
  5. The dependency is used consistently across the codebase

Let me verify one more aspect about the handlers implementation:


Let me check the actual handler implementations:


Let me check the full handler implementations to verify all gRPC handlers are properly implemented:


Bank module's gRPC handlers are properly implemented and compatible

The verification confirms that the bank module's gRPC handlers are properly implemented with all necessary message handlers and query handlers:

  • Message handlers:

    • MsgUpdateParams - For parameter updates
    • MsgSend - For coin transfers
    • MsgMint - For minting new coins
  • Query handlers:

    • QueryParams - For querying module parameters
    • QueryBalance - For querying account balances

The handlers include proper input validation, address encoding/decoding, and error handling. The dependency is well integrated and compatible with the gRPC infrastructure.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential dependency conflicts or issues

# Test 1: Check for any dependency conflicts
go mod verify

# Test 2: Check if there are any unnecessary dependencies
go mod tidy -v

# Test 3: Check if all dependencies are being used
go mod why -m cosmossdk.io/x/bank

Length of output: 279


Script:

#!/bin/bash
# Let's analyze the Go imports and dependencies using grep and ast-grep
# since Go toolchain is not available in the sandbox

# Check for bank module imports and usage
rg -l "cosmossdk.io/x/bank" --type go

# Check for gRPC related imports and handlers
rg "google.golang.org/grpc" --type go -A 2

# Look for bank module usage in handlers
ast-grep --pattern 'func $_($_ *server.Context) $_Handler {
  $$$
}'

# Check for any bank module type usage
rg "bank\." --type go -A 2

Length of output: 436716


Script:

#!/bin/bash
# Check bank module handler implementations
rg -l "func.*Handler" x/bank/v2/keeper/

Length of output: 70


Script:

#!/bin/bash
# Check the bank module handler implementations
rg "func.*Handler" x/bank/v2/keeper/handlers.go -A 5

Length of output: 303


Script:

#!/bin/bash
# Check all handler implementations in the bank module
cat x/bank/v2/keeper/handlers.go

Length of output: 4109

Comment on lines 1 to 7
syntax = "proto3";
package cosmos.base.grpc.v2;

import "google/protobuf/any.proto";

option go_package = "github.com/cosmos/cosmos-sdk/server/v2/api/grpc";

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Package directory structure needs adjustment

The package "cosmos.base.grpc.v2" should be within a directory "cosmos/base/grpc/v2" relative to root, but it's currently in "proto/cosmos/base/grpc/v2". This mismatch could cause issues with buf and other Protocol Buffer tools.

Consider moving the file to the correct directory structure or adjusting the package name to match the current directory structure.

🧰 Tools
🪛 buf

2-2: Files with package "cosmos.base.grpc.v2" must be within a directory "cosmos/base/grpc/v2" relative to root but were in directory "proto/cosmos/base/grpc/v2".

(PACKAGE_DIRECTORY_MATCH)

Comment on lines 74 to 75
RegisterV2Service(grpcSrv, appI)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling and documentation for service registration.

The RegisterV2Service call should include error handling to ensure proper service registration. Additionally, consider adding a comment explaining the purpose of this registration.

Apply this diff:

 	// Register the v2 gRPC service for handling queries
 	if err := RegisterV2Service(grpcSrv, appI); err != nil {
 		return fmt.Errorf("failed to register v2 service: %w", err)
 	}
-	RegisterV2Service(grpcSrv, appI)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RegisterV2Service(grpcSrv, appI)
// Register the v2 gRPC service for handling queries
if err := RegisterV2Service(grpcSrv, appI); err != nil {
return fmt.Errorf("failed to register v2 service: %w", err)
}

Comment on lines 31 to 40
type MockResponseMessage struct {
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}

func (m *MockResponseMessage) Reset() {}
func (m *MockResponseMessage) String() string { return "" }
func (m *MockResponseMessage) ProtoMessage() {}
func (m *MockResponseMessage) ValidateBasic() error {
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add XXX_MessageName method to MockResponseMessage.

For consistency with MockRequestMessage, implement the XXX_MessageName method for MockResponseMessage.

 func (m *MockResponseMessage) XXX_MessageName() string {
 	return "MockResponseMessage"
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type MockResponseMessage struct {
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}
func (m *MockResponseMessage) Reset() {}
func (m *MockResponseMessage) String() string { return "" }
func (m *MockResponseMessage) ProtoMessage() {}
func (m *MockResponseMessage) ValidateBasic() error {
return nil
}
type MockResponseMessage struct {
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}
func (m *MockResponseMessage) Reset() {}
func (m *MockResponseMessage) String() string { return "" }
func (m *MockResponseMessage) ProtoMessage() {}
func (m *MockResponseMessage) ValidateBasic() error {
return nil
}
func (m *MockResponseMessage) XXX_MessageName() string {
return "MockResponseMessage"
}

Comment on lines 211 to 224
func createTestRequest(t *testing.T) *QueryRequest {
reqMsg := &MockRequestMessage{Data: "request"}
reqBytes, err := proto.Marshal(reqMsg)
if err != nil {
t.Fatalf("failed to marshal request: %v", err)
}

return &QueryRequest{
Request: &gogoproto.Any{
TypeUrl: "/" proto.MessageName(reqMsg),
Value: reqBytes,
},
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Make createTestRequest more flexible.

Consider parameterizing the helper function to make it more reusable for different test scenarios.

-func createTestRequest(t *testing.T) *QueryRequest {
 func createTestRequest(t *testing.T, data string) *QueryRequest {
-	reqMsg := &MockRequestMessage{Data: "request"}
 	reqMsg := &MockRequestMessage{Data: data}
	reqBytes, err := proto.Marshal(reqMsg)
	if err != nil {
		t.Fatalf("failed to marshal request: %v", err)
	}

	return &QueryRequest{
		Request: &gogoproto.Any{
			TypeUrl: "/"   proto.MessageName(reqMsg),
			Value:   reqBytes,
		},
	}
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func createTestRequest(t *testing.T) *QueryRequest {
reqMsg := &MockRequestMessage{Data: "request"}
reqBytes, err := proto.Marshal(reqMsg)
if err != nil {
t.Fatalf("failed to marshal request: %v", err)
}
return &QueryRequest{
Request: &gogoproto.Any{
TypeUrl: "/" proto.MessageName(reqMsg),
Value: reqBytes,
},
}
}
func createTestRequest(t *testing.T, data string) *QueryRequest {
reqMsg := &MockRequestMessage{Data: data}
reqBytes, err := proto.Marshal(reqMsg)
if err != nil {
t.Fatalf("failed to marshal request: %v", err)
}
return &QueryRequest{
Request: &gogoproto.Any{
TypeUrl: "/" proto.MessageName(reqMsg),
Value: reqBytes,
},
}
}

Comment on lines 47 to 48
return nil, status.Errorf(codes.NotFound, "handler not found for %s", msgName)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid exposing internal error details to clients

Returning detailed error messages can leak internal information and pose security risks. Consider returning generic error messages to the client and logging the detailed errors internally.

Apply this diff to adjust the error messages:

     if !exists {
-        return nil, status.Errorf(codes.NotFound, "handler not found for %s", msgName)
         return nil, status.Error(codes.NotFound, "handler not found")
     }

     if err := proto.Unmarshal(request.Request.Value, protoMsg); err != nil {
-        return nil, status.Errorf(codes.InvalidArgument, "failed to unmarshal request: %v", err)
         return nil, status.Error(codes.InvalidArgument, "invalid request format")
     }

     if err != nil {
-        return nil, status.Errorf(codes.Internal, "query failed: %v", err)
         return nil, status.Error(codes.Internal, "internal server error")
     }

Also applies to: 52-53, 57-58

Comment on lines 19 to 21
if server == nil || app == nil {
panic("server and app must not be nil")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid panicking; return an error instead in RegisterV2Service

Panicking on invalid input can cause the application to crash unexpectedly. It's better to return an error and allow the caller to handle it appropriately.

Apply this diff to return an error:

-func RegisterV2Service[T transaction.Tx](server *grpc.Server, app serverv2.AppI[T]) {
 func RegisterV2Service[T transaction.Tx](server *grpc.Server, app serverv2.AppI[T]) error {
     if server == nil || app == nil {
-        panic("server and app must not be nil")
         return errors.New("server and app must not be nil")
     }
     RegisterServiceServer(server, NewV2Service(app))
     return nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if server == nil || app == nil {
panic("server and app must not be nil")
}
if server == nil || app == nil {
return errors.New("server and app must not be nil")
}

Comment on lines 1 to 2
// Code generated by protoc-gen-go-pulsar. DO NOT EDIT.
package grpcv2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Inconsistent code generation tools used

The file starts with a code generation notice from protoc-gen-go-pulsar on lines 1-2:

// Code generated by protoc-gen-go-pulsar. DO NOT EDIT.

However, later in the file at lines 2220-2221, there is another code generation notice indicating the code was generated by protoc-gen-go:

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:

Mixing generated code from different tools in the same file may lead to conflicts, unexpected behavior, and maintenance challenges. Consider separating the generated code into different files or ensuring that only a single code generator is used for this file to maintain consistency.

Comment on lines 341 to 439
unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) {
x := input.Message.Interface().(*QueryRequest)
if x == nil {
return protoiface.UnmarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Flags: input.Flags,
}, nil
}
options := runtime.UnmarshalInputToOptions(input)
_ = options
dAtA := input.Buf
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift = 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Request", wireType)
}
var msglen int
for shift := uint(0); ; shift = 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx msglen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
if x.Request == nil {
x.Request = &anypb.Any{}
}
if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Request); err != nil {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := runtime.Skip(dAtA[iNdEx:])
if err != nil {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
if (skippy < 0) || (iNdEx skippy) < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if (iNdEx skippy) > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
if !options.DiscardUnknown {
x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx skippy]...)
}
iNdEx = skippy
}
}

if iNdEx > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor long function for better maintainability

The unmarshal function in ProtoMethods spans over 98 lines (lines 341-439). Long functions can be difficult to read, test, and maintain. Per the Uber Go Style Guide, functions should be kept short and well-focused, ideally not exceeding 40 lines.

Consider refactoring the unmarshal function by breaking it into smaller, reusable helper functions that handle specific tasks such as:

  • Parsing the wire format
  • Processing each field based on fieldNum
  • Error handling and validation

This will improve readability and maintainability of the code.

Comment on lines 2220 to 2221
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Duplicate code generation notice

At lines 2220-2221, there's a second code generation notice:

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:

This suggests that the file includes code generated by protoc-gen-go in addition to the earlier code generated by protoc-gen-go-pulsar. Combining code from different generators in a single file may lead to confusion and potential conflicts. Ensure that the code is generated consistently using a single tool, or separate the generated code into distinct files.

proto/cosmos/base/grpc/v2/service.proto Outdated Show resolved Hide resolved
server/v2/api/grpc/service.go Outdated Show resolved Hide resolved
server/v2/go.mod Outdated Show resolved Hide resolved
server/v2/go.mod Show resolved Hide resolved
Copy link
Contributor

@randygrok your pull request is missing a changelog!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
proto/cosmos/base/grpc/v2/service.proto (2)

8-12: Add documentation comments for the Service and RPCs.

Please add documentation comments to describe:

  • The purpose and functionality of the Service
  • The expected behavior and use cases for the Query RPC
  • The purpose and return format of the ListQueryHandlers RPC

Example:

 // Service provides a generic query interface for cosmos-sdk state.
 service Service {
   // Query handles arbitrary query requests from clients and returns the corresponding responses.
   rpc Query(QueryRequest) returns (QueryResponse) {}

   // ListQueryHandlers returns a list of registered query handlers and their associated request/response types.
   rpc ListQueryHandlers(ListQueryHandlersRequest) returns (ListQueryHandlersResponse) {}
 }

The service design looks good, providing a flexible query interface using protobuf Any type.

🧰 Tools
🪛 GitHub Check: lint

[failure] 8-8:
Service "Service" should have a non-empty comment for documentation.


[failure] 9-9:
RPC "Query" should have a non-empty comment for documentation.


[failure] 11-11:
RPC "ListQueryHandlers" should have a non-empty comment for documentation.


14-31: Add documentation comments for all message types.

Please add documentation comments to describe each message type and its fields. Example:

 // QueryRequest wraps an arbitrary protobuf message as a query request.
 message QueryRequest {
   // request is the actual query request message.
   google.protobuf.Any request = 1;
 }

 // QueryResponse wraps an arbitrary protobuf message as a query response.
 message QueryResponse {
   // response contains the query result message.
   google.protobuf.Any response = 1;
 }

 // ListQueryHandlersRequest is used to request a list of all registered query handlers.
 message ListQueryHandlersRequest {}

 // ListQueryHandlersResponse contains a list of all registered query handlers.
 message ListQueryHandlersResponse {
   // handlers is the list of registered query handlers.
   repeated Handler handlers = 1;
 }

 // Handler describes a registered query handler's request and response types.
 message Handler {
   // request_name is the fully-qualified protobuf message name of the handler's request type.
   string request_name  = 1;
   // response_name is the fully-qualified protobuf message name of the handler's response type.
   string response_name = 2;
 }

The message definitions are well-structured and follow protobuf best practices:

  • Using Any type for generic request/response handling
  • Empty request message for ListQueryHandlers is appropriate
  • Handler message provides necessary type information for client code generation
🧰 Tools
🪛 GitHub Check: lint

[failure] 14-14:
Message "QueryRequest" should have a non-empty comment for documentation.


[failure] 18-18:
Message "QueryResponse" should have a non-empty comment for documentation.


[failure] 22-22:
Message "ListQueryHandlersRequest" should have a non-empty comment for documentation.


[failure] 24-24:
Message "ListQueryHandlersResponse" should have a non-empty comment for documentation.


[failure] 28-28:
Message "Handler" should have a non-empty comment for documentation.

📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f08976a and 5248508.

⛔ Files ignored due to path filters (2)
  • server/v2/api/grpc/service.pb.go is excluded by !**/*.pb.go
  • server/v2/go.sum is excluded by !**/*.sum
📒 Files selected for processing (4)
  • proto/cosmos/base/grpc/v2/service.proto (1 hunks)
  • server/v2/api/grpc/server.go (1 hunks)
  • server/v2/api/grpc/service.go (1 hunks)
  • server/v2/go.mod (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • server/v2/api/grpc/server.go
  • server/v2/go.mod
🧰 Additional context used
📓 Path-based instructions (1)
server/v2/api/grpc/service.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

🪛 buf
proto/cosmos/base/grpc/v2/service.proto

2-2: Files with package "cosmos.base.grpc.v2" must be within a directory "cosmos/base/grpc/v2" relative to root but were in directory "proto/cosmos/base/grpc/v2".

(PACKAGE_DIRECTORY_MATCH)

🪛 GitHub Check: lint
proto/cosmos/base/grpc/v2/service.proto

[failure] 8-8:
Service "Service" should have a non-empty comment for documentation.


[failure] 9-9:
RPC "Query" should have a non-empty comment for documentation.


[failure] 11-11:
RPC "ListQueryHandlers" should have a non-empty comment for documentation.


[failure] 14-14:
Message "QueryRequest" should have a non-empty comment for documentation.


[failure] 18-18:
Message "QueryResponse" should have a non-empty comment for documentation.


[failure] 22-22:
Message "ListQueryHandlersRequest" should have a non-empty comment for documentation.


[failure] 24-24:
Message "ListQueryHandlersResponse" should have a non-empty comment for documentation.


[failure] 28-28:
Message "Handler" should have a non-empty comment for documentation.

🔇 Additional comments (2)
server/v2/api/grpc/service.go (2)

20-26: Good job replacing panic with error return in RegisterV2Service

The function now returns an error instead of panicking when server or app is nil, which enhances code robustness and aligns with best practices.


50-51: Previous review comment is still valid regarding error messages

The earlier feedback about avoiding exposure of internal error details to clients remains applicable. Please consider adjusting the error messages to be more generic.

Also applies to: 55-56, 59-60

server/v2/go.mod Outdated
cosmossdk.io/server/v2/appmanager => ./appmanager
cosmossdk.io/server/v2/stf => ./stf
cosmossdk.io/store/v2 => ../../store/v2
cosmossdk.io/store/v2/db => ../../store/v2/db
cosmossdk.io/x/bank => ../../x/bank
cosmossdk.io/x/staking => ../../x/staking
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be deleted

server/v2/go.mod Outdated
cosmossdk.io/server/v2/appmanager => ./appmanager
cosmossdk.io/server/v2/stf => ./stf
cosmossdk.io/store/v2 => ../../store/v2
cosmossdk.io/store/v2/db => ../../store/v2/db
cosmossdk.io/x/bank => ../../x/bank
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

server/v2/go.mod Outdated

replace (
cosmossdk.io/api => ../../api
cosmossdk.io/core => ../../core
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? What are the core changes?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I dont include core it does not build

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait, maybe now works

Comment on lines 80 to 88
for handlerName := range handlersMap {
msg := handlersMap[handlerName].MakeMsg()
resp := handlersMap[handlerName].MakeMsgResp()

handlerDescriptors = append(handlerDescriptors, &Handler{
RequestName: proto.MessageName(msg),
ResponseName: proto.MessageName(resp),
})
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (2)
proto/cosmos/base/grpc/v2/service.proto (2)

8-15: Enhance service documentation for better clarity

While the service structure is good, the RPC documentation could be more descriptive:

  • For Query: Specify what types of requests are supported and any constraints
  • For ListQueryHandlers: Explain the purpose of handlers and when to use this endpoint

Consider updating the comments like this:

-// Service defines the gRPC service for query server for v2
 // Service defines the gRPC query service that allows clients to send dynamic queries
 // to the Cosmos SDK v2 server.
 service Service {
-  // Query queries the server with a request, the request can be any sdk Msg.
   // Query executes a query against the server. The request must be a valid protobuf
   // message type registered with the server's query handlers.
   rpc Query(QueryRequest) returns (QueryResponse) {}

-  // ListQueryHandlers lists all the available query handlers.
   // ListQueryHandlers returns a list of all registered query handlers and their
   // corresponding request/response message types, helping clients discover available queries.
   rpc ListQueryHandlers(ListQueryHandlersRequest) returns (ListQueryHandlersResponse) {}
 }

17-39: Consider future scalability improvements

The message definitions are well-structured, but consider these future enhancements:

  1. ListQueryHandlersRequest might need pagination support as the number of handlers grows
  2. Handler message could benefit from additional metadata fields like:
    • Description of the handler's purpose
    • Deprecated status
    • Required permissions

Would you like me to propose a detailed design for these enhancements?

📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 5248508 and c1646fd.

⛔ Files ignored due to path filters (3)
  • api/cosmos/base/grpc/v2/service_grpc.pb.go is excluded by !**/*.pb.go
  • server/v2/api/grpc/service.pb.go is excluded by !**/*.pb.go
  • server/v2/go.sum is excluded by !**/*.sum
📒 Files selected for processing (5)
  • api/cosmos/base/grpc/v2/service.pulsar.go (1 hunks)
  • proto/cosmos/base/grpc/v2/service.proto (1 hunks)
  • server/v2/api/grpc/service.go (1 hunks)
  • server/v2/api/grpc/service_test.go (1 hunks)
  • server/v2/go.mod (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • server/v2/api/grpc/service_test.go
  • server/v2/go.mod
🧰 Additional context used
📓 Path-based instructions (2)
api/cosmos/base/grpc/v2/service.pulsar.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/api/grpc/service.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

🪛 buf
proto/cosmos/base/grpc/v2/service.proto

2-2: Files with package "cosmos.base.grpc.v2" must be within a directory "cosmos/base/grpc/v2" relative to root but were in directory "proto/cosmos/base/grpc/v2".

(PACKAGE_DIRECTORY_MATCH)

🔇 Additional comments (2)
proto/cosmos/base/grpc/v2/service.proto (1)

1-7: LGTM! Package setup follows best practices

The package configuration and imports are well-structured. The use of google.protobuf.Any is appropriate for handling dynamic message types, and the go_package option is correctly set.

🧰 Tools
🪛 buf

2-2: Files with package "cosmos.base.grpc.v2" must be within a directory "cosmos/base/grpc/v2" relative to root but were in directory "proto/cosmos/base/grpc/v2".

(PACKAGE_DIRECTORY_MATCH)

server/v2/api/grpc/service.go (1)

50-51: Avoid exposing internal error details to clients

Returning detailed error messages can leak internal information and pose security risks. Consider returning generic error messages to the client and logging the detailed errors internally. This issue was previously raised and is still applicable.

Apply this diff to adjust the error messages:

-        return nil, status.Errorf(codes.NotFound, "handler not found for %s", msgName)
         return nil, status.Error(codes.NotFound, "handler not found")
-        return nil, status.Errorf(codes.InvalidArgument, "failed to unmarshal request: %v", err)
         return nil, status.Error(codes.InvalidArgument, "invalid request format")
-        return nil, status.Errorf(codes.Internal, "query failed: %v", err)
         return nil, status.Error(codes.Internal, "internal server error")
-        return nil, status.Errorf(codes.Internal, "failed to marshal response: %v", err)
         return nil, status.Error(codes.Internal, "internal server error")

Also applies to: 55-56, 60-61, 65-66

Comment on lines 80 to 88
for handlerName := range handlersMap {
msg := handlersMap[handlerName].MakeMsg()
resp := handlersMap[handlerName].MakeMsgResp()

handlerDescriptors = append(handlerDescriptors, &Handler{
RequestName: proto.MessageName(msg),
ResponseName: proto.MessageName(resp),
})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure deterministic iteration over map to avoid non-determinism

Iterating over a map in Go does not guarantee order, which may lead to non-deterministic results. If the order of handlerDescriptors is important, consider sorting the handler names before iterating over them.

Apply this diff to sort the handler names:

 import (
     "sort"
     // other imports
 )

 var handlerDescriptors []*Handler
 var handlerNames []string
 for handlerName := range handlersMap {
     handlerNames = append(handlerNames, handlerName)
 }
 
 sort.Strings(handlerNames)
 
 for _, handlerName := range handlerNames {
     msg := handlersMap[handlerName].MakeMsg()
     resp := handlersMap[handlerName].MakeMsgResp()

     handlerDescriptors = append(handlerDescriptors, &Handler{
         RequestName:  proto.MessageName(msg),
         ResponseName: proto.MessageName(resp),
     })
 }

This ensures that the handlers are processed in a consistent order.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for handlerName := range handlersMap {
msg := handlersMap[handlerName].MakeMsg()
resp := handlersMap[handlerName].MakeMsgResp()
handlerDescriptors = append(handlerDescriptors, &Handler{
RequestName: proto.MessageName(msg),
ResponseName: proto.MessageName(resp),
})
}
var handlerDescriptors []*Handler
var handlerNames []string
for handlerName := range handlersMap {
handlerNames = append(handlerNames, handlerName)
}
sort.Strings(handlerNames)
for _, handlerName := range handlerNames {
msg := handlersMap[handlerName].MakeMsg()
resp := handlersMap[handlerName].MakeMsgResp()
handlerDescriptors = append(handlerDescriptors, &Handler{
RequestName: proto.MessageName(msg),
ResponseName: proto.MessageName(resp),
})
}

Comment on lines 2233 to 2267
// QueryRequest is the request for the Query method
type QueryRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

Request *anypb.Any `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"`
}

func (x *QueryRequest) Reset() {
*x = QueryRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_cosmos_base_grpc_v2_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *QueryRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*QueryRequest) ProtoMessage() {}

// Deprecated: Use QueryRequest.ProtoReflect.Descriptor instead.
func (*QueryRequest) Descriptor() ([]byte, []int) {
return file_cosmos_base_grpc_v2_service_proto_rawDescGZIP(), []int{0}
}

func (x *QueryRequest) GetRequest() *anypb.Any {
if x != nil {
return x.Request
}
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider renaming fields to avoid stuttering

In the QueryRequest struct (lines 2233-2267), the field Request results in expressions like QueryRequest.Request, which can be repetitive. According to the Uber Go Style Guide, it's recommended to avoid stuttering in names. Consider renaming the field to something more descriptive to enhance readability.

Comment on lines 2270 to 2303
type QueryResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

Response *anypb.Any `protobuf:"bytes,1,opt,name=response,proto3" json:"response,omitempty"`
}

func (x *QueryResponse) Reset() {
*x = QueryResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_cosmos_base_grpc_v2_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *QueryResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*QueryResponse) ProtoMessage() {}

// Deprecated: Use QueryResponse.ProtoReflect.Descriptor instead.
func (*QueryResponse) Descriptor() ([]byte, []int) {
return file_cosmos_base_grpc_v2_service_proto_rawDescGZIP(), []int{1}
}

func (x *QueryResponse) GetResponse() *anypb.Any {
if x != nil {
return x.Response
}
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid repetitive naming in QueryResponse struct

Similarly, the QueryResponse struct (lines 2270-2303) has a field named Response, leading to QueryResponse.Response. To improve code clarity and adhere to the Uber Go Style Guide, consider renaming this field to prevent stuttering.

Comment on lines 2374 to 2410
RequestName string `protobuf:"bytes,1,opt,name=request_name,json=requestName,proto3" json:"request_name,omitempty"`
ResponseName string `protobuf:"bytes,2,opt,name=response_name,json=responseName,proto3" json:"response_name,omitempty"`
}

func (x *Handler) Reset() {
*x = Handler{}
if protoimpl.UnsafeEnabled {
mi := &file_cosmos_base_grpc_v2_service_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *Handler) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*Handler) ProtoMessage() {}

// Deprecated: Use Handler.ProtoReflect.Descriptor instead.
func (*Handler) Descriptor() ([]byte, []int) {
return file_cosmos_base_grpc_v2_service_proto_rawDescGZIP(), []int{4}
}

func (x *Handler) GetRequestName() string {
if x != nil {
return x.RequestName
}
return ""
}

func (x *Handler) GetResponseName() string {
if x != nil {
return x.ResponseName
}
return ""
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify field names in the Handler struct

The Handler struct (lines 2374-2410) contains fields RequestName and ResponseName. To align with Go naming conventions and improve readability, consider renaming these fields to Request and Response. This reduces redundancy and makes the code cleaner.

Comment on lines 116 to 120
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.base.grpc.v2.QueryRequest"))
}
panic(fmt.Errorf("message cosmos.base.grpc.v2.QueryRequest does not contain field %s", fd.FullName()))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid using panic in library code

The use of panic in methods like Has, Set, and Mutable across multiple structs can lead to unexpected crashes. According to the Uber Go Style Guide, it's better to return errors instead of panicking, allowing callers to handle exceptions gracefully.

Also applies to: 175-179, 201-205, 565-569, 611-615, 635-639, 964-980, 992-996, 1059-1065, 1425-1438, 1451-1461, 1509-1515, 1880-1893, 1906-1917, 1930-1940

Copy link
Contributor

@hieuvubk hieuvubk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Copy link
Member

@julienrbrt julienrbrt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you rebase? The new server/v2 landed on main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C:server/v2 api C:server/v2 Issues related to server/v2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants