mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-08 22:23:11 +00:00
snative
This commit is contained in:
@@ -462,10 +462,8 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
||||
// NOTE: Call() transfers the value from caller to callee iff call succeeds.
|
||||
|
||||
if isDoug {
|
||||
// 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
|
||||
// permissions
|
||||
// setupDoug(vmach, txCache, _s)
|
||||
// enables the snative contracts
|
||||
vmach.EnableDoug() // setupDoug(vmach, txCache, _s)
|
||||
}
|
||||
|
||||
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
|
||||
@@ -831,126 +829,3 @@ func hasBondPermission(state AccountGetter, accs map[string]*account.Account) bo
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
// permission management functions
|
||||
// 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!)
|
||||
func setupDoug(vmach *vm.VM, txCache *TxCache, _s *State) {
|
||||
|
||||
// get takes (address, permissionNum Word256), returns a permission int
|
||||
getFunc := func(args []byte, gas *uint64) (output []byte, err error) {
|
||||
if len(args) != 2*32 {
|
||||
return nil, fmt.Errorf("Get() takes two arguments (address, permission number)")
|
||||
}
|
||||
var addr, permNum Word256
|
||||
copy(addr[:], args[:32])
|
||||
copy(permNum[:], args[32:64])
|
||||
vmAcc := txCache.GetAccount(addr)
|
||||
if vmAcc == nil {
|
||||
return nil, fmt.Errorf("Unknown account %X", addr)
|
||||
}
|
||||
stAcc := toStateAccount(vmAcc)
|
||||
permN := uint(Uint64FromWord256(permNum))
|
||||
perm, err := stAcc.Permissions.Base.Get(permN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var permInt byte
|
||||
if perm {
|
||||
permInt = 0x1
|
||||
} else {
|
||||
permInt = 0x0
|
||||
}
|
||||
return LeftPadWord256([]byte{permInt}).Bytes(), nil
|
||||
}
|
||||
|
||||
// set takes (address, permissionNum, permissionValue Word256), returns the permission value
|
||||
setFunc := func(args []byte, gas *uint64) (output []byte, err error) {
|
||||
if len(args) != 3*32 {
|
||||
return nil, fmt.Errorf("Set() 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 := txCache.GetAccount(addr)
|
||||
if vmAcc == nil {
|
||||
return nil, fmt.Errorf("Unknown account %X", addr)
|
||||
}
|
||||
stAcc := toStateAccount(vmAcc)
|
||||
permN := uint(Uint64FromWord256(permNum))
|
||||
permV := !perm.IsZero()
|
||||
if err = stAcc.Permissions.Base.Set(permN, permV); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vmAcc = toVMAccount(stAcc)
|
||||
txCache.UpdateAccount(vmAcc)
|
||||
return perm.Bytes(), nil
|
||||
}
|
||||
|
||||
// add creates a new permission at the next available index and returns the index
|
||||
addFunc := func(args []byte, gas *uint64) (output []byte, err error) {
|
||||
if len(args) != 0 {
|
||||
return nil, fmt.Errorf("Add() takes no arguments")
|
||||
}
|
||||
|
||||
accounts := _s.GetAccounts()
|
||||
size := accounts.Size()
|
||||
var l int
|
||||
for i := uint64(0); i < size; i++ {
|
||||
_, v := accounts.GetByIndex(uint64(i))
|
||||
acc := v.(*account.Account)
|
||||
|
||||
if i == 0 {
|
||||
l = len(acc.Permissions.Other)
|
||||
} else if l != len(acc.Permissions.Other) {
|
||||
panic(Fmt("Accounts have different numbers of permissions: %v, %v", l, acc.Permissions.Other))
|
||||
}
|
||||
if _, err := acc.Permissions.Add(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txCache.UpdateAccount(toVMAccount(acc))
|
||||
}
|
||||
return Uint64ToWord256(uint64(l)).Bytes(), nil
|
||||
}
|
||||
|
||||
// rm takes (permissionNum) and removes the corresponding permission, shortening the `Other` list.
|
||||
// returns the permissionNum
|
||||
rmFunc := func(args []byte, gas *uint64) (output []byte, err error) {
|
||||
if len(args) != 32 {
|
||||
return nil, fmt.Errorf("Get() takes one argument (permissionNum)")
|
||||
}
|
||||
var permNum Word256
|
||||
copy(permNum[:], args[:32])
|
||||
permN := uint(Uint64FromWord256(permNum)) // danger?
|
||||
|
||||
accounts := _s.GetAccounts()
|
||||
size := accounts.Size()
|
||||
var l int
|
||||
for i := uint64(0); i < size; i++ {
|
||||
_, v := accounts.GetByIndex(uint64(i))
|
||||
acc := v.(*account.Account)
|
||||
|
||||
if i == 0 {
|
||||
l = len(acc.Permissions.Other)
|
||||
} else if l != len(acc.Permissions.Other) {
|
||||
panic(Fmt("Accounts have different numbers of permissions: %v, %v", l, acc.Permissions.Other))
|
||||
}
|
||||
acc.Permissions.Remove(permN)
|
||||
txCache.UpdateAccount(toVMAccount(acc))
|
||||
}
|
||||
return args, nil
|
||||
|
||||
}
|
||||
|
||||
// Set the native contract addresses and functions
|
||||
vmach.SetDougFunc(RightPadWord256([]byte("get")), vm.NativeContract(getFunc))
|
||||
vmach.SetDougFunc(RightPadWord256([]byte("set")), vm.NativeContract(setFunc))
|
||||
vmach.SetDougFunc(RightPadWord256([]byte("add")), vm.NativeContract(addFunc))
|
||||
vmach.SetDougFunc(RightPadWord256([]byte("rm")), vm.NativeContract(rmFunc))
|
||||
|
||||
// must be called or else functions not accessible
|
||||
vmach.EnableDoug()
|
||||
}
|
||||
*/
|
||||
|
||||
10
vm/native.go
10
vm/native.go
@@ -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
vm/snative.go
Normal file
165
vm/snative.go
Normal 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
|
||||
}
|
||||
20
vm/vm.go
20
vm/vm.go
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user