Skip to content

Commit

Permalink
Expose a query endpoint for latest published valset (#985)
Browse files Browse the repository at this point in the history
* Expose a query endpoint for latest published valset

Pigeon currently gets this information by querying the compass contract.
The problem is, when there is a just-in-time valset update, pigeon will
end up using an old valset because the new valset hasn't been committed
yet.  We need the newest valset that may still be pending on the evm
chain.

Now, we can query paloma instead of the evm contract.  Paloma knows what
the latest published valset is, even if it hasn't yet been committed.

* Add tests

---------

Co-authored-by: Tyler Ruppert <{ID}+{username}@users.noreply.github.com>
  • Loading branch information
MechanicalTyler and Tyler Ruppert authored Sep 20, 2023
1 parent 0ad129b commit bc6afd5
Show file tree
Hide file tree
Showing 6 changed files with 607 additions and 61 deletions.
12 changes: 12 additions & 0 deletions proto/palomachain/paloma/valset/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ service Query {
"/palomachain/paloma/valset/get_snapshot_by_id/{snapshotId}";
}

// Queries the most recent published snapshot for a chain.
rpc GetLatestPublishedSnapshot(QueryGetLatestPublishedSnapshotRequest)
returns (QueryGetLatestPublishedSnapshotResponse) {}

// Queries a list of GetValidatorAliveUntil items.
rpc GetValidatorAliveUntil(QueryGetValidatorAliveUntilRequest)
returns (QueryGetValidatorAliveUntilResponse) {
Expand Down Expand Up @@ -77,6 +81,14 @@ message QueryGetSnapshotByIDResponse {
Snapshot snapshot = 1;
}

message QueryGetLatestPublishedSnapshotRequest {
string chainReferenceID = 1;
}

message QueryGetLatestPublishedSnapshotResponse {
Snapshot snapshot = 1;
}

message QueryGetValidatorAliveUntilRequest {
bytes valAddress = 1
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress"];
Expand Down
1 change: 1 addition & 0 deletions x/valset/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func GetQueryCmd(queryRoute string) *cobra.Command {
cmd.AddCommand(CmdValidatorInfo())

cmd.AddCommand(CmdGetSnapshotByID())
cmd.AddCommand(CmdGetLatestPublishedSnapshot())

cmd.AddCommand(CmdGetValidatorAliveUntil())

Expand Down
39 changes: 39 additions & 0 deletions x/valset/client/cli/query_get_latest_published_snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cli

import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/palomachain/paloma/x/valset/types"
"github.com/spf13/cobra"
)

func CmdGetLatestPublishedSnapshot() *cobra.Command {
cmd := &cobra.Command{
Use: "get-latest-published-snapshot [chain-reference-id]",
Short: "Query GetLatestPublishedSnapshot",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

params := &types.QueryGetLatestPublishedSnapshotRequest{
ChainReferenceID: args[0],
}

res, err := queryClient.GetLatestPublishedSnapshot(cmd.Context(), params)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
26 changes: 26 additions & 0 deletions x/valset/keeper/grpc_query_get_latest_published_snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package keeper

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/palomachain/paloma/x/valset/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func (k Keeper) GetLatestPublishedSnapshot(goCtx context.Context, req *types.QueryGetLatestPublishedSnapshotRequest) (*types.QueryGetLatestPublishedSnapshotResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}

ctx := sdk.UnwrapSDKContext(goCtx)
snapshot, err := k.GetLatestSnapshotOnChain(ctx, req.ChainReferenceID)
if err != nil {
return nil, err
}

return &types.QueryGetLatestPublishedSnapshotResponse{
Snapshot: snapshot,
}, nil
}
72 changes: 72 additions & 0 deletions x/valset/keeper/grpc_query_get_latest_published_snapshot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package keeper

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
keeperutil "github.com/palomachain/paloma/util/keeper"
"github.com/palomachain/paloma/x/valset/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

func TestGetLatestPublishedSnapshot(t *testing.T) {
testcases := []struct {
name string
setup func(sdk.Context, *Keeper, mockedServices) *types.QueryGetLatestPublishedSnapshotResponse
request *types.QueryGetLatestPublishedSnapshotRequest
expectedError error
}{
{
name: "returns the latest published snapshot",
setup: func(ctx sdk.Context, k *Keeper, ms mockedServices) *types.QueryGetLatestPublishedSnapshotResponse {
ms.StakingKeeper.On("IterateValidators", mock.Anything, mock.Anything).Return(nil)

snapshot, err := k.createNewSnapshot(ctx)
require.NoError(t, err)

err = k.setSnapshotAsCurrent(ctx, snapshot)
require.NoError(t, err)

snapshot, err = k.GetCurrentSnapshot(ctx)
require.NoError(t, err)

k.SetSnapshotOnChain(ctx, snapshot.Id, "test-chain")

snapshot, err = k.GetCurrentSnapshot(ctx)
require.NoError(t, err)

return &types.QueryGetLatestPublishedSnapshotResponse{
Snapshot: snapshot,
}
},
request: &types.QueryGetLatestPublishedSnapshotRequest{
ChainReferenceID: "test-chain",
},
},
{
name: "returns error when no snapshot published",
setup: func(ctx sdk.Context, k *Keeper, ms mockedServices) *types.QueryGetLatestPublishedSnapshotResponse {
return nil
},
request: &types.QueryGetLatestPublishedSnapshotRequest{
ChainReferenceID: "test-chain",
},
expectedError: keeperutil.ErrNotFound.Format(&types.Snapshot{}, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
},
}

asserter := assert.New(t)
for _, tt := range testcases {
t.Run(tt.name, func(t *testing.T) {
k, ms, ctx := newValsetKeeper(t)

expected := tt.setup(ctx, k, ms)

actual, actualErr := k.GetLatestPublishedSnapshot(ctx, tt.request)
asserter.Equal(expected, actual)
asserter.Equal(tt.expectedError, actualErr)
})
}
}
Loading

0 comments on commit bc6afd5

Please sign in to comment.