Skip to content

Commit 0cda6aa

Browse files
authoredMar 14, 2024··
feat(x/data)!: support public resolvers for IPFS support (#2098)
1 parent 5fb7e60 commit 0cda6aa

22 files changed

+449
-238
lines changed
 

‎api/regen/data/v2/query.pulsar.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎api/regen/data/v2/state.pulsar.go

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎api/regen/data/v2/tx.pulsar.go

+195-114
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎proto/regen/data/v2/query.proto

+1
Original file line numberDiff line numberDiff line change
@@ -353,5 +353,6 @@ message ResolverInfo {
353353
string url = 2;
354354

355355
// manager is the address of the account that manages the resolver.
356+
// This will be empty if the resolver is public.
356357
string manager = 3;
357358
}

‎proto/regen/data/v2/state.proto

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ message Resolver {
7070
// url is the URL of the resolver.
7171
string url = 2;
7272

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

‎proto/regen/data/v2/tx.proto

+32-12
Original file line numberDiff line numberDiff line change
@@ -106,20 +106,39 @@ message MsgAttestResponse {
106106

107107
// MsgDefineResolver is the Msg/DefineResolver request type.
108108
message MsgDefineResolver {
109-
option (cosmos.msg.v1.signer) = "manager";
109+
option (cosmos.msg.v1.signer) = "definer";
110110

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

117-
// resolver_url is a resolver URL which should refer to an HTTP service
118-
// which will respond to a GET request with the IRI of a ContentHash
119+
// resolver_url is a resolver URL.
120+
//
121+
// If it refers to an HTTP URL, that HTTP service should
122+
// respond to a GET request with the IRI of a ContentHash as the path parameter
119123
// and return the content if it exists or a 404. For graph data, resolvers
120124
// should use the HTTP Accept header to negotiate the RDF serialization
121125
// format.
126+
//
127+
// To use IPFS, the resolver_url ipfs: should be defined with public set to true
128+
// and used as the resolver for any data hosted on IPFS. Content hashes must be
129+
// adapted to IPFS's CID format. The multicodec raw (0x55) should
130+
// be used for all raw content hashes and the multicodec rdfc-1 (0xb403)
131+
// should be used for all graph content hashes (unless new canonicalization
132+
// or merkle tree algorithms are used which may or may not be supported
133+
// by IPFS). Note that IPFS's tools currently do not support creating or
134+
// resolving RDFC-1 content hashes so upstream work will be needed for
135+
// that integration to be fully supported.
122136
string resolver_url = 2;
137+
138+
// public is a boolean indicating whether the resolver is public or not.
139+
// If public is false then only the definer can register data with this
140+
// resolver.
141+
bool public = 3;
123142
}
124143

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

133152
// MsgRegisterResolver is the Msg/RegisterResolver request type.
134153
message MsgRegisterResolver {
135-
option (cosmos.msg.v1.signer) = "manager";
154+
option (cosmos.msg.v1.signer) = "signer";
136155

137-
// manager is the address of the resolver manager who registered this
138-
// resolver with Msg/DefinedResolver.
139-
string manager = 1;
156+
// signer is the address registering data with the resolver. If
157+
// the resolver is not public then the signer must be the definer
158+
// of the resolver.
159+
string signer = 1;
140160

141161
// resolver_id is the ID of a resolver defined with Msg/DefineResolver.
142162
uint64 resolver_id = 2;

‎x/data/client/tx.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ Flags:
151151
}
152152

153153
msg := data.MsgDefineResolver{
154-
Manager: clientCtx.GetFromAddress().String(),
154+
Definer: clientCtx.GetFromAddress().String(),
155155
ResolverUrl: resolverURL,
156156
}
157157
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
@@ -210,7 +210,7 @@ Flags:
210210
}
211211

212212
msg := data.MsgRegisterResolver{
213-
Manager: clientCtx.GetFromAddress().String(),
213+
Signer: clientCtx.GetFromAddress().String(),
214214
ResolverId: resolverID,
215215
ContentHashes: contentHashes,
216216
}

‎x/data/features/msg_define_resolver.feature

+8-8
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@ Feature: MsgDefineResolver
44
Given the message
55
"""
66
{
7-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
7+
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
88
"resolver_url": "https://foo.bar"
99
}
1010
"""
1111
When the message is validated
1212
Then expect no error
1313

14-
Scenario: an error is returned if manager is empty
14+
Scenario: an error is returned if definer is empty
1515
Given the message
1616
"""
1717
{}
1818
"""
1919
When the message is validated
2020
Then expect the error "empty address string is not allowed: invalid address"
2121

22-
Scenario: an error is returned if manager is not a bech32 address
22+
Scenario: an error is returned if definer is not a bech32 address
2323
Given the message
2424
"""
2525
{
26-
"manager": "foo"
26+
"definer": "foo"
2727
}
2828
"""
2929
When the message is validated
@@ -33,7 +33,7 @@ Feature: MsgDefineResolver
3333
Given the message
3434
"""
3535
{
36-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
36+
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
3737
}
3838
"""
3939
When the message is validated
@@ -43,7 +43,7 @@ Feature: MsgDefineResolver
4343
Given the message
4444
"""
4545
{
46-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
46+
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
4747
"resolver_url": "foo.bar"
4848
}
4949
"""
@@ -54,7 +54,7 @@ Feature: MsgDefineResolver
5454
Given the message
5555
"""
5656
{
57-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
57+
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
5858
"resolver_url": "https://foo.bar"
5959
}
6060
"""
@@ -64,7 +64,7 @@ Feature: MsgDefineResolver
6464
{
6565
"type": "regen-ledger/MsgDefineResolver",
6666
"value": {
67-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
67+
"definer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
6868
"resolver_url": "https://foo.bar"
6969
}
7070
}

‎x/data/features/msg_register_resolver.feature

+9-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Feature: MsgRegisterResolver
44
Given the message
55
"""
66
{
7-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
7+
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
88
"resolver_id": 1,
99
"content_hashes": [
1010
{
@@ -20,19 +20,19 @@ Feature: MsgRegisterResolver
2020
When the message is validated
2121
Then expect no error
2222

23-
Scenario: an error is returned if manager is empty
23+
Scenario: an error is returned if signer is empty
2424
Given the message
2525
"""
2626
{}
2727
"""
2828
When the message is validated
2929
Then expect the error "empty address string is not allowed: invalid address"
3030

31-
Scenario: an error is returned if manager is not a bech32 address
31+
Scenario: an error is returned if signer is not a bech32 address
3232
Given the message
3333
"""
3434
{
35-
"manager": "foo"
35+
"signer": "foo"
3636
}
3737
"""
3838
When the message is validated
@@ -42,7 +42,7 @@ Feature: MsgRegisterResolver
4242
Given the message
4343
"""
4444
{
45-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
45+
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
4646
}
4747
"""
4848
When the message is validated
@@ -52,7 +52,7 @@ Feature: MsgRegisterResolver
5252
Given the message
5353
"""
5454
{
55-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
55+
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
5656
"resolver_id": 1
5757
}
5858
"""
@@ -63,7 +63,7 @@ Feature: MsgRegisterResolver
6363
Given the message
6464
"""
6565
{
66-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
66+
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
6767
"resolver_id": 1,
6868
"content_hashes": [
6969
{
@@ -89,8 +89,8 @@ Feature: MsgRegisterResolver
8989
}
9090
}
9191
],
92-
"manager": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6",
93-
"resolver_id": "1"
92+
"resolver_id": "1",
93+
"signer": "regen1depk54cuajgkzea6zpgkq36tnjwdzv4ak663u6"
9494
}
9595
}
9696
"""

‎x/data/msg_define_resolver.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var _ legacytx.LegacyMsg = &MsgDefineResolver{}
1212

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

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

2626
// GetSigners returns the expected signers for MsgDefineResolver.
2727
func (m *MsgDefineResolver) GetSigners() []sdk.AccAddress {
28-
addr, _ := sdk.AccAddressFromBech32(m.Manager)
28+
addr, _ := sdk.AccAddressFromBech32(m.Definer)
2929
return []sdk.AccAddress{addr}
3030
}
3131

‎x/data/msg_register_resolver.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ var _ legacytx.LegacyMsg = &MsgRegisterResolver{}
1010

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

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

3434
// GetSigners returns the expected signers for MsgRegisterResolver.
3535
func (m *MsgRegisterResolver) GetSigners() []sdk.AccAddress {
36-
addr, _ := sdk.AccAddressFromBech32(m.Manager)
36+
addr, _ := sdk.AccAddressFromBech32(m.Signer)
3737
return []sdk.AccAddress{addr}
3838
}
3939

‎x/data/query.pb.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎x/data/server/features/msg_define_resolver.feature

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ Feature: Msg/DefineResolver
1515
When alice attempts to define a resolver with url "https://foo.bar"
1616
Then expect the error "a resolver with the same URL and manager already exists: unique key violation"
1717

18+
Scenario: public resolvers can only be defined once per URL
19+
Given a public resolver is defined for the url "ipfs:"
20+
When alice attempts to define a public resolver with url "ipfs:"
21+
Then expect the error "a resolver with the same URL and manager already exists: unique key violation"
22+
1823
Rule: Event is emitted
1924

2025
Scenario: EventDefineResolver is emitted

‎x/data/server/features/msg_register_resolver.feature

+8-1
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,11 @@ Feature: Msg/RegisterResolver
7676
"id": 1,
7777
"iri": "regen:112wkBET2rRgE8pahuaczxKbmv7ciehqsne57F9gtzf1PVhwuFTX.bin"
7878
}
79-
"""
79+
"""
80+
81+
Rule: public resolvers allow anyone to register data
82+
83+
Scenario: register data to public resolver
84+
Given alice has defined a public resolver with url "ipfs:"
85+
When bob attempts to register the data to the resolver
86+
Then the data resolver entry exists

‎x/data/server/msg_define_resolver.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,23 @@ import (
55

66
"github.com/cosmos/cosmos-sdk/orm/types/ormerrors"
77
sdk "github.com/cosmos/cosmos-sdk/types"
8+
89
api "github.com/regen-network/regen-ledger/api/v2/regen/data/v1"
910
"github.com/regen-network/regen-ledger/x/data/v3"
1011
)
1112

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

20+
manager := definer
21+
if msg.Public {
22+
manager = nil
23+
}
24+
1925
id, err := s.stateStore.ResolverTable().InsertReturningID(ctx, &api.Resolver{
2026
Url: msg.ResolverUrl,
2127
Manager: manager,

‎x/data/server/msg_define_resolver_test.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,32 @@ func (s *defineResolverSuite) AliceHasDefinedAResolverWithUrl(a string) {
4141
require.NoError(s.t, err)
4242
}
4343

44+
func (s *defineResolverSuite) APublicResolverIsDefinedForTheUrl(a string) {
45+
err := s.server.stateStore.ResolverTable().Insert(s.ctx, &api.Resolver{
46+
Url: a,
47+
Manager: nil,
48+
})
49+
require.NoError(s.t, err)
50+
}
51+
4452
func (s *defineResolverSuite) AliceAttemptsToDefineAResolverWithUrl(a string) {
4553
_, s.err = s.server.DefineResolver(s.ctx, &data.MsgDefineResolver{
46-
Manager: s.alice.String(),
54+
Definer: s.alice.String(),
55+
ResolverUrl: a,
56+
})
57+
}
58+
59+
func (s *defineResolverSuite) AliceAttemptsToDefineAPublicResolverWithUrl(a string) {
60+
_, s.err = s.server.DefineResolver(s.ctx, &data.MsgDefineResolver{
61+
Definer: s.alice.String(),
4762
ResolverUrl: a,
63+
Public: true,
4864
})
4965
}
5066

5167
func (s *defineResolverSuite) BobAttemptsToDefineAResolverWithUrl(a string) {
5268
_, s.err = s.server.DefineResolver(s.ctx, &data.MsgDefineResolver{
53-
Manager: s.bob.String(),
69+
Definer: s.bob.String(),
5470
ResolverUrl: a,
5571
})
5672
}

‎x/data/server/msg_register_resolver.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ func (s serverImpl) RegisterResolver(ctx context.Context, msg *data.MsgRegisterR
1818
return nil, sdkerrors.ErrNotFound.Wrapf("resolver with id %d does not exist", msg.ResolverId)
1919
}
2020

21-
manager, err := sdk.AccAddressFromBech32(msg.Manager)
21+
signer, err := sdk.AccAddressFromBech32(msg.Signer)
2222
if err != nil {
2323
return nil, err
2424
}
2525

26-
if !bytes.Equal(resolver.Manager, manager) {
27-
return nil, data.ErrUnauthorizedResolverManager
26+
// if resolver isn't public, the signer must be the manager
27+
if resolver.Manager != nil {
28+
if !bytes.Equal(resolver.Manager, signer) {
29+
return nil, data.ErrUnauthorizedResolverManager
30+
}
2831
}
2932

3033
sdkCtx := sdk.UnwrapSDKContext(ctx)

‎x/data/server/msg_register_resolver_test.go

+16-6
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,23 @@ func (s *registerResolverSuite) TheContentHash(a gocuke.DocString) {
4444

4545
func (s *registerResolverSuite) AliceHasDefinedTheResolverWithUrl(a string) {
4646
res, err := s.server.DefineResolver(s.ctx, &data.MsgDefineResolver{
47-
Manager: s.alice.String(),
47+
Definer: s.alice.String(),
4848
ResolverUrl: a,
4949
})
5050
require.NoError(s.t, err)
5151

5252
s.id = res.ResolverId
5353
}
54+
func (s *registerResolverSuite) AliceHasDefinedAPublicResolverWithUrl(a string) {
55+
res, err := s.server.DefineResolver(s.ctx, &data.MsgDefineResolver{
56+
Definer: s.alice.String(),
57+
ResolverUrl: a,
58+
Public: true,
59+
})
60+
require.NoError(s.t, err)
61+
62+
s.id = res.ResolverId
63+
}
5464

5565
func (s *registerResolverSuite) AliceHasAnchoredTheDataAtBlockTime(a string) {
5666
blockTime, err := types.ParseDate("block time", a)
@@ -66,15 +76,15 @@ func (s *registerResolverSuite) AliceHasAnchoredTheDataAtBlockTime(a string) {
6676

6777
func (s *registerResolverSuite) AliceHasRegisteredTheDataToTheResolver() {
6878
_, s.err = s.server.RegisterResolver(s.ctx, &data.MsgRegisterResolver{
69-
Manager: s.alice.String(),
79+
Signer: s.alice.String(),
7080
ResolverId: s.id,
7181
ContentHashes: []*data.ContentHash{s.ch},
7282
})
7383
}
7484

7585
func (s *registerResolverSuite) AliceAttemptsToRegisterTheDataToTheResolver() {
7686
_, s.err = s.server.RegisterResolver(s.ctx, &data.MsgRegisterResolver{
77-
Manager: s.alice.String(),
87+
Signer: s.alice.String(),
7888
ResolverId: s.id,
7989
ContentHashes: []*data.ContentHash{s.ch},
8090
})
@@ -85,7 +95,7 @@ func (s *registerResolverSuite) AliceAttemptsToRegisterTheDataToAResolverWithId(
8595
require.NoError(s.t, err)
8696

8797
_, s.err = s.server.RegisterResolver(s.ctx, &data.MsgRegisterResolver{
88-
Manager: s.alice.String(),
98+
Signer: s.alice.String(),
8999
ResolverId: id,
90100
ContentHashes: []*data.ContentHash{s.ch},
91101
})
@@ -98,15 +108,15 @@ func (s *registerResolverSuite) AliceAttemptsToRegisterTheDataToTheResolverAtBlo
98108
s.ctx = sdk.WrapSDKContext(s.sdkCtx.WithBlockTime(blockTime))
99109

100110
_, s.err = s.server.RegisterResolver(s.ctx, &data.MsgRegisterResolver{
101-
Manager: s.alice.String(),
111+
Signer: s.alice.String(),
102112
ResolverId: s.id,
103113
ContentHashes: []*data.ContentHash{s.ch},
104114
})
105115
}
106116

107117
func (s *registerResolverSuite) BobAttemptsToRegisterTheDataToTheResolver() {
108118
_, s.err = s.server.RegisterResolver(s.ctx, &data.MsgRegisterResolver{
109-
Manager: s.bob.String(),
119+
Signer: s.bob.String(),
110120
ResolverId: s.id,
111121
ContentHashes: []*data.ContentHash{s.ch},
112122
})

‎x/data/server/testsuite/suite.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -174,22 +174,22 @@ func (s *IntegrationTestSuite) TestResolver() {
174174

175175
// can define a resolver
176176
defineResolver, err := s.msgClient.DefineResolver(s.ctx, &data.MsgDefineResolver{
177-
Manager: s.addr1.String(),
177+
Definer: s.addr1.String(),
178178
ResolverUrl: testURL,
179179
})
180180
require.NoError(err)
181181

182182
// can register content to a resolver
183183
_, err = s.msgClient.RegisterResolver(s.ctx, &data.MsgRegisterResolver{
184-
Manager: s.addr1.String(),
184+
Signer: s.addr1.String(),
185185
ResolverId: defineResolver.ResolverId,
186186
ContentHashes: hashes,
187187
})
188188
require.NoError(err)
189189

190190
// registering same data twice is a no-op
191191
_, err = s.msgClient.RegisterResolver(s.ctx, &data.MsgRegisterResolver{
192-
Manager: s.addr1.String(),
192+
Signer: s.addr1.String(),
193193
ResolverId: defineResolver.ResolverId,
194194
ContentHashes: hashes,
195195
})

‎x/data/simulation/operations.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ func SimulateMsgDefineResolver(ak data.AccountKeeper, bk data.BankKeeper, qryCli
230230
}
231231

232232
msg := &data.MsgDefineResolver{
233-
Manager: manager.Address.String(),
233+
Definer: manager.Address.String(),
234234
ResolverUrl: resolverURL,
235235
}
236236

@@ -301,7 +301,7 @@ func SimulateMsgRegisterResolver(ak data.AccountKeeper, bk data.BankKeeper,
301301
return simtypes.NoOpMsg(data.ModuleName, TypeMsgRegisterResolver, err.Error()), nil, err
302302
}
303303
msg := &data.MsgRegisterResolver{
304-
Manager: manager.String(),
304+
Signer: manager.String(),
305305
ResolverId: resolverID,
306306
ContentHashes: []*data.ContentHash{contentHash},
307307
}

‎x/data/state.pb.go

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎x/data/tx.pb.go

+125-65
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.