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

Remove redundant DB access for ACL #441

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions kernel/permission/acl/acl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package acl

import (
"encoding/json"
"errors"
"fmt"

"github.com/xuperchain/xupercore/kernel/permission/acl/utils"
pb "github.com/xuperchain/xupercore/protos"
)

// ACL is a wrapper for pb.ACL, which helps to deal with it
type ACL struct {
pb.Acl
}

func newACL(data []byte) (*ACL, error) {
acl := new(ACL)

err := json.Unmarshal(data, &acl.Acl)
if err != nil {
return nil, fmt.Errorf("unmarshal args acl error: %v", err)
}

if err := acl.check(); err != nil {
return nil, err
}
return acl, nil
}

// mustGetAKs get AK list when caller make sure no error occure
// usually called after checked ACL
func (l *ACL) mustGetAKs() []string {
aks, _ := l.getAKs()
return aks
}

// getAKs gets AK list under different permission rule,
// which works for AK2Account bucket
func (l *ACL) getAKs() ([]string, error) {
rule := l.GetPm().GetRule()
switch rule {
case pb.PermissionRule_SIGN_THRESHOLD:
aks := make([]string, 0, len(l.GetAksWeight()))
for ak := range l.GetAksWeight() {
aks = append(aks, ak)
}
return aks, nil
case pb.PermissionRule_SIGN_AKSET:
aks := make([]string, 0)
for _, akSets := range l.GetAkSets().GetSets() {
aks = append(aks, akSets.GetAks()...)
}
return aks, nil
default:
return nil, errors.New("permission rule is invalid")
}
}

func (l *ACL) check() error {

// check permission model
if l.GetPm() == nil {
return fmt.Errorf("valid acl failed, lack of argument of permission model")
}

// check AK limitation
switch l.GetPm().GetRule() {
case pb.PermissionRule_SIGN_THRESHOLD:
aksWeight := l.GetAksWeight()
if aksWeight == nil || len(aksWeight) > utils.GetAkLimit() {
return fmt.Errorf("valid acl failed, aksWeight is nil or size of aksWeight is very big")
}
case pb.PermissionRule_SIGN_AKSET:
akSets := l.GetAkSets()
if akSets == nil {
return fmt.Errorf("valid acl failed, akSets is nil")
}
sets := akSets.GetSets()
if sets == nil || len(sets) > utils.GetAkLimit() {
return fmt.Errorf("valid acl failed, Sets is nil or size of Sets is very big")
}
default:
return fmt.Errorf("valid acl failed, permission model is not found")
}

return nil
}
112 changes: 0 additions & 112 deletions kernel/permission/acl/ak_2_account.go

This file was deleted.

37 changes: 37 additions & 0 deletions kernel/permission/acl/bucket/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package bucket

import (
"github.com/xuperchain/xupercore/kernel/contract"
"github.com/xuperchain/xupercore/kernel/contract/sandbox"
"github.com/xuperchain/xupercore/kernel/permission/acl/utils"
)

// AccountBucket can access DB bucket used for account
type AccountBucket struct {
DB contract.XMState
}

// IsExist returns account existence in bucket
func (b *AccountBucket) IsExist(account string) (bool, error) {
acl, err := b.GetAccountACL(account)
if err != nil {
if err == sandbox.ErrNotFound {
return false, nil
}
return false, err
}
return acl != nil, nil
}

// GetAccountACL gets ACL by account name
func (b *AccountBucket) GetAccountACL(account string) ([]byte, error) {
return b.DB.Get(utils.GetAccountBucket(), []byte(account))
}

// SetAccountACL stores account's ACL in DB with:
//
// key: <ExtUtxoPrefix><AccountBucketPrefix>/<Account>
// value: ACL
func (b *AccountBucket) SetAccountACL(account string, acl []byte) error {
return b.DB.Put(utils.GetAccountBucket(), []byte(account), acl)
}
109 changes: 109 additions & 0 deletions kernel/permission/acl/bucket/account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package bucket

import (
"reflect"
"testing"

"github.com/xuperchain/xupercore/kernel/contract"
)

func TestAccountBucket_IsExist(t *testing.T) {
type args struct {
account string
}
tests := []struct {
name string
args args
want bool
wantErr bool
}{
{
name: "not exist",
args: args{
account: "Account_get_not_found",
},
want: false,
},
{
name: "other error",
args: args{
account: "Account_get_error_other",
},
wantErr: true,
},
{
name: "exist",
args: args{
account: "Account_exist",
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &AccountBucket{
DB: mockContext{},
}
got, err := b.IsExist(tt.args.account)
if (err != nil) != tt.wantErr {
t.Errorf("AccountBucket.IsExist() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("AccountBucket.IsExist() = %v, want %v", got, tt.want)
}
})
}
}

func TestAccountBucket_SetAccountACL(t *testing.T) {
type fields struct {
DB contract.XMState
}
type args struct {
account string
acl []byte
}
tests := []struct {
name string
fields fields
args args
wantErr bool
want bucketData
}{
{
name: "success",
args: args{
account: "Account_succ",
acl: []byte("acl"),
},
want: bucketData{
"Account_succ": []byte("acl"),
},
},
{
name: "fail",
args: args{
account: "Account_put_error",
acl: []byte("acl"),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &AccountBucket{
DB: mockContext{
Account: bucketData{},
},
}
if err := b.SetAccountACL(tt.args.account, tt.args.acl); (err != nil) != tt.wantErr {
t.Errorf("AccountBucket.SetAccountACL() error = %v, wantErr %v", err, tt.wantErr)
}
got := b.DB.(mockContext).Account
if !tt.wantErr && !reflect.DeepEqual(got, tt.want) {
t.Errorf("AccountBucket.SetAccountACL(), DB = %v, want %v", got, tt.want)
}
})
}
}
Loading