mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-26 03:01:42 +00:00
snative refactor and SNativeTx
This commit is contained in:
@ -1,5 +1,9 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
)
|
||||||
|
|
||||||
func Fingerprint(slice []byte) []byte {
|
func Fingerprint(slice []byte) []byte {
|
||||||
fingerprint := make([]byte, 6)
|
fingerprint := make([]byte, 6)
|
||||||
copy(fingerprint, slice)
|
copy(fingerprint, slice)
|
||||||
@ -32,3 +36,9 @@ func LeftPadBytes(slice []byte, l int) []byte {
|
|||||||
copy(padded[l-len(slice):], slice)
|
copy(padded[l-len(slice):], slice)
|
||||||
return padded
|
return padded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TrimmedString(b []byte) string {
|
||||||
|
trimSet := string([]byte{0})
|
||||||
|
return string(bytes.TrimLeft(b, trimSet))
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -12,11 +12,12 @@ var (
|
|||||||
|
|
||||||
type Word256 [32]byte
|
type Word256 [32]byte
|
||||||
|
|
||||||
func (w Word256) String() string { return string(w[:]) }
|
func (w Word256) String() string { return string(w[:]) }
|
||||||
func (w Word256) Copy() Word256 { return w }
|
func (w Word256) TrimmedString() string { return TrimmedString(w.Bytes()) }
|
||||||
func (w Word256) Bytes() []byte { return w[:] } // copied.
|
func (w Word256) Copy() Word256 { return w }
|
||||||
func (w Word256) Prefix(n int) []byte { return w[:n] }
|
func (w Word256) Bytes() []byte { return w[:] } // copied.
|
||||||
func (w Word256) Postfix(n int) []byte { return w[32-n:] }
|
func (w Word256) Prefix(n int) []byte { return w[:n] }
|
||||||
|
func (w Word256) Postfix(n int) []byte { return w[32-n:] }
|
||||||
func (w Word256) IsZero() bool {
|
func (w Word256) IsZero() bool {
|
||||||
accum := byte(0)
|
accum := byte(0)
|
||||||
for _, byt := range w {
|
for _, byt := range w {
|
||||||
|
@ -154,8 +154,15 @@ func (aP *AccountPermissions) RmRole(role string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
|
func PermFlagToString(pf PermFlag) string {
|
||||||
|
if pf < FirstSNativePermFlag {
|
||||||
|
return BasePermFlagToString(pf)
|
||||||
|
} else {
|
||||||
|
return SNativePermFlagToString(pf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func PermFlagToString(pf PermFlag) (perm string, err error) {
|
func BasePermFlagToString(pf PermFlag) (perm string) {
|
||||||
switch pf {
|
switch pf {
|
||||||
case Root:
|
case Root:
|
||||||
perm = "root"
|
perm = "root"
|
||||||
@ -171,13 +178,11 @@ func PermFlagToString(pf PermFlag) (perm string, err error) {
|
|||||||
perm = "bond"
|
perm = "bond"
|
||||||
case Name:
|
case Name:
|
||||||
perm = "name"
|
perm = "name"
|
||||||
default:
|
|
||||||
err = fmt.Errorf("Unknown permission flag %b", pf)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func PermStringToFlag(perm string) (pf PermFlag, err error) {
|
func BasePermStringToFlag(perm string) (pf PermFlag, err error) {
|
||||||
switch perm {
|
switch perm {
|
||||||
case "root":
|
case "root":
|
||||||
pf = Root
|
pf = Root
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/tendermint/tendermint/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------
|
||||||
|
// snative permissions
|
||||||
|
|
||||||
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
|
||||||
FirstSNativePermFlag PermFlag = 1 << 32
|
FirstSNativePermFlag PermFlag = 1 << 32
|
||||||
@ -8,11 +17,11 @@ const (
|
|||||||
// 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 = FirstSNativePermFlag << iota
|
HasBase PermFlag = FirstSNativePermFlag << iota
|
||||||
SetBasePerm
|
SetBase
|
||||||
UnsetBasePerm
|
UnsetBase
|
||||||
SetGlobalPerm
|
SetGlobal
|
||||||
ClearBasePerm
|
ClearBase
|
||||||
HasRole
|
HasRole
|
||||||
AddRole
|
AddRole
|
||||||
RmRole
|
RmRole
|
||||||
@ -21,3 +30,160 @@ const (
|
|||||||
TopSNativePermFlag PermFlag = FirstSNativePermFlag << (NumSNativePermissions - 1)
|
TopSNativePermFlag PermFlag = FirstSNativePermFlag << (NumSNativePermissions - 1)
|
||||||
AllSNativePermFlags PermFlag = (TopSNativePermFlag | (TopSNativePermFlag - 1)) &^ (FirstSNativePermFlag - 1)
|
AllSNativePermFlags PermFlag = (TopSNativePermFlag | (TopSNativePermFlag - 1)) &^ (FirstSNativePermFlag - 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------
|
||||||
|
// snative tx interface and argument encoding
|
||||||
|
|
||||||
|
// SNatives are represented as an interface in the SNative tx,
|
||||||
|
// so binary does the work of handling args and determining which snative we're calling
|
||||||
|
// NOTE: we're definining an implicit map from registration bytes to perm flags
|
||||||
|
type SNativeArgs interface {
|
||||||
|
PermFlag() PermFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SNativeArgsTypeHasBase = byte(0x01)
|
||||||
|
SNativeArgsTypeSetBase = byte(0x02)
|
||||||
|
SNativeArgsTypeUnsetBase = byte(0x03)
|
||||||
|
SNativeArgsTypeSetGlobal = byte(0x04)
|
||||||
|
SNativeArgsTypeClearBase = byte(0x05)
|
||||||
|
SNativeArgsTypeHasRole = byte(0x06)
|
||||||
|
SNativeArgsTypeAddRole = byte(0x07)
|
||||||
|
SNativeArgsTypeRmRole = byte(0x08)
|
||||||
|
)
|
||||||
|
|
||||||
|
// for binary.readReflect
|
||||||
|
var _ = binary.RegisterInterface(
|
||||||
|
struct{ SNativeArgs }{},
|
||||||
|
binary.ConcreteType{&HasBaseArgs{}, SNativeArgsTypeHasBase},
|
||||||
|
binary.ConcreteType{&SetBaseArgs{}, SNativeArgsTypeSetBase},
|
||||||
|
binary.ConcreteType{&UnsetBaseArgs{}, SNativeArgsTypeUnsetBase},
|
||||||
|
binary.ConcreteType{&SetGlobalArgs{}, SNativeArgsTypeSetGlobal},
|
||||||
|
binary.ConcreteType{&ClearBaseArgs{}, SNativeArgsTypeClearBase},
|
||||||
|
binary.ConcreteType{&HasRoleArgs{}, SNativeArgsTypeHasRole},
|
||||||
|
binary.ConcreteType{&AddRoleArgs{}, SNativeArgsTypeAddRole},
|
||||||
|
binary.ConcreteType{&RmRoleArgs{}, SNativeArgsTypeRmRole},
|
||||||
|
)
|
||||||
|
|
||||||
|
type HasBaseArgs struct {
|
||||||
|
Address []byte
|
||||||
|
Permission PermFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HasBaseArgs) PermFlag() PermFlag {
|
||||||
|
return HasBase
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetBaseArgs struct {
|
||||||
|
Address []byte
|
||||||
|
Permission PermFlag
|
||||||
|
Value bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SetBaseArgs) PermFlag() PermFlag {
|
||||||
|
return SetBase
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnsetBaseArgs struct {
|
||||||
|
Address []byte
|
||||||
|
Permission PermFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*UnsetBaseArgs) PermFlag() PermFlag {
|
||||||
|
return UnsetBase
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetGlobalArgs struct {
|
||||||
|
Permission PermFlag
|
||||||
|
Value bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SetGlobalArgs) PermFlag() PermFlag {
|
||||||
|
return SetGlobal
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClearBaseArgs struct {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ClearBaseArgs) PermFlag() PermFlag {
|
||||||
|
return ClearBase
|
||||||
|
}
|
||||||
|
|
||||||
|
type HasRoleArgs struct {
|
||||||
|
Address []byte
|
||||||
|
Role string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HasRoleArgs) PermFlag() PermFlag {
|
||||||
|
return HasRole
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddRoleArgs struct {
|
||||||
|
Address []byte
|
||||||
|
Role string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AddRoleArgs) PermFlag() PermFlag {
|
||||||
|
return AddRole
|
||||||
|
}
|
||||||
|
|
||||||
|
type RmRoleArgs struct {
|
||||||
|
Address []byte
|
||||||
|
Role string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*RmRoleArgs) PermFlag() PermFlag {
|
||||||
|
return RmRole
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------
|
||||||
|
// string utilities
|
||||||
|
|
||||||
|
func SNativePermFlagToString(pF PermFlag) (perm string) {
|
||||||
|
switch pF {
|
||||||
|
case HasBase:
|
||||||
|
perm = "HasBase"
|
||||||
|
case SetBase:
|
||||||
|
perm = "SetBase"
|
||||||
|
case UnsetBase:
|
||||||
|
perm = "UnsetBase"
|
||||||
|
case SetGlobal:
|
||||||
|
perm = "SetGlobal"
|
||||||
|
case ClearBase:
|
||||||
|
perm = "ClearBase"
|
||||||
|
case HasRole:
|
||||||
|
perm = "HasRole"
|
||||||
|
case AddRole:
|
||||||
|
perm = "AddRole"
|
||||||
|
case RmRole:
|
||||||
|
perm = "RmRole"
|
||||||
|
default:
|
||||||
|
perm = "#-UNKNOWN-#"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SNativeStringToPermFlag(perm string) (pF PermFlag, err error) {
|
||||||
|
switch perm {
|
||||||
|
case "HasBase":
|
||||||
|
pF = HasBase
|
||||||
|
case "SetBase":
|
||||||
|
pF = SetBase
|
||||||
|
case "UnsetBase":
|
||||||
|
pF = UnsetBase
|
||||||
|
case "SetGlobal":
|
||||||
|
pF = SetGlobal
|
||||||
|
case "ClearBase":
|
||||||
|
pF = ClearBase
|
||||||
|
case "HasRole":
|
||||||
|
pF = HasRole
|
||||||
|
case "AddRole":
|
||||||
|
pF = AddRole
|
||||||
|
case "RmRole":
|
||||||
|
pF = RmRole
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("Unknown permission %s", perm)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -424,26 +424,26 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
|
|
||||||
if outAcc == nil || len(outAcc.Code) == 0 {
|
if outAcc == nil || len(outAcc.Code) == 0 {
|
||||||
// check if its an snative
|
// check if its an snative
|
||||||
if _, ok := vm.RegisteredSNativeContracts[LeftPadWord256(tx.Address)]; ok {
|
trimmedAddr := TrimmedString(tx.Address)
|
||||||
// set the outAcc (simply a placeholder until we reach the call)
|
if _, unknownPermErr := ptypes.SNativeStringToPermFlag(string(trimmedAddr)); unknownPermErr == nil {
|
||||||
outAcc = &acm.Account{Address: tx.Address}
|
return fmt.Errorf("SNatives can not be called using CallTx. Either use a contract or a SNativeTx")
|
||||||
} else {
|
|
||||||
// if you call an account that doesn't exist
|
|
||||||
// or an account with no code then we take fees (sorry pal)
|
|
||||||
// NOTE: it's fine to create a contract and call it within one
|
|
||||||
// block (nonce will prevent re-ordering of those txs)
|
|
||||||
// but to create with one account and call with another
|
|
||||||
// you have to wait a block to avoid a re-ordering attack
|
|
||||||
// that will take your fees
|
|
||||||
inAcc.Balance -= tx.Fee
|
|
||||||
blockCache.UpdateAccount(inAcc)
|
|
||||||
if outAcc == nil {
|
|
||||||
log.Info(Fmt("Cannot find destination address %X. Deducting fee from caller", tx.Address))
|
|
||||||
} else {
|
|
||||||
log.Info(Fmt("Attempting to call an account (%X) with no code. Deducting fee from caller", tx.Address))
|
|
||||||
}
|
|
||||||
return types.ErrTxInvalidAddress
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if you call an account that doesn't exist
|
||||||
|
// or an account with no code then we take fees (sorry pal)
|
||||||
|
// NOTE: it's fine to create a contract and call it within one
|
||||||
|
// block (nonce will prevent re-ordering of those txs)
|
||||||
|
// but to create with one account and call with another
|
||||||
|
// you have to wait a block to avoid a re-ordering attack
|
||||||
|
// that will take your fees
|
||||||
|
inAcc.Balance -= tx.Fee
|
||||||
|
blockCache.UpdateAccount(inAcc)
|
||||||
|
if outAcc == nil {
|
||||||
|
log.Info(Fmt("Cannot find destination address %X. Deducting fee from caller", tx.Address))
|
||||||
|
} else {
|
||||||
|
log.Info(Fmt("Attempting to call an account (%X) with no code. Deducting fee from caller", tx.Address))
|
||||||
|
}
|
||||||
|
return types.ErrTxInvalidAddress
|
||||||
}
|
}
|
||||||
callee = toVMAccount(outAcc)
|
callee = toVMAccount(outAcc)
|
||||||
code = callee.Code
|
code = callee.Code
|
||||||
@ -697,6 +697,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
PanicCrisis("Failed to add validator")
|
PanicCrisis("Failed to add validator")
|
||||||
}
|
}
|
||||||
if evc != nil {
|
if evc != nil {
|
||||||
|
// TODO: fire for all inputs
|
||||||
evc.FireEvent(types.EventStringBond(), tx)
|
evc.FireEvent(types.EventStringBond(), tx)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -793,6 +794,100 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
case *types.SNativeTx:
|
||||||
|
var inAcc *acm.Account
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
inAcc = blockCache.GetAccount(tx.Input.Address)
|
||||||
|
if inAcc == nil {
|
||||||
|
log.Debug(Fmt("Can't find in account %X", tx.Input.Address))
|
||||||
|
return types.ErrTxInvalidAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
permFlag := tx.SNative.PermFlag()
|
||||||
|
// check permission
|
||||||
|
if !hasSNativePermission(blockCache, inAcc, permFlag) {
|
||||||
|
return fmt.Errorf("Account %X does not have permission to call snative %s (%b)", tx.Input.Address, tx.SNative, permFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pubKey should be present in either "inAcc" or "tx.Input"
|
||||||
|
if err := checkInputPubKey(inAcc, tx.Input); err != nil {
|
||||||
|
log.Debug(Fmt("Can't find pubkey for %X", tx.Input.Address))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
signBytes := acm.SignBytes(_s.ChainID, tx)
|
||||||
|
err := validateInput(inAcc, signBytes, tx.Input)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug(Fmt("validateInput failed on %X: %v", tx.Input.Address, err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := tx.Input.Amount
|
||||||
|
|
||||||
|
log.Debug("New SNativeTx", "snative", ptypes.SNativePermFlagToString(permFlag), "args", tx.SNative)
|
||||||
|
|
||||||
|
var permAcc *acm.Account
|
||||||
|
switch args := tx.SNative.(type) {
|
||||||
|
case *ptypes.HasBaseArgs:
|
||||||
|
// this one doesn't make sense from txs
|
||||||
|
return fmt.Errorf("HasBase is for contracts, not humans. Just look at the blockchain")
|
||||||
|
case *ptypes.SetBaseArgs:
|
||||||
|
if permAcc = blockCache.GetAccount(args.Address); permAcc == nil {
|
||||||
|
return fmt.Errorf("Trying to update permissions for unknown account %X", args.Address)
|
||||||
|
}
|
||||||
|
err = permAcc.Permissions.Base.Set(args.Permission, args.Value)
|
||||||
|
case *ptypes.UnsetBaseArgs:
|
||||||
|
if permAcc = blockCache.GetAccount(args.Address); permAcc == nil {
|
||||||
|
return fmt.Errorf("Trying to update permissions for unknown account %X", args.Address)
|
||||||
|
}
|
||||||
|
err = permAcc.Permissions.Base.Unset(args.Permission)
|
||||||
|
case *ptypes.SetGlobalArgs:
|
||||||
|
if permAcc = blockCache.GetAccount(ptypes.GlobalPermissionsAddress); permAcc == nil {
|
||||||
|
// PanicSanity("can't find global permissions account")
|
||||||
|
}
|
||||||
|
err = permAcc.Permissions.Base.Set(args.Permission, args.Value)
|
||||||
|
case *ptypes.ClearBaseArgs:
|
||||||
|
//
|
||||||
|
case *ptypes.HasRoleArgs:
|
||||||
|
return fmt.Errorf("HasRole is for contracts, not humans. Just look at the blockchain")
|
||||||
|
case *ptypes.AddRoleArgs:
|
||||||
|
if permAcc = blockCache.GetAccount(args.Address); permAcc == nil {
|
||||||
|
return fmt.Errorf("Trying to update roles for unknown account %X", args.Address)
|
||||||
|
}
|
||||||
|
if !permAcc.Permissions.AddRole(args.Role) {
|
||||||
|
return fmt.Errorf("Role (%s) already exists for account %X", args.Role, args.Address)
|
||||||
|
}
|
||||||
|
case *ptypes.RmRoleArgs:
|
||||||
|
if permAcc = blockCache.GetAccount(args.Address); permAcc == nil {
|
||||||
|
return fmt.Errorf("Trying to update roles for unknown account %X", args.Address)
|
||||||
|
}
|
||||||
|
if !permAcc.Permissions.RmRole(args.Role) {
|
||||||
|
return fmt.Errorf("Role (%s) does not exist for account %X", args.Role, args.Address)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// PanicSanity("invalid snative")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: maybe we want to take funds on error and allow txs in that don't do anythingi?
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good!
|
||||||
|
inAcc.Sequence += 1
|
||||||
|
inAcc.Balance -= value
|
||||||
|
blockCache.UpdateAccount(inAcc)
|
||||||
|
if permAcc != nil {
|
||||||
|
blockCache.UpdateAccount(permAcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
if evc != nil {
|
||||||
|
evc.FireEvent(types.EventStringAccInput(tx.Input.Address), tx)
|
||||||
|
evc.FireEvent(types.EventStringSNative(ptypes.SNativePermFlagToString(permFlag)), tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// binary decoding should not let this happen
|
// binary decoding should not let this happen
|
||||||
PanicSanity("Unknown Tx type")
|
PanicSanity("Unknown Tx type")
|
||||||
@ -804,7 +899,8 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
|
|
||||||
// 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 *acm.Account, perm ptypes.PermFlag) bool {
|
func HasPermission(state AccountGetter, acc *acm.Account, perm ptypes.PermFlag) bool {
|
||||||
if perm > ptypes.AllBasePermFlags {
|
if (perm > ptypes.AllBasePermFlags && perm < ptypes.FirstSNativePermFlag) ||
|
||||||
|
(perm > ptypes.AllSNativePermFlags) {
|
||||||
PanicSanity("Checking an unknown permission in state should never happen")
|
PanicSanity("Checking an unknown permission in state should never happen")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,17 +909,19 @@ func HasPermission(state AccountGetter, acc *acm.Account, perm ptypes.PermFlag)
|
|||||||
// this needs to fall back to global or do some other specific things
|
// this needs to fall back to global or do some other specific things
|
||||||
// eg. a bondAcc may be nil and so can only bond if global bonding is true
|
// eg. a bondAcc may be nil and so can only bond if global bonding is true
|
||||||
}
|
}
|
||||||
|
permString := ptypes.PermFlagToString(perm)
|
||||||
|
|
||||||
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.Info("Account does not have permission", "account", acc, "accPermissions", acc.Permissions, "perm", perm)
|
|
||||||
if state == nil {
|
if state == nil {
|
||||||
PanicSanity("All known global permissions should be set!")
|
PanicSanity("All known global permissions should be set!")
|
||||||
}
|
}
|
||||||
log.Info("Querying GlobalPermissionsAddress")
|
log.Info("Permission for account is not set. Querying GlobalPermissionsAddress", "perm", permString)
|
||||||
return HasPermission(nil, state.GetAccount(ptypes.GlobalPermissionsAddress), perm)
|
return HasPermission(nil, state.GetAccount(ptypes.GlobalPermissionsAddress), perm)
|
||||||
|
} else if v {
|
||||||
|
log.Info("Account has permission", "address", Fmt("%X", acc.Address), "perm", permString)
|
||||||
} else {
|
} else {
|
||||||
log.Info("Account has permission", "account", acc, "accPermissions", acc.Permissions, "perm", perm)
|
log.Info("Account does not have permission", "address", Fmt("%X", acc.Address), "perm", permString)
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
@ -873,3 +971,7 @@ func hasBondOrSendPermission(state AccountGetter, accs map[string]*acm.Account)
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasSNativePermission(state AccountGetter, acc *acm.Account, permFlag ptypes.PermFlag) bool {
|
||||||
|
return HasPermission(state, acc, permFlag)
|
||||||
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/tendermint/tendermint/events"
|
"github.com/tendermint/tendermint/events"
|
||||||
ptypes "github.com/tendermint/tendermint/permission/types"
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tendermint/vm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -344,7 +343,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
|
|
||||||
//------------------------------
|
//------------------------------
|
||||||
// call to simple contract
|
// call to simple contract
|
||||||
fmt.Println("##### SIMPLE CONTRACT")
|
fmt.Println("\n##### SIMPLE CONTRACT")
|
||||||
|
|
||||||
// create simple contract
|
// create simple contract
|
||||||
simpleContractAddr := NewContractAddress(user[0].Address, 100)
|
simpleContractAddr := NewContractAddress(user[0].Address, 100)
|
||||||
@ -367,14 +366,14 @@ func TestCallPermission(t *testing.T) {
|
|||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
// call to contract that calls simple contract - without perm
|
// call to contract that calls simple contract - without perm
|
||||||
fmt.Println("##### CALL TO SIMPLE CONTRACT (FAIL)")
|
fmt.Println("\n##### CALL TO SIMPLE CONTRACT (FAIL)")
|
||||||
|
|
||||||
// create contract that calls the simple contract
|
// create contract that calls the simple contract
|
||||||
contractCode := callContractCode(simpleContractAddr)
|
contractCode := callContractCode(simpleContractAddr)
|
||||||
caller1ContractAddr := NewContractAddress(user[0].Address, 101)
|
caller1ContractAddr := NewContractAddress(user[0].Address, 101)
|
||||||
caller1Acc := &acm.Account{
|
caller1Acc := &acm.Account{
|
||||||
Address: caller1ContractAddr,
|
Address: caller1ContractAddr,
|
||||||
Balance: 0,
|
Balance: 10000,
|
||||||
Code: contractCode,
|
Code: contractCode,
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
StorageRoot: Zero256.Bytes(),
|
StorageRoot: Zero256.Bytes(),
|
||||||
@ -394,7 +393,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
// call to contract that calls simple contract - with perm
|
// call to contract that calls simple contract - with perm
|
||||||
fmt.Println("##### CALL TO SIMPLE CONTRACT (PASS)")
|
fmt.Println("\n##### 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.Base.Set(ptypes.Call, true)
|
caller1Acc.Permissions.Base.Set(ptypes.Call, true)
|
||||||
@ -412,7 +411,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
// call to contract that calls contract that calls simple contract - without perm
|
// call to contract that calls contract that calls simple contract - without perm
|
||||||
// caller1Contract calls simpleContract. caller2Contract calls caller1Contract.
|
// caller1Contract calls simpleContract. caller2Contract calls caller1Contract.
|
||||||
// caller1Contract does not have call perms, but caller2Contract does.
|
// caller1Contract does not have call perms, but caller2Contract does.
|
||||||
fmt.Println("##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (FAIL)")
|
fmt.Println("\n##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (FAIL)")
|
||||||
|
|
||||||
contractCode2 := callContractCode(caller1ContractAddr)
|
contractCode2 := callContractCode(caller1ContractAddr)
|
||||||
caller2ContractAddr := NewContractAddress(user[0].Address, 102)
|
caller2ContractAddr := NewContractAddress(user[0].Address, 102)
|
||||||
@ -442,7 +441,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
// call to contract that calls contract that calls simple contract - without perm
|
// call to contract that calls contract that calls simple contract - without perm
|
||||||
// caller1Contract calls simpleContract. caller2Contract calls caller1Contract.
|
// caller1Contract calls simpleContract. caller2Contract calls caller1Contract.
|
||||||
// both caller1 and caller2 have permission
|
// both caller1 and caller2 have permission
|
||||||
fmt.Println("##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (PASS)")
|
fmt.Println("\n##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (PASS)")
|
||||||
|
|
||||||
caller1Acc.Permissions.Base.Set(ptypes.Call, true)
|
caller1Acc.Permissions.Base.Set(ptypes.Call, true)
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
blockCache.UpdateAccount(caller1Acc)
|
||||||
@ -467,7 +466,7 @@ func TestCreatePermission(t *testing.T) {
|
|||||||
|
|
||||||
//------------------------------
|
//------------------------------
|
||||||
// create a simple contract
|
// create a simple contract
|
||||||
fmt.Println("##### CREATE SIMPLE CONTRACT")
|
fmt.Println("\n##### CREATE SIMPLE CONTRACT")
|
||||||
|
|
||||||
contractCode := []byte{0x60}
|
contractCode := []byte{0x60}
|
||||||
createCode := wrapContractForCreate(contractCode)
|
createCode := wrapContractForCreate(contractCode)
|
||||||
@ -490,7 +489,7 @@ func TestCreatePermission(t *testing.T) {
|
|||||||
|
|
||||||
//------------------------------
|
//------------------------------
|
||||||
// create contract that uses the CREATE op
|
// create contract that uses the CREATE op
|
||||||
fmt.Println("##### CREATE FACTORY")
|
fmt.Println("\n##### CREATE FACTORY")
|
||||||
|
|
||||||
contractCode = []byte{0x60}
|
contractCode = []byte{0x60}
|
||||||
createCode = wrapContractForCreate(contractCode)
|
createCode = wrapContractForCreate(contractCode)
|
||||||
@ -515,7 +514,7 @@ func TestCreatePermission(t *testing.T) {
|
|||||||
|
|
||||||
//------------------------------
|
//------------------------------
|
||||||
// call the contract (should FAIL)
|
// call the contract (should FAIL)
|
||||||
fmt.Println("###### CALL THE FACTORY (FAIL)")
|
fmt.Println("\n###### CALL THE FACTORY (FAIL)")
|
||||||
|
|
||||||
// A single input, having the permission, should succeed
|
// A single input, having the permission, should succeed
|
||||||
tx, _ = types.NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 100, 100)
|
tx, _ = types.NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 100, 100)
|
||||||
@ -528,7 +527,7 @@ func TestCreatePermission(t *testing.T) {
|
|||||||
|
|
||||||
//------------------------------
|
//------------------------------
|
||||||
// call the contract (should PASS)
|
// call the contract (should PASS)
|
||||||
fmt.Println("###### CALL THE FACTORY (PASS)")
|
fmt.Println("\n###### CALL THE FACTORY (PASS)")
|
||||||
|
|
||||||
contractAcc.Permissions.Base.Set(ptypes.CreateContract, true)
|
contractAcc.Permissions.Base.Set(ptypes.CreateContract, true)
|
||||||
blockCache.UpdateAccount(contractAcc)
|
blockCache.UpdateAccount(contractAcc)
|
||||||
@ -543,7 +542,7 @@ func TestCreatePermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
fmt.Println("##### CALL to empty address")
|
fmt.Println("\n##### CALL to empty address")
|
||||||
zeroAddr := LeftPadBytes([]byte{}, 20)
|
zeroAddr := LeftPadBytes([]byte{}, 20)
|
||||||
code := callContractCode(zeroAddr)
|
code := callContractCode(zeroAddr)
|
||||||
|
|
||||||
@ -860,11 +859,12 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
Permissions: ptypes.ZeroAccountPermissions,
|
Permissions: ptypes.ZeroAccountPermissions,
|
||||||
}
|
}
|
||||||
doug.Permissions.Base.Set(ptypes.Call, true)
|
doug.Permissions.Base.Set(ptypes.Call, true)
|
||||||
|
//doug.Permissions.Base.Set(ptypes.HasBase, true)
|
||||||
blockCache.UpdateAccount(doug)
|
blockCache.UpdateAccount(doug)
|
||||||
|
|
||||||
fmt.Println("#### hasBasePerm")
|
fmt.Println("\n#### HasBase")
|
||||||
// hasBasePerm
|
// HasBase
|
||||||
snativeAddress, data := snativePermTestInput("hasBasePerm", user[3], ptypes.Bond, false)
|
snativeAddress, data := snativePermTestInputCALL("HasBase", user[3], ptypes.Bond, false)
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
// return value should be true or false as a 32 byte array...
|
// return value should be true or false as a 32 byte array...
|
||||||
@ -874,12 +874,12 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("#### setBasePerm")
|
fmt.Println("\n#### SetBase")
|
||||||
// setBasePerm
|
// SetBase
|
||||||
snativeAddress, data = snativePermTestInput("setBasePerm", user[3], ptypes.Bond, false)
|
snativeAddress, data = snativePermTestInputCALL("SetBase", user[3], ptypes.Bond, false)
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
||||||
snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.Bond, false)
|
snativeAddress, data = snativePermTestInputCALL("HasBase", user[3], ptypes.Bond, false)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
// return value should be true or false as a 32 byte array...
|
// return value should be true or false as a 32 byte array...
|
||||||
if !IsZeros(ret) {
|
if !IsZeros(ret) {
|
||||||
@ -887,9 +887,9 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
snativeAddress, data = snativePermTestInput("setBasePerm", user[3], ptypes.CreateContract, true)
|
snativeAddress, data = snativePermTestInputCALL("SetBase", user[3], ptypes.CreateContract, true)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
||||||
snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false)
|
snativeAddress, data = snativePermTestInputCALL("HasBase", user[3], ptypes.CreateContract, false)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
// return value should be true or false as a 32 byte array...
|
// return value should be true or false as a 32 byte array...
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
||||||
@ -898,12 +898,12 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("#### unsetBasePerm")
|
fmt.Println("\n#### UnsetBase")
|
||||||
// unsetBasePerm
|
// UnsetBase
|
||||||
snativeAddress, data = snativePermTestInput("unsetBasePerm", user[3], ptypes.CreateContract, false)
|
snativeAddress, data = snativePermTestInputCALL("UnsetBase", user[3], ptypes.CreateContract, false)
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
||||||
snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false)
|
snativeAddress, data = snativePermTestInputCALL("HasBase", user[3], ptypes.CreateContract, false)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
if !IsZeros(ret) {
|
if !IsZeros(ret) {
|
||||||
return fmt.Errorf("Expected 0. Got %X", ret)
|
return fmt.Errorf("Expected 0. Got %X", ret)
|
||||||
@ -911,12 +911,12 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("#### setGlobalPerm")
|
fmt.Println("\n#### SetGlobal")
|
||||||
// setGlobalPerm
|
// SetGlobalPerm
|
||||||
snativeAddress, data = snativePermTestInput("setGlobalPerm", user[3], ptypes.CreateContract, true)
|
snativeAddress, data = snativePermTestInputCALL("SetGlobal", user[3], ptypes.CreateContract, true)
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
||||||
snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false)
|
snativeAddress, data = snativePermTestInputCALL("HasBase", user[3], ptypes.CreateContract, false)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
// return value should be true or false as a 32 byte array...
|
// return value should be true or false as a 32 byte array...
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
||||||
@ -925,12 +925,12 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
// clearBasePerm
|
// ClearBase
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
fmt.Println("#### hasRole")
|
fmt.Println("\n#### HasRole")
|
||||||
// hasRole
|
// HasRole
|
||||||
snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "bumble")
|
snativeAddress, data = snativeRoleTestInputCALL("HasRole", user[3], "bumble")
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
||||||
@ -939,19 +939,19 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("#### addRole")
|
fmt.Println("\n#### AddRole")
|
||||||
// addRole
|
// AddRole
|
||||||
snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck")
|
snativeAddress, data = snativeRoleTestInputCALL("HasRole", user[3], "chuck")
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
if !IsZeros(ret) {
|
if !IsZeros(ret) {
|
||||||
return fmt.Errorf("Expected 0. Got %X", ret)
|
return fmt.Errorf("Expected 0. Got %X", ret)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
snativeAddress, data = snativeRoleTestInput("addRole", user[3], "chuck")
|
snativeAddress, data = snativeRoleTestInputCALL("AddRole", user[3], "chuck")
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
||||||
snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck")
|
snativeAddress, data = snativeRoleTestInputCALL("HasRole", user[3], "chuck")
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
||||||
return fmt.Errorf("Expected 1. Got %X", ret)
|
return fmt.Errorf("Expected 1. Got %X", ret)
|
||||||
@ -959,12 +959,12 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("#### rmRole")
|
fmt.Println("\n#### RmRole")
|
||||||
// rmRole
|
// RmRole
|
||||||
snativeAddress, data = snativeRoleTestInput("rmRole", user[3], "chuck")
|
snativeAddress, data = snativeRoleTestInputCALL("RmRole", user[3], "chuck")
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
||||||
snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck")
|
snativeAddress, data = snativeRoleTestInputCALL("HasRole", user[3], "chuck")
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
||||||
if !IsZeros(ret) {
|
if !IsZeros(ret) {
|
||||||
return fmt.Errorf("Expected 0. Got %X", ret)
|
return fmt.Errorf("Expected 0. Got %X", ret)
|
||||||
@ -973,7 +973,7 @@ func TestSNativeCALL(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSNativeCallTx(t *testing.T) {
|
func TestSNativeTx(t *testing.T) {
|
||||||
stateDB := dbm.GetDB("state")
|
stateDB := dbm.GetDB("state")
|
||||||
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
||||||
genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true) // give the 0 account permission
|
genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true) // give the 0 account permission
|
||||||
@ -984,123 +984,73 @@ func TestSNativeCallTx(t *testing.T) {
|
|||||||
blockCache := NewBlockCache(st)
|
blockCache := NewBlockCache(st)
|
||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
// Test CallTx to SNative contracts
|
// Test SNativeTx
|
||||||
var doug *acm.Account = nil
|
|
||||||
|
|
||||||
fmt.Println("#### hasBasePerm")
|
fmt.Println("\n#### SetBase")
|
||||||
// hasBasePerm
|
// SetBase
|
||||||
snativeAddress, data := snativePermTestInput("hasBasePerm", user[3], ptypes.Bond, false)
|
snativeArgs := snativePermTestInputTx("SetBase", user[3], ptypes.Bond, false)
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeTxExpectFail(t, blockCache, snativeArgs)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeTxExpectPass(t, blockCache, ptypes.SetBase, snativeArgs)
|
||||||
// return value should be true or false as a 32 byte array...
|
acc := blockCache.GetAccount(user[3].Address)
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
if v, _ := acc.Permissions.Base.Get(ptypes.Bond); v {
|
||||||
return fmt.Errorf("Expected 1. Got %X", ret)
|
t.Fatal("expected permission to be set false")
|
||||||
}
|
}
|
||||||
return nil
|
snativeArgs = snativePermTestInputTx("SetBase", user[3], ptypes.CreateContract, true)
|
||||||
})
|
testSNativeTxExpectPass(t, blockCache, ptypes.SetBase, snativeArgs)
|
||||||
|
acc = blockCache.GetAccount(user[3].Address)
|
||||||
|
if v, _ := acc.Permissions.Base.Get(ptypes.CreateContract); !v {
|
||||||
|
t.Fatal("expected permission to be set true")
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("#### setBasePerm")
|
fmt.Println("\n#### UnsetBase")
|
||||||
// setBasePerm
|
// UnsetBase
|
||||||
snativeAddress, data = snativePermTestInput("setBasePerm", user[3], ptypes.Bond, false)
|
snativeArgs = snativePermTestInputTx("UnsetBase", user[3], ptypes.CreateContract, false)
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeTxExpectFail(t, blockCache, snativeArgs)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
testSNativeTxExpectPass(t, blockCache, ptypes.UnsetBase, snativeArgs)
|
||||||
snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.Bond, false)
|
acc = blockCache.GetAccount(user[3].Address)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
if v, _ := acc.Permissions.Base.Get(ptypes.CreateContract); v {
|
||||||
// return value should be true or false as a 32 byte array...
|
t.Fatal("expected permission to be set false")
|
||||||
if !IsZeros(ret) {
|
}
|
||||||
return fmt.Errorf("Expected 0. Got %X", ret)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
snativeAddress, data = snativePermTestInput("setBasePerm", user[3], ptypes.CreateContract, true)
|
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
|
||||||
snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false)
|
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
|
||||||
// return value should be true or false as a 32 byte array...
|
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
|
||||||
return fmt.Errorf("Expected 1. Got %X", ret)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println("#### unsetBasePerm")
|
fmt.Println("\n#### SetGlobal")
|
||||||
// unsetBasePerm
|
// SetGlobalPerm
|
||||||
snativeAddress, data = snativePermTestInput("unsetBasePerm", user[3], ptypes.CreateContract, false)
|
snativeArgs = snativePermTestInputTx("SetGlobal", user[3], ptypes.CreateContract, true)
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeTxExpectFail(t, blockCache, snativeArgs)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
testSNativeTxExpectPass(t, blockCache, ptypes.SetGlobal, snativeArgs)
|
||||||
snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false)
|
acc = blockCache.GetAccount(ptypes.GlobalPermissionsAddress)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
if v, _ := acc.Permissions.Base.Get(ptypes.CreateContract); !v {
|
||||||
if !IsZeros(ret) {
|
t.Fatal("expected permission to be set true")
|
||||||
return fmt.Errorf("Expected 0. Got %X", ret)
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println("#### setGlobalPerm")
|
// ClearBase
|
||||||
// setGlobalPerm
|
|
||||||
snativeAddress, data = snativePermTestInput("setGlobalPerm", user[3], ptypes.CreateContract, true)
|
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
|
||||||
snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false)
|
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
|
||||||
// return value should be true or false as a 32 byte array...
|
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
|
||||||
return fmt.Errorf("Expected 1. Got %X", ret)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// clearBasePerm
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
fmt.Println("#### hasRole")
|
fmt.Println("\n#### AddRole")
|
||||||
// hasRole
|
// AddRole
|
||||||
snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "bumble")
|
snativeArgs = snativeRoleTestInputTx("AddRole", user[3], "chuck")
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
testSNativeTxExpectFail(t, blockCache, snativeArgs)
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeTxExpectPass(t, blockCache, ptypes.AddRole, snativeArgs)
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
acc = blockCache.GetAccount(user[3].Address)
|
||||||
return fmt.Errorf("Expected 1. Got %X", ret)
|
if v := acc.Permissions.HasRole("chuck"); !v {
|
||||||
}
|
t.Fatal("expected role to be added")
|
||||||
return nil
|
}
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println("#### addRole")
|
fmt.Println("\n#### RmRole")
|
||||||
// addRole
|
// RmRole
|
||||||
snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck")
|
snativeArgs = snativeRoleTestInputTx("RmRole", user[3], "chuck")
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
testSNativeTxExpectFail(t, blockCache, snativeArgs)
|
||||||
if !IsZeros(ret) {
|
testSNativeTxExpectPass(t, blockCache, ptypes.RmRole, snativeArgs)
|
||||||
return fmt.Errorf("Expected 0. Got %X", ret)
|
acc = blockCache.GetAccount(user[3].Address)
|
||||||
}
|
if v := acc.Permissions.HasRole("chuck"); v {
|
||||||
return nil
|
t.Fatal("expected role to be removed")
|
||||||
})
|
}
|
||||||
snativeAddress, data = snativeRoleTestInput("addRole", user[3], "chuck")
|
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
|
||||||
snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck")
|
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
|
||||||
if !IsZeros(ret[:31]) || ret[31] != byte(1) {
|
|
||||||
return fmt.Errorf("Expected 1. Got %X", ret)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println("#### rmRole")
|
|
||||||
// rmRole
|
|
||||||
snativeAddress, data = snativeRoleTestInput("rmRole", user[3], "chuck")
|
|
||||||
testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data)
|
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil })
|
|
||||||
snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck")
|
|
||||||
testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error {
|
|
||||||
if !IsZeros(ret) {
|
|
||||||
return fmt.Errorf("Expected 0. Got %X", ret)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
|
var ExceptionTimeOut = "timed out waiting for event"
|
||||||
|
|
||||||
// run ExecTx and wait for the Receive event on given addr
|
// run ExecTx and wait for the Receive event on given addr
|
||||||
// returns the msg data and an error/exception
|
// returns the msg data and an error/exception
|
||||||
func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid string) (interface{}, string) {
|
func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid string) (interface{}, string) {
|
||||||
@ -1117,7 +1067,14 @@ func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid
|
|||||||
}
|
}
|
||||||
evc.Flush()
|
evc.Flush()
|
||||||
}()
|
}()
|
||||||
msg := <-ch
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
var msg interface{}
|
||||||
|
select {
|
||||||
|
case msg = <-ch:
|
||||||
|
case <-ticker.C:
|
||||||
|
return nil, ExceptionTimeOut
|
||||||
|
}
|
||||||
|
|
||||||
switch ev := msg.(type) {
|
switch ev := msg.(type) {
|
||||||
case types.EventMsgCallTx:
|
case types.EventMsgCallTx:
|
||||||
return ev, ev.Exception
|
return ev, ev.Exception
|
||||||
@ -1130,52 +1087,77 @@ func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// give a contract perms for an snative, call it, it calls the snative, ensure the check funciton (f) succeeds
|
// give a contract perms for an snative, call it, it calls the snative, but shouldn't have permission
|
||||||
func testSNativeCALLExpectPass(t *testing.T, blockCache *BlockCache, doug *acm.Account, snativeAddress, data []byte, f func([]byte) error) {
|
func testSNativeCALLExpectFail(t *testing.T, blockCache *BlockCache, doug *acm.Account, snativeAddress, data []byte) {
|
||||||
perm := vm.RegisteredSNativePermissions[LeftPadWord256(snativeAddress)]
|
testSNativeCALL(t, false, blockCache, doug, snativeAddress, data, nil)
|
||||||
var addr []byte
|
|
||||||
if doug != nil {
|
|
||||||
contractCode := callContractCode(snativeAddress)
|
|
||||||
doug.Code = contractCode
|
|
||||||
doug.Permissions.Base.Set(perm, true)
|
|
||||||
blockCache.UpdateAccount(doug)
|
|
||||||
addr = doug.Address
|
|
||||||
} else {
|
|
||||||
acc := blockCache.GetAccount(user[0].Address)
|
|
||||||
acc.Permissions.Base.Set(perm, true)
|
|
||||||
blockCache.UpdateAccount(acc)
|
|
||||||
addr = snativeAddress
|
|
||||||
}
|
|
||||||
tx, _ := types.NewCallTx(blockCache, user[0].PubKey, addr, data, 100, 10000, 100)
|
|
||||||
tx.Sign(chainID, user[0])
|
|
||||||
ev, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(snativeAddress)) //
|
|
||||||
if exception != "" {
|
|
||||||
t.Fatal("Unexpected exception", exception)
|
|
||||||
}
|
|
||||||
evv := ev.(types.EventMsgCall)
|
|
||||||
ret := evv.Return
|
|
||||||
if err := f(ret); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes the contract has not been given the permission. calls the it, it calls the snative, expects to fail
|
// give a contract perms for an snative, call it, it calls the snative, ensure the check funciton (f) succeeds
|
||||||
func testSNativeCALLExpectFail(t *testing.T, blockCache *BlockCache, doug *acm.Account, snativeAddress, data []byte) {
|
func testSNativeCALLExpectPass(t *testing.T, blockCache *BlockCache, doug *acm.Account, snativeAddress, data []byte, f func([]byte) error) {
|
||||||
var addr []byte
|
testSNativeCALL(t, true, blockCache, doug, snativeAddress, data, f)
|
||||||
if doug != nil {
|
}
|
||||||
contractCode := callContractCode(snativeAddress)
|
|
||||||
doug.Code = contractCode
|
func testSNativeCALL(t *testing.T, expectPass bool, blockCache *BlockCache, doug *acm.Account, snativeAddress, data []byte, f func([]byte) error) {
|
||||||
blockCache.UpdateAccount(doug)
|
if expectPass {
|
||||||
addr = doug.Address
|
perm, err := ptypes.SNativeStringToPermFlag(TrimmedString(snativeAddress))
|
||||||
} else {
|
if err != nil {
|
||||||
addr = snativeAddress
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
doug.Permissions.Base.Set(perm, true)
|
||||||
}
|
}
|
||||||
|
var addr []byte
|
||||||
|
contractCode := callContractCode(snativeAddress)
|
||||||
|
doug.Code = contractCode
|
||||||
|
blockCache.UpdateAccount(doug)
|
||||||
|
addr = doug.Address
|
||||||
tx, _ := types.NewCallTx(blockCache, user[0].PubKey, addr, data, 100, 10000, 100)
|
tx, _ := types.NewCallTx(blockCache, user[0].PubKey, addr, data, 100, 10000, 100)
|
||||||
tx.Sign(chainID, user[0])
|
tx.Sign(chainID, user[0])
|
||||||
fmt.Println("subscribing to", types.EventStringAccReceive(snativeAddress))
|
fmt.Println("subscribing to", types.EventStringAccReceive(snativeAddress))
|
||||||
_, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(snativeAddress))
|
ev, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(snativeAddress))
|
||||||
if exception == "" {
|
if exception == ExceptionTimeOut {
|
||||||
t.Fatal("Expected exception")
|
t.Fatal("Timed out waiting for event")
|
||||||
|
}
|
||||||
|
if expectPass {
|
||||||
|
if exception != "" {
|
||||||
|
t.Fatal("Unexpected exception", exception)
|
||||||
|
}
|
||||||
|
evv := ev.(types.EventMsgCall)
|
||||||
|
ret := evv.Return
|
||||||
|
if err := f(ret); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if exception == "" {
|
||||||
|
t.Fatal("Expected exception")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSNativeTxExpectFail(t *testing.T, blockCache *BlockCache, snativeArgs ptypes.SNativeArgs) {
|
||||||
|
testSNativeTx(t, false, blockCache, 0, snativeArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSNativeTxExpectPass(t *testing.T, blockCache *BlockCache, perm ptypes.PermFlag, snativeArgs ptypes.SNativeArgs) {
|
||||||
|
testSNativeTx(t, true, blockCache, perm, snativeArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSNativeTx(t *testing.T, expectPass bool, blockCache *BlockCache, perm ptypes.PermFlag, snativeArgs ptypes.SNativeArgs) {
|
||||||
|
if expectPass {
|
||||||
|
acc := blockCache.GetAccount(user[0].Address)
|
||||||
|
acc.Permissions.Base.Set(perm, true)
|
||||||
|
blockCache.UpdateAccount(acc)
|
||||||
|
}
|
||||||
|
tx, _ := types.NewSNativeTx(blockCache, user[0].PubKey, snativeArgs)
|
||||||
|
tx.Sign(chainID, user[0])
|
||||||
|
err := ExecTx(blockCache, tx, true, nil)
|
||||||
|
if expectPass {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Unexpected exception", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Expected exception")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1189,31 +1171,58 @@ func boolToWord256(v bool) Word256 {
|
|||||||
return LeftPadWord256([]byte{vint})
|
return LeftPadWord256([]byte{vint})
|
||||||
}
|
}
|
||||||
|
|
||||||
func snativePermTestInput(name string, user *acm.PrivAccount, perm ptypes.PermFlag, val bool) (addr []byte, data []byte) {
|
func snativePermTestInputCALL(name string, user *acm.PrivAccount, perm ptypes.PermFlag, val bool) (addr []byte, data []byte) {
|
||||||
addr = LeftPadWord256([]byte(name)).Postfix(20)
|
addr = LeftPadWord256([]byte(name)).Postfix(20)
|
||||||
switch name {
|
switch name {
|
||||||
case "hasBasePerm", "unsetBasePerm":
|
case "HasBase", "UnsetBase":
|
||||||
data = LeftPadBytes(user.Address, 32)
|
data = LeftPadBytes(user.Address, 32)
|
||||||
data = append(data, Uint64ToWord256(uint64(perm)).Bytes()...)
|
data = append(data, Uint64ToWord256(uint64(perm)).Bytes()...)
|
||||||
case "setBasePerm":
|
case "SetBase":
|
||||||
data = LeftPadBytes(user.Address, 32)
|
data = LeftPadBytes(user.Address, 32)
|
||||||
data = append(data, Uint64ToWord256(uint64(perm)).Bytes()...)
|
data = append(data, Uint64ToWord256(uint64(perm)).Bytes()...)
|
||||||
data = append(data, boolToWord256(val).Bytes()...)
|
data = append(data, boolToWord256(val).Bytes()...)
|
||||||
case "setGlobalPerm":
|
case "SetGlobal":
|
||||||
data = Uint64ToWord256(uint64(perm)).Bytes()
|
data = Uint64ToWord256(uint64(perm)).Bytes()
|
||||||
data = append(data, boolToWord256(val).Bytes()...)
|
data = append(data, boolToWord256(val).Bytes()...)
|
||||||
case "clearBasePerm":
|
case "ClearBase":
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func snativeRoleTestInput(name string, user *acm.PrivAccount, role string) (addr []byte, data []byte) {
|
func snativePermTestInputTx(name string, user *acm.PrivAccount, perm ptypes.PermFlag, val bool) (snativeArgs ptypes.SNativeArgs) {
|
||||||
|
switch name {
|
||||||
|
case "HasBase":
|
||||||
|
snativeArgs = &ptypes.HasBaseArgs{user.Address, perm}
|
||||||
|
case "UnsetBase":
|
||||||
|
snativeArgs = &ptypes.UnsetBaseArgs{user.Address, perm}
|
||||||
|
case "SetBase":
|
||||||
|
snativeArgs = &ptypes.SetBaseArgs{user.Address, perm, val}
|
||||||
|
case "SetGlobal":
|
||||||
|
snativeArgs = &ptypes.SetGlobalArgs{perm, val}
|
||||||
|
case "ClearBase":
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func snativeRoleTestInputCALL(name string, user *acm.PrivAccount, role string) (addr []byte, data []byte) {
|
||||||
addr = LeftPadWord256([]byte(name)).Postfix(20)
|
addr = LeftPadWord256([]byte(name)).Postfix(20)
|
||||||
data = LeftPadBytes(user.Address, 32)
|
data = LeftPadBytes(user.Address, 32)
|
||||||
data = append(data, LeftPadBytes([]byte(role), 32)...)
|
data = append(data, LeftPadBytes([]byte(role), 32)...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func snativeRoleTestInputTx(name string, user *acm.PrivAccount, role string) (snativeArgs ptypes.SNativeArgs) {
|
||||||
|
switch name {
|
||||||
|
case "HasRole":
|
||||||
|
snativeArgs = &ptypes.HasRoleArgs{user.Address, role}
|
||||||
|
case "AddRole":
|
||||||
|
snativeArgs = &ptypes.AddRoleArgs{user.Address, role}
|
||||||
|
case "RmRole":
|
||||||
|
snativeArgs = &ptypes.RmRoleArgs{user.Address, role}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// convenience function for contract that calls a given address
|
// convenience function for contract that calls a given address
|
||||||
func callContractCode(contractAddr []byte) []byte {
|
func callContractCode(contractAddr []byte) []byte {
|
||||||
// calldatacopy into mem and use as input to call
|
// calldatacopy into mem and use as input to call
|
||||||
|
@ -22,6 +22,10 @@ func EventStringLogEvent(addr []byte) string {
|
|||||||
return fmt.Sprintf("Log/%X", addr)
|
return fmt.Sprintf("Log/%X", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EventStringSNative(name string) string {
|
||||||
|
return fmt.Sprintf("SNative/%s", name)
|
||||||
|
}
|
||||||
|
|
||||||
func EventStringBond() string {
|
func EventStringBond() string {
|
||||||
return "Bond"
|
return "Bond"
|
||||||
}
|
}
|
||||||
|
30
types/tx.go
30
types/tx.go
@ -8,6 +8,7 @@ import (
|
|||||||
acm "github.com/tendermint/tendermint/account"
|
acm "github.com/tendermint/tendermint/account"
|
||||||
"github.com/tendermint/tendermint/binary"
|
"github.com/tendermint/tendermint/binary"
|
||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -44,7 +45,11 @@ Validation Txs:
|
|||||||
- BondTx New validator posts a bond
|
- BondTx New validator posts a bond
|
||||||
- UnbondTx Validator leaves
|
- UnbondTx Validator leaves
|
||||||
- DupeoutTx Validator dupes out (equivocates)
|
- DupeoutTx Validator dupes out (equivocates)
|
||||||
|
|
||||||
|
Admin Txs:
|
||||||
|
- SNativeTx (CapTx ?)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type Tx interface {
|
type Tx interface {
|
||||||
WriteSignBytes(chainID string, w io.Writer, n *int64, err *error)
|
WriteSignBytes(chainID string, w io.Writer, n *int64, err *error)
|
||||||
}
|
}
|
||||||
@ -61,6 +66,9 @@ const (
|
|||||||
TxTypeUnbond = byte(0x12)
|
TxTypeUnbond = byte(0x12)
|
||||||
TxTypeRebond = byte(0x13)
|
TxTypeRebond = byte(0x13)
|
||||||
TxTypeDupeout = byte(0x14)
|
TxTypeDupeout = byte(0x14)
|
||||||
|
|
||||||
|
// Admin transactions
|
||||||
|
TxTypeSNative = byte(0x20)
|
||||||
)
|
)
|
||||||
|
|
||||||
// for binary.readReflect
|
// for binary.readReflect
|
||||||
@ -73,6 +81,7 @@ var _ = binary.RegisterInterface(
|
|||||||
binary.ConcreteType{&UnbondTx{}, TxTypeUnbond},
|
binary.ConcreteType{&UnbondTx{}, TxTypeUnbond},
|
||||||
binary.ConcreteType{&RebondTx{}, TxTypeRebond},
|
binary.ConcreteType{&RebondTx{}, TxTypeRebond},
|
||||||
binary.ConcreteType{&DupeoutTx{}, TxTypeDupeout},
|
binary.ConcreteType{&DupeoutTx{}, TxTypeDupeout},
|
||||||
|
binary.ConcreteType{&SNativeTx{}, TxTypeSNative},
|
||||||
)
|
)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -314,6 +323,27 @@ func (tx *DupeoutTx) String() string {
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type SNativeTx struct {
|
||||||
|
Input *TxInput `json:"input"`
|
||||||
|
SNative ptypes.SNativeArgs `json:"snative"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check the tx.SNative encoding ...
|
||||||
|
func (tx *SNativeTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
||||||
|
binary.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
|
||||||
|
binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"args":%v`, TxTypeSNative, tx.SNative)), w, n, err)
|
||||||
|
binary.WriteTo([]byte(`,"input":`), w, n, err)
|
||||||
|
tx.Input.WriteSignBytes(w, n, err)
|
||||||
|
binary.WriteTo([]byte(Fmt(`,"snative":%s`, tx.SNative)), w, n, err)
|
||||||
|
binary.WriteTo([]byte(`}]}`), w, n, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *SNativeTx) String() string {
|
||||||
|
return Fmt("SNativeTx{%v -> %v}", tx.Input, tx.SNative)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// This should match the leaf hashes of Block.Data.Hash()'s SimpleMerkleTree.
|
// This should match the leaf hashes of Block.Data.Hash()'s SimpleMerkleTree.
|
||||||
func TxID(chainID string, tx Tx) []byte {
|
func TxID(chainID string, tx Tx) []byte {
|
||||||
signBytes := acm.SignBytes(chainID, tx)
|
signBytes := acm.SignBytes(chainID, tx)
|
||||||
|
@ -3,6 +3,7 @@ package types
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
acm "github.com/tendermint/tendermint/account"
|
acm "github.com/tendermint/tendermint/account"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AccountGetter interface {
|
type AccountGetter interface {
|
||||||
@ -222,3 +223,38 @@ func NewRebondTx(addr []byte, height int) *RebondTx {
|
|||||||
func (tx *RebondTx) Sign(chainID string, privAccount *acm.PrivAccount) {
|
func (tx *RebondTx) Sign(chainID string, privAccount *acm.PrivAccount) {
|
||||||
tx.Signature = privAccount.Sign(chainID, tx).(acm.SignatureEd25519)
|
tx.Signature = privAccount.Sign(chainID, tx).(acm.SignatureEd25519)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// SNativeTx interface for creating tx
|
||||||
|
|
||||||
|
func NewSNativeTx(st AccountGetter, from acm.PubKey, snativeArgs ptypes.SNativeArgs) (*SNativeTx, error) {
|
||||||
|
addr := from.Address()
|
||||||
|
acc := st.GetAccount(addr)
|
||||||
|
if acc == nil {
|
||||||
|
return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from)
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce := acc.Sequence + 1
|
||||||
|
return NewSNativeTxWithNonce(from, snativeArgs, nonce), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSNativeTxWithNonce(from acm.PubKey, snativeArgs ptypes.SNativeArgs, nonce int) *SNativeTx {
|
||||||
|
addr := from.Address()
|
||||||
|
input := &TxInput{
|
||||||
|
Address: addr,
|
||||||
|
Amount: 1, // NOTE: amounts can't be 0 ...
|
||||||
|
Sequence: nonce,
|
||||||
|
Signature: acm.SignatureEd25519{},
|
||||||
|
PubKey: from,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SNativeTx{
|
||||||
|
Input: input,
|
||||||
|
SNative: snativeArgs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *SNativeTx) Sign(chainID string, privAccount *acm.PrivAccount) {
|
||||||
|
tx.Input.PubKey = privAccount.PubKey
|
||||||
|
tx.Input.Signature = privAccount.Sign(chainID, tx)
|
||||||
|
}
|
||||||
|
107
vm/snative.go
107
vm/snative.go
@ -7,17 +7,11 @@ import (
|
|||||||
ptypes "github.com/tendermint/tendermint/permission/types"
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
type snativeInfo struct {
|
||||||
// Registered SNative contracts
|
PermFlag ptypes.PermFlag
|
||||||
|
NArgs int
|
||||||
var RegisteredSNativeContracts = map[Word256]SNativeContract{
|
ArgsError error
|
||||||
LeftPadWord256([]byte("hasBasePerm")): hasBasePerm,
|
Executable SNativeContract
|
||||||
LeftPadWord256([]byte("setBasePerm")): setBasePerm,
|
|
||||||
LeftPadWord256([]byte("unsetBasePerm")): unsetBasePerm,
|
|
||||||
LeftPadWord256([]byte("setGlobalPerm")): setGlobalPerm,
|
|
||||||
LeftPadWord256([]byte("hasRole")): hasRole,
|
|
||||||
LeftPadWord256([]byte("addRole")): addRole,
|
|
||||||
LeftPadWord256([]byte("rmRole")): rmRole,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes an appState so it can lookup/update accounts,
|
// Takes an appState so it can lookup/update accounts,
|
||||||
@ -25,6 +19,37 @@ var RegisteredSNativeContracts = map[Word256]SNativeContract{
|
|||||||
// and some input bytes (presumably 32byte words)
|
// and some input bytes (presumably 32byte words)
|
||||||
type SNativeContract func(appState AppState, acc *Account, input []byte) (output []byte, err error)
|
type SNativeContract func(appState AppState, acc *Account, input []byte) (output []byte, err error)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
// Registered SNative contracts
|
||||||
|
|
||||||
|
// sets the number of arguments, a friendly error message, and the snative function ("executable")
|
||||||
|
func getSNativeInfo(permFlag ptypes.PermFlag) *snativeInfo {
|
||||||
|
si := &snativeInfo{PermFlag: permFlag}
|
||||||
|
var errS string
|
||||||
|
switch permFlag {
|
||||||
|
case ptypes.HasBase:
|
||||||
|
si.NArgs, errS, si.Executable = 2, "hasBasePerm() takes two arguments (address, permission number)", hasBasePerm
|
||||||
|
case ptypes.SetBase:
|
||||||
|
si.NArgs, errS, si.Executable = 3, "setBasePerm() takes three arguments (address, permission number, permission value)", setBasePerm
|
||||||
|
case ptypes.UnsetBase:
|
||||||
|
si.NArgs, errS, si.Executable = 2, "unsetBasePerm() takes two arguments (address, permission number)", unsetBasePerm
|
||||||
|
case ptypes.SetGlobal:
|
||||||
|
si.NArgs, errS, si.Executable = 2, "setGlobalPerm() takes two arguments (permission number, permission value)", setGlobalPerm
|
||||||
|
case ptypes.ClearBase:
|
||||||
|
//
|
||||||
|
case ptypes.HasRole:
|
||||||
|
si.NArgs, errS, si.Executable = 2, "hasRole() takes two arguments (address, role)", hasRole
|
||||||
|
case ptypes.AddRole:
|
||||||
|
si.NArgs, errS, si.Executable = 2, "addRole() takes two arguments (address, role)", addRole
|
||||||
|
case ptypes.RmRole:
|
||||||
|
si.NArgs, errS, si.Executable = 2, "rmRole() takes two arguments (address, role)", rmRole
|
||||||
|
default:
|
||||||
|
PanicSanity(Fmt("should never happen. PermFlag: %b", permFlag))
|
||||||
|
}
|
||||||
|
si.ArgsError = fmt.Errorf(errS)
|
||||||
|
return si
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// snative are native contracts that can access and manipulate the chain state
|
// snative are native contracts that can access and manipulate the chain state
|
||||||
// (in particular the permissions values)
|
// (in particular the permissions values)
|
||||||
@ -32,12 +57,6 @@ type SNativeContract func(appState AppState, acc *Account, input []byte) (output
|
|||||||
// TODO: catch errors, log em, return 0s to the vm (should some errors cause exceptions though?)
|
// TODO: catch errors, log em, return 0s to the vm (should some errors cause exceptions though?)
|
||||||
|
|
||||||
func hasBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
func hasBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
||||||
if !HasPermission(appState, acc, ptypes.HasBasePerm) {
|
|
||||||
return nil, ErrInvalidPermission{acc.Address, "HasBasePerm"}
|
|
||||||
}
|
|
||||||
if len(args) != 2*32 {
|
|
||||||
return nil, fmt.Errorf("hasBasePerm() takes two arguments (address, permission number)")
|
|
||||||
}
|
|
||||||
addr, permNum := returnTwoArgs(args)
|
addr, permNum := returnTwoArgs(args)
|
||||||
vmAcc := appState.GetAccount(addr)
|
vmAcc := appState.GetAccount(addr)
|
||||||
if vmAcc == nil {
|
if vmAcc == nil {
|
||||||
@ -58,12 +77,6 @@ func hasBasePerm(appState AppState, acc *Account, args []byte) (output []byte, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
func setBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
||||||
if !HasPermission(appState, acc, ptypes.SetBasePerm) {
|
|
||||||
return nil, ErrInvalidPermission{acc.Address, "SetBasePerm"}
|
|
||||||
}
|
|
||||||
if len(args) != 3*32 {
|
|
||||||
return nil, fmt.Errorf("setBasePerm() takes three arguments (address, permission number, permission value)")
|
|
||||||
}
|
|
||||||
addr, permNum, perm := returnThreeArgs(args)
|
addr, permNum, perm := returnThreeArgs(args)
|
||||||
vmAcc := appState.GetAccount(addr)
|
vmAcc := appState.GetAccount(addr)
|
||||||
if vmAcc == nil {
|
if vmAcc == nil {
|
||||||
@ -83,12 +96,6 @@ func setBasePerm(appState AppState, acc *Account, args []byte) (output []byte, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func unsetBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
func unsetBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
||||||
if !HasPermission(appState, acc, ptypes.UnsetBasePerm) {
|
|
||||||
return nil, ErrInvalidPermission{acc.Address, "UnsetBasePerm"}
|
|
||||||
}
|
|
||||||
if len(args) != 2*32 {
|
|
||||||
return nil, fmt.Errorf("unsetBasePerm() takes two arguments (address, permission number)")
|
|
||||||
}
|
|
||||||
addr, permNum := returnTwoArgs(args)
|
addr, permNum := returnTwoArgs(args)
|
||||||
vmAcc := appState.GetAccount(addr)
|
vmAcc := appState.GetAccount(addr)
|
||||||
if vmAcc == nil {
|
if vmAcc == nil {
|
||||||
@ -107,12 +114,6 @@ func unsetBasePerm(appState AppState, acc *Account, args []byte) (output []byte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setGlobalPerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
func setGlobalPerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
||||||
if !HasPermission(appState, acc, ptypes.SetGlobalPerm) {
|
|
||||||
return nil, ErrInvalidPermission{acc.Address, "SetGlobalPerm"}
|
|
||||||
}
|
|
||||||
if len(args) != 2*32 {
|
|
||||||
return nil, fmt.Errorf("setGlobalPerm() takes two arguments (permission number, permission value)")
|
|
||||||
}
|
|
||||||
permNum, perm := returnTwoArgs(args)
|
permNum, perm := returnTwoArgs(args)
|
||||||
vmAcc := appState.GetAccount(ptypes.GlobalPermissionsAddress256)
|
vmAcc := appState.GetAccount(ptypes.GlobalPermissionsAddress256)
|
||||||
if vmAcc == nil {
|
if vmAcc == nil {
|
||||||
@ -133,19 +134,10 @@ func setGlobalPerm(appState AppState, acc *Account, args []byte) (output []byte,
|
|||||||
|
|
||||||
// TODO: needs access to an iterator ...
|
// TODO: needs access to an iterator ...
|
||||||
func clearPerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
func clearPerm(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
||||||
if !HasPermission(appState, acc, ptypes.ClearBasePerm) {
|
|
||||||
return nil, ErrInvalidPermission{acc.Address, "ClearPerm"}
|
|
||||||
}
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasRole(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
func hasRole(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
||||||
if !HasPermission(appState, acc, ptypes.HasRole) {
|
|
||||||
return nil, ErrInvalidPermission{acc.Address, "HasRole"}
|
|
||||||
}
|
|
||||||
if len(args) != 2*32 {
|
|
||||||
return nil, fmt.Errorf("hasRole() takes two arguments (address, role)")
|
|
||||||
}
|
|
||||||
addr, role := returnTwoArgs(args)
|
addr, role := returnTwoArgs(args)
|
||||||
vmAcc := appState.GetAccount(addr)
|
vmAcc := appState.GetAccount(addr)
|
||||||
if vmAcc == nil {
|
if vmAcc == nil {
|
||||||
@ -163,12 +155,6 @@ func hasRole(appState AppState, acc *Account, args []byte) (output []byte, err e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addRole(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
func addRole(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
||||||
if !HasPermission(appState, acc, ptypes.AddRole) {
|
|
||||||
return nil, ErrInvalidPermission{acc.Address, "AddRole"}
|
|
||||||
}
|
|
||||||
if len(args) != 2*32 {
|
|
||||||
return nil, fmt.Errorf("addRole() takes two arguments (address, role)")
|
|
||||||
}
|
|
||||||
addr, role := returnTwoArgs(args)
|
addr, role := returnTwoArgs(args)
|
||||||
vmAcc := appState.GetAccount(addr)
|
vmAcc := appState.GetAccount(addr)
|
||||||
if vmAcc == nil {
|
if vmAcc == nil {
|
||||||
@ -187,12 +173,6 @@ func addRole(appState AppState, acc *Account, args []byte) (output []byte, err e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func rmRole(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
func rmRole(appState AppState, acc *Account, args []byte) (output []byte, err error) {
|
||||||
if !HasPermission(appState, acc, ptypes.RmRole) {
|
|
||||||
return nil, ErrInvalidPermission{acc.Address, "RmRole"}
|
|
||||||
}
|
|
||||||
if len(args) != 2*32 {
|
|
||||||
return nil, fmt.Errorf("rmRole() takes two arguments (address, role)")
|
|
||||||
}
|
|
||||||
addr, role := returnTwoArgs(args)
|
addr, role := returnTwoArgs(args)
|
||||||
vmAcc := appState.GetAccount(addr)
|
vmAcc := appState.GetAccount(addr)
|
||||||
if vmAcc == nil {
|
if vmAcc == nil {
|
||||||
@ -232,28 +212,17 @@ func ValidPermN(n ptypes.PermFlag) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes length has already been checked
|
// CONTRACT: length has already been checked
|
||||||
func returnTwoArgs(args []byte) (a Word256, b Word256) {
|
func returnTwoArgs(args []byte) (a Word256, b Word256) {
|
||||||
copy(a[:], args[:32])
|
copy(a[:], args[:32])
|
||||||
copy(b[:], args[32:64])
|
copy(b[:], args[32:64])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes length has already been checked
|
// CONTRACT: length has already been checked
|
||||||
func returnThreeArgs(args []byte) (a Word256, b Word256, c Word256) {
|
func returnThreeArgs(args []byte) (a Word256, b Word256, c Word256) {
|
||||||
copy(a[:], args[:32])
|
copy(a[:], args[:32])
|
||||||
copy(b[:], args[32:64])
|
copy(b[:], args[32:64])
|
||||||
copy(c[:], args[64:96])
|
copy(c[:], args[64:96])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// mostly a convenience for testing
|
|
||||||
var RegisteredSNativePermissions = map[Word256]ptypes.PermFlag{
|
|
||||||
LeftPadWord256([]byte("hasBasePerm")): ptypes.HasBasePerm,
|
|
||||||
LeftPadWord256([]byte("setBasePerm")): ptypes.SetBasePerm,
|
|
||||||
LeftPadWord256([]byte("unsetBasePerm")): ptypes.UnsetBasePerm,
|
|
||||||
LeftPadWord256([]byte("setGlobalPerm")): ptypes.SetGlobalPerm,
|
|
||||||
LeftPadWord256([]byte("hasRole")): ptypes.HasRole,
|
|
||||||
LeftPadWord256([]byte("addRole")): ptypes.AddRole,
|
|
||||||
LeftPadWord256([]byte("rmRole")): ptypes.RmRole,
|
|
||||||
}
|
|
||||||
|
84
vm/vm.go
84
vm/vm.go
@ -95,6 +95,46 @@ func HasPermission(appState AppState, acc *Account, perm ptypes.PermFlag) bool {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vm *VM) fireEvent(exception *string, output *[]byte, caller, callee *Account, input []byte, value int64, gas *int64) {
|
||||||
|
// fire the post call event (including exception if applicable)
|
||||||
|
if vm.evc != nil {
|
||||||
|
vm.evc.FireEvent(types.EventStringAccReceive(callee.Address.Postfix(20)), types.EventMsgCall{
|
||||||
|
&types.CallData{caller.Address.Postfix(20), callee.Address.Postfix(20), input, value, *gas},
|
||||||
|
vm.origin.Postfix(20),
|
||||||
|
vm.txid,
|
||||||
|
*output,
|
||||||
|
*exception,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// call an snative contract (includes event processing)
|
||||||
|
// addr and permFlag refer to the same snative's address and it's permFlag
|
||||||
|
func (vm *VM) callSNative(addr Word256, permFlag ptypes.PermFlag, caller *Account, input []byte, value int64, gas *int64) (ret []byte, err error) {
|
||||||
|
exception := new(string)
|
||||||
|
// fire the post call event (including exception if applicable)
|
||||||
|
defer vm.fireEvent(exception, &ret, caller, &Account{Address: addr}, input, value, gas)
|
||||||
|
|
||||||
|
if !HasPermission(vm.appState, caller, permFlag) {
|
||||||
|
err = ErrInvalidPermission{caller.Address, addr.TrimmedString()}
|
||||||
|
*exception = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
snInfo := getSNativeInfo(permFlag)
|
||||||
|
if len(input) != snInfo.NArgs*32 {
|
||||||
|
err = snInfo.ArgsError
|
||||||
|
*exception = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// SNATIVE ACCESS
|
||||||
|
ret, err = snInfo.Executable(vm.appState, caller, input)
|
||||||
|
// END SNATIVE ACCESS
|
||||||
|
if err != nil {
|
||||||
|
*exception = err.Error()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
@ -102,30 +142,8 @@ func HasPermission(appState AppState, acc *Account, perm ptypes.PermFlag) bool {
|
|||||||
func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) {
|
func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) {
|
||||||
|
|
||||||
exception := new(string)
|
exception := new(string)
|
||||||
defer func() {
|
// fire the post call event (including exception if applicable)
|
||||||
if vm.evc != nil {
|
defer vm.fireEvent(exception, &output, caller, callee, input, value, gas)
|
||||||
vm.evc.FireEvent(types.EventStringAccReceive(callee.Address.Postfix(20)), types.EventMsgCall{
|
|
||||||
&types.CallData{caller.Address.Postfix(20), callee.Address.Postfix(20), input, value, *gas},
|
|
||||||
vm.origin.Postfix(20),
|
|
||||||
vm.txid,
|
|
||||||
output,
|
|
||||||
*exception,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// SNATIVE ACCESS
|
|
||||||
// if code is empty, callee may be snative contract
|
|
||||||
if len(code) == 0 {
|
|
||||||
if snativeContract, ok := RegisteredSNativeContracts[callee.Address]; ok {
|
|
||||||
output, err = snativeContract(vm.appState, caller, input)
|
|
||||||
if err != nil {
|
|
||||||
*exception = err.Error()
|
|
||||||
}
|
|
||||||
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()
|
||||||
@ -779,19 +797,27 @@ 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]; ok {
|
// nil account means either the address is the name of an snative,
|
||||||
acc = &Account{Address: addr}
|
// or we're sending funds to a new account
|
||||||
|
|
||||||
|
// trim the 0s off the address and check if its known
|
||||||
|
trimmedAddr := addr.TrimmedString()
|
||||||
|
if permFlag, unknownPermErr := ptypes.SNativeStringToPermFlag(trimmedAddr); unknownPermErr == nil {
|
||||||
|
ret, err = vm.callSNative(addr, permFlag, callee, input, value, gas)
|
||||||
} 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
|
|
||||||
if !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}
|
||||||
|
vm.appState.UpdateAccount(acc)
|
||||||
|
// send funds to new account
|
||||||
|
ret, err = vm.Call(callee, acc, acc.Code, args, value, gas)
|
||||||
}
|
}
|
||||||
vm.appState.UpdateAccount(acc)
|
} else {
|
||||||
|
// call standard contract
|
||||||
|
ret, err = vm.Call(callee, acc, acc.Code, args, value, gas)
|
||||||
}
|
}
|
||||||
ret, err = vm.Call(callee, acc, acc.Code, args, value, gas)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user