mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
move perms to vm.Account
This commit is contained in:
parent
c6c0701b69
commit
94f21ad012
@ -6,8 +6,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/binary"
|
"github.com/tendermint/tendermint/binary"
|
||||||
. "github.com/tendermint/tendermint/common"
|
|
||||||
"github.com/tendermint/tendermint/merkle"
|
"github.com/tendermint/tendermint/merkle"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Signable is an interface for all signable things.
|
// Signable is an interface for all signable things.
|
||||||
@ -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 Permissions `json:"permissions"`
|
Permissions *ptypes.Permissions `json:"permissions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acc *Account) Copy() *Account {
|
func (acc *Account) Copy() *Account {
|
||||||
@ -73,100 +73,10 @@ var AccountCodec = binary.Codec{
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
var GlobalPermissionsAddress = LeftPadBytes([]byte{}, 20)
|
|
||||||
var DougAddress = GlobalPermissionsAddress
|
|
||||||
|
|
||||||
type Permission uint
|
|
||||||
|
|
||||||
const (
|
|
||||||
SendPermission Permission = iota
|
|
||||||
CallPermission
|
|
||||||
CreatePermission
|
|
||||||
BondPermission
|
|
||||||
|
|
||||||
NumBasePermissions = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
type Permissions struct {
|
|
||||||
Send bool
|
|
||||||
Call bool
|
|
||||||
Create bool
|
|
||||||
Bond bool
|
|
||||||
Other []bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Permissions) Get(ty uint) (bool, error) {
|
|
||||||
tyP := Permission(ty)
|
|
||||||
switch tyP {
|
|
||||||
case SendPermission:
|
|
||||||
return p.Send, nil
|
|
||||||
case CallPermission:
|
|
||||||
return p.Call, nil
|
|
||||||
case CreatePermission:
|
|
||||||
return p.Create, nil
|
|
||||||
case BondPermission:
|
|
||||||
return p.Bond, nil
|
|
||||||
default:
|
|
||||||
ty = ty - 4
|
|
||||||
if ty <= uint(len(p.Other)-1) {
|
|
||||||
return p.Other[ty], nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("Unknown permission number %v", ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Permissions) Set(ty uint, val bool) error {
|
|
||||||
tyP := Permission(ty)
|
|
||||||
switch tyP {
|
|
||||||
case SendPermission:
|
|
||||||
p.Send = val
|
|
||||||
case CallPermission:
|
|
||||||
p.Call = val
|
|
||||||
case CreatePermission:
|
|
||||||
p.Create = val
|
|
||||||
case BondPermission:
|
|
||||||
p.Bond = val
|
|
||||||
default:
|
|
||||||
ty = ty - 4
|
|
||||||
if ty <= uint(len(p.Other)-1) {
|
|
||||||
p.Other[ty] = val
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("Unknown permission number %v", ty)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add should be called on all accounts in tandem
|
|
||||||
func (p Permissions) Add(val bool) (uint, error) {
|
|
||||||
l := len(p.Other)
|
|
||||||
p.Other = append(p.Other, val)
|
|
||||||
return uint(l), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove should be called on all accounts in tandem
|
|
||||||
func (p Permissions) Remove(ty uint) error {
|
|
||||||
if ty < uint(NumBasePermissions) || ty >= uint(len(p.Other)) {
|
|
||||||
return fmt.Errorf("Invalid permission number %v", ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pop the permission out of the array
|
|
||||||
perms := p.Other[:ty]
|
|
||||||
if ty+1 < uint(len(p.Other)) {
|
|
||||||
perms = append(perms, p.Other[ty+1:]...)
|
|
||||||
}
|
|
||||||
p.Other = perms
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaults for a Big Bad Public Blockchain
|
// defaults for a Big Bad Public Blockchain
|
||||||
var DefaultPermissions = Permissions{
|
var DefaultPermissions = ptypes.Permissions{
|
||||||
Send: true,
|
Send: true,
|
||||||
Call: true,
|
Call: true,
|
||||||
Create: true,
|
Create: true,
|
||||||
Bond: true,
|
Bond: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Permissions) String() string {
|
|
||||||
return fmt.Sprintf("CanSend:%v, CanCall:%v, CanCreate:%v, CanBond:%v", p.Send, p.Call, p.Create, p.Bond)
|
|
||||||
}
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
acm "github.com/tendermint/tendermint/account"
|
acm "github.com/tendermint/tendermint/account"
|
||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ func GetAccount(address []byte) (*acm.Account, error) {
|
|||||||
Balance: 0,
|
Balance: 0,
|
||||||
Code: nil,
|
Code: nil,
|
||||||
StorageRoot: nil,
|
StorageRoot: nil,
|
||||||
Permissions: cache.GetAccount(acm.GlobalPermissionsAddress).Permissions,
|
Permissions: cache.GetAccount(ptypes.GlobalPermissionsAddress).Permissions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return account, nil
|
return account, nil
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/tendermint/tendermint/account"
|
"github.com/tendermint/tendermint/account"
|
||||||
. "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" // for GlobalPermissionAddress ...
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tendermint/vm"
|
"github.com/tendermint/tendermint/vm"
|
||||||
)
|
)
|
||||||
@ -177,7 +178,7 @@ func getOrMakeOutputs(state AccountGetter, accounts map[string]*account.Account,
|
|||||||
PubKey: nil,
|
PubKey: nil,
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
Balance: 0,
|
Balance: 0,
|
||||||
Permissions: state.GetAccount(account.GlobalPermissionsAddress).Permissions,
|
Permissions: state.GetAccount(ptypes.GlobalPermissionsAddress).Permissions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
accounts[string(out.Address)] = acc
|
accounts[string(out.Address)] = acc
|
||||||
@ -442,7 +443,6 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
log.Debug(Fmt("Attempting to call an account (%X) with no code. Deducting fee from caller", tx.Address))
|
log.Debug(Fmt("Attempting to call an account (%X) with no code. Deducting fee from caller", tx.Address))
|
||||||
}
|
}
|
||||||
return types.ErrTxInvalidAddress
|
return types.ErrTxInvalidAddress
|
||||||
|
|
||||||
}
|
}
|
||||||
callee = toVMAccount(outAcc)
|
callee = toVMAccount(outAcc)
|
||||||
code = callee.Code
|
code = callee.Code
|
||||||
@ -458,6 +458,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
txCache.UpdateAccount(callee) // because we adjusted by input above.
|
txCache.UpdateAccount(callee) // because we adjusted by input above.
|
||||||
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()
|
||||||
// NOTE: Call() transfers the value from caller to callee iff call succeeds.
|
// NOTE: Call() transfers the value from caller to callee iff call succeeds.
|
||||||
|
|
||||||
if isDoug {
|
if isDoug {
|
||||||
@ -466,14 +467,6 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
|||||||
// permissions
|
// permissions
|
||||||
setupDoug(vmach, txCache, _s)
|
setupDoug(vmach, txCache, _s)
|
||||||
}
|
}
|
||||||
// set the contract's permissions
|
|
||||||
// (the vm doesn't know about account.Account or account.Permissions
|
|
||||||
vmach.SetPermissionsGetter(func(vmAcc *vm.Account) (bool, bool, bool) {
|
|
||||||
stAcc := toStateAccount(vmAcc)
|
|
||||||
p := stAcc.Permissions
|
|
||||||
return p.Send, p.Call, p.Create
|
|
||||||
})
|
|
||||||
vmach.SetPermissions(callee)
|
|
||||||
|
|
||||||
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
|
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
|
||||||
exception := ""
|
exception := ""
|
||||||
|
@ -10,15 +10,14 @@ import (
|
|||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
dbm "github.com/tendermint/tendermint/db"
|
dbm "github.com/tendermint/tendermint/db"
|
||||||
"github.com/tendermint/tendermint/merkle"
|
"github.com/tendermint/tendermint/merkle"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GenesisAccount struct {
|
type GenesisAccount struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
Amount int64 `json:"amount"`
|
Amount uint64 `json:"amount"`
|
||||||
Address []byte `json:"address"`
|
Permissions *ptypes.Permissions `json:"global_permissions"` // pointer so optional
|
||||||
Amount uint64 `json:"amount"`
|
|
||||||
Permissions *account.Permissions `json:"global_permissions"` // pointer so optional
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenesisValidator struct {
|
type GenesisValidator struct {
|
||||||
@ -29,7 +28,7 @@ type GenesisValidator struct {
|
|||||||
|
|
||||||
type GenesisParams struct {
|
type GenesisParams struct {
|
||||||
// Default permissions for newly created accounts
|
// Default permissions for newly created accounts
|
||||||
GlobalPermissions *account.Permissions `json:"global_permissions"`
|
GlobalPermissions *ptypes.Permissions `json:"global_permissions"`
|
||||||
|
|
||||||
// TODO: other params we may want to tweak?
|
// TODO: other params we may want to tweak?
|
||||||
}
|
}
|
||||||
@ -74,9 +73,10 @@ 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 := account.DefaultPermissions
|
perm_ := account.DefaultPermissions
|
||||||
|
perm := &perm_
|
||||||
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,
|
||||||
@ -90,12 +90,13 @@ 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 := account.DefaultPermissions
|
globalPerms_ := account.DefaultPermissions
|
||||||
|
globalPerms := &globalPerms_
|
||||||
if genDoc.Params != nil && genDoc.Params.GlobalPermissions != nil {
|
if genDoc.Params != nil && genDoc.Params.GlobalPermissions != nil {
|
||||||
globalPerms = *(genDoc.Params.GlobalPermissions)
|
globalPerms = genDoc.Params.GlobalPermissions
|
||||||
}
|
}
|
||||||
permsAcc := &account.Account{
|
permsAcc := &account.Account{
|
||||||
Address: account.GlobalPermissionsAddress,
|
Address: ptypes.GlobalPermissionsAddress,
|
||||||
PubKey: nil,
|
PubKey: nil,
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
Balance: 1337,
|
Balance: 1337,
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
dbm "github.com/tendermint/tendermint/db"
|
dbm "github.com/tendermint/tendermint/db"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ func makeUsers(n int) []*account.PrivAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
PermsAllFalse = account.Permissions{
|
PermsAllFalse = ptypes.Permissions{
|
||||||
Send: false,
|
Send: false,
|
||||||
Call: false,
|
Call: false,
|
||||||
Create: false,
|
Create: false,
|
||||||
@ -69,7 +70,7 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func newBaseGenDoc(globalPerm, accountPerm account.Permissions) GenesisDoc {
|
func newBaseGenDoc(globalPerm, accountPerm ptypes.Permissions) GenesisDoc {
|
||||||
genAccounts := []GenesisAccount{}
|
genAccounts := []GenesisAccount{}
|
||||||
for _, u := range user[:5] {
|
for _, u := range user[:5] {
|
||||||
accPerm := accountPerm
|
accPerm := accountPerm
|
||||||
@ -290,6 +291,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
Code: []byte{0x60},
|
Code: []byte{0x60},
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
StorageRoot: Zero256.Bytes(),
|
StorageRoot: Zero256.Bytes(),
|
||||||
|
Permissions: ptypes.NilPermissions.Copy(),
|
||||||
}
|
}
|
||||||
st.UpdateAccount(simpleAcc)
|
st.UpdateAccount(simpleAcc)
|
||||||
|
|
||||||
@ -313,6 +315,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
Code: contractCode,
|
Code: contractCode,
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
StorageRoot: Zero256.Bytes(),
|
StorageRoot: Zero256.Bytes(),
|
||||||
|
Permissions: ptypes.NilPermissions.Copy(),
|
||||||
}
|
}
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
blockCache.UpdateAccount(caller1Acc)
|
||||||
|
|
||||||
@ -356,6 +359,7 @@ func TestCallPermission(t *testing.T) {
|
|||||||
Code: contractCode2,
|
Code: contractCode2,
|
||||||
Sequence: 0,
|
Sequence: 0,
|
||||||
StorageRoot: Zero256.Bytes(),
|
StorageRoot: Zero256.Bytes(),
|
||||||
|
Permissions: ptypes.NilPermissions.Copy(),
|
||||||
}
|
}
|
||||||
caller1Acc.Permissions.Call = false
|
caller1Acc.Permissions.Call = false
|
||||||
caller2Acc.Permissions.Call = true
|
caller2Acc.Permissions.Call = true
|
||||||
@ -418,135 +422,3 @@ func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, addr []b
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
- CallTx (Create)
|
|
||||||
x - 1 input, no perm, send perm, call perm
|
|
||||||
- CallTx to create new contract, perm
|
|
||||||
- contract runs create but doesn't have create perm
|
|
||||||
- contract runs create but has perm
|
|
||||||
- contract runs call with empty address (has call perm, not create perm)
|
|
||||||
- contract runs call with empty address (has call perm, and create perm)
|
|
||||||
- contract runs call (with perm), runs contract that runs create (without perm)
|
|
||||||
- contract runs call (with perm), runs contract that runs create (with perm)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: this is just a copy of CALL...
|
|
||||||
func TestCreatePermission(t *testing.T) {
|
|
||||||
stateDB := dbm.GetDB("state")
|
|
||||||
genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse)
|
|
||||||
genDoc.Accounts[0].Permissions.Call = true // give the 0 account permission
|
|
||||||
st := MakeGenesisState(stateDB, &genDoc)
|
|
||||||
blockCache := NewBlockCache(st)
|
|
||||||
|
|
||||||
//------------------------------
|
|
||||||
// create simple contract
|
|
||||||
fmt.Println("##### SIMPLE CONTRACT")
|
|
||||||
|
|
||||||
// create simple contract
|
|
||||||
simpleContractAddr := NewContractAddress(user[0].Address, 100)
|
|
||||||
simpleAcc := &account.Account{
|
|
||||||
Address: simpleContractAddr,
|
|
||||||
Balance: 0,
|
|
||||||
Code: []byte{0x60},
|
|
||||||
Sequence: 0,
|
|
||||||
StorageRoot: Zero256.Bytes(),
|
|
||||||
}
|
|
||||||
st.UpdateAccount(simpleAcc)
|
|
||||||
|
|
||||||
// A single input, having the permission, should succeed
|
|
||||||
tx, _ := NewCallTx(blockCache, user[0].PubKey, simpleContractAddr, nil, 100, 100, 100)
|
|
||||||
SignCallTx(tx, user[0])
|
|
||||||
if err := ExecTx(blockCache, tx, true, nil); err != nil {
|
|
||||||
t.Fatal("Transaction failed", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------
|
|
||||||
// call to contract that calls simple contract - without perm
|
|
||||||
fmt.Println("##### CALL TO SIMPLE CONTRACT (FAIL)")
|
|
||||||
|
|
||||||
// create contract that calls the simple contract
|
|
||||||
contractCode := callContractCode(simpleContractAddr)
|
|
||||||
caller1ContractAddr := NewContractAddress(user[0].Address, 101)
|
|
||||||
caller1Acc := &account.Account{
|
|
||||||
Address: caller1ContractAddr,
|
|
||||||
Balance: 0,
|
|
||||||
Code: contractCode,
|
|
||||||
Sequence: 0,
|
|
||||||
StorageRoot: Zero256.Bytes(),
|
|
||||||
}
|
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
|
||||||
|
|
||||||
// A single input, having the permission, but the contract doesn't have permission
|
|
||||||
tx, _ = NewCallTx(blockCache, user[0].PubKey, caller1ContractAddr, nil, 100, 10000, 100)
|
|
||||||
SignCallTx(tx, user[0])
|
|
||||||
|
|
||||||
// we need to subscribe to the Receive event to detect the exception
|
|
||||||
exception := execTxWaitEvent(t, blockCache, tx, caller1ContractAddr) //
|
|
||||||
if exception == "" {
|
|
||||||
t.Fatal("Expected exception")
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------
|
|
||||||
// call to contract that calls simple contract - with perm
|
|
||||||
fmt.Println("##### CALL TO SIMPLE CONTRACT (PASS)")
|
|
||||||
|
|
||||||
// A single input, having the permission, and the contract has permission
|
|
||||||
caller1Acc.Permissions.Call = true
|
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
|
||||||
tx, _ = NewCallTx(blockCache, user[0].PubKey, caller1ContractAddr, nil, 100, 10000, 100)
|
|
||||||
SignCallTx(tx, user[0])
|
|
||||||
|
|
||||||
// we need to subscribe to the Receive event to detect the exception
|
|
||||||
exception = execTxWaitEvent(t, blockCache, tx, caller1ContractAddr) //
|
|
||||||
if exception != "" {
|
|
||||||
t.Fatal("Unexpected exception:", exception)
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------
|
|
||||||
// call to contract that calls contract that calls simple contract - without perm
|
|
||||||
// caller1Contract calls simpleContract. caller2Contract calls caller1Contract.
|
|
||||||
// caller1Contract does not have call perms, but caller2Contract does.
|
|
||||||
fmt.Println("##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (FAIL)")
|
|
||||||
|
|
||||||
contractCode2 := callContractCode(caller1ContractAddr)
|
|
||||||
caller2ContractAddr := NewContractAddress(user[0].Address, 102)
|
|
||||||
caller2Acc := &account.Account{
|
|
||||||
Address: caller2ContractAddr,
|
|
||||||
Balance: 1000,
|
|
||||||
Code: contractCode2,
|
|
||||||
Sequence: 0,
|
|
||||||
StorageRoot: Zero256.Bytes(),
|
|
||||||
}
|
|
||||||
caller1Acc.Permissions.Call = false
|
|
||||||
caller2Acc.Permissions.Call = true
|
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
|
||||||
blockCache.UpdateAccount(caller2Acc)
|
|
||||||
|
|
||||||
tx, _ = NewCallTx(blockCache, user[0].PubKey, caller2ContractAddr, nil, 100, 10000, 100)
|
|
||||||
SignCallTx(tx, user[0])
|
|
||||||
|
|
||||||
// we need to subscribe to the Receive event to detect the exception
|
|
||||||
exception = execTxWaitEvent(t, blockCache, tx, caller1ContractAddr) //
|
|
||||||
if exception == "" {
|
|
||||||
t.Fatal("Expected exception")
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------
|
|
||||||
// call to contract that calls contract that calls simple contract - without perm
|
|
||||||
// caller1Contract calls simpleContract. caller2Contract calls caller1Contract.
|
|
||||||
// both caller1 and caller2 have permission
|
|
||||||
fmt.Println("##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (PASS)")
|
|
||||||
|
|
||||||
caller1Acc.Permissions.Call = true
|
|
||||||
blockCache.UpdateAccount(caller1Acc)
|
|
||||||
|
|
||||||
tx, _ = NewCallTx(blockCache, user[0].PubKey, caller2ContractAddr, nil, 100, 10000, 100)
|
|
||||||
SignCallTx(tx, user[0])
|
|
||||||
|
|
||||||
// we need to subscribe to the Receive event to detect the exception
|
|
||||||
exception = execTxWaitEvent(t, blockCache, tx, caller1ContractAddr) //
|
|
||||||
if exception != "" {
|
|
||||||
t.Fatal("Unexpected exception", exception)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -24,12 +24,13 @@ 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 := account.DefaultPermissions
|
||||||
acc := &account.Account{
|
acc := &account.Account{
|
||||||
Address: privAccount.PubKey.Address(),
|
Address: privAccount.PubKey.Address(),
|
||||||
PubKey: privAccount.PubKey,
|
PubKey: privAccount.PubKey,
|
||||||
Sequence: RandInt(),
|
Sequence: RandInt(),
|
||||||
Balance: minBalance,
|
Balance: minBalance,
|
||||||
Permissions: account.DefaultPermissions,
|
Permissions: &perms,
|
||||||
}
|
}
|
||||||
if randBalance {
|
if randBalance {
|
||||||
acc.Balance += int64(RandUint32())
|
acc.Balance += int64(RandUint32())
|
||||||
|
@ -3,6 +3,7 @@ package state
|
|||||||
import (
|
import (
|
||||||
ac "github.com/tendermint/tendermint/account"
|
ac "github.com/tendermint/tendermint/account"
|
||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types" // for GlobalPermissionAddress ...
|
||||||
"github.com/tendermint/tendermint/vm"
|
"github.com/tendermint/tendermint/vm"
|
||||||
"github.com/tendermint/tendermint/vm/sha3"
|
"github.com/tendermint/tendermint/vm/sha3"
|
||||||
)
|
)
|
||||||
@ -79,7 +80,8 @@ func (cache *TxCache) CreateAccount(creator *vm.Account) *vm.Account {
|
|||||||
Code: nil,
|
Code: nil,
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
StorageRoot: Zero256,
|
StorageRoot: Zero256,
|
||||||
Other: otherAccountInfo{nil, toStateAccount(cache.GetAccount(LeftPadWord256(ac.GlobalPermissionsAddress))).Permissions},
|
Permissions: cache.GetAccount(ptypes.GlobalPermissionsAddress256).Permissions,
|
||||||
|
Other: nil,
|
||||||
}
|
}
|
||||||
cache.accounts[addr] = vmAccountInfo{account, false}
|
cache.accounts[addr] = vmAccountInfo{account, false}
|
||||||
return account
|
return account
|
||||||
@ -155,12 +157,6 @@ func NewContractAddress(caller []byte, nonce int) []byte {
|
|||||||
return sha3.Sha3(temp)[:20]
|
return sha3.Sha3(temp)[:20]
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct for carrying data the vm need not know about
|
|
||||||
type otherAccountInfo struct {
|
|
||||||
PubKey ac.PubKey
|
|
||||||
Permissions ac.Permissions
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts backend.Account to vm.Account struct.
|
// Converts backend.Account to vm.Account struct.
|
||||||
func toVMAccount(acc *ac.Account) *vm.Account {
|
func toVMAccount(acc *ac.Account) *vm.Account {
|
||||||
return &vm.Account{
|
return &vm.Account{
|
||||||
@ -169,20 +165,18 @@ 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),
|
||||||
Other: otherAccountInfo{acc.PubKey, acc.Permissions},
|
Permissions: acc.Permissions.Copy(),
|
||||||
|
Other: acc.PubKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts vm.Account to backend.Account struct.
|
// Converts vm.Account to backend.Account struct.
|
||||||
func toStateAccount(acc *vm.Account) *ac.Account {
|
func toStateAccount(acc *vm.Account) *ac.Account {
|
||||||
otherInfo, ok := acc.Other.(otherAccountInfo)
|
pubKey, ok := acc.Other.(ac.PubKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("vm.Account.Other should be type state.otherAccountInfo")
|
pubKey = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pubKey := otherInfo.PubKey
|
|
||||||
perms := otherInfo.Permissions
|
|
||||||
|
|
||||||
var storageRoot []byte
|
var storageRoot []byte
|
||||||
if acc.StorageRoot.IsZero() {
|
if acc.StorageRoot.IsZero() {
|
||||||
storageRoot = nil
|
storageRoot = nil
|
||||||
@ -196,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: perms,
|
Permissions: acc.Permissions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +53,7 @@ func TestVM(t *testing.T) {
|
|||||||
N := []byte{0x0f, 0x0f}
|
N := []byte{0x0f, 0x0f}
|
||||||
// Loop N times
|
// Loop N times
|
||||||
code := []byte{0x60, 0x00, 0x60, 0x20, 0x52, 0x5B, byte(0x60 + len(N) - 1)}
|
code := []byte{0x60, 0x00, 0x60, 0x20, 0x52, 0x5B, byte(0x60 + len(N) - 1)}
|
||||||
for i := 0; i < len(N); i++ {
|
code = append(code, N...)
|
||||||
code = append(code, N[i])
|
|
||||||
}
|
|
||||||
code = append(code, []byte{0x60, 0x20, 0x51, 0x12, 0x15, 0x60, byte(0x1b + len(N)), 0x57, 0x60, 0x01, 0x60, 0x20, 0x51, 0x01, 0x60, 0x20, 0x52, 0x60, 0x05, 0x56, 0x5B}...)
|
code = append(code, []byte{0x60, 0x20, 0x51, 0x12, 0x15, 0x60, byte(0x1b + len(N)), 0x57, 0x60, 0x01, 0x60, 0x20, 0x51, 0x01, 0x60, 0x20, 0x52, 0x60, 0x05, 0x56, 0x5B}...)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
output, err := ourVm.Call(account1, account2, code, []byte{}, 0, &gas)
|
output, err := ourVm.Call(account1, account2, code, []byte{}, 0, &gas)
|
||||||
@ -120,6 +118,7 @@ func TestSendCall(t *testing.T) {
|
|||||||
|
|
||||||
//----------------------------------------------
|
//----------------------------------------------
|
||||||
// account2 has insufficient balance, should fail
|
// account2 has insufficient balance, should fail
|
||||||
|
fmt.Println("Should fail with insufficient balance")
|
||||||
|
|
||||||
exception := runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 1000)
|
exception := runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 1000)
|
||||||
if exception == "" {
|
if exception == "" {
|
||||||
@ -137,6 +136,7 @@ func TestSendCall(t *testing.T) {
|
|||||||
|
|
||||||
//----------------------------------------------
|
//----------------------------------------------
|
||||||
// insufficient gas, should fail
|
// insufficient gas, should fail
|
||||||
|
fmt.Println("Should fail with insufficient gas")
|
||||||
|
|
||||||
account2.Balance = 100000
|
account2.Balance = 100000
|
||||||
exception = runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 100)
|
exception = runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 100)
|
||||||
|
@ -2,6 +2,7 @@ package vm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
|
ptypes "github.com/tendermint/tendermint/permission/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -15,6 +16,8 @@ type Account struct {
|
|||||||
Nonce int64
|
Nonce int64
|
||||||
StorageRoot Word256
|
StorageRoot Word256
|
||||||
Other interface{} // For holding all other data.
|
Other interface{} // For holding all other data.
|
||||||
|
|
||||||
|
Permissions *ptypes.Permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acc *Account) String() string {
|
func (acc *Account) String() string {
|
||||||
|
50
vm/vm.go
50
vm/vm.go
@ -60,24 +60,18 @@ type VM struct {
|
|||||||
|
|
||||||
evc events.Fireable
|
evc events.Fireable
|
||||||
|
|
||||||
doug bool // is this the gendoug contract
|
doug bool // is this the gendoug contract
|
||||||
|
perms bool // permission checking can be turned off
|
||||||
sendPerm, callPerm, createPerm bool // this contract's permissions
|
|
||||||
|
|
||||||
getPerms func(*Account) (bool, bool, bool) // gets permissions out of an account (wraps toStateFunction to get perms out of Other)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVM(appState AppState, params Params, origin Word256, txid []byte) *VM {
|
func NewVM(appState AppState, params Params, origin Word256, txid []byte) *VM {
|
||||||
return &VM{
|
return &VM{
|
||||||
appState: appState,
|
appState: appState,
|
||||||
params: params,
|
params: params,
|
||||||
origin: origin,
|
origin: origin,
|
||||||
callDepth: 0,
|
callDepth: 0,
|
||||||
txid: txid,
|
txid: txid,
|
||||||
doug: false,
|
doug: false,
|
||||||
sendPerm: true,
|
|
||||||
callPerm: true,
|
|
||||||
createPerm: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,23 +85,9 @@ func (vm *VM) EnableDoug() {
|
|||||||
vm.doug = true
|
vm.doug = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VM) SetPermissionsGetter(getPerms func(acc *Account) (bool, bool, bool)) {
|
// run permission checks before call and create
|
||||||
vm.getPerms = getPerms
|
func (vm *VM) EnablePermissions() {
|
||||||
}
|
vm.perms = true
|
||||||
|
|
||||||
func (vm *VM) SetPermissions(acc *Account) {
|
|
||||||
if vm.getPerms != nil {
|
|
||||||
send, call, create := vm.getPerms(acc)
|
|
||||||
vm.setPermissions(send, call, create)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the contract's generic permissions
|
|
||||||
func (vm *VM) setPermissions(send, call, create bool) {
|
|
||||||
// TODO: distinction between send and call not defined at the VM yet (it's all through a CALL!)
|
|
||||||
vm.sendPerm = send
|
|
||||||
vm.callPerm = call
|
|
||||||
vm.createPerm = create
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
@ -701,7 +681,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.createPerm {
|
if vm.perms && !callee.Permissions.Create {
|
||||||
return nil, ErrPermission{"create"}
|
return nil, ErrPermission{"create"}
|
||||||
}
|
}
|
||||||
contractValue := stack.Pop64()
|
contractValue := stack.Pop64()
|
||||||
@ -729,7 +709,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.callPerm {
|
if vm.perms && !callee.Permissions.Call {
|
||||||
return nil, ErrPermission{"call"}
|
return nil, ErrPermission{"call"}
|
||||||
}
|
}
|
||||||
gasLimit := stack.Pop64()
|
gasLimit := stack.Pop64()
|
||||||
@ -786,11 +766,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
}
|
}
|
||||||
vm.appState.UpdateAccount(acc)
|
vm.appState.UpdateAccount(acc)
|
||||||
}
|
}
|
||||||
// copy permissions and set permissions for new contract
|
|
||||||
send, call, create := vm.sendPerm, vm.callPerm, vm.createPerm
|
|
||||||
vm.SetPermissions(acc)
|
|
||||||
ret, err = vm.Call(callee, acc, acc.Code, args, value, gas)
|
ret, err = vm.Call(callee, acc, acc.Code, args, value, gas)
|
||||||
vm.sendPerm, vm.callPerm, vm.createPerm = send, call, create
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user