From cb8bc156c92bce8c55cefe89eacbfe8a93fd15cb Mon Sep 17 00:00:00 2001
From: Silas Davis <silas@monax.io>
Date: Wed, 4 Apr 2018 19:46:41 +0100
Subject: [PATCH] Add MemoryState and rename AddressableSigner rename

Signed-off-by: Silas Davis <silas@monax.io>
---
 account/private_account.go        |  8 ++--
 account/state/memory_state.go     | 80 +++++++++++++++++++++++++++++++
 account/state/state_cache_test.go | 45 +++--------------
 execution/accounts.go             | 68 ++++++++++++++++++++++++++
 execution/execution_test.go       | 14 +++---
 execution/state.go                |  3 ++
 execution/transactor.go           | 75 ++++++++++++++++++++++-------
 execution/transactor_test.go      | 42 ++++++++++++++++
 txs/bond_tx.go                    |  2 +-
 txs/call_tx.go                    |  4 +-
 txs/name_tx.go                    |  4 +-
 txs/permission_tx.go              |  4 +-
 txs/rebond_tx.go                  |  4 +-
 txs/send_tx.go                    |  2 +-
 txs/tx.go                         |  2 +-
 txs/unbond_tx.go                  |  4 +-
 16 files changed, 281 insertions(+), 80 deletions(-)
 create mode 100644 account/state/memory_state.go
 create mode 100644 execution/accounts.go
 create mode 100644 execution/transactor_test.go

diff --git a/account/private_account.go b/account/private_account.go
index 0ef0bed6..3ca56cd7 100644
--- a/account/private_account.go
+++ b/account/private_account.go
@@ -20,13 +20,13 @@ import (
 	"github.com/tendermint/go-wire"
 )
 
-type SigningAccount interface {
+type AddressableSigner interface {
 	Addressable
 	Signer
 }
 
 type PrivateAccount interface {
-	SigningAccount
+	AddressableSigner
 	PrivateKey() PrivateKey
 }
 
@@ -99,8 +99,8 @@ func (pa *ConcretePrivateAccount) String() string {
 }
 
 // Convert slice of ConcretePrivateAccounts to slice of SigningAccounts
-func SigningAccounts(concretePrivateAccounts []*ConcretePrivateAccount) []SigningAccount {
-	signingAccounts := make([]SigningAccount, len(concretePrivateAccounts))
+func SigningAccounts(concretePrivateAccounts []*ConcretePrivateAccount) []AddressableSigner {
+	signingAccounts := make([]AddressableSigner, len(concretePrivateAccounts))
 	for i, cpa := range concretePrivateAccounts {
 		signingAccounts[i] = cpa.PrivateAccount()
 	}
diff --git a/account/state/memory_state.go b/account/state/memory_state.go
new file mode 100644
index 00000000..35f1ad69
--- /dev/null
+++ b/account/state/memory_state.go
@@ -0,0 +1,80 @@
+package state
+
+import (
+	"fmt"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/binary"
+)
+
+type MemoryState struct {
+	Accounts map[acm.Address]acm.Account
+	Storage  map[acm.Address]map[binary.Word256]binary.Word256
+}
+
+var _ IterableWriter = &MemoryState{}
+
+// Get an in-memory state Iterable
+func NewMemoryState() *MemoryState {
+	return &MemoryState{
+		Accounts: make(map[acm.Address]acm.Account),
+		Storage:  make(map[acm.Address]map[binary.Word256]binary.Word256),
+	}
+}
+
+func (ms *MemoryState) GetAccount(address acm.Address) (acm.Account, error) {
+	return ms.Accounts[address], nil
+}
+
+func (ms *MemoryState) UpdateAccount(updatedAccount acm.Account) error {
+	if updatedAccount == nil {
+		return fmt.Errorf("UpdateAccount passed nil account in MemoryState")
+	}
+	ms.Accounts[updatedAccount.Address()] = updatedAccount
+	return nil
+}
+
+func (ms *MemoryState) RemoveAccount(address acm.Address) error {
+	delete(ms.Accounts, address)
+	return nil
+}
+
+func (ms *MemoryState) GetStorage(address acm.Address, key binary.Word256) (binary.Word256, error) {
+	storage, ok := ms.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
+}
+
+func (ms *MemoryState) SetStorage(address acm.Address, key, value binary.Word256) error {
+	storage, ok := ms.Storage[address]
+	if !ok {
+		storage = make(map[binary.Word256]binary.Word256)
+		ms.Storage[address] = storage
+	}
+	storage[key] = value
+	return nil
+}
+
+func (ms *MemoryState) IterateAccounts(consumer func(acm.Account) (stop bool)) (stopped bool, err error) {
+	for _, acc := range ms.Accounts {
+		if consumer(acc) {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
+func (ms *MemoryState) IterateStorage(address acm.Address, consumer func(key, value binary.Word256) (stop bool)) (stopped bool, err error) {
+	for key, value := range ms.Storage[address] {
+		if consumer(key, value) {
+			return true, nil
+		}
+	}
+	return false, nil
+}
diff --git a/account/state/state_cache_test.go b/account/state/state_cache_test.go
index a0c5bc80..2c414708 100644
--- a/account/state/state_cache_test.go
+++ b/account/state/state_cache_test.go
@@ -1,7 +1,6 @@
 package state
 
 import (
-	"fmt"
 	"testing"
 
 	acm "github.com/hyperledger/burrow/account"
@@ -15,7 +14,7 @@ import (
 func TestStateCache_GetAccount(t *testing.T) {
 	// Build backend states for read and write
 	readBackend := testAccounts()
-	writeBackend := NewCache(newTestState())
+	writeBackend := NewCache(NewMemoryState())
 	cache := NewCache(readBackend)
 
 	acc := readBackend.Accounts[addressOf("acc1")]
@@ -34,7 +33,7 @@ func TestStateCache_GetAccount(t *testing.T) {
 
 func TestStateCache_UpdateAccount(t *testing.T) {
 	// Build backend states for read and write
-	backend := NewCache(newTestState())
+	backend := NewCache(NewMemoryState())
 	cache := NewCache(backend)
 	// Create acccount
 	accNew := acm.NewConcreteAccountFromSecret("accNew")
@@ -102,7 +101,7 @@ func TestStateCache_Sync(t *testing.T) {
 func TestStateCache_get(t *testing.T) {
 }
 
-func testAccounts() *testState {
+func testAccounts() *MemoryState {
 	acc1 := acm.NewConcreteAccountFromSecret("acc1")
 	acc1.Permissions.Base.Perms = permission.AddRole | permission.Send
 	acc1.Permissions.Base.SetBit = acc1.Permissions.Base.Perms
@@ -124,22 +123,8 @@ func addressOf(secret string) acm.Address {
 	return acm.NewConcreteAccountFromSecret(secret).Address
 }
 
-// testState StateIterable
-
-type testState struct {
-	Accounts map[acm.Address]acm.Account
-	Storage  map[acm.Address]map[binary.Word256]binary.Word256
-}
-
-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()
+func account(acc acm.Account, keyvals ...string) *MemoryState {
+	ts := NewMemoryState()
 	ts.Accounts[acc.Address()] = acc
 	ts.Storage[acc.Address()] = make(map[binary.Word256]binary.Word256)
 	for i := 0; i < len(keyvals); i += 2 {
@@ -148,8 +133,8 @@ func account(acc acm.Account, keyvals ...string) *testState {
 	return ts
 }
 
-func combine(states ...*testState) *testState {
-	ts := newTestState()
+func combine(states ...*MemoryState) *MemoryState {
+	ts := NewMemoryState()
 	for _, state := range states {
 		for _, acc := range state.Accounts {
 			ts.Accounts[acc.Address()] = acc
@@ -162,19 +147,3 @@ func combine(states ...*testState) *testState {
 func word(str string) binary.Word256 {
 	return binary.LeftPadWord256([]byte(str))
 }
-
-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/execution/accounts.go b/execution/accounts.go
new file mode 100644
index 00000000..7dc11149
--- /dev/null
+++ b/execution/accounts.go
@@ -0,0 +1,68 @@
+package execution
+
+import (
+	"fmt"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/keys"
+)
+
+type Accounts struct {
+	state.Iterable
+	keyClient keys.KeyClient
+}
+
+type SigningAccount struct {
+	acm.Account
+	acm.Signer
+}
+
+func NewAccounts(iterable state.Iterable, keyClient keys.KeyClient) *Accounts {
+	return &Accounts{
+		Iterable:  iterable,
+		keyClient: keyClient,
+	}
+}
+
+func (accs *Accounts) SigningAccount(address acm.Address) (*SigningAccount, error) {
+	signer := keys.Signer(accs.keyClient, address)
+	account, err := accs.GetAccount(address)
+	if err != nil {
+		return nil, err
+	}
+	// If the account is unknown to us return a zeroed account
+	if account != nil {
+		account = acm.ConcreteAccount{
+			Address: address,
+		}.Account()
+	}
+	return &SigningAccount{
+		Account: account,
+		Signer:  signer,
+	}, nil
+}
+
+func (accs *Accounts) SigningAccountFromPrivateKey(privateKeyBytes []byte) (*SigningAccount, error) {
+	if len(privateKeyBytes) != 64 {
+		return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privateKeyBytes))
+	}
+	privateAccount, err := acm.GeneratePrivateAccountFromPrivateKeyBytes(privateKeyBytes)
+	if err != nil {
+		return nil, err
+	}
+	account, err := accs.GetAccount(privateAccount.Address())
+	if err != nil {
+		return nil, err
+	}
+	// If the account is unknown to us return a zeroed account
+	if account != nil {
+		account = acm.ConcreteAccount{
+			Address: privateAccount.Address(),
+		}.Account()
+	}
+	return &SigningAccount{
+		Account: account,
+		Signer:  privateAccount,
+	}, nil
+}
diff --git a/execution/execution_test.go b/execution/execution_test.go
index 6401c8fc..f1cdfb56 100644
--- a/execution/execution_test.go
+++ b/execution/execution_test.go
@@ -119,8 +119,8 @@ var testGenesisDoc, testPrivAccounts, _ = deterministicGenesis.
 	GenesisDoc(3, true, 1000, 1, true, 1000)
 var testChainID = testGenesisDoc.ChainID()
 
-func makeUsers(n int) []acm.SigningAccount {
-	users := make([]acm.SigningAccount, n)
+func makeUsers(n int) []acm.AddressableSigner {
+	users := make([]acm.AddressableSigner, n)
 	for i := 0; i < n; i++ {
 		secret := "mysecret" + strconv.Itoa(i)
 		users[i] = acm.GeneratePrivateAccountFromSecret(secret)
@@ -1703,7 +1703,7 @@ func execTxWithStateNewBlock(state *State, blockchain bcm.MutableBlockchain, tx
 }
 
 func makeGenesisState(numAccounts int, randBalance bool, minBalance uint64, numValidators int, randBonded bool,
-	minBonded int64) (*State, []acm.SigningAccount) {
+	minBonded int64) (*State, []acm.AddressableSigner) {
 	testGenesisDoc, privAccounts, _ := deterministicGenesis.GenesisDoc(numAccounts, randBalance, minBalance,
 		numValidators, randBonded, minBonded)
 	s0, err := MakeGenesisState(dbm.NewMemDB(), testGenesisDoc)
@@ -1860,7 +1860,7 @@ func permNameToFuncID(name string) []byte {
 	return id[:]
 }
 
-func snativePermTestInputCALL(name string, user acm.SigningAccount, perm ptypes.PermFlag,
+func snativePermTestInputCALL(name string, user acm.AddressableSigner, perm ptypes.PermFlag,
 	val bool) (addr acm.Address, pF ptypes.PermFlag, data []byte) {
 	addr = permissionsContract.Address()
 	switch name {
@@ -1883,7 +1883,7 @@ func snativePermTestInputCALL(name string, user acm.SigningAccount, perm ptypes.
 	return
 }
 
-func snativePermTestInputTx(name string, user acm.SigningAccount, perm ptypes.PermFlag,
+func snativePermTestInputTx(name string, user acm.AddressableSigner, perm ptypes.PermFlag,
 	val bool) (snativeArgs snatives.PermArgs) {
 
 	switch name {
@@ -1899,7 +1899,7 @@ func snativePermTestInputTx(name string, user acm.SigningAccount, perm ptypes.Pe
 	return
 }
 
-func snativeRoleTestInputCALL(name string, user acm.SigningAccount,
+func snativeRoleTestInputCALL(name string, user acm.AddressableSigner,
 	role string) (addr acm.Address, pF ptypes.PermFlag, data []byte) {
 	addr = permissionsContract.Address()
 	data = user.Address().Word256().Bytes()
@@ -1913,7 +1913,7 @@ func snativeRoleTestInputCALL(name string, user acm.SigningAccount,
 	return
 }
 
-func snativeRoleTestInputTx(name string, user acm.SigningAccount, role string) (snativeArgs snatives.PermArgs) {
+func snativeRoleTestInputTx(name string, user acm.AddressableSigner, role string) (snativeArgs snatives.PermArgs) {
 	switch name {
 	case "hasRole":
 		snativeArgs = snatives.HasRoleArgs(user.Address(), role)
diff --git a/execution/state.go b/execution/state.go
index 73fb51df..7b98a32a 100644
--- a/execution/state.go
+++ b/execution/state.go
@@ -185,6 +185,9 @@ func (s *State) GetAccount(address acm.Address) (acm.Account, error) {
 func (s *State) UpdateAccount(account acm.Account) error {
 	s.Lock()
 	defer s.Unlock()
+	if account == nil {
+		return fmt.Errorf("UpdateAccount passed nil account in execution.State")
+	}
 	// TODO: find a way to implement something equivalent to this so we can set the account StorageRoot
 	//storageRoot := s.tree.SubTreeHash(prefixedKey(storagePrefix, account.Address().Bytes()))
 	// Alternatively just abandon and
diff --git a/execution/transactor.go b/execution/transactor.go
index a875fe6b..ddbe8fe7 100644
--- a/execution/transactor.go
+++ b/execution/transactor.go
@@ -17,11 +17,10 @@ package execution
 import (
 	"context"
 	"fmt"
+	"runtime/debug"
 	"sync"
 	"time"
 
-	"runtime/debug"
-
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/account/state"
 	"github.com/hyperledger/burrow/binary"
@@ -45,9 +44,14 @@ type Call struct {
 	GasUsed uint64
 }
 
+type SequencedAddressableSigner interface {
+	acm.AddressableSigner
+	Sequence() uint64
+}
+
 // Transactor is the controller/middleware for the v0 RPC
 type Transactor struct {
-	txMtx            sync.Mutex
+	sync.Mutex
 	tip              blockchain.Tip
 	state            state.Iterable
 	eventEmitter     event.Emitter
@@ -161,6 +165,44 @@ func (trans *Transactor) BroadcastTx(tx txs.Tx) (*txs.Receipt, error) {
 	}
 }
 
+// Orders calls to BroadcastTx using lock (waits for response from core before releasing)
+func (trans *Transactor) Transact2(inputAccount SequencedAddressableSigner, address *acm.Address, data []byte, gasLimit,
+	fee uint64) (*txs.Receipt, error) {
+	trans.Lock()
+	defer trans.Unlock()
+	// TODO: [Silas] we should consider revising this method and removing fee, or
+	// possibly adding an amount parameter. It is non-sensical to just be able to
+	// set the fee. Our support of fees in general is questionable since at the
+	// moment all we do is deduct the fee effectively leaking token. It is possible
+	// someone may be using the sending of native token to payable functions but
+	// they can be served by broadcasting a token.
+
+	// We hard-code the amount to be equal to the fee which means the CallTx we
+	// generate transfers 0 value, which is the most sensible default since in
+	// recent solidity compilers the EVM generated will throw an error if value
+	// is transferred to a non-payable function.
+	txInput := &txs.TxInput{
+		Address:   inputAccount.Address(),
+		Amount:    fee,
+		Sequence:  inputAccount.Sequence() + 1,
+		PublicKey: inputAccount.PublicKey(),
+	}
+	tx := &txs.CallTx{
+		Input:    txInput,
+		Address:  address,
+		GasLimit: gasLimit,
+		Fee:      fee,
+		Data:     data,
+	}
+
+	// Got ourselves a tx.
+	err := tx.Sign(trans.tip.ChainID(), inputAccount)
+	if err != nil {
+		return nil, err
+	}
+	return trans.BroadcastTx(tx)
+}
+
 // Orders calls to BroadcastTx using lock (waits for response from core before releasing)
 func (trans *Transactor) Transact(privKey []byte, address *acm.Address, data []byte, gasLimit,
 	fee uint64) (*txs.Receipt, error) {
@@ -168,13 +210,12 @@ func (trans *Transactor) Transact(privKey []byte, address *acm.Address, data []b
 	if len(privKey) != 64 {
 		return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privKey))
 	}
-	trans.txMtx.Lock()
-	defer trans.txMtx.Unlock()
+	trans.Lock()
+	defer trans.Unlock()
 	pa, err := acm.GeneratePrivateAccountFromPrivateKeyBytes(privKey)
 	if err != nil {
 		return nil, err
 	}
-	// [Silas] This is puzzling, if the account doesn't exist the CallTx will fail, so what's the point in this?
 	acc, err := trans.state.GetAccount(pa.Address())
 	if err != nil {
 		return nil, err
@@ -210,7 +251,7 @@ func (trans *Transactor) Transact(privKey []byte, address *acm.Address, data []b
 	}
 
 	// Got ourselves a tx.
-	txS, errS := trans.SignTx(tx, []acm.SigningAccount{pa})
+	txS, errS := trans.SignTx(tx, []acm.AddressableSigner{pa})
 	if errS != nil {
 		return nil, errS
 	}
@@ -265,14 +306,13 @@ func (trans *Transactor) Send(privKey []byte, toAddress acm.Address, amount uint
 
 	pk := &[64]byte{}
 	copy(pk[:], privKey)
-	trans.txMtx.Lock()
-	defer trans.txMtx.Unlock()
+	trans.Lock()
+	defer trans.Unlock()
 	pa, err := acm.GeneratePrivateAccountFromPrivateKeyBytes(privKey)
 	if err != nil {
 		return nil, err
 	}
-	cache := trans.state
-	acc, err := cache.GetAccount(pa.Address())
+	acc, err := trans.state.GetAccount(pa.Address())
 	if err != nil {
 		return nil, err
 	}
@@ -297,7 +337,7 @@ func (trans *Transactor) Send(privKey []byte, toAddress acm.Address, amount uint
 	tx.Outputs = append(tx.Outputs, txOutput)
 
 	// Got ourselves a tx.
-	txS, errS := trans.SignTx(tx, []acm.SigningAccount{pa})
+	txS, errS := trans.SignTx(tx, []acm.AddressableSigner{pa})
 	if errS != nil {
 		return nil, errS
 	}
@@ -349,14 +389,13 @@ func (trans *Transactor) TransactNameReg(privKey []byte, name, data string, amou
 	if len(privKey) != 64 {
 		return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privKey))
 	}
-	trans.txMtx.Lock()
-	defer trans.txMtx.Unlock()
+	trans.Lock()
+	defer trans.Unlock()
 	pa, err := acm.GeneratePrivateAccountFromPrivateKeyBytes(privKey)
 	if err != nil {
 		return nil, err
 	}
-	cache := trans.state // XXX: DON'T MUTATE THIS CACHE (used internally for CheckTx)
-	acc, err := cache.GetAccount(pa.Address())
+	acc, err := trans.state.GetAccount(pa.Address())
 	if err != nil {
 		return nil, err
 	}
@@ -366,7 +405,7 @@ func (trans *Transactor) TransactNameReg(privKey []byte, name, data string, amou
 	}
 	tx := txs.NewNameTxWithSequence(pa.PublicKey(), name, data, amount, fee, sequence)
 	// Got ourselves a tx.
-	txS, errS := trans.SignTx(tx, []acm.SigningAccount{pa})
+	txS, errS := trans.SignTx(tx, []acm.AddressableSigner{pa})
 	if errS != nil {
 		return nil, errS
 	}
@@ -374,7 +413,7 @@ func (trans *Transactor) TransactNameReg(privKey []byte, name, data string, amou
 }
 
 // Sign a transaction
-func (trans *Transactor) SignTx(tx txs.Tx, signingAccounts []acm.SigningAccount) (txs.Tx, error) {
+func (trans *Transactor) SignTx(tx txs.Tx, signingAccounts []acm.AddressableSigner) (txs.Tx, error) {
 	// more checks?
 	err := tx.Sign(trans.tip.ChainID(), signingAccounts...)
 	if err != nil {
diff --git a/execution/transactor_test.go b/execution/transactor_test.go
new file mode 100644
index 00000000..83c281a4
--- /dev/null
+++ b/execution/transactor_test.go
@@ -0,0 +1,42 @@
+package execution
+
+import (
+	"testing"
+	"time"
+
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/blockchain"
+	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/txs"
+	"github.com/tendermint/abci/types"
+)
+
+func TestTransactor_TransactAndHold(t *testing.T) {
+}
+
+type testTransactor struct {
+	ResponseCh chan<- *types.Response
+	state.IterableWriter
+	event.Emitter
+	*Transactor
+}
+
+func newTestTransactor(txProcessor func(tx txs.Tx) (*types.Response, error)) testTransactor {
+	st := state.NewMemoryState()
+	emitter := event.NewEmitter(logger)
+	trans := NewTransactor(blockchain.NewTip(testChainID, time.Time{}, nil), st,
+		emitter, func(tx txs.Tx, callback func(res *types.Response)) error {
+			res, err := txProcessor(tx)
+			if err != nil {
+				return err
+			}
+			callback(res)
+			return nil
+		}, logger)
+
+	return testTransactor{
+		IterableWriter: st,
+		Emitter:        emitter,
+		Transactor:     trans,
+	}
+}
diff --git a/txs/bond_tx.go b/txs/bond_tx.go
index b6537092..aa6aecea 100644
--- a/txs/bond_tx.go
+++ b/txs/bond_tx.go
@@ -90,7 +90,7 @@ func (tx *BondTx) AddOutput(addr acm.Address, amt uint64) error {
 	return nil
 }
 
-func (tx *BondTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error {
+func (tx *BondTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
 	if len(signingAccounts) != len(tx.Inputs)+1 {
 		return fmt.Errorf("BondTx expects %v SigningAccounts but got %v", len(tx.Inputs)+1,
 			len(signingAccounts))
diff --git a/txs/call_tx.go b/txs/call_tx.go
index 234972cd..a3d0f1b8 100644
--- a/txs/call_tx.go
+++ b/txs/call_tx.go
@@ -55,9 +55,9 @@ func NewCallTxWithSequence(from acm.PublicKey, to *acm.Address, data []byte,
 	}
 }
 
-func (tx *CallTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error {
+func (tx *CallTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
 	if len(signingAccounts) != 1 {
-		return fmt.Errorf("CallTx expects a single SigningAccount for its single Input but %v were provieded",
+		return fmt.Errorf("CallTx expects a single AddressableSigner for its single Input but %v were provieded",
 			len(signingAccounts))
 	}
 	var err error
diff --git a/txs/name_tx.go b/txs/name_tx.go
index a9143ab3..76ef57dc 100644
--- a/txs/name_tx.go
+++ b/txs/name_tx.go
@@ -56,9 +56,9 @@ func NewNameTxWithSequence(from acm.PublicKey, name, data string, amt, fee, sequ
 	}
 }
 
-func (tx *NameTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error {
+func (tx *NameTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
 	if len(signingAccounts) != 1 {
-		return fmt.Errorf("NameTx expects a single SigningAccount for its single Input but %v were provieded",
+		return fmt.Errorf("NameTx expects a single AddressableSigner for its single Input but %v were provieded",
 			len(signingAccounts))
 	}
 	var err error
diff --git a/txs/permission_tx.go b/txs/permission_tx.go
index a1ed4969..c2dad89b 100644
--- a/txs/permission_tx.go
+++ b/txs/permission_tx.go
@@ -46,9 +46,9 @@ func NewPermissionsTxWithSequence(from acm.PublicKey, args snatives.PermArgs, se
 	}
 }
 
-func (tx *PermissionsTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error {
+func (tx *PermissionsTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
 	if len(signingAccounts) != 1 {
-		return fmt.Errorf("PermissionsTx expects a single SigningAccount for its single Input but %v were provieded",
+		return fmt.Errorf("PermissionsTx expects a single AddressableSigner for its single Input but %v were provieded",
 			len(signingAccounts))
 	}
 	var err error
diff --git a/txs/rebond_tx.go b/txs/rebond_tx.go
index 93b95898..b5b22ff4 100644
--- a/txs/rebond_tx.go
+++ b/txs/rebond_tx.go
@@ -24,9 +24,9 @@ func NewRebondTx(addr acm.Address, height int) *RebondTx {
 	}
 }
 
-func (tx *RebondTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error {
+func (tx *RebondTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
 	if len(signingAccounts) != 1 {
-		return fmt.Errorf("RebondTx expects a single SigningAccount for its signature but %v were provieded",
+		return fmt.Errorf("RebondTx expects a single AddressableSigner for its signature but %v were provieded",
 			len(signingAccounts))
 	}
 	var err error
diff --git a/txs/send_tx.go b/txs/send_tx.go
index 02c7039c..e9212fd8 100644
--- a/txs/send_tx.go
+++ b/txs/send_tx.go
@@ -86,7 +86,7 @@ func (tx *SendTx) AddOutput(addr acm.Address, amt uint64) error {
 	return nil
 }
 
-func (tx *SendTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error {
+func (tx *SendTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
 	if len(signingAccounts) != len(tx.Inputs) {
 		return fmt.Errorf("SendTx has %v Inputs but was provided with %v SigningAccounts", len(tx.Inputs),
 			len(signingAccounts))
diff --git a/txs/tx.go b/txs/tx.go
index 3e7f0419..dec958e2 100644
--- a/txs/tx.go
+++ b/txs/tx.go
@@ -84,7 +84,7 @@ type Tx interface {
 	String() string
 	GetInputs() []TxInput
 	Hash(chainID string) []byte
-	Sign(chainID string, signingAccounts ...acm.SigningAccount) error
+	Sign(chainID string, signingAccounts ...acm.AddressableSigner) error
 }
 
 type Encoder interface {
diff --git a/txs/unbond_tx.go b/txs/unbond_tx.go
index ab016a0d..8bd84f29 100644
--- a/txs/unbond_tx.go
+++ b/txs/unbond_tx.go
@@ -24,9 +24,9 @@ func NewUnbondTx(addr acm.Address, height int) *UnbondTx {
 	}
 }
 
-func (tx *UnbondTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error {
+func (tx *UnbondTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
 	if len(signingAccounts) != 1 {
-		return fmt.Errorf("UnbondTx expects a single SigningAccount for its signature but %v were provieded",
+		return fmt.Errorf("UnbondTx expects a single AddressableSigner for its signature but %v were provieded",
 			len(signingAccounts))
 	}
 	var err error
-- 
GitLab