diff --git a/.circleci/config.yml b/.circleci/config.yml
index f09a13f05a04ca6fb8512662d9bb9d05ed95d3b6..3de942fc59b4470c9e5d70eba903c1919a09ad69 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -4,7 +4,7 @@
 defaults: &defaults
   working_directory: /go/src/github.com/hyperledger/burrow
   docker:
-    - image: circleci/golang:1.9.3
+    - image: circleci/golang:1.10.1
 
 tag_filters: &tags_filters
   tags:
diff --git a/Gopkg.lock b/Gopkg.lock
index 99eff5eeb676cebb4462eedf0560de196c54c395..f0fafcb1a93d0e3afa0e45c62c618442186f4c54 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -7,6 +7,12 @@
   revision = "b26d9c308763d68093482582cea63d69be07a0f0"
   version = "v0.3.0"
 
+[[projects]]
+  name = "github.com/OneOfOne/xxhash"
+  packages = ["."]
+  revision = "4e9e81466dc37c9fd94ce9ecf42020ef54112203"
+  version = "v1.2.1"
+
 [[projects]]
   branch = "master"
   name = "github.com/btcsuite/btcd"
@@ -474,6 +480,6 @@
 [solve-meta]
   analyzer-name = "dep"
   analyzer-version = 1
-  inputs-digest = "5db3ac43679cafd5f68104e93a248b62266d313aef2d8ba3bd7f3986a5a99834"
+  inputs-digest = "f8f72aa18c801bd7e61464decf6e8108d2f38410ec921a8e7015a1e5b8878db3"
   solver-name = "gps-cdcl"
   solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
index b1f9779a1f7fc121303e95d73ea11a438bde1664..0ac9a88a7b6b402d618eb66362e80a7a57bb13d4 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -71,10 +71,6 @@
   name = "github.com/tendermint/iavl"
   version = "~0.5.0"
 
-[[constraint]]
-  name = "github.com/tendermint/merkleeyes"
-  version = "~0.2.4"
-
 [[constraint]]
   name = "github.com/tendermint/tendermint"
   version = "~0.15.0"
diff --git a/Makefile b/Makefile
index 77bcfd8d2fbc49f8aa49a77f49a5ea6fcf470d02..b899206273c5bf25357bcf0113b50e670ad8c063 100644
--- a/Makefile
+++ b/Makefile
@@ -147,8 +147,9 @@ test: check
 .PHONY: test_integration
 test_integration:
 	@go get github.com/monax/bosmarmot/keys/cmd/monax-keys
-	@go test ./keys/integration -tags integration
-	@go test ./rpc/tm/integration -tags integration
+	@go test -tags integration ./keys/integration
+	@go test -tags integration ./rpc/v0/integration
+	@go test -tags integration ./rpc/tm/integration
 
 # Run integration test from bosmarmot (separated from other integration tests so we can
 # make exception when this test fails when we make a breaking change in Burrow)
diff --git a/account/account.go b/account/account.go
index ab6e987480246167cc4373884ac5bcfc7482a968..725eda71a79ebc99cbf849ece47cee5f22f877a1 100644
--- a/account/account.go
+++ b/account/account.go
@@ -156,8 +156,8 @@ func (acc *ConcreteAccount) String() string {
 		return "Account{nil}"
 	}
 
-	return fmt.Sprintf("Account{Address: %s; PublicKey: %v Balance: %v; CodeBytes: %v; StorageRoot: 0x%X; Permissions: %s}",
-		acc.Address, acc.PublicKey, acc.Balance, len(acc.Code), acc.StorageRoot, acc.Permissions)
+	return fmt.Sprintf("Account{Address: %s; Sequence: %v; PublicKey: %v Balance: %v; CodeBytes: %v; StorageRoot: 0x%X; Permissions: %s}",
+		acc.Address, acc.Sequence, acc.PublicKey, acc.Balance, len(acc.Code), acc.StorageRoot, acc.Permissions)
 }
 
 // ConcreteAccount
diff --git a/account/private_account.go b/account/private_account.go
index 9b705a02d518ede77b9047bc4288473259fff961..3ca56cd7f0852ed348c08f10b972c23557090790 100644
--- a/account/private_account.go
+++ b/account/private_account.go
@@ -20,12 +20,16 @@ import (
 	"github.com/tendermint/go-wire"
 )
 
-type PrivateAccount interface {
+type AddressableSigner interface {
 	Addressable
-	PrivateKey() PrivateKey
 	Signer
 }
 
+type PrivateAccount interface {
+	AddressableSigner
+	PrivateKey() PrivateKey
+}
+
 //
 type ConcretePrivateAccount struct {
 	Address    Address
@@ -82,25 +86,25 @@ func (pa ConcretePrivateAccount) Sign(msg []byte) (Signature, error) {
 	return pa.PrivateKey.Sign(msg)
 }
 
-func ChainSign(pa PrivateAccount, chainID string, o Signable) Signature {
-	sig, err := pa.Sign(SignBytes(chainID, o))
+func ChainSign(signer Signer, chainID string, o Signable) (Signature, error) {
+	sig, err := signer.Sign(SignBytes(chainID, o))
 	if err != nil {
-		panic(err)
+		return Signature{}, err
 	}
-	return sig
+	return sig, nil
 }
 
 func (pa *ConcretePrivateAccount) String() string {
 	return fmt.Sprintf("ConcretePrivateAccount{%s}", pa.Address)
 }
 
-// Convert slice of ConcretePrivateAccounts to slice of PrivateAccounts
-func PrivateAccounts(concretePrivateAccounts []*ConcretePrivateAccount) []PrivateAccount {
-	privateAccounts := make([]PrivateAccount, len(concretePrivateAccounts))
+// Convert slice of ConcretePrivateAccounts to slice of SigningAccounts
+func SigningAccounts(concretePrivateAccounts []*ConcretePrivateAccount) []AddressableSigner {
+	signingAccounts := make([]AddressableSigner, len(concretePrivateAccounts))
 	for i, cpa := range concretePrivateAccounts {
-		privateAccounts[i] = cpa.PrivateAccount()
+		signingAccounts[i] = cpa.PrivateAccount()
 	}
-	return privateAccounts
+	return signingAccounts
 }
 
 // Generates a new account with private key.
diff --git a/account/state/memory_state.go b/account/state/memory_state.go
new file mode 100644
index 0000000000000000000000000000000000000000..35f1ad696e5e4820c751f973e1148a120980caed
--- /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.go b/account/state/state_cache.go
index 04107211e78eb756221a7c02293d8f3f3a66a8ca..a3675177e53bfe12a4ae3d1f5d84bf3abad58a6d 100644
--- a/account/state/state_cache.go
+++ b/account/state/state_cache.go
@@ -32,6 +32,7 @@ type Cache interface {
 
 type stateCache struct {
 	sync.RWMutex
+	name     string
 	backend  Reader
 	accounts map[acm.Address]*accountInfo
 }
@@ -44,13 +45,25 @@ type accountInfo struct {
 	updated bool
 }
 
+type CacheOption func(*stateCache)
+
 // 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 NewCache(backend Reader) Cache {
-	return &stateCache{
+func NewCache(backend Reader, options ...CacheOption) Cache {
+	cache := &stateCache{
 		backend:  backend,
 		accounts: make(map[acm.Address]*accountInfo),
 	}
+	for _, option := range options {
+		option(cache)
+	}
+	return cache
+}
+
+func Name(name string) CacheOption {
+	return func(cache *stateCache) {
+		cache.name = name
+	}
 }
 
 func (cache *stateCache) GetAccount(address acm.Address) (acm.Account, error) {
@@ -233,6 +246,13 @@ func (cache *stateCache) Flush(state IterableWriter) error {
 	return nil
 }
 
+func (cache *stateCache) String() string {
+	if cache.name == "" {
+		return fmt.Sprintf("StateCache{Length: %v}", len(cache.accounts))
+	}
+	return fmt.Sprintf("StateCache{Name: %v; Length: %v}", cache.name, len(cache.accounts))
+}
+
 // Get the cache accountInfo item creating it if necessary
 func (cache *stateCache) get(address acm.Address) (*accountInfo, error) {
 	cache.RLock()
diff --git a/account/state/state_cache_test.go b/account/state/state_cache_test.go
index a0c5bc80ec8afc715c962d6d45a722ba4b75a4d0..af02081f5fda1bdc4b0ae95411f8389677f8471e 100644
--- a/account/state/state_cache_test.go
+++ b/account/state/state_cache_test.go
@@ -1,9 +1,10 @@
 package state
 
 import (
-	"fmt"
 	"testing"
 
+	"fmt"
+
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/execution/evm/asm"
@@ -15,7 +16,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")]
@@ -32,9 +33,25 @@ func TestStateCache_GetAccount(t *testing.T) {
 	assert.Equal(t, acm.AsConcreteAccount(acc), acm.AsConcreteAccount(accOut))
 }
 
+func TestStateCache_Miss(t *testing.T) {
+	readBackend := testAccounts()
+	cache := NewCache(readBackend)
+
+	acc1Address := addressOf("acc1")
+	acc1, err := cache.GetAccount(acc1Address)
+	require.NoError(t, err)
+	fmt.Println(acc1)
+
+	acc1Exp := readBackend.Accounts[acc1Address]
+	assert.Equal(t, acc1Exp, acc1)
+	acc8, err := cache.GetAccount(addressOf("acc8"))
+	require.NoError(t, err)
+	assert.Nil(t, acc8)
+}
+
 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 +119,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 +141,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 +151,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 +165,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/blockchain/blockchain.go b/blockchain/blockchain.go
index dae49f81adc865be17b0c5f4d9d6fc1a9dee0975..c81f4524e0e516be3bdea4494033030b90b92d46 100644
--- a/blockchain/blockchain.go
+++ b/blockchain/blockchain.go
@@ -31,8 +31,6 @@ var stateKey = []byte("BlockchainState")
 
 // Immutable Root of blockchain
 type Root interface {
-	// ChainID precomputed from GenesisDoc
-	ChainID() string
 	// GenesisHash precomputed from GenesisDoc
 	GenesisHash() []byte
 	GenesisDoc() genesis.GenesisDoc
@@ -40,6 +38,8 @@ type Root interface {
 
 // Immutable pointer to the current tip of the blockchain
 type Tip interface {
+	// ChainID precomputed from GenesisDoc
+	ChainID() string
 	// All Last* references are to the block last committed
 	LastBlockHeight() uint64
 	LastBlockTime() time.Time
@@ -66,12 +66,12 @@ type MutableBlockchain interface {
 }
 
 type root struct {
-	chainID     string
 	genesisHash []byte
 	genesisDoc  genesis.GenesisDoc
 }
 
 type tip struct {
+	chainID               string
 	lastBlockHeight       uint64
 	lastBlockTime         time.Time
 	lastBlockHash         []byte
@@ -132,12 +132,9 @@ func NewBlockchain(db dbm.DB, genesisDoc *genesis.GenesisDoc) *blockchain {
 	}
 	root := NewRoot(genesisDoc)
 	return &blockchain{
-		db:   db,
-		root: root,
-		tip: &tip{
-			lastBlockTime:         root.genesisDoc.GenesisTime,
-			appHashAfterLastBlock: root.genesisHash,
-		},
+		db:         db,
+		root:       root,
+		tip:        NewTip(genesisDoc.ChainID(), root.genesisDoc.GenesisTime, root.genesisHash),
 		validators: validators,
 	}
 }
@@ -159,19 +156,17 @@ func LoadBlockchain(db dbm.DB) (*blockchain, error) {
 
 func NewRoot(genesisDoc *genesis.GenesisDoc) *root {
 	return &root{
-		chainID:     genesisDoc.ChainID(),
 		genesisHash: genesisDoc.Hash(),
 		genesisDoc:  *genesisDoc,
 	}
 }
 
-// Create
-func NewTip(lastBlockHeight uint64, lastBlockTime time.Time, lastBlockHash []byte, appHashAfterLastBlock []byte) *tip {
+// Create genesis Tip
+func NewTip(chainID string, genesisTime time.Time, genesisHash []byte) *tip {
 	return &tip{
-		lastBlockHeight:       lastBlockHeight,
-		lastBlockTime:         lastBlockTime,
-		lastBlockHash:         lastBlockHash,
-		appHashAfterLastBlock: appHashAfterLastBlock,
+		chainID:               chainID,
+		lastBlockTime:         genesisTime,
+		appHashAfterLastBlock: genesisHash,
 	}
 }
 
@@ -239,10 +234,6 @@ func Decode(encodedState []byte) (*PersistedState, error) {
 	return persistedState, nil
 }
 
-func (r *root) ChainID() string {
-	return r.chainID
-}
-
 func (r *root) GenesisHash() []byte {
 	return r.genesisHash
 }
@@ -251,6 +242,10 @@ func (r *root) GenesisDoc() genesis.GenesisDoc {
 	return r.genesisDoc
 }
 
+func (t *tip) ChainID() string {
+	return t.chainID
+}
+
 func (t *tip) LastBlockHeight() uint64 {
 	return t.lastBlockHeight
 }
diff --git a/cmd/burrow/main.go b/cmd/burrow/main.go
index 5074510fd81418f55fc01b7ce01e5ce6b0359a4e..bacc1ccd4e9261fbaa0346cd1c0e06063a6171c3 100644
--- a/cmd/burrow/main.go
+++ b/cmd/burrow/main.go
@@ -229,7 +229,12 @@ func main() {
 					}
 				}
 
-				conf.GenesisDoc.ChainName = *chainNameOpt
+				if *chainNameOpt != "" {
+					if conf.GenesisDoc == nil {
+						fatalf("Unable to set ChainName since no GenesisDoc/GenesisSpec provided.")
+					}
+					conf.GenesisDoc.ChainName = *chainNameOpt
+				}
 
 				if *jsonOutOpt {
 					os.Stdout.WriteString(conf.JSONString())
diff --git a/config/config.go b/config/config.go
index 160f240632db14485053c0f20a91a77f3678e97e..fa39dba4e8dffc5c6b6211fd7eb1c4c9d27377ae 100644
--- a/config/config.go
+++ b/config/config.go
@@ -61,15 +61,14 @@ func (conf *BurrowConfig) Kernel(ctx context.Context) (*core.Kernel, error) {
 
 	var exeOptions []execution.ExecutionOption
 	if conf.Execution != nil {
-		var err error
 		exeOptions, err = conf.Execution.ExecutionOptions()
 		if err != nil {
 			return nil, err
 		}
 	}
 
-	return core.NewKernel(ctx, privValidator, conf.GenesisDoc, conf.Tendermint.TendermintConfig(), conf.RPC, exeOptions,
-		logger)
+	return core.NewKernel(ctx, keyClient, privValidator, conf.GenesisDoc, conf.Tendermint.TendermintConfig(), conf.RPC,
+		exeOptions, logger)
 }
 
 func (conf *BurrowConfig) JSONString() string {
diff --git a/consensus/tendermint/abci/app.go b/consensus/tendermint/abci/app.go
index 1bc0700c3cafbd9a214cbe42350c812fcdd66391..99320fb3b9b558d1d1a845bb507e37882b7eb93e 100644
--- a/consensus/tendermint/abci/app.go
+++ b/consensus/tendermint/abci/app.go
@@ -2,7 +2,6 @@ package abci
 
 import (
 	"fmt"
-	"sync"
 	"time"
 
 	bcm "github.com/hyperledger/burrow/blockchain"
@@ -19,7 +18,6 @@ import (
 const responseInfoName = "Burrow"
 
 type abciApp struct {
-	mtx sync.Mutex
 	// State
 	blockchain bcm.MutableBlockchain
 	checker    execution.BatchExecutor
@@ -68,8 +66,6 @@ func (app *abciApp) Query(reqQuery abci_types.RequestQuery) (respQuery abci_type
 }
 
 func (app *abciApp) CheckTx(txBytes []byte) abci_types.ResponseCheckTx {
-	app.mtx.Lock()
-	defer app.mtx.Unlock()
 	tx, err := app.txDecoder.DecodeTx(txBytes)
 	if err != nil {
 		app.logger.TraceMsg("CheckTx decoding error",
@@ -92,7 +88,7 @@ func (app *abciApp) CheckTx(txBytes []byte) abci_types.ResponseCheckTx {
 			"creates_contract", receipt.CreatesContract)
 		return abci_types.ResponseCheckTx{
 			Code: codes.EncodingErrorCode,
-			Log:  fmt.Sprintf("Could not execute transaction: %s, error: %v", tx, err),
+			Log:  fmt.Sprintf("CheckTx could not execute transaction: %s, error: %v", tx, err),
 		}
 	}
 
@@ -119,8 +115,6 @@ func (app *abciApp) BeginBlock(block abci_types.RequestBeginBlock) (respBeginBlo
 }
 
 func (app *abciApp) DeliverTx(txBytes []byte) abci_types.ResponseDeliverTx {
-	app.mtx.Lock()
-	defer app.mtx.Unlock()
 	tx, err := app.txDecoder.DecodeTx(txBytes)
 	if err != nil {
 		app.logger.TraceMsg("DeliverTx decoding error",
@@ -142,7 +136,7 @@ func (app *abciApp) DeliverTx(txBytes []byte) abci_types.ResponseDeliverTx {
 			"creates_contract", receipt.CreatesContract)
 		return abci_types.ResponseDeliverTx{
 			Code: codes.TxExecutionErrorCode,
-			Log:  fmt.Sprintf("Could not execute transaction: %s, error: %s", tx, err),
+			Log:  fmt.Sprintf("DeliverTx could not execute transaction: %s, error: %s", tx, err),
 		}
 	}
 
@@ -164,8 +158,6 @@ func (app *abciApp) EndBlock(reqEndBlock abci_types.RequestEndBlock) (respEndBlo
 }
 
 func (app *abciApp) Commit() abci_types.ResponseCommit {
-	app.mtx.Lock()
-	defer app.mtx.Unlock()
 	tip := app.blockchain.Tip()
 	app.logger.InfoMsg("Committing block",
 		"tag", "Commit",
@@ -177,13 +169,12 @@ func (app *abciApp) Commit() abci_types.ResponseCommit {
 		"last_block_time", tip.LastBlockTime(),
 		"last_block_hash", tip.LastBlockHash())
 
-	err := app.checker.Reset()
-	if err != nil {
-		return abci_types.ResponseCommit{
-			Code: codes.CommitErrorCode,
-			Log:  fmt.Sprintf("Could not reset check cache during commit: %s", err),
-		}
-	}
+	// Commit state before resetting check cache so that the emptied cache servicing some RPC requests will fall through
+	// to committed state when check state is reset
+	// TODO: determine why the ordering of updates does not experience invalid sequence number during recheck. It
+	// seems there is nothing to stop a Transact transaction from querying the checker cache before it has been replayed
+	// all transactions and so would formulate a transaction with the same sequence number as one in mempool.
+	// However this is not observed in v0_tests.go - we need to understand why or create a test that exposes this
 	appHash, err := app.committer.Commit()
 	if err != nil {
 		return abci_types.ResponseCommit{
@@ -201,6 +192,14 @@ func (app *abciApp) Commit() abci_types.ResponseCommit {
 		}
 	}
 
+	err = app.checker.Reset()
+	if err != nil {
+		return abci_types.ResponseCommit{
+			Code: codes.CommitErrorCode,
+			Log:  fmt.Sprintf("Could not reset check cache during commit: %s", err),
+		}
+	}
+
 	// Perform a sanity check our block height
 	if app.blockchain.LastBlockHeight() != uint64(app.block.Header.Height) {
 		app.logger.InfoMsg("Burrow block height disagrees with Tendermint block height",
@@ -214,6 +213,7 @@ func (app *abciApp) Commit() abci_types.ResponseCommit {
 				app.blockchain.LastBlockHeight(), app.block.Header.Height),
 		}
 	}
+
 	return abci_types.ResponseCommit{
 		Code: codes.TxExecutionSuccessCode,
 		Data: appHash,
diff --git a/core/integration/test_wrapper.go b/core/integration/test_wrapper.go
new file mode 100644
index 0000000000000000000000000000000000000000..20875d1723db28cfedbfde7d6d31c14b7420704b
--- /dev/null
+++ b/core/integration/test_wrapper.go
@@ -0,0 +1,129 @@
+// +build integration
+
+// Space above here matters
+// Copyright 2017 Monax Industries Limited
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package integration
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"strconv"
+	"time"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/consensus/tendermint/validator"
+	"github.com/hyperledger/burrow/core"
+	"github.com/hyperledger/burrow/genesis"
+	"github.com/hyperledger/burrow/keys/mock"
+	"github.com/hyperledger/burrow/logging"
+	"github.com/hyperledger/burrow/logging/config"
+	"github.com/hyperledger/burrow/logging/lifecycle"
+	"github.com/hyperledger/burrow/permission"
+	"github.com/hyperledger/burrow/rpc"
+	tm_config "github.com/tendermint/tendermint/config"
+)
+
+const (
+	chainName = "Integration_Test_Chain"
+	testDir   = "./test_scratch/tm_test"
+)
+
+// Enable logger output during tests
+var debugLogging = false
+
+// We use this to wrap tests
+func TestWrapper(privateAccounts []acm.PrivateAccount, genesisDoc *genesis.GenesisDoc, runner func(*core.Kernel) int) int {
+	fmt.Println("Running with integration TestWrapper (core/integration/test_wrapper.go)...")
+
+	os.RemoveAll(testDir)
+	os.MkdirAll(testDir, 0777)
+	os.Chdir(testDir)
+
+	tmConf := tm_config.DefaultConfig()
+	logger := logging.NewNoopLogger()
+	if debugLogging {
+		var err error
+		// Change config as needed
+		logger, err = lifecycle.NewLoggerFromLoggingConfig(&config.LoggingConfig{
+			ExcludeTrace: false,
+			RootSink: config.Sink().
+				SetTransform(config.FilterTransform(config.IncludeWhenAnyMatches,
+					//"","",
+					"method", "GetAccount",
+					"method", "BroadcastTx",
+					"tag", "sequence",
+					"tag", "Commit",
+					"tag", "CheckTx",
+					"tag", "DeliverTx",
+				)).
+				//AddSinks(config.Sink().SetTransform(config.FilterTransform(config.ExcludeWhenAnyMatches, "run_call", "false")).
+				AddSinks(config.Sink().SetTransform(config.PruneTransform("log_channel", "trace", "scope", "returns", "run_id", "args")).
+					AddSinks(config.Sink().SetTransform(config.SortTransform("tx_hash", "time", "message", "method")).
+						SetOutput(config.StdoutOutput()))),
+		})
+		if err != nil {
+			panic(err)
+		}
+	}
+
+	validatorAccount := privateAccounts[0]
+	privValidator := validator.NewPrivValidatorMemory(validatorAccount, validatorAccount)
+	keyClient := mock.NewMockKeyClient(privateAccounts...)
+	kernel, err := core.NewKernel(context.Background(), keyClient, privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(),
+		nil, logger)
+	if err != nil {
+		panic(err)
+	}
+	// Sometimes better to not shutdown as logging errors on shutdown may obscure real issue
+	defer func() {
+		//kernel.Shutdown(context.Background())
+	}()
+
+	err = kernel.Boot()
+	if err != nil {
+		panic(err)
+	}
+
+	return runner(kernel)
+}
+
+func TestGenesisDoc(addressables []acm.PrivateAccount) *genesis.GenesisDoc {
+	accounts := make(map[string]acm.Account, len(addressables))
+	for i, pa := range addressables {
+		account := acm.FromAddressable(pa)
+		account.AddToBalance(1 << 32)
+		account.SetPermissions(permission.AllAccountPermissions.Clone())
+		accounts[fmt.Sprintf("user_%v", i)] = account
+	}
+	genesisTime, err := time.Parse("02-01-2006", "27-10-2017")
+	if err != nil {
+		panic("could not parse test genesis time")
+	}
+	return genesis.MakeGenesisDocFromAccounts(chainName, nil, genesisTime, accounts,
+		map[string]acm.Validator{
+			"genesis_validator": acm.AsValidator(accounts["user_0"]),
+		})
+}
+
+// Deterministic account generation helper. Pass number of accounts to make
+func MakePrivateAccounts(n int) []acm.PrivateAccount {
+	accounts := make([]acm.PrivateAccount, n)
+	for i := 0; i < n; i++ {
+		accounts[i] = acm.GeneratePrivateAccountFromSecret("mysecret" + strconv.Itoa(i))
+	}
+	return accounts
+}
diff --git a/core/kernel.go b/core/kernel.go
index c033098e393abbc52dc8254e7acb6a652863f2eb..1a1fed0c465be49b492a0984ac4fc84b6620ced1 100644
--- a/core/kernel.go
+++ b/core/kernel.go
@@ -32,6 +32,7 @@ import (
 	"github.com/hyperledger/burrow/event"
 	"github.com/hyperledger/burrow/execution"
 	"github.com/hyperledger/burrow/genesis"
+	"github.com/hyperledger/burrow/keys"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
 	"github.com/hyperledger/burrow/process"
@@ -63,9 +64,9 @@ type Kernel struct {
 	shutdownOnce   sync.Once
 }
 
-func NewKernel(ctx context.Context, privValidator tm_types.PrivValidator, genesisDoc *genesis.GenesisDoc,
-	tmConf *tm_config.Config, rpcConfig *rpc.RPCConfig, exeOptions []execution.ExecutionOption,
-	logger *logging.Logger) (*Kernel, error) {
+func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tm_types.PrivValidator,
+	genesisDoc *genesis.GenesisDoc, tmConf *tm_config.Config, rpcConfig *rpc.RPCConfig,
+	exeOptions []execution.ExecutionOption, logger *logging.Logger) (*Kernel, error) {
 
 	logger = logger.WithScope("NewKernel()").With(structure.TimeKey, kitlog.DefaultTimestampUTC)
 	tmLogger := logger.With(structure.CallerKey, kitlog.Caller(LoggingCallerDepth+1))
@@ -100,10 +101,12 @@ func NewKernel(ctx context.Context, privValidator tm_types.PrivValidator, genesi
 		return nil, err
 	}
 	txCodec := txs.NewGoWireCodec()
-	transactor := execution.NewTransactor(blockchain, state, emitter, tendermint.BroadcastTxAsyncFunc(tmNode, txCodec),
+	transactor := execution.NewTransactor(blockchain, emitter, tendermint.BroadcastTxAsyncFunc(tmNode, txCodec),
 		logger)
 
-	service := rpc.NewService(ctx, state, state, emitter, blockchain, transactor, query.NewNodeView(tmNode, txCodec), logger)
+	nameReg := state
+	service := rpc.NewService(ctx, state, nameReg, checker, committer, emitter, blockchain, keyClient, transactor,
+		query.NewNodeView(tmNode, txCodec), logger)
 
 	launchers := []process.Launcher{
 		{
diff --git a/core/kernel_test.go b/core/kernel_test.go
index aa1af7efc1aefc498cef965014a6d163d6e7f5ab..e1e4d65d17c0416ae3ea0a613e35632c059915e6 100644
--- a/core/kernel_test.go
+++ b/core/kernel_test.go
@@ -12,6 +12,7 @@ import (
 	"github.com/hyperledger/burrow/consensus/tendermint"
 	"github.com/hyperledger/burrow/consensus/tendermint/validator"
 	"github.com/hyperledger/burrow/genesis"
+	"github.com/hyperledger/burrow/keys/mock"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/rpc"
 	"github.com/stretchr/testify/assert"
@@ -64,7 +65,8 @@ func bootWaitBlocksShutdown(privValidator tm_types.PrivValidator, genesisDoc *ge
 	tmConf *tm_config.Config, logger *logging.Logger,
 	blockChecker func(block *tm_types.EventDataNewBlock) (cont bool)) error {
 
-	kern, err := NewKernel(context.Background(), privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), nil, logger)
+	kern, err := NewKernel(context.Background(), mock.NewMockKeyClient(), privValidator, genesisDoc, tmConf,
+		rpc.DefaultRPCConfig(), nil, logger)
 	if err != nil {
 		return err
 	}
diff --git a/event/convention.go b/event/convention.go
index 450ebf734fa0783d08d4b6608e4b57ea14244eb5..33a66a501f7e686898ecbaf86654ce8eb601ee52 100644
--- a/event/convention.go
+++ b/event/convention.go
@@ -11,6 +11,7 @@ const (
 	MessageTypeKey = "MessageType"
 	TxTypeKey      = "TxType"
 	TxHashKey      = "TxHash"
+	StackDepthKey  = "StackDepth"
 )
 
 // Get a query that matches events with a specific eventID
diff --git a/execution/accounts.go b/execution/accounts.go
new file mode 100644
index 0000000000000000000000000000000000000000..eaa01a188060befb672b6d8f542b27e59abd7f42
--- /dev/null
+++ b/execution/accounts.go
@@ -0,0 +1,95 @@
+package execution
+
+import (
+	"fmt"
+	"sync"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/keys"
+	burrow_sync "github.com/hyperledger/burrow/sync"
+)
+
+type Accounts struct {
+	burrow_sync.RingMutex
+	state.Reader
+	keyClient keys.KeyClient
+}
+
+type SigningAccount struct {
+	acm.Account
+	acm.Signer
+}
+
+type SequentialSigningAccount struct {
+	accountLocker sync.Locker
+	getter        func() (*SigningAccount, error)
+}
+
+func NewAccounts(reader state.Reader, keyClient keys.KeyClient, mutexCount int) *Accounts {
+	return &Accounts{
+		// TODO: use the no hash variant of RingMutex after it has a test
+		RingMutex: *burrow_sync.NewRingMutexXXHash(mutexCount),
+		Reader:    reader,
+		keyClient: keyClient,
+	}
+}
+func (accs *Accounts) SigningAccount(address acm.Address, signer acm.Signer) (*SigningAccount, error) {
+	account, err := state.GetMutableAccount(accs.Reader, 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,
+		}.MutableAccount()
+	}
+	pubKey, err := accs.keyClient.PublicKey(address)
+	if err != nil {
+		return nil, err
+	}
+	account.SetPublicKey(pubKey)
+	return &SigningAccount{
+		Account: account,
+		Signer:  signer,
+	}, nil
+}
+
+func (accs *Accounts) SequentialSigningAccount(address acm.Address) *SequentialSigningAccount {
+	signer := keys.Signer(accs.keyClient, address)
+	return &SequentialSigningAccount{
+		accountLocker: accs.Mutex(address.Bytes()),
+		getter: func() (*SigningAccount, error) {
+			return accs.SigningAccount(address, signer)
+		},
+	}
+}
+
+func (accs *Accounts) SequentialSigningAccountFromPrivateKey(privateKeyBytes []byte) (*SequentialSigningAccount, 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
+	}
+	return &SequentialSigningAccount{
+		accountLocker: accs.Mutex(privateAccount.Address().Bytes()),
+		getter: func() (*SigningAccount, error) {
+			return accs.SigningAccount(privateAccount.Address(), privateAccount)
+		},
+	}, nil
+}
+
+type UnlockFunc func()
+
+func (ssa *SequentialSigningAccount) Lock() (*SigningAccount, UnlockFunc, error) {
+	ssa.accountLocker.Lock()
+	account, err := ssa.getter()
+	if err != nil {
+		ssa.accountLocker.Unlock()
+		return nil, nil, err
+	}
+	return account, ssa.accountLocker.Unlock, err
+}
diff --git a/execution/events/events.go b/execution/events/events.go
index efbe1f244debb97a195c3d48b2cf06c9e2cb8e72..6f8c394fc20f095d3c8292552c00fb5011c02ac0 100644
--- a/execution/events/events.go
+++ b/execution/events/events.go
@@ -29,9 +29,13 @@ type EventDataTx struct {
 
 // For re-use
 var sendTxQuery = event.NewQueryBuilder().
-	AndEquals(event.MessageTypeKey, reflect.TypeOf(EventDataTx{}).String()).
+	AndEquals(event.MessageTypeKey, reflect.TypeOf(&EventDataTx{}).String()).
 	AndEquals(event.TxTypeKey, reflect.TypeOf(&txs.SendTx{}).String())
 
+var callTxQuery = event.NewQueryBuilder().
+	AndEquals(event.MessageTypeKey, reflect.TypeOf(&EventDataTx{}).String()).
+	AndEquals(event.TxTypeKey, reflect.TypeOf(&txs.CallTx{}).String())
+
 type eventDataTx struct {
 	Tx        txs.Wrapper
 	Return    []byte
@@ -60,7 +64,6 @@ func (edTx *EventDataTx) UnmarshalJSON(data []byte) error {
 }
 
 // Publish/Subscribe
-
 func SubscribeAccountOutputSendTx(ctx context.Context, subscribable event.Subscribable, subscriber string,
 	address acm.Address, txHash []byte, ch chan<- *txs.SendTx) error {
 
diff --git a/execution/evm/abi/types.go b/execution/evm/abi/types.go
index 09ac0e4c364b73a48514b1f5007fe3704b7e182d..0c7f300dddde3545cc47aa9378f5d9d2f61a6a6f 100644
--- a/execution/evm/abi/types.go
+++ b/execution/evm/abi/types.go
@@ -14,6 +14,8 @@
 
 package abi
 
+import "github.com/hyperledger/burrow/execution/evm/sha3"
+
 // Ethereum defines types and calling conventions for the ABI
 // (application binary interface) here: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
 // We make a start of representing them here
@@ -51,3 +53,13 @@ type (
 	Address          [AddressLength]byte
 	FunctionSelector [FunctionSelectorLength]byte
 )
+
+func FunctionID(signature string) FunctionSelector {
+	return FirstFourBytes(sha3.Sha3([]byte(signature)))
+}
+
+func FirstFourBytes(byteSlice []byte) [4]byte {
+	var bs [4]byte
+	copy(bs[:], byteSlice[:4])
+	return bs
+}
diff --git a/execution/evm/events/events.go b/execution/evm/events/events.go
index af90a399e8fcd203456684026df64eca7c825ef5..a9308bb5b075cfd6e6fe59a8de7d663ea86392e5 100644
--- a/execution/evm/events/events.go
+++ b/execution/evm/events/events.go
@@ -33,11 +33,12 @@ func EventStringLogEvent(addr acm.Address) string    { return fmt.Sprintf("Log/%
 
 // EventDataCall fires when we call a contract, and when a contract calls another contract
 type EventDataCall struct {
-	CallData  *CallData
-	Origin    acm.Address
-	TxID      []byte
-	Return    []byte
-	Exception string
+	CallData   *CallData
+	Origin     acm.Address
+	TxHash     []byte
+	StackDepth int
+	Return     []byte
+	Exception  string
 }
 
 type CallData struct {
@@ -58,9 +59,11 @@ type EventDataLog struct {
 
 // Publish/Subscribe
 
-// Subscribe to account call event - if TxHash is provided listens for a specifc Tx otherwise captures all
+// Subscribe to account call event - if TxHash is provided listens for a specifc Tx otherwise captures all, if
+// stackDepth is greater than or equal to 0 captures calls at a specific stack depth (useful for capturing the return
+// of the root call over recursive calls
 func SubscribeAccountCall(ctx context.Context, subscribable event.Subscribable, subscriber string, address acm.Address,
-	txHash []byte, ch chan<- *EventDataCall) error {
+	txHash []byte, stackDepth int, ch chan<- *EventDataCall) error {
 
 	query := event.QueryForEventID(EventStringAccountCall(address))
 
@@ -68,6 +71,10 @@ func SubscribeAccountCall(ctx context.Context, subscribable event.Subscribable,
 		query = query.AndEquals(event.TxHashKey, hex.EncodeUpperToString(txHash))
 	}
 
+	if stackDepth >= 0 {
+		query = query.AndEquals(event.StackDepthKey, stackDepth)
+	}
+
 	return event.SubscribeCallback(ctx, subscribable, subscriber, query, func(message interface{}) bool {
 		eventDataCall, ok := message.(*EventDataCall)
 		if ok {
@@ -93,7 +100,11 @@ func SubscribeLogEvent(ctx context.Context, subscribable event.Subscribable, sub
 
 func PublishAccountCall(publisher event.Publisher, address acm.Address, eventDataCall *EventDataCall) error {
 	return event.PublishWithEventID(publisher, EventStringAccountCall(address), eventDataCall,
-		map[string]interface{}{"address": address, event.TxHashKey: hex.EncodeUpperToString(eventDataCall.TxID)})
+		map[string]interface{}{
+			"address":           address,
+			event.TxHashKey:     hex.EncodeUpperToString(eventDataCall.TxHash),
+			event.StackDepthKey: eventDataCall.StackDepth,
+		})
 }
 
 func PublishLogEvent(publisher event.Publisher, address acm.Address, eventDataLog *EventDataLog) error {
diff --git a/execution/evm/snative.go b/execution/evm/snative.go
index 34375a0adf50b456ad74383a31f0936f0e1f223c..1bb3e89cf7ddd0fbafde63c0328cd29c9084c514 100644
--- a/execution/evm/snative.go
+++ b/execution/evm/snative.go
@@ -248,7 +248,7 @@ func (contract *SNativeContractDescription) Dispatch(state state.Writer, caller
 			"identifier but arguments are only %v bytes long", len(args))
 	}
 
-	function, err := contract.FunctionByID(firstFourBytes(args))
+	function, err := contract.FunctionByID(abi.FirstFourBytes(args))
 	if err != nil {
 		return nil, err
 	}
@@ -325,7 +325,7 @@ func (function *SNativeFunctionDescription) Signature() string {
 
 // Get function calling identifier FunctionSelector
 func (function *SNativeFunctionDescription) ID() abi.FunctionSelector {
-	return firstFourBytes(sha3.Sha3([]byte(function.Signature())))
+	return abi.FunctionID(function.Signature())
 }
 
 // Get number of function arguments
@@ -566,9 +566,3 @@ func byteFromBool(b bool) byte {
 	}
 	return 0x0
 }
-
-func firstFourBytes(byteSlice []byte) [4]byte {
-	var bs [4]byte
-	copy(bs[:], byteSlice[:4])
-	return bs
-}
diff --git a/execution/evm/snative_test.go b/execution/evm/snative_test.go
index 39c31e7232972d7394da2af1c013cbe839c3ffd5..7c25aaf7910d884869ff6a43719a6f3120f9885c 100644
--- a/execution/evm/snative_test.go
+++ b/execution/evm/snative_test.go
@@ -123,7 +123,7 @@ func funcIDFromHex(t *testing.T, hexString string) abi.FunctionSelector {
 		t.Fatalf("FunctionSelector must be 4 bytes but '%s' is %v bytes", hexString,
 			len(bs))
 	}
-	return firstFourBytes(bs)
+	return abi.FirstFourBytes(bs)
 }
 
 func permFlagToWord256(permFlag ptypes.PermFlag) Word256 {
diff --git a/execution/evm/vm.go b/execution/evm/vm.go
index f94cf768ea702cde7fd208e7fb117cc96ab68d46..5597fe037f7425bde516b25dbd557eaed98f9dd0 100644
--- a/execution/evm/vm.go
+++ b/execution/evm/vm.go
@@ -159,11 +159,18 @@ func (vm *VM) fireCallEvent(exception *string, output *[]byte, callerAddress, ca
 	// fire the post call event (including exception if applicable)
 	if vm.publisher != nil {
 		events.PublishAccountCall(vm.publisher, calleeAddress, &events.EventDataCall{
-			&events.CallData{Caller: callerAddress, Callee: calleeAddress, Data: input, Value: value, Gas: *gas},
-			vm.origin,
-			vm.txHash,
-			*output,
-			*exception,
+			CallData: &events.CallData{
+				Caller: callerAddress,
+				Callee: calleeAddress,
+				Data:   input,
+				Value:  value,
+				Gas:    *gas,
+			},
+			Origin:     vm.origin,
+			TxHash:     vm.txHash,
+			StackDepth: vm.stackDepth,
+			Return:     *output,
+			Exception:  *exception,
 		})
 	}
 }
diff --git a/execution/evm/vm_test.go b/execution/evm/vm_test.go
index 82d79012b6127a72fe7f4ae112613041145c8bcf..27ce077083f3aea74d99c513e551f78e101799f5 100644
--- a/execution/evm/vm_test.go
+++ b/execution/evm/vm_test.go
@@ -442,7 +442,8 @@ func runVM(eventCh chan<- *evm_events.EventDataCall, ourVm *VM, caller, callee a
 	emitter := event.NewEmitter(logging.NewNoopLogger())
 	fmt.Printf("subscribe to %s\n", subscribeAddr)
 
-	err := evm_events.SubscribeAccountCall(context.Background(), emitter, "test", subscribeAddr, nil, eventCh)
+	err := evm_events.SubscribeAccountCall(context.Background(), emitter, "test", subscribeAddr,
+		nil, -1, eventCh)
 	if err != nil {
 		return nil, err
 	}
diff --git a/execution/execution.go b/execution/execution.go
index 58277636ad5dab3f1242bb5444ea1be3d0a93143..82db5e94cb4f3ebaeed8b0a306f1b3ac990eed8c 100644
--- a/execution/execution.go
+++ b/execution/execution.go
@@ -53,7 +53,7 @@ type BatchCommitter interface {
 }
 
 type executor struct {
-	sync.Mutex
+	sync.RWMutex
 	chainID      string
 	tip          bcm.Tip
 	runCall      bool
@@ -69,42 +69,32 @@ type executor struct {
 var _ BatchExecutor = (*executor)(nil)
 
 // Wraps a cache of what is variously known as the 'check cache' and 'mempool'
-func NewBatchChecker(state *State,
-	chainID string,
-	tip bcm.Tip,
-	logger *logging.Logger,
+func NewBatchChecker(backend *State, chainID string, tip bcm.Tip, logger *logging.Logger,
 	options ...ExecutionOption) BatchExecutor {
-	return newExecutor(false, state, chainID, tip, event.NewNoOpPublisher(),
+
+	return newExecutor("CheckCache", false, backend, chainID, tip, event.NewNoOpPublisher(),
 		logger.WithScope("NewBatchExecutor"), options...)
 }
 
-func NewBatchCommitter(state *State,
-	chainID string,
-	tip bcm.Tip,
-	publisher event.Publisher,
-	logger *logging.Logger,
+func NewBatchCommitter(backend *State, chainID string, tip bcm.Tip, publisher event.Publisher, logger *logging.Logger,
 	options ...ExecutionOption) BatchCommitter {
 
-	return newExecutor(true, state, chainID, tip, publisher,
+	return newExecutor("CommitCache", true, backend, chainID, tip, publisher,
 		logger.WithScope("NewBatchCommitter"), options...)
 }
 
-func newExecutor(runCall bool,
-	backend *State,
-	chainID string,
-	tip bcm.Tip,
-	eventFireable event.Publisher,
-	logger *logging.Logger,
-	options ...ExecutionOption) *executor {
+func newExecutor(name string, runCall bool, backend *State, chainID string, tip bcm.Tip, publisher event.Publisher,
+	logger *logging.Logger, options ...ExecutionOption) *executor {
+
 	exe := &executor{
 		chainID:      chainID,
 		tip:          tip,
 		runCall:      runCall,
 		state:        backend,
-		stateCache:   state.NewCache(backend),
+		stateCache:   state.NewCache(backend, state.Name(name)),
 		nameRegCache: NewNameRegCache(backend),
-		publisher:    eventFireable,
-		eventCache:   event.NewEventCache(eventFireable),
+		publisher:    publisher,
+		eventCache:   event.NewEventCache(publisher),
 		logger:       logger.With(structure.ComponentKey, "Executor"),
 	}
 	for _, option := range options {
@@ -115,11 +105,15 @@ func newExecutor(runCall bool,
 
 // Accounts
 func (exe *executor) GetAccount(address acm.Address) (acm.Account, error) {
+	exe.RLock()
+	defer exe.RUnlock()
 	return exe.stateCache.GetAccount(address)
 }
 
 // Storage
 func (exe *executor) GetStorage(address acm.Address, key binary.Word256) (binary.Word256, error) {
+	exe.RLock()
+	defer exe.RUnlock()
 	return exe.stateCache.GetStorage(address, key)
 }
 
@@ -128,7 +122,7 @@ func (exe *executor) Commit() (hash []byte, err error) {
 	defer exe.Unlock()
 	defer func() {
 		if r := recover(); r != nil {
-			err = fmt.Errorf("recovered from panic in executor.Commit(): %v", r)
+			err = fmt.Errorf("recovered from panic in executor.Commit(): %v\n%v", r, debug.Stack())
 		}
 	}()
 	// flush the caches
@@ -151,6 +145,8 @@ func (exe *executor) Commit() (hash []byte, err error) {
 }
 
 func (exe *executor) Reset() error {
+	exe.Lock()
+	defer exe.Unlock()
 	exe.stateCache.Reset(exe.state)
 	exe.nameRegCache.Reset(exe.state)
 	return nil
@@ -224,7 +220,6 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 			exe.stateCache.UpdateAccount(acc)
 		}
 
-		// if the exe.eventCache is nil, nothing will happen
 		if exe.eventCache != nil {
 			for _, i := range tx.Inputs {
 				events.PublishAccountInput(exe.eventCache, i.Address, txHash, tx, nil, "")
@@ -251,6 +246,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 			return txs.ErrTxInvalidAddress
 		}
 
+		// Calling a nil destination is defined as requesting contract creation
 		createContract := tx.Address == nil
 		if createContract {
 			if !hasCreateContractPermission(exe.stateCache, inAcc, logger) {
@@ -328,7 +324,7 @@ func (exe *executor) Execute(tx txs.Tx) (err error) {
 				callee  acm.MutableAccount = nil // initialized below
 				code    []byte             = nil
 				ret     []byte             = nil
-				txCache                    = state.NewCache(exe.stateCache)
+				txCache                    = state.NewCache(exe.stateCache, state.Name("TxCache"))
 				params                     = evm.Params{
 					BlockHeight: exe.tip.LastBlockHeight(),
 					BlockHash:   binary.LeftPadWord256(exe.tip.LastBlockHash()),
diff --git a/execution/execution_test.go b/execution/execution_test.go
index 70c9fe37010d22db449edd90e59ba4d668311f12..50ce476712b1182f84a7dc725369223efe6b0412 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.PrivateAccount {
-	users := make([]acm.PrivateAccount, 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)
@@ -129,12 +129,12 @@ func makeUsers(n int) []acm.PrivateAccount {
 }
 
 func makeExecutor(state *State) *executor {
-	return newExecutor(true, state, testChainID, bcm.NewBlockchain(nil, testGenesisDoc), event.NewEmitter(logger),
-		logger)
+	return newExecutor("makeExecutorCache", true, state, testChainID,
+		bcm.NewBlockchain(nil, testGenesisDoc), event.NewEmitter(logger), logger)
 }
 
 func newBaseGenDoc(globalPerm, accountPerm ptypes.AccountPermissions) genesis.GenesisDoc {
-	genAccounts := []genesis.Account{}
+	var genAccounts []genesis.Account
 	for _, user := range users[:5] {
 		accountPermCopy := accountPerm // Create new instance for custom overridability.
 		genAccounts = append(genAccounts, genesis.Account{
@@ -192,7 +192,7 @@ func TestSendFails(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[1].Address(), 5)
-	tx.SignInput(testChainID, 0, users[0])
+	require.NoError(t, tx.Sign(testChainID, users[0]))
 	if err := batchCommitter.Execute(tx); err == nil {
 		t.Fatal("Expected error")
 	} else {
@@ -205,7 +205,7 @@ func TestSendFails(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[4].Address(), 5)
-	tx.SignInput(testChainID, 0, users[2])
+	require.NoError(t, tx.Sign(testChainID, users[2]))
 	if err := batchCommitter.Execute(tx); err == nil {
 		t.Fatal("Expected error")
 	} else {
@@ -218,7 +218,7 @@ func TestSendFails(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[4].Address(), 5)
-	tx.SignInput(testChainID, 0, users[3])
+	require.NoError(t, tx.Sign(testChainID, users[3]))
 	if err := batchCommitter.Execute(tx); err == nil {
 		t.Fatal("Expected error")
 	} else {
@@ -234,7 +234,7 @@ func TestSendFails(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[6].Address(), 5)
-	tx.SignInput(testChainID, 0, users[3])
+	require.NoError(t, tx.Sign(testChainID, users[3]))
 	if err := batchCommitter.Execute(tx); err == nil {
 		t.Fatal("Expected error")
 	} else {
@@ -366,7 +366,7 @@ func TestSendPermission(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[1].Address(), 5)
-	tx.SignInput(testChainID, 0, users[0])
+	require.NoError(t, tx.Sign(testChainID, users[0]))
 	if err := batchCommitter.Execute(tx); err != nil {
 		t.Fatal("Transaction failed", err)
 	}
@@ -380,8 +380,7 @@ func TestSendPermission(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[2].Address(), 10)
-	tx.SignInput(testChainID, 0, users[0])
-	tx.SignInput(testChainID, 1, users[1])
+	require.NoError(t, tx.Sign(testChainID, users[:2]...))
 	if err := batchCommitter.Execute(tx); err == nil {
 		t.Fatal("Expected error")
 	} else {
@@ -651,7 +650,7 @@ func TestCreateAccountPermission(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[6].Address(), 5)
-	tx.SignInput(testChainID, 0, users[0])
+	require.NoError(t, tx.Sign(testChainID, users[0]))
 	if err := batchCommitter.Execute(tx); err != nil {
 		t.Fatal("Transaction failed", err)
 	}
@@ -665,8 +664,7 @@ func TestCreateAccountPermission(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[7].Address(), 10)
-	tx.SignInput(testChainID, 0, users[0])
-	tx.SignInput(testChainID, 1, users[1])
+	require.NoError(t, tx.Sign(testChainID, users[:2]...))
 	if err := batchCommitter.Execute(tx); err == nil {
 		t.Fatal("Expected error")
 	} else {
@@ -683,8 +681,7 @@ func TestCreateAccountPermission(t *testing.T) {
 	}
 	tx.AddOutput(users[7].Address(), 4)
 	tx.AddOutput(users[4].Address(), 6)
-	tx.SignInput(testChainID, 0, users[0])
-	tx.SignInput(testChainID, 1, users[1])
+	require.NoError(t, tx.Sign(testChainID, users[:2]...))
 	if err := batchCommitter.Execute(tx); err == nil {
 		t.Fatal("Expected error")
 	} else {
@@ -703,8 +700,7 @@ func TestCreateAccountPermission(t *testing.T) {
 		t.Fatal(err)
 	}
 	tx.AddOutput(users[7].Address(), 10)
-	tx.SignInput(testChainID, 0, users[0])
-	tx.SignInput(testChainID, 1, users[1])
+	require.NoError(t, tx.Sign(testChainID, users[:2]...))
 	if err := batchCommitter.Execute(tx); err != nil {
 		t.Fatal("Unexpected error", err)
 	}
@@ -719,8 +715,7 @@ func TestCreateAccountPermission(t *testing.T) {
 	}
 	tx.AddOutput(users[7].Address(), 7)
 	tx.AddOutput(users[4].Address(), 3)
-	tx.SignInput(testChainID, 0, users[0])
-	tx.SignInput(testChainID, 1, users[1])
+	require.NoError(t, tx.Sign(testChainID, users[:2]...))
 	if err := batchCommitter.Execute(tx); err != nil {
 		t.Fatal("Unexpected error", err)
 	}
@@ -1002,7 +997,7 @@ func TestTxSequence(t *testing.T) {
 		tx := txs.NewSendTx()
 		tx.AddInputWithSequence(acc0PubKey, 1, sequence)
 		tx.AddOutput(acc1.Address(), 1)
-		tx.Inputs[0].Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+		require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 		stateCopy := state.Copy(dbm.NewMemDB())
 		err := execTxWithState(stateCopy, tx)
 		if i == 1 {
@@ -1216,19 +1211,19 @@ func TestNameTxs(t *testing.T) {
 // Test creating a contract from futher down the call stack
 /*
 contract Factory {
-    address a;
-    function create() returns (address){
-        a = new PreFactory();
-        return a;
-    }
+   address a;
+   function create() returns (address){
+       a = new PreFactory();
+       return a;
+   }
 }
 
 contract PreFactory{
-    address a;
-    function create(Factory c) returns (address) {
-    	a = c.create();
-    	return a;
-    }
+   address a;
+   function create(Factory c) returns (address) {
+   	a = c.create();
+   	return a;
+   }
 }
 */
 
@@ -1270,7 +1265,7 @@ func TestCreates(t *testing.T) {
 		Data:     createData,
 	}
 
-	tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+	require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 	err := execTxWithState(state, tx)
 	if err != nil {
 		t.Errorf("Got error in executing call transaction, %v", err)
@@ -1294,7 +1289,7 @@ func TestCreates(t *testing.T) {
 		Data:     createData,
 	}
 
-	tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+	require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 	err = execTxWithState(state, tx)
 	if err != nil {
 		t.Errorf("Got error in executing call transaction, %v", err)
@@ -1311,9 +1306,9 @@ func TestCreates(t *testing.T) {
 
 /*
 contract Caller {
-    function send(address x){
-        x.send(msg.value);
-    }
+   function send(address x){
+       x.send(msg.value);
+   }
 }
 */
 var callerCode, _ = hex.DecodeString("60606040526000357c0100000000000000000000000000000000000000000000000000000000900480633e58c58c146037576035565b005b604b6004808035906020019091905050604d565b005b8073ffffffffffffffffffffffffffffffffffffffff16600034604051809050600060405180830381858888f19350505050505b5056")
@@ -1349,7 +1344,7 @@ func TestContractSend(t *testing.T) {
 		Data:     sendData,
 	}
 
-	tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+	require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 	err := execTxWithState(state, tx)
 	if err != nil {
 		t.Errorf("Got error in executing call transaction, %v", err)
@@ -1391,7 +1386,7 @@ func TestMerklePanic(t *testing.T) {
 			},
 		}
 
-		tx.Inputs[0].Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+		require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 		err := execTxWithState(stateSendTx, tx)
 		if err != nil {
 			t.Errorf("Got error in executing send transaction, %v", err)
@@ -1417,7 +1412,7 @@ func TestMerklePanic(t *testing.T) {
 			GasLimit: 10,
 		}
 
-		tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+		require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 		err := execTxWithState(stateCallTx, tx)
 		if err != nil {
 			t.Errorf("Got error in executing call transaction, %v", err)
@@ -1458,7 +1453,7 @@ func TestTxs(t *testing.T) {
 			},
 		}
 
-		tx.Inputs[0].Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+		require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 		err := execTxWithState(stateSendTx, tx)
 		if err != nil {
 			t.Errorf("Got error in executing send transaction, %v", err)
@@ -1492,7 +1487,7 @@ func TestTxs(t *testing.T) {
 			GasLimit: 10,
 		}
 
-		tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+		require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 		err := execTxWithState(stateCallTx, tx)
 		if err != nil {
 			t.Errorf("Got error in executing call transaction, %v", err)
@@ -1543,7 +1538,7 @@ proof-of-work chain as proof of what happened while they were gone `
 			Data: entryData,
 		}
 
-		tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+		require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 
 		err := execTxWithState(stateNameTx, tx)
 		if err != nil {
@@ -1566,7 +1561,7 @@ proof-of-work chain as proof of what happened while they were gone `
 		// test a bad string
 		tx.Data = string([]byte{0, 1, 2, 3, 127, 128, 129, 200, 251})
 		tx.Input.Sequence += 1
-		tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+		require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 		err = execTxWithState(stateNameTx, tx)
 		if _, ok := err.(txs.ErrTxInvalidString); !ok {
 			t.Errorf("Expected invalid string error. Got: %s", err.Error())
@@ -1648,7 +1643,7 @@ func TestSelfDestruct(t *testing.T) {
 
 	// send call tx with no data, cause self-destruct
 	tx := txs.NewCallTxWithSequence(acc0PubKey, addressPtr(acc1), nil, sendingAmount, 1000, 0, acc0.Sequence()+1)
-	tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+	require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 
 	// we use cache instead of execTxWithState so we can run the tx twice
 	exe := NewBatchCommitter(state, testChainID, bcm.NewBlockchain(nil, testGenesisDoc), event.NewNoOpPublisher(), logger)
@@ -1659,7 +1654,7 @@ func TestSelfDestruct(t *testing.T) {
 	// if we do it again, we won't get an error, but the self-destruct
 	// shouldn't happen twice and the caller should lose fee
 	tx.Input.Sequence += 1
-	tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx)
+	require.NoError(t, tx.Sign(testChainID, privAccounts[0]))
 	if err := exe.Execute(tx); err != nil {
 		t.Errorf("Got error in executing call transaction, %v", err)
 	}
@@ -1681,7 +1676,8 @@ func TestSelfDestruct(t *testing.T) {
 }
 
 func execTxWithStateAndBlockchain(state *State, tip bcm.Tip, tx txs.Tx) error {
-	exe := newExecutor(true, state, testChainID, tip, event.NewNoOpPublisher(), logger)
+	exe := newExecutor("execTxWithStateAndBlockchainCache", true, state, testChainID, tip,
+		event.NewNoOpPublisher(), logger)
 	if err := exe.Execute(tx); err != nil {
 		return err
 	} else {
@@ -1708,7 +1704,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.PrivateAccount) {
+	minBonded int64) (*State, []acm.AddressableSigner) {
 	testGenesisDoc, privAccounts, _ := deterministicGenesis.GenesisDoc(numAccounts, randBalance, minBalance,
 		numValidators, randBonded, minBonded)
 	s0, err := MakeGenesisState(dbm.NewMemDB(), testGenesisDoc)
@@ -1865,7 +1861,7 @@ func permNameToFuncID(name string) []byte {
 	return id[:]
 }
 
-func snativePermTestInputCALL(name string, user acm.PrivateAccount, 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 {
@@ -1888,7 +1884,7 @@ func snativePermTestInputCALL(name string, user acm.PrivateAccount, perm ptypes.
 	return
 }
 
-func snativePermTestInputTx(name string, user acm.PrivateAccount, perm ptypes.PermFlag,
+func snativePermTestInputTx(name string, user acm.AddressableSigner, perm ptypes.PermFlag,
 	val bool) (snativeArgs snatives.PermArgs) {
 
 	switch name {
@@ -1904,7 +1900,7 @@ func snativePermTestInputTx(name string, user acm.PrivateAccount, perm ptypes.Pe
 	return
 }
 
-func snativeRoleTestInputCALL(name string, user acm.PrivateAccount,
+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()
@@ -1918,7 +1914,7 @@ func snativeRoleTestInputCALL(name string, user acm.PrivateAccount,
 	return
 }
 
-func snativeRoleTestInputTx(name string, user acm.PrivateAccount, 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 73fb51df903ab78f9dfaa3cf77375a270c317cdd..7b98a32ab84e92e9c239b8cab17ba04afc791ec7 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 9050949dc451ab537b6ee653e76f80636e659eea..9ffc547760af366f9ae4222592ac5af44c226ed8 100644
--- a/execution/transactor.go
+++ b/execution/transactor.go
@@ -17,10 +17,8 @@ package execution
 import (
 	"context"
 	"fmt"
-	"sync"
-	"time"
-
 	"runtime/debug"
+	"time"
 
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/account/state"
@@ -45,38 +43,20 @@ type Call struct {
 	GasUsed uint64
 }
 
-type Transactor interface {
-	Call(fromAddress, toAddress acm.Address, data []byte) (*Call, error)
-	CallCode(fromAddress acm.Address, code, data []byte) (*Call, error)
-	BroadcastTx(tx txs.Tx) (*txs.Receipt, error)
-	BroadcastTxAsync(tx txs.Tx, callback func(res *abci_types.Response)) error
-	Transact(privKey []byte, address *acm.Address, data []byte, gasLimit, fee uint64) (*txs.Receipt, error)
-	TransactAndHold(privKey []byte, address *acm.Address, data []byte, gasLimit, fee uint64) (*evm_events.EventDataCall, error)
-	Send(privKey []byte, toAddress acm.Address, amount uint64) (*txs.Receipt, error)
-	SendAndHold(privKey []byte, toAddress acm.Address, amount uint64) (*txs.Receipt, error)
-	TransactNameReg(privKey []byte, name, data string, amount, fee uint64) (*txs.Receipt, error)
-	SignTx(tx txs.Tx, privAccounts []acm.PrivateAccount) (txs.Tx, error)
-}
-
 // Transactor is the controller/middleware for the v0 RPC
-type transactor struct {
-	txMtx            sync.Mutex
-	blockchain       blockchain.Blockchain
-	state            state.Iterable
+type Transactor struct {
+	tip              blockchain.Tip
 	eventEmitter     event.Emitter
 	broadcastTxAsync func(tx txs.Tx, callback func(res *abci_types.Response)) error
 	logger           *logging.Logger
 }
 
-var _ Transactor = &transactor{}
-
-func NewTransactor(blockchain blockchain.Blockchain, state state.Iterable, eventEmitter event.Emitter,
+func NewTransactor(tip blockchain.Tip, eventEmitter event.Emitter,
 	broadcastTxAsync func(tx txs.Tx, callback func(res *abci_types.Response)) error,
-	logger *logging.Logger) *transactor {
+	logger *logging.Logger) *Transactor {
 
-	return &transactor{
-		blockchain:       blockchain,
-		state:            state,
+	return &Transactor{
+		tip:              tip,
 		eventEmitter:     eventEmitter,
 		broadcastTxAsync: broadcastTxAsync,
 		logger:           logger.With(structure.ComponentKey, "Transactor"),
@@ -85,14 +65,16 @@ func NewTransactor(blockchain blockchain.Blockchain, state state.Iterable, event
 
 // Run a contract's code on an isolated and unpersisted state
 // Cannot be used to create new contracts
-func (trans *transactor) Call(fromAddress, toAddress acm.Address, data []byte) (call *Call, err error) {
+func (trans *Transactor) Call(reader state.Reader, fromAddress, toAddress acm.Address,
+	data []byte) (call *Call, err error) {
+
 	if evm.RegisteredNativeContract(toAddress.Word256()) {
 		return nil, fmt.Errorf("attempt to call native contract at address "+
 			"%X, but native contracts can not be called directly. Use a deployed "+
 			"contract that calls the native function instead", toAddress)
 	}
 	// This was being run against CheckTx cache, need to understand the reasoning
-	callee, err := state.GetMutableAccount(trans.state, toAddress)
+	callee, err := state.GetMutableAccount(reader, toAddress)
 	if err != nil {
 		return nil, err
 	}
@@ -100,8 +82,8 @@ 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 := state.NewCache(trans.state)
-	params := vmParams(trans.blockchain)
+	txCache := state.NewCache(reader)
+	params := vmParams(trans.tip)
 
 	vmach := evm.NewVM(txCache, params, caller.Address(), nil, trans.logger.WithScope("Call"))
 	vmach.SetPublisher(trans.eventEmitter)
@@ -122,12 +104,12 @@ func (trans *transactor) Call(fromAddress, toAddress acm.Address, data []byte) (
 
 // Run the given code on an isolated and unpersisted state
 // Cannot be used to create new contracts.
-func (trans *transactor) CallCode(fromAddress acm.Address, code, data []byte) (*Call, error) {
+func (trans *Transactor) CallCode(reader state.Reader, fromAddress acm.Address, code, data []byte) (*Call, error) {
 	// 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 := state.NewCache(trans.state)
-	params := vmParams(trans.blockchain)
+	txCache := state.NewCache(reader)
+	params := vmParams(trans.tip)
 
 	vmach := evm.NewVM(txCache, params, caller.Address(), nil, trans.logger.WithScope("CallCode"))
 	gas := params.GasLimit
@@ -139,14 +121,15 @@ func (trans *transactor) CallCode(fromAddress acm.Address, code, data []byte) (*
 	return &Call{Return: ret, GasUsed: gasUsed}, nil
 }
 
-func (trans *transactor) BroadcastTxAsync(tx txs.Tx, callback func(res *abci_types.Response)) error {
+func (trans *Transactor) BroadcastTxAsync(tx txs.Tx, callback func(res *abci_types.Response)) error {
 	return trans.broadcastTxAsync(tx, callback)
 }
 
-// Broadcast a transaction.
-func (trans *transactor) BroadcastTx(tx txs.Tx) (*txs.Receipt, error) {
+// Broadcast a transaction and waits for a response from the mempool. Transactions to BroadcastTx will block during
+// various mempool operations (managed by Tendermint) including mempool Reap, Commit, and recheckTx.
+func (trans *Transactor) BroadcastTx(tx txs.Tx) (*txs.Receipt, error) {
 	trans.logger.Trace.Log("method", "BroadcastTx",
-		"tx_hash", tx.Hash(trans.blockchain.ChainID()),
+		"tx_hash", tx.Hash(trans.tip.ChainID()),
 		"tx", tx.String())
 	responseCh := make(chan *abci_types.Response, 1)
 	err := trans.BroadcastTxAsync(tx, func(res *abci_types.Response) {
@@ -177,43 +160,24 @@ 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) Transact(privKey []byte, address *acm.Address, data []byte, gasLimit,
-	fee uint64) (*txs.Receipt, error) {
-
-	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()
-	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())
+func (trans *Transactor) Transact(sequentialSigningAccount *SequentialSigningAccount, address *acm.Address, data []byte,
+	gasLimit, fee uint64) (*txs.Receipt, error) {
+	// Note we rely on back pressure from BroadcastTx when serialising access to from a particular input account while
+	// the mempool rechecks (and so the checker, having just be reset does not yet have the latest sequence numbers
+	// for some accounts). BroadcastTx will block when the mempool is rechecking or during a commit so provided
+	// subsequent Transacts from the same input account block on those ahead of it we are able to stream transactions
+	// continuously with sequential sequence numbers. By taking this lock we ensure this.
+	inputAccount, unlock, err := sequentialSigningAccount.Lock()
 	if err != nil {
 		return nil, err
 	}
-	sequence := uint64(1)
-	if acc != nil {
-		sequence = acc.Sequence() + uint64(1)
-	}
-	// 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.
+	defer unlock()
+
 	txInput := &txs.TxInput{
-		Address:   pa.Address(),
+		Address:   inputAccount.Address(),
 		Amount:    fee,
-		Sequence:  sequence,
-		PublicKey: pa.PublicKey(),
+		Sequence:  inputAccount.Sequence() + 1,
+		PublicKey: inputAccount.PublicKey(),
 	}
 	tx := &txs.CallTx{
 		Input:    txInput,
@@ -224,17 +188,17 @@ func (trans *transactor) Transact(privKey []byte, address *acm.Address, data []b
 	}
 
 	// Got ourselves a tx.
-	txS, errS := trans.SignTx(tx, []acm.PrivateAccount{pa})
-	if errS != nil {
-		return nil, errS
+	err = tx.Sign(trans.tip.ChainID(), inputAccount)
+	if err != nil {
+		return nil, err
 	}
-	return trans.BroadcastTx(txS)
+	return trans.BroadcastTx(tx)
 }
 
-func (trans *transactor) TransactAndHold(privKey []byte, address *acm.Address, data []byte, gasLimit,
+func (trans *Transactor) TransactAndHold(sequentialSigningAccount *SequentialSigningAccount, address *acm.Address, data []byte, gasLimit,
 	fee uint64) (*evm_events.EventDataCall, error) {
 
-	receipt, err := trans.Transact(privKey, address, data, gasLimit, fee)
+	receipt, err := trans.Transact(sequentialSigningAccount, address, data, gasLimit, fee)
 	if err != nil {
 		return nil, err
 	}
@@ -249,7 +213,7 @@ func (trans *transactor) TransactAndHold(privKey []byte, address *acm.Address, d
 	}
 
 	err = evm_events.SubscribeAccountCall(context.Background(), trans.eventEmitter, subID, receipt.ContractAddress,
-		receipt.TxHash, wc)
+		receipt.TxHash, 0, wc)
 	if err != nil {
 		return nil, err
 	}
@@ -271,55 +235,33 @@ func (trans *transactor) TransactAndHold(privKey []byte, address *acm.Address, d
 	}
 }
 
-func (trans *transactor) Send(privKey []byte, toAddress acm.Address, amount uint64) (*txs.Receipt, error) {
-	if len(privKey) != 64 {
-		return nil, fmt.Errorf("Private key is not of the right length: %d\n",
-			len(privKey))
-	}
+func (trans *Transactor) Send(sequentialSigningAccount *SequentialSigningAccount, toAddress acm.Address, amount uint64) (*txs.Receipt, error) {
+	tx := txs.NewSendTx()
 
-	pk := &[64]byte{}
-	copy(pk[:], privKey)
-	trans.txMtx.Lock()
-	defer trans.txMtx.Unlock()
-	pa, err := acm.GeneratePrivateAccountFromPrivateKeyBytes(privKey)
-	if err != nil {
-		return nil, err
-	}
-	cache := trans.state
-	acc, err := cache.GetAccount(pa.Address())
+	inputAccount, unlock, err := sequentialSigningAccount.Lock()
 	if err != nil {
 		return nil, err
 	}
-	sequence := uint64(1)
-	if acc != nil {
-		sequence = acc.Sequence() + uint64(1)
-	}
-
-	tx := txs.NewSendTx()
-
+	defer unlock()
 	txInput := &txs.TxInput{
-		Address:   pa.Address(),
+		Address:   inputAccount.Address(),
 		Amount:    amount,
-		Sequence:  sequence,
-		PublicKey: pa.PublicKey(),
+		Sequence:  inputAccount.Sequence() + 1,
+		PublicKey: inputAccount.PublicKey(),
 	}
-
 	tx.Inputs = append(tx.Inputs, txInput)
-
 	txOutput := &txs.TxOutput{Address: toAddress, Amount: amount}
-
 	tx.Outputs = append(tx.Outputs, txOutput)
 
-	// Got ourselves a tx.
-	txS, errS := trans.SignTx(tx, []acm.PrivateAccount{pa})
-	if errS != nil {
-		return nil, errS
+	err = tx.Sign(trans.tip.ChainID(), inputAccount)
+	if err != nil {
+		return nil, err
 	}
-	return trans.BroadcastTx(txS)
+	return trans.BroadcastTx(tx)
 }
 
-func (trans *transactor) SendAndHold(privKey []byte, toAddress acm.Address, amount uint64) (*txs.Receipt, error) {
-	receipt, err := trans.Send(privKey, toAddress, amount)
+func (trans *Transactor) SendAndHold(sequentialSigningAccount *SequentialSigningAccount, toAddress acm.Address, amount uint64) (*txs.Receipt, error) {
+	receipt, err := trans.Send(sequentialSigningAccount, toAddress, amount)
 	if err != nil {
 		return nil, err
 	}
@@ -341,17 +283,12 @@ func (trans *transactor) SendAndHold(privKey []byte, toAddress acm.Address, amou
 	timer := time.NewTimer(BlockingTimeoutSeconds * time.Second)
 	defer timer.Stop()
 
-	pa, err := acm.GeneratePrivateAccountFromPrivateKeyBytes(privKey)
-	if err != nil {
-		return nil, err
-	}
-
 	select {
 	case <-timer.C:
 		return nil, fmt.Errorf("transaction timed out TxHash: %X", receipt.TxHash)
 	case sendTx := <-wc:
 		// This is a double check - we subscribed to this tx's hash so something has gone wrong if the amounts don't match
-		if sendTx.Inputs[0].Address == pa.Address() && sendTx.Inputs[0].Amount == amount {
+		if sendTx.Inputs[0].Amount == amount {
 			return receipt, nil
 		}
 		return nil, fmt.Errorf("received SendTx but hash doesn't seem to match what we subscribed to, "+
@@ -359,83 +296,34 @@ func (trans *transactor) SendAndHold(privKey []byte, toAddress acm.Address, amou
 	}
 }
 
-func (trans *transactor) TransactNameReg(privKey []byte, name, data string, amount, fee uint64) (*txs.Receipt, error) {
+func (trans *Transactor) TransactNameReg(sequentialSigningAccount *SequentialSigningAccount, name, data string, amount,
+	fee uint64) (*txs.Receipt, error) {
 
-	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()
-	pa, err := acm.GeneratePrivateAccountFromPrivateKeyBytes(privKey)
+	inputAccount, unlock, err := sequentialSigningAccount.Lock()
 	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())
+	defer unlock()
+	// Formulate and sign
+	tx := txs.NewNameTxWithSequence(inputAccount.PublicKey(), name, data, amount, fee, inputAccount.Sequence()+1)
+	err = tx.Sign(trans.tip.ChainID(), inputAccount)
 	if err != nil {
 		return nil, err
 	}
-	sequence := uint64(1)
-	if acc == nil {
-		sequence = acc.Sequence() + uint64(1)
-	}
-	tx := txs.NewNameTxWithSequence(pa.PublicKey(), name, data, amount, fee, sequence)
-	// Got ourselves a tx.
-	txS, errS := trans.SignTx(tx, []acm.PrivateAccount{pa})
-	if errS != nil {
-		return nil, errS
-	}
-	return trans.BroadcastTx(txS)
+	return trans.BroadcastTx(tx)
 }
 
 // Sign a transaction
-func (trans *transactor) SignTx(tx txs.Tx, privAccounts []acm.PrivateAccount) (txs.Tx, error) {
+func (trans *Transactor) SignTx(tx txs.Tx, signingAccounts []acm.AddressableSigner) (txs.Tx, error) {
 	// more checks?
-
-	for i, privAccount := range privAccounts {
-		if privAccount == nil || privAccount.PrivateKey().Unwrap() == nil {
-			return nil, fmt.Errorf("invalid (empty) privAccount @%v", i)
-		}
-	}
-	chainID := trans.blockchain.ChainID()
-	switch tx.(type) {
-	case *txs.NameTx:
-		nameTx := tx.(*txs.NameTx)
-		nameTx.Input.PublicKey = privAccounts[0].PublicKey()
-		nameTx.Input.Signature = acm.ChainSign(privAccounts[0], chainID, nameTx)
-	case *txs.SendTx:
-		sendTx := tx.(*txs.SendTx)
-		for i, input := range sendTx.Inputs {
-			input.PublicKey = privAccounts[i].PublicKey()
-			input.Signature = acm.ChainSign(privAccounts[i], chainID, sendTx)
-		}
-	case *txs.CallTx:
-		callTx := tx.(*txs.CallTx)
-		callTx.Input.PublicKey = privAccounts[0].PublicKey()
-		callTx.Input.Signature = acm.ChainSign(privAccounts[0], chainID, callTx)
-	case *txs.BondTx:
-		bondTx := tx.(*txs.BondTx)
-		// the first privaccount corresponds to the BondTx pub key.
-		// the rest to the inputs
-		bondTx.Signature = acm.ChainSign(privAccounts[0], chainID, bondTx)
-		for i, input := range bondTx.Inputs {
-			input.PublicKey = privAccounts[i+1].PublicKey()
-			input.Signature = acm.ChainSign(privAccounts[i+1], chainID, bondTx)
-		}
-	case *txs.UnbondTx:
-		unbondTx := tx.(*txs.UnbondTx)
-		unbondTx.Signature = acm.ChainSign(privAccounts[0], chainID, unbondTx)
-	case *txs.RebondTx:
-		rebondTx := tx.(*txs.RebondTx)
-		rebondTx.Signature = acm.ChainSign(privAccounts[0], chainID, rebondTx)
-	default:
-		return nil, fmt.Errorf("Object is not a proper transaction: %v\n", tx)
+	err := tx.Sign(trans.tip.ChainID(), signingAccounts...)
+	if err != nil {
+		return nil, err
 	}
 	return tx, nil
 }
 
-func vmParams(blockchain blockchain.Blockchain) evm.Params {
-	tip := blockchain.Tip()
+func vmParams(tip blockchain.Tip) evm.Params {
 	return evm.Params{
 		BlockHeight: tip.LastBlockHeight(),
 		BlockHash:   binary.LeftPadWord256(tip.LastBlockHash()),
diff --git a/execution/transactor_test.go b/execution/transactor_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5f0689a513feb04731cc9170b01ebf6a928b7c66
--- /dev/null
+++ b/execution/transactor_test.go
@@ -0,0 +1,46 @@
+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),
+		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,
+	}
+}
+
+func TestTransactor_Transact(t *testing.T) {
+	//trans := newTestTransactor()
+}
diff --git a/genesis/deterministic_genesis.go b/genesis/deterministic_genesis.go
index 402a588bdc2afb617404b82469b46c159f3d820a..de80e258883a9598a7ab32ce5310952d6d9ad95b 100644
--- a/genesis/deterministic_genesis.go
+++ b/genesis/deterministic_genesis.go
@@ -21,10 +21,10 @@ func NewDeterministicGenesis(seed int64) *deterministicGenesis {
 }
 
 func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, minBalance uint64, numValidators int,
-	randBonded bool, minBonded int64) (*GenesisDoc, []acm.PrivateAccount, []acm.PrivateAccount) {
+	randBonded bool, minBonded int64) (*GenesisDoc, []acm.AddressableSigner, []acm.AddressableSigner) {
 
 	accounts := make([]Account, numAccounts)
-	privAccounts := make([]acm.PrivateAccount, numAccounts)
+	privAccounts := make([]acm.AddressableSigner, numAccounts)
 	defaultPerms := permission.DefaultAccountPermissions
 	for i := 0; i < numAccounts; i++ {
 		account, privAccount := dg.Account(randBalance, minBalance)
@@ -38,7 +38,7 @@ func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, mi
 		privAccounts[i] = privAccount
 	}
 	validators := make([]Validator, numValidators)
-	privValidators := make([]acm.PrivateAccount, numValidators)
+	privValidators := make([]acm.AddressableSigner, numValidators)
 	for i := 0; i < numValidators; i++ {
 		validator := acm.GeneratePrivateAccountFromSecret(fmt.Sprintf("val_%v", i))
 		privValidators[i] = validator
@@ -65,7 +65,7 @@ func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, mi
 
 }
 
-func (dg *deterministicGenesis) Account(randBalance bool, minBalance uint64) (acm.Account, acm.PrivateAccount) {
+func (dg *deterministicGenesis) Account(randBalance bool, minBalance uint64) (acm.Account, acm.AddressableSigner) {
 	privateKey, err := acm.GeneratePrivateKey(dg.random)
 	if err != nil {
 		panic(fmt.Errorf("could not generate private key deterministically"))
diff --git a/keys/mock/key_client_mock.go b/keys/mock/key_client_mock.go
index 2254c1105c7577c8dfef4e3f98068ce841c03e5a..96a614cac83ebe8367a84e76fad91563a1198375 100644
--- a/keys/mock/key_client_mock.go
+++ b/keys/mock/key_client_mock.go
@@ -59,6 +59,19 @@ func newMockKey() (*MockKey, error) {
 	return key, nil
 }
 
+func mockKeyFromPrivateAccount(privateAccount acm.PrivateAccount) *MockKey {
+	_, ok := privateAccount.PrivateKey().Unwrap().(crypto.PrivKeyEd25519)
+	if !ok {
+		panic(fmt.Errorf("mock key client only supports ed25519 private keys at present"))
+	}
+	key := &MockKey{
+		Address:   privateAccount.Address(),
+		PublicKey: privateAccount.PublicKey().RawBytes(),
+	}
+	copy(key.PrivateKey[:], privateAccount.PrivateKey().RawBytes())
+	return key
+}
+
 func (mockKey *MockKey) Sign(message []byte) (acm.Signature, error) {
 	return acm.SignatureFromBytes(ed25519.Sign(&mockKey.PrivateKey, message)[:])
 }
@@ -73,10 +86,14 @@ type MockKeyClient struct {
 	knownKeys map[acm.Address]*MockKey
 }
 
-func NewMockKeyClient() *MockKeyClient {
-	return &MockKeyClient{
+func NewMockKeyClient(privateAccounts ...acm.PrivateAccount) *MockKeyClient {
+	client := &MockKeyClient{
 		knownKeys: make(map[acm.Address]*MockKey),
 	}
+	for _, pa := range privateAccounts {
+		client.knownKeys[pa.Address()] = mockKeyFromPrivateAccount(pa)
+	}
+	return client
 }
 
 func (mock *MockKeyClient) NewKey() acm.Address {
diff --git a/logging/config/config.go b/logging/config/config.go
index dca01d2ed6049399c11a7f1d251c9a71afa874e8..8616aeb7ac0aec1a18098c127f9bc6daf343d8af 100644
--- a/logging/config/config.go
+++ b/logging/config/config.go
@@ -15,6 +15,7 @@ import (
 type LoggingConfig struct {
 	RootSink     *SinkConfig `toml:",omitempty"`
 	ExcludeTrace bool
+	NonBlocking  bool
 }
 
 // For encoding a top-level '[logging]' TOML table
diff --git a/logging/lifecycle/lifecycle.go b/logging/lifecycle/lifecycle.go
index d130904c2e5b9f2bf3d21aaadd1edda29409eadb..f17622e694153483e4cccd99aa686687cb430982 100644
--- a/logging/lifecycle/lifecycle.go
+++ b/logging/lifecycle/lifecycle.go
@@ -38,64 +38,56 @@ import (
 
 // Obtain a logger from a LoggingConfig
 func NewLoggerFromLoggingConfig(loggingConfig *config.LoggingConfig) (*logging.Logger, error) {
-	var logger *logging.Logger
-	var errCh channels.Channel
-	var err error
 	if loggingConfig == nil {
-		logger, errCh, err = NewStdErrLogger()
-		if err != nil {
-			return nil, err
-		}
+		return NewStdErrLogger()
 	} else {
-		outputLogger, err := loggerFromLoggingConfig(loggingConfig)
+		outputLogger, errCh, err := loggerFromLoggingConfig(loggingConfig)
 		if err != nil {
 			return nil, err
 		}
-		logger, errCh = NewLogger(outputLogger)
+		logger := NewLogger(outputLogger)
 		if loggingConfig.ExcludeTrace {
 			logger.Trace = kitlog.NewNopLogger()
 		}
+		go func() {
+			err := <-errCh.Out()
+			if err != nil {
+				fmt.Printf("Logging error: %v", err)
+			}
+		}()
+		return logger, nil
 	}
-	go func() {
-		err := <-errCh.Out()
-		if err != nil {
-			fmt.Printf("Logging error: %v", err)
-		}
-	}()
-
-	return logger, nil
 }
 
 // Hot swap logging config by replacing output loggers of passed InfoTraceLogger
 // with those built from loggingConfig
-func SwapOutputLoggersFromLoggingConfig(logger *logging.Logger, loggingConfig *config.LoggingConfig) error {
-	outputLogger, err := loggerFromLoggingConfig(loggingConfig)
+func SwapOutputLoggersFromLoggingConfig(logger *logging.Logger, loggingConfig *config.LoggingConfig) (error, channels.Channel) {
+	outputLogger, errCh, err := loggerFromLoggingConfig(loggingConfig)
 	if err != nil {
-		return err
+		return err, channels.NewDeadChannel()
 	}
 	logger.SwapOutput(outputLogger)
-	return nil
+	return nil, errCh
 }
 
-func NewStdErrLogger() (*logging.Logger, channels.Channel, error) {
+func NewStdErrLogger() (*logging.Logger, error) {
 	outputLogger, err := loggers.NewStreamLogger(os.Stderr, loggers.TerminalFormat)
 	if err != nil {
-		return nil, nil, err
+		return nil, err
 	}
-	logger, errCh := NewLogger(outputLogger)
-	return logger, errCh, nil
+	return NewLogger(outputLogger), nil
 }
 
 // Provided a standard logger that outputs to the supplied underlying outputLogger
-func NewLogger(outputLogger kitlog.Logger) (*logging.Logger, channels.Channel) {
-	logger, errCh := logging.NewLogger(outputLogger)
+func NewLogger(outputLogger kitlog.Logger) *logging.Logger {
+	logger := logging.NewLogger(outputLogger)
 	// Create a random ID based on start time
 	uuid, _ := simpleuuid.NewTime(time.Now())
 	var runId string
 	if uuid != nil {
 		runId = uuid.String()
 	}
-	return logger.With(structure.RunId, runId), errCh
+	return logger.With(structure.RunId, runId)
 }
 
 func JustLogger(logger *logging.Logger, _ channels.Channel) *logging.Logger {
@@ -103,15 +95,19 @@ func JustLogger(logger *logging.Logger, _ channels.Channel) *logging.Logger {
 }
 
 func CaptureStdlibLogOutput(infoTraceLogger *logging.Logger) {
-	stdlib.CaptureRootLogger(infoTraceLogger.
-		With(structure.CapturedLoggingSourceKey, "stdlib_log"))
+	stdlib.CaptureRootLogger(infoTraceLogger.With(structure.CapturedLoggingSourceKey, "stdlib_log"))
 }
 
 // Helpers
-func loggerFromLoggingConfig(loggingConfig *config.LoggingConfig) (kitlog.Logger, error) {
+func loggerFromLoggingConfig(loggingConfig *config.LoggingConfig) (kitlog.Logger, channels.Channel, error) {
 	outputLogger, _, err := loggingConfig.RootSink.BuildLogger()
 	if err != nil {
-		return nil, err
+		return nil, nil, err
+	}
+	var errCh channels.Channel = channels.NewDeadChannel()
+	var logger kitlog.Logger = loggers.BurrowFormatLogger(outputLogger)
+	if loggingConfig.NonBlocking {
+		logger, errCh = loggers.NonBlockingLogger(logger)
 	}
-	return outputLogger, nil
+	return logger, errCh, err
 }
diff --git a/logging/logger.go b/logging/logger.go
index 51346c4f18d34ebd7c60603ee562afbf724c2509..3382293b9e1dc2c2dba8c2e022bdb635df6bd414 100644
--- a/logging/logger.go
+++ b/logging/logger.go
@@ -15,9 +15,7 @@
 package logging
 
 import (
-	"github.com/eapache/channels"
 	kitlog "github.com/go-kit/kit/log"
-	"github.com/hyperledger/burrow/logging/loggers"
 	"github.com/hyperledger/burrow/logging/structure"
 )
 
@@ -43,22 +41,21 @@ type Logger struct {
 }
 
 // Create an InfoTraceLogger by passing the initial outputLogger.
-func NewLogger(outputLogger kitlog.Logger) (*Logger, channels.Channel) {
+func NewLogger(outputLogger kitlog.Logger) *Logger {
 	// We will never halt the progress of a log emitter. If log output takes too
 	// long will start dropping log lines by using a ring buffer.
 	swapLogger := new(kitlog.SwapLogger)
 	swapLogger.Swap(outputLogger)
-	wrappedOutputLogger, errCh := wrapOutputLogger(swapLogger)
 	return &Logger{
 		Output: swapLogger,
 		// logging contexts
-		Info: kitlog.With(wrappedOutputLogger,
+		Info: kitlog.With(swapLogger,
 			structure.ChannelKey, structure.InfoChannelName,
 		),
-		Trace: kitlog.With(wrappedOutputLogger,
+		Trace: kitlog.With(swapLogger,
 			structure.ChannelKey, structure.TraceChannelName,
 		),
-	}, errCh
+	}
 }
 
 func NewNoopLogger() *Logger {
@@ -140,10 +137,3 @@ func Msg(logger kitlog.Logger, message string, keyvals ...interface{}) error {
 	prepended := structure.CopyPrepend(keyvals, structure.MessageKey, message)
 	return logger.Log(prepended...)
 }
-
-// Wrap the output loggers with a a set of standard transforms, a non-blocking
-// ChannelLogger and an outer context
-func wrapOutputLogger(outputLogger kitlog.Logger) (kitlog.Logger, channels.Channel) {
-	//return loggers.NonBlockingLogger(loggers.BurrowFormatLogger(outputLogger))
-	return loggers.BurrowFormatLogger(outputLogger), channels.NewDeadChannel()
-}
diff --git a/logging/logger_test.go b/logging/logger_test.go
index 05c0858c1764171c1776ca9be766e5aed6ab3c7f..0829fb39c389e9f15c8d64dfda160b68f230d0f4 100644
--- a/logging/logger_test.go
+++ b/logging/logger_test.go
@@ -23,7 +23,7 @@ import (
 
 func TestLogger(t *testing.T) {
 	stderrLogger := kitlog.NewLogfmtLogger(os.Stderr)
-	logger, _ := NewLogger(stderrLogger)
+	logger := NewLogger(stderrLogger)
 	logger.Trace.Log("hello", "barry")
 }
 
diff --git a/rpc/jsonrpc.go b/rpc/jsonrpc.go
index 17b683beb81c67d4d9778ab15153fd9e36f6dfb8..b9b52e910f3070e00472b3b3b35876a638cdcb4d 100644
--- a/rpc/jsonrpc.go
+++ b/rpc/jsonrpc.go
@@ -16,6 +16,7 @@ package rpc
 
 import (
 	"encoding/json"
+	"fmt"
 )
 
 // JSON-RPC 2.0 error codes.
@@ -66,6 +67,10 @@ type (
 	}
 )
 
+func (err RPCError) Error() string {
+	return fmt.Sprintf("Error %v: %s", err.Code, err.Message)
+}
+
 // Create a new RPC request. This is the generic struct that is passed to RPC
 // methods
 func NewRPCRequest(id string, method string, params json.RawMessage) *RPCRequest {
diff --git a/rpc/service.go b/rpc/service.go
index 13d698346c30f135f78793536539b3263cff6eb9..28965eded7324281a5e136bab5933392d36f073e 100644
--- a/rpc/service.go
+++ b/rpc/service.go
@@ -18,6 +18,8 @@ import (
 	"context"
 	"fmt"
 
+	"sync"
+
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/account/state"
 	"github.com/hyperledger/burrow/binary"
@@ -25,6 +27,7 @@ import (
 	"github.com/hyperledger/burrow/consensus/tendermint/query"
 	"github.com/hyperledger/burrow/event"
 	"github.com/hyperledger/burrow/execution"
+	"github.com/hyperledger/burrow/keys"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
 	"github.com/hyperledger/burrow/permission"
@@ -36,33 +39,39 @@ import (
 
 // Magic! Should probably be configurable, but not shouldn't be so huge we
 // end up DoSing ourselves.
-const MaxBlockLookback = 100
+const MaxBlockLookback = 1000
+const AccountsRingMutexCount = 100
 
 // Base service that provides implementation for all underlying RPC methods
 type Service struct {
-	ctx          context.Context
-	iterable     state.Iterable
-	subscribable event.Subscribable
-	nameReg      execution.NameRegIterable
-	blockchain   bcm.Blockchain
-	transactor   execution.Transactor
-	nodeView     query.NodeView
-	logger       *logging.Logger
+	ctx             context.Context
+	committedState  state.Iterable
+	commitLocker    sync.Locker
+	nameReg         execution.NameRegIterable
+	accounts        *execution.Accounts
+	mempoolAccounts *execution.Accounts
+	subscribable    event.Subscribable
+	blockchain      bcm.Blockchain
+	transactor      *execution.Transactor
+	nodeView        query.NodeView
+	logger          *logging.Logger
 }
 
-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 {
+func NewService(ctx context.Context, committedState state.Iterable, nameReg execution.NameRegIterable,
+	checker state.Reader, committer execution.BatchCommitter, subscribable event.Subscribable, blockchain bcm.Blockchain,
+	keyClient keys.KeyClient, transactor *execution.Transactor, nodeView query.NodeView, logger *logging.Logger) *Service {
 
 	return &Service{
-		ctx:          ctx,
-		iterable:     iterable,
-		nameReg:      nameReg,
-		subscribable: subscribable,
-		blockchain:   blockchain,
-		transactor:   transactor,
-		nodeView:     nodeView,
-		logger:       logger.With(structure.ComponentKey, "Service"),
+		ctx:             ctx,
+		committedState:  committedState,
+		accounts:        execution.NewAccounts(committedState, keyClient, AccountsRingMutexCount),
+		mempoolAccounts: execution.NewAccounts(checker, keyClient, AccountsRingMutexCount),
+		nameReg:         nameReg,
+		subscribable:    subscribable,
+		blockchain:      blockchain,
+		transactor:      transactor,
+		nodeView:        nodeView,
+		logger:          logger.With(structure.ComponentKey, "Service"),
 	}
 }
 
@@ -75,12 +84,33 @@ func NewSubscribableService(subscribable event.Subscribable, logger *logging.Log
 	}
 }
 
-// Transacting...
-
-func (s *Service) Transactor() execution.Transactor {
+// Get a Transactor providing methods for delegating signing and the core BroadcastTx function for publishing
+// transactions to the network
+func (s *Service) Transactor() *execution.Transactor {
 	return s.transactor
 }
 
+// By providing certain methods on the Transactor (such as Transact, Send, etc) with the (non-final) MempoolAccounts
+// rather than the committed (final) Accounts state the transactor can assign a sequence number based on all of the txs
+// it has seen since the last block - provided these transactions are successfully committed (via DeliverTx) then
+// subsequent transactions will have valid sequence numbers. This allows Burrow to coordinate sequencing and signing
+// for a key it holds or is provided - it is down to the key-holder to manage the mutual information between transactions
+// concurrent within a new block window.
+
+// Get the latest committed account state and signing accounts
+func (s *Service) Accounts() *execution.Accounts {
+	return s.accounts
+}
+
+// Get pending account state residing in the mempool
+func (s *Service) MempoolAccounts() *execution.Accounts {
+	return s.mempoolAccounts
+}
+
+func (s *Service) CommitLocker() sync.Locker {
+	return s.commitLocker
+}
+
 func (s *Service) ListUnconfirmedTxs(maxTxs int) (*ResultListUnconfirmedTxs, error) {
 	// Get all transactions for now
 	transactions, err := s.nodeView.MempoolTransactions(maxTxs)
@@ -180,7 +210,7 @@ func (s *Service) Peers() (*ResultPeers, error) {
 
 func (s *Service) NetInfo() (*ResultNetInfo, error) {
 	listening := s.nodeView.IsListening()
-	listeners := []string{}
+	var listeners []string
 	for _, listener := range s.nodeView.Listeners() {
 		listeners = append(listeners, listener.String())
 	}
@@ -203,7 +233,7 @@ func (s *Service) Genesis() (*ResultGenesis, error) {
 
 // Accounts
 func (s *Service) GetAccount(address acm.Address) (*ResultGetAccount, error) {
-	acc, err := s.iterable.GetAccount(address)
+	acc, err := s.accounts.GetAccount(address)
 	if err != nil {
 		return nil, err
 	}
@@ -215,7 +245,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.iterable.IterateAccounts(func(account acm.Account) (stop bool) {
+	s.committedState.IterateAccounts(func(account acm.Account) (stop bool) {
 		if predicate(account) {
 			accounts = append(accounts, acm.AsConcreteAccount(account))
 		}
@@ -229,7 +259,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.iterable.GetAccount(address)
+	account, err := s.accounts.GetAccount(address)
 	if err != nil {
 		return nil, err
 	}
@@ -237,7 +267,7 @@ func (s *Service) GetStorage(address acm.Address, key []byte) (*ResultGetStorage
 		return nil, fmt.Errorf("UnknownAddress: %s", address)
 	}
 
-	value, err := s.iterable.GetStorage(address, binary.LeftPadWord256(key))
+	value, err := s.accounts.GetStorage(address, binary.LeftPadWord256(key))
 	if err != nil {
 		return nil, err
 	}
@@ -248,7 +278,7 @@ func (s *Service) GetStorage(address acm.Address, key []byte) (*ResultGetStorage
 }
 
 func (s *Service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) {
-	account, err := s.iterable.GetAccount(address)
+	account, err := s.accounts.GetAccount(address)
 	if err != nil {
 		return nil, err
 	}
@@ -256,7 +286,7 @@ func (s *Service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) {
 		return nil, fmt.Errorf("UnknownAddress: %X", address)
 	}
 	var storageItems []StorageItem
-	s.iterable.IterateStorage(address, func(key, value binary.Word256) (stop bool) {
+	s.committedState.IterateStorage(address, func(key, value binary.Word256) (stop bool) {
 		storageItems = append(storageItems, StorageItem{Key: key.UnpadLeft(), Value: value.UnpadLeft()})
 		return
 	})
@@ -267,7 +297,7 @@ func (s *Service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) {
 }
 
 func (s *Service) GetAccountHumanReadable(address acm.Address) (*ResultGetAccountHumanReadable, error) {
-	acc, err := s.iterable.GetAccount(address)
+	acc, err := s.accounts.GetAccount(address)
 	if err != nil {
 		return nil, err
 	}
diff --git a/rpc/tm/integration/client_test.go b/rpc/tm/integration/client_test.go
index a827524f9de0ac13e438dd2f8d76ad002fda442f..268953bc695c506ca61d9f8357dd99aaaee820ef 100644
--- a/rpc/tm/integration/client_test.go
+++ b/rpc/tm/integration/client_test.go
@@ -59,14 +59,15 @@ func TestBroadcastTx(t *testing.T) {
 		require.NoError(t, err)
 		assert.False(t, receipt.CreatesContract, "This tx should not create a contract")
 		assert.NotEmpty(t, receipt.TxHash, "Failed to compute tx hash")
-		n, errp := new(int), new(error)
-		buf := new(bytes.Buffer)
+
+		buf, n, errp := new(bytes.Buffer), new(int), new(error)
 		hasher := ripemd160.New()
 		tx.WriteSignBytes(genesisDoc.ChainID(), buf, n, errp)
 		assert.NoError(t, *errp)
 		txSignBytes := buf.Bytes()
 		hasher.Write(txSignBytes)
 		txHashExpected := hasher.Sum(nil)
+
 		if bytes.Compare(receipt.TxHash, txHashExpected) != 0 {
 			t.Fatalf("The receipt hash '%x' does not equal the ripemd160 hash of the "+
 				"transaction signed bytes calculated in the test: '%x'",
diff --git a/rpc/tm/integration/shared_test.go b/rpc/tm/integration/main_test.go
similarity index 82%
rename from rpc/tm/integration/shared_test.go
rename to rpc/tm/integration/main_test.go
index 9e8f1d17d1dc0d498b145a7dbe9767c6549eb643..9833d45c9668313b8104da27c639286373b376d0 100644
--- a/rpc/tm/integration/shared_test.go
+++ b/rpc/tm/integration/main_test.go
@@ -21,11 +21,14 @@ import (
 	"os"
 	"testing"
 	"time"
+
+	"github.com/hyperledger/burrow/core"
+	"github.com/hyperledger/burrow/core/integration"
 )
 
 // Needs to be in a _test.go file to be picked up
 func TestMain(m *testing.M) {
-	returnValue := TestWrapper(func() int {
+	returnValue := integration.TestWrapper(privateAccounts, genesisDoc, func(*core.Kernel) int {
 		return m.Run()
 	})
 
diff --git a/rpc/tm/integration/shared.go b/rpc/tm/integration/shared.go
index 2849634c4418dd5e1219ca256fe8c7ac93bbc037..e9c1981f3554daaf5af1d065ac41d3db7b53ae62 100644
--- a/rpc/tm/integration/shared.go
+++ b/rpc/tm/integration/shared.go
@@ -19,139 +19,38 @@ package integration
 
 import (
 	"bytes"
-	"context"
-	"fmt"
 	"hash/fnv"
-	"strconv"
 	"testing"
 
-	"os"
-
-	"time"
-
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/binary"
-	"github.com/hyperledger/burrow/consensus/tendermint/validator"
-	"github.com/hyperledger/burrow/core"
+	"github.com/hyperledger/burrow/core/integration"
 	"github.com/hyperledger/burrow/execution"
-	"github.com/hyperledger/burrow/genesis"
-	"github.com/hyperledger/burrow/logging"
-	"github.com/hyperledger/burrow/logging/config"
-	"github.com/hyperledger/burrow/logging/lifecycle"
-	"github.com/hyperledger/burrow/permission"
 	"github.com/hyperledger/burrow/rpc"
 	tm_client "github.com/hyperledger/burrow/rpc/tm/client"
 	"github.com/hyperledger/burrow/txs"
 	"github.com/stretchr/testify/require"
-	tm_config "github.com/tendermint/tendermint/config"
 	"github.com/tendermint/tendermint/rpc/lib/client"
 )
 
 const (
-	chainName         = "RPC_Test_Chain"
 	rpcAddr           = "0.0.0.0:46657"
 	websocketAddr     = rpcAddr
 	websocketEndpoint = "/websocket"
-	testDir           = "./test_scratch/tm_test"
 )
 
-// Enable logger output during tests
-var debugLogging = true
-
 // global variables for use across all tests
 var (
-	privateAccounts = makePrivateAccounts(5) // make keys
+	privateAccounts = integration.MakePrivateAccounts(5) // make keys
 	jsonRpcClient   = rpcclient.NewJSONRPCClient(rpcAddr)
 	httpClient      = rpcclient.NewURIClient(rpcAddr)
 	clients         = map[string]tm_client.RPCClient{
 		"JSONRPC": jsonRpcClient,
 		"HTTP":    httpClient,
 	}
-	// Initialised in initGlobalVariables
-	genesisDoc = new(genesis.GenesisDoc)
+	genesisDoc = integration.TestGenesisDoc(privateAccounts)
 )
 
-// We use this to wrap tests
-func TestWrapper(runner func() int) int {
-	fmt.Println("Running with integration TestWrapper (rpc/tm/integration/shared.go)...")
-
-	os.RemoveAll(testDir)
-	os.MkdirAll(testDir, 0777)
-	os.Chdir(testDir)
-
-	tmConf := tm_config.DefaultConfig()
-	logger := logging.NewNoopLogger()
-	if debugLogging {
-		var err error
-		// Change config as needed
-		logger, err = lifecycle.NewLoggerFromLoggingConfig(&config.LoggingConfig{
-			RootSink: config.Sink().
-				SetTransform(config.FilterTransform(config.IncludeWhenAnyMatches,
-					//"","",
-					"method", "GetAccount",
-					"method", "BroadcastTx",
-					"tag", "sequence",
-					"tag", "Commit",
-					"tag", "CheckTx",
-					"tag", "DeliverTx",
-				)).
-				//AddSinks(config.Sink().SetTransform(config.FilterTransform(config.ExcludeWhenAnyMatches, "run_call", "false")).
-				AddSinks(config.Sink().SetTransform(config.PruneTransform("log_channel", "trace", "scope", "returns", "run_id", "args")).
-					AddSinks(config.Sink().SetTransform(config.SortTransform("tx_hash", "time", "message", "method")).
-						SetOutput(config.StdoutOutput()))),
-		})
-		if err != nil {
-			panic(err)
-		}
-	}
-
-	privValidator := validator.NewPrivValidatorMemory(privateAccounts[0], privateAccounts[0])
-	genesisDoc = testGenesisDoc()
-	kernel, err := core.NewKernel(context.Background(), privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(),
-		nil, logger)
-	if err != nil {
-		panic(err)
-	}
-	// Sometimes better to not shutdown as logging errors on shutdown may obscure real issue
-	defer func() {
-		//kernel.Shutdown(context.Background())
-	}()
-
-	err = kernel.Boot()
-	if err != nil {
-		panic(err)
-	}
-
-	return runner()
-}
-
-func testGenesisDoc() *genesis.GenesisDoc {
-	accounts := make(map[string]acm.Account, len(privateAccounts))
-	for i, pa := range privateAccounts {
-		account := acm.FromAddressable(pa)
-		account.AddToBalance(1 << 32)
-		account.SetPermissions(permission.AllAccountPermissions.Clone())
-		accounts[fmt.Sprintf("user_%v", i)] = account
-	}
-	genesisTime, err := time.Parse("02-01-2006", "27-10-2017")
-	if err != nil {
-		panic("could not parse test genesis time")
-	}
-	return genesis.MakeGenesisDocFromAccounts(chainName, nil, genesisTime, accounts,
-		map[string]acm.Validator{
-			"genesis_validator": acm.AsValidator(accounts["user_0"]),
-		})
-}
-
-// Deterministic account generation helper. Pass number of accounts to make
-func makePrivateAccounts(n int) []acm.PrivateAccount {
-	accounts := make([]acm.PrivateAccount, n)
-	for i := 0; i < n; i++ {
-		accounts[i] = acm.GeneratePrivateAccountFromSecret("mysecret" + strconv.Itoa(i))
-	}
-	return accounts
-}
-
 //-------------------------------------------------------------------------------
 // some default transaction functions
 
@@ -165,7 +64,7 @@ func makeDefaultSendTx(t *testing.T, client tm_client.RPCClient, addr acm.Addres
 
 func makeDefaultSendTxSigned(t *testing.T, client tm_client.RPCClient, addr acm.Address, amt uint64) *txs.SendTx {
 	tx := makeDefaultSendTx(t, client, addr, amt)
-	tx.SignInput(genesisDoc.ChainID(), 0, privateAccounts[0])
+	require.NoError(t, tx.Sign(genesisDoc.ChainID(), privateAccounts[0]))
 	return tx
 }
 
@@ -174,14 +73,14 @@ func makeDefaultCallTx(t *testing.T, client tm_client.RPCClient, addr *acm.Addre
 	sequence := getSequence(t, client, privateAccounts[0].Address())
 	tx := txs.NewCallTxWithSequence(privateAccounts[0].PublicKey(), addr, code, amt, gasLim, fee,
 		sequence+1)
-	tx.Sign(genesisDoc.ChainID(), privateAccounts[0])
+	require.NoError(t, tx.Sign(genesisDoc.ChainID(), privateAccounts[0]))
 	return tx
 }
 
 func makeDefaultNameTx(t *testing.T, client tm_client.RPCClient, name, value string, amt, fee uint64) *txs.NameTx {
 	sequence := getSequence(t, client, privateAccounts[0].Address())
 	tx := txs.NewNameTxWithSequence(privateAccounts[0].PublicKey(), name, value, amt, fee, sequence+1)
-	tx.Sign(genesisDoc.ChainID(), privateAccounts[0])
+	require.NoError(t, tx.Sign(genesisDoc.ChainID(), privateAccounts[0]))
 	return tx
 }
 
diff --git a/rpc/tm/integration/websocket_helpers.go b/rpc/tm/integration/websocket_helpers.go
index ec1c7ff2cfc22e50aa1b6c4840697fe0e72a316c..cbaa5749343add811a116d0628e5d0a92e800988 100644
--- a/rpc/tm/integration/websocket_helpers.go
+++ b/rpc/tm/integration/websocket_helpers.go
@@ -302,9 +302,9 @@ func unmarshalValidateCall(origin acm.Address, returnCode []byte, txid *[]byte)
 		if !bytes.Equal(ret, returnCode) {
 			return true, fmt.Errorf("call did not return correctly. Got %x, expected %x", ret, returnCode)
 		}
-		if !bytes.Equal(data.TxID, *txid) {
+		if !bytes.Equal(data.TxHash, *txid) {
 			return true, fmt.Errorf("TxIDs do not match up! Got %x, expected %x",
-				data.TxID, *txid)
+				data.TxHash, *txid)
 		}
 		return true, nil
 	}
diff --git a/rpc/tm/methods.go b/rpc/tm/methods.go
index 719f8cd1e4c927a6e98c6649db5b77327eff61fd..27753d43d6f98b86803fe911cfb74a0d87165d53 100644
--- a/rpc/tm/methods.go
+++ b/rpc/tm/methods.go
@@ -73,14 +73,14 @@ func GetRoutes(service *rpc.Service, logger *logging.Logger) map[string]*gorpc.R
 		}, "tx"),
 
 		SignTx: gorpc.NewRPCFunc(func(tx txs.Tx, concretePrivateAccounts []*acm.ConcretePrivateAccount) (*rpc.ResultSignTx, error) {
-			tx, err := service.Transactor().SignTx(tx, acm.PrivateAccounts(concretePrivateAccounts))
+			tx, err := service.Transactor().SignTx(tx, acm.SigningAccounts(concretePrivateAccounts))
 			return &rpc.ResultSignTx{Tx: txs.Wrap(tx)}, err
 
 		}, "tx,privAccounts"),
 
 		// Simulated call
 		Call: gorpc.NewRPCFunc(func(fromAddress, toAddress acm.Address, data []byte) (*rpc.ResultCall, error) {
-			call, err := service.Transactor().Call(fromAddress, toAddress, data)
+			call, err := service.Transactor().Call(service.Accounts(), fromAddress, toAddress, data)
 			if err != nil {
 				return nil, err
 			}
@@ -88,7 +88,7 @@ func GetRoutes(service *rpc.Service, logger *logging.Logger) map[string]*gorpc.R
 		}, "fromAddress,toAddress,data"),
 
 		CallCode: gorpc.NewRPCFunc(func(fromAddress acm.Address, code, data []byte) (*rpc.ResultCall, error) {
-			call, err := service.Transactor().CallCode(fromAddress, code, data)
+			call, err := service.Transactor().CallCode(service.Accounts(), fromAddress, code, data)
 			if err != nil {
 				return nil, err
 			}
diff --git a/rpc/v0/client.go b/rpc/v0/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..5bf27c5ff14a27fd8da0456f96f5a6f8879980a2
--- /dev/null
+++ b/rpc/v0/client.go
@@ -0,0 +1,127 @@
+package v0
+
+import (
+	"bytes"
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+	"time"
+
+	"github.com/hyperledger/burrow/execution"
+	"github.com/hyperledger/burrow/execution/evm/events"
+	"github.com/hyperledger/burrow/rpc"
+	"github.com/hyperledger/burrow/txs"
+)
+
+type V0Client struct {
+	url    string
+	codec  rpc.Codec
+	client *http.Client
+}
+
+type RPCResponse struct {
+	Result  json.RawMessage `json:"result"`
+	Error   *rpc.RPCError   `json:"error"`
+	Id      string          `json:"id"`
+	JSONRPC string          `json:"jsonrpc"`
+}
+
+func NewV0Client(url string) *V0Client {
+	return &V0Client{
+		url:   url,
+		codec: NewTCodec(),
+		client: &http.Client{
+			Timeout: 1000 * time.Second,
+		},
+	}
+}
+
+func (vc *V0Client) Transact(param TransactParam) (*txs.Receipt, error) {
+	receipt := new(txs.Receipt)
+	err := vc.CallMethod(TRANSACT, param, receipt)
+	if err != nil {
+		return nil, err
+	}
+	return receipt, nil
+}
+
+func (vc *V0Client) TransactAndHold(param TransactParam) (*events.EventDataCall, error) {
+	eventDataCall := new(events.EventDataCall)
+	err := vc.CallMethod(TRANSACT_AND_HOLD, param, eventDataCall)
+	if err != nil {
+		return nil, err
+	}
+	return eventDataCall, nil
+}
+
+func (vc *V0Client) Send(param SendParam) (*txs.Receipt, error) {
+	receipt := new(txs.Receipt)
+	err := vc.CallMethod(SEND, param, receipt)
+	if err != nil {
+		return nil, err
+	}
+	return receipt, nil
+}
+
+func (vc *V0Client) SendAndHold(param SendParam) (*txs.Receipt, error) {
+	receipt := new(txs.Receipt)
+	err := vc.CallMethod(SEND_AND_HOLD, param, receipt)
+	if err != nil {
+		return nil, err
+	}
+	return receipt, nil
+}
+
+func (vc *V0Client) Call(param CallParam) (*execution.Call, error) {
+	call := new(execution.Call)
+	err := vc.CallMethod(CALL, param, call)
+	if err != nil {
+		return nil, err
+	}
+	return call, nil
+}
+
+func (vc *V0Client) CallCode(param CallCodeParam) (*execution.Call, error) {
+	call := new(execution.Call)
+	err := vc.CallMethod(CALL_CODE, param, call)
+	if err != nil {
+		return nil, err
+	}
+	return call, nil
+}
+
+func (vc *V0Client) CallMethod(method string, param interface{}, result interface{}) error {
+	// Marhsal into JSONRPC request object
+	bs, err := vc.codec.EncodeBytes(param)
+	if err != nil {
+		return err
+	}
+	request := rpc.NewRPCRequest("test", method, bs)
+	bs, err = json.Marshal(request)
+	if err != nil {
+		return err
+	}
+	// Post to JSONService
+	resp, err := vc.client.Post(vc.url, "application/json", bytes.NewBuffer(bs))
+	if err != nil {
+		return err
+	}
+	// Marshal into JSONRPC response object
+	bs, err = ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return err
+	}
+	rpcResponse := new(RPCResponse)
+	err = json.Unmarshal(bs, rpcResponse)
+	if err != nil {
+		return err
+	}
+	if rpcResponse.Error != nil {
+		return rpcResponse.Error
+	}
+	vc.codec.DecodeBytes(result, rpcResponse.Result)
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/rpc/v0/integration/main_test.go b/rpc/v0/integration/main_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5a0375653533e0e49b14512aca4d1517115783fc
--- /dev/null
+++ b/rpc/v0/integration/main_test.go
@@ -0,0 +1,42 @@
+// +build integration
+
+// Space above here matters
+// Copyright 2017 Monax Industries Limited
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package integration
+
+import (
+	"os"
+	"testing"
+	"time"
+
+	"github.com/hyperledger/burrow/core"
+	"github.com/hyperledger/burrow/core/integration"
+)
+
+var privateAccounts = integration.MakePrivateAccounts(5) // make keys
+var genesisDoc = integration.TestGenesisDoc(privateAccounts)
+var kernel *core.Kernel
+
+// Needs to be in a _test.go file to be picked up
+func TestMain(m *testing.M) {
+	returnValue := integration.TestWrapper(privateAccounts, genesisDoc, func(kern *core.Kernel) int {
+		kernel = kern
+		return m.Run()
+	})
+
+	time.Sleep(3 * time.Second)
+	os.Exit(returnValue)
+}
diff --git a/rpc/v0/integration/strange_loop.go b/rpc/v0/integration/strange_loop.go
new file mode 100644
index 0000000000000000000000000000000000000000..f8137df9465c72ab725616c6463092a4006d9db0
--- /dev/null
+++ b/rpc/v0/integration/strange_loop.go
@@ -0,0 +1,3 @@
+package integration
+
+const strangeLoopBytecode = "60606040526017600055602260015560116002556001600360006101000a81548160ff021916908315150217905550341561003957600080fd5b6102c9806100486000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ebb384dd14610046575b600080fd5b341561005157600080fd5b61005961006f565b6040518082815260200191505060405180910390f35b60006002549050600360009054906101000a900460ff16156101cf57600154600254121561012e5760026000815480929190600101919050555060025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b151561011157600080fd5b5af1151561011e57600080fd5b50505060405180519050506101ca565b6000600360006101000a81548160ff02191690831515021790555060025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15156101b157600080fd5b5af115156101be57600080fd5b50505060405180519050505b610299565b6000546002541315610273576002600081548092919060019003919050555060025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b151561025657600080fd5b5af1151561026357600080fd5b5050506040518051905050610298565b6001600360006101000a81548160ff021916908315150217905550600254905061029a565b5b5b905600a165627a7a7230582071446a8de59540361bd59bb4f5a84f884006f53e50c1c89d2bfbdb72f92fd4700029"
diff --git a/rpc/v0/integration/strange_loop.sh b/rpc/v0/integration/strange_loop.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d0cf04eecf86779b63ccdfb604aeee15792a52ec
--- /dev/null
+++ b/rpc/v0/integration/strange_loop.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+echo -e "package integration\n\nconst strangeLoopBytecode = \"$(solc --bin rpc/v0/integration/strange_loop.sol | tail -1)\"" > "${script_dir}/strange_loop.go"
diff --git a/rpc/v0/integration/strange_loop.sol b/rpc/v0/integration/strange_loop.sol
new file mode 100644
index 0000000000000000000000000000000000000000..2a3e07f242d5da224a6e5a9e502c8df38e308a39
--- /dev/null
+++ b/rpc/v0/integration/strange_loop.sol
@@ -0,0 +1,31 @@
+pragma solidity ^0.4.16;
+
+contract StrangeLoop {
+    int top = 23;
+    int bottom = 34;
+    int depth = 17;
+    bool down = true;
+
+    function UpsieDownsie() public returns (int i) {
+        i = depth;
+        if (down) {
+            if (depth < bottom) {
+                depth++;
+                i = depth;
+                this.UpsieDownsie();
+            } else {
+                down = false;
+                i = depth;
+                this.UpsieDownsie();
+            }
+        } else if (depth > top) {
+            depth--;
+            i = depth;
+            this.UpsieDownsie();
+        } else {
+            down = true;
+            i = depth;
+            return;
+        }
+    }
+}
\ No newline at end of file
diff --git a/rpc/v0/integration/v0_test.go b/rpc/v0/integration/v0_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b5229d74f927db974663f47ad71fea5619a7dd3e
--- /dev/null
+++ b/rpc/v0/integration/v0_test.go
@@ -0,0 +1,240 @@
+// +build integration
+
+// Space above here matters
+// Copyright 2017 Monax Industries Limited
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package integration
+
+import (
+	"encoding/hex"
+	"fmt"
+	"testing"
+
+	"context"
+
+	"sync"
+
+	"github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/binary"
+	"github.com/hyperledger/burrow/consensus/tendermint"
+	"github.com/hyperledger/burrow/execution/evm/abi"
+	"github.com/hyperledger/burrow/rpc/v0"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"github.com/tendermint/tendermint/types"
+)
+
+func TestTransactCallNoCode(t *testing.T) {
+	cli := v0.NewV0Client("http://localhost:1337/rpc")
+
+	// Flip flops between sending private key and input address to test private key and address based signing
+	privKey, inputAddress := privKeyInputAddressAlternator(privateAccounts[0])
+	toAddress := privateAccounts[2].Address()
+
+	numCreates := 1000
+	countCh := committedTxCount(t)
+	for i := 0; i < numCreates; i++ {
+		receipt, err := cli.Transact(v0.TransactParam{
+			PrivKey:      privKey(i),
+			InputAddress: inputAddress(i),
+			Address:      toAddress.Bytes(),
+			Data:         []byte{},
+			Fee:          2,
+			GasLimit:     10000 + uint64(i),
+		})
+		require.NoError(t, err)
+		assert.False(t, receipt.CreatesContract)
+		assert.Equal(t, toAddress, receipt.ContractAddress)
+	}
+	require.Equal(t, numCreates, <-countCh)
+}
+
+func TestTransactCreate(t *testing.T) {
+	numGoroutines := 100
+	numCreates := 10
+	wg := new(sync.WaitGroup)
+	wg.Add(numGoroutines)
+	cli := v0.NewV0Client("http://localhost:1337/rpc")
+	// Flip flops between sending private key and input address to test private key and address based signing
+	privKey, inputAddress := privKeyInputAddressAlternator(privateAccounts[0])
+	bc, err := hex.DecodeString(strangeLoopBytecode)
+	require.NoError(t, err)
+	countCh := committedTxCount(t)
+	for i := 0; i < numGoroutines; i++ {
+		go func() {
+			for j := 0; j < numCreates; j++ {
+				create, err := cli.Transact(v0.TransactParam{
+					PrivKey:      privKey(j),
+					InputAddress: inputAddress(j),
+					Address:      nil,
+					Data:         bc,
+					Fee:          2,
+					GasLimit:     10000,
+				})
+				if assert.NoError(t, err) {
+					assert.True(t, create.CreatesContract)
+				}
+			}
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+
+	require.Equal(t, numGoroutines*numCreates, <-countCh)
+}
+
+func BenchmarkTransactCreateContract(b *testing.B) {
+	cli := v0.NewV0Client("http://localhost:1337/rpc")
+
+	privKey, inputAddress := privKeyInputAddressAlternator(privateAccounts[0])
+	bc, err := hex.DecodeString(strangeLoopBytecode)
+	require.NoError(b, err)
+	for i := 0; i < b.N; i++ {
+		create, err := cli.Transact(v0.TransactParam{
+			PrivKey:      privKey(i),
+			InputAddress: inputAddress(i),
+			Address:      nil,
+			Data:         bc,
+			Fee:          2,
+			GasLimit:     10000,
+		})
+		require.NoError(b, err)
+		assert.True(b, create.CreatesContract)
+	}
+}
+
+func TestTransactAndHold(t *testing.T) {
+	cli := v0.NewV0Client("http://localhost:1337/rpc")
+	bc, err := hex.DecodeString(strangeLoopBytecode)
+	require.NoError(t, err)
+	privKey, inputAddress := privKeyInputAddressAlternator(privateAccounts[0])
+
+	numGoroutines := 5
+	numRuns := 2
+	countCh := committedTxCount(t)
+	for i := 0; i < numGoroutines; i++ {
+		for j := 0; j < numRuns; j++ {
+			create, err := cli.TransactAndHold(v0.TransactParam{
+				PrivKey:      privKey(j),
+				InputAddress: inputAddress(j),
+				Address:      nil,
+				Data:         bc,
+				Fee:          2,
+				GasLimit:     10000,
+			})
+			require.NoError(t, err)
+			assert.Equal(t, 0, create.StackDepth)
+			functionID := abi.FunctionID("UpsieDownsie()")
+			call, err := cli.TransactAndHold(v0.TransactParam{
+				PrivKey:      privKey(j),
+				InputAddress: inputAddress(j),
+				Address:      create.CallData.Callee.Bytes(),
+				Data:         functionID[:],
+				Fee:          2,
+				GasLimit:     10000,
+			})
+			require.NoError(t, err)
+			depth := binary.Uint64FromWord256(binary.LeftPadWord256(call.Return))
+			// Would give 23 if taken from wrong frame
+			assert.Equal(t, 18, int(depth))
+		}
+	}
+	require.Equal(t, numGoroutines*numRuns*2, <-countCh)
+}
+
+func TestSend(t *testing.T) {
+	cli := v0.NewV0Client("http://localhost:1337/rpc")
+
+	numSends := 1000
+	privKey, inputAddress := privKeyInputAddressAlternator(privateAccounts[0])
+	countCh := committedTxCount(t)
+	for i := 0; i < numSends; i++ {
+		send, err := cli.Send(v0.SendParam{
+			PrivKey:      privKey(i),
+			InputAddress: inputAddress(i),
+			Amount:       2003,
+			ToAddress:    privateAccounts[3].Address().Bytes(),
+		})
+		require.NoError(t, err)
+		assert.Equal(t, false, send.CreatesContract)
+	}
+	require.Equal(t, numSends, <-countCh)
+}
+
+func TestSendAndHold(t *testing.T) {
+	cli := v0.NewV0Client("http://localhost:1337/rpc")
+
+	privKey, inputAddress := privKeyInputAddressAlternator(privateAccounts[0])
+
+	for i := 0; i < 2; i++ {
+		send, err := cli.SendAndHold(v0.SendParam{
+			PrivKey:      privKey(i),
+			InputAddress: inputAddress(i),
+			Amount:       2003,
+			ToAddress:    privateAccounts[3].Address().Bytes(),
+		})
+		require.NoError(t, err)
+		assert.Equal(t, false, send.CreatesContract)
+	}
+}
+
+var committedTxCountIndex = 0
+
+func committedTxCount(t *testing.T) chan int {
+	var numTxs int64
+	emptyBlocks := 0
+	maxEmptyBlocks := 2
+	outCh := make(chan int)
+	ch := make(chan *types.EventDataNewBlock)
+	ctx := context.Background()
+	subscriber := fmt.Sprintf("committedTxCount_%v", committedTxCountIndex)
+	committedTxCountIndex++
+	require.NoError(t, tendermint.SubscribeNewBlock(ctx, kernel.Emitter, subscriber, ch))
+
+	go func() {
+		for ed := range ch {
+			if ed.Block.NumTxs == 0 {
+				emptyBlocks++
+			} else {
+				emptyBlocks = 0
+			}
+			if emptyBlocks > maxEmptyBlocks {
+				break
+			}
+			numTxs += ed.Block.NumTxs
+			t.Logf("Total TXs committed at block %v: %v (+%v)\n", ed.Block.Height, numTxs, ed.Block.NumTxs)
+		}
+		require.NoError(t, kernel.Emitter.UnsubscribeAll(ctx, subscriber))
+		outCh <- int(numTxs)
+	}()
+	return outCh
+}
+
+// Returns a pair of functions that mutually exclusively return the private key bytes or input address bytes of a
+// private account in the same iteration of a loop indexed by an int
+func privKeyInputAddressAlternator(privateAccount account.PrivateAccount) (func(int) []byte, func(int) []byte) {
+	privKey := privateAccount.PrivateKey().RawBytes()
+	inputAddress := privateAccount.Address().Bytes()
+	return alternator(privKey, 0), alternator(inputAddress, 1)
+}
+
+func alternator(ret []byte, res int) func(int) []byte {
+	return func(i int) []byte {
+		if i%2 == res {
+			return ret
+		}
+		return nil
+	}
+}
diff --git a/rpc/v0/json_service.go b/rpc/v0/json_service.go
index cac693d2a0bd5960aed26ec0cd223e5687ef858f..d075eeddcf586832a9d62e28301c2ea57fdf8530 100644
--- a/rpc/v0/json_service.go
+++ b/rpc/v0/json_service.go
@@ -52,8 +52,7 @@ func NewJSONServer(service server.HttpService) *JsonRpcServer {
 }
 
 // Start adds the rpc path to the router.
-func (jrs *JsonRpcServer) Start(config *server.ServerConfig,
-	router *gin.Engine) {
+func (jrs *JsonRpcServer) Start(config *server.ServerConfig, router *gin.Engine) {
 	router.POST(config.HTTP.JsonRpcEndpoint, jrs.handleFunc)
 	jrs.running = true
 }
diff --git a/rpc/v0/methods.go b/rpc/v0/methods.go
index ef994e04dc76916301f9428fdf6255948c7cf2c2..346b53148a780d307473f31c106f3a2ab796edf5 100644
--- a/rpc/v0/methods.go
+++ b/rpc/v0/methods.go
@@ -15,6 +15,8 @@
 package v0
 
 import (
+	"fmt"
+
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/execution"
 	"github.com/hyperledger/burrow/logging"
@@ -66,7 +68,6 @@ type RequestHandlerFunc func(request *rpc.RPCRequest, requester interface{}) (in
 func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) map[string]RequestHandlerFunc {
 	accountFilterFactory := filters.NewAccountFilterFactory()
 	nameRegFilterFactory := filters.NewNameRegFilterFactory()
-
 	return map[string]RequestHandlerFunc{
 		// Accounts
 		GET_ACCOUNTS: func(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) {
@@ -172,7 +173,7 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			call, err := service.Transactor().Call(from, address, param.Data)
+			call, err := service.Transactor().Call(service.MempoolAccounts(), from, address, param.Data)
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
@@ -188,7 +189,7 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			call, err := service.Transactor().CallCode(from, param.Code, param.Data)
+			call, err := service.Transactor().CallCode(service.MempoolAccounts(), from, param.Code, param.Data)
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
@@ -213,7 +214,7 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			txRet, err := service.Transactor().SignTx(param.Tx, acm.PrivateAccounts(param.PrivAccounts))
+			txRet, err := service.Transactor().SignTx(param.Tx, acm.SigningAccounts(param.PrivAccounts))
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
@@ -229,7 +230,12 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			receipt, err := service.Transactor().Transact(param.PrivKey, address, param.Data, param.GasLimit, param.Fee)
+			// Use mempool state so that transact can generate a run of sequence numbers when formulating transactions
+			inputAccount, err := signingAccount(service.MempoolAccounts(), param.PrivKey, param.InputAddress)
+			if err != nil {
+				return nil, rpc.INVALID_PARAMS, err
+			}
+			receipt, err := service.Transactor().Transact(inputAccount, address, param.Data, param.GasLimit, param.Fee)
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
@@ -245,7 +251,11 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			ce, err := service.Transactor().TransactAndHold(param.PrivKey, address, param.Data, param.GasLimit, param.Fee)
+			inputAccount, err := signingAccount(service.MempoolAccounts(), param.PrivKey, param.InputAddress)
+			if err != nil {
+				return nil, rpc.INVALID_PARAMS, err
+			}
+			ce, err := service.Transactor().TransactAndHold(inputAccount, address, param.Data, param.GasLimit, param.Fee)
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
@@ -261,7 +271,12 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			receipt, err := service.Transactor().Send(param.PrivKey, toAddress, param.Amount)
+			// Run Send against mempool state
+			inputAccount, err := signingAccount(service.MempoolAccounts(), param.PrivKey, param.InputAddress)
+			if err != nil {
+				return nil, rpc.INVALID_PARAMS, err
+			}
+			receipt, err := service.Transactor().Send(inputAccount, toAddress, param.Amount)
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
@@ -277,7 +292,12 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			rec, err := service.Transactor().SendAndHold(param.PrivKey, toAddress, param.Amount)
+			// Run Send against mempool state
+			inputAccount, err := signingAccount(service.MempoolAccounts(), param.PrivKey, param.InputAddress)
+			if err != nil {
+				return nil, rpc.INVALID_PARAMS, err
+			}
+			rec, err := service.Transactor().SendAndHold(inputAccount, toAddress, param.Amount)
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
@@ -289,7 +309,11 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			receipt, err := service.Transactor().TransactNameReg(param.PrivKey, param.Name, param.Data, param.Amount, param.Fee)
+			inputAccount, err := signingAccount(service.MempoolAccounts(), param.PrivKey, param.InputAddress)
+			if err != nil {
+				return nil, rpc.INVALID_PARAMS, err
+			}
+			receipt, err := service.Transactor().TransactNameReg(inputAccount, param.Name, param.Data, param.Amount, param.Fee)
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
@@ -418,3 +442,19 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 		},
 	}
 }
+
+// Gets signing account from onr of private key or address - failing if both are provided
+func signingAccount(accounts *execution.Accounts, privKey, addressBytes []byte) (*execution.SequentialSigningAccount, error) {
+	if len(addressBytes) > 0 {
+		if len(privKey) > 0 {
+			return nil, fmt.Errorf("privKey and address provided but only one or the other should be given")
+		}
+		address, err := acm.AddressFromBytes(addressBytes)
+		if err != nil {
+			return nil, err
+		}
+		return accounts.SequentialSigningAccount(address), nil
+	}
+
+	return accounts.SequentialSigningAccountFromPrivateKey(privKey)
+}
diff --git a/rpc/v0/params.go b/rpc/v0/params.go
index f3cc8efc05ed9e2f5ed108b68ad4eb315d7357fb..2635308ef25aad3cb2bf01331bfca58763d34709 100644
--- a/rpc/v0/params.go
+++ b/rpc/v0/params.go
@@ -88,18 +88,20 @@ type (
 	// Used when sending a transaction to be created and signed on the server
 	// (using the private key). This only uses the standard key type for now.
 	TransactParam struct {
-		PrivKey  []byte `json:"priv_key"`
-		Data     []byte `json:"data"`
-		Address  []byte `json:"address"`
-		Fee      uint64 `json:"fee"`
-		GasLimit uint64 `json:"gas_limit"`
+		PrivKey      []byte `json:"priv_key"`
+		InputAddress []byte `json:"input_account"`
+		Data         []byte `json:"data"`
+		Address      []byte `json:"address"`
+		Fee          uint64 `json:"fee"`
+		GasLimit     uint64 `json:"gas_limit"`
 	}
 
 	// Used when sending a 'Send' transaction.
 	SendParam struct {
-		PrivKey   []byte `json:"priv_key"`
-		ToAddress []byte `json:"to_address"`
-		Amount    uint64 `json:"amount"`
+		PrivKey      []byte `json:"priv_key"`
+		InputAddress []byte `json:"input_account"`
+		ToAddress    []byte `json:"to_address"`
+		Amount       uint64 `json:"amount"`
 	}
 
 	NameRegEntryParam struct {
@@ -109,10 +111,11 @@ type (
 	// Used when sending a namereg transaction to be created and signed on the server
 	// (using the private key). This only uses the standard key type for now.
 	TransactNameRegParam struct {
-		PrivKey []byte `json:"priv_key"`
-		Name    string `json:"name"`
-		Data    string `json:"data"`
-		Fee     uint64 `json:"fee"`
-		Amount  uint64 `json:"amount"`
+		PrivKey      []byte `json:"priv_key"`
+		InputAddress []byte `json:"input_account"`
+		Name         string `json:"name"`
+		Data         string `json:"data"`
+		Fee          uint64 `json:"fee"`
+		Amount       uint64 `json:"amount"`
 	}
 )
diff --git a/rpc/v0/server/server.go b/rpc/v0/server/server.go
index 9edc900f03d42fe5640e2edf8108dc1a11b2cfdc..5a6240013cdd6baa6402740bf864dedadccf934d 100644
--- a/rpc/v0/server/server.go
+++ b/rpc/v0/server/server.go
@@ -64,7 +64,7 @@ type ServeProcess struct {
 // Initializes all the servers and starts listening for connections.
 func (serveProcess *ServeProcess) Start() error {
 	router := gin.New()
-
+	gin.SetMode(gin.ReleaseMode)
 	config := serveProcess.config
 
 	ch := NewCORSMiddleware(config.CORS)
diff --git a/sync/ring_mutex.go b/sync/ring_mutex.go
new file mode 100644
index 0000000000000000000000000000000000000000..50240956eda7e38e5f9eca423d0c5a5a5982f5a0
--- /dev/null
+++ b/sync/ring_mutex.go
@@ -0,0 +1,92 @@
+package sync
+
+import (
+	"sync"
+
+	"hash"
+
+	"encoding/binary"
+
+	"github.com/OneOfOne/xxhash"
+)
+
+type RingMutex struct {
+	mtxs       []sync.RWMutex
+	hash       func(address []byte) uint64
+	mutexCount uint64
+}
+
+// Create a RW mutex that provides a pseudo-independent set of mutexes for addresses
+// where the address space is mapped into possibly much smaller set of backing
+// mutexes using the xxhash (non-cryptographic)
+// hash function // modulo size. If some addresses collide modulo size they will be unnecessary
+// contention between those addresses, but you can trade space against contention
+// as desired.
+func NewRingMutex(mutexCount int, hashMaker func() hash.Hash64) *RingMutex {
+	ringMutex := &RingMutex{
+		mutexCount: uint64(mutexCount),
+		// max slice length is bounded by max(int) thus the argument type
+		mtxs: make([]sync.RWMutex, mutexCount, mutexCount),
+		hash: func(address []byte) uint64 {
+			buf := make([]byte, 8)
+			copy(buf, address)
+			return binary.LittleEndian.Uint64(buf)
+		},
+	}
+	if hashMaker != nil {
+		hasherPool := &sync.Pool{
+			New: func() interface{} {
+				return hashMaker()
+			},
+		}
+		ringMutex.hash = func(address []byte) uint64 {
+			h := hasherPool.Get().(hash.Hash64)
+			defer func() {
+				h.Reset()
+				hasherPool.Put(h)
+			}()
+			h.Write(address)
+			return h.Sum64()
+		}
+	}
+	return ringMutex
+}
+
+func NewRingMutexNoHash(mutexCount int) *RingMutex {
+	return NewRingMutex(mutexCount, nil)
+}
+
+func NewRingMutexXXHash(mutexCount int) *RingMutex {
+	return NewRingMutex(mutexCount, func() hash.Hash64 {
+		return xxhash.New64()
+	})
+}
+
+func (mtx *RingMutex) Lock(address []byte) {
+	mtx.Mutex(address).Lock()
+}
+
+func (mtx *RingMutex) Unlock(address []byte) {
+	mtx.Mutex(address).Unlock()
+}
+
+func (mtx *RingMutex) RLock(address []byte) {
+	mtx.Mutex(address).RLock()
+}
+
+func (mtx *RingMutex) RUnlock(address []byte) {
+	mtx.Mutex(address).RUnlock()
+}
+
+// Return the size of the underlying array of mutexes
+func (mtx *RingMutex) MutexCount() uint64 {
+	return mtx.mutexCount
+}
+
+func (mtx *RingMutex) Mutex(address []byte) *sync.RWMutex {
+	return &mtx.mtxs[mtx.index(address)]
+}
+
+func (mtx *RingMutex) index(address []byte) uint64 {
+	return mtx.hash(address) % mtx.mutexCount
+}
diff --git a/sync/ring_mutex_test.go b/sync/ring_mutex_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b6d8f40dc7c180d84a31b63556325653897c67cb
--- /dev/null
+++ b/sync/ring_mutex_test.go
@@ -0,0 +1,98 @@
+package sync
+
+import (
+	"encoding/base64"
+	"testing"
+
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestRingMutexXXHash_Lock(t *testing.T) {
+	mutexCount := 10
+	numAddresses := byte(20)
+	mtxs := []*RingMutex{NewRingMutexXXHash(mutexCount)}
+
+	for _, mtx := range mtxs {
+		// Using fewer mutexes than addresses to lock against should cause contention
+		writeCh := make(chan []byte)
+		checksum := 0
+
+		// We'll try to acquire a locks on all of our unique addresses, knowing that
+		// some of them will share an underlying RWMutex
+		for i := byte(0); i < numAddresses; i++ {
+			address := []byte{i}
+			go func() {
+				mtx.Lock(address)
+				writeCh <- address
+			}()
+		}
+
+		// We should receive a message from all of those addresses for which we could
+		// acquire a lock, this should be almost surely deterministic since we are
+		// launching our goroutines sequentially from a single goroutine (if this bit
+		// breaks we can add a short pause between the 'go' statements above, for the
+		// purposes of the predictability of this test)
+		addresses := receiveAddresses(writeCh)
+		checksum += len(addresses)
+		// we hit lock contention on the tenth address so get 9 back
+		assert.Equal(t, 9, len(addresses))
+		// Unlock the 9 locked mutexes
+		unlockAddresses(mtx, addresses)
+
+		// Which should trigger another batch to make progress
+		addresses = receiveAddresses(writeCh)
+		checksum += len(addresses)
+		// Again the number we get back (but not the order) should be deterministic
+		// because we are unlocking sequentially from a single goroutine
+		assert.Equal(t, 7, len(addresses))
+		unlockAddresses(mtx, addresses)
+
+		// And again
+		addresses = receiveAddresses(writeCh)
+		checksum += len(addresses)
+		assert.Equal(t, 3, len(addresses))
+		unlockAddresses(mtx, addresses)
+
+		// And so on
+		addresses = receiveAddresses(writeCh)
+		checksum += len(addresses)
+		assert.Equal(t, 1, len(addresses))
+		unlockAddresses(mtx, addresses)
+
+		// Until we have unblocked all of the goroutines we released
+		addresses = receiveAddresses(writeCh)
+		checksum += len(addresses)
+		assert.Equal(t, 0, len(addresses))
+		unlockAddresses(mtx, addresses)
+		checksum += len(addresses)
+
+		// Check we've heard back from all of them
+		assert.EqualValues(t, numAddresses, checksum)
+	}
+}
+
+func TestRingMutex_XXHash(t *testing.T) {
+	mtx := NewRingMutexXXHash(10)
+	address, err := base64.StdEncoding.DecodeString("/+ulTkCzpYg2ePaZtqS8dycJBLY9387yZPst8LX5YL0=")
+	assert.NoError(t, err)
+	assert.EqualValues(t, 8509033946529530334, mtx.hash(address))
+}
+
+func receiveAddresses(returnCh chan []byte) [][]byte {
+	var addresses [][]byte
+	for {
+		select {
+		case address := <-returnCh:
+			addresses = append(addresses, address)
+		case <-time.After(50 * time.Millisecond):
+			return addresses
+		}
+	}
+}
+func unlockAddresses(mtx *RingMutex, addresses [][]byte) {
+	for _, address := range addresses {
+		mtx.Unlock(address)
+	}
+}
diff --git a/txs/README.md b/txs/README.md
deleted file mode 100644
index f99294b007dd8ac4b3a453f0256d9c0aeb43d247..0000000000000000000000000000000000000000
--- a/txs/README.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# `tendermint/block`
-
-## Block
-
-TODO: document
-
-### Header
-
-### Validation
-
-### Data
-
-## PartSet
-
-PartSet is used to split a byteslice of data into parts (pieces) for transmission.
-By splitting data into smaller parts and computing a Merkle root hash on the list,
-you can verify that a part is legitimately part of the complete data, and the
-part can be forwarded to other peers before all the parts are known.  In short,
-it's a fast way to propagate a large file over a gossip network.
-
-PartSet was inspired by the LibSwift project.
-
-Usage:
-
-```Go
-data := RandBytes(2 << 20) // Something large
-
-partSet := NewPartSetFromData(data)
-partSet.Total()     // Total number of 4KB parts
-partSet.Count()     // Equal to the Total, since we already have all the parts
-partSet.Hash()      // The Merkle root hash
-partSet.BitArray()  // A BitArray of partSet.Total() 1's
-
-header := partSet.Header() // Send this to the peer
-header.Total        // Total number of parts
-header.Hash         // The merkle root hash
-
-// Now we'll reconstruct the data from the parts
-partSet2 := NewPartSetFromHeader(header)
-partSet2.Total()    // Same total as partSet.Total()
-partSet2.Count()    // Zero, since this PartSet doesn't have any parts yet.
-partSet2.Hash()     // Same hash as in partSet.Hash()
-partSet2.BitArray() // A BitArray of partSet.Total() 0's
-
-// In a gossip network the parts would arrive in arbitrary order, perhaps
-// in response to explicit requests for parts, or optimistically in response
-// to the receiving peer's partSet.BitArray().
-for !partSet2.IsComplete() {
-    part := receivePartFromGossipNetwork()
-    added, err := partSet2.AddPart(part)
-    if err != nil {
-		// A wrong part,
-        // the merkle trail does not hash to partSet2.Hash()
-    } else if !added {
-        // A duplicate part already received
-    }
-}
-
-data2, _ := ioutil.ReadAll(partSet2.GetReader())
-bytes.Equal(data, data2) // true
-```
diff --git a/txs/bond_tx.go b/txs/bond_tx.go
new file mode 100644
index 0000000000000000000000000000000000000000..aa6aecea7d64472134e3a87ce99f17f3ed5c3824
--- /dev/null
+++ b/txs/bond_tx.go
@@ -0,0 +1,111 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/tendermint/go-wire"
+)
+
+type BondTx struct {
+	PubKey    acm.PublicKey
+	Signature acm.Signature
+	Inputs    []*TxInput
+	UnbondTo  []*TxOutput
+	txHashMemoizer
+}
+
+var _ Tx = &BondTx{}
+
+func NewBondTx(pubkey acm.PublicKey) (*BondTx, error) {
+	return &BondTx{
+		PubKey:   pubkey,
+		Inputs:   []*TxInput{},
+		UnbondTo: []*TxOutput{},
+	}, nil
+}
+
+func (tx *BondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err)
+	for i, in := range tx.Inputs {
+		in.WriteSignBytes(w, n, err)
+		if i != len(tx.Inputs)-1 {
+			wire.WriteTo([]byte(","), w, n, err)
+		}
+	}
+	wire.WriteTo([]byte(fmt.Sprintf(`],"pub_key":`)), w, n, err)
+	wire.WriteTo(wire.JSONBytes(tx.PubKey), w, n, err)
+	wire.WriteTo([]byte(`,"unbond_to":[`), w, n, err)
+	for i, out := range tx.UnbondTo {
+		out.WriteSignBytes(w, n, err)
+		if i != len(tx.UnbondTo)-1 {
+			wire.WriteTo([]byte(","), w, n, err)
+		}
+	}
+	wire.WriteTo([]byte(`]}]}`), w, n, err)
+}
+
+func (tx *BondTx) GetInputs() []TxInput {
+	return copyInputs(tx.Inputs)
+}
+
+func (tx *BondTx) String() string {
+	return fmt.Sprintf("BondTx{%v: %v -> %v}", tx.PubKey, tx.Inputs, tx.UnbondTo)
+}
+
+func (tx *BondTx) Hash(chainID string) []byte {
+	return tx.txHashMemoizer.hash(chainID, tx)
+}
+
+func (tx *BondTx) AddInput(st state.AccountGetter, pubkey acm.PublicKey, amt uint64) error {
+	addr := pubkey.Address()
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return err
+	}
+	if acc == nil {
+		return fmt.Errorf("Invalid address %s from pubkey %s", addr, pubkey)
+	}
+	return tx.AddInputWithSequence(pubkey, amt, acc.Sequence()+uint64(1))
+}
+
+func (tx *BondTx) AddInputWithSequence(pubkey acm.PublicKey, amt uint64, sequence uint64) error {
+	tx.Inputs = append(tx.Inputs, &TxInput{
+		Address:   pubkey.Address(),
+		Amount:    amt,
+		Sequence:  sequence,
+		PublicKey: pubkey,
+	})
+	return nil
+}
+
+func (tx *BondTx) AddOutput(addr acm.Address, amt uint64) error {
+	tx.UnbondTo = append(tx.UnbondTo, &TxOutput{
+		Address: addr,
+		Amount:  amt,
+	})
+	return nil
+}
+
+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))
+	}
+	var err error
+	tx.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx)
+	if err != nil {
+		return fmt.Errorf("could not sign %v: %v", tx, err)
+	}
+	for i := 1; i <= len(signingAccounts); i++ {
+		tx.Inputs[i].PublicKey = signingAccounts[i].PublicKey()
+		tx.Inputs[i].Signature, err = acm.ChainSign(signingAccounts[i], chainID, tx)
+		if err != nil {
+			return fmt.Errorf("could not sign tx %v input %v: %v", tx, tx.Inputs[i], err)
+		}
+	}
+	return nil
+}
diff --git a/txs/call_tx.go b/txs/call_tx.go
new file mode 100644
index 0000000000000000000000000000000000000000..a3d0f1b849db203f34c55739bfd827ede46af135
--- /dev/null
+++ b/txs/call_tx.go
@@ -0,0 +1,90 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/tendermint/go-wire"
+)
+
+type CallTx struct {
+	Input *TxInput
+	// Pointer since CallTx defines unset 'to' address as inducing account creation
+	Address  *acm.Address
+	GasLimit uint64
+	Fee      uint64
+	Data     []byte
+	txHashMemoizer
+}
+
+var _ Tx = &CallTx{}
+
+func NewCallTx(st state.AccountGetter, from acm.PublicKey, to *acm.Address, data []byte,
+	amt, gasLimit, fee uint64) (*CallTx, error) {
+
+	addr := from.Address()
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return nil, err
+	}
+	if acc == nil {
+		return nil, fmt.Errorf("invalid address %s from pubkey %s", addr, from)
+	}
+
+	sequence := acc.Sequence() + 1
+	return NewCallTxWithSequence(from, to, data, amt, gasLimit, fee, sequence), nil
+}
+
+func NewCallTxWithSequence(from acm.PublicKey, to *acm.Address, data []byte,
+	amt, gasLimit, fee, sequence uint64) *CallTx {
+	input := &TxInput{
+		Address:   from.Address(),
+		Amount:    amt,
+		Sequence:  sequence,
+		PublicKey: from,
+	}
+
+	return &CallTx{
+		Input:    input,
+		Address:  to,
+		GasLimit: gasLimit,
+		Fee:      fee,
+		Data:     data,
+	}
+}
+
+func (tx *CallTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
+	if len(signingAccounts) != 1 {
+		return fmt.Errorf("CallTx expects a single AddressableSigner for its single Input but %v were provieded",
+			len(signingAccounts))
+	}
+	var err error
+	tx.Input.PublicKey = signingAccounts[0].PublicKey()
+	tx.Input.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx)
+	if err != nil {
+		return fmt.Errorf("could not sign %v: %v", tx, err)
+	}
+	return nil
+}
+
+func (tx *CallTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err)
+	tx.Input.WriteSignBytes(w, n, err)
+	wire.WriteTo([]byte(`}]}`), w, n, err)
+}
+
+func (tx *CallTx) GetInputs() []TxInput {
+	return []TxInput{*tx.Input}
+}
+
+func (tx *CallTx) String() string {
+	return fmt.Sprintf("CallTx{%v -> %s: %X}", tx.Input, tx.Address, tx.Data)
+}
+
+func (tx *CallTx) Hash(chainID string) []byte {
+	return tx.txHashMemoizer.hash(chainID, tx)
+}
diff --git a/txs/name_tx.go b/txs/name_tx.go
new file mode 100644
index 0000000000000000000000000000000000000000..76ef57dceb4b4d568e1f5da46d9ce5d4575e5480
--- /dev/null
+++ b/txs/name_tx.go
@@ -0,0 +1,123 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	"regexp"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/tendermint/go-wire"
+)
+
+// Name should be file system lik
+// Data should be anything permitted in JSON
+var regexpAlphaNum = regexp.MustCompile("^[a-zA-Z0-9._/-@]*$")
+var regexpJSON = regexp.MustCompile(`^[a-zA-Z0-9_/ \-+"':,\n\t.{}()\[\]]*$`)
+
+type NameTx struct {
+	Input *TxInput
+	Name  string
+	Data  string
+	Fee   uint64
+	txHashMemoizer
+}
+
+var _ Tx = &NameTx{}
+
+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 {
+		return nil, err
+	}
+	if acc == nil {
+		return nil, fmt.Errorf("Invalid address %s from pubkey %s", addr, from)
+	}
+
+	sequence := acc.Sequence() + 1
+	return NewNameTxWithSequence(from, name, data, amt, fee, sequence), nil
+}
+
+func NewNameTxWithSequence(from acm.PublicKey, name, data string, amt, fee, sequence uint64) *NameTx {
+	input := &TxInput{
+		Address:   from.Address(),
+		Amount:    amt,
+		Sequence:  sequence,
+		PublicKey: from,
+	}
+
+	return &NameTx{
+		Input: input,
+		Name:  name,
+		Data:  data,
+		Fee:   fee,
+	}
+}
+
+func (tx *NameTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
+	if len(signingAccounts) != 1 {
+		return fmt.Errorf("NameTx expects a single AddressableSigner for its single Input but %v were provieded",
+			len(signingAccounts))
+	}
+	var err error
+	tx.Input.PublicKey = signingAccounts[0].PublicKey()
+	tx.Input.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx)
+	if err != nil {
+		return fmt.Errorf("could not sign %v: %v", tx, err)
+	}
+	return nil
+}
+
+func (tx *NameTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"data":%s,"fee":%v`, TxTypeName, jsonEscape(tx.Data), tx.Fee)), w, n, err)
+	wire.WriteTo([]byte(`,"input":`), w, n, err)
+	tx.Input.WriteSignBytes(w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"name":%s`, jsonEscape(tx.Name))), w, n, err)
+	wire.WriteTo([]byte(`}]}`), w, n, err)
+}
+
+func (tx *NameTx) GetInputs() []TxInput {
+	return []TxInput{*tx.Input}
+}
+
+func (tx *NameTx) ValidateStrings() error {
+	if len(tx.Name) == 0 {
+		return ErrTxInvalidString{"Name must not be empty"}
+	}
+	if len(tx.Name) > MaxNameLength {
+		return ErrTxInvalidString{fmt.Sprintf("Name is too long. Max %d bytes", MaxNameLength)}
+	}
+	if len(tx.Data) > MaxDataLength {
+		return ErrTxInvalidString{fmt.Sprintf("Data is too long. Max %d bytes", MaxDataLength)}
+	}
+
+	if !validateNameRegEntryName(tx.Name) {
+		return ErrTxInvalidString{fmt.Sprintf("Invalid characters found in NameTx.Name (%s). Only alphanumeric, underscores, dashes, forward slashes, and @ are allowed", tx.Name)}
+	}
+
+	if !validateNameRegEntryData(tx.Data) {
+		return ErrTxInvalidString{fmt.Sprintf("Invalid characters found in NameTx.Data (%s). Only the kind of things found in a JSON file are allowed", tx.Data)}
+	}
+
+	return nil
+}
+
+func (tx *NameTx) String() string {
+	return fmt.Sprintf("NameTx{%v -> %s: %s}", tx.Input, tx.Name, tx.Data)
+}
+
+func (tx *NameTx) Hash(chainID string) []byte {
+	return tx.txHashMemoizer.hash(chainID, tx)
+}
+
+// filter strings
+func validateNameRegEntryName(name string) bool {
+	return regexpAlphaNum.Match([]byte(name))
+}
+
+func validateNameRegEntryData(data string) bool {
+	return regexpJSON.Match([]byte(data))
+}
diff --git a/txs/names.go b/txs/names.go
index 23c693f0a1a8db9a6c6c559f30f601092482db99..3b0bceff26e0807dc549db8d198155af544a3e41 100644
--- a/txs/names.go
+++ b/txs/names.go
@@ -14,10 +14,6 @@
 
 package txs
 
-import (
-	"regexp"
-)
-
 var (
 	MinNameRegistrationPeriod uint64 = 5
 
@@ -31,22 +27,8 @@ var (
 
 	MaxNameLength = 64
 	MaxDataLength = 1 << 16
-
-	// Name should be file system lik
-	// Data should be anything permitted in JSON
-	regexpAlphaNum = regexp.MustCompile("^[a-zA-Z0-9._/-@]*$")
-	regexpJSON     = regexp.MustCompile(`^[a-zA-Z0-9_/ \-+"':,\n\t.{}()\[\]]*$`)
 )
 
-// filter strings
-func validateNameRegEntryName(name string) bool {
-	return regexpAlphaNum.Match([]byte(name))
-}
-
-func validateNameRegEntryData(data string) bool {
-	return regexpJSON.Match([]byte(data))
-}
-
 // base cost is "effective" number of bytes
 func NameBaseCost(name, data string) uint64 {
 	return uint64(len(data) + 32)
diff --git a/txs/permission_tx.go b/txs/permission_tx.go
new file mode 100644
index 0000000000000000000000000000000000000000..c2dad89bf1750cd35ab217fa613e591ce64305f1
--- /dev/null
+++ b/txs/permission_tx.go
@@ -0,0 +1,82 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/permission/snatives"
+	"github.com/tendermint/go-wire"
+)
+
+type PermissionsTx struct {
+	Input    *TxInput
+	PermArgs snatives.PermArgs
+	txHashMemoizer
+}
+
+var _ Tx = &PermissionsTx{}
+
+func NewPermissionsTx(st state.AccountGetter, from acm.PublicKey, args snatives.PermArgs) (*PermissionsTx, error) {
+	addr := from.Address()
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return nil, err
+	}
+	if acc == nil {
+		return nil, fmt.Errorf("Invalid address %s from pubkey %s", addr, from)
+	}
+
+	sequence := acc.Sequence() + 1
+	return NewPermissionsTxWithSequence(from, args, sequence), nil
+}
+
+func NewPermissionsTxWithSequence(from acm.PublicKey, args snatives.PermArgs, sequence uint64) *PermissionsTx {
+	input := &TxInput{
+		Address:   from.Address(),
+		Amount:    1, // NOTE: amounts can't be 0 ...
+		Sequence:  sequence,
+		PublicKey: from,
+	}
+
+	return &PermissionsTx{
+		Input:    input,
+		PermArgs: args,
+	}
+}
+
+func (tx *PermissionsTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
+	if len(signingAccounts) != 1 {
+		return fmt.Errorf("PermissionsTx expects a single AddressableSigner for its single Input but %v were provieded",
+			len(signingAccounts))
+	}
+	var err error
+	tx.Input.PublicKey = signingAccounts[0].PublicKey()
+	tx.Input.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx)
+	if err != nil {
+		return fmt.Errorf("could not sign %v: %v", tx, err)
+	}
+	return nil
+}
+
+func (tx *PermissionsTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"args":"`, TxTypePermissions)), w, n, err)
+	wire.WriteJSON(&tx.PermArgs, w, n, err)
+	wire.WriteTo([]byte(`","input":`), w, n, err)
+	tx.Input.WriteSignBytes(w, n, err)
+	wire.WriteTo([]byte(`}]}`), w, n, err)
+}
+
+func (tx *PermissionsTx) GetInputs() []TxInput {
+	return []TxInput{*tx.Input}
+}
+
+func (tx *PermissionsTx) String() string {
+	return fmt.Sprintf("PermissionsTx{%v -> %v}", tx.Input, tx.PermArgs)
+}
+
+func (tx *PermissionsTx) Hash(chainID string) []byte {
+	return tx.txHashMemoizer.hash(chainID, tx)
+}
diff --git a/txs/rebond_tx.go b/txs/rebond_tx.go
new file mode 100644
index 0000000000000000000000000000000000000000..b5b22ff4b0f87e123b6b7101f2049b28d47405e5
--- /dev/null
+++ b/txs/rebond_tx.go
@@ -0,0 +1,55 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/tendermint/go-wire"
+)
+
+type RebondTx struct {
+	Address   acm.Address
+	Height    int
+	Signature acm.Signature
+	txHashMemoizer
+}
+
+var _ Tx = &RebondTx{}
+
+func NewRebondTx(addr acm.Address, height int) *RebondTx {
+	return &RebondTx{
+		Address: addr,
+		Height:  height,
+	}
+}
+
+func (tx *RebondTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
+	if len(signingAccounts) != 1 {
+		return fmt.Errorf("RebondTx expects a single AddressableSigner for its signature but %v were provieded",
+			len(signingAccounts))
+	}
+	var err error
+	tx.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx)
+	if err != nil {
+		return fmt.Errorf("could not sign %v: %v", tx, err)
+	}
+	return nil
+}
+
+func (tx *RebondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err)
+}
+
+func (tx *RebondTx) GetInputs() []TxInput {
+	return nil
+}
+
+func (tx *RebondTx) String() string {
+	return fmt.Sprintf("RebondTx{%s,%v,%v}", tx.Address, tx.Height, tx.Signature)
+}
+
+func (tx *RebondTx) Hash(chainID string) []byte {
+	return tx.txHashMemoizer.hash(chainID, tx)
+}
diff --git a/txs/send_tx.go b/txs/send_tx.go
new file mode 100644
index 0000000000000000000000000000000000000000..e9212fd8042ff5511a643b6b2ea7c32a94065978
--- /dev/null
+++ b/txs/send_tx.go
@@ -0,0 +1,103 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/tendermint/go-wire"
+)
+
+type SendTx struct {
+	Inputs  []*TxInput
+	Outputs []*TxOutput
+	txHashMemoizer
+}
+
+var _ Tx = &SendTx{}
+
+func NewSendTx() *SendTx {
+	return &SendTx{
+		Inputs:  []*TxInput{},
+		Outputs: []*TxOutput{},
+	}
+}
+
+func (tx *SendTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err)
+	for i, in := range tx.Inputs {
+		in.WriteSignBytes(w, n, err)
+		if i != len(tx.Inputs)-1 {
+			wire.WriteTo([]byte(","), w, n, err)
+		}
+	}
+	wire.WriteTo([]byte(`],"outputs":[`), w, n, err)
+	for i, out := range tx.Outputs {
+		out.WriteSignBytes(w, n, err)
+		if i != len(tx.Outputs)-1 {
+			wire.WriteTo([]byte(","), w, n, err)
+		}
+	}
+	wire.WriteTo([]byte(`]}]}`), w, n, err)
+}
+
+func (tx *SendTx) GetInputs() []TxInput {
+	return copyInputs(tx.Inputs)
+}
+
+func (tx *SendTx) String() string {
+	return fmt.Sprintf("SendTx{%v -> %v}", tx.Inputs, tx.Outputs)
+}
+
+func (tx *SendTx) Hash(chainID string) []byte {
+	return tx.txHashMemoizer.hash(chainID, tx)
+}
+
+func (tx *SendTx) AddInput(st state.AccountGetter, pubkey acm.PublicKey, amt uint64) error {
+	addr := pubkey.Address()
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return err
+	}
+	if acc == nil {
+		return fmt.Errorf("invalid address %s from pubkey %s", addr, pubkey)
+	}
+	return tx.AddInputWithSequence(pubkey, amt, acc.Sequence()+1)
+}
+
+func (tx *SendTx) AddInputWithSequence(pubkey acm.PublicKey, amt uint64, sequence uint64) error {
+	addr := pubkey.Address()
+	tx.Inputs = append(tx.Inputs, &TxInput{
+		Address:   addr,
+		Amount:    amt,
+		Sequence:  sequence,
+		PublicKey: pubkey,
+	})
+	return nil
+}
+
+func (tx *SendTx) AddOutput(addr acm.Address, amt uint64) error {
+	tx.Outputs = append(tx.Outputs, &TxOutput{
+		Address: addr,
+		Amount:  amt,
+	})
+	return nil
+}
+
+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))
+	}
+	var err error
+	for i, signingAccount := range signingAccounts {
+		tx.Inputs[i].PublicKey = signingAccount.PublicKey()
+		tx.Inputs[i].Signature, err = acm.ChainSign(signingAccount, chainID, tx)
+		if err != nil {
+			return fmt.Errorf("could not sign tx %v input %v: %v", tx, tx.Inputs[i], err)
+		}
+	}
+	return nil
+}
diff --git a/txs/tx.go b/txs/tx.go
index e79c1e457fdc625f83b42aad39974237e97111db..dec958e22c3f19420a819d81a2f0e10d795bc2f8 100644
--- a/txs/tx.go
+++ b/txs/tx.go
@@ -21,8 +21,6 @@ import (
 	"io"
 
 	acm "github.com/hyperledger/burrow/account"
-	"github.com/hyperledger/burrow/permission/snatives"
-	"github.com/tendermint/go-wire"
 	"github.com/tendermint/go-wire/data"
 	"golang.org/x/crypto/ripemd160"
 )
@@ -37,23 +35,6 @@ var (
 	ErrTxInvalidSignature  = errors.New("error invalid signature")
 )
 
-type ErrTxInvalidString struct {
-	Msg string
-}
-
-func (e ErrTxInvalidString) Error() string {
-	return e.Msg
-}
-
-type ErrTxInvalidSequence struct {
-	Got      uint64
-	Expected uint64
-}
-
-func (e ErrTxInvalidSequence) Error() string {
-	return fmt.Sprintf("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected)
-}
-
 /*
 Tx (Transaction) is an atomic operation on the ledger state.
 
@@ -95,104 +76,35 @@ var mapper = data.NewMapper(Wrapper{}).
 	RegisterImplementation(&RebondTx{}, "rebond_tx", TxTypeRebond).
 	RegisterImplementation(&PermissionsTx{}, "permissions_tx", TxTypePermissions)
 
-//-----------------------------------------------------------------------------
-
-type (
-	// TODO: replace with sum-type struct like ResultEvent
-	Tx interface {
-		WriteSignBytes(chainID string, w io.Writer, n *int, err *error)
-		String() string
-		GetInputs() []TxInput
-		Hash(chainID string) []byte
-	}
-
-	Wrapper struct {
-		Tx `json:"unwrap"`
-	}
+	//-----------------------------------------------------------------------------
 
-	Encoder interface {
-		EncodeTx(tx Tx) ([]byte, error)
-	}
-
-	Decoder interface {
-		DecodeTx(txBytes []byte) (Tx, error)
-	}
-
-	TxInput struct {
-		Address   acm.Address
-		Amount    uint64
-		Sequence  uint64
-		Signature acm.Signature
-		PublicKey acm.PublicKey
-	}
-
-	TxOutput struct {
-		Address acm.Address
-		Amount  uint64
-	}
-
-	// BroadcastTx or Transact
-	Receipt struct {
-		TxHash          []byte
-		CreatesContract bool
-		ContractAddress acm.Address
-	}
-
-	//-------------------
-	// Transaction Types
-	SendTx struct {
-		Inputs  []*TxInput
-		Outputs []*TxOutput
-		txHashMemoizer
-	}
-
-	NameTx struct {
-		Input *TxInput
-		Name  string
-		Data  string
-		Fee   uint64
-		txHashMemoizer
-	}
-
-	CallTx struct {
-		Input *TxInput
-		// Pointer since CallTx defines unset 'to' address as inducing account creation
-		Address  *acm.Address
-		GasLimit uint64
-		Fee      uint64
-		Data     []byte
-		txHashMemoizer
-	}
+// TODO: replace with sum-type struct like ResultEvent
+type Tx interface {
+	WriteSignBytes(chainID string, w io.Writer, n *int, err *error)
+	String() string
+	GetInputs() []TxInput
+	Hash(chainID string) []byte
+	Sign(chainID string, signingAccounts ...acm.AddressableSigner) error
+}
 
-	PermissionsTx struct {
-		Input    *TxInput
-		PermArgs snatives.PermArgs
-		txHashMemoizer
-	}
+type Encoder interface {
+	EncodeTx(tx Tx) ([]byte, error)
+}
 
-	// Out of service
-	BondTx struct {
-		PubKey    acm.PublicKey
-		Signature acm.Signature
-		Inputs    []*TxInput
-		UnbondTo  []*TxOutput
-		txHashMemoizer
-	}
+type Decoder interface {
+	DecodeTx(txBytes []byte) (Tx, error)
+}
 
-	UnbondTx struct {
-		Address   acm.Address
-		Height    int
-		Signature acm.Signature
-		txHashMemoizer
-	}
+// BroadcastTx or Transact
+type Receipt struct {
+	TxHash          []byte
+	CreatesContract bool
+	ContractAddress acm.Address
+}
 
-	RebondTx struct {
-		Address   acm.Address
-		Height    int
-		Signature acm.Signature
-		txHashMemoizer
-	}
-)
+type Wrapper struct {
+	Tx `json:"unwrap"`
+}
 
 // Wrap the Tx in a struct that allows for go-wire JSON serialisation
 func Wrap(tx Tx) Wrapper {
@@ -226,242 +138,6 @@ func (txw *Wrapper) Unwrap() Tx {
 	return txw.Tx
 }
 
-func (txIn *TxInput) ValidateBasic() error {
-	if len(txIn.Address) != 20 {
-		return ErrTxInvalidAddress
-	}
-	if txIn.Amount == 0 {
-		return ErrTxInvalidAmount
-	}
-	return nil
-}
-
-func (txIn *TxInput) WriteSignBytes(w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"address":"%s","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err)
-}
-
-func (txIn *TxInput) String() string {
-	return fmt.Sprintf("TxInput{%s,%v,%v,%v,%v}", txIn.Address, txIn.Amount, txIn.Sequence, txIn.Signature, txIn.PublicKey)
-}
-
-//-----------------------------------------------------------------------------
-
-func (txOut *TxOutput) ValidateBasic() error {
-	if len(txOut.Address) != 20 {
-		return ErrTxInvalidAddress
-	}
-	if txOut.Amount == 0 {
-		return ErrTxInvalidAmount
-	}
-	return nil
-}
-
-func (txOut *TxOutput) WriteSignBytes(w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"address":"%s","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err)
-}
-
-func (txOut *TxOutput) String() string {
-	return fmt.Sprintf("TxOutput{%s,%v}", txOut.Address, txOut.Amount)
-}
-
-//-----------------------------------------------------------------------------
-
-func (tx *SendTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err)
-	for i, in := range tx.Inputs {
-		in.WriteSignBytes(w, n, err)
-		if i != len(tx.Inputs)-1 {
-			wire.WriteTo([]byte(","), w, n, err)
-		}
-	}
-	wire.WriteTo([]byte(`],"outputs":[`), w, n, err)
-	for i, out := range tx.Outputs {
-		out.WriteSignBytes(w, n, err)
-		if i != len(tx.Outputs)-1 {
-			wire.WriteTo([]byte(","), w, n, err)
-		}
-	}
-	wire.WriteTo([]byte(`]}]}`), w, n, err)
-}
-
-func (tx *SendTx) GetInputs() []TxInput {
-	return copyInputs(tx.Inputs)
-}
-
-func (tx *SendTx) String() string {
-	return fmt.Sprintf("SendTx{%v -> %v}", tx.Inputs, tx.Outputs)
-}
-
-func (tx *SendTx) Hash(chainID string) []byte {
-	return tx.txHashMemoizer.hash(chainID, tx)
-}
-
-//-----------------------------------------------------------------------------
-
-func (tx *CallTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err)
-	tx.Input.WriteSignBytes(w, n, err)
-	wire.WriteTo([]byte(`}]}`), w, n, err)
-}
-
-func (tx *CallTx) GetInputs() []TxInput {
-	return []TxInput{*tx.Input}
-}
-
-func (tx *CallTx) String() string {
-	return fmt.Sprintf("CallTx{%v -> %s: %X}", tx.Input, tx.Address, tx.Data)
-}
-
-func (tx *CallTx) Hash(chainID string) []byte {
-	return tx.txHashMemoizer.hash(chainID, tx)
-}
-
-//-----------------------------------------------------------------------------
-
-func (tx *NameTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"data":%s,"fee":%v`, TxTypeName, jsonEscape(tx.Data), tx.Fee)), w, n, err)
-	wire.WriteTo([]byte(`,"input":`), w, n, err)
-	tx.Input.WriteSignBytes(w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"name":%s`, jsonEscape(tx.Name))), w, n, err)
-	wire.WriteTo([]byte(`}]}`), w, n, err)
-}
-
-func (tx *NameTx) GetInputs() []TxInput {
-	return []TxInput{*tx.Input}
-}
-
-func (tx *NameTx) ValidateStrings() error {
-	if len(tx.Name) == 0 {
-		return ErrTxInvalidString{"Name must not be empty"}
-	}
-	if len(tx.Name) > MaxNameLength {
-		return ErrTxInvalidString{fmt.Sprintf("Name is too long. Max %d bytes", MaxNameLength)}
-	}
-	if len(tx.Data) > MaxDataLength {
-		return ErrTxInvalidString{fmt.Sprintf("Data is too long. Max %d bytes", MaxDataLength)}
-	}
-
-	if !validateNameRegEntryName(tx.Name) {
-		return ErrTxInvalidString{fmt.Sprintf("Invalid characters found in NameTx.Name (%s). Only alphanumeric, underscores, dashes, forward slashes, and @ are allowed", tx.Name)}
-	}
-
-	if !validateNameRegEntryData(tx.Data) {
-		return ErrTxInvalidString{fmt.Sprintf("Invalid characters found in NameTx.Data (%s). Only the kind of things found in a JSON file are allowed", tx.Data)}
-	}
-
-	return nil
-}
-
-func (tx *NameTx) String() string {
-	return fmt.Sprintf("NameTx{%v -> %s: %s}", tx.Input, tx.Name, tx.Data)
-}
-
-func (tx *NameTx) Hash(chainID string) []byte {
-	return tx.txHashMemoizer.hash(chainID, tx)
-}
-
-//-----------------------------------------------------------------------------
-
-func (tx *BondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err)
-	for i, in := range tx.Inputs {
-		in.WriteSignBytes(w, n, err)
-		if i != len(tx.Inputs)-1 {
-			wire.WriteTo([]byte(","), w, n, err)
-		}
-	}
-	wire.WriteTo([]byte(fmt.Sprintf(`],"pub_key":`)), w, n, err)
-	wire.WriteTo(wire.JSONBytes(tx.PubKey), w, n, err)
-	wire.WriteTo([]byte(`,"unbond_to":[`), w, n, err)
-	for i, out := range tx.UnbondTo {
-		out.WriteSignBytes(w, n, err)
-		if i != len(tx.UnbondTo)-1 {
-			wire.WriteTo([]byte(","), w, n, err)
-		}
-	}
-	wire.WriteTo([]byte(`]}]}`), w, n, err)
-}
-
-func (tx *BondTx) GetInputs() []TxInput {
-	return copyInputs(tx.Inputs)
-}
-
-func (tx *BondTx) String() string {
-	return fmt.Sprintf("BondTx{%v: %v -> %v}", tx.PubKey, tx.Inputs, tx.UnbondTo)
-}
-
-func (tx *BondTx) Hash(chainID string) []byte {
-	return tx.txHashMemoizer.hash(chainID, tx)
-}
-
-//-----------------------------------------------------------------------------
-
-func (tx *UnbondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err)
-}
-
-func (tx *UnbondTx) GetInputs() []TxInput {
-	return nil
-}
-
-func (tx *UnbondTx) String() string {
-	return fmt.Sprintf("UnbondTx{%s,%v,%v}", tx.Address, tx.Height, tx.Signature)
-}
-
-func (tx *UnbondTx) Hash(chainID string) []byte {
-	return tx.txHashMemoizer.hash(chainID, tx)
-}
-
-//-----------------------------------------------------------------------------
-
-func (tx *RebondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err)
-}
-
-func (tx *RebondTx) GetInputs() []TxInput {
-	return nil
-}
-
-func (tx *RebondTx) String() string {
-	return fmt.Sprintf("RebondTx{%s,%v,%v}", tx.Address, tx.Height, tx.Signature)
-}
-
-func (tx *RebondTx) Hash(chainID string) []byte {
-	return tx.txHashMemoizer.hash(chainID, tx)
-}
-
-//-----------------------------------------------------------------------------
-
-func (tx *PermissionsTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"args":"`, TxTypePermissions)), w, n, err)
-	wire.WriteJSON(&tx.PermArgs, w, n, err)
-	wire.WriteTo([]byte(`","input":`), w, n, err)
-	tx.Input.WriteSignBytes(w, n, err)
-	wire.WriteTo([]byte(`}]}`), w, n, err)
-}
-
-func (tx *PermissionsTx) GetInputs() []TxInput {
-	return []TxInput{*tx.Input}
-}
-
-func (tx *PermissionsTx) String() string {
-	return fmt.Sprintf("PermissionsTx{%v -> %v}", tx.Input, tx.PermArgs)
-}
-
-func (tx *PermissionsTx) Hash(chainID string) []byte {
-	return tx.txHashMemoizer.hash(chainID, tx)
-}
-
-//-----------------------------------------------------------------------------
-
 // Avoid re-hashing the same in-memory Tx
 type txHashMemoizer struct {
 	txHashBytes []byte
@@ -499,6 +175,23 @@ func GenerateReceipt(chainId string, tx Tx) Receipt {
 	return receipt
 }
 
+type ErrTxInvalidString struct {
+	Msg string
+}
+
+func (e ErrTxInvalidString) Error() string {
+	return e.Msg
+}
+
+type ErrTxInvalidSequence struct {
+	Got      uint64
+	Expected uint64
+}
+
+func (e ErrTxInvalidSequence) Error() string {
+	return fmt.Sprintf("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected)
+}
+
 //--------------------------------------------------------------------------------
 
 func copyInputs(inputs []*TxInput) []TxInput {
diff --git a/txs/tx_input.go b/txs/tx_input.go
new file mode 100644
index 0000000000000000000000000000000000000000..8ed9059da1b7d1827b310f8b0b58a77c1ea6ef1d
--- /dev/null
+++ b/txs/tx_input.go
@@ -0,0 +1,35 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/tendermint/go-wire"
+)
+
+type TxInput struct {
+	Address   acm.Address
+	Amount    uint64
+	Sequence  uint64
+	Signature acm.Signature
+	PublicKey acm.PublicKey
+}
+
+func (txIn *TxInput) ValidateBasic() error {
+	if len(txIn.Address) != 20 {
+		return ErrTxInvalidAddress
+	}
+	if txIn.Amount == 0 {
+		return ErrTxInvalidAmount
+	}
+	return nil
+}
+
+func (txIn *TxInput) WriteSignBytes(w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"address":"%s","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err)
+}
+
+func (txIn *TxInput) String() string {
+	return fmt.Sprintf("TxInput{%s,%v,%v,%v,%v}", txIn.Address, txIn.Amount, txIn.Sequence, txIn.Signature, txIn.PublicKey)
+}
diff --git a/txs/tx_output.go b/txs/tx_output.go
new file mode 100644
index 0000000000000000000000000000000000000000..79c17b4953aa5e7ba4c41119e6c7546f4dd8c5a3
--- /dev/null
+++ b/txs/tx_output.go
@@ -0,0 +1,32 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/tendermint/go-wire"
+)
+
+type TxOutput struct {
+	Address acm.Address
+	Amount  uint64
+}
+
+func (txOut *TxOutput) ValidateBasic() error {
+	if len(txOut.Address) != 20 {
+		return ErrTxInvalidAddress
+	}
+	if txOut.Amount == 0 {
+		return ErrTxInvalidAmount
+	}
+	return nil
+}
+
+func (txOut *TxOutput) WriteSignBytes(w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"address":"%s","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err)
+}
+
+func (txOut *TxOutput) String() string {
+	return fmt.Sprintf("TxOutput{%s,%v}", txOut.Address, txOut.Amount)
+}
diff --git a/txs/tx_utils.go b/txs/tx_utils.go
deleted file mode 100644
index dd5ddae2455d1e718e05535d07b8376aa4081b56..0000000000000000000000000000000000000000
--- a/txs/tx_utils.go
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2017 Monax Industries Limited
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package txs
-
-import (
-	"fmt"
-
-	acm "github.com/hyperledger/burrow/account"
-	"github.com/hyperledger/burrow/account/state"
-	"github.com/hyperledger/burrow/permission/snatives"
-)
-
-//----------------------------------------------------------------------------
-// SendTx interface for adding inputs/outputs and adding signatures
-
-func NewSendTx() *SendTx {
-	return &SendTx{
-		Inputs:  []*TxInput{},
-		Outputs: []*TxOutput{},
-	}
-}
-
-func (tx *SendTx) AddInput(st state.AccountGetter, pubkey acm.PublicKey, amt uint64) error {
-	addr := pubkey.Address()
-	acc, err := st.GetAccount(addr)
-	if err != nil {
-		return err
-	}
-	if acc == nil {
-		return fmt.Errorf("invalid address %s from pubkey %s", addr, pubkey)
-	}
-	return tx.AddInputWithSequence(pubkey, amt, acc.Sequence()+1)
-}
-
-func (tx *SendTx) AddInputWithSequence(pubkey acm.PublicKey, amt uint64, sequence uint64) error {
-	addr := pubkey.Address()
-	tx.Inputs = append(tx.Inputs, &TxInput{
-		Address:   addr,
-		Amount:    amt,
-		Sequence:  sequence,
-		PublicKey: pubkey,
-	})
-	return nil
-}
-
-func (tx *SendTx) AddOutput(addr acm.Address, amt uint64) error {
-	tx.Outputs = append(tx.Outputs, &TxOutput{
-		Address: addr,
-		Amount:  amt,
-	})
-	return nil
-}
-
-func (tx *SendTx) SignInput(chainID string, i int, privAccount acm.PrivateAccount) error {
-	if i >= len(tx.Inputs) {
-		return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs))
-	}
-	tx.Inputs[i].PublicKey = privAccount.PublicKey()
-	tx.Inputs[i].Signature = acm.ChainSign(privAccount, chainID, tx)
-	return nil
-}
-
-//----------------------------------------------------------------------------
-// CallTx interface for creating tx
-
-func NewCallTx(st state.AccountGetter, from acm.PublicKey, to *acm.Address, data []byte,
-	amt, gasLimit, fee uint64) (*CallTx, error) {
-
-	addr := from.Address()
-	acc, err := st.GetAccount(addr)
-	if err != nil {
-		return nil, err
-	}
-	if acc == nil {
-		return nil, fmt.Errorf("invalid address %s from pubkey %s", addr, from)
-	}
-
-	sequence := acc.Sequence() + 1
-	return NewCallTxWithSequence(from, to, data, amt, gasLimit, fee, sequence), nil
-}
-
-func NewCallTxWithSequence(from acm.PublicKey, to *acm.Address, data []byte,
-	amt, gasLimit, fee, sequence uint64) *CallTx {
-	input := &TxInput{
-		Address:   from.Address(),
-		Amount:    amt,
-		Sequence:  sequence,
-		PublicKey: from,
-	}
-
-	return &CallTx{
-		Input:    input,
-		Address:  to,
-		GasLimit: gasLimit,
-		Fee:      fee,
-		Data:     data,
-	}
-}
-
-func (tx *CallTx) Sign(chainID string, privAccount acm.PrivateAccount) {
-	tx.Input.PublicKey = privAccount.PublicKey()
-	tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx)
-}
-
-//----------------------------------------------------------------------------
-// NameTx interface for creating tx
-
-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 {
-		return nil, err
-	}
-	if acc == nil {
-		return nil, fmt.Errorf("Invalid address %s from pubkey %s", addr, from)
-	}
-
-	sequence := acc.Sequence() + 1
-	return NewNameTxWithSequence(from, name, data, amt, fee, sequence), nil
-}
-
-func NewNameTxWithSequence(from acm.PublicKey, name, data string, amt, fee, sequence uint64) *NameTx {
-	input := &TxInput{
-		Address:   from.Address(),
-		Amount:    amt,
-		Sequence:  sequence,
-		PublicKey: from,
-	}
-
-	return &NameTx{
-		Input: input,
-		Name:  name,
-		Data:  data,
-		Fee:   fee,
-	}
-}
-
-func (tx *NameTx) Sign(chainID string, privAccount acm.PrivateAccount) {
-	tx.Input.PublicKey = privAccount.PublicKey()
-	tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx)
-}
-
-//----------------------------------------------------------------------------
-// BondTx interface for adding inputs/outputs and adding signatures
-
-func NewBondTx(pubkey acm.PublicKey) (*BondTx, error) {
-	return &BondTx{
-		PubKey:   pubkey,
-		Inputs:   []*TxInput{},
-		UnbondTo: []*TxOutput{},
-	}, nil
-}
-
-func (tx *BondTx) AddInput(st state.AccountGetter, pubkey acm.PublicKey, amt uint64) error {
-	addr := pubkey.Address()
-	acc, err := st.GetAccount(addr)
-	if err != nil {
-		return err
-	}
-	if acc == nil {
-		return fmt.Errorf("Invalid address %s from pubkey %s", addr, pubkey)
-	}
-	return tx.AddInputWithSequence(pubkey, amt, acc.Sequence()+uint64(1))
-}
-
-func (tx *BondTx) AddInputWithSequence(pubkey acm.PublicKey, amt uint64, sequence uint64) error {
-	tx.Inputs = append(tx.Inputs, &TxInput{
-		Address:   pubkey.Address(),
-		Amount:    amt,
-		Sequence:  sequence,
-		PublicKey: pubkey,
-	})
-	return nil
-}
-
-func (tx *BondTx) AddOutput(addr acm.Address, amt uint64) error {
-	tx.UnbondTo = append(tx.UnbondTo, &TxOutput{
-		Address: addr,
-		Amount:  amt,
-	})
-	return nil
-}
-
-func (tx *BondTx) SignBond(chainID string, privAccount acm.PrivateAccount) error {
-	tx.Signature = acm.ChainSign(privAccount, chainID, tx)
-	return nil
-}
-
-func (tx *BondTx) SignInput(chainID string, i int, privAccount acm.PrivateAccount) error {
-	if i >= len(tx.Inputs) {
-		return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs))
-	}
-	tx.Inputs[i].PublicKey = privAccount.PublicKey()
-	tx.Inputs[i].Signature = acm.ChainSign(privAccount, chainID, tx)
-	return nil
-}
-
-//----------------------------------------------------------------------
-// UnbondTx interface for creating tx
-
-func NewUnbondTx(addr acm.Address, height int) *UnbondTx {
-	return &UnbondTx{
-		Address: addr,
-		Height:  height,
-	}
-}
-
-func (tx *UnbondTx) Sign(chainID string, privAccount acm.PrivateAccount) {
-	tx.Signature = acm.ChainSign(privAccount, chainID, tx)
-}
-
-//----------------------------------------------------------------------
-// RebondTx interface for creating tx
-
-func NewRebondTx(addr acm.Address, height int) *RebondTx {
-	return &RebondTx{
-		Address: addr,
-		Height:  height,
-	}
-}
-
-func (tx *RebondTx) Sign(chainID string, privAccount acm.PrivateAccount) {
-	tx.Signature = acm.ChainSign(privAccount, chainID, tx)
-}
-
-//----------------------------------------------------------------------------
-// PermissionsTx interface for creating tx
-
-func NewPermissionsTx(st state.AccountGetter, from acm.PublicKey, args snatives.PermArgs) (*PermissionsTx, error) {
-	addr := from.Address()
-	acc, err := st.GetAccount(addr)
-	if err != nil {
-		return nil, err
-	}
-	if acc == nil {
-		return nil, fmt.Errorf("Invalid address %s from pubkey %s", addr, from)
-	}
-
-	sequence := acc.Sequence() + 1
-	return NewPermissionsTxWithSequence(from, args, sequence), nil
-}
-
-func NewPermissionsTxWithSequence(from acm.PublicKey, args snatives.PermArgs, sequence uint64) *PermissionsTx {
-	input := &TxInput{
-		Address:   from.Address(),
-		Amount:    1, // NOTE: amounts can't be 0 ...
-		Sequence:  sequence,
-		PublicKey: from,
-	}
-
-	return &PermissionsTx{
-		Input:    input,
-		PermArgs: args,
-	}
-}
-
-func (tx *PermissionsTx) Sign(chainID string, privAccount acm.PrivateAccount) {
-	tx.Input.PublicKey = privAccount.PublicKey()
-	tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx)
-}
diff --git a/txs/unbond_tx.go b/txs/unbond_tx.go
new file mode 100644
index 0000000000000000000000000000000000000000..786530295ff2596aea475ea8b534953fa53d0986
--- /dev/null
+++ b/txs/unbond_tx.go
@@ -0,0 +1,55 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/tendermint/go-wire"
+)
+
+type UnbondTx struct {
+	Address   acm.Address
+	Height    int
+	Signature acm.Signature
+	txHashMemoizer
+}
+
+var _ Tx = &UnbondTx{}
+
+func NewUnbondTx(addr acm.Address, height int) *UnbondTx {
+	return &UnbondTx{
+		Address: addr,
+		Height:  height,
+	}
+}
+
+func (tx *UnbondTx) Sign(chainID string, signingAccounts ...acm.AddressableSigner) error {
+	if len(signingAccounts) != 1 {
+		return fmt.Errorf("UnbondTx expects a single AddressableSigner for its signature but %v were provided",
+			len(signingAccounts))
+	}
+	var err error
+	tx.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx)
+	if err != nil {
+		return fmt.Errorf("could not sign %v: %v", tx, err)
+	}
+	return nil
+}
+
+func (tx *UnbondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err)
+}
+
+func (tx *UnbondTx) GetInputs() []TxInput {
+	return nil
+}
+
+func (tx *UnbondTx) String() string {
+	return fmt.Sprintf("UnbondTx{%s,%v,%v}", tx.Address, tx.Height, tx.Signature)
+}
+
+func (tx *UnbondTx) Hash(chainID string) []byte {
+	return tx.txHashMemoizer.hash(chainID, tx)
+}
diff --git a/vendor/github.com/OneOfOne/xxhash/LICENSE b/vendor/github.com/OneOfOne/xxhash/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..9e30b4f342e115f0954c080f9609542fcc23a331
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/LICENSE
@@ -0,0 +1,187 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
diff --git a/vendor/github.com/OneOfOne/xxhash/xxhash.go b/vendor/github.com/OneOfOne/xxhash/xxhash.go
new file mode 100644
index 0000000000000000000000000000000000000000..817783d1a309dca1dd9e44b27fffc7b26a406e55
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/xxhash.go
@@ -0,0 +1,191 @@
+package xxhash
+
+const (
+	prime32x1 uint32 = 2654435761
+	prime32x2 uint32 = 2246822519
+	prime32x3 uint32 = 3266489917
+	prime32x4 uint32 = 668265263
+	prime32x5 uint32 = 374761393
+
+	prime64x1 uint64 = 11400714785074694791
+	prime64x2 uint64 = 14029467366897019727
+	prime64x3 uint64 = 1609587929392839161
+	prime64x4 uint64 = 9650029242287828579
+	prime64x5 uint64 = 2870177450012600261
+
+	maxInt32 int32 = (1<<31 - 1)
+)
+
+// Checksum32 returns the checksum of the input data with the seed set to 0.
+func Checksum32(in []byte) uint32 {
+	return Checksum32S(in, 0)
+}
+
+// ChecksumString32 returns the checksum of the input data, without creating a copy, with the seed set to 0.
+func ChecksumString32(s string) uint32 {
+	return ChecksumString32S(s, 0)
+}
+
+type XXHash32 struct {
+	mem            [16]byte
+	ln, memIdx     int32
+	v1, v2, v3, v4 uint32
+	seed           uint32
+}
+
+// Size returns the number of bytes Sum will return.
+func (xx *XXHash32) Size() int {
+	return 4
+}
+
+// BlockSize returns the hash's underlying block size.
+// The Write method must be able to accept any amount
+// of data, but it may operate more efficiently if all writes
+// are a multiple of the block size.
+func (xx *XXHash32) BlockSize() int {
+	return 16
+}
+
+// NewS32 creates a new hash.Hash32 computing the 32bit xxHash checksum starting with the specific seed.
+func NewS32(seed uint32) (xx *XXHash32) {
+	xx = &XXHash32{
+		seed: seed,
+	}
+	xx.Reset()
+	return
+}
+
+// New32 creates a new hash.Hash32 computing the 32bit xxHash checksum starting with the seed set to 0.
+func New32() *XXHash32 {
+	return NewS32(0)
+}
+
+func (xx *XXHash32) Reset() {
+	xx.v1 = xx.seed + prime32x1 + prime32x2
+	xx.v2 = xx.seed + prime32x2
+	xx.v3 = xx.seed
+	xx.v4 = xx.seed - prime32x1
+	xx.ln, xx.memIdx = 0, 0
+}
+
+// Sum appends the current hash to b and returns the resulting slice.
+// It does not change the underlying hash state.
+func (xx *XXHash32) Sum(in []byte) []byte {
+	s := xx.Sum32()
+	return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
+}
+
+// Checksum64 an alias for Checksum64S(in, 0)
+func Checksum64(in []byte) uint64 {
+	return Checksum64S(in, 0)
+}
+
+// ChecksumString64 returns the checksum of the input data, without creating a copy, with the seed set to 0.
+func ChecksumString64(s string) uint64 {
+	return ChecksumString64S(s, 0)
+}
+
+type XXHash64 struct {
+	v1, v2, v3, v4 uint64
+	seed           uint64
+	ln             uint64
+	mem            [32]byte
+	memIdx         int8
+}
+
+var zeroVs64 = [...]uint64{
+	// workaround static overflow checker
+	func(s uint64) uint64 { return s + prime64x1 + prime64x2 }(0),
+	prime64x2,
+	0,
+	func(s uint64) uint64 { return s - prime64x1 }(0),
+}
+
+// Size returns the number of bytes Sum will return.
+func (xx *XXHash64) Size() int {
+	return 8
+}
+
+// BlockSize returns the hash's underlying block size.
+// The Write method must be able to accept any amount
+// of data, but it may operate more efficiently if all writes
+// are a multiple of the block size.
+func (xx *XXHash64) BlockSize() int {
+	return 32
+}
+
+// NewS64 creates a new hash.Hash64 computing the 64bit xxHash checksum starting with the specific seed.
+func NewS64(seed uint64) (xx *XXHash64) {
+	xx = &XXHash64{
+		seed: seed,
+	}
+	xx.Reset()
+	return
+}
+
+// New64 creates a new hash.Hash64 computing the 64bit xxHash checksum starting with the seed set to 0x0.
+func New64() *XXHash64 {
+	return NewS64(0)
+}
+
+func (xx *XXHash64) Reset() {
+	xx.ln, xx.memIdx = 0, 0
+	xx.v1, xx.v2, xx.v3, xx.v4 = resetVs64(xx.seed)
+}
+
+// Sum appends the current hash to b and returns the resulting slice.
+// It does not change the underlying hash state.
+func (xx *XXHash64) Sum(in []byte) []byte {
+	s := xx.Sum64()
+	return append(in, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
+}
+
+// force the compiler to use ROTL instructions
+
+func rotl32_1(x uint32) uint32  { return (x << 1) | (x >> (32 - 1)) }
+func rotl32_7(x uint32) uint32  { return (x << 7) | (x >> (32 - 7)) }
+func rotl32_11(x uint32) uint32 { return (x << 11) | (x >> (32 - 11)) }
+func rotl32_12(x uint32) uint32 { return (x << 12) | (x >> (32 - 12)) }
+func rotl32_13(x uint32) uint32 { return (x << 13) | (x >> (32 - 13)) }
+func rotl32_17(x uint32) uint32 { return (x << 17) | (x >> (32 - 17)) }
+func rotl32_18(x uint32) uint32 { return (x << 18) | (x >> (32 - 18)) }
+
+func rotl64_1(x uint64) uint64  { return (x << 1) | (x >> (64 - 1)) }
+func rotl64_7(x uint64) uint64  { return (x << 7) | (x >> (64 - 7)) }
+func rotl64_11(x uint64) uint64 { return (x << 11) | (x >> (64 - 11)) }
+func rotl64_12(x uint64) uint64 { return (x << 12) | (x >> (64 - 12)) }
+func rotl64_18(x uint64) uint64 { return (x << 18) | (x >> (64 - 18)) }
+func rotl64_23(x uint64) uint64 { return (x << 23) | (x >> (64 - 23)) }
+func rotl64_27(x uint64) uint64 { return (x << 27) | (x >> (64 - 27)) }
+func rotl64_31(x uint64) uint64 { return (x << 31) | (x >> (64 - 31)) }
+
+func mix64(h uint64) uint64 {
+	h ^= h >> 33
+	h *= prime64x2
+	h ^= h >> 29
+	h *= prime64x3
+	h ^= h >> 32
+	return h
+}
+
+func resetVs64(seed uint64) (v1, v2, v3, v4 uint64) {
+	if seed == 0 {
+		return zeroVs64[0], zeroVs64[1], zeroVs64[2], zeroVs64[3]
+	}
+	return (seed + prime64x1 + prime64x2), (seed + prime64x2), (seed), (seed - prime64x1)
+}
+
+// borrowed from cespare
+func round64(h, v uint64) uint64 {
+	h += v * prime64x2
+	h = rotl64_31(h)
+	h *= prime64x1
+	return h
+}
+
+func mergeRound64(h, v uint64) uint64 {
+	v = round64(0, v)
+	h ^= v
+	h = h*prime64x1 + prime64x4
+	return h
+}
diff --git a/vendor/github.com/OneOfOne/xxhash/xxhash_go17.go b/vendor/github.com/OneOfOne/xxhash/xxhash_go17.go
new file mode 100644
index 0000000000000000000000000000000000000000..d4ebc0530777c9533c3f42f0062cad4b57b0ba17
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/xxhash_go17.go
@@ -0,0 +1,160 @@
+package xxhash
+
+func u32(in []byte) uint32 {
+	return uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
+}
+func u64(in []byte) uint64 {
+	return uint64(in[0]) | uint64(in[1])<<8 | uint64(in[2])<<16 | uint64(in[3])<<24 | uint64(in[4])<<32 | uint64(in[5])<<40 | uint64(in[6])<<48 | uint64(in[7])<<56
+}
+
+// Checksum32S returns the checksum of the input bytes with the specific seed.
+func Checksum32S(in []byte, seed uint32) (h uint32) {
+	var i int
+
+	if len(in) > 15 {
+		var (
+			v1 = seed + prime32x1 + prime32x2
+			v2 = seed + prime32x2
+			v3 = seed + 0
+			v4 = seed - prime32x1
+		)
+		for ; i < len(in)-15; i += 16 {
+			in := in[i : i+16 : len(in)]
+			v1 += u32(in[0:4:len(in)]) * prime32x2
+			v1 = rotl32_13(v1) * prime32x1
+
+			v2 += u32(in[4:8:len(in)]) * prime32x2
+			v2 = rotl32_13(v2) * prime32x1
+
+			v3 += u32(in[8:12:len(in)]) * prime32x2
+			v3 = rotl32_13(v3) * prime32x1
+
+			v4 += u32(in[12:16:len(in)]) * prime32x2
+			v4 = rotl32_13(v4) * prime32x1
+		}
+
+		h = rotl32_1(v1) + rotl32_7(v2) + rotl32_12(v3) + rotl32_18(v4)
+
+	} else {
+		h = seed + prime32x5
+	}
+
+	h += uint32(len(in))
+	for ; i <= len(in)-4; i += 4 {
+		in := in[i : i+4 : len(in)]
+		h += u32(in[0:4:len(in)]) * prime32x3
+		h = rotl32_17(h) * prime32x4
+	}
+
+	for ; i < len(in); i++ {
+		h += uint32(in[i]) * prime32x5
+		h = rotl32_11(h) * prime32x1
+	}
+
+	h ^= h >> 15
+	h *= prime32x2
+	h ^= h >> 13
+	h *= prime32x3
+	h ^= h >> 16
+
+	return
+}
+
+func (xx *XXHash32) Write(in []byte) (n int, err error) {
+	i, ml := 0, int(xx.memIdx)
+	n = len(in)
+	xx.ln += int32(n)
+
+	if d := 16 - ml; ml > 0 && ml+len(in) > 16 {
+		xx.memIdx += int32(copy(xx.mem[xx.memIdx:], in[:d]))
+		ml, in = 16, in[d:len(in):len(in)]
+	} else if ml+len(in) < 16 {
+		xx.memIdx += int32(copy(xx.mem[xx.memIdx:], in))
+		return
+	}
+
+	if ml > 0 {
+		i += 16 - ml
+		xx.memIdx += int32(copy(xx.mem[xx.memIdx:len(xx.mem):len(xx.mem)], in))
+		in := xx.mem[:16:len(xx.mem)]
+
+		xx.v1 += u32(in[0:4:len(in)]) * prime32x2
+		xx.v1 = rotl32_13(xx.v1) * prime32x1
+
+		xx.v2 += u32(in[4:8:len(in)]) * prime32x2
+		xx.v2 = rotl32_13(xx.v2) * prime32x1
+
+		xx.v3 += u32(in[8:12:len(in)]) * prime32x2
+		xx.v3 = rotl32_13(xx.v3) * prime32x1
+
+		xx.v4 += u32(in[12:16:len(in)]) * prime32x2
+		xx.v4 = rotl32_13(xx.v4) * prime32x1
+
+		xx.memIdx = 0
+	}
+
+	for ; i <= len(in)-16; i += 16 {
+		in := in[i : i+16 : len(in)]
+		xx.v1 += u32(in[0:4:len(in)]) * prime32x2
+		xx.v1 = rotl32_13(xx.v1) * prime32x1
+
+		xx.v2 += u32(in[4:8:len(in)]) * prime32x2
+		xx.v2 = rotl32_13(xx.v2) * prime32x1
+
+		xx.v3 += u32(in[8:12:len(in)]) * prime32x2
+		xx.v3 = rotl32_13(xx.v3) * prime32x1
+
+		xx.v4 += u32(in[12:16:len(in)]) * prime32x2
+		xx.v4 = rotl32_13(xx.v4) * prime32x1
+	}
+
+	if len(in)-i != 0 {
+		xx.memIdx += int32(copy(xx.mem[xx.memIdx:], in[i:len(in):len(in)]))
+	}
+
+	return
+}
+
+func (xx *XXHash32) Sum32() (h uint32) {
+	var i int32
+	if xx.ln > 15 {
+		h = rotl32_1(xx.v1) + rotl32_7(xx.v2) + rotl32_12(xx.v3) + rotl32_18(xx.v4)
+	} else {
+		h = xx.seed + prime32x5
+	}
+
+	h += uint32(xx.ln)
+
+	if xx.memIdx > 0 {
+		for ; i < xx.memIdx-3; i += 4 {
+			in := xx.mem[i : i+4 : len(xx.mem)]
+			h += u32(in[0:4:len(in)]) * prime32x3
+			h = rotl32_17(h) * prime32x4
+		}
+
+		for ; i < xx.memIdx; i++ {
+			h += uint32(xx.mem[i]) * prime32x5
+			h = rotl32_11(h) * prime32x1
+		}
+	}
+	h ^= h >> 15
+	h *= prime32x2
+	h ^= h >> 13
+	h *= prime32x3
+	h ^= h >> 16
+
+	return
+}
+
+// Checksum64S returns the 64bit xxhash checksum for a single input
+func Checksum64S(in []byte, seed uint64) uint64 {
+	if len(in) == 0 && seed == 0 {
+		return 0xef46db3751d8e999
+	}
+
+	if len(in) > 31 {
+		return checksum64(in, seed)
+	}
+
+	return checksum64Short(in, seed)
+}
diff --git a/vendor/github.com/OneOfOne/xxhash/xxhash_safe.go b/vendor/github.com/OneOfOne/xxhash/xxhash_safe.go
new file mode 100644
index 0000000000000000000000000000000000000000..5252b774dd19771ce822432c677ebd3a81dfd8be
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/xxhash_safe.go
@@ -0,0 +1,183 @@
+// +build appengine safe
+
+package xxhash
+
+// Backend returns the current version of xxhash being used.
+const Backend = "GoSafe"
+
+func ChecksumString32S(s string, seed uint32) uint32 {
+	return Checksum32S([]byte(s), seed)
+}
+
+func (xx *XXHash32) WriteString(s string) (int, error) {
+	if len(s) == 0 {
+		return 0, nil
+	}
+	return xx.Write([]byte(s))
+}
+
+func ChecksumString64S(s string, seed uint64) uint64 {
+	return Checksum64S([]byte(s), seed)
+}
+
+func (xx *XXHash64) WriteString(s string) (int, error) {
+	if len(s) == 0 {
+		return 0, nil
+	}
+	return xx.Write([]byte(s))
+}
+
+func checksum64(in []byte, seed uint64) (h uint64) {
+	var (
+		v1, v2, v3, v4 = resetVs64(seed)
+
+		i int
+	)
+
+	for ; i < len(in)-31; i += 32 {
+		in := in[i : i+32 : len(in)]
+		v1 = round64(v1, u64(in[0:8:len(in)]))
+		v2 = round64(v2, u64(in[8:16:len(in)]))
+		v3 = round64(v3, u64(in[16:24:len(in)]))
+		v4 = round64(v4, u64(in[24:32:len(in)]))
+	}
+
+	h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)
+
+	h = mergeRound64(h, v1)
+	h = mergeRound64(h, v2)
+	h = mergeRound64(h, v3)
+	h = mergeRound64(h, v4)
+
+	h += uint64(len(in))
+
+	for ; i < len(in)-7; i += 8 {
+		h ^= round64(0, u64(in[i:len(in):len(in)]))
+		h = rotl64_27(h)*prime64x1 + prime64x4
+	}
+
+	for ; i < len(in)-3; i += 4 {
+		h ^= uint64(u32(in[i:len(in):len(in)])) * prime64x1
+		h = rotl64_23(h)*prime64x2 + prime64x3
+	}
+
+	for ; i < len(in); i++ {
+		h ^= uint64(in[i]) * prime64x5
+		h = rotl64_11(h) * prime64x1
+	}
+
+	return mix64(h)
+}
+
+func checksum64Short(in []byte, seed uint64) uint64 {
+	var (
+		h = seed + prime64x5 + uint64(len(in))
+		i int
+	)
+
+	for ; i < len(in)-7; i += 8 {
+		k := u64(in[i : i+8 : len(in)])
+		h ^= round64(0, k)
+		h = rotl64_27(h)*prime64x1 + prime64x4
+	}
+
+	for ; i < len(in)-3; i += 4 {
+		h ^= uint64(u32(in[i:i+4:len(in)])) * prime64x1
+		h = rotl64_23(h)*prime64x2 + prime64x3
+	}
+
+	for ; i < len(in); i++ {
+		h ^= uint64(in[i]) * prime64x5
+		h = rotl64_11(h) * prime64x1
+	}
+
+	return mix64(h)
+}
+
+func (xx *XXHash64) Write(in []byte) (n int, err error) {
+	var (
+		ml = int(xx.memIdx)
+		d  = 32 - ml
+	)
+
+	n = len(in)
+	xx.ln += uint64(n)
+
+	if ml+len(in) < 32 {
+		xx.memIdx += int8(copy(xx.mem[xx.memIdx:len(xx.mem):len(xx.mem)], in))
+		return
+	}
+
+	i, v1, v2, v3, v4 := 0, xx.v1, xx.v2, xx.v3, xx.v4
+	if ml > 0 && ml+len(in) > 32 {
+		xx.memIdx += int8(copy(xx.mem[xx.memIdx:len(xx.mem):len(xx.mem)], in[:d:len(in)]))
+		in = in[d:len(in):len(in)]
+
+		in := xx.mem[0:32:len(xx.mem)]
+
+		v1 = round64(v1, u64(in[0:8:len(in)]))
+		v2 = round64(v2, u64(in[8:16:len(in)]))
+		v3 = round64(v3, u64(in[16:24:len(in)]))
+		v4 = round64(v4, u64(in[24:32:len(in)]))
+
+		xx.memIdx = 0
+	}
+
+	for ; i < len(in)-31; i += 32 {
+		in := in[i : i+32 : len(in)]
+		v1 = round64(v1, u64(in[0:8:len(in)]))
+		v2 = round64(v2, u64(in[8:16:len(in)]))
+		v3 = round64(v3, u64(in[16:24:len(in)]))
+		v4 = round64(v4, u64(in[24:32:len(in)]))
+	}
+
+	if len(in)-i != 0 {
+		xx.memIdx += int8(copy(xx.mem[xx.memIdx:], in[i:len(in):len(in)]))
+	}
+
+	xx.v1, xx.v2, xx.v3, xx.v4 = v1, v2, v3, v4
+
+	return
+}
+
+func (xx *XXHash64) Sum64() (h uint64) {
+	var i int
+	if xx.ln > 31 {
+		v1, v2, v3, v4 := xx.v1, xx.v2, xx.v3, xx.v4
+		h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)
+
+		h = mergeRound64(h, v1)
+		h = mergeRound64(h, v2)
+		h = mergeRound64(h, v3)
+		h = mergeRound64(h, v4)
+	} else {
+		h = xx.seed + prime64x5
+	}
+
+	h += uint64(xx.ln)
+	if xx.memIdx > 0 {
+		in := xx.mem[:xx.memIdx]
+		for ; i < int(xx.memIdx)-7; i += 8 {
+			in := in[i : i+8 : len(in)]
+			k := u64(in[0:8:len(in)])
+			k *= prime64x2
+			k = rotl64_31(k)
+			k *= prime64x1
+			h ^= k
+			h = rotl64_27(h)*prime64x1 + prime64x4
+		}
+
+		for ; i < int(xx.memIdx)-3; i += 4 {
+			in := in[i : i+4 : len(in)]
+			h ^= uint64(u32(in[0:4:len(in)])) * prime64x1
+			h = rotl64_23(h)*prime64x2 + prime64x3
+		}
+
+		for ; i < int(xx.memIdx); i++ {
+			h ^= uint64(in[i]) * prime64x5
+			h = rotl64_11(h) * prime64x1
+		}
+	}
+
+	return mix64(h)
+}
diff --git a/vendor/github.com/OneOfOne/xxhash/xxhash_unsafe.go b/vendor/github.com/OneOfOne/xxhash/xxhash_unsafe.go
new file mode 100644
index 0000000000000000000000000000000000000000..59661249b1e51914cf2861d8f8ee436be8401b76
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/xxhash_unsafe.go
@@ -0,0 +1,234 @@
+// +build !safe
+// +build !appengine
+
+package xxhash
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+// Backend returns the current version of xxhash being used.
+const Backend = "GoUnsafe"
+
+// ChecksumString32S returns the checksum of the input data, without creating a copy, with the specific seed.
+func ChecksumString32S(s string, seed uint32) uint32 {
+	if len(s) == 0 {
+		return Checksum32S(nil, seed)
+	}
+	ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
+	return Checksum32S((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s):len(s)], seed)
+}
+
+func (xx *XXHash32) WriteString(s string) (int, error) {
+	if len(s) == 0 {
+		return 0, nil
+	}
+
+	ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
+	return xx.Write((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s):len(s)])
+}
+
+// ChecksumString64S returns the checksum of the input data, without creating a copy, with the specific seed.
+func ChecksumString64S(s string, seed uint64) uint64 {
+	if len(s) == 0 {
+		return Checksum64S(nil, seed)
+	}
+
+	ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
+	return Checksum64S((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s):len(s)], seed)
+}
+
+func (xx *XXHash64) WriteString(s string) (int, error) {
+	if len(s) == 0 {
+		return 0, nil
+	}
+	ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
+	return xx.Write((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s)])
+}
+
+func checksum64(in []byte, seed uint64) uint64 {
+	var (
+		wordsLen = len(in) >> 3
+		words    = ((*[maxInt32 / 8]uint64)(unsafe.Pointer(&in[0])))[:wordsLen:wordsLen]
+
+		h uint64 = prime64x5
+
+		v1, v2, v3, v4 = resetVs64(seed)
+
+		i int
+	)
+
+	for ; i < len(words)-3; i += 4 {
+		words := (*[4]uint64)(unsafe.Pointer(&words[i]))
+
+		v1 = round64(v1, words[0])
+		v2 = round64(v2, words[1])
+		v3 = round64(v3, words[2])
+		v4 = round64(v4, words[3])
+	}
+
+	h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)
+
+	h = mergeRound64(h, v1)
+	h = mergeRound64(h, v2)
+	h = mergeRound64(h, v3)
+	h = mergeRound64(h, v4)
+
+	h += uint64(len(in))
+
+	for _, k := range words[i:] {
+		h ^= round64(0, k)
+		h = rotl64_27(h)*prime64x1 + prime64x4
+	}
+
+	if in = in[wordsLen<<3 : len(in) : len(in)]; len(in) > 3 {
+		words := (*[1]uint32)(unsafe.Pointer(&in[0]))
+		h ^= uint64(words[0]) * prime64x1
+		h = rotl64_23(h)*prime64x2 + prime64x3
+
+		in = in[4:len(in):len(in)]
+	}
+
+	for _, b := range in {
+		h ^= uint64(b) * prime64x5
+		h = rotl64_11(h) * prime64x1
+	}
+
+	return mix64(h)
+}
+
+func checksum64Short(in []byte, seed uint64) uint64 {
+	var (
+		h = seed + prime64x5 + uint64(len(in))
+		i int
+	)
+
+	if len(in) > 7 {
+		var (
+			wordsLen = len(in) >> 3
+			words    = ((*[maxInt32 / 8]uint64)(unsafe.Pointer(&in[0])))[:wordsLen:wordsLen]
+		)
+
+		for i := range words {
+			h ^= round64(0, words[i])
+			h = rotl64_27(h)*prime64x1 + prime64x4
+		}
+
+		i = wordsLen << 3
+	}
+
+	if in = in[i:len(in):len(in)]; len(in) > 3 {
+		words := (*[1]uint32)(unsafe.Pointer(&in[0]))
+		h ^= uint64(words[0]) * prime64x1
+		h = rotl64_23(h)*prime64x2 + prime64x3
+
+		in = in[4:len(in):len(in)]
+	}
+
+	for _, b := range in {
+		h ^= uint64(b) * prime64x5
+		h = rotl64_11(h) * prime64x1
+	}
+
+	return mix64(h)
+}
+
+func (xx *XXHash64) Write(in []byte) (n int, err error) {
+	mem, idx := xx.mem[:], int(xx.memIdx)
+
+	xx.ln, n = xx.ln+uint64(len(in)), len(in)
+
+	if idx+len(in) < 32 {
+		xx.memIdx += int8(copy(mem[idx:len(mem):len(mem)], in))
+		return
+	}
+
+	var (
+		v1, v2, v3, v4 = xx.v1, xx.v2, xx.v3, xx.v4
+
+		i int
+	)
+
+	if d := 32 - int(idx); d > 0 && int(idx)+len(in) > 31 {
+		copy(mem[idx:len(mem):len(mem)], in[:len(in):len(in)])
+
+		words := (*[4]uint64)(unsafe.Pointer(&mem[0]))
+
+		v1 = round64(v1, words[0])
+		v2 = round64(v2, words[1])
+		v3 = round64(v3, words[2])
+		v4 = round64(v4, words[3])
+
+		if in, xx.memIdx = in[d:len(in):len(in)], 0; len(in) == 0 {
+			goto RET
+		}
+	}
+
+	for ; i < len(in)-31; i += 32 {
+		words := (*[4]uint64)(unsafe.Pointer(&in[i]))
+
+		v1 = round64(v1, words[0])
+		v2 = round64(v2, words[1])
+		v3 = round64(v3, words[2])
+		v4 = round64(v4, words[3])
+	}
+
+	if len(in)-i != 0 {
+		xx.memIdx += int8(copy(mem[xx.memIdx:len(mem):len(mem)], in[i:len(in):len(in)]))
+	}
+
+RET:
+	xx.v1, xx.v2, xx.v3, xx.v4 = v1, v2, v3, v4
+
+	return
+}
+
+func (xx *XXHash64) Sum64() (h uint64) {
+	if seed := xx.seed; xx.ln > 31 {
+		v1, v2, v3, v4 := xx.v1, xx.v2, xx.v3, xx.v4
+		h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)
+
+		h = mergeRound64(h, v1)
+		h = mergeRound64(h, v2)
+		h = mergeRound64(h, v3)
+		h = mergeRound64(h, v4)
+	} else if seed == 0 {
+		h = prime64x5
+	} else {
+		h = seed + prime64x5
+	}
+
+	h += uint64(xx.ln)
+
+	if xx.memIdx == 0 {
+		return mix64(h)
+	}
+
+	var (
+		in       = xx.mem[:xx.memIdx:xx.memIdx]
+		wordsLen = len(in) >> 3
+		words    = ((*[maxInt32 / 8]uint64)(unsafe.Pointer(&in[0])))[:wordsLen:wordsLen]
+	)
+
+	for _, k := range words {
+		h ^= round64(0, k)
+		h = rotl64_27(h)*prime64x1 + prime64x4
+	}
+
+	if in = in[wordsLen<<3 : len(in) : len(in)]; len(in) > 3 {
+		words := (*[1]uint32)(unsafe.Pointer(&in[0]))
+
+		h ^= uint64(words[0]) * prime64x1
+		h = rotl64_23(h)*prime64x2 + prime64x3
+
+		in = in[4:len(in):len(in)]
+	}
+
+	for _, b := range in {
+		h ^= uint64(b) * prime64x5
+		h = rotl64_11(h) * prime64x1
+	}
+
+	return mix64(h)
+}