Skip to content

Commit

Permalink
fix: ACP Persistance fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Lodek committed Jan 15, 2024
1 parent 2cddbac commit 96ce0b1
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 14 deletions.
2 changes: 1 addition & 1 deletion x/acp/embedded/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// part of any deployment or real chain.
//
// Example usage:
// ```
// ```go
// acp, _ := NewLocalACP()
// ctx := acp.GetCtx()
// msgServer := acp.GetMsgServer()
Expand Down
109 changes: 109 additions & 0 deletions x/acp/embedded/embedded_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package embedded

import (
"os"
"testing"

"cosmossdk.io/log"
prototypes "github.com/cosmos/gogoproto/types"
"github.com/google/uuid"
"github.com/stretchr/testify/require"

"github.com/sourcenetwork/sourcehub/x/acp/types"
)

func TestLocalACPIsPersistentAccrossCalls(t *testing.T) {
var storePath string
var polId string

// Given a previously created Embedded ACP store
storePath = setupDirectory(t)
t.Logf("store dir: %v", storePath)

acp, err := NewLocalACP(
WithPersistentStorage(storePath),
WithLogger(log.NewTestLogger(t)),
)
require.Nil(t, err)

srv := acp.GetMsgService()
ctx := acp.GetCtx()
createResp, err := srv.CreatePolicy(ctx, getCreatePolMsg())

require.Nil(t, err)
polId = createResp.Policy.Id
acp.close() // close first instance

// create new ACP with same path
acp, err = NewLocalACP(
WithPersistentStorage(storePath),
WithLogger(log.NewTestLogger(t)),
)
ctx = acp.GetCtx()
require.Nil(t, err)

// When I query the store for a stored Policy
query := acp.GetQueryService()
resp, err := query.Policy(ctx, &types.QueryPolicyRequest{
Id: polId,
})

respIds, errIds := query.PolicyIds(ctx, &types.QueryPolicyIdsRequest{})

// Then the Policy is fetched
require.Nil(t, errIds)
require.True(t, len(respIds.Ids) == 1)
t.Logf("ids %v", respIds.Ids)

require.Nil(t, err)
require.NotNil(t, resp.Policy)

// cleanup
acp.close()
os.RemoveAll(storePath)
}

func setupDirectory(t *testing.T) string {
path := "/tmp/" + uuid.New().String()
err := os.Mkdir(path, os.ModePerm)
require.Nil(t, err)

return path
}

func getCreatePolMsg() *types.MsgCreatePolicy {
policyStr := `
name: policy
description: ok
resources:
file:
relations:
owner:
doc: owner owns
types:
- actor-resource
reader:
admin:
manages:
- reader
permissions:
own:
expr: owner
doc: own doc
read:
expr: owner + reader
actor:
name: actor-resource
doc: my actor
`

var creator = "cosmos1gue5de6a8fdff0jut08vw5sg9pk6rr00cstakj"
var timestamp = prototypes.TimestampNow()

return &types.MsgCreatePolicy{
Creator: creator,
Policy: policyStr,
MarshalType: types.PolicyMarshalingType_SHORT_YAML,
CreationTime: timestamp,
}
}
38 changes: 27 additions & 11 deletions x/acp/embedded/local_acp.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (

const (
defaultDataDir string = ".sourcehub-embedded-acp"
levelDbSubdir string = "data"
dataFile string = "data"
)

// LocalACP wraps the acp module Keeper with a local storage.
Expand All @@ -34,12 +34,14 @@ const (
type LocalACP struct {
baseCtx context.Context
keeper *keeper.Keeper
msgServer types.MsgServer
accKeeper types.AccountKeeper
db dbm.DB
}

// GetMsgService returns an implementation of acp's MsgServer
func (l *LocalACP) GetMsgService() types.MsgServer {
return keeper.NewMsgServerImpl(*l.keeper)
return l.msgServer
}

// GetQueryService returns an implementation of acp's QueryServer
Expand All @@ -53,22 +55,30 @@ func (l *LocalACP) GetCtx() context.Context {
return l.baseCtx
}

// closes the underlying DB
func (l *LocalACP) close() {
l.db.Close()
}

// NewLocalACP creates an instance of LocalACP with the given options.
//
// The default ACP configuration persists data under the user home directory and produces no logs.
func NewLocalACP(options ...Option) (LocalACP, error) {
o := newDefaultOption()
o.Apply(options...)

storeKey := storetypes.NewKVStoreKey(types.StoreKey)

db, err := o.GetDB()
if err != nil {
return LocalACP{}, err
}

memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey)
storeKey := storetypes.NewKVStoreKey(types.StoreKey)

stateStore := store.NewCommitMultiStore(db, o.logger, o.metrics)
stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db)
stateStore.MountStoreWithDB(memStoreKey, storetypes.StoreTypeMemory, nil)

err = stateStore.LoadLatestVersion()
if err != nil {
return LocalACP{}, err
Expand All @@ -78,6 +88,7 @@ func NewLocalACP(options ...Option) (LocalACP, error) {
cdc := codec.NewProtoCodec(registry)

accKeeper := &testutil.AccountKeeperStub{}

storeService := runtime.NewKVStoreService(storeKey)
authority := authtypes.NewModuleAddress(govtypes.ModuleName)

Expand All @@ -96,7 +107,9 @@ func NewLocalACP(options ...Option) (LocalACP, error) {
return LocalACP{
baseCtx: ctx,
keeper: &k,
msgServer: NewMsgServer(k, stateStore),
accKeeper: accKeeper,
db: db,
}, nil
}

Expand All @@ -110,6 +123,13 @@ func WithPersistentStorage(path string) Option {
}
}

// WithInMemStore configures Embeded ACP to use a volatile in memory store
func WithInMemStore() Option {
return func(o *option) {
o.storePath = ""
}
}

// WithLogger configures Embedded ACP's Logger
func WithLogger(logger log.Logger) Option {
return func(o *option) {
Expand Down Expand Up @@ -161,14 +181,10 @@ func (o *option) Apply(opts ...Option) {

// GetDB returns the DB to be used by Local ACP
func (o *option) GetDB() (dbm.DB, error) {
backend := dbm.GoLevelDBBackend
if o.storePath == "" {
return dbm.NewMemDB(), nil
}

db, err := dbm.NewGoLevelDB(levelDbSubdir, o.storePath, nil)
if err != nil {
return nil, fmt.Errorf("failed creating embedded acp DB: %w", err)
backend = dbm.MemDBBackend
}

return db, nil
return dbm.NewDB(dataFile, backend, o.storePath)
}
98 changes: 98 additions & 0 deletions x/acp/embedded/msg_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package embedded

import (
"context"

"cosmossdk.io/store"
"github.com/sourcenetwork/sourcehub/x/acp/keeper"
"github.com/sourcenetwork/sourcehub/x/acp/types"
)

var _ (types.MsgServer) = (*msgServer)(nil)

// msgServer implements the ACP module MsgServer interface.
//
// Effectively msgServer wraps a keeper with the module's native implementation
// but additionally it calls the commit method in the commit multi store after each method call
type msgServer struct {
types.UnimplementedMsgServer

msgServer types.MsgServer
cms store.CommitMultiStore
}

// NewMsgSrever creates a message server for Embedded ACP
func NewMsgServer(k keeper.Keeper, cms store.CommitMultiStore) types.MsgServer {
srv := keeper.NewMsgServerImpl(k)
return &msgServer{
msgServer: srv,
cms: cms,
}
}

func (s *msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) {
resp, err := s.msgServer.UpdateParams(ctx, msg)
if err != nil {
return nil, err
}

s.cms.Commit()
return resp, nil
}

func (s *msgServer) CreatePolicy(ctx context.Context, msg *types.MsgCreatePolicy) (*types.MsgCreatePolicyResponse, error) {
resp, err := s.msgServer.CreatePolicy(ctx, msg)
if err != nil {
return nil, err
}

s.cms.Commit()
return resp, nil
}

func (s *msgServer) SetRelationship(ctx context.Context, msg *types.MsgSetRelationship) (*types.MsgSetRelationshipResponse, error) {
resp, err := s.msgServer.SetRelationship(ctx, msg)
if err != nil {
return nil, err
}

s.cms.Commit()
return resp, nil
}
func (s *msgServer) DeleteRelationship(ctx context.Context, msg *types.MsgDeleteRelationship) (*types.MsgDeleteRelationshipResponse, error) {
resp, err := s.msgServer.DeleteRelationship(ctx, msg)
if err != nil {
return nil, err
}

s.cms.Commit()
return resp, nil
}
func (s *msgServer) RegisterObject(ctx context.Context, msg *types.MsgRegisterObject) (*types.MsgRegisterObjectResponse, error) {
resp, err := s.msgServer.RegisterObject(ctx, msg)
if err != nil {
return nil, err
}

s.cms.Commit()
return resp, nil
}

func (s *msgServer) UnregisterObject(ctx context.Context, msg *types.MsgUnregisterObject) (*types.MsgUnregisterObjectResponse, error) {
resp, err := s.msgServer.UnregisterObject(ctx, msg)
if err != nil {
return nil, err
}

s.cms.Commit()
return resp, nil
}
func (s *msgServer) CheckAccess(ctx context.Context, msg *types.MsgCheckAccess) (*types.MsgCheckAccessResponse, error) {
resp, err := s.msgServer.CheckAccess(ctx, msg)
if err != nil {
return nil, err
}

s.cms.Commit()
return resp, nil
}
7 changes: 6 additions & 1 deletion x/acp/keeper/keeper_common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ var creator = "cosmos1gue5de6a8fdff0jut08vw5sg9pk6rr00cstakj"
var timestamp = prototypes.TimestampNow()

func setupMsgServer(t *testing.T) (types.MsgServer, context.Context) {
keeper, ctx := setupKeeper(t)
return NewMsgServerImpl(keeper), ctx
}

func setupKeeper(t *testing.T) (Keeper, context.Context) {
storeKey := storetypes.NewKVStoreKey(types.StoreKey)

db := dbm.NewMemDB()
Expand All @@ -51,5 +56,5 @@ func setupMsgServer(t *testing.T) (types.MsgServer, context.Context) {
// Initialize params
keeper.SetParams(ctx, types.DefaultParams())

return NewMsgServerImpl(keeper), ctx
return keeper, ctx
}
2 changes: 1 addition & 1 deletion x/acp/keeper/msg_server_create_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (k msgServer) CreatePolicy(goCtx context.Context, msg *types.MsgCreatePolic
if err != nil {
return nil, err
}
ctx.Logger().Info(event.String())
ctx.Logger().Info("EventPolicyCreated: %v", event.String())

return &types.MsgCreatePolicyResponse{
Policy: pol,
Expand Down
22 changes: 22 additions & 0 deletions x/acp/keeper/query_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package keeper

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/sourcenetwork/sourcehub/x/acp/types"
)

func TestQueryPolicy_UnknownPolicyReturnsPolicyNotFoundErr(t *testing.T) {
k, ctx := setupKeeper(t)

req := types.QueryPolicyRequest{
Id: "not found",
}

resp, err := k.Policy(ctx, &req)

require.Nil(t, resp)
require.ErrorIs(t, err, types.ErrPolicyNotFound)
}

0 comments on commit 96ce0b1

Please sign in to comment.