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

test(server/v2/cometbft): Add Consensus query p2p, app, grpc #22771

Merged
merged 8 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 188 additions & 7 deletions server/v2/cometbft/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
gogotypes "github.com/cosmos/gogoproto/types"
"github.com/stretchr/testify/require"

"reflect"
Copy link
Member

Choose a reason for hiding this comment

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

Could you run the linter? Weird that it doesn't fail, but the import sorting is wrong


appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
Expand All @@ -33,6 +35,9 @@ import (
"cosmossdk.io/server/v2/stf/branch"
"cosmossdk.io/server/v2/stf/mock"
consensustypes "cosmossdk.io/x/consensus/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
gogoproto "github.com/cosmos/gogoproto/proto"
)

var (
Expand All @@ -53,7 +58,9 @@ var (
Msg: &gogotypes.BoolValue{Value: true},
GasLimit: 0,
}
actorName = []byte("cookies")
actorName = []byte("cookies")
testAcc = sdk.AccAddress([]byte("addr1_______________"))
versionStr = "0.0.0"
)

func getQueryRouterBuilder[T any, PT interface {
Expand Down Expand Up @@ -583,11 +590,7 @@ func TestConsensus_Info(t *testing.T) {
require.Equal(t, res.LastBlockHeight, int64(1))
}

// TODO:
// - GRPC request
// - app request
// - p2p request
func TestConsensus_Query(t *testing.T) {
func TestConsensus_QueryStore(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})

// Write data to state storage
Expand Down Expand Up @@ -648,11 +651,149 @@ func TestConsensus_Query(t *testing.T) {
require.Equal(t, res.Value, []byte(nil))
}

func TestConsensus_GRPCQuery(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})

_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)

_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
Hash: emptyHash[:],
})
require.NoError(t, err)

// empty request
res, err := c.Query(context.Background(), &abciproto.QueryRequest{})
require.NoError(t, err)
require.Equal(t, res.Code, uint32(1))
require.Contains(t, res.Log, "no query path provided")

// query request not exist in handler map
invalidReq := testdata.EchoRequest{
Message: "echo",
}
invalidReqBz, err := invalidReq.Marshal()
require.NoError(t, err)
invalidQuery := abci.QueryRequest{
Data: invalidReqBz,
Path: "testpb.EchoRequest",
}
invalidRes, err := c.Query(context.TODO(), &invalidQuery)
require.Error(t, err)
require.Nil(t, invalidRes)
require.Contains(t, err.Error(), "no query handler found")

// Valid query
req := testdata.SayHelloRequest{Name: "foo"}
reqBz, err := req.Marshal()
require.NoError(t, err)
reqQuery := abci.QueryRequest{
Data: reqBz,
Path: "testpb.SayHelloRequest",
}

resQuery, err := c.Query(context.TODO(), &reqQuery)
require.NoError(t, err)
require.Equal(t, abci.CodeTypeOK, resQuery.Code, resQuery)

var response testdata.SayHelloResponse
require.NoError(t, response.Unmarshal(resQuery.Value))
require.Equal(t, "Hello foo!", response.Greeting)
}

func TestConsensus_P2PQuery(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})

_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)

_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
Hash: emptyHash[:],
})
require.NoError(t, err)

// empty request
res, err := c.Query(context.Background(), &abciproto.QueryRequest{})
require.NoError(t, err)
require.Equal(t, res.Code, uint32(1))
require.Contains(t, res.Log, "no query path provided")

addrQuery := abci.QueryRequest{
Path: "/p2p/filter/addr/1.1.1.1:8000",
}
res, err = c.Query(context.TODO(), &addrQuery)
require.NoError(t, err)
require.Equal(t, uint32(3), res.Code)

idQuery := abci.QueryRequest{
Path: "/p2p/filter/id/testid",
}
res, err = c.Query(context.TODO(), &idQuery)
require.NoError(t, err)
require.Equal(t, uint32(4), res.Code)
}

func TestConsensus_AppQuery(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})

_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)

_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
Hash: emptyHash[:],
})
require.NoError(t, err)

tx := mock.Tx{
Sender: testAcc,
Msg: &gogotypes.BoolValue{Value: true},
GasLimit: 1000,
}
txBytes := tx.Bytes()

// simulate by calling Query with encoded tx
query := abci.QueryRequest{
Path: "/app/simulate",
Data: txBytes,
}
queryResult, err := c.Query(context.TODO(), &query)
require.NoError(t, err)
require.True(t, queryResult.IsOK(), queryResult.Log)

// Query app version
res, err := c.Query(context.TODO(), &abci.QueryRequest{Path: "app/version"})
require.NoError(t, err)
require.True(t, res.IsOK())
require.Equal(t, versionStr, string(res.Value))
}

func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock.Tx]) *consensus[mock.Tx] {
t.Helper()

queryHandler := make(map[string]appmodulev2.Handler)
msgRouterBuilder := getMsgRouterBuilder(t, func(ctx context.Context, msg *gogotypes.BoolValue) (*gogotypes.BoolValue, error) {
return nil, nil
return msg, nil
})

queryRouterBuilder := getQueryRouterBuilder(t, func(ctx context.Context, q *consensustypes.QueryParamsRequest) (*consensustypes.QueryParamsResponse, error) {
Expand All @@ -669,6 +810,32 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock.
}, nil
})

var helloFooHandler = func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error) {
typedReq := msg.(*testdata.SayHelloRequest)
handler := testdata.QueryImpl{}
typedResp, err := handler.SayHello(ctx, typedReq)
if err != nil {
return nil, err
}

return typedResp, nil
}

queryRouterBuilder.RegisterHandler(
proto.MessageName(&testdata.SayHelloRequest{}),
helloFooHandler,
)
Comment on lines +824 to +827
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

Check the error return value of RegisterHandler

The call to queryRouterBuilder.RegisterHandler does not check the returned error. Ignoring errors may lead to unexpected behavior or panics during runtime. Please handle the error appropriately.

Apply the following fix to handle the error:

+	err := queryRouterBuilder.RegisterHandler(
 		proto.MessageName(&testdata.SayHelloRequest{}),
 		helloFooHandler,
 	)
+	require.NoError(t, err)
 	
-	queryRouterBuilder.RegisterHandler(
-		proto.MessageName(&testdata.SayHelloRequest{}),
-		helloFooHandler,
-	)

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 golangci-lint (1.62.2)

824-824: Error return value of queryRouterBuilder.RegisterHandler is not checked

(errcheck)


queryHandler[proto.MessageName(&testdata.SayHelloRequest{})] = appmodulev2.Handler{
Func: helloFooHandler,
MakeMsg: func() transaction.Msg {
return reflect.New(gogoproto.MessageType(proto.MessageName(&testdata.SayHelloRequest{})).Elem()).Interface().(transaction.Msg)
},
MakeMsgResp: func() transaction.Msg {
return reflect.New(gogoproto.MessageType(proto.MessageName(&testdata.SayHelloResponse{})).Elem()).Interface().(transaction.Msg)
},
}

s, err := stf.New(
log.NewNopLogger().With("module", "stf"),
msgRouterBuilder,
Expand Down Expand Up @@ -709,6 +876,16 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock.
nil,
)

addrPeerFilter := func(info string) (*abci.QueryResponse, error) {
require.Equal(t, "1.1.1.1:8000", info)
return &abci.QueryResponse{Code: uint32(3)}, nil
}

idPeerFilter := func(id string) (*abci.QueryResponse, error) {
require.Equal(t, "testid", id)
return &abci.QueryResponse{Code: uint32(4)}, nil
}

return &consensus[mock.Tx]{
logger: log.NewNopLogger(),
appName: "testing-app",
Expand All @@ -719,6 +896,10 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock.
txCodec: mock.TxCodec{},
chainID: "test",
getProtoRegistry: sync.OnceValues(proto.MergedRegistry),
queryHandlersMap: queryHandler,
addrPeerFilter: addrPeerFilter,
idPeerFilter: idPeerFilter,
version: versionStr,
}
}

Expand Down
7 changes: 6 additions & 1 deletion server/v2/cometbft/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,19 @@ func intoABCISimulationResponse(txRes server.TxResult, indexSet map[string]struc
msgResponses[i] = anyMsg
}

errMsg := ""
if txRes.Error != nil {
errMsg = txRes.Error.Error()
}

res := &sdk.SimulationResponse{
GasInfo: sdk.GasInfo{
GasWanted: txRes.GasWanted,
GasUsed: txRes.GasUsed,
},
Result: &sdk.Result{
Data: []byte{},
Log: txRes.Error.Error(),
Log: errMsg,
Events: abciEvents,
MsgResponses: msgResponses,
},
Expand Down
Loading