PermFlag rename; Make Permission fields value (nonpointer) fields; Permissions & Snatives on by default; Remove dead code

This commit is contained in:
Jae Kwon
2015-07-07 14:26:05 -07:00
parent 21295f4ae2
commit a999a4bad0
14 changed files with 88 additions and 199 deletions

View File

@ -28,7 +28,7 @@ test: build
draw_deps: draw_deps:
# requires brew install graphviz # requires brew install graphviz
go get github.com/hirokidaichi/goviz go get github.com/hirokidaichi/goviz
goviz -i github.com/tendermint/tendermint/cmd/tendermint | dot -Tpng -o hoge.png goviz -i github.com/tendermint/tendermint/cmd/tendermint | dot -Tpng -o huge.png
list_deps: list_deps:
go list -f '{{join .Deps "\n"}}' github.com/tendermint/tendermint/... | xargs go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' go list -f '{{join .Deps "\n"}}' github.com/tendermint/tendermint/... | xargs go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}'

View File

@ -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.AccountPermissions `json:"permissions"` Permissions ptypes.AccountPermissions `json:"permissions"`
} }
func (acc *Account) Copy() *Account { func (acc *Account) Copy() *Account {
@ -55,7 +55,7 @@ func (acc *Account) Copy() *Account {
func (acc *Account) String() string { func (acc *Account) String() string {
// return fmt.Sprintf("Account{%X:%v C:%v S:%X}", acc.Address, acc.PubKey, len(acc.Code), acc.StorageRoot) // return fmt.Sprintf("Account{%X:%v C:%v S:%X}", acc.Address, acc.PubKey, len(acc.Code), acc.StorageRoot)
return fmt.Sprintf("Account{%X:%v C:%v S:%X P:(%s)}", acc.Address, acc.PubKey, len(acc.Code), acc.StorageRoot, acc.Permissions) return fmt.Sprintf("Account{%X:%v C:%v S:%X P:%s}", acc.Address, acc.PubKey, len(acc.Code), acc.StorageRoot, acc.Permissions)
} }
func AccountEncoder(o interface{}, w io.Writer, n *int64, err *error) { func AccountEncoder(o interface{}, w io.Writer, n *int64, err *error) {

View File

@ -14,27 +14,6 @@ func (e ErrInvalidPermission) Error() string {
return fmt.Sprintf("invalid permission %d", e) 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 // set=false. This error should be caught and the global
// value fetched for the permission by the caller // value fetched for the permission by the caller
type ErrValueNotSet PermFlag type ErrValueNotSet PermFlag

View File

@ -3,7 +3,6 @@ package types
import ( import (
"fmt" "fmt"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"reflect"
) )
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
@ -20,34 +19,34 @@ type PermFlag uint64
// Base permission references are like unix (the index is already bit shifted) // Base permission references are like unix (the index is already bit shifted)
const ( const (
Root PermFlag = 1 << iota // 1 Root PermFlag = 1 << iota // 1
Send // 2 Send // 2
Call // 4 Call // 4
CreateContract // 8 CreateContract // 8
CreateAccount // 16 CreateAccount // 16
Bond // 32 Bond // 32
Name // 64 Name // 64
NumBasePermissions uint = 7 // NOTE Adjust this too.
DefaultBBPB = Send | Call | CreateContract | CreateAccount | Bond | Name TopBasePermFlag PermFlag = 1 << (NumBasePermissions - 1)
AllBasePermFlags PermFlag = TopBasePermFlag | (TopBasePermFlag - 1)
// XXX: must be adjusted if base perms added/removed AllPermFlags PermFlag = AllBasePermFlags | AllSNativePermFlags
NumBasePermissions uint = 7 DefaultBasePermFlags PermFlag = Send | Call | CreateContract | CreateAccount | Bond | Name
TopBasePermission PermFlag = 1 << (NumBasePermissions - 1)
AllBasePermissions PermFlag = TopBasePermission | (TopBasePermission - 1)
AllSet PermFlag = AllBasePermissions | AllSNativePermissions
) )
// should have same ordering as above var (
type BasePermissionsString struct { ZeroBasePermissions = BasePermissions{0, 0}
Root bool `json:"root,omitempty"` ZeroAccountPermissions = AccountPermissions{
Send bool `json:"send,omitempty"` Base: ZeroBasePermissions,
Call bool `json:"call,omitempty"` }
CreateContract bool `json:"create_contract,omitempty"` DefaultAccountPermissions = AccountPermissions{
CreateAccount bool `json:"create_account,omitempty"` Base: BasePermissions{
Bond bool `json:"bond,omitempty"` Perms: DefaultBasePermFlags,
Name bool `json:"name,omitempty"` SetBit: AllPermFlags,
} },
Roles: []string{},
}
)
//--------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------
@ -60,10 +59,6 @@ type BasePermissions struct {
SetBit PermFlag `json:"set"` SetBit PermFlag `json:"set"`
} }
func NewBasePermissions() *BasePermissions {
return &BasePermissions{0, 0}
}
// Get a permission value. ty should be a power of 2. // Get a permission value. ty should be a power of 2.
// ErrValueNotSet is returned if the permission's set bit is off, // ErrValueNotSet is returned if the permission's set bit is off,
// and should be caught by caller so the global permission can be fetched // and should be caught by caller so the global permission can be fetched
@ -108,32 +103,15 @@ func (p *BasePermissions) IsSet(ty PermFlag) bool {
return p.SetBit&ty > 0 return p.SetBit&ty > 0
} }
func (p *BasePermissions) Copy() *BasePermissions { func (p BasePermissions) String() string {
if p == nil {
return nil
}
return &BasePermissions{
Perms: p.Perms,
SetBit: p.SetBit,
}
}
func (p *BasePermissions) String() string {
return fmt.Sprintf("Base: %b; Set: %b", p.Perms, p.SetBit) return fmt.Sprintf("Base: %b; Set: %b", p.Perms, p.SetBit)
} }
//--------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------
type AccountPermissions struct { type AccountPermissions struct {
Base *BasePermissions `json:"base"` Base BasePermissions `json:"base"`
Roles []string `json:"roles"` Roles []string `json:"roles"`
}
func NewAccountPermissions() *AccountPermissions {
return &AccountPermissions{
Base: NewBasePermissions(),
Roles: []string{},
}
} }
// Returns true if the role is found // Returns true if the role is found
@ -175,75 +153,7 @@ func (aP *AccountPermissions) RmRole(role string) bool {
return false return false
} }
func (aP *AccountPermissions) Copy() *AccountPermissions { //--------------------------------------------------------------------------------
if aP == nil {
return nil
}
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{},
}
}
//---------------------------------------------------------------------------------------------
// Utilities to make bitmasks human readable
func NewDefaultAccountPermissionsString() BasePermissionsString {
return BasePermissionsString{
Root: false,
Bond: true,
Send: true,
Call: true,
Name: true,
CreateAccount: true,
CreateContract: true,
}
}
func AccountPermissionsFromStrings(perms *BasePermissionsString, roles []string) (*AccountPermissions, error) {
base := NewBasePermissions()
permRv := reflect.ValueOf(perms)
for i := uint(0); i < uint(permRv.NumField()); i++ {
v := permRv.Field(int(i)).Bool()
base.Set(1<<i, v)
}
aP := &AccountPermissions{
Base: base,
Roles: make([]string, len(roles)),
}
copy(aP.Roles, roles)
return aP, nil
}
func AccountPermissionsToStrings(aP *AccountPermissions) (*BasePermissionsString, []string, error) {
perms := new(BasePermissionsString)
permsRv := reflect.ValueOf(perms).Elem()
for i := uint(0); i < NumBasePermissions; i++ {
pf := PermFlag(1 << i)
if aP.Base.IsSet(pf) {
// won't err if the bit is set
v, _ := aP.Base.Get(pf)
f := permsRv.Field(int(i))
f.SetBool(v)
}
}
roles := make([]string, len(aP.Roles))
copy(roles, aP.Roles)
return perms, roles, nil
}
func PermFlagToString(pf PermFlag) (perm string, err error) { func PermFlagToString(pf PermFlag) (perm string, err error) {
switch pf { switch pf {

View File

@ -2,13 +2,13 @@ package types
const ( const (
// first 32 bits of BasePermission are for chain, second 32 are for snative // first 32 bits of BasePermission are for chain, second 32 are for snative
FirstSNativePerm PermFlag = 1 << 32 FirstSNativePermFlag PermFlag = 1 << 32
) )
// we need to reset iota with no const block // we need to reset iota with no const block
const ( const (
// each snative has an associated permission flag // each snative has an associated permission flag
HasBasePerm PermFlag = FirstSNativePerm << iota HasBasePerm PermFlag = FirstSNativePermFlag << iota
SetBasePerm SetBasePerm
UnsetBasePerm UnsetBasePerm
SetGlobalPerm SetGlobalPerm
@ -16,9 +16,8 @@ const (
HasRole HasRole
AddRole AddRole
RmRole RmRole
NumSNativePermissions uint = 8 // NOTE adjust this too
// XXX: must be adjusted if snative's added/removed TopSNativePermFlag PermFlag = FirstSNativePermFlag << (NumSNativePermissions - 1)
NumSNativePermissions uint = 8 AllSNativePermFlags PermFlag = (TopSNativePermFlag | (TopSNativePermFlag - 1)) &^ (FirstSNativePermFlag - 1)
TopSNativePermission PermFlag = FirstSNativePerm << (NumSNativePermissions - 1)
AllSNativePermissions PermFlag = (TopSNativePermission | (TopSNativePermission - 1)) &^ (FirstSNativePerm - 1)
) )

View File

@ -187,7 +187,7 @@ func getOrMakeOutputs(state AccountGetter, accounts map[string]*account.Account,
PubKey: nil, PubKey: nil,
Sequence: 0, Sequence: 0,
Balance: 0, Balance: 0,
Permissions: ptypes.NewAccountPermissions(), Permissions: ptypes.ZeroAccountPermissions,
} }
} }
accounts[string(out.Address)] = acc accounts[string(out.Address)] = acc
@ -293,7 +293,8 @@ func adjustByOutputs(accounts map[string]*account.Account, outs []*types.TxOutpu
// If the tx is invalid, an error will be returned. // If the tx is invalid, an error will be returned.
// Unlike ExecBlock(), state will not be altered. // Unlike ExecBlock(), state will not be altered.
func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Fireable) error { func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Fireable) (err error) {
// TODO: do something with fees // TODO: do something with fees
fees := int64(0) fees := int64(0)
_s := blockCache.State() // hack to access validators and block height _s := blockCache.State() // hack to access validators and block height
@ -467,9 +468,6 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
vmach := vm.NewVM(txCache, params, caller.Address, account.HashSignBytes(_s.ChainID, tx)) vmach := vm.NewVM(txCache, params, caller.Address, account.HashSignBytes(_s.ChainID, tx))
vmach.SetFireable(evc) vmach.SetFireable(evc)
vmach.EnablePermissions() // permission checks on CALL/CREATE
vmach.EnableSNatives() // allows calls to snatives (with permission checks)
// NOTE: Call() transfers the value from caller to callee iff call succeeds. // NOTE: Call() transfers the value from caller to callee iff call succeeds.
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas) ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
exception := "" exception := ""
@ -814,7 +812,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
// Get permission on an account or fall back to global value // Get permission on an account or fall back to global value
func HasPermission(state AccountGetter, acc *account.Account, perm ptypes.PermFlag) bool { func HasPermission(state AccountGetter, acc *account.Account, perm ptypes.PermFlag) bool {
if perm > ptypes.AllBasePermissions { if perm > ptypes.AllBasePermFlags {
panic("Checking an unknown permission in state should never happen") panic("Checking an unknown permission in state should never happen")
} }
@ -826,10 +824,14 @@ func HasPermission(state AccountGetter, acc *account.Account, perm ptypes.PermFl
v, err := acc.Permissions.Base.Get(perm) v, err := acc.Permissions.Base.Get(perm)
if _, ok := err.(ptypes.ErrValueNotSet); ok { if _, ok := err.(ptypes.ErrValueNotSet); ok {
log.Debug("Account does not have permission", "account", acc, "accPermissions", acc.Permissions, "perm", perm)
if state == nil { if state == nil {
panic("All known global permissions should be set!") panic("All known global permissions should be set!")
} }
log.Debug("Querying GlobalPermissionsAddress")
return HasPermission(nil, state.GetAccount(ptypes.GlobalPermissionsAddress), perm) return HasPermission(nil, state.GetAccount(ptypes.GlobalPermissionsAddress), perm)
} else {
log.Debug("Account has permission", "account", acc, "accPermissions", acc.Permissions, "perm", perm)
} }
return v return v
} }

View File

@ -88,9 +88,9 @@ 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 := ptypes.NewDefaultAccountPermissions() perm := ptypes.ZeroAccountPermissions
if genAcc.Permissions != nil { if genAcc.Permissions != nil {
perm = genAcc.Permissions perm = *genAcc.Permissions
} }
acc := &account.Account{ acc := &account.Account{
Address: genAcc.Address, Address: genAcc.Address,
@ -104,12 +104,12 @@ 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 := ptypes.NewDefaultAccountPermissions() globalPerms := ptypes.DefaultAccountPermissions
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 // XXX: make sure the set bits are all true
// Without it the HasPermission() functions will fail // Without it the HasPermission() functions will fail
globalPerms.Base.SetBit = ptypes.AllSet globalPerms.Base.SetBit = ptypes.AllPermFlags
} }
permsAcc := &account.Account{ permsAcc := &account.Account{

View File

@ -92,16 +92,17 @@ func makeUsers(n int) []*account.PrivAccount {
} }
var ( var (
PermsAllFalse = ptypes.NewAccountPermissions() PermsAllFalse = ptypes.ZeroAccountPermissions
) )
func newBaseGenDoc(globalPerm, accountPerm *ptypes.AccountPermissions) GenesisDoc { func newBaseGenDoc(globalPerm, accountPerm ptypes.AccountPermissions) GenesisDoc {
genAccounts := []GenesisAccount{} genAccounts := []GenesisAccount{}
for _, u := range user[:5] { for _, u := range user[:5] {
accountPermCopy := accountPerm // Create new instance for custom overridability.
genAccounts = append(genAccounts, GenesisAccount{ genAccounts = append(genAccounts, GenesisAccount{
Address: u.Address, Address: u.Address,
Amount: 1000000, Amount: 1000000,
Permissions: accountPerm.Copy(), Permissions: &accountPermCopy,
}) })
} }
@ -109,7 +110,7 @@ func newBaseGenDoc(globalPerm, accountPerm *ptypes.AccountPermissions) GenesisDo
GenesisTime: time.Now(), GenesisTime: time.Now(),
ChainID: chainID, ChainID: chainID,
Params: &GenesisParams{ Params: &GenesisParams{
GlobalPermissions: globalPerm, GlobalPermissions: &globalPerm,
}, },
Accounts: genAccounts, Accounts: genAccounts,
Validators: []GenesisValidator{ Validators: []GenesisValidator{
@ -353,7 +354,7 @@ func TestCallPermission(t *testing.T) {
Code: []byte{0x60}, Code: []byte{0x60},
Sequence: 0, Sequence: 0,
StorageRoot: Zero256.Bytes(), StorageRoot: Zero256.Bytes(),
Permissions: ptypes.NewAccountPermissions(), Permissions: ptypes.ZeroAccountPermissions,
} }
st.UpdateAccount(simpleAcc) st.UpdateAccount(simpleAcc)
@ -377,7 +378,7 @@ func TestCallPermission(t *testing.T) {
Code: contractCode, Code: contractCode,
Sequence: 0, Sequence: 0,
StorageRoot: Zero256.Bytes(), StorageRoot: Zero256.Bytes(),
Permissions: ptypes.NewAccountPermissions(), Permissions: ptypes.ZeroAccountPermissions,
} }
blockCache.UpdateAccount(caller1Acc) blockCache.UpdateAccount(caller1Acc)
@ -421,7 +422,7 @@ func TestCallPermission(t *testing.T) {
Code: contractCode2, Code: contractCode2,
Sequence: 0, Sequence: 0,
StorageRoot: Zero256.Bytes(), StorageRoot: Zero256.Bytes(),
Permissions: ptypes.NewAccountPermissions(), Permissions: ptypes.ZeroAccountPermissions,
} }
caller1Acc.Permissions.Base.Set(ptypes.Call, false) caller1Acc.Permissions.Base.Set(ptypes.Call, false)
caller2Acc.Permissions.Base.Set(ptypes.Call, true) caller2Acc.Permissions.Base.Set(ptypes.Call, true)
@ -553,7 +554,7 @@ func TestCreatePermission(t *testing.T) {
Code: code, Code: code,
Sequence: 0, Sequence: 0,
StorageRoot: Zero256.Bytes(), StorageRoot: Zero256.Bytes(),
Permissions: ptypes.NewAccountPermissions(), Permissions: ptypes.ZeroAccountPermissions,
} }
contractAcc.Permissions.Base.Set(ptypes.Call, true) contractAcc.Permissions.Base.Set(ptypes.Call, true)
contractAcc.Permissions.Base.Set(ptypes.CreateContract, true) contractAcc.Permissions.Base.Set(ptypes.CreateContract, true)
@ -805,7 +806,7 @@ func TestCreateAccountPermission(t *testing.T) {
Code: contractCode, Code: contractCode,
Sequence: 0, Sequence: 0,
StorageRoot: Zero256.Bytes(), StorageRoot: Zero256.Bytes(),
Permissions: ptypes.NewAccountPermissions(), Permissions: ptypes.ZeroAccountPermissions,
} }
blockCache.UpdateAccount(caller1Acc) blockCache.UpdateAccount(caller1Acc)
@ -856,7 +857,7 @@ func TestSNativeCALL(t *testing.T) {
Code: nil, Code: nil,
Sequence: 0, Sequence: 0,
StorageRoot: Zero256.Bytes(), StorageRoot: Zero256.Bytes(),
Permissions: ptypes.NewAccountPermissions(), Permissions: ptypes.ZeroAccountPermissions,
} }
doug.Permissions.Base.Set(ptypes.Call, true) doug.Permissions.Base.Set(ptypes.Call, true)
blockCache.UpdateAccount(doug) blockCache.UpdateAccount(doug)

View File

@ -25,7 +25,7 @@ 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 := ptypes.NewDefaultAccountPermissions() perms := ptypes.DefaultAccountPermissions
acc := &account.Account{ acc := &account.Account{
Address: privAccount.PubKey.Address(), Address: privAccount.PubKey.Address(),
PubKey: privAccount.PubKey, PubKey: privAccount.PubKey,
@ -73,12 +73,13 @@ func RandGenesisState(numAccounts int, randBalance bool, minBalance int64, numVa
db := dbm.NewMemDB() db := dbm.NewMemDB()
accounts := make([]GenesisAccount, numAccounts) accounts := make([]GenesisAccount, numAccounts)
privAccounts := make([]*account.PrivAccount, numAccounts) privAccounts := make([]*account.PrivAccount, numAccounts)
defaultPerms := ptypes.DefaultAccountPermissions
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(), Permissions: &defaultPerms, // This will get copied into each state.Account.
} }
privAccounts[i] = privAccount privAccounts[i] = privAccount
} }
@ -105,7 +106,7 @@ func RandGenesisState(numAccounts int, randBalance bool, minBalance int64, numVa
Accounts: accounts, Accounts: accounts,
Validators: validators, Validators: validators,
Params: &GenesisParams{ Params: &GenesisParams{
GlobalPermissions: ptypes.NewDefaultAccountPermissions(), GlobalPermissions: &defaultPerms,
}, },
}) })
s0.Save() s0.Save()

View File

@ -165,7 +165,7 @@ func toVMAccount(acc *ac.Account) *vm.Account {
Code: acc.Code, // This is crazy. Code: acc.Code, // This is crazy.
Nonce: int64(acc.Sequence), Nonce: int64(acc.Sequence),
StorageRoot: LeftPadWord256(acc.StorageRoot), StorageRoot: LeftPadWord256(acc.StorageRoot),
Permissions: acc.Permissions.Copy(), Permissions: acc.Permissions, // Copy
Other: acc.PubKey, Other: acc.PubKey,
} }
} }
@ -190,7 +190,7 @@ func toStateAccount(acc *vm.Account) *ac.Account {
Code: acc.Code, Code: acc.Code,
Sequence: int(acc.Nonce), Sequence: int(acc.Nonce),
StorageRoot: storageRoot, StorageRoot: storageRoot,
Permissions: acc.Permissions, Permissions: acc.Permissions, // Copy
} }
} }

View File

@ -224,9 +224,9 @@ func (e ErrInvalidPermission) Error() string {
// Checks if a permission flag is valid (a known base chain or snative permission) // Checks if a permission flag is valid (a known base chain or snative permission)
func ValidPermN(n ptypes.PermFlag) bool { func ValidPermN(n ptypes.PermFlag) bool {
if n > ptypes.TopBasePermission && n < ptypes.FirstSNativePerm { if n > ptypes.TopBasePermFlag && n < ptypes.FirstSNativePermFlag {
return false return false
} else if n > ptypes.TopSNativePermission { } else if n > ptypes.TopSNativePermFlag {
return false return false
} }
return true return true

View File

@ -10,16 +10,22 @@ 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" . "github.com/tendermint/tendermint/vm"
) )
func newAppState() *FakeAppState { func newAppState() *FakeAppState {
return &FakeAppState{ fas := &FakeAppState{
accounts: make(map[string]*Account), accounts: make(map[string]*Account),
storage: make(map[string]Word256), storage: make(map[string]Word256),
logs: nil, logs: nil,
} }
// For default permissions
fas.accounts[ptypes.GlobalPermissionsAddress256.String()] = &Account{
Permissions: ptypes.DefaultAccountPermissions,
}
return fas
} }
func newParams() Params { func newParams() Params {

View File

@ -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.AccountPermissions Permissions ptypes.AccountPermissions
} }
func (acc *Account) String() string { func (acc *Account) String() string {

View File

@ -60,9 +60,6 @@ type VM struct {
callDepth int callDepth int
evc events.Fireable evc events.Fireable
perms bool // permission checking can be turned off
snative bool // access to snatives
} }
func NewVM(appState AppState, params Params, origin Word256, txid []byte) *VM { func NewVM(appState AppState, params Params, origin Word256, txid []byte) *VM {
@ -80,25 +77,17 @@ func (vm *VM) SetFireable(evc events.Fireable) {
vm.evc = evc vm.evc = evc
} }
// to allow calls to native DougContracts (off by default) // CONTRACT: it is the duty of the contract writer to call known permissions
func (vm *VM) EnableSNatives() {
vm.snative = true
}
// run permission checks before call and create
func (vm *VM) EnablePermissions() {
vm.perms = true
}
// XXX: it is the duty of the contract writer to call known permissions
// we do not convey if a permission is not set // we do not convey if a permission is not set
// (unlike in state/execution, where we guarantee HasPermission is called // (unlike in state/execution, where we guarantee HasPermission is called
// on known permissions and panics else) // on known permissions and panics else)
// If the perm is not defined in the acc nor set by default in GlobalPermissions,
// prints a log warning and returns false.
func HasPermission(appState AppState, acc *Account, perm ptypes.PermFlag) bool { func HasPermission(appState AppState, acc *Account, perm ptypes.PermFlag) bool {
v, err := acc.Permissions.Base.Get(perm) v, err := acc.Permissions.Base.Get(perm)
if _, ok := err.(ptypes.ErrValueNotSet); ok { if _, ok := err.(ptypes.ErrValueNotSet); ok {
if appState == nil { if appState == nil {
fmt.Printf("\n\n***** Unknown permission %b! ********\n\n", perm) log.Warn(Fmt("\n\n***** Unknown permission %b! ********\n\n", perm))
return false return false
} }
return HasPermission(nil, appState.GetAccount(ptypes.GlobalPermissionsAddress256), perm) return HasPermission(nil, appState.GetAccount(ptypes.GlobalPermissionsAddress256), perm)
@ -125,8 +114,9 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas
} }
}() }()
// SNATIVE ACCESS
// if code is empty, callee may be snative contract // if code is empty, callee may be snative contract
if vm.snative && len(code) == 0 { if len(code) == 0 {
if snativeContract, ok := RegisteredSNativeContracts[callee.Address]; ok { if snativeContract, ok := RegisteredSNativeContracts[callee.Address]; ok {
output, err = snativeContract(vm.appState, caller, input) output, err = snativeContract(vm.appState, caller, input)
if err != nil { if err != nil {
@ -135,6 +125,7 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas
return return
} }
} }
// SNATIVE ACCESS END
if err = transfer(caller, callee, value); err != nil { if err = transfer(caller, callee, value); err != nil {
*exception = err.Error() *exception = err.Error()
@ -708,7 +699,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 && !HasPermission(vm.appState, callee, ptypes.CreateContract) { if !HasPermission(vm.appState, callee, ptypes.CreateContract) {
return nil, ErrPermission{"create_contract"} return nil, ErrPermission{"create_contract"}
} }
contractValue := stack.Pop64() contractValue := stack.Pop64()
@ -736,7 +727,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 && !HasPermission(vm.appState, callee, ptypes.Call) { if !HasPermission(vm.appState, callee, ptypes.Call) {
return nil, ErrPermission{"call"} return nil, ErrPermission{"call"}
} }
gasLimit := stack.Pop64() gasLimit := stack.Pop64()
@ -782,12 +773,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
ret, err = vm.Call(callee, callee, acc.Code, args, value, gas) ret, err = vm.Call(callee, callee, acc.Code, args, value, gas)
} else { } else {
if acc == nil { if acc == nil {
if _, ok := RegisteredSNativeContracts[addr]; vm.snative && ok { if _, ok := RegisteredSNativeContracts[addr]; ok {
acc = &Account{Address: addr} acc = &Account{Address: addr}
} else { } else {
// if we have not seen the account before, create it // if we have not seen the account before, create it
// so we can send funds // so we can send funds
if vm.perms && !HasPermission(vm.appState, caller, ptypes.CreateAccount) { if !HasPermission(vm.appState, caller, ptypes.CreateAccount) {
return nil, ErrPermission{"create_account"} return nil, ErrPermission{"create_account"}
} }
acc = &Account{Address: addr} acc = &Account{Address: addr}