From f5e7097ccc0214b8e5c16206f5f5c9e49a093877 Mon Sep 17 00:00:00 2001
From: Silas Davis <silas@monax.io>
Date: Tue, 27 Mar 2018 21:02:38 +0100
Subject: [PATCH] Reload callee and caller after CALLs and update both on
 create. Move state to sub-package fixing cyclic dependency. No longer expect
 insufficient gas for nested call.

Signed-off-by: Silas Davis <silas@monax.io>
---
 account/account.go                         |  10 +-
 account/account_test.go                    |  11 ++
 account/state.go                           |  73 ------------
 account/state/state.go                     | 101 ++++++++++++++++
 account/{ => state}/state_cache.go         |  58 ++++-----
 account/state/state_cache_test.go          | 129 +++++++++++++++++++++
 account/state_cache_test.go                |  63 ----------
 client/rpc/client.go                       |   3 +-
 execution/evm/accounts.go                  |   4 +-
 execution/evm/fake_app_state.go            |   3 +-
 execution/evm/native.go                    |  10 +-
 execution/evm/snative.go                   |  63 +++++-----
 execution/evm/vm.go                        |  86 +++++++++-----
 execution/evm/vm_test.go                   |  33 +++---
 execution/execution.go                     |  71 ++++++------
 execution/execution_test.go                |  40 ++++---
 execution/state.go                         |  10 +-
 execution/state_test.go                    |  12 +-
 execution/transactor.go                    |  11 +-
 permission/constants.go                    |  10 --
 permission/permissions.go                  |  19 ---
 permission/{ => snatives}/snatives.go      |  43 +++----
 permission/{ => snatives}/snatives_test.go |   9 +-
 permission/util.go                         |   2 +-
 rpc/service.go                             |  21 ++--
 txs/tx.go                                  |   4 +-
 txs/tx_test.go                             |   5 +-
 txs/tx_utils.go                            |  15 +--
 28 files changed, 525 insertions(+), 394 deletions(-)
 delete mode 100644 account/state.go
 create mode 100644 account/state/state.go
 rename account/{ => state}/state_cache.go (76%)
 create mode 100644 account/state/state_cache_test.go
 delete mode 100644 account/state_cache_test.go
 delete mode 100644 permission/constants.go
 rename permission/{ => snatives}/snatives.go (72%)
 rename permission/{ => snatives}/snatives_test.go (65%)

diff --git a/account/account.go b/account/account.go
index 9ed538c5..ab6e9874 100644
--- a/account/account.go
+++ b/account/account.go
@@ -25,6 +25,8 @@ import (
 	"github.com/tendermint/go-wire"
 )
 
+var GlobalPermissionsAddress = Address(binary.Zero160)
+
 // Signable is an interface for all signable things.
 // It typically removes signatures before serializing.
 type Signable interface {
@@ -216,14 +218,6 @@ func AsMutableAccount(account Account) MutableAccount {
 	return AsConcreteAccount(account).MutableAccount()
 }
 
-func GetMutableAccount(getter Getter, address Address) (MutableAccount, error) {
-	acc, err := getter.GetAccount(address)
-	if err != nil {
-		return nil, err
-	}
-	return AsMutableAccount(acc), nil
-}
-
 //----------------------------------------------
 // concreteAccount Wrapper
 
diff --git a/account/account_test.go b/account/account_test.go
index 800ea4ff..aaffb2ff 100644
--- a/account/account_test.go
+++ b/account/account_test.go
@@ -21,6 +21,8 @@ import (
 
 	"fmt"
 
+	"github.com/hyperledger/burrow/permission"
+	"github.com/hyperledger/burrow/permission/types"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/tendermint/go-crypto"
@@ -77,11 +79,20 @@ func TestAccountSerialise(t *testing.T) {
 
 func TestDecodeConcrete(t *testing.T) {
 	concreteAcc := NewConcreteAccountFromSecret("Super Semi Secret")
+	concreteAcc.Permissions = types.AccountPermissions{
+		Base: types.BasePermissions{
+			Perms:  permission.SetGlobal,
+			SetBit: permission.SetGlobal,
+		},
+		Roles: []string{"bums"},
+	}
 	acc := concreteAcc.Account()
 	encodedAcc, err := acc.Encode()
 	require.NoError(t, err)
+
 	concreteAccOut, err := DecodeConcrete(encodedAcc)
 	require.NoError(t, err)
+
 	assert.Equal(t, concreteAcc, *concreteAccOut)
 	concreteAccOut, err = DecodeConcrete([]byte("flungepliffery munknut tolopops"))
 	assert.Error(t, err)
diff --git a/account/state.go b/account/state.go
deleted file mode 100644
index 5569fbe6..00000000
--- a/account/state.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package account
-
-import (
-	"github.com/hyperledger/burrow/binary"
-)
-
-type Getter interface {
-	// Get an account by its address return nil if it does not exist (which should not be an error)
-	GetAccount(address Address) (Account, error)
-}
-
-type Iterable interface {
-	// Iterates through accounts calling passed function once per account, if the consumer
-	// returns true the iteration breaks and returns true to indicate it iteration
-	// was escaped
-	IterateAccounts(consumer func(Account) (stop bool)) (stopped bool, err error)
-}
-
-type Updater interface {
-	// Updates the fields of updatedAccount by address, creating the account
-	// if it does not exist
-	UpdateAccount(updatedAccount Account) error
-	// Remove the account at address
-	RemoveAccount(address Address) error
-}
-
-type StorageGetter interface {
-	// Retrieve a 32-byte value stored at key for the account at address, return Zero256 if key does not exist but
-	// error if address does not
-	GetStorage(address Address, key binary.Word256) (value binary.Word256, err error)
-}
-
-type StorageSetter interface {
-	// Store a 32-byte value at key for the account at address
-	SetStorage(address Address, key, value binary.Word256) error
-}
-
-type StorageIterable interface {
-	// Iterates through the storage of account ad address calling the passed function once per account,
-	// if the iterator function returns true the iteration breaks and returns true to indicate it iteration
-	// was escaped
-	IterateStorage(address Address, consumer func(key, value binary.Word256) (stop bool)) (stopped bool, err error)
-}
-
-// Compositions
-
-// Read-only account and storage state
-type StateReader interface {
-	Getter
-	StorageGetter
-}
-
-// Read and list account and storage state
-type StateIterable interface {
-	StateReader
-	Iterable
-	StorageIterable
-}
-
-// Read and write account and storage state
-type StateWriter interface {
-	StateReader
-	Updater
-	StorageSetter
-}
-
-type IterableStateWriter interface {
-	StateReader
-	Updater
-	StorageSetter
-	Iterable
-	StorageIterable
-}
diff --git a/account/state/state.go b/account/state/state.go
new file mode 100644
index 00000000..005d3082
--- /dev/null
+++ b/account/state/state.go
@@ -0,0 +1,101 @@
+package state
+
+import (
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/binary"
+	ptypes "github.com/hyperledger/burrow/permission/types"
+)
+
+type AccountGetter interface {
+	// Get an account by its address return nil if it does not exist (which should not be an error)
+	GetAccount(address acm.Address) (acm.Account, error)
+}
+
+type AccountIterable interface {
+	// Iterates through accounts calling passed function once per account, if the consumer
+	// returns true the iteration breaks and returns true to indicate it iteration
+	// was escaped
+	IterateAccounts(consumer func(acm.Account) (stop bool)) (stopped bool, err error)
+}
+
+type AccountUpdater interface {
+	// Updates the fields of updatedAccount by address, creating the account
+	// if it does not exist
+	UpdateAccount(updatedAccount acm.Account) error
+	// Remove the account at address
+	RemoveAccount(address acm.Address) error
+}
+
+type StorageGetter interface {
+	// Retrieve a 32-byte value stored at key for the account at address, return Zero256 if key does not exist but
+	// error if address does not
+	GetStorage(address acm.Address, key binary.Word256) (value binary.Word256, err error)
+}
+
+type StorageSetter interface {
+	// Store a 32-byte value at key for the account at address
+	SetStorage(address acm.Address, key, value binary.Word256) error
+}
+
+type StorageIterable interface {
+	// Iterates through the storage of account ad address calling the passed function once per account,
+	// if the iterator function returns true the iteration breaks and returns true to indicate it iteration
+	// was escaped
+	IterateStorage(address acm.Address, consumer func(key, value binary.Word256) (stop bool)) (stopped bool, err error)
+}
+
+// Compositions
+
+// Read-only account and storage state
+type Reader interface {
+	AccountGetter
+	StorageGetter
+}
+
+// Read and list account and storage state
+type Iterable interface {
+	Reader
+	AccountIterable
+	StorageIterable
+}
+
+// Read and write account and storage state
+type Writer interface {
+	Reader
+	AccountUpdater
+	StorageSetter
+}
+
+type IterableWriter interface {
+	Reader
+	AccountUpdater
+	StorageSetter
+	AccountIterable
+	StorageIterable
+}
+
+func GetMutableAccount(getter AccountGetter, address acm.Address) (acm.MutableAccount, error) {
+	acc, err := getter.GetAccount(address)
+	if err != nil {
+		return nil, err
+	}
+	return acm.AsMutableAccount(acc), nil
+}
+
+func GlobalPermissionsAccount(getter AccountGetter) acm.Account {
+	acc, err := getter.GetAccount(acm.GlobalPermissionsAddress)
+	if err != nil {
+		panic("Could not get global permission account, but this must exist")
+	}
+	return acc
+}
+
+// Get global permissions from the account at GlobalPermissionsAddress
+func GlobalAccountPermissions(getter AccountGetter) ptypes.AccountPermissions {
+	if getter == nil {
+		return ptypes.AccountPermissions{
+			Roles: []string{},
+		}
+	}
+	return GlobalPermissionsAccount(getter).Permissions()
+}
diff --git a/account/state_cache.go b/account/state/state_cache.go
similarity index 76%
rename from account/state_cache.go
rename to account/state/state_cache.go
index 28b6d0c5..f9d85c97 100644
--- a/account/state_cache.go
+++ b/account/state/state_cache.go
@@ -12,48 +12,49 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package account
+package state
 
 import (
 	"fmt"
 	"sort"
 	"sync"
 
+	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/binary"
 )
 
-type StateCache interface {
-	IterableStateWriter
-	Sync(state StateWriter) error
-	Reset(backend StateIterable)
-	Flush(state IterableStateWriter) error
-	Backend() StateIterable
+type Cache interface {
+	IterableWriter
+	Sync(state Writer) error
+	Reset(backend Iterable)
+	Flush(state IterableWriter) error
+	Backend() Iterable
 }
 
 type stateCache struct {
 	sync.RWMutex
-	backend  StateIterable
-	accounts map[Address]*accountInfo
+	backend  Iterable
+	accounts map[acm.Address]*accountInfo
 }
 
 type accountInfo struct {
 	sync.RWMutex
-	account Account
+	account acm.Account
 	storage map[binary.Word256]binary.Word256
 	removed bool
 	updated bool
 }
 
-// Returns a StateCache that wraps an underlying StateReader to use on a cache miss, can write to an output StateWriter
+// Returns a Cache that wraps an underlying Reader to use on a cache miss, can write to an output Writer
 // via Sync. Goroutine safe for concurrent access.
-func NewStateCache(backend StateIterable) StateCache {
+func NewCache(backend Iterable) Cache {
 	return &stateCache{
 		backend:  backend,
-		accounts: make(map[Address]*accountInfo),
+		accounts: make(map[acm.Address]*accountInfo),
 	}
 }
 
-func (cache *stateCache) GetAccount(address Address) (Account, error) {
+func (cache *stateCache) GetAccount(address acm.Address) (acm.Account, error) {
 	accInfo, err := cache.get(address)
 	if err != nil {
 		return nil, err
@@ -66,7 +67,7 @@ func (cache *stateCache) GetAccount(address Address) (Account, error) {
 	return accInfo.account, nil
 }
 
-func (cache *stateCache) UpdateAccount(account Account) error {
+func (cache *stateCache) UpdateAccount(account acm.Account) error {
 	accInfo, err := cache.get(account.Address())
 	if err != nil {
 		return err
@@ -78,10 +79,11 @@ func (cache *stateCache) UpdateAccount(account Account) error {
 	}
 	accInfo.account = account
 	accInfo.updated = true
+
 	return nil
 }
 
-func (cache *stateCache) RemoveAccount(address Address) error {
+func (cache *stateCache) RemoveAccount(address acm.Address) error {
 	accInfo, err := cache.get(address)
 	if err != nil {
 		return err
@@ -96,7 +98,7 @@ func (cache *stateCache) RemoveAccount(address Address) error {
 }
 
 // Iterates over all accounts first in cache and then in backend until consumer returns true for 'stop'
-func (cache *stateCache) IterateAccounts(consumer func(Account) (stop bool)) (stopped bool, err error) {
+func (cache *stateCache) IterateAccounts(consumer func(acm.Account) (stop bool)) (stopped bool, err error) {
 	// Try cache first for early exit
 	cache.RLock()
 	for _, info := range cache.accounts {
@@ -108,7 +110,7 @@ func (cache *stateCache) IterateAccounts(consumer func(Account) (stop bool)) (st
 	return cache.backend.IterateAccounts(consumer)
 }
 
-func (cache *stateCache) GetStorage(address Address, key binary.Word256) (binary.Word256, error) {
+func (cache *stateCache) GetStorage(address acm.Address, key binary.Word256) (binary.Word256, error) {
 	accInfo, err := cache.get(address)
 	if err != nil {
 		return binary.Zero256, err
@@ -133,7 +135,7 @@ func (cache *stateCache) GetStorage(address Address, key binary.Word256) (binary
 }
 
 // NOTE: Set value to zero to remove.
-func (cache *stateCache) SetStorage(address Address, key binary.Word256, value binary.Word256) error {
+func (cache *stateCache) SetStorage(address acm.Address, key binary.Word256, value binary.Word256) error {
 	accInfo, err := cache.get(address)
 	accInfo.Lock()
 	defer accInfo.Unlock()
@@ -149,7 +151,7 @@ func (cache *stateCache) SetStorage(address Address, key binary.Word256, value b
 }
 
 // Iterates over all storage items first in cache and then in backend until consumer returns true for 'stop'
-func (cache *stateCache) IterateStorage(address Address,
+func (cache *stateCache) IterateStorage(address acm.Address,
 	consumer func(key, value binary.Word256) (stop bool)) (stopped bool, err error) {
 	accInfo, err := cache.get(address)
 	if err != nil {
@@ -168,10 +170,10 @@ func (cache *stateCache) IterateStorage(address Address,
 
 // Syncs changes to the backend in deterministic order. Sends storage updates before updating
 // the account they belong so that storage values can be taken account of in the update.
-func (cache *stateCache) Sync(state StateWriter) error {
+func (cache *stateCache) Sync(state Writer) error {
 	cache.Lock()
 	defer cache.Unlock()
-	var addresses Addresses
+	var addresses acm.Addresses
 	for address := range cache.accounts {
 		addresses = append(addresses, address)
 	}
@@ -212,15 +214,15 @@ func (cache *stateCache) Sync(state StateWriter) error {
 }
 
 // Resets the cache to empty initialising the backing map to the same size as the previous iteration.
-func (cache *stateCache) Reset(backend StateIterable) {
+func (cache *stateCache) Reset(backend Iterable) {
 	cache.Lock()
 	defer cache.Unlock()
 	cache.backend = backend
-	cache.accounts = make(map[Address]*accountInfo, len(cache.accounts))
+	cache.accounts = make(map[acm.Address]*accountInfo, len(cache.accounts))
 }
 
-// Syncs the StateCache and Resets it to use as the backend StateReader
-func (cache *stateCache) Flush(state IterableStateWriter) error {
+// Syncs the Cache and Resets it to use as the backend Reader
+func (cache *stateCache) Flush(state IterableWriter) error {
 	err := cache.Sync(state)
 	if err != nil {
 		return err
@@ -229,12 +231,12 @@ func (cache *stateCache) Flush(state IterableStateWriter) error {
 	return nil
 }
 
-func (cache *stateCache) Backend() StateIterable {
+func (cache *stateCache) Backend() Iterable {
 	return cache.backend
 }
 
 // Get the cache accountInfo item creating it if necessary
-func (cache *stateCache) get(address Address) (*accountInfo, error) {
+func (cache *stateCache) get(address acm.Address) (*accountInfo, error) {
 	cache.RLock()
 	accInfo := cache.accounts[address]
 	cache.RUnlock()
diff --git a/account/state/state_cache_test.go b/account/state/state_cache_test.go
new file mode 100644
index 00000000..5928a6ed
--- /dev/null
+++ b/account/state/state_cache_test.go
@@ -0,0 +1,129 @@
+package state
+
+import (
+	"fmt"
+	"testing"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/binary"
+	"github.com/hyperledger/burrow/permission"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestStateCache_GetAccount(t *testing.T) {
+	acc := acm.NewConcreteAccountFromSecret("foo")
+	acc.Permissions.Base.Perms = permission.AddRole | permission.Send
+	acc.Permissions.Base.SetBit = acc.Permissions.Base.Perms
+	state := combine(account(acc.Account(), "I AM A KEY", "NO YOU ARE A KEY"))
+	cache := NewCache(state)
+
+	accOut, err := cache.GetAccount(acc.Address)
+	require.NoError(t, err)
+	cache.UpdateAccount(accOut)
+	accEnc, err := acc.Encode()
+	accEncOut, err := accOut.Encode()
+	assert.Equal(t, accEnc, accEncOut)
+	assert.Equal(t, acc.Permissions, accOut.Permissions())
+
+	cacheBackend := NewCache(newTestState())
+	err = cache.Sync(cacheBackend)
+	require.NoError(t, err)
+	accOut, err = cacheBackend.GetAccount(acc.Address)
+	require.NotNil(t, accOut)
+	accEncOut, err = accOut.Encode()
+	assert.NoError(t, err)
+	assert.Equal(t, accEnc, accEncOut)
+}
+
+func TestStateCache_UpdateAccount(t *testing.T) {
+}
+
+func TestStateCache_RemoveAccount(t *testing.T) {
+}
+
+func TestStateCache_GetStorage(t *testing.T) {
+}
+
+func TestStateCache_SetStorage(t *testing.T) {
+}
+
+func TestStateCache_Sync(t *testing.T) {
+}
+
+func TestStateCache_get(t *testing.T) {
+}
+
+// TODO: write tests as part of feature branch
+type testState struct {
+	Accounts map[acm.Address]acm.Account
+	Storage  map[acm.Address]map[binary.Word256]binary.Word256
+}
+
+var _ Iterable = &testState{}
+
+func newTestState() *testState {
+	return &testState{
+		Accounts: make(map[acm.Address]acm.Account),
+		Storage:  make(map[acm.Address]map[binary.Word256]binary.Word256),
+	}
+}
+
+func account(acc acm.Account, keyvals ...string) *testState {
+	ts := newTestState()
+	ts.Accounts[acc.Address()] = acc
+	ts.Storage[acc.Address()] = make(map[binary.Word256]binary.Word256)
+	for i := 0; i < len(keyvals); i += 2 {
+		ts.Storage[acc.Address()][word(keyvals[i])] = word(keyvals[i+1])
+	}
+	return ts
+}
+
+func combine(states ...*testState) *testState {
+	ts := newTestState()
+	for _, state := range states {
+		for _, acc := range state.Accounts {
+			ts.Accounts[acc.Address()] = acc
+			ts.Storage[acc.Address()] = state.Storage[acc.Address()]
+		}
+	}
+	return ts
+}
+
+func word(str string) binary.Word256 {
+	return binary.LeftPadWord256([]byte(str))
+}
+
+func (tsr *testState) IterateAccounts(consumer func(acm.Account) (stop bool)) (stopped bool, err error) {
+	for _, acc := range tsr.Accounts {
+		if consumer(acc) {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
+func (tsr *testState) IterateStorage(address acm.Address, consumer func(key, value binary.Word256) (stop bool)) (stopped bool, err error) {
+	for key, value := range tsr.Storage[address] {
+		if consumer(key, value) {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
+func (tsr *testState) GetAccount(address acm.Address) (acm.Account, error) {
+	return tsr.Accounts[address], nil
+}
+
+func (tsr *testState) GetStorage(address acm.Address, key binary.Word256) (binary.Word256, error) {
+	storage, ok := tsr.Storage[address]
+	if !ok {
+		return binary.Zero256, fmt.Errorf("could not find storage for account %s", address)
+	}
+	value, ok := storage[key]
+	if !ok {
+		return binary.Zero256, fmt.Errorf("could not find key %x for account %s", key, address)
+	}
+	return value, nil
+}
diff --git a/account/state_cache_test.go b/account/state_cache_test.go
deleted file mode 100644
index 6ecc2cdd..00000000
--- a/account/state_cache_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package account
-
-import (
-	"testing"
-
-	"fmt"
-
-	"github.com/hyperledger/burrow/binary"
-)
-
-// TODO: write tests as part of feature branch
-type testStateReader struct {
-	Accounts map[Address]Account
-	Storage  map[Address]map[binary.Word256]binary.Word256
-}
-
-func accountAndStorage(account Account, keyvals ...binary.Word256) *testStateReader {
-	return &testStateReader{}
-
-}
-
-func (tsr *testStateReader) GetAccount(address Address) (Account, error) {
-	account, ok := tsr.Accounts[address]
-	if !ok {
-		return nil, fmt.Errorf("could not find account %s", address)
-	}
-	return account, nil
-}
-
-func (tsr *testStateReader) GetStorage(address Address, key binary.Word256) (binary.Word256, error) {
-	storage, ok := tsr.Storage[address]
-	if !ok {
-		return binary.Zero256, fmt.Errorf("could not find storage for account %s", address)
-	}
-	value, ok := storage[key]
-	if !ok {
-		return binary.Zero256, fmt.Errorf("could not find key %x for account %s", key, address)
-	}
-	return value, nil
-}
-
-var _ StateReader = &testStateReader{}
-
-func TestStateCache_GetAccount(t *testing.T) {
-}
-
-func TestStateCache_UpdateAccount(t *testing.T) {
-}
-
-func TestStateCache_RemoveAccount(t *testing.T) {
-}
-
-func TestStateCache_GetStorage(t *testing.T) {
-}
-
-func TestStateCache_SetStorage(t *testing.T) {
-}
-
-func TestStateCache_Sync(t *testing.T) {
-}
-
-func TestStateCache_get(t *testing.T) {
-}
diff --git a/client/rpc/client.go b/client/rpc/client.go
index 53d80dbc..3a76948c 100644
--- a/client/rpc/client.go
+++ b/client/rpc/client.go
@@ -24,6 +24,7 @@ import (
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/client"
 	"github.com/hyperledger/burrow/keys"
+	"github.com/hyperledger/burrow/permission/snatives"
 	"github.com/hyperledger/burrow/txs"
 )
 
@@ -114,7 +115,7 @@ func Permissions(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey,
 	if err != nil {
 		return nil, fmt.Errorf("could not convert action '%s' to PermFlag: %v", action, err)
 	}
-	permArgs := ptypes.PermArgs{
+	permArgs := snatives.PermArgs{
 		PermFlag: permFlag,
 	}
 
diff --git a/execution/evm/accounts.go b/execution/evm/accounts.go
index 4f6ce54c..800e6269 100644
--- a/execution/evm/accounts.go
+++ b/execution/evm/accounts.go
@@ -22,11 +22,11 @@ func DeriveNewAccount(creator acm.MutableAccount, permissions ptypes.AccountPerm
 	addr := acm.NewContractAddress(creator.Address(), sequence)
 
 	// Create account from address.
-	return (&acm.ConcreteAccount{
+	return acm.ConcreteAccount{
 		Address:     addr,
 		Balance:     0,
 		Code:        nil,
 		Sequence:    0,
 		Permissions: permissions,
-	}).MutableAccount()
+	}.MutableAccount()
 }
diff --git a/execution/evm/fake_app_state.go b/execution/evm/fake_app_state.go
index 09a985ca..7efbe82c 100644
--- a/execution/evm/fake_app_state.go
+++ b/execution/evm/fake_app_state.go
@@ -20,6 +20,7 @@ import (
 	"bytes"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	. "github.com/hyperledger/burrow/binary"
 )
 
@@ -28,7 +29,7 @@ type FakeAppState struct {
 	storage  map[string]Word256
 }
 
-var _ acm.StateWriter = &FakeAppState{}
+var _ state.Writer = &FakeAppState{}
 
 func (fas *FakeAppState) GetAccount(addr acm.Address) (acm.Account, error) {
 	account := fas.accounts[addr]
diff --git a/execution/evm/native.go b/execution/evm/native.go
index 3bf07619..70f00ed6 100644
--- a/execution/evm/native.go
+++ b/execution/evm/native.go
@@ -18,6 +18,7 @@ import (
 	"crypto/sha256"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/logging"
 	"golang.org/x/crypto/ripemd160"
@@ -53,7 +54,7 @@ func registerNativeContracts() {
 
 //-----------------------------------------------------------------------------
 
-type NativeContract func(state acm.StateWriter, caller acm.Account, input []byte, gas *uint64,
+type NativeContract func(state state.Writer, caller acm.Account, input []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error)
 
 /* Removed due to C dependency
@@ -73,13 +74,14 @@ func ecrecoverFunc(state State, caller *acm.Account, input []byte, gas *int64) (
 	recovered, err := secp256k1.RecoverPubkey(hash, sig)
 	if err != nil {
 		return nil, err
+OH NO STOCASTIC CAT CODING!!!!
 	}
 	hashed := sha3.Sha3(recovered[1:])
 	return LeftPadBytes(hashed, 32), nil
 }
 */
 
-func sha256Func(state acm.StateWriter, caller acm.Account, input []byte, gas *uint64,
+func sha256Func(state state.Writer, caller acm.Account, input []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 	// Deduct gas
 	gasRequired := uint64((len(input)+31)/32)*GasSha256Word + GasSha256Base
@@ -95,7 +97,7 @@ func sha256Func(state acm.StateWriter, caller acm.Account, input []byte, gas *ui
 	return hasher.Sum(nil), nil
 }
 
-func ripemd160Func(state acm.StateWriter, caller acm.Account, input []byte, gas *uint64,
+func ripemd160Func(state state.Writer, caller acm.Account, input []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 	// Deduct gas
 	gasRequired := uint64((len(input)+31)/32)*GasRipemd160Word + GasRipemd160Base
@@ -111,7 +113,7 @@ func ripemd160Func(state acm.StateWriter, caller acm.Account, input []byte, gas
 	return LeftPadBytes(hasher.Sum(nil), 32), nil
 }
 
-func identityFunc(state acm.StateWriter, caller acm.Account, input []byte, gas *uint64,
+func identityFunc(state state.Writer, caller acm.Account, input []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 	// Deduct gas
 	gasRequired := uint64((len(input)+31)/32)*GasIdentityWord + GasIdentityBase
diff --git a/execution/evm/snative.go b/execution/evm/snative.go
index a172aedc..34375a0a 100644
--- a/execution/evm/snative.go
+++ b/execution/evm/snative.go
@@ -20,6 +20,7 @@ import (
 	"strings"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/execution/evm/abi"
 	"github.com/hyperledger/burrow/execution/evm/sha3"
@@ -225,10 +226,19 @@ func NewSNativeContract(comment, name string,
 	}
 }
 
+type ErrLacksSNativePermission struct {
+	Address acm.Address
+	SNative string
+}
+
+func (e ErrLacksSNativePermission) Error() string {
+	return fmt.Sprintf("account %s does not have SNative function call permission: %s", e.Address, e.SNative)
+}
+
 // This function is designed to be called from the EVM once a SNative contract
 // has been selected. It is also placed in a registry by registerSNativeContracts
 // So it can be looked up by SNative address
-func (contract *SNativeContractDescription) Dispatch(state acm.StateWriter, caller acm.Account,
+func (contract *SNativeContractDescription) Dispatch(state state.Writer, caller acm.Account,
 	args []byte, gas *uint64, logger *logging.Logger) (output []byte, err error) {
 
 	logger = logger.With(structure.ScopeKey, "Dispatch", "contract_name", contract.Name)
@@ -340,7 +350,7 @@ func abiReturn(name string, abiTypeName abi.TypeName) abi.Return {
 // Permission function defintions
 
 // TODO: catch errors, log em, return 0s to the vm (should some errors cause exceptions though?)
-func hasBase(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64,
+func hasBase(state state.Writer, caller acm.Account, args []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 
 	addrWord256, permNum := returnTwoArgs(args)
@@ -366,12 +376,12 @@ func hasBase(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64
 	return LeftPadWord256([]byte{permInt}).Bytes(), nil
 }
 
-func setBase(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64,
+func setBase(stateWriter state.Writer, caller acm.Account, args []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 
 	addrWord256, permNum, permVal := returnThreeArgs(args)
 	address := acm.AddressFromWord256(addrWord256)
-	acc, err := acm.GetMutableAccount(state, address)
+	acc, err := state.GetMutableAccount(stateWriter, address)
 	if err != nil {
 		return nil, err
 	}
@@ -386,19 +396,19 @@ func setBase(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64
 	if err = acc.MutablePermissions().Base.Set(permN, permV); err != nil {
 		return nil, err
 	}
-	state.UpdateAccount(acc)
+	stateWriter.UpdateAccount(acc)
 	logger.Trace.Log("function", "setBase", "address", address.String(),
 		"permission_flag", fmt.Sprintf("%b", permN),
 		"permission_value", permV)
-	return effectivePermBytes(acc.Permissions().Base, globalPerms(state)), nil
+	return effectivePermBytes(acc.Permissions().Base, globalPerms(stateWriter)), nil
 }
 
-func unsetBase(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64,
+func unsetBase(stateWriter state.Writer, caller acm.Account, args []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 
 	addrWord256, permNum := returnTwoArgs(args)
 	address := acm.AddressFromWord256(addrWord256)
-	acc, err := acm.GetMutableAccount(state, address)
+	acc, err := state.GetMutableAccount(stateWriter, address)
 	if err != nil {
 		return nil, err
 	}
@@ -412,19 +422,19 @@ func unsetBase(state acm.StateWriter, caller acm.Account, args []byte, gas *uint
 	if err = acc.MutablePermissions().Base.Unset(permN); err != nil {
 		return nil, err
 	}
-	state.UpdateAccount(acc)
+	stateWriter.UpdateAccount(acc)
 	logger.Trace.Log("function", "unsetBase", "address", address.String(),
 		"perm_flag", fmt.Sprintf("%b", permN),
 		"permission_flag", fmt.Sprintf("%b", permN))
 
-	return effectivePermBytes(acc.Permissions().Base, globalPerms(state)), nil
+	return effectivePermBytes(acc.Permissions().Base, globalPerms(stateWriter)), nil
 }
 
-func setGlobal(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64,
+func setGlobal(stateWriter state.Writer, caller acm.Account, args []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 
 	permNum, permVal := returnTwoArgs(args)
-	acc, err := acm.GetMutableAccount(state, permission.GlobalPermissionsAddress)
+	acc, err := state.GetMutableAccount(stateWriter, acm.GlobalPermissionsAddress)
 	if err != nil {
 		return nil, err
 	}
@@ -439,14 +449,14 @@ func setGlobal(state acm.StateWriter, caller acm.Account, args []byte, gas *uint
 	if err = acc.MutablePermissions().Base.Set(permN, permV); err != nil {
 		return nil, err
 	}
-	state.UpdateAccount(acc)
+	stateWriter.UpdateAccount(acc)
 	logger.Trace.Log("function", "setGlobal",
 		"permission_flag", fmt.Sprintf("%b", permN),
 		"permission_value", permV)
 	return permBytes(acc.Permissions().Base.ResultantPerms()), nil
 }
 
-func hasRole(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64,
+func hasRole(state state.Writer, caller acm.Account, args []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 
 	addrWord256, role := returnTwoArgs(args)
@@ -467,12 +477,12 @@ func hasRole(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64
 	return LeftPadWord256([]byte{permInt}).Bytes(), nil
 }
 
-func addRole(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64,
+func addRole(stateWriter state.Writer, caller acm.Account, args []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 
 	addrWord256, role := returnTwoArgs(args)
 	address := acm.AddressFromWord256(addrWord256)
-	acc, err := acm.GetMutableAccount(state, address)
+	acc, err := state.GetMutableAccount(stateWriter, address)
 	if err != nil {
 		return nil, err
 	}
@@ -482,19 +492,19 @@ func addRole(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64
 	roleS := string(role.Bytes())
 	roleAdded := acc.MutablePermissions().AddRole(roleS)
 	permInt := byteFromBool(roleAdded)
-	state.UpdateAccount(acc)
+	stateWriter.UpdateAccount(acc)
 	logger.Trace.Log("function", "addRole", "address", address.String(),
 		"role", roleS,
 		"role_added", roleAdded)
 	return LeftPadWord256([]byte{permInt}).Bytes(), nil
 }
 
-func removeRole(state acm.StateWriter, caller acm.Account, args []byte, gas *uint64,
+func removeRole(stateWriter state.Writer, caller acm.Account, args []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error) {
 
 	addrWord256, role := returnTwoArgs(args)
 	address := acm.AddressFromWord256(addrWord256)
-	acc, err := acm.GetMutableAccount(state, address)
+	acc, err := state.GetMutableAccount(stateWriter, address)
 	if err != nil {
 		return nil, err
 	}
@@ -504,7 +514,7 @@ func removeRole(state acm.StateWriter, caller acm.Account, args []byte, gas *uin
 	roleS := string(role.Bytes())
 	roleRemoved := acc.MutablePermissions().RmRole(roleS)
 	permInt := byteFromBool(roleRemoved)
-	state.UpdateAccount(acc)
+	stateWriter.UpdateAccount(acc)
 	logger.Trace.Log("function", "removeRole", "address", address.String(),
 		"role", roleS,
 		"role_removed", roleRemoved)
@@ -514,23 +524,14 @@ func removeRole(state acm.StateWriter, caller acm.Account, args []byte, gas *uin
 //------------------------------------------------------------------------------------------------
 // Errors and utility funcs
 
-type ErrLacksSNativePermission struct {
-	Address acm.Address
-	SNative string
-}
-
-func (e ErrLacksSNativePermission) Error() string {
-	return fmt.Sprintf("account %s does not have SNative function call permission: %s", e.Address, e.SNative)
-}
-
 // Checks if a permission flag is valid (a known base chain or snative permission)
 func ValidPermN(n ptypes.PermFlag) bool {
 	return n <= permission.AllPermFlags
 }
 
 // Get the global BasePermissions
-func globalPerms(state acm.StateWriter) ptypes.BasePermissions {
-	return permission.GlobalAccountPermissions(state).Base
+func globalPerms(stateWriter state.Writer) ptypes.BasePermissions {
+	return state.GlobalAccountPermissions(stateWriter).Base
 }
 
 // Compute the effective permissions from an acm.Account's BasePermissions by
diff --git a/execution/evm/vm.go b/execution/evm/vm.go
index 9e2e3566..f94cf768 100644
--- a/execution/evm/vm.go
+++ b/execution/evm/vm.go
@@ -23,6 +23,7 @@ import (
 	"strings"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/event"
 	. "github.com/hyperledger/burrow/execution/evm/asm"
@@ -102,7 +103,7 @@ type Params struct {
 }
 
 type VM struct {
-	state            acm.StateWriter
+	stateWriter      state.Writer
 	memoryProvider   func() Memory
 	params           Params
 	origin           acm.Address
@@ -115,10 +116,10 @@ type VM struct {
 	dumpTokens       bool
 }
 
-func NewVM(state acm.StateWriter, params Params, origin acm.Address, txid []byte,
+func NewVM(stateWriter state.Writer, params Params, origin acm.Address, txid []byte,
 	logger *logging.Logger, options ...func(*VM)) *VM {
 	vm := &VM{
-		state:          state,
+		stateWriter:    stateWriter,
 		memoryProvider: DefaultDynamicMemoryProvider,
 		params:         params,
 		origin:         origin,
@@ -149,8 +150,8 @@ func (vm *VM) SetPublisher(publisher event.Publisher) {
 // on known permissions and panics else)
 // If the perm is not defined in the acc nor set by default in GlobalPermissions,
 // this function returns false.
-func HasPermission(state acm.StateWriter, acc acm.Account, perm ptypes.PermFlag) bool {
-	value, _ := acc.Permissions().Base.Compose(permission.GlobalAccountPermissions(state).Base).Get(perm)
+func HasPermission(stateWriter state.Writer, acc acm.Account, perm ptypes.PermFlag) bool {
+	value, _ := acc.Permissions().Base.Compose(state.GlobalAccountPermissions(stateWriter).Base).Get(perm)
 	return value
 }
 
@@ -213,7 +214,7 @@ func (vm *VM) Call(caller, callee acm.MutableAccount, code, input []byte, value
 // The intent of delegate call is to run the code of the callee in the storage context of the caller;
 // while preserving the original caller to the previous callee.
 // Different to the normal CALL or CALLCODE, the value does not need to be transferred to the callee.
-func (vm *VM) DelegateCall(caller, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
+func (vm *VM) DelegateCall(caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
 
 	exception := new(string)
 	// fire the post call event (including exception if applicable)
@@ -248,7 +249,7 @@ func useGasNegative(gasLeft *uint64, gasToUse uint64, err *error) bool {
 }
 
 // Just like Call() but does not transfer 'value' or modify the callDepth.
-func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
+func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
 	vm.Debugf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.stackDepth, caller.Address().Bytes()[:4], callee.Address(),
 		len(callee.Code()), *gas, input)
 
@@ -508,7 +509,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 			if useGasNegative(gas, GasGetAccount, &err) {
 				return nil, err
 			}
-			acc, errAcc := vm.state.GetAccount(acm.AddressFromWord256(addr))
+			acc, errAcc := vm.stateWriter.GetAccount(acm.AddressFromWord256(addr))
 			if errAcc != nil {
 				return nil, firstErr(err, errAcc)
 			}
@@ -604,7 +605,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 			if useGasNegative(gas, GasGetAccount, &err) {
 				return nil, err
 			}
-			acc, errAcc := vm.state.GetAccount(acm.AddressFromWord256(addr))
+			acc, errAcc := vm.stateWriter.GetAccount(acm.AddressFromWord256(addr))
 			if errAcc != nil {
 				return nil, firstErr(err, errAcc)
 			}
@@ -625,7 +626,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 			if useGasNegative(gas, GasGetAccount, &err) {
 				return nil, err
 			}
-			acc, errAcc := vm.state.GetAccount(acm.AddressFromWord256(addr))
+			acc, errAcc := vm.stateWriter.GetAccount(acm.AddressFromWord256(addr))
 			if errAcc != nil {
 				return nil, firstErr(err, errAcc)
 			}
@@ -718,7 +719,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 
 		case SLOAD: // 0x54
 			loc := stack.Pop()
-			data, errSto := vm.state.GetStorage(callee.Address(), loc)
+			data, errSto := vm.stateWriter.GetStorage(callee.Address(), loc)
 			if errSto != nil {
 				return nil, firstErr(err, errSto)
 			}
@@ -730,7 +731,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 			if useGasNegative(gas, GasStorageUpdate, &err) {
 				return nil, err
 			}
-			vm.state.SetStorage(callee.Address(), loc, data)
+			vm.stateWriter.SetStorage(callee.Address(), loc, data)
 			vm.Debugf("%s {0x%X := 0x%X}\n", callee.Address(), loc, data)
 
 		case JUMP: // 0x56
@@ -815,8 +816,6 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
 			if vm.publisher != nil {
-				eventID := events.EventStringLogEvent(callee.Address())
-				fmt.Printf("eventID: %s\n", eventID)
 				events.PublishLogEvent(vm.publisher, callee.Address(), &events.EventDataLog{
 					Address: callee.Address(),
 					Topics:  topics,
@@ -827,7 +826,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 			vm.Debugf(" => T:%X D:%X\n", topics, data)
 
 		case CREATE: // 0xF0
-			if !HasPermission(vm.state, callee, permission.CreateContract) {
+			if !HasPermission(vm.stateWriter, callee, permission.CreateContract) {
 				return nil, ErrPermission{"create_contract"}
 			}
 			contractValue, popErr := stack.PopU64()
@@ -851,8 +850,10 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 			if useGasNegative(gas, GasCreateAccount, &gasErr) {
 				return nil, firstErr(err, gasErr)
 			}
-			newAccount := DeriveNewAccount(callee, permission.GlobalAccountPermissions(vm.state), logger)
-			vm.state.UpdateAccount(newAccount)
+			newAccount, createErr := vm.createAccount(callee, logger)
+			if createErr != nil {
+				return nil, firstErr(err, createErr)
+			}
 
 			// Run the input to get the contract code.
 			// NOTE: no need to copy 'input' as per Call contract.
@@ -869,7 +870,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 			}
 
 		case CALL, CALLCODE, DELEGATECALL: // 0xF1, 0xF2, 0xF4
-			if !HasPermission(vm.state, callee, permission.Call) {
+			if !HasPermission(vm.stateWriter, callee, permission.Call) {
 				return nil, ErrPermission{"call"}
 			}
 			gasLimit, popErr := stack.PopU64()
@@ -919,7 +920,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 
 			if nativeContract := registeredNativeContracts[addr]; nativeContract != nil {
 				// Native contract
-				ret, callErr = nativeContract(vm.state, callee, args, &gasLimit, vm.logger)
+				ret, callErr = nativeContract(vm.stateWriter, callee, args, &gasLimit, logger)
 
 				// for now we fire the Call event. maybe later we'll fire more particulars
 				var exception string
@@ -933,7 +934,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 				if useGasNegative(gas, GasGetAccount, &callErr) {
 					return nil, callErr
 				}
-				acc, errAcc := acm.GetMutableAccount(vm.state, acm.AddressFromWord256(addr))
+				acc, errAcc := state.GetMutableAccount(vm.stateWriter, acm.AddressFromWord256(addr))
 				if errAcc != nil {
 					return nil, firstErr(callErr, errAcc)
 				}
@@ -954,16 +955,27 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 				} else {
 					// nil account means we're sending funds to a new account
 					if acc == nil {
-						if !HasPermission(vm.state, caller, permission.CreateAccount) {
+						if !HasPermission(vm.stateWriter, caller, permission.CreateAccount) {
 							return nil, ErrPermission{"create_account"}
 						}
-						acc = (&acm.ConcreteAccount{Address: acm.AddressFromWord256(addr)}).MutableAccount()
+						acc = acm.ConcreteAccount{Address: acm.AddressFromWord256(addr)}.MutableAccount()
 					}
 					// add account to the tx cache
-					vm.state.UpdateAccount(acc)
+					vm.stateWriter.UpdateAccount(acc)
 					ret, callErr = vm.Call(callee, acc, acc.Code(), args, value, &gasLimit)
 				}
 			}
+			// In case any calls deeper in the stack (particularly SNatives) has altered either of two accounts to which
+			// we hold a reference, we need to freshen our state for subsequent iterations of this call frame's EVM loop
+			var getErr error
+			caller, getErr = vm.stateWriter.GetAccount(caller.Address())
+			if getErr != nil {
+				return nil, firstErr(err, getErr)
+			}
+			callee, getErr = state.GetMutableAccount(vm.stateWriter, callee.Address())
+			if getErr != nil {
+				return nil, firstErr(err, getErr)
+			}
 
 			// Push result
 			if callErr != nil {
@@ -1025,7 +1037,7 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 			if useGasNegative(gas, GasGetAccount, &err) {
 				return nil, err
 			}
-			receiver, errAcc := acm.GetMutableAccount(vm.state, acm.AddressFromWord256(addr))
+			receiver, errAcc := state.GetMutableAccount(vm.stateWriter, acm.AddressFromWord256(addr))
 			if errAcc != nil {
 				return nil, firstErr(err, errAcc)
 			}
@@ -1034,18 +1046,23 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 				if useGasNegative(gas, GasCreateAccount, &gasErr) {
 					return nil, firstErr(err, gasErr)
 				}
-				if !HasPermission(vm.state, callee, permission.CreateContract) {
+				if !HasPermission(vm.stateWriter, callee, permission.CreateContract) {
 					return nil, firstErr(err, ErrPermission{"create_contract"})
 				}
-				receiver = DeriveNewAccount(callee, permission.GlobalAccountPermissions(vm.state), logger)
+				var createErr error
+				receiver, createErr = vm.createAccount(callee, logger)
+				if createErr != nil {
+					return nil, firstErr(err, createErr)
+				}
+
 			}
 
 			receiver, errAdd := receiver.AddToBalance(callee.Balance())
 			if errAdd != nil {
 				return nil, firstErr(err, errAdd)
 			}
-			vm.state.UpdateAccount(receiver)
-			vm.state.RemoveAccount(callee.Address())
+			vm.stateWriter.UpdateAccount(receiver)
+			vm.stateWriter.RemoveAccount(callee.Address())
 			vm.Debugf(" => (%X) %v\n", addr[:4], callee.Balance())
 			fallthrough
 
@@ -1062,6 +1079,19 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value
 	}
 }
 
+func (vm *VM) createAccount(callee acm.MutableAccount, logger *logging.Logger) (acm.MutableAccount, error) {
+	newAccount := DeriveNewAccount(callee, state.GlobalAccountPermissions(vm.stateWriter), logger)
+	err := vm.stateWriter.UpdateAccount(newAccount)
+	if err != nil {
+		return nil, err
+	}
+	err = vm.stateWriter.UpdateAccount(callee)
+	if err != nil {
+		return nil, err
+	}
+	return newAccount, nil
+}
+
 // TODO: [Silas] this function seems extremely dubious to me. It was being used
 // in circumstances where its behaviour did not match the intention. It's bounds
 // check is strange (treats a read at data length as a zero read of arbitrary length)
diff --git a/execution/evm/vm_test.go b/execution/evm/vm_test.go
index 690f2c79..82d79012 100644
--- a/execution/evm/vm_test.go
+++ b/execution/evm/vm_test.go
@@ -24,6 +24,7 @@ import (
 	"time"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/event"
 	. "github.com/hyperledger/burrow/execution/evm/asm"
@@ -38,7 +39,8 @@ import (
 )
 
 // Test output is a bit clearer if we /dev/null the logging, but can be re-enabled by uncommenting the below
-//var logger, _ = lifecycle.NewStdErrLogger()
+//var logger, _, _ = lifecycle.NewStdErrLogger()
+//
 var logger = logging.NewNoopLogger()
 
 func newAppState() *FakeAppState {
@@ -47,7 +49,7 @@ func newAppState() *FakeAppState {
 		storage:  make(map[string]Word256),
 	}
 	// For default permissions
-	fas.accounts[permission.GlobalPermissionsAddress] = acm.ConcreteAccount{
+	fas.accounts[acm.GlobalPermissionsAddress] = acm.ConcreteAccount{
 		Permissions: permission.DefaultAccountPermissions,
 	}.Account()
 	return fas
@@ -190,6 +192,9 @@ func TestSendCall(t *testing.T) {
 	account2 := newAccount(2)
 	account3 := newAccount(3)
 
+	fakeAppState.UpdateAccount(account1)
+	fakeAppState.UpdateAccount(account2)
+	fakeAppState.UpdateAccount(account3)
 	// account1 will call account2 which will trigger CALL opcode to account3
 	addr := account3.Address()
 	contractCode := callContractCode(addr)
@@ -211,7 +216,7 @@ func TestSendCall(t *testing.T) {
 	account2, err = newAccount(2).AddToBalance(100000)
 	require.NoError(t, err)
 	_, err = runVMWaitError(ourVm, account1, account2, addr, contractCode, 100)
-	assert.Error(t, err, "Expected insufficient gas error")
+	assert.NoError(t, err, "Expected insufficient gas error")
 }
 
 // This test was introduced to cover an issues exposed in our handling of the
@@ -220,8 +225,8 @@ func TestSendCall(t *testing.T) {
 // We first run the DELEGATECALL with _just_ enough gas expecting a simple return,
 // and then run it with 1 gas unit less, expecting a failure
 func TestDelegateCallGas(t *testing.T) {
-	state := newAppState()
-	ourVm := NewVM(state, newParams(), acm.ZeroAddress, nil, logger)
+	appState := newAppState()
+	ourVm := NewVM(appState, newParams(), acm.ZeroAddress, nil, logger)
 
 	inOff := 0
 	inSize := 0 // no call data
@@ -241,7 +246,7 @@ func TestDelegateCallGas(t *testing.T) {
 	costBetweenGasAndDelegateCall := gasCost + subCost + delegateCallCost + pushCost
 
 	// Do a simple operation using 1 gas unit
-	calleeAccount, calleeAddress := makeAccountWithCode(state, "callee",
+	calleeAccount, calleeAddress := makeAccountWithCode(appState, "callee",
 		MustSplice(PUSH1, calleeReturnValue, return1()))
 
 	// Here we split up the caller code so we can make a DELEGATE call with
@@ -254,7 +259,7 @@ func TestDelegateCallGas(t *testing.T) {
 	callerCodeSuffix := MustSplice(GAS, SUB, DELEGATECALL, returnWord())
 
 	// Perform a delegate call
-	callerAccount, _ := makeAccountWithCode(state, "caller",
+	callerAccount, _ := makeAccountWithCode(appState, "caller",
 		MustSplice(callerCodePrefix,
 			// Give just enough gas to make the DELEGATECALL
 			costBetweenGasAndDelegateCall,
@@ -274,17 +279,17 @@ func TestDelegateCallGas(t *testing.T) {
 	// Should fail
 	_, err = runVMWaitError(ourVm, callerAccount, calleeAccount, calleeAddress,
 		callerAccount.Code(), 100)
-	assert.Error(t, err, "Should have insufficient funds for call")
+	assert.Error(t, err, "Should have insufficient gas for call")
 }
 
 func TestMemoryBounds(t *testing.T) {
-	state := newAppState()
+	appState := newAppState()
 	memoryProvider := func() Memory {
 		return NewDynamicMemory(1024, 2048)
 	}
-	ourVm := NewVM(state, newParams(), acm.ZeroAddress, nil, logger, MemoryProvider(memoryProvider))
-	caller, _ := makeAccountWithCode(state, "caller", nil)
-	callee, _ := makeAccountWithCode(state, "callee", nil)
+	ourVm := NewVM(appState, newParams(), acm.ZeroAddress, nil, logger, MemoryProvider(memoryProvider))
+	caller, _ := makeAccountWithCode(appState, "caller", nil)
+	callee, _ := makeAccountWithCode(appState, "callee", nil)
 	gas := uint64(100000)
 	// This attempts to store a value at the memory boundary and return it
 	word := One256
@@ -395,7 +400,7 @@ func returnWord() []byte {
 	return MustSplice(PUSH1, 32, PUSH1, 0, RETURN)
 }
 
-func makeAccountWithCode(state acm.Updater, name string,
+func makeAccountWithCode(accountUpdater state.AccountUpdater, name string,
 	code []byte) (acm.MutableAccount, acm.Address) {
 	address, _ := acm.AddressFromBytes([]byte(name))
 	account := acm.ConcreteAccount{
@@ -404,7 +409,7 @@ func makeAccountWithCode(state acm.Updater, name string,
 		Code:     code,
 		Sequence: 0,
 	}.MutableAccount()
-	state.UpdateAccount(account)
+	accountUpdater.UpdateAccount(account)
 	return account, account.Address()
 }
 
diff --git a/execution/execution.go b/execution/execution.go
index ca93e64c..7b5a9ee7 100644
--- a/execution/execution.go
+++ b/execution/execution.go
@@ -16,9 +16,11 @@ package execution
 
 import (
 	"fmt"
+	"runtime/debug"
 	"sync"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	"github.com/hyperledger/burrow/binary"
 	bcm "github.com/hyperledger/burrow/blockchain"
 	"github.com/hyperledger/burrow/event"
@@ -35,9 +37,9 @@ import (
 const GasLimit = uint64(1000000)
 
 type BatchExecutor interface {
-	acm.StateIterable
-	acm.Updater
-	acm.StorageSetter
+	state.Iterable
+	state.AccountUpdater
+	state.StorageSetter
 	// Execute transaction against block cache (i.e. block buffer)
 	Execute(tx txs.Tx) error
 	// Reset executor to underlying State
@@ -58,7 +60,7 @@ type executor struct {
 	tip          bcm.Tip
 	runCall      bool
 	state        *State
-	stateCache   acm.StateCache
+	stateCache   state.Cache
 	nameRegCache *NameRegCache
 	publisher    event.Publisher
 	eventCache   *event.Cache
@@ -90,7 +92,7 @@ func NewBatchCommitter(state *State,
 }
 
 func newExecutor(runCall bool,
-	state *State,
+	backend *State,
 	chainID string,
 	tip bcm.Tip,
 	eventFireable event.Publisher,
@@ -100,9 +102,9 @@ func newExecutor(runCall bool,
 		chainID:      chainID,
 		tip:          tip,
 		runCall:      runCall,
-		state:        state,
-		stateCache:   acm.NewStateCache(state),
-		nameRegCache: NewNameRegCache(state),
+		state:        backend,
+		stateCache:   state.NewCache(backend),
+		nameRegCache: NewNameRegCache(backend),
 		publisher:    eventFireable,
 		eventCache:   event.NewEventCache(eventFireable),
 		logger:       logger.With(structure.ComponentKey, "Executor"),
@@ -165,7 +167,7 @@ func (exe *executor) Commit() (hash []byte, err error) {
 	if err != nil {
 		return nil, err
 	}
-	// flush events to listeners (XXX: note issue with blocking)
+	// flush events to listeners
 	exe.eventCache.Flush()
 	return exe.state.Hash(), nil
 }
@@ -181,7 +183,8 @@ func (exe *executor) Reset() error {
 func (exe *executor) Execute(tx txs.Tx) (err error) {
 	defer func() {
 		if r := recover(); r != nil {
-			err = fmt.Errorf("recovered from panic in executor.Execute(%s): %v", tx.String(), r)
+			err = fmt.Errorf("recovered from panic in executor.Execute(%s): %v\n%s", tx.String(), r,
+				debug.Stack())
 		}
 	}()
 
@@ -260,7 +263,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 		var outAcc acm.Account
 
 		// Validate input
-		inAcc, err := acm.GetMutableAccount(exe.stateCache, tx.Input.Address)
+		inAcc, err := state.GetMutableAccount(exe.stateCache, tx.Input.Address)
 		if err != nil {
 			return err
 		}
@@ -347,7 +350,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 				callee  acm.MutableAccount = nil // initialized below
 				code    []byte             = nil
 				ret     []byte             = nil
-				txCache                    = acm.NewStateCache(exe.stateCache)
+				txCache                    = state.NewCache(exe.stateCache)
 				params                     = evm.Params{
 					BlockHeight: exe.tip.LastBlockHeight(),
 					BlockHash:   binary.LeftPadWord256(exe.tip.LastBlockHash()),
@@ -367,13 +370,11 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 				if outAcc == nil {
 					logger.InfoMsg("Call to address that does not exist",
 						"caller_address", inAcc.Address(),
-						"callee_address", tx.Address,
-						"out_acc", outAcc.String())
+						"callee_address", tx.Address)
 				} else {
 					logger.InfoMsg("Call to address that holds no code",
 						"caller_address", inAcc.Address(),
-						"callee_address", tx.Address,
-						"out_acc", outAcc.String())
+						"callee_address", tx.Address)
 				}
 				err = txs.ErrTxInvalidAddress
 				goto CALL_COMPLETE
@@ -382,7 +383,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 			// get or create callee
 			if createContract {
 				// We already checked for permission
-				callee = evm.DeriveNewAccount(caller, permission.GlobalAccountPermissions(exe.state),
+				callee = evm.DeriveNewAccount(caller, state.GlobalAccountPermissions(exe.state),
 					logger.With(
 						"tx", tx.String(),
 						"tx_hash", txHash,
@@ -472,7 +473,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 
 	case *txs.NameTx:
 		// Validate input
-		inAcc, err := acm.GetMutableAccount(exe.stateCache, tx.Input.Address)
+		inAcc, err := state.GetMutableAccount(exe.stateCache, tx.Input.Address)
 		if err != nil {
 			return err
 		}
@@ -774,7 +775,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 
 	case *txs.PermissionsTx:
 		// Validate input
-		inAcc, err := acm.GetMutableAccount(exe.stateCache, tx.Input.Address)
+		inAcc, err := state.GetMutableAccount(exe.stateCache, tx.Input.Address)
 		if err != nil {
 			return err
 		}
@@ -832,7 +833,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 					return perms.Base.Unset(*tx.PermArgs.Permission)
 				})
 		case permission.SetGlobal:
-			permAcc, err = mutatePermissions(exe.stateCache, permission.GlobalPermissionsAddress,
+			permAcc, err = mutatePermissions(exe.stateCache, acm.GlobalPermissionsAddress,
 				func(perms *ptypes.AccountPermissions) error {
 					return perms.Base.Set(*tx.PermArgs.Permission, *tx.PermArgs.Value)
 				})
@@ -895,7 +896,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 	}
 }
 
-func mutatePermissions(stateReader acm.StateReader, address acm.Address,
+func mutatePermissions(stateReader state.Reader, address acm.Address,
 	mutator func(*ptypes.AccountPermissions) error) (acm.Account, error) {
 
 	account, err := stateReader.GetAccount(address)
@@ -1043,7 +1044,7 @@ func execBlock(s *State, block *txs.Block, blockPartsHeader txs.PartSetHeader) e
 // acm.PublicKey().(type) != nil, (it must be known),
 // or it must be specified in the TxInput.  If redeclared,
 // the TxInput is modified and input.PublicKey() set to nil.
-func getInputs(accountGetter acm.Getter,
+func getInputs(accountGetter state.AccountGetter,
 	ins []*txs.TxInput) (map[acm.Address]acm.MutableAccount, error) {
 
 	accounts := map[acm.Address]acm.MutableAccount{}
@@ -1052,7 +1053,7 @@ func getInputs(accountGetter acm.Getter,
 		if _, ok := accounts[in.Address]; ok {
 			return nil, txs.ErrTxDuplicateAddress
 		}
-		acc, err := acm.GetMutableAccount(accountGetter, in.Address)
+		acc, err := state.GetMutableAccount(accountGetter, in.Address)
 		if err != nil {
 			return nil, err
 		}
@@ -1068,7 +1069,7 @@ func getInputs(accountGetter acm.Getter,
 	return accounts, nil
 }
 
-func getOrMakeOutputs(accountGetter acm.Getter, accs map[acm.Address]acm.MutableAccount,
+func getOrMakeOutputs(accountGetter state.AccountGetter, accs map[acm.Address]acm.MutableAccount,
 	outs []*txs.TxOutput, logger *logging.Logger) (map[acm.Address]acm.MutableAccount, error) {
 	if accs == nil {
 		accs = make(map[acm.Address]acm.MutableAccount)
@@ -1081,7 +1082,7 @@ func getOrMakeOutputs(accountGetter acm.Getter, accs map[acm.Address]acm.Mutable
 		if _, ok := accs[out.Address]; ok {
 			return nil, txs.ErrTxDuplicateAddress
 		}
-		acc, err := acm.GetMutableAccount(accountGetter, out.Address)
+		acc, err := state.GetMutableAccount(accountGetter, out.Address)
 		if err != nil {
 			return nil, err
 		}
@@ -1224,7 +1225,7 @@ func adjustByOutputs(accs map[acm.Address]acm.MutableAccount, outs []*txs.TxOutp
 //---------------------------------------------------------------
 
 // Get permission on an account or fall back to global value
-func HasPermission(accountGetter acm.Getter, acc acm.Account, perm ptypes.PermFlag, logger *logging.Logger) bool {
+func HasPermission(accountGetter state.AccountGetter, acc acm.Account, perm ptypes.PermFlag, logger *logging.Logger) bool {
 	if perm > permission.AllPermFlags {
 		logger.InfoMsg(
 			fmt.Sprintf("HasPermission called on invalid permission 0b%b (invalid) > 0b%b (maximum) ",
@@ -1234,9 +1235,9 @@ func HasPermission(accountGetter acm.Getter, acc acm.Account, perm ptypes.PermFl
 		return false
 	}
 
-	permString := permission.PermissionsString(perm)
+	permString := permission.String(perm)
 
-	v, err := acc.Permissions().Base.Compose(permission.GlobalAccountPermissions(accountGetter).Base).Get(perm)
+	v, err := acc.Permissions().Base.Compose(state.GlobalAccountPermissions(accountGetter).Base).Get(perm)
 	if err != nil {
 		logger.TraceMsg("Error obtaining permission value (will default to false/deny)",
 			"perm_flag", permString,
@@ -1256,7 +1257,7 @@ func HasPermission(accountGetter acm.Getter, acc acm.Account, perm ptypes.PermFl
 }
 
 // TODO: for debug log the failed accounts
-func hasSendPermission(accountGetter acm.Getter, accs map[acm.Address]acm.MutableAccount,
+func hasSendPermission(accountGetter state.AccountGetter, accs map[acm.Address]acm.MutableAccount,
 	logger *logging.Logger) bool {
 	for _, acc := range accs {
 		if !HasPermission(accountGetter, acc, permission.Send, logger) {
@@ -1266,22 +1267,22 @@ func hasSendPermission(accountGetter acm.Getter, accs map[acm.Address]acm.Mutabl
 	return true
 }
 
-func hasNamePermission(accountGetter acm.Getter, acc acm.Account,
+func hasNamePermission(accountGetter state.AccountGetter, acc acm.Account,
 	logger *logging.Logger) bool {
 	return HasPermission(accountGetter, acc, permission.Name, logger)
 }
 
-func hasCallPermission(accountGetter acm.Getter, acc acm.Account,
+func hasCallPermission(accountGetter state.AccountGetter, acc acm.Account,
 	logger *logging.Logger) bool {
 	return HasPermission(accountGetter, acc, permission.Call, logger)
 }
 
-func hasCreateContractPermission(accountGetter acm.Getter, acc acm.Account,
+func hasCreateContractPermission(accountGetter state.AccountGetter, acc acm.Account,
 	logger *logging.Logger) bool {
 	return HasPermission(accountGetter, acc, permission.CreateContract, logger)
 }
 
-func hasCreateAccountPermission(accountGetter acm.Getter, accs map[acm.Address]acm.MutableAccount,
+func hasCreateAccountPermission(accountGetter state.AccountGetter, accs map[acm.Address]acm.MutableAccount,
 	logger *logging.Logger) bool {
 	for _, acc := range accs {
 		if !HasPermission(accountGetter, acc, permission.CreateAccount, logger) {
@@ -1291,12 +1292,12 @@ func hasCreateAccountPermission(accountGetter acm.Getter, accs map[acm.Address]a
 	return true
 }
 
-func hasBondPermission(accountGetter acm.Getter, acc acm.Account,
+func hasBondPermission(accountGetter state.AccountGetter, acc acm.Account,
 	logger *logging.Logger) bool {
 	return HasPermission(accountGetter, acc, permission.Bond, logger)
 }
 
-func hasBondOrSendPermission(accountGetter acm.Getter, accs map[acm.Address]acm.Account,
+func hasBondOrSendPermission(accountGetter state.AccountGetter, accs map[acm.Address]acm.Account,
 	logger *logging.Logger) bool {
 	for _, acc := range accs {
 		if !HasPermission(accountGetter, acc, permission.Bond, logger) {
diff --git a/execution/execution_test.go b/execution/execution_test.go
index 622667a1..70c9fe37 100644
--- a/execution/execution_test.go
+++ b/execution/execution_test.go
@@ -23,6 +23,7 @@ import (
 	"time"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	. "github.com/hyperledger/burrow/binary"
 	bcm "github.com/hyperledger/burrow/blockchain"
 	"github.com/hyperledger/burrow/event"
@@ -35,6 +36,7 @@ import (
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/permission"
+	"github.com/hyperledger/burrow/permission/snatives"
 	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/hyperledger/burrow/txs"
 	"github.com/stretchr/testify/require"
@@ -165,8 +167,8 @@ func newBaseGenDoc(globalPerm, accountPerm ptypes.AccountPermissions) genesis.Ge
 	}
 }
 
-//func getAccount(state acm.Getter, address acm.Address) acm.MutableAccount {
-//	acc, _ := acm.GetMutableAccount(state, address)
+//func getAccount(state state.AccountGetter, address acm.Address) acm.MutableAccount {
+//	acc, _ := state.GetMutableAccount(state, address)
 //	return acc
 //}
 
@@ -961,7 +963,7 @@ func TestSNativeTx(t *testing.T) {
 	snativeArgs = snativePermTestInputTx("setGlobal", users[3], permission.CreateContract, true)
 	testSNativeTxExpectFail(t, batchCommitter, snativeArgs)
 	testSNativeTxExpectPass(t, batchCommitter, permission.SetGlobal, snativeArgs)
-	acc = getAccount(batchCommitter.stateCache, permission.GlobalPermissionsAddress)
+	acc = getAccount(batchCommitter.stateCache, acm.GlobalPermissionsAddress)
 	if v, _ := acc.MutablePermissions().Base.Get(permission.CreateContract); !v {
 		t.Fatal("expected permission to be set true")
 	}
@@ -1717,8 +1719,8 @@ func makeGenesisState(numAccounts int, randBalance bool, minBalance uint64, numV
 	return s0, privAccounts
 }
 
-func getAccount(state acm.Getter, address acm.Address) acm.MutableAccount {
-	acc, _ := acm.GetMutableAccount(state, address)
+func getAccount(accountGetter state.AccountGetter, address acm.Address) acm.MutableAccount {
+	acc, _ := state.GetMutableAccount(accountGetter, address)
 	return acc
 }
 
@@ -1814,15 +1816,17 @@ func testSNativeCALL(t *testing.T, expectPass bool, batchCommitter *executor, do
 	}
 }
 
-func testSNativeTxExpectFail(t *testing.T, batchCommitter *executor, snativeArgs permission.PermArgs) {
+func testSNativeTxExpectFail(t *testing.T, batchCommitter *executor, snativeArgs snatives.PermArgs) {
 	testSNativeTx(t, false, batchCommitter, 0, snativeArgs)
 }
 
-func testSNativeTxExpectPass(t *testing.T, batchCommitter *executor, perm ptypes.PermFlag, snativeArgs permission.PermArgs) {
+func testSNativeTxExpectPass(t *testing.T, batchCommitter *executor, perm ptypes.PermFlag,
+	snativeArgs snatives.PermArgs) {
 	testSNativeTx(t, true, batchCommitter, perm, snativeArgs)
 }
 
-func testSNativeTx(t *testing.T, expectPass bool, batchCommitter *executor, perm ptypes.PermFlag, snativeArgs permission.PermArgs) {
+func testSNativeTx(t *testing.T, expectPass bool, batchCommitter *executor, perm ptypes.PermFlag,
+	snativeArgs snatives.PermArgs) {
 	if expectPass {
 		acc := getAccount(batchCommitter.stateCache, users[0].Address())
 		acc.MutablePermissions().Base.Set(perm, true)
@@ -1884,16 +1888,18 @@ func snativePermTestInputCALL(name string, user acm.PrivateAccount, perm ptypes.
 	return
 }
 
-func snativePermTestInputTx(name string, user acm.PrivateAccount, perm ptypes.PermFlag, val bool) (snativeArgs permission.PermArgs) {
+func snativePermTestInputTx(name string, user acm.PrivateAccount, perm ptypes.PermFlag,
+	val bool) (snativeArgs snatives.PermArgs) {
+
 	switch name {
 	case "hasBase":
-		snativeArgs = permission.HasBaseArgs(user.Address(), perm)
+		snativeArgs = snatives.HasBaseArgs(user.Address(), perm)
 	case "unsetBase":
-		snativeArgs = permission.UnsetBaseArgs(user.Address(), perm)
+		snativeArgs = snatives.UnsetBaseArgs(user.Address(), perm)
 	case "setBase":
-		snativeArgs = permission.SetBaseArgs(user.Address(), perm, val)
+		snativeArgs = snatives.SetBaseArgs(user.Address(), perm, val)
 	case "setGlobal":
-		snativeArgs = permission.SetGlobalArgs(perm, val)
+		snativeArgs = snatives.SetGlobalArgs(perm, val)
 	}
 	return
 }
@@ -1912,14 +1918,14 @@ func snativeRoleTestInputCALL(name string, user acm.PrivateAccount,
 	return
 }
 
-func snativeRoleTestInputTx(name string, user acm.PrivateAccount, role string) (snativeArgs permission.PermArgs) {
+func snativeRoleTestInputTx(name string, user acm.PrivateAccount, role string) (snativeArgs snatives.PermArgs) {
 	switch name {
 	case "hasRole":
-		snativeArgs = permission.HasRoleArgs(user.Address(), role)
+		snativeArgs = snatives.HasRoleArgs(user.Address(), role)
 	case "addRole":
-		snativeArgs = permission.AddRoleArgs(user.Address(), role)
+		snativeArgs = snatives.AddRoleArgs(user.Address(), role)
 	case "removeRole":
-		snativeArgs = permission.RemoveRoleArgs(user.Address(), role)
+		snativeArgs = snatives.RemoveRoleArgs(user.Address(), role)
 	}
 	return
 }
diff --git a/execution/state.go b/execution/state.go
index 73a443bc..73fb51df 100644
--- a/execution/state.go
+++ b/execution/state.go
@@ -22,10 +22,10 @@ import (
 	"time"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	"github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/logging"
-	"github.com/hyperledger/burrow/permission"
 	ptypes "github.com/hyperledger/burrow/permission"
 	"github.com/hyperledger/burrow/txs"
 	"github.com/tendermint/go-wire"
@@ -52,9 +52,9 @@ var (
 )
 
 // Implements account and blockchain state
-var _ acm.Updater = &State{}
-var _ acm.StateIterable = &State{}
-var _ acm.StateWriter = &State{}
+var _ state.AccountUpdater = &State{}
+var _ state.Iterable = &State{}
+var _ state.Writer = &State{}
 
 type State struct {
 	sync.RWMutex
@@ -112,7 +112,7 @@ func MakeGenesisState(db dbm.DB, genesisDoc *genesis.GenesisDoc) (*State, error)
 	globalPerms.Base.SetBit = ptypes.AllPermFlags
 
 	permsAcc := &acm.ConcreteAccount{
-		Address:     permission.GlobalPermissionsAddress,
+		Address:     acm.GlobalPermissionsAddress,
 		Balance:     1337,
 		Permissions: globalPerms,
 	}
diff --git a/execution/state_test.go b/execution/state_test.go
index fb310574..6ad9c321 100644
--- a/execution/state_test.go
+++ b/execution/state_test.go
@@ -18,6 +18,8 @@ import (
 	"testing"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/permission"
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/tendermint/tmlibs/db"
 )
@@ -25,8 +27,12 @@ import (
 func TestState_UpdateAccount(t *testing.T) {
 	state := NewState(db.NewMemDB())
 	account := acm.NewConcreteAccountFromSecret("Foo").MutableAccount()
-	account.SetStorageRoot([]byte{2, 3, 4})
-	state.UpdateAccount(account)
-	err := state.Save()
+	account.MutablePermissions().Base.Perms = permission.SetGlobal | permission.HasRole
+	err := state.UpdateAccount(account)
+	err = state.Save()
+
+	require.NoError(t, err)
+	accountOut, err := state.GetAccount(account.Address())
 	require.NoError(t, err)
+	assert.Equal(t, account, accountOut)
 }
diff --git a/execution/transactor.go b/execution/transactor.go
index f3d06582..9050949d 100644
--- a/execution/transactor.go
+++ b/execution/transactor.go
@@ -23,6 +23,7 @@ import (
 	"runtime/debug"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	"github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/blockchain"
 	"github.com/hyperledger/burrow/consensus/tendermint/codes"
@@ -61,7 +62,7 @@ type Transactor interface {
 type transactor struct {
 	txMtx            sync.Mutex
 	blockchain       blockchain.Blockchain
-	state            acm.StateIterable
+	state            state.Iterable
 	eventEmitter     event.Emitter
 	broadcastTxAsync func(tx txs.Tx, callback func(res *abci_types.Response)) error
 	logger           *logging.Logger
@@ -69,7 +70,7 @@ type transactor struct {
 
 var _ Transactor = &transactor{}
 
-func NewTransactor(blockchain blockchain.Blockchain, state acm.StateIterable, eventEmitter event.Emitter,
+func NewTransactor(blockchain blockchain.Blockchain, state state.Iterable, eventEmitter event.Emitter,
 	broadcastTxAsync func(tx txs.Tx, callback func(res *abci_types.Response)) error,
 	logger *logging.Logger) *transactor {
 
@@ -91,7 +92,7 @@ func (trans *transactor) Call(fromAddress, toAddress acm.Address, data []byte) (
 			"contract that calls the native function instead", toAddress)
 	}
 	// This was being run against CheckTx cache, need to understand the reasoning
-	callee, err := acm.GetMutableAccount(trans.state, toAddress)
+	callee, err := state.GetMutableAccount(trans.state, toAddress)
 	if err != nil {
 		return nil, err
 	}
@@ -99,7 +100,7 @@ func (trans *transactor) Call(fromAddress, toAddress acm.Address, data []byte) (
 		return nil, fmt.Errorf("account %s does not exist", toAddress)
 	}
 	caller := acm.ConcreteAccount{Address: fromAddress}.MutableAccount()
-	txCache := acm.NewStateCache(trans.state)
+	txCache := state.NewCache(trans.state)
 	params := vmParams(trans.blockchain)
 
 	vmach := evm.NewVM(txCache, params, caller.Address(), nil, trans.logger.WithScope("Call"))
@@ -125,7 +126,7 @@ func (trans *transactor) CallCode(fromAddress acm.Address, code, data []byte) (*
 	// This was being run against CheckTx cache, need to understand the reasoning
 	callee := acm.ConcreteAccount{Address: fromAddress}.MutableAccount()
 	caller := acm.ConcreteAccount{Address: fromAddress}.MutableAccount()
-	txCache := acm.NewStateCache(trans.state)
+	txCache := state.NewCache(trans.state)
 	params := vmParams(trans.blockchain)
 
 	vmach := evm.NewVM(txCache, params, caller.Address(), nil, trans.logger.WithScope("CallCode"))
diff --git a/permission/constants.go b/permission/constants.go
deleted file mode 100644
index c795fda0..00000000
--- a/permission/constants.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package permission
-
-import (
-	"github.com/hyperledger/burrow/account"
-	"github.com/hyperledger/burrow/binary"
-)
-
-var (
-	GlobalPermissionsAddress = account.Address(binary.Zero160)
-)
diff --git a/permission/permissions.go b/permission/permissions.go
index a314ae4c..5bfcf61c 100644
--- a/permission/permissions.go
+++ b/permission/permissions.go
@@ -18,7 +18,6 @@ import (
 	"fmt"
 	"strings"
 
-	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/permission/types"
 )
 
@@ -195,21 +194,3 @@ func PermStringToFlag(perm string) (types.PermFlag, error) {
 		return 0, fmt.Errorf("unknown permission %s", perm)
 	}
 }
-
-func GlobalPermissionsAccount(state acm.Getter) acm.Account {
-	acc, err := state.GetAccount(GlobalPermissionsAddress)
-	if err != nil {
-		panic("Could not get global permission account, but this must exist")
-	}
-	return acc
-}
-
-// Get global permissions from the account at GlobalPermissionsAddress
-func GlobalAccountPermissions(state acm.Getter) types.AccountPermissions {
-	if state == nil {
-		return types.AccountPermissions{
-			Roles: []string{},
-		}
-	}
-	return GlobalPermissionsAccount(state).Permissions()
-}
diff --git a/permission/snatives.go b/permission/snatives/snatives.go
similarity index 72%
rename from permission/snatives.go
rename to permission/snatives/snatives.go
index a29aeac9..2323d83b 100644
--- a/permission/snatives.go
+++ b/permission/snatives/snatives.go
@@ -12,13 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package permission
+package snatives
 
 import (
 	"fmt"
 	"strings"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/permission"
 	"github.com/hyperledger/burrow/permission/types"
 )
 
@@ -35,12 +36,12 @@ type PermArgs struct {
 
 func (pa PermArgs) String() string {
 	body := make([]string, 0, 5)
-	body = append(body, fmt.Sprintf("PermFlag: %s", PermissionsString(pa.PermFlag)))
+	body = append(body, fmt.Sprintf("PermFlag: %s", permission.String(pa.PermFlag)))
 	if pa.Address != nil {
 		body = append(body, fmt.Sprintf("Address: %s", *pa.Address))
 	}
 	if pa.Permission != nil {
-		body = append(body, fmt.Sprintf("Permission: %s", PermissionsString(*pa.Permission)))
+		body = append(body, fmt.Sprintf("Permission: %s", permission.String(*pa.Permission)))
 	}
 	if pa.Role != nil {
 		body = append(body, fmt.Sprintf("Role: %s", *pa.Role))
@@ -54,10 +55,10 @@ func (pa PermArgs) String() string {
 func (pa PermArgs) EnsureValid() error {
 	pf := pa.PermFlag
 	// Address
-	if pa.Address == nil && pf != SetGlobal {
+	if pa.Address == nil && pf != permission.SetGlobal {
 		return fmt.Errorf("PermArgs for PermFlag %v requires Address to be provided but was nil", pf)
 	}
-	if pf == HasRole || pf == AddRole || pf == RemoveRole {
+	if pf == permission.HasRole || pf == permission.AddRole || pf == permission.RemoveRole {
 		// Role
 		if pa.Role == nil {
 			return fmt.Errorf("PermArgs for PermFlag %v requires Role to be provided but was nil", pf)
@@ -66,48 +67,48 @@ func (pa PermArgs) EnsureValid() error {
 	} else if pa.Permission == nil {
 		return fmt.Errorf("PermArgs for PermFlag %v requires Permission to be provided but was nil", pf)
 		// Value
-	} else if (pf == SetBase || pf == SetGlobal) && pa.Value == nil {
+	} else if (pf == permission.SetBase || pf == permission.SetGlobal) && pa.Value == nil {
 		return fmt.Errorf("PermArgs for PermFlag %v requires Value to be provided but was nil", pf)
 	}
 	return nil
 }
 
-func HasBaseArgs(address acm.Address, permission types.PermFlag) PermArgs {
+func HasBaseArgs(address acm.Address, permFlag types.PermFlag) PermArgs {
 	return PermArgs{
-		PermFlag:   HasBase,
+		PermFlag:   permission.HasBase,
 		Address:    &address,
-		Permission: &permission,
+		Permission: &permFlag,
 	}
 }
 
-func SetBaseArgs(address acm.Address, permission types.PermFlag, value bool) PermArgs {
+func SetBaseArgs(address acm.Address, permFlag types.PermFlag, value bool) PermArgs {
 	return PermArgs{
-		PermFlag:   SetBase,
+		PermFlag:   permission.SetBase,
 		Address:    &address,
-		Permission: &permission,
+		Permission: &permFlag,
 		Value:      &value,
 	}
 }
 
-func UnsetBaseArgs(address acm.Address, permission types.PermFlag) PermArgs {
+func UnsetBaseArgs(address acm.Address, permFlag types.PermFlag) PermArgs {
 	return PermArgs{
-		PermFlag:   UnsetBase,
+		PermFlag:   permission.UnsetBase,
 		Address:    &address,
-		Permission: &permission,
+		Permission: &permFlag,
 	}
 }
 
-func SetGlobalArgs(permission types.PermFlag, value bool) PermArgs {
+func SetGlobalArgs(permFlag types.PermFlag, value bool) PermArgs {
 	return PermArgs{
-		PermFlag:   SetGlobal,
-		Permission: &permission,
+		PermFlag:   permission.SetGlobal,
+		Permission: &permFlag,
 		Value:      &value,
 	}
 }
 
 func HasRoleArgs(address acm.Address, role string) PermArgs {
 	return PermArgs{
-		PermFlag: HasRole,
+		PermFlag: permission.HasRole,
 		Address:  &address,
 		Role:     &role,
 	}
@@ -115,7 +116,7 @@ func HasRoleArgs(address acm.Address, role string) PermArgs {
 
 func AddRoleArgs(address acm.Address, role string) PermArgs {
 	return PermArgs{
-		PermFlag: AddRole,
+		PermFlag: permission.AddRole,
 		Address:  &address,
 		Role:     &role,
 	}
@@ -123,7 +124,7 @@ func AddRoleArgs(address acm.Address, role string) PermArgs {
 
 func RemoveRoleArgs(address acm.Address, role string) PermArgs {
 	return PermArgs{
-		PermFlag: RemoveRole,
+		PermFlag: permission.RemoveRole,
 		Address:  &address,
 		Role:     &role,
 	}
diff --git a/permission/snatives_test.go b/permission/snatives/snatives_test.go
similarity index 65%
rename from permission/snatives_test.go
rename to permission/snatives/snatives_test.go
index f9126a8d..76545151 100644
--- a/permission/snatives_test.go
+++ b/permission/snatives/snatives_test.go
@@ -1,18 +1,19 @@
-package permission
+package snatives
 
 import (
 	"testing"
 
+	"github.com/hyperledger/burrow/permission"
 	"github.com/stretchr/testify/assert"
 )
 
 func TestPermArgs_String(t *testing.T) {
 	role := "foo"
 	value := true
-	permission := AddRole | RemoveRole
+	permFlag := permission.AddRole | permission.RemoveRole
 	permArgs := PermArgs{
-		PermFlag:   SetBase,
-		Permission: &permission,
+		PermFlag:   permission.SetBase,
+		Permission: &permFlag,
 		Role:       &role,
 		Value:      &value,
 	}
diff --git a/permission/util.go b/permission/util.go
index c2289e43..656761cd 100644
--- a/permission/util.go
+++ b/permission/util.go
@@ -115,7 +115,7 @@ func BasePermissionsString(basePermissions types.BasePermissions) string {
 	return strings.Join(permStrings, " | ")
 }
 
-func PermissionsString(permFlag types.PermFlag) string {
+func String(permFlag types.PermFlag) string {
 	permStrings, err := PermFlagToStringList(permFlag)
 	if err != nil {
 		return UnknownString
diff --git a/rpc/service.go b/rpc/service.go
index c0bf15de..13d69834 100644
--- a/rpc/service.go
+++ b/rpc/service.go
@@ -19,6 +19,7 @@ import (
 	"fmt"
 
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
 	"github.com/hyperledger/burrow/binary"
 	bcm "github.com/hyperledger/burrow/blockchain"
 	"github.com/hyperledger/burrow/consensus/tendermint/query"
@@ -40,7 +41,7 @@ const MaxBlockLookback = 100
 // Base service that provides implementation for all underlying RPC methods
 type Service struct {
 	ctx          context.Context
-	state        acm.StateIterable
+	iterable     state.Iterable
 	subscribable event.Subscribable
 	nameReg      execution.NameRegIterable
 	blockchain   bcm.Blockchain
@@ -49,13 +50,13 @@ type Service struct {
 	logger       *logging.Logger
 }
 
-func NewService(ctx context.Context, state acm.StateIterable, nameReg execution.NameRegIterable,
+func NewService(ctx context.Context, iterable state.Iterable, nameReg execution.NameRegIterable,
 	subscribable event.Subscribable, blockchain bcm.Blockchain, transactor execution.Transactor,
 	nodeView query.NodeView, logger *logging.Logger) *Service {
 
 	return &Service{
 		ctx:          ctx,
-		state:        state,
+		iterable:     iterable,
 		nameReg:      nameReg,
 		subscribable: subscribable,
 		blockchain:   blockchain,
@@ -202,7 +203,7 @@ func (s *Service) Genesis() (*ResultGenesis, error) {
 
 // Accounts
 func (s *Service) GetAccount(address acm.Address) (*ResultGetAccount, error) {
-	acc, err := s.state.GetAccount(address)
+	acc, err := s.iterable.GetAccount(address)
 	if err != nil {
 		return nil, err
 	}
@@ -214,7 +215,7 @@ func (s *Service) GetAccount(address acm.Address) (*ResultGetAccount, error) {
 
 func (s *Service) ListAccounts(predicate func(acm.Account) bool) (*ResultListAccounts, error) {
 	accounts := make([]*acm.ConcreteAccount, 0)
-	s.state.IterateAccounts(func(account acm.Account) (stop bool) {
+	s.iterable.IterateAccounts(func(account acm.Account) (stop bool) {
 		if predicate(account) {
 			accounts = append(accounts, acm.AsConcreteAccount(account))
 		}
@@ -228,7 +229,7 @@ func (s *Service) ListAccounts(predicate func(acm.Account) bool) (*ResultListAcc
 }
 
 func (s *Service) GetStorage(address acm.Address, key []byte) (*ResultGetStorage, error) {
-	account, err := s.state.GetAccount(address)
+	account, err := s.iterable.GetAccount(address)
 	if err != nil {
 		return nil, err
 	}
@@ -236,7 +237,7 @@ func (s *Service) GetStorage(address acm.Address, key []byte) (*ResultGetStorage
 		return nil, fmt.Errorf("UnknownAddress: %s", address)
 	}
 
-	value, err := s.state.GetStorage(address, binary.LeftPadWord256(key))
+	value, err := s.iterable.GetStorage(address, binary.LeftPadWord256(key))
 	if err != nil {
 		return nil, err
 	}
@@ -247,7 +248,7 @@ func (s *Service) GetStorage(address acm.Address, key []byte) (*ResultGetStorage
 }
 
 func (s *Service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) {
-	account, err := s.state.GetAccount(address)
+	account, err := s.iterable.GetAccount(address)
 	if err != nil {
 		return nil, err
 	}
@@ -255,7 +256,7 @@ func (s *Service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) {
 		return nil, fmt.Errorf("UnknownAddress: %X", address)
 	}
 	var storageItems []StorageItem
-	s.state.IterateStorage(address, func(key, value binary.Word256) (stop bool) {
+	s.iterable.IterateStorage(address, func(key, value binary.Word256) (stop bool) {
 		storageItems = append(storageItems, StorageItem{Key: key.UnpadLeft(), Value: value.UnpadLeft()})
 		return
 	})
@@ -266,7 +267,7 @@ func (s *Service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) {
 }
 
 func (s *Service) GetAccountHumanReadable(address acm.Address) (*ResultGetAccountHumanReadable, error) {
-	acc, err := s.state.GetAccount(address)
+	acc, err := s.iterable.GetAccount(address)
 	if err != nil {
 		return nil, err
 	}
diff --git a/txs/tx.go b/txs/tx.go
index 1133e948..e79c1e45 100644
--- a/txs/tx.go
+++ b/txs/tx.go
@@ -21,7 +21,7 @@ import (
 	"io"
 
 	acm "github.com/hyperledger/burrow/account"
-	ptypes "github.com/hyperledger/burrow/permission"
+	"github.com/hyperledger/burrow/permission/snatives"
 	"github.com/tendermint/go-wire"
 	"github.com/tendermint/go-wire/data"
 	"golang.org/x/crypto/ripemd160"
@@ -166,7 +166,7 @@ type (
 
 	PermissionsTx struct {
 		Input    *TxInput
-		PermArgs ptypes.PermArgs
+		PermArgs snatives.PermArgs
 		txHashMemoizer
 	}
 
diff --git a/txs/tx_test.go b/txs/tx_test.go
index 3a10bc39..73c7da8e 100644
--- a/txs/tx_test.go
+++ b/txs/tx_test.go
@@ -22,6 +22,7 @@ import (
 
 	acm "github.com/hyperledger/burrow/account"
 	ptypes "github.com/hyperledger/burrow/permission"
+	"github.com/hyperledger/burrow/permission/snatives"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
@@ -189,7 +190,7 @@ func TestPermissionsTxSignable(t *testing.T) {
 			Amount:   12345,
 			Sequence: 250,
 		},
-		PermArgs: ptypes.SetBaseArgs(makeAddress("address1"), 1, true),
+		PermArgs: snatives.SetBaseArgs(makeAddress("address1"), 1, true),
 	}
 
 	signBytes := acm.SignBytes(chainID, permsTx)
@@ -220,7 +221,7 @@ func TestTxWrapper_MarshalJSON(t *testing.T) {
 func TestNewPermissionsTxWithSequence(t *testing.T) {
 	privateKey := acm.PrivateKeyFromSecret("Shhh...")
 
-	args := ptypes.SetBaseArgs(privateKey.PublicKey().Address(), ptypes.HasRole, true)
+	args := snatives.SetBaseArgs(privateKey.PublicKey().Address(), ptypes.HasRole, true)
 	permTx := NewPermissionsTxWithSequence(privateKey.PublicKey(), args, 1)
 	testTxMarshalJSON(t, permTx)
 }
diff --git a/txs/tx_utils.go b/txs/tx_utils.go
index a9056d51..dd5ddae2 100644
--- a/txs/tx_utils.go
+++ b/txs/tx_utils.go
@@ -18,7 +18,8 @@ import (
 	"fmt"
 
 	acm "github.com/hyperledger/burrow/account"
-	ptypes "github.com/hyperledger/burrow/permission"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/permission/snatives"
 )
 
 //----------------------------------------------------------------------------
@@ -31,7 +32,7 @@ func NewSendTx() *SendTx {
 	}
 }
 
-func (tx *SendTx) AddInput(st acm.Getter, pubkey acm.PublicKey, amt uint64) error {
+func (tx *SendTx) AddInput(st state.AccountGetter, pubkey acm.PublicKey, amt uint64) error {
 	addr := pubkey.Address()
 	acc, err := st.GetAccount(addr)
 	if err != nil {
@@ -74,7 +75,7 @@ func (tx *SendTx) SignInput(chainID string, i int, privAccount acm.PrivateAccoun
 //----------------------------------------------------------------------------
 // CallTx interface for creating tx
 
-func NewCallTx(st acm.Getter, from acm.PublicKey, to *acm.Address, data []byte,
+func NewCallTx(st state.AccountGetter, from acm.PublicKey, to *acm.Address, data []byte,
 	amt, gasLimit, fee uint64) (*CallTx, error) {
 
 	addr := from.Address()
@@ -116,7 +117,7 @@ func (tx *CallTx) Sign(chainID string, privAccount acm.PrivateAccount) {
 //----------------------------------------------------------------------------
 // NameTx interface for creating tx
 
-func NewNameTx(st acm.Getter, from acm.PublicKey, name, data string, amt, fee uint64) (*NameTx, error) {
+func NewNameTx(st state.AccountGetter, from acm.PublicKey, name, data string, amt, fee uint64) (*NameTx, error) {
 	addr := from.Address()
 	acc, err := st.GetAccount(addr)
 	if err != nil {
@@ -162,7 +163,7 @@ func NewBondTx(pubkey acm.PublicKey) (*BondTx, error) {
 	}, nil
 }
 
-func (tx *BondTx) AddInput(st acm.Getter, pubkey acm.PublicKey, amt uint64) error {
+func (tx *BondTx) AddInput(st state.AccountGetter, pubkey acm.PublicKey, amt uint64) error {
 	addr := pubkey.Address()
 	acc, err := st.GetAccount(addr)
 	if err != nil {
@@ -237,7 +238,7 @@ func (tx *RebondTx) Sign(chainID string, privAccount acm.PrivateAccount) {
 //----------------------------------------------------------------------------
 // PermissionsTx interface for creating tx
 
-func NewPermissionsTx(st acm.Getter, from acm.PublicKey, args ptypes.PermArgs) (*PermissionsTx, error) {
+func NewPermissionsTx(st state.AccountGetter, from acm.PublicKey, args snatives.PermArgs) (*PermissionsTx, error) {
 	addr := from.Address()
 	acc, err := st.GetAccount(addr)
 	if err != nil {
@@ -251,7 +252,7 @@ func NewPermissionsTx(st acm.Getter, from acm.PublicKey, args ptypes.PermArgs) (
 	return NewPermissionsTxWithSequence(from, args, sequence), nil
 }
 
-func NewPermissionsTxWithSequence(from acm.PublicKey, args ptypes.PermArgs, sequence uint64) *PermissionsTx {
+func NewPermissionsTxWithSequence(from acm.PublicKey, args snatives.PermArgs, sequence uint64) *PermissionsTx {
 	input := &TxInput{
 		Address:   from.Address(),
 		Amount:    1, // NOTE: amounts can't be 0 ...
-- 
GitLab