diff --git a/core/kernel.go b/core/kernel.go
index 28ff55a7271f663b3a6f4c5e145f8fb5ae41251f..aae2435ab8e51725eb692ee38f83cd4d34ad6e83 100644
--- a/core/kernel.go
+++ b/core/kernel.go
@@ -106,10 +106,11 @@ func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tmTy
 
 	txCodec := txs.NewAminoCodec()
 	tmGenesisDoc := tendermint.DeriveGenesisDoc(genesisDoc)
-	checker := execution.NewBatchChecker(kern.State, kern.Blockchain, kern.Logger)
+	checker := execution.NewBatchChecker(kern.State, kern.Blockchain, keyClient, kern.Logger)
 
 	kern.Emitter = event.NewEmitter(kern.Logger)
-	committer := execution.NewBatchCommitter(kern.State, kern.Blockchain, kern.Emitter, kern.Logger, exeOptions...)
+	committer := execution.NewBatchCommitter(kern.State, kern.Blockchain, kern.Emitter, keyClient, kern.Logger,
+		exeOptions...)
 
 	kern.nodeInfo = fmt.Sprintf("Burrow_%s_%X", genesisDoc.ChainID(), privValidator.GetAddress())
 	app := abci.NewApp(kern.nodeInfo, kern.Blockchain, checker, committer, txCodec, kern.Panic, logger)
diff --git a/crypto/public_key.go b/crypto/public_key.go
index 171d86cec5daf51aa73068b88f7da3bb052c8295..58203830c5c717463bb2fe0dc75edd10a71c1a6e 100644
--- a/crypto/public_key.go
+++ b/crypto/public_key.go
@@ -32,6 +32,10 @@ func PublicKeyLength(curveType CurveType) int {
 	}
 }
 
+func (p PublicKey) IsSet() bool {
+	return p.CurveType != CurveTypeUnset && p.IsValid()
+}
+
 func (p PublicKey) MarshalJSON() ([]byte, error) {
 	jStruct := PublicKeyJSON{
 		CurveType: p.CurveType.String(),
diff --git a/execution/contexts/call_context.go b/execution/contexts/call_context.go
index 385d05e1882961a310fe3d7e255578deee68dc80..2dec797dc5dd87c78ffa8afec7a7b16f179195e5 100644
--- a/execution/contexts/call_context.go
+++ b/execution/contexts/call_context.go
@@ -61,25 +61,12 @@ func (ctx *CallContext) Precheck() (*acm.MutableAccount, acm.Account, error) {
 		return nil, nil, errors.ErrorCodeInvalidAddress
 	}
 
-	err = validateInput(inAcc, ctx.tx.Input)
-	if err != nil {
-		ctx.Logger.InfoMsg("validateInput failed",
-			"tx_input", ctx.tx.Input, structure.ErrorKey, err)
-		return nil, nil, err
-	}
 	if ctx.tx.Input.Amount < ctx.tx.Fee {
 		ctx.Logger.InfoMsg("Sender did not send enough to cover the fee",
 			"tx_input", ctx.tx.Input)
 		return nil, nil, errors.ErrorCodeInsufficientFunds
 	}
 
-	ctx.Logger.TraceMsg("Incrementing sequence number for CallTx",
-		"tag", "sequence",
-		"account", inAcc.Address(),
-		"old_sequence", inAcc.Sequence(),
-		"new_sequence", inAcc.Sequence()+1)
-
-	inAcc.IncSequence()
 	err = inAcc.SubtractFromBalance(ctx.tx.Fee)
 	if err != nil {
 		return nil, nil, err
diff --git a/execution/contexts/governance_context.go b/execution/contexts/governance_context.go
index b53a78c97d8868394bffedc5e76a81d0e14bffa4..f4455a0e393ba41d3aeb4ad8bc9623a0c03c11ff 100644
--- a/execution/contexts/governance_context.go
+++ b/execution/contexts/governance_context.go
@@ -7,9 +7,11 @@ import (
 	"github.com/hyperledger/burrow/acm"
 	"github.com/hyperledger/burrow/acm/state"
 	"github.com/hyperledger/burrow/acm/validator"
+	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/execution/errors"
 	"github.com/hyperledger/burrow/execution/exec"
 	"github.com/hyperledger/burrow/genesis/spec"
+	"github.com/hyperledger/burrow/keys"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/permission"
 	"github.com/hyperledger/burrow/txs/payload"
@@ -18,6 +20,7 @@ import (
 type GovernanceContext struct {
 	StateWriter  state.ReaderWriter
 	ValidatorSet validator.Writer
+	KeyClient    keys.KeyClient
 	Logger       *logging.Logger
 	tx           *payload.GovTx
 	txe          *exec.TxExecution
@@ -32,7 +35,8 @@ func (ctx *GovernanceContext) Execute(txe *exec.TxExecution) error {
 	if !ok {
 		return fmt.Errorf("payload must be NameTx, but is: %v", txe.Envelope.Tx.Payload)
 	}
-	accounts, err := getInputs(ctx.StateWriter, ctx.tx.Inputs)
+	// Nothing down with any incoming funds at this point
+	accounts, _, err := getInputs(ctx.StateWriter, ctx.tx.Inputs)
 	if err != nil {
 		return err
 	}
@@ -53,6 +57,13 @@ func (ctx *GovernanceContext) Execute(txe *exec.TxExecution) error {
 			return fmt.Errorf("could not execution GovTx since account template %v contains neither "+
 				"address or public key", update)
 		}
+		if update.PublicKey == nil {
+			update.PublicKey, err = ctx.MaybeGetPublicKey(*update.Address)
+			if err != nil {
+				return err
+			}
+		}
+		// Check address
 		if update.PublicKey != nil {
 			address := update.PublicKey.Address()
 			if update.Address != nil && address != *update.Address {
@@ -60,8 +71,7 @@ func (ctx *GovernanceContext) Execute(txe *exec.TxExecution) error {
 					"GovTx", update.PublicKey, address, update.Address)
 			}
 			update.Address = &address
-		}
-		if update.PublicKey == nil && update.Balances().HasPower() {
+		} else if update.Balances().HasPower() {
 			// If we are updating power we will need the key
 			return fmt.Errorf("GovTx must be provided with public key when updating validator power")
 		}
@@ -132,3 +142,21 @@ func (ctx *GovernanceContext) UpdateAccount(account *acm.MutableAccount, update
 	err = ctx.StateWriter.UpdateAccount(account)
 	return
 }
+
+func (ctx *GovernanceContext) MaybeGetPublicKey(address crypto.Address) (*crypto.PublicKey, error) {
+	// First try state in case chain has received input previously
+	acc, err := ctx.StateWriter.GetAccount(address)
+	if err != nil {
+		return nil, err
+	}
+	if acc != nil && acc.PublicKey().IsSet() {
+		publicKey := acc.PublicKey()
+		return &publicKey, nil
+	}
+	// Then try key client
+	publicKey, err := ctx.KeyClient.PublicKey(address)
+	if err == nil {
+		return &publicKey, nil
+	}
+	return nil, nil
+}
diff --git a/execution/contexts/name_context.go b/execution/contexts/name_context.go
index 10c37a15bf50e408e73039e547d430eba203a5ac..a2215b0bf2296a4baa46b917f726ae407fd1b01f 100644
--- a/execution/contexts/name_context.go
+++ b/execution/contexts/name_context.go
@@ -11,7 +11,6 @@ import (
 	"github.com/hyperledger/burrow/execution/exec"
 	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/logging"
-	"github.com/hyperledger/burrow/logging/structure"
 	"github.com/hyperledger/burrow/txs/payload"
 )
 
@@ -48,12 +47,6 @@ func (ctx *NameContext) Execute(txe *exec.TxExecution) error {
 	if !hasNamePermission(ctx.StateWriter, inAcc, ctx.Logger) {
 		return fmt.Errorf("account %s does not have Name permission", ctx.tx.Input.Address)
 	}
-	err = validateInput(inAcc, ctx.tx.Input)
-	if err != nil {
-		ctx.Logger.InfoMsg("validateInput failed",
-			"tx_input", ctx.tx.Input, structure.ErrorKey, err)
-		return err
-	}
 	if ctx.tx.Input.Amount < ctx.tx.Fee {
 		ctx.Logger.InfoMsg("Sender did not send enough to cover the fee",
 			"tx_input", ctx.tx.Input)
@@ -172,7 +165,6 @@ func (ctx *NameContext) Execute(txe *exec.TxExecution) error {
 		"account", inAcc.Address(),
 		"old_sequence", inAcc.Sequence(),
 		"new_sequence", inAcc.Sequence()+1)
-	inAcc.IncSequence()
 	err = inAcc.SubtractFromBalance(value)
 	if err != nil {
 		return err
diff --git a/execution/contexts/permissions_context.go b/execution/contexts/permissions_context.go
index ac4c450b3adf904ba0d85f776aac597e62804a2e..dc1f994989d38840e8d9f85a2ca13cc8a2b66555 100644
--- a/execution/contexts/permissions_context.go
+++ b/execution/contexts/permissions_context.go
@@ -10,7 +10,6 @@ import (
 	"github.com/hyperledger/burrow/execution/errors"
 	"github.com/hyperledger/burrow/execution/exec"
 	"github.com/hyperledger/burrow/logging"
-	"github.com/hyperledger/burrow/logging/structure"
 	"github.com/hyperledger/burrow/permission"
 	"github.com/hyperledger/burrow/txs/payload"
 )
@@ -51,14 +50,6 @@ func (ctx *PermissionsContext) Execute(txe *exec.TxExecution) error {
 			permFlag.String(), permFlag)
 	}
 
-	err = validateInput(inAcc, ctx.tx.Input)
-	if err != nil {
-		ctx.Logger.InfoMsg("validateInput failed",
-			"tx_input", ctx.tx.Input,
-			structure.ErrorKey, err)
-		return err
-	}
-
 	value := ctx.tx.Input.Amount
 
 	ctx.Logger.TraceMsg("New PermsTx",
@@ -114,12 +105,6 @@ func (ctx *PermissionsContext) Execute(txe *exec.TxExecution) error {
 	}
 
 	// Good!
-	ctx.Logger.TraceMsg("Incrementing sequence number for PermsTx",
-		"tag", "sequence",
-		"account", inAcc.Address(),
-		"old_sequence", inAcc.Sequence(),
-		"new_sequence", inAcc.Sequence()+1)
-	inAcc.IncSequence()
 	err = inAcc.SubtractFromBalance(value)
 	if err != nil {
 		return err
diff --git a/execution/contexts/send_context.go b/execution/contexts/send_context.go
index a50c0b8839c6733f7b5705121a43106b7faccd3b..c9c3b5a361c7a3a3c343b59fbf89b0c6e7a63c9b 100644
--- a/execution/contexts/send_context.go
+++ b/execution/contexts/send_context.go
@@ -25,7 +25,7 @@ func (ctx *SendContext) Execute(txe *exec.TxExecution) error {
 	if !ok {
 		return fmt.Errorf("payload must be NameTx, but is: %v", txe.Envelope.Tx.Payload)
 	}
-	accounts, err := getInputs(ctx.StateWriter, ctx.tx.Inputs)
+	accounts, inTotal, err := getInputs(ctx.StateWriter, ctx.tx.Inputs)
 	if err != nil {
 		return err
 	}
@@ -43,10 +43,6 @@ func (ctx *SendContext) Execute(txe *exec.TxExecution) error {
 		return err
 	}
 
-	inTotal, err := validateInputs(accounts, ctx.tx.Inputs)
-	if err != nil {
-		return err
-	}
 	outTotal, err := validateOutputs(ctx.tx.Outputs)
 	if err != nil {
 		return err
diff --git a/execution/contexts/shared.go b/execution/contexts/shared.go
index 77a1197441bf57045e592b77819aa16bcc4853fc..b33f3226da8799cefeefdfc1fb4a9f649565c6f4 100644
--- a/execution/contexts/shared.go
+++ b/execution/contexts/shared.go
@@ -17,25 +17,25 @@ import (
 // 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 state.AccountGetter,
-	ins []*payload.TxInput) (map[crypto.Address]*acm.MutableAccount, error) {
-
+func getInputs(accountGetter state.AccountGetter, ins []*payload.TxInput) (map[crypto.Address]*acm.MutableAccount, uint64, error) {
+	var total uint64
 	accounts := map[crypto.Address]*acm.MutableAccount{}
 	for _, in := range ins {
 		// Account shouldn't be duplicated
 		if _, ok := accounts[in.Address]; ok {
-			return nil, errors.ErrorCodeDuplicateAddress
+			return nil, total, errors.ErrorCodeDuplicateAddress
 		}
 		acc, err := state.GetMutableAccount(accountGetter, in.Address)
 		if err != nil {
-			return nil, err
+			return nil, total, err
 		}
 		if acc == nil {
-			return nil, errors.ErrorCodeInvalidAddress
+			return nil, total, errors.ErrorCodeInvalidAddress
 		}
 		accounts[in.Address] = acc
+		total += in.Amount
 	}
-	return accounts, nil
+	return accounts, total, nil
 }
 
 func getOrMakeOutputs(accountGetter state.AccountGetter, accs map[crypto.Address]*acm.MutableAccount,
@@ -82,38 +82,6 @@ func getOrMakeOutput(accountGetter state.AccountGetter, accs map[crypto.Address]
 	return acc, nil
 }
 
-func validateInputs(accs map[crypto.Address]*acm.MutableAccount, ins []*payload.TxInput) (uint64, error) {
-	total := uint64(0)
-	for _, in := range ins {
-		acc := accs[in.Address]
-		if acc == nil {
-			return 0, fmt.Errorf("validateInputs() expects account in accounts, but account %s not found", in.Address)
-		}
-		err := validateInput(acc, in)
-		if err != nil {
-			return 0, err
-		}
-		// Good. Add amount to total
-		total += in.Amount
-	}
-	return total, nil
-}
-
-func validateInput(acc *acm.MutableAccount, in *payload.TxInput) error {
-	// Check sequences
-	if acc.Sequence()+1 != uint64(in.Sequence) {
-		return payload.ErrTxInvalidSequence{
-			Input:   in,
-			Account: acc,
-		}
-	}
-	// Check amount
-	if acc.Balance() < uint64(in.Amount) {
-		return errors.ErrorCodeInsufficientFunds
-	}
-	return nil
-}
-
 func validateOutputs(outs []*payload.TxOutput) (uint64, error) {
 	total := uint64(0)
 	for _, out := range outs {
@@ -137,12 +105,6 @@ func adjustByInputs(accs map[crypto.Address]*acm.MutableAccount, ins []*payload.
 		if err != nil {
 			return err
 		}
-		logger.TraceMsg("Incrementing sequence number for SendTx (adjustByInputs)",
-			"tag", "sequence",
-			"account", acc.Address(),
-			"old_sequence", acc.Sequence(),
-			"new_sequence", acc.Sequence()+1)
-		acc.IncSequence()
 	}
 	return nil
 }
diff --git a/execution/evm/accounts.go b/execution/evm/accounts.go
index 65c578e375a9485f05d3976484e414240954fe88..ad4ffae31fd5d3a4fbe5ffc216f7c713be4f6c1c 100644
--- a/execution/evm/accounts.go
+++ b/execution/evm/accounts.go
@@ -11,16 +11,15 @@ import (
 // sequence number incremented
 func DeriveNewAccount(creator *acm.MutableAccount, permissions permission.AccountPermissions,
 	logger *logging.Logger) *acm.MutableAccount {
-	// Generate an address
-	sequence := creator.Sequence()
+
 	logger.TraceMsg("Incrementing sequence number in DeriveNewAccount()",
 		"tag", "sequence",
 		"account", creator.Address(),
-		"old_sequence", sequence,
-		"new_sequence", sequence+1)
-	creator.IncSequence()
+		"old_sequence", creator.Sequence(),
+		"new_sequence", creator.Sequence()+1)
 
-	addr := crypto.NewContractAddress(creator.Address(), sequence)
+	creator.IncSequence()
+	addr := crypto.NewContractAddress(creator.Address(), creator.Sequence())
 
 	// Create account from address.
 	return acm.ConcreteAccount{
diff --git a/execution/execution.go b/execution/execution.go
index 5547075b81ad4664c32694bfaca8cb96f205f047..25f1da1924b40886dabbc20a23e4a6c7de0752fe 100644
--- a/execution/execution.go
+++ b/execution/execution.go
@@ -31,6 +31,7 @@ import (
 	"github.com/hyperledger/burrow/execution/evm"
 	"github.com/hyperledger/burrow/execution/exec"
 	"github.com/hyperledger/burrow/execution/names"
+	"github.com/hyperledger/burrow/keys"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
 	"github.com/hyperledger/burrow/txs"
@@ -87,7 +88,7 @@ type executor struct {
 var _ BatchExecutor = (*executor)(nil)
 
 // Wraps a cache of what is variously known as the 'check cache' and 'mempool'
-func NewBatchChecker(backend ExecutorState, blockchain *bcm.Blockchain, logger *logging.Logger,
+func NewBatchChecker(backend ExecutorState, blockchain *bcm.Blockchain, keyClient keys.KeyClient, logger *logging.Logger,
 	options ...ExecutionOption) BatchExecutor {
 
 	exe := newExecutor("CheckCache", false, backend, blockchain, event.NewNoOpPublisher(),
@@ -97,13 +98,14 @@ func NewBatchChecker(backend ExecutorState, blockchain *bcm.Blockchain, logger *
 		&contexts.GovernanceContext{
 			ValidatorSet: exe.blockchain.ValidatorChecker(),
 			StateWriter:  exe.stateCache,
+			KeyClient:    keyClient,
 			Logger:       exe.logger,
 		},
 	)
 }
 
-func NewBatchCommitter(backend ExecutorState, blockchain *bcm.Blockchain, emitter event.Publisher, logger *logging.Logger,
-	options ...ExecutionOption) BatchCommitter {
+func NewBatchCommitter(backend ExecutorState, blockchain *bcm.Blockchain, emitter event.Publisher,
+	keyClient keys.KeyClient, logger *logging.Logger, options ...ExecutionOption) BatchCommitter {
 
 	exe := newExecutor("CommitCache", true, backend, blockchain, emitter,
 		logger.WithScope("NewBatchCommitter"), options...)
@@ -112,6 +114,7 @@ func NewBatchCommitter(backend ExecutorState, blockchain *bcm.Blockchain, emitte
 		&contexts.GovernanceContext{
 			ValidatorSet: exe.blockchain.ValidatorWriter(),
 			StateWriter:  exe.stateCache,
+			KeyClient:    keyClient,
 			Logger:       exe.logger,
 		},
 	)
@@ -189,50 +192,26 @@ func (exe *executor) Execute(txEnv *txs.Envelope) (txe *exec.TxExecution, err er
 		return nil, err
 	}
 
-	// Initialise public keys for accounts we have seen
-	for _, sig := range txEnv.Signatories {
-		// pointer dereferences are safe since txEnv.Validate() is run by txEnv.Verify() above which checks they are
-		// non-nil
-		acc, err := state.GetMutableAccount(exe.stateCache, *sig.Address)
-		if err != nil {
-			return nil, fmt.Errorf("error getting account on which to set public key: %v", *sig.Address)
-		}
-		acc.SetPublicKey(*sig.PublicKey)
-		err = exe.stateCache.UpdateAccount(acc)
-		if err != nil {
-			return nil, fmt.Errorf("error updating account after setting public key: %v", err)
-		}
-	}
-
 	if txExecutor, ok := exe.contexts[txEnv.Tx.Type()]; ok {
 		// Establish new TxExecution
 		txe := exe.blockExecution.Tx(txEnv)
+		// Validate inputs and check sequence numbers
+		err = txEnv.Tx.ValidateInputs(exe.stateCache)
+		if err != nil {
+			return nil, err
+		}
 		err = txExecutor.Execute(txe)
 		if err != nil {
 			return nil, err
 		}
+		// Initialise public keys and increment sequence numbers for Tx inputs
+		exe.updateSignatories(txEnv)
 		// Return execution for this tx
 		return txe, nil
 	}
 	return nil, fmt.Errorf("unknown transaction type: %v", txEnv.Tx.Type())
 }
 
-func (exe *executor) finaliseBlockExecution(header *abciTypes.Header) (*exec.BlockExecution, error) {
-	if header != nil && uint64(header.Height) != exe.blockExecution.Height {
-		return nil, fmt.Errorf("trying to finalise block execution with height %v but passed Tendermint"+
-			"block header at height %v", exe.blockExecution.Height, header.Height)
-	}
-	// Capture BlockExecution to return
-	be := exe.blockExecution
-	// Set the header when provided
-	be.BlockHeader = exec.BlockHeaderFromHeader(header)
-	// Start new execution for the next height
-	exe.blockExecution = &exec.BlockExecution{
-		Height: exe.blockExecution.Height + 1,
-	}
-	return be, nil
-}
-
 func (exe *executor) Commit(blockHash []byte, blockTime time.Time, header *abciTypes.Header) (_ []byte, err error) {
 
 	// The write lock to the executor is controlled by the caller (e.g. abci.App) so we do not acquire it here to avoid
@@ -319,3 +298,49 @@ func (exe *executor) GetStorage(address crypto.Address, key binary.Word256) (bin
 	defer exe.RUnlock()
 	return exe.stateCache.GetStorage(address, key)
 }
+
+func (exe *executor) finaliseBlockExecution(header *abciTypes.Header) (*exec.BlockExecution, error) {
+	if header != nil && uint64(header.Height) != exe.blockExecution.Height {
+		return nil, fmt.Errorf("trying to finalise block execution with height %v but passed Tendermint"+
+			"block header at height %v", exe.blockExecution.Height, header.Height)
+	}
+	// Capture BlockExecution to return
+	be := exe.blockExecution
+	// Set the header when provided
+	be.BlockHeader = exec.BlockHeaderFromHeader(header)
+	// Start new execution for the next height
+	exe.blockExecution = &exec.BlockExecution{
+		Height: exe.blockExecution.Height + 1,
+	}
+	return be, nil
+}
+
+// Capture public keys and update sequence numbers
+func (exe *executor) updateSignatories(txEnv *txs.Envelope) error {
+	for _, sig := range txEnv.Signatories {
+		// pointer dereferences are safe since txEnv.Validate() is run by txEnv.Verify() above which checks they are
+		// non-nil
+		acc, err := state.GetMutableAccount(exe.stateCache, *sig.Address)
+		if err != nil {
+			return fmt.Errorf("error getting account on which to set public key: %v", *sig.Address)
+		}
+		// Important that verify has been run against signatories at this point
+		if sig.PublicKey.Address() != acc.Address() {
+			return fmt.Errorf("unexpected mismatch between address %v and supplied public key %v",
+				acc.Address(), sig.PublicKey)
+		}
+		acc.SetPublicKey(*sig.PublicKey)
+
+		exe.logger.TraceMsg("Incrementing sequence number Tx signatory/input",
+			"tag", "sequence",
+			"account", acc.Address(),
+			"old_sequence", acc.Sequence(),
+			"new_sequence", acc.Sequence()+1)
+		acc.IncSequence()
+		err = exe.stateCache.UpdateAccount(acc)
+		if err != nil {
+			return fmt.Errorf("error updating account after setting public key: %v", err)
+		}
+	}
+	return nil
+}
diff --git a/genesis/spec/genesis_spec.go b/genesis/spec/genesis_spec.go
index 6990afa1273983ff9db44b1f9adc28434502e4b3..b660a4c1ffcb7d027be94de818a7ed7e23af9464 100644
--- a/genesis/spec/genesis_spec.go
+++ b/genesis/spec/genesis_spec.go
@@ -32,7 +32,7 @@ type GenesisSpec struct {
 
 func (gs *GenesisSpec) RealiseKeys(keyClient keys.KeyClient) error {
 	for _, templateAccount := range gs.Accounts {
-		_, _, err := templateAccount.RealisePubKeyAndAddress(keyClient)
+		_, _, err := templateAccount.RealisePublicKeyAndAddress(keyClient)
 		if err != nil {
 			return err
 		}
diff --git a/genesis/spec/template_account.go b/genesis/spec/template_account.go
index 152a8097f0ceb81f9eada960e7232bbe431a8b03..fb5c55f98f5f47b2a96cba5b2a717cebb5307f46 100644
--- a/genesis/spec/template_account.go
+++ b/genesis/spec/template_account.go
@@ -13,7 +13,7 @@ import (
 func (ta TemplateAccount) Validator(keyClient keys.KeyClient, index int, generateNodeKeys bool) (*genesis.Validator, error) {
 	var err error
 	gv := new(genesis.Validator)
-	gv.PublicKey, gv.Address, err = ta.RealisePubKeyAndAddress(keyClient)
+	gv.PublicKey, gv.Address, err = ta.RealisePublicKeyAndAddress(keyClient)
 	if err != nil {
 		return nil, err
 	}
@@ -55,7 +55,7 @@ func (ta TemplateAccount) AccountPermissions() (permission.AccountPermissions, e
 func (ta TemplateAccount) GenesisAccount(keyClient keys.KeyClient, index int) (*genesis.Account, error) {
 	var err error
 	ga := new(genesis.Account)
-	ga.PublicKey, ga.Address, err = ta.RealisePubKeyAndAddress(keyClient)
+	ga.PublicKey, ga.Address, err = ta.RealisePublicKeyAndAddress(keyClient)
 	if err != nil {
 		return nil, err
 	}
@@ -78,7 +78,7 @@ func (ta TemplateAccount) GenesisAccount(keyClient keys.KeyClient, index int) (*
 
 // Adds a public key and address to the template. If PublicKey will try to fetch it by Address.
 // If both PublicKey and Address are not set will use the keyClient to generate a new keypair
-func (ta TemplateAccount) RealisePubKeyAndAddress(keyClient keys.KeyClient) (pubKey crypto.PublicKey, address crypto.Address, err error) {
+func (ta TemplateAccount) RealisePublicKeyAndAddress(keyClient keys.KeyClient) (pubKey crypto.PublicKey, address crypto.Address, err error) {
 	if ta.PublicKey == nil {
 		if ta.Address == nil {
 			// If neither PublicKey or Address set then generate a new one
diff --git a/integration/governance/governance_test.go b/integration/governance/governance_test.go
index c8f5c97218df2d3ca2c66f163f514d93f08c7461..594d4e47ceb26477be70bb43ac1683171dfdbb80 100644
--- a/integration/governance/governance_test.go
+++ b/integration/governance/governance_test.go
@@ -14,12 +14,14 @@ import (
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/execution/errors"
 	"github.com/hyperledger/burrow/execution/exec"
+	"github.com/hyperledger/burrow/genesis/spec"
 	"github.com/hyperledger/burrow/governance"
 	"github.com/hyperledger/burrow/integration/rpctest"
 	"github.com/hyperledger/burrow/permission"
 	"github.com/hyperledger/burrow/rpc/rpcevents"
 	"github.com/hyperledger/burrow/rpc/rpcquery"
 	"github.com/hyperledger/burrow/rpc/rpctransact"
+	"github.com/hyperledger/burrow/txs"
 	"github.com/hyperledger/burrow/txs/payload"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -155,6 +157,54 @@ func TestCreateAccount(t *testing.T) {
 	assert.Equal(t, amount, ca.Balance)
 }
 
+func TestChangePowerByAddress(t *testing.T) {
+	// Should use the key client to look up public key
+	inputAddress := privateAccounts[0].Address()
+	grpcAddress := testConfigs[0].RPC.GRPC.ListenAddress
+	tcli := rpctest.NewTransactClient(t, grpcAddress)
+	qcli := rpctest.NewQueryClient(t, grpcAddress)
+
+	acc := account(2)
+	address := acc.Address()
+	power := uint64(2445)
+	govSync(tcli, governance.UpdateAccountTx(inputAddress, &spec.TemplateAccount{
+		Address: &address,
+		Amounts: balance.New().Power(power),
+	}))
+
+	vs, err := qcli.GetValidatorSet(context.Background(), &rpcquery.GetValidatorSetParam{})
+	require.NoError(t, err)
+	set := validator.UnpersistSet(vs.Set)
+	assert.Equal(t, new(big.Int).SetUint64(power), set.Power(acc))
+}
+
+func TestInvalidSequenceNumber(t *testing.T) {
+	inputAddress := privateAccounts[0].Address()
+	tcli1 := rpctest.NewTransactClient(t, testConfigs[0].RPC.GRPC.ListenAddress)
+	tcli2 := rpctest.NewTransactClient(t, testConfigs[4].RPC.GRPC.ListenAddress)
+	qcli := rpctest.NewQueryClient(t, testConfigs[0].RPC.GRPC.ListenAddress)
+
+	acc := account(2)
+	address := acc.Address()
+	power := uint64(2445)
+	tx := governance.UpdateAccountTx(inputAddress, &spec.TemplateAccount{
+		Address: &address,
+		Amounts: balance.New().Power(power),
+	})
+
+	setSequence(t, qcli, tx)
+	_, err := localSignAndBroadcastSync(t, tcli1, tx)
+	require.NoError(t, err)
+
+	// Make it a different Tx hash so it can enter cache but keep sequence number
+	tx.AccountUpdates[0].Amounts = balance.New().Power(power).Native(1)
+	_, err = localSignAndBroadcastSync(t, tcli2, tx)
+	require.Error(t, err)
+	assert.Contains(t, err.Error(), "invalid sequence")
+}
+
+// Helpers
+
 func getMaxFlow(t testing.TB, qcli rpcquery.QueryClient) uint64 {
 	vs, err := qcli.GetValidatorSet(context.Background(), &rpcquery.GetValidatorSetParam{})
 	require.NoError(t, err)
@@ -194,6 +244,22 @@ func alterPower(vs *validator.Set, i int, power uint64) {
 	vs.AlterPower(account(i), new(big.Int).SetUint64(power))
 }
 
+func setSequence(t testing.TB, qcli rpcquery.QueryClient, tx payload.Payload) {
+	for _, input := range tx.GetInputs() {
+		ca, err := qcli.GetAccount(context.Background(), &rpcquery.GetAccountParam{Address: input.Address})
+		require.NoError(t, err)
+		input.Sequence = ca.Sequence + 1
+	}
+}
+
+func localSignAndBroadcastSync(t testing.TB, tcli rpctransact.TransactClient, tx payload.Payload) (*exec.TxExecution, error) {
+	txEnv := txs.Enclose(genesisDoc.ChainID(), tx)
+	err := txEnv.Sign(privateAccounts[0])
+	require.NoError(t, err)
+
+	return tcli.BroadcastTxSync(context.Background(), &rpctransact.TxEnvelopeParam{Envelope: txEnv})
+}
+
 func waitNBlocks(t testing.TB, ecli rpcevents.ExecutionEventsClient, n int) {
 	stream, err := ecli.GetBlocks(context.Background(), &rpcevents.BlocksRequest{
 		BlockRange: rpcevents.NewBlockRange(rpcevents.LatestBound(), rpcevents.StreamBound()),
diff --git a/txs/payload/payload.go b/txs/payload/payload.go
index d55a8cadd48e940fa2fccfa4f1e8fa3230a7736d..71404eecd1b2f6ca2e98cd73b93cf1788dd515b6 100644
--- a/txs/payload/payload.go
+++ b/txs/payload/payload.go
@@ -1,6 +1,8 @@
 package payload
 
-import "fmt"
+import (
+	"fmt"
+)
 
 /*
 Payload (Transaction) is an atomic operation on the ledger state.
@@ -95,29 +97,6 @@ type Payload interface {
 	Size() int
 }
 
-type UnknownTx struct {
-}
-
-func (UnknownTx) String() string {
-	panic("implement me")
-}
-
-func (UnknownTx) GetInputs() []*TxInput {
-	panic("implement me")
-}
-
-func (UnknownTx) Type() Type {
-	panic("implement me")
-}
-
-func (UnknownTx) Any() *Any {
-	panic("implement me")
-}
-
-func (UnknownTx) Size() int {
-	panic("implement me")
-}
-
 func New(txType Type) (Payload, error) {
 	switch txType {
 	case TypeSend:
diff --git a/txs/payload/tx_input.go b/txs/payload/tx_input.go
index ff02d7cf9e313130a94e15385c1a584c4bad720a..b3367aca4577df7d601eade8a30e07b071392c5d 100644
--- a/txs/payload/tx_input.go
+++ b/txs/payload/tx_input.go
@@ -2,8 +2,49 @@ package payload
 
 import (
 	"fmt"
+
+	"github.com/hyperledger/burrow/acm"
+	"github.com/hyperledger/burrow/acm/state"
+	"github.com/hyperledger/burrow/execution/errors"
 )
 
-func (txIn *TxInput) String() string {
-	return fmt.Sprintf("TxInput{%s, Amount: %v, Sequence:%v}", txIn.Address, txIn.Amount, txIn.Sequence)
+func (input *TxInput) String() string {
+	return fmt.Sprintf("TxInput{%s, Amount: %v, Sequence:%v}", input.Address, input.Amount, input.Sequence)
+}
+
+func (input *TxInput) Validate(acc acm.Account) error {
+	if input.Address != acc.Address() {
+		return fmt.Errorf("trying to validate input from address %v but passed account %v", input.Address,
+			acc.Address())
+	}
+	// Check sequences
+	if acc.Sequence()+1 != uint64(input.Sequence) {
+		return ErrTxInvalidSequence{
+			Input:   input,
+			Account: acc,
+		}
+	}
+	// Check amount
+	if acc.Balance() < uint64(input.Amount) {
+		return errors.ErrorCodeInsufficientFunds
+	}
+	return nil
+}
+
+func ValidateInputs(getter state.AccountGetter, ins []*TxInput) error {
+	for _, in := range ins {
+		acc, err := getter.GetAccount(in.Address)
+		if err != nil {
+			return err
+		}
+		if acc == nil {
+			return fmt.Errorf("validateInputs() expects to be able to retrive accoutn %v but it was not found",
+				in.Address)
+		}
+		err = in.Validate(acc)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
 }
diff --git a/txs/tx.go b/txs/tx.go
index 45b15ca85d815ca92bf71fcc5861665589b06b50..0f1c2e163b78b0f1731ad6e7fc1c87269b34ebdb 100644
--- a/txs/tx.go
+++ b/txs/tx.go
@@ -19,6 +19,7 @@ import (
 	"fmt"
 
 	"github.com/hyperledger/burrow/acm"
+	"github.com/hyperledger/burrow/acm/state"
 	"github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event/query"
@@ -76,6 +77,10 @@ func (tx *Tx) SignBytes() ([]byte, error) {
 	return bs, nil
 }
 
+func (tx *Tx) ValidateInputs(getter state.AccountGetter) error {
+	return payload.ValidateInputs(getter, tx.GetInputs())
+}
+
 // Serialisation intermediate for switching on type
 type wrapper struct {
 	ChainID string