From 9eb3c3c7decdd32adc0c9ee14e0639f18cd437b9 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 10 Jul 2017 13:50:11 +0200 Subject: [PATCH] Start specifying the roles module --- modules/coin/errors.go | 16 ++++----- modules/roles/error.go | 60 +++++++++++++++++++++++++++++++ modules/roles/handler.go | 4 +++ modules/roles/middleware.go | 1 + modules/roles/store.go | 44 +++++++++++++++++++++++ modules/roles/tx.go | 70 +++++++++++++++++++++++++++++++++++++ 6 files changed, 187 insertions(+), 8 deletions(-) create mode 100644 modules/roles/error.go create mode 100644 modules/roles/handler.go create mode 100644 modules/roles/middleware.go create mode 100644 modules/roles/store.go create mode 100644 modules/roles/tx.go diff --git a/modules/coin/errors.go b/modules/coin/errors.go index 7b86f6343..bc3d7c5b7 100644 --- a/modules/coin/errors.go +++ b/modules/coin/errors.go @@ -2,20 +2,20 @@ package coin import ( - rawerr "errors" + "fmt" abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/errors" ) var ( - errNoAccount = rawerr.New("No such account") - errInsufficientFunds = rawerr.New("Insufficient Funds") - errNoInputs = rawerr.New("No Input Coins") - errNoOutputs = rawerr.New("No Output Coins") - errInvalidAddress = rawerr.New("Invalid Address") - errInvalidCoins = rawerr.New("Invalid Coins") - errInvalidSequence = rawerr.New("Invalid Sequence") + errNoAccount = fmt.Errorf("No such account") + errInsufficientFunds = fmt.Errorf("Insufficient Funds") + errNoInputs = fmt.Errorf("No Input Coins") + errNoOutputs = fmt.Errorf("No Output Coins") + errInvalidAddress = fmt.Errorf("Invalid Address") + errInvalidCoins = fmt.Errorf("Invalid Coins") + errInvalidSequence = fmt.Errorf("Invalid Sequence") ) var ( diff --git a/modules/roles/error.go b/modules/roles/error.go new file mode 100644 index 000000000..52041a252 --- /dev/null +++ b/modules/roles/error.go @@ -0,0 +1,60 @@ +//nolint +package roles + +import ( + "fmt" + + abci "github.com/tendermint/abci/types" + "github.com/tendermint/basecoin/errors" +) + +var ( + errNoRole = fmt.Errorf("No such role") + errRoleExists = fmt.Errorf("Role already exists") + errNotMember = fmt.Errorf("Not a member") + errInsufficientSigs = fmt.Errorf("Not enough signatures") + errNoMembers = fmt.Errorf("No members specified") + errTooManyMembers = fmt.Errorf("Too many members specified") +) + +func ErrNoRole() errors.TMError { + return errors.WithCode(errNoRole, abci.CodeType_Unauthorized) +} +func IsNoRoleErr(err error) bool { + return errors.IsSameError(errNoRole, err) +} + +func ErrRoleExists() errors.TMError { + return errors.WithCode(errRoleExists, abci.CodeType_Unauthorized) +} +func IsRoleExistsErr(err error) bool { + return errors.IsSameError(errRoleExists, err) +} + +func ErrNotMember() errors.TMError { + return errors.WithCode(errNotMember, abci.CodeType_Unauthorized) +} +func IsNotMemberErr(err error) bool { + return errors.IsSameError(errNotMember, err) +} + +func ErrInsufficientSigs() errors.TMError { + return errors.WithCode(errInsufficientSigs, abci.CodeType_Unauthorized) +} +func IsInsufficientSigsErr(err error) bool { + return errors.IsSameError(errInsufficientSigs, err) +} + +func ErrNoMembers() errors.TMError { + return errors.WithCode(errNoMembers, abci.CodeType_Unauthorized) +} +func IsNoMembersErr(err error) bool { + return errors.IsSameError(errNoMembers, err) +} + +func ErrTooManyMembers() errors.TMError { + return errors.WithCode(errTooManyMembers, abci.CodeType_Unauthorized) +} +func IsTooManyMembersErr(err error) bool { + return errors.IsSameError(errTooManyMembers, err) +} diff --git a/modules/roles/handler.go b/modules/roles/handler.go new file mode 100644 index 000000000..a20d4f27a --- /dev/null +++ b/modules/roles/handler.go @@ -0,0 +1,4 @@ +package roles + +//NameRole - name space of the roles module +const NameRole = "role" diff --git a/modules/roles/middleware.go b/modules/roles/middleware.go new file mode 100644 index 000000000..3258a668d --- /dev/null +++ b/modules/roles/middleware.go @@ -0,0 +1 @@ +package roles diff --git a/modules/roles/store.go b/modules/roles/store.go new file mode 100644 index 000000000..fe83a7416 --- /dev/null +++ b/modules/roles/store.go @@ -0,0 +1,44 @@ +package roles + +import ( + "fmt" + + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/errors" + "github.com/tendermint/basecoin/state" + wire "github.com/tendermint/go-wire" +) + +// Role - structure to hold permissioning +type Role struct { + MinSigs uint32 `json:"min_sigs"` + Signers []basecoin.Actor `json:"signers"` +} + +// MakeKey creates the lookup key for a role +func MakeKey(role []byte) []byte { + prefix := []byte(NameRole + "/") + return append(prefix, role...) +} + +func loadRole(store state.KVStore, key []byte) (role Role, err error) { + data := store.Get(key) + if len(data) == 0 { + return role, ErrNoRole() + } + err = wire.ReadBinaryBytes(data, &role) + if err != nil { + msg := fmt.Sprintf("Error reading role %X", key) + return role, errors.ErrInternal(msg) + } + return role, nil +} + +func createRole(store state.KVStore, key []byte, role Role) error { + if _, err := loadRole(store, key); !IsNoRoleErr(err) { + return ErrRoleExists() + } + bin := wire.BinaryBytes(role) + store.Set(key, bin) + return nil // real stores can return error... +} diff --git a/modules/roles/tx.go b/modules/roles/tx.go new file mode 100644 index 000000000..270c43027 --- /dev/null +++ b/modules/roles/tx.go @@ -0,0 +1,70 @@ +package roles + +import ( + "github.com/tendermint/go-wire/data" + + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/errors" +) + +// AssumeRoleTx is a layered tx that can wrap your normal tx to give it +// the authority to use a given role. +type AssumeRoleTx struct { + Role data.Bytes `json:"role"` + Tx basecoin.Tx `json:"tx"` +} + +// NewAssumeRoleTx creates a new wrapper to add a role to a tx execution +func NewAssumeRoleTx(role []byte, tx basecoin.Tx) basecoin.Tx { + return AssumeRoleTx{Role: role, Tx: tx}.Wrap() +} + +// ValidateBasic - validate nothing is empty +func (tx AssumeRoleTx) ValidateBasic() error { + if len(tx.Role) == 0 { + return ErrNoRole() + } + if tx.Tx.Empty() { + return errors.ErrUnknownTxType(tx.Tx) + } + return nil +} + +// Wrap - used to satisfy TxInner +func (tx AssumeRoleTx) Wrap() basecoin.Tx { + return basecoin.Tx{tx} +} + +// CreateRoleTx is used to construct a new role +// +// TODO: add ability to update signers on a role... but that adds a lot +// more complexity to the permissions +type CreateRoleTx struct { + Role data.Bytes `json:"role"` + MinSigs uint32 `json:"min_sigs"` + Signers []basecoin.Actor `json:"signers"` +} + +// NewCreateRoleTx creates a new role, which we can later use +func NewCreateRoleTx(role []byte, minSigs uint32, signers []basecoin.Actor) basecoin.Tx { + return CreateRoleTx{Role: role, MinSigs: minSigs, Signers: signers}.Wrap() +} + +// ValidateBasic - validate nothing is empty +func (tx CreateRoleTx) ValidateBasic() error { + if len(tx.Role) == 0 { + return ErrNoRole() + } + if tx.MinSigs == 0 { + return ErrNoMembers() + } + if len(tx.Signers) == 0 { + return ErrNoMembers() + } + return nil +} + +// Wrap - used to satisfy TxInner +func (tx CreateRoleTx) Wrap() basecoin.Tx { + return basecoin.Tx{tx} +}