From 91171977d3cd0b87db9ece1f1e56f59c17d2e081 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 15:45:55 -0800 Subject: [PATCH 01/40] Ran ignite scaffold map claim --module supplier supplier_address session_id root_hash --no-message --yes --- go.mod | 2 +- go.sum | 3 +- proto/pocket/supplier/claim.proto | 13 ++ proto/pocket/supplier/genesis.proto | 4 +- proto/pocket/supplier/query.proto | 42 +++++- proto/poktroll/supplier/tx.proto | 7 + x/supplier/client/cli/query.go | 4 +- x/supplier/client/cli/query_claim.go | 80 +++++++++++ x/supplier/client/cli/query_claim_test.go | 162 ++++++++++++++++++++++ x/supplier/genesis.go | 9 +- x/supplier/genesis_test.go | 13 +- x/supplier/keeper/claim.go | 63 +++++++++ x/supplier/keeper/claim_test.go | 66 +++++++++ x/supplier/keeper/msg_server_test.go | 7 +- x/supplier/keeper/query_claim.go | 57 ++++++++ x/supplier/keeper/query_claim_test.go | 130 +++++++++++++++++ x/supplier/types/codec.go | 3 + x/supplier/types/genesis.go | 15 +- x/supplier/types/genesis_test.go | 26 +++- x/supplier/types/key_claim.go | 23 +++ 20 files changed, 706 insertions(+), 23 deletions(-) create mode 100644 proto/pocket/supplier/claim.proto create mode 100644 proto/poktroll/supplier/tx.proto create mode 100644 x/supplier/client/cli/query_claim.go create mode 100644 x/supplier/client/cli/query_claim_test.go create mode 100644 x/supplier/keeper/claim.go create mode 100644 x/supplier/keeper/claim_test.go create mode 100644 x/supplier/keeper/query_claim.go create mode 100644 x/supplier/keeper/query_claim_test.go create mode 100644 x/supplier/types/key_claim.go diff --git a/go.mod b/go.mod index 95c298124..1f263d032 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 + github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c github.com/regen-network/gocuke v0.6.2 github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 @@ -135,7 +136,6 @@ require ( github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect diff --git a/go.sum b/go.sum index 48ddd50c7..cb47c97c6 100644 --- a/go.sum +++ b/go.sum @@ -935,7 +935,6 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= @@ -1583,6 +1582,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c h1:XyPmGsaCFgWwi/xz8XveRMZjXPqJhzagg/MA4W6o2O0= +github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c/go.mod h1:t40oLsJlR9eRh9oDJTJZEUPk5e2/lCR+g2NCOhxrRxU= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/polyfloyd/go-errorlint v1.0.0/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA= diff --git a/proto/pocket/supplier/claim.proto b/proto/pocket/supplier/claim.proto new file mode 100644 index 000000000..34fcc0d91 --- /dev/null +++ b/proto/pocket/supplier/claim.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +package pocket.supplier; + +option go_package = "pocket/x/supplier/types"; + +message Claim { + string index = 1; + string supplierAddress = 2; + string sessionId = 3; + string rootHash = 4; + +} + diff --git a/proto/pocket/supplier/genesis.proto b/proto/pocket/supplier/genesis.proto index 81d3550d0..cdf8fb554 100644 --- a/proto/pocket/supplier/genesis.proto +++ b/proto/pocket/supplier/genesis.proto @@ -5,12 +5,14 @@ package pocket.supplier; import "gogoproto/gogo.proto"; import "pocket/supplier/params.proto"; import "pocket/shared/supplier.proto"; +import "pocket/supplier/claim.proto"; option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; // GenesisState defines the supplier module's genesis state. message GenesisState { - Params params = 1 [(gogoproto.nullable) = false]; + Params params = 1 [(gogoproto.nullable) = false]; repeated pocket.shared.Supplier supplierList = 2 [(gogoproto.nullable) = false]; + repeated Claim claimList = 3 [(gogoproto.nullable) = false]; } diff --git a/proto/pocket/supplier/query.proto b/proto/pocket/supplier/query.proto index 6ed7eb194..1ee03c516 100644 --- a/proto/pocket/supplier/query.proto +++ b/proto/pocket/supplier/query.proto @@ -7,26 +7,37 @@ import "google/api/annotations.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; import "pocket/supplier/params.proto"; import "pocket/shared/supplier.proto"; +import "pocket/supplier/claim.proto"; option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; // Query defines the gRPC querier service. service Query { - + // Parameters queries the parameters of the module. rpc Params (QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/pocket/supplier/params"; - + } - + // Queries a list of Supplier items. rpc Supplier (QueryGetSupplierRequest) returns (QueryGetSupplierResponse) { option (google.api.http).get = "/pocket/supplier/supplier/{address}"; - + } rpc SupplierAll (QueryAllSupplierRequest) returns (QueryAllSupplierResponse) { option (google.api.http).get = "/pocket/supplier/supplier"; - + + } + + // Queries a list of Claim items. + rpc Claim (QueryGetClaimRequest) returns (QueryGetClaimResponse) { + option (google.api.http).get = "/pocket/supplier/claim/{index}"; + + } + rpc ClaimAll (QueryAllClaimRequest) returns (QueryAllClaimResponse) { + option (google.api.http).get = "/pocket/supplier/claim"; + } } // QueryParamsRequest is request type for the Query/Params RPC method. @@ -34,7 +45,7 @@ message QueryParamsRequest {} // QueryParamsResponse is response type for the Query/Params RPC method. message QueryParamsResponse { - + // params holds all the parameters of this module. Params params = 1 [(gogoproto.nullable) = false]; } @@ -52,7 +63,24 @@ message QueryAllSupplierRequest { } message QueryAllSupplierResponse { - repeated pocket.shared.Supplier supplier = 1 [(gogoproto.nullable) = false]; + repeated pocket.shared.Supplier supplier = 1 [(gogoproto.nullable) = false]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +message QueryGetClaimRequest { + string index = 1; +} + +message QueryGetClaimResponse { + Claim claim = 1 [(gogoproto.nullable) = false]; +} + +message QueryAllClaimRequest { + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +message QueryAllClaimResponse { + repeated Claim claim = 1 [(gogoproto.nullable) = false]; cosmos.base.query.v1beta1.PageResponse pagination = 2; } diff --git a/proto/poktroll/supplier/tx.proto b/proto/poktroll/supplier/tx.proto new file mode 100644 index 000000000..a79dbc183 --- /dev/null +++ b/proto/poktroll/supplier/tx.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; +package poktroll.supplier; + +option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; + +// Msg defines the Msg service. +service Msg {} \ No newline at end of file diff --git a/x/supplier/client/cli/query.go b/x/supplier/client/cli/query.go index da1e3de17..eb6e6979f 100644 --- a/x/supplier/client/cli/query.go +++ b/x/supplier/client/cli/query.go @@ -27,7 +27,9 @@ func GetQueryCmd(queryRoute string) *cobra.Command { cmd.AddCommand(CmdQueryParams()) cmd.AddCommand(CmdListSupplier()) cmd.AddCommand(CmdShowSupplier()) - // this line is used by starport scaffolding # 1 + cmd.AddCommand(CmdListClaim()) + cmd.AddCommand(CmdShowClaim()) +// this line is used by starport scaffolding # 1 return cmd } diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go new file mode 100644 index 000000000..a8462062a --- /dev/null +++ b/x/supplier/client/cli/query_claim.go @@ -0,0 +1,80 @@ +package cli + +import ( + "github.com/spf13/cobra" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + + + "pocket/x/supplier/types" +) + +func CmdListClaim() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-claim", + Short: "list all claim", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryAllClaimRequest{ + Pagination: pageReq, + } + + res, err := queryClient.ClaimAll(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddPaginationFlagsToCmd(cmd, cmd.Use) + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdShowClaim() *cobra.Command { + cmd := &cobra.Command{ + Use: "show-claim [index]", + Short: "shows a claim", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + argIndex := args[0] + + params := &types.QueryGetClaimRequest{ + Index: argIndex, + + } + + res, err := queryClient.Claim(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go new file mode 100644 index 000000000..069ca494a --- /dev/null +++ b/x/supplier/client/cli/query_claim_test.go @@ -0,0 +1,162 @@ +package cli_test + +import ( + "fmt" + "strconv" + "testing" + + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/stretchr/testify/require" + tmcli "github.com/cometbft/cometbft/libs/cli" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "pocket/testutil/network" + "pocket/testutil/nullify" + "pocket/x/supplier/client/cli" + "pocket/x/supplier/types" +) + +// Prevent strconv unused error +var _ = strconv.IntSize + +func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Claim) { + t.Helper() + cfg := network.DefaultConfig() + state := types.GenesisState{} + for i := 0; i < n; i++ { + claim := types.Claim{ + Index: strconv.Itoa(i), + + } + nullify.Fill(&claim) + state.ClaimList = append(state.ClaimList, claim) + } + buf, err := cfg.Codec.MarshalJSON(&state) + require.NoError(t, err) + cfg.GenesisState[types.ModuleName] = buf + return network.New(t, cfg), state.ClaimList +} + +func TestShowClaim(t *testing.T) { + net, objs := networkWithClaimObjects(t, 2) + + ctx := net.Validators[0].ClientCtx + common := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tests := []struct { + desc string + idIndex string + + args []string + err error + obj types.Claim + }{ + { + desc: "found", + idIndex: objs[0].Index, + + args: common, + obj: objs[0], + }, + { + desc: "not found", + idIndex: strconv.Itoa(100000), + + args: common, + err: status.Error(codes.NotFound, "not found"), + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + args := []string{ + tc.idIndex, + + } + args = append(args, tc.args...) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) + if tc.err != nil { + stat, ok := status.FromError(tc.err) + require.True(t, ok) + require.ErrorIs(t, stat.Err(), tc.err) + } else { + require.NoError(t, err) + var resp types.QueryGetClaimResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.NotNil(t, resp.Claim) + require.Equal(t, + nullify.Fill(&tc.obj), + nullify.Fill(&resp.Claim), + ) + } + }) + } +} + +func TestListClaim(t *testing.T) { + net, objs := networkWithClaimObjects(t, 5) + + ctx := net.Validators[0].ClientCtx + request := func(next []byte, offset, limit uint64, total bool) []string { + args := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + if next == nil { + args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) + } else { + args = append(args, fmt.Sprintf("--%s=%s", flags.FlagPageKey, next)) + } + args = append(args, fmt.Sprintf("--%s=%d", flags.FlagLimit, limit)) + if total { + args = append(args, fmt.Sprintf("--%s", flags.FlagCountTotal)) + } + return args + } + t.Run("ByOffset", func(t *testing.T) { + step := 2 + for i := 0; i < len(objs); i += step { + args := request(nil, uint64(i), uint64(step), false) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) + require.NoError(t, err) + var resp types.QueryAllClaimResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.LessOrEqual(t, len(resp.Claim), step) + require.Subset(t, + nullify.Fill(objs), + nullify.Fill(resp.Claim), + ) + } + }) + t.Run("ByKey", func(t *testing.T) { + step := 2 + var next []byte + for i := 0; i < len(objs); i += step { + args := request(next, 0, uint64(step), false) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) + require.NoError(t, err) + var resp types.QueryAllClaimResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.LessOrEqual(t, len(resp.Claim), step) + require.Subset(t, + nullify.Fill(objs), + nullify.Fill(resp.Claim), + ) + next = resp.Pagination.NextKey + } + }) + t.Run("Total", func(t *testing.T) { + args := request(nil, 0, uint64(len(objs)), true) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) + require.NoError(t, err) + var resp types.QueryAllClaimResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.NoError(t, err) + require.Equal(t, len(objs), int(resp.Pagination.Total)) + require.ElementsMatch(t, + nullify.Fill(objs), + nullify.Fill(resp.Claim), + ) + }) +} diff --git a/x/supplier/genesis.go b/x/supplier/genesis.go index fb7d59806..29f433b5a 100644 --- a/x/supplier/genesis.go +++ b/x/supplier/genesis.go @@ -13,7 +13,11 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) for _, supplier := range genState.SupplierList { k.SetSupplier(ctx, supplier) } - // this line is used by starport scaffolding # genesis/module/init + // Set all the claim +for _, elem := range genState.ClaimList { + k.SetClaim(ctx, elem) +} +// this line is used by starport scaffolding # genesis/module/init k.SetParams(ctx, genState.Params) } @@ -23,7 +27,8 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.Params = k.GetParams(ctx) genesis.SupplierList = k.GetAllSupplier(ctx) - // this line is used by starport scaffolding # genesis/module/export + genesis.ClaimList = k.GetAllClaim(ctx) +// this line is used by starport scaffolding # genesis/module/export return genesis } diff --git a/x/supplier/genesis_test.go b/x/supplier/genesis_test.go index b6af0545c..679caf38d 100644 --- a/x/supplier/genesis_test.go +++ b/x/supplier/genesis_test.go @@ -56,7 +56,15 @@ func TestGenesis(t *testing.T) { }, }, }, - // this line is used by starport scaffolding # genesis/test/state + ClaimList: []types.Claim{ + { + Index: "0", +}, + { + Index: "1", +}, + }, + // this line is used by starport scaffolding # genesis/test/state } k, ctx := keepertest.SupplierKeeper(t) @@ -68,5 +76,6 @@ func TestGenesis(t *testing.T) { nullify.Fill(got) require.ElementsMatch(t, genesisState.SupplierList, got.SupplierList) - // this line is used by starport scaffolding # genesis/test/assert + require.ElementsMatch(t, genesisState.ClaimList, got.ClaimList) +// this line is used by starport scaffolding # genesis/test/assert } diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go new file mode 100644 index 000000000..434c2f1b3 --- /dev/null +++ b/x/supplier/keeper/claim.go @@ -0,0 +1,63 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "pocket/x/supplier/types" + "github.com/cosmos/cosmos-sdk/store/prefix" +) + +// SetClaim set a specific claim in the store from its index +func (k Keeper) SetClaim(ctx sdk.Context, claim types.Claim) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) + b := k.cdc.MustMarshal(&claim) + store.Set(types.ClaimKey( + claim.Index, + ), b) +} + +// GetClaim returns a claim from its index +func (k Keeper) GetClaim( + ctx sdk.Context, + index string, + +) (val types.Claim, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) + + b := store.Get(types.ClaimKey( + index, + )) + if b == nil { + return val, false + } + + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +// RemoveClaim removes a claim from the store +func (k Keeper) RemoveClaim( + ctx sdk.Context, + index string, + +) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) + store.Delete(types.ClaimKey( + index, + )) +} + +// GetAllClaim returns all claim +func (k Keeper) GetAllClaim(ctx sdk.Context) (list []types.Claim) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var val types.Claim + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + + return +} diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go new file mode 100644 index 000000000..144fce135 --- /dev/null +++ b/x/supplier/keeper/claim_test.go @@ -0,0 +1,66 @@ +package keeper_test + +import ( + "strconv" + "testing" + + "pocket/x/supplier/keeper" + "pocket/x/supplier/types" + keepertest "pocket/testutil/keeper" + "pocket/testutil/nullify" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +// Prevent strconv unused error +var _ = strconv.IntSize + +func createNClaim(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim { + items := make([]types.Claim, n) + for i := range items { + items[i].Index = strconv.Itoa(i) + + keeper.SetClaim(ctx, items[i]) + } + return items +} + +func TestClaimGet(t *testing.T) { + keeper, ctx := keepertest.SupplierKeeper(t) + items := createNClaim(keeper, ctx, 10) + for _, item := range items { + rst, found := keeper.GetClaim(ctx, + item.Index, + + ) + require.True(t, found) + require.Equal(t, + nullify.Fill(&item), + nullify.Fill(&rst), + ) + } +} +func TestClaimRemove(t *testing.T) { + keeper, ctx := keepertest.SupplierKeeper(t) + items := createNClaim(keeper, ctx, 10) + for _, item := range items { + keeper.RemoveClaim(ctx, + item.Index, + + ) + _, found := keeper.GetClaim(ctx, + item.Index, + + ) + require.False(t, found) + } +} + +func TestClaimGetAll(t *testing.T) { + keeper, ctx := keepertest.SupplierKeeper(t) + items := createNClaim(keeper, ctx, 10) + require.ElementsMatch(t, + nullify.Fill(items), + nullify.Fill(keeper.GetAllClaim(ctx)), + ) +} diff --git a/x/supplier/keeper/msg_server_test.go b/x/supplier/keeper/msg_server_test.go index 7e4d01f27..39fc0075f 100644 --- a/x/supplier/keeper/msg_server_test.go +++ b/x/supplier/keeper/msg_server_test.go @@ -6,10 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - - keepertest "github.com/pokt-network/poktroll/testutil/keeper" - "github.com/pokt-network/poktroll/x/supplier/keeper" - "github.com/pokt-network/poktroll/x/supplier/types" + "github.com/pokt-network/poktroll/x/supplier/types" + "github.com/pokt-network/poktroll/x/supplier/keeper" + keepertest "github.com/pokt-network/poktroll/testutil/keeper" ) func setupMsgServer(t testing.TB) (types.MsgServer, context.Context) { diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go new file mode 100644 index 000000000..fdfa482c8 --- /dev/null +++ b/x/supplier/keeper/query_claim.go @@ -0,0 +1,57 @@ +package keeper + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "pocket/x/supplier/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (k Keeper) ClaimAll(goCtx context.Context, req *types.QueryAllClaimRequest) (*types.QueryAllClaimResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + var claims []types.Claim + ctx := sdk.UnwrapSDKContext(goCtx) + + store := ctx.KVStore(k.storeKey) + claimStore := prefix.NewStore(store, types.KeyPrefix(types.ClaimKeyPrefix)) + + pageRes, err := query.Paginate(claimStore, req.Pagination, func(key []byte, value []byte) error { + var claim types.Claim + if err := k.cdc.Unmarshal(value, &claim); err != nil { + return err + } + + claims = append(claims, claim) + return nil + }) + + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryAllClaimResponse{Claim: claims, Pagination: pageRes}, nil +} + +func (k Keeper) Claim(goCtx context.Context, req *types.QueryGetClaimRequest) (*types.QueryGetClaimResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + val, found := k.GetClaim( + ctx, + req.Index, + ) + if !found { + return nil, status.Error(codes.NotFound, "not found") + } + + return &types.QueryGetClaimResponse{Claim: val}, nil +} \ No newline at end of file diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go new file mode 100644 index 000000000..cf6820663 --- /dev/null +++ b/x/supplier/keeper/query_claim_test.go @@ -0,0 +1,130 @@ +package keeper_test + +import ( + "strconv" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "pocket/x/supplier/types" + "pocket/testutil/nullify" + keepertest "pocket/testutil/keeper" +) + +// Prevent strconv unused error +var _ = strconv.IntSize + +func TestClaimQuerySingle(t *testing.T) { + keeper, ctx := keepertest.SupplierKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + msgs := createNClaim(keeper, ctx, 2) + tests := []struct { + desc string + request *types.QueryGetClaimRequest + response *types.QueryGetClaimResponse + err error + }{ + { + desc: "First", + request: &types.QueryGetClaimRequest{ + Index: msgs[0].Index, + + }, + response: &types.QueryGetClaimResponse{Claim: msgs[0]}, + }, + { + desc: "Second", + request: &types.QueryGetClaimRequest{ + Index: msgs[1].Index, + + }, + response: &types.QueryGetClaimResponse{Claim: msgs[1]}, + }, + { + desc: "KeyNotFound", + request: &types.QueryGetClaimRequest{ + Index:strconv.Itoa(100000), + + }, + err: status.Error(codes.NotFound, "not found"), + }, + { + desc: "InvalidRequest", + err: status.Error(codes.InvalidArgument, "invalid request"), + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + response, err := keeper.Claim(wctx, tc.request) + if tc.err != nil { + require.ErrorIs(t, err, tc.err) + } else { + require.NoError(t, err) + require.Equal(t, + nullify.Fill(tc.response), + nullify.Fill(response), + ) + } + }) + } +} + +func TestClaimQueryPaginated(t *testing.T) { + keeper, ctx := keepertest.SupplierKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + msgs := createNClaim(keeper, ctx, 5) + + request := func(next []byte, offset, limit uint64, total bool) *types.QueryAllClaimRequest { + return &types.QueryAllClaimRequest{ + Pagination: &query.PageRequest{ + Key: next, + Offset: offset, + Limit: limit, + CountTotal: total, + }, + } + } + t.Run("ByOffset", func(t *testing.T) { + step := 2 + for i := 0; i < len(msgs); i += step { + resp, err := keeper.ClaimAll(wctx, request(nil, uint64(i), uint64(step), false)) + require.NoError(t, err) + require.LessOrEqual(t, len(resp.Claim), step) + require.Subset(t, + nullify.Fill(msgs), + nullify.Fill(resp.Claim), + ) + } + }) + t.Run("ByKey", func(t *testing.T) { + step := 2 + var next []byte + for i := 0; i < len(msgs); i += step { + resp, err := keeper.ClaimAll(wctx, request(next, 0, uint64(step), false)) + require.NoError(t, err) + require.LessOrEqual(t, len(resp.Claim), step) + require.Subset(t, + nullify.Fill(msgs), + nullify.Fill(resp.Claim), + ) + next = resp.Pagination.NextKey + } + }) + t.Run("Total", func(t *testing.T) { + resp, err := keeper.ClaimAll(wctx, request(nil, 0, 0, true)) + require.NoError(t, err) + require.Equal(t, len(msgs), int(resp.Pagination.Total)) + require.ElementsMatch(t, + nullify.Fill(msgs), + nullify.Fill(resp.Claim), + ) + }) + t.Run("InvalidRequest", func(t *testing.T) { + _, err := keeper.ClaimAll(wctx, nil) + require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request")) + }) +} diff --git a/x/supplier/types/codec.go b/x/supplier/types/codec.go index 3bb7fcd12..a6ccc8df5 100644 --- a/x/supplier/types/codec.go +++ b/x/supplier/types/codec.go @@ -1,6 +1,7 @@ package types import ( +"github.com/cosmos/cosmos-sdk/types/msgservice" "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -28,6 +29,8 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { ) // this line is used by starport scaffolding # 3 +msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/supplier/types/genesis.go b/x/supplier/types/genesis.go index 2f4ff1872..930802853 100644 --- a/x/supplier/types/genesis.go +++ b/x/supplier/types/genesis.go @@ -17,7 +17,8 @@ const DefaultIndex uint64 = 1 func DefaultGenesis() *GenesisState { return &GenesisState{ SupplierList: []sharedtypes.Supplier{}, - // this line is used by starport scaffolding # genesis/types/default + ClaimList: []Claim{}, +// this line is used by starport scaffolding # genesis/types/default Params: DefaultParams(), } } @@ -63,7 +64,17 @@ func (gs GenesisState) Validate() error { } } - // this line is used by starport scaffolding # genesis/types/validate + // Check for duplicated index in claim +claimIndexMap := make(map[string]struct{}) + +for _, elem := range gs.ClaimList { + index := string(ClaimKey(elem.Index)) + if _, ok := claimIndexMap[index]; ok { + return fmt.Errorf("duplicated index for claim") + } + claimIndexMap[index] = struct{}{} +} +// this line is used by starport scaffolding # genesis/types/validate return gs.Params.Validate() } diff --git a/x/supplier/types/genesis_test.go b/x/supplier/types/genesis_test.go index ba806c98b..65267170f 100644 --- a/x/supplier/types/genesis_test.go +++ b/x/supplier/types/genesis_test.go @@ -70,7 +70,15 @@ func TestGenesisState_Validate(t *testing.T) { Services: serviceList2, }, }, - // this line is used by starport scaffolding # types/genesis/validField + ClaimList: []types.Claim{ + { + Index: "0", +}, + { + Index: "1", +}, +}, +// this line is used by starport scaffolding # types/genesis/validField }, valid: true, }, @@ -298,7 +306,21 @@ func TestGenesisState_Validate(t *testing.T) { }, valid: false, }, - // this line is used by starport scaffolding # types/genesis/testcase + { + desc: "duplicated claim", + genState: &types.GenesisState{ + ClaimList: []types.Claim{ + { + Index: "0", +}, + { + Index: "0", +}, + }, + }, + valid: false, +}, +// this line is used by starport scaffolding # types/genesis/testcase } for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go new file mode 100644 index 000000000..88f7db3da --- /dev/null +++ b/x/supplier/types/key_claim.go @@ -0,0 +1,23 @@ +package types + +import "encoding/binary" + +var _ binary.ByteOrder + +const ( + // ClaimKeyPrefix is the prefix to retrieve all Claim + ClaimKeyPrefix = "Claim/value/" +) + +// ClaimKey returns the store key to retrieve a Claim from the index fields +func ClaimKey( +index string, +) []byte { + var key []byte + + indexBytes := []byte(index) + key = append(key, indexBytes...) + key = append(key, []byte("/")...) + + return key +} \ No newline at end of file From 1d31b944edc60e198ae7d45469d97481262c2b25 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 15:58:28 -0800 Subject: [PATCH 02/40] WIP - updating saffolded claim --- go.mod | 5 +- go.sum | 4 +- proto/pocket/supplier/claim.proto | 16 ++--- proto/pocket/supplier/genesis.proto | 1 - proto/poktroll/supplier/tx.proto | 7 -- x/supplier/client/cli/query_claim.go | 84 +++++++++++------------ x/supplier/client/cli/query_claim_test.go | 36 +++++----- x/supplier/genesis.go | 10 +-- x/supplier/genesis_test.go | 13 +--- x/supplier/types/genesis.go | 15 +--- x/supplier/types/genesis_test.go | 26 +------ 11 files changed, 78 insertions(+), 139 deletions(-) delete mode 100644 proto/poktroll/supplier/tx.proto diff --git a/go.mod b/go.mod index 1f263d032..2d699d1cf 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -19,7 +18,6 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 - github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c github.com/regen-network/gocuke v0.6.2 github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 @@ -28,7 +26,6 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -72,6 +69,7 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -266,6 +264,7 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index cb47c97c6..ef5829bd5 100644 --- a/go.sum +++ b/go.sum @@ -933,8 +933,8 @@ github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoD github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= @@ -1582,8 +1582,6 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c h1:XyPmGsaCFgWwi/xz8XveRMZjXPqJhzagg/MA4W6o2O0= -github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c/go.mod h1:t40oLsJlR9eRh9oDJTJZEUPk5e2/lCR+g2NCOhxrRxU= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/polyfloyd/go-errorlint v1.0.0/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA= diff --git a/proto/pocket/supplier/claim.proto b/proto/pocket/supplier/claim.proto index 34fcc0d91..dadf06cbb 100644 --- a/proto/pocket/supplier/claim.proto +++ b/proto/pocket/supplier/claim.proto @@ -1,13 +1,13 @@ syntax = "proto3"; package pocket.supplier; -option go_package = "pocket/x/supplier/types"; +option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; + +import "cosmos_proto/cosmos.proto"; -message Claim { - string index = 1; - string supplierAddress = 2; - string sessionId = 3; - string rootHash = 4; - -} +message Claim { + string supplier_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // the address of the supplier that submitted this claims + string session_id = 2; // session id from the SessionHeader + bytes root_hash = 3; // smt.SMST#Root() +} \ No newline at end of file diff --git a/proto/pocket/supplier/genesis.proto b/proto/pocket/supplier/genesis.proto index cdf8fb554..a35a4a994 100644 --- a/proto/pocket/supplier/genesis.proto +++ b/proto/pocket/supplier/genesis.proto @@ -13,6 +13,5 @@ option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; message GenesisState { Params params = 1 [(gogoproto.nullable) = false]; repeated pocket.shared.Supplier supplierList = 2 [(gogoproto.nullable) = false]; - repeated Claim claimList = 3 [(gogoproto.nullable) = false]; } diff --git a/proto/poktroll/supplier/tx.proto b/proto/poktroll/supplier/tx.proto deleted file mode 100644 index a79dbc183..000000000 --- a/proto/poktroll/supplier/tx.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto3"; -package poktroll.supplier; - -option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; - -// Msg defines the Msg service. -service Msg {} \ No newline at end of file diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index a8462062a..3eb32c759 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -1,12 +1,11 @@ package cli import ( - "github.com/spf13/cobra" + "pocket/x/supplier/types" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - - - "pocket/x/supplier/types" + "github.com/spf13/cobra" ) func CmdListClaim() *cobra.Command { @@ -14,35 +13,35 @@ func CmdListClaim() *cobra.Command { Use: "list-claim", Short: "list all claim", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } - pageReq, err := client.ReadPageRequest(cmd.Flags()) - if err != nil { - return err - } + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } - queryClient := types.NewQueryClient(clientCtx) + queryClient := types.NewQueryClient(clientCtx) - params := &types.QueryAllClaimRequest{ - Pagination: pageReq, - } + params := &types.QueryAllClaimRequest{ + Pagination: pageReq, + } - res, err := queryClient.ClaimAll(cmd.Context(), params) - if err != nil { - return err - } + res, err := queryClient.ClaimAll(cmd.Context(), params) + if err != nil { + return err + } - return clientCtx.PrintProto(res) + return clientCtx.PrintProto(res) }, } flags.AddPaginationFlagsToCmd(cmd, cmd.Use) flags.AddQueryFlagsToCmd(cmd) - return cmd + return cmd } func CmdShowClaim() *cobra.Command { @@ -51,30 +50,29 @@ func CmdShowClaim() *cobra.Command { Short: "shows a claim", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - argIndex := args[0] - - params := &types.QueryGetClaimRequest{ - Index: argIndex, - - } - - res, err := queryClient.Claim(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + argIndex := args[0] + + params := &types.QueryGetClaimRequest{ + Index: argIndex, + } + + res, err := queryClient.Claim(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) }, } flags.AddQueryFlagsToCmd(cmd) - return cmd + return cmd } diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 069ca494a..ee1e62551 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -5,17 +5,17 @@ import ( "strconv" "testing" + tmcli "github.com/cometbft/cometbft/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/stretchr/testify/require" - tmcli "github.com/cometbft/cometbft/libs/cli" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "pocket/testutil/network" "pocket/testutil/nullify" "pocket/x/supplier/client/cli" - "pocket/x/supplier/types" + "pocket/x/supplier/types" ) // Prevent strconv unused error @@ -26,12 +26,11 @@ func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Cla cfg := network.DefaultConfig() state := types.GenesisState{} for i := 0; i < n; i++ { - claim := types.Claim{ + claim := types.Claim{ Index: strconv.Itoa(i), - } nullify.Fill(&claim) - state.ClaimList = append(state.ClaimList, claim) + // state.ClaimList = append(state.ClaimList, claim) } buf, err := cfg.Codec.MarshalJSON(&state) require.NoError(t, err) @@ -47,24 +46,24 @@ func TestShowClaim(t *testing.T) { fmt.Sprintf("--%s=json", tmcli.OutputFlag), } tests := []struct { - desc string + desc string idIndex string - + args []string err error obj types.Claim }{ { - desc: "found", + desc: "found", idIndex: objs[0].Index, - + args: common, obj: objs[0], }, { - desc: "not found", + desc: "not found", idIndex: strconv.Itoa(100000), - + args: common, err: status.Error(codes.NotFound, "not found"), }, @@ -72,8 +71,7 @@ func TestShowClaim(t *testing.T) { for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { args := []string{ - tc.idIndex, - + tc.idIndex, } args = append(args, tc.args...) out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) @@ -124,9 +122,9 @@ func TestListClaim(t *testing.T) { require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.Claim), - ) + nullify.Fill(objs), + nullify.Fill(resp.Claim), + ) } }) t.Run("ByKey", func(t *testing.T) { @@ -140,9 +138,9 @@ func TestListClaim(t *testing.T) { require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.Claim), - ) + nullify.Fill(objs), + nullify.Fill(resp.Claim), + ) next = resp.Pagination.NextKey } }) diff --git a/x/supplier/genesis.go b/x/supplier/genesis.go index 29f433b5a..929938667 100644 --- a/x/supplier/genesis.go +++ b/x/supplier/genesis.go @@ -13,11 +13,8 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) for _, supplier := range genState.SupplierList { k.SetSupplier(ctx, supplier) } - // Set all the claim -for _, elem := range genState.ClaimList { - k.SetClaim(ctx, elem) -} -// this line is used by starport scaffolding # genesis/module/init + + // this line is used by starport scaffolding # genesis/module/init k.SetParams(ctx, genState.Params) } @@ -27,8 +24,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.Params = k.GetParams(ctx) genesis.SupplierList = k.GetAllSupplier(ctx) - genesis.ClaimList = k.GetAllClaim(ctx) -// this line is used by starport scaffolding # genesis/module/export + // this line is used by starport scaffolding # genesis/module/export return genesis } diff --git a/x/supplier/genesis_test.go b/x/supplier/genesis_test.go index 679caf38d..b6af0545c 100644 --- a/x/supplier/genesis_test.go +++ b/x/supplier/genesis_test.go @@ -56,15 +56,7 @@ func TestGenesis(t *testing.T) { }, }, }, - ClaimList: []types.Claim{ - { - Index: "0", -}, - { - Index: "1", -}, - }, - // this line is used by starport scaffolding # genesis/test/state + // this line is used by starport scaffolding # genesis/test/state } k, ctx := keepertest.SupplierKeeper(t) @@ -76,6 +68,5 @@ func TestGenesis(t *testing.T) { nullify.Fill(got) require.ElementsMatch(t, genesisState.SupplierList, got.SupplierList) - require.ElementsMatch(t, genesisState.ClaimList, got.ClaimList) -// this line is used by starport scaffolding # genesis/test/assert + // this line is used by starport scaffolding # genesis/test/assert } diff --git a/x/supplier/types/genesis.go b/x/supplier/types/genesis.go index 930802853..2f4ff1872 100644 --- a/x/supplier/types/genesis.go +++ b/x/supplier/types/genesis.go @@ -17,8 +17,7 @@ const DefaultIndex uint64 = 1 func DefaultGenesis() *GenesisState { return &GenesisState{ SupplierList: []sharedtypes.Supplier{}, - ClaimList: []Claim{}, -// this line is used by starport scaffolding # genesis/types/default + // this line is used by starport scaffolding # genesis/types/default Params: DefaultParams(), } } @@ -64,17 +63,7 @@ func (gs GenesisState) Validate() error { } } - // Check for duplicated index in claim -claimIndexMap := make(map[string]struct{}) - -for _, elem := range gs.ClaimList { - index := string(ClaimKey(elem.Index)) - if _, ok := claimIndexMap[index]; ok { - return fmt.Errorf("duplicated index for claim") - } - claimIndexMap[index] = struct{}{} -} -// this line is used by starport scaffolding # genesis/types/validate + // this line is used by starport scaffolding # genesis/types/validate return gs.Params.Validate() } diff --git a/x/supplier/types/genesis_test.go b/x/supplier/types/genesis_test.go index 65267170f..ba806c98b 100644 --- a/x/supplier/types/genesis_test.go +++ b/x/supplier/types/genesis_test.go @@ -70,15 +70,7 @@ func TestGenesisState_Validate(t *testing.T) { Services: serviceList2, }, }, - ClaimList: []types.Claim{ - { - Index: "0", -}, - { - Index: "1", -}, -}, -// this line is used by starport scaffolding # types/genesis/validField + // this line is used by starport scaffolding # types/genesis/validField }, valid: true, }, @@ -306,21 +298,7 @@ func TestGenesisState_Validate(t *testing.T) { }, valid: false, }, - { - desc: "duplicated claim", - genState: &types.GenesisState{ - ClaimList: []types.Claim{ - { - Index: "0", -}, - { - Index: "0", -}, - }, - }, - valid: false, -}, -// this line is used by starport scaffolding # types/genesis/testcase + // this line is used by starport scaffolding # types/genesis/testcase } for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { From 978161a080318b7727c1ce649b01ca27054f8801 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 16:18:40 -0800 Subject: [PATCH 03/40] Fixed inconsistencies due to the new import --- go.mod | 5 +- go.sum | 4 +- proto/pocket/supplier/claim.proto | 12 ++-- x/supplier/client/cli/query_claim.go | 82 +++++++++++------------ x/supplier/client/cli/query_claim_test.go | 40 ++++++----- x/supplier/keeper/claim.go | 42 ++++++------ x/supplier/keeper/claim_test.go | 19 +++--- x/supplier/keeper/query_claim.go | 12 ++-- x/supplier/keeper/query_claim_test.go | 41 ++++++------ 9 files changed, 122 insertions(+), 135 deletions(-) diff --git a/go.mod b/go.mod index 1f263d032..2d699d1cf 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -19,7 +18,6 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 - github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c github.com/regen-network/gocuke v0.6.2 github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 @@ -28,7 +26,6 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -72,6 +69,7 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -266,6 +264,7 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index cb47c97c6..ef5829bd5 100644 --- a/go.sum +++ b/go.sum @@ -933,8 +933,8 @@ github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoD github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= @@ -1582,8 +1582,6 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c h1:XyPmGsaCFgWwi/xz8XveRMZjXPqJhzagg/MA4W6o2O0= -github.com/pokt-network/poktroll v0.0.0-20231106202723-6e5cad87803c/go.mod h1:t40oLsJlR9eRh9oDJTJZEUPk5e2/lCR+g2NCOhxrRxU= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/polyfloyd/go-errorlint v1.0.0/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA= diff --git a/proto/pocket/supplier/claim.proto b/proto/pocket/supplier/claim.proto index 34fcc0d91..2368c5072 100644 --- a/proto/pocket/supplier/claim.proto +++ b/proto/pocket/supplier/claim.proto @@ -1,13 +1,13 @@ syntax = "proto3"; package pocket.supplier; -option go_package = "pocket/x/supplier/types"; +option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; message Claim { - string index = 1; - string supplierAddress = 2; - string sessionId = 3; - string rootHash = 4; - + string index = 1; + string supplierAddress = 2; + string sessionId = 3; + string rootHash = 4; + } diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index a8462062a..445607ba6 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -1,12 +1,11 @@ package cli import ( - "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" - - "pocket/x/supplier/types" + "github.com/pokt-network/poktroll/x/supplier/types" ) func CmdListClaim() *cobra.Command { @@ -14,35 +13,35 @@ func CmdListClaim() *cobra.Command { Use: "list-claim", Short: "list all claim", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } - pageReq, err := client.ReadPageRequest(cmd.Flags()) - if err != nil { - return err - } + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } - queryClient := types.NewQueryClient(clientCtx) + queryClient := types.NewQueryClient(clientCtx) - params := &types.QueryAllClaimRequest{ - Pagination: pageReq, - } + params := &types.QueryAllClaimRequest{ + Pagination: pageReq, + } - res, err := queryClient.ClaimAll(cmd.Context(), params) - if err != nil { - return err - } + res, err := queryClient.ClaimAll(cmd.Context(), params) + if err != nil { + return err + } - return clientCtx.PrintProto(res) + return clientCtx.PrintProto(res) }, } flags.AddPaginationFlagsToCmd(cmd, cmd.Use) flags.AddQueryFlagsToCmd(cmd) - return cmd + return cmd } func CmdShowClaim() *cobra.Command { @@ -51,30 +50,29 @@ func CmdShowClaim() *cobra.Command { Short: "shows a claim", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - argIndex := args[0] - - params := &types.QueryGetClaimRequest{ - Index: argIndex, - - } - - res, err := queryClient.Claim(cmd.Context(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + argIndex := args[0] + + params := &types.QueryGetClaimRequest{ + Index: argIndex, + } + + res, err := queryClient.Claim(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) }, } flags.AddQueryFlagsToCmd(cmd) - return cmd + return cmd } diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 069ca494a..9ca4fb9f6 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -5,17 +5,17 @@ import ( "strconv" "testing" + tmcli "github.com/cometbft/cometbft/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/stretchr/testify/require" - tmcli "github.com/cometbft/cometbft/libs/cli" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "pocket/testutil/network" - "pocket/testutil/nullify" - "pocket/x/supplier/client/cli" - "pocket/x/supplier/types" + "github.com/pokt-network/poktroll/testutil/network" + "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/x/supplier/client/cli" + "github.com/pokt-network/poktroll/x/supplier/types" ) // Prevent strconv unused error @@ -26,9 +26,8 @@ func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Cla cfg := network.DefaultConfig() state := types.GenesisState{} for i := 0; i < n; i++ { - claim := types.Claim{ + claim := types.Claim{ Index: strconv.Itoa(i), - } nullify.Fill(&claim) state.ClaimList = append(state.ClaimList, claim) @@ -47,24 +46,24 @@ func TestShowClaim(t *testing.T) { fmt.Sprintf("--%s=json", tmcli.OutputFlag), } tests := []struct { - desc string + desc string idIndex string - + args []string err error obj types.Claim }{ { - desc: "found", + desc: "found", idIndex: objs[0].Index, - + args: common, obj: objs[0], }, { - desc: "not found", + desc: "not found", idIndex: strconv.Itoa(100000), - + args: common, err: status.Error(codes.NotFound, "not found"), }, @@ -72,8 +71,7 @@ func TestShowClaim(t *testing.T) { for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { args := []string{ - tc.idIndex, - + tc.idIndex, } args = append(args, tc.args...) out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) @@ -124,9 +122,9 @@ func TestListClaim(t *testing.T) { require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.Claim), - ) + nullify.Fill(objs), + nullify.Fill(resp.Claim), + ) } }) t.Run("ByKey", func(t *testing.T) { @@ -140,9 +138,9 @@ func TestListClaim(t *testing.T) { require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.Claim), - ) + nullify.Fill(objs), + nullify.Fill(resp.Claim), + ) next = resp.Pagination.NextKey } }) diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 434c2f1b3..a550dddb0 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -1,34 +1,34 @@ package keeper import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "pocket/x/supplier/types" "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/pokt-network/poktroll/x/supplier/types" ) // SetClaim set a specific claim in the store from its index func (k Keeper) SetClaim(ctx sdk.Context, claim types.Claim) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) b := k.cdc.MustMarshal(&claim) store.Set(types.ClaimKey( - claim.Index, - ), b) + claim.Index, + ), b) } // GetClaim returns a claim from its index func (k Keeper) GetClaim( - ctx sdk.Context, - index string, - + ctx sdk.Context, + index string, + ) (val types.Claim, found bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) b := store.Get(types.ClaimKey( - index, - )) - if b == nil { - return val, false - } + index, + )) + if b == nil { + return val, false + } k.cdc.MustUnmarshal(b, &val) return val, true @@ -36,19 +36,19 @@ func (k Keeper) GetClaim( // RemoveClaim removes a claim from the store func (k Keeper) RemoveClaim( - ctx sdk.Context, - index string, - + ctx sdk.Context, + index string, + ) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) store.Delete(types.ClaimKey( - index, - )) + index, + )) } // GetAllClaim returns all claim func (k Keeper) GetAllClaim(ctx sdk.Context) (list []types.Claim) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) defer iterator.Close() @@ -56,8 +56,8 @@ func (k Keeper) GetAllClaim(ctx sdk.Context) (list []types.Claim) { for ; iterator.Valid(); iterator.Next() { var val types.Claim k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) + list = append(list, val) } - return + return } diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go index 144fce135..93ae0df40 100644 --- a/x/supplier/keeper/claim_test.go +++ b/x/supplier/keeper/claim_test.go @@ -4,11 +4,11 @@ import ( "strconv" "testing" - "pocket/x/supplier/keeper" - "pocket/x/supplier/types" - keepertest "pocket/testutil/keeper" - "pocket/testutil/nullify" sdk "github.com/cosmos/cosmos-sdk/types" + keepertest "github.com/pokt-network/poktroll/testutil/keeper" + "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/x/supplier/keeper" + "github.com/pokt-network/poktroll/x/supplier/types" "github.com/stretchr/testify/require" ) @@ -19,7 +19,7 @@ func createNClaim(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim { items := make([]types.Claim, n) for i := range items { items[i].Index = strconv.Itoa(i) - + keeper.SetClaim(ctx, items[i]) } return items @@ -30,8 +30,7 @@ func TestClaimGet(t *testing.T) { items := createNClaim(keeper, ctx, 10) for _, item := range items { rst, found := keeper.GetClaim(ctx, - item.Index, - + item.Index, ) require.True(t, found) require.Equal(t, @@ -45,12 +44,10 @@ func TestClaimRemove(t *testing.T) { items := createNClaim(keeper, ctx, 10) for _, item := range items { keeper.RemoveClaim(ctx, - item.Index, - + item.Index, ) _, found := keeper.GetClaim(ctx, - item.Index, - + item.Index, ) require.False(t, found) } diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index fdfa482c8..80a0ff61c 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - "pocket/x/supplier/types" + "github.com/pokt-network/poktroll/x/supplier/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -46,12 +46,12 @@ func (k Keeper) Claim(goCtx context.Context, req *types.QueryGetClaimRequest) (* ctx := sdk.UnwrapSDKContext(goCtx) val, found := k.GetClaim( - ctx, - req.Index, - ) + ctx, + req.Index, + ) if !found { - return nil, status.Error(codes.NotFound, "not found") + return nil, status.Error(codes.NotFound, "not found") } return &types.QueryGetClaimResponse{Claim: val}, nil -} \ No newline at end of file +} diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index cf6820663..3ec5d0ec0 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -1,7 +1,7 @@ package keeper_test import ( - "strconv" + "strconv" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -10,9 +10,9 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "pocket/x/supplier/types" - "pocket/testutil/nullify" - keepertest "pocket/testutil/keeper" + keepertest "github.com/pokt-network/poktroll/testutil/keeper" + "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/x/supplier/types" ) // Prevent strconv unused error @@ -29,28 +29,25 @@ func TestClaimQuerySingle(t *testing.T) { err error }{ { - desc: "First", - request: &types.QueryGetClaimRequest{ - Index: msgs[0].Index, - + desc: "First", + request: &types.QueryGetClaimRequest{ + Index: msgs[0].Index, }, response: &types.QueryGetClaimResponse{Claim: msgs[0]}, }, { - desc: "Second", - request: &types.QueryGetClaimRequest{ - Index: msgs[1].Index, - + desc: "Second", + request: &types.QueryGetClaimRequest{ + Index: msgs[1].Index, }, response: &types.QueryGetClaimResponse{Claim: msgs[1]}, }, { - desc: "KeyNotFound", + desc: "KeyNotFound", request: &types.QueryGetClaimRequest{ - Index:strconv.Itoa(100000), - + Index: strconv.Itoa(100000), }, - err: status.Error(codes.NotFound, "not found"), + err: status.Error(codes.NotFound, "not found"), }, { desc: "InvalidRequest", @@ -95,9 +92,9 @@ func TestClaimQueryPaginated(t *testing.T) { require.NoError(t, err) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, - nullify.Fill(msgs), - nullify.Fill(resp.Claim), - ) + nullify.Fill(msgs), + nullify.Fill(resp.Claim), + ) } }) t.Run("ByKey", func(t *testing.T) { @@ -108,9 +105,9 @@ func TestClaimQueryPaginated(t *testing.T) { require.NoError(t, err) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, - nullify.Fill(msgs), - nullify.Fill(resp.Claim), - ) + nullify.Fill(msgs), + nullify.Fill(resp.Claim), + ) next = resp.Pagination.NextKey } }) From 1ee4487314bf26ef3efd825fef32fbdda14e175c Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 16:22:01 -0800 Subject: [PATCH 04/40] make go_develop_and_test compiles again --- docs/static/openapi.yml | 240 +++++++++++++++++++++++++++++++ proto/poktroll/supplier/tx.proto | 7 - x/supplier/types/codec.go | 3 +- x/supplier/types/key_claim.go | 16 +-- 4 files changed, 249 insertions(+), 17 deletions(-) delete mode 100644 proto/poktroll/supplier/tx.proto diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 687106365..45155d6e5 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -47430,6 +47430,179 @@ paths: additionalProperties: {} tags: - Query + /pocket/supplier/claim: + get: + operationId: PocketSupplierClaimAll + responses: + '200': + description: A successful response. + schema: + type: object + properties: + claim: + type: array + items: + type: object + properties: + index: + type: string + supplierAddress: + type: string + sessionId: + type: string + rootHash: + type: string + pagination: + type: object + properties: + next_key: + type: string + format: byte + description: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently. It will be empty if + there are no more results. + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + default: + description: An unexpected error response. + schema: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + '@type': + type: string + additionalProperties: {} + parameters: + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + - name: pagination.reverse + description: >- + reverse is set to true if results are to be returned in the + descending order. + + + Since: cosmos-sdk 0.43 + in: query + required: false + type: boolean + tags: + - Query + /pocket/supplier/claim/{index}: + get: + summary: Queries a list of Claim items. + operationId: PocketSupplierClaim + responses: + '200': + description: A successful response. + schema: + type: object + properties: + claim: + type: object + properties: + index: + type: string + supplierAddress: + type: string + sessionId: + type: string + rootHash: + type: string + default: + description: An unexpected error response. + schema: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + '@type': + type: string + additionalProperties: {} + parameters: + - name: index + in: path + required: true + type: string + tags: + - Query /pocket/supplier/params: get: summary: Parameters queries the parameters of the module. @@ -77864,6 +78037,17 @@ definitions: title: >- SupplierServiceConfig holds the service configuration the supplier stakes for + pocket.supplier.Claim: + type: object + properties: + index: + type: string + supplierAddress: + type: string + sessionId: + type: string + rootHash: + type: string pocket.supplier.MsgCreateClaimResponse: type: object pocket.supplier.MsgStakeSupplierResponse: @@ -77875,6 +78059,48 @@ definitions: pocket.supplier.Params: type: object description: Params defines the parameters for the module. + pocket.supplier.QueryAllClaimResponse: + type: object + properties: + claim: + type: array + items: + type: object + properties: + index: + type: string + supplierAddress: + type: string + sessionId: + type: string + rootHash: + type: string + pagination: + type: object + properties: + next_key: + type: string + format: byte + description: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently. It will be empty if + there are no more results. + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } pocket.supplier.QueryAllSupplierResponse: type: object properties: @@ -78021,6 +78247,20 @@ definitions: repeated Bar results = 1; PageResponse page = 2; } + pocket.supplier.QueryGetClaimResponse: + type: object + properties: + claim: + type: object + properties: + index: + type: string + supplierAddress: + type: string + sessionId: + type: string + rootHash: + type: string pocket.supplier.QueryGetSupplierResponse: type: object properties: diff --git a/proto/poktroll/supplier/tx.proto b/proto/poktroll/supplier/tx.proto deleted file mode 100644 index a79dbc183..000000000 --- a/proto/poktroll/supplier/tx.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto3"; -package poktroll.supplier; - -option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; - -// Msg defines the Msg service. -service Msg {} \ No newline at end of file diff --git a/x/supplier/types/codec.go b/x/supplier/types/codec.go index a6ccc8df5..364fde198 100644 --- a/x/supplier/types/codec.go +++ b/x/supplier/types/codec.go @@ -1,7 +1,6 @@ package types import ( -"github.com/cosmos/cosmos-sdk/types/msgservice" "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -29,7 +28,7 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { ) // this line is used by starport scaffolding # 3 -msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go index 88f7db3da..e57164b57 100644 --- a/x/supplier/types/key_claim.go +++ b/x/supplier/types/key_claim.go @@ -5,19 +5,19 @@ import "encoding/binary" var _ binary.ByteOrder const ( - // ClaimKeyPrefix is the prefix to retrieve all Claim + // ClaimKeyPrefix is the prefix to retrieve all Claim ClaimKeyPrefix = "Claim/value/" ) // ClaimKey returns the store key to retrieve a Claim from the index fields func ClaimKey( -index string, + index string, ) []byte { var key []byte - - indexBytes := []byte(index) - key = append(key, indexBytes...) - key = append(key, []byte("/")...) - + + indexBytes := []byte(index) + key = append(key, indexBytes...) + key = append(key, []byte("/")...) + return key -} \ No newline at end of file +} From 497368935fd3774dd93c85d597ef0b4e746f42a3 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 16:32:37 -0800 Subject: [PATCH 05/40] Updates in progress --- docs/static/openapi.yml | 60 +++-- go.mod | 4 +- x/supplier/client/cli/query_claim_test.go | 273 ++++++++++------------ x/supplier/keeper/claim.go | 12 +- x/supplier/types/codec.go | 2 - x/supplier/types/key_claim.go | 14 +- 6 files changed, 181 insertions(+), 184 deletions(-) diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 45155d6e5..857c72741 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -47444,14 +47444,16 @@ paths: items: type: object properties: - index: + supplier_address: type: string - supplierAddress: + title: the address of the supplier that submitted this claims + session_id: type: string - sessionId: - type: string - rootHash: + title: session id from the SessionHeader + root_hash: type: string + format: byte + title: smt.SMST#Root() pagination: type: object properties: @@ -47570,14 +47572,16 @@ paths: claim: type: object properties: - index: - type: string - supplierAddress: + supplier_address: type: string - sessionId: + title: the address of the supplier that submitted this claims + session_id: type: string - rootHash: + title: session id from the SessionHeader + root_hash: type: string + format: byte + title: smt.SMST#Root() default: description: An unexpected error response. schema: @@ -78040,14 +78044,16 @@ definitions: pocket.supplier.Claim: type: object properties: - index: - type: string - supplierAddress: + supplier_address: type: string - sessionId: + title: the address of the supplier that submitted this claims + session_id: type: string - rootHash: + title: session id from the SessionHeader + root_hash: type: string + format: byte + title: smt.SMST#Root() pocket.supplier.MsgCreateClaimResponse: type: object pocket.supplier.MsgStakeSupplierResponse: @@ -78067,14 +78073,16 @@ definitions: items: type: object properties: - index: - type: string - supplierAddress: + supplier_address: type: string - sessionId: + title: the address of the supplier that submitted this claims + session_id: type: string - rootHash: + title: session id from the SessionHeader + root_hash: type: string + format: byte + title: smt.SMST#Root() pagination: type: object properties: @@ -78253,14 +78261,16 @@ definitions: claim: type: object properties: - index: - type: string - supplierAddress: + supplier_address: type: string - sessionId: + title: the address of the supplier that submitted this claims + session_id: type: string - rootHash: + title: session id from the SessionHeader + root_hash: type: string + format: byte + title: smt.SMST#Root() pocket.supplier.QueryGetSupplierResponse: type: object properties: diff --git a/go.mod b/go.mod index 2d699d1cf..3eee15c4b 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -26,6 +27,7 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -69,7 +71,6 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -264,7 +265,6 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index d1aea5742..4d91b4f77 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -1,160 +1,145 @@ package cli_test import ( - "fmt" "strconv" - "testing" - - tmcli "github.com/cometbft/cometbft/libs/cli" - "github.com/cosmos/cosmos-sdk/client/flags" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/pokt-network/poktroll/testutil/network" - "github.com/pokt-network/poktroll/testutil/nullify" - "github.com/pokt-network/poktroll/x/supplier/client/cli" - "github.com/pokt-network/poktroll/x/supplier/types" ) // Prevent strconv unused error var _ = strconv.IntSize -func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Claim) { - t.Helper() - cfg := network.DefaultConfig() - state := types.GenesisState{} - for i := 0; i < n; i++ { - claim := types.Claim{ - Index: strconv.Itoa(i), - } - nullify.Fill(&claim) - // state.ClaimList = append(state.ClaimList, claim) - } - buf, err := cfg.Codec.MarshalJSON(&state) - require.NoError(t, err) - cfg.GenesisState[types.ModuleName] = buf - return network.New(t, cfg), state.ClaimList -} +// func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Claim) { +// t.Helper() +// cfg := network.DefaultConfig() +// state := types.GenesisState{} +// for i := 0; i < n; i++ { +// claim := types.Claim{ +// Index: strconv.Itoa(i), +// } +// nullify.Fill(&claim) +// } +// buf, err := cfg.Codec.MarshalJSON(&state) +// require.NoError(t, err) +// cfg.GenesisState[types.ModuleName] = buf +// return network.New(t, cfg), state.ClaimList +// } -func TestShowClaim(t *testing.T) { - net, objs := networkWithClaimObjects(t, 2) +// func TestShowClaim(t *testing.T) { +// net, objs := networkWithClaimObjects(t, 2) - ctx := net.Validators[0].ClientCtx - common := []string{ - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - } - tests := []struct { - desc string - idIndex string +// ctx := net.Validators[0].ClientCtx +// common := []string{ +// fmt.Sprintf("--%s=json", tmcli.OutputFlag), +// } +// tests := []struct { +// desc string +// idIndex string - args []string - err error - obj types.Claim - }{ - { - desc: "found", - idIndex: objs[0].Index, +// args []string +// err error +// obj types.Claim +// }{ +// { +// desc: "found", +// idIndex: objs[0].Index, - args: common, - obj: objs[0], - }, - { - desc: "not found", - idIndex: strconv.Itoa(100000), +// args: common, +// obj: objs[0], +// }, +// { +// desc: "not found", +// idIndex: strconv.Itoa(100000), - args: common, - err: status.Error(codes.NotFound, "not found"), - }, - } - for _, tc := range tests { - t.Run(tc.desc, func(t *testing.T) { - args := []string{ - tc.idIndex, - } - args = append(args, tc.args...) - out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) - if tc.err != nil { - stat, ok := status.FromError(tc.err) - require.True(t, ok) - require.ErrorIs(t, stat.Err(), tc.err) - } else { - require.NoError(t, err) - var resp types.QueryGetClaimResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.NotNil(t, resp.Claim) - require.Equal(t, - nullify.Fill(&tc.obj), - nullify.Fill(&resp.Claim), - ) - } - }) - } -} +// args: common, +// err: status.Error(codes.NotFound, "not found"), +// }, +// } +// for _, tc := range tests { +// t.Run(tc.desc, func(t *testing.T) { +// args := []string{ +// tc.idIndex, +// } +// args = append(args, tc.args...) +// out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) +// if tc.err != nil { +// stat, ok := status.FromError(tc.err) +// require.True(t, ok) +// require.ErrorIs(t, stat.Err(), tc.err) +// } else { +// require.NoError(t, err) +// var resp types.QueryGetClaimResponse +// require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) +// require.NotNil(t, resp.Claim) +// require.Equal(t, +// nullify.Fill(&tc.obj), +// nullify.Fill(&resp.Claim), +// ) +// } +// }) +// } +// } -func TestListClaim(t *testing.T) { - net, objs := networkWithClaimObjects(t, 5) +// func TestListClaim(t *testing.T) { +// net, objs := networkWithClaimObjects(t, 5) - ctx := net.Validators[0].ClientCtx - request := func(next []byte, offset, limit uint64, total bool) []string { - args := []string{ - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - } - if next == nil { - args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) - } else { - args = append(args, fmt.Sprintf("--%s=%s", flags.FlagPageKey, next)) - } - args = append(args, fmt.Sprintf("--%s=%d", flags.FlagLimit, limit)) - if total { - args = append(args, fmt.Sprintf("--%s", flags.FlagCountTotal)) - } - return args - } - t.Run("ByOffset", func(t *testing.T) { - step := 2 - for i := 0; i < len(objs); i += step { - args := request(nil, uint64(i), uint64(step), false) - out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) - require.NoError(t, err) - var resp types.QueryAllClaimResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.LessOrEqual(t, len(resp.Claim), step) - require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.Claim), - ) - } - }) - t.Run("ByKey", func(t *testing.T) { - step := 2 - var next []byte - for i := 0; i < len(objs); i += step { - args := request(next, 0, uint64(step), false) - out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) - require.NoError(t, err) - var resp types.QueryAllClaimResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.LessOrEqual(t, len(resp.Claim), step) - require.Subset(t, - nullify.Fill(objs), - nullify.Fill(resp.Claim), - ) - next = resp.Pagination.NextKey - } - }) - t.Run("Total", func(t *testing.T) { - args := request(nil, 0, uint64(len(objs)), true) - out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) - require.NoError(t, err) - var resp types.QueryAllClaimResponse - require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.NoError(t, err) - require.Equal(t, len(objs), int(resp.Pagination.Total)) - require.ElementsMatch(t, - nullify.Fill(objs), - nullify.Fill(resp.Claim), - ) - }) -} +// ctx := net.Validators[0].ClientCtx +// request := func(next []byte, offset, limit uint64, total bool) []string { +// args := []string{ +// fmt.Sprintf("--%s=json", tmcli.OutputFlag), +// } +// if next == nil { +// args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) +// } else { +// args = append(args, fmt.Sprintf("--%s=%s", flags.FlagPageKey, next)) +// } +// args = append(args, fmt.Sprintf("--%s=%d", flags.FlagLimit, limit)) +// if total { +// args = append(args, fmt.Sprintf("--%s", flags.FlagCountTotal)) +// } +// return args +// } +// t.Run("ByOffset", func(t *testing.T) { +// step := 2 +// for i := 0; i < len(objs); i += step { +// args := request(nil, uint64(i), uint64(step), false) +// out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) +// require.NoError(t, err) +// var resp types.QueryAllClaimResponse +// require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) +// require.LessOrEqual(t, len(resp.Claim), step) +// require.Subset(t, +// nullify.Fill(objs), +// nullify.Fill(resp.Claim), +// ) +// } +// }) +// t.Run("ByKey", func(t *testing.T) { +// step := 2 +// var next []byte +// for i := 0; i < len(objs); i += step { +// args := request(next, 0, uint64(step), false) +// out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) +// require.NoError(t, err) +// var resp types.QueryAllClaimResponse +// require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) +// require.LessOrEqual(t, len(resp.Claim), step) +// require.Subset(t, +// nullify.Fill(objs), +// nullify.Fill(resp.Claim), +// ) +// next = resp.Pagination.NextKey +// } +// }) +// t.Run("Total", func(t *testing.T) { +// args := request(nil, 0, uint64(len(objs)), true) +// out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) +// require.NoError(t, err) +// var resp types.QueryAllClaimResponse +// require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) +// require.NoError(t, err) +// require.Equal(t, len(objs), int(resp.Pagination.Total)) +// require.ElementsMatch(t, +// nullify.Fill(objs), +// nullify.Fill(resp.Claim), +// ) +// }) +// } diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index a550dddb0..3a95e8d98 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -3,6 +3,7 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -11,20 +12,21 @@ func (k Keeper) SetClaim(ctx sdk.Context, claim types.Claim) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) b := k.cdc.MustMarshal(&claim) store.Set(types.ClaimKey( - claim.Index, + claim.SessionId, + claim.SupplierAddress, ), b) } // GetClaim returns a claim from its index func (k Keeper) GetClaim( ctx sdk.Context, - index string, + sessionId, supplierAddr string, ) (val types.Claim, found bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) b := store.Get(types.ClaimKey( - index, + sessionId, supplierAddr, )) if b == nil { return val, false @@ -37,12 +39,12 @@ func (k Keeper) GetClaim( // RemoveClaim removes a claim from the store func (k Keeper) RemoveClaim( ctx sdk.Context, - index string, + sessionId, supplierAddr string, ) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) store.Delete(types.ClaimKey( - index, + sessionId, supplierAddr, )) } diff --git a/x/supplier/types/codec.go b/x/supplier/types/codec.go index 364fde198..3bb7fcd12 100644 --- a/x/supplier/types/codec.go +++ b/x/supplier/types/codec.go @@ -29,8 +29,6 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { // this line is used by starport scaffolding # 3 msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) - - msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } var ( diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go index e57164b57..0938c07b0 100644 --- a/x/supplier/types/key_claim.go +++ b/x/supplier/types/key_claim.go @@ -9,14 +9,16 @@ const ( ClaimKeyPrefix = "Claim/value/" ) -// ClaimKey returns the store key to retrieve a Claim from the index fields -func ClaimKey( - index string, -) []byte { +// ClaimKey returns the store key to retrieve a Claim +func ClaimKey(sessionId, supplierAddr string) []byte { var key []byte - indexBytes := []byte(index) - key = append(key, indexBytes...) + sessionBz := []byte(sessionId) + key = append(key, sessionBz...) + key = append(key, []byte("/")...) + + supplierAddrBz := []byte(supplierAddr) + key = append(key, supplierAddrBz...) key = append(key, []byte("/")...) return key From 70ce89ff07d39044b3a0c487aa9db65adedd6b8d Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 16:32:55 -0800 Subject: [PATCH 06/40] Ran go_imports --- x/supplier/client/cli/query.go | 2 +- x/supplier/genesis.go | 10 +++++----- x/supplier/keeper/claim.go | 1 + x/supplier/keeper/query_claim.go | 3 ++- x/supplier/types/genesis.go | 20 ++++++++++---------- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/x/supplier/client/cli/query.go b/x/supplier/client/cli/query.go index eb6e6979f..f70e996ba 100644 --- a/x/supplier/client/cli/query.go +++ b/x/supplier/client/cli/query.go @@ -29,7 +29,7 @@ func GetQueryCmd(queryRoute string) *cobra.Command { cmd.AddCommand(CmdShowSupplier()) cmd.AddCommand(CmdListClaim()) cmd.AddCommand(CmdShowClaim()) -// this line is used by starport scaffolding # 1 + // this line is used by starport scaffolding # 1 return cmd } diff --git a/x/supplier/genesis.go b/x/supplier/genesis.go index 29f433b5a..feb23355f 100644 --- a/x/supplier/genesis.go +++ b/x/supplier/genesis.go @@ -14,10 +14,10 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) k.SetSupplier(ctx, supplier) } // Set all the claim -for _, elem := range genState.ClaimList { - k.SetClaim(ctx, elem) -} -// this line is used by starport scaffolding # genesis/module/init + for _, elem := range genState.ClaimList { + k.SetClaim(ctx, elem) + } + // this line is used by starport scaffolding # genesis/module/init k.SetParams(ctx, genState.Params) } @@ -28,7 +28,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.SupplierList = k.GetAllSupplier(ctx) genesis.ClaimList = k.GetAllClaim(ctx) -// this line is used by starport scaffolding # genesis/module/export + // this line is used by starport scaffolding # genesis/module/export return genesis } diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index a550dddb0..cf847cd71 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -3,6 +3,7 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/pokt-network/poktroll/x/supplier/types" ) diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 80a0ff61c..d4d8e3542 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -6,9 +6,10 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - "github.com/pokt-network/poktroll/x/supplier/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/pokt-network/poktroll/x/supplier/types" ) func (k Keeper) ClaimAll(goCtx context.Context, req *types.QueryAllClaimRequest) (*types.QueryAllClaimResponse, error) { diff --git a/x/supplier/types/genesis.go b/x/supplier/types/genesis.go index 930802853..d1a13a9aa 100644 --- a/x/supplier/types/genesis.go +++ b/x/supplier/types/genesis.go @@ -17,8 +17,8 @@ const DefaultIndex uint64 = 1 func DefaultGenesis() *GenesisState { return &GenesisState{ SupplierList: []sharedtypes.Supplier{}, - ClaimList: []Claim{}, -// this line is used by starport scaffolding # genesis/types/default + ClaimList: []Claim{}, + // this line is used by starport scaffolding # genesis/types/default Params: DefaultParams(), } } @@ -65,16 +65,16 @@ func (gs GenesisState) Validate() error { } // Check for duplicated index in claim -claimIndexMap := make(map[string]struct{}) + claimIndexMap := make(map[string]struct{}) -for _, elem := range gs.ClaimList { - index := string(ClaimKey(elem.Index)) - if _, ok := claimIndexMap[index]; ok { - return fmt.Errorf("duplicated index for claim") + for _, elem := range gs.ClaimList { + index := string(ClaimKey(elem.Index)) + if _, ok := claimIndexMap[index]; ok { + return fmt.Errorf("duplicated index for claim") + } + claimIndexMap[index] = struct{}{} } - claimIndexMap[index] = struct{}{} -} -// this line is used by starport scaffolding # genesis/types/validate + // this line is used by starport scaffolding # genesis/types/validate return gs.Params.Validate() } From 1d5dfdc0d5fb47f586641c9d71a5706701cd05f0 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 16:43:12 -0800 Subject: [PATCH 07/40] Fix some linter errors --- x/supplier/genesis_test.go | 18 ++++++------ x/supplier/keeper/msg_server_test.go | 7 +++-- x/supplier/types/genesis_test.go | 42 ++++++++++++++-------------- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/x/supplier/genesis_test.go b/x/supplier/genesis_test.go index 679caf38d..348faf560 100644 --- a/x/supplier/genesis_test.go +++ b/x/supplier/genesis_test.go @@ -57,14 +57,14 @@ func TestGenesis(t *testing.T) { }, }, ClaimList: []types.Claim{ - { - Index: "0", -}, - { - Index: "1", -}, - }, - // this line is used by starport scaffolding # genesis/test/state + { + Index: "0", + }, + { + Index: "1", + }, + }, + // this line is used by starport scaffolding # genesis/test/state } k, ctx := keepertest.SupplierKeeper(t) @@ -77,5 +77,5 @@ func TestGenesis(t *testing.T) { require.ElementsMatch(t, genesisState.SupplierList, got.SupplierList) require.ElementsMatch(t, genesisState.ClaimList, got.ClaimList) -// this line is used by starport scaffolding # genesis/test/assert + // this line is used by starport scaffolding # genesis/test/assert } diff --git a/x/supplier/keeper/msg_server_test.go b/x/supplier/keeper/msg_server_test.go index 39fc0075f..7e4d01f27 100644 --- a/x/supplier/keeper/msg_server_test.go +++ b/x/supplier/keeper/msg_server_test.go @@ -6,9 +6,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/x/supplier/types" - "github.com/pokt-network/poktroll/x/supplier/keeper" - keepertest "github.com/pokt-network/poktroll/testutil/keeper" + + keepertest "github.com/pokt-network/poktroll/testutil/keeper" + "github.com/pokt-network/poktroll/x/supplier/keeper" + "github.com/pokt-network/poktroll/x/supplier/types" ) func setupMsgServer(t testing.TB) (types.MsgServer, context.Context) { diff --git a/x/supplier/types/genesis_test.go b/x/supplier/types/genesis_test.go index 65267170f..4a3fb7956 100644 --- a/x/supplier/types/genesis_test.go +++ b/x/supplier/types/genesis_test.go @@ -71,14 +71,14 @@ func TestGenesisState_Validate(t *testing.T) { }, }, ClaimList: []types.Claim{ - { - Index: "0", -}, - { - Index: "1", -}, -}, -// this line is used by starport scaffolding # types/genesis/validField + { + Index: "0", + }, + { + Index: "1", + }, + }, + // this line is used by starport scaffolding # types/genesis/validField }, valid: true, }, @@ -307,20 +307,20 @@ func TestGenesisState_Validate(t *testing.T) { valid: false, }, { - desc: "duplicated claim", - genState: &types.GenesisState{ - ClaimList: []types.Claim{ - { - Index: "0", -}, - { - Index: "0", -}, + desc: "duplicated claim", + genState: &types.GenesisState{ + ClaimList: []types.Claim{ + { + Index: "0", + }, + { + Index: "0", + }, + }, + }, + valid: false, }, - }, - valid: false, -}, -// this line is used by starport scaffolding # types/genesis/testcase + // this line is used by starport scaffolding # types/genesis/testcase } for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { From f8f11cf039566d30df87be660056a620eda47f00 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 17:15:33 -0800 Subject: [PATCH 08/40] temp --- x/supplier/client/cli/query_claim.go | 4 +- x/supplier/keeper/claim.go | 110 ++++++++++++++++++++++----- x/supplier/keeper/claim_test.go | 38 ++++----- x/supplier/keeper/query_claim.go | 2 +- x/supplier/types/key_claim.go | 37 ++++++--- 5 files changed, 141 insertions(+), 50 deletions(-) diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 445607ba6..8a92a429d 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -46,9 +46,9 @@ func CmdListClaim() *cobra.Command { func CmdShowClaim() *cobra.Command { cmd := &cobra.Command{ - Use: "show-claim [index]", + Use: "show-claim ", Short: "shows a claim", - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 3a95e8d98..720681e08 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -7,17 +7,37 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -// SetClaim set a specific claim in the store from its index -func (k Keeper) SetClaim(ctx sdk.Context, claim types.Claim) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) - b := k.cdc.MustMarshal(&claim) - store.Set(types.ClaimKey( - claim.SessionId, - claim.SupplierAddress, - ), b) +// InsertClaim set a specific a claim given a sessionId & supplierAddr +func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { + claimBz := k.cdc.MustMarshal(&claim) + parentStore := ctx.KVStore(k.storeKey) + + // Store the whole claim in the primary key store + primaryStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + primaryKey := types.ClaimPrimaryKey(claim) + primaryStore.Set(primaryKey, claimBz) + + // Save the claim in the main claim store with primary key + // primaryStore := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("claim")) + // primaryStore.Set(claim.PrimaryKey(), claim.Marshal()) + + // Store the param + // heightStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimHeightPrefix)) + // heightKey := HeightKey(claim.Height) // Serialize height into a byte slice if needed + // heightStore.Set(heightKey, claim.PrimaryKey()) + + // Index by address + addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimHeightPrefix)) + addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress) + addressStoreIndex.Set(addressKey, primaryKey) + + // ClaimHeightPrefix + // ClaimAddressPrefix + // ClaimSessionIdPrefix + } -// GetClaim returns a claim from its index +// GetClaim returns a claim given a sessionId & supplierAddr func (k Keeper) GetClaim( ctx sdk.Context, sessionId, supplierAddr string, @@ -37,20 +57,21 @@ func (k Keeper) GetClaim( } // RemoveClaim removes a claim from the store -func (k Keeper) RemoveClaim( - ctx sdk.Context, - sessionId, supplierAddr string, +// func (k Keeper) RemoveClaim( +// ctx sdk.Context, +// supplierAddr string, +// sessionId, -) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) - store.Delete(types.ClaimKey( - sessionId, supplierAddr, - )) -} +// ) { +// store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) +// store.Delete(types.ClaimKey( +// sessionId, supplierAddr, +// )) +// } -// GetAllClaim returns all claim -func (k Keeper) GetAllClaim(ctx sdk.Context) (list []types.Claim) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) +// GetAllClaims returns all claim +func (k Keeper) GetAllClaims(ctx sdk.Context) (list []types.Claim) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) defer iterator.Close() @@ -63,3 +84,50 @@ func (k Keeper) GetAllClaim(ctx sdk.Context) (list []types.Claim) { return } + +// When retrieving by height: +// func (k Keeper) GetClaimsByHeight(ctx sdk.Context, height int64) []Claim { +// heightStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimHeightPrefix)) +// heightKey := HeightKey(height) // Serialize height into a byte slice if needed + +// // Iterate over the height index store using heightKey +// iterator := sdk.KVStorePrefixIterator(heightStore, heightKey) +// defer iterator.Close() + +// var claims []Claim +// for ; iterator.Valid(); iterator.Next() { +// primaryKey := iterator.Value() +// claim := GetClaimByPrimaryKey(ctx, claimStoreKey, primaryKey) +// claims = append(claims, claim) +// } + +// return claims +// } + +// When retrieving by address: +func (k Keeper) GetClaimsByAddress(ctx sdk.Context, address sdk.AccAddress) []Claim { + addressStore := prefix.NewStore(ctx.KVStore(addressIndexStoreKey), types.KeyPrefix(types.ClaimAddressPrefix)) + addressKey := AddressKey(address) // Serialize address into a byte slice if needed + + // Iterate over the address index store using addressKey + iterator := sdk.KVStorePrefixIterator(addressStore, addressKey) + defer iterator.Close() + + var claims []Claim + for ; iterator.Valid(); iterator.Next() { + primaryKey := iterator.Value() + claim := GetClaimByPrimaryKey(ctx, claimStoreKey, primaryKey) + claims = append(claims, claim) + } + + return claims +} + +// // Helper function to get a claim by primary key: +func GetClaimByPrimaryKey(ctx sdk.Context, claimStoreKey sdk.StoreKey, primaryKey []byte) Claim { + primaryStore := prefix.NewStore(ctx.KVStore(claimStoreKey), []byte("claim")) + byteClaim := primaryStore.Get(primaryKey) + var claim Claim + claim.Unmarshal(byteClaim) // Unmarshal byte slice into Claim object + return claim +} diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go index 93ae0df40..19b41bf52 100644 --- a/x/supplier/keeper/claim_test.go +++ b/x/supplier/keeper/claim_test.go @@ -5,49 +5,53 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + keepertest "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/testutil/sample" "github.com/pokt-network/poktroll/x/supplier/keeper" "github.com/pokt-network/poktroll/x/supplier/types" - "github.com/stretchr/testify/require" ) // Prevent strconv unused error var _ = strconv.IntSize func createNClaim(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim { - items := make([]types.Claim, n) - for i := range items { - items[i].Index = strconv.Itoa(i) + claims := make([]types.Claim, n) + for i := range claims { + claims[i].SupplierAddress = sample.AccAddress() - keeper.SetClaim(ctx, items[i]) + keeper.InsertClaim(ctx, claims[i]) } - return items + return claims } func TestClaimGet(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) - items := createNClaim(keeper, ctx, 10) - for _, item := range items { + claims := createNClaim(keeper, ctx, 10) + for _, claim := range claims { rst, found := keeper.GetClaim(ctx, - item.Index, + claim.Index, ) require.True(t, found) require.Equal(t, - nullify.Fill(&item), + nullify.Fill(&claim), nullify.Fill(&rst), ) } } func TestClaimRemove(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) - items := createNClaim(keeper, ctx, 10) - for _, item := range items { + claims := createNClaim(keeper, ctx, 10) + for _, claim := range claims { keeper.RemoveClaim(ctx, - item.Index, + claim.SessionId, + claim.SupplierAddress, ) _, found := keeper.GetClaim(ctx, - item.Index, + claim.SessionId, + claim.SupplierAddress, ) require.False(t, found) } @@ -55,9 +59,9 @@ func TestClaimRemove(t *testing.T) { func TestClaimGetAll(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) - items := createNClaim(keeper, ctx, 10) + claims := createNClaim(keeper, ctx, 10) require.ElementsMatch(t, - nullify.Fill(items), - nullify.Fill(keeper.GetAllClaim(ctx)), + nullify.Fill(claims), + nullify.Fill(keeper.GetAllClaims(ctx)), ) } diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index d4d8e3542..b96276a3d 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -21,7 +21,7 @@ func (k Keeper) ClaimAll(goCtx context.Context, req *types.QueryAllClaimRequest) ctx := sdk.UnwrapSDKContext(goCtx) store := ctx.KVStore(k.storeKey) - claimStore := prefix.NewStore(store, types.KeyPrefix(types.ClaimKeyPrefix)) + claimStore := prefix.NewStore(store, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) pageRes, err := query.Paginate(claimStore, req.Pagination, func(key []byte, value []byte) error { var claim types.Claim diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go index 0938c07b0..ea1e83d26 100644 --- a/x/supplier/types/key_claim.go +++ b/x/supplier/types/key_claim.go @@ -1,24 +1,43 @@ package types -import "encoding/binary" +import ( + "encoding/binary" +) var _ binary.ByteOrder const ( - // ClaimKeyPrefix is the prefix to retrieve all Claim - ClaimKeyPrefix = "Claim/value/" + // ClaimPrimaryKeyPrefix is the prefix to retrieve all Claim (the primary store) + ClaimPrimaryKeyPrefix = "Claim/value/" + + // ClaimHeightPrefix is the key to retrieve a Claim's Primary Key from the Height index + ClaimHeightPrefix = "Claim/height/" + + // ClaimAddressPrefix is the key to retrieve a Claim's Primary Key from the Address index + ClaimAddressPrefix = "Claim/address/" + + // ClaimSessionIdPrefix is the key to retrieve a Claim's Primary Key from the SessionId index + ClaimSessionIdPrefix = "Claim/sessionId/" ) -// ClaimKey returns the store key to retrieve a Claim -func ClaimKey(sessionId, supplierAddr string) []byte { +// ClaimPrimaryKey returns the primary store key to retrieve a Claim +func ClaimPrimaryKey(claim Claim) []byte { var key []byte - sessionBz := []byte(sessionId) - key = append(key, sessionBz...) + // We are guaranteed uniqueness of the primary key if it's a composite of the (sessionId, supplierAddr) + key = append(key, []byte(claim.SessionId)...) + key = append(key, []byte("/")...) + key = append(key, []byte(claim.SupplierAddress)...) key = append(key, []byte("/")...) - supplierAddrBz := []byte(supplierAddr) - key = append(key, supplierAddrBz...) + return key +} + +// ClaimSupplierAddressKey returns the address key to iterate through claims given a supplier Address +func ClaimSupplierAddressKey(supplierAddr string) []byte { + var key []byte + + key = append(key, []byte(supplierAddr)...) key = append(key, []byte("/")...) return key From 872bb6fda53294943bff6dd41930eae8176f1ac0 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Mon, 6 Nov 2023 19:30:33 -0800 Subject: [PATCH 09/40] Snapshotting some super rough WIP --- x/supplier/keeper/claim.go | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 720681e08..c9b66e03c 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -131,3 +131,48 @@ func GetClaimByPrimaryKey(ctx sdk.Context, claimStoreKey sdk.StoreKey, primaryKe claim.Unmarshal(byteClaim) // Unmarshal byte slice into Claim object return claim } + +// GetOlshCount get the total number of olsh +// func (k Keeper) GetOlshCount(ctx sdk.Context) uint64 { +// store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{}) +// byteKey := types.KeyPrefix(types.OlshCountKey) +// bz := store.Get(byteKey) + +// // Count doesn't exist: no element +// if bz == nil { +// return 0 +// } + +// // Parse bytes +// return binary.BigEndian.Uint64(bz) +// } + +// // SetOlshCount set the total number of olsh +// func (k Keeper) SetOlshCount(ctx sdk.Context, count uint64) { +// store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{}) +// byteKey := types.KeyPrefix(types.OlshCountKey) +// bz := make([]byte, 8) +// binary.BigEndian.PutUint64(bz, count) +// store.Set(byteKey, bz) +// } + +// // AppendOlsh appends a olsh in the store with a new id and update the count +// func (k Keeper) AppendOlsh( +// ctx sdk.Context, +// olsh types.Olsh, +// ) uint64 { +// // Create the olsh +// count := k.GetOlshCount(ctx) + +// // Set the ID of the appended value +// olsh.Id = count + +// store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.OlshKey)) +// appendedValue := k.cdc.MustMarshal(&olsh) +// store.Set(GetOlshIDBytes(olsh.Id), appendedValue) + +// // Update olsh count +// k.SetOlshCount(ctx, count+1) + +// return count +// } From b1b514a9bd2b08dbd34b25ea71e900a04237fecd Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 7 Nov 2023 14:44:49 -0800 Subject: [PATCH 10/40] Update x/supplier/client/cli/query_claim.go Co-authored-by: Bryan White --- x/supplier/client/cli/query_claim.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 445607ba6..5e4289259 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -12,6 +12,7 @@ func CmdListClaim() *cobra.Command { cmd := &cobra.Command{ Use: "list-claim", Short: "list all claim", + Args: cobra.NoArgs(), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { From 2562c9025ce7a4cc2b9e6367bb290e38def486a3 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 7 Nov 2023 14:45:12 -0800 Subject: [PATCH 11/40] Update x/supplier/client/cli/query_claim.go Co-authored-by: Bryan White --- x/supplier/client/cli/query_claim.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 5e4289259..1ebbccdbc 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -47,7 +47,7 @@ func CmdListClaim() *cobra.Command { func CmdShowClaim() *cobra.Command { cmd := &cobra.Command{ - Use: "show-claim [index]", + Use: "show-claim ", Short: "shows a claim", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { From 369db3820a27efd333aa6517b13be86444bf1c97 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 7 Nov 2023 14:45:45 -0800 Subject: [PATCH 12/40] Update x/supplier/client/cli/query_claim.go Co-authored-by: harry <53987565+h5law@users.noreply.github.com> --- x/supplier/client/cli/query_claim.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 1ebbccdbc..20c9047ef 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -11,7 +11,7 @@ import ( func CmdListClaim() *cobra.Command { cmd := &cobra.Command{ Use: "list-claim", - Short: "list all claim", + Short: "list all claims", Args: cobra.NoArgs(), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) From 3f6e68aebbaef8598ea077ec061b1ca58805d308 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 7 Nov 2023 09:25:20 +0100 Subject: [PATCH 13/40] [Miner] feat: add `TxClient` (#94) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: add `TxClient` interface * chore: add option support to `ReplayObservable` * feat: add `txClient` implementation * test: `txClient` * test: tx client integration * chore: s/tx/transaction/g * chore: update pkg README.md template * wip: client pkg README * docs: fix client pkg godoc comment * fix: flakey test * chore: dial back godoc comments 😅 * chore: revise (and move to godoc.go) `testblock` & `testeventsquery` pkg godoc comment * chore: update go.mod * chore: refactor & condense godoc comments * chore: fix import paths post-update * chore: review feedback improvements * docs: update client README.md * docs: add `tx query` usage association between `txContext` & `Blockchain` * docs: add TOC * chore: review feedback improvements Co-authored-by: Daniel Olshansky * docs: improve godoc comments & client README.md --------- Co-authored-by: Daniel Olshansky --- docs/pkg/client/README.md | 147 +++++ docs/template/pkg/README.md | 21 +- internal/testclient/testblock/client.go | 73 +++ internal/testclient/testblock/godoc.go | 4 + internal/testclient/testeventsquery/client.go | 61 +- internal/testclient/testeventsquery/godoc.go | 5 + internal/testclient/testtx/context.go | 113 +--- pkg/client/godoc.go | 12 + pkg/client/interface.go | 56 +- pkg/client/services.go | 19 + pkg/client/tx/client.go | 567 ++++++++++++++++++ pkg/client/tx/client_integration_test.go | 65 ++ pkg/client/tx/client_test.go | 413 +++++++++++++ pkg/client/tx/context.go | 13 +- pkg/client/tx/encoding.go | 18 + pkg/client/tx/errors.go | 53 ++ pkg/client/tx/options.go | 22 + pkg/observable/channel/replay.go | 3 +- 18 files changed, 1514 insertions(+), 151 deletions(-) create mode 100644 docs/pkg/client/README.md create mode 100644 internal/testclient/testblock/godoc.go create mode 100644 internal/testclient/testeventsquery/godoc.go create mode 100644 pkg/client/godoc.go create mode 100644 pkg/client/services.go create mode 100644 pkg/client/tx/client.go create mode 100644 pkg/client/tx/client_integration_test.go create mode 100644 pkg/client/tx/client_test.go create mode 100644 pkg/client/tx/encoding.go create mode 100644 pkg/client/tx/errors.go create mode 100644 pkg/client/tx/options.go diff --git a/docs/pkg/client/README.md b/docs/pkg/client/README.md new file mode 100644 index 000000000..6f4032800 --- /dev/null +++ b/docs/pkg/client/README.md @@ -0,0 +1,147 @@ +# Package `client` + +## Table of Contents + +- [Overview](#overview) +- [Features](#features) +- [Architecture Overview](#architecture-overview) + - [Component Diagram Legend](#component-diagram-legend) + - [Clients Dependency Tree](#clients-dependency-tree) + - [Network Interaction](#network-interaction) +- [Installation](#installation) +- [Usage](#usage) + - [Basic Example](#basic-example) + - [Advanced Usage](#advanced-usage) + - [Configuration](#configuration) +- [API Reference](#api-reference) +- [Best Practices](#best-practices) +- [FAQ](#faq) + + +## Overview + +The `client` package exposes go APIs to facilitate interactions with the Pocket network. +It includes lower-level interfaces for working with transactions and subscribing to events generally, as well as higher-level interfaces for tracking blocks and broadcasting protocol-specific transactions. + +## Features + +| Interface | Description | +|-------------------------|----------------------------------------------------------------------------------------------------| +| **`SupplierClient`** | A high-level client for use by the "supplier" actor. | +| **`TxClient`** | A high-level client used to build, sign, and broadcast transaction from cosmos-sdk messages. | +| **`TxContext`** | Abstracts and encapsulates the transaction building, signing, encoding, and broadcasting concerns. | +| **`BlockClient`** | Exposes methods for receiving notifications about newly committed blocks. | +| **`EventsQueryClient`** | Encapsulates blockchain event subscriptions. | +| **`Connection`** | A transport agnostic communication channel for sending and receiving messages. | +| **`Dialer`** | Abstracts the establishment of connections. | + +## Architecture Overview + +```mermaid +--- +title: Component Diagram Legend +--- +flowchart + +c[Component] +d[Dependency Component] +s[[Subcomponent]] +r[Remote Component] + +c --"direct usage via #DependencyMethod()"--> d +c -."usage via network I/O".-> r +c --> s +``` + +> **Figure 1**: A legend for the component diagrams in this document. + +```mermaid +--- +title: Clients Dependency Tree +--- +flowchart + +sup[SupplierClient] +tx[TxClient] +txctx[[TxContext]] +bl[BlockClient] +evt[EventsQueryClient] +conn[[Connection]] +dial[[Dialer]] + +sup --"#SignAndBroadcast()"--> tx + +tx --"#CommittedBlocksSequence()"--> bl +tx --"#BroadcastTx"--> txctx +tx --"#EventsBytes()"--> evt +bl --"#EventsBytes()"--> evt +evt --> conn +evt --"#DialContext()"--> dial +dial --"(returns)"--> conn +``` + +> **Figure 2**: An overview which articulates the dependency relationships between the various client interfaces and their subcompnents. + +```mermaid +--- +title: Network Interaction +--- +flowchart + +txctx[[TxContext]] +conn[[Connection]] +dial[[Dialer]] + +chain[Blockchain] + +conn <-."subscribed events".-> chain +dial -."RPC subscribe".-> chain +txctx -."tx broadcast".-> chain +txctx -."tx query".-> chain +``` + +> **Figure 3**: An overview of how client subcomponents interact with the network. + +## Installation + +```bash +go get github.com/pokt-network/poktroll/pkg/client +``` + +## Usage + +### Basic Example + +```go +// TODO: Code example showcasing the use of TxClient or any other primary interface. +``` + +### Advanced Usage + +```go +// TODO: Example illustrating advanced features or edge cases of the package. +``` + +### Configuration + +- **TxClientOption**: Function type that modifies the `TxClient` allowing for flexible and optional configurations. +- **EventsQueryClientOption**: Modifies the `EventsQueryClient` to apply custom behaviors or configurations. + +## API Reference + +For the complete API details, see the [godoc](https://pkg.go.dev/github.com/pokt-network/poktroll/pkg/client). + +## Best Practices + +- **Use Abstractions**: Instead of directly communicating with blockchain platforms, leverage the provided interfaces for consistent and error-free interactions. +- **Stay Updated**: With evolving blockchain technologies, ensure to keep the package updated for any new features or security patches. + +## FAQ + +#### How does the `TxClient` interface differ from `TxContext`? + +While `TxClient` is centered around signing and broadcasting transactions, `TxContext` consolidates operational dependencies for the transaction lifecycle, like building, encoding, and querying. + +#### Can I extend or customize the provided interfaces? + +Yes, the package is designed with modularity in mind. You can either implement the interfaces based on your requirements or extend them for additional functionalities. \ No newline at end of file diff --git a/docs/template/pkg/README.md b/docs/template/pkg/README.md index 44f41885a..10fdc2755 100644 --- a/docs/template/pkg/README.md +++ b/docs/template/pkg/README.md @@ -70,12 +70,7 @@ If the package can be configured in some way, describe it here: ## API Reference -While `godoc` will provide the detailed API reference, you can highlight or briefly describe key functions, types, or methods here. - -- `FunctionOrType1()`: A short description of its purpose. -- `FunctionOrType2(param Type)`: Another brief description. - -For the complete API details, see the [godoc](https://pkg.go.dev/github.com/yourusername/yourproject/[PackageName]). +For the complete API details, see the [godoc](https://pkg.go.dev/github.com/pokt-network/poktroll/[PackageName]). ## Best Practices @@ -90,16 +85,4 @@ Answer for question 1. #### Question 2? -Answer for question 2. - -## Contributing - -Briefly describe how others can contribute to this package. Link to the main contributing guide if you have one. - -## Changelog - -For detailed release notes, see the [CHANGELOG](../CHANGELOG.md) at the root level or link to a separate CHANGELOG specific to this package. - -## License - -This package is released under the XYZ License. For more information, see the [LICENSE](../LICENSE) file at the root level. \ No newline at end of file +Answer for question 2. \ No newline at end of file diff --git a/internal/testclient/testblock/client.go b/internal/testclient/testblock/client.go index 0918ee64f..ebd2ebcd7 100644 --- a/internal/testclient/testblock/client.go +++ b/internal/testclient/testblock/client.go @@ -5,14 +5,19 @@ import ( "testing" "cosmossdk.io/depinject" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "github.com/pokt-network/poktroll/internal/mocks/mockclient" "github.com/pokt-network/poktroll/internal/testclient" "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/client/block" + "github.com/pokt-network/poktroll/pkg/observable/channel" ) +// NewLocalnetClient creates and returns a new BlockClient that's configured for +// use with the localnet sequencer. func NewLocalnetClient(ctx context.Context, t *testing.T) client.BlockClient { t.Helper() @@ -25,3 +30,71 @@ func NewLocalnetClient(ctx context.Context, t *testing.T) client.BlockClient { return bClient } + +// NewOneTimeCommittedBlocksSequenceBlockClient creates a new mock BlockClient. +// This mock BlockClient will expect a call to CommittedBlocksSequence, and +// when that call is made, it returns a new BlocksObservable that is notified of +// blocks sent on the given blocksPublishCh. +// blocksPublishCh is the channel the caller can use to publish blocks the observable. +func NewOneTimeCommittedBlocksSequenceBlockClient( + t *testing.T, + blocksPublishCh chan client.Block, +) *mockclient.MockBlockClient { + t.Helper() + + // Create a mock for the block client which expects the LatestBlock method to be called any number of times. + blockClientMock := NewAnyTimeLatestBlockBlockClient(t, nil, 0) + + // Set up the mock expectation for the CommittedBlocksSequence method. When + // the method is called, it returns a new replay observable that publishes + // blocks sent on the given blocksPublishCh. + blockClientMock.EXPECT().CommittedBlocksSequence( + gomock.AssignableToTypeOf(context.Background()), + ).DoAndReturn(func(ctx context.Context) client.BlocksObservable { + // Create a new replay observable with a replay buffer size of 1. Blocks + // are published to this observable via the provided blocksPublishCh. + withPublisherOpt := channel.WithPublisher(blocksPublishCh) + obs, _ := channel.NewReplayObservable[client.Block]( + ctx, 1, withPublisherOpt, + ) + return obs + }) + + return blockClientMock +} + +// NewAnyTimeLatestBlockBlockClient creates a mock BlockClient that expects +// calls to the LatestBlock method any number of times. When the LatestBlock +// method is called, it returns a mock Block with the provided hash and height. +func NewAnyTimeLatestBlockBlockClient( + t *testing.T, + hash []byte, + height int64, +) *mockclient.MockBlockClient { + t.Helper() + ctrl := gomock.NewController(t) + + // Create a mock block that returns the provided hash and height. + blockMock := NewAnyTimesBlock(t, hash, height) + // Create a mock block client that expects calls to LatestBlock method and + // returns the mock block. + blockClientMock := mockclient.NewMockBlockClient(ctrl) + blockClientMock.EXPECT().LatestBlock(gomock.Any()).Return(blockMock).AnyTimes() + + return blockClientMock +} + +// NewAnyTimesBlock creates a mock Block that expects calls to Height and Hash +// methods any number of times. When the methods are called, they return the +// provided height and hash respectively. +func NewAnyTimesBlock(t *testing.T, hash []byte, height int64) *mockclient.MockBlock { + t.Helper() + ctrl := gomock.NewController(t) + + // Create a mock block that returns the provided hash and height AnyTimes. + blockMock := mockclient.NewMockBlock(ctrl) + blockMock.EXPECT().Height().Return(height).AnyTimes() + blockMock.EXPECT().Hash().Return(hash).AnyTimes() + + return blockMock +} diff --git a/internal/testclient/testblock/godoc.go b/internal/testclient/testblock/godoc.go new file mode 100644 index 000000000..866bb4f70 --- /dev/null +++ b/internal/testclient/testblock/godoc.go @@ -0,0 +1,4 @@ +// Package testblock provides helper functions for constructing real (e.g. localnet) +// and mock BlockClient objects with pre-configured and/or parameterized call +// arguments, return value(s), and/or expectations thereof. Intended for use in tests. +package testblock diff --git a/internal/testclient/testeventsquery/client.go b/internal/testclient/testeventsquery/client.go index 0aa618fe9..2c68606ce 100644 --- a/internal/testclient/testeventsquery/client.go +++ b/internal/testclient/testeventsquery/client.go @@ -2,10 +2,13 @@ package testeventsquery import ( "context" + "fmt" "testing" "time" + cosmoskeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/internal/mocks/mockclient" "github.com/pokt-network/poktroll/internal/testclient" @@ -15,14 +18,68 @@ import ( "github.com/pokt-network/poktroll/pkg/observable/channel" ) -// NewLocalnetClient returns a new events query client which is configured to -// connect to the localnet sequencer. +// NewLocalnetClient creates and returns a new events query client that's configured +// for use with the localnet sequencer. Any options provided are applied to the client. func NewLocalnetClient(t *testing.T, opts ...client.EventsQueryClientOption) client.EventsQueryClient { t.Helper() return eventsquery.NewEventsQueryClient(testclient.CometLocalWebsocketURL, opts...) } +// NewOneTimeEventsQuery creates a mock of the EventsQueryClient which expects +// a single call to the EventsBytes method. query is the query string which is +// expected to be received by that call. +// It returns a mock client whose event bytes method constructs a new observable. +// The caller can simulate blockchain events by sending on the value publishCh +// points to, which is set by this helper function. +func NewOneTimeEventsQuery( + ctx context.Context, + t *testing.T, + query string, + publishCh *chan<- either.Bytes, +) *mockclient.MockEventsQueryClient { + t.Helper() + ctrl := gomock.NewController(t) + + eventsQueryClient := mockclient.NewMockEventsQueryClient(ctrl) + eventsQueryClient.EXPECT().EventsBytes(gomock.Eq(ctx), gomock.Eq(query)). + DoAndReturn(func( + ctx context.Context, + query string, + ) (eventsBzObservable client.EventsBytesObservable, err error) { + eventsBzObservable, *publishCh = channel.NewObservable[either.Bytes]() + return eventsBzObservable, nil + }).Times(1) + return eventsQueryClient +} + +// NewOneTimeTxEventsQueryClient creates a mock of the Events that expects +// a single call to the EventsBytes method where the query is for transaction +// events for sender address matching that of the given key. +// The caller can simulate blockchain events by sending on the value publishCh +// points to, which is set by this helper function. +func NewOneTimeTxEventsQueryClient( + ctx context.Context, + t *testing.T, + key *cosmoskeyring.Record, + publishCh *chan<- either.Bytes, +) *mockclient.MockEventsQueryClient { + t.Helper() + + signingAddr, err := key.GetAddress() + require.NoError(t, err) + + expectedEventsQuery := fmt.Sprintf( + "tm.event='Tx' AND message.sender='%s'", + signingAddr, + ) + return NewOneTimeEventsQuery( + ctx, t, + expectedEventsQuery, + publishCh, + ) +} + // NewAnyTimesEventsBytesEventsQueryClient returns a new events query client which // is configured to return the expected event bytes when queried with the expected // query, any number of times. The returned client also expects to be closed once. diff --git a/internal/testclient/testeventsquery/godoc.go b/internal/testclient/testeventsquery/godoc.go new file mode 100644 index 000000000..0caa02997 --- /dev/null +++ b/internal/testclient/testeventsquery/godoc.go @@ -0,0 +1,5 @@ +// Package testeventsquery provides helper functions for constructing real +// (e.g. localnet) and mock EventsQueryClient objects with pre-configured and/or +// parameterized call arguments, return value(s), and/or expectations thereof. +// Intended for use in tests. +package testeventsquery diff --git a/internal/testclient/testtx/context.go b/internal/testclient/testtx/context.go index e7d1f8446..fa25494e7 100644 --- a/internal/testclient/testtx/context.go +++ b/internal/testclient/testtx/context.go @@ -30,25 +30,10 @@ import ( // correlations between these "times" values and the contexts in which the expected // methods may be called. -// NewOneTimeErrTxTimeoutTxContext creates a mock transaction context designed to simulate a specific -// timeout error scenario during transaction broadcasting. -// -// Parameters: -// - t: The testing.T instance for the current test. -// - keyring: The Cosmos SDK keyring containing the signer's cryptographic keys. -// - signingKeyName: The name of the key within the keyring to use for signing. -// - expectedTx: A pointer whose value will be set to the expected transaction -// bytes (in hexadecimal format). -// - expectedErrMsg: A pointer whose value will be set to the expected error -// message string. -// -// The function performs the following actions: -// 1. It retrieves the signer's cryptographic key from the provided keyring using the signingKeyName. -// 2. It computes the corresponding address of the signer's key. -// 3. It then formats an error message indicating that the fee payer's address does not exist. -// 4. It creates a base mock transaction context using NewBaseTxContext. -// 5. It sets up the mock behavior for the BroadcastTxSync method to return a specific preset response. -// 6. It also sets up the mock behavior for the QueryTx method to return a specific error response. +// NewOneTimeErrTxTimeoutTxContext creates a mock transaction context designed to +// simulate a specific timeout error scenario during transaction broadcasting. +// expectedErrMsg is populated with the same error message which is presented in +// the result from the QueryTx method so that it can be asserted against. func NewOneTimeErrTxTimeoutTxContext( t *testing.T, keyring cosmoskeyring.Keyring, @@ -116,24 +101,8 @@ func NewOneTimeErrTxTimeoutTxContext( // NewOneTimeErrCheckTxTxContext creates a mock transaction context to simulate // a specific error scenario during the ABCI check-tx phase (i.e., during initial // validation before the transaction is included in the block). -// -// Parameters: -// - t: The testing.T instance for the current test. -// - keyring: The Cosmos SDK keyring containing the signer's cryptographic keys. -// - signingKeyName: The name of the key within the keyring to be used for signing. -// - expectedTx: A pointer whose value will be set to the expected transaction -// bytes (in hexadecimal format). -// - expectedErrMsg: A pointer whose value will be set to the expected error -// message string. -// -// The function operates as follows: -// 1. Retrieves the signer's cryptographic key from the provided keyring based on -// the signingKeyName. -// 2. Determines the corresponding address of the signer's key. -// 3. Composes an error message suggesting that the fee payer's address is unrecognized. -// 4. Creates a base mock transaction context using the NewBaseTxContext function. -// 5. Sets up the mock behavior for the BroadcastTxSync method to return a specific -// error response related to the check phase of the transaction. +// expectedErrMsg is populated with the same error message which is presented in +// the result from the QueryTx method so that it can be asserted against. func NewOneTimeErrCheckTxTxContext( t *testing.T, keyring cosmoskeyring.Keyring, @@ -179,22 +148,7 @@ func NewOneTimeErrCheckTxTxContext( } // NewOneTimeTxTxContext creates a mock transaction context primed to respond with -// a single successful transaction response. This function facilitates testing by -// ensuring that the BroadcastTxSync method will return a specific, controlled response -// without actually broadcasting the transaction to the network. -// -// Parameters: -// - t: The testing.T instance used for the current test, typically passed from -// the calling test function. -// - keyring: The Cosmos SDK keyring containing the available cryptographic keys. -// - signingKeyName: The name of the key within the keyring used for transaction signing. -// - expectedTx: A pointer whose value will be set to the expected transaction -// bytes (in hexadecimal format). -// -// The function operates as follows: -// 1. Constructs a base mock transaction context using the NewBaseTxContext function. -// 2. Configures the mock behavior for the BroadcastTxSync method to return a pre-defined -// successful transaction response, ensuring that this behavior will only be triggered once. +// a single successful transaction response. func NewOneTimeTxTxContext( t *testing.T, keyring cosmoskeyring.Keyring, @@ -224,30 +178,11 @@ func NewOneTimeTxTxContext( return txCtxMock } -// NewBaseTxContext establishes a foundational mock transaction context with -// predefined behaviors suitable for a broad range of testing scenarios. It ensures -// that when interactions like transaction building, signing, and encoding occur -// in the test environment, they produce predictable and controlled outcomes. -// -// Parameters: -// - t: The testing.T instance used for the current test, typically passed from -// the calling test function. -// - signingKeyName: The name of the key within the keyring to be used for -// transaction signing. -// - keyring: The Cosmos SDK keyring containing the available cryptographic keys. -// - expectedTx: A pointer whose value will be set to the expected transaction -// bytes (in hexadecimal format). -// - expectedErrMsg: A pointer whose value will be set to the expected error -// message string. -// -// The function works as follows: -// 1. Invokes the NewAnyTimesTxTxContext to create a base mock transaction context. -// 2. Sets the expectation that NewTxBuilder method will be called exactly once. -// 3. Configures the mock behavior for the SignTx method to utilize the context's -// signing logic. -// 4. Overrides the EncodeTx method's behavior to intercept the encoding operation, -// capture the encoded transaction bytes, compute the transaction hash, and populate -// the expectedTx and expectedTxHash parameters accordingly. +// NewBaseTxContext creates a mock transaction context that's configured to expect +// calls to NewTxBuilder, SignTx, and EncodeTx methods, any number of times. +// EncodeTx is used to intercept the encoded transaction bytes and store them in +// the expectedTx output parameter. Each of these methods proxies to the corresponding +// method on a real transaction context. func NewBaseTxContext( t *testing.T, signingKeyName string, @@ -281,30 +216,6 @@ func NewBaseTxContext( // NewAnyTimesTxTxContext initializes a mock transaction context that's configured to allow // arbitrary calls to certain predefined interactions, primarily concerning the retrieval // of account numbers and sequences. -// -// Parameters: -// - t: The testing.T instance used for the current test, typically passed from the calling test function. -// - keyring: The Cosmos SDK keyring containing the available cryptographic keys. -// -// The function operates in the following manner: -// 1. Establishes a new gomock controller for setting up mock expectations and behaviors. -// 2. Prepares a set of flags suitable for localnet testing environments. -// 3. Sets up a mock behavior to intercept the GetAccountNumberSequence method calls, -// ensuring that whenever this method is invoked, it consistently returns an account number -// and sequence of 1, without making real queries to the underlying infrastructure. -// 4. Constructs a client context tailored for localnet testing with the provided keyring -// and the mocked account retriever. -// 5. Initializes a transaction factory from the client context and validates its integrity. -// 6. Injects the transaction factory and client context dependencies to create a new transaction context. -// 7. Creates a mock transaction context that always returns the provided keyring when the GetKeyring method is called. -// -// This setup aids tests by facilitating the creation of mock transaction contexts that have predictable -// and controlled outcomes for account number and sequence retrieval operations. -// -// Returns: -// - A mock transaction context suitable for setting additional expectations in tests. -// - A real transaction context initialized with the supplied dependencies. - func NewAnyTimesTxTxContext( t *testing.T, keyring cosmoskeyring.Keyring, diff --git a/pkg/client/godoc.go b/pkg/client/godoc.go new file mode 100644 index 000000000..66da550dd --- /dev/null +++ b/pkg/client/godoc.go @@ -0,0 +1,12 @@ +// Package client defines interfaces and types that facilitate interactions +// with blockchain functionalities, both transactional and observational. It is +// built to provide an abstraction layer for sending, receiving, and querying +// blockchain data, thereby offering a standardized way of integrating with +// various blockchain platforms. +// +// The client package leverages external libraries like cosmos-sdk and cometbft, +// but there is a preference to minimize direct dependencies on these external +// libraries, when defining interfaces, aiming for a cleaner decoupling. +// It seeks to provide a flexible and comprehensive interface layer, adaptable to +// different blockchain configurations and requirements. +package client diff --git a/pkg/client/interface.go b/pkg/client/interface.go index 2d67c90c0..32dab250c 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -1,4 +1,5 @@ //go:generate mockgen -destination=../../internal/mocks/mockclient/events_query_client_mock.go -package=mockclient . Dialer,Connection,EventsQueryClient +//go:generate mockgen -destination=../../internal/mocks/mockclient/block_client_mock.go -package=mockclient . Block,BlockClient //go:generate mockgen -destination=../../internal/mocks/mockclient/tx_client_mock.go -package=mockclient . TxContext //go:generate mockgen -destination=../../internal/mocks/mockclient/cosmos_tx_builder_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client TxBuilder //go:generate mockgen -destination=../../internal/mocks/mockclient/cosmos_keyring_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/crypto/keyring Keyring @@ -18,9 +19,18 @@ import ( "github.com/pokt-network/poktroll/pkg/observable" ) +// TxClient provides a synchronous interface initiating and waiting for transactions +// derived from cosmos-sdk messages, in a cosmos-sdk based blockchain network. +type TxClient interface { + SignAndBroadcast( + ctx context.Context, + msgs ...cosmostypes.Msg, + ) either.AsyncError +} + // TxContext provides an interface which consolidates the operational dependencies -// required to facilitate the sender side of the tx lifecycle: build, sign, encode, -// broadcast, query (optional). +// required to facilitate the sender side of the transaction lifecycle: build, sign, +// encode, broadcast, and query (optional). // // TODO_IMPROVE: Avoid depending on cosmos-sdk structs or interfaces; add Pocket // interface types to substitute: @@ -29,13 +39,13 @@ import ( // - Keyring // - TxBuilder type TxContext interface { - // GetKeyring returns the associated key management mechanism for the tx context. + // GetKeyring returns the associated key management mechanism for the transaction context. GetKeyring() cosmoskeyring.Keyring - // NewTxBuilder creates and returns a new tx builder instance. + // NewTxBuilder creates and returns a new transaction builder instance. NewTxBuilder() cosmosclient.TxBuilder - // SignTx signs a tx using the specified key name. It can operate in offline mode, + // SignTx signs a transaction using the specified key name. It can operate in offline mode, // and can overwrite any existing signatures based on the provided flags. SignTx( keyName string, @@ -43,14 +53,14 @@ type TxContext interface { offline, overwriteSig bool, ) error - // EncodeTx takes a tx builder and encodes it, returning its byte representation. + // EncodeTx takes a transaction builder and encodes it, returning its byte representation. EncodeTx(txBuilder cosmosclient.TxBuilder) ([]byte, error) - // BroadcastTx broadcasts the given tx to the network. + // BroadcastTx broadcasts the given transaction to the network. BroadcastTx(txBytes []byte) (*cosmostypes.TxResponse, error) - // QueryTx retrieves a tx status based on its hash and optionally provides - // proof of the tx. + // QueryTx retrieves a transaction status based on its hash and optionally provides + // proof of the transaction. QueryTx( ctx context.Context, txHash []byte, @@ -60,6 +70,7 @@ type TxContext interface { // BlocksObservable is an observable which is notified with an either // value which contains either an error or the event message bytes. +// // TODO_HACK: The purpose of this type is to work around gomock's lack of // support for generic types. For the same reason, this type cannot be an // alias (i.e. EventsBytesObservable = observable.Observable[either.Either[[]byte]]). @@ -84,23 +95,24 @@ type Block interface { Hash() []byte } -// TODO_CONSIDERATION: the cosmos-sdk CLI code seems to use a cometbft RPC client -// which includes a `#Subscribe()` method for a similar purpose. Perhaps we could -// replace this custom websocket client with that. -// (see: https://github.com/cometbft/cometbft/blob/main/rpc/client/http/http.go#L110) -// (see: https://github.com/cosmos/cosmos-sdk/blob/main/client/rpc/tx.go#L114) -// -// NOTE: a branch which attempts this is available at: -// https://github.com/pokt-network/poktroll/pull/74 - // EventsBytesObservable is an observable which is notified with an either // value which contains either an error or the event message bytes. +// // TODO_HACK: The purpose of this type is to work around gomock's lack of // support for generic types. For the same reason, this type cannot be an // alias (i.e. EventsBytesObservable = observable.Observable[either.Bytes]). type EventsBytesObservable observable.Observable[either.Bytes] // EventsQueryClient is used to subscribe to chain event messages matching the given query, +// +// TODO_CONSIDERATION: the cosmos-sdk CLI code seems to use a cometbft RPC client +// which includes a `#Subscribe()` method for a similar purpose. Perhaps we could +// replace our custom implementation with one which wraps that. +// (see: https://github.com/cometbft/cometbft/blob/main/rpc/client/http/http.go#L110) +// (see: https://github.com/cosmos/cosmos-sdk/blob/main/client/rpc/tx.go#L114) +// +// NOTE: a branch which attempts this is available at: +// https://github.com/pokt-network/poktroll/pull/74 type EventsQueryClient interface { // EventsBytes returns an observable which is notified about chain event messages // matching the given query. It receives an either value which contains either an @@ -131,8 +143,8 @@ type Dialer interface { DialContext(ctx context.Context, urlStr string) (Connection, error) } -// EventsQueryClientOption is an interface-wide type which can be implemented to use or modify the -// query client during construction. This would likely be done in an -// implementation-specific way; e.g. using a type assertion to assign to an -// implementation struct field(s). +// EventsQueryClientOption defines a function type that modifies the EventsQueryClient. type EventsQueryClientOption func(EventsQueryClient) + +// TxClientOption defines a function type that modifies the TxClient. +type TxClientOption func(TxClient) diff --git a/pkg/client/services.go b/pkg/client/services.go new file mode 100644 index 000000000..0d2ca060d --- /dev/null +++ b/pkg/client/services.go @@ -0,0 +1,19 @@ +package client + +import ( + "fmt" + + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +) + +// NewTestApplicationServiceConfig returns a slice of application service configs for testing. +func NewTestApplicationServiceConfig(prefix string, count int) []*sharedtypes.ApplicationServiceConfig { + appSvcCfg := make([]*sharedtypes.ApplicationServiceConfig, count) + for i, _ := range appSvcCfg { + serviceId := fmt.Sprintf("%s%d", prefix, i) + appSvcCfg[i] = &sharedtypes.ApplicationServiceConfig{ + ServiceId: &sharedtypes.ServiceId{Id: serviceId}, + } + } + return appSvcCfg +} diff --git a/pkg/client/tx/client.go b/pkg/client/tx/client.go new file mode 100644 index 000000000..805443eb4 --- /dev/null +++ b/pkg/client/tx/client.go @@ -0,0 +1,567 @@ +package tx + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "sync" + + "cosmossdk.io/depinject" + abciTypes "github.com/cometbft/cometbft/abci/types" + comettypes "github.com/cometbft/cometbft/types" + cosmostypes "github.com/cosmos/cosmos-sdk/types" + "go.uber.org/multierr" + + "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/either" + "github.com/pokt-network/poktroll/pkg/observable" + "github.com/pokt-network/poktroll/pkg/observable/channel" +) + +const ( + // DefaultCommitTimeoutHeightOffset is the default number of blocks after the + // latest block (when broadcasting) that a transactions should be considered + // errored if it has not been committed. + DefaultCommitTimeoutHeightOffset = 5 + // txWithSenderAddrQueryFmt is the query used to subscribe to cometbft transactions + // events where the sender address matches the interpolated address. + // (see: https://docs.cosmos.network/v0.47/core/events#subscribing-to-events) + txWithSenderAddrQueryFmt = "tm.event='Tx' AND message.sender='%s'" +) + +var _ client.TxClient = (*txClient)(nil) + +// txClient orchestrates building, signing, broadcasting, and querying of +// transactions. It maintains a single events query subscription to its own +// transactions (via the EventsQueryClient) in order to receive notifications +// regarding their status. +// It also depends on the BlockClient as a timer, synchronized to block height, +// to facilitate transaction timeout logic. If a transaction doesn't appear to +// have been committed by commitTimeoutHeightOffset number of blocks have elapsed, +// it is considered as timed out. Upon timeout, the client queries the network for +// the last status of the transaction, which is used to derive the asynchronous +// error that's populated in the either.AsyncError. +type txClient struct { + // TODO_TECHDEBT: this should be configurable & integrated w/ viper, flags, etc. + // commitTimeoutHeightOffset is the number of blocks after the latest block + // that a transactions should be considered errored if it has not been committed. + commitTimeoutHeightOffset int64 + // signingKeyName is the name of the key in the keyring to use for signing + // transactions. + signingKeyName string + // signingAddr is the address of the signing key referenced by signingKeyName. + // It is hydrated from the keyring by calling Keyring#Key() with signingKeyName. + signingAddr cosmostypes.AccAddress + // txCtx is the transactions context which encapsulates transactions building, signing, + // broadcasting, and querying, as well as keyring access. + txCtx client.TxContext + // eventsQueryClient is the client used to subscribe to transactions events from this + // sender. It is used to receive notifications about transactions events corresponding + // to transactions which it has constructed, signed, and broadcast. + eventsQueryClient client.EventsQueryClient + // blockClient is the client used to query for the latest block height. + // It is used to implement timout logic for transactions which weren't committed. + blockClient client.BlockClient + + // txsMutex protects txErrorChans and txTimeoutPool maps. + txsMutex sync.Mutex + // txErrorChans maps tx_hash->channel which will receive an error or nil, + // and close, when the transactions with the given hash is committed. + txErrorChans txErrorChansByHash + // txTimeoutPool maps timeout_block_height->map_of_txsByHash. It + // is used to ensure that transactions error channels receive and close in the event + // that they have not already by the given timeout height. + txTimeoutPool txTimeoutPool +} + +type ( + txTimeoutPool map[height]txErrorChansByHash + txErrorChansByHash map[txHash]chan error + height = int64 + txHash = string +) + +// TxEvent is used to deserialize incoming websocket messages from +// the transactions subscription. +type TxEvent struct { + // Tx is the binary representation of the tx hash. + Tx []byte `json:"tx"` + Events []abciTypes.Event `json:"events"` +} + +// NewTxClient attempts to construct a new TxClient using the given dependencies +// and options. +// +// It performs the following steps: +// 1. Initializes a default txClient with the default commit timeout height +// offset, an empty error channel map, and an empty transaction timeout pool. +// 2. Injects the necessary dependencies using depinject. +// 3. Applies any provided options to customize the client. +// 4. Validates and sets any missing default configurations using the +// validateConfigAndSetDefaults method. +// 5. Subscribes the client to its own transactions. This step might be +// reconsidered for relocation to a potential Start() method in the future. +func NewTxClient( + ctx context.Context, + deps depinject.Config, + opts ...client.TxClientOption, +) (client.TxClient, error) { + tClient := &txClient{ + commitTimeoutHeightOffset: DefaultCommitTimeoutHeightOffset, + txErrorChans: make(txErrorChansByHash), + txTimeoutPool: make(txTimeoutPool), + } + + if err := depinject.Inject( + deps, + &tClient.txCtx, + &tClient.eventsQueryClient, + &tClient.blockClient, + ); err != nil { + return nil, err + } + + for _, opt := range opts { + opt(tClient) + } + + if err := tClient.validateConfigAndSetDefaults(); err != nil { + return nil, err + } + + // Start an events query subscription for transactions originating from this + // client's signing address. + // TODO_CONSIDERATION: move this into a #Start() method + if err := tClient.subscribeToOwnTxs(ctx); err != nil { + return nil, err + } + + // Launch a separate goroutine to handle transaction timeouts. + // TODO_CONSIDERATION: move this into a #Start() method + go tClient.goTimeoutPendingTransactions(ctx) + + return tClient, nil +} + +// SignAndBroadcast signs a set of Cosmos SDK messages, constructs a transaction, +// and broadcasts it to the network. The function performs several steps to +// ensure the messages and the resultant transaction are valid: +// +// 1. Validates each message in the provided set. +// 2. Constructs the transaction using the Cosmos SDK's transaction builder. +// 3. Calculates and sets the transaction's timeout height. +// 4. Sets a default gas limit (note: this will be made configurable in the future). +// 5. Signs the transaction. +// 6. Validates the constructed transaction. +// 7. Serializes and broadcasts the transaction. +// 8. Checks the broadcast response for errors. +// 9. If all the above steps are successful, the function registers the +// transaction as pending. +// +// If any step encounters an error, it returns an either.AsyncError populated with +// the synchronous error. If the function completes successfully, it returns an +// either.AsyncError populated with the error channel which will receive if the +// transaction results in an asynchronous error or times out. +func (tClient *txClient) SignAndBroadcast( + ctx context.Context, + msgs ...cosmostypes.Msg, +) either.AsyncError { + var validationErrs error + for i, msg := range msgs { + if err := msg.ValidateBasic(); err != nil { + validationErr := ErrInvalidMsg.Wrapf("in msg with index %d: %s", i, err) + validationErrs = multierr.Append(validationErrs, validationErr) + } + } + if validationErrs != nil { + return either.SyncErr(validationErrs) + } + + // Construct the transactions using cosmos' transactions builder. + txBuilder := tClient.txCtx.NewTxBuilder() + if err := txBuilder.SetMsgs(msgs...); err != nil { + // return synchronous error + return either.SyncErr(err) + } + + // Calculate timeout height + timeoutHeight := tClient.blockClient.LatestBlock(ctx). + Height() + tClient.commitTimeoutHeightOffset + + // TODO_TECHDEBT: this should be configurable + txBuilder.SetGasLimit(200000) + txBuilder.SetTimeoutHeight(uint64(timeoutHeight)) + + // sign transactions + err := tClient.txCtx.SignTx( + tClient.signingKeyName, + txBuilder, + false, false, + ) + if err != nil { + return either.SyncErr(err) + } + + // ensure transactions is valid + // NOTE: this makes the transactions valid; i.e. it is *REQUIRED* + if err := txBuilder.GetTx().ValidateBasic(); err != nil { + return either.SyncErr(err) + } + + // serialize transactions + txBz, err := tClient.txCtx.EncodeTx(txBuilder) + if err != nil { + return either.SyncErr(err) + } + + txResponse, err := tClient.txCtx.BroadcastTx(txBz) + if err != nil { + return either.SyncErr(err) + } + + if txResponse.Code != 0 { + return either.SyncErr(ErrCheckTx.Wrapf(txResponse.RawLog)) + } + + return tClient.addPendingTransactions(normalizeTxHashHex(txResponse.TxHash), timeoutHeight) +} + +// validateConfigAndSetDefaults ensures that the necessary configurations for the +// txClient are set, and populates any missing defaults. +// +// 1. It checks if the signing key name is set and returns an error if it's empty. +// 2. It then retrieves the key record from the keyring using the signing key name +// and checks its existence. +// 3. The address of the signing key is computed and assigned to txClient#signgingAddr. +// 4. Lastly, it ensures that commitTimeoutHeightOffset has a valid value, setting +// it to DefaultCommitTimeoutHeightOffset if it's zero or negative. +// +// Returns: +// - ErrEmptySigningKeyName if the signing key name is not provided. +// - ErrNoSuchSigningKey if the signing key is not found in the keyring. +// - ErrSigningKeyAddr if there's an issue retrieving the address for the signing key. +// - nil if validation is successful and defaults are set appropriately. +func (tClient *txClient) validateConfigAndSetDefaults() error { + if tClient.signingKeyName == "" { + return ErrEmptySigningKeyName + } + + keyRecord, err := tClient.txCtx.GetKeyring().Key(tClient.signingKeyName) + if err != nil { + return ErrNoSuchSigningKey.Wrapf("name %q: %s", tClient.signingKeyName, err) + } + signingAddr, err := keyRecord.GetAddress() + if err != nil { + return ErrSigningKeyAddr.Wrapf("name %q: %s", tClient.signingKeyName, err) + } + tClient.signingAddr = signingAddr + + if tClient.commitTimeoutHeightOffset <= 0 { + tClient.commitTimeoutHeightOffset = DefaultCommitTimeoutHeightOffset + } + return nil +} + +// addPendingTransactions registers a new pending transaction for monitoring and +// notification of asynchronous errors. It accomplishes the following: +// +// 1. Creates an error notification channel (if one doesn't already exist) and associates +// it with the provided transaction hash in the txErrorChans map. +// +// 2. Ensures that there's an initialized map of transactions by hash for the +// given timeout height in the txTimeoutPool. The same error notification channel +// is also associated with the transaction hash in this map. +// +// Both txErrorChans and txTimeoutPool store references to the same error notification +// channel for a given transaction hash. This ensures idempotency of error handling +// for any given transaction between asynchronous, transaction-specific errors and +// transaction timeout logic. +// +// Note: The error channels are buffered to prevent blocking on send operations and +// are intended to convey a single error event. +// +// Returns: +// - An either.AsyncError populated with the error notification channel for the +// provided transaction hash. +func (tClient *txClient) addPendingTransactions( + txHash string, + timeoutHeight int64, +) either.AsyncError { + tClient.txsMutex.Lock() + defer tClient.txsMutex.Unlock() + + // Initialize txTimeoutPool map if necessary. + txsByHash, ok := tClient.txTimeoutPool[timeoutHeight] + if !ok { + txsByHash = make(map[string]chan error) + tClient.txTimeoutPool[timeoutHeight] = txsByHash + } + + // Initialize txErrorChans map in txTimeoutPool map if necessary. + errCh, ok := txsByHash[txHash] + if !ok { + // NB: intentionally buffered to avoid blocking on send. Only intended + // to send/receive a single error. + errCh = make(chan error, 1) + txsByHash[txHash] = errCh + } + + // Initialize txErrorChans map if necessary. + if _, ok := tClient.txErrorChans[txHash]; !ok { + // NB: both maps hold a reference to the same channel so that we can check + // if the channel has already been closed when timing out. + tClient.txErrorChans[txHash] = errCh + } + + return either.AsyncErr(errCh) +} + +// subscribeToOwnTxs establishes an event query subscription to monitor transactions +// originating from this client's signing address. +// +// It performs the following steps: +// +// 1. Forms a query to fetch transaction events specific to the client's signing address. +// 2. Maps raw event bytes observable notifications to a new transaction event objects observable. +// 3. Handle each transaction event. +// +// Important considerations: +// There's uncertainty surrounding the potential for asynchronous errors post transaction broadcast. +// Current implementation and observations suggest that errors might be returned synchronously, +// even when using Cosmos' BroadcastTxAsync method. Further investigation is required. +// +// This function also spawns a goroutine to handle transaction timeouts via goTimeoutPendingTransactions. +// +// Parameters: +// - ctx: Context for managing the function's lifecycle and child operations. +// +// Returns: +// - An error if there's a failure during the event query or subscription process. +func (tClient *txClient) subscribeToOwnTxs(ctx context.Context) error { + // Form a query based on the client's signing address. + query := fmt.Sprintf(txWithSenderAddrQueryFmt, tClient.signingAddr) + + // Fetch transaction events matching the query. + eventsBz, err := tClient.eventsQueryClient.EventsBytes(ctx, query) + if err != nil { + return err + } + + // Convert raw event data into a stream of transaction events. + txEventsObservable := channel.Map[ + either.Bytes, either.Either[*TxEvent], + ](ctx, eventsBz, tClient.txEventFromEventBz) + txEventsObserver := txEventsObservable.Subscribe(ctx) + + // Handle transaction events asynchronously. + go tClient.goHandleTxEvents(txEventsObserver) + + return nil +} + +// goHandleTxEvents ranges over the transaction events observable, performing +// the following steps on each: +// +// 1. Normalize hexadeimal transaction hash. +// 2. Retrieves the transaction's error channel from txErrorChans. +// 3. Closes and removes it from txErrorChans. +// 4. Removes the transaction error channel from txTimeoutPool. +// +// It is intended to be called in a goroutine. +func (tClient *txClient) goHandleTxEvents( + txEventsObserver observable.Observer[either.Either[*TxEvent]], +) { + for eitherTxEvent := range txEventsObserver.Ch() { + txEvent, err := eitherTxEvent.ValueOrError() + if err != nil { + return + } + + // Convert transaction hash into its normalized hex form. + txHashHex := txHashBytesToNormalizedHex(comettypes.Tx(txEvent.Tx).Hash()) + + tClient.txsMutex.Lock() + + // Check for a corresponding error channel in the map. + txErrCh, ok := tClient.txErrorChans[txHashHex] + if !ok { + panic("Received tx event without an associated error channel.") + } + + // TODO_INVESTIGATE: it seems like it may not be possible for the + // txEvent to represent an error. Cosmos' #BroadcastTxSync() is being + // called internally, which will return an error if the transaction + // is not accepted by the mempool. + // + // It's unclear if a cosmos chain is capable of returning an async + // error for a transaction at this point; even when substituting + // #BroadcastTxAsync(), the error is returned synchronously: + // + // > error in json rpc client, with http response metadata: (Status: + // > 200 OK, Protocol HTTP/1.1). RPC error -32000 - tx added to local + // > mempool but failed to gossip: validation failed + // + // Potential parse and send transaction error on txErrCh here. + + // Close and remove from txErrChans + close(txErrCh) + delete(tClient.txErrorChans, txHashHex) + + // Remove from the txTimeoutPool. + for timeoutHeight, txErrorChans := range tClient.txTimeoutPool { + // Handled transaction isn't in this timeout height. + if _, ok := txErrorChans[txHashHex]; !ok { + continue + } + + delete(txErrorChans, txHashHex) + if len(txErrorChans) == 0 { + delete(tClient.txTimeoutPool, timeoutHeight) + } + } + + tClient.txsMutex.Unlock() + } +} + +// goTimeoutPendingTransactions monitors blocks and handles transaction timeouts. +// For each block observed, it checks if there are transactions associated with that +// block's height in the txTimeoutPool. If transactions are found, the function +// evaluates whether they have already been processed by the transaction events +// query subscription logic. If not, a timeout error is generated and sent on the +// transaction's error channel. Finally, the error channel is closed and removed +// from the txTimeoutPool. +func (tClient *txClient) goTimeoutPendingTransactions(ctx context.Context) { + // Subscribe to a sequence of committed blocks. + blockCh := tClient.blockClient.CommittedBlocksSequence(ctx).Subscribe(ctx).Ch() + + // Iterate over each incoming block. + for block := range blockCh { + select { + case <-ctx.Done(): + // Exit if the context signals done. + return + default: + } + + tClient.txsMutex.Lock() + + // Retrieve transactions associated with the current block's height. + txsByHash, ok := tClient.txTimeoutPool[block.Height()] + if !ok { + // If no transactions are found for the current block height, continue. + tClient.txsMutex.Unlock() + continue + } + + // Process each transaction for the current block height. + for txHash, txErrCh := range txsByHash { + select { + // Check if the transaction was processed by its subscription. + case err, ok := <-txErrCh: + if ok { + // Unexpected state: error channel should be closed after processing. + panic(fmt.Errorf("Expected txErrCh to be closed; received err: %w", err)) + } + // Remove the processed transaction. + delete(txsByHash, txHash) + tClient.txsMutex.Unlock() + continue + default: + } + + // Transaction was not processed by its subscription: handle timeout. + txErrCh <- tClient.getTxTimeoutError(ctx, txHash) // Send a timeout error. + close(txErrCh) // Close the error channel. + delete(txsByHash, txHash) // Remove the transaction. + } + + // Clean up the txTimeoutPool for the current block height. + delete(tClient.txTimeoutPool, block.Height()) + tClient.txsMutex.Unlock() + } +} + +// txEventFromEventBz deserializes a binary representation of a transaction event +// into a TxEvent structure. +// +// Parameters: +// - eitherEventBz: Binary data of the event, potentially encapsulating an error. +// +// Returns: +// - eitherTxEvent: The TxEvent or an encapsulated error, facilitating clear +// error management in the caller's context. +// - skip: A flag denoting if the event should be bypassed. A value of true +// suggests the event be disregarded, progressing to the succeeding message. +func (tClient *txClient) txEventFromEventBz( + eitherEventBz either.Bytes, +) (eitherTxEvent either.Either[*TxEvent], skip bool) { + + // Extract byte data from the given event. In case of failure, wrap the error + // and denote the event for skipping. + eventBz, err := eitherEventBz.ValueOrError() + if err != nil { + return either.Error[*TxEvent](err), true + } + + // Unmarshal byte data into a TxEvent object. + txEvt, err := tClient.unmarshalTxEvent(eventBz) + switch { + // If the error indicates a non-transactional event, return the TxEvent and + // signal for skipping. + case errors.Is(err, ErrNonTxEventBytes): + return either.Success(txEvt), true + // For other errors, wrap them and flag the event to be skipped. + case err != nil: + return either.Error[*TxEvent](ErrUnmarshalTx.Wrapf("%s", err)), true + } + + // For successful unmarshalling, return the TxEvent. + return either.Success(txEvt), false +} + +// unmarshalTxEvent attempts to deserialize a slice of bytes into a TxEvent. +// It checks if the given bytes correspond to a valid transaction event. +// If the resulting TxEvent has empty transaction bytes, it assumes that +// the message was not a transaction event and returns an ErrNonTxEventBytes error. +func (tClient *txClient) unmarshalTxEvent(eventBz []byte) (*TxEvent, error) { + txEvent := new(TxEvent) + + // Try to deserialize the provided bytes into a TxEvent. + if err := json.Unmarshal(eventBz, txEvent); err != nil { + return nil, err + } + + // Check if the TxEvent has empty transaction bytes, which indicates + // the message might not be a valid transaction event. + if bytes.Equal(txEvent.Tx, []byte{}) { + return nil, ErrNonTxEventBytes.Wrapf("%s", string(eventBz)) + } + + return txEvent, nil +} + +// getTxTimeoutError checks if a transaction with the specified hash has timed out. +// The function decodes the provided hexadecimal hash into bytes and queries the +// transaction using the byte hash. If any error occurs during this process, +// appropriate wrapped errors are returned for easier debugging. +func (tClient *txClient) getTxTimeoutError(ctx context.Context, txHashHex string) error { + + // Decode the provided hex hash into bytes. + txHash, err := hex.DecodeString(txHashHex) + if err != nil { + return ErrInvalidTxHash.Wrapf("%s", txHashHex) + } + + // Query the transaction using the decoded byte hash. + txResponse, err := tClient.txCtx.QueryTx(ctx, txHash, false) + if err != nil { + return ErrQueryTx.Wrapf("with hash: %s: %s", txHashHex, err) + } + + // Return a timeout error with details about the transaction. + return ErrTxTimeout.Wrapf("with hash %s: %s", txHashHex, txResponse.TxResult.Log) +} diff --git a/pkg/client/tx/client_integration_test.go b/pkg/client/tx/client_integration_test.go new file mode 100644 index 000000000..c2d5db6e5 --- /dev/null +++ b/pkg/client/tx/client_integration_test.go @@ -0,0 +1,65 @@ +//go:build integration + +package tx_test + +import ( + "context" + "testing" + + "cosmossdk.io/depinject" + "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/pkg/client/tx" + + "github.com/pokt-network/poktroll/internal/testclient/testblock" + "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" + "github.com/pokt-network/poktroll/internal/testclient/testtx" + "github.com/pokt-network/poktroll/pkg/client" + apptypes "github.com/pokt-network/poktroll/x/application/types" +) + +func TestTxClient_SignAndBroadcast_Integration(t *testing.T) { + t.Skip("TODO_TECHDEBT: this test depends on some setup which is currently not implemented in this test: staked application and servicer with matching services") + + var ctx = context.Background() + + keyring, signingKey := newTestKeyringWithKey(t) + + eventsQueryClient := testeventsquery.NewLocalnetClient(t) + + _, txCtx := testtx.NewAnyTimesTxTxContext(t, keyring) + + // Construct a new mock block client because it is a required dependency. Since + // we're not exercising transactions timeouts in this test, we don't need to set any + // particular expectations on it, nor do we care about the value of blockHash + // argument. + blockClientMock := testblock.NewLocalnetClient(ctx, t) + + // Construct a new depinject config with the mocks we created above. + txClientDeps := depinject.Supply( + eventsQueryClient, + txCtx, + blockClientMock, + ) + + // Construct the transaction client. + txClient, err := tx.NewTxClient(ctx, txClientDeps, tx.WithSigningKeyName(testSigningKeyName)) + require.NoError(t, err) + + signingKeyAddr, err := signingKey.GetAddress() + require.NoError(t, err) + + // Construct a valid (arbitrary) message to sign, encode, and broadcast. + appStake := types.NewCoin("upokt", types.NewInt(1000000)) + appStakeMsg := &apptypes.MsgStakeApplication{ + Address: signingKeyAddr.String(), + Stake: &appStake, + Services: client.NewTestApplicationServiceConfig(testServiceIdPrefix, 2), + } + + // Sign and broadcast the message. + eitherErr := txClient.SignAndBroadcast(ctx, appStakeMsg) + err, _ = eitherErr.SyncOrAsyncError() + require.NoError(t, err) +} diff --git a/pkg/client/tx/client_test.go b/pkg/client/tx/client_test.go new file mode 100644 index 000000000..6cb5d33da --- /dev/null +++ b/pkg/client/tx/client_test.go @@ -0,0 +1,413 @@ +package tx_test + +import ( + "context" + "encoding/json" + "testing" + "time" + + "cosmossdk.io/depinject" + cometbytes "github.com/cometbft/cometbft/libs/bytes" + cosmoskeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/internal/mocks/mockclient" + "github.com/pokt-network/poktroll/internal/testclient" + "github.com/pokt-network/poktroll/internal/testclient/testblock" + "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" + "github.com/pokt-network/poktroll/internal/testclient/testtx" + "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/client/tx" + "github.com/pokt-network/poktroll/pkg/either" + apptypes "github.com/pokt-network/poktroll/x/application/types" +) + +const ( + testSigningKeyName = "test_signer" + // NB: testServiceIdPrefix must not be longer than 7 characters due to + // maxServiceIdLen. + testServiceIdPrefix = "testsvc" + txCommitTimeout = 10 * time.Millisecond +) + +// TODO_TECHDEBT: add coverage for the transactions client handling an events bytes error either. + +func TestTxClient_SignAndBroadcast_Succeeds(t *testing.T) { + var ( + // expectedTx is the expected transactions bytes that will be signed and broadcast + // by the transaction client. It is computed and assigned in the + // testtx.NewOneTimeTxTxContext helper function. The same reference needs + // to be used across the expectations that are set on the transactions context mock. + expectedTx cometbytes.HexBytes + // eventsBzPublishCh is the channel that the mock events query client + // will use to publish the transactions event bytes. It is used near the end of + // the test to mock the network signaling that the transactions was committed. + eventsBzPublishCh chan<- either.Bytes + blocksPublishCh chan client.Block + ctx = context.Background() + ) + + keyring, signingKey := newTestKeyringWithKey(t) + + eventsQueryClient := testeventsquery.NewOneTimeTxEventsQueryClient( + ctx, t, signingKey, &eventsBzPublishCh, + ) + + txCtxMock := testtx.NewOneTimeTxTxContext( + t, keyring, + testSigningKeyName, + &expectedTx, + ) + + // Construct a new mock block client because it is a required dependency. + // Since we're not exercising transactions timeouts in this test, we don't need to + // set any particular expectations on it, nor do we care about the contents + // of the latest block. + blockClientMock := testblock.NewOneTimeCommittedBlocksSequenceBlockClient( + t, blocksPublishCh, + ) + + // Construct a new depinject config with the mocks we created above. + txClientDeps := depinject.Supply( + eventsQueryClient, + txCtxMock, + blockClientMock, + ) + + // Construct the transaction client. + txClient, err := tx.NewTxClient( + ctx, txClientDeps, tx.WithSigningKeyName(testSigningKeyName), + ) + require.NoError(t, err) + + signingKeyAddr, err := signingKey.GetAddress() + require.NoError(t, err) + + // Construct a valid (arbitrary) message to sign, encode, and broadcast. + appStake := types.NewCoin("upokt", types.NewInt(1000000)) + appStakeMsg := &apptypes.MsgStakeApplication{ + Address: signingKeyAddr.String(), + Stake: &appStake, + Services: client.NewTestApplicationServiceConfig(testServiceIdPrefix, 2), + } + + // Sign and broadcast the message. + eitherErr := txClient.SignAndBroadcast(ctx, appStakeMsg) + err, errCh := eitherErr.SyncOrAsyncError() + require.NoError(t, err) + + // Construct the expected transaction event bytes from the expected transaction bytes. + txEventBz, err := json.Marshal(&tx.TxEvent{Tx: expectedTx}) + require.NoError(t, err) + + // Publish the transaction event bytes to the events query client so that the transaction client + // registers the transactions as committed (i.e. removes it from the timeout pool). + eventsBzPublishCh <- either.Success[[]byte](txEventBz) + + // Assert that the error channel was closed without receiving. + select { + case err, ok := <-errCh: + require.NoError(t, err) + require.Falsef(t, ok, "expected errCh to be closed") + case <-time.After(txCommitTimeout): + t.Fatal("test timed out waiting for errCh to receive") + } +} + +func TestTxClient_NewTxClient_Error(t *testing.T) { + // Construct an empty in-memory keyring. + keyring := cosmoskeyring.NewInMemory(testclient.EncodingConfig.Marshaler) + + tests := []struct { + name string + signingKeyName string + expectedErr error + }{ + { + name: "empty signing key name", + signingKeyName: "", + expectedErr: tx.ErrEmptySigningKeyName, + }, + { + name: "signing key does not exist", + signingKeyName: "nonexistent", + expectedErr: tx.ErrNoSuchSigningKey, + }, + // TODO_TECHDEBT: add coverage for this error case + // { + // name: "failed to get address", + // testSigningKeyName: "incompatible", + // expectedErr: tx.ErrSigningKeyAddr, + // }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var ( + ctrl = gomock.NewController(t) + ctx = context.Background() + ) + + // Construct a new mock events query client. Since we expect the + // NewTxClient call to fail, we don't need to set any expectations + // on this mock. + eventsQueryClient := mockclient.NewMockEventsQueryClient(ctrl) + + // Construct a new mock transactions context. + txCtxMock, _ := testtx.NewAnyTimesTxTxContext(t, keyring) + + // Construct a new mock block client. Since we expect the NewTxClient + // call to fail, we don't need to set any expectations on this mock. + blockClientMock := mockclient.NewMockBlockClient(ctrl) + + // Construct a new depinject config with the mocks we created above. + txClientDeps := depinject.Supply( + eventsQueryClient, + txCtxMock, + blockClientMock, + ) + + // Construct a signing key option using the test signing key name. + signingKeyOpt := tx.WithSigningKeyName(tt.signingKeyName) + + // Attempt to create the transactions client. + txClient, err := tx.NewTxClient(ctx, txClientDeps, signingKeyOpt) + require.ErrorIs(t, err, tt.expectedErr) + require.Nil(t, txClient) + }) + } +} + +func TestTxClient_SignAndBroadcast_SyncError(t *testing.T) { + var ( + // eventsBzPublishCh is the channel that the mock events query client + // will use to publish the transactions event bytes. It is not used in + // this test but is required to use the NewOneTimeTxEventsQueryClient + // helper. + eventsBzPublishCh chan<- either.Bytes + // blocksPublishCh is the channel that the mock block client will use + // to publish the latest block. It is not used in this test but is + // required to use the NewOneTimeCommittedBlocksSequenceBlockClient + // helper. + blocksPublishCh chan client.Block + ctx = context.Background() + ) + + keyring, signingKey := newTestKeyringWithKey(t) + + // Construct a new mock events query client. Since we expect the + // NewTxClient call to fail, we don't need to set any expectations + // on this mock. + eventsQueryClient := testeventsquery.NewOneTimeTxEventsQueryClient( + ctx, t, signingKey, &eventsBzPublishCh, + ) + + // Construct a new mock transaction context. + txCtxMock, _ := testtx.NewAnyTimesTxTxContext(t, keyring) + + // Construct a new mock block client because it is a required dependency. + // Since we're not exercising transactions timeouts in this test, we don't need to + // set any particular expectations on it, nor do we care about the contents + // of the latest block. + blockClientMock := testblock.NewOneTimeCommittedBlocksSequenceBlockClient( + t, blocksPublishCh, + ) + + // Construct a new depinject config with the mocks we created above. + txClientDeps := depinject.Supply( + eventsQueryClient, + txCtxMock, + blockClientMock, + ) + + // Construct the transaction client. + txClient, err := tx.NewTxClient( + ctx, txClientDeps, tx.WithSigningKeyName(testSigningKeyName), + ) + require.NoError(t, err) + + // Construct an invalid (arbitrary) message to sign, encode, and broadcast. + signingAddr, err := signingKey.GetAddress() + require.NoError(t, err) + appStakeMsg := &apptypes.MsgStakeApplication{ + // Providing address to avoid panic from #GetSigners(). + Address: signingAddr.String(), + Stake: nil, + // NB: explicitly omitting required fields + } + + eitherErr := txClient.SignAndBroadcast(ctx, appStakeMsg) + err, _ = eitherErr.SyncOrAsyncError() + require.ErrorIs(t, err, tx.ErrInvalidMsg) + + time.Sleep(10 * time.Millisecond) +} + +// TODO_INCOMPLETE: add coverage for async error; i.e. insufficient gas or on-chain error +func TestTxClient_SignAndBroadcast_CheckTxError(t *testing.T) { + var ( + // expectedErrMsg is the expected error message that will be returned + // by the transaction client. It is computed and assigned in the + // testtx.NewOneTimeErrCheckTxTxContext helper function. + expectedErrMsg string + // eventsBzPublishCh is the channel that the mock events query client + // will use to publish the transactions event bytes. It is used near the end of + // the test to mock the network signaling that the transactions was committed. + eventsBzPublishCh chan<- either.Bytes + blocksPublishCh chan client.Block + ctx = context.Background() + ) + + keyring, signingKey := newTestKeyringWithKey(t) + + eventsQueryClient := testeventsquery.NewOneTimeTxEventsQueryClient( + ctx, t, signingKey, &eventsBzPublishCh, + ) + + txCtxMock := testtx.NewOneTimeErrCheckTxTxContext( + t, keyring, + testSigningKeyName, + &expectedErrMsg, + ) + + // Construct a new mock block client because it is a required dependency. + // Since we're not exercising transactions timeouts in this test, we don't need to + // set any particular expectations on it, nor do we care about the contents + // of the latest block. + blockClientMock := testblock.NewOneTimeCommittedBlocksSequenceBlockClient( + t, blocksPublishCh, + ) + + // Construct a new depinject config with the mocks we created above. + txClientDeps := depinject.Supply( + eventsQueryClient, + txCtxMock, + blockClientMock, + ) + + // Construct the transaction client. + txClient, err := tx.NewTxClient(ctx, txClientDeps, tx.WithSigningKeyName(testSigningKeyName)) + require.NoError(t, err) + + signingKeyAddr, err := signingKey.GetAddress() + require.NoError(t, err) + + // Construct a valid (arbitrary) message to sign, encode, and broadcast. + appStake := types.NewCoin("upokt", types.NewInt(1000000)) + appStakeMsg := &apptypes.MsgStakeApplication{ + Address: signingKeyAddr.String(), + Stake: &appStake, + Services: client.NewTestApplicationServiceConfig(testServiceIdPrefix, 2), + } + + // Sign and broadcast the message. + eitherErr := txClient.SignAndBroadcast(ctx, appStakeMsg) + err, _ = eitherErr.SyncOrAsyncError() + require.ErrorIs(t, err, tx.ErrCheckTx) + require.ErrorContains(t, err, expectedErrMsg) +} + +func TestTxClient_SignAndBroadcast_Timeout(t *testing.T) { + var ( + // expectedErrMsg is the expected error message that will be returned + // by the transaction client. It is computed and assigned in the + // testtx.NewOneTimeErrCheckTxTxContext helper function. + expectedErrMsg string + // eventsBzPublishCh is the channel that the mock events query client + // will use to publish the transaction event bytes. It is used near the end of + // the test to mock the network signaling that the transaction was committed. + eventsBzPublishCh chan<- either.Bytes + blocksPublishCh = make(chan client.Block, tx.DefaultCommitTimeoutHeightOffset) + ctx = context.Background() + ) + + keyring, signingKey := newTestKeyringWithKey(t) + + eventsQueryClient := testeventsquery.NewOneTimeTxEventsQueryClient( + ctx, t, signingKey, &eventsBzPublishCh, + ) + + txCtxMock := testtx.NewOneTimeErrTxTimeoutTxContext( + t, keyring, + testSigningKeyName, + &expectedErrMsg, + ) + + // Construct a new mock block client because it is a required dependency. + // Since we're not exercising transaction timeouts in this test, we don't need to + // set any particular expectations on it, nor do we care about the contents + // of the latest block. + blockClientMock := testblock.NewOneTimeCommittedBlocksSequenceBlockClient( + t, blocksPublishCh, + ) + + // Construct a new depinject config with the mocks we created above. + txClientDeps := depinject.Supply( + eventsQueryClient, + txCtxMock, + blockClientMock, + ) + + // Construct the transaction client. + txClient, err := tx.NewTxClient( + ctx, txClientDeps, tx.WithSigningKeyName(testSigningKeyName), + ) + require.NoError(t, err) + + signingKeyAddr, err := signingKey.GetAddress() + require.NoError(t, err) + + // Construct a valid (arbitrary) message to sign, encode, and broadcast. + appStake := types.NewCoin("upokt", types.NewInt(1000000)) + appStakeMsg := &apptypes.MsgStakeApplication{ + Address: signingKeyAddr.String(), + Stake: &appStake, + Services: client.NewTestApplicationServiceConfig(testServiceIdPrefix, 2), + } + + // Sign and broadcast the message in a transaction. + eitherErr := txClient.SignAndBroadcast(ctx, appStakeMsg) + err, errCh := eitherErr.SyncOrAsyncError() + require.NoError(t, err) + + for i := 0; i < tx.DefaultCommitTimeoutHeightOffset; i++ { + blocksPublishCh <- testblock.NewAnyTimesBlock(t, []byte{}, int64(i+1)) + } + + // Assert that we receive the expected error type & message. + select { + case err := <-errCh: + require.ErrorIs(t, err, tx.ErrTxTimeout) + require.ErrorContains(t, err, expectedErrMsg) + // NB: wait 110% of txCommitTimeout; a bit longer than strictly necessary in + // order to mitigate flakiness. + case <-time.After(txCommitTimeout * 110 / 100): + t.Fatal("test timed out waiting for errCh to receive") + } + + // Assert that the error channel was closed. + select { + case err, ok := <-errCh: + require.Falsef(t, ok, "expected errCh to be closed") + require.NoError(t, err) + // NB: Give the error channel some time to be ready to receive in order to + // mitigate flakiness. + case <-time.After(50 * time.Millisecond): + t.Fatal("expected errCh to be closed") + } +} + +// TODO_TECHDEBT: add coverage for sending multiple messages simultaneously +func TestTxClient_SignAndBroadcast_MultipleMsgs(t *testing.T) { + t.SkipNow() +} + +// newTestKeyringWithKey creates a new in-memory keyring with a test key +// with testSigningKeyName as its name. +func newTestKeyringWithKey(t *testing.T) (cosmoskeyring.Keyring, *cosmoskeyring.Record) { + keyring := cosmoskeyring.NewInMemory(testclient.EncodingConfig.Marshaler) + key, _ := testclient.NewKey(t, testSigningKeyName, keyring) + return keyring, key +} diff --git a/pkg/client/tx/context.go b/pkg/client/tx/context.go index 5865ae526..eca32f943 100644 --- a/pkg/client/tx/context.go +++ b/pkg/client/tx/context.go @@ -22,7 +22,7 @@ type cosmosTxContext struct { // Holds cosmos-sdk client context. // (see: https://pkg.go.dev/github.com/cosmos/cosmos-sdk@v0.47.5/client#Context) clientCtx cosmosclient.Context - // Holds the cosmos-sdk tx factory. + // Holds the cosmos-sdk transaction factory. // (see: https://pkg.go.dev/github.com/cosmos/cosmos-sdk@v0.47.5/client/tx#Factory) txFactory cosmostx.Factory } @@ -67,7 +67,7 @@ func (txCtx cosmosTxContext) SignTx( ) } -// NewTxBuilder returns a new tx builder instance using the cosmos-sdk client tx config. +// NewTxBuilder returns a new transaction builder instance using the cosmos-sdk client transaction config. func (txCtx cosmosTxContext) NewTxBuilder() cosmosclient.TxBuilder { return txCtx.clientCtx.TxConfig.NewTxBuilder() } @@ -77,14 +77,15 @@ func (txCtx cosmosTxContext) EncodeTx(txBuilder cosmosclient.TxBuilder) ([]byte, return txCtx.clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) } -// BroadcastTx broadcasts the given tx to the network, blocking until the check-tx -// ABCI operation completes and returns a TxResponse of the tx status at that point in time. +// BroadcastTx broadcasts the given transaction to the network, blocking until the check-tx +// ABCI operation completes and returns a TxResponse of the transaction status at that point in time. func (txCtx cosmosTxContext) BroadcastTx(txBytes []byte) (*cosmostypes.TxResponse, error) { - return txCtx.clientCtx.BroadcastTxSync(txBytes) + return txCtx.clientCtx.BroadcastTxAsync(txBytes) + //return txCtx.clientCtx.BroadcastTxSync(txBytes) } // QueryTx queries the transaction based on its hash and optionally provides proof -// of the transaction. It returns the tx query result. +// of the transaction. It returns the transaction query result. func (txCtx cosmosTxContext) QueryTx( ctx context.Context, txHash []byte, diff --git a/pkg/client/tx/encoding.go b/pkg/client/tx/encoding.go new file mode 100644 index 000000000..78612e7b7 --- /dev/null +++ b/pkg/client/tx/encoding.go @@ -0,0 +1,18 @@ +package tx + +import ( + "fmt" + "strings" +) + +// normalizeTxHashHex defines canonical and unambiguous representation for a +// transaction hash hexadecimal string; lower-case. +func normalizeTxHashHex(txHash string) string { + return strings.ToLower(txHash) +} + +// txHashBytesToNormalizedHex converts a transaction hash bytes to a normalized +// hexadecimal string representation. +func txHashBytesToNormalizedHex(txHash []byte) string { + return normalizeTxHashHex(fmt.Sprintf("%x", txHash)) +} diff --git a/pkg/client/tx/errors.go b/pkg/client/tx/errors.go new file mode 100644 index 000000000..474f2ac19 --- /dev/null +++ b/pkg/client/tx/errors.go @@ -0,0 +1,53 @@ +package tx + +import errorsmod "cosmossdk.io/errors" + +var ( + // ErrEmptySigningKeyName represents an error which indicates that the + // provided signing key name is empty or unspecified. + ErrEmptySigningKeyName = errorsmod.Register(codespace, 1, "empty signing key name") + + // ErrNoSuchSigningKey represents an error signifying that the requested + // signing key does not exist or could not be located. + ErrNoSuchSigningKey = errorsmod.Register(codespace, 2, "signing key does not exist") + + // ErrSigningKeyAddr is raised when there's a failure in retrieving the + // associated address for the provided signing key. + ErrSigningKeyAddr = errorsmod.Register(codespace, 3, "failed to get address for signing key") + + // ErrInvalidMsg signifies that there was an issue in validating the + // transaction message. This could be due to format, content, or other + // constraints imposed on the message. + ErrInvalidMsg = errorsmod.Register(codespace, 4, "failed to validate tx message") + + // ErrCheckTx indicates an error occurred during the ABCI check transaction + // process, which verifies the transaction's integrity before it is added + // to the mempool. + ErrCheckTx = errorsmod.Register(codespace, 5, "error during ABCI check tx") + + // ErrTxTimeout is raised when a transaction has taken too long to + // complete, surpassing a predefined threshold. + ErrTxTimeout = errorsmod.Register(codespace, 6, "tx timed out") + + // ErrQueryTx indicates an error occurred while trying to query for the status + // of a specific transaction, likely due to issues with the query parameters + // or the state of the blockchain network. + ErrQueryTx = errorsmod.Register(codespace, 7, "error encountered while querying for tx") + + // ErrInvalidTxHash represents an error which is triggered when the + // transaction hash provided does not adhere to the expected format or + // constraints, implying it may be corrupted or tampered with. + ErrInvalidTxHash = errorsmod.Register(codespace, 8, "invalid tx hash") + + // ErrNonTxEventBytes indicates an attempt to deserialize bytes that do not + // correspond to a transaction event. This error is triggered when the provided + // byte data isn't recognized as a valid transaction event representation. + ErrNonTxEventBytes = errorsmod.Register(codespace, 9, "attempted to deserialize non-tx event bytes") + + // ErrUnmarshalTx signals a failure in the unmarshalling process of a transaction. + // This error is triggered when the system encounters issues translating a set of + // bytes into the corresponding Tx structure or object. + ErrUnmarshalTx = errorsmod.Register(codespace, 10, "failed to unmarshal tx") + + codespace = "tx_client" +) diff --git a/pkg/client/tx/options.go b/pkg/client/tx/options.go new file mode 100644 index 000000000..34e782b6d --- /dev/null +++ b/pkg/client/tx/options.go @@ -0,0 +1,22 @@ +package tx + +import ( + "github.com/pokt-network/poktroll/pkg/client" +) + +// WithCommitTimeoutBlocks sets the timeout duration in terms of number of blocks +// for the client to wait for broadcast transactions to be committed before +// returning a timeout error. +func WithCommitTimeoutBlocks(timeout int64) client.TxClientOption { + return func(client client.TxClient) { + client.(*txClient).commitTimeoutHeightOffset = timeout + } +} + +// WithSigningKeyName sets the name of the key which should be retrieved from the +// keyring and used for signing transactions. +func WithSigningKeyName(keyName string) client.TxClientOption { + return func(client client.TxClient) { + client.(*txClient).signingKeyName = keyName + } +} diff --git a/pkg/observable/channel/replay.go b/pkg/observable/channel/replay.go index 583edb4e5..a3935543d 100644 --- a/pkg/observable/channel/replay.go +++ b/pkg/observable/channel/replay.go @@ -38,8 +38,9 @@ type replayObservable[V any] struct { func NewReplayObservable[V any]( ctx context.Context, replayBufferSize int, + opts ...option[V], ) (observable.ReplayObservable[V], chan<- V) { - obsvbl, publishCh := NewObservable[V]() + obsvbl, publishCh := NewObservable[V](opts...) return ToReplayObservable[V](ctx, replayBufferSize, obsvbl), publishCh } From 3c4401cba4f3a4ef89a6afe11405c2b1c7a74be9 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 7 Nov 2023 09:44:14 +0100 Subject: [PATCH 14/40] [Off-chain] refactor: keyring errors & helpers (#131) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: add `TxClient` interface * chore: add option support to `ReplayObservable` * feat: add `txClient` implementation * test: `txClient` * test: tx client integration * chore: s/tx/transaction/g * chore: update pkg README.md template * wip: client pkg README * docs: fix client pkg godoc comment * refactor: consolidate keyring errors & helpers * refactor: keyring test helpers * fix: flakey test * chore: dial back godoc comments 😅 * chore: revise (and move to godoc.go) `testblock` & `testeventsquery` pkg godoc comment * chore: update go.mod * chore: refactor & condense godoc comments * chore: fix import paths post-update --- internal/testclient/testeventsquery/client.go | 18 +++++++----- internal/testclient/testkeyring/keyring.go | 17 +++++++++++ pkg/client/keyring/errors.go | 19 ++++++++++++ pkg/client/keyring/keyring.go | 29 +++++++++++++++++++ pkg/client/tx/client.go | 17 +++++------ pkg/client/tx/client_integration_test.go | 3 +- pkg/client/tx/client_test.go | 26 +++++++---------- pkg/client/tx/errors.go | 12 -------- 8 files changed, 94 insertions(+), 47 deletions(-) create mode 100644 internal/testclient/testkeyring/keyring.go create mode 100644 pkg/client/keyring/errors.go create mode 100644 pkg/client/keyring/keyring.go diff --git a/internal/testclient/testeventsquery/client.go b/internal/testclient/testeventsquery/client.go index 2c68606ce..fbf7daeb1 100644 --- a/internal/testclient/testeventsquery/client.go +++ b/internal/testclient/testeventsquery/client.go @@ -27,11 +27,12 @@ func NewLocalnetClient(t *testing.T, opts ...client.EventsQueryClientOption) cli } // NewOneTimeEventsQuery creates a mock of the EventsQueryClient which expects -// a single call to the EventsBytes method. query is the query string which is -// expected to be received by that call. -// It returns a mock client whose event bytes method constructs a new observable. -// The caller can simulate blockchain events by sending on the value publishCh -// points to, which is set by this helper function. +// a single call to the EventsBytes method. It returns a mock client whose event +// bytes method always constructs a new observable. query is the query string +// for which event bytes subscription is expected to be for. +// The caller can simulate blockchain events by sending on publishCh, the value +// of which is set to the publish channel of the events bytes observable publish +// channel. func NewOneTimeEventsQuery( ctx context.Context, t *testing.T, @@ -53,11 +54,12 @@ func NewOneTimeEventsQuery( return eventsQueryClient } -// NewOneTimeTxEventsQueryClient creates a mock of the Events that expects +// NewOneTimeTxEventsQueryClient creates a mock of the Events that expects to to // a single call to the EventsBytes method where the query is for transaction // events for sender address matching that of the given key. -// The caller can simulate blockchain events by sending on the value publishCh -// points to, which is set by this helper function. +// The caller can simulate blockchain events by sending on publishCh, the value +// of which is set to the publish channel of the events bytes observable publish +// channel. func NewOneTimeTxEventsQueryClient( ctx context.Context, t *testing.T, diff --git a/internal/testclient/testkeyring/keyring.go b/internal/testclient/testkeyring/keyring.go new file mode 100644 index 000000000..40fbc64c8 --- /dev/null +++ b/internal/testclient/testkeyring/keyring.go @@ -0,0 +1,17 @@ +package testkeyring + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/keyring" + + "github.com/pokt-network/poktroll/internal/testclient" +) + +// NewTestKeyringWithKey creates a new in-memory keyring with a test key +// with testSigningKeyName as its name. +func NewTestKeyringWithKey(t *testing.T, keyName string) (keyring.Keyring, *keyring.Record) { + keyring := keyring.NewInMemory(testclient.EncodingConfig.Marshaler) + key, _ := testclient.NewKey(t, keyName, keyring) + return keyring, key +} diff --git a/pkg/client/keyring/errors.go b/pkg/client/keyring/errors.go new file mode 100644 index 000000000..7be8a677a --- /dev/null +++ b/pkg/client/keyring/errors.go @@ -0,0 +1,19 @@ +package keyring + +import "cosmossdk.io/errors" + +var ( + // ErrEmptySigningKeyName represents an error which indicates that the + // provided signing key name is empty or unspecified. + ErrEmptySigningKeyName = errors.Register(codespace, 1, "empty signing key name") + + // ErrNoSuchSigningKey represents an error signifying that the requested + // signing key does not exist or could not be located. + ErrNoSuchSigningKey = errors.Register(codespace, 2, "signing key does not exist") + + // ErrSigningKeyAddr is raised when there's a failure in retrieving the + // associated address for the provided signing key. + ErrSigningKeyAddr = errors.Register(codespace, 3, "failed to get address for signing key") + + codespace = "keyring" +) diff --git a/pkg/client/keyring/keyring.go b/pkg/client/keyring/keyring.go new file mode 100644 index 000000000..a77d35b6e --- /dev/null +++ b/pkg/client/keyring/keyring.go @@ -0,0 +1,29 @@ +package keyring + +import ( + cosmoskeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" + cosmostypes "github.com/cosmos/cosmos-sdk/types" +) + +// KeyNameToAddr attempts to retrieve the key with the given name from the +// given keyring and compute its address. +func KeyNameToAddr( + keyName string, + keyring cosmoskeyring.Keyring, +) (cosmostypes.AccAddress, error) { + if keyName == "" { + return nil, ErrEmptySigningKeyName + } + + keyRecord, err := keyring.Key(keyName) + if err != nil { + return nil, ErrNoSuchSigningKey.Wrapf("name %q: %s", keyName, err) + } + + signingAddr, err := keyRecord.GetAddress() + if err != nil { + return nil, ErrSigningKeyAddr.Wrapf("name %q: %s", keyName, err) + } + + return signingAddr, nil +} diff --git a/pkg/client/tx/client.go b/pkg/client/tx/client.go index 805443eb4..1c083559b 100644 --- a/pkg/client/tx/client.go +++ b/pkg/client/tx/client.go @@ -16,6 +16,7 @@ import ( "go.uber.org/multierr" "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/client/keyring" "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" @@ -245,18 +246,14 @@ func (tClient *txClient) SignAndBroadcast( // - ErrSigningKeyAddr if there's an issue retrieving the address for the signing key. // - nil if validation is successful and defaults are set appropriately. func (tClient *txClient) validateConfigAndSetDefaults() error { - if tClient.signingKeyName == "" { - return ErrEmptySigningKeyName - } - - keyRecord, err := tClient.txCtx.GetKeyring().Key(tClient.signingKeyName) - if err != nil { - return ErrNoSuchSigningKey.Wrapf("name %q: %s", tClient.signingKeyName, err) - } - signingAddr, err := keyRecord.GetAddress() + signingAddr, err := keyring.KeyNameToAddr( + tClient.signingKeyName, + tClient.txCtx.GetKeyring(), + ) if err != nil { - return ErrSigningKeyAddr.Wrapf("name %q: %s", tClient.signingKeyName, err) + return err } + tClient.signingAddr = signingAddr if tClient.commitTimeoutHeightOffset <= 0 { diff --git a/pkg/client/tx/client_integration_test.go b/pkg/client/tx/client_integration_test.go index c2d5db6e5..737c8a628 100644 --- a/pkg/client/tx/client_integration_test.go +++ b/pkg/client/tx/client_integration_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + "github.com/pokt-network/poktroll/internal/testclient/testkeyring" "github.com/pokt-network/poktroll/pkg/client/tx" "github.com/pokt-network/poktroll/internal/testclient/testblock" @@ -24,7 +25,7 @@ func TestTxClient_SignAndBroadcast_Integration(t *testing.T) { var ctx = context.Background() - keyring, signingKey := newTestKeyringWithKey(t) + keyring, signingKey := testkeyring.NewTestKeyringWithKey(t, testSigningKeyName) eventsQueryClient := testeventsquery.NewLocalnetClient(t) diff --git a/pkg/client/tx/client_test.go b/pkg/client/tx/client_test.go index 6cb5d33da..f6f1d08a9 100644 --- a/pkg/client/tx/client_test.go +++ b/pkg/client/tx/client_test.go @@ -17,8 +17,10 @@ import ( "github.com/pokt-network/poktroll/internal/testclient" "github.com/pokt-network/poktroll/internal/testclient/testblock" "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" + "github.com/pokt-network/poktroll/internal/testclient/testkeyring" "github.com/pokt-network/poktroll/internal/testclient/testtx" "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/client/keyring" "github.com/pokt-network/poktroll/pkg/client/tx" "github.com/pokt-network/poktroll/pkg/either" apptypes "github.com/pokt-network/poktroll/x/application/types" @@ -49,7 +51,7 @@ func TestTxClient_SignAndBroadcast_Succeeds(t *testing.T) { ctx = context.Background() ) - keyring, signingKey := newTestKeyringWithKey(t) + keyring, signingKey := testkeyring.NewTestKeyringWithKey(t, testSigningKeyName) eventsQueryClient := testeventsquery.NewOneTimeTxEventsQueryClient( ctx, t, signingKey, &eventsBzPublishCh, @@ -118,7 +120,7 @@ func TestTxClient_SignAndBroadcast_Succeeds(t *testing.T) { func TestTxClient_NewTxClient_Error(t *testing.T) { // Construct an empty in-memory keyring. - keyring := cosmoskeyring.NewInMemory(testclient.EncodingConfig.Marshaler) + memKeyring := cosmoskeyring.NewInMemory(testclient.EncodingConfig.Marshaler) tests := []struct { name string @@ -128,12 +130,12 @@ func TestTxClient_NewTxClient_Error(t *testing.T) { { name: "empty signing key name", signingKeyName: "", - expectedErr: tx.ErrEmptySigningKeyName, + expectedErr: keyring.ErrEmptySigningKeyName, }, { name: "signing key does not exist", signingKeyName: "nonexistent", - expectedErr: tx.ErrNoSuchSigningKey, + expectedErr: keyring.ErrNoSuchSigningKey, }, // TODO_TECHDEBT: add coverage for this error case // { @@ -156,7 +158,7 @@ func TestTxClient_NewTxClient_Error(t *testing.T) { eventsQueryClient := mockclient.NewMockEventsQueryClient(ctrl) // Construct a new mock transactions context. - txCtxMock, _ := testtx.NewAnyTimesTxTxContext(t, keyring) + txCtxMock, _ := testtx.NewAnyTimesTxTxContext(t, memKeyring) // Construct a new mock block client. Since we expect the NewTxClient // call to fail, we don't need to set any expectations on this mock. @@ -195,7 +197,7 @@ func TestTxClient_SignAndBroadcast_SyncError(t *testing.T) { ctx = context.Background() ) - keyring, signingKey := newTestKeyringWithKey(t) + keyring, signingKey := testkeyring.NewTestKeyringWithKey(t, testSigningKeyName) // Construct a new mock events query client. Since we expect the // NewTxClient call to fail, we don't need to set any expectations @@ -260,7 +262,7 @@ func TestTxClient_SignAndBroadcast_CheckTxError(t *testing.T) { ctx = context.Background() ) - keyring, signingKey := newTestKeyringWithKey(t) + keyring, signingKey := testkeyring.NewTestKeyringWithKey(t, testSigningKeyName) eventsQueryClient := testeventsquery.NewOneTimeTxEventsQueryClient( ctx, t, signingKey, &eventsBzPublishCh, @@ -323,7 +325,7 @@ func TestTxClient_SignAndBroadcast_Timeout(t *testing.T) { ctx = context.Background() ) - keyring, signingKey := newTestKeyringWithKey(t) + keyring, signingKey := testkeyring.NewTestKeyringWithKey(t, testSigningKeyName) eventsQueryClient := testeventsquery.NewOneTimeTxEventsQueryClient( ctx, t, signingKey, &eventsBzPublishCh, @@ -403,11 +405,3 @@ func TestTxClient_SignAndBroadcast_Timeout(t *testing.T) { func TestTxClient_SignAndBroadcast_MultipleMsgs(t *testing.T) { t.SkipNow() } - -// newTestKeyringWithKey creates a new in-memory keyring with a test key -// with testSigningKeyName as its name. -func newTestKeyringWithKey(t *testing.T) (cosmoskeyring.Keyring, *cosmoskeyring.Record) { - keyring := cosmoskeyring.NewInMemory(testclient.EncodingConfig.Marshaler) - key, _ := testclient.NewKey(t, testSigningKeyName, keyring) - return keyring, key -} diff --git a/pkg/client/tx/errors.go b/pkg/client/tx/errors.go index 474f2ac19..1e43f1d05 100644 --- a/pkg/client/tx/errors.go +++ b/pkg/client/tx/errors.go @@ -3,18 +3,6 @@ package tx import errorsmod "cosmossdk.io/errors" var ( - // ErrEmptySigningKeyName represents an error which indicates that the - // provided signing key name is empty or unspecified. - ErrEmptySigningKeyName = errorsmod.Register(codespace, 1, "empty signing key name") - - // ErrNoSuchSigningKey represents an error signifying that the requested - // signing key does not exist or could not be located. - ErrNoSuchSigningKey = errorsmod.Register(codespace, 2, "signing key does not exist") - - // ErrSigningKeyAddr is raised when there's a failure in retrieving the - // associated address for the provided signing key. - ErrSigningKeyAddr = errorsmod.Register(codespace, 3, "failed to get address for signing key") - // ErrInvalidMsg signifies that there was an issue in validating the // transaction message. This could be due to format, content, or other // constraints imposed on the message. From d67edeeed4f68020d2911681837bddac2f4fdbd3 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 7 Nov 2023 09:55:19 +0100 Subject: [PATCH 15/40] [Miner] feat: add supplier client (#42) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: add `TxClient` interface * chore: add option support to `ReplayObservable` * feat: add `txClient` implementation * test: `txClient` * test: tx client integration * chore: s/tx/transaction/g * chore: update pkg README.md template * wip: client pkg README * docs: fix client pkg godoc comment * refactor: consolidate keyring errors & helpers * refactor: keyring test helpers * fix: flakey test * chore: dial back godoc comments 😅 * chore: add `SupplierClient` interface * feat: add supplier client implementation * test: supplier test helpers * test: supplier client tests * test: supplier client integration test * chore: update go.mod * trigger CI * chore: revise (and move to godoc.go) `testblock` & `testeventsquery` pkg godoc comment * chore: update go.mod * chore: refactor & condense godoc comments * chore: fix import paths post-update * chore: add godoc comment --- go.mod | 2 + go.sum | 4 + internal/testclient/keyring.go | 2 + internal/testclient/testsupplier/client.go | 37 ++++ internal/testclient/testtx/client.go | 93 +++++++++ internal/testclient/testtx/context.go | 22 ++ pkg/client/interface.go | 32 ++- pkg/client/supplier/client.go | 127 ++++++++++++ .../supplier/client_integration_test.go | 36 ++++ pkg/client/supplier/client_test.go | 190 ++++++++++++++++++ pkg/client/supplier/options.go | 14 ++ 11 files changed, 557 insertions(+), 2 deletions(-) create mode 100644 internal/testclient/testsupplier/client.go create mode 100644 internal/testclient/testtx/client.go create mode 100644 pkg/client/supplier/client.go create mode 100644 pkg/client/supplier/client_integration_test.go create mode 100644 pkg/client/supplier/client_test.go create mode 100644 pkg/client/supplier/options.go diff --git a/go.mod b/go.mod index 2d699d1cf..a8ef04265 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 + github.com/pokt-network/smt v0.7.1 github.com/regen-network/gocuke v0.6.2 github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 @@ -86,6 +87,7 @@ require ( github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/badger/v3 v3.2103.5 // indirect + github.com/dgraph-io/badger/v4 v4.2.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/go-units v0.5.0 // indirect diff --git a/go.sum b/go.sum index ef5829bd5..64f7566f0 100644 --- a/go.sum +++ b/go.sum @@ -520,6 +520,8 @@ github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdw github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= +github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= +github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= @@ -1582,6 +1584,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pokt-network/smt v0.7.1 h1:WHcZeMLe+9U1/kCAhdbssdyTYzYxxb74sf8MCvG34M8= +github.com/pokt-network/smt v0.7.1/go.mod h1:K7BLEOWoZGZmY5USQuYvTkZ3qXjE6m39BMufBvVo3U8= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/polyfloyd/go-errorlint v1.0.0/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA= diff --git a/internal/testclient/keyring.go b/internal/testclient/keyring.go index a3c8dc14c..59d54f908 100644 --- a/internal/testclient/keyring.go +++ b/internal/testclient/keyring.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/require" ) +// NewKey creates a new Secp256k1 key and mnemonic for the given name within +// the provided keyring. func NewKey( t *testing.T, name string, diff --git a/internal/testclient/testsupplier/client.go b/internal/testclient/testsupplier/client.go new file mode 100644 index 000000000..be5df6507 --- /dev/null +++ b/internal/testclient/testsupplier/client.go @@ -0,0 +1,37 @@ +package testsupplier + +import ( + "testing" + + "cosmossdk.io/depinject" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/internal/testclient/testtx" + "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/client/supplier" + "github.com/pokt-network/poktroll/pkg/client/tx" +) + +// NewLocalnetClient creates and returns a new supplier client that connects to +// the localnet sequencer. +func NewLocalnetClient( + t *testing.T, + signingKeyName string, +) client.SupplierClient { + t.Helper() + + txClientOpt := tx.WithSigningKeyName(signingKeyName) + supplierClientOpt := supplier.WithSigningKeyName(signingKeyName) + + txCtx := testtx.NewLocalnetContext(t) + txClient := testtx.NewLocalnetClient(t, txClientOpt) + + deps := depinject.Supply( + txCtx, + txClient, + ) + + supplierClient, err := supplier.NewSupplierClient(deps, supplierClientOpt) + require.NoError(t, err) + return supplierClient +} diff --git a/internal/testclient/testtx/client.go b/internal/testclient/testtx/client.go new file mode 100644 index 000000000..3e843dd91 --- /dev/null +++ b/internal/testclient/testtx/client.go @@ -0,0 +1,93 @@ +package testtx + +import ( + "context" + "testing" + "time" + + "cosmossdk.io/depinject" + cosmostypes "github.com/cosmos/cosmos-sdk/types" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/internal/mocks/mockclient" + "github.com/pokt-network/poktroll/internal/testclient/testblock" + "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" + "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/client/tx" + "github.com/pokt-network/poktroll/pkg/either" +) + +type signAndBroadcastFn func(context.Context, cosmostypes.Msg) either.AsyncError + +// TODO_CONSIDERATION: functions like these (NewLocalnetXXX) could probably accept +// and return depinject.Config arguments to support shared dependencies. + +// NewLocalnetClient creates and returns a new client for use with the localnet +// sequencer. +func NewLocalnetClient(t *testing.T, opts ...client.TxClientOption) client.TxClient { + t.Helper() + + ctx := context.Background() + txCtx := NewLocalnetContext(t) + eventsQueryClient := testeventsquery.NewLocalnetClient(t) + blockClient := testblock.NewLocalnetClient(ctx, t) + + deps := depinject.Supply( + txCtx, + eventsQueryClient, + blockClient, + ) + + txClient, err := tx.NewTxClient(ctx, deps, opts...) + require.NoError(t, err) + + return txClient +} + +// NewOneTimeDelayedSignAndBroadcastTxClient constructs a mock TxClient with the +// expectation to perform a SignAndBroadcast operation with a specified delay. +func NewOneTimeDelayedSignAndBroadcastTxClient( + t *testing.T, + delay time.Duration, +) *mockclient.MockTxClient { + t.Helper() + + signAndBroadcast := newSignAndBroadcastSucceedsDelayed(delay) + return NewOneTimeSignAndBroadcastTxClient(t, signAndBroadcast) +} + +// NewOneTimeSignAndBroadcastTxClient constructs a mock TxClient with the +// expectation to perform a SignAndBroadcast operation, which will call and receive +// the return from the given signAndBroadcast function. +func NewOneTimeSignAndBroadcastTxClient( + t *testing.T, + signAndBroadcast signAndBroadcastFn, +) *mockclient.MockTxClient { + t.Helper() + + var ctrl = gomock.NewController(t) + + txClient := mockclient.NewMockTxClient(ctrl) + txClient.EXPECT().SignAndBroadcast( + gomock.AssignableToTypeOf(context.Background()), + gomock.Any(), + ).DoAndReturn(signAndBroadcast).Times(1) + + return txClient +} + +// newSignAndBroadcastSucceedsDelayed returns a signAndBroadcastFn that succeeds +// after the given delay. +func newSignAndBroadcastSucceedsDelayed(delay time.Duration) signAndBroadcastFn { + return func(ctx context.Context, msg cosmostypes.Msg) either.AsyncError { + errCh := make(chan error) + + go func() { + time.Sleep(delay) + close(errCh) + }() + + return either.AsyncErr(errCh) + } +} diff --git a/internal/testclient/testtx/context.go b/internal/testclient/testtx/context.go index fa25494e7..134d7b2c4 100644 --- a/internal/testclient/testtx/context.go +++ b/internal/testclient/testtx/context.go @@ -23,6 +23,28 @@ import ( "github.com/pokt-network/poktroll/pkg/client/tx" ) +// NewLocalnetContext creates and returns a new transaction context configured +// for use with the localnet sequencer. +func NewLocalnetContext(t *testing.T) client.TxContext { + t.Helper() + + flagSet := testclient.NewLocalnetFlagSet(t) + clientCtx := testclient.NewLocalnetClientCtx(t, flagSet) + txFactory, err := cosmostx.NewFactoryCLI(*clientCtx, flagSet) + require.NoError(t, err) + require.NotEmpty(t, txFactory) + + deps := depinject.Supply( + *clientCtx, + txFactory, + ) + + txCtx, err := tx.NewTxContext(deps) + require.NoError(t, err) + + return txCtx +} + // TODO_IMPROVE: these mock constructor helpers could include parameters for the // "times" (e.g. exact, min, max) values which are passed to their respective // gomock.EXPECT() method calls (i.e. Times(), MinTimes(), MaxTimes()). diff --git a/pkg/client/interface.go b/pkg/client/interface.go index 32dab250c..c088df35c 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -1,6 +1,6 @@ //go:generate mockgen -destination=../../internal/mocks/mockclient/events_query_client_mock.go -package=mockclient . Dialer,Connection,EventsQueryClient //go:generate mockgen -destination=../../internal/mocks/mockclient/block_client_mock.go -package=mockclient . Block,BlockClient -//go:generate mockgen -destination=../../internal/mocks/mockclient/tx_client_mock.go -package=mockclient . TxContext +//go:generate mockgen -destination=../../internal/mocks/mockclient/tx_client_mock.go -package=mockclient . TxContext,TxClient //go:generate mockgen -destination=../../internal/mocks/mockclient/cosmos_tx_builder_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client TxBuilder //go:generate mockgen -destination=../../internal/mocks/mockclient/cosmos_keyring_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/crypto/keyring Keyring //go:generate mockgen -destination=../../internal/mocks/mockclient/cosmos_client_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client AccountRetriever @@ -14,11 +14,36 @@ import ( cosmosclient "github.com/cosmos/cosmos-sdk/client" cosmoskeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" cosmostypes "github.com/cosmos/cosmos-sdk/types" + "github.com/pokt-network/smt" "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" ) +// SupplierClient is an interface for sufficient for a supplier operator to be +// able to construct blockchain transactions from pocket protocol-specific messages +// related to its role. +type SupplierClient interface { + // CreateClaim sends a claim message which creates an on-chain commitment by + // calling supplier to the given smt.SparseMerkleSumTree root hash of the given + // session's mined relays. + CreateClaim( + ctx context.Context, + sessionHeader sessiontypes.SessionHeader, + rootHash []byte, + ) error + // SubmitProof sends a proof message which contains the + // smt.SparseMerkleClosestProof, corresponding to some previously created claim + // for the same session. The proof is validated on-chain as part of the pocket + // protocol. + SubmitProof( + ctx context.Context, + sessionHeader sessiontypes.SessionHeader, + proof *smt.SparseMerkleClosestProof, + ) error +} + // TxClient provides a synchronous interface initiating and waiting for transactions // derived from cosmos-sdk messages, in a cosmos-sdk based blockchain network. type TxClient interface { @@ -79,7 +104,7 @@ type BlocksObservable observable.ReplayObservable[Block] // BlockClient is an interface which provides notifications about newly committed // blocks as well as direct access to the latest block via some blockchain API. type BlockClient interface { - // Blocks returns an observable which emits newly committed blocks. + // CommittedBlocksSequence returns an observable which emits newly committed blocks. CommittedBlocksSequence(context.Context) BlocksObservable // LatestBlock returns the latest block that has been committed. LatestBlock(context.Context) Block @@ -148,3 +173,6 @@ type EventsQueryClientOption func(EventsQueryClient) // TxClientOption defines a function type that modifies the TxClient. type TxClientOption func(TxClient) + +// SupplierClientOption defines a function type that modifies the SupplierClient. +type SupplierClientOption func(SupplierClient) diff --git a/pkg/client/supplier/client.go b/pkg/client/supplier/client.go new file mode 100644 index 000000000..a0172c3c5 --- /dev/null +++ b/pkg/client/supplier/client.go @@ -0,0 +1,127 @@ +package supplier + +import ( + "context" + + "cosmossdk.io/depinject" + cosmostypes "github.com/cosmos/cosmos-sdk/types" + "github.com/pokt-network/smt" + + "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/client/keyring" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" +) + +var _ client.SupplierClient = (*supplierClient)(nil) + +// supplierClient +type supplierClient struct { + signingKeyName string + signingKeyAddr cosmostypes.AccAddress + + txClient client.TxClient + txCtx client.TxContext +} + +// NewSupplierClient constructs a new SupplierClient with the given dependencies +// and options. If a signingKeyName is not configured, an error will be returned. +// +// Required dependencies: +// - client.TxClient +// - client.TxContext +// +// Available options: +// - WithSigningKeyName +func NewSupplierClient( + deps depinject.Config, + opts ...client.SupplierClientOption, +) (*supplierClient, error) { + sClient := &supplierClient{} + + if err := depinject.Inject( + deps, + &sClient.txClient, + &sClient.txCtx, + ); err != nil { + return nil, err + } + + for _, opt := range opts { + opt(sClient) + } + + if err := sClient.validateConfigAndSetDefaults(); err != nil { + return nil, err + } + + return sClient, nil +} + +// SubmitProof constructs a submit proof message then signs and broadcasts it +// to the network via #txClient. It blocks until the transaction is included in +// a block or times out. +func (sClient *supplierClient) SubmitProof( + ctx context.Context, + sessionHeader sessiontypes.SessionHeader, + proof *smt.SparseMerkleClosestProof, +) error { + proofBz, err := proof.Marshal() + if err != nil { + return err + } + + msg := &suppliertypes.MsgSubmitProof{ + SupplierAddress: sClient.signingKeyAddr.String(), + SessionHeader: &sessionHeader, + Proof: proofBz, + } + eitherErr := sClient.txClient.SignAndBroadcast(ctx, msg) + err, errCh := eitherErr.SyncOrAsyncError() + if err != nil { + return err + } + + return <-errCh +} + +// CreateClaim constructs a creates claim message then signs and broadcasts it +// to the network via #txClient. It blocks until the transaction is included in +// a block or times out. +func (sClient *supplierClient) CreateClaim( + ctx context.Context, + sessionHeader sessiontypes.SessionHeader, + rootHash []byte, +) error { + msg := &suppliertypes.MsgCreateClaim{ + SupplierAddress: sClient.signingKeyAddr.String(), + SessionHeader: &sessionHeader, + RootHash: rootHash, + } + eitherErr := sClient.txClient.SignAndBroadcast(ctx, msg) + err, errCh := eitherErr.SyncOrAsyncError() + if err != nil { + return err + } + + err = <-errCh + return err +} + +// validateConfigAndSetDefaults attempts to get the address from the keyring +// corresponding to the key whose name matches the configured signingKeyName. +// If signingKeyName is empty or the keyring does not contain the corresponding +// key, an error is returned. +func (sClient *supplierClient) validateConfigAndSetDefaults() error { + signingAddr, err := keyring.KeyNameToAddr( + sClient.signingKeyName, + sClient.txCtx.GetKeyring(), + ) + if err != nil { + return err + } + + sClient.signingKeyAddr = signingAddr + + return nil +} diff --git a/pkg/client/supplier/client_integration_test.go b/pkg/client/supplier/client_integration_test.go new file mode 100644 index 000000000..8af759186 --- /dev/null +++ b/pkg/client/supplier/client_integration_test.go @@ -0,0 +1,36 @@ +//go:build integration + +package supplier_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/internal/testclient/testsupplier" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" +) + +func TestNewSupplierClient_Localnet(t *testing.T) { + t.Skip("TODO_TECHDEBT: this test depends on some setup which is currently not implemented in this test: staked application and servicer with matching services") + + var ( + signingKeyName = "app1" + ctx = context.Background() + ) + + supplierClient := testsupplier.NewLocalnetClient(t, signingKeyName) + require.NotNil(t, supplierClient) + + var rootHash []byte + sessionHeader := sessiontypes.SessionHeader{ + ApplicationAddress: "", + SessionStartBlockHeight: 0, + SessionId: "", + } + err := supplierClient.CreateClaim(ctx, sessionHeader, rootHash) + require.NoError(t, err) + + require.True(t, false) +} diff --git a/pkg/client/supplier/client_test.go b/pkg/client/supplier/client_test.go new file mode 100644 index 000000000..9cb6e85c6 --- /dev/null +++ b/pkg/client/supplier/client_test.go @@ -0,0 +1,190 @@ +package supplier_test + +import ( + "context" + "crypto/sha256" + "testing" + "time" + + "cosmossdk.io/depinject" + "github.com/golang/mock/gomock" + "github.com/pokt-network/smt" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/internal/mocks/mockclient" + "github.com/pokt-network/poktroll/internal/testclient/testkeyring" + "github.com/pokt-network/poktroll/internal/testclient/testtx" + "github.com/pokt-network/poktroll/pkg/client/keyring" + "github.com/pokt-network/poktroll/pkg/client/supplier" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" +) + +var testSigningKeyName = "test_signer" + +func TestNewSupplierClient(t *testing.T) { + ctrl := gomock.NewController(t) + + memKeyring, _ := testkeyring.NewTestKeyringWithKey(t, testSigningKeyName) + txCtxMock, _ := testtx.NewAnyTimesTxTxContext(t, memKeyring) + txClientMock := mockclient.NewMockTxClient(ctrl) + + deps := depinject.Supply( + txCtxMock, + txClientMock, + ) + + tests := []struct { + name string + signingKeyName string + expectedErr error + }{ + { + name: "valid signing key name", + signingKeyName: testSigningKeyName, + expectedErr: nil, + }, + { + name: "empty signing key name", + signingKeyName: "", + expectedErr: keyring.ErrEmptySigningKeyName, + }, + { + name: "no such signing key name", + signingKeyName: "nonexistent", + expectedErr: keyring.ErrNoSuchSigningKey, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + signingKeyOpt := supplier.WithSigningKeyName(tt.signingKeyName) + + supplierClient, err := supplier.NewSupplierClient(deps, signingKeyOpt) + if tt.expectedErr != nil { + require.ErrorIs(t, err, tt.expectedErr) + require.Nil(t, supplierClient) + } else { + require.NoError(t, err) + require.NotNil(t, supplierClient) + } + }) + } +} + +func TestSupplierClient_CreateClaim(t *testing.T) { + var ( + signAndBroadcastDelay = 50 * time.Millisecond + doneCh = make(chan struct{}, 1) + ctx = context.Background() + ) + + keyring, testAppKey := testkeyring.NewTestKeyringWithKey(t, testSigningKeyName) + + testAppAddr, err := testAppKey.GetAddress() + require.NoError(t, err) + + txCtxMock, _ := testtx.NewAnyTimesTxTxContext(t, keyring) + txClientMock := testtx.NewOneTimeDelayedSignAndBroadcastTxClient(t, signAndBroadcastDelay) + + signingKeyOpt := supplier.WithSigningKeyName(testAppKey.Name) + deps := depinject.Supply( + txCtxMock, + txClientMock, + ) + + supplierClient, err := supplier.NewSupplierClient(deps, signingKeyOpt) + require.NoError(t, err) + require.NotNil(t, supplierClient) + + var rootHash []byte + sessionHeader := sessiontypes.SessionHeader{ + ApplicationAddress: testAppAddr.String(), + SessionStartBlockHeight: 0, + SessionId: "", + } + + go func() { + err = supplierClient.CreateClaim(ctx, sessionHeader, rootHash) + require.NoError(t, err) + close(doneCh) + }() + + // TODO_IMPROVE: this could be rewritten to record the times at which + // things happen and then compare them to the expected times. + + select { + case <-doneCh: + t.Fatal("expected CreateClaim to block for signAndBroadcastDelay") + case <-time.After(signAndBroadcastDelay * 95 / 100): + t.Log("OK: CreateClaim blocked for at least 95% of signAndBroadcastDelay") + } + + select { + case <-time.After(signAndBroadcastDelay): + t.Fatal("expected CreateClaim to unblock after signAndBroadcastDelay") + case <-doneCh: + t.Log("OK: CreateClaim unblocked after signAndBroadcastDelay") + } +} + +func TestSupplierClient_SubmitProof(t *testing.T) { + var ( + signAndBroadcastDelay = 50 * time.Millisecond + doneCh = make(chan struct{}, 1) + ctx = context.Background() + ) + + keyring, testAppKey := testkeyring.NewTestKeyringWithKey(t, testSigningKeyName) + + testAppAddr, err := testAppKey.GetAddress() + require.NoError(t, err) + + txCtxMock, _ := testtx.NewAnyTimesTxTxContext(t, keyring) + txClientMock := testtx.NewOneTimeDelayedSignAndBroadcastTxClient(t, signAndBroadcastDelay) + + signingKeyOpt := supplier.WithSigningKeyName(testAppKey.Name) + deps := depinject.Supply( + txCtxMock, + txClientMock, + ) + + supplierClient, err := supplier.NewSupplierClient(deps, signingKeyOpt) + require.NoError(t, err) + require.NotNil(t, supplierClient) + + sessionHeader := sessiontypes.SessionHeader{ + ApplicationAddress: testAppAddr.String(), + SessionStartBlockHeight: 0, + SessionId: "", + } + + kvStore, err := smt.NewKVStore("") + require.NoError(t, err) + + tree := smt.NewSparseMerkleSumTree(kvStore, sha256.New()) + proof, err := tree.ProveClosest([]byte{1}) + require.NoError(t, err) + + go func() { + err = supplierClient.SubmitProof(ctx, sessionHeader, proof) + require.NoError(t, err) + close(doneCh) + }() + + // TODO_IMPROVE: this could be rewritten to record the times at which + // things happen and then compare them to the expected times. + + select { + case <-doneCh: + t.Fatal("expected SubmitProof to block for signAndBroadcastDelay") + case <-time.After(signAndBroadcastDelay * 95 / 100): + t.Log("OK: SubmitProof blocked for at least 95% of signAndBroadcastDelay") + } + + select { + case <-time.After(signAndBroadcastDelay): + t.Fatal("expected SubmitProof to unblock after signAndBroadcastDelay") + case <-doneCh: + t.Log("OK: SubmitProof unblocked after signAndBroadcastDelay") + } +} diff --git a/pkg/client/supplier/options.go b/pkg/client/supplier/options.go new file mode 100644 index 000000000..f4460c8c9 --- /dev/null +++ b/pkg/client/supplier/options.go @@ -0,0 +1,14 @@ +package supplier + +import ( + "github.com/pokt-network/poktroll/pkg/client" +) + +// WithSigningKeyName sets the name of the key which the supplier client should +// retrieve from the keyring to use for authoring and signing CreateClaim and +// SubmitProof messages. +func WithSigningKeyName(keyName string) client.SupplierClientOption { + return func(sClient client.SupplierClient) { + sClient.(*supplierClient).signingKeyName = keyName + } +} From 13479cf159b0dbec9e24befc99c3858f5fa6f040 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 7 Nov 2023 21:13:53 +0100 Subject: [PATCH 16/40] [Testing, Docs] refactor: move /internal/... to /testutil/... for godocs (#153) * refactor: move /internal pkgs to /testutil * chore: cleanup --- internal/mocks/mocks.go | 10 ---------- pkg/client/block/client_integration_test.go | 2 +- pkg/client/block/client_test.go | 4 ++-- pkg/client/events_query/client_integration_test.go | 2 +- pkg/client/events_query/client_test.go | 9 +++++---- pkg/client/interface.go | 12 ++++++------ pkg/client/supplier/client_integration_test.go | 2 +- pkg/client/supplier/client_test.go | 7 ++++--- pkg/client/tx/client_integration_test.go | 8 ++++---- pkg/client/tx/client_test.go | 13 +++++++------ pkg/observable/channel/observable_test.go | 4 ++-- pkg/observable/channel/replay_test.go | 2 +- {internal/mocks => testutil}/mockclient/mocks.go | 0 {internal => testutil}/testchannel/drain.go | 0 {internal => testutil}/testclient/keyring.go | 0 {internal => testutil}/testclient/localnet.go | 0 .../testclient/testblock/client.go | 7 ++++--- .../testclient/testblock/godoc.go | 0 .../testclient/testeventsquery/client.go | 5 +++-- .../testclient/testeventsquery/connection.go | 2 +- .../testclient/testeventsquery/godoc.go | 0 .../testclient/testkeyring/keyring.go | 2 +- .../testclient/testsupplier/client.go | 2 +- {internal => testutil}/testclient/testtx/client.go | 7 ++++--- {internal => testutil}/testclient/testtx/context.go | 5 +++-- {internal => testutil}/testerrors/require.go | 0 26 files changed, 51 insertions(+), 54 deletions(-) delete mode 100644 internal/mocks/mocks.go rename {internal/mocks => testutil}/mockclient/mocks.go (100%) rename {internal => testutil}/testchannel/drain.go (100%) rename {internal => testutil}/testclient/keyring.go (100%) rename {internal => testutil}/testclient/localnet.go (100%) rename {internal => testutil}/testclient/testblock/client.go (95%) rename {internal => testutil}/testclient/testblock/godoc.go (100%) rename {internal => testutil}/testclient/testeventsquery/client.go (97%) rename {internal => testutil}/testclient/testeventsquery/connection.go (95%) rename {internal => testutil}/testclient/testeventsquery/godoc.go (100%) rename {internal => testutil}/testclient/testkeyring/keyring.go (88%) rename {internal => testutil}/testclient/testsupplier/client.go (93%) rename {internal => testutil}/testclient/testtx/client.go (93%) rename {internal => testutil}/testclient/testtx/context.go (98%) rename {internal => testutil}/testerrors/require.go (100%) diff --git a/internal/mocks/mocks.go b/internal/mocks/mocks.go deleted file mode 100644 index 423f63d3e..000000000 --- a/internal/mocks/mocks.go +++ /dev/null @@ -1,10 +0,0 @@ -package mocks - -// This file is in place to declare the package for dynamically generated structs. -// -// Note that this does not follow the Cosmos SDK pattern of committing Mocks to main. -// For example, they commit auto-generate code to main: https://github.com/cosmos/cosmos-sdk/blob/main/x/gov/testutil/expected_keepers_mocks.go -// Documentation on how Cosmos uses mockgen can be found here: https://docs.cosmos.network/main/build/building-modules/testing#unit-tests -// -// IMPORTANT: We have attempted to use `.gitkeep` files instead, but it causes a circular dependency issue with protobuf and mock generation -// since we are leveraging `ignite` to compile `.proto` files which requires `.go` files to compile. diff --git a/pkg/client/block/client_integration_test.go b/pkg/client/block/client_integration_test.go index fd7e633ab..c242d7474 100644 --- a/pkg/client/block/client_integration_test.go +++ b/pkg/client/block/client_integration_test.go @@ -12,8 +12,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/testclient/testblock" "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/testutil/testclient/testblock" ) const blockIntegrationSubTimeout = 5 * time.Second diff --git a/pkg/client/block/client_test.go b/pkg/client/block/client_test.go index b2a5515b3..768fa59f9 100644 --- a/pkg/client/block/client_test.go +++ b/pkg/client/block/client_test.go @@ -10,10 +10,10 @@ import ( comettypes "github.com/cometbft/cometbft/types" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/testclient" - "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/client/block" + "github.com/pokt-network/poktroll/testutil/testclient" + "github.com/pokt-network/poktroll/testutil/testclient/testeventsquery" ) const ( diff --git a/pkg/client/events_query/client_integration_test.go b/pkg/client/events_query/client_integration_test.go index 05bf09c1a..a6a0e3bcd 100644 --- a/pkg/client/events_query/client_integration_test.go +++ b/pkg/client/events_query/client_integration_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" + "github.com/pokt-network/poktroll/testutil/testclient/testeventsquery" ) // The query use to subscribe for new block events on the websocket endpoint exposed by CometBFT nodes diff --git a/pkg/client/events_query/client_test.go b/pkg/client/events_query/client_test.go index 0ba52ec88..aae5f72d2 100644 --- a/pkg/client/events_query/client_test.go +++ b/pkg/client/events_query/client_test.go @@ -13,14 +13,15 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/mocks/mockclient" - "github.com/pokt-network/poktroll/internal/testchannel" - "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" - "github.com/pokt-network/poktroll/internal/testerrors" + "github.com/pokt-network/poktroll/testutil/mockclient" + eventsquery "github.com/pokt-network/poktroll/pkg/client/events_query" "github.com/pokt-network/poktroll/pkg/client/events_query/websocket" "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable" + "github.com/pokt-network/poktroll/testutil/testchannel" + "github.com/pokt-network/poktroll/testutil/testclient/testeventsquery" + "github.com/pokt-network/poktroll/testutil/testerrors" ) func TestEventsQueryClient_Subscribe_Succeeds(t *testing.T) { diff --git a/pkg/client/interface.go b/pkg/client/interface.go index c088df35c..1a9bcb500 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -1,9 +1,9 @@ -//go:generate mockgen -destination=../../internal/mocks/mockclient/events_query_client_mock.go -package=mockclient . Dialer,Connection,EventsQueryClient -//go:generate mockgen -destination=../../internal/mocks/mockclient/block_client_mock.go -package=mockclient . Block,BlockClient -//go:generate mockgen -destination=../../internal/mocks/mockclient/tx_client_mock.go -package=mockclient . TxContext,TxClient -//go:generate mockgen -destination=../../internal/mocks/mockclient/cosmos_tx_builder_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client TxBuilder -//go:generate mockgen -destination=../../internal/mocks/mockclient/cosmos_keyring_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/crypto/keyring Keyring -//go:generate mockgen -destination=../../internal/mocks/mockclient/cosmos_client_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client AccountRetriever +//go:generate mockgen -destination=../../testutil/mockclient/events_query_client_mock.go -package=mockclient . Dialer,Connection,EventsQueryClient +//go:generate mockgen -destination=../../testutil/mockclient/block_client_mock.go -package=mockclient . Block,BlockClient +//go:generate mockgen -destination=../../testutil/mockclient/tx_client_mock.go -package=mockclient . TxContext,TxClient +//go:generate mockgen -destination=../../testutil/mockclient/cosmos_tx_builder_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client TxBuilder +//go:generate mockgen -destination=../../testutil/mockclient/cosmos_keyring_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/crypto/keyring Keyring +//go:generate mockgen -destination=../../testutil/mockclient/cosmos_client_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client AccountRetriever package client diff --git a/pkg/client/supplier/client_integration_test.go b/pkg/client/supplier/client_integration_test.go index 8af759186..f7ea11f56 100644 --- a/pkg/client/supplier/client_integration_test.go +++ b/pkg/client/supplier/client_integration_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/testclient/testsupplier" + "github.com/pokt-network/poktroll/testutil/testclient/testsupplier" sessiontypes "github.com/pokt-network/poktroll/x/session/types" ) diff --git a/pkg/client/supplier/client_test.go b/pkg/client/supplier/client_test.go index 9cb6e85c6..830426946 100644 --- a/pkg/client/supplier/client_test.go +++ b/pkg/client/supplier/client_test.go @@ -11,11 +11,12 @@ import ( "github.com/pokt-network/smt" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/mocks/mockclient" - "github.com/pokt-network/poktroll/internal/testclient/testkeyring" - "github.com/pokt-network/poktroll/internal/testclient/testtx" + "github.com/pokt-network/poktroll/testutil/mockclient" + "github.com/pokt-network/poktroll/pkg/client/keyring" "github.com/pokt-network/poktroll/pkg/client/supplier" + "github.com/pokt-network/poktroll/testutil/testclient/testkeyring" + "github.com/pokt-network/poktroll/testutil/testclient/testtx" sessiontypes "github.com/pokt-network/poktroll/x/session/types" ) diff --git a/pkg/client/tx/client_integration_test.go b/pkg/client/tx/client_integration_test.go index 737c8a628..2716e9f64 100644 --- a/pkg/client/tx/client_integration_test.go +++ b/pkg/client/tx/client_integration_test.go @@ -10,12 +10,12 @@ import ( "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/testclient/testkeyring" "github.com/pokt-network/poktroll/pkg/client/tx" + "github.com/pokt-network/poktroll/testutil/testclient/testblock" + "github.com/pokt-network/poktroll/testutil/testclient/testeventsquery" + "github.com/pokt-network/poktroll/testutil/testclient/testkeyring" + "github.com/pokt-network/poktroll/testutil/testclient/testtx" - "github.com/pokt-network/poktroll/internal/testclient/testblock" - "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" - "github.com/pokt-network/poktroll/internal/testclient/testtx" "github.com/pokt-network/poktroll/pkg/client" apptypes "github.com/pokt-network/poktroll/x/application/types" ) diff --git a/pkg/client/tx/client_test.go b/pkg/client/tx/client_test.go index f6f1d08a9..bb4f78f6b 100644 --- a/pkg/client/tx/client_test.go +++ b/pkg/client/tx/client_test.go @@ -13,16 +13,17 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/mocks/mockclient" - "github.com/pokt-network/poktroll/internal/testclient" - "github.com/pokt-network/poktroll/internal/testclient/testblock" - "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" - "github.com/pokt-network/poktroll/internal/testclient/testkeyring" - "github.com/pokt-network/poktroll/internal/testclient/testtx" + "github.com/pokt-network/poktroll/testutil/mockclient" + "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/client/keyring" "github.com/pokt-network/poktroll/pkg/client/tx" "github.com/pokt-network/poktroll/pkg/either" + "github.com/pokt-network/poktroll/testutil/testclient" + "github.com/pokt-network/poktroll/testutil/testclient/testblock" + "github.com/pokt-network/poktroll/testutil/testclient/testeventsquery" + "github.com/pokt-network/poktroll/testutil/testclient/testkeyring" + "github.com/pokt-network/poktroll/testutil/testclient/testtx" apptypes "github.com/pokt-network/poktroll/x/application/types" ) diff --git a/pkg/observable/channel/observable_test.go b/pkg/observable/channel/observable_test.go index cb89c79d8..b278546fc 100644 --- a/pkg/observable/channel/observable_test.go +++ b/pkg/observable/channel/observable_test.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" - "github.com/pokt-network/poktroll/internal/testchannel" - "github.com/pokt-network/poktroll/internal/testerrors" "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" + "github.com/pokt-network/poktroll/testutil/testchannel" + "github.com/pokt-network/poktroll/testutil/testerrors" ) const ( diff --git a/pkg/observable/channel/replay_test.go b/pkg/observable/channel/replay_test.go index 0f9b3e9ac..6e01f123e 100644 --- a/pkg/observable/channel/replay_test.go +++ b/pkg/observable/channel/replay_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/testerrors" "github.com/pokt-network/poktroll/pkg/observable/channel" + "github.com/pokt-network/poktroll/testutil/testerrors" ) func TestReplayObservable(t *testing.T) { diff --git a/internal/mocks/mockclient/mocks.go b/testutil/mockclient/mocks.go similarity index 100% rename from internal/mocks/mockclient/mocks.go rename to testutil/mockclient/mocks.go diff --git a/internal/testchannel/drain.go b/testutil/testchannel/drain.go similarity index 100% rename from internal/testchannel/drain.go rename to testutil/testchannel/drain.go diff --git a/internal/testclient/keyring.go b/testutil/testclient/keyring.go similarity index 100% rename from internal/testclient/keyring.go rename to testutil/testclient/keyring.go diff --git a/internal/testclient/localnet.go b/testutil/testclient/localnet.go similarity index 100% rename from internal/testclient/localnet.go rename to testutil/testclient/localnet.go diff --git a/internal/testclient/testblock/client.go b/testutil/testclient/testblock/client.go similarity index 95% rename from internal/testclient/testblock/client.go rename to testutil/testclient/testblock/client.go index ebd2ebcd7..7fc1a0341 100644 --- a/internal/testclient/testblock/client.go +++ b/testutil/testclient/testblock/client.go @@ -8,12 +8,13 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/mocks/mockclient" - "github.com/pokt-network/poktroll/internal/testclient" - "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" + "github.com/pokt-network/poktroll/testutil/mockclient" + "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/client/block" "github.com/pokt-network/poktroll/pkg/observable/channel" + "github.com/pokt-network/poktroll/testutil/testclient" + "github.com/pokt-network/poktroll/testutil/testclient/testeventsquery" ) // NewLocalnetClient creates and returns a new BlockClient that's configured for diff --git a/internal/testclient/testblock/godoc.go b/testutil/testclient/testblock/godoc.go similarity index 100% rename from internal/testclient/testblock/godoc.go rename to testutil/testclient/testblock/godoc.go diff --git a/internal/testclient/testeventsquery/client.go b/testutil/testclient/testeventsquery/client.go similarity index 97% rename from internal/testclient/testeventsquery/client.go rename to testutil/testclient/testeventsquery/client.go index fbf7daeb1..3ce867fde 100644 --- a/internal/testclient/testeventsquery/client.go +++ b/testutil/testclient/testeventsquery/client.go @@ -10,12 +10,13 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/mocks/mockclient" - "github.com/pokt-network/poktroll/internal/testclient" + "github.com/pokt-network/poktroll/testutil/mockclient" + "github.com/pokt-network/poktroll/pkg/client" eventsquery "github.com/pokt-network/poktroll/pkg/client/events_query" "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable/channel" + "github.com/pokt-network/poktroll/testutil/testclient" ) // NewLocalnetClient creates and returns a new events query client that's configured diff --git a/internal/testclient/testeventsquery/connection.go b/testutil/testclient/testeventsquery/connection.go similarity index 95% rename from internal/testclient/testeventsquery/connection.go rename to testutil/testclient/testeventsquery/connection.go index 27a38f2ae..c8af4e6ad 100644 --- a/internal/testclient/testeventsquery/connection.go +++ b/testutil/testclient/testeventsquery/connection.go @@ -5,8 +5,8 @@ import ( "github.com/golang/mock/gomock" - "github.com/pokt-network/poktroll/internal/mocks/mockclient" "github.com/pokt-network/poktroll/pkg/either" + "github.com/pokt-network/poktroll/testutil/mockclient" ) // NewOneTimeMockConnAndDialer returns a new mock connection and mock dialer that diff --git a/internal/testclient/testeventsquery/godoc.go b/testutil/testclient/testeventsquery/godoc.go similarity index 100% rename from internal/testclient/testeventsquery/godoc.go rename to testutil/testclient/testeventsquery/godoc.go diff --git a/internal/testclient/testkeyring/keyring.go b/testutil/testclient/testkeyring/keyring.go similarity index 88% rename from internal/testclient/testkeyring/keyring.go rename to testutil/testclient/testkeyring/keyring.go index 40fbc64c8..bb83baf88 100644 --- a/internal/testclient/testkeyring/keyring.go +++ b/testutil/testclient/testkeyring/keyring.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/pokt-network/poktroll/internal/testclient" + "github.com/pokt-network/poktroll/testutil/testclient" ) // NewTestKeyringWithKey creates a new in-memory keyring with a test key diff --git a/internal/testclient/testsupplier/client.go b/testutil/testclient/testsupplier/client.go similarity index 93% rename from internal/testclient/testsupplier/client.go rename to testutil/testclient/testsupplier/client.go index be5df6507..f5ee73969 100644 --- a/internal/testclient/testsupplier/client.go +++ b/testutil/testclient/testsupplier/client.go @@ -6,10 +6,10 @@ import ( "cosmossdk.io/depinject" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/testclient/testtx" "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/client/supplier" "github.com/pokt-network/poktroll/pkg/client/tx" + "github.com/pokt-network/poktroll/testutil/testclient/testtx" ) // NewLocalnetClient creates and returns a new supplier client that connects to diff --git a/internal/testclient/testtx/client.go b/testutil/testclient/testtx/client.go similarity index 93% rename from internal/testclient/testtx/client.go rename to testutil/testclient/testtx/client.go index 3e843dd91..496c99023 100644 --- a/internal/testclient/testtx/client.go +++ b/testutil/testclient/testtx/client.go @@ -10,12 +10,13 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/mocks/mockclient" - "github.com/pokt-network/poktroll/internal/testclient/testblock" - "github.com/pokt-network/poktroll/internal/testclient/testeventsquery" + "github.com/pokt-network/poktroll/testutil/mockclient" + "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/client/tx" "github.com/pokt-network/poktroll/pkg/either" + "github.com/pokt-network/poktroll/testutil/testclient/testblock" + "github.com/pokt-network/poktroll/testutil/testclient/testeventsquery" ) type signAndBroadcastFn func(context.Context, cosmostypes.Msg) either.AsyncError diff --git a/internal/testclient/testtx/context.go b/testutil/testclient/testtx/context.go similarity index 98% rename from internal/testclient/testtx/context.go rename to testutil/testclient/testtx/context.go index 134d7b2c4..35b3dfb71 100644 --- a/internal/testclient/testtx/context.go +++ b/testutil/testclient/testtx/context.go @@ -17,10 +17,11 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/internal/mocks/mockclient" - "github.com/pokt-network/poktroll/internal/testclient" + "github.com/pokt-network/poktroll/testutil/mockclient" + "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/client/tx" + "github.com/pokt-network/poktroll/testutil/testclient" ) // NewLocalnetContext creates and returns a new transaction context configured diff --git a/internal/testerrors/require.go b/testutil/testerrors/require.go similarity index 100% rename from internal/testerrors/require.go rename to testutil/testerrors/require.go From afa624f928d5a7e4300862b3c0cbe66c2b5fe874 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 7 Nov 2023 14:59:10 -0800 Subject: [PATCH 17/40] Tend to review comments --- docs/static/openapi.yml | 57 +++++++++++++++++++-------- go.mod | 4 +- proto/pocket/supplier/claim.proto | 8 ++-- proto/pocket/supplier/genesis.proto | 1 + proto/pocket/supplier/query.proto | 26 ++++++------ x/supplier/client/cli/query_claim.go | 2 +- x/supplier/genesis.go | 2 +- x/supplier/keeper/claim.go | 4 +- x/supplier/keeper/claim_test.go | 13 +++--- x/supplier/keeper/query_claim.go | 2 +- x/supplier/keeper/query_claim_test.go | 15 +++---- 11 files changed, 79 insertions(+), 55 deletions(-) diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 45155d6e5..44bbb46d6 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -47432,7 +47432,7 @@ paths: - Query /pocket/supplier/claim: get: - operationId: PocketSupplierClaimAll + operationId: PocketSupplierAllClaims responses: '200': description: A successful response. @@ -47446,12 +47446,17 @@ paths: properties: index: type: string - supplierAddress: + supplier_address: type: string - sessionId: + session_id: type: string - rootHash: + root_hash: type: string + description: >- + TODO_UPNEXT(@Olshansk): The structure below is the default + (untouched) scaffolded type. Update + + and productionize it for our use case. pagination: type: object properties: @@ -47572,12 +47577,17 @@ paths: properties: index: type: string - supplierAddress: + supplier_address: type: string - sessionId: + session_id: type: string - rootHash: + root_hash: type: string + description: >- + TODO_UPNEXT(@Olshansk): The structure below is the default + (untouched) scaffolded type. Update + + and productionize it for our use case. default: description: An unexpected error response. schema: @@ -78042,12 +78052,17 @@ definitions: properties: index: type: string - supplierAddress: + supplier_address: type: string - sessionId: + session_id: type: string - rootHash: + root_hash: type: string + description: >- + TODO_UPNEXT(@Olshansk): The structure below is the default (untouched) + scaffolded type. Update + + and productionize it for our use case. pocket.supplier.MsgCreateClaimResponse: type: object pocket.supplier.MsgStakeSupplierResponse: @@ -78069,12 +78084,17 @@ definitions: properties: index: type: string - supplierAddress: + supplier_address: type: string - sessionId: + session_id: type: string - rootHash: + root_hash: type: string + description: >- + TODO_UPNEXT(@Olshansk): The structure below is the default + (untouched) scaffolded type. Update + + and productionize it for our use case. pagination: type: object properties: @@ -78255,12 +78275,17 @@ definitions: properties: index: type: string - supplierAddress: + supplier_address: type: string - sessionId: + session_id: type: string - rootHash: + root_hash: type: string + description: >- + TODO_UPNEXT(@Olshansk): The structure below is the default (untouched) + scaffolded type. Update + + and productionize it for our use case. pocket.supplier.QueryGetSupplierResponse: type: object properties: diff --git a/go.mod b/go.mod index a8ef04265..63e3b8cd4 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -27,6 +28,7 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -70,7 +72,6 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -266,7 +267,6 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/proto/pocket/supplier/claim.proto b/proto/pocket/supplier/claim.proto index 2368c5072..d58a266df 100644 --- a/proto/pocket/supplier/claim.proto +++ b/proto/pocket/supplier/claim.proto @@ -3,11 +3,13 @@ package pocket.supplier; option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; +// TODO_UPNEXT(@Olshansk): The structure below is the default (untouched) scaffolded type. Update +// and productionize it for our use case. message Claim { string index = 1; - string supplierAddress = 2; - string sessionId = 3; - string rootHash = 4; + string supplier_address = 2; + string session_id = 3; + string root_hash = 4; } diff --git a/proto/pocket/supplier/genesis.proto b/proto/pocket/supplier/genesis.proto index cdf8fb554..b8f184ef9 100644 --- a/proto/pocket/supplier/genesis.proto +++ b/proto/pocket/supplier/genesis.proto @@ -13,6 +13,7 @@ option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; message GenesisState { Params params = 1 [(gogoproto.nullable) = false]; repeated pocket.shared.Supplier supplierList = 2 [(gogoproto.nullable) = false]; + // TODO_UPNEXT(@Olshansk): Delete `claimList` from the genesis state. repeated Claim claimList = 3 [(gogoproto.nullable) = false]; } diff --git a/proto/pocket/supplier/query.proto b/proto/pocket/supplier/query.proto index 1ee03c516..98853686f 100644 --- a/proto/pocket/supplier/query.proto +++ b/proto/pocket/supplier/query.proto @@ -13,31 +13,31 @@ option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; // Query defines the gRPC querier service. service Query { - + // Parameters queries the parameters of the module. rpc Params (QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/pocket/supplier/params"; - + } - + // Queries a list of Supplier items. - rpc Supplier (QueryGetSupplierRequest) returns (QueryGetSupplierResponse) { + rpc Supplier (QueryGetSupplierRequest) returns (QueryGetSupplierResponse) { option (google.api.http).get = "/pocket/supplier/supplier/{address}"; - + } rpc SupplierAll (QueryAllSupplierRequest) returns (QueryAllSupplierResponse) { option (google.api.http).get = "/pocket/supplier/supplier"; - + } - + // Queries a list of Claim items. - rpc Claim (QueryGetClaimRequest) returns (QueryGetClaimResponse) { + rpc Claim (QueryGetClaimRequest) returns (QueryGetClaimResponse) { option (google.api.http).get = "/pocket/supplier/claim/{index}"; - + } - rpc ClaimAll (QueryAllClaimRequest) returns (QueryAllClaimResponse) { + rpc AllClaims (QueryAllClaimRequest) returns (QueryAllClaimResponse) { option (google.api.http).get = "/pocket/supplier/claim"; - + } } // QueryParamsRequest is request type for the Query/Params RPC method. @@ -45,7 +45,6 @@ message QueryParamsRequest {} // QueryParamsResponse is response type for the Query/Params RPC method. message QueryParamsResponse { - // params holds all the parameters of this module. Params params = 1 [(gogoproto.nullable) = false]; } @@ -82,5 +81,4 @@ message QueryAllClaimRequest { message QueryAllClaimResponse { repeated Claim claim = 1 [(gogoproto.nullable) = false]; cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - +} \ No newline at end of file diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 20c9047ef..06e0f30e9 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -30,7 +30,7 @@ func CmdListClaim() *cobra.Command { Pagination: pageReq, } - res, err := queryClient.ClaimAll(cmd.Context(), params) + res, err := queryClient.AllClaims(cmd.Context(), params) if err != nil { return err } diff --git a/x/supplier/genesis.go b/x/supplier/genesis.go index feb23355f..f517fa576 100644 --- a/x/supplier/genesis.go +++ b/x/supplier/genesis.go @@ -27,7 +27,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.Params = k.GetParams(ctx) genesis.SupplierList = k.GetAllSupplier(ctx) - genesis.ClaimList = k.GetAllClaim(ctx) + genesis.ClaimList = k.GetAllClaims(ctx) // this line is used by starport scaffolding # genesis/module/export return genesis diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index cf847cd71..db6f627b4 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -47,8 +47,8 @@ func (k Keeper) RemoveClaim( )) } -// GetAllClaim returns all claim -func (k Keeper) GetAllClaim(ctx sdk.Context) (list []types.Claim) { +// GetAllClaims returns all claim +func (k Keeper) GetAllClaims(ctx sdk.Context) (list []types.Claim) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go index 93ae0df40..9b6ba4c31 100644 --- a/x/supplier/keeper/claim_test.go +++ b/x/supplier/keeper/claim_test.go @@ -5,17 +5,18 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + keepertest "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/nullify" "github.com/pokt-network/poktroll/x/supplier/keeper" "github.com/pokt-network/poktroll/x/supplier/types" - "github.com/stretchr/testify/require" ) // Prevent strconv unused error var _ = strconv.IntSize -func createNClaim(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim { +func createNClaims(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim { items := make([]types.Claim, n) for i := range items { items[i].Index = strconv.Itoa(i) @@ -27,7 +28,7 @@ func createNClaim(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim { func TestClaimGet(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) - items := createNClaim(keeper, ctx, 10) + items := createNClaims(keeper, ctx, 10) for _, item := range items { rst, found := keeper.GetClaim(ctx, item.Index, @@ -41,7 +42,7 @@ func TestClaimGet(t *testing.T) { } func TestClaimRemove(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) - items := createNClaim(keeper, ctx, 10) + items := createNClaims(keeper, ctx, 10) for _, item := range items { keeper.RemoveClaim(ctx, item.Index, @@ -55,9 +56,9 @@ func TestClaimRemove(t *testing.T) { func TestClaimGetAll(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) - items := createNClaim(keeper, ctx, 10) + items := createNClaims(keeper, ctx, 10) require.ElementsMatch(t, nullify.Fill(items), - nullify.Fill(keeper.GetAllClaim(ctx)), + nullify.Fill(keeper.GetAllClaims(ctx)), ) } diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index d4d8e3542..9c11710f4 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -12,7 +12,7 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -func (k Keeper) ClaimAll(goCtx context.Context, req *types.QueryAllClaimRequest) (*types.QueryAllClaimResponse, error) { +func (k Keeper) AllClaims(goCtx context.Context, req *types.QueryAllClaimRequest) (*types.QueryAllClaimResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index 3ec5d0ec0..ff0e8af91 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -15,13 +15,10 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -// Prevent strconv unused error -var _ = strconv.IntSize - func TestClaimQuerySingle(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) wctx := sdk.WrapSDKContext(ctx) - msgs := createNClaim(keeper, ctx, 2) + msgs := createNClaims(keeper, ctx, 2) tests := []struct { desc string request *types.QueryGetClaimRequest @@ -73,7 +70,7 @@ func TestClaimQuerySingle(t *testing.T) { func TestClaimQueryPaginated(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) wctx := sdk.WrapSDKContext(ctx) - msgs := createNClaim(keeper, ctx, 5) + msgs := createNClaims(keeper, ctx, 5) request := func(next []byte, offset, limit uint64, total bool) *types.QueryAllClaimRequest { return &types.QueryAllClaimRequest{ @@ -88,7 +85,7 @@ func TestClaimQueryPaginated(t *testing.T) { t.Run("ByOffset", func(t *testing.T) { step := 2 for i := 0; i < len(msgs); i += step { - resp, err := keeper.ClaimAll(wctx, request(nil, uint64(i), uint64(step), false)) + resp, err := keeper.AllClaims(wctx, request(nil, uint64(i), uint64(step), false)) require.NoError(t, err) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, @@ -101,7 +98,7 @@ func TestClaimQueryPaginated(t *testing.T) { step := 2 var next []byte for i := 0; i < len(msgs); i += step { - resp, err := keeper.ClaimAll(wctx, request(next, 0, uint64(step), false)) + resp, err := keeper.AllClaims(wctx, request(next, 0, uint64(step), false)) require.NoError(t, err) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, @@ -112,7 +109,7 @@ func TestClaimQueryPaginated(t *testing.T) { } }) t.Run("Total", func(t *testing.T) { - resp, err := keeper.ClaimAll(wctx, request(nil, 0, 0, true)) + resp, err := keeper.AllClaims(wctx, request(nil, 0, 0, true)) require.NoError(t, err) require.Equal(t, len(msgs), int(resp.Pagination.Total)) require.ElementsMatch(t, @@ -121,7 +118,7 @@ func TestClaimQueryPaginated(t *testing.T) { ) }) t.Run("InvalidRequest", func(t *testing.T) { - _, err := keeper.ClaimAll(wctx, nil) + _, err := keeper.AllClaims(wctx, nil) require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request")) }) } From ca62bb2b633603273be93ab3b0c60bfd25b082cd Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 7 Nov 2023 15:19:45 -0800 Subject: [PATCH 18/40] Fixing whitespace --- go.mod | 4 ++-- proto/pocket/application/query.proto | 3 --- proto/pocket/gateway/query.proto | 5 +---- proto/pocket/session/query.proto | 2 -- proto/pocket/supplier/claim.proto | 1 - proto/pocket/supplier/query.proto | 5 ----- x/supplier/client/cli/query_claim.go | 7 ++++++- x/supplier/client/cli/query_claim_test.go | 3 --- 8 files changed, 9 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index a8ef04265..63e3b8cd4 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -27,6 +28,7 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -70,7 +72,6 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -266,7 +267,6 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/proto/pocket/application/query.proto b/proto/pocket/application/query.proto index 28a48fb99..949ed3a07 100644 --- a/proto/pocket/application/query.proto +++ b/proto/pocket/application/query.proto @@ -16,17 +16,14 @@ service Query { // Parameters queries the parameters of the module. rpc Params (QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/pocket/application/params"; - } // Queries a list of Application items. rpc Application (QueryGetApplicationRequest) returns (QueryGetApplicationResponse) { option (google.api.http).get = "/pocket/application/application/{address}"; - } rpc ApplicationAll (QueryAllApplicationRequest) returns (QueryAllApplicationResponse) { option (google.api.http).get = "/pocket/application/application"; - } } // QueryParamsRequest is request type for the Query/Params RPC method. diff --git a/proto/pocket/gateway/query.proto b/proto/pocket/gateway/query.proto index 48bd62f98..91080554d 100644 --- a/proto/pocket/gateway/query.proto +++ b/proto/pocket/gateway/query.proto @@ -16,17 +16,14 @@ service Query { // Parameters queries the parameters of the module. rpc Params (QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/pocket/gateway/params"; - } // Queries a list of Gateway items. - rpc Gateway (QueryGetGatewayRequest) returns (QueryGetGatewayResponse) { + rpc Gateway (QueryGetGatewayRequest) returns (QueryGetGatewayResponse) { option (google.api.http).get = "/pocket/gateway/gateway/{address}"; - } rpc GatewayAll (QueryAllGatewayRequest) returns (QueryAllGatewayResponse) { option (google.api.http).get = "/pocket/gateway/gateway"; - } } // QueryParamsRequest is request type for the Query/Params RPC method. diff --git a/proto/pocket/session/query.proto b/proto/pocket/session/query.proto index f8b1c7187..8bd3ab2aa 100644 --- a/proto/pocket/session/query.proto +++ b/proto/pocket/session/query.proto @@ -17,13 +17,11 @@ service Query { // Parameters queries the parameters of the module. rpc Params (QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/pocket/session/params"; - } // Queries a list of GetSession items. rpc GetSession (QueryGetSessionRequest) returns (QueryGetSessionResponse) { option (google.api.http).get = "/pocket/session/get_session"; - } } // QueryParamsRequest is request type for the Query/Params RPC method. diff --git a/proto/pocket/supplier/claim.proto b/proto/pocket/supplier/claim.proto index d58a266df..c0c293083 100644 --- a/proto/pocket/supplier/claim.proto +++ b/proto/pocket/supplier/claim.proto @@ -10,6 +10,5 @@ message Claim { string supplier_address = 2; string session_id = 3; string root_hash = 4; - } diff --git a/proto/pocket/supplier/query.proto b/proto/pocket/supplier/query.proto index 98853686f..bf1954ca3 100644 --- a/proto/pocket/supplier/query.proto +++ b/proto/pocket/supplier/query.proto @@ -17,27 +17,22 @@ service Query { // Parameters queries the parameters of the module. rpc Params (QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/pocket/supplier/params"; - } // Queries a list of Supplier items. rpc Supplier (QueryGetSupplierRequest) returns (QueryGetSupplierResponse) { option (google.api.http).get = "/pocket/supplier/supplier/{address}"; - } rpc SupplierAll (QueryAllSupplierRequest) returns (QueryAllSupplierResponse) { option (google.api.http).get = "/pocket/supplier/supplier"; - } // Queries a list of Claim items. rpc Claim (QueryGetClaimRequest) returns (QueryGetClaimResponse) { option (google.api.http).get = "/pocket/supplier/claim/{index}"; - } rpc AllClaims (QueryAllClaimRequest) returns (QueryAllClaimResponse) { option (google.api.http).get = "/pocket/supplier/claim"; - } } // QueryParamsRequest is request type for the Query/Params RPC method. diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 06e0f30e9..324840a02 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -1,6 +1,8 @@ package cli import ( + "strconv" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" @@ -8,11 +10,14 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) +// Prevent strconv unused error +var _ = strconv.IntSize + func CmdListClaim() *cobra.Command { cmd := &cobra.Command{ Use: "list-claim", Short: "list all claims", - Args: cobra.NoArgs(), + Args: cobra.NoArgs(), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 9ca4fb9f6..b6f7d4b8e 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -18,9 +18,6 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -// Prevent strconv unused error -var _ = strconv.IntSize - func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Claim) { t.Helper() cfg := network.DefaultConfig() From 15b5fb32840bced74da258628a2d45f1a8a600b2 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 7 Nov 2023 15:28:45 -0800 Subject: [PATCH 19/40] Fixed the last broken test --- go.mod | 4 ++-- x/supplier/client/cli/query_claim.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 63e3b8cd4..a8ef04265 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -28,7 +27,6 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -72,6 +70,7 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -267,6 +266,7 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 324840a02..eaa0cae66 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -17,7 +17,7 @@ func CmdListClaim() *cobra.Command { cmd := &cobra.Command{ Use: "list-claim", Short: "list all claims", - Args: cobra.NoArgs(), + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { From f488ec5a5ef0ddfe68f6414b66911459159df7c0 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 7 Nov 2023 17:36:34 -0800 Subject: [PATCH 20/40] Cleaned up the code enough so it compiles w/ a secondary index but still a WIP --- Makefile | 16 ++++ go.mod | 4 +- x/supplier/keeper/claim.go | 175 +++++++++------------------------- x/supplier/types/key_claim.go | 19 +++- 4 files changed, 80 insertions(+), 134 deletions(-) diff --git a/Makefile b/Makefile index 19c8fe59e..101131666 100644 --- a/Makefile +++ b/Makefile @@ -407,6 +407,22 @@ acc_balance_query_app1: ## Query the balance of app1 acc_balance_total_supply: ## Query the total supply of the network poktrolld --home=$(POCKETD_HOME) q bank total --node $(POCKET_NODE) +############## +### Claims ### +############## + +.PHONY: claim_list +claim_list: ## List all the claims + poktrolld --home=$(POCKETD_HOME) q claim list-claims --node $(POCKET_NODE) + +.PHONY: claim_list_address +claim_list_address: ## List all the claims for a specific address (make claim_list_address ADDR=pokt...) + poktrolld --home=$(POCKETD_HOME) q claim list-claims $(ADDR) --node $(POCKET_NODE) + +.PHONY: claim_list_height +claim_list_height: ## List all the claims for a specific height (make claim_list_height HEIGHT=...) + poktrolld --home=$(POCKETD_HOME) q claim list-claims --height $(HEIGHT) --node $(POCKET_NODE) + ###################### ### Ignite Helpers ### ###################### diff --git a/go.mod b/go.mod index 63e3b8cd4..a8ef04265 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -28,7 +27,6 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -72,6 +70,7 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -267,6 +266,7 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index c9b66e03c..d341f649b 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -1,178 +1,97 @@ package keeper import ( + "encoding/binary" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/poktroll/x/supplier/types" ) -// InsertClaim set a specific a claim given a sessionId & supplierAddr +// InsertClaim adds a claim to the store func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { claimBz := k.cdc.MustMarshal(&claim) parentStore := ctx.KVStore(k.storeKey) - // Store the whole claim in the primary key store + // Update the primary store - primaryStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) - primaryKey := types.ClaimPrimaryKey(claim) + primaryKey := types.ClaimPrimaryKey(claim.SessionId, claim.SupplierAddress) primaryStore.Set(primaryKey, claimBz) - // Save the claim in the main claim store with primary key - // primaryStore := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("claim")) - // primaryStore.Set(claim.PrimaryKey(), claim.Marshal()) + // Update the session index + // TODO - // Store the param - // heightStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimHeightPrefix)) - // heightKey := HeightKey(claim.Height) // Serialize height into a byte slice if needed - // heightStore.Set(heightKey, claim.PrimaryKey()) + // Update the height index + // TODO - // Index by address - addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimHeightPrefix)) - addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress) + // Update the address index + addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimAddressPrefix)) + addressClaimCount := k.getCount(ctx, addressStoreIndex) + addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, addressClaimCount) addressStoreIndex.Set(addressKey, primaryKey) - - // ClaimHeightPrefix - // ClaimAddressPrefix - // ClaimSessionIdPrefix - + k.setCount(ctx, addressStoreIndex, addressClaimCount+1) } // GetClaim returns a claim given a sessionId & supplierAddr -func (k Keeper) GetClaim( - ctx sdk.Context, - sessionId, supplierAddr string, - -) (val types.Claim, found bool) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) - - b := store.Get(types.ClaimKey( - sessionId, supplierAddr, - )) - if b == nil { - return val, false - } - - k.cdc.MustUnmarshal(b, &val) - return val, true +func (k Keeper) GetClaim(ctx sdk.Context, sessionId, supplierAddr string) (val types.Claim, found bool) { + primaryKey := types.ClaimPrimaryKey(sessionId, supplierAddr) + return k.getClaimByPrimaryKey(ctx, primaryKey) } -// RemoveClaim removes a claim from the store -// func (k Keeper) RemoveClaim( -// ctx sdk.Context, -// supplierAddr string, -// sessionId, - -// ) { -// store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) -// store.Delete(types.ClaimKey( -// sessionId, supplierAddr, -// )) -// } - // GetAllClaims returns all claim -func (k Keeper) GetAllClaims(ctx sdk.Context) (list []types.Claim) { +func (k Keeper) GetAllClaims(ctx sdk.Context) (claims []types.Claim) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var val types.Claim k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) + claims = append(claims, val) } return } -// When retrieving by height: -// func (k Keeper) GetClaimsByHeight(ctx sdk.Context, height int64) []Claim { -// heightStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimHeightPrefix)) -// heightKey := HeightKey(height) // Serialize height into a byte slice if needed - -// // Iterate over the height index store using heightKey -// iterator := sdk.KVStorePrefixIterator(heightStore, heightKey) -// defer iterator.Close() - -// var claims []Claim -// for ; iterator.Valid(); iterator.Next() { -// primaryKey := iterator.Value() -// claim := GetClaimByPrimaryKey(ctx, claimStoreKey, primaryKey) -// claims = append(claims, claim) -// } - -// return claims -// } - // When retrieving by address: -func (k Keeper) GetClaimsByAddress(ctx sdk.Context, address sdk.AccAddress) []Claim { - addressStore := prefix.NewStore(ctx.KVStore(addressIndexStoreKey), types.KeyPrefix(types.ClaimAddressPrefix)) - addressKey := AddressKey(address) // Serialize address into a byte slice if needed +func (k Keeper) GetClaimsByAddress(ctx sdk.Context, address sdk.AccAddress) (claims []types.Claim) { + addressStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimAddressPrefix)) - // Iterate over the address index store using addressKey - iterator := sdk.KVStorePrefixIterator(addressStore, addressKey) + iterator := sdk.KVStorePrefixIterator(addressStore, []byte(address)) defer iterator.Close() - var claims []Claim for ; iterator.Valid(); iterator.Next() { primaryKey := iterator.Value() - claim := GetClaimByPrimaryKey(ctx, claimStoreKey, primaryKey) - claims = append(claims, claim) + claim, claimFound := k.getClaimByPrimaryKey(ctx, primaryKey) + if claimFound { + claims = append(claims, claim) + } } return claims } -// // Helper function to get a claim by primary key: -func GetClaimByPrimaryKey(ctx sdk.Context, claimStoreKey sdk.StoreKey, primaryKey []byte) Claim { - primaryStore := prefix.NewStore(ctx.KVStore(claimStoreKey), []byte("claim")) - byteClaim := primaryStore.Get(primaryKey) - var claim Claim - claim.Unmarshal(byteClaim) // Unmarshal byte slice into Claim object - return claim +func (k Keeper) getClaimByPrimaryKey(ctx sdk.Context, primaryKey []byte) (val types.Claim, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + b := store.Get(primaryKey) + if b == nil { + return val, false + } + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +func (k Keeper) getCount(ctx sdk.Context, store prefix.Store) uint64 { + bz := store.Get(types.CountKey) + if bz == nil { + return 0 // Count doesn't exist: no element + } + return binary.BigEndian.Uint64(bz) } -// GetOlshCount get the total number of olsh -// func (k Keeper) GetOlshCount(ctx sdk.Context) uint64 { -// store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{}) -// byteKey := types.KeyPrefix(types.OlshCountKey) -// bz := store.Get(byteKey) - -// // Count doesn't exist: no element -// if bz == nil { -// return 0 -// } - -// // Parse bytes -// return binary.BigEndian.Uint64(bz) -// } - -// // SetOlshCount set the total number of olsh -// func (k Keeper) SetOlshCount(ctx sdk.Context, count uint64) { -// store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{}) -// byteKey := types.KeyPrefix(types.OlshCountKey) -// bz := make([]byte, 8) -// binary.BigEndian.PutUint64(bz, count) -// store.Set(byteKey, bz) -// } - -// // AppendOlsh appends a olsh in the store with a new id and update the count -// func (k Keeper) AppendOlsh( -// ctx sdk.Context, -// olsh types.Olsh, -// ) uint64 { -// // Create the olsh -// count := k.GetOlshCount(ctx) - -// // Set the ID of the appended value -// olsh.Id = count - -// store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.OlshKey)) -// appendedValue := k.cdc.MustMarshal(&olsh) -// store.Set(GetOlshIDBytes(olsh.Id), appendedValue) - -// // Update olsh count -// k.SetOlshCount(ctx, count+1) - -// return count -// } +func (k Keeper) setCount(ctx sdk.Context, store prefix.Store, count uint64) { + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, count) + store.Set(types.CountKey, bz) +} diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go index ea1e83d26..64823ca36 100644 --- a/x/supplier/types/key_claim.go +++ b/x/supplier/types/key_claim.go @@ -6,7 +6,12 @@ import ( var _ binary.ByteOrder +var ( + CountKey = KeyPrefix("count") +) + const ( + // ClaimPrimaryKeyPrefix is the prefix to retrieve all Claim (the primary store) ClaimPrimaryKeyPrefix = "Claim/value/" @@ -21,23 +26,29 @@ const ( ) // ClaimPrimaryKey returns the primary store key to retrieve a Claim -func ClaimPrimaryKey(claim Claim) []byte { +func ClaimPrimaryKey(sessionId, supplierAddr string) []byte { var key []byte // We are guaranteed uniqueness of the primary key if it's a composite of the (sessionId, supplierAddr) - key = append(key, []byte(claim.SessionId)...) + // because every supplier can only have one claim per session. + key = append(key, []byte(sessionId)...) key = append(key, []byte("/")...) - key = append(key, []byte(claim.SupplierAddress)...) + key = append(key, []byte(supplierAddr)...) key = append(key, []byte("/")...) return key } // ClaimSupplierAddressKey returns the address key to iterate through claims given a supplier Address -func ClaimSupplierAddressKey(supplierAddr string) []byte { +func ClaimSupplierAddressKey(supplierAddr string, claimNum uint64) []byte { var key []byte + numBz := make([]byte, 8) + binary.BigEndian.PutUint64(numBz, claimNum) + key = append(key, []byte(supplierAddr)...) + key = append(key, []byte("/num/")...) + key = append(key, numBz...) key = append(key, []byte("/")...) return key From bc33dda11004f92c516a8e6e1ec42f16347f42dc Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 9 Nov 2023 13:45:40 -0800 Subject: [PATCH 21/40] Non-funtional snapshot --- proto/pocket/supplier/genesis.proto | 2 -- proto/pocket/supplier/query.proto | 2 +- x/supplier/genesis.go | 5 ----- x/supplier/genesis_test.go | 9 --------- x/supplier/keeper/query_claim.go | 2 +- x/supplier/types/genesis.go | 11 ----------- x/supplier/types/genesis_test.go | 22 ---------------------- 7 files changed, 2 insertions(+), 51 deletions(-) diff --git a/proto/pocket/supplier/genesis.proto b/proto/pocket/supplier/genesis.proto index b8f184ef9..a35a4a994 100644 --- a/proto/pocket/supplier/genesis.proto +++ b/proto/pocket/supplier/genesis.proto @@ -13,7 +13,5 @@ option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; message GenesisState { Params params = 1 [(gogoproto.nullable) = false]; repeated pocket.shared.Supplier supplierList = 2 [(gogoproto.nullable) = false]; - // TODO_UPNEXT(@Olshansk): Delete `claimList` from the genesis state. - repeated Claim claimList = 3 [(gogoproto.nullable) = false]; } diff --git a/proto/pocket/supplier/query.proto b/proto/pocket/supplier/query.proto index 8e15e041a..401165ee7 100644 --- a/proto/pocket/supplier/query.proto +++ b/proto/pocket/supplier/query.proto @@ -62,7 +62,7 @@ message QueryAllSupplierResponse { } message QueryGetClaimRequest { - string index = 1; + string supplier_address = 1; } message QueryGetClaimResponse { diff --git a/x/supplier/genesis.go b/x/supplier/genesis.go index bda688fb9..156d80118 100644 --- a/x/supplier/genesis.go +++ b/x/supplier/genesis.go @@ -14,10 +14,6 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) for _, supplier := range genState.SupplierList { k.SetSupplier(ctx, supplier) } - // Set all the claim - for _, elem := range genState.ClaimList { - k.SetClaim(ctx, elem) - } // this line is used by starport scaffolding # genesis/module/init k.SetParams(ctx, genState.Params) } @@ -28,7 +24,6 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.Params = k.GetParams(ctx) genesis.SupplierList = k.GetAllSupplier(ctx) - genesis.ClaimList = k.GetAllClaims(ctx) // this line is used by starport scaffolding # genesis/module/export return genesis diff --git a/x/supplier/genesis_test.go b/x/supplier/genesis_test.go index 3afdd0a8a..ba9b521f8 100644 --- a/x/supplier/genesis_test.go +++ b/x/supplier/genesis_test.go @@ -56,14 +56,6 @@ func TestGenesis(t *testing.T) { }, }, }, - ClaimList: []types.Claim{ - { - Index: "0", - }, - { - Index: "1", - }, - }, // this line is used by starport scaffolding # genesis/test/state } @@ -76,6 +68,5 @@ func TestGenesis(t *testing.T) { nullify.Fill(got) require.ElementsMatch(t, genesisState.SupplierList, got.SupplierList) - require.ElementsMatch(t, genesisState.ClaimList, got.ClaimList) // this line is used by starport scaffolding # genesis/test/assert } diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 47167fbfa..9825587fc 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -48,7 +48,7 @@ func (k Keeper) Claim(goCtx context.Context, req *types.QueryGetClaimRequest) (* val, found := k.GetClaim( ctx, - req.Index, + req.Index ) if !found { return nil, status.Error(codes.NotFound, "not found") diff --git a/x/supplier/types/genesis.go b/x/supplier/types/genesis.go index 521bfdc0d..b68751dcd 100644 --- a/x/supplier/types/genesis.go +++ b/x/supplier/types/genesis.go @@ -17,7 +17,6 @@ const DefaultIndex uint64 = 1 func DefaultGenesis() *GenesisState { return &GenesisState{ SupplierList: []sharedtypes.Supplier{}, - ClaimList: []Claim{}, // this line is used by starport scaffolding # genesis/types/default Params: DefaultParams(), } @@ -63,16 +62,6 @@ func (gs GenesisState) Validate() error { } } - // Check for duplicated index in claim - claimIndexMap := make(map[string]struct{}) - - for _, elem := range gs.ClaimList { - index := string(ClaimKey(elem.Index)) - if _, ok := claimIndexMap[index]; ok { - return fmt.Errorf("duplicated index for claim") - } - claimIndexMap[index] = struct{}{} - } // this line is used by starport scaffolding # genesis/types/validate return gs.Params.Validate() diff --git a/x/supplier/types/genesis_test.go b/x/supplier/types/genesis_test.go index 6a0c11190..5625fa435 100644 --- a/x/supplier/types/genesis_test.go +++ b/x/supplier/types/genesis_test.go @@ -70,14 +70,6 @@ func TestGenesisState_Validate(t *testing.T) { Services: serviceList2, }, }, - ClaimList: []types.Claim{ - { - Index: "0", - }, - { - Index: "1", - }, - }, // this line is used by starport scaffolding # types/genesis/validField }, valid: true, @@ -306,20 +298,6 @@ func TestGenesisState_Validate(t *testing.T) { }, valid: false, }, - { - desc: "duplicated claim", - genState: &types.GenesisState{ - ClaimList: []types.Claim{ - { - Index: "0", - }, - { - Index: "0", - }, - }, - }, - valid: false, - }, // this line is used by starport scaffolding # types/genesis/testcase } for _, tc := range tests { From 746d765d208f6aa2631c97fb3526bbf8473388a3 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 9 Nov 2023 18:00:48 -0800 Subject: [PATCH 22/40] Unit tests are passing but more work ahead --- .gitignore | 7 + docs/static/openapi.yml | 373 ++++++++++++----------- proto/pocket/supplier/genesis.proto | 1 - proto/pocket/supplier/query.proto | 14 +- x/supplier/client/cli/query.go | 2 +- x/supplier/client/cli/query_claim.go | 35 ++- x/supplier/keeper/claim.go | 127 +++----- x/supplier/keeper/claim_test.go | 7 +- x/supplier/keeper/query_claim.go | 3 +- x/supplier/keeper/query_claim_test.go | 55 +++- x/supplier/types/key_claim.go | 11 +- x/supplier/types/message_create_claim.go | 2 +- x/supplier/types/query_get_claim.go | 19 ++ 13 files changed, 348 insertions(+), 308 deletions(-) create mode 100644 x/supplier/types/query_get_claim.go diff --git a/.gitignore b/.gitignore index 6dbdd3c40..c6e3508f1 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,11 @@ localnet_config.yaml # Relase artifacts produced by `ignite chain build --release` release +# Only keep one go module in our codebase go.work.sum + +# Avoid accidently commiting gomock artifacts +**/gomock_reflect_* + + +gomock_reflect diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 7c5739927..9d23a20d2 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -47427,7 +47427,59 @@ paths: additionalProperties: {} tags: - Query - /pocket/supplier/claim: + /pocket/supplier/claim/{session_id}/{supplier_address}: + get: + summary: Queries a list of Claim items. + operationId: PocketSupplierClaim + responses: + '200': + description: A successful response. + schema: + type: object + properties: + claim: + type: object + properties: + supplier_address: + type: string + title: the address of the supplier that submitted this claims + session_id: + type: string + title: session id from the SessionHeader + root_hash: + type: string + format: byte + title: smt.SMST#Root() + default: + description: An unexpected error response. + schema: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + '@type': + type: string + additionalProperties: {} + parameters: + - name: session_id + in: path + required: true + type: string + - name: supplier_address + in: path + required: true + type: string + tags: + - Query + /pocket/supplier/claims: get: operationId: PocketSupplierAllClaims responses: @@ -47554,31 +47606,37 @@ paths: in: query required: false type: boolean + - name: supplier_address + in: query + required: false + type: string + - name: session_id + in: query + required: false + type: string + - name: session_end_height + in: query + required: false + type: string + format: uint64 tags: - Query - /pocket/supplier/claim/{index}: + /pocket/supplier/params: get: - summary: Queries a list of Claim items. - operationId: PocketSupplierClaim + summary: Parameters queries the parameters of the module. + operationId: PocketSupplierParams responses: '200': description: A successful response. schema: type: object properties: - claim: + params: + description: params holds all the parameters of this module. type: object - properties: - supplier_address: - type: string - title: the address of the supplier that submitted this claims - session_id: - type: string - title: session id from the SessionHeader - root_hash: - type: string - format: byte - title: smt.SMST#Root() + description: >- + QueryParamsResponse is response type for the Query/Params RPC + method. default: description: An unexpected error response. schema: @@ -47597,29 +47655,131 @@ paths: '@type': type: string additionalProperties: {} - parameters: - - name: index - in: path - required: true - type: string tags: - Query - /pocket/supplier/params: + /pocket/supplier/supplier/{address}: get: - summary: Parameters queries the parameters of the module. - operationId: PocketSupplierParams + summary: Queries a list of Supplier items. + operationId: PocketSupplierSupplier responses: '200': description: A successful response. schema: type: object properties: - params: - description: params holds all the parameters of this module. + supplier: type: object - description: >- - QueryParamsResponse is response type for the Query/Params RPC - method. + properties: + address: + type: string + title: >- + The Bech32 address of the supplier using cosmos' + ScalarDescriptor to ensure deterministic encoding + stake: + title: The total amount of uPOKT the supplier has staked + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. + + + NOTE: The amount field is an Int which implements the + custom method + + signatures required by gogoproto. + services: + type: array + items: + type: object + properties: + service: + title: The Service for which the supplier is configured + type: object + properties: + id: + type: string + description: Unique identifier for the service + title: >- + For example, what if we want to request a + session for a certain service but with some + additional configs that identify it? + name: + type: string + description: >- + (Optional) Semantic human readable name for the + service + title: >- + TODO_TECHDEBT: Name is currently unused but acts + as a reminder than an optional onchain + representation of the service is necessary + endpoints: + type: array + items: + type: object + properties: + url: + type: string + title: URL of the endpoint + rpc_type: + title: Type of RPC exposed on the url above + type: string + enum: + - UNKNOWN_RPC + - GRPC + - WEBSOCKET + - JSON_RPC + default: UNKNOWN_RPC + description: |- + - UNKNOWN_RPC: Undefined RPC type + - GRPC: gRPC + - WEBSOCKET: WebSocket + - JSON_RPC: JSON-RPC + configs: + type: array + items: + type: object + properties: + key: + title: Config option key + type: string + enum: + - UNKNOWN_CONFIG + - TIMEOUT + default: UNKNOWN_CONFIG + description: >- + Enum to define configuration options + + TODO_RESEARCH: Should these be configs, + SLAs or something else? There will be + more discussion once we get closer to + implementing on-chain QoS. + + - UNKNOWN_CONFIG: Undefined config option + - TIMEOUT: Timeout setting + value: + type: string + title: Config option value + title: >- + Key-value wrapper for config options, as + proto maps can't be keyed by enums + title: >- + Additional configuration options for the + endpoint + title: >- + SupplierEndpoint message to hold service + configuration details + title: List of endpoints for the service + title: >- + SupplierServiceConfig holds the service configuration + the supplier stakes for + title: The service configs this supplier can support + description: >- + Supplier is the type defining the actor in Pocket Network that + provides RPC services. default: description: An unexpected error response. schema: @@ -47638,9 +47798,14 @@ paths: '@type': type: string additionalProperties: {} + parameters: + - name: address + in: path + required: true + type: string tags: - Query - /pocket/supplier/supplier: + /pocket/supplier/suppliers: get: operationId: PocketSupplierSupplierAll responses: @@ -47869,154 +48034,6 @@ paths: type: boolean tags: - Query - /pocket/supplier/supplier/{address}: - get: - summary: Queries a list of Supplier items. - operationId: PocketSupplierSupplier - responses: - '200': - description: A successful response. - schema: - type: object - properties: - supplier: - type: object - properties: - address: - type: string - title: >- - The Bech32 address of the supplier using cosmos' - ScalarDescriptor to ensure deterministic encoding - stake: - title: The total amount of uPOKT the supplier has staked - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the - custom method - - signatures required by gogoproto. - services: - type: array - items: - type: object - properties: - service: - title: The Service for which the supplier is configured - type: object - properties: - id: - type: string - description: Unique identifier for the service - title: >- - For example, what if we want to request a - session for a certain service but with some - additional configs that identify it? - name: - type: string - description: >- - (Optional) Semantic human readable name for the - service - title: >- - TODO_TECHDEBT: Name is currently unused but acts - as a reminder than an optional onchain - representation of the service is necessary - endpoints: - type: array - items: - type: object - properties: - url: - type: string - title: URL of the endpoint - rpc_type: - title: Type of RPC exposed on the url above - type: string - enum: - - UNKNOWN_RPC - - GRPC - - WEBSOCKET - - JSON_RPC - default: UNKNOWN_RPC - description: |- - - UNKNOWN_RPC: Undefined RPC type - - GRPC: gRPC - - WEBSOCKET: WebSocket - - JSON_RPC: JSON-RPC - configs: - type: array - items: - type: object - properties: - key: - title: Config option key - type: string - enum: - - UNKNOWN_CONFIG - - TIMEOUT - default: UNKNOWN_CONFIG - description: >- - Enum to define configuration options - - TODO_RESEARCH: Should these be configs, - SLAs or something else? There will be - more discussion once we get closer to - implementing on-chain QoS. - - - UNKNOWN_CONFIG: Undefined config option - - TIMEOUT: Timeout setting - value: - type: string - title: Config option value - title: >- - Key-value wrapper for config options, as - proto maps can't be keyed by enums - title: >- - Additional configuration options for the - endpoint - title: >- - SupplierEndpoint message to hold service - configuration details - title: List of endpoints for the service - title: >- - SupplierServiceConfig holds the service configuration - the supplier stakes for - title: The service configs this supplier can support - description: >- - Supplier is the type defining the actor in Pocket Network that - provides RPC services. - default: - description: An unexpected error response. - schema: - type: object - properties: - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - '@type': - type: string - additionalProperties: {} - parameters: - - name: address - in: path - required: true - type: string - tags: - - Query definitions: cosmos.auth.v1beta1.AddressBytesToStringResponse: type: object diff --git a/proto/pocket/supplier/genesis.proto b/proto/pocket/supplier/genesis.proto index a35a4a994..5bba7baea 100644 --- a/proto/pocket/supplier/genesis.proto +++ b/proto/pocket/supplier/genesis.proto @@ -5,7 +5,6 @@ package pocket.supplier; import "gogoproto/gogo.proto"; import "pocket/supplier/params.proto"; import "pocket/shared/supplier.proto"; -import "pocket/supplier/claim.proto"; option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; diff --git a/proto/pocket/supplier/query.proto b/proto/pocket/supplier/query.proto index 401165ee7..fdc90a4c2 100644 --- a/proto/pocket/supplier/query.proto +++ b/proto/pocket/supplier/query.proto @@ -24,15 +24,15 @@ service Query { option (google.api.http).get = "/pocket/supplier/supplier/{address}"; } rpc SupplierAll (QueryAllSupplierRequest) returns (QueryAllSupplierResponse) { - option (google.api.http).get = "/pocket/supplier/supplier"; + option (google.api.http).get = "/pocket/supplier/suppliers"; } // Queries a list of Claim items. rpc Claim (QueryGetClaimRequest) returns (QueryGetClaimResponse) { - option (google.api.http).get = "/pocket/supplier/claim/{index}"; + option (google.api.http).get = "/pocket/supplier/claim/{session_id}/{supplier_address}"; } rpc AllClaims (QueryAllClaimsRequest) returns (QueryAllClaimsResponse) { - option (google.api.http).get = "/pocket/supplier/claim"; + option (google.api.http).get = "/pocket/supplier/claims"; } } // QueryParamsRequest is request type for the Query/Params RPC method. @@ -62,7 +62,8 @@ message QueryAllSupplierResponse { } message QueryGetClaimRequest { - string supplier_address = 1; + string session_id = 1; + string supplier_address = 2; } message QueryGetClaimResponse { @@ -71,6 +72,11 @@ message QueryGetClaimResponse { message QueryAllClaimsRequest { cosmos.base.query.v1beta1.PageRequest pagination = 1; + oneof filter { + string supplier_address = 2; + string session_id = 3; + uint64 session_end_height = 4; + } } message QueryAllClaimsResponse { diff --git a/x/supplier/client/cli/query.go b/x/supplier/client/cli/query.go index f70e996ba..ab7697ac9 100644 --- a/x/supplier/client/cli/query.go +++ b/x/supplier/client/cli/query.go @@ -27,7 +27,7 @@ func GetQueryCmd(queryRoute string) *cobra.Command { cmd.AddCommand(CmdQueryParams()) cmd.AddCommand(CmdListSupplier()) cmd.AddCommand(CmdShowSupplier()) - cmd.AddCommand(CmdListClaim()) + cmd.AddCommand(CmdListClaims()) cmd.AddCommand(CmdShowClaim()) // this line is used by starport scaffolding # 1 diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 7e742a017..ced71ad79 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -13,28 +13,26 @@ import ( // Prevent strconv unused error var _ = strconv.IntSize -func CmdListClaim() *cobra.Command { +func CmdListClaims() *cobra.Command { cmd := &cobra.Command{ Use: "list-claims", Short: "list all claims", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) + pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { return err } + params := &types.QueryAllClaimsRequest{ + Pagination: pageReq, + } - pageReq, err := client.ReadPageRequest(cmd.Flags()) + clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } - queryClient := types.NewQueryClient(clientCtx) - params := &types.QueryAllClaimsRequest{ - Pagination: pageReq, - } - res, err := queryClient.AllClaims(cmd.Context(), params) if err != nil { return err @@ -53,9 +51,20 @@ func CmdListClaim() *cobra.Command { func CmdShowClaim() *cobra.Command { cmd := &cobra.Command{ Use: "show-claim ", - Short: "shows a claim", + Short: "shows a specific claim", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { + sessionId := args[0] + supplierAddr := args[1] + + getClaimRequest := &types.QueryGetClaimRequest{ + SessionId: sessionId, + SupplierAddress: supplierAddr, + } + if err := getClaimRequest.ValidateBasic(); err != nil { + return err + } + clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err @@ -63,13 +72,7 @@ func CmdShowClaim() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) - argIndex := args[0] - - params := &types.QueryGetClaimRequest{ - Index: argIndex, - } - - res, err := queryClient.Claim(cmd.Context(), params) + res, err := queryClient.Claim(cmd.Context(), getClaimRequest) if err != nil { return err } diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 3928cab3a..0be972f4b 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -1,8 +1,6 @@ package keeper import ( - "encoding/binary" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,90 +9,66 @@ import ( // InsertClaim adds a claim to the store func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { + logger := k.Logger(ctx).With("method", "InsertClaim") + claimBz := k.cdc.MustMarshal(&claim) parentStore := ctx.KVStore(k.storeKey) - // Update the primary store - + // Update the primary store: ClaimPrimaryKey -> ClaimObject primaryStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) primaryKey := types.ClaimPrimaryKey(claim.SessionId, claim.SupplierAddress) primaryStore.Set(primaryKey, claimBz) - // Update the session index - // TODO + logger.Info("inserted claim with primaryKey %s", primaryKey) - // Update the height index - // TODO - - // Update the address index + // Update the address index: supplierAddress -> [ClaimPrimaryKey] addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimAddressPrefix)) - addressClaimCount := k.getCount(ctx, addressStoreIndex) - addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, addressClaimCount) + addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, primaryKey) addressStoreIndex.Set(addressKey, primaryKey) - k.setCount(ctx, addressStoreIndex, addressClaimCount+1) + + // TODO: Index by sessionId + // TODO: Index by sessionEndHeight +} + +// RemoveClaim removes a claim from the store +func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + + primaryKey := types.ClaimPrimaryKey(sessionId, supplierAddr) + claim, foundClaim := k.getClaimByPrimaryKey(ctx, primaryKey) + if !foundClaim { + k.Logger(ctx).Error("trying to delete non-existent claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId) + } + + addressStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimAddressPrefix)) + addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, primaryKey) + + addressStore.Delete(addressKey) + store.Delete(primaryKey) } -// GetClaim returns a claim given a sessionId & supplierAddr +// GetClaim returns a Claim given a SessionId & SupplierAddr func (k Keeper) GetClaim(ctx sdk.Context, sessionId, supplierAddr string) (val types.Claim, found bool) { primaryKey := types.ClaimPrimaryKey(sessionId, supplierAddr) return k.getClaimByPrimaryKey(ctx, primaryKey) } -// SetClaim set a specific claim in the store from its index -// func (k Keeper) SetClaim(ctx sdk.Context, claim types.Claim) { -// store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) -// b := k.cdc.MustMarshal(&claim) -// store.Set(types.ClaimKey( -// claim.Index, -// ), b) -// } - -// // GetClaim returns a claim from its index -// func (k Keeper) GetClaim( -// ctx sdk.Context, -// index string, - -// ) (val types.Claim, found bool) { -// store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) - -// b := store.Get(types.ClaimKey( -// index, -// )) -// if b == nil { -// return val, false -// } - -// k.cdc.MustUnmarshal(b, &val) -// return val, true -// } - -// // RemoveClaim removes a claim from the store -// func (k Keeper) RemoveClaim( -// ctx sdk.Context, -// index string, - -// ) { -// store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) -// store.Delete(types.ClaimKey( -// index, -// )) -// } - -// // GetAllClaims returns all claim -// func (k Keeper) GetAllClaims(ctx sdk.Context) (list []types.Claim) { -// store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimKeyPrefix)) -// iterator := sdk.KVStorePrefixIterator(store, []byte{}) -// defer iterator.Close() - -// for ; iterator.Valid(); iterator.Next() { -// var val types.Claim -// k.cdc.MustUnmarshal(iterator.Value(), &val) -// claims = append(claims, val) -// } - -// return -// } - -// When retrieving by address: +// GetAllClaims returns all claim +func (k Keeper) GetAllClaims(ctx sdk.Context) (claims []types.Claim) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var val types.Claim + k.cdc.MustUnmarshal(iterator.Value(), &val) + claims = append(claims, val) + } + + return +} + +// GetClaimsByAddress returns all claims for a given address func (k Keeper) GetClaimsByAddress(ctx sdk.Context, address sdk.AccAddress) (claims []types.Claim) { addressStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimAddressPrefix)) @@ -112,6 +86,7 @@ func (k Keeper) GetClaimsByAddress(ctx sdk.Context, address sdk.AccAddress) (cla return claims } +// getClaimByPrimaryKey is a helper that retrieves, if exists, the Claim associated with the key provided func (k Keeper) getClaimByPrimaryKey(ctx sdk.Context, primaryKey []byte) (val types.Claim, found bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) b := store.Get(primaryKey) @@ -121,17 +96,3 @@ func (k Keeper) getClaimByPrimaryKey(ctx sdk.Context, primaryKey []byte) (val ty k.cdc.MustUnmarshal(b, &val) return val, true } - -func (k Keeper) getCount(ctx sdk.Context, store prefix.Store) uint64 { - bz := store.Get(types.CountKey) - if bz == nil { - return 0 // Count doesn't exist: no element - } - return binary.BigEndian.Uint64(bz) -} - -func (k Keeper) setCount(ctx sdk.Context, store prefix.Store, count uint64) { - bz := make([]byte, 8) - binary.BigEndian.PutUint64(bz, count) - store.Set(types.CountKey, bz) -} diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go index 443e83cf0..7b9a997f6 100644 --- a/x/supplier/keeper/claim_test.go +++ b/x/supplier/keeper/claim_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "fmt" "strconv" "testing" @@ -21,7 +22,8 @@ func createNClaims(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim claims := make([]types.Claim, n) for i := range claims { claims[i].SupplierAddress = sample.AccAddress() - + claims[i].SessionId = fmt.Sprintf("session-%d", i) + claims[i].RootHash = []byte(fmt.Sprintf("rootHash-%d", i)) keeper.InsertClaim(ctx, claims[i]) } return claims @@ -32,7 +34,8 @@ func TestClaimGet(t *testing.T) { claims := createNClaims(keeper, ctx, 10) for _, claim := range claims { rst, found := keeper.GetClaim(ctx, - claim.Index, + claim.SessionId, + claim.SupplierAddress, ) require.True(t, found) require.Equal(t, diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 9825587fc..15dd065f3 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -48,7 +48,8 @@ func (k Keeper) Claim(goCtx context.Context, req *types.QueryGetClaimRequest) (* val, found := k.GetClaim( ctx, - req.Index + req.SessionId, + req.SupplierAddress, ) if !found { return nil, status.Error(codes.NotFound, "not found") diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index 0d403a104..6b0abbcfd 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "strconv" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,43 +11,71 @@ import ( keepertest "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/testutil/sample" "github.com/pokt-network/poktroll/x/supplier/types" ) func TestClaimQuerySingle(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) wctx := sdk.WrapSDKContext(ctx) - msgs := createNClaims(keeper, ctx, 2) + claims := createNClaims(keeper, ctx, 2) tests := []struct { - desc string - request *types.QueryGetClaimRequest + desc string + + request *types.QueryGetClaimRequest + response *types.QueryGetClaimResponse err error }{ { - desc: "First", + desc: "First Claim", + request: &types.QueryGetClaimRequest{ - Index: msgs[0].Index, + SessionId: claims[0].SessionId, + SupplierAddress: claims[0].SupplierAddress, }, - response: &types.QueryGetClaimResponse{Claim: msgs[0]}, + + response: &types.QueryGetClaimResponse{Claim: claims[0]}, }, { - desc: "Second", + desc: "Second Claim", + request: &types.QueryGetClaimRequest{ - Index: msgs[1].Index, + SessionId: claims[1].SessionId, + SupplierAddress: claims[1].SupplierAddress, }, - response: &types.QueryGetClaimResponse{Claim: msgs[1]}, + + response: &types.QueryGetClaimResponse{Claim: claims[1]}, }, { - desc: "KeyNotFound", + desc: "Claim Not Found - Random SessionId", + request: &types.QueryGetClaimRequest{ - Index: strconv.Itoa(100000), + SessionId: "not a real session id", + SupplierAddress: claims[0].SupplierAddress, }, + err: status.Error(codes.NotFound, "not found"), }, { - desc: "InvalidRequest", - err: status.Error(codes.InvalidArgument, "invalid request"), + desc: "Claim Not Found - Random Supplier Address", + + request: &types.QueryGetClaimRequest{ + SessionId: claims[0].SessionId, + SupplierAddress: sample.AccAddress(), + }, + + err: status.Error(codes.NotFound, "not found"), + }, + { + desc: "InvalidRequest - Missing SessionId", + + err: status.Error(codes.InvalidArgument, "invalid request"), + }, + { + desc: "InvalidRequest - Missing SessionId", + + err: status.Error(codes.InvalidArgument, "invalid request"), }, } for _, tc := range tests { diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go index 64823ca36..ed11c5eae 100644 --- a/x/supplier/types/key_claim.go +++ b/x/supplier/types/key_claim.go @@ -25,7 +25,7 @@ const ( ClaimSessionIdPrefix = "Claim/sessionId/" ) -// ClaimPrimaryKey returns the primary store key to retrieve a Claim +// ClaimPrimaryKey returns the primary store key to retrieve a Claim by creating a composite key of the sessionId and supplierAddr func ClaimPrimaryKey(sessionId, supplierAddr string) []byte { var key []byte @@ -40,15 +40,12 @@ func ClaimPrimaryKey(sessionId, supplierAddr string) []byte { } // ClaimSupplierAddressKey returns the address key to iterate through claims given a supplier Address -func ClaimSupplierAddressKey(supplierAddr string, claimNum uint64) []byte { +func ClaimSupplierAddressKey(supplierAddr string, primaryKey []byte) []byte { var key []byte - numBz := make([]byte, 8) - binary.BigEndian.PutUint64(numBz, claimNum) - key = append(key, []byte(supplierAddr)...) - key = append(key, []byte("/num/")...) - key = append(key, numBz...) + key = append(key, []byte("/")...) + key = append(key, primaryKey...) key = append(key, []byte("/")...) return key diff --git a/x/supplier/types/message_create_claim.go b/x/supplier/types/message_create_claim.go index 0e702c956..0b810208c 100644 --- a/x/supplier/types/message_create_claim.go +++ b/x/supplier/types/message_create_claim.go @@ -67,4 +67,4 @@ func (msg *MsgCreateClaim) ValidateBasic() error { } return nil -} +} \ No newline at end of file diff --git a/x/supplier/types/query_get_claim.go b/x/supplier/types/query_get_claim.go new file mode 100644 index 000000000..97b968a2a --- /dev/null +++ b/x/supplier/types/query_get_claim.go @@ -0,0 +1,19 @@ +package types + +import ( + sdkerrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NOTE: Please note that `QueryGetClaimRequest` is not a `sdk.Msg`, and is therefore not a message/request +// that will be signable or invoke a state transition. However, following a similar `ValidateBasic` pattern +// allows us to localize & reuse validation logic. +func (query *QueryGetClaimRequest) ValidateBasic() error { + // Validate the supplier address + if _, err := sdk.AccAddressFromBech32(query.SupplierAddress); err != nil { + return sdkerrors.Wrapf(ErrSupplierInvalidAddress, "invalid supplier address for claim being retrieved %s; (%v)", query.SupplierAddress, err) + } + + // TODO_TECHDEBT: Validate the session ID once we have a deterministic way to generate it + return nil +} From 3d5581ab216aa7f9f4c660c01cc9a55f29fe9576 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 9 Nov 2023 19:48:40 -0800 Subject: [PATCH 23/40] Compiling with unit tests passing --- .gitignore | 6 +- Makefile | 16 ++-- docs/static/openapi.yml | 20 +++++ go.mod | 4 +- proto/pocket/supplier/claim.proto | 3 +- x/supplier/client/cli/query_claim.go | 89 +++++++++++++++++++- x/supplier/client/cli/tx_create_claim.go | 3 +- x/supplier/keeper/claim.go | 52 ++++++++++-- x/supplier/keeper/msg_server_create_claim.go | 8 ++ x/supplier/types/errors.go | 1 + x/supplier/types/key_claim.go | 26 ++++-- x/supplier/types/message_create_claim.go | 8 +- x/supplier/types/query_get_claim.go | 30 ++++++- 13 files changed, 228 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index c6e3508f1..cf0b4e656 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,6 @@ localnet/*/config/*.json !localnet/poktrolld/config/client.toml !localnet/poktrolld/config/config.toml - # Macos .DS_Store **/.DS_Store @@ -65,8 +64,5 @@ release # Only keep one go module in our codebase go.work.sum -# Avoid accidently commiting gomock artifacts +# Avoid accidentally committing gomock artifacts **/gomock_reflect_* - - -gomock_reflect diff --git a/Makefile b/Makefile index ab69b6542..c6430f25a 100644 --- a/Makefile +++ b/Makefile @@ -445,17 +445,21 @@ acc_balance_total_supply: ## Query the total supply of the network ### Claims ### ############## -.PHONY: claim_list +.PHONY: claims_list claim_list: ## List all the claims poktrolld --home=$(POCKETD_HOME) q claim list-claims --node $(POCKET_NODE) -.PHONY: claim_list_address -claim_list_address: ## List all the claims for a specific address (make claim_list_address ADDR=pokt...) - poktrolld --home=$(POCKETD_HOME) q claim list-claims $(ADDR) --node $(POCKET_NODE) +.PHONY: claims_list_address +claim_list_address: ## List all the claims for a specific address (specified via ADDR variable) + poktrolld --home=$(POCKETD_HOME) q claim list-claims address $(ADDR) --node $(POCKET_NODE) .PHONY: claim_list_height -claim_list_height: ## List all the claims for a specific height (make claim_list_height HEIGHT=...) - poktrolld --home=$(POCKETD_HOME) q claim list-claims --height $(HEIGHT) --node $(POCKET_NODE) +claim_list_height: ## List all the claims ending at a specific height (specified via HEIGHT variable) + poktrolld --home=$(POCKETD_HOME) q claim list-claims height $(HEIGHT) --node $(POCKET_NODE) + +.PHONY: claim_list_session +claim_list_session: ## List all the claims ending at a specific session (specified via SESSION variable) + poktrolld --home=$(POCKETD_HOME) q claim list-claims session $(SESSION) --node $(POCKET_NODE) ###################### ### Ignite Helpers ### diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 9d23a20d2..9cc79959c 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -47446,6 +47446,10 @@ paths: session_id: type: string title: session id from the SessionHeader + session_end_block_height: + type: string + format: uint64 + title: session end block height from the SessionHeader root_hash: type: string format: byte @@ -47499,6 +47503,10 @@ paths: session_id: type: string title: session id from the SessionHeader + session_end_block_height: + type: string + format: uint64 + title: session end block height from the SessionHeader root_hash: type: string format: byte @@ -78036,6 +78044,10 @@ definitions: session_id: type: string title: session id from the SessionHeader + session_end_block_height: + type: string + format: uint64 + title: session end block height from the SessionHeader root_hash: type: string format: byte @@ -78065,6 +78077,10 @@ definitions: session_id: type: string title: session id from the SessionHeader + session_end_block_height: + type: string + format: uint64 + title: session end block height from the SessionHeader root_hash: type: string format: byte @@ -78249,6 +78265,10 @@ definitions: session_id: type: string title: session id from the SessionHeader + session_end_block_height: + type: string + format: uint64 + title: session end block height from the SessionHeader root_hash: type: string format: byte diff --git a/go.mod b/go.mod index 6856b606c..51aa32938 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -28,6 +29,7 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -71,7 +73,6 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -267,7 +268,6 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/proto/pocket/supplier/claim.proto b/proto/pocket/supplier/claim.proto index 5fff5f2a3..f4ae16adb 100644 --- a/proto/pocket/supplier/claim.proto +++ b/proto/pocket/supplier/claim.proto @@ -8,5 +8,6 @@ import "cosmos_proto/cosmos.proto"; message Claim { string supplier_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // the address of the supplier that submitted this claims string session_id = 2; // session id from the SessionHeader - bytes root_hash = 3; // smt.SMST#Root() + uint64 session_end_block_height = 3; // session end block height from the SessionHeader + bytes root_hash = 4; // smt.SMST#Root() } \ No newline at end of file diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index ced71ad79..32ba1fd6a 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -1,6 +1,7 @@ package cli import ( + "fmt" "strconv" "github.com/cosmos/cosmos-sdk/client" @@ -13,19 +14,48 @@ import ( // Prevent strconv unused error var _ = strconv.IntSize +const ( + FlagSessionEndHeight = "height" + FlagSessionId = "session" + FlagSupplierAddress = "address" +) + +// AddPaginationFlagsToCmd adds common pagination flags to cmd +func AddClaimFilterFlags(cmd *cobra.Command) { + cmd.Flags().Uint64(FlagSessionEndHeight, 0, "claims whose session ends at this height will be returned") + cmd.Flags().String(FlagSessionId, "", "claims matching this session id will be returned") + cmd.Flags().String(FlagSupplierAddress, "", "claims submitted by suppliers matching this address will be returned") +} + func CmdListClaims() *cobra.Command { cmd := &cobra.Command{ Use: "list-claims", Short: "list all claims", - Args: cobra.NoArgs, + Long: `List all the claims that the node being queried has in its state. + +The claims can be optionally filtered by one of --session --height or --address flags + +Example: +$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --node $(POCKET_NODE) +$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --session --node $(POCKET_NODE) +$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --height --node $(POCKET_NODE) +$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --address --node $(POCKET_NODE)`, + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { return err } - params := &types.QueryAllClaimsRequest{ + + req := &types.QueryAllClaimsRequest{ Pagination: pageReq, } + if err := updateClaimsFilter(cmd, req); err != nil { + return err + } + if err := req.ValidateBasic(); err != nil { + return err + } clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { @@ -33,7 +63,7 @@ func CmdListClaims() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.AllClaims(cmd.Context(), params) + res, err := queryClient.AllClaims(cmd.Context(), req) if err != nil { return err } @@ -42,17 +72,68 @@ func CmdListClaims() *cobra.Command { }, } + AddClaimFilterFlags(cmd) flags.AddPaginationFlagsToCmd(cmd, cmd.Use) flags.AddQueryFlagsToCmd(cmd) return cmd } +func updateClaimsFilter(cmd *cobra.Command, req *types.QueryAllClaimsRequest) error { + sessionId, _ := cmd.Flags().GetString(FlagSessionId) + supplierAddr, _ := cmd.Flags().GetString(FlagSupplierAddress) + sessionEndHeight, _ := cmd.Flags().GetUint64(FlagSessionEndHeight) + + // Preparing a shared error in case more than one flag was set + err := fmt.Errorf("can only specify one flag filter but got sessionId (%s), supplierAddr (%s) and sessionEngHeight (%d)", sessionId, supplierAddr, sessionEndHeight) + + // Use the session id as the filter + if sessionId != "" { + // If the session id is set, then the other flags must not be set + if supplierAddr != "" || sessionEndHeight > 0 { + return err + } + // Set the session id filter + req.Filter.(*types.QueryAllClaimsRequest_SessionId).SessionId = sessionId + return nil + } + + // Use the supplier address as the filter + if supplierAddr != "" { + // If the supplier address is set, then the other flags must not be set + if sessionId != "" || sessionEndHeight > 0 { + return err + } + // Set the supplier address filter + req.Filter.(*types.QueryAllClaimsRequest_SupplierAddress).SupplierAddress = supplierAddr + return nil + } + + // Use the session end height as the filter + if sessionEndHeight > 0 { + // If the session end height is set, then the other flags must not be set + if sessionId != "" || supplierAddr != "" { + return err + } + // Set the session end height filter + req.Filter.(*types.QueryAllClaimsRequest_SessionEndHeight).SessionEndHeight = sessionEndHeight + return nil + } + + return nil +} + func CmdShowClaim() *cobra.Command { cmd := &cobra.Command{ Use: "show-claim ", Short: "shows a specific claim", - Args: cobra.ExactArgs(2), + Long: `List a specific claim that the node being queried has access to (if it still exists) + +A unique claim can be defined via a session_id that a supplier participated in + +Example: +$ poktrolld --home=$(POKTROLLD_HOME) q claim show-claims --node $(POCKET_NODE)`, + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { sessionId := args[0] supplierAddr := args[1] diff --git a/x/supplier/client/cli/tx_create_claim.go b/x/supplier/client/cli/tx_create_claim.go index 2869ce95d..616c6ce39 100644 --- a/x/supplier/client/cli/tx_create_claim.go +++ b/x/supplier/client/cli/tx_create_claim.go @@ -39,8 +39,9 @@ func CmdCreateClaim() *cobra.Command { return err } + supplierAddress := clientCtx.GetFromAddress().String() msg := types.NewMsgCreateClaim( - clientCtx.GetFromAddress().String(), + supplierAddress, argSessionHeader, argRootHash, ) diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 0be972f4b..a28b96151 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -1,6 +1,8 @@ package keeper import ( + "encoding/binary" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -22,29 +24,40 @@ func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { logger.Info("inserted claim with primaryKey %s", primaryKey) // Update the address index: supplierAddress -> [ClaimPrimaryKey] - addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimAddressPrefix)) + addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSupplierAddressPrefix)) addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, primaryKey) addressStoreIndex.Set(addressKey, primaryKey) - // TODO: Index by sessionId - // TODO: Index by sessionEndHeight + // Update the session end height index: sessionEndHeight -> [ClaimPrimaryKey] + sessionHeightStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) + heightKey := types.ClaimSupplierEndSessionHeightKey(claim.SessionEndBlockHeight, primaryKey) + sessionHeightStoreIndex.Set(heightKey, primaryKey) } // RemoveClaim removes a claim from the store func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + parentStore := ctx.KVStore(k.storeKey) + store := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + // Check if the claim exists primaryKey := types.ClaimPrimaryKey(sessionId, supplierAddr) claim, foundClaim := k.getClaimByPrimaryKey(ctx, primaryKey) if !foundClaim { k.Logger(ctx).Error("trying to delete non-existent claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId) } - addressStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimAddressPrefix)) + // Prepare the indices for deletion + addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSupplierAddressPrefix)) + sessionHeightStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) + addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, primaryKey) + heightKey := types.ClaimSupplierEndSessionHeightKey(claim.SessionEndBlockHeight, primaryKey) - addressStore.Delete(addressKey) + // Delete all the entries store.Delete(primaryKey) + addressStoreIndex.Delete(addressKey) + sessionHeightStoreIndex.Delete(heightKey) + } // GetClaim returns a Claim given a SessionId & SupplierAddr @@ -68,11 +81,32 @@ func (k Keeper) GetAllClaims(ctx sdk.Context) (claims []types.Claim) { return } -// GetClaimsByAddress returns all claims for a given address +// GetClaimsByAddress returns all claims for a given supplier address func (k Keeper) GetClaimsByAddress(ctx sdk.Context, address sdk.AccAddress) (claims []types.Claim) { - addressStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimAddressPrefix)) + addressStoreIndex := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimSupplierAddressPrefix)) + + iterator := sdk.KVStorePrefixIterator(addressStoreIndex, []byte(address)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + primaryKey := iterator.Value() + claim, claimFound := k.getClaimByPrimaryKey(ctx, primaryKey) + if claimFound { + claims = append(claims, claim) + } + } + + return claims +} + +// GetClaimsByAddress returns all claims whose session ended at the given block height +func (k Keeper) GetClaimsByHeight(ctx sdk.Context, height uint64) (claims []types.Claim) { + sessionHeightStoreIndex := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) + + heightBz := make([]byte, 8) + binary.BigEndian.PutUint64(heightBz, height) - iterator := sdk.KVStorePrefixIterator(addressStore, []byte(address)) + iterator := sdk.KVStorePrefixIterator(sessionHeightStoreIndex, heightBz) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index 752da7343..b67163751 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -15,6 +15,14 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *types.MsgCreateClaim) return nil, err } + claim := types.Claim{ + SupplierAddress: msg.SupplierAddress, + SessionId: msg.SessionHeader.SessionId, + SessionEndBlockHeight: uint64(msg.SessionHeader.SessionEndBlockHeight), + RootHash: msg.RootHash, + } + k.Keeper.InsertClaim(ctx, claim) + /* INCOMPLETE: Handling the message diff --git a/x/supplier/types/errors.go b/x/supplier/types/errors.go index bc5a32be9..c175461ed 100644 --- a/x/supplier/types/errors.go +++ b/x/supplier/types/errors.go @@ -17,4 +17,5 @@ var ( ErrSupplierInvalidSessionId = sdkerrors.Register(ModuleName, 7, "invalid session ID") ErrSupplierInvalidService = sdkerrors.Register(ModuleName, 8, "invalid service in supplier") ErrSupplierInvalidClaimRootHash = sdkerrors.Register(ModuleName, 9, "invalid root hash") + ErrSupplierInvalidSessionEndHeight = sdkerrors.Register(ModuleName, 10, "invalid session ending height") ) diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go index ed11c5eae..d18226c52 100644 --- a/x/supplier/types/key_claim.go +++ b/x/supplier/types/key_claim.go @@ -15,14 +15,11 @@ const ( // ClaimPrimaryKeyPrefix is the prefix to retrieve all Claim (the primary store) ClaimPrimaryKeyPrefix = "Claim/value/" - // ClaimHeightPrefix is the key to retrieve a Claim's Primary Key from the Height index - ClaimHeightPrefix = "Claim/height/" + // ClaimSupplierAddressPrefix is the key to retrieve a Claim's Primary Key from the Address index + ClaimSupplierAddressPrefix = "Claim/address/" - // ClaimAddressPrefix is the key to retrieve a Claim's Primary Key from the Address index - ClaimAddressPrefix = "Claim/address/" - - // ClaimSessionIdPrefix is the key to retrieve a Claim's Primary Key from the SessionId index - ClaimSessionIdPrefix = "Claim/sessionId/" + // ClaimSessionEndHeightPrefix is the key to retrieve a Claim's Primary Key from the Height index + ClaimSessionEndHeightPrefix = "Claim/height/" ) // ClaimPrimaryKey returns the primary store key to retrieve a Claim by creating a composite key of the sessionId and supplierAddr @@ -50,3 +47,18 @@ func ClaimSupplierAddressKey(supplierAddr string, primaryKey []byte) []byte { return key } + +// ClaimSupplierAddressKey returns the address key to iterate through claims given a supplier Address +func ClaimSupplierEndSessionHeightKey(sessionEndHeight uint64, primaryKey []byte) []byte { + var key []byte + + heightBz := make([]byte, 8) + binary.BigEndian.PutUint64(heightBz, sessionEndHeight) + + key = append(key, []byte(heightBz)...) + key = append(key, []byte("/")...) + key = append(key, primaryKey...) + key = append(key, []byte("/")...) + + return key +} diff --git a/x/supplier/types/message_create_claim.go b/x/supplier/types/message_create_claim.go index 0b810208c..0b20c27ec 100644 --- a/x/supplier/types/message_create_claim.go +++ b/x/supplier/types/message_create_claim.go @@ -12,7 +12,11 @@ const TypeMsgCreateClaim = "create_claim" var _ sdk.Msg = (*MsgCreateClaim)(nil) -func NewMsgCreateClaim(supplierAddress string, sessionHeader *sessiontypes.SessionHeader, rootHash []byte) *MsgCreateClaim { +func NewMsgCreateClaim( + supplierAddress string, + sessionHeader *sessiontypes.SessionHeader, + rootHash []byte, +) *MsgCreateClaim { return &MsgCreateClaim{ SupplierAddress: supplierAddress, SessionHeader: sessionHeader, @@ -67,4 +71,4 @@ func (msg *MsgCreateClaim) ValidateBasic() error { } return nil -} \ No newline at end of file +} diff --git a/x/supplier/types/query_get_claim.go b/x/supplier/types/query_get_claim.go index 97b968a2a..92be4e0d2 100644 --- a/x/supplier/types/query_get_claim.go +++ b/x/supplier/types/query_get_claim.go @@ -1,13 +1,17 @@ package types import ( + fmt "fmt" + sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" ) -// NOTE: Please note that `QueryGetClaimRequest` is not a `sdk.Msg`, and is therefore not a message/request +// NOTE: Please note that these messages are not of type `sdk.Msg`, and are therefore not a message/request // that will be signable or invoke a state transition. However, following a similar `ValidateBasic` pattern // allows us to localize & reuse validation logic. + +// ValidateBasic performs basic (non-state-dependant) validation on a QueryGetClaimRequest. func (query *QueryGetClaimRequest) ValidateBasic() error { // Validate the supplier address if _, err := sdk.AccAddressFromBech32(query.SupplierAddress); err != nil { @@ -17,3 +21,27 @@ func (query *QueryGetClaimRequest) ValidateBasic() error { // TODO_TECHDEBT: Validate the session ID once we have a deterministic way to generate it return nil } + +// ValidateBasic performs basic (non-state-dependant) validation on a QueryAllClaimsRequest. +func (query *QueryAllClaimsRequest) ValidateBasic() error { + switch filter := query.Filter.(type) { + case *QueryAllClaimsRequest_SupplierAddress: + if _, err := sdk.AccAddressFromBech32(filter.SupplierAddress); err != nil { + return sdkerrors.Wrapf(ErrSupplierInvalidAddress, "invalid supplier address for claims being retrieved %s; (%v)", filter.SupplierAddress, err) + } + + case *QueryAllClaimsRequest_SessionId: + // TODO_TECHDEBT: Validate the session ID once we have a deterministic way to generate it + fmt.Println("TODO: SessionID check is currently a noop: ", filter.SessionId) + + case *QueryAllClaimsRequest_SessionEndHeight: + if filter.SessionEndHeight < 0 { + return sdkerrors.Wrapf(ErrSupplierInvalidSessionEndHeight, "invalid session end height for claims being retrieved %d", filter.SessionEndHeight) + } + + default: + // No filter is set + fmt.Println("No specific filter set") + } + return nil +} From bea61067339c5545e71dba8488895430c21f20a9 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 9 Nov 2023 20:01:14 -0800 Subject: [PATCH 24/40] Self reviewed all the files except for claims_test --- Makefile | 4 + docs/static/openapi.yml | 25 +- proto/pocket/supplier/claim.proto | 3 +- x/supplier/client/cli/query_claim.go | 103 +-- x/supplier/client/cli/query_claim_test.go | 731 ++++--------------- x/supplier/keeper/claim.go | 12 +- x/supplier/keeper/msg_server_create_claim.go | 3 + 7 files changed, 236 insertions(+), 645 deletions(-) diff --git a/Makefile b/Makefile index c6430f25a..4a23c727b 100644 --- a/Makefile +++ b/Makefile @@ -445,6 +445,10 @@ acc_balance_total_supply: ## Query the total supply of the network ### Claims ### ############## +.PHONY: claim_create +claim_create: ## Create a dummy claims + poktrolld --home=$(POCKETD_HOME) q claim list-claims --node $(POCKET_NODE) + .PHONY: claims_list claim_list: ## List all the claims poktrolld --home=$(POCKETD_HOME) q claim list-claims --node $(POCKET_NODE) diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 9cc79959c..467f7783e 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -47442,7 +47442,7 @@ paths: properties: supplier_address: type: string - title: the address of the supplier that submitted this claims + title: the address of the supplier that submitted this claim session_id: type: string title: session id from the SessionHeader @@ -47454,6 +47454,9 @@ paths: type: string format: byte title: smt.SMST#Root() + title: >- + Claim is the serialized object stored on-chain for claims + pending to be proven default: description: An unexpected error response. schema: @@ -47499,7 +47502,7 @@ paths: properties: supplier_address: type: string - title: the address of the supplier that submitted this claims + title: the address of the supplier that submitted this claim session_id: type: string title: session id from the SessionHeader @@ -47511,6 +47514,9 @@ paths: type: string format: byte title: smt.SMST#Root() + title: >- + Claim is the serialized object stored on-chain for claims + pending to be proven pagination: type: object properties: @@ -78040,7 +78046,7 @@ definitions: properties: supplier_address: type: string - title: the address of the supplier that submitted this claims + title: the address of the supplier that submitted this claim session_id: type: string title: session id from the SessionHeader @@ -78052,6 +78058,9 @@ definitions: type: string format: byte title: smt.SMST#Root() + title: >- + Claim is the serialized object stored on-chain for claims pending to be + proven pocket.supplier.MsgCreateClaimResponse: type: object pocket.supplier.MsgStakeSupplierResponse: @@ -78073,7 +78082,7 @@ definitions: properties: supplier_address: type: string - title: the address of the supplier that submitted this claims + title: the address of the supplier that submitted this claim session_id: type: string title: session id from the SessionHeader @@ -78085,6 +78094,9 @@ definitions: type: string format: byte title: smt.SMST#Root() + title: >- + Claim is the serialized object stored on-chain for claims pending to + be proven pagination: type: object properties: @@ -78261,7 +78273,7 @@ definitions: properties: supplier_address: type: string - title: the address of the supplier that submitted this claims + title: the address of the supplier that submitted this claim session_id: type: string title: session id from the SessionHeader @@ -78273,6 +78285,9 @@ definitions: type: string format: byte title: smt.SMST#Root() + title: >- + Claim is the serialized object stored on-chain for claims pending to + be proven pocket.supplier.QueryGetSupplierResponse: type: object properties: diff --git a/proto/pocket/supplier/claim.proto b/proto/pocket/supplier/claim.proto index f4ae16adb..5b8121855 100644 --- a/proto/pocket/supplier/claim.proto +++ b/proto/pocket/supplier/claim.proto @@ -5,8 +5,9 @@ option go_package = "github.com/pokt-network/poktroll/x/supplier/types"; import "cosmos_proto/cosmos.proto"; +// Claim is the serialized object stored on-chain for claims pending to be proven message Claim { - string supplier_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // the address of the supplier that submitted this claims + string supplier_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // the address of the supplier that submitted this claim string session_id = 2; // session id from the SessionHeader uint64 session_end_block_height = 3; // session end block height from the SessionHeader bytes root_hash = 4; // smt.SMST#Root() diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 32ba1fd6a..ce8dd0f3b 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -15,9 +15,9 @@ import ( var _ = strconv.IntSize const ( - FlagSessionEndHeight = "height" - FlagSessionId = "session" - FlagSupplierAddress = "address" + FlagSessionEndHeight = "session-end-height" + FlagSessionId = "session-id" + FlagSupplierAddress = "supplier-address" ) // AddPaginationFlagsToCmd adds common pagination flags to cmd @@ -33,13 +33,13 @@ func CmdListClaims() *cobra.Command { Short: "list all claims", Long: `List all the claims that the node being queried has in its state. -The claims can be optionally filtered by one of --session --height or --address flags +The claims can be optionally filtered by one of --session-end-height --session-id or --supplier-address flags Example: $ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --node $(POCKET_NODE) -$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --session --node $(POCKET_NODE) -$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --height --node $(POCKET_NODE) -$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --address --node $(POCKET_NODE)`, +$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --session-id --node $(POCKET_NODE) +$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --session-end-height --node $(POCKET_NODE) +$ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --supplier-address --node $(POCKET_NODE)`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { pageReq, err := client.ReadPageRequest(cmd.Flags()) @@ -79,50 +79,6 @@ $ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --address 0 { - return err - } - // Set the session id filter - req.Filter.(*types.QueryAllClaimsRequest_SessionId).SessionId = sessionId - return nil - } - - // Use the supplier address as the filter - if supplierAddr != "" { - // If the supplier address is set, then the other flags must not be set - if sessionId != "" || sessionEndHeight > 0 { - return err - } - // Set the supplier address filter - req.Filter.(*types.QueryAllClaimsRequest_SupplierAddress).SupplierAddress = supplierAddr - return nil - } - - // Use the session end height as the filter - if sessionEndHeight > 0 { - // If the session end height is set, then the other flags must not be set - if sessionId != "" || supplierAddr != "" { - return err - } - // Set the session end height filter - req.Filter.(*types.QueryAllClaimsRequest_SessionEndHeight).SessionEndHeight = sessionEndHeight - return nil - } - - return nil -} - func CmdShowClaim() *cobra.Command { cmd := &cobra.Command{ Use: "show-claim ", @@ -166,3 +122,48 @@ $ poktrolld --home=$(POKTROLLD_HOME) q claim show-claims 0 { + return err + } + // Set the session id filter + req.Filter.(*types.QueryAllClaimsRequest_SessionId).SessionId = sessionId + return nil + } + + // Use the supplier address as the filter + if supplierAddr != "" { + // If the supplier address is set, then the other flags must not be set + if sessionId != "" || sessionEndHeight > 0 { + return err + } + // Set the supplier address filter + req.Filter.(*types.QueryAllClaimsRequest_SupplierAddress).SupplierAddress = supplierAddr + return nil + } + + // Use the session end height as the filter + if sessionEndHeight > 0 { + // If the session end height is set, then the other flags must not be set + if sessionId != "" || supplierAddr != "" { + return err + } + // Set the session end height filter + req.Filter.(*types.QueryAllClaimsRequest_SessionEndHeight).SessionEndHeight = sessionEndHeight + return nil + } + + return nil +} diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 3990d9d2c..012bd44c4 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -1,598 +1,157 @@ package cli_test -// import ( -// "fmt" -// "strconv" -// "testing" -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// +import ( + "fmt" + "strconv" + "testing" -// tmcli "github.com/cometbft/cometbft/libs/cli" -// "github.com/cosmos/cosmos-sdk/client/flags" -// clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" -// "github.com/stretchr/testify/require" -// "google.golang.org/grpc/codes" -// "google.golang.org/grpc/status" + tmcli "github.com/cometbft/cometbft/libs/cli" + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" -// "github.com/pokt-network/poktroll/testutil/network" -// "github.com/pokt-network/poktroll/testutil/nullify" -// "github.com/pokt-network/poktroll/x/supplier/client/cli" -// "github.com/pokt-network/poktroll/x/supplier/types" -// ) + "github.com/pokt-network/poktroll/testutil/network" + "github.com/pokt-network/poktroll/testutil/nullify" + "github.com/pokt-network/poktroll/x/supplier/client/cli" + "github.com/pokt-network/poktroll/x/supplier/types" +) -// func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Claim) { -// t.Helper() -// cfg := network.DefaultConfig() -// state := types.GenesisState{} -// for i := 0; i < n; i++ { -// claim := types.Claim{ -// Index: strconv.Itoa(i), -// } -// nullify.Fill(&claim) -// state.ClaimList = append(state.ClaimList, claim) -// } -// buf, err := cfg.Codec.MarshalJSON(&state) -// require.NoError(t, err) -// cfg.GenesisState[types.ModuleName] = buf -// return network.New(t, cfg), state.ClaimList -// } +func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Claim) { + t.Helper() + cfg := network.DefaultConfig() + state := types.GenesisState{} + for i := 0; i < n; i++ { + claim := types.Claim{ + Index: strconv.Itoa(i), + } + nullify.Fill(&claim) + state.ClaimList = append(state.ClaimList, claim) + } + buf, err := cfg.Codec.MarshalJSON(&state) + require.NoError(t, err) + cfg.GenesisState[types.ModuleName] = buf + return network.New(t, cfg), state.ClaimList +} -// func TestShowClaim(t *testing.T) { -// net, objs := networkWithClaimObjects(t, 2) +func TestShowClaim(t *testing.T) { + net, claims := networkWithClaimObjects(t, 2) -// ctx := net.Validators[0].ClientCtx -// common := []string{ -// fmt.Sprintf("--%s=json", tmcli.OutputFlag), -// } -// tests := []struct { -// desc string -// idIndex string + ctx := net.Validators[0].ClientCtx + common := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tests := []struct { + desc string + idIndex string -// args []string -// err error -// obj types.Claim -// }{ -// { -// desc: "found", -// idIndex: objs[0].Index, + args []string + err error + obj types.Claim + }{ + { + desc: "found", + idIndex: claims[0].Index, -// args: common, -// obj: objs[0], -// }, -// { -// desc: "not found", -// idIndex: strconv.Itoa(100000), + args: common, + obj: claims[0], + }, + { + desc: "not found", + idIndex: strconv.Itoa(100000), -// args: common, -// err: status.Error(codes.NotFound, "not found"), -// }, -// } -// for _, tc := range tests { -// t.Run(tc.desc, func(t *testing.T) { -// args := []string{ -// tc.idIndex, -// } -// args = append(args, tc.args...) -// out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) -// if tc.err != nil { -// stat, ok := status.FromError(tc.err) -// require.True(t, ok) -// require.ErrorIs(t, stat.Err(), tc.err) -// } else { -// require.NoError(t, err) -// var resp types.QueryGetClaimResponse -// require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) -// require.NotNil(t, resp.Claim) -// require.Equal(t, -// nullify.Fill(&tc.obj), -// nullify.Fill(&resp.Claim), -// ) -// } -// }) -// } -// } + args: common, + err: status.Error(codes.NotFound, "not found"), + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + args := []string{ + tc.idIndex, + } + args = append(args, tc.args...) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) + if tc.err != nil { + stat, ok := status.FromError(tc.err) + require.True(t, ok) + require.ErrorIs(t, stat.Err(), tc.err) + } else { + require.NoError(t, err) + var resp types.QueryGetClaimResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.NotNil(t, resp.Claim) + require.Equal(t, + nullify.Fill(&tc.obj), + nullify.Fill(&resp.Claim), + ) + } + }) + } +} -// func TestListClaim(t *testing.T) { -// net, objs := networkWithClaimObjects(t, 5) +func TestListClaim(t *testing.T) { + net, claims := networkWithClaimObjects(t, 5) -// ctx := net.Validators[0].ClientCtx -// request := func(next []byte, offset, limit uint64, total bool) []string { -// args := []string{ -// fmt.Sprintf("--%s=json", tmcli.OutputFlag), -// } -// if next == nil { -// args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) -// } else { -// args = append(args, fmt.Sprintf("--%s=%s", flags.FlagPageKey, next)) -// } -// args = append(args, fmt.Sprintf("--%s=%d", flags.FlagLimit, limit)) -// if total { -// args = append(args, fmt.Sprintf("--%s", flags.FlagCountTotal)) -// } -// return args -// } -// t.Run("ByOffset", func(t *testing.T) { -// step := 2 -// for i := 0; i < len(objs); i += step { -// args := request(nil, uint64(i), uint64(step), false) -// out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) -// require.NoError(t, err) -// var resp types.QueryAllClaimsResponse -// require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) -// require.LessOrEqual(t, len(resp.Claim), step) -// require.Subset(t, -// nullify.Fill(objs), -// nullify.Fill(resp.Claim), -// ) -// } -// }) -// t.Run("ByKey", func(t *testing.T) { -// step := 2 -// var next []byte -// for i := 0; i < len(objs); i += step { -// args := request(next, 0, uint64(step), false) -// out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) -// require.NoError(t, err) -// var resp types.QueryAllClaimsResponse -// require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) -// require.LessOrEqual(t, len(resp.Claim), step) -// require.Subset(t, -// nullify.Fill(objs), -// nullify.Fill(resp.Claim), -// ) -// next = resp.Pagination.NextKey -// } -// }) -// t.Run("Total", func(t *testing.T) { -// args := request(nil, 0, uint64(len(objs)), true) -// out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaim(), args) -// require.NoError(t, err) -// var resp types.QueryAllClaimsResponse -// require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) -// require.NoError(t, err) -// require.Equal(t, len(objs), int(resp.Pagination.Total)) -// require.ElementsMatch(t, -// nullify.Fill(objs), -// nullify.Fill(resp.Claim), -// ) -// }) -// } + ctx := net.Validators[0].ClientCtx + request := func(next []byte, offset, limit uint64, total bool) []string { + args := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + if next == nil { + args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) + } else { + args = append(args, fmt.Sprintf("--%s=%s", flags.FlagPageKey, next)) + } + args = append(args, fmt.Sprintf("--%s=%d", flags.FlagLimit, limit)) + if total { + args = append(args, fmt.Sprintf("--%s", flags.FlagCountTotal)) + } + return args + } + t.Run("ByOffset", func(t *testing.T) { + step := 2 + for i := 0; i < len(claims); i += step { + args := request(nil, uint64(i), uint64(step), false) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) + require.NoError(t, err) + var resp types.QueryAllClaimsResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.LessOrEqual(t, len(resp.Claim), step) + require.Subset(t, + nullify.Fill(claims), + nullify.Fill(resp.Claim), + ) + } + }) + t.Run("ByKey", func(t *testing.T) { + step := 2 + var next []byte + for i := 0; i < len(claims); i += step { + args := request(next, 0, uint64(step), false) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) + require.NoError(t, err) + var resp types.QueryAllClaimsResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.LessOrEqual(t, len(resp.Claim), step) + require.Subset(t, + nullify.Fill(claims), + nullify.Fill(resp.Claim), + ) + next = resp.Pagination.NextKey + } + }) + t.Run("Total", func(t *testing.T) { + args := request(nil, 0, uint64(len(claims)), true) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) + require.NoError(t, err) + var resp types.QueryAllClaimsResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + require.NoError(t, err) + require.Equal(t, len(claims), int(resp.Pagination.Total)) + require.ElementsMatch(t, + nullify.Fill(claims), + nullify.Fill(resp.Claim), + ) + }) +} diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index a28b96151..ed0ffa7dd 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -21,21 +21,27 @@ func (k Keeper) InsertClaim(ctx sdk.Context, claim types.Claim) { primaryKey := types.ClaimPrimaryKey(claim.SessionId, claim.SupplierAddress) primaryStore.Set(primaryKey, claimBz) - logger.Info("inserted claim with primaryKey %s", primaryKey) + logger.Info("inserted claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey) // Update the address index: supplierAddress -> [ClaimPrimaryKey] addressStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSupplierAddressPrefix)) addressKey := types.ClaimSupplierAddressKey(claim.SupplierAddress, primaryKey) addressStoreIndex.Set(addressKey, primaryKey) + logger.Info("indexed claim for supplier %s with primaryKey %s", claim.SupplierAddress, primaryKey) + // Update the session end height index: sessionEndHeight -> [ClaimPrimaryKey] sessionHeightStoreIndex := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimSessionEndHeightPrefix)) heightKey := types.ClaimSupplierEndSessionHeightKey(claim.SessionEndBlockHeight, primaryKey) sessionHeightStoreIndex.Set(heightKey, primaryKey) + + logger.Info("indexed claim for supplier %s at session ending height %d", claim.SupplierAddress, claim.SessionEndBlockHeight) } // RemoveClaim removes a claim from the store func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { + logger := k.Logger(ctx).With("method", "RemoveClaim") + parentStore := ctx.KVStore(k.storeKey) store := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) @@ -43,7 +49,8 @@ func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { primaryKey := types.ClaimPrimaryKey(sessionId, supplierAddr) claim, foundClaim := k.getClaimByPrimaryKey(ctx, primaryKey) if !foundClaim { - k.Logger(ctx).Error("trying to delete non-existent claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId) + logger.Error("trying to delete non-existent claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId) + return } // Prepare the indices for deletion @@ -58,6 +65,7 @@ func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { addressStoreIndex.Delete(addressKey) sessionHeightStoreIndex.Delete(heightKey) + logger.Info("deleted claim with primary key %s for supplier %s and session %s", primaryKey, supplierAddr, sessionId) } // GetClaim returns a Claim given a SessionId & SupplierAddr diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index b67163751..ad28d2a2d 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -10,6 +10,7 @@ import ( func (k msgServer) CreateClaim(goCtx context.Context, msg *types.MsgCreateClaim) (*types.MsgCreateClaimResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + logger := k.Logger(ctx).With("method", "CreateClaim") if err := msg.ValidateBasic(); err != nil { return nil, err @@ -23,6 +24,8 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *types.MsgCreateClaim) } k.Keeper.InsertClaim(ctx, claim) + logger.Info("created claim for supplier %s at session ending height %d", claim.SupplierAddress, claim.SessionEndBlockHeight) + /* INCOMPLETE: Handling the message From 58b524bf0851e998707e25ee31111140bf702632 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 9 Nov 2023 21:09:37 -0800 Subject: [PATCH 25/40] Working on localnet --- Makefile | 30 +++++++++++++------ docs/static/openapi.yml | 30 ++++++++++--------- x/supplier/client/cli/query_claim.go | 12 ++++++-- x/supplier/client/cli/tx_create_claim.go | 38 +++++++++++++++++++----- 4 files changed, 76 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index 4a23c727b..ff2973013 100644 --- a/Makefile +++ b/Makefile @@ -446,24 +446,36 @@ acc_balance_total_supply: ## Query the total supply of the network ############## .PHONY: claim_create -claim_create: ## Create a dummy claims - poktrolld --home=$(POCKETD_HOME) q claim list-claims --node $(POCKET_NODE) +claim_create: ## Create a dummy claim by supplier1 + poktrolld --home=$(POKTROLLD_HOME) tx supplier create-claim \ + 7b226170706c69636174696f6e5f61646472657373223a22706f6b74316d7271743566377168387578733237636a6d397437763965373461397676646e71356a766134222c2273657276696365223a7b226964223a22616e76696c222c226e616d65223a22227d2c2273657373696f6e5f73746172745f626c6f636b5f686569676874223a2231222c2273657373696f6e5f6964223a2273657373696f6e5f6964222c2273657373696f6e5f656e645f626c6f636b5f686569676874223a2235227d \ + 726f6f745f68617368 \ + --from supplier1 --node $(POCKET_NODE) .PHONY: claims_list claim_list: ## List all the claims - poktrolld --home=$(POCKETD_HOME) q claim list-claims --node $(POCKET_NODE) + poktrolld --home=$(POKTROLLD_HOME) q supplier list-claims --node $(POCKET_NODE) .PHONY: claims_list_address claim_list_address: ## List all the claims for a specific address (specified via ADDR variable) - poktrolld --home=$(POCKETD_HOME) q claim list-claims address $(ADDR) --node $(POCKET_NODE) + poktrolld --home=$(POKTROLLD_HOME) q supplier list-claims --supplier-address $(ADDR) --node $(POCKET_NODE) + +.PHONY: claims_list_address_supplier1 +claim_list_address_supplier1: ## List all the claims for supplier1 + SUPPLIER1=$$(make poktrolld_addr ACC_NAME=supplier1) && \ + ADDR=$$SUPPLIER1 make claim_list_address .PHONY: claim_list_height claim_list_height: ## List all the claims ending at a specific height (specified via HEIGHT variable) - poktrolld --home=$(POCKETD_HOME) q claim list-claims height $(HEIGHT) --node $(POCKET_NODE) + poktrolld --home=$(POKTROLLD_HOME) q supplier list-claims --session-end-height $(HEIGHT) --node $(POCKET_NODE) + +.PHONY: claim_list_height_5 +claim_list_height_5: ## List all the claims at height 5 + HEIGHT=5 make claim_list_height -.PHONY: claim_list_session -claim_list_session: ## List all the claims ending at a specific session (specified via SESSION variable) - poktrolld --home=$(POCKETD_HOME) q claim list-claims session $(SESSION) --node $(POCKET_NODE) +# .PHONY: claim_list_session +# claim_list_session: ## List all the claims ending at a specific session (specified via SESSION variable) +# poktrolld --home=$(POKTROLLD_HOME) q supplier list-claims session $(SESSION) --node $(POCKET_NODE) ###################### ### Ignite Helpers ### @@ -501,4 +513,4 @@ openapi_gen: ## Generate the OpenAPI spec for the Ignite API .PHONY: poktrolld_addr poktrolld_addr: ## Retrieve the address for an account by ACC_NAME - @echo $(shell poktrolld keys show -a $(ACC_NAME)) + @echo $(shell poktrolld --home=$(POKTROLLD_HOME) keys show -a $(ACC_NAME)) diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index 49e961372..467f7783e 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -46480,7 +46480,7 @@ paths: service: title: >- The Service for which the application is - configured + configured for type: object properties: id: @@ -46660,7 +46660,9 @@ paths: type: object properties: service: - title: The Service for which the application is configured + title: >- + The Service for which the application is configured + for type: object properties: id: @@ -47176,7 +47178,7 @@ paths: service: title: >- The Service for which the application is - configured + configured for type: object properties: id: @@ -47243,7 +47245,7 @@ paths: service: title: >- The Service for which the supplier is - configured + configured for type: object properties: id: @@ -76812,7 +76814,7 @@ definitions: type: object properties: service: - title: The Service for which the application is configured + title: The Service for which the application is configured for type: object properties: id: @@ -76896,7 +76898,7 @@ definitions: type: object properties: service: - title: The Service for which the application is configured + title: The Service for which the application is configured for type: object properties: id: @@ -76990,7 +76992,7 @@ definitions: type: object properties: service: - title: The Service for which the application is configured + title: The Service for which the application is configured for type: object properties: id: @@ -77041,7 +77043,7 @@ definitions: type: object properties: service: - title: The Service for which the application is configured + title: The Service for which the application is configured for type: object properties: id: @@ -77309,7 +77311,7 @@ definitions: type: object properties: service: - title: The Service for which the application is configured + title: The Service for which the application is configured for type: object properties: id: @@ -77373,7 +77375,7 @@ definitions: type: object properties: service: - title: The Service for which the supplier is configured + title: The Service for which the supplier is configured for type: object properties: id: @@ -77563,7 +77565,7 @@ definitions: type: object properties: service: - title: The Service for which the application is configured + title: The Service for which the application is configured for type: object properties: id: @@ -77625,7 +77627,7 @@ definitions: type: object properties: service: - title: The Service for which the supplier is configured + title: The Service for which the supplier is configured for type: object properties: id: @@ -77839,7 +77841,7 @@ definitions: type: object properties: service: - title: The Service for which the supplier is configured + title: The Service for which the supplier is configured for type: object properties: id: @@ -77968,7 +77970,7 @@ definitions: type: object properties: service: - title: The Service for which the supplier is configured + title: The Service for which the supplier is configured for type: object properties: id: diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index ce8dd0f3b..cecd92b62 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -139,7 +139,9 @@ func updateClaimsFilter(cmd *cobra.Command, req *types.QueryAllClaimsRequest) er return err } // Set the session id filter - req.Filter.(*types.QueryAllClaimsRequest_SessionId).SessionId = sessionId + req.Filter = &types.QueryAllClaimsRequest_SessionId{ + SessionId: sessionId, + } return nil } @@ -150,7 +152,9 @@ func updateClaimsFilter(cmd *cobra.Command, req *types.QueryAllClaimsRequest) er return err } // Set the supplier address filter - req.Filter.(*types.QueryAllClaimsRequest_SupplierAddress).SupplierAddress = supplierAddr + req.Filter = &types.QueryAllClaimsRequest_SupplierAddress{ + SupplierAddress: supplierAddr, + } return nil } @@ -161,7 +165,9 @@ func updateClaimsFilter(cmd *cobra.Command, req *types.QueryAllClaimsRequest) er return err } // Set the session end height filter - req.Filter.(*types.QueryAllClaimsRequest_SessionEndHeight).SessionEndHeight = sessionEndHeight + req.Filter = &types.QueryAllClaimsRequest_SessionEndHeight{ + SessionEndHeight: sessionEndHeight, + } return nil } diff --git a/x/supplier/client/cli/tx_create_claim.go b/x/supplier/client/cli/tx_create_claim.go index 616c6ce39..1eb9fda4e 100644 --- a/x/supplier/client/cli/tx_create_claim.go +++ b/x/supplier/client/cli/tx_create_claim.go @@ -1,13 +1,14 @@ package cli import ( - "encoding/base64" - "encoding/json" + "encoding/hex" "strconv" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/spf13/cobra" sessiontypes "github.com/pokt-network/poktroll/x/session/types" @@ -24,12 +25,32 @@ func CmdCreateClaim() *cobra.Command { Short: "Broadcast message create-claim", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { - argSessionHeader := new(sessiontypes.SessionHeader) - err = json.Unmarshal([]byte(args[0]), argSessionHeader) + // fmt.Println("OLSH") + // argSessionHeader := &sessiontypes.SessionHeader{ + // ApplicationAddress: "pokt1mrqt5f7qh8uxs27cjm9t7v9e74a9vvdnq5jva4", + // SessionStartBlockHeight: 1, + // SessionId: "session_id", + // SessionEndBlockHeight: 5, + // Service: &sharedtypes.Service{ + // Id: "anvil", + // }, + // } + // fmt.Println("HERE", argSessionHeader) + // cdc := codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) + // bz := cdc.MustMarshalJSON(argSessionHeader) + // fmt.Println("HERE", hex.EncodeToString(bz)) + + // Get the session header + cdc := codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) + sessionHeaderBz, err := hex.DecodeString(args[0]) if err != nil { return err } - argRootHash, err := base64.StdEncoding.DecodeString(args[1]) + sessionHeader := sessiontypes.SessionHeader{} + cdc.MustUnmarshalJSON(sessionHeaderBz, &sessionHeader) + + // Get the root hash + rootHash, err := hex.DecodeString(args[1]) if err != nil { return err } @@ -38,16 +59,17 @@ func CmdCreateClaim() *cobra.Command { if err != nil { return err } - supplierAddress := clientCtx.GetFromAddress().String() + msg := types.NewMsgCreateClaim( supplierAddress, - argSessionHeader, - argRootHash, + &sessionHeader, + rootHash, ) if err := msg.ValidateBasic(); err != nil { return err } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } From 6f38d15e213d53fbe031c9d4d76c97d47e284867 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 14 Nov 2023 17:13:20 -0800 Subject: [PATCH 26/40] Working on the create claim tests --- Makefile | 7 +- x/supplier/client/cli/query_claim_test.go | 102 ++++++++++++++++++---- x/supplier/client/cli/tx_create_claim.go | 16 ---- x/supplier/keeper/claim.go | 4 + 4 files changed, 92 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index ff2973013..c7003a0fb 100644 --- a/Makefile +++ b/Makefile @@ -445,11 +445,14 @@ acc_balance_total_supply: ## Query the total supply of the network ### Claims ### ############## +# TODO_IN_THIS_PR: Explain where/how I got these; `encodeSessionHeader` in `x/supplier/client/cli/query_claim_test.go` +ENCODED_SESSION_HEADER = "7b226170706c69636174696f6e5f61646472657373223a22706f6b74316d7271743566377168387578733237636a6d397437763965373461397676646e71356a766134222c2273657276696365223a7b226964223a22616e76696c222c226e616d65223a22227d2c2273657373696f6e5f73746172745f626c6f636b5f686569676874223a2231222c2273657373696f6e5f6964223a2273657373696f6e5f6964222c2273657373696f6e5f656e645f626c6f636b5f686569676874223a2235227d" +ENCODED_ROOT_HASH = "726f6f745f68617368" .PHONY: claim_create claim_create: ## Create a dummy claim by supplier1 poktrolld --home=$(POKTROLLD_HOME) tx supplier create-claim \ - 7b226170706c69636174696f6e5f61646472657373223a22706f6b74316d7271743566377168387578733237636a6d397437763965373461397676646e71356a766134222c2273657276696365223a7b226964223a22616e76696c222c226e616d65223a22227d2c2273657373696f6e5f73746172745f626c6f636b5f686569676874223a2231222c2273657373696f6e5f6964223a2273657373696f6e5f6964222c2273657373696f6e5f656e645f626c6f636b5f686569676874223a2235227d \ - 726f6f745f68617368 \ + $(ENCODED_SESSION_HEADER) \ + $(ENCODED_ROOT_HASH) \ --from supplier1 --node $(POCKET_NODE) .PHONY: claims_list diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 012bd44c4..9c1807097 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -1,38 +1,90 @@ package cli_test import ( + "encoding/hex" "fmt" - "strconv" "testing" + sdkmath "cosmossdk.io/math" tmcli "github.com/cometbft/cometbft/libs/cli" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "github.com/pokt-network/poktroll/testutil/network" "github.com/pokt-network/poktroll/testutil/nullify" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" "github.com/pokt-network/poktroll/x/supplier/client/cli" "github.com/pokt-network/poktroll/x/supplier/types" ) -func networkWithClaimObjects(t *testing.T, n int) (*network.Network, []types.Claim) { +func encodeSessionHeader( + t *testing.T, +) string { t.Helper() + argSessionHeader := &sessiontypes.SessionHeader{ + ApplicationAddress: "pokt1mrqt5f7qh8uxs27cjm9t7v9e74a9vvdnq5jva4", + SessionStartBlockHeight: 1, + SessionId: "session_id", + SessionEndBlockHeight: 5, + Service: &sharedtypes.Service{ + Id: "anvil", + }, + } + cdc := codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) + sessionHeaderBz := cdc.MustMarshalJSON(argSessionHeader) + return hex.EncodeToString(sessionHeaderBz) +} + +func createClaim(t *testing.T, ctx client.Context, supplierAddr string) *types.Claim { + t.Helper() + + sessionHeaderEncoded := encodeSessionHeader(t) + + rootHash := []byte("root_hash") + rootHashEncoded := hex.EncodeToString(rootHash) + + args := []string{ + sessionHeaderEncoded, + rootHashEncoded, + fmt.Sprintf("--%s=%s", flags.FlagFrom, supplierAddr), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("upokt", sdkmath.NewInt(10))).String()), + } + + _, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdCreateClaim(), args) + require.NoError(t, err) + + return &types.Claim{ + SupplierAddress: "pokt1mrqt5f7qh8uxs27cjm9t7v9e74a9vvdnq5jva4", + SessionId: "session_id", + SessionEndBlockHeight: 5, + RootHash: rootHash, + } +} + +func networkWithClaimObjects(t *testing.T, n int) (net *network.Network, claims []types.Claim) { + t.Helper() + cfg := network.DefaultConfig() - state := types.GenesisState{} + net = network.New(t, cfg) + validator := net.Validators[0] + ctx := validator.ClientCtx + for i := 0; i < n; i++ { - claim := types.Claim{ - Index: strconv.Itoa(i), - } - nullify.Fill(&claim) - state.ClaimList = append(state.ClaimList, claim) + claim := createClaim(t, ctx, validator.Address.String()) + claims = append(claims, *claim) } - buf, err := cfg.Codec.MarshalJSON(&state) - require.NoError(t, err) - cfg.GenesisState[types.ModuleName] = buf - return network.New(t, cfg), state.ClaimList + + return net, claims } func TestShowClaim(t *testing.T) { @@ -43,23 +95,34 @@ func TestShowClaim(t *testing.T) { fmt.Sprintf("--%s=json", tmcli.OutputFlag), } tests := []struct { - desc string - idIndex string + desc string + sessionId string + supplierAddr string args []string err error obj types.Claim }{ { - desc: "found", - idIndex: claims[0].Index, + desc: "claim found", + sessionId: claims[0].SessionId, + supplierAddr: claims[0].SupplierAddress, args: common, obj: claims[0], }, { - desc: "not found", - idIndex: strconv.Itoa(100000), + desc: "claim not found (wrong session ID)", + sessionId: "wrong_session_id", + supplierAddr: claims[0].SupplierAddress, + + args: common, + err: status.Error(codes.NotFound, "not found"), + }, + { + desc: "claim not found (wrong supplier address)", + sessionId: claims[0].SessionId, + supplierAddr: "wrong_supplier_address", args: common, err: status.Error(codes.NotFound, "not found"), @@ -68,7 +131,8 @@ func TestShowClaim(t *testing.T) { for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { args := []string{ - tc.idIndex, + tc.sessionId, + tc.supplierAddr, } args = append(args, tc.args...) out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdShowClaim(), args) diff --git a/x/supplier/client/cli/tx_create_claim.go b/x/supplier/client/cli/tx_create_claim.go index 1eb9fda4e..2dfce2e50 100644 --- a/x/supplier/client/cli/tx_create_claim.go +++ b/x/supplier/client/cli/tx_create_claim.go @@ -25,21 +25,6 @@ func CmdCreateClaim() *cobra.Command { Short: "Broadcast message create-claim", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { - // fmt.Println("OLSH") - // argSessionHeader := &sessiontypes.SessionHeader{ - // ApplicationAddress: "pokt1mrqt5f7qh8uxs27cjm9t7v9e74a9vvdnq5jva4", - // SessionStartBlockHeight: 1, - // SessionId: "session_id", - // SessionEndBlockHeight: 5, - // Service: &sharedtypes.Service{ - // Id: "anvil", - // }, - // } - // fmt.Println("HERE", argSessionHeader) - // cdc := codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) - // bz := cdc.MustMarshalJSON(argSessionHeader) - // fmt.Println("HERE", hex.EncodeToString(bz)) - // Get the session header cdc := codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) sessionHeaderBz, err := hex.DecodeString(args[0]) @@ -69,7 +54,6 @@ func CmdCreateClaim() *cobra.Command { if err := msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index ed0ffa7dd..3f6b897a3 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -74,6 +74,10 @@ func (k Keeper) GetClaim(ctx sdk.Context, sessionId, supplierAddr string) (val t return k.getClaimByPrimaryKey(ctx, primaryKey) } + // primaryStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + // primaryKey := types.ClaimPrimaryKey(claim.SessionId, claim.SupplierAddress) + // primaryStore.Set(primaryKey, claimBz) + // GetAllClaims returns all claim func (k Keeper) GetAllClaims(ctx sdk.Context) (claims []types.Claim) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) From ac990667ec4058ee9f4f805510dce5f26f4b7be7 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 14 Nov 2023 17:43:52 -0800 Subject: [PATCH 27/40] Updated x/supplier/keeper/claim_test.go --- x/supplier/keeper/claim.go | 22 +++++++++--- x/supplier/keeper/claim_test.go | 62 +++++++++++++++++++++++++++------ x/supplier/types/key_claim.go | 6 +--- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 3f6b897a3..2b1d7de7c 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -74,10 +74,6 @@ func (k Keeper) GetClaim(ctx sdk.Context, sessionId, supplierAddr string) (val t return k.getClaimByPrimaryKey(ctx, primaryKey) } - // primaryStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) - // primaryKey := types.ClaimPrimaryKey(claim.SessionId, claim.SupplierAddress) - // primaryStore.Set(primaryKey, claimBz) - // GetAllClaims returns all claim func (k Keeper) GetAllClaims(ctx sdk.Context) (claims []types.Claim) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) @@ -94,7 +90,7 @@ func (k Keeper) GetAllClaims(ctx sdk.Context) (claims []types.Claim) { } // GetClaimsByAddress returns all claims for a given supplier address -func (k Keeper) GetClaimsByAddress(ctx sdk.Context, address sdk.AccAddress) (claims []types.Claim) { +func (k Keeper) GetClaimsByAddress(ctx sdk.Context, address string) (claims []types.Claim) { addressStoreIndex := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimSupplierAddressPrefix)) iterator := sdk.KVStorePrefixIterator(addressStoreIndex, []byte(address)) @@ -132,6 +128,22 @@ func (k Keeper) GetClaimsByHeight(ctx sdk.Context, height uint64) (claims []type return claims } +// GetClaimsByAddress returns all claims matching the given session id +func (k Keeper) GetClaimsBySession(ctx sdk.Context, sessionId string) (claims []types.Claim) { + sessionIdStoreIndex := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + + iterator := sdk.KVStorePrefixIterator(sessionIdStoreIndex, []byte(sessionId)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var val types.Claim + k.cdc.MustUnmarshal(iterator.Value(), &val) + claims = append(claims, val) + } + + return claims +} + // getClaimByPrimaryKey is a helper that retrieves, if exists, the Claim associated with the key provided func (k Keeper) getClaimByPrimaryKey(ctx sdk.Context, primaryKey []byte) (val types.Claim, found bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) diff --git a/x/supplier/keeper/claim_test.go b/x/supplier/keeper/claim_test.go index 7b9a997f6..c60403a45 100644 --- a/x/supplier/keeper/claim_test.go +++ b/x/supplier/keeper/claim_test.go @@ -23,28 +23,29 @@ func createNClaims(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Claim for i := range claims { claims[i].SupplierAddress = sample.AccAddress() claims[i].SessionId = fmt.Sprintf("session-%d", i) + claims[i].SessionEndBlockHeight = uint64(i) claims[i].RootHash = []byte(fmt.Sprintf("rootHash-%d", i)) keeper.InsertClaim(ctx, claims[i]) } return claims } -func TestClaimGet(t *testing.T) { +func TestClaim_Get(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) claims := createNClaims(keeper, ctx, 10) for _, claim := range claims { - rst, found := keeper.GetClaim(ctx, + foundClaim, isClaimFound := keeper.GetClaim(ctx, claim.SessionId, claim.SupplierAddress, ) - require.True(t, found) + require.True(t, isClaimFound) require.Equal(t, nullify.Fill(&claim), - nullify.Fill(&rst), + nullify.Fill(&foundClaim), ) } } -func TestClaimRemove(t *testing.T) { +func TestClaim_Remove(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) claims := createNClaims(keeper, ctx, 10) for _, claim := range claims { @@ -52,19 +53,58 @@ func TestClaimRemove(t *testing.T) { claim.SessionId, claim.SupplierAddress, ) - _, found := keeper.GetClaim(ctx, + _, isClaimFound := keeper.GetClaim(ctx, claim.SessionId, claim.SupplierAddress, ) - require.False(t, found) + require.False(t, isClaimFound) } } -func TestGetAllClaims(t *testing.T) { +func TestClaim_GetAll(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) - items := createNClaims(keeper, ctx, 10) + claims := createNClaims(keeper, ctx, 10) + + // Get all the claims and check if they match + allFoundClaims := keeper.GetAllClaims(ctx) + require.ElementsMatch(t, + nullify.Fill(claims), + nullify.Fill(allFoundClaims), + ) +} + +func TestClaim_GetAll_ByAddress(t *testing.T) { + keeper, ctx := keepertest.SupplierKeeper(t) + claims := createNClaims(keeper, ctx, 10) + + // Get all claims for a given address + allFoundClaimsByAddress := keeper.GetClaimsByAddress(ctx, claims[3].SupplierAddress) + require.ElementsMatch(t, + nullify.Fill([]types.Claim{claims[3]}), + nullify.Fill(allFoundClaimsByAddress), + ) +} + +func TestClaim_GetAll_ByHeight(t *testing.T) { + keeper, ctx := keepertest.SupplierKeeper(t) + claims := createNClaims(keeper, ctx, 10) + + // Get all claims for a given ending session block height + allFoundClaimsEndingAtHeight := keeper.GetClaimsByHeight(ctx, claims[6].SessionEndBlockHeight) + require.ElementsMatch(t, + nullify.Fill([]types.Claim{claims[6]}), + nullify.Fill(allFoundClaimsEndingAtHeight), + ) +} + +func TestClaim_GetAll_BySession(t *testing.T) { + keeper, ctx := keepertest.SupplierKeeper(t) + claims := createNClaims(keeper, ctx, 10) + + // Get all claims for a given ending session block height + allFoundClaimsForSession := keeper.GetClaimsBySession(ctx, claims[8].SessionId) require.ElementsMatch(t, - nullify.Fill(items), - nullify.Fill(keeper.GetAllClaims(ctx)), + nullify.Fill([]types.Claim{claims[8]}), + nullify.Fill(allFoundClaimsForSession), ) } diff --git a/x/supplier/types/key_claim.go b/x/supplier/types/key_claim.go index d18226c52..03186bf15 100644 --- a/x/supplier/types/key_claim.go +++ b/x/supplier/types/key_claim.go @@ -6,13 +6,9 @@ import ( var _ binary.ByteOrder -var ( - CountKey = KeyPrefix("count") -) - const ( - // ClaimPrimaryKeyPrefix is the prefix to retrieve all Claim (the primary store) + // ClaimPrimaryKeyPrefix is the prefix to retrieve the entire Claim object (the primary store) ClaimPrimaryKeyPrefix = "Claim/value/" // ClaimSupplierAddressPrefix is the key to retrieve a Claim's Primary Key from the Address index From a26e9c8b4e022e085861ff7f7b6019bfc48b8416 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 14 Nov 2023 17:53:58 -0800 Subject: [PATCH 28/40] Fixed TestClaim_QuerySingle --- x/supplier/keeper/query_claim.go | 5 +++++ x/supplier/keeper/query_claim_test.go | 18 +++++++++++++----- x/supplier/types/query_get_claim.go | 3 +++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 15dd065f3..8b4b4724b 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -44,6 +44,11 @@ func (k Keeper) Claim(goCtx context.Context, req *types.QueryGetClaimRequest) (* if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } + + if err := req.ValidateBasic(); err != nil { + return nil, err + } + ctx := sdk.UnwrapSDKContext(goCtx) val, found := k.GetClaim( diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index 6b0abbcfd..9940e2f27 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -15,7 +15,7 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) -func TestClaimQuerySingle(t *testing.T) { +func TestClaim_QuerySingle(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) wctx := sdk.WrapSDKContext(ctx) claims := createNClaims(keeper, ctx, 2) @@ -69,13 +69,21 @@ func TestClaimQuerySingle(t *testing.T) { }, { desc: "InvalidRequest - Missing SessionId", + request: &types.QueryGetClaimRequest{ + // SessionId: Intentionally Omitted + SupplierAddress: claims[0].SupplierAddress, + }, - err: status.Error(codes.InvalidArgument, "invalid request"), + err: types.ErrSupplierInvalidSessionId, }, { - desc: "InvalidRequest - Missing SessionId", + desc: "InvalidRequest - Missing SupplierAddress", + request: &types.QueryGetClaimRequest{ + SessionId: claims[0].SessionId, + // SupplierAddress: Intentionally Omitted, + }, - err: status.Error(codes.InvalidArgument, "invalid request"), + err: types.ErrSupplierInvalidAddress, }, } for _, tc := range tests { @@ -94,7 +102,7 @@ func TestClaimQuerySingle(t *testing.T) { } } -func TestClaimQueryPaginated(t *testing.T) { +func TestClaim_QueryPaginated(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) wctx := sdk.WrapSDKContext(ctx) msgs := createNClaims(keeper, ctx, 5) diff --git a/x/supplier/types/query_get_claim.go b/x/supplier/types/query_get_claim.go index 92be4e0d2..0b7e1623f 100644 --- a/x/supplier/types/query_get_claim.go +++ b/x/supplier/types/query_get_claim.go @@ -19,6 +19,9 @@ func (query *QueryGetClaimRequest) ValidateBasic() error { } // TODO_TECHDEBT: Validate the session ID once we have a deterministic way to generate it + if query.SessionId == "" { + return sdkerrors.Wrapf(ErrSupplierInvalidSessionId, "invalid session ID for claim being retrieved %s", query.SessionId) + } return nil } From 6c5161d61c0e40c9914b59edb62f3cecccd9a71f Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 14 Nov 2023 19:03:02 -0800 Subject: [PATCH 29/40] Implemented filtered paginated claim queries --- x/supplier/keeper/query_claim.go | 50 ++++++++++++++++++++++++--- x/supplier/keeper/query_claim_test.go | 44 +++++++++++++++++++---- 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 8b4b4724b..79418dedb 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "encoding/binary" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -17,16 +18,55 @@ func (k Keeper) AllClaims(goCtx context.Context, req *types.QueryAllClaimsReques return nil, status.Error(codes.InvalidArgument, "invalid request") } - var claims []types.Claim ctx := sdk.UnwrapSDKContext(goCtx) - store := ctx.KVStore(k.storeKey) - claimStore := prefix.NewStore(store, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + // isCustomIndex is used to determined if we'll be using the store that points + // to the actual Claim values, or a secondary index that points to the primary keys. + var isCustomIndex bool + var claimStore sdk.KVStore + switch filter := req.Filter.(type) { + case *types.QueryAllClaimsRequest_SupplierAddress: + isCustomIndex = true + keyPrefix := types.KeyPrefix(types.ClaimSupplierAddressPrefix) + keyPrefix = append(keyPrefix, []byte(filter.SupplierAddress)...) + claimStore = prefix.NewStore(store, keyPrefix) + + case *types.QueryAllClaimsRequest_SessionEndHeight: + isCustomIndex = true + heightBz := make([]byte, 8) + binary.BigEndian.PutUint64(heightBz, filter.SessionEndHeight) + + keyPrefix := types.KeyPrefix(types.ClaimSessionEndHeightPrefix) + keyPrefix = append(keyPrefix, heightBz...) + claimStore = prefix.NewStore(store, keyPrefix) + + case *types.QueryAllClaimsRequest_SessionId: + isCustomIndex = false + keyPrefix := types.KeyPrefix(types.ClaimPrimaryKeyPrefix) + keyPrefix = append(keyPrefix, []byte(filter.SessionId)...) + claimStore = prefix.NewStore(store, keyPrefix) + + default: + isCustomIndex = false + keyPrefix := types.KeyPrefix(types.ClaimPrimaryKeyPrefix) + claimStore = prefix.NewStore(store, keyPrefix) + } + + var claims []types.Claim pageRes, err := query.Paginate(claimStore, req.Pagination, func(key []byte, value []byte) error { var claim types.Claim - if err := k.cdc.Unmarshal(value, &claim); err != nil { - return err + if isCustomIndex { + // We retrieve the primaryKey, and need to query the actual Claim before decoding it. + claim, claimFound := k.getClaimByPrimaryKey(ctx, value) + if claimFound { + claims = append(claims, claim) + } + } else { + // The value is an encoded Claim. + if err := k.cdc.Unmarshal(value, &claim); err != nil { + return err + } } claims = append(claims, claim) diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index 9940e2f27..bb7265129 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -105,7 +105,7 @@ func TestClaim_QuerySingle(t *testing.T) { func TestClaim_QueryPaginated(t *testing.T) { keeper, ctx := keepertest.SupplierKeeper(t) wctx := sdk.WrapSDKContext(ctx) - msgs := createNClaims(keeper, ctx, 5) + claims := createNClaims(keeper, ctx, 10) request := func(next []byte, offset, limit uint64, total bool) *types.QueryAllClaimsRequest { return &types.QueryAllClaimsRequest{ @@ -119,12 +119,12 @@ func TestClaim_QueryPaginated(t *testing.T) { } t.Run("ByOffset", func(t *testing.T) { step := 2 - for i := 0; i < len(msgs); i += step { + for i := 0; i < len(claims); i += step { resp, err := keeper.AllClaims(wctx, request(nil, uint64(i), uint64(step), false)) require.NoError(t, err) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, - nullify.Fill(msgs), + nullify.Fill(claims), nullify.Fill(resp.Claim), ) } @@ -132,12 +132,12 @@ func TestClaim_QueryPaginated(t *testing.T) { t.Run("ByKey", func(t *testing.T) { step := 2 var next []byte - for i := 0; i < len(msgs); i += step { + for i := 0; i < len(claims); i += step { resp, err := keeper.AllClaims(wctx, request(next, 0, uint64(step), false)) require.NoError(t, err) require.LessOrEqual(t, len(resp.Claim), step) require.Subset(t, - nullify.Fill(msgs), + nullify.Fill(claims), nullify.Fill(resp.Claim), ) next = resp.Pagination.NextKey @@ -146,9 +146,9 @@ func TestClaim_QueryPaginated(t *testing.T) { t.Run("Total", func(t *testing.T) { resp, err := keeper.AllClaims(wctx, request(nil, 0, 0, true)) require.NoError(t, err) - require.Equal(t, len(msgs), int(resp.Pagination.Total)) + require.Equal(t, len(claims), int(resp.Pagination.Total)) require.ElementsMatch(t, - nullify.Fill(msgs), + nullify.Fill(claims), nullify.Fill(resp.Claim), ) }) @@ -156,4 +156,34 @@ func TestClaim_QueryPaginated(t *testing.T) { _, err := keeper.AllClaims(wctx, nil) require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request")) }) + + t.Run("BySupplierAddress", func(t *testing.T) { + req := request(nil, 0, 0, true) + req.Filter = &types.QueryAllClaimsRequest_SupplierAddress{ + SupplierAddress: claims[0].SupplierAddress, + } + resp, err := keeper.AllClaims(wctx, req) + require.NoError(t, err) + require.Equal(t, 1, int(resp.Pagination.Total)) + }) + + t.Run("BySessionId", func(t *testing.T) { + req := request(nil, 0, 0, true) + req.Filter = &types.QueryAllClaimsRequest_SessionId{ + SessionId: claims[0].SessionId, + } + resp, err := keeper.AllClaims(wctx, req) + require.NoError(t, err) + require.Equal(t, 1, int(resp.Pagination.Total)) + }) + + t.Run("BySessionEndHeight", func(t *testing.T) { + req := request(nil, 0, 0, true) + req.Filter = &types.QueryAllClaimsRequest_SessionEndHeight{ + SessionEndHeight: claims[0].SessionEndBlockHeight, + } + resp, err := keeper.AllClaims(wctx, req) + require.NoError(t, err) + require.Equal(t, 1, int(resp.Pagination.Total)) + }) } From 58ab0d2bbe3b3927e223bd282f7bafdc77b83970 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 14 Nov 2023 20:36:17 -0800 Subject: [PATCH 30/40] Left 4 TODO_IN_THIS_PR after some debugging but still hitting issues with tets --- Makefile | 1 + testutil/network/network.go | 23 +++++++ x/supplier/client/cli/query_claim.go | 2 +- x/supplier/client/cli/query_claim_test.go | 79 ++++++++++++++++------- x/supplier/client/cli/tx_create_claim.go | 9 ++- x/supplier/keeper/claim.go | 2 +- 6 files changed, 87 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index c7003a0fb..0ca7b416e 100644 --- a/Makefile +++ b/Makefile @@ -476,6 +476,7 @@ claim_list_height: ## List all the claims ending at a specific height (specified claim_list_height_5: ## List all the claims at height 5 HEIGHT=5 make claim_list_height +# TODO_IN_THIS_PR: Test and uncomment this. # .PHONY: claim_list_session # claim_list_session: ## List all the claims ending at a specific session (specified via SESSION variable) # poktrolld --home=$(POKTROLLD_HOME) q supplier list-claims session $(SESSION) --node $(POCKET_NODE) diff --git a/testutil/network/network.go b/testutil/network/network.go index 28f4eaa2f..529b44700 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -172,6 +172,29 @@ func DefaultSupplierModuleGenesisState(t *testing.T, n int) *suppliertypes.Genes return state } +// SupplierModuleGenesisStateWithAccount generates a GenesisState object with a single supplier with the given address. +func SupplierModuleGenesisStateWithAccount(t *testing.T, address string) *suppliertypes.GenesisState { + t.Helper() + state := suppliertypes.DefaultGenesis() + supplier := sharedtypes.Supplier{ + Address: address, + Stake: &sdk.Coin{Denom: "upokt", Amount: sdk.NewInt(10000)}, + Services: []*sharedtypes.SupplierServiceConfig{ + { + Service: &sharedtypes.Service{Id: "svc1"}, + Endpoints: []*sharedtypes.SupplierEndpoint{ + { + Url: "http://localhost:1", + RpcType: sharedtypes.RPCType_JSON_RPC, + }, + }, + }, + }, + } + state.SupplierList = append(state.SupplierList, supplier) + return state +} + // Initialize an Account by sending it some funds from the validator in the network to the address provided func InitAccount(t *testing.T, net *Network, addr sdk.AccAddress) { t.Helper() diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index cecd92b62..3e15caa19 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -67,7 +67,7 @@ $ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --supplier-address Date: Wed, 15 Nov 2023 19:29:53 -0800 Subject: [PATCH 31/40] This test passes: go test -v -run TestClaim_Show ./x/supplier/client/cli/... --- go.mod | 4 +-- x/application/keeper/query_application.go | 3 ++- x/gateway/keeper/query_gateway.go | 3 ++- x/supplier/client/cli/query_claim.go | 1 - x/supplier/client/cli/query_claim_test.go | 8 +++--- x/supplier/client/cli/query_supplier_test.go | 26 ++++++++++---------- x/supplier/keeper/query_claim.go | 3 ++- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index adbedcf85..da331e2f6 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/athanorlabs/go-dleq v0.1.0 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -31,7 +30,6 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -75,6 +73,7 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -270,6 +269,7 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/x/application/keeper/query_application.go b/x/application/keeper/query_application.go index 1a6b2a1b7..e9275df92 100644 --- a/x/application/keeper/query_application.go +++ b/x/application/keeper/query_application.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "fmt" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -51,7 +52,7 @@ func (k Keeper) Application(goCtx context.Context, req *types.QueryGetApplicatio req.Address, ) if !found { - return nil, status.Error(codes.NotFound, "not found") + return nil, status.Error(codes.NotFound, fmt.Sprintf("application with address %s not found", req.Address)) } return &types.QueryGetApplicationResponse{Application: val}, nil diff --git a/x/gateway/keeper/query_gateway.go b/x/gateway/keeper/query_gateway.go index bd0576a2d..ddfd3b30a 100644 --- a/x/gateway/keeper/query_gateway.go +++ b/x/gateway/keeper/query_gateway.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "fmt" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -51,7 +52,7 @@ func (k Keeper) Gateway(goCtx context.Context, req *types.QueryGetGatewayRequest req.Address, ) if !found { - return nil, status.Error(codes.NotFound, "not found") + return nil, status.Error(codes.NotFound, fmt.Sprintf("gateways with address %s not found", req.Address)) } return &types.QueryGetGatewayResponse{Gateway: val}, nil diff --git a/x/supplier/client/cli/query_claim.go b/x/supplier/client/cli/query_claim.go index 3e15caa19..26a667a3b 100644 --- a/x/supplier/client/cli/query_claim.go +++ b/x/supplier/client/cli/query_claim.go @@ -67,7 +67,6 @@ $ poktrolld --home=$(POKTROLLD_HOME) q claim list-claims --supplier-address Date: Thu, 16 Nov 2023 11:09:22 -0800 Subject: [PATCH 32/40] TestClaim_List works but need to clean up the tests --- testutil/network/network.go | 56 +++++-- x/supplier/client/cli/query_claim_test.go | 148 +++++++++++++++---- x/supplier/keeper/msg_server_create_claim.go | 3 +- x/supplier/keeper/query_claim.go | 16 +- 4 files changed, 169 insertions(+), 54 deletions(-) diff --git a/testutil/network/network.go b/testutil/network/network.go index 529b44700..fc799db89 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -173,25 +173,28 @@ func DefaultSupplierModuleGenesisState(t *testing.T, n int) *suppliertypes.Genes } // SupplierModuleGenesisStateWithAccount generates a GenesisState object with a single supplier with the given address. -func SupplierModuleGenesisStateWithAccount(t *testing.T, address string) *suppliertypes.GenesisState { +func SupplierModuleGenesisStateWithAccounts(t *testing.T, addresses []string) *suppliertypes.GenesisState { t.Helper() state := suppliertypes.DefaultGenesis() - supplier := sharedtypes.Supplier{ - Address: address, - Stake: &sdk.Coin{Denom: "upokt", Amount: sdk.NewInt(10000)}, - Services: []*sharedtypes.SupplierServiceConfig{ - { - Service: &sharedtypes.Service{Id: "svc1"}, - Endpoints: []*sharedtypes.SupplierEndpoint{ - { - Url: "http://localhost:1", - RpcType: sharedtypes.RPCType_JSON_RPC, + for _, addr := range addresses { + supplier := sharedtypes.Supplier{ + Address: addr, + Stake: &sdk.Coin{Denom: "upokt", Amount: sdk.NewInt(10000)}, + Services: []*sharedtypes.SupplierServiceConfig{ + { + Service: &sharedtypes.Service{Id: "svc1"}, + Endpoints: []*sharedtypes.SupplierEndpoint{ + { + Url: "http://localhost:1", + RpcType: sharedtypes.RPCType_JSON_RPC, + }, }, }, }, - }, + } + state.SupplierList = append(state.SupplierList, supplier) } - state.SupplierList = append(state.SupplierList, supplier) + return state } @@ -210,3 +213,30 @@ func InitAccount(t *testing.T, net *Network, addr sdk.AccAddress) { _, err := clitestutil.MsgSendExec(ctx, val.Address, addr, amount, args...) require.NoError(t, err) } + +// Initialize an Account by sending it some funds from the validator in the network to the address provided +func InitAccountWithSequence( + t *testing.T, + net *Network, + addr sdk.AccAddress, + signerAccountNumber int, + signatureSequencerNumber int, +) { + t.Helper() + val := net.Validators[0] + ctx := val.ClientCtx + args := []string{ + fmt.Sprintf("--%s=true", flags.FlagOffline), + fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, signerAccountNumber), + fmt.Sprintf("--%s=%d", flags.FlagSequence, signatureSequencerNumber), + + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(net.Config.BondDenom, sdkmath.NewInt(10))).String()), + } + amount := sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(200))) + res, err := clitestutil.MsgSendExec(ctx, val.Address, addr, amount, args...) + require.NoError(t, err) + fmt.Println("OLSH 000", res) +} diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 91621e6aa..d3c9bbf3f 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -27,28 +27,34 @@ import ( "github.com/pokt-network/poktroll/x/supplier/types" ) +// TODO_TECHDEBT: This should not be hardcoded once the num blocks per session is configurable +const numBlocksPerSession = 4 + func encodeSessionHeader(t *testing.T, sessionId string, sessionEndHeight int64) string { t.Helper() argSessionHeader := &sessiontypes.SessionHeader{ ApplicationAddress: sample.AccAddress(), - SessionStartBlockHeight: 1, + SessionStartBlockHeight: sessionEndHeight - numBlocksPerSession, SessionId: sessionId, SessionEndBlockHeight: sessionEndHeight, - Service: &sharedtypes.Service{ - Id: "anvil", - }, + Service: &sharedtypes.Service{Id: "anvil"}, // hardcoded for simplicity } cdc := codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) sessionHeaderBz := cdc.MustMarshalJSON(argSessionHeader) return base64.StdEncoding.EncodeToString(sessionHeaderBz) } -func createClaim(t *testing.T, net *network.Network, ctx client.Context, supplierAddr string) *types.Claim { +func createClaim( + t *testing.T, + net *network.Network, + ctx client.Context, + sessionId string, + supplierAddr string, + sessionEndHeight int64, +) *types.Claim { t.Helper() - sessionEndHeight := int64(5) - sessionId := "session_id" rootHash := []byte("root_hash") sessionHeaderEncoded := encodeSessionHeader(t, sessionId, sessionEndHeight) rootHashEncoded := base64.StdEncoding.EncodeToString(rootHash) @@ -56,6 +62,11 @@ func createClaim(t *testing.T, net *network.Network, ctx client.Context, supplie args := []string{ sessionHeaderEncoded, rootHashEncoded, + + // fmt.Sprintf("--%s=true", flags.FlagOffline), + // fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, signerAccountNumber), + // fmt.Sprintf("--%s=%d", flags.FlagSequence, signatureSequencerNumber), + fmt.Sprintf("--%s=%s", flags.FlagFrom, supplierAddr), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), @@ -64,6 +75,7 @@ func createClaim(t *testing.T, net *network.Network, ctx client.Context, supplie _, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdCreateClaim(), args) require.NoError(t, err) + // fmt.Println("TODO_IN_THIS_PR - understand the error around account sequence numbers: ", res) return &types.Claim{ SupplierAddress: supplierAddr, @@ -73,7 +85,11 @@ func createClaim(t *testing.T, net *network.Network, ctx client.Context, supplie } } -func networkWithClaimObjects(t *testing.T, n int) (net *network.Network, claims []types.Claim) { +func networkWithClaimObjects( + t *testing.T, + numSessions int, + numClaimsPerSession int, +) (net *network.Network, claims []types.Claim) { t.Helper() // Prepare the network @@ -83,37 +99,50 @@ func networkWithClaimObjects(t *testing.T, n int) (net *network.Network, claims // Prepare the keyring for the supplier account kr := ctx.Keyring - accounts := testutil.CreateKeyringAccounts(t, kr, 1) - supplierAccount := accounts[0] - supplierAddress := supplierAccount.Address.String() - - // Update the context with the new keyring + accounts := testutil.CreateKeyringAccounts(t, kr, numClaimsPerSession) ctx = ctx.WithKeyring(kr) - // Initialize the supplier account - network.InitAccount(t, net, supplierAccount.Address) + // Initialize all the accounts + for i, account := range accounts { + // network.InitAccount(t, net, account.Address) + network.InitAccountWithSequence(t, net, account.Address, 0, i+1) + } // need to wait for the account to be initialized in the next block require.NoError(t, net.WaitForNextBlock()) + addresses := make([]string, len(accounts)) + for i, account := range accounts { + addresses[i] = account.Address.String() + } + // Create one supplier - supplierGenesisState := network.SupplierModuleGenesisStateWithAccount(t, supplierAddress) + supplierGenesisState := network.SupplierModuleGenesisStateWithAccounts(t, addresses) buf, err := cfg.Codec.MarshalJSON(supplierGenesisState) require.NoError(t, err) cfg.GenesisState[types.ModuleName] = buf // Create n claims for the supplier - for i := 0; i < n; i++ { - claim := createClaim(t, net, ctx, supplierAddress) - claims = append(claims, *claim) + sessionEndHeight := int64(1) + for sessionNum := 0; sessionNum < numSessions; sessionNum++ { + sessionEndHeight += numBlocksPerSession + sessionId := fmt.Sprintf("session_id%d", sessionNum) + for claimNum := 0; claimNum < numClaimsPerSession; claimNum++ { + claim := createClaim(t, net, ctx, sessionId, addresses[claimNum], sessionEndHeight) + claims = append(claims, *claim) + // TODO_IN_THIS_PR: Figure out why putting this AFTER the leads to an error + // need to wait for the claims to be stored on-chain in the next block + require.NoError(t, net.WaitForNextBlock()) + } } - // need to wait for the claims to be stored on-chain in the next block - require.NoError(t, net.WaitForNextBlock()) return net, claims } func TestClaim_Show(t *testing.T) { - net, claims := networkWithClaimObjects(t, 2) + numSessions := 1 + numClaimsPerSession := 2 + + net, claims := networkWithClaimObjects(t, numSessions, numClaimsPerSession) ctx := net.Validators[0].ClientCtx common := []string{ @@ -180,12 +209,16 @@ func TestClaim_Show(t *testing.T) { } func TestClaim_List(t *testing.T) { - net, claims := networkWithClaimObjects(t, 5) + numSessions := 2 + numClaimsPerSession := 5 + totalClaims := numSessions * numClaimsPerSession + + net, claims := networkWithClaimObjects(t, numSessions, numClaimsPerSession) ctx := net.Validators[0].ClientCtx - request := func(next []byte, offset, limit uint64, total bool) []string { + prepareArgs := func(next []byte, offset, limit uint64, total bool) []string { args := []string{ - // fmt.Sprintf("--%s=json", tmcli.OutputFlag), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), } if next == nil { args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) @@ -201,8 +234,8 @@ func TestClaim_List(t *testing.T) { t.Run("ByOffset", func(t *testing.T) { step := 2 - for i := 0; i < len(claims); i += step { - args := request(nil, uint64(i), uint64(step), false) + for i := 0; i < totalClaims; i += step { + args := prepareArgs(nil, uint64(i), uint64(step), false) out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) require.NoError(t, err) @@ -216,11 +249,12 @@ func TestClaim_List(t *testing.T) { ) } }) + t.Run("ByKey", func(t *testing.T) { step := 2 var next []byte - for i := 0; i < len(claims); i += step { - args := request(next, 0, uint64(step), false) + for i := 0; i < totalClaims; i += step { + args := prepareArgs(next, 0, uint64(step), false) out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) require.NoError(t, err) @@ -235,15 +269,67 @@ func TestClaim_List(t *testing.T) { next = resp.Pagination.NextKey } }) + + t.Run("ByAddress", func(t *testing.T) { + args := prepareArgs(nil, 0, uint64(totalClaims), true) + args = append(args, fmt.Sprintf("--%s=%s", cli.FlagSupplierAddress, claims[0].SupplierAddress)) + + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) + require.NoError(t, err) + + var resp types.QueryAllClaimsResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + + require.Equal(t, numSessions, int(resp.Pagination.Total)) + // require.ElementsMatch(t, + // nullify.Fill(claims), + // nullify.Fill(resp.Claim), + // ) + }) + + t.Run("BySession", func(t *testing.T) { + args := prepareArgs(nil, 0, uint64(totalClaims), true) + args = append(args, fmt.Sprintf("--%s=%s", cli.FlagSessionId, claims[0].SessionId)) + + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) + require.NoError(t, err) + + var resp types.QueryAllClaimsResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + + require.Equal(t, numClaimsPerSession, int(resp.Pagination.Total)) + // require.ElementsMatch(t, + // nullify.Fill(claims), + // nullify.Fill(resp.Claim), + // ) + }) + + t.Run("ByHeight", func(t *testing.T) { + args := prepareArgs(nil, 0, uint64(totalClaims), true) + args = append(args, fmt.Sprintf("--%s=%d", cli.FlagSessionEndHeight, claims[0].SessionEndBlockHeight)) + + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) + require.NoError(t, err) + + var resp types.QueryAllClaimsResponse + require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + + require.Equal(t, numClaimsPerSession, int(resp.Pagination.Total)) + // require.ElementsMatch(t, + // nullify.Fill(claims), + // nullify.Fill(resp.Claim), + // ) + }) + t.Run("Total", func(t *testing.T) { - args := request(nil, 0, uint64(len(claims)), true) + args := prepareArgs(nil, 0, uint64(totalClaims), true) out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) require.NoError(t, err) var resp types.QueryAllClaimsResponse require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) - require.Equal(t, len(claims), int(resp.Pagination.Total)) + require.Equal(t, totalClaims, int(resp.Pagination.Total)) require.ElementsMatch(t, nullify.Fill(claims), nullify.Fill(resp.Claim), diff --git a/x/supplier/keeper/msg_server_create_claim.go b/x/supplier/keeper/msg_server_create_claim.go index ad28d2a2d..7a7722294 100644 --- a/x/supplier/keeper/msg_server_create_claim.go +++ b/x/supplier/keeper/msg_server_create_claim.go @@ -25,9 +25,10 @@ func (k msgServer) CreateClaim(goCtx context.Context, msg *types.MsgCreateClaim) k.Keeper.InsertClaim(ctx, claim) logger.Info("created claim for supplier %s at session ending height %d", claim.SupplierAddress, claim.SessionEndBlockHeight) + logger.Info("TODO_INCOMPLETE: Handling actual claim business logic %s", claim.SessionId) /* - INCOMPLETE: Handling the message + TODO_INCOMPLETE: Handling the message ## Validation diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 74146733a..a446bf5f1 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -25,34 +25,31 @@ func (k Keeper) AllClaims(goCtx context.Context, req *types.QueryAllClaimsReques // isCustomIndex is used to determined if we'll be using the store that points // to the actual Claim values, or a secondary index that points to the primary keys. var isCustomIndex bool - var claimStore sdk.KVStore + var keyPrefix []byte switch filter := req.Filter.(type) { case *types.QueryAllClaimsRequest_SupplierAddress: isCustomIndex = true - keyPrefix := types.KeyPrefix(types.ClaimSupplierAddressPrefix) + keyPrefix = types.KeyPrefix(types.ClaimSupplierAddressPrefix) keyPrefix = append(keyPrefix, []byte(filter.SupplierAddress)...) - claimStore = prefix.NewStore(store, keyPrefix) case *types.QueryAllClaimsRequest_SessionEndHeight: isCustomIndex = true heightBz := make([]byte, 8) binary.BigEndian.PutUint64(heightBz, filter.SessionEndHeight) - keyPrefix := types.KeyPrefix(types.ClaimSessionEndHeightPrefix) + keyPrefix = types.KeyPrefix(types.ClaimSessionEndHeightPrefix) keyPrefix = append(keyPrefix, heightBz...) - claimStore = prefix.NewStore(store, keyPrefix) case *types.QueryAllClaimsRequest_SessionId: isCustomIndex = false - keyPrefix := types.KeyPrefix(types.ClaimPrimaryKeyPrefix) + keyPrefix = types.KeyPrefix(types.ClaimPrimaryKeyPrefix) keyPrefix = append(keyPrefix, []byte(filter.SessionId)...) - claimStore = prefix.NewStore(store, keyPrefix) default: isCustomIndex = false - keyPrefix := types.KeyPrefix(types.ClaimPrimaryKeyPrefix) - claimStore = prefix.NewStore(store, keyPrefix) + keyPrefix = types.KeyPrefix(types.ClaimPrimaryKeyPrefix) } + claimStore := prefix.NewStore(store, keyPrefix) var claims []types.Claim pageRes, err := query.Paginate(claimStore, req.Pagination, func(key []byte, value []byte) error { @@ -64,6 +61,7 @@ func (k Keeper) AllClaims(goCtx context.Context, req *types.QueryAllClaimsReques claims = append(claims, claim) } } else { + fmt.Println("OLSH HERE") // The value is an encoded Claim. if err := k.cdc.Unmarshal(value, &claim); err != nil { return err From d5d3cb577018287e582bb26c5ebb292943875228 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 16 Nov 2023 13:15:17 -0800 Subject: [PATCH 33/40] Checkpoint where tests pass --- go.mod | 4 ++-- testutil/network/network.go | 16 +++++++++---- x/supplier/client/cli/query_claim_test.go | 28 +++++++++++------------ x/supplier/client/cli/tx_create_claim.go | 1 + x/supplier/keeper/query_claim.go | 1 - 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index da331e2f6..adbedcf85 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/athanorlabs/go-dleq v0.1.0 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -30,6 +31,7 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.12.0 golang.org/x/sync v0.3.0 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -73,7 +75,6 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -269,7 +270,6 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/testutil/network/network.go b/testutil/network/network.go index fc799db89..d05c283be 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -1,6 +1,7 @@ package network import ( + "encoding/json" "fmt" "testing" "time" @@ -210,8 +211,12 @@ func InitAccount(t *testing.T, net *Network, addr sdk.AccAddress) { fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(net.Config.BondDenom, sdkmath.NewInt(10))).String()), } amount := sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(200))) - _, err := clitestutil.MsgSendExec(ctx, val.Address, addr, amount, args...) + responseRaw, err := clitestutil.MsgSendExec(ctx, val.Address, addr, amount, args...) require.NoError(t, err) + var responseJson map[string]interface{} + err = json.Unmarshal(responseRaw.Bytes(), &responseJson) + require.NoError(t, err) + require.Equal(t, float64(0), responseJson["code"], "code is not 0 in the response: %v", responseJson) } // Initialize an Account by sending it some funds from the validator in the network to the address provided @@ -219,11 +224,11 @@ func InitAccountWithSequence( t *testing.T, net *Network, addr sdk.AccAddress, - signerAccountNumber int, signatureSequencerNumber int, ) { t.Helper() val := net.Validators[0] + signerAccountNumber := 0 ctx := val.ClientCtx args := []string{ fmt.Sprintf("--%s=true", flags.FlagOffline), @@ -236,7 +241,10 @@ func InitAccountWithSequence( fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(net.Config.BondDenom, sdkmath.NewInt(10))).String()), } amount := sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(200))) - res, err := clitestutil.MsgSendExec(ctx, val.Address, addr, amount, args...) + responseRaw, err := clitestutil.MsgSendExec(ctx, val.Address, addr, amount, args...) + require.NoError(t, err) + var responseJson map[string]interface{} + err = json.Unmarshal(responseRaw.Bytes(), &responseJson) require.NoError(t, err) - fmt.Println("OLSH 000", res) + require.Equal(t, float64(0), responseJson["code"], "code is not 0 in the response: %v", responseJson) } diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index d3c9bbf3f..36b47d885 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -2,6 +2,7 @@ package cli_test import ( "encoding/base64" + "encoding/json" "fmt" "testing" @@ -49,8 +50,8 @@ func createClaim( t *testing.T, net *network.Network, ctx client.Context, - sessionId string, supplierAddr string, + sessionId string, sessionEndHeight int64, ) *types.Claim { t.Helper() @@ -62,20 +63,18 @@ func createClaim( args := []string{ sessionHeaderEncoded, rootHashEncoded, - - // fmt.Sprintf("--%s=true", flags.FlagOffline), - // fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, signerAccountNumber), - // fmt.Sprintf("--%s=%d", flags.FlagSequence, signatureSequencerNumber), - fmt.Sprintf("--%s=%s", flags.FlagFrom, supplierAddr), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(net.Config.BondDenom, sdkmath.NewInt(10))).String()), } - _, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdCreateClaim(), args) + responseRaw, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdCreateClaim(), args) + require.NoError(t, err) + var responseJson map[string]interface{} + err = json.Unmarshal(responseRaw.Bytes(), &responseJson) require.NoError(t, err) - // fmt.Println("TODO_IN_THIS_PR - understand the error around account sequence numbers: ", res) + require.Equal(t, float64(0), responseJson["code"], "code is not 0 in the response: %v", responseJson) return &types.Claim{ SupplierAddress: supplierAddr, @@ -104,8 +103,8 @@ func networkWithClaimObjects( // Initialize all the accounts for i, account := range accounts { - // network.InitAccount(t, net, account.Address) - network.InitAccountWithSequence(t, net, account.Address, 0, i+1) + signatureSequenceNumber := i + 1 + network.InitAccountWithSequence(t, net, account.Address, signatureSequenceNumber) } // need to wait for the account to be initialized in the next block require.NoError(t, net.WaitForNextBlock()) @@ -121,19 +120,18 @@ func networkWithClaimObjects( require.NoError(t, err) cfg.GenesisState[types.ModuleName] = buf - // Create n claims for the supplier + // Create numSessions * numClaimsPerSession claims for the supplier sessionEndHeight := int64(1) for sessionNum := 0; sessionNum < numSessions; sessionNum++ { sessionEndHeight += numBlocksPerSession sessionId := fmt.Sprintf("session_id%d", sessionNum) for claimNum := 0; claimNum < numClaimsPerSession; claimNum++ { - claim := createClaim(t, net, ctx, sessionId, addresses[claimNum], sessionEndHeight) + supplierAddr := addresses[claimNum] + claim := createClaim(t, net, ctx, supplierAddr, sessionId, sessionEndHeight) claims = append(claims, *claim) - // TODO_IN_THIS_PR: Figure out why putting this AFTER the leads to an error - // need to wait for the claims to be stored on-chain in the next block - require.NoError(t, net.WaitForNextBlock()) } } + require.NoError(t, net.WaitForNextBlock()) return net, claims } diff --git a/x/supplier/client/cli/tx_create_claim.go b/x/supplier/client/cli/tx_create_claim.go index 1fb412deb..9fd509e55 100644 --- a/x/supplier/client/cli/tx_create_claim.go +++ b/x/supplier/client/cli/tx_create_claim.go @@ -57,6 +57,7 @@ func CmdCreateClaim() *cobra.Command { if err := msg.ValidateBasic(); err != nil { return err } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index a446bf5f1..1b23d2e50 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -61,7 +61,6 @@ func (k Keeper) AllClaims(goCtx context.Context, req *types.QueryAllClaimsReques claims = append(claims, claim) } } else { - fmt.Println("OLSH HERE") // The value is an encoded Claim. if err := k.cdc.Unmarshal(value, &claim); err != nil { return err From 4ace899951f6bb1d8205f895870bbd44a5ee8210 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 16 Nov 2023 13:25:40 -0800 Subject: [PATCH 34/40] Add TECHDEBT TODO --- x/supplier/client/cli/query_claim_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 36b47d885..c493832bd 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -129,9 +129,10 @@ func networkWithClaimObjects( supplierAddr := addresses[claimNum] claim := createClaim(t, net, ctx, supplierAddr, sessionId, sessionEndHeight) claims = append(claims, *claim) + // TODO_TECHDEBT(#196): Move this outside of the forloop so that the test iteration is faster + require.NoError(t, net.WaitForNextBlock()) } } - require.NoError(t, net.WaitForNextBlock()) return net, claims } From 4f08f7c51691f2f1897801e3c50930c6bfb93422 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 16 Nov 2023 13:28:46 -0800 Subject: [PATCH 35/40] Make claim_create_dummy works --- Makefile | 10 +++++----- x/supplier/client/cli/query_claim_test.go | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 8e3630c9e..eba936e11 100644 --- a/Makefile +++ b/Makefile @@ -455,11 +455,11 @@ acc_balance_total_supply: ## Query the total supply of the network ### Claims ### ############## -# TODO_IN_THIS_PR: Explain where/how I got these; `encodeSessionHeader` in `x/supplier/client/cli/query_claim_test.go` -ENCODED_SESSION_HEADER = "7b226170706c69636174696f6e5f61646472657373223a22706f6b74316d7271743566377168387578733237636a6d397437763965373461397676646e71356a766134222c2273657276696365223a7b226964223a22616e76696c222c226e616d65223a22227d2c2273657373696f6e5f73746172745f626c6f636b5f686569676874223a2231222c2273657373696f6e5f6964223a2273657373696f6e5f6964222c2273657373696f6e5f656e645f626c6f636b5f686569676874223a2235227d" -ENCODED_ROOT_HASH = "726f6f745f68617368" -.PHONY: claim_create -claim_create: ## Create a dummy claim by supplier1 +# These encoded values were generated using the `encodeSessionHeader` helpers in `query_claim_test.go` as dummy values. +ENCODED_SESSION_HEADER = "eyJhcHBsaWNhdGlvbl9hZGRyZXNzIjoicG9rdDFleXJuNDUwa3JoZnpycmVyemd0djd2c3J4bDA5NDN0dXN4azRhayIsInNlcnZpY2UiOnsiaWQiOiJhbnZpbCIsIm5hbWUiOiIifSwic2Vzc2lvbl9zdGFydF9ibG9ja19oZWlnaHQiOiI1Iiwic2Vzc2lvbl9pZCI6InNlc3Npb25faWQxIiwic2Vzc2lvbl9lbmRfYmxvY2tfaGVpZ2h0IjoiOSJ9" +ENCODED_ROOT_HASH = "cm9vdF9oYXNo" +.PHONY: claim_create_dummy +claim_create_dummy: ## Create a dummy claim by supplier1 poktrolld --home=$(POKTROLLD_HOME) tx supplier create-claim \ $(ENCODED_SESSION_HEADER) \ $(ENCODED_ROOT_HASH) \ diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index c493832bd..2b09b57f7 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -60,6 +60,7 @@ func createClaim( sessionHeaderEncoded := encodeSessionHeader(t, sessionId, sessionEndHeight) rootHashEncoded := base64.StdEncoding.EncodeToString(rootHash) + fmt.Println("OLSH", sessionHeaderEncoded, rootHashEncoded) args := []string{ sessionHeaderEncoded, rootHashEncoded, From 0fccf81155446fded055a6c35c2c3db5dac19ada Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 16 Nov 2023 13:44:28 -0800 Subject: [PATCH 36/40] Confirmed that make claim list works --- Makefile | 6 +++--- x/supplier/client/cli/query_claim_test.go | 2 -- x/supplier/keeper/query_claim_test.go | 9 ++++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index eba936e11..aee512d1f 100644 --- a/Makefile +++ b/Makefile @@ -487,9 +487,9 @@ claim_list_height_5: ## List all the claims at height 5 HEIGHT=5 make claim_list_height # TODO_IN_THIS_PR: Test and uncomment this. -# .PHONY: claim_list_session -# claim_list_session: ## List all the claims ending at a specific session (specified via SESSION variable) -# poktrolld --home=$(POKTROLLD_HOME) q supplier list-claims session $(SESSION) --node $(POCKET_NODE) +.PHONY: claim_list_session +claim_list_session: ## List all the claims ending at a specific session (specified via SESSION variable) + poktrolld --home=$(POKTROLLD_HOME) q supplier list-claims --session-id $(SESSION) --node $(POCKET_NODE) ###################### ### Ignite Helpers ### diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 2b09b57f7..457fa452d 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -336,5 +336,3 @@ func TestClaim_List(t *testing.T) { ) }) } - -// TODO_IN_THIS_PR: Add tests that query when querying with address/session/height filters diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index bb7265129..0f41d9469 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -36,6 +36,7 @@ func TestClaim_QuerySingle(t *testing.T) { }, response: &types.QueryGetClaimResponse{Claim: claims[0]}, + err: nil, }, { desc: "Second Claim", @@ -46,6 +47,7 @@ func TestClaim_QuerySingle(t *testing.T) { }, response: &types.QueryGetClaimResponse{Claim: claims[1]}, + err: nil, }, { desc: "Claim Not Found - Random SessionId", @@ -55,7 +57,7 @@ func TestClaim_QuerySingle(t *testing.T) { SupplierAddress: claims[0].SupplierAddress, }, - err: status.Error(codes.NotFound, "not found"), + err: status.Error(codes.NotFound, "claim not found"), }, { desc: "Claim Not Found - Random Supplier Address", @@ -65,7 +67,7 @@ func TestClaim_QuerySingle(t *testing.T) { SupplierAddress: sample.AccAddress(), }, - err: status.Error(codes.NotFound, "not found"), + err: status.Error(codes.NotFound, "claim not found"), }, { desc: "InvalidRequest - Missing SessionId", @@ -90,7 +92,8 @@ func TestClaim_QuerySingle(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { response, err := keeper.Claim(wctx, tc.request) if tc.err != nil { - require.ErrorIs(t, err, tc.err) + require.Error(t, err) + require.ErrorContains(t, err, tc.err.Error()) } else { require.NoError(t, err) require.Equal(t, From cec2da0149a76f36c6641d8840a1e620762679f6 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 16 Nov 2023 16:26:46 -0800 Subject: [PATCH 37/40] Make go_test finally works again --- x/application/client/cli/tx_delegate_to_gateway_test.go | 4 ++-- x/application/client/cli/tx_undelegate_from_gateway_test.go | 4 ++-- x/application/keeper/query_application.go | 2 +- x/application/keeper/query_application_test.go | 4 ++-- x/gateway/keeper/query_gateway.go | 2 +- x/gateway/keeper/query_gateway_test.go | 4 ++-- x/supplier/client/cli/query_claim_test.go | 1 - x/supplier/keeper/query_claim_test.go | 1 - 8 files changed, 10 insertions(+), 12 deletions(-) diff --git a/x/application/client/cli/tx_delegate_to_gateway_test.go b/x/application/client/cli/tx_delegate_to_gateway_test.go index 97ad29a91..22d2630b2 100644 --- a/x/application/client/cli/tx_delegate_to_gateway_test.go +++ b/x/application/client/cli/tx_delegate_to_gateway_test.go @@ -78,8 +78,8 @@ func TestCLI_DelegateToGateway(t *testing.T) { } // Initialize the App and Gateway Accounts by sending it some funds from the validator account that is part of genesis - network.InitAccount(t, net, appAccount.Address) - network.InitAccount(t, net, gatewayAccount.Address) + network.InitAccountWithSequence(t, net, appAccount.Address, 1) + network.InitAccountWithSequence(t, net, gatewayAccount.Address, 2) // Run the tests for _, tt := range tests { diff --git a/x/application/client/cli/tx_undelegate_from_gateway_test.go b/x/application/client/cli/tx_undelegate_from_gateway_test.go index a1c57973d..a5d942268 100644 --- a/x/application/client/cli/tx_undelegate_from_gateway_test.go +++ b/x/application/client/cli/tx_undelegate_from_gateway_test.go @@ -78,8 +78,8 @@ func TestCLI_UndelegateFromGateway(t *testing.T) { } // Initialize the App and Gateway Accounts by sending it some funds from the validator account that is part of genesis - network.InitAccount(t, net, appAccount.Address) - network.InitAccount(t, net, gatewayAccount.Address) + network.InitAccountWithSequence(t, net, appAccount.Address, 1) + network.InitAccountWithSequence(t, net, gatewayAccount.Address, 2) // Run the tests for _, tt := range tests { diff --git a/x/application/keeper/query_application.go b/x/application/keeper/query_application.go index e9275df92..c08c3c925 100644 --- a/x/application/keeper/query_application.go +++ b/x/application/keeper/query_application.go @@ -52,7 +52,7 @@ func (k Keeper) Application(goCtx context.Context, req *types.QueryGetApplicatio req.Address, ) if !found { - return nil, status.Error(codes.NotFound, fmt.Sprintf("application with address %s not found", req.Address)) + return nil, status.Error(codes.NotFound, fmt.Sprintf("application not found: address %s", req.Address)) } return &types.QueryGetApplicationResponse{Application: val}, nil diff --git a/x/application/keeper/query_application_test.go b/x/application/keeper/query_application_test.go index feb0fef55..0cc9c35e9 100644 --- a/x/application/keeper/query_application_test.go +++ b/x/application/keeper/query_application_test.go @@ -47,7 +47,7 @@ func TestApplicationQuerySingle(t *testing.T) { request: &types.QueryGetApplicationRequest{ Address: strconv.Itoa(100000), }, - err: status.Error(codes.NotFound, "not found"), + err: status.Error(codes.NotFound, "application not found"), }, { desc: "InvalidRequest", @@ -58,7 +58,7 @@ func TestApplicationQuerySingle(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { response, err := keeper.Application(wctx, tc.request) if tc.err != nil { - require.ErrorIs(t, err, tc.err) + require.ErrorContains(t, err, tc.err.Error()) } else { require.NoError(t, err) require.Equal(t, diff --git a/x/gateway/keeper/query_gateway.go b/x/gateway/keeper/query_gateway.go index ddfd3b30a..7e18dea34 100644 --- a/x/gateway/keeper/query_gateway.go +++ b/x/gateway/keeper/query_gateway.go @@ -52,7 +52,7 @@ func (k Keeper) Gateway(goCtx context.Context, req *types.QueryGetGatewayRequest req.Address, ) if !found { - return nil, status.Error(codes.NotFound, fmt.Sprintf("gateways with address %s not found", req.Address)) + return nil, status.Error(codes.NotFound, fmt.Sprintf("gateway not found: address %s", req.Address)) } return &types.QueryGetGatewayResponse{Gateway: val}, nil diff --git a/x/gateway/keeper/query_gateway_test.go b/x/gateway/keeper/query_gateway_test.go index 9d44de980..4c289e6ae 100644 --- a/x/gateway/keeper/query_gateway_test.go +++ b/x/gateway/keeper/query_gateway_test.go @@ -47,7 +47,7 @@ func TestGatewayQuerySingle(t *testing.T) { request: &types.QueryGetGatewayRequest{ Address: strconv.Itoa(100000), }, - err: status.Error(codes.NotFound, "not found"), + err: status.Error(codes.NotFound, "gateway not found"), }, { desc: "InvalidRequest", @@ -58,7 +58,7 @@ func TestGatewayQuerySingle(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { response, err := keeper.Gateway(wctx, tc.request) if tc.err != nil { - require.ErrorIs(t, err, tc.err) + require.ErrorContains(t, err, tc.err.Error()) } else { require.NoError(t, err) require.Equal(t, diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index 457fa452d..e7f0c34e0 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -60,7 +60,6 @@ func createClaim( sessionHeaderEncoded := encodeSessionHeader(t, sessionId, sessionEndHeight) rootHashEncoded := base64.StdEncoding.EncodeToString(rootHash) - fmt.Println("OLSH", sessionHeaderEncoded, rootHashEncoded) args := []string{ sessionHeaderEncoded, rootHashEncoded, diff --git a/x/supplier/keeper/query_claim_test.go b/x/supplier/keeper/query_claim_test.go index 0f41d9469..dcae244e1 100644 --- a/x/supplier/keeper/query_claim_test.go +++ b/x/supplier/keeper/query_claim_test.go @@ -92,7 +92,6 @@ func TestClaim_QuerySingle(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { response, err := keeper.Claim(wctx, tc.request) if tc.err != nil { - require.Error(t, err) require.ErrorContains(t, err, tc.err.Error()) } else { require.NoError(t, err) From a45148e03b8f55907a38f8175d85de9ac105de91 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 16 Nov 2023 16:33:26 -0800 Subject: [PATCH 38/40] Remove TODO_IN_THIS comment --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index aee512d1f..dc7666200 100644 --- a/Makefile +++ b/Makefile @@ -486,7 +486,6 @@ claim_list_height: ## List all the claims ending at a specific height (specified claim_list_height_5: ## List all the claims at height 5 HEIGHT=5 make claim_list_height -# TODO_IN_THIS_PR: Test and uncomment this. .PHONY: claim_list_session claim_list_session: ## List all the claims ending at a specific session (specified via SESSION variable) poktrolld --home=$(POKTROLLD_HOME) q supplier list-claims --session-id $(SESSION) --node $(POCKET_NODE) From c0968089cdd7e7e15c894eb89555200b9d075e87 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 16 Nov 2023 18:43:44 -0800 Subject: [PATCH 39/40] s/store/primaryStore --- x/supplier/keeper/claim.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/x/supplier/keeper/claim.go b/x/supplier/keeper/claim.go index 031dbcb60..511d8f7da 100644 --- a/x/supplier/keeper/claim.go +++ b/x/supplier/keeper/claim.go @@ -43,7 +43,7 @@ func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { logger := k.Logger(ctx).With("method", "RemoveClaim") parentStore := ctx.KVStore(k.storeKey) - store := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + primaryStore := prefix.NewStore(parentStore, types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) // Check if the claim exists primaryKey := types.ClaimPrimaryKey(sessionId, supplierAddr) @@ -61,7 +61,7 @@ func (k Keeper) RemoveClaim(ctx sdk.Context, sessionId, supplierAddr string) { heightKey := types.ClaimSupplierEndSessionHeightKey(claim.SessionEndBlockHeight, primaryKey) // Delete all the entries (primary store and secondary indices) - store.Delete(primaryKey) + primaryStore.Delete(primaryKey) addressStoreIndex.Delete(addressKey) sessionHeightStoreIndex.Delete(heightKey) @@ -76,8 +76,8 @@ func (k Keeper) GetClaim(ctx sdk.Context, sessionId, supplierAddr string) (val t // GetAllClaims returns all claim func (k Keeper) GetAllClaims(ctx sdk.Context) (claims []types.Claim) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) + primaryStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(primaryStore, []byte{}) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { @@ -146,8 +146,8 @@ func (k Keeper) GetClaimsBySession(ctx sdk.Context, sessionId string) (claims [] // getClaimByPrimaryKey is a helper that retrieves, if exists, the Claim associated with the key provided func (k Keeper) getClaimByPrimaryKey(ctx sdk.Context, primaryKey []byte) (val types.Claim, found bool) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) - b := store.Get(primaryKey) + primaryStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ClaimPrimaryKeyPrefix)) + b := primaryStore.Get(primaryKey) if b == nil { return val, false } From d3b0c5a0e4f455669564616d158512ca7f78db14 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 16 Nov 2023 18:53:58 -0800 Subject: [PATCH 40/40] Added back commented out tests --- x/supplier/client/cli/query_claim_test.go | 54 ++++++++++++++++------- x/supplier/keeper/query_claim.go | 4 +- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/x/supplier/client/cli/query_claim_test.go b/x/supplier/client/cli/query_claim_test.go index e7f0c34e0..c36abf15a 100644 --- a/x/supplier/client/cli/query_claim_test.go +++ b/x/supplier/client/cli/query_claim_test.go @@ -270,8 +270,16 @@ func TestClaim_List(t *testing.T) { }) t.Run("ByAddress", func(t *testing.T) { + supplierAddr := claims[0].SupplierAddress args := prepareArgs(nil, 0, uint64(totalClaims), true) - args = append(args, fmt.Sprintf("--%s=%s", cli.FlagSupplierAddress, claims[0].SupplierAddress)) + args = append(args, fmt.Sprintf("--%s=%s", cli.FlagSupplierAddress, supplierAddr)) + + expectedClaims := make([]types.Claim, 0) + for _, claim := range claims { + if claim.SupplierAddress == supplierAddr { + expectedClaims = append(expectedClaims, claim) + } + } out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) require.NoError(t, err) @@ -280,15 +288,23 @@ func TestClaim_List(t *testing.T) { require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) require.Equal(t, numSessions, int(resp.Pagination.Total)) - // require.ElementsMatch(t, - // nullify.Fill(claims), - // nullify.Fill(resp.Claim), - // ) + require.ElementsMatch(t, + nullify.Fill(expectedClaims), + nullify.Fill(resp.Claim), + ) }) t.Run("BySession", func(t *testing.T) { + sessionId := claims[0].SessionId args := prepareArgs(nil, 0, uint64(totalClaims), true) - args = append(args, fmt.Sprintf("--%s=%s", cli.FlagSessionId, claims[0].SessionId)) + args = append(args, fmt.Sprintf("--%s=%s", cli.FlagSessionId, sessionId)) + + expectedClaims := make([]types.Claim, 0) + for _, claim := range claims { + if claim.SessionId == sessionId { + expectedClaims = append(expectedClaims, claim) + } + } out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) require.NoError(t, err) @@ -297,15 +313,23 @@ func TestClaim_List(t *testing.T) { require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) require.Equal(t, numClaimsPerSession, int(resp.Pagination.Total)) - // require.ElementsMatch(t, - // nullify.Fill(claims), - // nullify.Fill(resp.Claim), - // ) + require.ElementsMatch(t, + nullify.Fill(expectedClaims), + nullify.Fill(resp.Claim), + ) }) t.Run("ByHeight", func(t *testing.T) { + sessionEndHeight := claims[0].SessionEndBlockHeight args := prepareArgs(nil, 0, uint64(totalClaims), true) - args = append(args, fmt.Sprintf("--%s=%d", cli.FlagSessionEndHeight, claims[0].SessionEndBlockHeight)) + args = append(args, fmt.Sprintf("--%s=%d", cli.FlagSessionEndHeight, sessionEndHeight)) + + expectedClaims := make([]types.Claim, 0) + for _, claim := range claims { + if claim.SessionEndBlockHeight == sessionEndHeight { + expectedClaims = append(expectedClaims, claim) + } + } out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListClaims(), args) require.NoError(t, err) @@ -314,10 +338,10 @@ func TestClaim_List(t *testing.T) { require.NoError(t, net.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) require.Equal(t, numClaimsPerSession, int(resp.Pagination.Total)) - // require.ElementsMatch(t, - // nullify.Fill(claims), - // nullify.Fill(resp.Claim), - // ) + require.ElementsMatch(t, + nullify.Fill(expectedClaims), + nullify.Fill(resp.Claim), + ) }) t.Run("Total", func(t *testing.T) { diff --git a/x/supplier/keeper/query_claim.go b/x/supplier/keeper/query_claim.go index 1b23d2e50..7009d3bab 100644 --- a/x/supplier/keeper/query_claim.go +++ b/x/supplier/keeper/query_claim.go @@ -53,7 +53,6 @@ func (k Keeper) AllClaims(goCtx context.Context, req *types.QueryAllClaimsReques var claims []types.Claim pageRes, err := query.Paginate(claimStore, req.Pagination, func(key []byte, value []byte) error { - var claim types.Claim if isCustomIndex { // We retrieve the primaryKey, and need to query the actual Claim before decoding it. claim, claimFound := k.getClaimByPrimaryKey(ctx, value) @@ -62,12 +61,13 @@ func (k Keeper) AllClaims(goCtx context.Context, req *types.QueryAllClaimsReques } } else { // The value is an encoded Claim. + var claim types.Claim if err := k.cdc.Unmarshal(value, &claim); err != nil { return err } + claims = append(claims, claim) } - claims = append(claims, claim) return nil })