Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(x/data): unique constraints on resolver url and manager #1219

Merged
merged 9 commits into from
Jul 4, 2022
2 changes: 1 addition & 1 deletion .github/workflows/proto-registry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: bufbuild/buf-setup-action@v2
- uses: bufbuild/buf-setup-action@v1
- uses: bufbuild/buf-push-action@v1
with:
input: 'proto'
Expand Down
42 changes: 36 additions & 6 deletions api/regen/data/v1/state.cosmos_orm.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 22 additions & 22 deletions api/regen/data/v1/state.pulsar.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/regen/data/v1/state.proto
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ message Resolver {
id : 4
primary_key : {fields : "id", auto_increment : true}
index : {id : 1, fields : "url"}
index : {id : 2, fields : "manager"}
index : {id : 2, fields : "url,manager", unique: true}
};

// id is the ID of the resolver.
Expand Down
5 changes: 1 addition & 4 deletions x/data/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ import sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
const DataCodespace = "regen.data"

var (
ErrHashVerificationFailed = sdkerrors.Register(DataCodespace, 1, "hash verification failed")
ErrInvalidIRI = sdkerrors.Register(DataCodespace, 2, "invalid IRI")
ErrInvalidMediaExtension = sdkerrors.Register(DataCodespace, 3, "invalid media extension")
ErrResolverURLExists = sdkerrors.Register(DataCodespace, 4, "resolver URL already exists")
ErrResolverUndefined = sdkerrors.Register(DataCodespace, 5, "resolver undefined")
ErrUnauthorizedResolverManager = sdkerrors.Register(DataCodespace, 6, "unauthorized resolver manager")
ErrUnauthorizedResolverManager = sdkerrors.Register(DataCodespace, 4, "unauthorized resolver manager")
)
16 changes: 10 additions & 6 deletions x/data/server/features/define_resolver.feature
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
Feature: Define Resolver

Rule: the resolver is defined with no unique constraints on the URL
A resolver can be defined:
- when the url and manager combination is unique

Scenario: the url is unique
When alice attempts to define a resolver with url "https://foo.bar"
Then expect the resolver with id "1" and url "https://foo.bar" and manager alice
Rule: The url and manager combination must be unique

Scenario: the url and manager combination is unique
Given alice has defined a resolver with url "https://foo.bar"
When bob attempts to define a resolver with url "https://foo.bar"
Then expect the resolver with id "2" and url "https://foo.bar" and manager bob

Scenario: the url is not unique
Scenario: the url and manager combination is not unique
Given alice has defined a resolver with url "https://foo.bar"
When alice attempts to define a resolver with url "https://foo.bar"
Then expect the resolver with id "2" and url "https://foo.bar" and manager alice
Then expect the error "a resolver with the same URL and manager already exists: unique key violation"
8 changes: 7 additions & 1 deletion x/data/server/msg_define_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package server

import (
"context"
"fmt"

"github.com/cosmos/cosmos-sdk/orm/types/ormerrors"
sdk "github.com/cosmos/cosmos-sdk/types"

api "github.com/regen-network/regen-ledger/api/regen/data/v1"
Expand All @@ -21,7 +23,11 @@ func (s serverImpl) DefineResolver(ctx context.Context, msg *data.MsgDefineResol
Manager: manager,
})
if err != nil {
return nil, data.ErrResolverURLExists
if err == ormerrors.UniqueKeyViolation {
return nil, fmt.Errorf("a resolver with the same URL and manager already exists: %s", err)
} else {
return nil, err
}
}

err = sdk.UnwrapSDKContext(ctx).EventManager().EmitTypedEvent(&data.EventDefineResolver{
Expand Down
13 changes: 11 additions & 2 deletions x/data/server/msg_define_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
type defineResolverSuite struct {
*baseSuite
alice sdk.AccAddress
bob sdk.AccAddress
resolverUrl string
err error
}
Expand All @@ -26,6 +27,7 @@ func TestDefineResolver(t *testing.T) {
func (s *defineResolverSuite) Before(t gocuke.TestingT) {
s.baseSuite = setupBase(t)
s.alice = s.addrs[0]
s.bob = s.addrs[1]
}

func (s *defineResolverSuite) AliceHasDefinedAResolverWithUrl(a string) {
Expand All @@ -43,14 +45,21 @@ func (s *defineResolverSuite) AliceAttemptsToDefineAResolverWithUrl(a string) {
})
}

func (s *defineResolverSuite) ExpectTheResolverWithIdAndUrlAndManagerAlice(a string, b string) {
func (s *defineResolverSuite) BobAttemptsToDefineAResolverWithUrl(a string) {
_, s.err = s.server.DefineResolver(s.ctx, &data.MsgDefineResolver{
Manager: s.bob.String(),
ResolverUrl: a,
})
}

func (s *defineResolverSuite) ExpectTheResolverWithIdAndUrlAndManagerBob(a string, b string) {
id, err := strconv.ParseUint(a, 10, 64)
require.NoError(s.t, err)

resolver, err := s.server.stateStore.ResolverTable().Get(s.ctx, id)
require.NoError(s.t, err)
require.Equal(s.t, b, resolver.Url)
require.Equal(s.t, s.alice.Bytes(), resolver.Manager)
require.Equal(s.t, s.bob.Bytes(), resolver.Manager)
}

func (s *defineResolverSuite) ExpectTheError(a string) {
Expand Down
2 changes: 1 addition & 1 deletion x/data/server/query_resolvers_by_hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestQuery_ResolversByHash(t *testing.T) {
require.NoError(t, err)
rid2, err := s.server.stateStore.ResolverTable().InsertReturningID(s.ctx, &api.Resolver{
Url: url,
Manager: s.addrs[0],
Manager: s.addrs[1],
})
require.NoError(t, err)

Expand Down
2 changes: 1 addition & 1 deletion x/data/server/query_resolvers_by_iri_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestQuery_ResolversByIRI(t *testing.T) {
require.NoError(t, err)
rid2, err := s.server.stateStore.ResolverTable().InsertReturningID(s.ctx, &api.Resolver{
Url: url,
Manager: s.addrs[0],
Manager: s.addrs[1],
})
require.NoError(t, err)

Expand Down
2 changes: 1 addition & 1 deletion x/data/server/query_resolvers_by_url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestQuery_ResolversByURL(t *testing.T) {
require.NoError(t, err)
err = s.server.stateStore.ResolverTable().Insert(s.ctx, &api.Resolver{
Url: url,
Manager: s.addrs[0],
Manager: s.addrs[1],
})
require.NoError(t, err)

Expand Down
56 changes: 28 additions & 28 deletions x/data/state.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.