mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-13 13:21:20 +00:00
permission/types pkg, Base and Roles
This commit is contained in:
@ -45,7 +45,7 @@ type Account struct {
|
|||||||
Code []byte `json:"code"` // VM code
|
Code []byte `json:"code"` // VM code
|
||||||
StorageRoot []byte `json:"storage_root"` // VM storage merkle root.
|
StorageRoot []byte `json:"storage_root"` // VM storage merkle root.
|
||||||
|
|
||||||
Permissions *ptypes.Permissions `json:"permissions"`
|
Permissions *ptypes.AccountPermissions `json:"permissions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acc *Account) Copy() *Account {
|
func (acc *Account) Copy() *Account {
|
||||||
@ -70,13 +70,3 @@ var AccountCodec = binary.Codec{
|
|||||||
Encode: AccountEncoder,
|
Encode: AccountEncoder,
|
||||||
Decode: AccountDecoder,
|
Decode: AccountDecoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// defaults for a Big Bad Public Blockchain
|
|
||||||
var DefaultPermissions = ptypes.Permissions{
|
|
||||||
Send: true,
|
|
||||||
Call: true,
|
|
||||||
Create: true,
|
|
||||||
Bond: true,
|
|
||||||
}
|
|
||||||
|
44
permission/types/errors.go
Normal file
44
permission/types/errors.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
// Some errors
|
||||||
|
|
||||||
|
// permission number out of bounds
|
||||||
|
type ErrInvalidPermission PermFlag
|
||||||
|
|
||||||
|
func (e ErrInvalidPermission) Error() string {
|
||||||
|
return fmt.Sprintf("invalid permission %d", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown string for permission
|
||||||
|
type ErrInvalidPermissionString string
|
||||||
|
|
||||||
|
func (e ErrInvalidPermissionString) Error() string {
|
||||||
|
return fmt.Sprintf("invalid permission '%s'", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// already exists (err on add)
|
||||||
|
type ErrPermissionExists string
|
||||||
|
|
||||||
|
func (e ErrPermissionExists) Error() string {
|
||||||
|
return fmt.Sprintf("permission '%s' already exists", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown string for snative contract
|
||||||
|
type ErrInvalidSNativeString string
|
||||||
|
|
||||||
|
func (e ErrInvalidSNativeString) Error() string {
|
||||||
|
return fmt.Sprintf("invalid snative contract '%s'", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set=false. This error should be caught and the global
|
||||||
|
// value fetched for the permission by the caller
|
||||||
|
type ErrValueNotSet PermFlag
|
||||||
|
|
||||||
|
func (e ErrValueNotSet) Error() string {
|
||||||
|
return fmt.Sprintf("the value for permission %d is not set", e)
|
||||||
|
}
|
165
permission/types/permissions.go
Normal file
165
permission/types/permissions.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
. "github.com/tendermint/tendermint/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var (
|
||||||
|
GlobalPermissionsAddress = Zero256[:20]
|
||||||
|
GlobalPermissionsAddress256 = Zero256
|
||||||
|
DougAddress = append([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, []byte("THISISDOUG")...)
|
||||||
|
DougAddress256 = LeftPadWord256(DougAddress)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A particular permission
|
||||||
|
type PermFlag uint16
|
||||||
|
|
||||||
|
// Base permission references are like unix (the index is already bit shifted)
|
||||||
|
const (
|
||||||
|
Send PermFlag = 1 << iota // 1
|
||||||
|
Call // 2
|
||||||
|
Create // 4
|
||||||
|
Bond // 8
|
||||||
|
Root // 16
|
||||||
|
|
||||||
|
DefaultBBPB = Send | Call | Create | Bond
|
||||||
|
|
||||||
|
NumBasePermissions uint = 5
|
||||||
|
TopBasePermission PermFlag = 1 << (NumBasePermissions - 1)
|
||||||
|
AllSet PermFlag = 1<<NumBasePermissions - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Base chain permissions struct
|
||||||
|
type BasePermissions struct {
|
||||||
|
// bit array with "has"/"doesn't have" for each permission
|
||||||
|
Perms PermFlag
|
||||||
|
|
||||||
|
// bit array with "set"/"not set" for each permission (not-set should fall back to global)
|
||||||
|
SetBit PermFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBasePermissions() *BasePermissions {
|
||||||
|
return &BasePermissions{0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a permission value. ty should be a power of 2.
|
||||||
|
// ErrValueNotSet is returned if the permission's set bit is off,
|
||||||
|
// and should be caught by caller so the global permission can be fetched
|
||||||
|
func (p *BasePermissions) Get(ty PermFlag) (bool, error) {
|
||||||
|
if ty > TopBasePermission {
|
||||||
|
return false, ErrInvalidPermission(ty)
|
||||||
|
}
|
||||||
|
if p.SetBit&ty == 0 {
|
||||||
|
return false, ErrValueNotSet(ty)
|
||||||
|
}
|
||||||
|
return p.Perms&ty > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a permission bit. Will set the permission's set bit to true.
|
||||||
|
func (p *BasePermissions) Set(ty PermFlag, value bool) error {
|
||||||
|
if ty > TopBasePermission {
|
||||||
|
return ErrInvalidPermission(ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetBit |= ty
|
||||||
|
if value {
|
||||||
|
p.Perms |= ty
|
||||||
|
} else {
|
||||||
|
p.Perms &= ^ty
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the permission's set bit to false
|
||||||
|
func (p *BasePermissions) Unset(ty PermFlag) error {
|
||||||
|
if ty > TopBasePermission {
|
||||||
|
return ErrInvalidPermission(ty)
|
||||||
|
}
|
||||||
|
p.SetBit &= ^ty
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *BasePermissions) Copy() *BasePermissions {
|
||||||
|
return &BasePermissions{
|
||||||
|
Perms: p.Perms,
|
||||||
|
SetBit: p.SetBit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *BasePermissions) String() string {
|
||||||
|
return fmt.Sprintf("Base: %b; Set: %b", p.Perms, p.SetBit)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type AccountPermissions struct {
|
||||||
|
Base *BasePermissions
|
||||||
|
Roles []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAccountPermissions() *AccountPermissions {
|
||||||
|
return &AccountPermissions{
|
||||||
|
Base: NewBasePermissions(),
|
||||||
|
Roles: []string{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the role is found
|
||||||
|
func (aP *AccountPermissions) HasRole(role string) bool {
|
||||||
|
for _, r := range aP.Roles {
|
||||||
|
if r == role {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the role is added, and false if it already exists
|
||||||
|
func (aP *AccountPermissions) AddRole(role string) bool {
|
||||||
|
for _, r := range aP.Roles {
|
||||||
|
if r == role {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aP.Roles = append(aP.Roles, role)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the role is removed, and false if it is not found
|
||||||
|
func (aP *AccountPermissions) RmRole(role string) bool {
|
||||||
|
for i, r := range aP.Roles {
|
||||||
|
if r == role {
|
||||||
|
post := []string{}
|
||||||
|
if len(aP.Roles) > i+1 {
|
||||||
|
post = aP.Roles[i+1:]
|
||||||
|
}
|
||||||
|
aP.Roles = append(aP.Roles[:i], post...)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aP *AccountPermissions) Copy() *AccountPermissions {
|
||||||
|
r := make([]string, len(aP.Roles))
|
||||||
|
copy(r, aP.Roles)
|
||||||
|
return &AccountPermissions{
|
||||||
|
Base: aP.Base.Copy(),
|
||||||
|
Roles: r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultAccountPermissions() *AccountPermissions {
|
||||||
|
return &AccountPermissions{
|
||||||
|
Base: &BasePermissions{
|
||||||
|
Perms: DefaultBBPB,
|
||||||
|
SetBit: AllSet,
|
||||||
|
},
|
||||||
|
Roles: []string{},
|
||||||
|
}
|
||||||
|
}
|
@ -178,7 +178,7 @@ func getOrMakeOutputs(state AccountGetter, accounts map[string]*account.Account,
|
|||||||
PubKey: nil,
|
PubKey: nil,
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
Balance: 0,
|
Balance: 0,
|
||||||
Permissions: state.GetAccount(ptypes.GlobalPermissionsAddress).Permissions,
|
Permissions: ptypes.NewAccountPermissions(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
accounts[string(out.Address)] = acc
|
accounts[string(out.Address)] = acc
|
||||||
@ -307,7 +307,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ensure all inputs have send permissions
|
// ensure all inputs have send permissions
|
||||||
if !hasSendPermission(accounts) {
|
if !hasSendPermission(blockCache, accounts) {
|
||||||
return fmt.Errorf("At least one input lacks permission for SendTx")
|
return fmt.Errorf("At least one input lacks permission for SendTx")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,11 +364,11 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
|
|
||||||
createAccount := len(tx.Address) == 0
|
createAccount := len(tx.Address) == 0
|
||||||
if createAccount {
|
if createAccount {
|
||||||
if !hasCreatePermission(inAcc) {
|
if !hasCreatePermission(blockCache, inAcc) {
|
||||||
return fmt.Errorf("Account %X does not have Create permission", tx.Input.Address)
|
return fmt.Errorf("Account %X does not have Create permission", tx.Input.Address)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !hasCallPermission(inAcc) {
|
if !hasCallPermission(blockCache, inAcc) {
|
||||||
return fmt.Errorf("Account %X does not have Call permission", tx.Input.Address)
|
return fmt.Errorf("Account %X does not have Call permission", tx.Input.Address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,7 +465,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
// we need to bind a copy of the accounts tree (from the txCache)
|
// we need to bind a copy of the accounts tree (from the txCache)
|
||||||
// so the gendoug can make a native call to create accounts and update
|
// so the gendoug can make a native call to create accounts and update
|
||||||
// permissions
|
// permissions
|
||||||
setupDoug(vmach, txCache, _s)
|
// setupDoug(vmach, txCache, _s)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
|
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
|
||||||
@ -636,7 +636,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasBondPermission(accounts) {
|
if !hasBondPermission(blockCache, accounts) {
|
||||||
return fmt.Errorf("At least one input lacks permission to bond")
|
return fmt.Errorf("At least one input lacks permission to bond")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,38 +790,49 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// TODO: for debug log the failed accounts
|
// TODO: for debug log the failed accounts
|
||||||
|
|
||||||
func hasSendPermission(accs map[string]*account.Account) bool {
|
// Get permission on an account or fall back to global value
|
||||||
|
func HasPermission(state AccountGetter, acc *account.Account, perm ptypes.PermFlag) bool {
|
||||||
|
v, err := acc.Permissions.Base.Get(perm)
|
||||||
|
fmt.Printf("has permission? %x %v %b %v %v\n", acc.Address, acc.Permissions, perm, v, err)
|
||||||
|
if _, ok := err.(ptypes.ErrValueNotSet); ok {
|
||||||
|
return HasPermission(state, state.GetAccount(ptypes.GlobalPermissionsAddress), perm)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasSendPermission(state AccountGetter, accs map[string]*account.Account) bool {
|
||||||
for _, acc := range accs {
|
for _, acc := range accs {
|
||||||
if !acc.Permissions.Send {
|
if !HasPermission(state, acc, ptypes.Send) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasCallPermission(acc *account.Account) bool {
|
func hasCallPermission(state AccountGetter, acc *account.Account) bool {
|
||||||
if !acc.Permissions.Call {
|
if !HasPermission(state, acc, ptypes.Call) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasCreatePermission(acc *account.Account) bool {
|
func hasCreatePermission(state AccountGetter, acc *account.Account) bool {
|
||||||
if !acc.Permissions.Create {
|
if !HasPermission(state, acc, ptypes.Create) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasBondPermission(accs map[string]*account.Account) bool {
|
func hasBondPermission(state AccountGetter, accs map[string]*account.Account) bool {
|
||||||
for _, acc := range accs {
|
for _, acc := range accs {
|
||||||
if !acc.Permissions.Bond {
|
if !HasPermission(state, acc, ptypes.Bond) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// permission management functions
|
// permission management functions
|
||||||
// get/set closures which bind the txCache (for modifying an accounts permissions)
|
// get/set closures which bind the txCache (for modifying an accounts permissions)
|
||||||
// add/rm closures which bind txCache & state (for creating/removing permissions on *all* accounts - expensive!)
|
// add/rm closures which bind txCache & state (for creating/removing permissions on *all* accounts - expensive!)
|
||||||
@ -841,7 +852,7 @@ func setupDoug(vmach *vm.VM, txCache *TxCache, _s *State) {
|
|||||||
}
|
}
|
||||||
stAcc := toStateAccount(vmAcc)
|
stAcc := toStateAccount(vmAcc)
|
||||||
permN := uint(Uint64FromWord256(permNum))
|
permN := uint(Uint64FromWord256(permNum))
|
||||||
perm, err := stAcc.Permissions.Get(permN)
|
perm, err := stAcc.Permissions.Base.Get(permN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -870,7 +881,7 @@ func setupDoug(vmach *vm.VM, txCache *TxCache, _s *State) {
|
|||||||
stAcc := toStateAccount(vmAcc)
|
stAcc := toStateAccount(vmAcc)
|
||||||
permN := uint(Uint64FromWord256(permNum))
|
permN := uint(Uint64FromWord256(permNum))
|
||||||
permV := !perm.IsZero()
|
permV := !perm.IsZero()
|
||||||
if err = stAcc.Permissions.Set(permN, permV); err != nil {
|
if err = stAcc.Permissions.Base.Set(permN, permV); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
vmAcc = toVMAccount(stAcc)
|
vmAcc = toVMAccount(stAcc)
|
||||||
@ -942,3 +953,4 @@ func setupDoug(vmach *vm.VM, txCache *TxCache, _s *State) {
|
|||||||
// must be called or else functions not accessible
|
// must be called or else functions not accessible
|
||||||
vmach.EnableDoug()
|
vmach.EnableDoug()
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -15,9 +15,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GenesisAccount struct {
|
type GenesisAccount struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
Amount uint64 `json:"amount"`
|
Amount uint64 `json:"amount"`
|
||||||
Permissions *ptypes.Permissions `json:"global_permissions"` // pointer so optional
|
Permissions *ptypes.AccountPermissions `json:"global_permissions"` // pointer so optional
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenesisValidator struct {
|
type GenesisValidator struct {
|
||||||
@ -28,7 +28,7 @@ type GenesisValidator struct {
|
|||||||
|
|
||||||
type GenesisParams struct {
|
type GenesisParams struct {
|
||||||
// Default permissions for newly created accounts
|
// Default permissions for newly created accounts
|
||||||
GlobalPermissions *ptypes.Permissions `json:"global_permissions"`
|
GlobalPermissions *ptypes.AccountPermissions `json:"global_permissions"`
|
||||||
|
|
||||||
// TODO: other params we may want to tweak?
|
// TODO: other params we may want to tweak?
|
||||||
}
|
}
|
||||||
@ -73,8 +73,7 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State {
|
|||||||
// Make accounts state tree
|
// Make accounts state tree
|
||||||
accounts := merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db)
|
accounts := merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db)
|
||||||
for _, genAcc := range genDoc.Accounts {
|
for _, genAcc := range genDoc.Accounts {
|
||||||
perm_ := account.DefaultPermissions
|
perm := ptypes.NewDefaultAccountPermissions()
|
||||||
perm := &perm_
|
|
||||||
if genAcc.Permissions != nil {
|
if genAcc.Permissions != nil {
|
||||||
perm = genAcc.Permissions
|
perm = genAcc.Permissions
|
||||||
}
|
}
|
||||||
@ -90,10 +89,11 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State {
|
|||||||
|
|
||||||
// global permissions are saved as the 0 address
|
// global permissions are saved as the 0 address
|
||||||
// so they are included in the accounts tree
|
// so they are included in the accounts tree
|
||||||
globalPerms_ := account.DefaultPermissions
|
globalPerms := ptypes.NewDefaultAccountPermissions()
|
||||||
globalPerms := &globalPerms_
|
|
||||||
if genDoc.Params != nil && genDoc.Params.GlobalPermissions != nil {
|
if genDoc.Params != nil && genDoc.Params.GlobalPermissions != nil {
|
||||||
globalPerms = genDoc.Params.GlobalPermissions
|
globalPerms = genDoc.Params.GlobalPermissions
|
||||||
|
// XXX: make sure the set bits are all true
|
||||||
|
globalPerms.Base.SetBit = ptypes.AllSet
|
||||||
}
|
}
|
||||||
permsAcc := &account.Account{
|
permsAcc := &account.Account{
|
||||||
Address: ptypes.GlobalPermissionsAddress,
|
Address: ptypes.GlobalPermissionsAddress,
|
||||||
|
@ -62,29 +62,23 @@ func makeUsers(n int) []*account.PrivAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
PermsAllFalse = ptypes.Permissions{
|
PermsAllFalse = ptypes.NewAccountPermissions()
|
||||||
Send: false,
|
|
||||||
Call: false,
|
|
||||||
Create: false,
|
|
||||||
Bond: false,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func newBaseGenDoc(globalPerm, accountPerm ptypes.Permissions) GenesisDoc {
|
func newBaseGenDoc(globalPerm, accountPerm *ptypes.AccountPermissions) GenesisDoc {
|
||||||
genAccounts := []GenesisAccount{}
|
genAccounts := []GenesisAccount{}
|
||||||
for _, u := range user[:5] {
|
for _, u := range user[:5] {
|
||||||
accPerm := accountPerm
|
|
||||||
genAccounts = append(genAccounts, GenesisAccount{
|
genAccounts = append(genAccounts, GenesisAccount{
|
||||||
Address: u.Address,
|
Address: u.Address,
|
||||||
Amount: 1000000,
|
Amount: 1000000,
|
||||||
Permissions: &accPerm,
|
Permissions: accountPerm.Copy(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return GenesisDoc{
|
return GenesisDoc{
|
||||||
GenesisTime: time.Now(),
|
GenesisTime: time.Now(),
|
||||||
Params: &GenesisParams{
|
Params: &GenesisParams{
|
||||||
GlobalPermissions: &globalPerm,
|
GlobalPermissions: globalPerm,
|
||||||
},
|
},
|
||||||
Accounts: genAccounts,
|
Accounts: genAccounts,
|
||||||
Validators: []GenesisValidator{
|
Validators: []GenesisValidator{
|
||||||
@ -104,9 +98,9 @@ func newBaseGenDoc(globalPerm, accountPerm ptypes.Permissions) GenesisDoc {
|
|||||||
func TestSendFails(t *testing.T) {
|
func TestSendFails(t *testing.T) {
|
||||||
stateDB := dbm.GetDB("state")
|
stateDB := dbm.GetDB("state")
|
||||||
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
||||||
genDoc.Accounts[1].Permissions.Send = true
|
genDoc.Accounts[1].Permissions.Base.Set(ptypes.Send, true)
|
||||||
genDoc.Accounts[2].Permissions.Call = true
|
genDoc.Accounts[2].Permissions.Base.Set(ptypes.Call, true)
|
||||||
genDoc.Accounts[3].Permissions.Create = true
|
genDoc.Accounts[3].Permissions.Base.Set(ptypes.Create, true)
|
||||||
st := MakeGenesisState(stateDB, &genDoc)
|
st := MakeGenesisState(stateDB, &genDoc)
|
||||||
blockCache := NewBlockCache(st)
|
blockCache := NewBlockCache(st)
|
||||||
|
|
||||||
@ -156,9 +150,9 @@ func TestSendFails(t *testing.T) {
|
|||||||
func TestCallFails(t *testing.T) {
|
func TestCallFails(t *testing.T) {
|
||||||
stateDB := dbm.GetDB("state")
|
stateDB := dbm.GetDB("state")
|
||||||
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
||||||
genDoc.Accounts[1].Permissions.Send = true
|
genDoc.Accounts[1].Permissions.Base.Set(ptypes.Send, true)
|
||||||
genDoc.Accounts[2].Permissions.Call = true
|
genDoc.Accounts[2].Permissions.Base.Set(ptypes.Call, true)
|
||||||
genDoc.Accounts[3].Permissions.Create = true
|
genDoc.Accounts[3].Permissions.Base.Set(ptypes.Create, true)
|
||||||
st := MakeGenesisState(stateDB, &genDoc)
|
st := MakeGenesisState(stateDB, &genDoc)
|
||||||
blockCache := NewBlockCache(st)
|
blockCache := NewBlockCache(st)
|
||||||
|
|
||||||
@ -226,7 +220,7 @@ func TestCallFails(t *testing.T) {
|
|||||||
func TestSendPermission(t *testing.T) {
|
func TestSendPermission(t *testing.T) {
|
||||||
stateDB := dbm.GetDB("state")
|
stateDB := dbm.GetDB("state")
|
||||||
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
||||||
genDoc.Accounts[0].Permissions.Send = true // give the 0 account permission
|
genDoc.Accounts[0].Permissions.Base.Set(ptypes.Send, true) // give the 0 account permission
|
||||||
st := MakeGenesisState(stateDB, &genDoc)
|
st := MakeGenesisState(stateDB, &genDoc)
|
||||||
blockCache := NewBlockCache(st)
|
blockCache := NewBlockCache(st)
|
||||||
|
|
||||||
@ -275,7 +269,7 @@ func callContractCode(contractAddr []byte) []byte {
|
|||||||
func TestCallPermission(t *testing.T) {
|
func TestCallPermission(t *testing.T) {
|
||||||
stateDB := dbm.GetDB("state")
|
stateDB := dbm.GetDB("state")
|
||||||
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
||||||
genDoc.Accounts[0].Permissions.Call = true // give the 0 account permission
|
genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true) // give the 0 account permission
|
||||||
st := MakeGenesisState(stateDB, &genDoc)
|
st := MakeGenesisState(stateDB, &genDoc)
|
||||||
blockCache := NewBlockCache(st)
|
blockCache := NewBlockCache(st)
|
||||||
|
|
||||||
@ -291,7 +285,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
Code: []byte{0x60},
|
Code: []byte{0x60},
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
StorageRoot: Zero256.Bytes(),
|
StorageRoot: Zero256.Bytes(),
|
||||||
Permissions: ptypes.NilPermissions.Copy(),
|
Permissions: ptypes.NewAccountPermissions(),
|
||||||
}
|
}
|
||||||
st.UpdateAccount(simpleAcc)
|
st.UpdateAccount(simpleAcc)
|
||||||
|
|
||||||
@ -315,7 +309,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
Code: contractCode,
|
Code: contractCode,
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
StorageRoot: Zero256.Bytes(),
|
StorageRoot: Zero256.Bytes(),
|
||||||
Permissions: ptypes.NilPermissions.Copy(),
|
Permissions: ptypes.NewAccountPermissions(),
|
||||||
}
|
}
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
blockCache.UpdateAccount(caller1Acc)
|
||||||
|
|
||||||
@ -334,7 +328,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
fmt.Println("##### CALL TO SIMPLE CONTRACT (PASS)")
|
fmt.Println("##### CALL TO SIMPLE CONTRACT (PASS)")
|
||||||
|
|
||||||
// A single input, having the permission, and the contract has permission
|
// A single input, having the permission, and the contract has permission
|
||||||
caller1Acc.Permissions.Call = true
|
caller1Acc.Permissions.Base.Set(ptypes.Call, true)
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
blockCache.UpdateAccount(caller1Acc)
|
||||||
tx, _ = NewCallTx(blockCache, user[0].PubKey, caller1ContractAddr, nil, 100, 10000, 100)
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, caller1ContractAddr, nil, 100, 10000, 100)
|
||||||
SignCallTx(tx, user[0])
|
SignCallTx(tx, user[0])
|
||||||
@ -359,10 +353,10 @@ func TestCallPermission(t *testing.T) {
|
|||||||
Code: contractCode2,
|
Code: contractCode2,
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
StorageRoot: Zero256.Bytes(),
|
StorageRoot: Zero256.Bytes(),
|
||||||
Permissions: ptypes.NilPermissions.Copy(),
|
Permissions: ptypes.NewAccountPermissions(),
|
||||||
}
|
}
|
||||||
caller1Acc.Permissions.Call = false
|
caller1Acc.Permissions.Base.Set(ptypes.Call, false)
|
||||||
caller2Acc.Permissions.Call = true
|
caller2Acc.Permissions.Base.Set(ptypes.Call, true)
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
blockCache.UpdateAccount(caller1Acc)
|
||||||
blockCache.UpdateAccount(caller2Acc)
|
blockCache.UpdateAccount(caller2Acc)
|
||||||
|
|
||||||
@ -381,7 +375,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
// both caller1 and caller2 have permission
|
// both caller1 and caller2 have permission
|
||||||
fmt.Println("##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (PASS)")
|
fmt.Println("##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (PASS)")
|
||||||
|
|
||||||
caller1Acc.Permissions.Call = true
|
caller1Acc.Permissions.Base.Set(ptypes.Call, true)
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
blockCache.UpdateAccount(caller1Acc)
|
||||||
|
|
||||||
tx, _ = NewCallTx(blockCache, user[0].PubKey, caller2ContractAddr, nil, 100, 10000, 100)
|
tx, _ = NewCallTx(blockCache, user[0].PubKey, caller2ContractAddr, nil, 100, 10000, 100)
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/tendermint/tendermint/account"
|
"github.com/tendermint/tendermint/account"
|
||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
dbm "github.com/tendermint/tendermint/db"
|
dbm "github.com/tendermint/tendermint/db"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -24,13 +25,13 @@ func Tempfile(prefix string) (*os.File, string) {
|
|||||||
|
|
||||||
func RandAccount(randBalance bool, minBalance int64) (*account.Account, *account.PrivAccount) {
|
func RandAccount(randBalance bool, minBalance int64) (*account.Account, *account.PrivAccount) {
|
||||||
privAccount := account.GenPrivAccount()
|
privAccount := account.GenPrivAccount()
|
||||||
perms := account.DefaultPermissions
|
perms := ptypes.NewDefaultAccountPermissions()
|
||||||
acc := &account.Account{
|
acc := &account.Account{
|
||||||
Address: privAccount.PubKey.Address(),
|
Address: privAccount.PubKey.Address(),
|
||||||
PubKey: privAccount.PubKey,
|
PubKey: privAccount.PubKey,
|
||||||
Sequence: RandInt(),
|
Sequence: RandInt(),
|
||||||
Balance: minBalance,
|
Balance: minBalance,
|
||||||
Permissions: &perms,
|
Permissions: perms,
|
||||||
}
|
}
|
||||||
if randBalance {
|
if randBalance {
|
||||||
acc.Balance += int64(RandUint32())
|
acc.Balance += int64(RandUint32())
|
||||||
@ -75,8 +76,9 @@ func RandGenesisState(numAccounts int, randBalance bool, minBalance int64, numVa
|
|||||||
for i := 0; i < numAccounts; i++ {
|
for i := 0; i < numAccounts; i++ {
|
||||||
account, privAccount := RandAccount(randBalance, minBalance)
|
account, privAccount := RandAccount(randBalance, minBalance)
|
||||||
accounts[i] = GenesisAccount{
|
accounts[i] = GenesisAccount{
|
||||||
Address: account.Address,
|
Address: account.Address,
|
||||||
Amount: account.Balance,
|
Amount: account.Balance,
|
||||||
|
Permissions: ptypes.NewDefaultAccountPermissions(),
|
||||||
}
|
}
|
||||||
privAccounts[i] = privAccount
|
privAccounts[i] = privAccount
|
||||||
}
|
}
|
||||||
@ -102,6 +104,9 @@ func RandGenesisState(numAccounts int, randBalance bool, minBalance int64, numVa
|
|||||||
ChainID: "tendermint_test",
|
ChainID: "tendermint_test",
|
||||||
Accounts: accounts,
|
Accounts: accounts,
|
||||||
Validators: validators,
|
Validators: validators,
|
||||||
|
Params: &GenesisParams{
|
||||||
|
GlobalPermissions: ptypes.NewDefaultAccountPermissions(),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
s0.Save()
|
s0.Save()
|
||||||
return s0, privAccounts, privValidators
|
return s0, privAccounts, privValidators
|
||||||
|
@ -17,7 +17,7 @@ type Account struct {
|
|||||||
StorageRoot Word256
|
StorageRoot Word256
|
||||||
Other interface{} // For holding all other data.
|
Other interface{} // For holding all other data.
|
||||||
|
|
||||||
Permissions *ptypes.Permissions
|
Permissions *ptypes.AccountPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acc *Account) String() string {
|
func (acc *Account) String() string {
|
||||||
|
13
vm/vm.go
13
vm/vm.go
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
"github.com/tendermint/tendermint/events"
|
"github.com/tendermint/tendermint/events"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tendermint/vm/sha3"
|
"github.com/tendermint/tendermint/vm/sha3"
|
||||||
)
|
)
|
||||||
@ -90,6 +91,14 @@ func (vm *VM) EnablePermissions() {
|
|||||||
vm.perms = true
|
vm.perms = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vm *VM) HasPermission(acc *Account, perm ptypes.PermFlag) bool {
|
||||||
|
v, err := acc.Permissions.Base.Get(perm)
|
||||||
|
if _, ok := err.(ptypes.ErrValueNotSet); ok {
|
||||||
|
return vm.HasPermission(vm.appState.GetAccount(ptypes.GlobalPermissionsAddress256), perm)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// CONTRACT appState is aware of caller and callee, so we can just mutate them.
|
// CONTRACT appState is aware of caller and callee, so we can just mutate them.
|
||||||
// value: To be transferred from caller to callee. Refunded upon error.
|
// value: To be transferred from caller to callee. Refunded upon error.
|
||||||
// gas: Available gas. No refunds for gas.
|
// gas: Available gas. No refunds for gas.
|
||||||
@ -681,7 +690,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
dbg.Printf(" => %v\n", log)
|
dbg.Printf(" => %v\n", log)
|
||||||
|
|
||||||
case CREATE: // 0xF0
|
case CREATE: // 0xF0
|
||||||
if vm.perms && !callee.Permissions.Create {
|
if vm.perms && !vm.HasPermission(callee, ptypes.Create) {
|
||||||
return nil, ErrPermission{"create"}
|
return nil, ErrPermission{"create"}
|
||||||
}
|
}
|
||||||
contractValue := stack.Pop64()
|
contractValue := stack.Pop64()
|
||||||
@ -709,7 +718,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
}
|
}
|
||||||
|
|
||||||
case CALL, CALLCODE: // 0xF1, 0xF2
|
case CALL, CALLCODE: // 0xF1, 0xF2
|
||||||
if vm.perms && !callee.Permissions.Call {
|
if vm.perms && !vm.HasPermission(callee, ptypes.Call) {
|
||||||
return nil, ErrPermission{"call"}
|
return nil, ErrPermission{"call"}
|
||||||
}
|
}
|
||||||
gasLimit := stack.Pop64()
|
gasLimit := stack.Pop64()
|
||||||
|
Reference in New Issue
Block a user