This commit is contained in:
Ethan Buchman
2015-07-07 14:07:56 -07:00
committed by Jae Kwon
parent 87ed1f5fda
commit ab2b1643cb
4 changed files with 182 additions and 142 deletions
-10
View File
@@ -89,13 +89,3 @@ func identityFunc(input []byte, gas *int64) (output []byte, err error) {
// Return identity
return input, nil
}
//-----------------------------------------------------------------------------
// Doug Contracts are stateful and must be set with closures wrapping the current tx cache
// Note they should be reset to refresh the closure or it will be stale
var dougContracts = make(map[Word256]NativeContract)
func (vm *VM) SetDougFunc(n Word256, f NativeContract) {
dougContracts[n] = f
}
+165
View File
@@ -0,0 +1,165 @@
package vm
import (
"fmt"
. "github.com/tendermint/tendermint/common"
ptypes "github.com/tendermint/tendermint/permission/types"
)
type SNativeContract func(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(args []byte) (output []byte, err error) {
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))
var permInt byte
if vm.HasPermission(vmAcc, permN) {
permInt = 0x1
} else {
permInt = 0x0
}
return LeftPadWord256([]byte{permInt}).Bytes(), nil
}
func (vm *VM) setBasePerm(args []byte) (output []byte, err error) {
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))
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(args []byte) (output []byte, err error) {
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 err = vmAcc.Permissions.Base.Unset(permN); err != nil {
return nil, err
}
vm.appState.UpdateAccount(vmAcc)
return permNum.Bytes(), nil
}
func (vm *VM) setGlobalPerm(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))
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(args []byte) (output []byte, err error) {
return nil, nil
}
func (vm *VM) hasRole(args []byte) (output []byte, err error) {
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(args []byte) (output []byte, err error) {
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(args []byte) (output []byte, err error) {
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
}
+15 -5
View File
@@ -61,8 +61,9 @@ type VM struct {
evc events.Fireable
doug bool // is this the gendoug contract
perms bool // permission checking can be turned off
doug bool // is this the gendoug contract
perms bool // permission checking can be turned off
snativeContracts map[Word256]SNativeContract
}
func NewVM(appState AppState, params Params, origin Word256, txid []byte) *VM {
@@ -84,6 +85,15 @@ func (vm *VM) SetFireable(evc events.Fireable) {
// to allow calls to native DougContracts (off by default)
func (vm *VM) EnableDoug() {
vm.doug = true
vm.snativeContracts = map[Word256]SNativeContract{
RightPadWord256([]byte("hasBasePerm")): vm.hasBasePerm,
RightPadWord256([]byte("setBasePerm")): vm.setBasePerm,
RightPadWord256([]byte("unsetBasePerm")): vm.unsetBasePerm,
RightPadWord256([]byte("setGlobalPerm")): vm.setGlobalPerm,
RightPadWord256([]byte("hasRole")): vm.hasRole,
RightPadWord256([]byte("addRole")): vm.addRole,
RightPadWord256([]byte("rmRole")): vm.rmRole,
}
}
// run permission checks before call and create
@@ -747,10 +757,10 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
if nativeContract := nativeContracts[addr]; nativeContract != nil {
// Native contract
ret, err = nativeContract(args, &gasLimit)
} else if dougContract := dougContracts[addr]; vm.doug && dougContract != nil {
// This is Doug and we're calling a doug contract
} else if snativeContract := vm.snativeContracts[addr]; vm.doug && snativeContract != nil {
// This is Doug and we're calling a snative contract
// TODO: Doug contract should have all permissions
ret, err = dougContract(args, &gasLimit)
ret, err = snativeContract(args)
} else {
// EVM contract
if ok = useGas(gas, GasGetAccount); !ok {