Skip to content

Commit

Permalink
feat(x/data)!: support public resolvers for IPFS support (#2098)
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronc authored Mar 14, 2024
1 parent 5fb7e60 commit 0cda6aa
Show file tree
Hide file tree
Showing 22 changed files with 449 additions and 238 deletions.
1 change: 1 addition & 0 deletions api/regen/data/v2/query.pulsar.go

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

4 changes: 2 additions & 2 deletions api/regen/data/v2/state.pulsar.go

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

309 changes: 195 additions & 114 deletions api/regen/data/v2/tx.pulsar.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions proto/regen/data/v2/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -353,5 +353,6 @@ message ResolverInfo {
string url = 2;

// manager is the address of the account that manages the resolver.
// This will be empty if the resolver is public.
string manager = 3;
}
4 changes: 2 additions & 2 deletions proto/regen/data/v2/state.proto
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ message Resolver {
// url is the URL of the resolver.
string url = 2;

// manager is the bytes address of the resolver manager who is allowed
// to make calls to Msg/RegisterResolver for this resolver.
// manager is the bytes address of the resolver manager who defined
// this resolver. If the resolver is public, then this field is empty.
bytes manager = 3;
}

Expand Down
44 changes: 32 additions & 12 deletions proto/regen/data/v2/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,39 @@ message MsgAttestResponse {

// MsgDefineResolver is the Msg/DefineResolver request type.
message MsgDefineResolver {
option (cosmos.msg.v1.signer) = "manager";
option (cosmos.msg.v1.signer) = "definer";

// manager is the address of the resolver manager. The manager is able
// to make future calls using the ID returned by this operation with
// Msg/RegisterResolver. To authorize other accounts to register resolvers,
// the manager should make use of cosmos.authz.
string manager = 1;
// definer is the address of the account defining the resolver. If
// the boolean public is set to true, then any user can register
// data with this resolver. If the boolean public is set to false,
// then only the definer can register data with this resolver and
// must use a feature such as cosmos.authz to authorize other accounts
// to register data with this resolver.
string definer = 1;

// resolver_url is a resolver URL which should refer to an HTTP service
// which will respond to a GET request with the IRI of a ContentHash
// resolver_url is a resolver URL.
//
// If it refers to an HTTP URL, that HTTP service should
// respond to a GET request with the IRI of a ContentHash as the path parameter
// and return the content if it exists or a 404. For graph data, resolvers
// should use the HTTP Accept header to negotiate the RDF serialization
// format.
//
// To use IPFS, the resolver_url ipfs: should be defined with public set to true
// and used as the resolver for any data hosted on IPFS. Content hashes must be
// adapted to IPFS's CID format. The multicodec raw (0x55) should
// be used for all raw content hashes and the multicodec rdfc-1 (0xb403)
// should be used for all graph content hashes (unless new canonicalization
// or merkle tree algorithms are used which may or may not be supported
// by IPFS). Note that IPFS's tools currently do not support creating or
// resolving RDFC-1 content hashes so upstream work will be needed for
// that integration to be fully supported.
string resolver_url = 2;

// public is a boolean indicating whether the resolver is public or not.
// If public is false then only the definer can register data with this
// resolver.
bool public = 3;
}

// MsgDefineResolverResponse is the Msg/DefineResolver response type.
Expand All @@ -132,11 +151,12 @@ message MsgDefineResolverResponse {

// MsgRegisterResolver is the Msg/RegisterResolver request type.
message MsgRegisterResolver {
option (cosmos.msg.v1.signer) = "manager";
option (cosmos.msg.v1.signer) = "signer";

// manager is the address of the resolver manager who registered this
// resolver with Msg/DefinedResolver.
string manager = 1;
// signer is the address registering data with the resolver. If
// the resolver is not public then the signer must be the definer
// of the resolver.
string signer = 1;

// resolver_id is the ID of a resolver defined with Msg/DefineResolver.
uint64 resolver_id = 2;
Expand Down
4 changes: 2 additions & 2 deletions x/data/client/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ Flags:
}

msg := data.MsgDefineResolver{
Manager: clientCtx.GetFromAddress().String(),
Definer: clientCtx.GetFromAddress().String(),
ResolverUrl: resolverURL,
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
Expand Down Expand Up @@ -210,7 +210,7 @@ Flags:
}

msg := data.MsgRegisterResolver{
Manager: clientCtx.GetFromAddress().String(),
Signer: clientCtx.GetFromAddress().String(),
ResolverId: resolverID,
ContentHashes: contentHashes,
}
Expand Down
16 changes: 8 additions & 8 deletions x/data/features/msg_define_resolver.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ Feature: MsgDefineResolver
Given the message
"""
{
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"resolver_url": "https://foo.bar"
}
"""
When the message is validated
Then expect no error

Scenario: an error is returned if manager is empty
Scenario: an error is returned if definer is empty
Given the message
"""
{}
"""
When the message is validated
Then expect the error "empty address string is not allowed: invalid address"

Scenario: an error is returned if manager is not a bech32 address
Scenario: an error is returned if definer is not a bech32 address
Given the message
"""
{
"manager": "foo"
"definer": "foo"
}
"""
When the message is validated
Expand All @@ -33,7 +33,7 @@ Feature: MsgDefineResolver
Given the message
"""
{
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
}
"""
When the message is validated
Expand All @@ -43,7 +43,7 @@ Feature: MsgDefineResolver
Given the message
"""
{
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"resolver_url": "foo.bar"
}
"""
Expand All @@ -54,7 +54,7 @@ Feature: MsgDefineResolver
Given the message
"""
{
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"resolver_url": "https://foo.bar"
}
"""
Expand All @@ -64,7 +64,7 @@ Feature: MsgDefineResolver
{
"type": "regen-ledger/MsgDefineResolver",
"value": {
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"resolver_url": "https://foo.bar"
}
}
Expand Down
18 changes: 9 additions & 9 deletions x/data/features/msg_register_resolver.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Feature: MsgRegisterResolver
Given the message
"""
{
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"resolver_id": 1,
"content_hashes": [
{
Expand All @@ -20,19 +20,19 @@ Feature: MsgRegisterResolver
When the message is validated
Then expect no error

Scenario: an error is returned if manager is empty
Scenario: an error is returned if signer is empty
Given the message
"""
{}
"""
When the message is validated
Then expect the error "empty address string is not allowed: invalid address"

Scenario: an error is returned if manager is not a bech32 address
Scenario: an error is returned if signer is not a bech32 address
Given the message
"""
{
"manager": "foo"
"signer": "foo"
}
"""
When the message is validated
Expand All @@ -42,7 +42,7 @@ Feature: MsgRegisterResolver
Given the message
"""
{
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
}
"""
When the message is validated
Expand All @@ -52,7 +52,7 @@ Feature: MsgRegisterResolver
Given the message
"""
{
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"resolver_id": 1
}
"""
Expand All @@ -63,7 +63,7 @@ Feature: MsgRegisterResolver
Given the message
"""
{
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"resolver_id": 1,
"content_hashes": [
{
Expand All @@ -89,8 +89,8 @@ Feature: MsgRegisterResolver
}
}
],
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
"resolver_id": "1"
"resolver_id": "1",
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
}
}
"""
Expand Down
4 changes: 2 additions & 2 deletions x/data/msg_define_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var _ legacytx.LegacyMsg = &MsgDefineResolver{}

// ValidateBasic does a sanity check on the provided data.
func (m *MsgDefineResolver) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Manager); err != nil {
if _, err := sdk.AccAddressFromBech32(m.Definer); err != nil {
return sdkerrors.ErrInvalidAddress.Wrap(err.Error())
}

Expand All @@ -25,7 +25,7 @@ func (m *MsgDefineResolver) ValidateBasic() error {

// GetSigners returns the expected signers for MsgDefineResolver.
func (m *MsgDefineResolver) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Manager)
addr, _ := sdk.AccAddressFromBech32(m.Definer)
return []sdk.AccAddress{addr}
}

Expand Down
4 changes: 2 additions & 2 deletions x/data/msg_register_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var _ legacytx.LegacyMsg = &MsgRegisterResolver{}

// ValidateBasic does a sanity check on the provided data.
func (m *MsgRegisterResolver) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Manager); err != nil {
if _, err := sdk.AccAddressFromBech32(m.Signer); err != nil {
return sdkerrors.ErrInvalidAddress.Wrap(err.Error())
}

Expand All @@ -33,7 +33,7 @@ func (m *MsgRegisterResolver) ValidateBasic() error {

// GetSigners returns the expected signers for MsgRegisterResolver.
func (m *MsgRegisterResolver) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Manager)
addr, _ := sdk.AccAddressFromBech32(m.Signer)
return []sdk.AccAddress{addr}
}

Expand Down
1 change: 1 addition & 0 deletions x/data/query.pb.go

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

5 changes: 5 additions & 0 deletions x/data/server/features/msg_define_resolver.feature
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ Feature: Msg/DefineResolver
When alice attempts to define a resolver with url "https://foo.bar"
Then expect the error "a resolver with the same URL and manager already exists: unique key violation"

Scenario: public resolvers can only be defined once per URL
Given a public resolver is defined for the url "ipfs:"
When alice attempts to define a public resolver with url "ipfs:"
Then expect the error "a resolver with the same URL and manager already exists: unique key violation"

Rule: Event is emitted

Scenario: EventDefineResolver is emitted
Expand Down
9 changes: 8 additions & 1 deletion x/data/server/features/msg_register_resolver.feature
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,11 @@ Feature: Msg/RegisterResolver
"id": 1,
"iri": "regen:112wkBET2rRgE8pahuaczxKbmv7ciehqsne57F9gtzf1PVhwuFTX.bin"
}
"""
"""

Rule: public resolvers allow anyone to register data

Scenario: register data to public resolver
Given alice has defined a public resolver with url "ipfs:"
When bob attempts to register the data to the resolver
Then the data resolver entry exists
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 @@ -5,17 +5,23 @@ import (

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

api "github.com/regen-network/regen-ledger/api/v2/regen/data/v1"
"github.com/regen-network/regen-ledger/x/data/v3"
)

// DefineResolver defines a resolver URL and assigns it a new integer ID that can be used in calls to RegisterResolver.
func (s serverImpl) DefineResolver(ctx context.Context, msg *data.MsgDefineResolver) (*data.MsgDefineResolverResponse, error) {
manager, err := sdk.AccAddressFromBech32(msg.Manager)
definer, err := sdk.AccAddressFromBech32(msg.Definer)
if err != nil {
return nil, err
}

manager := definer
if msg.Public {
manager = nil
}

id, err := s.stateStore.ResolverTable().InsertReturningID(ctx, &api.Resolver{
Url: msg.ResolverUrl,
Manager: manager,
Expand Down
20 changes: 18 additions & 2 deletions x/data/server/msg_define_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,32 @@ func (s *defineResolverSuite) AliceHasDefinedAResolverWithUrl(a string) {
require.NoError(s.t, err)
}

func (s *defineResolverSuite) APublicResolverIsDefinedForTheUrl(a string) {
err := s.server.stateStore.ResolverTable().Insert(s.ctx, &api.Resolver{
Url: a,
Manager: nil,
})
require.NoError(s.t, err)
}

func (s *defineResolverSuite) AliceAttemptsToDefineAResolverWithUrl(a string) {
_, s.err = s.server.DefineResolver(s.ctx, &data.MsgDefineResolver{
Manager: s.alice.String(),
Definer: s.alice.String(),
ResolverUrl: a,
})
}

func (s *defineResolverSuite) AliceAttemptsToDefineAPublicResolverWithUrl(a string) {
_, s.err = s.server.DefineResolver(s.ctx, &data.MsgDefineResolver{
Definer: s.alice.String(),
ResolverUrl: a,
Public: true,
})
}

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

0 comments on commit 0cda6aa

Please sign in to comment.