Skip to content

Commit

Permalink
Merge pull request #73 from bandprotocol/nathachai/query-pending-requ…
Browse files Browse the repository at this point in the history
…ests

gRPC Query Pending Requests
  • Loading branch information
taobun authored May 25, 2021
2 parents 77e3743 + c6c82d6 commit 6cf61c4
Show file tree
Hide file tree
Showing 9 changed files with 912 additions and 146 deletions.
22 changes: 22 additions & 0 deletions proto/oracle/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ service Query {
option (google.api.http).get = "/oracle/v1/requests/{request_id}";
}

// PendingRequests queries list of pending request IDs assigned to given
// validator.
rpc PendingRequests(QueryPendingRequestsRequest)
returns (QueryPendingRequestsResponse) {
option (google.api.http).get =
"/oracle/v1/pending_requests/{validator_address}";
}

// Validator queries properties of given validator address.
rpc Validator(QueryValidatorRequest) returns (QueryValidatorResponse) {
option (google.api.http).get = "/oracle/v1/validators/{validator_address}";
Expand Down Expand Up @@ -157,6 +165,20 @@ message QueryRequestResponse {
Result result = 3;
}

// QueryPendingRequestRequest is request type for the Query/PendingRequests RPC
// method.
message QueryPendingRequestsRequest {
// ValidatorAddress is address of a validator
string validator_address = 1;
}

// QueryPendingRequestResponse is response type for the Query/PendingRequests
// RPC method.
message QueryPendingRequestsResponse {
// RequestIDs is a list of pending request IDs assigned to the given validator
repeated int64 request_ids = 1 [ (gogoproto.customname) = "RequestIDs" ];
}

// QueryParamsRequest is request type for the Query/Params RPC method.
message QueryParamsRequest {}

Expand Down
50 changes: 30 additions & 20 deletions x/oracle/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func GetQueryCmd() *cobra.Command {
GetQueryCmdValidatorStatus(),
GetQueryCmdReporters(),
GetQueryActiveValidators(),
// GetQueryPendingRequests(storeKey, cdc),
GetQueryPendingRequests(),
GetQueryRequestVerification(),
GetQueryRequestPool(),
)
Expand Down Expand Up @@ -282,28 +282,38 @@ func GetQueryActiveValidators() *cobra.Command {
return cmd
}

// // GetQueryPendingRequests implements the query pending requests command.
// func GetQueryPendingRequests(route string, cdc *codec.Codec) *cobra.Command {
// return &cobra.Command{
// Use: "pending-requests [validator]",
// Args: cobra.MaximumNArgs(1),
// RunE: func(cmd *cobra.Command, args []string) error {
// cliCtx := context.NewCLIContext().WithCodec(cdc)
// GetQueryPendingRequests implements the query pending requests command.
func GetQueryPendingRequests() *cobra.Command {
cmd := &cobra.Command{
Use: "pending-requests [validator-address]",
Short: "Get list of pending request IDs assigned to given validator",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

// path := fmt.Sprintf("custom/%s/%s", route, types.QueryPendingRequests)
// if len(args) == 1 {
// path += "/" + args[0]
// }
valAddress, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return fmt.Errorf("unable to parse given validator address: %w", err)
}

// bz, _, err := cliCtx.Query(path)
// if err != nil {
// return err
// }
r, err := queryClient.PendingRequests(context.Background(), &types.QueryPendingRequestsRequest{
ValidatorAddress: valAddress.String(),
})
if err != nil {
return err
}

// return printOutput(cliCtx, cdc, bz, &[]types.RequestID{})
// },
// }
// }
return clientCtx.PrintProto(r)
},
}
flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetQueryRequestVerification implements the query request verification command.
func GetQueryRequestVerification() *cobra.Command {
Expand Down
62 changes: 62 additions & 0 deletions x/oracle/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,68 @@ func (k Querier) Request(c context.Context, req *types.QueryRequestRequest) (*ty
return &types.QueryRequestResponse{Request: &request, Reports: reports, Result: &result}, nil
}

func (k Querier) PendingRequests(c context.Context, req *types.QueryPendingRequestsRequest) (*types.QueryPendingRequestsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)
valAddress, err := sdk.ValAddressFromBech32(req.ValidatorAddress)
if err != nil {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("unable to parse given validator address: %v", err))
}

lastExpired := k.GetRequestLastExpired(ctx)
requestCount := k.GetRequestCount(ctx)

var pendingIDs []int64
for id := lastExpired + 1; int64(id) <= requestCount; id++ {
oracleReq := k.MustGetRequest(ctx, id)

// If all validators reported on this request, then skip it.
reports := k.GetReports(ctx, id)
if len(reports) == len(oracleReq.RequestedValidators) {
continue
}

// Skip if validator hasn't been assigned or has been reported.
// If the validator isn't in requested validators set, then skip it.
isInValidatorSet := false
for _, v := range oracleReq.RequestedValidators {
val, err := sdk.ValAddressFromBech32(v)
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("unable to parse validator address in requested validators %v: %v", v, err))
}
if valAddress.Equals(val) {
isInValidatorSet = true
break
}
}
if !isInValidatorSet {
continue
}

// If the validator has reported, then skip it.
reported := false
for _, r := range reports {
val, err := sdk.ValAddressFromBech32(r.Validator)
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("unable to parse validator address in requested validators %v: %v", r.Validator, err))
}
if valAddress.Equals(val) {
reported = true
break
}
}
if reported {
continue
}

pendingIDs = append(pendingIDs, int64(id))
}

return &types.QueryPendingRequestsResponse{RequestIDs: pendingIDs}, nil
}

// Validator queries oracle info of validator for given validator
// address.
func (k Querier) Validator(c context.Context, req *types.QueryValidatorRequest) (*types.QueryValidatorResponse, error) {
Expand Down
125 changes: 125 additions & 0 deletions x/oracle/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,131 @@ func (suite *RequestVerificationTestSuite) TestFailedRequestAlreadyExpired() {
suite.assert.Nil(res, "response should be nil")
}

type PendingRequestsTestSuite struct {
suite.Suite

assert *require.Assertions
querier keeper.Querier

ctx sdk.Context
}

func (suite *PendingRequestsTestSuite) SetupTest() {
suite.assert = require.New(suite.T())
_, ctx, k := testapp.CreateTestInput(true)

suite.querier = keeper.Querier{
Keeper: k,
}
suite.ctx = ctx
}

func (suite *PendingRequestsTestSuite) TestSuccess() {
assignedButPendingReq := types.NewRequest(
1,
BasicCalldata,
[]sdk.ValAddress{testapp.Validators[0].ValAddress},
1,
1,
testapp.ParseTime(0),
"",
[]types.RawRequest{
types.NewRawRequest(1, 1, []byte("testdata")),
types.NewRawRequest(2, 2, []byte("testdata")),
types.NewRawRequest(3, 3, []byte("testdata")),
},
nil,
0,
)
notBeAssignedReq := types.NewRequest(
1,
BasicCalldata,
[]sdk.ValAddress{testapp.Validators[1].ValAddress},
1,
1,
testapp.ParseTime(0),
"",
[]types.RawRequest{
types.NewRawRequest(1, 1, []byte("testdata")),
types.NewRawRequest(2, 2, []byte("testdata")),
types.NewRawRequest(3, 3, []byte("testdata")),
},
nil,
0,
)
alreadyReportAllReq := types.NewRequest(
1,
BasicCalldata,
[]sdk.ValAddress{
testapp.Validators[0].ValAddress,
testapp.Validators[1].ValAddress,
},
1,
1,
testapp.ParseTime(0),
"",
[]types.RawRequest{
types.NewRawRequest(1, 1, []byte("testdata")),
types.NewRawRequest(2, 2, []byte("testdata")),
types.NewRawRequest(3, 3, []byte("testdata")),
},
nil,
0,
)
assignedButReportedReq := types.NewRequest(
1,
BasicCalldata,
[]sdk.ValAddress{
testapp.Validators[0].ValAddress,
testapp.Validators[1].ValAddress,
},
1,
1,
testapp.ParseTime(0),
"",
[]types.RawRequest{
types.NewRawRequest(1, 1, []byte("testdata")),
types.NewRawRequest(2, 2, []byte("testdata")),
types.NewRawRequest(3, 3, []byte("testdata")),
},
nil,
0,
)

suite.querier.Keeper.SetRequest(suite.ctx, types.RequestID(3), assignedButPendingReq)
suite.querier.Keeper.SetRequest(suite.ctx, types.RequestID(4), notBeAssignedReq)
suite.querier.Keeper.SetRequest(suite.ctx, types.RequestID(5), alreadyReportAllReq)
suite.querier.Keeper.SetRequest(suite.ctx, types.RequestID(6), assignedButReportedReq)
suite.querier.Keeper.SetRequestCount(suite.ctx, 4)
suite.querier.Keeper.SetRequestLastExpired(suite.ctx, 2)
suite.querier.Keeper.SetReport(suite.ctx, 5, types.NewReport(testapp.Validators[0].ValAddress, true, []types.RawReport{
types.NewRawReport(1, 0, []byte("testdata")),
types.NewRawReport(2, 0, []byte("testdata")),
types.NewRawReport(3, 0, []byte("testdata")),
}))
suite.querier.Keeper.SetReport(suite.ctx, 5, types.NewReport(testapp.Validators[1].ValAddress, true, []types.RawReport{
types.NewRawReport(1, 0, []byte("testdata")),
types.NewRawReport(2, 0, []byte("testdata")),
types.NewRawReport(3, 0, []byte("testdata")),
}))
suite.querier.Keeper.SetReport(suite.ctx, 6, types.NewReport(testapp.Validators[0].ValAddress, true, []types.RawReport{
types.NewRawReport(1, 0, []byte("testdata")),
types.NewRawReport(2, 0, []byte("testdata")),
types.NewRawReport(3, 0, []byte("testdata")),
}))

r, err := suite.querier.PendingRequests(sdk.WrapSDKContext(suite.ctx), &types.QueryPendingRequestsRequest{
ValidatorAddress: sdk.ValAddress(testapp.Validators[0].Address).String(),
})

suite.assert.Equal(&types.QueryPendingRequestsResponse{RequestIDs: []int64{3}}, r)
suite.assert.NoError(err)
}

func TestRequestVerification(t *testing.T) {
suite.Run(t, new(RequestVerificationTestSuite))
}

func TestPendingRequests(t *testing.T) {
suite.Run(t, new(PendingRequestsTestSuite))
}
Loading

0 comments on commit 6cf61c4

Please sign in to comment.