You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

226 lines
6.7 KiB

package vm
import (
"fmt"
. "github.com/tendermint/tendermint/common"
ptypes "github.com/tendermint/tendermint/permission/types"
)
// Checks if a permission flag is valid (a known base chain or snative permission)
func ValidPermN(n ptypes.PermFlag) bool {
if n > ptypes.TopBasePermission && n < FirstSNativePerm {
return false
} else if n > TopSNativePermission {
return false
}
return true
}
const (
// first 32 bits of BasePermission are for chain, second 32 are for snative
FirstSNativePerm ptypes.PermFlag = 1 << 32
HasBasePerm ptypes.PermFlag = FirstSNativePerm << iota
SetBasePerm
UnsetBasePerm
SetGlobalPerm
ClearBasePerm
HasRole
AddRole
RmRole
// XXX: must be adjusted if snative's added/removed
NumSNativePermissions uint = 8
TopSNativePermission ptypes.PermFlag = FirstSNativePerm << (NumSNativePermissions - 1)
)
type SNativeContract func(acc *Account, input []byte) (output []byte, err error)
//-----------------------------------------------------------------------------
// snative are native contracts that can access and manipulate the chain state
// (in particular the permissions values)
// TODO: catch errors, log em, return 0s to the vm (should some errors cause exceptions though?)
func (vm *VM) hasBasePerm(acc *Account, args []byte) (output []byte, err error) {
if !vm.HasPermission(acc, HasBasePerm) {
return nil, fmt.Errorf("acc %X does not have permission to call snative.HasBasePerm")
}
if len(args) != 2*32 {
return nil, fmt.Errorf("hasBasePerm() takes two arguments (address, permission number)")
}
var addr, permNum Word256
copy(addr[:], args[:32])
copy(permNum[:], args[32:64])
vmAcc := vm.appState.GetAccount(addr)
if vmAcc == nil {
return nil, fmt.Errorf("Unknown account %X", addr)
}
permN := ptypes.PermFlag(Uint64FromWord256(permNum)) // already shifted
if !ValidPermN(permN) {
return nil, ptypes.ErrInvalidPermission(permN)
}
var permInt byte
if vm.HasPermission(vmAcc, permN) {
permInt = 0x1
} else {
permInt = 0x0
}
return LeftPadWord256([]byte{permInt}).Bytes(), nil
}
func (vm *VM) setBasePerm(acc *Account, args []byte) (output []byte, err error) {
if !vm.HasPermission(acc, SetBasePerm) {
return nil, fmt.Errorf("acc %X does not have permission to call snative.SetBasePerm")
}
if len(args) != 3*32 {
return nil, fmt.Errorf("setBasePerm() takes three arguments (address, permission number, permission value)")
}
var addr, permNum, perm Word256
copy(addr[:], args[:32])
copy(permNum[:], args[32:64])
copy(perm[:], args[64:96])
vmAcc := vm.appState.GetAccount(addr)
if vmAcc == nil {
return nil, fmt.Errorf("Unknown account %X", addr)
}
permN := ptypes.PermFlag(Uint64FromWord256(permNum))
if !ValidPermN(permN) {
return nil, ptypes.ErrInvalidPermission(permN)
}
permV := !perm.IsZero()
if err = vmAcc.Permissions.Base.Set(permN, permV); err != nil {
return nil, err
}
vm.appState.UpdateAccount(vmAcc)
return perm.Bytes(), nil
}
func (vm *VM) unsetBasePerm(acc *Account, args []byte) (output []byte, err error) {
if !vm.HasPermission(acc, UnsetBasePerm) {
return nil, fmt.Errorf("acc %X does not have permission to call snative.UnsetBasePerm")
}
if len(args) != 2*32 {
return nil, fmt.Errorf("unsetBasePerm() takes two arguments (address, permission number)")
}
var addr, permNum Word256
copy(addr[:], args[:32])
copy(permNum[:], args[32:64])
vmAcc := vm.appState.GetAccount(addr)
if vmAcc == nil {
return nil, fmt.Errorf("Unknown account %X", addr)
}
permN := ptypes.PermFlag(Uint64FromWord256(permNum))
if !ValidPermN(permN) {
return nil, ptypes.ErrInvalidPermission(permN)
}
if err = vmAcc.Permissions.Base.Unset(permN); err != nil {
return nil, err
}
vm.appState.UpdateAccount(vmAcc)
return permNum.Bytes(), nil
}
func (vm *VM) setGlobalPerm(acc *Account, args []byte) (output []byte, err error) {
if len(args) != 2*32 {
return nil, fmt.Errorf("setGlobalPerm() takes three arguments (permission number, permission value)")
}
var permNum, perm Word256
copy(permNum[:], args[32:64])
copy(perm[:], args[64:96])
vmAcc := vm.appState.GetAccount(ptypes.GlobalPermissionsAddress256)
if vmAcc == nil {
panic("cant find the global permissions account")
}
permN := ptypes.PermFlag(Uint64FromWord256(permNum))
if !ValidPermN(permN) {
return nil, ptypes.ErrInvalidPermission(permN)
}
permV := !perm.IsZero()
if err = vmAcc.Permissions.Base.Set(permN, permV); err != nil {
return nil, err
}
vm.appState.UpdateAccount(vmAcc)
return perm.Bytes(), nil
}
// TODO: needs access to an iterator ...
func (vm *VM) clearPerm(acc *Account, args []byte) (output []byte, err error) {
if !vm.HasPermission(acc, ClearBasePerm) {
return nil, fmt.Errorf("acc %X does not have permission to call snative.ClearBasePerm")
}
return nil, nil
}
func (vm *VM) hasRole(acc *Account, args []byte) (output []byte, err error) {
if !vm.HasPermission(acc, HasRole) {
return nil, fmt.Errorf("acc %X does not have permission to call snative.HasRole")
}
if len(args) != 2*32 {
return nil, fmt.Errorf("hasRole() takes two arguments (address, role)")
}
var addr, role Word256
copy(addr[:], args[32:64])
copy(role[:], args[64:96])
vmAcc := vm.appState.GetAccount(addr)
if vmAcc == nil {
return nil, fmt.Errorf("Unknown account %X", addr)
}
roleS := string(role.Bytes())
var permInt byte
if vmAcc.Permissions.HasRole(roleS) {
permInt = 0x1
} else {
permInt = 0x0
}
return LeftPadWord256([]byte{permInt}).Bytes(), nil
}
func (vm *VM) addRole(acc *Account, args []byte) (output []byte, err error) {
if !vm.HasPermission(acc, AddRole) {
return nil, fmt.Errorf("acc %X does not have permission to call snative.AddRole")
}
if len(args) != 2*32 {
return nil, fmt.Errorf("addRole() takes two arguments (address, role)")
}
var addr, role Word256
copy(addr[:], args[32:64])
copy(role[:], args[64:96])
vmAcc := vm.appState.GetAccount(addr)
if vmAcc == nil {
return nil, fmt.Errorf("Unknown account %X", addr)
}
roleS := string(role.Bytes())
var permInt byte
if vmAcc.Permissions.AddRole(roleS) {
permInt = 0x1
} else {
permInt = 0x0
}
return LeftPadWord256([]byte{permInt}).Bytes(), nil
}
func (vm *VM) rmRole(acc *Account, args []byte) (output []byte, err error) {
if !vm.HasPermission(acc, RmRole) {
return nil, fmt.Errorf("acc %X does not have permission to call snative.RmRole")
}
if len(args) != 2*32 {
return nil, fmt.Errorf("rmRole() takes two arguments (address, role)")
}
var addr, role Word256
copy(addr[:], args[32:64])
copy(role[:], args[64:96])
vmAcc := vm.appState.GetAccount(addr)
if vmAcc == nil {
return nil, fmt.Errorf("Unknown account %X", addr)
}
roleS := string(role.Bytes())
var permInt byte
if vmAcc.Permissions.RmRole(roleS) {
permInt = 0x1
} else {
permInt = 0x0
}
return LeftPadWord256([]byte{permInt}).Bytes(), nil
}