diff --git a/proto/regen/ecocredit/v1/tx.proto b/proto/regen/ecocredit/v1/tx.proto index 84ea41c7f1..49182bab1e 100644 --- a/proto/regen/ecocredit/v1/tx.proto +++ b/proto/regen/ecocredit/v1/tx.proto @@ -157,8 +157,8 @@ service Msg { // the scope of the provided credit class, the credits will be minted to the // existing credit batch, otherwise the credits will be issued in a new credit // batch. The new credit batch will be created under an existing project if a - // project with a matching reference id already exists within the scope of the - // credit class, otherwise a new project will be created. + // project with a matching reference id already exists, otherwise a new project + // will be created. rpc BridgeReceive(MsgBridgeReceive) returns (MsgBridgeReceiveResponse); // AddCreditType is a governance method that allows the addition of new diff --git a/x/ecocredit/base/keeper/features/msg_create_project.feature b/x/ecocredit/base/keeper/features/msg_create_project.feature index faa4ffe721..47174400ae 100644 --- a/x/ecocredit/base/keeper/features/msg_create_project.feature +++ b/x/ecocredit/base/keeper/features/msg_create_project.feature @@ -4,7 +4,6 @@ Feature: CreateProject - when the credit class exists - when the admin is an allowed credit class issuer - when the non-empty reference id is unique within the scope of the credit class - - the project sequence is updated - the project properties are added - the response includes the project id @@ -55,26 +54,7 @@ Feature: CreateProject Scenario: non-empty reference id is not unique within credit class Given a project with project id "C01-001" and reference id "VCS-001" When alice attempts to create a project with class id "C01" and reference id "VCS-001" - Then expect the error "a project with reference id VCS-001 already exists within this credit class: invalid request" - - Rule: the project sequence is updated - - Background: - Given a credit type with abbreviation "C" - And a credit class with class id "C01" and issuer alice - And a credit class with class id "C02" and issuer alice - - Scenario: the project sequence is updated - Given a project sequence with class id "C01" and next sequence "1" - When alice attempts to create a project with class id "C01" - Then expect project sequence with class id "C01" and next sequence "2" - - Scenario: the project sequence is not updated - Given a project sequence with class id "C01" and next sequence "1" - When alice attempts to create a project with class id "C02" - Then expect project sequence with class id "C01" and next sequence "1" - - # no failing scenario - state transitions only occur upon successful message execution + Then expect the error "a project with reference id VCS-001 already exists: invalid request" Rule: the project properties are added @@ -115,7 +95,7 @@ Feature: CreateProject Then expect the response """ { - "project_id": "C01-001" + "project_id": "P001" } """ @@ -132,6 +112,6 @@ Feature: CreateProject Then expect event with properties """ { - "project_id": "C01-001" + "project_id": "P001" } """ diff --git a/x/ecocredit/base/keeper/msg_create_project.go b/x/ecocredit/base/keeper/msg_create_project.go index 124bd08a05..ac6b6282bf 100644 --- a/x/ecocredit/base/keeper/msg_create_project.go +++ b/x/ecocredit/base/keeper/msg_create_project.go @@ -39,8 +39,8 @@ func (k Keeper) CreateProject(ctx context.Context, req *types.MsgCreateProject) return nil, err } - // check if non-empty reference id is unique within the scope of the credit class - err = k.verifyReferenceID(ctx, classInfo.Key, req.ReferenceId) + // check if non-empty reference id is unique across all projects + err = k.verifyReferenceID(ctx, req.ReferenceId) if err != nil { return nil, err } @@ -94,17 +94,17 @@ func (k Keeper) createNewProject(ctx context.Context) (*api.Project, string, err return newProject, projectID, nil } -// verifyReferenceID prevents multiple projects from having the same reference id within the -// scope of a credit class. We verify this here at the message server level rather than at the -// ORM level because reference id is optional and therefore multiple projects within the scope -// of a credit class can have an empty reference id (see BridgeReceive for more information) -func (k Keeper) verifyReferenceID(ctx context.Context, classKey uint64, referenceID string) error { +// verifyReferenceID prevents multiple projects from having the same reference id. +// We verify this here at the message server level rather than at the +// ORM level because reference id is optional any project can have an empty reference id. +// (see BridgeReceive for more information) +func (k Keeper) verifyReferenceID(ctx context.Context, referenceID string) error { if referenceID == "" { // reference id is optional so an empty reference id is valid return nil } - key := api.ProjectClassKeyReferenceIdIndexKey{}.WithClassKeyReferenceId(classKey, referenceID) + key := api.ProjectReferenceIdIndexKey{}.WithReferenceId(referenceID) it, err := k.stateStore.ProjectTable().List(ctx, key) if err != nil { return err @@ -112,8 +112,7 @@ func (k Keeper) verifyReferenceID(ctx context.Context, classKey uint64, referenc defer it.Close() if it.Next() { return sdkerrors.ErrInvalidRequest.Wrapf( - "a project with reference id %s already exists within this credit class", referenceID, - ) + "a project with reference id %s already exists", referenceID) } return nil diff --git a/x/ecocredit/base/keeper/msg_create_project_test.go b/x/ecocredit/base/keeper/msg_create_project_test.go index 5b2f24b007..591f5b78c3 100644 --- a/x/ecocredit/base/keeper/msg_create_project_test.go +++ b/x/ecocredit/base/keeper/msg_create_project_test.go @@ -3,8 +3,6 @@ package keeper import ( "encoding/json" - "strconv" - "strings" "testing" "github.com/gogo/protobuf/jsonpb" @@ -61,40 +59,12 @@ func (s *createProjectSuite) ACreditClassWithClassIdAndIssuerAlice(a string) { require.NoError(s.t, err) } -func (s *createProjectSuite) AProjectSequenceWithClassIdAndNextSequence(a, b string) { - class, err := s.k.stateStore.ClassTable().GetById(s.ctx, a) - require.NoError(s.t, err) - - nextSequence, err := strconv.ParseUint(b, 10, 32) - require.NoError(s.t, err) - - err = s.k.stateStore.ProjectSequenceTable().Insert(s.ctx, &api.ProjectSequence{ - ClassKey: class.Key, - NextSequence: nextSequence, - }) - require.NoError(s.t, err) -} - func (s *createProjectSuite) AProjectWithProjectIdAndReferenceId(a, b string) { - classID := base.GetClassIDFromLegacyProjectID(a) - - class, err := s.k.stateStore.ClassTable().GetById(s.ctx, classID) - require.NoError(s.t, err) - - err = s.k.stateStore.ProjectTable().Insert(s.ctx, &api.Project{ + err := s.k.stateStore.ProjectTable().Insert(s.ctx, &api.Project{ Id: a, ReferenceId: b, }) require.NoError(s.t, err) - - seq := s.getProjectSequence(a) - - // Save because project sequence may already exist - err = s.k.stateStore.ProjectSequenceTable().Save(s.ctx, &api.ProjectSequence{ - ClassKey: class.Key, - NextSequence: seq + 1, - }) - require.NoError(s.t, err) } func (s *createProjectSuite) AliceAttemptsToCreateAProjectWithClassId(a string) { @@ -145,19 +115,6 @@ func (s *createProjectSuite) ExpectErrorContains(a string) { require.ErrorContains(s.t, s.err, a) } -func (s *createProjectSuite) ExpectProjectSequenceWithClassIdAndNextSequence(a string, b string) { - project, err := s.stateStore.ClassTable().GetById(s.ctx, a) - require.NoError(s.t, err) - - nextSequence, err := strconv.ParseUint(b, 10, 64) - require.NoError(s.t, err) - - projectSequence, err := s.stateStore.ProjectSequenceTable().Get(s.ctx, project.Key) - require.NoError(s.t, err) - - require.Equal(s.t, nextSequence, projectSequence.NextSequence) -} - func (s *createProjectSuite) ExpectProjectProperties(a gocuke.DocString) { var expected types.Project err := jsonpb.UnmarshalString(a.Content, &expected) @@ -190,10 +147,3 @@ func (s *createProjectSuite) ExpectEventWithProperties(a gocuke.DocString) { err = testutil.MatchEvent(&event, sdkEvent) require.NoError(s.t, err) } - -func (s *createProjectSuite) getProjectSequence(projectID string) uint64 { - str := strings.Split(projectID, "-") - seq, err := strconv.ParseUint(str[1], 10, 32) - require.NoError(s.t, err) - return seq -}