From 9c3cda21d0e820719c7a2ffc1e03303377058a79 Mon Sep 17 00:00:00 2001 From: Matt Witkowski Date: Thu, 4 Apr 2024 15:06:07 -0400 Subject: [PATCH 1/6] Remove module handlers and queriers for v0.50. (#1896) * Update changelog. * Convert send_restrictions_test to not use handler. Start moving tests over to keeper. * migrate msgdeleteaccess test over. * Move more tests over to msg_server tests. * More converted tests. * Finish migrating handler to message server for marker. * Update msgfees to have todos for gov migration. * Remove handler from attribute module. * Migrate tests to msgserver for name module. * Remove handler and migrate tests for metadata. * Remove queriers that are no longer needed. --- CHANGELOG.md | 1 + x/attribute/handler.go | 36 - x/attribute/handler_test.go | 204 ---- x/attribute/keeper/msg_server_test.go | 215 ++++ x/marker/handler.go | 67 +- x/marker/handler_test.go | 524 +------- x/marker/keeper/msg_server_test.go | 691 +++++++++++ x/marker/keeper/querier.go | 177 --- x/marker/keeper/querier_test.go | 156 --- x/marker/keeper/query_server.go | 20 +- x/marker/keeper/send_restrictions_test.go | 10 +- x/metadata/handler.go | 98 -- x/metadata/handler_test.go | 1320 --------------------- x/metadata/keeper/msg_server_test.go | 1300 +++++++++++++++++++- x/metadata/keeper/querier.go | 255 ---- x/msgfees/handler.go | 2 + x/msgfees/keeper/proposal_handler.go | 2 + x/name/handler.go | 25 +- x/name/handler_test.go | 270 ----- x/name/keeper/msg_server_test.go | 190 +++ 20 files changed, 2402 insertions(+), 3161 deletions(-) delete mode 100644 x/attribute/handler.go delete mode 100644 x/attribute/handler_test.go delete mode 100644 x/marker/keeper/querier.go delete mode 100644 x/marker/keeper/querier_test.go delete mode 100644 x/metadata/handler.go delete mode 100644 x/metadata/handler_test.go delete mode 100644 x/metadata/keeper/querier.go delete mode 100644 x/name/handler_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e5be3d5b5..9c24d2a249 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * Remove unsupported database types [#1760](https://github.com/provenance-io/provenance/issues/1760). +* Remove handlers from provenance modules [#1760](https://github.com/provenance-io/provenance/issues/1760). * Updated app.go to use RegisterStreamingServices on BaseApp [#1760](https://github.com/provenance-io/provenance/issues/1760). * Bump the SDK to `v0.50.5-pio-1` (from an earlier ephemeral version) [#1897](https://github.com/provenance-io/provenance/pull/1897). diff --git a/x/attribute/handler.go b/x/attribute/handler.go deleted file mode 100644 index 2351d6df22..0000000000 --- a/x/attribute/handler.go +++ /dev/null @@ -1,36 +0,0 @@ -package attribute - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/provenance-io/provenance/x/attribute/keeper" - "github.com/provenance-io/provenance/x/attribute/types" -) - -// NewHandler returns a handler for attribute messages. -// TODO[1760]: attribute: Delete the attribute NewHandler. -func NewHandler(k keeper.Keeper) func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgAddAttributeRequest: - res, err := msgServer.AddAttribute(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgUpdateAttributeRequest: - res, err := msgServer.UpdateAttribute(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteAttributeRequest: - res, err := msgServer.DeleteAttribute(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteDistinctAttributeRequest: - res, err := msgServer.DeleteDistinctAttribute(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - default: - return nil, sdkerrors.ErrUnknownRequest.Wrapf("unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} diff --git a/x/attribute/handler_test.go b/x/attribute/handler_test.go deleted file mode 100644 index 7474ca01cc..0000000000 --- a/x/attribute/handler_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package attribute_test - -import ( - "fmt" - "testing" - - "github.com/golang/protobuf/proto" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/provenance-io/provenance/app" - "github.com/provenance-io/provenance/x/attribute" - "github.com/provenance-io/provenance/x/attribute/types" - nametypes "github.com/provenance-io/provenance/x/name/types" -) - -// TODO[1760]: attribute: Migrate the attribute handler tests to the keeper. - -type HandlerTestSuite struct { - suite.Suite - - app *app.App - ctx sdk.Context - handler func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) - - pubkey1 cryptotypes.PubKey - user1 string - user1Addr sdk.AccAddress -} - -func (s *HandlerTestSuite) SetupTest() { - s.app = app.Setup(s.T()) - s.ctx = s.app.BaseApp.NewContext(false) - s.handler = attribute.NewHandler(s.app.AttributeKeeper) - - s.pubkey1 = secp256k1.GenPrivKey().PubKey() - s.user1Addr = sdk.AccAddress(s.pubkey1.Address()) - s.user1 = s.user1Addr.String() - - s.app.AccountKeeper.SetAccount(s.ctx, s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.user1Addr)) - - var nameData nametypes.GenesisState - nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("name", s.user1Addr, false)) - nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("example.name", s.user1Addr, false)) - nameData.Params.AllowUnrestrictedNames = false - nameData.Params.MaxNameLevels = 16 - nameData.Params.MinSegmentLength = 2 - nameData.Params.MaxSegmentLength = 16 - - s.app.NameKeeper.InitGenesis(s.ctx, nameData) - -} - -func TestHandlerTestSuite(t *testing.T) { - suite.Run(t, new(HandlerTestSuite)) -} - -type CommonTest struct { - name string - msg sdk.Msg - signers []string - errorMsg string - expectedEvent proto.Message -} - -func (s *HandlerTestSuite) containsMessage(result *sdk.Result, msg proto.Message) bool { - events := result.GetEvents().ToABCIEvents() - for _, event := range events { - typeEvent, _ := sdk.ParseTypedEvent(event) - if assert.ObjectsAreEqual(msg, typeEvent) { - return true - } - } - return false -} - -func (s *HandlerTestSuite) runTests(cases []CommonTest) { - for _, tc := range cases { - s.T().Run(tc.name, func(t *testing.T) { - response, err := s.handler(s.ctx, tc.msg) - - if len(tc.errorMsg) > 0 { - assert.EqualError(t, err, tc.errorMsg) - } else { - if tc.expectedEvent != nil { - result := s.containsMessage(response, tc.expectedEvent) - s.True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) - } - - } - }) - } -} - -func (s *HandlerTestSuite) TestMsgAddAttributeRequest() { - cases := []CommonTest{ - { - "should successfully add new attribute", - types.NewMsgAddAttributeRequest(s.user1, - s.user1Addr, "example.name", types.AttributeType_String, []byte("value")), - []string{s.user1}, - "", - types.NewEventAttributeAdd( - types.Attribute{ - Address: s.user1, - Name: "example.name", - Value: []byte("value"), - AttributeType: types.AttributeType_String, - }, - s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgUpdateAttributeRequest() { - testAttr := types.Attribute{ - Address: s.user1, - Name: "example.name", - Value: []byte("value"), - AttributeType: types.AttributeType_String, - } - var attrData types.GenesisState - attrData.Attributes = append(attrData.Attributes, testAttr) - attrData.Params.MaxValueLength = 100 - s.app.AttributeKeeper.InitGenesis(s.ctx, &attrData) - - cases := []CommonTest{ - { - "should successfully update attribute", - types.NewMsgUpdateAttributeRequest( - s.user1, - s.user1Addr, "example.name", - []byte("value"), []byte("1"), - types.AttributeType_String, - types.AttributeType_Int), - []string{s.user1}, - "", - types.NewEventAttributeUpdate( - testAttr, - types.Attribute{ - Address: s.user1, - Name: "example.name", - Value: []byte("1"), - AttributeType: types.AttributeType_Int, - }, - s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgDistinctDeleteAttributeRequest() { - testAttr := types.Attribute{ - Address: s.user1, - Name: "example.name", - Value: []byte("value"), - AttributeType: types.AttributeType_String, - } - var attrData types.GenesisState - attrData.Attributes = append(attrData.Attributes, testAttr) - attrData.Params.MaxValueLength = 100 - s.app.AttributeKeeper.InitGenesis(s.ctx, &attrData) - - cases := []CommonTest{ - { - "should successfully delete attribute with value", - types.NewMsgDeleteDistinctAttributeRequest(s.user1, s.user1Addr, "example.name", []byte("value")), - []string{s.user1}, - "", - types.NewEventDistinctAttributeDelete("example.name", "value", s.user1, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgDeleteAttributeRequest() { - testAttr := types.Attribute{ - Address: s.user1, - Name: "example.name", - Value: []byte("value"), - AttributeType: types.AttributeType_String, - } - var attrData types.GenesisState - attrData.Attributes = append(attrData.Attributes, testAttr) - attrData.Params.MaxValueLength = 100 - s.app.AttributeKeeper.InitGenesis(s.ctx, &attrData) - - cases := []CommonTest{ - { - "should successfully add new attribute", - types.NewMsgDeleteAttributeRequest(s.user1, s.user1Addr, "example.name"), - []string{s.user1}, - "", - types.NewEventAttributeDelete("example.name", s.user1, s.user1), - }, - } - s.runTests(cases) -} diff --git a/x/attribute/keeper/msg_server_test.go b/x/attribute/keeper/msg_server_test.go index 6360771091..b24e02982c 100644 --- a/x/attribute/keeper/msg_server_test.go +++ b/x/attribute/keeper/msg_server_test.go @@ -5,6 +5,9 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/gogoproto/proto" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -16,6 +19,7 @@ import ( simapp "github.com/provenance-io/provenance/app" "github.com/provenance-io/provenance/x/attribute/keeper" "github.com/provenance-io/provenance/x/attribute/types" + nametypes "github.com/provenance-io/provenance/x/name/types" ) type MsgServerTestSuite struct { @@ -48,12 +52,32 @@ func (s *MsgServerTestSuite) SetupTest() { s.owner1 = s.owner1Addr.String() acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.owner1Addr) s.app.AccountKeeper.SetAccount(s.ctx, acc) + + var nameData nametypes.GenesisState + nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("name", s.owner1Addr, false)) + nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("example.name", s.owner1Addr, false)) + nameData.Params.AllowUnrestrictedNames = false + nameData.Params.MaxNameLevels = 16 + nameData.Params.MinSegmentLength = 2 + nameData.Params.MaxSegmentLength = 16 + + s.app.NameKeeper.InitGenesis(s.ctx, nameData) } func TestMsgServerTestSuite(t *testing.T) { suite.Run(t, new(MsgServerTestSuite)) } +func (s *MsgServerTestSuite) containsMessage(events []abci.Event, msg proto.Message) bool { + for _, event := range events { + typeEvent, _ := sdk.ParseTypedEvent(event) + if assert.ObjectsAreEqual(msg, typeEvent) { + return true + } + } + return false +} + func (s *MsgServerTestSuite) TestUpdateAttributeExpiration() { twoHoursInPast := time.Now().UTC().Add(-2 * time.Hour) twoHoursInFuture := time.Now().UTC().Add(2 * time.Hour) @@ -111,3 +135,194 @@ func (s *MsgServerTestSuite) TestUpdateAttributeExpiration() { }) } } + +func (s *MsgServerTestSuite) TestMsgAddAttributeRequest() { + + testcases := []struct { + name string + msg *types.MsgAddAttributeRequest + signers []string + errorMsg string + expectedEvent proto.Message + }{ + { + name: "should successfully add new attribute", + msg: types.NewMsgAddAttributeRequest(s.owner1, + s.owner1Addr, "example.name", types.AttributeType_String, []byte("value")), + signers: []string{s.owner1}, + expectedEvent: types.NewEventAttributeAdd( + types.Attribute{ + Address: s.owner1, + Name: "example.name", + Value: []byte("value"), + AttributeType: types.AttributeType_String, + }, + s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + _, err := s.msgServer.AddAttribute(s.ctx, tc.msg) + + if len(tc.errorMsg) > 0 { + s.Assert().EqualError(err, tc.errorMsg) + } else { + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) + } + + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgUpdateAttributeRequest() { + testAttr := types.Attribute{ + Address: s.owner1, + Name: "example.name", + Value: []byte("value"), + AttributeType: types.AttributeType_String, + } + var attrData types.GenesisState + attrData.Attributes = append(attrData.Attributes, testAttr) + attrData.Params.MaxValueLength = 100 + s.app.AttributeKeeper.InitGenesis(s.ctx, &attrData) + + testcases := []struct { + name string + msg *types.MsgUpdateAttributeRequest + signers []string + errorMsg string + expectedEvent proto.Message + }{ + { + name: "should successfully update attribute", + msg: types.NewMsgUpdateAttributeRequest( + s.owner1, + s.owner1Addr, "example.name", + []byte("value"), []byte("1"), + types.AttributeType_String, + types.AttributeType_Int), + signers: []string{s.owner1}, + expectedEvent: types.NewEventAttributeUpdate( + testAttr, + types.Attribute{ + Address: s.owner1, + Name: "example.name", + Value: []byte("1"), + AttributeType: types.AttributeType_Int, + }, + s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + _, err := s.msgServer.UpdateAttribute(s.ctx, tc.msg) + + if len(tc.errorMsg) > 0 { + s.Assert().EqualError(err, tc.errorMsg) + } else { + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) + } + + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgDistinctDeleteAttributeRequest() { + testAttr := types.Attribute{ + Address: s.owner1, + Name: "example.name", + Value: []byte("value"), + AttributeType: types.AttributeType_String, + } + var attrData types.GenesisState + attrData.Attributes = append(attrData.Attributes, testAttr) + attrData.Params.MaxValueLength = 100 + s.app.AttributeKeeper.InitGenesis(s.ctx, &attrData) + + testcases := []struct { + name string + msg *types.MsgDeleteDistinctAttributeRequest + signers []string + errorMsg string + expectedEvent proto.Message + }{ + { + name: "should successfully delete attribute with value", + msg: types.NewMsgDeleteDistinctAttributeRequest(s.owner1, s.owner1Addr, "example.name", []byte("value")), + signers: []string{s.owner1}, + expectedEvent: types.NewEventDistinctAttributeDelete("example.name", "value", s.owner1, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + _, err := s.msgServer.DeleteDistinctAttribute(s.ctx, tc.msg) + + if len(tc.errorMsg) > 0 { + s.Assert().EqualError(err, tc.errorMsg) + } else { + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) + } + + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgDeleteAttributeRequest() { + testAttr := types.Attribute{ + Address: s.owner1, + Name: "example.name", + Value: []byte("value"), + AttributeType: types.AttributeType_String, + } + var attrData types.GenesisState + attrData.Attributes = append(attrData.Attributes, testAttr) + attrData.Params.MaxValueLength = 100 + s.app.AttributeKeeper.InitGenesis(s.ctx, &attrData) + + testcases := []struct { + name string + msg *types.MsgDeleteAttributeRequest + signers []string + errorMsg string + expectedEvent proto.Message + }{ + { + name: "should successfully add new attribute", + msg: types.NewMsgDeleteAttributeRequest(s.owner1, s.owner1Addr, "example.name"), + signers: []string{s.owner1}, + expectedEvent: types.NewEventAttributeDelete("example.name", s.owner1, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + _, err := s.msgServer.DeleteAttribute(s.ctx, tc.msg) + + if len(tc.errorMsg) > 0 { + s.Assert().EqualError(err, tc.errorMsg) + } else { + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) + } + + } + }) + } +} diff --git a/x/marker/handler.go b/x/marker/handler.go index e4f4a7c673..101b8d31fb 100644 --- a/x/marker/handler.go +++ b/x/marker/handler.go @@ -9,72 +9,7 @@ import ( "github.com/provenance-io/provenance/x/marker/types" ) -// NewHandler returns a handler for marker messages. -// TODO[1760]: marker: Delete the marker NewHandler. -func NewHandler(k keeper.Keeper) func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgAddMarkerRequest: - res, err := msgServer.AddMarker(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgAddAccessRequest: - res, err := msgServer.AddAccess(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteAccessRequest: - res, err := msgServer.DeleteAccess(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgFinalizeRequest: - res, err := msgServer.Finalize(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgActivateRequest: - res, err := msgServer.Activate(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgCancelRequest: - res, err := msgServer.Cancel(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteRequest: - res, err := msgServer.Delete(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgMintRequest: - res, err := msgServer.Mint(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgBurnRequest: - res, err := msgServer.Burn(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgWithdrawRequest: - res, err := msgServer.Withdraw(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgTransferRequest: - res, err := msgServer.Transfer(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgIbcTransferRequest: - res, err := msgServer.IbcTransfer(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgSetDenomMetadataRequest: - res, err := msgServer.SetDenomMetadata(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgAddFinalizeActivateMarkerRequest: - res, err := msgServer.AddFinalizeActivateMarker(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgSetAccountDataRequest: - res, err := msgServer.SetAccountData(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.ErrUnknownRequest.Wrapf("unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} +// TODO[1760]: marker: Migrate the legacy gov proposals. func NewProposalHandler(k keeper.Keeper) govtypesv1beta1.Handler { return func(ctx sdk.Context, content govtypesv1beta1.Content) error { diff --git a/x/marker/handler_test.go b/x/marker/handler_test.go index 8123a94dcb..e5e7b3d527 100644 --- a/x/marker/handler_test.go +++ b/x/marker/handler_test.go @@ -1,41 +1,32 @@ package marker_test import ( - "fmt" "testing" - "github.com/golang/protobuf/proto" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - sdkmath "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/provenance-io/provenance/app" - attrtypes "github.com/provenance-io/provenance/x/attribute/types" "github.com/provenance-io/provenance/x/marker" "github.com/provenance-io/provenance/x/marker/keeper" "github.com/provenance-io/provenance/x/marker/types" ) -// TODO[1760]: marker: Migrate the marker handler tests to the keeper. +// TODO[1760]: marker: Migrate the legacy gov proposals. type HandlerTestSuite struct { suite.Suite - app *app.App - ctx sdk.Context - handler func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) + app *app.App + ctx sdk.Context pubkey1 cryptotypes.PubKey user1 string @@ -49,7 +40,6 @@ type HandlerTestSuite struct { func (s *HandlerTestSuite) SetupTest() { s.app = app.Setup(s.T()) s.ctx = s.app.BaseApp.NewContext(false) - s.handler = marker.NewHandler(s.app.MarkerKeeper) s.pubkey1 = secp256k1.GenPrivKey().PubKey() s.user1Addr = sdk.AccAddress(s.pubkey1.Address()) @@ -70,17 +60,6 @@ func TestHandlerTestSuite(t *testing.T) { suite.Run(t, new(HandlerTestSuite)) } -func TestInvalidMsg(t *testing.T) { - k := keeper.Keeper{} - h := marker.NewHandler(k) - - res, err := h(sdk.NewContext(nil, cmtproto.Header{}, false, nil), testdata.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - require.Contains(t, err.Error(), "unrecognized marker message type") - require.Contains(t, err.Error(), "testdata.TestMsg") -} - func TestInvalidProposal(t *testing.T) { k := keeper.Keeper{} h := marker.NewProposalHandler(k) @@ -88,500 +67,3 @@ func TestInvalidProposal(t *testing.T) { err := h(sdk.NewContext(nil, cmtproto.Header{}, false, nil), govtypesv1beta1.NewTextProposal("Test", "description")) require.ErrorContains(t, err, "unrecognized marker proposal content type: *v1beta1.TextProposal") } - -func (s *HandlerTestSuite) containsMessage(result *sdk.Result, msg proto.Message) bool { - events := result.GetEvents().ToABCIEvents() - for _, event := range events { - typeEvent, _ := sdk.ParseTypedEvent(event) - if assert.ObjectsAreEqual(msg, typeEvent) { - return true - } - } - return false -} - -// noAccessErr creates an expected error message for an address not having access on a marker. -func (s *HandlerTestSuite) noAccessErr(addr string, role types.Access, denom string) string { - mAddr, err := types.MarkerAddress(denom) - s.Require().NoError(err, "MarkerAddress(%q)", denom) - return fmt.Sprintf("%s does not have %s on %s marker (%s)", addr, role, denom, mAddr) -} - -type CommonTest struct { - name string - msg sdk.Msg - errorMsg string - expectedEvent proto.Message -} - -func (s *HandlerTestSuite) runTests(cases []CommonTest) { - for _, tc := range cases { - s.Run(tc.name, func() { - response, err := s.handler(s.ctx, tc.msg) - if len(tc.errorMsg) > 0 { - s.Require().EqualError(err, tc.errorMsg, "handler(%T) error", tc.msg) - } else { - s.Require().NoError(err, "handler(%T) error", tc.msg) - if tc.expectedEvent != nil { - result := s.containsMessage(response, tc.expectedEvent) - s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) - } - } - }) - } -} - -func (s *HandlerTestSuite) TestMsgAddAccessRequest() { - accessMintGrant := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("MINT"), - } - - accessInvalidGrant := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("Invalid"), - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest("hotdog", sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - }, - { - name: "should successfully grant access to marker", - msg: types.NewMsgAddAccessRequest("hotdog", s.user1Addr, accessMintGrant), - expectedEvent: types.NewEventMarkerAddAccess(&accessMintGrant, "hotdog", s.user1), - }, - { - name: "should fail to ADD access to marker, validate basic fails", - msg: types.NewMsgAddAccessRequest("hotdog", s.user1Addr, accessInvalidGrant), - errorMsg: "invalid access type: invalid request", - }, - { - - name: "should fail to ADD access to marker, keeper AddAccess failure", - msg: types.NewMsgAddAccessRequest("hotdog", s.user2Addr, accessMintGrant), - errorMsg: fmt.Sprintf("updates to pending marker hotdog can only be made by %s: unauthorized", s.user1), - }, - } - - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgDeleteAccessMarkerRequest() { - hotdogDenom := "hotdog" - accessMintGrant := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("MINT"), - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup grant access to marker", - msg: types.NewMsgAddAccessRequest(hotdogDenom, s.user1Addr, accessMintGrant), - }, - { - name: "should successfully delete grant access to marker", - msg: types.NewDeleteAccessRequest(hotdogDenom, s.user1Addr, s.user1Addr), - expectedEvent: types.NewEventMarkerDeleteAccess(s.user1, hotdogDenom, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgActivateMarkerRequest() { - hotdogDenom := "hotdog" - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup finalize marker", - msg: types.NewMsgFinalizeRequest(hotdogDenom, s.user1Addr), - }, - { - name: "should successfully activate marker", - msg: types.NewMsgActivateRequest(hotdogDenom, s.user1Addr), - expectedEvent: types.NewEventMarkerActivate(hotdogDenom, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgCancelMarkerRequest() { - hotdogDenom := "hotdog" - accessDeleteGrant := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("DELETE"), - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup grant delete access to marker", - msg: types.NewMsgAddAccessRequest(hotdogDenom, s.user1Addr, accessDeleteGrant), - }, - { - name: "should successfully cancel marker", - msg: types.NewMsgCancelRequest(hotdogDenom, s.user1Addr), - expectedEvent: types.NewEventMarkerCancel(hotdogDenom, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgDeleteMarkerRequest() { - hotdogDenom := "hotdog" - accessDeleteMintGrant := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("DELETE,MINT"), - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup grant delete access to marker", - msg: types.NewMsgAddAccessRequest(hotdogDenom, s.user1Addr, accessDeleteMintGrant), - }, - { - name: "setup cancel marker", - msg: types.NewMsgCancelRequest(hotdogDenom, s.user1Addr), - }, - { - name: "should successfully delete marker", - msg: types.NewMsgDeleteRequest(hotdogDenom, s.user1Addr), - expectedEvent: types.NewEventMarkerDelete(hotdogDenom, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgMintMarkerRequest() { - hotdogDenom := "hotdog" - access := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("MINT,BURN"), - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup grant mint access to marker", - msg: types.NewMsgAddAccessRequest(hotdogDenom, s.user1Addr, access), - }, - { - name: "should successfully mint marker", - msg: types.NewMsgMintRequest(s.user1Addr, sdk.NewInt64Coin(hotdogDenom, 100)), - expectedEvent: types.NewEventMarkerMint("100", hotdogDenom, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgBurnMarkerRequest() { - hotdogDenom := "hotdog" - access := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("DELETE,MINT,BURN"), - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup grant mint access to marker", - msg: types.NewMsgAddAccessRequest(hotdogDenom, s.user1Addr, access), - }, - { - name: "should successfully burn marker", - msg: types.NewMsgBurnRequest(s.user1Addr, sdk.NewInt64Coin(hotdogDenom, 100)), - expectedEvent: types.NewEventMarkerBurn("100", hotdogDenom, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgWithdrawMarkerRequest() { - hotdogDenom := "hotdog" - access := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("DELETE,MINT,WITHDRAW"), - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup grant access to marker", - msg: types.NewMsgAddAccessRequest(hotdogDenom, s.user1Addr, access), - }, - { - name: "setup finalize marker", - msg: types.NewMsgFinalizeRequest(hotdogDenom, s.user1Addr), - }, - { - name: "setup activate marker", - msg: types.NewMsgActivateRequest(hotdogDenom, s.user1Addr), - }, - { - name: "should successfully withdraw marker", - msg: types.NewMsgWithdrawRequest(s.user1Addr, s.user1Addr, hotdogDenom, sdk.NewCoins(sdk.NewInt64Coin(hotdogDenom, 100))), - expectedEvent: types.NewEventMarkerWithdraw("100hotdog", hotdogDenom, s.user1, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgTransferMarkerRequest() { - hotdogDenom := "hotdog" - access := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("DELETE,MINT,WITHDRAW,TRANSFER"), - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_RestrictedCoin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup grant access to marker", - msg: types.NewMsgAddAccessRequest(hotdogDenom, s.user1Addr, access), - }, - { - name: "setup finalize marker", - msg: types.NewMsgFinalizeRequest(hotdogDenom, s.user1Addr), - }, - { - name: "setup activate marker", - msg: types.NewMsgActivateRequest(hotdogDenom, s.user1Addr), - }, - { - name: "should successfully mint marker", - msg: types.NewMsgMintRequest(s.user1Addr, sdk.NewInt64Coin(hotdogDenom, 1000)), - }, - { - name: "should successfully transfer marker", - msg: types.NewMsgTransferRequest(s.user1Addr, s.user1Addr, s.user2Addr, sdk.NewInt64Coin(hotdogDenom, 0)), - expectedEvent: types.NewEventMarkerTransfer("0", hotdogDenom, s.user1, s.user2, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgSetDenomMetadataRequest() { - hotdogDenom := "hotdog" - hotdogName := "Jason" - hotdogSymbol := "WIFI" - access := types.AccessGrant{ - Address: s.user1, - Permissions: types.AccessListByNames("DELETE,MINT,WITHDRAW,TRANSFER"), - } - - hotdogMetadata := banktypes.Metadata{ - Description: "a description", - DenomUnits: []*banktypes.DenomUnit{ - {Denom: fmt.Sprintf("n%s", hotdogDenom), Exponent: 0, Aliases: []string{fmt.Sprintf("nano%s", hotdogDenom)}}, - {Denom: fmt.Sprintf("u%s", hotdogDenom), Exponent: 3, Aliases: []string{}}, - {Denom: hotdogDenom, Exponent: 9, Aliases: []string{}}, - {Denom: fmt.Sprintf("mega%s", hotdogDenom), Exponent: 15, Aliases: []string{}}, - }, - Base: fmt.Sprintf("n%s", hotdogDenom), - Display: hotdogDenom, - Name: hotdogName, - Symbol: hotdogSymbol, - } - - cases := []CommonTest{ - { - name: "setup new marker for test", - msg: types.NewMsgAddMarkerRequest(fmt.Sprintf("n%s", hotdogDenom), sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_RestrictedCoin, true, true, false, []string{}, 0, 0), - }, - { - name: "setup grant access to marker", - msg: types.NewMsgAddAccessRequest(fmt.Sprintf("n%s", hotdogDenom), s.user1Addr, access), - }, - { - name: "should successfully set denom metadata on marker", - msg: types.NewSetDenomMetadataRequest(hotdogMetadata, s.user1Addr), - expectedEvent: types.NewEventMarkerSetDenomMetadata(hotdogMetadata, s.user1), - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgAddFinalizeActivateMarkerRequest() { - denom := "hotdog" - rdenom := "restrictedhotdog" - denomWithDashPeriod := fmt.Sprintf("%s-my.marker", denom) - msgWithActiveStatus := types.NewMsgAddFinalizeActivateMarkerRequest(denom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, []types.AccessGrant{*types.NewAccessGrant(s.user1Addr, []types.Access{types.Access_Mint, types.Access_Admin})}, 0, 0) - msgWithActiveStatusAttr := types.NewMsgAddFinalizeActivateMarkerRequest(rdenom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_RestrictedCoin, true, true, false, []string{"attributes.one.com", "attributes.two.com"}, []types.AccessGrant{*types.NewAccessGrant(s.user1Addr, []types.Access{types.Access_Mint, types.Access_Admin})}, 0, 0) - - accessGrantWrongStatus := types.NewMsgAddFinalizeActivateMarkerRequest(denom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, nil, 0, 0) - - cases := []CommonTest{ - { - name: "should successfully ADD,FINALIZE,ACTIVATE new marker", - msg: msgWithActiveStatus, - expectedEvent: types.NewEventMarkerAdd(denom, types.MustGetMarkerAddress(denom).String(), "100", "proposed", s.user1, types.MarkerType_Coin.String()), - }, - { - name: "should successfully ADD,FINALIZE,ACTIVATE new marker with attributes", - msg: msgWithActiveStatusAttr, - expectedEvent: types.NewEventMarkerAdd(rdenom, types.MustGetMarkerAddress(rdenom).String(), "100", "proposed", s.user1, types.MarkerType_RestrictedCoin.String()), - }, - { - name: "should fail to ADD,FINALIZE,ACTIVATE new marker, validate basic failure", - msg: accessGrantWrongStatus, - errorMsg: "since this will activate the marker, must have at least one access list defined: invalid request", - }, - { - name: "should fail to ADD,FINALIZE,ACTIVATE new marker, marker already exists", - msg: types.NewMsgAddMarkerRequest(denom, sdkmath.NewInt(100), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - errorMsg: fmt.Sprintf("marker address already exists for %s: invalid request", types.MustGetMarkerAddress(denom)), - }, - { - name: "should successfully add marker with dash and period", - msg: types.NewMsgAddMarkerRequest(denomWithDashPeriod, sdkmath.NewInt(1000), s.user1Addr, s.user1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0), - expectedEvent: types.NewEventMarkerAdd(denomWithDashPeriod, types.MustGetMarkerAddress(denomWithDashPeriod).String(), "1000", "proposed", s.user1, types.MarkerType_Coin.String()), - }, - { - name: "should successfully mint denom", - msg: types.NewMsgMintRequest(s.user1Addr, sdk.NewInt64Coin(denom, 1000)), - expectedEvent: types.NewEventMarkerMint("1000", denom, s.user1), - }, - { - name: "should fail to burn denom, user doesn't have permissions", - msg: types.NewMsgBurnRequest(s.user1Addr, sdk.NewInt64Coin(denom, 50)), - errorMsg: s.noAccessErr(s.user1, types.Access_Burn, denom) + ": invalid request", - }, - } - s.runTests(cases) -} - -func (s *HandlerTestSuite) TestMsgSetAccountDataRequest() { - denomU := "aducoin" - denomR := "adrcoin" - - denomUAddr := types.MustGetMarkerAddress(denomU).String() - denomRAddr := types.MustGetMarkerAddress(denomR).String() - - authority := s.app.MarkerKeeper.GetAuthority() - - s.T().Logf("%s: %s", denomU, denomUAddr) - s.T().Logf("%s: %s", denomR, denomRAddr) - s.T().Logf("authority: %s", authority) - - tests := []CommonTest{ - { - name: "should successfully add/finalize/active unrestricted marker", - msg: types.NewMsgAddFinalizeActivateMarkerRequest( - denomU, sdkmath.NewInt(100), - s.user1Addr, s.user1Addr, // From and Manager. - types.MarkerType_Coin, - true, // Supply fixed - true, // Allow gov - false, // don't allow forced transfer - []string{}, // No required attributes. - []types.AccessGrant{ - {Address: s.user1, Permissions: []types.Access{types.Access_Mint, types.Access_Admin}}, - {Address: s.user2, Permissions: []types.Access{types.Access_Deposit}}, - }, - 0, - 0, - ), - }, - { - name: "should successfully add/finalize/active restricted marker", - msg: types.NewMsgAddFinalizeActivateMarkerRequest( - denomR, sdkmath.NewInt(100), - s.user1Addr, s.user1Addr, // From and Manager. - types.MarkerType_RestrictedCoin, - true, // Supply fixed - true, // Allow gov - false, // don't allow forced transfer - []string{}, // No required attributes. - []types.AccessGrant{ - {Address: s.user1, Permissions: []types.Access{types.Access_Mint, types.Access_Admin}}, - {Address: s.user2, Permissions: []types.Access{types.Access_Deposit}}, - }, - 0, - 0, - ), - }, - { - name: "should successfully set account data on unrestricted marker via gov prop", - msg: &types.MsgSetAccountDataRequest{ - Denom: denomU, - Value: "This is some unrestricted coin data.", - Signer: authority, - }, - expectedEvent: &attrtypes.EventAccountDataUpdated{Account: denomUAddr}, - }, - { - name: "should successfully set account data on unrestricted marker by signer with deposit", - msg: &types.MsgSetAccountDataRequest{ - Denom: denomU, - Value: "This is some different unrestricted coin data.", - Signer: s.user2, - }, - expectedEvent: &attrtypes.EventAccountDataUpdated{Account: denomUAddr}, - }, - { - name: "should fail to set account data on unrestricted marker because signer does not have deposit", - msg: &types.MsgSetAccountDataRequest{ - Denom: denomU, - Value: "This is some unrestricted coin data. This won't get used though.", - Signer: s.user1, - }, - errorMsg: s.noAccessErr(s.user1, types.Access_Deposit, denomU), - }, - { - name: "should successfully set account data on restricted marker via gov prop", - msg: &types.MsgSetAccountDataRequest{ - Denom: denomR, - Value: "This is some restricted coin data.", - Signer: authority, - }, - expectedEvent: &attrtypes.EventAccountDataUpdated{Account: denomRAddr}, - }, - { - name: "should successfully set account data on restricted marker by signer with deposit", - msg: &types.MsgSetAccountDataRequest{ - Denom: denomR, - Value: "This is some different restricted coin data.", - Signer: s.user2, - }, - expectedEvent: &attrtypes.EventAccountDataUpdated{Account: denomRAddr}, - }, - { - name: "should fail to set account data on restricted marker because signer does not have deposit", - msg: &types.MsgSetAccountDataRequest{ - Denom: denomR, - Value: "This is some restricted coin data. This won't get used though.", - Signer: s.user1, - }, - errorMsg: s.noAccessErr(s.user1, types.Access_Deposit, denomR), - }, - } - s.runTests(tests) -} diff --git a/x/marker/keeper/msg_server_test.go b/x/marker/keeper/msg_server_test.go index dcc1279d66..78dde04112 100644 --- a/x/marker/keeper/msg_server_test.go +++ b/x/marker/keeper/msg_server_test.go @@ -17,10 +17,12 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/gogoproto/proto" simapp "github.com/provenance-io/provenance/app" + attrtypes "github.com/provenance-io/provenance/x/attribute/types" markerkeeper "github.com/provenance-io/provenance/x/marker/keeper" "github.com/provenance-io/provenance/x/marker/types" ) @@ -39,6 +41,12 @@ type MsgServerTestSuite struct { owner1Addr sdk.AccAddress acct1 sdk.AccountI + privkey2 cryptotypes.PrivKey + pubkey2 cryptotypes.PubKey + owner2 string + owner2Addr sdk.AccAddress + acct2 sdk.AccountI + addresses []sdk.AccAddress } @@ -55,6 +63,13 @@ func (s *MsgServerTestSuite) SetupTest() { s.owner1 = s.owner1Addr.String() acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.owner1Addr) s.app.AccountKeeper.SetAccount(s.ctx, acc) + + s.privkey2 = secp256k1.GenPrivKey() + s.pubkey2 = s.privkey2.PubKey() + s.owner2Addr = sdk.AccAddress(s.pubkey2.Address()) + s.owner2 = s.owner2Addr.String() + acc = s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.owner2Addr) + s.app.AccountKeeper.SetAccount(s.ctx, acc) } func TestMsgServerTestSuite(t *testing.T) { suite.Run(t, new(MsgServerTestSuite)) @@ -264,6 +279,13 @@ func (s *MsgServerTestSuite) containsMessage(events []abci.Event, msg proto.Mess return false } +// noAccessErr creates an expected error message for an address not having access on a marker. +func (s *MsgServerTestSuite) noAccessErr(addr string, role types.Access, denom string) string { + mAddr, err := types.MarkerAddress(denom) + s.Require().NoError(err, "MarkerAddress(%q)", denom) + return fmt.Sprintf("%s does not have %s on %s marker (%s)", addr, role, denom, mAddr) +} + func (s *MsgServerTestSuite) TestMsgFinalizeMarkerRequest() { authUser := testUserAddress("test") noNavMarker := types.NewEmptyMarkerAccount( @@ -718,3 +740,672 @@ func (s *MsgServerTestSuite) TestAddNetAssetValue() { }) } } + +func (s *MsgServerTestSuite) TestMsgAddAccessRequest() { + accessMintGrant := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("MINT"), + } + + accessInvalidGrant := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("Invalid"), + } + + addMarkerMsg := types.NewMsgAddMarkerRequest("hotdog", sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + testCases := []struct { + name string + msg *types.MsgAddAccessRequest + errorMsg string + expectedEvent proto.Message + }{ + { + name: "should successfully grant access to marker", + msg: types.NewMsgAddAccessRequest("hotdog", s.owner1Addr, accessMintGrant), + expectedEvent: types.NewEventMarkerAddAccess(&accessMintGrant, "hotdog", s.owner1), + }, + { + name: "should fail to ADD access to marker, validate basic fails", + msg: types.NewMsgAddAccessRequest("hotdog", s.owner1Addr, accessInvalidGrant), + errorMsg: "invalid access type: invalid request", + }, + { + + name: "should fail to ADD access to marker, keeper AddAccess failure", + msg: types.NewMsgAddAccessRequest("hotdog", s.owner2Addr, accessMintGrant), + errorMsg: fmt.Sprintf("updates to pending marker hotdog can only be made by %s: unauthorized", s.owner1), + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.AddAccess(s.ctx, tc.msg) + if len(tc.errorMsg) > 0 { + s.Require().EqualError(err, tc.errorMsg, "handler(%T) error", tc.msg) + } else { + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgDeleteAccessMarkerRequest() { + hotdogDenom := "hotdog" + accessMintGrant := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("MINT"), + } + + addMarkerMsg := types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + addAccessMsg := types.NewMsgAddAccessRequest(hotdogDenom, s.owner1Addr, accessMintGrant) + _, err = s.msgServer.AddAccess(s.ctx, addAccessMsg) + s.Assert().NoError(err, "should add access to newly added marker") + + testcases := []struct { + name string + msg *types.MsgDeleteAccessRequest + expectedEvent proto.Message + }{ + { + name: "should successfully delete grant access to marker", + msg: types.NewDeleteAccessRequest(hotdogDenom, s.owner1Addr, s.owner1Addr), + expectedEvent: types.NewEventMarkerDeleteAccess(s.owner1, hotdogDenom, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.DeleteAccess(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgActivateMarkerRequest() { + hotdogDenom := "hotdog" + + addMarkerMsg := types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + finalizeMarkerMsg := types.NewMsgFinalizeRequest(hotdogDenom, s.owner1Addr) + _, err = s.msgServer.Finalize(s.ctx, finalizeMarkerMsg) + s.Assert().NoError(err, "should not throw error when finalizing request") + + testcases := []struct { + name string + msg *types.MsgActivateRequest + expectedEvent proto.Message + }{ + { + name: "should successfully activate marker", + msg: types.NewMsgActivateRequest(hotdogDenom, s.owner1Addr), + expectedEvent: types.NewEventMarkerActivate(hotdogDenom, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.Activate(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgCancelMarkerRequest() { + hotdogDenom := "hotdog" + accessDeleteGrant := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("DELETE"), + } + + addMarkerMsg := types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + addAccessMsg := types.NewMsgAddAccessRequest(hotdogDenom, s.owner1Addr, accessDeleteGrant) + _, err = s.msgServer.AddAccess(s.ctx, addAccessMsg) + s.Assert().NoError(err, "should not throw error when adding access to marker") + + testcases := []struct { + name string + msg *types.MsgCancelRequest + expectedEvent proto.Message + }{ + { + name: "should successfully cancel marker", + msg: types.NewMsgCancelRequest(hotdogDenom, s.owner1Addr), + expectedEvent: types.NewEventMarkerCancel(hotdogDenom, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.Cancel(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgDeleteMarkerRequest() { + hotdogDenom := "hotdog" + accessDeleteMintGrant := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("DELETE,MINT"), + } + + addMarkerMsg := types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + addAccessMsg := types.NewMsgAddAccessRequest(hotdogDenom, s.owner1Addr, accessDeleteMintGrant) + _, err = s.msgServer.AddAccess(s.ctx, addAccessMsg) + s.Assert().NoError(err, "should not throw error when adding access to marker") + + cancelMsg := types.NewMsgCancelRequest(hotdogDenom, s.owner1Addr) + _, err = s.msgServer.Cancel(s.ctx, cancelMsg) + s.Assert().NoError(err, "should not throw error when canceling marker") + + testcases := []struct { + name string + msg *types.MsgDeleteRequest + expectedEvent proto.Message + }{ + { + name: "should successfully delete marker", + msg: types.NewMsgDeleteRequest(hotdogDenom, s.owner1Addr), + expectedEvent: types.NewEventMarkerDelete(hotdogDenom, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.Delete(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgMintMarkerRequest() { + hotdogDenom := "hotdog" + access := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("MINT,BURN"), + } + + addMarkerMsg := types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + addAccessMsg := types.NewMsgAddAccessRequest(hotdogDenom, s.owner1Addr, access) + _, err = s.msgServer.AddAccess(s.ctx, addAccessMsg) + s.Assert().NoError(err, "should not throw error when adding access to marker") + + testcases := []struct { + name string + msg *types.MsgMintRequest + expectedEvent proto.Message + }{ + { + name: "should successfully mint marker", + msg: types.NewMsgMintRequest(s.owner1Addr, sdk.NewInt64Coin(hotdogDenom, 100)), + expectedEvent: types.NewEventMarkerMint("100", hotdogDenom, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.Mint(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgBurnMarkerRequest() { + hotdogDenom := "hotdog" + access := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("DELETE,MINT,BURN"), + } + + addMarkerMsg := types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + addAccessMsg := types.NewMsgAddAccessRequest(hotdogDenom, s.owner1Addr, access) + _, err = s.msgServer.AddAccess(s.ctx, addAccessMsg) + s.Assert().NoError(err, "should not throw error when adding access to marker") + + testcases := []struct { + name string + msg *types.MsgBurnRequest + expectedEvent proto.Message + }{ + { + name: "should successfully burn marker", + msg: types.NewMsgBurnRequest(s.owner1Addr, sdk.NewInt64Coin(hotdogDenom, 100)), + expectedEvent: types.NewEventMarkerBurn("100", hotdogDenom, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.Burn(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgWithdrawMarkerRequest() { + hotdogDenom := "hotdog" + access := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("DELETE,MINT,WITHDRAW"), + } + + addMarkerMsg := types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_RestrictedCoin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + addAccessMsg := types.NewMsgAddAccessRequest(hotdogDenom, s.owner1Addr, access) + _, err = s.msgServer.AddAccess(s.ctx, addAccessMsg) + s.Assert().NoError(err, "should not throw error when adding access to marker") + + finalizeMsg := types.NewMsgFinalizeRequest(hotdogDenom, s.owner1Addr) + _, err = s.msgServer.Finalize(s.ctx, finalizeMsg) + s.Assert().NoError(err, "should not throw error when finalizing marker") + + activateMsg := types.NewMsgActivateRequest(hotdogDenom, s.owner1Addr) + _, err = s.msgServer.Activate(s.ctx, activateMsg) + s.Assert().NoError(err, "should not throw error when activating marker message") + + testcases := []struct { + name string + msg *types.MsgWithdrawRequest + expectedEvent proto.Message + }{ + { + name: "should successfully withdraw marker", + msg: types.NewMsgWithdrawRequest(s.owner1Addr, s.owner1Addr, hotdogDenom, sdk.NewCoins(sdk.NewInt64Coin(hotdogDenom, 100))), + expectedEvent: types.NewEventMarkerWithdraw("100hotdog", hotdogDenom, s.owner1, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.Withdraw(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgTransferMarkerRequest() { + hotdogDenom := "hotdog" + access := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("DELETE,MINT,WITHDRAW,TRANSFER"), + } + + addMarkerMsg := types.NewMsgAddMarkerRequest(hotdogDenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_RestrictedCoin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should sucessfully add marker") + + addAccessMsg := types.NewMsgAddAccessRequest(hotdogDenom, s.owner1Addr, access) + _, err = s.msgServer.AddAccess(s.ctx, addAccessMsg) + s.Assert().NoError(err, "should not throw error when adding access to marker") + + finalizeMsg := types.NewMsgFinalizeRequest(hotdogDenom, s.owner1Addr) + _, err = s.msgServer.Finalize(s.ctx, finalizeMsg) + s.Assert().NoError(err, "should not throw error when finalizing marker") + + activateMsg := types.NewMsgActivateRequest(hotdogDenom, s.owner1Addr) + _, err = s.msgServer.Activate(s.ctx, activateMsg) + s.Assert().NoError(err, "should not throw error when activating marker message") + + mintMsg := types.NewMsgMintRequest(s.owner1Addr, sdk.NewInt64Coin(hotdogDenom, 1000)) + _, err = s.msgServer.Mint(s.ctx, mintMsg) + s.Assert().NoError(err, "should not throw error when minting marker") + + testcases := []struct { + name string + msg *types.MsgTransferRequest + expectedEvent proto.Message + }{ + { + name: "should successfully transfer marker", + msg: types.NewMsgTransferRequest(s.owner1Addr, s.owner1Addr, s.owner2Addr, sdk.NewInt64Coin(hotdogDenom, 0)), + expectedEvent: types.NewEventMarkerTransfer("0", hotdogDenom, s.owner1, s.owner2, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.Transfer(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgSetDenomMetadataRequest() { + hotdogDenom := "hotdog" + hotdogName := "Jason" + hotdogSymbol := "WIFI" + access := types.AccessGrant{ + Address: s.owner1, + Permissions: types.AccessListByNames("DELETE,MINT,WITHDRAW,TRANSFER"), + } + + hotdogMetadata := banktypes.Metadata{ + Description: "a description", + DenomUnits: []*banktypes.DenomUnit{ + {Denom: fmt.Sprintf("n%s", hotdogDenom), Exponent: 0, Aliases: []string{fmt.Sprintf("nano%s", hotdogDenom)}}, + {Denom: fmt.Sprintf("u%s", hotdogDenom), Exponent: 3, Aliases: []string{}}, + {Denom: hotdogDenom, Exponent: 9, Aliases: []string{}}, + {Denom: fmt.Sprintf("mega%s", hotdogDenom), Exponent: 15, Aliases: []string{}}, + }, + Base: fmt.Sprintf("n%s", hotdogDenom), + Display: hotdogDenom, + Name: hotdogName, + Symbol: hotdogSymbol, + } + + addMarkerMsg := types.NewMsgAddMarkerRequest(fmt.Sprintf("n%s", hotdogDenom), sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_RestrictedCoin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, addMarkerMsg) + s.Assert().NoError(err, "should successfully add marker") + + addAccessMsg := types.NewMsgAddAccessRequest(fmt.Sprintf("n%s", hotdogDenom), s.owner1Addr, access) + _, err = s.msgServer.AddAccess(s.ctx, addAccessMsg) + s.Assert().NoError(err, "should not throw error when adding access to marker") + + testcases := []struct { + name string + msg *types.MsgSetDenomMetadataRequest + expectedEvent proto.Message + }{ + { + name: "should successfully set denom metadata on marker", + msg: types.NewSetDenomMetadataRequest(hotdogMetadata, s.owner1Addr), + expectedEvent: types.NewEventMarkerSetDenomMetadata(hotdogMetadata, s.owner1), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.SetDenomMetadata(s.ctx, tc.msg) + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgAddFinalizeActivateMarkerRequest() { + denom := "hotdog" + rdenom := "restrictedhotdog" + denomWithDashPeriod := fmt.Sprintf("%s-my.marker", denom) + + testcases := []struct { + name string + handler func(sdk.Context) error + expectedEvent proto.Message + errorMsg string + }{ + { + name: "should successfully ADD,FINALIZE,ACTIVATE new marker", + handler: func(ctx sdk.Context) error { + msg := types.NewMsgAddFinalizeActivateMarkerRequest(denom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, []types.AccessGrant{*types.NewAccessGrant(s.owner1Addr, []types.Access{types.Access_Mint, types.Access_Admin})}, 0, 0) + _, err := s.msgServer.AddFinalizeActivateMarker(s.ctx, msg) + return err + }, + expectedEvent: types.NewEventMarkerAdd(denom, types.MustGetMarkerAddress(denom).String(), "100", "proposed", s.owner1, types.MarkerType_Coin.String()), + }, + { + name: "should successfully ADD,FINALIZE,ACTIVATE new marker with attributes", + handler: func(ctx sdk.Context) error { + msg := types.NewMsgAddFinalizeActivateMarkerRequest(rdenom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_RestrictedCoin, true, true, false, []string{"attributes.one.com", "attributes.two.com"}, []types.AccessGrant{*types.NewAccessGrant(s.owner1Addr, []types.Access{types.Access_Mint, types.Access_Admin})}, 0, 0) + _, err := s.msgServer.AddFinalizeActivateMarker(s.ctx, msg) + return err + }, + expectedEvent: types.NewEventMarkerAdd(rdenom, types.MustGetMarkerAddress(rdenom).String(), "100", "proposed", s.owner1, types.MarkerType_RestrictedCoin.String()), + }, + { + name: "should fail to ADD,FINALIZE,ACTIVATE new marker, validate basic failure", + handler: func(ctx sdk.Context) error { + msg := types.NewMsgAddFinalizeActivateMarkerRequest(denom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, nil, 0, 0) + _, err := s.msgServer.AddFinalizeActivateMarker(s.ctx, msg) + return err + }, + errorMsg: "since this will activate the marker, must have at least one access list defined: invalid request", + }, + { + name: "should fail to ADD,FINALIZE,ACTIVATE new marker, marker already exists", + handler: func(ctx sdk.Context) error { + msg := types.NewMsgAddMarkerRequest(denom, sdkmath.NewInt(100), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, msg) + return err + }, + errorMsg: fmt.Sprintf("marker address already exists for %s: invalid request", types.MustGetMarkerAddress(denom)), + }, + { + name: "should successfully add marker with dash and period", + handler: func(ctx sdk.Context) error { + msg := types.NewMsgAddMarkerRequest(denomWithDashPeriod, sdkmath.NewInt(1000), s.owner1Addr, s.owner1Addr, types.MarkerType_Coin, true, true, false, []string{}, 0, 0) + _, err := s.msgServer.AddMarker(s.ctx, msg) + return err + }, + expectedEvent: types.NewEventMarkerAdd(denomWithDashPeriod, types.MustGetMarkerAddress(denomWithDashPeriod).String(), "1000", "proposed", s.owner1, types.MarkerType_Coin.String()), + }, + { + name: "should successfully mint denom", + handler: func(ctx sdk.Context) error { + msg := types.NewMsgMintRequest(s.owner1Addr, sdk.NewInt64Coin(denom, 1000)) + _, err := s.msgServer.Mint(s.ctx, msg) + return err + }, + expectedEvent: types.NewEventMarkerMint("1000", denom, s.owner1), + }, + { + name: "should fail to burn denom, user doesn't have permissions", + handler: func(ctx sdk.Context) error { + msg := types.NewMsgBurnRequest(s.owner1Addr, sdk.NewInt64Coin(denom, 50)) + _, err := s.msgServer.Burn(s.ctx, msg) + return err + }, + errorMsg: s.noAccessErr(s.owner1, types.Access_Burn, denom) + ": invalid request", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + err := tc.handler(s.ctx) + if len(tc.errorMsg) > 0 { + s.Require().EqualError(err, tc.errorMsg, "should have the correct error") + } else { + s.Require().NoError(err, "should have no error") + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n", tc.expectedEvent) + } + } + }) + } +} + +func (s *MsgServerTestSuite) TestMsgSetAccountDataRequest() { + denomU := "aducoin" + denomR := "adrcoin" + + denomUAddr := types.MustGetMarkerAddress(denomU).String() + denomRAddr := types.MustGetMarkerAddress(denomR).String() + + authority := s.app.MarkerKeeper.GetAuthority() + + msg := types.NewMsgAddFinalizeActivateMarkerRequest( + denomU, sdkmath.NewInt(100), + s.owner1Addr, s.owner1Addr, // From and Manager. + types.MarkerType_Coin, + true, // Supply fixed + true, // Allow gov + false, // don't allow forced transfer + []string{}, // No required attributes. + []types.AccessGrant{ + {Address: s.owner1, Permissions: []types.Access{types.Access_Mint, types.Access_Admin}}, + {Address: s.owner2, Permissions: []types.Access{types.Access_Deposit}}, + }, + 0, + 0, + ) + _, err := s.msgServer.AddFinalizeActivateMarker(s.ctx, msg) + s.Assert().NoError(err, "should successfully add/finalize/active unrestricted marker") + + msg = types.NewMsgAddFinalizeActivateMarkerRequest( + denomR, sdkmath.NewInt(100), + s.owner1Addr, s.owner1Addr, // From and Manager. + types.MarkerType_RestrictedCoin, + true, // Supply fixed + true, // Allow gov + false, // don't allow forced transfer + []string{}, // No required attributes. + []types.AccessGrant{ + {Address: s.owner1, Permissions: []types.Access{types.Access_Mint, types.Access_Admin}}, + {Address: s.owner2, Permissions: []types.Access{types.Access_Deposit}}, + }, + 0, + 0, + ) + _, err = s.msgServer.AddFinalizeActivateMarker(s.ctx, msg) + s.Assert().NoError(err, "should successfully add/finalize/active restricted marker") + + testcases := []struct { + name string + msg *types.MsgSetAccountDataRequest + expectedEvent proto.Message + errorMsg string + }{ + { + name: "should successfully set account data on unrestricted marker via gov prop", + msg: &types.MsgSetAccountDataRequest{ + Denom: denomU, + Value: "This is some unrestricted coin data.", + Signer: authority, + }, + expectedEvent: &attrtypes.EventAccountDataUpdated{Account: denomUAddr}, + }, + { + name: "should successfully set account data on unrestricted marker by signer with deposit", + msg: &types.MsgSetAccountDataRequest{ + Denom: denomU, + Value: "This is some different unrestricted coin data.", + Signer: s.owner2, + }, + expectedEvent: &attrtypes.EventAccountDataUpdated{Account: denomUAddr}, + }, + { + name: "should fail to set account data on unrestricted marker because signer does not have deposit", + msg: &types.MsgSetAccountDataRequest{ + Denom: denomU, + Value: "This is some unrestricted coin data. This won't get used though.", + Signer: s.owner1, + }, + errorMsg: s.noAccessErr(s.owner1, types.Access_Deposit, denomU), + }, + { + name: "should successfully set account data on restricted marker via gov prop", + msg: &types.MsgSetAccountDataRequest{ + Denom: denomR, + Value: "This is some restricted coin data.", + Signer: authority, + }, + expectedEvent: &attrtypes.EventAccountDataUpdated{Account: denomRAddr}, + }, + { + name: "should successfully set account data on restricted marker by signer with deposit", + msg: &types.MsgSetAccountDataRequest{ + Denom: denomR, + Value: "This is some different restricted coin data.", + Signer: s.owner2, + }, + expectedEvent: &attrtypes.EventAccountDataUpdated{Account: denomRAddr}, + }, + { + name: "should fail to set account data on restricted marker because signer does not have deposit", + msg: &types.MsgSetAccountDataRequest{ + Denom: denomR, + Value: "This is some restricted coin data. This won't get used though.", + Signer: s.owner1, + }, + errorMsg: s.noAccessErr(s.owner1, types.Access_Deposit, denomR), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + response, err := s.msgServer.SetAccountData(s.ctx, tc.msg) + if len(tc.errorMsg) > 0 { + s.Require().EqualError(err, tc.errorMsg, "handler(%T) error", tc.msg) + } else { + s.Require().NoError(err, "handler(%T) error", tc.msg) + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Assert().True(result, "Expected typed event was not found in response.\n Expected: %+v\n Response: %+v", tc.expectedEvent, response) + } + } + }) + } +} diff --git a/x/marker/keeper/querier.go b/x/marker/keeper/querier.go deleted file mode 100644 index e2275ce666..0000000000 --- a/x/marker/keeper/querier.go +++ /dev/null @@ -1,177 +0,0 @@ -package keeper - -import ( - "strings" - - abci "github.com/cometbft/cometbft/abci/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/provenance-io/provenance/x/marker/types" -) - -// TODO[1760]: marker: Delete the marker Querier. - -// NewQuerier is the module level router for state queries (using the Legacy Amino Codec) -func NewQuerier(keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { - switch path[0] { - case types.QueryMarkers: - return queryMarkers(ctx, path[1:], req, keeper, legacyQuerierCdc) - case types.QueryHolders: - return queryHolders(ctx, path[1:], req, keeper, legacyQuerierCdc) - case types.QueryMarker: - return queryMarker(ctx, path[1:], req, keeper, legacyQuerierCdc) - case types.QueryMarkerAccess: - return queryAccess(ctx, path[1:], req, keeper, legacyQuerierCdc) - case types.QueryMarkerEscrow: - return queryCoins(ctx, path[1:], req, keeper, legacyQuerierCdc) - case types.QueryMarkerSupply: - return querySupply(ctx, path[1:], req, keeper, legacyQuerierCdc) - default: - return nil, sdkerrors.ErrUnknownRequest.Wrapf("unknown %s query endpoint: %s", types.ModuleName, path[0]) - } - } -} - -// query for a single marker by denom or address -func queryMarker(ctx sdk.Context, path []string, _ abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - account, err := accountForDenomOrAddress(ctx, keeper, path[0]) - if err != nil { - return nil, err - } - - res, err := codec.MarshalJSONIndent(legacyQuerierCdc, account) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return res, nil -} - -// query for access records on an account -func queryAccess(ctx sdk.Context, path []string, _ abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - account, err := accountForDenomOrAddress(ctx, keeper, path[0]) - if err != nil { - return nil, err - } - - m := account.(*types.MarkerAccount) - res, err := codec.MarshalJSONIndent(legacyQuerierCdc, m.AccessControl) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return res, nil -} - -// query for coins on a marker account -func queryCoins(ctx sdk.Context, path []string, _ abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - account, err := accountForDenomOrAddress(ctx, keeper, path[0]) - if err != nil { - return nil, err - } - - m := account.(*types.MarkerAccount) - res, err := codec.MarshalJSONIndent(legacyQuerierCdc, keeper.GetEscrow(ctx, m)) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return res, nil -} - -// query for supply of coin on a marker account -func querySupply(ctx sdk.Context, path []string, _ abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - account, err := accountForDenomOrAddress(ctx, keeper, path[0]) - if err != nil { - return nil, err - } - - m := account.(*types.MarkerAccount) - res, err := codec.MarshalJSONIndent(legacyQuerierCdc, m.Supply) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return res, nil -} - -// query for all marker accounts -func queryMarkers(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - var params types.QueryMarkersParams - - err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms) - if err != nil { - return nil, sdkerrors.ErrJSONUnmarshal.Wrap(err.Error()) - } - - filteredMarkers := make([]types.MarkerAccount, 0) - keeper.IterateMarkers(ctx, func(record types.MarkerAccountI) bool { - if len(params.Status) < 1 || strings.EqualFold(record.GetStatus().String(), params.Status) { - m := record.(*types.MarkerAccount) - filteredMarkers = append(filteredMarkers, *m) - } - return false - }) - - start, end := client.Paginate(len(filteredMarkers), params.Page, params.Limit, len(filteredMarkers)) - if start < 0 || end < 0 { - filteredMarkers = []types.MarkerAccount{} - } else { - filteredMarkers = filteredMarkers[start:end] - } - - res, err := codec.MarshalJSONIndent(legacyQuerierCdc, filteredMarkers) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return res, nil -} - -// query for all accounts holding the given marker coins -func queryHolders(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - var params types.QueryMarkersParams - - err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms) - if err != nil { - return nil, sdkerrors.ErrJSONUnmarshal.Wrap(err.Error()) - } - - holders := keeper.GetAllMarkerHolders(ctx, params.Denom) - - start, end := client.Paginate(len(holders), params.Page, params.Limit, len(holders)) - if start < 0 || end < 0 { - holders = []types.Balance{} - } else { - holders = holders[start:end] - } - - res, err := codec.MarshalJSONIndent(legacyQuerierCdc, holders) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return res, nil -} - -func accountForDenomOrAddress(ctx sdk.Context, keeper Keeper, lookup string) (types.MarkerAccountI, error) { - var addrErr, err error - var addr sdk.AccAddress - var account types.MarkerAccountI - - // try to parse the argument as an address, if this fails try as a denom string. - if addr, addrErr = sdk.AccAddressFromBech32(lookup); addrErr != nil { - account, err = keeper.GetMarkerByDenom(ctx, lookup) - } else { - account, err = keeper.GetMarker(ctx, addr) - } - if err != nil { - return nil, types.ErrMarkerNotFound.Wrap("invalid denom or address") - } - return account, nil -} diff --git a/x/marker/keeper/querier_test.go b/x/marker/keeper/querier_test.go deleted file mode 100644 index fa052a56fc..0000000000 --- a/x/marker/keeper/querier_test.go +++ /dev/null @@ -1,156 +0,0 @@ -package keeper_test - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/cometbft/cometbft/abci/types" - - simapp "github.com/provenance-io/provenance/app" - markerkeeper "github.com/provenance-io/provenance/x/marker/keeper" - markertypes "github.com/provenance-io/provenance/x/marker/types" -) - -func TestNewQuerier(t *testing.T) { - app := simapp.Setup(t) - ctx := app.BaseApp.NewContext(false) - cdc := app.LegacyAmino() - user := testUserAddress("test") - - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - - querier := markerkeeper.NewQuerier(app.MarkerKeeper, app.LegacyAmino()) - - // should error for a route pointing to some other query module - bz, err := querier(ctx, []string{"other"}, query) - require.Error(t, err) - require.Nil(t, bz) - - allMarkersParama := markertypes.NewQueryMarkersParams(1, 20, "testcoin", "") - bz, errRes := cdc.MarshalJSON(allMarkersParama) - require.Nil(t, errRes) - - query.Path = fmt.Sprintf("/custom/%s/%s", markertypes.QuerierRoute, markertypes.QueryMarkers) - query.Data = bz - - // get all markers should not return an error even if there are no markers - _, err = querier(ctx, []string{markertypes.QueryMarkers}, query) - require.Nil(t, err) - - // get all holders should not return an error even if there are no of type - _, err = querier(ctx, []string{markertypes.QueryHolders}, query) - require.Nil(t, err) - - // create a marker account - mac := markertypes.NewEmptyMarkerAccount("testcoin", user.String(), []markertypes.AccessGrant{*markertypes.NewAccessGrant(user, - []markertypes.Access{markertypes.Access_Mint})}) - require.NoError(t, app.MarkerKeeper.AddMarkerAccount(ctx, mac)) - - // get all markers should not return an error - _, err = querier(ctx, []string{markertypes.QueryMarkers}, query) - require.Nil(t, err) - - // get all holders should not return an error - _, err = querier(ctx, []string{markertypes.QueryHolders}, query) - require.Nil(t, err) - - // pull marker using denom on QueryMarker endpoint - query.Path = fmt.Sprintf("/custom/%s/%s/%s", markertypes.QuerierRoute, markertypes.QueryMarker, "testcoin") - query.Data = []byte{} - - _, err = querier(ctx, []string{markertypes.QueryMarker, "testcoin"}, query) - require.Nil(t, err) - - // pull marker using addess on QueryMarker endpoint - query.Path = fmt.Sprintf("/custom/%s/%s/%s", markertypes.QuerierRoute, markertypes.QueryMarker, - markertypes.MustGetMarkerAddress("testcoin")) - query.Data = []byte{} - - _, err = querier(ctx, []string{markertypes.QueryMarker, markertypes.MustGetMarkerAddress("testcoin").String()}, - query) - require.Nil(t, err) - - // pull marker using invalid denom on QueryMarker endpoint - query.Path = fmt.Sprintf("/custom/%s/%s/%s", markertypes.QuerierRoute, markertypes.QueryMarker, "other") - query.Data = []byte{} - - _, err = querier(ctx, []string{markertypes.QueryMarker, "other"}, query) - require.Error(t, err) -} - -func TestQuerierAccess(t *testing.T) { - app := simapp.Setup(t) - ctx := app.BaseApp.NewContext(false) - user := testUserAddress("test") - // create a marker account - mac := markertypes.NewEmptyMarkerAccount("testcoin", user.String(), []markertypes.AccessGrant{*markertypes.NewAccessGrant(user, - []markertypes.Access{markertypes.Access_Mint})}) - require.NoError(t, app.MarkerKeeper.AddMarkerAccount(ctx, mac)) - - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - - querier := markerkeeper.NewQuerier(app.MarkerKeeper, app.LegacyAmino()) - - // pull marker access list - query.Path = fmt.Sprintf("/custom/%s/%s/%s", markertypes.QuerierRoute, markertypes.QueryMarkerAccess, "testcoin") - query.Data = []byte{} - - _, err := querier(ctx, []string{markertypes.QueryMarkerAccess, "testcoin"}, query) - require.Nil(t, err) -} - -func TestQuerierCoins(t *testing.T) { - app := simapp.Setup(t) - ctx := app.BaseApp.NewContext(false) - user := testUserAddress("test") - // create a marker account - mac := markertypes.NewEmptyMarkerAccount("testcoin", user.String(), []markertypes.AccessGrant{*markertypes.NewAccessGrant(user, - []markertypes.Access{markertypes.Access_Mint})}) - require.NoError(t, app.MarkerKeeper.AddMarkerAccount(ctx, mac)) - - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - - querier := markerkeeper.NewQuerier(app.MarkerKeeper, app.LegacyAmino()) - - // pull marker account coins in escrow - query.Path = fmt.Sprintf("/custom/%s/%s/%s", markertypes.QuerierRoute, markertypes.QueryMarkerEscrow, "testcoin") - query.Data = []byte{} - - _, err := querier(ctx, []string{markertypes.QueryMarkerEscrow, "testcoin"}, query) - require.Nil(t, err) -} - -func TestQuerierSupply(t *testing.T) { - app := simapp.Setup(t) - ctx := app.BaseApp.NewContext(false) - user := testUserAddress("test") - // create a marker account - mac := markertypes.NewEmptyMarkerAccount("testcoin", user.String(), []markertypes.AccessGrant{*markertypes.NewAccessGrant(user, - []markertypes.Access{markertypes.Access_Mint})}) - require.NoError(t, app.MarkerKeeper.AddMarkerAccount(ctx, mac)) - - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - - querier := markerkeeper.NewQuerier(app.MarkerKeeper, app.LegacyAmino()) - - // pull marker account total supply - query.Path = fmt.Sprintf("/custom/%s/%s/%s", markertypes.QuerierRoute, markertypes.QueryMarkerSupply, "testcoin") - query.Data = []byte{} - - _, err := querier(ctx, []string{markertypes.QueryMarkerSupply, "testcoin"}, query) - require.Nil(t, err) -} diff --git a/x/marker/keeper/query_server.go b/x/marker/keeper/query_server.go index 5c09a45c7b..07167d35a0 100644 --- a/x/marker/keeper/query_server.go +++ b/x/marker/keeper/query_server.go @@ -6,8 +6,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" "cosmossdk.io/store/prefix" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -204,3 +204,21 @@ func (k Keeper) NetAssetValues(c context.Context, req *types.QueryNetAssetValues return &types.QueryNetAssetValuesResponse{NetAssetValues: navs}, nil } + +// accountForDenomOrAddress attempts to first get a marker by account address and then by denom. +func accountForDenomOrAddress(ctx sdk.Context, keeper Keeper, lookup string) (types.MarkerAccountI, error) { + var addrErr, err error + var addr sdk.AccAddress + var account types.MarkerAccountI + + // try to parse the argument as an address, if this fails try as a denom string. + if addr, addrErr = sdk.AccAddressFromBech32(lookup); addrErr != nil { + account, err = keeper.GetMarkerByDenom(ctx, lookup) + } else { + account, err = keeper.GetMarker(ctx, addr) + } + if err != nil { + return nil, types.ErrMarkerNotFound.Wrap("invalid denom or address") + } + return account, nil +} diff --git a/x/marker/keeper/send_restrictions_test.go b/x/marker/keeper/send_restrictions_test.go index a5e572d4ad..9d558c62ca 100644 --- a/x/marker/keeper/send_restrictions_test.go +++ b/x/marker/keeper/send_restrictions_test.go @@ -15,8 +15,8 @@ import ( simapp "github.com/provenance-io/provenance/app" attrTypes "github.com/provenance-io/provenance/x/attribute/types" - "github.com/provenance-io/provenance/x/marker" "github.com/provenance-io/provenance/x/marker/keeper" + markerkeeper "github.com/provenance-io/provenance/x/marker/keeper" "github.com/provenance-io/provenance/x/marker/types" ) @@ -643,6 +643,7 @@ func TestBankSendCoinsUsesSendRestrictionFn(t *testing.T) { app := simapp.Setup(t) ctx := app.BaseApp.NewContext(false) + msgServer := markerkeeper.NewMsgServerImpl(app.MarkerKeeper) app.MarkerKeeper.AddMarkerAccount(ctx, types.NewEmptyMarkerAccount("navcoin", addrNameOwner.String(), []types.AccessGrant{})) app.AccountKeeper.SetAccount(ctx, app.AccountKeeper.NewAccountWithAddress(ctx, addrNameOwner)) err := app.NameKeeper.SetNameRecord(ctx, "kyc.provenance.io", addrNameOwner, false) @@ -670,8 +671,7 @@ func TestBankSendCoinsUsesSendRestrictionFn(t *testing.T) { AllowForcedTransfer: false, RequiredAttributes: []string{"kyc.provenance.io"}, } - markerHandler := marker.NewHandler(app.MarkerKeeper) - _, err = markerHandler(ctx, makeMarkerMsg) + _, err = msgServer.AddFinalizeActivateMarker(ctx, makeMarkerMsg) require.NoError(t, err, "makeMarkerMsg") err = app.MarkerKeeper.WithdrawCoins(ctx, addrHasWithdraw, addrHasAttr, markerDenom, cz(100, markerDenom)) require.NoError(t, err, "WithdrawCoins to addrHasTransfer") @@ -737,6 +737,7 @@ func TestBankInputOutputCoinsUsesSendRestrictionFn(t *testing.T) { app := simapp.Setup(t) ctx := app.BaseApp.NewContext(false) + msgServer := markerkeeper.NewMsgServerImpl(app.MarkerKeeper) app.MarkerKeeper.AddMarkerAccount(ctx, types.NewEmptyMarkerAccount("navcoin", addrManager.String(), []types.AccessGrant{})) app.AccountKeeper.SetAccount(ctx, app.AccountKeeper.NewAccountWithAddress(ctx, addrManager)) err := app.NameKeeper.SetNameRecord(ctx, "rando.io", addrManager, false) @@ -777,8 +778,7 @@ func TestBankInputOutputCoinsUsesSendRestrictionFn(t *testing.T) { AllowForcedTransfer: false, RequiredAttributes: []string{"rando.io"}, } - markerHandler := marker.NewHandler(app.MarkerKeeper) - _, err = markerHandler(ctx, makeMarkerMsg) + _, err = msgServer.AddFinalizeActivateMarker(ctx, makeMarkerMsg) require.NoError(t, err, "MsgAddFinalizeActivateMarkerRequest") err = app.MarkerKeeper.WithdrawCoins(ctx, addrManager, addrManager, markerDenom, cz(100)) require.NoError(t, err, "WithdrawCoins to addrInput") diff --git a/x/metadata/handler.go b/x/metadata/handler.go deleted file mode 100644 index 4fcf1f66ca..0000000000 --- a/x/metadata/handler.go +++ /dev/null @@ -1,98 +0,0 @@ -package metadata - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/provenance-io/provenance/x/metadata/keeper" - "github.com/provenance-io/provenance/x/metadata/types" -) - -// NewHandler returns a handler for metadata messages. -// TODO[1760]: metadata: Delete the metadata NewHandler. -func NewHandler(k keeper.Keeper) func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgWriteScopeRequest: - res, err := msgServer.WriteScope(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteScopeRequest: - res, err := msgServer.DeleteScope(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgAddScopeDataAccessRequest: - res, err := msgServer.AddScopeDataAccess(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteScopeDataAccessRequest: - res, err := msgServer.DeleteScopeDataAccess(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgAddScopeOwnerRequest: - res, err := msgServer.AddScopeOwner(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteScopeOwnerRequest: - res, err := msgServer.DeleteScopeOwner(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgUpdateValueOwnersRequest: - res, err := msgServer.UpdateValueOwners(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgMigrateValueOwnerRequest: - res, err := msgServer.MigrateValueOwner(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgWriteRecordRequest: - res, err := msgServer.WriteRecord(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteRecordRequest: - res, err := msgServer.DeleteRecord(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgWriteSessionRequest: - res, err := msgServer.WriteSession(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgWriteScopeSpecificationRequest: - res, err := msgServer.WriteScopeSpecification(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteScopeSpecificationRequest: - res, err := msgServer.DeleteScopeSpecification(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgWriteContractSpecificationRequest: - res, err := msgServer.WriteContractSpecification(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteContractSpecificationRequest: - res, err := msgServer.DeleteContractSpecification(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgAddContractSpecToScopeSpecRequest: - res, err := msgServer.AddContractSpecToScopeSpec(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteContractSpecFromScopeSpecRequest: - res, err := msgServer.DeleteContractSpecFromScopeSpec(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgWriteRecordSpecificationRequest: - res, err := msgServer.WriteRecordSpecification(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteRecordSpecificationRequest: - res, err := msgServer.DeleteRecordSpecification(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgBindOSLocatorRequest: - res, err := msgServer.BindOSLocator(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteOSLocatorRequest: - res, err := msgServer.DeleteOSLocator(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgModifyOSLocatorRequest: - res, err := msgServer.ModifyOSLocator(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgSetAccountDataRequest: - res, err := msgServer.SetAccountData(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.ErrUnknownRequest.Wrapf("unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} diff --git a/x/metadata/handler_test.go b/x/metadata/handler_test.go deleted file mode 100644 index 3c30ba5b07..0000000000 --- a/x/metadata/handler_test.go +++ /dev/null @@ -1,1320 +0,0 @@ -package metadata_test - -import ( - "encoding/base64" - "fmt" - "strings" - "testing" - - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/provenance-io/provenance/app" - "github.com/provenance-io/provenance/x/metadata" - "github.com/provenance-io/provenance/x/metadata/types" -) - -// TODO[1760]: metadata: Migrate the metadata handler tests to the keeper. - -type MetadataHandlerTestSuite struct { - suite.Suite - - app *app.App - ctx sdk.Context - handler func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) - - pubkey1 cryptotypes.PubKey - user1 string - user1Addr sdk.AccAddress - - pubkey2 cryptotypes.PubKey - user2 string - user2Addr sdk.AccAddress -} - -func (s *MetadataHandlerTestSuite) SetupTest() { - s.app = app.Setup(s.T()) - s.ctx = s.app.BaseApp.NewContext(false) - s.handler = metadata.NewHandler(s.app.MetadataKeeper) - - s.pubkey1 = secp256k1.GenPrivKey().PubKey() - s.user1Addr = sdk.AccAddress(s.pubkey1.Address()) - s.user1 = s.user1Addr.String() - user1Acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.user1Addr) - s.Require().NoError(user1Acc.SetPubKey(s.pubkey1), "SetPubKey user1") - - privKey, _ := secp256r1.GenPrivKey() - s.pubkey2 = privKey.PubKey() - s.user2Addr = sdk.AccAddress(s.pubkey2.Address()) - s.user2 = s.user2Addr.String() - user2Acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.user2Addr) - s.Require().NoError(user2Acc.SetPubKey(s.pubkey1), "SetPubKey user2") - - s.app.AccountKeeper.SetAccount(s.ctx, user1Acc) - s.app.AccountKeeper.SetAccount(s.ctx, user2Acc) -} - -func TestMetadataHandlerTestSuite(t *testing.T) { - suite.Run(t, new(MetadataHandlerTestSuite)) -} - -func ownerPartyList(addresses ...string) []types.Party { - retval := make([]types.Party, len(addresses)) - for i, addr := range addresses { - retval[i] = types.Party{Address: addr, Role: types.PartyType_PARTY_TYPE_OWNER} - } - return retval -} - -// AssertErrorValue asserts that: -// - If errorString is empty, theError must be nil -// - If errorString is not empty, theError must equal the errorString. -func AssertErrorValue(t *testing.T, theError error, errorString string, msgAndArgs ...interface{}) bool { - t.Helper() - if len(errorString) > 0 { - return assert.EqualError(t, theError, errorString, msgAndArgs...) - } - return assert.NoError(t, theError, msgAndArgs...) -} - -// AssertErrorValue asserts that: -// - If errorString is empty, theError must be nil -// - If errorString is not empty, theError must equal the errorString. -func (s *MetadataHandlerTestSuite) AssertErrorValue(theError error, errorString string, msgAndArgs ...interface{}) bool { - return AssertErrorValue(s.T(), theError, errorString, msgAndArgs...) -} - -// TODO: WriteScope tests -// TODO: DeleteScope tests - -func (s *MetadataHandlerTestSuite) TestAddAndDeleteScopeDataAccess() { - scopeSpecID := types.ScopeSpecMetadataAddress(uuid.New()) - scopeSpec := types.NewScopeSpecification(scopeSpecID, nil, []string{s.user1}, []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, []types.MetadataAddress{}) - scopeID := types.ScopeMetadataAddress(uuid.New()) - scope := types.NewScope(scopeID, scopeSpecID, ownerPartyList(s.user1), []string{s.user1}, "", false) - dneScopeID := types.ScopeMetadataAddress(uuid.New()) - user3 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - - cases := []struct { - name string - msg sdk.Msg - signers []string - errorMsg string - }{ - { - "setup test with new scope specification", - types.NewMsgWriteScopeSpecificationRequest(*scopeSpec, []string{s.user1}), - []string{s.user1}, - "", - }, - { - "setup test with new scope", - types.NewMsgWriteScopeRequest(*scope, []string{s.user1}, 0), - []string{s.user1}, - "", - }, - { - "should fail to ADD address to data access, msg validate basic failure", - types.NewMsgAddScopeDataAccessRequest(scopeID, []string{}, []string{s.user1}), - []string{s.user1}, - "data access list cannot be empty: invalid request", - }, - { - "should fail to ADD address to data access, validate add failure", - types.NewMsgAddScopeDataAccessRequest(dneScopeID, []string{s.user1}, []string{s.user1}), - []string{s.user1}, - fmt.Sprintf("scope not found with id %s: not found", dneScopeID), - }, - { - "should fail to ADD address to data access, validate add failure", - types.NewMsgAddScopeDataAccessRequest(scopeID, []string{s.user1}, []string{s.user1}), - []string{s.user1}, - fmt.Sprintf("address already exists for data access %s: invalid request", s.user1), - }, - { - "should successfully ADD address to data access", - types.NewMsgAddScopeDataAccessRequest(scopeID, []string{s.user2}, []string{s.user1}), - []string{s.user1}, - "", - }, - { - "should fail to DELETE address from data access, msg validate basic failure", - types.NewMsgDeleteScopeDataAccessRequest(scopeID, []string{}, []string{s.user1}), - []string{s.user1}, - "data access list cannot be empty: invalid request", - }, - { - "should fail to DELETE address from data access, validate add failure", - types.NewMsgDeleteScopeDataAccessRequest(dneScopeID, []string{s.user1}, []string{s.user1}), - []string{s.user1}, - fmt.Sprintf("scope not found with id %s: not found", dneScopeID), - }, - { - "should fail to DELETE address from data access, validate add failure", - types.NewMsgDeleteScopeDataAccessRequest(scopeID, []string{user3}, []string{s.user1}), - []string{s.user1}, - fmt.Sprintf("address does not exist in scope data access: %s: invalid request", user3), - }, - { - "should successfully DELETE address from data access", - types.NewMsgDeleteScopeDataAccessRequest(scopeID, []string{s.user2}, []string{s.user1}), - []string{s.user1}, - "", - }, - } - - for _, tc := range cases { - s.T().Run(tc.name, func(t *testing.T) { - _, err := s.handler(s.ctx, tc.msg) - if len(tc.errorMsg) > 0 { - assert.EqualError(t, err, tc.errorMsg) - } else { - assert.NoError(t, err) - } - }) - } - - s.T().Run("data access actually deleted and added", func(t *testing.T) { - addrOriginator := "cosmos1rr4d0eu62pgt4edw38d2ev27798pfhdhm39zct" - addrServicer := "cosmos1a7mmtar5ke5fxk5gn00dlag0zfmdkmhapmugk7" - scopeA := types.Scope{ - ScopeId: types.ScopeMetadataAddress(uuid.New()), - SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), - DataAccess: []string{addrOriginator, addrServicer}, - ValueOwnerAddress: addrServicer, - Owners: []types.Party{ - { - Address: addrOriginator, - Role: types.PartyType_PARTY_TYPE_ORIGINATOR, - }, - }, - } - - scopeSpecA := types.ScopeSpecification{ - SpecificationId: scopeA.SpecificationId, - Description: &types.Description{ - Name: "com.figure.origination.loan", - Description: "Figure loan origination", - }, - OwnerAddresses: []string{"cosmos1q8n4v4m0hm8v0a7n697nwtpzhfsz3f4d40lnsu"}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_ORIGINATOR}, - ContractSpecIds: nil, - } - - s.app.MetadataKeeper.SetScope(s.ctx, scopeA) - s.app.MetadataKeeper.SetScopeSpecification(s.ctx, scopeSpecA) - - msgDel := types.NewMsgDeleteScopeDataAccessRequest( - scopeA.ScopeId, - []string{addrServicer}, - []string{addrOriginator}, - ) - - _, errDel := s.handler(s.ctx, msgDel) - require.NoError(t, errDel, "Failed to make DeleteScopeDataAccessRequest call") - - scopeB, foundB := s.app.MetadataKeeper.GetScope(s.ctx, scopeA.ScopeId) - require.Truef(t, foundB, "Scope %s not found after DeleteScopeOwnerRequest call.", scopeA.ScopeId) - - assert.Equal(t, scopeA.ScopeId, scopeB.ScopeId, "del ScopeId") - assert.Equal(t, scopeA.SpecificationId, scopeB.SpecificationId, "del SpecificationId") - assert.Equal(t, scopeA.DataAccess[0:1], scopeB.DataAccess, "del DataAccess") - assert.Equal(t, scopeA.ValueOwnerAddress, scopeB.ValueOwnerAddress, "del ValueOwnerAddress") - assert.Equal(t, scopeA.Owners, scopeB.Owners, "del Owners") - - // Stop test if it's already failed. - if t.Failed() { - t.FailNow() - } - - msgAdd := types.NewMsgAddScopeDataAccessRequest( - scopeA.ScopeId, - []string{addrServicer}, - []string{addrOriginator}, - ) - - _, errAdd := s.handler(s.ctx, msgAdd) - require.NoError(t, errAdd, "Failed to make AddScopeDataAccessRequest call") - - scopeC, foundC := s.app.MetadataKeeper.GetScope(s.ctx, scopeA.ScopeId) - require.Truef(t, foundC, "Scope %s not found after AddScopeOwnerRequest call.", scopeA.ScopeId) - - assert.Equal(t, scopeA.ScopeId, scopeC.ScopeId, "add ScopeId") - assert.Equal(t, scopeA.SpecificationId, scopeC.SpecificationId, "add SpecificationId") - assert.Equal(t, scopeA.DataAccess, scopeC.DataAccess, "add DataAccess") - assert.Equal(t, scopeA.ValueOwnerAddress, scopeC.ValueOwnerAddress, "add ValueOwnerAddress") - assert.Equal(t, scopeA.Owners, scopeC.Owners, "add Owners") - }) -} - -func (s *MetadataHandlerTestSuite) TestAddAndDeleteScopeOwners() { - scopeSpecID := types.ScopeSpecMetadataAddress(uuid.New()) - scopeSpec := types.NewScopeSpecification(scopeSpecID, nil, []string{s.user1}, []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, []types.MetadataAddress{}) - scopeID := types.ScopeMetadataAddress(uuid.New()) - scope := types.NewScope(scopeID, scopeSpecID, ownerPartyList(s.user1), []string{s.user1}, "", false) - dneScopeID := types.ScopeMetadataAddress(uuid.New()) - user3 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - - cases := []struct { - name string - msg sdk.Msg - signers []string - errorMsg string - }{ - { - "setup test with new scope specification", - types.NewMsgWriteScopeSpecificationRequest(*scopeSpec, []string{s.user1}), - []string{s.user1}, - "", - }, - { - "setup test with new scope", - types.NewMsgWriteScopeRequest(*scope, []string{s.user1}, 0), - []string{s.user1}, - "", - }, - { - "should fail to ADD owners, msg validate basic failure", - types.NewMsgAddScopeOwnerRequest(scopeID, []types.Party{}, []string{s.user1}), - []string{s.user1}, - "invalid owners: at least one party is required: invalid request", - }, - { - "should fail to ADD owners, can not find scope", - types.NewMsgAddScopeOwnerRequest(dneScopeID, []types.Party{{Address: s.user1, Role: types.PartyType_PARTY_TYPE_OWNER}}, []string{s.user1}), - []string{s.user1}, - fmt.Sprintf("scope not found with id %s: not found", dneScopeID), - }, - { - "should fail to ADD owners, validate add failure", - types.NewMsgAddScopeOwnerRequest(scopeID, []types.Party{{Address: s.user1, Role: types.PartyType_PARTY_TYPE_OWNER}}, []string{s.user1}), - []string{s.user1}, - fmt.Sprintf("party already exists with address %s and role %s", s.user1, types.PartyType_PARTY_TYPE_OWNER), - }, - { - "should successfully ADD owners", - types.NewMsgAddScopeOwnerRequest(scopeID, []types.Party{{Address: s.user2, Role: types.PartyType_PARTY_TYPE_OWNER}}, []string{s.user1}), - []string{s.user1}, - "", - }, - { - "should fail to DELETE owners, msg validate basic failure", - types.NewMsgDeleteScopeOwnerRequest(scopeID, []string{}, []string{s.user1, s.user2}), - []string{s.user1}, - "at least one owner address is required: invalid request", - }, - { - "should fail to DELETE owners, validate add failure", - types.NewMsgDeleteScopeOwnerRequest(dneScopeID, []string{s.user1}, []string{s.user1, s.user2}), - []string{s.user1}, - fmt.Sprintf("scope not found with id %s: not found", dneScopeID), - }, - { - "should fail to DELETE owners, validate add failure", - types.NewMsgDeleteScopeOwnerRequest(scopeID, []string{user3}, []string{s.user1, s.user2}), - []string{s.user1}, - fmt.Sprintf("address does not exist in scope owners: %s", user3), - }, - { - "should successfully DELETE owners", - types.NewMsgDeleteScopeOwnerRequest(scopeID, []string{s.user2}, []string{s.user1, s.user2}), - []string{s.user1}, - "", - }, - } - - for _, tc := range cases { - s.T().Run(tc.name, func(t *testing.T) { - _, err := s.handler(s.ctx, tc.msg) - if len(tc.errorMsg) > 0 { - assert.EqualError(t, err, tc.errorMsg) - } else { - assert.NoError(t, err) - } - }) - } - - s.T().Run("owner actually deleted and added", func(t *testing.T) { - addrOriginator := "cosmos1rr4d0eu62pgt4edw38d2ev27798pfhdhm39zct" - addrServicer := "cosmos1a7mmtar5ke5fxk5gn00dlag0zfmdkmhapmugk7" - scopeA := types.Scope{ - ScopeId: types.ScopeMetadataAddress(uuid.New()), - SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), - DataAccess: []string{addrOriginator, addrServicer}, - ValueOwnerAddress: addrServicer, - Owners: []types.Party{ - { - Address: addrOriginator, - Role: types.PartyType_PARTY_TYPE_ORIGINATOR, - }, - { - Address: addrServicer, - Role: types.PartyType_PARTY_TYPE_SERVICER, - }, - }, - } - - scopeSpecA := types.ScopeSpecification{ - SpecificationId: scopeA.SpecificationId, - Description: &types.Description{ - Name: "com.figure.origination.loan", - Description: "Figure loan origination", - }, - OwnerAddresses: []string{"cosmos1q8n4v4m0hm8v0a7n697nwtpzhfsz3f4d40lnsu"}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_ORIGINATOR}, - ContractSpecIds: nil, - } - - s.app.MetadataKeeper.SetScope(s.ctx, scopeA) - s.app.MetadataKeeper.SetScopeSpecification(s.ctx, scopeSpecA) - - msgDel := types.NewMsgDeleteScopeOwnerRequest( - scopeA.ScopeId, - []string{addrServicer}, - []string{addrOriginator, addrServicer}, - ) - - _, errDel := s.handler(s.ctx, msgDel) - require.NoError(t, errDel, "Failed to make DeleteScopeOwnerRequest call") - - scopeB, foundB := s.app.MetadataKeeper.GetScope(s.ctx, scopeA.ScopeId) - require.Truef(t, foundB, "Scope %s not found after DeleteScopeOwnerRequest call.", scopeA.ScopeId) - - assert.Equal(t, scopeA.ScopeId, scopeB.ScopeId, "del ScopeId") - assert.Equal(t, scopeA.SpecificationId, scopeB.SpecificationId, "del SpecificationId") - assert.Equal(t, scopeA.DataAccess, scopeB.DataAccess, "del DataAccess") - assert.Equal(t, scopeA.ValueOwnerAddress, scopeB.ValueOwnerAddress, "del ValueOwnerAddress") - assert.Equal(t, scopeA.Owners[0:1], scopeB.Owners, "del Owners") - - // Stop test if it's already failed. - if t.Failed() { - t.FailNow() - } - - msgAdd := types.NewMsgAddScopeOwnerRequest( - scopeA.ScopeId, - []types.Party{{Address: addrServicer, Role: types.PartyType_PARTY_TYPE_SERVICER}}, - []string{addrOriginator}, - ) - - _, errAdd := s.handler(s.ctx, msgAdd) - require.NoError(t, errAdd, "Failed to make DeleteScopeOwnerRequest call") - - scopeC, foundC := s.app.MetadataKeeper.GetScope(s.ctx, scopeA.ScopeId) - require.Truef(t, foundC, "Scope %s not found after AddScopeOwnerRequest call.", scopeA.ScopeId) - - assert.Equal(t, scopeA.ScopeId, scopeC.ScopeId, "add ScopeId") - assert.Equal(t, scopeA.SpecificationId, scopeC.SpecificationId, "add SpecificationId") - assert.Equal(t, scopeA.DataAccess, scopeC.DataAccess, "add DataAccess") - assert.Equal(t, scopeA.ValueOwnerAddress, scopeC.ValueOwnerAddress, "add ValueOwnerAddress") - assert.Equal(t, scopeA.Owners, scopeC.Owners, "add Owners") - }) -} - -func (s *MetadataHandlerTestSuite) TestUpdateValueOwners() { - scopeID1 := types.ScopeMetadataAddress(uuid.New()) - scopeID2 := types.ScopeMetadataAddress(uuid.New()) - scopeIDNotFound := types.ScopeMetadataAddress(uuid.New()) - - scopeID3Diff1 := types.ScopeMetadataAddress(uuid.New()) - scopeID3Diff2 := types.ScopeMetadataAddress(uuid.New()) - scopeID3Diff3 := types.ScopeMetadataAddress(uuid.New()) - scopeID3Same1 := types.ScopeMetadataAddress(uuid.New()) - scopeID3Same2 := types.ScopeMetadataAddress(uuid.New()) - scopeID3Same3 := types.ScopeMetadataAddress(uuid.New()) - - owner1 := sdk.AccAddress("owner1______________").String() - owner2 := sdk.AccAddress("owner2______________").String() - owner3Diff1 := sdk.AccAddress("owner3Diff1_________").String() - owner3Diff2 := sdk.AccAddress("owner3Diff2_________").String() - owner3Diff3 := sdk.AccAddress("owner3Diff3_________").String() - owner3Same1 := sdk.AccAddress("owner3Same1_________").String() - owner3Same2 := sdk.AccAddress("owner3Same2_________").String() - owner3Same3 := sdk.AccAddress("owner3Same3_________").String() - - dataAccess1 := sdk.AccAddress("dataAccess1_________").String() - dataAccess2 := sdk.AccAddress("dataAccess2_________").String() - dataAccess3Diff1 := sdk.AccAddress("dataAccess3Diff1____").String() - dataAccess3Diff2 := sdk.AccAddress("dataAccess3Diff2____").String() - dataAccess3Diff3 := sdk.AccAddress("dataAccess3Diff3____").String() - dataAccess3Same1 := sdk.AccAddress("dataAccess3Same1____").String() - dataAccess3Same2 := sdk.AccAddress("dataAccess3Same2____").String() - dataAccess3Same3 := sdk.AccAddress("dataAccess3Same3____").String() - - valueOwner1 := sdk.AccAddress("valueOwner1_________").String() - valueOwner2 := sdk.AccAddress("valueOwner2_________").String() - valueOwner3Diff1 := sdk.AccAddress("valueOwner3Diff1____").String() - valueOwner3Diff2 := sdk.AccAddress("valueOwner3Diff2____").String() - valueOwner3Diff3 := sdk.AccAddress("valueOwner3Diff3____").String() - valueOwner3Same := sdk.AccAddress("valueOwner3Same_____").String() - - scopeSpecID := types.ScopeSpecMetadataAddress(uuid.New()) - ns := func(scopeID types.MetadataAddress, owner, dataAccess, valueOwner string) types.Scope { - return types.Scope{ - ScopeId: scopeID, - SpecificationId: scopeSpecID, - Owners: []types.Party{{Address: owner, Role: types.PartyType_PARTY_TYPE_OWNER}}, - DataAccess: []string{dataAccess}, - ValueOwnerAddress: valueOwner, - } - } - ids := func(scopeIDs ...types.MetadataAddress) []types.MetadataAddress { - return scopeIDs - } - - newValueOwner := sdk.AccAddress("newValueOwner_______").String() - - tests := []struct { - name string - starters []types.Scope - scopeIDs []types.MetadataAddress - signers []string - expErr string - }{ - { - name: "scope 1 of 3 not found", - starters: []types.Scope{ - ns(scopeID1, owner1, dataAccess1, valueOwner1), - ns(scopeID2, owner2, dataAccess2, valueOwner2), - }, - scopeIDs: ids(scopeIDNotFound, scopeID1, scopeID2), - signers: []string{valueOwner1, valueOwner2}, - expErr: "scope not found with id " + scopeIDNotFound.String() + ": not found", - }, - { - name: "scope 2 of 3 not found", - starters: []types.Scope{ - ns(scopeID1, owner1, dataAccess1, valueOwner1), - ns(scopeID2, owner2, dataAccess2, valueOwner2), - }, - scopeIDs: ids(scopeID1, scopeIDNotFound, scopeID2), - signers: []string{valueOwner1, valueOwner2}, - expErr: "scope not found with id " + scopeIDNotFound.String() + ": not found", - }, - { - name: "scope 3 of 3 not found", - starters: []types.Scope{ - ns(scopeID1, owner1, dataAccess1, valueOwner1), - ns(scopeID2, owner2, dataAccess2, valueOwner2), - }, - scopeIDs: ids(scopeID1, scopeID2, scopeIDNotFound), - signers: []string{valueOwner1, valueOwner2}, - expErr: "scope not found with id " + scopeIDNotFound.String() + ": not found", - }, - { - name: "not properly signed", - starters: []types.Scope{ - ns(scopeID1, owner1, dataAccess1, valueOwner1), - ns(scopeID2, owner2, dataAccess2, valueOwner2), - }, - scopeIDs: ids(scopeID1, scopeID2), - signers: []string{valueOwner1}, - expErr: "missing signature from existing value owner " + valueOwner2 + ": invalid request", - }, - { - name: "1 scope without value owner", - starters: []types.Scope{ - ns(scopeID1, owner1, dataAccess1, ""), - }, - scopeIDs: ids(scopeID1), - signers: []string{owner1}, - expErr: "scope " + scopeID1.String() + " does not yet have a value owner: invalid request", - }, - { - name: "1 scope updated", - starters: []types.Scope{ - ns(scopeID1, owner1, dataAccess1, valueOwner1), - }, - scopeIDs: ids(scopeID1), - signers: []string{valueOwner1}, - expErr: "", - }, - { - name: "3 scopes updated all different", - starters: []types.Scope{ - ns(scopeID3Diff1, owner3Diff1, dataAccess3Diff1, valueOwner3Diff1), - ns(scopeID3Diff2, owner3Diff2, dataAccess3Diff2, valueOwner3Diff2), - ns(scopeID3Diff3, owner3Diff3, dataAccess3Diff3, valueOwner3Diff3), - }, - scopeIDs: ids(scopeID3Diff1, scopeID3Diff2, scopeID3Diff3), - signers: []string{valueOwner3Diff1, valueOwner3Diff2, valueOwner3Diff3}, - expErr: "", - }, - { - name: "3 scopes updated all same", - starters: []types.Scope{ - ns(scopeID3Same1, owner3Same1, dataAccess3Same1, valueOwner3Same), - ns(scopeID3Same2, owner3Same2, dataAccess3Same2, valueOwner3Same), - ns(scopeID3Same3, owner3Same3, dataAccess3Same3, valueOwner3Same), - }, - scopeIDs: ids(scopeID3Same1, scopeID3Same2, scopeID3Same3), - signers: []string{valueOwner3Same}, - expErr: "", - }, - } - - for _, tc := range tests { - s.Run(tc.name, func() { - for _, scope := range tc.starters { - s.app.MetadataKeeper.SetScope(s.ctx, scope) - defer s.app.MetadataKeeper.RemoveScope(s.ctx, scope.ScopeId) - } - msg := types.MsgUpdateValueOwnersRequest{ - ScopeIds: tc.scopeIDs, - ValueOwnerAddress: newValueOwner, - Signers: tc.signers, - } - _, err := s.handler(s.ctx, &msg) - if len(tc.expErr) > 0 { - s.Assert().EqualError(err, tc.expErr, "handler(MsgUpdateValueOwnersRequest)") - } else { - s.Require().NoError(err, "handler(MsgUpdateValueOwnersRequest)") - - for i, scopeID := range tc.scopeIDs { - scope, found := s.app.MetadataKeeper.GetScope(s.ctx, scopeID) - if s.Assert().True(found, "[%d]GetScope(%s) found bool", i, scopeID) { - s.Assert().Equal(newValueOwner, scope.ValueOwnerAddress, "[%d] updated scope's value owner", i) - } - } - } - }) - } -} - -func (s *MetadataHandlerTestSuite) TestMigrateValueOwner() { - scopeSpecID := types.ScopeSpecMetadataAddress(uuid.New()) - storeScope := func(valueOwner string, scopeID types.MetadataAddress) { - scope := types.Scope{ - ScopeId: scopeID, - SpecificationId: scopeSpecID, - Owners: []types.Party{{Address: s.user1, Role: types.PartyType_PARTY_TYPE_OWNER}}, - ValueOwnerAddress: valueOwner, - } - s.app.MetadataKeeper.SetScope(s.ctx, scope) - } - addr := func(str string) string { - return sdk.AccAddress(str).String() - } - - addrW1 := addr("addrW1______________") - addrW3 := addr("addrW3______________") - - scopeID1 := types.ScopeMetadataAddress(uuid.New()) - scopeID31 := types.ScopeMetadataAddress(uuid.New()) - scopeID32 := types.ScopeMetadataAddress(uuid.New()) - scopeID33 := types.ScopeMetadataAddress(uuid.New()) - - storeScope(addrW1, scopeID1) - storeScope(addrW3, scopeID31) - storeScope(addrW3, scopeID32) - storeScope(addrW3, scopeID33) - - tests := []struct { - name string - msg *types.MsgMigrateValueOwnerRequest - expErr string - scopeIDs []types.MetadataAddress - }{ - { - name: "err from IterateScopesForValueOwner", - msg: &types.MsgMigrateValueOwnerRequest{ - Existing: "", - Proposed: "doesn't matter", - Signers: []string{"who cares"}, - }, - expErr: "cannot iterate over invalid value owner \"\": empty address string is not allowed: invalid request", - }, - { - name: "no scopes", - msg: &types.MsgMigrateValueOwnerRequest{ - Existing: addr("unknown_value_owner_"), - Proposed: addr("does_not_matter_____"), - Signers: []string{addr("signer______________")}, - }, - expErr: "no scopes found with value owner \"" + addr("unknown_value_owner_") + "\": not found", - }, - { - name: "err from ValidateUpdateValueOwners", - msg: &types.MsgMigrateValueOwnerRequest{ - Existing: addrW1, - Proposed: addr("not_for_public_use__"), - Signers: []string{addr("incorrect_signer____")}, - }, - expErr: "missing signature from existing value owner " + addrW1 + ": invalid request", - }, - { - name: "1 scope updated", - msg: &types.MsgMigrateValueOwnerRequest{ - Existing: addrW1, - Proposed: addr("proposed_value_owner"), - Signers: []string{addrW1}, - }, - scopeIDs: []types.MetadataAddress{scopeID1}, - }, - { - name: "3 scopes updated", - msg: &types.MsgMigrateValueOwnerRequest{ - Existing: addrW3, - Proposed: addr("a_longer_proposed_value_owner___"), - Signers: []string{addrW3}, - }, - scopeIDs: []types.MetadataAddress{scopeID31, scopeID32, scopeID33}, - }, - } - - for _, tc := range tests { - s.Run(tc.name, func() { - _, err := s.handler(s.ctx, tc.msg) - if len(tc.expErr) > 0 { - s.Assert().EqualError(err, tc.expErr, "Metadata hander(%T)", tc.msg) - } else { - if s.Assert().NoError(err, tc.expErr, "Metadata hander(%T)", tc.msg) { - for i, scopeID := range tc.scopeIDs { - scope, found := s.app.MetadataKeeper.GetScope(s.ctx, scopeID) - s.Assert().True(found, "[%d]: GetScope(%q) found boolean", i, scopeID.String()) - actual := scope.ValueOwnerAddress - s.Assert().Equal(tc.msg.Proposed, actual, "[%d] %q value owner after migrate", i, scopeID.String()) - } - } - } - }) - } -} - -func (s *MetadataHandlerTestSuite) TestWriteSession() { - cSpec := types.ContractSpecification{ - SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - Source: types.NewContractSpecificationSourceHash("somesource"), - ClassName: "someclass", - } - s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec) - sSpec := types.ScopeSpecification{ - SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - ContractSpecIds: []types.MetadataAddress{cSpec.SpecificationId}, - } - s.app.MetadataKeeper.SetScopeSpecification(s.ctx, sSpec) - - scopeUUID := uuid.New() - scope := types.Scope{ - ScopeId: types.ScopeMetadataAddress(scopeUUID), - SpecificationId: sSpec.SpecificationId, - Owners: []types.Party{{ - Address: s.user1, - Role: types.PartyType_PARTY_TYPE_OWNER, - }}, - DataAccess: nil, - ValueOwnerAddress: "", - } - s.app.MetadataKeeper.SetScope(s.ctx, scope) - - someBytes, err := base64.StdEncoding.DecodeString("ChFIRUxMTyBQUk9WRU5BTkNFIQ==") - require.NoError(s.T(), err, "trying to create someBytes") - - cases := []struct { - name string - session types.Session - signers []string - errorMsg string - }{ - { - "valid without context", - types.Session{ - SessionId: types.SessionMetadataAddress(scopeUUID, uuid.New()), - SpecificationId: cSpec.SpecificationId, - Parties: scope.Owners, - Name: "someclass", - Context: nil, - Audit: nil, - }, - []string{s.user1}, - "", - }, - { - "valid with context", - types.Session{ - SessionId: types.SessionMetadataAddress(scopeUUID, uuid.New()), - SpecificationId: cSpec.SpecificationId, - Parties: scope.Owners, - Name: "someclass", - Context: someBytes, - Audit: nil, - }, - []string{s.user1}, - "", - }, - } - - for _, tc := range cases { - s.T().Run(tc.name, func(t *testing.T) { - msg := types.MsgWriteSessionRequest{ - Session: tc.session, - Signers: tc.signers, - SessionIdComponents: nil, - SpecUuid: "", - } - _, err := s.handler(s.ctx, &msg) - if len(tc.errorMsg) > 0 { - assert.EqualError(t, err, tc.errorMsg) - } else { - assert.NoError(t, err) - } - }) - } -} - -func (s *MetadataHandlerTestSuite) TestWriteDeleteRecord() { - cSpecUUID := uuid.New() - cSpec := types.ContractSpecification{ - SpecificationId: types.ContractSpecMetadataAddress(cSpecUUID), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - Source: types.NewContractSpecificationSourceHash("somesource1"), - ClassName: "someclass1", - } - s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec) - defer func() { - s.Assert().NoError(s.app.MetadataKeeper.RemoveContractSpecification(s.ctx, cSpec.SpecificationId), "removing contract spec") - }() - - sSpecUUID := uuid.New() - sSpec := types.ScopeSpecification{ - SpecificationId: types.ScopeSpecMetadataAddress(sSpecUUID), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - ContractSpecIds: []types.MetadataAddress{cSpec.SpecificationId}, - } - s.app.MetadataKeeper.SetScopeSpecification(s.ctx, sSpec) - defer func() { - s.Assert().NoError(s.app.MetadataKeeper.RemoveScopeSpecification(s.ctx, sSpec.SpecificationId), "removing scope spec") - }() - - rSpec := types.RecordSpecification{ - SpecificationId: types.RecordSpecMetadataAddress(cSpecUUID, "record"), - Name: "record", - Inputs: []*types.InputSpecification{ - { - Name: "ri1", - TypeName: "string", - Source: types.NewInputSpecificationSourceHash("ri1hash"), - }, - }, - TypeName: "string", - ResultType: types.DefinitionType_DEFINITION_TYPE_RECORD_LIST, - ResponsibleParties: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - } - s.app.MetadataKeeper.SetRecordSpecification(s.ctx, rSpec) - defer func() { - s.Assert().NoError(s.app.MetadataKeeper.RemoveRecordSpecification(s.ctx, rSpec.SpecificationId), "removing record spec 1") - }() - - scopeUUID := uuid.New() - scope := types.Scope{ - ScopeId: types.ScopeMetadataAddress(scopeUUID), - SpecificationId: sSpec.SpecificationId, - Owners: []types.Party{{ - Address: s.user1, - Role: types.PartyType_PARTY_TYPE_OWNER, - }}, - DataAccess: nil, - ValueOwnerAddress: "", - } - s.app.MetadataKeeper.SetScope(s.ctx, scope) - defer s.app.MetadataKeeper.RemoveScope(s.ctx, scope.ScopeId) - - session1UUID := uuid.New() - session1 := types.Session{ - SessionId: types.SessionMetadataAddress(scopeUUID, session1UUID), - SpecificationId: cSpec.SpecificationId, - Parties: ownerPartyList(s.user1), - Name: "someclass1", - } - s.app.MetadataKeeper.SetSession(s.ctx, session1) - defer s.app.MetadataKeeper.RemoveSession(s.ctx, session1.SessionId) - - session2UUID := uuid.New() - session2 := types.Session{ - SessionId: types.SessionMetadataAddress(scopeUUID, session2UUID), - SpecificationId: cSpec.SpecificationId, - Parties: ownerPartyList(s.user1), - Name: "someclass1", - } - s.app.MetadataKeeper.SetSession(s.ctx, session2) - defer s.app.MetadataKeeper.RemoveSession(s.ctx, session2.SessionId) - - record := types.Record{ - Name: rSpec.Name, - SessionId: session1.SessionId, - Process: types.Process{ - ProcessId: &types.Process_Hash{Hash: "rprochash"}, - Name: "rproc", - Method: "rprocmethod", - }, - Inputs: []types.RecordInput{ - { - Name: rSpec.Inputs[0].Name, - Source: &types.RecordInput_Hash{Hash: "rhash"}, - TypeName: rSpec.Inputs[0].TypeName, - Status: types.RecordInputStatus_Proposed, - }, - }, - Outputs: []types.RecordOutput{ - { - Hash: "rout1", - Status: types.ResultStatus_RESULT_STATUS_PASS, - }, - { - Hash: "rout2", - Status: types.ResultStatus_RESULT_STATUS_PASS, - }, - }, - SpecificationId: rSpec.SpecificationId, - } - recordID := types.RecordMetadataAddress(scopeUUID, rSpec.Name) - // Not adding the record here because we're testing that stuff. - - s.T().Run("write invalid record", func(t *testing.T) { - // Make a record with an unknown spec id. Try to write it and expect an error. - badRecord := types.Record{ - Name: rSpec.Name, - SessionId: session1.SessionId, - Process: types.Process{ - ProcessId: &types.Process_Hash{Hash: "badrprochash"}, - Name: "badrproc", - Method: "badrprocmethod", - }, - Inputs: []types.RecordInput{ - { - Name: rSpec.Inputs[0].Name, - Source: &types.RecordInput_Hash{Hash: "badrhash"}, - TypeName: rSpec.Inputs[0].TypeName, - Status: types.RecordInputStatus_Proposed, - }, - }, - Outputs: []types.RecordOutput{ - { - Hash: "badrout1", - Status: types.ResultStatus_RESULT_STATUS_PASS, - }, - { - Hash: "badrout2", - Status: types.ResultStatus_RESULT_STATUS_PASS, - }, - }, - SpecificationId: types.RecordSpecMetadataAddress(uuid.New(), rSpec.Name), - } - msg := types.MsgWriteRecordRequest{ - Record: badRecord, - Signers: []string{s.user1}, - SessionIdComponents: nil, - ContractSpecUuid: "", - Parties: ownerPartyList(s.user1), - } - _, err := s.handler(s.ctx, &msg) - require.Error(t, err, "sending bad MsgWriteRecordRequest") - require.Contains(t, err.Error(), "proposed specification id") - require.Contains(t, err.Error(), "does not match expected") - }) - - s.T().Run("write record to session 1", func(t *testing.T) { - msg := types.MsgWriteRecordRequest{ - Record: record, - Signers: []string{s.user1}, - SessionIdComponents: nil, - ContractSpecUuid: "", - Parties: ownerPartyList(s.user1), - } - _, err := s.handler(s.ctx, &msg) - require.NoError(t, err, "sending MsgWriteRecordRequest") - r, rok := s.app.MetadataKeeper.GetRecord(s.ctx, recordID) - if assert.True(t, rok, "GetRecord bool") { - assert.Equal(t, record, r, "GetRecord record") - } - }) - - s.T().Run("Update record to other session", func(t *testing.T) { - record.SessionId = session2.SessionId - msg := types.MsgWriteRecordRequest{ - Record: record, - Signers: []string{s.user1}, - SessionIdComponents: nil, - ContractSpecUuid: "", - Parties: ownerPartyList(s.user1), - } - _, err := s.handler(s.ctx, &msg) - require.NoError(t, err, "sending MsgWriteRecordRequest") - r, rok := s.app.MetadataKeeper.GetRecord(s.ctx, recordID) - if assert.True(t, rok, "GetRecord bool") { - assert.Equal(t, record, r, "GetRecord record") - } - // Make sure the session was deleted since it's now empty. - _, sok := s.app.MetadataKeeper.GetSession(s.ctx, session1.SessionId) - assert.False(t, sok, "GetSession session 1 bool") - }) - - s.T().Run("delete the record", func(t *testing.T) { - msg := types.MsgDeleteRecordRequest{ - RecordId: recordID, - Signers: []string{s.user1}, - } - _, err := s.handler(s.ctx, &msg) - require.NoError(t, err, "sending MsgDeleteRecordRequest") - _, rok := s.app.MetadataKeeper.GetRecord(s.ctx, recordID) - assert.False(t, rok, "GetRecord bool") - // Make sure the session was deleted since it's now empty. - _, sok := s.app.MetadataKeeper.GetSession(s.ctx, session2.SessionId) - assert.False(t, sok, "GetSession session 2 bool") - }) -} - -// TODO: WriteScopeSpecification tests -// TODO: DeleteScopeSpecification tests -// TODO: WriteContractSpecification tests -// TODO: DeleteContractSpecification tests - -func (s *MetadataHandlerTestSuite) TestAddContractSpecToScopeSpec() { - cSpec := types.ContractSpecification{ - SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - Source: types.NewContractSpecificationSourceHash("somesource"), - ClassName: "someclass", - } - s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec) - sSpec := types.ScopeSpecification{ - SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - ContractSpecIds: []types.MetadataAddress{cSpec.SpecificationId}, - } - s.app.MetadataKeeper.SetScopeSpecification(s.ctx, sSpec) - - cSpec2 := types.ContractSpecification{ - SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - Source: types.NewContractSpecificationSourceHash("somesource"), - ClassName: "someclass", - } - s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec2) - - unknownContractSpecId := types.ContractSpecMetadataAddress(uuid.New()) - unknownScopeSpecId := types.ScopeSpecMetadataAddress(uuid.New()) - - cases := []struct { - name string - contractSpecId types.MetadataAddress - scopeSpecId types.MetadataAddress - signers []string - errorMsg string - }{ - { - "fail to add contract spec, cannot find contract spec", - unknownContractSpecId, - sSpec.SpecificationId, - []string{s.user1}, - fmt.Sprintf("contract specification not found with id %s: not found", unknownContractSpecId), - }, - { - "fail to add contract spec, cannot find scope spec", - cSpec2.SpecificationId, - unknownScopeSpecId, - []string{s.user1}, - fmt.Sprintf("scope specification not found with id %s: not found", unknownScopeSpecId), - }, - { - "fail to add contract spec, scope spec already has contract spec", - cSpec.SpecificationId, - sSpec.SpecificationId, - []string{s.user1}, - fmt.Sprintf("scope spec %s already contains contract spec %s: invalid request", sSpec.SpecificationId, cSpec.SpecificationId), - }, - { - "should successfully add contract spec to scope spec", - cSpec2.SpecificationId, - sSpec.SpecificationId, - []string{s.user1}, - "", - }, - } - - for _, tc := range cases { - s.T().Run(tc.name, func(t *testing.T) { - msg := types.MsgAddContractSpecToScopeSpecRequest{ - ContractSpecificationId: tc.contractSpecId, - ScopeSpecificationId: tc.scopeSpecId, - Signers: tc.signers, - } - _, err := s.handler(s.ctx, &msg) - if len(tc.errorMsg) > 0 { - assert.EqualError(t, err, tc.errorMsg) - } else { - assert.NoError(t, err) - } - }) - } -} - -func (s *MetadataHandlerTestSuite) TestDeleteContractSpecFromScopeSpec() { - cSpec := types.ContractSpecification{ - SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - Source: types.NewContractSpecificationSourceHash("somesource"), - ClassName: "someclass", - } - s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec) - cSpec2 := types.ContractSpecification{ - SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - Source: types.NewContractSpecificationSourceHash("somesource"), - ClassName: "someclass", - } - s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec2) - cSpecDNE := types.ContractSpecMetadataAddress(uuid.New()) // Does Not Exist. - sSpec := types.ScopeSpecification{ - SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), - Description: nil, - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - ContractSpecIds: []types.MetadataAddress{cSpec.SpecificationId, cSpec2.SpecificationId, cSpecDNE}, - } - s.app.MetadataKeeper.SetScopeSpecification(s.ctx, sSpec) - - unknownScopeSpecId := types.ScopeSpecMetadataAddress(uuid.New()) - - cases := []struct { - name string - contractSpecId types.MetadataAddress - scopeSpecId types.MetadataAddress - signers []string - errorMsg string - }{ - { - "cannot find contract spec", - cSpecDNE, - sSpec.SpecificationId, - []string{s.user1}, - "", - }, - { - "fail to delete contract spec from scope spec, cannot find scope spec", - cSpec2.SpecificationId, - unknownScopeSpecId, - []string{s.user1}, - fmt.Sprintf("scope specification not found with id %s: not found", unknownScopeSpecId), - }, - { - "should succeed to add contract spec to scope spec", - cSpec2.SpecificationId, - sSpec.SpecificationId, - []string{s.user1}, - "", - }, - { - "fail to delete contract spec from scope spec, scope spec does not contain contract spec", - cSpec2.SpecificationId, - sSpec.SpecificationId, - []string{s.user1}, - fmt.Sprintf("contract specification %s not found in scope specification %s: not found", cSpec2.SpecificationId, sSpec.SpecificationId), - }, - } - - for _, tc := range cases { - s.T().Run(tc.name, func(t *testing.T) { - msg := types.MsgDeleteContractSpecFromScopeSpecRequest{ - ContractSpecificationId: tc.contractSpecId, - ScopeSpecificationId: tc.scopeSpecId, - Signers: tc.signers, - } - _, err := s.handler(s.ctx, &msg) - if len(tc.errorMsg) > 0 { - assert.EqualError(t, err, tc.errorMsg) - } else { - assert.NoError(t, err) - } - }) - } -} - -// TODO: WriteRecordSpecification tests -// TODO: DeleteRecordSpecification tests - -// TODO: BindOSLocator tests -// TODO: DeleteOSLocator tests -// TODO: ModifyOSLocator tests - -func (s *MetadataHandlerTestSuite) TestSetAccountData() { - scopeSpec := types.ScopeSpecification{ - SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), - OwnerAddresses: []string{s.user1}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - } - s.app.MetadataKeeper.SetScopeSpecification(s.ctx, scopeSpec) - - scope := types.Scope{ - ScopeId: types.ScopeMetadataAddress(uuid.New()), - SpecificationId: scopeSpec.SpecificationId, - Owners: []types.Party{{Address: s.user1, Role: types.PartyType_PARTY_TYPE_OWNER}}, - } - s.app.MetadataKeeper.SetScope(s.ctx, scope) - - tests := []struct { - name string - msg *types.MsgSetAccountDataRequest - exp *types.MsgSetAccountDataResponse - expErr string - }{ - { - name: "incorrect signer", - msg: &types.MsgSetAccountDataRequest{ - MetadataAddr: scope.ScopeId, - Value: "This won't work.", - Signers: []string{s.user2}, - }, - expErr: "missing signature: " + s.user1 + ": invalid request", - }, - { - name: "value too long", - msg: &types.MsgSetAccountDataRequest{ - MetadataAddr: scope.ScopeId, - Value: strings.Repeat("This won't work. ", 1000), - Signers: []string{s.user1}, - }, - expErr: "could not set accountdata for \"" + scope.ScopeId.String() + "\": attribute value length of 17000 exceeds max length 10000: invalid request", - }, - { - name: "all good", - msg: &types.MsgSetAccountDataRequest{ - MetadataAddr: scope.ScopeId, - Value: "This value is a good value for this scope.", - Signers: []string{s.user1}, - }, - exp: &types.MsgSetAccountDataResponse{}, - }, - } - - for _, tc := range tests { - s.Run(tc.name, func() { - var err error - var result *sdk.Result - testFunc := func() { - result, err = s.handler(s.ctx, tc.msg) - } - s.Require().NotPanics(testFunc, "%T hander", tc.msg) - s.AssertErrorValue(err, tc.expErr, "%T handler error", tc.msg) - if tc.exp == nil { - s.Assert().Nil(result, "%T handler result", tc.msg) - } else { - if s.Assert().Len(result.MsgResponses, 1, "%T handler result MsgResponses", tc.msg) { - resp, isResp := result.MsgResponses[0].GetCachedValue().(*types.MsgSetAccountDataResponse) - s.Require().True(isResp, "casting %T handler result.MsgResponses[0].GetCachedValue() to %T", tc.msg, resp) - s.Assert().Equal(tc.exp, resp, "%T handler msg response", tc.msg) - } - } - }) - } -} - -func (s *MetadataHandlerTestSuite) TestIssue412WriteScopeOptionalField() { - ownerAddress := "cosmos1vz99nyd2er8myeugsr4xm5duwhulhp5ae4dvpa" - specIDStr := "scopespec1qjkyp28sldx5r9ueaxqc5adrc5wszy6nsh" - specUUIDStr := "ac40a8f0-fb4d-4197-99e9-818a75a3c51d" - specID, specIDErr := types.MetadataAddressFromBech32(specIDStr) - require.NoError(s.T(), specIDErr, "converting scopeIDStr to a metadata address") - - s.T().Run("Ensure ID and UUID strings match", func(t *testing.T) { - specIDFromID, e1 := types.MetadataAddressFromBech32(specIDStr) - require.NoError(t, e1, "specIDFromIDStr") - specUUIDFromID, e2 := specIDFromID.ScopeSpecUUID() - require.NoError(t, e2, "specUUIDActualStr") - specUUIDStrActual := specUUIDFromID.String() - assert.Equal(t, specUUIDStr, specUUIDStrActual, "UUID strings") - - specIDFFromUUID := types.ScopeSpecMetadataAddress(uuid.MustParse(specUUIDStr)) - specIDStrActual := specIDFFromUUID.String() - assert.Equal(t, specIDStr, specIDStrActual, "ID strings") - - assert.Equal(t, specIDFromID, specIDFFromUUID, "scope spec ids") - }) - - s.T().Run("Setting scope spec with just a spec ID", func(t *testing.T) { - msg := types.MsgWriteScopeSpecificationRequest{ - Specification: types.ScopeSpecification{ - SpecificationId: specID, - Description: &types.Description{ - Name: "io.prov.contracts.examplekotlin.helloWorld", - Description: "A generic scope that allows for a lot of example hello world contracts.", - }, - OwnerAddresses: []string{ownerAddress}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - ContractSpecIds: nil, - }, - Signers: []string{ownerAddress}, - SpecUuid: "", - } - res, err := s.handler(s.ctx, &msg) - assert.NoError(t, err) - assert.NotNil(t, 0, res) - }) - - s.T().Run("Setting scope spec with just a UUID", func(t *testing.T) { - msg := types.MsgWriteScopeSpecificationRequest{ - Specification: types.ScopeSpecification{ - SpecificationId: nil, - Description: &types.Description{ - Name: "io.prov.contracts.examplekotlin.helloWorld", - Description: "A generic scope that allows for a lot of example hello world contracts.", - }, - OwnerAddresses: []string{ownerAddress}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - ContractSpecIds: nil, - }, - Signers: []string{ownerAddress}, - SpecUuid: specUUIDStr, - } - res, err := s.handler(s.ctx, &msg) - assert.NoError(t, err) - assert.NotNil(t, 0, res) - }) - - s.T().Run("Setting scope spec with matching ID and UUID", func(t *testing.T) { - msg := types.MsgWriteScopeSpecificationRequest{ - Specification: types.ScopeSpecification{ - SpecificationId: specID, - Description: &types.Description{ - Name: "io.prov.contracts.examplekotlin.helloWorld", - Description: "A generic scope that allows for a lot of example hello world contracts.", - }, - OwnerAddresses: []string{ownerAddress}, - PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, - ContractSpecIds: nil, - }, - Signers: []string{ownerAddress}, - SpecUuid: specUUIDStr, - } - res, err := s.handler(s.ctx, &msg) - assert.NoError(t, err) - assert.NotNil(t, 0, res) - }) -} diff --git a/x/metadata/keeper/msg_server_test.go b/x/metadata/keeper/msg_server_test.go index 0ff5e1e94f..56a5571448 100644 --- a/x/metadata/keeper/msg_server_test.go +++ b/x/metadata/keeper/msg_server_test.go @@ -1,59 +1,1303 @@ package keeper_test import ( + "encoding/base64" "fmt" + "strings" "testing" - "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/google/uuid" - - "github.com/stretchr/testify/suite" - simapp "github.com/provenance-io/provenance/app" + "github.com/provenance-io/provenance/app" "github.com/provenance-io/provenance/x/metadata/keeper" - metadatakeeper "github.com/provenance-io/provenance/x/metadata/keeper" "github.com/provenance-io/provenance/x/metadata/types" ) type MsgServerTestSuite struct { suite.Suite - app *simapp.App - ctx sdk.Context - msgServer types.MsgServer - blockStartTime time.Time + app *app.App + ctx sdk.Context + msgServer types.MsgServer - privkey1 cryptotypes.PrivKey - pubkey1 cryptotypes.PubKey - owner1 string - owner1Addr sdk.AccAddress - acct1 authtypes.AccountI + pubkey1 cryptotypes.PubKey + user1 string + user1Addr sdk.AccAddress - addresses []sdk.AccAddress + pubkey2 cryptotypes.PubKey + user2 string + user2Addr sdk.AccAddress } func (s *MsgServerTestSuite) SetupTest() { - - s.blockStartTime = time.Now() - s.app = simapp.Setup(s.T()) + s.app = app.Setup(s.T()) s.ctx = keeper.AddAuthzCacheToContext(s.app.BaseApp.NewContext(false)) - s.msgServer = metadatakeeper.NewMsgServerImpl(s.app.MetadataKeeper) - - s.privkey1 = secp256k1.GenPrivKey() - s.pubkey1 = s.privkey1.PubKey() - s.owner1Addr = sdk.AccAddress(s.pubkey1.Address()) - s.owner1 = s.owner1Addr.String() - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.owner1Addr) - s.app.AccountKeeper.SetAccount(s.ctx, acc) + s.msgServer = keeper.NewMsgServerImpl(s.app.MetadataKeeper) + + s.pubkey1 = secp256k1.GenPrivKey().PubKey() + s.user1Addr = sdk.AccAddress(s.pubkey1.Address()) + s.user1 = s.user1Addr.String() + user1Acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.user1Addr) + s.Require().NoError(user1Acc.SetPubKey(s.pubkey1), "SetPubKey user1") + + privKey, _ := secp256r1.GenPrivKey() + s.pubkey2 = privKey.PubKey() + s.user2Addr = sdk.AccAddress(s.pubkey2.Address()) + s.user2 = s.user2Addr.String() + user2Acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.user2Addr) + s.Require().NoError(user2Acc.SetPubKey(s.pubkey1), "SetPubKey user2") + + s.app.AccountKeeper.SetAccount(s.ctx, user1Acc) + s.app.AccountKeeper.SetAccount(s.ctx, user2Acc) } + func TestMsgServerTestSuite(t *testing.T) { suite.Run(t, new(MsgServerTestSuite)) } +// AssertErrorValue asserts that: +// - If errorString is empty, theError must be nil +// - If errorString is not empty, theError must equal the errorString. +func (s *MsgServerTestSuite) AssertErrorValue(theError error, errorString string, msgAndArgs ...interface{}) bool { + return AssertErrorValue(s.T(), theError, errorString, msgAndArgs...) +} + +// TODO: WriteScope tests +// TODO: DeleteScope tests + +func (s *MsgServerTestSuite) TestAddAndDeleteScopeDataAccess() { + scopeSpecID := types.ScopeSpecMetadataAddress(uuid.New()) + scopeSpec := types.NewScopeSpecification(scopeSpecID, nil, []string{s.user1}, []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, []types.MetadataAddress{}) + scopeID := types.ScopeMetadataAddress(uuid.New()) + scope := types.NewScope(scopeID, scopeSpecID, ownerPartyList(s.user1), []string{s.user1}, "", false) + dneScopeID := types.ScopeMetadataAddress(uuid.New()) + user3 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + scopeSpecMsg := types.NewMsgWriteScopeSpecificationRequest(*scopeSpec, []string{s.user1}) + _, err := s.msgServer.WriteScopeSpecification(s.ctx, scopeSpecMsg) + s.Assert().NoError(err, "setup test with new scope specification") + + writeScopeMsg := types.NewMsgWriteScopeRequest(*scope, []string{s.user1}, 0) + _, err = s.msgServer.WriteScope(s.ctx, writeScopeMsg) + s.Assert().NoError(err, "setup test with new scope") + + cases := []struct { + name string + addMsg *types.MsgAddScopeDataAccessRequest + delMsg *types.MsgDeleteScopeDataAccessRequest + signers []string + errorMsg string + }{ + + { + name: "should fail to ADD address to data access, msg validate basic failure", + addMsg: types.NewMsgAddScopeDataAccessRequest(scopeID, []string{}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: "data access list cannot be empty: invalid request", + }, + { + name: "should fail to ADD address to data access, validate add failure", + addMsg: types.NewMsgAddScopeDataAccessRequest(dneScopeID, []string{s.user1}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: fmt.Sprintf("scope not found with id %s: not found", dneScopeID), + }, + { + name: "should fail to ADD address to data access, validate add failure", + addMsg: types.NewMsgAddScopeDataAccessRequest(scopeID, []string{s.user1}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: fmt.Sprintf("address already exists for data access %s: invalid request", s.user1), + }, + { + name: "should successfully ADD address to data access", + addMsg: types.NewMsgAddScopeDataAccessRequest(scopeID, []string{s.user2}, []string{s.user1}), + signers: []string{s.user1}, + }, + { + name: "should fail to DELETE address from data access, msg validate basic failure", + delMsg: types.NewMsgDeleteScopeDataAccessRequest(scopeID, []string{}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: "data access list cannot be empty: invalid request", + }, + { + name: "should fail to DELETE address from data access, validate add failure", + delMsg: types.NewMsgDeleteScopeDataAccessRequest(dneScopeID, []string{s.user1}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: fmt.Sprintf("scope not found with id %s: not found", dneScopeID), + }, + { + name: "should fail to DELETE address from data access, validate add failure", + delMsg: types.NewMsgDeleteScopeDataAccessRequest(scopeID, []string{user3}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: fmt.Sprintf("address does not exist in scope data access: %s: invalid request", user3), + }, + { + name: "should successfully DELETE address from data access", + delMsg: types.NewMsgDeleteScopeDataAccessRequest(scopeID, []string{s.user2}, []string{s.user1}), + signers: []string{s.user1}, + }, + } + + for _, tc := range cases { + s.T().Run(tc.name, func(t *testing.T) { + var err error + if tc.delMsg != nil { + _, err = s.msgServer.DeleteScopeDataAccess(s.ctx, tc.delMsg) + } + if tc.addMsg != nil { + _, err = s.msgServer.AddScopeDataAccess(s.ctx, tc.addMsg) + } + + if len(tc.errorMsg) > 0 { + assert.EqualError(t, err, tc.errorMsg) + } else { + assert.NoError(t, err) + } + }) + } + + s.T().Run("data access actually deleted and added", func(t *testing.T) { + addrOriginator := "cosmos1rr4d0eu62pgt4edw38d2ev27798pfhdhm39zct" + addrServicer := "cosmos1a7mmtar5ke5fxk5gn00dlag0zfmdkmhapmugk7" + scopeA := types.Scope{ + ScopeId: types.ScopeMetadataAddress(uuid.New()), + SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), + DataAccess: []string{addrOriginator, addrServicer}, + ValueOwnerAddress: addrServicer, + Owners: []types.Party{ + { + Address: addrOriginator, + Role: types.PartyType_PARTY_TYPE_ORIGINATOR, + }, + }, + } + + scopeSpecA := types.ScopeSpecification{ + SpecificationId: scopeA.SpecificationId, + Description: &types.Description{ + Name: "com.figure.origination.loan", + Description: "Figure loan origination", + }, + OwnerAddresses: []string{"cosmos1q8n4v4m0hm8v0a7n697nwtpzhfsz3f4d40lnsu"}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_ORIGINATOR}, + ContractSpecIds: nil, + } + + s.app.MetadataKeeper.SetScope(s.ctx, scopeA) + s.app.MetadataKeeper.SetScopeSpecification(s.ctx, scopeSpecA) + + msgDel := types.NewMsgDeleteScopeDataAccessRequest( + scopeA.ScopeId, + []string{addrServicer}, + []string{addrOriginator}, + ) + + _, errDel := s.msgServer.DeleteScopeDataAccess(s.ctx, msgDel) + require.NoError(t, errDel, "Failed to make DeleteScopeDataAccessRequest call") + + scopeB, foundB := s.app.MetadataKeeper.GetScope(s.ctx, scopeA.ScopeId) + require.Truef(t, foundB, "Scope %s not found after DeleteScopeOwnerRequest call.", scopeA.ScopeId) + + assert.Equal(t, scopeA.ScopeId, scopeB.ScopeId, "del ScopeId") + assert.Equal(t, scopeA.SpecificationId, scopeB.SpecificationId, "del SpecificationId") + assert.Equal(t, scopeA.DataAccess[0:1], scopeB.DataAccess, "del DataAccess") + assert.Equal(t, scopeA.ValueOwnerAddress, scopeB.ValueOwnerAddress, "del ValueOwnerAddress") + assert.Equal(t, scopeA.Owners, scopeB.Owners, "del Owners") + + // Stop test if it's already failed. + if t.Failed() { + t.FailNow() + } + + msgAdd := types.NewMsgAddScopeDataAccessRequest( + scopeA.ScopeId, + []string{addrServicer}, + []string{addrOriginator}, + ) + + _, errAdd := s.msgServer.AddScopeDataAccess(s.ctx, msgAdd) + require.NoError(t, errAdd, "Failed to make AddScopeDataAccessRequest call") + + scopeC, foundC := s.app.MetadataKeeper.GetScope(s.ctx, scopeA.ScopeId) + require.Truef(t, foundC, "Scope %s not found after AddScopeOwnerRequest call.", scopeA.ScopeId) + + assert.Equal(t, scopeA.ScopeId, scopeC.ScopeId, "add ScopeId") + assert.Equal(t, scopeA.SpecificationId, scopeC.SpecificationId, "add SpecificationId") + assert.Equal(t, scopeA.DataAccess, scopeC.DataAccess, "add DataAccess") + assert.Equal(t, scopeA.ValueOwnerAddress, scopeC.ValueOwnerAddress, "add ValueOwnerAddress") + assert.Equal(t, scopeA.Owners, scopeC.Owners, "add Owners") + }) +} + +func (s *MsgServerTestSuite) TestAddAndDeleteScopeOwners() { + scopeSpecID := types.ScopeSpecMetadataAddress(uuid.New()) + scopeSpec := types.NewScopeSpecification(scopeSpecID, nil, []string{s.user1}, []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, []types.MetadataAddress{}) + scopeID := types.ScopeMetadataAddress(uuid.New()) + scope := types.NewScope(scopeID, scopeSpecID, ownerPartyList(s.user1), []string{s.user1}, "", false) + dneScopeID := types.ScopeMetadataAddress(uuid.New()) + user3 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + scopeSpecMsg := types.NewMsgWriteScopeSpecificationRequest(*scopeSpec, []string{s.user1}) + _, err := s.msgServer.WriteScopeSpecification(s.ctx, scopeSpecMsg) + s.Assert().NoError(err, "setup test with new scope specification") + + writeScopeMsg := types.NewMsgWriteScopeRequest(*scope, []string{s.user1}, 0) + _, err = s.msgServer.WriteScope(s.ctx, writeScopeMsg) + s.Assert().NoError(err, "setup test with new scope") + + cases := []struct { + name string + addMsg *types.MsgAddScopeOwnerRequest + delMsg *types.MsgDeleteScopeOwnerRequest + signers []string + errorMsg string + }{ + { + name: "should fail to ADD owners, msg validate basic failure", + addMsg: types.NewMsgAddScopeOwnerRequest(scopeID, []types.Party{}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: "invalid owners: at least one party is required: invalid request", + }, + { + name: "should fail to ADD owners, can not find scope", + addMsg: types.NewMsgAddScopeOwnerRequest(dneScopeID, []types.Party{{Address: s.user1, Role: types.PartyType_PARTY_TYPE_OWNER}}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: fmt.Sprintf("scope not found with id %s: not found", dneScopeID), + }, + { + name: "should fail to ADD owners, validate add failure", + addMsg: types.NewMsgAddScopeOwnerRequest(scopeID, []types.Party{{Address: s.user1, Role: types.PartyType_PARTY_TYPE_OWNER}}, []string{s.user1}), + signers: []string{s.user1}, + errorMsg: fmt.Sprintf("party already exists with address %s and role %s", s.user1, types.PartyType_PARTY_TYPE_OWNER), + }, + { + name: "should successfully ADD owners", + addMsg: types.NewMsgAddScopeOwnerRequest(scopeID, []types.Party{{Address: s.user2, Role: types.PartyType_PARTY_TYPE_OWNER}}, []string{s.user1}), + signers: []string{s.user1}, + }, + { + name: "should fail to DELETE owners, msg validate basic failure", + delMsg: types.NewMsgDeleteScopeOwnerRequest(scopeID, []string{}, []string{s.user1, s.user2}), + signers: []string{s.user1}, + errorMsg: "at least one owner address is required: invalid request", + }, + { + name: "should fail to DELETE owners, validate add failure", + delMsg: types.NewMsgDeleteScopeOwnerRequest(dneScopeID, []string{s.user1}, []string{s.user1, s.user2}), + signers: []string{s.user1}, + errorMsg: fmt.Sprintf("scope not found with id %s: not found", dneScopeID), + }, + { + name: "should fail to DELETE owners, validate add failure", + delMsg: types.NewMsgDeleteScopeOwnerRequest(scopeID, []string{user3}, []string{s.user1, s.user2}), + signers: []string{s.user1}, + errorMsg: fmt.Sprintf("address does not exist in scope owners: %s", user3), + }, + { + name: "should successfully DELETE owners", + delMsg: types.NewMsgDeleteScopeOwnerRequest(scopeID, []string{s.user2}, []string{s.user1, s.user2}), + signers: []string{s.user1}, + }, + } + + for _, tc := range cases { + s.T().Run(tc.name, func(t *testing.T) { + var err error + if tc.delMsg != nil { + _, err = s.msgServer.DeleteScopeOwner(s.ctx, tc.delMsg) + } + if tc.addMsg != nil { + _, err = s.msgServer.AddScopeOwner(s.ctx, tc.addMsg) + } + if len(tc.errorMsg) > 0 { + assert.EqualError(t, err, tc.errorMsg) + } else { + assert.NoError(t, err) + } + }) + } + + s.T().Run("owner actually deleted and added", func(t *testing.T) { + addrOriginator := "cosmos1rr4d0eu62pgt4edw38d2ev27798pfhdhm39zct" + addrServicer := "cosmos1a7mmtar5ke5fxk5gn00dlag0zfmdkmhapmugk7" + scopeA := types.Scope{ + ScopeId: types.ScopeMetadataAddress(uuid.New()), + SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), + DataAccess: []string{addrOriginator, addrServicer}, + ValueOwnerAddress: addrServicer, + Owners: []types.Party{ + { + Address: addrOriginator, + Role: types.PartyType_PARTY_TYPE_ORIGINATOR, + }, + { + Address: addrServicer, + Role: types.PartyType_PARTY_TYPE_SERVICER, + }, + }, + } + + scopeSpecA := types.ScopeSpecification{ + SpecificationId: scopeA.SpecificationId, + Description: &types.Description{ + Name: "com.figure.origination.loan", + Description: "Figure loan origination", + }, + OwnerAddresses: []string{"cosmos1q8n4v4m0hm8v0a7n697nwtpzhfsz3f4d40lnsu"}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_ORIGINATOR}, + ContractSpecIds: nil, + } + + s.app.MetadataKeeper.SetScope(s.ctx, scopeA) + s.app.MetadataKeeper.SetScopeSpecification(s.ctx, scopeSpecA) + + msgDel := types.NewMsgDeleteScopeOwnerRequest( + scopeA.ScopeId, + []string{addrServicer}, + []string{addrOriginator, addrServicer}, + ) + + _, errDel := s.msgServer.DeleteScopeOwner(s.ctx, msgDel) + require.NoError(t, errDel, "Failed to make DeleteScopeOwnerRequest call") + + scopeB, foundB := s.app.MetadataKeeper.GetScope(s.ctx, scopeA.ScopeId) + require.Truef(t, foundB, "Scope %s not found after DeleteScopeOwnerRequest call.", scopeA.ScopeId) + + assert.Equal(t, scopeA.ScopeId, scopeB.ScopeId, "del ScopeId") + assert.Equal(t, scopeA.SpecificationId, scopeB.SpecificationId, "del SpecificationId") + assert.Equal(t, scopeA.DataAccess, scopeB.DataAccess, "del DataAccess") + assert.Equal(t, scopeA.ValueOwnerAddress, scopeB.ValueOwnerAddress, "del ValueOwnerAddress") + assert.Equal(t, scopeA.Owners[0:1], scopeB.Owners, "del Owners") + + // Stop test if it's already failed. + if t.Failed() { + t.FailNow() + } + + msgAdd := types.NewMsgAddScopeOwnerRequest( + scopeA.ScopeId, + []types.Party{{Address: addrServicer, Role: types.PartyType_PARTY_TYPE_SERVICER}}, + []string{addrOriginator}, + ) + + _, errAdd := s.msgServer.AddScopeOwner(s.ctx, msgAdd) + require.NoError(t, errAdd, "Failed to make DeleteScopeOwnerRequest call") + + scopeC, foundC := s.app.MetadataKeeper.GetScope(s.ctx, scopeA.ScopeId) + require.Truef(t, foundC, "Scope %s not found after AddScopeOwnerRequest call.", scopeA.ScopeId) + + assert.Equal(t, scopeA.ScopeId, scopeC.ScopeId, "add ScopeId") + assert.Equal(t, scopeA.SpecificationId, scopeC.SpecificationId, "add SpecificationId") + assert.Equal(t, scopeA.DataAccess, scopeC.DataAccess, "add DataAccess") + assert.Equal(t, scopeA.ValueOwnerAddress, scopeC.ValueOwnerAddress, "add ValueOwnerAddress") + assert.Equal(t, scopeA.Owners, scopeC.Owners, "add Owners") + }) +} + +func (s *MsgServerTestSuite) TestUpdateValueOwners() { + scopeID1 := types.ScopeMetadataAddress(uuid.New()) + scopeID2 := types.ScopeMetadataAddress(uuid.New()) + scopeIDNotFound := types.ScopeMetadataAddress(uuid.New()) + + scopeID3Diff1 := types.ScopeMetadataAddress(uuid.New()) + scopeID3Diff2 := types.ScopeMetadataAddress(uuid.New()) + scopeID3Diff3 := types.ScopeMetadataAddress(uuid.New()) + scopeID3Same1 := types.ScopeMetadataAddress(uuid.New()) + scopeID3Same2 := types.ScopeMetadataAddress(uuid.New()) + scopeID3Same3 := types.ScopeMetadataAddress(uuid.New()) + + owner1 := sdk.AccAddress("owner1______________").String() + owner2 := sdk.AccAddress("owner2______________").String() + owner3Diff1 := sdk.AccAddress("owner3Diff1_________").String() + owner3Diff2 := sdk.AccAddress("owner3Diff2_________").String() + owner3Diff3 := sdk.AccAddress("owner3Diff3_________").String() + owner3Same1 := sdk.AccAddress("owner3Same1_________").String() + owner3Same2 := sdk.AccAddress("owner3Same2_________").String() + owner3Same3 := sdk.AccAddress("owner3Same3_________").String() + + dataAccess1 := sdk.AccAddress("dataAccess1_________").String() + dataAccess2 := sdk.AccAddress("dataAccess2_________").String() + dataAccess3Diff1 := sdk.AccAddress("dataAccess3Diff1____").String() + dataAccess3Diff2 := sdk.AccAddress("dataAccess3Diff2____").String() + dataAccess3Diff3 := sdk.AccAddress("dataAccess3Diff3____").String() + dataAccess3Same1 := sdk.AccAddress("dataAccess3Same1____").String() + dataAccess3Same2 := sdk.AccAddress("dataAccess3Same2____").String() + dataAccess3Same3 := sdk.AccAddress("dataAccess3Same3____").String() + + valueOwner1 := sdk.AccAddress("valueOwner1_________").String() + valueOwner2 := sdk.AccAddress("valueOwner2_________").String() + valueOwner3Diff1 := sdk.AccAddress("valueOwner3Diff1____").String() + valueOwner3Diff2 := sdk.AccAddress("valueOwner3Diff2____").String() + valueOwner3Diff3 := sdk.AccAddress("valueOwner3Diff3____").String() + valueOwner3Same := sdk.AccAddress("valueOwner3Same_____").String() + + scopeSpecID := types.ScopeSpecMetadataAddress(uuid.New()) + ns := func(scopeID types.MetadataAddress, owner, dataAccess, valueOwner string) types.Scope { + return types.Scope{ + ScopeId: scopeID, + SpecificationId: scopeSpecID, + Owners: []types.Party{{Address: owner, Role: types.PartyType_PARTY_TYPE_OWNER}}, + DataAccess: []string{dataAccess}, + ValueOwnerAddress: valueOwner, + } + } + ids := func(scopeIDs ...types.MetadataAddress) []types.MetadataAddress { + return scopeIDs + } + + newValueOwner := sdk.AccAddress("newValueOwner_______").String() + + tests := []struct { + name string + starters []types.Scope + scopeIDs []types.MetadataAddress + signers []string + expErr string + }{ + { + name: "scope 1 of 3 not found", + starters: []types.Scope{ + ns(scopeID1, owner1, dataAccess1, valueOwner1), + ns(scopeID2, owner2, dataAccess2, valueOwner2), + }, + scopeIDs: ids(scopeIDNotFound, scopeID1, scopeID2), + signers: []string{valueOwner1, valueOwner2}, + expErr: "scope not found with id " + scopeIDNotFound.String() + ": not found", + }, + { + name: "scope 2 of 3 not found", + starters: []types.Scope{ + ns(scopeID1, owner1, dataAccess1, valueOwner1), + ns(scopeID2, owner2, dataAccess2, valueOwner2), + }, + scopeIDs: ids(scopeID1, scopeIDNotFound, scopeID2), + signers: []string{valueOwner1, valueOwner2}, + expErr: "scope not found with id " + scopeIDNotFound.String() + ": not found", + }, + { + name: "scope 3 of 3 not found", + starters: []types.Scope{ + ns(scopeID1, owner1, dataAccess1, valueOwner1), + ns(scopeID2, owner2, dataAccess2, valueOwner2), + }, + scopeIDs: ids(scopeID1, scopeID2, scopeIDNotFound), + signers: []string{valueOwner1, valueOwner2}, + expErr: "scope not found with id " + scopeIDNotFound.String() + ": not found", + }, + { + name: "not properly signed", + starters: []types.Scope{ + ns(scopeID1, owner1, dataAccess1, valueOwner1), + ns(scopeID2, owner2, dataAccess2, valueOwner2), + }, + scopeIDs: ids(scopeID1, scopeID2), + signers: []string{valueOwner1}, + expErr: "missing signature from existing value owner " + valueOwner2 + ": invalid request", + }, + { + name: "1 scope without value owner", + starters: []types.Scope{ + ns(scopeID1, owner1, dataAccess1, ""), + }, + scopeIDs: ids(scopeID1), + signers: []string{owner1}, + expErr: "scope " + scopeID1.String() + " does not yet have a value owner: invalid request", + }, + { + name: "1 scope updated", + starters: []types.Scope{ + ns(scopeID1, owner1, dataAccess1, valueOwner1), + }, + scopeIDs: ids(scopeID1), + signers: []string{valueOwner1}, + expErr: "", + }, + { + name: "3 scopes updated all different", + starters: []types.Scope{ + ns(scopeID3Diff1, owner3Diff1, dataAccess3Diff1, valueOwner3Diff1), + ns(scopeID3Diff2, owner3Diff2, dataAccess3Diff2, valueOwner3Diff2), + ns(scopeID3Diff3, owner3Diff3, dataAccess3Diff3, valueOwner3Diff3), + }, + scopeIDs: ids(scopeID3Diff1, scopeID3Diff2, scopeID3Diff3), + signers: []string{valueOwner3Diff1, valueOwner3Diff2, valueOwner3Diff3}, + expErr: "", + }, + { + name: "3 scopes updated all same", + starters: []types.Scope{ + ns(scopeID3Same1, owner3Same1, dataAccess3Same1, valueOwner3Same), + ns(scopeID3Same2, owner3Same2, dataAccess3Same2, valueOwner3Same), + ns(scopeID3Same3, owner3Same3, dataAccess3Same3, valueOwner3Same), + }, + scopeIDs: ids(scopeID3Same1, scopeID3Same2, scopeID3Same3), + signers: []string{valueOwner3Same}, + expErr: "", + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + for _, scope := range tc.starters { + s.app.MetadataKeeper.SetScope(s.ctx, scope) + defer s.app.MetadataKeeper.RemoveScope(s.ctx, scope.ScopeId) + } + msg := types.MsgUpdateValueOwnersRequest{ + ScopeIds: tc.scopeIDs, + ValueOwnerAddress: newValueOwner, + Signers: tc.signers, + } + _, err := s.msgServer.UpdateValueOwners(s.ctx, &msg) + if len(tc.expErr) > 0 { + s.Assert().EqualError(err, tc.expErr, "handler(MsgUpdateValueOwnersRequest)") + } else { + s.Require().NoError(err, "handler(MsgUpdateValueOwnersRequest)") + + for i, scopeID := range tc.scopeIDs { + scope, found := s.app.MetadataKeeper.GetScope(s.ctx, scopeID) + if s.Assert().True(found, "[%d]GetScope(%s) found bool", i, scopeID) { + s.Assert().Equal(newValueOwner, scope.ValueOwnerAddress, "[%d] updated scope's value owner", i) + } + } + } + }) + } +} + +func (s *MsgServerTestSuite) TestMigrateValueOwner() { + scopeSpecID := types.ScopeSpecMetadataAddress(uuid.New()) + storeScope := func(valueOwner string, scopeID types.MetadataAddress) { + scope := types.Scope{ + ScopeId: scopeID, + SpecificationId: scopeSpecID, + Owners: []types.Party{{Address: s.user1, Role: types.PartyType_PARTY_TYPE_OWNER}}, + ValueOwnerAddress: valueOwner, + } + s.app.MetadataKeeper.SetScope(s.ctx, scope) + } + addr := func(str string) string { + return sdk.AccAddress(str).String() + } + + addrW1 := addr("addrW1______________") + addrW3 := addr("addrW3______________") + + scopeID1 := types.ScopeMetadataAddress(uuid.New()) + scopeID31 := types.ScopeMetadataAddress(uuid.New()) + scopeID32 := types.ScopeMetadataAddress(uuid.New()) + scopeID33 := types.ScopeMetadataAddress(uuid.New()) + + storeScope(addrW1, scopeID1) + storeScope(addrW3, scopeID31) + storeScope(addrW3, scopeID32) + storeScope(addrW3, scopeID33) + + tests := []struct { + name string + msg *types.MsgMigrateValueOwnerRequest + expErr string + scopeIDs []types.MetadataAddress + }{ + { + name: "err from IterateScopesForValueOwner", + msg: &types.MsgMigrateValueOwnerRequest{ + Existing: "", + Proposed: "doesn't matter", + Signers: []string{"who cares"}, + }, + expErr: "cannot iterate over invalid value owner \"\": empty address string is not allowed: invalid request", + }, + { + name: "no scopes", + msg: &types.MsgMigrateValueOwnerRequest{ + Existing: addr("unknown_value_owner_"), + Proposed: addr("does_not_matter_____"), + Signers: []string{addr("signer______________")}, + }, + expErr: "no scopes found with value owner \"" + addr("unknown_value_owner_") + "\": not found", + }, + { + name: "err from ValidateUpdateValueOwners", + msg: &types.MsgMigrateValueOwnerRequest{ + Existing: addrW1, + Proposed: addr("not_for_public_use__"), + Signers: []string{addr("incorrect_signer____")}, + }, + expErr: "missing signature from existing value owner " + addrW1 + ": invalid request", + }, + { + name: "1 scope updated", + msg: &types.MsgMigrateValueOwnerRequest{ + Existing: addrW1, + Proposed: addr("proposed_value_owner"), + Signers: []string{addrW1}, + }, + scopeIDs: []types.MetadataAddress{scopeID1}, + }, + { + name: "3 scopes updated", + msg: &types.MsgMigrateValueOwnerRequest{ + Existing: addrW3, + Proposed: addr("a_longer_proposed_value_owner___"), + Signers: []string{addrW3}, + }, + scopeIDs: []types.MetadataAddress{scopeID31, scopeID32, scopeID33}, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + _, err := s.msgServer.MigrateValueOwner(s.ctx, tc.msg) + if len(tc.expErr) > 0 { + s.Assert().EqualError(err, tc.expErr, "Metadata hander(%T)", tc.msg) + } else { + if s.Assert().NoError(err, tc.expErr, "Metadata hander(%T)", tc.msg) { + for i, scopeID := range tc.scopeIDs { + scope, found := s.app.MetadataKeeper.GetScope(s.ctx, scopeID) + s.Assert().True(found, "[%d]: GetScope(%q) found boolean", i, scopeID.String()) + actual := scope.ValueOwnerAddress + s.Assert().Equal(tc.msg.Proposed, actual, "[%d] %q value owner after migrate", i, scopeID.String()) + } + } + } + }) + } +} + +func (s *MsgServerTestSuite) TestWriteSession() { + cSpec := types.ContractSpecification{ + SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + Source: types.NewContractSpecificationSourceHash("somesource"), + ClassName: "someclass", + } + s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec) + sSpec := types.ScopeSpecification{ + SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + ContractSpecIds: []types.MetadataAddress{cSpec.SpecificationId}, + } + s.app.MetadataKeeper.SetScopeSpecification(s.ctx, sSpec) + + scopeUUID := uuid.New() + scope := types.Scope{ + ScopeId: types.ScopeMetadataAddress(scopeUUID), + SpecificationId: sSpec.SpecificationId, + Owners: []types.Party{{ + Address: s.user1, + Role: types.PartyType_PARTY_TYPE_OWNER, + }}, + DataAccess: nil, + ValueOwnerAddress: "", + } + s.app.MetadataKeeper.SetScope(s.ctx, scope) + + someBytes, err := base64.StdEncoding.DecodeString("ChFIRUxMTyBQUk9WRU5BTkNFIQ==") + require.NoError(s.T(), err, "trying to create someBytes") + + cases := []struct { + name string + session types.Session + signers []string + errorMsg string + }{ + { + "valid without context", + types.Session{ + SessionId: types.SessionMetadataAddress(scopeUUID, uuid.New()), + SpecificationId: cSpec.SpecificationId, + Parties: scope.Owners, + Name: "someclass", + Context: nil, + Audit: nil, + }, + []string{s.user1}, + "", + }, + { + "valid with context", + types.Session{ + SessionId: types.SessionMetadataAddress(scopeUUID, uuid.New()), + SpecificationId: cSpec.SpecificationId, + Parties: scope.Owners, + Name: "someclass", + Context: someBytes, + Audit: nil, + }, + []string{s.user1}, + "", + }, + } + + for _, tc := range cases { + s.T().Run(tc.name, func(t *testing.T) { + msg := types.MsgWriteSessionRequest{ + Session: tc.session, + Signers: tc.signers, + SessionIdComponents: nil, + SpecUuid: "", + } + _, err := s.msgServer.WriteSession(s.ctx, &msg) + if len(tc.errorMsg) > 0 { + assert.EqualError(t, err, tc.errorMsg) + } else { + assert.NoError(t, err) + } + }) + } +} + +func (s *MsgServerTestSuite) TestWriteDeleteRecord() { + cSpecUUID := uuid.New() + cSpec := types.ContractSpecification{ + SpecificationId: types.ContractSpecMetadataAddress(cSpecUUID), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + Source: types.NewContractSpecificationSourceHash("somesource1"), + ClassName: "someclass1", + } + s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec) + defer func() { + s.Assert().NoError(s.app.MetadataKeeper.RemoveContractSpecification(s.ctx, cSpec.SpecificationId), "removing contract spec") + }() + + sSpecUUID := uuid.New() + sSpec := types.ScopeSpecification{ + SpecificationId: types.ScopeSpecMetadataAddress(sSpecUUID), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + ContractSpecIds: []types.MetadataAddress{cSpec.SpecificationId}, + } + s.app.MetadataKeeper.SetScopeSpecification(s.ctx, sSpec) + defer func() { + s.Assert().NoError(s.app.MetadataKeeper.RemoveScopeSpecification(s.ctx, sSpec.SpecificationId), "removing scope spec") + }() + + rSpec := types.RecordSpecification{ + SpecificationId: types.RecordSpecMetadataAddress(cSpecUUID, "record"), + Name: "record", + Inputs: []*types.InputSpecification{ + { + Name: "ri1", + TypeName: "string", + Source: types.NewInputSpecificationSourceHash("ri1hash"), + }, + }, + TypeName: "string", + ResultType: types.DefinitionType_DEFINITION_TYPE_RECORD_LIST, + ResponsibleParties: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + } + s.app.MetadataKeeper.SetRecordSpecification(s.ctx, rSpec) + defer func() { + s.Assert().NoError(s.app.MetadataKeeper.RemoveRecordSpecification(s.ctx, rSpec.SpecificationId), "removing record spec 1") + }() + + scopeUUID := uuid.New() + scope := types.Scope{ + ScopeId: types.ScopeMetadataAddress(scopeUUID), + SpecificationId: sSpec.SpecificationId, + Owners: []types.Party{{ + Address: s.user1, + Role: types.PartyType_PARTY_TYPE_OWNER, + }}, + DataAccess: nil, + ValueOwnerAddress: "", + } + s.app.MetadataKeeper.SetScope(s.ctx, scope) + defer s.app.MetadataKeeper.RemoveScope(s.ctx, scope.ScopeId) + + session1UUID := uuid.New() + session1 := types.Session{ + SessionId: types.SessionMetadataAddress(scopeUUID, session1UUID), + SpecificationId: cSpec.SpecificationId, + Parties: ownerPartyList(s.user1), + Name: "someclass1", + } + s.app.MetadataKeeper.SetSession(s.ctx, session1) + defer s.app.MetadataKeeper.RemoveSession(s.ctx, session1.SessionId) + + session2UUID := uuid.New() + session2 := types.Session{ + SessionId: types.SessionMetadataAddress(scopeUUID, session2UUID), + SpecificationId: cSpec.SpecificationId, + Parties: ownerPartyList(s.user1), + Name: "someclass1", + } + s.app.MetadataKeeper.SetSession(s.ctx, session2) + defer s.app.MetadataKeeper.RemoveSession(s.ctx, session2.SessionId) + + record := types.Record{ + Name: rSpec.Name, + SessionId: session1.SessionId, + Process: types.Process{ + ProcessId: &types.Process_Hash{Hash: "rprochash"}, + Name: "rproc", + Method: "rprocmethod", + }, + Inputs: []types.RecordInput{ + { + Name: rSpec.Inputs[0].Name, + Source: &types.RecordInput_Hash{Hash: "rhash"}, + TypeName: rSpec.Inputs[0].TypeName, + Status: types.RecordInputStatus_Proposed, + }, + }, + Outputs: []types.RecordOutput{ + { + Hash: "rout1", + Status: types.ResultStatus_RESULT_STATUS_PASS, + }, + { + Hash: "rout2", + Status: types.ResultStatus_RESULT_STATUS_PASS, + }, + }, + SpecificationId: rSpec.SpecificationId, + } + recordID := types.RecordMetadataAddress(scopeUUID, rSpec.Name) + // Not adding the record here because we're testing that stuff. + + s.T().Run("write invalid record", func(t *testing.T) { + // Make a record with an unknown spec id. Try to write it and expect an error. + badRecord := types.Record{ + Name: rSpec.Name, + SessionId: session1.SessionId, + Process: types.Process{ + ProcessId: &types.Process_Hash{Hash: "badrprochash"}, + Name: "badrproc", + Method: "badrprocmethod", + }, + Inputs: []types.RecordInput{ + { + Name: rSpec.Inputs[0].Name, + Source: &types.RecordInput_Hash{Hash: "badrhash"}, + TypeName: rSpec.Inputs[0].TypeName, + Status: types.RecordInputStatus_Proposed, + }, + }, + Outputs: []types.RecordOutput{ + { + Hash: "badrout1", + Status: types.ResultStatus_RESULT_STATUS_PASS, + }, + { + Hash: "badrout2", + Status: types.ResultStatus_RESULT_STATUS_PASS, + }, + }, + SpecificationId: types.RecordSpecMetadataAddress(uuid.New(), rSpec.Name), + } + msg := types.MsgWriteRecordRequest{ + Record: badRecord, + Signers: []string{s.user1}, + SessionIdComponents: nil, + ContractSpecUuid: "", + Parties: ownerPartyList(s.user1), + } + _, err := s.msgServer.WriteRecord(s.ctx, &msg) + require.Error(t, err, "sending bad MsgWriteRecordRequest") + require.Contains(t, err.Error(), "proposed specification id") + require.Contains(t, err.Error(), "does not match expected") + }) + + s.T().Run("write record to session 1", func(t *testing.T) { + msg := types.MsgWriteRecordRequest{ + Record: record, + Signers: []string{s.user1}, + SessionIdComponents: nil, + ContractSpecUuid: "", + Parties: ownerPartyList(s.user1), + } + _, err := s.msgServer.WriteRecord(s.ctx, &msg) + require.NoError(t, err, "sending MsgWriteRecordRequest") + r, rok := s.app.MetadataKeeper.GetRecord(s.ctx, recordID) + if assert.True(t, rok, "GetRecord bool") { + assert.Equal(t, record, r, "GetRecord record") + } + }) + + s.T().Run("Update record to other session", func(t *testing.T) { + record.SessionId = session2.SessionId + msg := types.MsgWriteRecordRequest{ + Record: record, + Signers: []string{s.user1}, + SessionIdComponents: nil, + ContractSpecUuid: "", + Parties: ownerPartyList(s.user1), + } + _, err := s.msgServer.WriteRecord(s.ctx, &msg) + require.NoError(t, err, "sending MsgWriteRecordRequest") + r, rok := s.app.MetadataKeeper.GetRecord(s.ctx, recordID) + if assert.True(t, rok, "GetRecord bool") { + assert.Equal(t, record, r, "GetRecord record") + } + // Make sure the session was deleted since it's now empty. + _, sok := s.app.MetadataKeeper.GetSession(s.ctx, session1.SessionId) + assert.False(t, sok, "GetSession session 1 bool") + }) + + s.T().Run("delete the record", func(t *testing.T) { + msg := types.MsgDeleteRecordRequest{ + RecordId: recordID, + Signers: []string{s.user1}, + } + _, err := s.msgServer.DeleteRecord(s.ctx, &msg) + require.NoError(t, err, "sending MsgDeleteRecordRequest") + _, rok := s.app.MetadataKeeper.GetRecord(s.ctx, recordID) + assert.False(t, rok, "GetRecord bool") + // Make sure the session was deleted since it's now empty. + _, sok := s.app.MetadataKeeper.GetSession(s.ctx, session2.SessionId) + assert.False(t, sok, "GetSession session 2 bool") + }) +} + +// TODO: WriteScopeSpecification tests +// TODO: DeleteScopeSpecification tests +// TODO: WriteContractSpecification tests +// TODO: DeleteContractSpecification tests + +func (s *MsgServerTestSuite) TestAddContractSpecToScopeSpec() { + cSpec := types.ContractSpecification{ + SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + Source: types.NewContractSpecificationSourceHash("somesource"), + ClassName: "someclass", + } + s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec) + sSpec := types.ScopeSpecification{ + SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + ContractSpecIds: []types.MetadataAddress{cSpec.SpecificationId}, + } + s.app.MetadataKeeper.SetScopeSpecification(s.ctx, sSpec) + + cSpec2 := types.ContractSpecification{ + SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + Source: types.NewContractSpecificationSourceHash("somesource"), + ClassName: "someclass", + } + s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec2) + + unknownContractSpecId := types.ContractSpecMetadataAddress(uuid.New()) + unknownScopeSpecId := types.ScopeSpecMetadataAddress(uuid.New()) + + cases := []struct { + name string + contractSpecId types.MetadataAddress + scopeSpecId types.MetadataAddress + signers []string + errorMsg string + }{ + { + "fail to add contract spec, cannot find contract spec", + unknownContractSpecId, + sSpec.SpecificationId, + []string{s.user1}, + fmt.Sprintf("contract specification not found with id %s: not found", unknownContractSpecId), + }, + { + "fail to add contract spec, cannot find scope spec", + cSpec2.SpecificationId, + unknownScopeSpecId, + []string{s.user1}, + fmt.Sprintf("scope specification not found with id %s: not found", unknownScopeSpecId), + }, + { + "fail to add contract spec, scope spec already has contract spec", + cSpec.SpecificationId, + sSpec.SpecificationId, + []string{s.user1}, + fmt.Sprintf("scope spec %s already contains contract spec %s: invalid request", sSpec.SpecificationId, cSpec.SpecificationId), + }, + { + "should successfully add contract spec to scope spec", + cSpec2.SpecificationId, + sSpec.SpecificationId, + []string{s.user1}, + "", + }, + } + + for _, tc := range cases { + s.T().Run(tc.name, func(t *testing.T) { + msg := types.MsgAddContractSpecToScopeSpecRequest{ + ContractSpecificationId: tc.contractSpecId, + ScopeSpecificationId: tc.scopeSpecId, + Signers: tc.signers, + } + _, err := s.msgServer.AddContractSpecToScopeSpec(s.ctx, &msg) + if len(tc.errorMsg) > 0 { + assert.EqualError(t, err, tc.errorMsg) + } else { + assert.NoError(t, err) + } + }) + } +} + +func (s *MsgServerTestSuite) TestDeleteContractSpecFromScopeSpec() { + cSpec := types.ContractSpecification{ + SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + Source: types.NewContractSpecificationSourceHash("somesource"), + ClassName: "someclass", + } + s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec) + cSpec2 := types.ContractSpecification{ + SpecificationId: types.ContractSpecMetadataAddress(uuid.New()), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + Source: types.NewContractSpecificationSourceHash("somesource"), + ClassName: "someclass", + } + s.app.MetadataKeeper.SetContractSpecification(s.ctx, cSpec2) + cSpecDNE := types.ContractSpecMetadataAddress(uuid.New()) // Does Not Exist. + sSpec := types.ScopeSpecification{ + SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), + Description: nil, + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + ContractSpecIds: []types.MetadataAddress{cSpec.SpecificationId, cSpec2.SpecificationId, cSpecDNE}, + } + s.app.MetadataKeeper.SetScopeSpecification(s.ctx, sSpec) + + unknownScopeSpecId := types.ScopeSpecMetadataAddress(uuid.New()) + + cases := []struct { + name string + contractSpecId types.MetadataAddress + scopeSpecId types.MetadataAddress + signers []string + errorMsg string + }{ + { + "cannot find contract spec", + cSpecDNE, + sSpec.SpecificationId, + []string{s.user1}, + "", + }, + { + "fail to delete contract spec from scope spec, cannot find scope spec", + cSpec2.SpecificationId, + unknownScopeSpecId, + []string{s.user1}, + fmt.Sprintf("scope specification not found with id %s: not found", unknownScopeSpecId), + }, + { + "should succeed to add contract spec to scope spec", + cSpec2.SpecificationId, + sSpec.SpecificationId, + []string{s.user1}, + "", + }, + { + "fail to delete contract spec from scope spec, scope spec does not contain contract spec", + cSpec2.SpecificationId, + sSpec.SpecificationId, + []string{s.user1}, + fmt.Sprintf("contract specification %s not found in scope specification %s: not found", cSpec2.SpecificationId, sSpec.SpecificationId), + }, + } + + for _, tc := range cases { + s.T().Run(tc.name, func(t *testing.T) { + msg := types.MsgDeleteContractSpecFromScopeSpecRequest{ + ContractSpecificationId: tc.contractSpecId, + ScopeSpecificationId: tc.scopeSpecId, + Signers: tc.signers, + } + _, err := s.msgServer.DeleteContractSpecFromScopeSpec(s.ctx, &msg) + if len(tc.errorMsg) > 0 { + assert.EqualError(t, err, tc.errorMsg) + } else { + assert.NoError(t, err) + } + }) + } +} + +// TODO: WriteRecordSpecification tests +// TODO: DeleteRecordSpecification tests + +// TODO: BindOSLocator tests +// TODO: DeleteOSLocator tests +// TODO: ModifyOSLocator tests + +func (s *MsgServerTestSuite) TestSetAccountData() { + scopeSpec := types.ScopeSpecification{ + SpecificationId: types.ScopeSpecMetadataAddress(uuid.New()), + OwnerAddresses: []string{s.user1}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + } + s.app.MetadataKeeper.SetScopeSpecification(s.ctx, scopeSpec) + + scope := types.Scope{ + ScopeId: types.ScopeMetadataAddress(uuid.New()), + SpecificationId: scopeSpec.SpecificationId, + Owners: []types.Party{{Address: s.user1, Role: types.PartyType_PARTY_TYPE_OWNER}}, + } + s.app.MetadataKeeper.SetScope(s.ctx, scope) + + tests := []struct { + name string + msg *types.MsgSetAccountDataRequest + exp *types.MsgSetAccountDataResponse + expErr string + }{ + { + name: "incorrect signer", + msg: &types.MsgSetAccountDataRequest{ + MetadataAddr: scope.ScopeId, + Value: "This won't work.", + Signers: []string{s.user2}, + }, + expErr: "missing signature: " + s.user1 + ": invalid request", + }, + { + name: "value too long", + msg: &types.MsgSetAccountDataRequest{ + MetadataAddr: scope.ScopeId, + Value: strings.Repeat("This won't work. ", 1000), + Signers: []string{s.user1}, + }, + expErr: "could not set accountdata for \"" + scope.ScopeId.String() + "\": attribute value length of 17000 exceeds max length 10000: invalid request", + }, + { + name: "all good", + msg: &types.MsgSetAccountDataRequest{ + MetadataAddr: scope.ScopeId, + Value: "This value is a good value for this scope.", + Signers: []string{s.user1}, + }, + exp: &types.MsgSetAccountDataResponse{}, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + var err error + var result *types.MsgSetAccountDataResponse + testFunc := func() { + result, err = s.msgServer.SetAccountData(s.ctx, tc.msg) + } + s.Require().NotPanics(testFunc, "%T hander", tc.msg) + s.AssertErrorValue(err, tc.expErr, "%T handler error", tc.msg) + if tc.exp == nil { + s.Assert().Nil(result, "%T handler result", tc.msg) + } else { + s.Assert().Equal(tc.exp, result, "%T handler msg response", tc.msg) + } + }) + } +} + +func (s *MsgServerTestSuite) TestIssue412WriteScopeOptionalField() { + ownerAddress := "cosmos1vz99nyd2er8myeugsr4xm5duwhulhp5ae4dvpa" + specIDStr := "scopespec1qjkyp28sldx5r9ueaxqc5adrc5wszy6nsh" + specUUIDStr := "ac40a8f0-fb4d-4197-99e9-818a75a3c51d" + specID, specIDErr := types.MetadataAddressFromBech32(specIDStr) + require.NoError(s.T(), specIDErr, "converting scopeIDStr to a metadata address") + + s.T().Run("Ensure ID and UUID strings match", func(t *testing.T) { + specIDFromID, e1 := types.MetadataAddressFromBech32(specIDStr) + require.NoError(t, e1, "specIDFromIDStr") + specUUIDFromID, e2 := specIDFromID.ScopeSpecUUID() + require.NoError(t, e2, "specUUIDActualStr") + specUUIDStrActual := specUUIDFromID.String() + assert.Equal(t, specUUIDStr, specUUIDStrActual, "UUID strings") + + specIDFFromUUID := types.ScopeSpecMetadataAddress(uuid.MustParse(specUUIDStr)) + specIDStrActual := specIDFFromUUID.String() + assert.Equal(t, specIDStr, specIDStrActual, "ID strings") + + assert.Equal(t, specIDFromID, specIDFFromUUID, "scope spec ids") + }) + + s.T().Run("Setting scope spec with just a spec ID", func(t *testing.T) { + msg := types.MsgWriteScopeSpecificationRequest{ + Specification: types.ScopeSpecification{ + SpecificationId: specID, + Description: &types.Description{ + Name: "io.prov.contracts.examplekotlin.helloWorld", + Description: "A generic scope that allows for a lot of example hello world contracts.", + }, + OwnerAddresses: []string{ownerAddress}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + ContractSpecIds: nil, + }, + Signers: []string{ownerAddress}, + SpecUuid: "", + } + res, err := s.msgServer.WriteScopeSpecification(s.ctx, &msg) + assert.NoError(t, err) + assert.NotNil(t, 0, res) + }) + + s.T().Run("Setting scope spec with just a UUID", func(t *testing.T) { + msg := types.MsgWriteScopeSpecificationRequest{ + Specification: types.ScopeSpecification{ + SpecificationId: nil, + Description: &types.Description{ + Name: "io.prov.contracts.examplekotlin.helloWorld", + Description: "A generic scope that allows for a lot of example hello world contracts.", + }, + OwnerAddresses: []string{ownerAddress}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + ContractSpecIds: nil, + }, + Signers: []string{ownerAddress}, + SpecUuid: specUUIDStr, + } + res, err := s.msgServer.WriteScopeSpecification(s.ctx, &msg) + assert.NoError(t, err) + assert.NotNil(t, 0, res) + }) + + s.T().Run("Setting scope spec with matching ID and UUID", func(t *testing.T) { + msg := types.MsgWriteScopeSpecificationRequest{ + Specification: types.ScopeSpecification{ + SpecificationId: specID, + Description: &types.Description{ + Name: "io.prov.contracts.examplekotlin.helloWorld", + Description: "A generic scope that allows for a lot of example hello world contracts.", + }, + OwnerAddresses: []string{ownerAddress}, + PartiesInvolved: []types.PartyType{types.PartyType_PARTY_TYPE_OWNER}, + ContractSpecIds: nil, + }, + Signers: []string{ownerAddress}, + SpecUuid: specUUIDStr, + } + res, err := s.msgServer.WriteScopeSpecification(s.ctx, &msg) + assert.NoError(t, err) + assert.NotNil(t, 0, res) + }) +} + func (s *MsgServerTestSuite) TestAddNetAssetValue() { scopeSpecUUIDNF := uuid.New() scopeSpecIDNF := types.ScopeSpecMetadataAddress(scopeSpecUUIDNF) diff --git a/x/metadata/keeper/querier.go b/x/metadata/keeper/querier.go deleted file mode 100644 index f6da41b5a8..0000000000 --- a/x/metadata/keeper/querier.go +++ /dev/null @@ -1,255 +0,0 @@ -package keeper - -import ( - "strings" - - "github.com/google/uuid" - - abci "github.com/cometbft/cometbft/abci/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/provenance-io/provenance/x/metadata/types" -) - -// TODO[1760]: metadata: Delete the metadata Querier. - -// NewQuerier creates a querier for auth REST endpoints -func NewQuerier(k Keeper, legacyQuerierCdc *codec.LegacyAmino) func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { - switch path[0] { - case types.QueryScope: - return queryScope(ctx, path, req, k, legacyQuerierCdc) - case types.QueryOwnership: - return queryAddressScopes(ctx, path, req, k, legacyQuerierCdc) - case types.QueryParams: - return queryParams(ctx, k, legacyQuerierCdc) - case types.QueryScopeSpec: - return queryScopeSpecification(ctx, path, k, legacyQuerierCdc) - // TODO: add contract spec stuff - // TODO: add record spec stuff - case types.QueryOSParams: - return queryOSLocatorParams(ctx, k, legacyQuerierCdc) - case types.QueryOSGet: - return queryOSGet(ctx, path, k, legacyQuerierCdc) - case types.QueryOSGetByURI: - return queryOSGetByURI(ctx, path, k, legacyQuerierCdc) - case types.QueryOSGetByScope: - return queryOSGetByScope(ctx, path, k, legacyQuerierCdc) - case types.QueryOSGetAll: - return queryOSGetAll(ctx, k, legacyQuerierCdc) - default: - return nil, sdkerrors.ErrUnknownRequest.Wrap("unknown query endpoint") - } - } -} - -// Query for a scope by UUID. -func queryScope(ctx sdk.Context, path []string, _ abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - scopeUUID, err := uuid.Parse(strings.TrimSpace(path[1])) - if err != nil { - ctx.Logger().Error(err.Error()) - return nil, sdkerrors.ErrInvalidRequest.Wrap(err.Error()) - } - scope, found := k.GetScope(ctx, types.ScopeMetadataAddress(scopeUUID)) - if !found { - return nil, sdkerrors.ErrKeyNotFound.Wrap("scope does not exist") - } - scopeBytes, err := k.cdc.Marshal(&scope) - if err != nil { - return nil, sdkerrors.ErrInvalidRequest.Wrap(err.Error()) - } - res, err := legacyQuerierCdc.MarshalJSON(types.QueryResScope{Scope: scopeBytes}) - if err != nil { - ctx.Logger().Error("unable to marshal scope to JSON", "err", err) - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - return res, nil -} - -// Query for a scopes associated with an address. -func queryAddressScopes(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - params := types.QueryMetadataParams{Page: 0, Limit: 100} - address, err := sdk.AccAddressFromBech32(strings.TrimSpace(path[1])) - if err != nil || address.Empty() { - errm := "invalid address to query scopes for" - ctx.Logger().Error(errm) - return nil, sdkerrors.ErrInvalidRequest.Wrap(errm) - } - scopes := make([]string, 0) - err = k.IterateScopesForAddress(ctx, address, func(scopeID types.MetadataAddress) (stop bool) { - scopes = append(scopes, scopeID.String()) - return false - }) - // check for parameters used for paging. - if len(req.Data) > 0 { - err = legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms) - if err != nil { - return nil, sdkerrors.ErrJSONUnmarshal.Wrap(err.Error()) - } - } - - // TODO: consider a parameter configuration item for the limit here (1000) - - // BOOKMARK -- create a v1 to v0 migration function to re-assemble a scope from groups and records - - start, end := client.Paginate(len(scopes), params.Page, params.Limit, 1000) - if start < 0 || end < 0 { - scopes = []string{} - } else { - scopes = scopes[start:end] - } - if err != nil { - ctx.Logger().Error("unable to get scope IDs for address", "err", err) - return nil, sdkerrors.ErrInvalidRequest.Wrap(err.Error()) - } - res, err := legacyQuerierCdc.MarshalJSON(types.QueryResOwnership{Address: address, ScopeID: scopes}) - if err != nil { - ctx.Logger().Error("unable to marshal scope ids to JSON", "err", err) - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - return res, nil -} - -func queryParams(ctx sdk.Context, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - params := k.GetParams(ctx) - - res, err := codec.MarshalJSONIndent(legacyQuerierCdc, params) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return res, nil -} - -// query for a scope specification by specification id -func queryScopeSpecification(ctx sdk.Context, path []string, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - specificationUUID, err := uuid.Parse(strings.TrimSpace(path[1])) - if err != nil { - ctx.Logger().Error(err.Error()) - return nil, sdkerrors.ErrInvalidRequest.Wrap(err.Error()) - } - scopeSpec, found := k.GetScopeSpecification(ctx, types.ScopeMetadataAddress(specificationUUID)) - if !found { - return nil, sdkerrors.ErrKeyNotFound.Wrapf("scope specification uuid [%s] does not exist", specificationUUID) - } - res, err := legacyQuerierCdc.MarshalJSON(types.NewQueryResScopeSpec(scopeSpec)) - if err != nil { - ctx.Logger().Error("unable to marshal scope spec to JSON", "specificationUUID", specificationUUID, "err", err) - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - return res, nil -} - -func queryOSLocatorParams(ctx sdk.Context, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - params := keeper.GetOSLocatorParams(ctx) - - res, err := codec.MarshalJSONIndent(legacyQuerierCdc, params) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return res, nil -} - -func queryOSGet(ctx sdk.Context, path []string, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - accAddr, err := sdk.AccAddressFromBech32(path[1]) - if err != nil { - return nil, types.ErrInvalidAddress - } - msgs, _ := keeper.GetOsLocatorRecord(ctx, accAddr) - - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, msgs) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return bz, nil -} - -func queryOSGetByURI(ctx sdk.Context, path []string, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - // intentionally leaving out pagination for now for this one, not really anything legacy rest for this :shrug: - var records []types.ObjectStoreLocator - - appendToRecords := func(record types.ObjectStoreLocator) bool { - if record.LocatorUri == path[1] { - records = append(records, record) - // have to get all the uri associated with an address..imo..check - } - return false - } - if err := keeper.IterateOSLocators(ctx, appendToRecords); err != nil { - return nil, err - } - uniqueRecords := uniqueRecords(records) - - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, &uniqueRecords) - - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return bz, nil -} - -func queryOSGetAll(ctx sdk.Context, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - // intentionally leaving out pagination for now for this one, not really anything legacy rest for this :shrug: - var records []types.ObjectStoreLocator - - appendToRecords := func(record types.ObjectStoreLocator) bool { - records = append(records, record) - // have to get all the uri associated with an address..imo..check - return false - } - if err := keeper.IterateOSLocators(ctx, appendToRecords); err != nil { - return nil, err - } - uniqueRecords := uniqueRecords(records) - - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, &uniqueRecords) - - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return bz, nil -} - -func queryOSGetByScope(ctx sdk.Context, path []string, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - locators, lErr := keeper.GetOSLocatorByScope(ctx, path[1]) - if lErr != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(lErr.Error()) - } - - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, locators) - if err != nil { - return nil, sdkerrors.ErrJSONMarshal.Wrap(err.Error()) - } - - return bz, nil -} - -func uniqueRecords(records []types.ObjectStoreLocator) []types.ObjectStoreLocator { - if len(records) == 0 { - return records - } - seen := make([]types.ObjectStoreLocator, 0, len(records)) - -slice: - for i, n := range records { - if i == 0 { - records = records[:0] - } - for _, t := range seen { - if n.Owner == t.Owner && n.LocatorUri == t.LocatorUri { - continue slice - } - } - seen = append(seen, n) - records = append(records, n) - } - return records -} diff --git a/x/msgfees/handler.go b/x/msgfees/handler.go index 42a3fc5422..30c008926a 100644 --- a/x/msgfees/handler.go +++ b/x/msgfees/handler.go @@ -10,6 +10,8 @@ import ( "github.com/provenance-io/provenance/x/msgfees/types" ) +// TODO[1760]: marker: Migrate the legacy gov proposals. + func NewProposalHandler(k keeper.Keeper, registry cdctypes.InterfaceRegistry) govtypesv1beta1.Handler { return func(ctx sdk.Context, content govtypesv1beta1.Content) error { switch c := content.(type) { diff --git a/x/msgfees/keeper/proposal_handler.go b/x/msgfees/keeper/proposal_handler.go index 3100a44869..2220fab3b8 100644 --- a/x/msgfees/keeper/proposal_handler.go +++ b/x/msgfees/keeper/proposal_handler.go @@ -10,6 +10,8 @@ import ( "github.com/provenance-io/provenance/x/msgfees/types" ) +// TODO[1760]: marker: Migrate the legacy gov proposals. + // HandleAddMsgFeeProposal handles an Add msg fees governance proposal request func HandleAddMsgFeeProposal(ctx sdk.Context, k Keeper, proposal *types.AddMsgFeeProposal, registry codectypes.InterfaceRegistry) error { if err := proposal.ValidateBasic(); err != nil { diff --git a/x/name/handler.go b/x/name/handler.go index c9d9febdb8..68b53d009a 100644 --- a/x/name/handler.go +++ b/x/name/handler.go @@ -9,30 +9,7 @@ import ( "github.com/provenance-io/provenance/x/name/types" ) -// Returns a handler for name messages. -// TODO[1760]: name: Delete the name NewHandler. -func NewHandler(k keeper.Keeper) func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgBindNameRequest: - res, err := msgServer.BindName(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgDeleteNameRequest: - res, err := msgServer.DeleteName(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - case *types.MsgModifyNameRequest: - res, err := msgServer.ModifyName(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - default: - return nil, sdkerrors.ErrUnknownRequest.Wrapf("unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} - +// TODO[1760]: marker: Migrate the legacy gov proposals. func NewProposalHandler(k keeper.Keeper) govtypesv1beta1.Handler { return func(ctx sdk.Context, content govtypesv1beta1.Content) error { switch c := content.(type) { diff --git a/x/name/handler_test.go b/x/name/handler_test.go deleted file mode 100644 index cb1ec5dbde..0000000000 --- a/x/name/handler_test.go +++ /dev/null @@ -1,270 +0,0 @@ -package name_test - -import ( - "fmt" - "strings" - "testing" - - "github.com/golang/protobuf/proto" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - - cerrs "cosmossdk.io/errors" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - simapp "github.com/provenance-io/provenance/app" - "github.com/provenance-io/provenance/x/name" - "github.com/provenance-io/provenance/x/name/keeper" - nametypes "github.com/provenance-io/provenance/x/name/types" -) - -// TODO[1760]: name: Migrate the name handler tests to the keeper. - -func TestInvalidMsg(t *testing.T) { - k := keeper.Keeper{} - h := name.NewHandler(k) - - res, err := h(sdk.NewContext(nil, cmtproto.Header{}, false, nil), testdata.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - - _, _, log := cerrs.ABCIInfo(err, false) - require.True(t, strings.Contains(log, "unrecognized name message type")) -} - -func containsMessage(result *sdk.Result, msg proto.Message) bool { - events := result.GetEvents().ToABCIEvents() - for _, event := range events { - typeEvent, _ := sdk.ParseTypedEvent(event) - if assert.ObjectsAreEqual(msg, typeEvent) { - return true - } - } - return false -} - -// create name record -func TestCreateName(t *testing.T) { - priv1 := secp256k1.GenPrivKey() - addr1 := sdk.AccAddress(priv1.PubKey().Address()) - priv2, _ := secp256r1.GenPrivKey() - addr2 := sdk.AccAddress(priv2.PubKey().Address()) - - tests := []struct { - name string - expectedError error - msg *nametypes.MsgBindNameRequest - expectedEvent proto.Message - }{ - { - name: "create name record", - msg: nametypes.NewMsgBindNameRequest(nametypes.NewNameRecord("new", addr2, false), nametypes.NewNameRecord("example.name", addr1, false)), - expectedError: nil, - expectedEvent: nametypes.NewEventNameBound(addr2.String(), "new.example.name", false), - }, - { - name: "create bad name record", - msg: nametypes.NewMsgBindNameRequest(nametypes.NewNameRecord("new", addr2, false), nametypes.NewNameRecord("foo.name", addr1, false)), - expectedError: sdkerrors.ErrInvalidRequest.Wrap(nametypes.ErrNameNotBound.Error()), - }, - } - - acc1 := &authtypes.BaseAccount{ - Address: addr1.String(), - } - acc2 := &authtypes.BaseAccount{ - Address: addr2.String(), - } - accs := authtypes.GenesisAccounts{acc1, acc2} - app := simapp.SetupWithGenesisAccounts(t, "", accs) - ctx := app.BaseApp.NewContext(false) - - var nameData nametypes.GenesisState - nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("name", addr1, false)) - nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("example.name", addr1, false)) - nameData.Params.AllowUnrestrictedNames = false - nameData.Params.MaxNameLevels = 16 - nameData.Params.MinSegmentLength = 2 - nameData.Params.MaxSegmentLength = 16 - - app.NameKeeper.InitGenesis(ctx, nameData) - - handler := name.NewHandler(app.NameKeeper) - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - response, err := handler(ctx, tc.msg) - if tc.expectedError != nil { - require.EqualError(t, err, tc.expectedError.Error()) - } else { - require.NoError(t, err) - } - if tc.expectedEvent != nil { - result := containsMessage(response, tc.expectedEvent) - require.True(t, result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) - } - }) - } -} - -// delete name record -func TestDeleteName(t *testing.T) { - priv1 := secp256k1.GenPrivKey() - addr1 := sdk.AccAddress(priv1.PubKey().Address()) - - tests := []struct { - name string - expectedError error - msg *nametypes.MsgDeleteNameRequest - expectedEvent proto.Message - }{ - { - name: "delete name record", - msg: nametypes.NewMsgDeleteNameRequest(nametypes.NewNameRecord("example.name", addr1, false)), - expectedError: nil, - expectedEvent: nametypes.NewEventNameUnbound(addr1.String(), "example.name", false), - }, - { - name: "create bad name record", - msg: nametypes.NewMsgDeleteNameRequest(nametypes.NewNameRecord("example.name", addr1, false)), - expectedError: sdkerrors.ErrInvalidRequest.Wrap("name does not exist"), - }, - } - - acc1 := &authtypes.BaseAccount{ - Address: addr1.String(), - } - accs := authtypes.GenesisAccounts{acc1} - app := simapp.SetupWithGenesisAccounts(t, "", accs) - ctx := app.BaseApp.NewContext(false) - - var nameData nametypes.GenesisState - nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("name", addr1, false)) - nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("example.name", addr1, false)) - nameData.Params.AllowUnrestrictedNames = false - nameData.Params.MaxNameLevels = 16 - nameData.Params.MinSegmentLength = 2 - nameData.Params.MaxSegmentLength = 16 - - app.NameKeeper.InitGenesis(ctx, nameData) - - handler := name.NewHandler(app.NameKeeper) - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - response, err := handler(ctx, tc.msg) - if tc.expectedError != nil { - require.EqualError(t, err, tc.expectedError.Error()) - } else { - require.NoError(t, err) - } - if tc.expectedEvent != nil { - result := containsMessage(response, tc.expectedEvent) - require.True(t, result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) - } - }) - } -} - -func TestModifyName(t *testing.T) { - priv1 := secp256k1.GenPrivKey() - addr1 := sdk.AccAddress(priv1.PubKey().Address()) - - acc1 := &authtypes.BaseAccount{ - Address: addr1.String(), - } - accs := authtypes.GenesisAccounts{acc1} - app := simapp.SetupWithGenesisAccounts(t, "", accs) - ctx := app.BaseApp.NewContext(false) - - var nameData nametypes.GenesisState - nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("name", addr1, false)) - nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("example.name", addr1, false)) - nameData.Params.AllowUnrestrictedNames = false - nameData.Params.MaxNameLevels = 16 - nameData.Params.MinSegmentLength = 2 - nameData.Params.MaxSegmentLength = 16 - app.NameKeeper.InitGenesis(ctx, nameData) - - handler := name.NewHandler(app.NameKeeper) - authority := app.NameKeeper.GetAuthority() - - tests := []struct { - name string - expectedError error - msg *nametypes.MsgModifyNameRequest - expectedEvent proto.Message - }{ - { - name: "modify name record, via gov ", - msg: nametypes.NewMsgModifyNameRequest(authority, "name", addr1, true), - expectedError: nil, - expectedEvent: nametypes.NewEventNameUpdate(addr1.String(), "name", true), - }, - { - name: "modify name record, via owner", - msg: nametypes.NewMsgModifyNameRequest(addr1.String(), "name", addr1, true), - expectedError: nil, - expectedEvent: nametypes.NewEventNameUpdate(addr1.String(), "name", true), - }, - { - name: "modify name record with multi level", - msg: nametypes.NewMsgModifyNameRequest(authority, "example.name", addr1, true), - expectedError: nil, - expectedEvent: nametypes.NewEventNameUpdate(addr1.String(), "example.name", true), - }, - { - name: "modify name - fails with invalid address", - msg: nametypes.NewMsgModifyNameRequest(authority, "name", sdk.AccAddress{}, true), - expectedError: sdkerrors.ErrInvalidRequest.Wrap("empty address string is not allowed"), - expectedEvent: nil, - }, - { - name: "modify name - fails with non existent root record", - msg: nametypes.NewMsgModifyNameRequest(authority, "jackthecat", addr1, true), - expectedError: sdkerrors.ErrInvalidRequest.Wrap(nametypes.ErrNameNotBound.Error()), - expectedEvent: nil, - }, - { - name: "modify name - fails with non existent subdomain record", - msg: nametypes.NewMsgModifyNameRequest(authority, "jackthecat.name", addr1, true), - expectedError: sdkerrors.ErrInvalidRequest.Wrap(nametypes.ErrNameNotBound.Error()), - expectedEvent: nil, - }, - { - name: "modify name - fails with invalid authority", - msg: nametypes.NewMsgModifyNameRequest("jackthecat", "name", addr1, true), - expectedError: sdkerrors.ErrUnauthorized.Wrapf("expected %s or %s got %s", authority, addr1.String(), "jackthecat"), - expectedEvent: nil, - }, - { - name: "modify name - fails with empty authority", - msg: nametypes.NewMsgModifyNameRequest("", "name", addr1, true), - expectedError: sdkerrors.ErrUnauthorized.Wrapf("expected %s or %s got %s", authority, addr1.String(), ""), - expectedEvent: nil, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - response, err := handler(ctx, tc.msg) - if tc.expectedError != nil { - require.EqualError(t, err, tc.expectedError.Error()) - } else { - require.NoError(t, err) - } - if tc.expectedEvent != nil { - result := containsMessage(response, tc.expectedEvent) - require.True(t, result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) - } - }) - } -} diff --git a/x/name/keeper/msg_server_test.go b/x/name/keeper/msg_server_test.go index 5a5f3a0ef7..bcb098bff8 100644 --- a/x/name/keeper/msg_server_test.go +++ b/x/name/keeper/msg_server_test.go @@ -2,13 +2,18 @@ package keeper_test import ( "encoding/binary" + "fmt" "testing" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/gogoproto/proto" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -31,6 +36,12 @@ type MsgServerTestSuite struct { owner1Addr sdk.AccAddress acct1 sdk.AccountI + privkey2 cryptotypes.PrivKey + pubkey2 cryptotypes.PubKey + owner2 string + owner2Addr sdk.AccAddress + acct2 sdk.AccountI + addresses []sdk.AccAddress } @@ -47,12 +58,39 @@ func (s *MsgServerTestSuite) SetupTest() { s.owner1 = s.owner1Addr.String() acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.owner1Addr) s.app.AccountKeeper.SetAccount(s.ctx, acc) + + s.privkey2 = secp256k1.GenPrivKey() + s.pubkey2 = s.privkey2.PubKey() + s.owner2Addr = sdk.AccAddress(s.pubkey2.Address()) + s.owner2 = s.owner2Addr.String() + acc2 := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, s.owner2Addr) + s.app.AccountKeeper.SetAccount(s.ctx, acc2) + + var nameData types.GenesisState + nameData.Bindings = append(nameData.Bindings, types.NewNameRecord("name", s.owner1Addr, false)) + nameData.Bindings = append(nameData.Bindings, types.NewNameRecord("example.name", s.owner1Addr, false)) + nameData.Params.AllowUnrestrictedNames = false + nameData.Params.MaxNameLevels = 16 + nameData.Params.MinSegmentLength = 2 + nameData.Params.MaxSegmentLength = 16 + + s.app.NameKeeper.InitGenesis(s.ctx, nameData) } func TestMsgServerTestSuite(t *testing.T) { suite.Run(t, new(MsgServerTestSuite)) } +func (s *MsgServerTestSuite) containsMessage(events []abci.Event, msg proto.Message) bool { + for _, event := range events { + typeEvent, _ := sdk.ParseTypedEvent(event) + if assert.ObjectsAreEqual(msg, typeEvent) { + return true + } + } + return false +} + func (s *MsgServerTestSuite) TestDeleteNameRequest() { name := "jackthecat.io" s.Require().NoError(s.app.NameKeeper.SetNameRecord(s.ctx, name, s.owner1Addr, false)) @@ -142,3 +180,155 @@ func (s *MsgServerTestSuite) TestDeleteNameRemovingAttributeAccounts() { } } + +// create name record +func (s *MsgServerTestSuite) TestCreateName() { + tests := []struct { + name string + expectedError error + msg *types.MsgBindNameRequest + expectedEvent proto.Message + }{ + { + name: "create name record", + msg: types.NewMsgBindNameRequest(types.NewNameRecord("new", s.owner2Addr, false), types.NewNameRecord("example.name", s.owner1Addr, false)), + expectedError: nil, + expectedEvent: types.NewEventNameBound(s.owner2, "new.example.name", false), + }, + { + name: "create bad name record", + msg: types.NewMsgBindNameRequest(types.NewNameRecord("new", s.owner2Addr, false), types.NewNameRecord("foo.name", s.owner1Addr, false)), + expectedError: sdkerrors.ErrInvalidRequest.Wrap(types.ErrNameNotBound.Error()), + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + _, err := s.msgServer.BindName(s.ctx, tc.msg) + if tc.expectedError != nil { + s.Require().EqualError(err, tc.expectedError.Error()) + } else { + s.Require().NoError(err) + } + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Require().True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) + } + }) + } +} + +// delete name record +func (s *MsgServerTestSuite) TestDeleteName() { + tests := []struct { + name string + expectedError error + msg *types.MsgDeleteNameRequest + expectedEvent proto.Message + }{ + { + name: "delete name record", + msg: types.NewMsgDeleteNameRequest(types.NewNameRecord("example.name", s.owner1Addr, false)), + expectedError: nil, + expectedEvent: types.NewEventNameUnbound(s.owner1, "example.name", false), + }, + { + name: "create bad name record", + msg: types.NewMsgDeleteNameRequest(types.NewNameRecord("example.name", s.owner1Addr, false)), + expectedError: sdkerrors.ErrInvalidRequest.Wrap("name does not exist"), + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + _, err := s.msgServer.DeleteName(s.ctx, tc.msg) + if tc.expectedError != nil { + s.Require().EqualError(err, tc.expectedError.Error()) + } else { + s.Require().NoError(err) + } + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Require().True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) + } + }) + } +} + +func (s *MsgServerTestSuite) TestModifyName() { + authority := s.app.NameKeeper.GetAuthority() + + tests := []struct { + name string + expectedError error + msg *types.MsgModifyNameRequest + expectedEvent proto.Message + }{ + { + name: "modify name record, via gov ", + msg: types.NewMsgModifyNameRequest(authority, "name", s.owner1Addr, true), + expectedError: nil, + expectedEvent: types.NewEventNameUpdate(s.owner1, "name", true), + }, + { + name: "modify name record, via owner", + msg: types.NewMsgModifyNameRequest(s.owner1, "name", s.owner1Addr, true), + expectedError: nil, + expectedEvent: types.NewEventNameUpdate(s.owner1, "name", true), + }, + { + name: "modify name record with multi level", + msg: types.NewMsgModifyNameRequest(authority, "example.name", s.owner1Addr, true), + expectedError: nil, + expectedEvent: types.NewEventNameUpdate(s.owner1, "example.name", true), + }, + { + name: "modify name - fails with invalid address", + msg: types.NewMsgModifyNameRequest(authority, "name", sdk.AccAddress{}, true), + expectedError: sdkerrors.ErrInvalidRequest.Wrap("empty address string is not allowed"), + expectedEvent: nil, + }, + { + name: "modify name - fails with non existent root record", + msg: types.NewMsgModifyNameRequest(authority, "jackthecat", s.owner1Addr, true), + expectedError: sdkerrors.ErrInvalidRequest.Wrap(types.ErrNameNotBound.Error()), + expectedEvent: nil, + }, + { + name: "modify name - fails with non existent subdomain record", + msg: types.NewMsgModifyNameRequest(authority, "jackthecat.name", s.owner1Addr, true), + expectedError: sdkerrors.ErrInvalidRequest.Wrap(types.ErrNameNotBound.Error()), + expectedEvent: nil, + }, + { + name: "modify name - fails with invalid authority", + msg: types.NewMsgModifyNameRequest("jackthecat", "name", s.owner1Addr, true), + expectedError: sdkerrors.ErrUnauthorized.Wrapf("expected %s or %s got %s", authority, s.owner1, "jackthecat"), + expectedEvent: nil, + }, + { + name: "modify name - fails with empty authority", + msg: types.NewMsgModifyNameRequest("", "name", s.owner1Addr, true), + expectedError: sdkerrors.ErrUnauthorized.Wrapf("expected %s or %s got %s", authority, s.owner1, ""), + expectedEvent: nil, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + _, err := s.msgServer.ModifyName(s.ctx, tc.msg) + if tc.expectedError != nil { + s.Require().EqualError(err, tc.expectedError.Error()) + } else { + s.Require().NoError(err) + } + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Require().True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) + } + }) + } +} From f011a8941895e9962a80f19ad26d17be098479c2 Mon Sep 17 00:00:00 2001 From: Matt Witkowski Date: Fri, 5 Apr 2024 12:09:47 -0400 Subject: [PATCH 2/6] Adds IBC and BasicModuleManager (#1879) * Modify changelog. * Add skeleton for ibc upgrade. * Add logic for v7 upgrade. * Add param migration. * Add upgrades for ibcv8 and add logging. Updated umber tests as well * Remove ModuleBasics, and migrate ibc params. * Update changelog to account for ModuleBasics. * Fix typo in changelog. * Add signing options. * Add finalize block to make test pass and help ensure encoder/decoders are working. * Fix remaining test in app_test.go * Remove replace comment for ibc-go dependency. * Remove commented out code. * Update interfaces for modules. --- CHANGELOG.md | 2 + app/app.go | 97 +++++--------------- app/app_test.go | 15 ++- app/encoding.go | 4 - app/genesis.go | 7 -- app/test_helpers.go | 8 +- app/upgrades.go | 75 ++++++++++++++- app/upgrades_test.go | 17 +++- cmd/provenanced/cmd/root.go | 38 +++++--- cmd/provenanced/cmd/testnet_test.go | 13 ++- go.mod | 7 +- testutil/ibc/testchain.go | 2 +- testutil/network.go | 4 +- x/attribute/module.go | 10 +- x/exchange/module/module.go | 9 +- x/hold/module/module.go | 9 +- x/ibchooks/ibc_middleware_test.go | 2 +- x/ibchooks/module.go | 8 +- x/ibcratelimit/module/ibc_middleware_test.go | 2 +- x/ibcratelimit/module/module.go | 9 +- x/marker/module.go | 9 +- x/metadata/module.go | 8 +- x/msgfees/module/module.go | 9 +- x/name/module.go | 9 +- x/oracle/module/module.go | 9 +- x/reward/module/module.go | 10 +- x/trigger/module/module.go | 11 ++- 27 files changed, 242 insertions(+), 161 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c24d2a249..aaa6c6fa51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * Remove unsupported database types [#1760](https://github.com/provenance-io/provenance/issues/1760). +* Update ibc and migrate params [#1760](https://github.com/provenance-io/provenance/issues/1760). +* Replace ModuleBasics with BasicModuleManager [#1760](https://github.com/provenance-io/provenance/issues/1760). * Remove handlers from provenance modules [#1760](https://github.com/provenance-io/provenance/issues/1760). * Updated app.go to use RegisterStreamingServices on BaseApp [#1760](https://github.com/provenance-io/provenance/issues/1760). * Bump the SDK to `v0.50.5-pio-1` (from an earlier ephemeral version) [#1897](https://github.com/provenance-io/provenance/pull/1897). diff --git a/app/app.go b/app/app.go index 6e3e868ffa..39e1226c41 100644 --- a/app/app.go +++ b/app/app.go @@ -191,56 +191,6 @@ var ( // DefaultPowerReduction pio specific value for power reduction for TokensFromConsensusPower DefaultPowerReduction = sdkmath.NewIntFromUint64(1_000_000_000) - // ModuleBasics defines the module BasicManager is in charge of setting up basic, - // non-dependant module elements, such as codec registration - // and genesis verification. - ModuleBasics = module.NewBasicManager( - auth.AppModuleBasic{}, - genutil.AppModuleBasic{}, - bank.AppModuleBasic{}, - capability.AppModuleBasic{}, - staking.AppModuleBasic{}, - mint.AppModuleBasic{}, - distr.AppModuleBasic{}, - gov.NewAppModuleBasic(append( - []govclient.ProposalHandler{}, - paramsclient.ProposalHandler, - nameclient.RootNameProposalHandler, - ), - ), - params.AppModuleBasic{}, - crisis.AppModuleBasic{}, - slashing.AppModuleBasic{}, - feegrantmodule.AppModuleBasic{}, - upgrade.AppModuleBasic{}, - evidence.AppModuleBasic{}, - authzmodule.AppModuleBasic{}, - groupmodule.AppModuleBasic{}, - vesting.AppModuleBasic{}, - // quarantinemodule.AppModuleBasic{}, // TODO[1760]: quarantine - // sanctionmodule.AppModuleBasic{}, // TODO[1760]: sanction - consensus.AppModuleBasic{}, - - ibc.AppModuleBasic{}, - ibctransfer.AppModuleBasic{}, - ica.AppModuleBasic{}, - icq.AppModuleBasic{}, - ibchooks.AppModuleBasic{}, - ibcratelimitmodule.AppModuleBasic{}, - - marker.AppModuleBasic{}, - attribute.AppModuleBasic{}, - name.AppModuleBasic{}, - metadata.AppModuleBasic{}, - wasm.AppModuleBasic{}, - msgfeesmodule.AppModuleBasic{}, - rewardmodule.AppModuleBasic{}, - triggermodule.AppModuleBasic{}, - oraclemodule.AppModuleBasic{}, - holdmodule.AppModuleBasic{}, - exchangemodule.AppModuleBasic{}, - ) - // module account permissions maccPerms = map[string][]string{ authtypes.FeeCollectorName: nil, @@ -449,7 +399,7 @@ func New( app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) // set the BaseApp's parameter store - // TODO[1760]: Update upgrade handler + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]), @@ -838,25 +788,24 @@ func New( icaModule, ) - // TODO[1760]: app-module: BasicModuleManager: Make sure that this setup has everything we need (it was just copied from the SDK). // BasicModuleManager defines the module BasicManager is in charge of setting up basic, // non-dependant module elements, such as codec registration and genesis verification. // By default it is composed of all the module from the module manager. // Additionally, app module basics can be overwritten by passing them as argument. - /* - app.BasicModuleManager = module.NewBasicManagerFromManager( - app.mm, - map[string]module.AppModuleBasic{ - genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), - govtypes.ModuleName: gov.NewAppModuleBasic( - []govclient.ProposalHandler{ - paramsclient.ProposalHandler, - }, + app.BasicModuleManager = module.NewBasicManagerFromManager( + app.mm, + map[string]module.AppModuleBasic{ + genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + govtypes.ModuleName: gov.NewAppModuleBasic( + append( + []govclient.ProposalHandler{}, + paramsclient.ProposalHandler, + nameclient.RootNameProposalHandler, ), - }) - app.BasicModuleManager.RegisterLegacyAminoCodec(legacyAmino) - app.BasicModuleManager.RegisterInterfaces(interfaceRegistry) - */ + ), + }) + app.BasicModuleManager.RegisterLegacyAminoCodec(legacyAmino) + app.BasicModuleManager.RegisterInterfaces(interfaceRegistry) // NOTE: upgrade module is required to be prioritized app.mm.SetOrderPreBlockers( @@ -1299,9 +1248,8 @@ func (app *App) InterfaceRegistry() types.InterfaceRegistry { } // DefaultGenesis returns a default genesis from the registered AppModuleBasic's. -func (a *App) DefaultGenesis() map[string]json.RawMessage { - // TODO[1760] This was changed to ModuleBasics, but it will be removed - return ModuleBasics.DefaultGenesis(a.appCodec) +func (app *App) DefaultGenesis() map[string]json.RawMessage { + return app.BasicModuleManager.DefaultGenesis(app.appCodec) } // GetKey returns the KVStoreKey for the provided store key. @@ -1352,7 +1300,7 @@ func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig serverconfig.API nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register grpc-gateway routes for all modules. - ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + app.BasicModuleManager.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // register swagger API from root so that other applications can override easily if apiConfig.Swagger { @@ -1420,11 +1368,12 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino // register the key tables for legacy param subspaces keyTable := ibcclienttypes.ParamKeyTable() keyTable.RegisterParamSet(&ibcconnectiontypes.Params{}) - paramsKeeper.Subspace(ibctransfertypes.ModuleName) // TODO[1760]: params: Migrate ibc-transfer params. - paramsKeeper.Subspace(ibcexported.ModuleName) // TODO[1760]: params: Migrate ibc-host params. - paramsKeeper.Subspace(icahosttypes.SubModuleName) // TODO[1760]: params: Migrate ica-host params. - paramsKeeper.Subspace(icqtypes.ModuleName) // TODO[1760]: params: Migrate icq params. - paramsKeeper.Subspace(ibchookstypes.ModuleName) // TODO[1760]: params: Migrate ibc-hooks params. + paramsKeeper.Subspace(ibcexported.ModuleName).WithKeyTable(keyTable) + paramsKeeper.Subspace(ibctransfertypes.ModuleName).WithKeyTable(ibctransfertypes.ParamKeyTable()) + paramsKeeper.Subspace(icahosttypes.SubModuleName).WithKeyTable(icahosttypes.ParamKeyTable()) + + paramsKeeper.Subspace(icqtypes.ModuleName) // TODO[1760]: params: Migrate icq params. + paramsKeeper.Subspace(ibchookstypes.ModuleName) // TODO[1760]: params: Migrate ibc-hooks params. return paramsKeeper } diff --git a/app/app_test.go b/app/app_test.go index 6a06b08419..3a28e476a5 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -47,12 +47,17 @@ func TestSimAppExportAndBlockedAddrs(t *testing.T) { ) } + // finalize block so we have CheckTx state set + _, err := app.FinalizeBlock(&abci.RequestFinalizeBlock{ + Height: 1, + }) + require.NoError(t, err) + app.Commit() // Making a new app object with the db, so that initchain hasn't been called app2 := New(log.NewTestLogger(t), opts.DB, nil, true, - map[int64]bool{}, opts.HomePath, 0, opts.EncConfig, simtestutil.EmptyAppOptions{}) - var err error + map[int64]bool{}, opts.HomePath, 0, MakeEncodingConfig(), simtestutil.EmptyAppOptions{}) require.NotPanics(t, func() { _, err = app2.ExportAppStateAndValidators(false, nil, nil) }, "exporting app state at current height") @@ -144,6 +149,12 @@ func TestExportAppStateAndValidators(t *testing.T) { allAccounts := app.AccountKeeper.GetAllAccounts(ctx) logAccounts(t, allAccounts, "allAccounts") + // finalize block so we have CheckTx state set + _, err := app.FinalizeBlock(&abci.RequestFinalizeBlock{ + Height: 1, + }) + require.NoError(t, err) + app.Commit() // Get an export diff --git a/app/encoding.go b/app/encoding.go index 7eaf6c0f5a..68187444f4 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -2,7 +2,6 @@ package app import ( "github.com/cosmos/cosmos-sdk/std" - "github.com/provenance-io/provenance/app/params" ) @@ -14,8 +13,5 @@ func MakeEncodingConfig() params.EncodingConfig { encodingConfig := params.MakeTestEncodingConfig() std.RegisterLegacyAminoCodec(encodingConfig.Amino) std.RegisterInterfaces(encodingConfig.InterfaceRegistry) - - ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) - ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) return encodingConfig } diff --git a/app/genesis.go b/app/genesis.go index 5bf0c1da80..69e3fb3666 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -2,8 +2,6 @@ package app import ( "encoding/json" - - "github.com/cosmos/cosmos-sdk/codec" ) // The genesis state of the blockchain is represented here as a map of raw json @@ -14,8 +12,3 @@ import ( // the ModuleBasicManager which populates json from each BasicModule // object provided to it during init. type GenesisState map[string]json.RawMessage - -// NewDefaultGenesisState generates the default state for the application. -func NewDefaultGenesisState(cdc codec.JSONCodec) GenesisState { - return ModuleBasics.DefaultGenesis(cdc) -} diff --git a/app/test_helpers.go b/app/test_helpers.go index 84b40f8d12..e46685e493 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -87,7 +87,7 @@ func setup(t *testing.T, withGenesis bool, invCheckPeriod uint, chainID string) app := New(loggerMaker(), db, nil, true, map[int64]bool{}, t.TempDir(), invCheckPeriod, encCdc, simtestutil.EmptyAppOptions{}, baseapp.SetChainID(chainID)) if withGenesis { - return app, NewDefaultGenesisState(encCdc.Marshaler) + return app, app.DefaultGenesis() } return app, GenesisState{} } @@ -162,7 +162,7 @@ func NewAppWithCustomOptions(t *testing.T, isCheckTx bool, options SetupOptions) } app := New(options.Logger, options.DB, nil, true, options.SkipUpgradeHeights, options.HomePath, options.InvCheckPeriod, options.EncConfig, options.AppOpts) - genesisState := NewDefaultGenesisState(app.appCodec) + genesisState := app.DefaultGenesis() genesisState = genesisStateWithValSet(t, app, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance) if !isCheckTx { @@ -224,7 +224,7 @@ func genesisStateWithValSet(t *testing.T, bondAmt := sdk.DefaultPowerReduction for _, val := range valSet.Validators { - pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) + pk, err := cryptocodec.FromCmtPubKeyInterface(val.PubKey) require.NoError(t, err) pkAny, err := codectypes.NewAnyWithValue(pk) require.NoError(t, err) @@ -353,7 +353,7 @@ func GenesisStateWithSingleValidator(t *testing.T, app *App) GenesisState { }, } - genesisState := NewDefaultGenesisState(app.appCodec) + genesisState := app.DefaultGenesis() genesisState = genesisStateWithValSet(t, app, genesisState, valSet, []authtypes.GenesisAccount{acc}, balances...) return genesisState diff --git a/app/upgrades.go b/app/upgrades.go index 0295093106..be81e0c7b0 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -9,15 +9,17 @@ import ( storetypes "cosmossdk.io/store/types" upgradetypes "cosmossdk.io/x/upgrade/types" - icqtypes "github.com/cosmos/ibc-apps/modules/async-icq/v8/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + icqtypes "github.com/cosmos/ibc-apps/modules/async-icq/v8/types" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctmmigrations "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint/migrations" "github.com/provenance-io/provenance/x/exchange" "github.com/provenance-io/provenance/x/hold" ibchookstypes "github.com/provenance-io/provenance/x/ibchooks/types" @@ -168,11 +170,26 @@ var upgrades = map[string]appUpgrade{ Added: []string{crisistypes.ModuleName}, Handler: func(ctx sdk.Context, app *App, vm module.VersionMap) (module.VersionMap, error) { var err error + + if err := pruneIBCExpiredConsensusStates(ctx, app); err != nil { + return nil, err + } + + err = migrateBaseappParams(ctx, app) + if err != nil { + return nil, err + } + vm, err = runModuleMigrations(ctx, app, vm) if err != nil { return nil, err } + err = updateIBCClients(ctx, app) + if err != nil { + return nil, err + } + removeInactiveValidatorDelegations(ctx, app) return vm, nil @@ -182,11 +199,26 @@ var upgrades = map[string]appUpgrade{ Added: []string{crisistypes.ModuleName}, Handler: func(ctx sdk.Context, app *App, vm module.VersionMap) (module.VersionMap, error) { var err error + + if err := pruneIBCExpiredConsensusStates(ctx, app); err != nil { + return nil, err + } + + err = migrateBaseappParams(ctx, app) + if err != nil { + return nil, err + } + vm, err = runModuleMigrations(ctx, app, vm) if err != nil { return nil, err } + err = updateIBCClients(ctx, app) + if err != nil { + return nil, err + } + removeInactiveValidatorDelegations(ctx, app) return vm, nil @@ -447,6 +479,43 @@ func updateIbcMarkerDenomMetadata(ctx sdk.Context, app *App) { ctx.Logger().Info("Done updating ibc marker denom metadata") } +// pruneIBCExpiredConsensusStates prunes expired consensus states for IBC. +func pruneIBCExpiredConsensusStates(ctx sdk.Context, app *App) error { + ctx.Logger().Info("Pruning expired consensus states for IBC.") + _, err := ibctmmigrations.PruneExpiredConsensusStates(ctx, app.appCodec, app.IBCKeeper.ClientKeeper) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("unable to prune expired consensus states, error: %s.", err)) + return err + } + ctx.Logger().Info("Done pruning expired consensus states for IBC.") + return nil +} + +// updateIBCClients updates the allowed clients for IBC. +// TODO: Remove with the umber handlers. +func updateIBCClients(ctx sdk.Context, app *App) error { + ctx.Logger().Info("Updating IBC AllowedClients.") + params := app.IBCKeeper.ClientKeeper.GetParams(ctx) + params.AllowedClients = append(params.AllowedClients, exported.Localhost) + app.IBCKeeper.ClientKeeper.SetParams(ctx, params) + ctx.Logger().Info("Done updating IBC AllowedClients.") + return nil +} + +// migrateBaseappParams migrates to new ConsensusParamsKeeper +// TODO: Remove with the umber handlers. +func migrateBaseappParams(ctx sdk.Context, app *App) error { + ctx.Logger().Info("Migrating legacy params.") + legacyBaseAppSubspace := app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable()) + err := baseapp.MigrateParams(ctx, legacyBaseAppSubspace, app.ConsensusParamsKeeper.ParamsStore) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("unable to migrate legacy params to ConsensusParamsKeeper, error: %s.", err)) + return err + } + ctx.Logger().Info("Done migrating legacy params.") + return nil +} + // convertNavUnits iterates all the net asset values and updates their units if they are using usd. // TODO: Remove with the tourmaline handlers. func convertNavUnits(ctx sdk.Context, app *App) { diff --git a/app/upgrades_test.go b/app/upgrades_test.go index f9a0e46bc2..b33292fed3 100644 --- a/app/upgrades_test.go +++ b/app/upgrades_test.go @@ -479,6 +479,12 @@ func (s *UpgradeTestSuite) TestTourmaline() { func (s *UpgradeTestSuite) TestUmberRC1() { expInLog := []string{ + "INF Pruning expired consensus states for IBC.", + "INF Done pruning expired consensus states for IBC.", + "INF Migrating legacy params.", + "INF Done migrating legacy params.", + "INF Updating IBC AllowedClients.", + "INF Done updating IBC AllowedClients.", "INF Starting module migrations. This may take a significant amount of time to complete. Do not restart node.", "INF removing all delegations from validators that have been inactive (unbonded) for 21 days", } @@ -487,7 +493,16 @@ func (s *UpgradeTestSuite) TestUmberRC1() { } func (s *UpgradeTestSuite) TestUmber() { - expInLog := []string{} + expInLog := []string{ + "INF Pruning expired consensus states for IBC.", + "INF Done pruning expired consensus states for IBC.", + "INF Migrating legacy params.", + "INF Done migrating legacy params.", + "INF Updating IBC AllowedClients.", + "INF Done updating IBC AllowedClients.", + "INF Starting module migrations. This may take a significant amount of time to complete. Do not restart node.", + "INF removing all delegations from validators that have been inactive (unbonded) for 21 days", + } s.AssertUpgradeHandlerLogs("umber", expInLog, nil) } diff --git a/cmd/provenanced/cmd/root.go b/cmd/provenanced/cmd/root.go index 43a2388a6b..09b7c52b22 100644 --- a/cmd/provenanced/cmd/root.go +++ b/cmd/provenanced/cmd/root.go @@ -37,7 +37,9 @@ import ( "github.com/cosmos/cosmos-sdk/server" serverconfig "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/tx/signing" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -65,7 +67,21 @@ const ( // NewRootCmd creates a new root command for provenanced. It is called once in the main function. // Providing sealConfig = false is only for unit tests that want to run multiple commands. func NewRootCmd(sealConfig bool) (*cobra.Command, params.EncodingConfig) { + // tempDir creates a temporary home directory. + tempDir, err := os.MkdirTemp("", "provenanced") + if err != nil { + panic(fmt.Errorf("failed to create temp dir: %w", err)) + } + os.RemoveAll(tempDir) + encodingConfig := app.MakeEncodingConfig() + tempApp := app.New(log.NewNopLogger(), dbm.NewMemDB(), nil, true, nil, + tempDir, + 0, + encodingConfig, + simtestutil.EmptyAppOptions{}, + ) + initClientCtx := client.Context{}. WithCodec(encodingConfig.Marshaler). WithInterfaceRegistry(encodingConfig.InterfaceRegistry). @@ -137,7 +153,7 @@ func NewRootCmd(sealConfig bool) (*cobra.Command, params.EncodingConfig) { }, } genAutoCompleteCmd(rootCmd) - initRootCmd(rootCmd, encodingConfig) + initRootCmd(rootCmd, encodingConfig, tempApp.BasicModuleManager) overwriteFlagDefaults(rootCmd, map[string]string{ flags.FlagChainID: "", flags.FlagKeyringBackend: "test", @@ -172,12 +188,12 @@ func Execute(rootCmd *cobra.Command) error { return executor.ExecuteContext(ctx) } -func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { +func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, basicManager module.BasicManager) { rootCmd.AddCommand( - InitCmd(app.ModuleBasics), + InitCmd(basicManager), // genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome), // TODO[1760]: genutil // genutilcli.GenTxCmd(app.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome), // TODO[1760]: genutil - genutilcli.ValidateGenesisCmd(app.ModuleBasics), + genutilcli.ValidateGenesisCmd(basicManager), AddGenesisAccountCmd(app.DefaultNodeHome), AddRootDomainAccountCmd(app.DefaultNodeHome), AddGenesisMarkerCmd(app.DefaultNodeHome), @@ -186,7 +202,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { AddGenesisDefaultMarketCmd(app.DefaultNodeHome), AddGenesisCustomMarketCmd(app.DefaultNodeHome), cmtcli.NewCompletionCmd(rootCmd, true), - testnetCmd(app.ModuleBasics, banktypes.GenesisBalancesIterator{}), + testnetCmd(basicManager, banktypes.GenesisBalancesIterator{}), debug.Cmd(), ConfigCmd(), AddMetaAddressCmd(), @@ -202,8 +218,8 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { // add keybase, auxiliary RPC, query, and tx child commands rootCmd.AddCommand( server.StatusCommand(), - queryCommand(), - txCommand(), + queryCommand(basicManager), + txCommand(basicManager), keys.Commands(), ) @@ -257,7 +273,7 @@ func addModuleInitFlags(startCmd *cobra.Command) { crisis.AddModuleInitFlags(startCmd) } -func queryCommand() *cobra.Command { +func queryCommand(basicManager module.BasicManager) *cobra.Command { cmd := &cobra.Command{ Use: "query", Aliases: []string{"q"}, @@ -275,13 +291,13 @@ func queryCommand() *cobra.Command { authcmd.QueryTxCmd(), ) - app.ModuleBasics.AddQueryCommands(cmd) + basicManager.AddQueryCommands(cmd) cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") return cmd } -func txCommand() *cobra.Command { +func txCommand(basicManager module.BasicManager) *cobra.Command { cmd := &cobra.Command{ Use: "tx", Short: "Transactions subcommands", @@ -303,7 +319,7 @@ func txCommand() *cobra.Command { flags.LineBreak, ) - app.ModuleBasics.AddTxCommands(cmd) + basicManager.AddTxCommands(cmd) cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") return cmd diff --git a/cmd/provenanced/cmd/testnet_test.go b/cmd/provenanced/cmd/testnet_test.go index 1c7f43368a..bf12ce5e44 100644 --- a/cmd/provenanced/cmd/testnet_test.go +++ b/cmd/provenanced/cmd/testnet_test.go @@ -11,9 +11,11 @@ import ( "cosmossdk.io/log" + dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" @@ -29,9 +31,16 @@ func Test_TestnetCmd(t *testing.T) { pioconfig.SetProvenanceConfig("", 0) logger := log.NewNopLogger() cfg, err := genutiltest.CreateDefaultCometConfig(home) + tempApp := app.New(log.NewNopLogger(), dbm.NewMemDB(), nil, true, nil, + home, + 0, + encodingConfig, + simtestutil.EmptyAppOptions{}, + ) + require.NoError(t, err) - err = genutiltest.ExecInitCmd(app.ModuleBasics, home, encodingConfig.Marshaler) + err = genutiltest.ExecInitCmd(tempApp.BasicModuleManager, home, encodingConfig.Marshaler) require.NoError(t, err) serverCtx := server.NewContext(viper.New(), cfg, logger) @@ -43,7 +52,7 @@ func Test_TestnetCmd(t *testing.T) { ctx := context.Background() ctx = context.WithValue(ctx, server.ServerContextKey, serverCtx) ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) - cmd := testnetCmd(app.ModuleBasics, banktypes.GenesisBalancesIterator{}) + cmd := testnetCmd(tempApp.BasicModuleManager, banktypes.GenesisBalancesIterator{}) cmd.SetArgs([]string{fmt.Sprintf("--%s=test", flags.FlagKeyringBackend), fmt.Sprintf("--output-dir=%s", home)}) err = cmd.ExecuteContext(ctx) require.NoError(t, err) diff --git a/go.mod b/go.mod index 5a4e33b609..b16fd9b0ac 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/provenance-io/provenance go 1.21 require ( + cosmossdk.io/core v0.11.0 cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.3.1 cosmossdk.io/math v1.3.0 @@ -32,6 +33,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/go-metrics v0.5.2 github.com/rakyll/statik v0.1.7 + github.com/regen-network/cosmos-proto v0.3.1 // TODO[1760]: Verify that this is still needed github.com/rs/zerolog v1.32.0 github.com/spf13/cast v1.6.0 github.com/spf13/cobra v1.8.0 @@ -46,8 +48,6 @@ require ( gopkg.in/yaml.v2 v2.4.0 ) -require github.com/regen-network/cosmos-proto v0.3.1 - require ( cloud.google.com/go v0.112.0 // indirect cloud.google.com/go/compute v1.24.0 // indirect @@ -57,7 +57,6 @@ require ( cosmossdk.io/api v0.7.3 // indirect cosmossdk.io/client/v2 v2.0.0-beta.1 // indirect cosmossdk.io/collections v0.4.0 // indirect - cosmossdk.io/core v0.11.0 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect cosmossdk.io/x/circuit v0.1.0 // indirect cosmossdk.io/x/nft v0.1.0 // indirect @@ -224,8 +223,6 @@ replace ( // TODO[1760]: Update once async-icq creates tag with our changes https://github.com/cosmos/ibc-apps/pull/168 github.com/cosmos/ibc-apps/modules/async-icq/v8 => github.com/provenance-io/ibc-apps/modules/async-icq/v8 v8.0.0-prov-1 - // TODO[1760]: ibc: Put this ibc-go replace back with an updated version (or delete it). - // github.com/cosmos/ibc-go/v6 => github.com/provenance-io/ibc-go/v6 v6.2.0-pio-1 // dgrijalva/jwt-go is deprecated and doesn't receive security updates. // TODO: remove it: https://github.com/cosmos/cosmos-sdk/issues/13134 github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2 diff --git a/testutil/ibc/testchain.go b/testutil/ibc/testchain.go index 2352ecaba3..85016678ce 100644 --- a/testutil/ibc/testchain.go +++ b/testutil/ibc/testchain.go @@ -28,7 +28,7 @@ type TestChain struct { func SetupTestingApp(t *testing.T) (ibctesting.TestingApp, map[string]json.RawMessage) { provenanceApp := provenanceapp.Setup(t) - return provenanceApp, provenanceapp.NewDefaultGenesisState(provenanceApp.AppCodec()) + return provenanceApp, provenanceApp.DefaultGenesis() } func (chain *TestChain) StoreContractCounterDirect(suite *suite.Suite) uint64 { diff --git a/testutil/network.go b/testutil/network.go index 7d977e5547..64eb72e3c8 100644 --- a/testutil/network.go +++ b/testutil/network.go @@ -41,6 +41,8 @@ func NewAppConstructor(encodingCfg params.EncodingConfig) testnet.AppConstructor // DefaultTestNetworkConfig creates a network configuration for inproc testing func DefaultTestNetworkConfig() testnet.Config { encCfg := provenanceapp.MakeEncodingConfig() + tempApp := NewAppConstructor(encCfg)(nil).(*provenanceapp.App) + return testnet.Config{ Codec: encCfg.Marshaler, TxConfig: encCfg.TxConfig, @@ -48,7 +50,7 @@ func DefaultTestNetworkConfig() testnet.Config { InterfaceRegistry: encCfg.InterfaceRegistry, AccountRetriever: authtypes.AccountRetriever{}, AppConstructor: NewAppConstructor(encCfg), - GenesisState: provenanceapp.ModuleBasics.DefaultGenesis(encCfg.Marshaler), + GenesisState: tempApp.DefaultGenesis(), TimeoutCommit: 2 * time.Second, ChainID: "chain-" + cmtrand.NewRand().Str(6), NumValidators: 4, diff --git a/x/attribute/module.go b/x/attribute/module.go index f1d4bcfdda..d2a5534476 100644 --- a/x/attribute/module.go +++ b/x/attribute/module.go @@ -11,6 +11,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" + "cosmossdk.io/core/appmodule" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -28,10 +29,11 @@ import ( ) var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModule{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) + _ appmodule.HasBeginBlocker = (*AppModule)(nil) ) // AppModuleBasic contains non-dependent elements for the attribute module. diff --git a/x/exchange/module/module.go b/x/exchange/module/module.go index a1f399d199..99f4d7d5f8 100644 --- a/x/exchange/module/module.go +++ b/x/exchange/module/module.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand" + "cosmossdk.io/core/appmodule" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -25,10 +26,10 @@ import ( ) var ( - _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModule = AppModule{} - _ module.AppModuleSimulation = AppModule{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) ) type AppModuleBasic struct { diff --git a/x/hold/module/module.go b/x/hold/module/module.go index 404e7dcc47..40f1d8ba69 100644 --- a/x/hold/module/module.go +++ b/x/hold/module/module.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand" + "cosmossdk.io/core/appmodule" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -25,10 +26,10 @@ import ( ) var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModule{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) ) type AppModule struct { diff --git a/x/ibchooks/ibc_middleware_test.go b/x/ibchooks/ibc_middleware_test.go index 55269db451..119fb8c589 100644 --- a/x/ibchooks/ibc_middleware_test.go +++ b/x/ibchooks/ibc_middleware_test.go @@ -82,7 +82,7 @@ func SetupSimApp() (ibctesting.TestingApp, map[string]json.RawMessage) { db := dbm.NewMemDB() encCdc := app.MakeEncodingConfig() provenanceApp := app.New(log.NewNopLogger(), db, nil, true, map[int64]bool{}, app.DefaultNodeHome, 5, encCdc, simtestutil.EmptyAppOptions{}) - genesis := app.NewDefaultGenesisState(encCdc.Marshaler) + genesis := provenanceApp.DefaultGenesis() return provenanceApp, genesis } diff --git a/x/ibchooks/module.go b/x/ibchooks/module.go index 936bd5650a..a7f40b527b 100644 --- a/x/ibchooks/module.go +++ b/x/ibchooks/module.go @@ -5,6 +5,7 @@ import ( "fmt" "math/rand" + "cosmossdk.io/core/appmodule" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -26,9 +27,10 @@ import ( ) var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) ) // AppModuleBasic defines the basic application module used by the ibchooks module. diff --git a/x/ibcratelimit/module/ibc_middleware_test.go b/x/ibcratelimit/module/ibc_middleware_test.go index ff4dcb44eb..61a0c12385 100644 --- a/x/ibcratelimit/module/ibc_middleware_test.go +++ b/x/ibcratelimit/module/ibc_middleware_test.go @@ -54,7 +54,7 @@ func SetupSimApp() (ibctesting.TestingApp, map[string]json.RawMessage) { db := dbm.NewMemDB() encCdc := app.MakeEncodingConfig() provenanceApp := app.New(log.NewNopLogger(), db, nil, true, map[int64]bool{}, app.DefaultNodeHome, 5, encCdc, simtestutil.EmptyAppOptions{}) - genesis := app.NewDefaultGenesisState(encCdc.Marshaler) + genesis := provenanceApp.DefaultGenesis() return provenanceApp, genesis } diff --git a/x/ibcratelimit/module/module.go b/x/ibcratelimit/module/module.go index ecdad2a450..01e51d9f42 100644 --- a/x/ibcratelimit/module/module.go +++ b/x/ibcratelimit/module/module.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand" + "cosmossdk.io/core/appmodule" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -28,10 +29,10 @@ import ( ) var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModule{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) ) // AppModuleBasic defines the basic application module used by the ibcratelimit module. diff --git a/x/marker/module.go b/x/marker/module.go index 730b3f1328..e36cd4be88 100644 --- a/x/marker/module.go +++ b/x/marker/module.go @@ -11,6 +11,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" + "cosmossdk.io/core/appmodule" feegrantkeeper "cosmossdk.io/x/feegrant/keeper" "github.com/cosmos/cosmos-sdk/client" @@ -31,9 +32,11 @@ import ( // type check to ensure the interface is properly implemented var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) + _ appmodule.HasBeginBlocker = (*AppModule)(nil) ) // AppModuleBasic contains non-dependent elements for the marker module. diff --git a/x/metadata/module.go b/x/metadata/module.go index f83e94887d..a67d1b40eb 100644 --- a/x/metadata/module.go +++ b/x/metadata/module.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand" + "cosmossdk.io/core/appmodule" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -36,9 +37,10 @@ const StoreKey = types.StoreKey // type check to ensure the interface is properly implemented var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) ) // AppModuleBasic contains non-dependent elements for the metadata module. diff --git a/x/msgfees/module/module.go b/x/msgfees/module/module.go index de827fdf2b..8b680268eb 100644 --- a/x/msgfees/module/module.go +++ b/x/msgfees/module/module.go @@ -10,6 +10,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" + "cosmossdk.io/core/appmodule" cerrs "cosmossdk.io/errors" sdkclient "github.com/cosmos/cosmos-sdk/client" @@ -26,10 +27,10 @@ import ( ) var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModule{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) ) // AppModuleBasic defines the basic application module used by the msgfee module. diff --git a/x/name/module.go b/x/name/module.go index dec09cd7a8..ea37c1656b 100644 --- a/x/name/module.go +++ b/x/name/module.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand" + "cosmossdk.io/core/appmodule" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -28,10 +29,10 @@ import ( // type check to ensure the interface is properly implemented var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModule{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) ) // AppModuleBasic contains non-dependent elements for the name module. diff --git a/x/oracle/module/module.go b/x/oracle/module/module.go index 2a823db534..5b7b3e9543 100644 --- a/x/oracle/module/module.go +++ b/x/oracle/module/module.go @@ -11,6 +11,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" + "cosmossdk.io/core/appmodule" cerrs "cosmossdk.io/errors" sdkclient "github.com/cosmos/cosmos-sdk/client" @@ -30,10 +31,10 @@ import ( ) var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModule{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) ) // AppModuleBasic defines the basic application module used by the oracle module. diff --git a/x/reward/module/module.go b/x/reward/module/module.go index a427f916f6..1fb2730042 100644 --- a/x/reward/module/module.go +++ b/x/reward/module/module.go @@ -11,6 +11,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" + "cosmossdk.io/core/appmodule" cerrs "cosmossdk.io/errors" sdkclient "github.com/cosmos/cosmos-sdk/client" @@ -30,9 +31,12 @@ import ( ) var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) + _ appmodule.HasBeginBlocker = (*AppModule)(nil) + _ appmodule.HasEndBlocker = (*AppModule)(nil) ) // AppModuleBasic defines the basic application module used by the reward module. diff --git a/x/trigger/module/module.go b/x/trigger/module/module.go index 977a574237..fdd8401471 100644 --- a/x/trigger/module/module.go +++ b/x/trigger/module/module.go @@ -11,6 +11,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" + "cosmossdk.io/core/appmodule" cerrs "cosmossdk.io/errors" sdkclient "github.com/cosmos/cosmos-sdk/client" @@ -30,10 +31,12 @@ import ( ) var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModule{} - // TODO[1760]: app-module: Add more assertions for the new types and clean up stuff no longer needed. + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) + _ appmodule.HasBeginBlocker = (*AppModule)(nil) + _ appmodule.HasEndBlocker = (*AppModule)(nil) ) // AppModuleBasic defines the basic application module used by the trigger module. From f8b66d4722c2ccf652b3b18ff7bd3e41f14e4844 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 12:05:44 -0600 Subject: [PATCH 3/6] Bump github.com/cosmos/ibc-go/v8 from 8.0.0 to 8.2.0 (#1910) * Bump github.com/cosmos/ibc-go/v8 from 8.0.0 to 8.2.0 Bumps [github.com/cosmos/ibc-go/v8](https://github.com/cosmos/ibc-go) from 8.0.0 to 8.2.0. - [Release notes](https://github.com/cosmos/ibc-go/releases) - [Changelog](https://github.com/cosmos/ibc-go/blob/v8.2.0/CHANGELOG.md) - [Commits](https://github.com/cosmos/ibc-go/compare/v8.0.0...v8.2.0) --- updated-dependencies: - dependency-name: github.com/cosmos/ibc-go/v8 dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Updated Changelog * Put dependencies section in correct place in changelog. --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] Co-authored-by: Daniel Wedul --- CHANGELOG.md | 4 ++++ go.mod | 4 ++-- go.sum | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aaa6c6fa51..f8f1b5f6fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * Updated app.go to use RegisterStreamingServices on BaseApp [#1760](https://github.com/provenance-io/provenance/issues/1760). * Bump the SDK to `v0.50.5-pio-1` (from an earlier ephemeral version) [#1897](https://github.com/provenance-io/provenance/pull/1897). +### Dependencies + +- Bump `github.com/cosmos/ibc-go/v8` from 8.0.0 to 8.2.0 ([#1910](https://github.com/provenance-io/provenance/pull/1910)) + --- ## [v1.18.0](https://github.com/provenance-io/provenance/releases/tag/v1.18.0) - 2024-03-22 diff --git a/go.mod b/go.mod index b16fd9b0ac..a63966b1cb 100644 --- a/go.mod +++ b/go.mod @@ -19,12 +19,12 @@ require ( github.com/cometbft/cometbft-db v0.9.1 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-proto v1.0.0-beta.4 - github.com/cosmos/cosmos-sdk v0.50.4 + github.com/cosmos/cosmos-sdk v0.50.5 github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/gogoproto v1.4.12 github.com/cosmos/ibc-apps/modules/async-icq/v8 v8.0.0 github.com/cosmos/ibc-go/modules/capability v1.0.0 - github.com/cosmos/ibc-go/v8 v8.0.0 + github.com/cosmos/ibc-go/v8 v8.2.0 // github.com/cosmos/rosetta v0.50.2 // TODO[1760]: rosetta github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.4 diff --git a/go.sum b/go.sum index eb9f9d594b..c7e5f449ea 100644 --- a/go.sum +++ b/go.sum @@ -372,8 +372,8 @@ github.com/cosmos/iavl v1.0.1 h1:D+mYbcRO2wptYzOM1Hxl9cpmmHU1ZEt9T2Wv5nZTeUw= github.com/cosmos/iavl v1.0.1/go.mod h1:8xIUkgVvwvVrBu81scdPty+/Dx9GqwHnAvXz4cwF7RY= github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE= github.com/cosmos/ibc-go/modules/capability v1.0.0/go.mod h1:D81ZxzjZAe0ZO5ambnvn1qedsFQ8lOwtqicG6liLBco= -github.com/cosmos/ibc-go/v8 v8.0.0 h1:QKipnr/NGwc+9L7NZipURvmSIu+nw9jOIWTJuDBqOhg= -github.com/cosmos/ibc-go/v8 v8.0.0/go.mod h1:C6IiJom0F3cIQCD5fKwVPDrDK9j/xTu563AWuOmXois= +github.com/cosmos/ibc-go/v8 v8.2.0 h1:7oCzyy1sZCcgpeQLnHxC56brsSz3KWwQGKXalXwXFzE= +github.com/cosmos/ibc-go/v8 v8.2.0/go.mod h1:wj3qx75iC/XNnsMqbPDCIGs0G6Y3E/lo3bdqCyoCy+8= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= From 588165be10771a7d9e6e69673a4e0d66eeb4c97c Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 5 Apr 2024 14:03:56 -0600 Subject: [PATCH 4/6] Always run the build/release actions and split test building into parts. (#1911) * Update the build/release github action: Re-enable the provenanced version steps. Always run the actions, but skip the actual build steps in the cases where we were previously skipping these actions altogether. * Split the build tests stuff into 4 parts like the normal tests. * Add a change to a .go file. * Add a checkout to the build init so the diff has something to look at. * Put the release github action back like it was, but still re-enable the provenanced version steps and also remove the step that builds the tests. * Remove temporary .go change. --- .github/workflows/release.yml | 7 ------- .github/workflows/test.yml | 13 +++++++++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 01654ed50b..6a60d66c68 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,8 +74,6 @@ jobs: export VERSION=${{ needs.build_init.outputs.version }} make build-release-zip - name: Provenanced version - # TODO[1760]: github: Re-enable the build_osx provenanced version step. - if: false run: build/provenanced version --long - uses: actions/upload-artifact@v4 with: @@ -105,12 +103,7 @@ jobs: export VERSION=${{ needs.build_init.outputs.version }} make build-release-zip - name: Provenanced version - # TODO[1760]: github: Re-enable the build_linux provenanced version step. - if: false run: build/provenanced version --long - - name: Compile Tests - # TODO[1760]: github: Delete this build_linux Compile Tests step. - run: go test -mod=readonly -timeout 30m -tags='norace ledger test_ledger_mock' -run='ZYX_NOT_A_REAL_TEST_XZY' ./... - uses: actions/upload-artifact@v4 with: name: linux-zip diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b87d5bd3d2..de7911bf50 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -112,16 +112,25 @@ jobs: build-tests: # TODO[1760]: Delete this build-tests action once the tests reliably pass again. needs: setup-tests + strategy: + fail-fast: false + matrix: + part: ["00", "01", "02", "03"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 if: needs.setup-tests.outputs.should-run with: go-version: ${{ needs.setup-tests.outputs.go-version }} + - uses: actions/download-artifact@v4 + if: needs.setup-tests.outputs.should-run + with: + name: "${{ needs.setup-tests.outputs.file-prefix }}-pkgs.txt.part.${{ matrix.part }}" - name: build tests + if: needs.setup-tests.outputs.should-run run: | - make build-tests + cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -timeout 30m -tags='norace ledger test_ledger_mock' -run='ZYX_NOPE_NOPE_XYZ' # This action performs a code coverage assessment but filters out generated code from proto based types # and grpc services From 90a9107e54ea334f3f013fad603367415f8f5954 Mon Sep 17 00:00:00 2001 From: provenanceio-bot <129784868+provenanceio-bot@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:12:28 -0600 Subject: [PATCH 5/6] Update buf.lock to latest commit hash (#1909) --- proto/buf.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proto/buf.lock b/proto/buf.lock index 5960a61c80..a9ec930f8d 100644 --- a/proto/buf.lock +++ b/proto/buf.lock @@ -4,5 +4,5 @@ deps: - remote: buf.build owner: provenance-io repository: third-party - commit: 818c7496178046068768c0fea57c046c - digest: shake256:044c2e28d3e5f8932435d992d90497bf2b81056938f03d054b2e04ec03502b182ef00f83bbcef26f3028457450f5eafec72a2e406b4436da28521b4238ee6e5f + commit: 5423d1b01b7e47fd94d5743632695951 + digest: shake256:352e660d08ed3a6d1277631b0c53d59d2832c7c03ee6f8ef65b50f33b644e96ebdc55e3cf8480a6992dc4596cfe2bc18eded0a01db3559f2de3760cb17ceb05f From 0583a639240e3ff2d4e208ac2315c650e31758c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 20:18:29 +0000 Subject: [PATCH 6/6] Bump google.golang.org/grpc from 1.62.1 to 1.63.0 (#1903) * Bump google.golang.org/grpc from 1.62.1 to 1.63.0 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.62.1 to 1.63.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.62.1...v1.63.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Updated Changelog * Put dependencies section in correct place in changelog. --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] Co-authored-by: Daniel Wedul --- CHANGELOG.md | 1 + go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8f1b5f6fc..273884ddf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies - Bump `github.com/cosmos/ibc-go/v8` from 8.0.0 to 8.2.0 ([#1910](https://github.com/provenance-io/provenance/pull/1910)) +- Bump `google.golang.org/grpc` from 1.62.1 to 1.63.0 ([#1903](https://github.com/provenance-io/provenance/pull/1903)) --- diff --git a/go.mod b/go.mod index a63966b1cb..3d74a7d0ab 100644 --- a/go.mod +++ b/go.mod @@ -42,8 +42,8 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 golang.org/x/text v0.14.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 - google.golang.org/grpc v1.62.1 + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de + google.golang.org/grpc v1.63.0 google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -194,15 +194,15 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.19.0 // indirect golang.org/x/net v0.21.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/term v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.162.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect diff --git a/go.sum b/go.sum index c7e5f449ea..25c4cefc9f 100644 --- a/go.sum +++ b/go.sum @@ -1230,8 +1230,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1621,12 +1621,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1668,8 +1668,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= +google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=