diff --git a/consensus/tendermint/tendermint.go b/consensus/tendermint/tendermint.go
index a18e35311bc60c7ccc1051d2d30bd3143617dc25..65a58d48603e00ab83bdb63237c64d17c0715e17 100644
--- a/consensus/tendermint/tendermint.go
+++ b/consensus/tendermint/tendermint.go
@@ -27,6 +27,7 @@ import (
 
 	crypto "github.com/tendermint/go-crypto"
 	p2p "github.com/tendermint/go-p2p"
+	tendermint_consensus "github.com/tendermint/tendermint/consensus"
 	node "github.com/tendermint/tendermint/node"
 	proxy "github.com/tendermint/tendermint/proxy"
 	tendermint_types "github.com/tendermint/tendermint/types"
@@ -40,6 +41,8 @@ import (
 	// files  "github.com/eris-ltd/eris-db/files"
 	blockchain_types "github.com/eris-ltd/eris-db/blockchain/types"
 	consensus_types "github.com/eris-ltd/eris-db/consensus/types"
+	"github.com/eris-ltd/eris-db/txs"
+	"github.com/tendermint/go-wire"
 )
 
 type Tendermint struct {
@@ -222,6 +225,44 @@ func (tendermint *Tendermint) BroadcastTransaction(transaction []byte,
 	return tendermint.tmintNode.MempoolReactor().BroadcastTx(transaction, callback)
 }
 
+func (tendermint *Tendermint) ListUnconfirmedTxs(
+	maxTxs int) ([]txs.Tx, error) {
+	tendermintTxs := tendermint.tmintNode.MempoolReactor().Mempool.Reap(maxTxs)
+	transactions := make([]txs.Tx, len(tendermintTxs))
+	for i, txBytes := range tendermintTxs {
+		tx, err := txs.DecodeTx(txBytes)
+		if err != nil {
+			return nil, err
+		}
+		transactions[i] = tx
+	}
+	return transactions, nil
+}
+
+func (tendermint *Tendermint) ListValidators() []consensus_types.Validator {
+	return consensus_types.FromTendermintValidators(tendermint.tmintNode.
+		ConsensusState().Validators.Validators)
+}
+
+func (tendermint *Tendermint) ConsensusState() *consensus_types.ConsensusState {
+	return consensus_types.FromRoundState(tendermint.tmintNode.ConsensusState().
+			GetRoundState())
+}
+
+func (tendermint *Tendermint) PeerConsensusStates() map[string]string {
+	peers := tendermint.tmintNode.Switch().Peers().List()
+	peerConsensusStates := make(map[string]string,
+		len(peers))
+	for _, peer := range peers {
+		peerState := peer.Data.Get(tendermint_types.PeerStateKey).(*tendermint_consensus.PeerState)
+		peerRoundState := peerState.GetRoundState()
+		// TODO: implement a proper mapping, this is a nasty way of marshalling
+		// to JSON
+		peerConsensusStates[peer.Key] = string(wire.JSONBytes(peerRoundState))
+	}
+	return peerConsensusStates
+}
+
 //------------------------------------------------------------------------------
 // Helper functions
 
diff --git a/consensus/types/consensus_engine.go b/consensus/types/consensus_engine.go
index 893ea85ecdbbd0504862236215bda7dcc5e09d55..8600bb3e827091cb22f99be2956449fad0f76783 100644
--- a/consensus/types/consensus_engine.go
+++ b/consensus/types/consensus_engine.go
@@ -2,6 +2,7 @@ package types
 
 import (
 	"github.com/eris-ltd/eris-db/event"
+	"github.com/eris-ltd/eris-db/txs"
 	"github.com/tendermint/go-crypto"
 	"github.com/tendermint/go-p2p"
 	tmsp_types "github.com/tendermint/tmsp/types"
@@ -24,4 +25,13 @@ type ConsensusEngine interface {
 	// Events
 	// For consensus events like NewBlock
 	Events() event.EventEmitter
+
+	// List pending transactions in the mempool, passing 0 for maxTxs gets an
+	// unbounded number of transactions
+	ListUnconfirmedTxs(maxTxs int) ([]txs.Tx, error)
+	ListValidators() []Validator
+	ConsensusState() *ConsensusState
+	// TODO: Consider creating a real type for PeerRoundState, but at the looks
+	// quite coupled to tendermint
+	PeerConsensusStates() map[string]string
 }
diff --git a/consensus/types/consensus_state.go b/consensus/types/consensus_state.go
new file mode 100644
index 0000000000000000000000000000000000000000..80f8fc876bbeb522badddaf35317bd926fc81dbc
--- /dev/null
+++ b/consensus/types/consensus_state.go
@@ -0,0 +1,30 @@
+package types
+
+import (
+	tendermint_consensus "github.com/tendermint/tendermint/consensus"
+	tendermint_types "github.com/tendermint/tendermint/types"
+)
+
+// ConsensusState
+type ConsensusState struct {
+	Height     int                        `json:"height"`
+	Round      int                        `json:"round"`
+	Step       uint8                      `json:"step"`
+	StartTime  string                     `json:"start_time"`
+	CommitTime string                     `json:"commit_time"`
+	Validators []Validator                `json:"validators"`
+	Proposal   *tendermint_types.Proposal `json:"proposal"`
+}
+
+func FromRoundState(rs *tendermint_consensus.RoundState) *ConsensusState {
+	cs := &ConsensusState{
+		CommitTime: rs.CommitTime.String(),
+		Height:     rs.Height,
+		Proposal:   rs.Proposal,
+		Round:      rs.Round,
+		StartTime:  rs.StartTime.String(),
+		Step:       uint8(rs.Step),
+		Validators: FromTendermintValidators(rs.Validators.Validators),
+	}
+	return cs
+}
diff --git a/consensus/types/validator.go b/consensus/types/validator.go
new file mode 100644
index 0000000000000000000000000000000000000000..f5567bbbb0692daea3593d2b6feaf081cbbf793b
--- /dev/null
+++ b/consensus/types/validator.go
@@ -0,0 +1,37 @@
+package types
+
+import (
+	"github.com/tendermint/go-wire"
+	tendermint_types "github.com/tendermint/tendermint/types"
+)
+
+var _ = wire.RegisterInterface(
+	struct{ Validator }{},
+	wire.ConcreteType{&TendermintValidator{}, byte(0x01)},
+)
+
+type Validator interface {
+	AssertIsValidator()
+}
+
+// Anticipating moving to our own definition of Validator, or at least
+// augmenting Tendermint's.
+type TendermintValidator struct {
+	*tendermint_types.Validator `json:"validator"`
+}
+
+func (validator *TendermintValidator) AssertIsValidator() {
+
+}
+
+var _ Validator = (*TendermintValidator)(nil)
+
+func FromTendermintValidators(tmValidators []*tendermint_types.Validator) []Validator {
+	validators := make([]Validator, len(tmValidators))
+	for i, tmValidator := range tmValidators {
+		// This embedding could be replaced by a mapping once if we want to describe
+		// a more general notion of validator
+		validators[i] = &TendermintValidator{tmValidator}
+	}
+	return validators
+}
diff --git a/core/types/types.go b/core/types/types.go
index 738bfb2fc2cf9f86ee64788023b6248d72cb22ab..274900ee723b91a8d6c06fec7a3a58294c3fc183 100644
--- a/core/types/types.go
+++ b/core/types/types.go
@@ -21,14 +21,12 @@ package types
 
 import (
 	"github.com/tendermint/go-p2p" // NodeInfo (drop this!)
-	tendermint_consensus "github.com/tendermint/tendermint/consensus"
 	"github.com/tendermint/tendermint/types"
 
 	account "github.com/eris-ltd/eris-db/account"
 )
 
 type (
-
 	// *********************************** Address ***********************************
 
 	// Accounts
@@ -81,17 +79,6 @@ type (
 
 	// *********************************** Consensus ***********************************
 
-	// ConsensusState
-	ConsensusState struct {
-		Height     int                `json:"height"`
-		Round      int                `json:"round"`
-		Step       uint8              `json:"step"`
-		StartTime  string             `json:"start_time"`
-		CommitTime string             `json:"commit_time"`
-		Validators []*types.Validator `json:"validators"`
-		Proposal   *types.Proposal    `json:"proposal"`
-	}
-
 	// Validators
 	ValidatorList struct {
 		BlockHeight         int                `json:"block_height"`
@@ -159,19 +146,6 @@ type (
 	}
 )
 
-func FromRoundState(rs *tendermint_consensus.RoundState) *ConsensusState {
-	cs := &ConsensusState{
-		CommitTime: rs.CommitTime.String(),
-		Height:     rs.Height,
-		Proposal:   rs.Proposal,
-		Round:      rs.Round,
-		StartTime:  rs.StartTime.String(),
-		Step:       uint8(rs.Step),
-		Validators: rs.Validators.Validators,
-	}
-	return cs
-}
-
 //------------------------------------------------------------------------------
 // copied in from NameReg
 
diff --git a/definitions/tendermint_pipe.go b/definitions/tendermint_pipe.go
index bffa94ad935ba507e82f97f9c87cde93abbe480b..37973ce4dcaffc918d477a19d809ae1a7d808175 100644
--- a/definitions/tendermint_pipe.go
+++ b/definitions/tendermint_pipe.go
@@ -69,4 +69,10 @@ type TendermintPipe interface {
 
 	// Blockchain
 	BlockchainInfo(minHeight, maxHeight, maxBlockLookback int) (*rpc_tm_types.ResultBlockchainInfo, error)
+	ListUnconfirmedTxs(maxTxs int) (*rpc_tm_types.ResultListUnconfirmedTxs, error)
+	GetBlock(height int) (*rpc_tm_types.ResultGetBlock, error)
+
+	// Consensus
+	ListValidators() (*rpc_tm_types.ResultListValidators, error)
+	DumpConsensusState() (*rpc_tm_types.ResultDumpConsensusState, error)
 }
diff --git a/manager/eris-mint/eris-mint.go b/manager/eris-mint/eris-mint.go
index 809540879b1d262b843adadcd544dff5126e609e..55d7374d175569234d9254301204f180e2502229 100644
--- a/manager/eris-mint/eris-mint.go
+++ b/manager/eris-mint/eris-mint.go
@@ -124,8 +124,7 @@ func (app *ErisMint) SetOption(key string, value string) (log string) {
 }
 
 // Implements manager/types.Application
-func (app *ErisMint) AppendTx(txBytes []byte) (res tmsp.Result) {
-
+func (app *ErisMint) AppendTx(txBytes []byte) tmsp.Result {
 	app.nTxs += 1
 
 	// XXX: if we had tx ids we could cache the decoded txs on CheckTx
@@ -149,7 +148,7 @@ func (app *ErisMint) AppendTx(txBytes []byte) (res tmsp.Result) {
 }
 
 // Implements manager/types.Application
-func (app *ErisMint) CheckTx(txBytes []byte) (res tmsp.Result) {
+func (app *ErisMint) CheckTx(txBytes []byte) tmsp.Result {
 	var n int
 	var err error
 	tx := new(txs.Tx)
diff --git a/manager/eris-mint/pipe.go b/manager/eris-mint/pipe.go
index 6339abc2daab3c055b5c1a226223d61036797957..b05ad45e737fbcafa20648029358d97dbb04509c 100644
--- a/manager/eris-mint/pipe.go
+++ b/manager/eris-mint/pipe.go
@@ -47,8 +47,8 @@ import (
 )
 
 type erisMintPipe struct {
-	erisMintState   *state.State
-	erisMint        *ErisMint
+	erisMintState *state.State
+	erisMint      *ErisMint
 	// Pipe implementations
 	accounts        *accounts
 	blockchain      blockchain_types.Blockchain
@@ -58,8 +58,8 @@ type erisMintPipe struct {
 	network         *network
 	transactor      *transactor
 	// Genesis cache
-	genesisDoc      *state_types.GenesisDoc
-	genesisState    *state.State
+	genesisDoc   *state_types.GenesisDoc
+	genesisState *state.State
 }
 
 // NOTE [ben] Compiler check to ensure erisMintPipe successfully implements
@@ -112,11 +112,11 @@ func NewErisMintPipe(moduleConfig *config.ModuleConfig,
 		genesisDoc:   genesisDoc,
 		genesisState: nil,
 		// TODO: What network-level information do we need?
-		network:       newNetwork(),
+		network: newNetwork(),
 		// consensus and blockchain should both be loaded into the pipe by a higher
 		// authority - this is a sort of dependency injection pattern
-		consensusEngine:     nil,
-		blockchain: nil,
+		consensusEngine: nil,
+		blockchain:      nil,
 	}, nil
 }
 
@@ -522,26 +522,34 @@ func (pipe *erisMintPipe) ListNames() (*rpc_tm_types.ResultListNames, error) {
 	return &rpc_tm_types.ResultListNames{blockHeight, names}, nil
 }
 
-// Memory pool
-// NOTE: txs must be signed
-func (pipe *erisMintPipe) BroadcastTxAsync(tx txs.Tx) (
-	*rpc_tm_types.ResultBroadcastTx, error) {
-	err := pipe.consensusEngine.BroadcastTransaction(txs.EncodeTx(tx), nil)
+func (pipe *erisMintPipe) broadcastTx(tx txs.Tx,
+	callback func(res *tmsp_types.Response)) (*rpc_tm_types.ResultBroadcastTx, error) {
+
+	txBytes, err := txs.EncodeTx(tx)
 	if err != nil {
-		return nil, fmt.Errorf("Error broadcasting txs: %v", err)
+		return nil, fmt.Errorf("Error encoding transaction: %v", err)
+	}
+	err = pipe.consensusEngine.BroadcastTransaction(txBytes, callback)
+	if err != nil {
+		return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
 	}
 	return &rpc_tm_types.ResultBroadcastTx{}, nil
 }
 
-func (pipe *erisMintPipe) BroadcastTxSync(tx txs.Tx) (*rpc_tm_types.ResultBroadcastTx,
-	error) {
+// Memory pool
+// NOTE: txs must be signed
+func (pipe *erisMintPipe) BroadcastTxAsync(tx txs.Tx) (*rpc_tm_types.ResultBroadcastTx, error) {
+	return pipe.broadcastTx(tx, nil)
+}
+
+func (pipe *erisMintPipe) BroadcastTxSync(tx txs.Tx) (*rpc_tm_types.ResultBroadcastTx, error) {
 	responseChannel := make(chan *tmsp_types.Response, 1)
-	err := pipe.consensusEngine.BroadcastTransaction(txs.EncodeTx(tx),
+	_, err := pipe.broadcastTx(tx,
 		func(res *tmsp_types.Response) {
 			responseChannel <- res
 		})
 	if err != nil {
-		return nil, fmt.Errorf("Error broadcasting txs: %v", err)
+		return nil, err
 	}
 	// NOTE: [ben] This Response is set in /consensus/tendermint/local_client.go
 	// a call to Application, here implemented by ErisMint, over local callback,
@@ -574,6 +582,18 @@ func (pipe *erisMintPipe) BroadcastTxSync(tx txs.Tx) (*rpc_tm_types.ResultBroadc
 	}
 }
 
+func (pipe *erisMintPipe) ListUnconfirmedTxs(maxTxs int) (*rpc_tm_types.ResultListUnconfirmedTxs, error) {
+	// Get all transactions for now
+	transactions, err := pipe.consensusEngine.ListUnconfirmedTxs(maxTxs)
+	if err != nil {
+		return nil, err
+	}
+	return &rpc_tm_types.ResultListUnconfirmedTxs{
+		N:   len(transactions),
+		Txs: transactions,
+	}, nil
+}
+
 // Returns the current blockchain height and metadata for a range of blocks
 // between minHeight and maxHeight. Only returns maxBlockLookback block metadata
 // from the top of the range of blocks.
@@ -599,5 +619,34 @@ func (pipe *erisMintPipe) BlockchainInfo(minHeight, maxHeight,
 		blockMetas = append(blockMetas, blockMeta)
 	}
 
-	return &rpc_tm_types.ResultBlockchainInfo{latestHeight, blockMetas}, nil
+	return &rpc_tm_types.ResultBlockchainInfo{
+		LastHeight: latestHeight,
+		BlockMetas: blockMetas,
+	}, nil
+}
+
+func (pipe *erisMintPipe) GetBlock(height int) (*rpc_tm_types.ResultGetBlock, error) {
+	return &rpc_tm_types.ResultGetBlock{
+		Block:     pipe.blockchain.Block(height),
+		BlockMeta: pipe.blockchain.BlockMeta(height),
+	}, nil
+}
+
+func (pipe *erisMintPipe) ListValidators() (*rpc_tm_types.ResultListValidators, error) {
+	validators := pipe.consensusEngine.ListValidators()
+	consensusState := pipe.consensusEngine.ConsensusState()
+	// TODO: when we reintroduce support for bonding and unbonding update this
+	// to reflect the mutable bonding state
+	return &rpc_tm_types.ResultListValidators{
+		BlockHeight: consensusState.Height,
+		BondedValidators: validators,
+		UnbondingValidators: nil,
+	}, nil
+}
+
+func (pipe *erisMintPipe) DumpConsensusState() (*rpc_tm_types.ResultDumpConsensusState, error) {
+	return &rpc_tm_types.ResultDumpConsensusState{
+		ConsensusState: pipe.consensusEngine.ConsensusState(),
+		PeerConsensusStates: pipe.consensusEngine.PeerConsensusStates(),
+	}, nil
 }
diff --git a/rpc/tendermint/client/client.go b/rpc/tendermint/client/client.go
index 0758eb20f487ea230557acf905fe6a55738b6a3b..6be71caa662d34786d9e0ec7841e6652ca7f8725 100644
--- a/rpc/tendermint/client/client.go
+++ b/rpc/tendermint/client/client.go
@@ -137,6 +137,9 @@ func performCall(client rpcclient.Client, method string,
 		_, err = cli.Call(method, paramsSlice, &res)
 	case *rpcclient.ClientURI:
 		_, err = cli.Call(method, paramsMap, &res)
+	default:
+		panic(fmt.Errorf("peformCall called against an unknown rpcclient.Client %v",
+			cli))
 	}
 	return
 
diff --git a/rpc/tendermint/core/routes.go b/rpc/tendermint/core/routes.go
index 714c1066d290c7f5cddf148e1064ae9eaf488cd0..8696ba8388d3d336fe5f71aaa2831d19f8d7eef2 100644
--- a/rpc/tendermint/core/routes.go
+++ b/rpc/tendermint/core/routes.go
@@ -38,15 +38,13 @@ func (tmRoutes *TendermintRoutes) GetRoutes() map[string]*rpc.RPCFunc {
 		"get_name":                rpc.NewRPCFunc(tmRoutes.GetNameResult, "name"),
 		"list_names":              rpc.NewRPCFunc(tmRoutes.ListNamesResult, ""),
 		"broadcast_tx":            rpc.NewRPCFunc(tmRoutes.BroadcastTxResult, "tx"),
+		"blockchain":              rpc.NewRPCFunc(tmRoutes.BlockchainInfo, "minHeight,maxHeight"),
+		"get_block":               rpc.NewRPCFunc(tmRoutes.GetBlock, "height"),
+		"list_validators":         rpc.NewRPCFunc(tmRoutes.ListValidators, ""),
+		"list_unconfirmed_txs":    rpc.NewRPCFunc(tmRoutes.ListUnconfirmedTxs, ""),
+		"dump_consensus_state":    rpc.NewRPCFunc(tmRoutes.DumpConsensusState, ""),
 		"unsafe/gen_priv_account": rpc.NewRPCFunc(tmRoutes.GenPrivAccountResult, ""),
 		"unsafe/sign_tx":          rpc.NewRPCFunc(tmRoutes.SignTxResult, "tx,privAccounts"),
-
-		// TODO: hookup
-		"blockchain": rpc.NewRPCFunc(tmRoutes.BlockchainInfo, "minHeight,maxHeight"),
-		//	"get_block":               rpc.NewRPCFunc(GetBlock, "height"),
-		// "list_validators":         rpc.NewRPCFunc(ListValidators, ""),
-		// "dump_consensus_state":    rpc.NewRPCFunc(DumpConsensusState, ""),
-		// "list_unconfirmed_txs":    rpc.NewRPCFunc(ListUnconfirmedTxs, ""),
 		// TODO: [Silas] do we also carry forward "consensus_state" as in v0?
 	}
 	return routes
@@ -211,5 +209,38 @@ func (tmRoutes *TendermintRoutes) BlockchainInfo(minHeight,
 	} else {
 		return r, nil
 	}
+}
 
+func (tmRoutes *TendermintRoutes) ListUnconfirmedTxs() (ctypes.ErisDBResult, error) {
+	// Get all Txs for now
+	r, err := tmRoutes.tendermintPipe.ListUnconfirmedTxs(0)
+	if err != nil {
+		return nil, err
+	} else {
+		return r, nil
+	}
+}
+func (tmRoutes *TendermintRoutes) GetBlock(height int) (ctypes.ErisDBResult, error) {
+	r, err := tmRoutes.tendermintPipe.GetBlock(height)
+	if err != nil {
+		return nil, err
+	} else {
+		return r, nil
+	}
+}
+func (tmRoutes *TendermintRoutes) ListValidators() (ctypes.ErisDBResult, error) {
+	r, err := tmRoutes.tendermintPipe.ListValidators()
+	if err != nil {
+		return nil, err
+	} else {
+		return r, nil
+	}
+}
+func (tmRoutes *TendermintRoutes) DumpConsensusState() (ctypes.ErisDBResult, error) {
+	r, err := tmRoutes.tendermintPipe.DumpConsensusState()
+	if err != nil {
+		return nil, err
+	} else {
+		return r, nil
+	}
 }
diff --git a/rpc/tendermint/core/types/responses.go b/rpc/tendermint/core/types/responses.go
index cacb5f5ff0beb38fc2fc7ec60807a8d9cb079571..41aee0262d21f10f29922b7d1f02ae81f95f0118 100644
--- a/rpc/tendermint/core/types/responses.go
+++ b/rpc/tendermint/core/types/responses.go
@@ -5,7 +5,7 @@ import (
 	core_types "github.com/eris-ltd/eris-db/core/types"
 	stypes "github.com/eris-ltd/eris-db/manager/eris-mint/state/types"
 	"github.com/eris-ltd/eris-db/txs"
-	"github.com/tendermint/tendermint/types"
+	tendermint_types "github.com/tendermint/tendermint/types"
 
 	consensus_types "github.com/eris-ltd/eris-db/consensus/types"
 	"github.com/tendermint/go-crypto"
@@ -42,13 +42,13 @@ type StorageItem struct {
 }
 
 type ResultBlockchainInfo struct {
-	LastHeight int                `json:"last_height"`
-	BlockMetas []*types.BlockMeta `json:"block_metas"`
+	LastHeight int                           `json:"last_height"`
+	BlockMetas []*tendermint_types.BlockMeta `json:"block_metas"`
 }
 
 type ResultGetBlock struct {
-	BlockMeta *types.BlockMeta `json:"block_meta"`
-	Block     *types.Block     `json:"block"`
+	BlockMeta *tendermint_types.BlockMeta `json:"block_meta"`
+	Block     *tendermint_types.Block     `json:"block"`
 }
 
 type ResultStatus struct {
@@ -76,14 +76,14 @@ type ResultNetInfo struct {
 }
 
 type ResultListValidators struct {
-	BlockHeight         int                `json:"block_height"`
-	BondedValidators    []*types.Validator `json:"bonded_validators"`
-	UnbondingValidators []*types.Validator `json:"unbonding_validators"`
+	BlockHeight         int                         `json:"block_height"`
+	BondedValidators    []consensus_types.Validator `json:"bonded_validators"`
+	UnbondingValidators []consensus_types.Validator `json:"unbonding_validators"`
 }
 
 type ResultDumpConsensusState struct {
-	RoundState      string   `json:"round_state"`
-	PeerRoundStates []string `json:"peer_round_states"`
+	ConsensusState      *consensus_types.ConsensusState `json:"consensus_state"`
+	PeerConsensusStates map[string]string              `json:"peer_consensus_states"`
 }
 
 type ResultListNames struct {
@@ -158,28 +158,30 @@ type ErisDBResult interface {
 	rpctypes.Result
 }
 
-// for wire.readReflect
-var _ = wire.RegisterInterface(
-	struct{ ErisDBResult }{},
-	wire.ConcreteType{&ResultGetStorage{}, ResultTypeGetStorage},
-	wire.ConcreteType{&ResultCall{}, ResultTypeCall},
-	wire.ConcreteType{&ResultListAccounts{}, ResultTypeListAccounts},
-	wire.ConcreteType{&ResultDumpStorage{}, ResultTypeDumpStorage},
-	wire.ConcreteType{&ResultBlockchainInfo{}, ResultTypeBlockchainInfo},
-	wire.ConcreteType{&ResultGetBlock{}, ResultTypeGetBlock},
-	wire.ConcreteType{&ResultStatus{}, ResultTypeStatus},
-	wire.ConcreteType{&ResultNetInfo{}, ResultTypeNetInfo},
-	wire.ConcreteType{&ResultListValidators{}, ResultTypeListValidators},
-	wire.ConcreteType{&ResultDumpConsensusState{}, ResultTypeDumpConsensusState},
-	wire.ConcreteType{&ResultListNames{}, ResultTypeListNames},
-	wire.ConcreteType{&ResultGenPrivAccount{}, ResultTypeGenPrivAccount},
-	wire.ConcreteType{&ResultGetAccount{}, ResultTypeGetAccount},
-	wire.ConcreteType{&ResultBroadcastTx{}, ResultTypeBroadcastTx},
-	wire.ConcreteType{&ResultListUnconfirmedTxs{}, ResultTypeListUnconfirmedTxs},
-	wire.ConcreteType{&ResultGetName{}, ResultTypeGetName},
-	wire.ConcreteType{&ResultGenesis{}, ResultTypeGenesis},
-	wire.ConcreteType{&ResultSignTx{}, ResultTypeSignTx},
-	wire.ConcreteType{&ResultEvent{}, ResultTypeEvent},
-	wire.ConcreteType{&ResultSubscribe{}, ResultTypeSubscribe},
-	wire.ConcreteType{&ResultUnsubscribe{}, ResultTypeUnsubscribe},
-)
+func ConcreteTypes() []wire.ConcreteType {
+	return []wire.ConcreteType{
+		{&ResultGetStorage{}, ResultTypeGetStorage},
+		{&ResultCall{}, ResultTypeCall},
+		{&ResultListAccounts{}, ResultTypeListAccounts},
+		{&ResultDumpStorage{}, ResultTypeDumpStorage},
+		{&ResultBlockchainInfo{}, ResultTypeBlockchainInfo},
+		{&ResultGetBlock{}, ResultTypeGetBlock},
+		{&ResultStatus{}, ResultTypeStatus},
+		{&ResultNetInfo{}, ResultTypeNetInfo},
+		{&ResultListValidators{}, ResultTypeListValidators},
+		{&ResultDumpConsensusState{}, ResultTypeDumpConsensusState},
+		{&ResultListNames{}, ResultTypeListNames},
+		{&ResultGenPrivAccount{}, ResultTypeGenPrivAccount},
+		{&ResultGetAccount{}, ResultTypeGetAccount},
+		{&ResultBroadcastTx{}, ResultTypeBroadcastTx},
+		{&ResultListUnconfirmedTxs{}, ResultTypeListUnconfirmedTxs},
+		{&ResultGetName{}, ResultTypeGetName},
+		{&ResultGenesis{}, ResultTypeGenesis},
+		{&ResultSignTx{}, ResultTypeSignTx},
+		{&ResultEvent{}, ResultTypeEvent},
+		{&ResultSubscribe{}, ResultTypeSubscribe},
+		{&ResultUnsubscribe{}, ResultTypeUnsubscribe},
+	}
+}
+
+var _ = wire.RegisterInterface(struct{ ErisDBResult }{}, ConcreteTypes()...)
diff --git a/rpc/tendermint/test/client_rpc_test.go b/rpc/tendermint/test/client_rpc_test.go
deleted file mode 100644
index 1a0a725df29d089b1180435a74e9df380f243a96..0000000000000000000000000000000000000000
--- a/rpc/tendermint/test/client_rpc_test.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// +build integration
-
-// Space above here matters
-package test
-
-import (
-	"testing"
-
-	//	ctypes "github.com/eris-ltd/eris-db/rpc/core/types"
-	_ "github.com/tendermint/tendermint/config/tendermint_test"
-)
-
-// When run with `-test.short` we only run:
-// TestHTTPStatus, TestHTTPBroadcast, TestJSONStatus, TestJSONBroadcast, TestWSConnect, TestWSSend
-
-//--------------------------------------------------------------------------------
-func TestHTTPStatus(t *testing.T) {
-	testStatus(t, "HTTP")
-}
-
-func TestHTTPGetAccount(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testGetAccount(t, "HTTP")
-}
-
-func TestHTTPBroadcastTx(t *testing.T) {
-	testBroadcastTx(t, "HTTP")
-}
-
-func TestHTTPGetStorage(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testGetStorage(t, "HTTP")
-}
-
-func TestHTTPCallCode(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testCallCode(t, "HTTP")
-}
-
-func TestHTTPCallContract(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testCall(t, "HTTP")
-}
-
-func TestHTTPNameReg(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testNameReg(t, "HTTP")
-}
-
-func TestHTTPBlockchainInfo(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testBlockchainInfo(t, "HTTP")
-}
-
-//--------------------------------------------------------------------------------
-// Test the JSONRPC client
-
-func TestJSONStatus(t *testing.T) {
-	testStatus(t, "JSONRPC")
-}
-
-func TestJSONGetAccount(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testGetAccount(t, "JSONRPC")
-}
-
-func TestJSONBroadcastTx(t *testing.T) {
-	testBroadcastTx(t, "JSONRPC")
-}
-
-func TestJSONGetStorage(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testGetStorage(t, "JSONRPC")
-}
-
-func TestJSONCallCode(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testCallCode(t, "JSONRPC")
-}
-
-func TestJSONCallContract(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testCall(t, "JSONRPC")
-}
-
-func TestJSONNameReg(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testNameReg(t, "JSONRPC")
-}
-
-func TestJSONBlockchainInfo(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-	testBlockchainInfo(t, "JSONRPC")
-}
diff --git a/rpc/tendermint/test/common.go b/rpc/tendermint/test/common.go
index 211d3549991fccb6d68a0754f254609311a0591a..76909182df98801eab3e08db5b5c4bbfd03617cf 100644
--- a/rpc/tendermint/test/common.go
+++ b/rpc/tendermint/test/common.go
@@ -4,10 +4,10 @@
 package test
 
 import (
-	"github.com/eris-ltd/eris-db/test/fixtures"
-	rpc_core "github.com/eris-ltd/eris-db/rpc/tendermint/core"
-	"testing"
 	"fmt"
+
+	rpc_core "github.com/eris-ltd/eris-db/rpc/tendermint/core"
+	"github.com/eris-ltd/eris-db/test/fixtures"
 )
 
 // Needs to be referenced by a *_test.go file to be picked up
@@ -26,7 +26,7 @@ func TestWrapper(runner func() int) int {
 	// start a node
 	ready := make(chan error)
 	server := make(chan *rpc_core.TendermintWebsocketServer)
-	defer func(){
+	defer func() {
 		// Shutdown -- make sure we don't hit a race on ffs.RemoveAll
 		tmServer := <-server
 		tmServer.Shutdown()
@@ -48,9 +48,9 @@ func TestWrapper(runner func() int) int {
 // inconsequential, so feel free to insert your own code if you want to use it
 // as an application entry point for delve debugging.
 func DebugMain() {
-	t := &testing.T{}
+	//t := &testing.T{}
 	TestWrapper(func() int {
-		testNameReg(t, "JSONRPC")
+		//testNameReg(t, "JSONRPC")
 		return 0
 	})
 }
diff --git a/rpc/tendermint/test/rpc_client_test.go b/rpc/tendermint/test/rpc_client_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6c3b5887cd5e535bdd70520c3ecd637f6784f5f6
--- /dev/null
+++ b/rpc/tendermint/test/rpc_client_test.go
@@ -0,0 +1,329 @@
+// +build integration
+
+// Space above here matters
+package test
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+
+	"golang.org/x/crypto/ripemd160"
+
+	edbcli "github.com/eris-ltd/eris-db/rpc/tendermint/client"
+	"github.com/eris-ltd/eris-db/txs"
+	"github.com/stretchr/testify/assert"
+	tm_common "github.com/tendermint/go-common"
+	rpcclient "github.com/tendermint/go-rpc/client"
+	_ "github.com/tendermint/tendermint/config/tendermint_test"
+)
+
+// When run with `-test.short` we only run:
+// TestHTTPStatus, TestHTTPBroadcast, TestJSONStatus, TestJSONBroadcast, TestWSConnect, TestWSSend
+
+// Note: the reason that we have tests implemented in tests.go is I believe
+// due to weirdness with go-wire's interface registration, and those global
+// registrations not being available within a *_test.go runtime context.
+func testWithAllClients(t *testing.T,
+	testFunction func(*testing.T, string, rpcclient.Client)) {
+	for clientName, client := range clients {
+		fmt.Printf("\x1b[47m\x1b[31mMARMOT DEBUG: Loop \x1b[0m\n")
+		testFunction(t, clientName, client)
+	}
+}
+
+//--------------------------------------------------------------------------------
+func TestStatus(t *testing.T) {
+	testWithAllClients(t, func(t *testing.T, clientName string, client rpcclient.Client) {
+		resp, err := edbcli.Status(client)
+		if err != nil {
+			t.Fatal(err)
+		}
+		fmt.Println(resp)
+		if resp.NodeInfo.Network != chainID {
+			t.Fatal(fmt.Errorf("ChainID mismatch: got %s expected %s",
+				resp.NodeInfo.Network, chainID))
+		}
+	})
+}
+
+func TestBroadcastTx(t *testing.T) {
+	wsc := newWSClient(t)
+	testWithAllClients(t, func(t *testing.T, clientName string, client rpcclient.Client) {
+		// Avoid duplicate Tx in mempool
+		amt := hashString(clientName) % 1000
+		toAddr := user[1].Address
+		tx := makeDefaultSendTxSigned(t, client, toAddr, amt)
+		//receipt := broadcastTx(t, client, tx)
+		receipt, err := broadcastTxAndWaitForBlock(t, client,wsc, tx)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if receipt.CreatesContract > 0 {
+			t.Fatal("This tx does not create a contract")
+		}
+		if len(receipt.TxHash) == 0 {
+			t.Fatal("Failed to compute tx hash")
+		}
+		n, errp := new(int), new(error)
+		buf := new(bytes.Buffer)
+		hasher := ripemd160.New()
+		tx.WriteSignBytes(chainID, buf, n, errp)
+		if *errp != nil {
+			t.Fatal(*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'",
+				receipt.TxHash, txHashExpected)
+		}
+	})
+}
+
+func TestGetAccount(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test in short mode.")
+	}
+	testWithAllClients(t, func(t *testing.T, clientName string, client rpcclient.Client) {
+		acc := getAccount(t, client, user[0].Address)
+		if acc == nil {
+			t.Fatal("Account was nil")
+		}
+		if bytes.Compare(acc.Address, user[0].Address) != 0 {
+			t.Fatalf("Failed to get correct account. Got %x, expected %x", acc.Address, user[0].Address)
+		}
+	})
+}
+
+func TestGetStorage(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test in short mode.")
+	}
+	testWithAllClients(t, func(t *testing.T, clientName string, client rpcclient.Client) {
+		wsc := newWSClient(t)
+		eid := txs.EventStringNewBlock()
+		subscribe(t, wsc, eid)
+		defer func() {
+			unsubscribe(t, wsc, eid)
+			wsc.Stop()
+		}()
+
+		amt, gasLim, fee := int64(1100), int64(1000), int64(1000)
+		code := []byte{0x60, 0x5, 0x60, 0x1, 0x55}
+		// Call with nil address will create a contract
+		tx := makeDefaultCallTx(t, client, nil, code, amt, gasLim, fee)
+		receipt, err := broadcastTxAndWaitForBlock(t, client, wsc, tx)
+		if err != nil {
+			t.Fatalf("Problem broadcasting transaction: %v", err)
+		}
+		assert.Equal(t, uint8(1), receipt.CreatesContract, "This transaction should"+
+			" create a contract")
+		assert.NotEqual(t, 0, len(receipt.TxHash), "Receipt should contain a"+
+			" transaction hash")
+		contractAddr := receipt.ContractAddr
+		assert.NotEqual(t, 0, len(contractAddr), "Transactions claims to have"+
+			" created a contract but the contract address is empty")
+
+		v := getStorage(t, client, contractAddr, []byte{0x1})
+		got := tm_common.LeftPadWord256(v)
+		expected := tm_common.LeftPadWord256([]byte{0x5})
+		if got.Compare(expected) != 0 {
+			t.Fatalf("Wrong storage value. Got %x, expected %x", got.Bytes(),
+				expected.Bytes())
+		}
+	})
+}
+
+func TestCallCode(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test in short mode.")
+	}
+
+	testWithAllClients(t, func(t *testing.T, clientName string, client rpcclient.Client) {
+		// add two integers and return the result
+		code := []byte{0x60, 0x5, 0x60, 0x6, 0x1, 0x60, 0x0, 0x52, 0x60, 0x20, 0x60,
+			0x0, 0xf3}
+		data := []byte{}
+		expected := []byte{0xb}
+		callCode(t, client, user[0].PubKey.Address(), code, data, expected)
+
+		// pass two ints as calldata, add, and return the result
+		code = []byte{0x60, 0x0, 0x35, 0x60, 0x20, 0x35, 0x1, 0x60, 0x0, 0x52, 0x60,
+			0x20, 0x60, 0x0, 0xf3}
+		data = append(tm_common.LeftPadWord256([]byte{0x5}).Bytes(),
+			tm_common.LeftPadWord256([]byte{0x6}).Bytes()...)
+		expected = []byte{0xb}
+		callCode(t, client, user[0].PubKey.Address(), code, data, expected)
+	})
+}
+
+func TestCallContract(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test in short mode.")
+	}
+	testWithAllClients(t, func(t *testing.T, clientName string, client rpcclient.Client) {
+		wsc := newWSClient(t)
+		eid := txs.EventStringNewBlock()
+		subscribe(t, wsc, eid)
+		defer func() {
+			unsubscribe(t, wsc, eid)
+			wsc.Stop()
+		}()
+
+		// create the contract
+		amt, gasLim, fee := int64(6969), int64(1000), int64(1000)
+		code, _, _ := simpleContract()
+		tx := makeDefaultCallTx(t, client, nil, code, amt, gasLim, fee)
+		receipt, err := broadcastTxAndWaitForBlock(t, client, wsc, tx)
+		if err != nil {
+			t.Fatalf("Problem broadcasting transaction: %v", err)
+		}
+		assert.Equal(t, uint8(1), receipt.CreatesContract, "This transaction should"+
+			" create a contract")
+		assert.NotEqual(t, 0, len(receipt.TxHash), "Receipt should contain a"+
+			" transaction hash")
+		contractAddr := receipt.ContractAddr
+		assert.NotEqual(t, 0, len(contractAddr), "Transactions claims to have"+
+			" created a contract but the contract address is empty")
+
+		// run a call through the contract
+		data := []byte{}
+		expected := []byte{0xb}
+		callContract(t, client, user[0].PubKey.Address(), contractAddr, data, expected)
+	})
+}
+
+func TestNameReg(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test in short mode.")
+	}
+	testWithAllClients(t, func(t *testing.T, clientName string, client rpcclient.Client) {
+		wsc := newWSClient(t)
+
+		txs.MinNameRegistrationPeriod = 1
+
+		// register a new name, check if its there
+		// since entries ought to be unique and these run against different clients, we append the client
+		name := "ye_old_domain_name_" + clientName
+		const data = "if not now, when"
+		fee := int64(1000)
+		numDesiredBlocks := int64(2)
+		amt := fee + numDesiredBlocks*txs.NameByteCostMultiplier*txs.NameBlockCostMultiplier*txs.NameBaseCost(name, data)
+
+		tx := makeDefaultNameTx(t, client, name, data, amt, fee)
+		// verify the name by both using the event and by checking get_name
+		subscribeAndWaitForNext(t, wsc, txs.EventStringNameReg(name),
+			func() {
+				broadcastTxAndWaitForBlock(t, client, wsc, tx)
+			},
+			func(eid string, eventData txs.EventData) (bool, error) {
+				eventDataTx := asEventDataTx(t, eventData)
+				tx, ok := eventDataTx.Tx.(*txs.NameTx)
+				if !ok {
+					t.Fatalf("Could not convert %v to *NameTx", eventDataTx)
+				}
+				assert.Equal(t, name, tx.Name)
+				assert.Equal(t, data, tx.Data)
+				return true, nil
+			})
+		mempoolCount = 0
+
+		entry := getNameRegEntry(t, client, name)
+		assert.Equal(t, data, entry.Data)
+		assert.Equal(t, user[0].Address, entry.Owner)
+
+		// update the data as the owner, make sure still there
+		numDesiredBlocks = int64(5)
+		const updatedData = "these are amongst the things I wish to bestow upon " +
+			"the youth of generations come: a safe supply of honey, and a better " +
+			"money. For what else shall they need"
+		amt = fee + numDesiredBlocks*txs.NameByteCostMultiplier*
+			txs.NameBlockCostMultiplier*txs.NameBaseCost(name, updatedData)
+		tx = makeDefaultNameTx(t, client, name, updatedData, amt, fee)
+		broadcastTxAndWaitForBlock(t, client, wsc, tx)
+		mempoolCount = 0
+		entry = getNameRegEntry(t, client, name)
+
+		assert.Equal(t, updatedData, entry.Data)
+
+		// try to update as non owner, should fail
+		tx = txs.NewNameTxWithNonce(user[1].PubKey, name, "never mind", amt, fee,
+			getNonce(t, client, user[1].Address)+1)
+		tx.Sign(chainID, user[1])
+
+		_, err := broadcastTxAndWaitForBlock(t, client, wsc, tx)
+		assert.Error(t, err, "Expected error when updating someone else's unexpired"+
+			" name registry entry")
+		if err != nil {
+			assert.Contains(t, err.Error(), "permission denied", "Error should be "+
+				"permission denied")
+		}
+
+		// Wait a couple of blocks to make sure name registration expires
+		waitNBlocks(t, wsc, 3)
+
+		//now the entry should be expired, so we can update as non owner
+		const data2 = "this is not my beautiful house"
+		tx = txs.NewNameTxWithNonce(user[1].PubKey, name, data2, amt, fee,
+			getNonce(t, client, user[1].Address)+1)
+		tx.Sign(chainID, user[1])
+		_, err = broadcastTxAndWaitForBlock(t, client, wsc, tx)
+		assert.NoError(t, err, "Should be able to update a previously expired name"+
+			" registry entry as a different address")
+		mempoolCount = 0
+		entry = getNameRegEntry(t, client, name)
+		assert.Equal(t, data2, entry.Data)
+		assert.Equal(t, user[1].Address, entry.Owner)
+	})
+}
+
+func TestBlockchainInfo(t *testing.T) {
+	testWithAllClients(t, func(t *testing.T, clientName string, client rpcclient.Client) {
+		wsc := newWSClient(t)
+		nBlocks := 4
+		waitNBlocks(t, wsc, nBlocks)
+
+		resp, err := edbcli.BlockchainInfo(client, 0, 0)
+		if err != nil {
+			t.Fatalf("Failed to get blockchain info: %v", err)
+		}
+		//TODO: [Silas] reintroduce this when Tendermint changes logic to fire
+		// NewBlock after saving a block
+		// see https://github.com/tendermint/tendermint/issues/273
+		//assert.Equal(t, 4, resp.LastHeight, "Last height should be 4 after waiting for first 4 blocks")
+		assert.True(t, nBlocks <= len(resp.BlockMetas),
+			"Should see at least 4 BlockMetas after waiting for first 4 blocks")
+
+		lastBlockHash := resp.BlockMetas[nBlocks-1].Hash
+		for i := nBlocks - 2; i >= 0; i-- {
+			assert.Equal(t, lastBlockHash, resp.BlockMetas[i].Header.LastBlockHash,
+				"Blockchain should be a hash tree!")
+			lastBlockHash = resp.BlockMetas[i].Hash
+		}
+
+		resp, err = edbcli.BlockchainInfo(client, 1, 2)
+		if err != nil {
+			t.Fatalf("Failed to get blockchain info: %v", err)
+		}
+
+		assert.Equal(t, 2, len(resp.BlockMetas),
+			"Should see 2 BlockMetas after extracting 2 blocks")
+	})
+}
+
+func TestListUnconfirmedTxs(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test in short mode.")
+	}
+}
+
+func asEventDataTx(t *testing.T, eventData txs.EventData) txs.EventDataTx {
+	eventDataTx, ok := eventData.(txs.EventDataTx)
+	if !ok {
+		t.Fatalf("Expected eventData to be EventDataTx was %v", eventData)
+	}
+	return eventDataTx
+}
diff --git a/rpc/tendermint/test/shared.go b/rpc/tendermint/test/shared.go
index d705d27857ecc5db7223f5ecddf5cb3d31a91c5b..0b9254f7a1aeb99f2cab905e1be55df91465900e 100644
--- a/rpc/tendermint/test/shared.go
+++ b/rpc/tendermint/test/shared.go
@@ -2,6 +2,7 @@ package test
 
 import (
 	"bytes"
+	"hash/fnv"
 	"strconv"
 	"testing"
 
@@ -34,8 +35,10 @@ var (
 	websocketAddr     string
 	websocketEndpoint string
 
-	user    = makeUsers(5) // make keys
-	clients map[string]rpcclient.Client
+	user          = makeUsers(5) // make keys
+	jsonRpcClient rpcclient.Client
+	httpClient    rpcclient.Client
+	clients       map[string]rpcclient.Client
 
 	testCore *core.Core
 )
@@ -85,9 +88,12 @@ func initGlobalVariables(ffs *fixtures.FileFixtures) error {
 		return err
 	}
 
+	jsonRpcClient = rpcclient.NewClientJSONRPC(rpcAddr)
+	httpClient = rpcclient.NewClientURI(rpcAddr)
+
 	clients = map[string]rpcclient.Client{
-		"JSONRPC": rpcclient.NewClientURI(rpcAddr),
-		"HTTP":    rpcclient.NewClientJSONRPC(rpcAddr),
+		"JSONRPC": jsonRpcClient,
+		"HTTP":    httpClient,
 	}
 	return nil
 }
@@ -125,34 +131,34 @@ func saveNewPriv() {
 //-------------------------------------------------------------------------------
 // some default transaction functions
 
-func makeDefaultSendTx(t *testing.T, typ string, addr []byte,
+func makeDefaultSendTx(t *testing.T, client rpcclient.Client, addr []byte,
 	amt int64) *txs.SendTx {
-	nonce := getNonce(t, typ, user[0].Address)
+	nonce := getNonce(t, client, user[0].Address)
 	tx := txs.NewSendTx()
 	tx.AddInputWithNonce(user[0].PubKey, amt, nonce+1)
 	tx.AddOutput(addr, amt)
 	return tx
 }
 
-func makeDefaultSendTxSigned(t *testing.T, typ string, addr []byte,
+func makeDefaultSendTxSigned(t *testing.T, client rpcclient.Client, addr []byte,
 	amt int64) *txs.SendTx {
-	tx := makeDefaultSendTx(t, typ, addr, amt)
+	tx := makeDefaultSendTx(t, client, addr, amt)
 	tx.SignInput(chainID, 0, user[0])
 	return tx
 }
 
-func makeDefaultCallTx(t *testing.T, typ string, addr, code []byte, amt, gasLim,
+func makeDefaultCallTx(t *testing.T, client rpcclient.Client, addr, code []byte, amt, gasLim,
 	fee int64) *txs.CallTx {
-	nonce := getNonce(t, typ, user[0].Address)
+	nonce := getNonce(t, client, user[0].Address)
 	tx := txs.NewCallTxWithNonce(user[0].PubKey, addr, code, amt, gasLim, fee,
 		nonce+1)
 	tx.Sign(chainID, user[0])
 	return tx
 }
 
-func makeDefaultNameTx(t *testing.T, typ string, name, value string, amt,
+func makeDefaultNameTx(t *testing.T, client rpcclient.Client, name, value string, amt,
 	fee int64) *txs.NameTx {
-	nonce := getNonce(t, typ, user[0].Address)
+	nonce := getNonce(t, client, user[0].Address)
 	tx := txs.NewNameTxWithNonce(user[0].PubKey, name, value, amt, fee, nonce+1)
 	tx.Sign(chainID, user[0])
 	return tx
@@ -162,8 +168,7 @@ func makeDefaultNameTx(t *testing.T, typ string, name, value string, amt,
 // rpc call wrappers (fail on err)
 
 // get an account's nonce
-func getNonce(t *testing.T, typ string, addr []byte) int {
-	client := clients[typ]
+func getNonce(t *testing.T, client rpcclient.Client, addr []byte) int {
 	ac, err := edbcli.GetAccount(client, addr)
 	if err != nil {
 		t.Fatal(err)
@@ -175,8 +180,7 @@ func getNonce(t *testing.T, typ string, addr []byte) int {
 }
 
 // get the account
-func getAccount(t *testing.T, typ string, addr []byte) *acm.Account {
-	client := clients[typ]
+func getAccount(t *testing.T, client rpcclient.Client, addr []byte) *acm.Account {
 	ac, err := edbcli.GetAccount(client, addr)
 	if err != nil {
 		t.Fatal(err)
@@ -185,9 +189,8 @@ func getAccount(t *testing.T, typ string, addr []byte) *acm.Account {
 }
 
 // sign transaction
-func signTx(t *testing.T, typ string, tx txs.Tx,
+func signTx(t *testing.T, client rpcclient.Client, tx txs.Tx,
 	privAcc *acm.PrivAccount) txs.Tx {
-	client := clients[typ]
 	signedTx, err := edbcli.SignTx(client, tx, []*acm.PrivAccount{privAcc})
 	if err != nil {
 		t.Fatal(err)
@@ -196,8 +199,7 @@ func signTx(t *testing.T, typ string, tx txs.Tx,
 }
 
 // broadcast transaction
-func broadcastTx(t *testing.T, typ string, tx txs.Tx) txs.Receipt {
-	client := clients[typ]
+func broadcastTx(t *testing.T, client rpcclient.Client, tx txs.Tx) txs.Receipt {
 	rec, err := edbcli.BroadcastTx(client, tx)
 	if err != nil {
 		t.Fatal(err)
@@ -216,8 +218,7 @@ func dumpStorage(t *testing.T, addr []byte) *rpc_types.ResultDumpStorage {
 	return resp
 }
 
-func getStorage(t *testing.T, typ string, addr, key []byte) []byte {
-	client := clients[typ]
+func getStorage(t *testing.T, client rpcclient.Client, addr, key []byte) []byte {
 	resp, err := edbcli.GetStorage(client, addr, key)
 	if err != nil {
 		t.Fatal(err)
@@ -252,8 +253,7 @@ func callContract(t *testing.T, client rpcclient.Client, fromAddress, toAddress,
 }
 
 // get the namereg entry
-func getNameRegEntry(t *testing.T, typ string, name string) *core_types.NameRegEntry {
-	client := clients[typ]
+func getNameRegEntry(t *testing.T, client rpcclient.Client, name string) *core_types.NameRegEntry {
 	entry, err := edbcli.GetName(client, name)
 	if err != nil {
 		t.Fatal(err)
@@ -261,29 +261,21 @@ func getNameRegEntry(t *testing.T, typ string, name string) *core_types.NameRegE
 	return entry
 }
 
-//--------------------------------------------------------------------------------
-// utility verification function
-
-func checkTx(t *testing.T, fromAddr []byte, priv *acm.PrivAccount,
-	tx *txs.SendTx) {
-	if bytes.Compare(tx.Inputs[0].Address, fromAddr) != 0 {
-		t.Fatal("Tx input addresses don't match!")
-	}
-
-	signBytes := acm.SignBytes(chainID, tx)
-	in := tx.Inputs[0] //(*types.SendTx).Inputs[0]
-
-	if err := in.ValidateBasic(); err != nil {
-		t.Fatal(err)
-	}
-	// Check signatures
-	// acc := getAccount(t, byteAddr)
-	// NOTE: using the acc here instead of the in fails; it is nil.
-	if !in.PubKey.VerifyBytes(signBytes, in.Signature) {
-		t.Fatal(txs.ErrTxInvalidSignature)
+// Returns a positive int64 hash of text (consumers want int64 instead of uint64)
+func hashString(text string) int64 {
+	hasher := fnv.New64()
+	hasher.Write([]byte(text))
+	value := int64(hasher.Sum64())
+	// Flip the sign if we wrapped
+	if value < 0 {
+		return -value
 	}
+	return value
 }
 
+//--------------------------------------------------------------------------------
+// utility verification function
+
 // simple contract returns 5 + 6 = 0xb
 func simpleContract() ([]byte, []byte, []byte) {
 	// this is the code we want to run when the contract is called
diff --git a/rpc/tendermint/test/tests.go b/rpc/tendermint/test/tests.go
deleted file mode 100644
index 43769b4b0f6f972c151b41c35ed2269ab9ad7a40..0000000000000000000000000000000000000000
--- a/rpc/tendermint/test/tests.go
+++ /dev/null
@@ -1,342 +0,0 @@
-package test
-
-import (
-	"bytes"
-	"fmt"
-	"testing"
-
-	edbcli "github.com/eris-ltd/eris-db/rpc/tendermint/client"
-	core_types "github.com/eris-ltd/eris-db/rpc/tendermint/core/types"
-	"github.com/eris-ltd/eris-db/txs"
-	"github.com/stretchr/testify/assert"
-
-	"time"
-
-	tm_common "github.com/tendermint/go-common"
-	"golang.org/x/crypto/ripemd160"
-)
-
-func testStatus(t *testing.T, typ string) {
-	client := clients[typ]
-	resp, err := edbcli.Status(client)
-	if err != nil {
-		t.Fatal(err)
-	}
-	fmt.Println(resp)
-	if resp.NodeInfo.Network != chainID {
-		t.Fatal(fmt.Errorf("ChainID mismatch: got %s expected %s",
-			resp.NodeInfo.Network, chainID))
-	}
-}
-
-func testGetAccount(t *testing.T, typ string) {
-	acc := getAccount(t, typ, user[0].Address)
-	if acc == nil {
-		t.Fatal("Account was nil")
-	}
-	if bytes.Compare(acc.Address, user[0].Address) != 0 {
-		t.Fatalf("Failed to get correct account. Got %x, expected %x", acc.Address, user[0].Address)
-	}
-}
-
-func testOneSignTx(t *testing.T, typ string, addr []byte, amt int64) {
-	tx := makeDefaultSendTx(t, typ, addr, amt)
-	tx2 := signTx(t, typ, tx, user[0])
-	tx2hash := txs.TxHash(chainID, tx2)
-	tx.SignInput(chainID, 0, user[0])
-	txhash := txs.TxHash(chainID, tx)
-	if bytes.Compare(txhash, tx2hash) != 0 {
-		t.Fatal("Got different signatures for signing via rpc vs tx_utils")
-	}
-
-	tx_ := signTx(t, typ, tx, user[0])
-	tx = tx_.(*txs.SendTx)
-	checkTx(t, user[0].Address, user[0], tx)
-}
-
-func testBroadcastTx(t *testing.T, typ string) {
-	amt := int64(100)
-	toAddr := user[1].Address
-	tx := makeDefaultSendTxSigned(t, typ, toAddr, amt)
-	receipt := broadcastTx(t, typ, tx)
-	if receipt.CreatesContract > 0 {
-		t.Fatal("This tx does not create a contract")
-	}
-	if len(receipt.TxHash) == 0 {
-		t.Fatal("Failed to compute tx hash")
-	}
-	n, err := new(int), new(error)
-	buf := new(bytes.Buffer)
-	hasher := ripemd160.New()
-	tx.WriteSignBytes(chainID, buf, n, err)
-	// [Silas] Currently tx.TxHash uses go-wire, we we drop that we can drop the prefix here
-	goWireBytes := append([]byte{0x01, 0xcf}, buf.Bytes()...)
-	hasher.Write(goWireBytes)
-	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'",
-			receipt.TxHash, txHashExpected)
-	}
-}
-
-func testGetStorage(t *testing.T, typ string) {
-	wsc := newWSClient(t)
-	eid := txs.EventStringNewBlock()
-	subscribe(t, wsc, eid)
-	defer func() {
-		unsubscribe(t, wsc, eid)
-		wsc.Stop()
-	}()
-
-	amt, gasLim, fee := int64(1100), int64(1000), int64(1000)
-	code := []byte{0x60, 0x5, 0x60, 0x1, 0x55}
-	// Call with nil address will create a contract
-	tx := makeDefaultCallTx(t, typ, nil, code, amt, gasLim, fee)
-	receipt, err := broadcastTxAndWaitForBlock(t, typ, wsc, tx)
-	if err != nil {
-		t.Fatalf("Problem broadcasting transaction: %v", err)
-	}
-	assert.Equal(t, uint8(1), receipt.CreatesContract, "This transaction should"+
-		" create a contract")
-	assert.NotEqual(t, 0, len(receipt.TxHash), "Receipt should contain a"+
-		" transaction hash")
-	contractAddr := receipt.ContractAddr
-	assert.NotEqual(t, 0, len(contractAddr), "Transactions claims to have"+
-		" created a contract but the contract address is empty")
-
-	v := getStorage(t, typ, contractAddr, []byte{0x1})
-	got := tm_common.LeftPadWord256(v)
-	expected := tm_common.LeftPadWord256([]byte{0x5})
-	if got.Compare(expected) != 0 {
-		t.Fatalf("Wrong storage value. Got %x, expected %x", got.Bytes(),
-			expected.Bytes())
-	}
-}
-
-func testCallCode(t *testing.T, typ string) {
-	client := clients[typ]
-
-	// add two integers and return the result
-	code := []byte{0x60, 0x5, 0x60, 0x6, 0x1, 0x60, 0x0, 0x52, 0x60, 0x20, 0x60,
-		0x0, 0xf3}
-	data := []byte{}
-	expected := []byte{0xb}
-	callCode(t, client, user[0].PubKey.Address(), code, data, expected)
-
-	// pass two ints as calldata, add, and return the result
-	code = []byte{0x60, 0x0, 0x35, 0x60, 0x20, 0x35, 0x1, 0x60, 0x0, 0x52, 0x60,
-		0x20, 0x60, 0x0, 0xf3}
-	data = append(tm_common.LeftPadWord256([]byte{0x5}).Bytes(),
-		tm_common.LeftPadWord256([]byte{0x6}).Bytes()...)
-	expected = []byte{0xb}
-	callCode(t, client, user[0].PubKey.Address(), code, data, expected)
-}
-
-func testCall(t *testing.T, typ string) {
-	wsc := newWSClient(t)
-	eid := txs.EventStringNewBlock()
-	subscribe(t, wsc, eid)
-	defer func() {
-		unsubscribe(t, wsc, eid)
-		wsc.Stop()
-	}()
-
-	client := clients[typ]
-
-	// create the contract
-	amt, gasLim, fee := int64(6969), int64(1000), int64(1000)
-	code, _, _ := simpleContract()
-	tx := makeDefaultCallTx(t, typ, nil, code, amt, gasLim, fee)
-	receipt, err := broadcastTxAndWaitForBlock(t, typ, wsc, tx)
-	if err != nil {
-		t.Fatalf("Problem broadcasting transaction: %v", err)
-	}
-	assert.Equal(t, uint8(1), receipt.CreatesContract, "This transaction should"+
-		" create a contract")
-	assert.NotEqual(t, 0, len(receipt.TxHash), "Receipt should contain a"+
-		" transaction hash")
-	contractAddr := receipt.ContractAddr
-	assert.NotEqual(t, 0, len(contractAddr), "Transactions claims to have"+
-		" created a contract but the contract address is empty")
-
-	// run a call through the contract
-	data := []byte{}
-	expected := []byte{0xb}
-	callContract(t, client, user[0].PubKey.Address(), contractAddr, data, expected)
-}
-
-func testNameReg(t *testing.T, typ string) {
-	wsc := newWSClient(t)
-
-	txs.MinNameRegistrationPeriod = 1
-
-	// register a new name, check if its there
-	// since entries ought to be unique and these run against different clients, we append the typ
-	name := "ye_old_domain_name_" + typ
-	const data = "if not now, when"
-	fee := int64(1000)
-	numDesiredBlocks := int64(2)
-	amt := fee + numDesiredBlocks*txs.NameByteCostMultiplier*txs.NameBlockCostMultiplier*txs.NameBaseCost(name, data)
-
-	tx := makeDefaultNameTx(t, typ, name, data, amt, fee)
-	// verify the name by both using the event and by checking get_name
-	subscribeAndWaitForNext(t, wsc, txs.EventStringNameReg(name),
-		func() {
-			broadcastTxAndWaitForBlock(t, typ, wsc, tx)
-		},
-		func(eid string, eventData txs.EventData) (bool, error) {
-			eventDataTx := asEventDataTx(t, eventData)
-			tx, ok := eventDataTx.Tx.(*txs.NameTx)
-			if !ok {
-				t.Fatalf("Could not convert %v to *NameTx", eventDataTx)
-			}
-			assert.Equal(t, name, tx.Name)
-			assert.Equal(t, data, tx.Data)
-			return true, nil
-		})
-	mempoolCount = 0
-
-	entry := getNameRegEntry(t, typ, name)
-	assert.Equal(t, data, entry.Data)
-	assert.Equal(t, user[0].Address, entry.Owner)
-
-	// update the data as the owner, make sure still there
-	numDesiredBlocks = int64(5)
-	const updatedData = "these are amongst the things I wish to bestow upon the youth of generations come: a safe supply of honey, and a better money. For what else shall they need"
-	amt = fee + numDesiredBlocks*txs.NameByteCostMultiplier*txs.NameBlockCostMultiplier*txs.NameBaseCost(name, updatedData)
-	tx = makeDefaultNameTx(t, typ, name, updatedData, amt, fee)
-	broadcastTxAndWaitForBlock(t, typ, wsc, tx)
-	mempoolCount = 0
-	entry = getNameRegEntry(t, typ, name)
-
-	assert.Equal(t, updatedData, entry.Data)
-
-	// try to update as non owner, should fail
-	tx = txs.NewNameTxWithNonce(user[1].PubKey, name, "never mind", amt, fee,
-		getNonce(t, typ, user[1].Address)+1)
-	tx.Sign(chainID, user[1])
-
-	_, err := broadcastTxAndWaitForBlock(t, typ, wsc, tx)
-	assert.Error(t, err, "Expected error when updating someone else's unexpired"+
-		" name registry entry")
-	assert.Contains(t, err.Error(), "permission denied", "Error should be " +
-			"permission denied")
-
-	// Wait a couple of blocks to make sure name registration expires
-	waitNBlocks(t, wsc, 3)
-
-	//now the entry should be expired, so we can update as non owner
-	const data2 = "this is not my beautiful house"
-	tx = txs.NewNameTxWithNonce(user[1].PubKey, name, data2, amt, fee,
-		getNonce(t, typ, user[1].Address)+1)
-	tx.Sign(chainID, user[1])
-	_, err = broadcastTxAndWaitForBlock(t, typ, wsc, tx)
-	assert.NoError(t, err, "Should be able to update a previously expired name"+
-		" registry entry as a different address")
-	mempoolCount = 0
-	entry = getNameRegEntry(t, typ, name)
-	assert.Equal(t, data2, entry.Data)
-	assert.Equal(t, user[1].Address, entry.Owner)
-}
-
-// ------ Test Utils -------
-
-func asEventDataTx(t *testing.T, eventData txs.EventData) txs.EventDataTx {
-	eventDataTx, ok := eventData.(txs.EventDataTx)
-	if !ok {
-		t.Fatalf("Expected eventData to be EventDataTx was %v", eventData)
-	}
-	return eventDataTx
-}
-
-func doNothing(_ string, _ txs.EventData) (bool, error) {
-	// And ask waitForEvent to stop waiting
-	return true, nil
-}
-
-func testSubscribe(t *testing.T) {
-	var subId string
-	wsc := newWSClient(t)
-	subscribe(t, wsc, txs.EventStringNewBlock())
-
-	timeout := time.NewTimer(timeoutSeconds * time.Second)
-Subscribe:
-	for {
-		select {
-		case <-timeout.C:
-			t.Fatal("Timed out waiting for subscription result")
-
-		case bs := <-wsc.ResultsCh:
-			resultSubscribe, ok := readResult(t, bs).(*core_types.ResultSubscribe)
-			if ok {
-				assert.Equal(t, txs.EventStringNewBlock(), resultSubscribe.Event)
-				subId = resultSubscribe.SubscriptionId
-				break Subscribe
-			}
-		}
-	}
-
-	seenBlock := false
-	timeout = time.NewTimer(timeoutSeconds * time.Second)
-	for {
-		select {
-		case <-timeout.C:
-			if !seenBlock {
-				t.Fatal("Timed out without seeing a NewBlock event")
-			}
-			return
-
-		case bs := <-wsc.ResultsCh:
-			resultEvent, ok := readResult(t, bs).(*core_types.ResultEvent)
-			if ok {
-				_, ok := resultEvent.Data.(txs.EventDataNewBlock)
-				if ok {
-					if seenBlock {
-						// There's a mild race here, but when we enter we've just seen a block
-						// so we should be able to unsubscribe before we see another block
-						t.Fatal("Continued to see NewBlock event after unsubscribing")
-					} else {
-						seenBlock = true
-						unsubscribe(t, wsc, subId)
-					}
-				}
-			}
-		}
-	}
-}
-
-func testBlockchainInfo(t *testing.T, typ string) {
-	client := clients[typ]
-	wsc := newWSClient(t)
-	nBlocks := 4
-	waitNBlocks(t, wsc, nBlocks)
-
-	resp, err := edbcli.BlockchainInfo(client, 0, 0)
-	if err != nil {
-		t.Fatalf("Failed to get blockchain info: %v", err)
-	}
-	//TODO: [Silas] reintroduce this when Tendermint changes logic to fire
-	// NewBlock after saving a block
-	// see https://github.com/tendermint/tendermint/issues/273
-	//assert.Equal(t, 4, resp.LastHeight, "Last height should be 4 after waiting for first 4 blocks")
-	assert.True(t, nBlocks <= len(resp.BlockMetas),
-		"Should see at least 4 BlockMetas after waiting for first 4 blocks")
-
-	lastBlockHash := resp.BlockMetas[nBlocks-1].Hash
-	for i := nBlocks - 2; i >= 0; i-- {
-		assert.Equal(t, lastBlockHash, resp.BlockMetas[i].Header.LastBlockHash,
-			"Blockchain should be a hash tree!")
-		lastBlockHash = resp.BlockMetas[i].Hash
-	}
-
-	resp, err = edbcli.BlockchainInfo(client, 1, 2)
-	if err != nil {
-		t.Fatalf("Failed to get blockchain info: %v", err)
-	}
-
-	assert.Equal(t, 2, len(resp.BlockMetas),
-		"Should see 2 BlockMetas after extracting 2 blocks")
-
-	fmt.Printf("%v\n", resp)
-}
diff --git a/rpc/tendermint/test/client_ws_test.go b/rpc/tendermint/test/websocket_client_test.go
similarity index 72%
rename from rpc/tendermint/test/client_ws_test.go
rename to rpc/tendermint/test/websocket_client_test.go
index 76c61fde59a4bf39d5973a3981c14333f3433e37..f10ae1e68687c49da1f712a8a7614c83c85713f4 100644
--- a/rpc/tendermint/test/client_ws_test.go
+++ b/rpc/tendermint/test/websocket_client_test.go
@@ -7,13 +7,14 @@ import (
 	"fmt"
 	"testing"
 
+	"time"
+
+	core_types "github.com/eris-ltd/eris-db/rpc/tendermint/core/types"
 	"github.com/eris-ltd/eris-db/txs"
 	"github.com/stretchr/testify/assert"
 	_ "github.com/tendermint/tendermint/config/tendermint_test"
 )
 
-var wsTyp = "JSONRPC"
-
 //--------------------------------------------------------------------------------
 // Test the websocket service
 
@@ -91,8 +92,8 @@ func TestWSSend(t *testing.T) {
 		wsc.Stop()
 	}()
 	waitForEvent(t, wsc, eidInput, func() {
-		tx := makeDefaultSendTxSigned(t, wsTyp, toAddr, amt)
-		broadcastTx(t, wsTyp, tx)
+		tx := makeDefaultSendTxSigned(t, jsonRpcClient, toAddr, amt)
+		broadcastTx(t, jsonRpcClient, tx)
 	}, unmarshalValidateSend(amt, toAddr))
 
 	waitForEvent(t, wsc, eidOutput, func() {},
@@ -115,8 +116,8 @@ func TestWSDoubleFire(t *testing.T) {
 	toAddr := user[1].Address
 	// broadcast the transaction, wait to hear about it
 	waitForEvent(t, wsc, eid, func() {
-		tx := makeDefaultSendTxSigned(t, wsTyp, toAddr, amt)
-		broadcastTx(t, wsTyp, tx)
+		tx := makeDefaultSendTxSigned(t, jsonRpcClient, toAddr, amt)
+		broadcastTx(t, jsonRpcClient, tx)
 	}, func(eid string, b txs.EventData) (bool, error) {
 		return true, nil
 	})
@@ -147,8 +148,8 @@ func TestWSCallWait(t *testing.T) {
 	var contractAddr []byte
 	// wait for the contract to be created
 	waitForEvent(t, wsc, eid1, func() {
-		tx := makeDefaultCallTx(t, wsTyp, nil, code, amt, gasLim, fee)
-		receipt := broadcastTx(t, wsTyp, tx)
+		tx := makeDefaultCallTx(t, jsonRpcClient, nil, code, amt, gasLim, fee)
+		receipt := broadcastTx(t, jsonRpcClient, tx)
 		contractAddr = receipt.ContractAddr
 	}, unmarshalValidateTx(amt, returnCode))
 
@@ -162,8 +163,8 @@ func TestWSCallWait(t *testing.T) {
 	// get the return value from a call
 	data := []byte{0x1}
 	waitForEvent(t, wsc, eid2, func() {
-		tx := makeDefaultCallTx(t, wsTyp, contractAddr, data, amt, gasLim, fee)
-		receipt := broadcastTx(t, wsTyp, tx)
+		tx := makeDefaultCallTx(t, jsonRpcClient, contractAddr, data, amt, gasLim, fee)
+		receipt := broadcastTx(t, jsonRpcClient, tx)
 		contractAddr = receipt.ContractAddr
 	}, unmarshalValidateTx(amt, returnVal))
 }
@@ -178,8 +179,8 @@ func TestWSCallNoWait(t *testing.T) {
 	amt, gasLim, fee := int64(10000), int64(1000), int64(1000)
 	code, _, returnVal := simpleContract()
 
-	tx := makeDefaultCallTx(t, wsTyp, nil, code, amt, gasLim, fee)
-	receipt := broadcastTx(t, wsTyp, tx)
+	tx := makeDefaultCallTx(t, jsonRpcClient, nil, code, amt, gasLim, fee)
+	receipt := broadcastTx(t, jsonRpcClient, tx)
 	contractAddr := receipt.ContractAddr
 
 	// susbscribe to the new contract
@@ -193,8 +194,8 @@ func TestWSCallNoWait(t *testing.T) {
 	// get the return value from a call
 	data := []byte{0x1}
 	waitForEvent(t, wsc, eid, func() {
-		tx := makeDefaultCallTx(t, wsTyp, contractAddr, data, amt, gasLim, fee)
-		broadcastTx(t, wsTyp, tx)
+		tx := makeDefaultCallTx(t, jsonRpcClient, contractAddr, data, amt, gasLim, fee)
+		broadcastTx(t, jsonRpcClient, tx)
 	}, unmarshalValidateTx(amt, returnVal))
 }
 
@@ -209,13 +210,13 @@ func TestWSCallCall(t *testing.T) {
 	txid := new([]byte)
 
 	// deploy the two contracts
-	tx := makeDefaultCallTx(t, wsTyp, nil, code, amt, gasLim, fee)
-	receipt := broadcastTx(t, wsTyp, tx)
+	tx := makeDefaultCallTx(t, jsonRpcClient, nil, code, amt, gasLim, fee)
+	receipt := broadcastTx(t, jsonRpcClient, tx)
 	contractAddr1 := receipt.ContractAddr
 
 	code, _, _ = simpleCallContract(contractAddr1)
-	tx = makeDefaultCallTx(t, wsTyp, nil, code, amt, gasLim, fee)
-	receipt = broadcastTx(t, wsTyp, tx)
+	tx = makeDefaultCallTx(t, jsonRpcClient, nil, code, amt, gasLim, fee)
+	receipt = broadcastTx(t, jsonRpcClient, tx)
 	contractAddr2 := receipt.ContractAddr
 
 	// subscribe to the new contracts
@@ -235,12 +236,59 @@ func TestWSCallCall(t *testing.T) {
 	})
 	// call it
 	waitForEvent(t, wsc, eid, func() {
-		tx := makeDefaultCallTx(t, wsTyp, contractAddr2, nil, amt, gasLim, fee)
-		broadcastTx(t, wsTyp, tx)
+		tx := makeDefaultCallTx(t, jsonRpcClient, contractAddr2, nil, amt, gasLim, fee)
+		broadcastTx(t, jsonRpcClient, tx)
 		*txid = txs.TxHash(chainID, tx)
 	}, unmarshalValidateCall(user[0].Address, returnVal, txid))
 }
 
 func TestSubscribe(t *testing.T) {
-	testSubscribe(t)
+	var subId string
+	wsc := newWSClient(t)
+	subscribe(t, wsc, txs.EventStringNewBlock())
+
+	timeout := time.NewTimer(timeoutSeconds * time.Second)
+Subscribe:
+	for {
+		select {
+		case <-timeout.C:
+			t.Fatal("Timed out waiting for subscription result")
+
+		case bs := <-wsc.ResultsCh:
+			resultSubscribe, ok := readResult(t, bs).(*core_types.ResultSubscribe)
+			if ok {
+				assert.Equal(t, txs.EventStringNewBlock(), resultSubscribe.Event)
+				subId = resultSubscribe.SubscriptionId
+				break Subscribe
+			}
+		}
+	}
+
+	seenBlock := false
+	timeout = time.NewTimer(timeoutSeconds * time.Second)
+	for {
+		select {
+		case <-timeout.C:
+			if !seenBlock {
+				t.Fatal("Timed out without seeing a NewBlock event")
+			}
+			return
+
+		case bs := <-wsc.ResultsCh:
+			resultEvent, ok := readResult(t, bs).(*core_types.ResultEvent)
+			if ok {
+				_, ok := resultEvent.Data.(txs.EventDataNewBlock)
+				if ok {
+					if seenBlock {
+						// There's a mild race here, but when we enter we've just seen a block
+						// so we should be able to unsubscribe before we see another block
+						t.Fatal("Continued to see NewBlock event after unsubscribing")
+					} else {
+						seenBlock = true
+						unsubscribe(t, wsc, subId)
+					}
+				}
+			}
+		}
+	}
 }
diff --git a/rpc/tendermint/test/ws_helpers.go b/rpc/tendermint/test/websocket_helpers.go
similarity index 75%
rename from rpc/tendermint/test/ws_helpers.go
rename to rpc/tendermint/test/websocket_helpers.go
index 1c71a72b812193f75004e8886e562b090c2f6d83..ef34569c31c100fdd4ba9712fef7d86ab7d7286b 100644
--- a/rpc/tendermint/test/ws_helpers.go
+++ b/rpc/tendermint/test/websocket_helpers.go
@@ -2,20 +2,16 @@ package test
 
 import (
 	"bytes"
-	"encoding/json"
 	"fmt"
 	"testing"
 	"time"
 
 	ctypes "github.com/eris-ltd/eris-db/rpc/tendermint/core/types"
 	"github.com/eris-ltd/eris-db/txs"
-	"github.com/tendermint/tendermint/types"
 	tm_types "github.com/tendermint/tendermint/types"
 
 	edbcli "github.com/eris-ltd/eris-db/rpc/tendermint/client"
-	"github.com/tendermint/go-events"
-	client "github.com/tendermint/go-rpc/client"
-	rpctypes "github.com/tendermint/go-rpc/types"
+	rpcclient "github.com/tendermint/go-rpc/client"
 	"github.com/tendermint/go-wire"
 )
 
@@ -27,8 +23,8 @@ const (
 // Utilities for testing the websocket service
 
 // create a new connection
-func newWSClient(t *testing.T) *client.WSClient {
-	wsc := client.NewWSClient(websocketAddr, websocketEndpoint)
+func newWSClient(t *testing.T) *rpcclient.WSClient {
+	wsc := rpcclient.NewWSClient(websocketAddr, websocketEndpoint)
 	if _, err := wsc.Start(); err != nil {
 		t.Fatal(err)
 	}
@@ -36,13 +32,13 @@ func newWSClient(t *testing.T) *client.WSClient {
 }
 
 // subscribe to an event
-func subscribe(t *testing.T, wsc *client.WSClient, eventId string) {
+func subscribe(t *testing.T, wsc *rpcclient.WSClient, eventId string) {
 	if err := wsc.Subscribe(eventId); err != nil {
 		t.Fatal(err)
 	}
 }
 
-func subscribeAndGetSubscriptionId(t *testing.T, wsc *client.WSClient,
+func subscribeAndGetSubscriptionId(t *testing.T, wsc *rpcclient.WSClient,
 	eventId string) string {
 	if err := wsc.Subscribe(eventId); err != nil {
 		t.Fatal(err)
@@ -63,14 +59,14 @@ func subscribeAndGetSubscriptionId(t *testing.T, wsc *client.WSClient,
 }
 
 // unsubscribe from an event
-func unsubscribe(t *testing.T, wsc *client.WSClient, subscriptionId string) {
+func unsubscribe(t *testing.T, wsc *rpcclient.WSClient, subscriptionId string) {
 	if err := wsc.Unsubscribe(subscriptionId); err != nil {
 		t.Fatal(err)
 	}
 }
 
 // broadcast transaction and wait for new block
-func broadcastTxAndWaitForBlock(t *testing.T, typ string, wsc *client.WSClient,
+func broadcastTxAndWaitForBlock(t *testing.T, client rpcclient.Client, wsc *rpcclient.WSClient,
 	tx txs.Tx) (txs.Receipt, error) {
 	var rec txs.Receipt
 	var err error
@@ -86,17 +82,17 @@ func broadcastTxAndWaitForBlock(t *testing.T, typ string, wsc *client.WSClient,
 				// state updates, so we have to wait for the block after the block we
 				// want in order for the Tx to be genuinely final.
 				// This should be addressed by: https://github.com/tendermint/tendermint/pull/265
-				return block.Height > initialHeight + 1
+				return block.Height > initialHeight+1
 			}
 		},
 		func() {
-			rec, err = edbcli.BroadcastTx(clients[typ], tx)
+			rec, err = edbcli.BroadcastTx(client, tx)
 			mempoolCount += 1
 		})
 	return rec, err
 }
 
-func waitNBlocks(t *testing.T, wsc *client.WSClient, n int) {
+func waitNBlocks(t *testing.T, wsc *rpcclient.WSClient, n int) {
 	i := 0
 	runThenWaitForBlock(t, wsc,
 		func(block *tm_types.Block) bool {
@@ -106,7 +102,7 @@ func waitNBlocks(t *testing.T, wsc *client.WSClient, n int) {
 		func() {})
 }
 
-func runThenWaitForBlock(t *testing.T, wsc *client.WSClient,
+func runThenWaitForBlock(t *testing.T, wsc *rpcclient.WSClient,
 	blockPredicate func(*tm_types.Block) bool, runner func()) {
 	subscribeAndWaitForNext(t, wsc, txs.EventStringNewBlock(),
 		runner,
@@ -115,7 +111,7 @@ func runThenWaitForBlock(t *testing.T, wsc *client.WSClient,
 		})
 }
 
-func subscribeAndWaitForNext(t *testing.T, wsc *client.WSClient, event string,
+func subscribeAndWaitForNext(t *testing.T, wsc *rpcclient.WSClient, event string,
 	runner func(),
 	eventDataChecker func(string, txs.EventData) (bool, error)) {
 	subId := subscribeAndGetSubscriptionId(t, wsc, event)
@@ -134,7 +130,7 @@ func subscribeAndWaitForNext(t *testing.T, wsc *client.WSClient, event string,
 // stopWaiting is true waitForEvent will return or if stopWaiting is false
 // waitForEvent will keep listening for new events. If an error is returned
 // waitForEvent will fail the test.
-func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string,
+func waitForEvent(t *testing.T, wsc *rpcclient.WSClient, eventid string,
 	runner func(),
 	eventDataChecker func(string, txs.EventData) (bool, error)) waitForEventResult {
 
@@ -207,45 +203,8 @@ func (err waitForEventResult) Timeout() bool {
 	return err.timeout
 }
 
-func acceptFirstBlock(_ *tm_types.Block) bool {
-	return true
-}
-
 //--------------------------------------------------------------------------------
 
-func unmarshalResponseNewBlock(b []byte) (*types.Block, error) {
-	// unmarshall and assert somethings
-	var response rpctypes.RPCResponse
-	var err error
-	wire.ReadJSON(&response, b, &err)
-	if err != nil {
-		return nil, err
-	}
-	if response.Error != "" {
-		return nil, fmt.Errorf(response.Error)
-	}
-	// TODO
-	//block := response.Result.(*ctypes.ResultEvent).Data.(types.EventDataNewBlock).Block
-	// return block, nil
-	return nil, nil
-}
-
-func unmarshalResponseNameReg(b []byte) (*txs.NameTx, error) {
-	// unmarshall and assert somethings
-	var response rpctypes.RPCResponse
-	var err error
-	wire.ReadJSON(&response, b, &err)
-	if err != nil {
-		return nil, err
-	}
-	if response.Error != "" {
-		return nil, fmt.Errorf(response.Error)
-	}
-	_, val := UnmarshalEvent(*response.Result)
-	tx := txs.DecodeTx(val.(types.EventDataTx).Tx).(*txs.NameTx)
-	return tx, nil
-}
-
 func unmarshalValidateSend(amt int64,
 	toAddr []byte) func(string, txs.EventData) (bool, error) {
 	return func(eid string, eventData txs.EventData) (bool, error) {
@@ -314,22 +273,6 @@ func unmarshalValidateCall(origin,
 	}
 }
 
-// Unmarshal a json event
-func UnmarshalEvent(b json.RawMessage) (string, events.EventData) {
-	var err error
-	result := new(ctypes.ErisDBResult)
-	wire.ReadJSONPtr(result, b, &err)
-	if err != nil {
-		panic(err)
-	}
-	event, ok := (*result).(*ctypes.ResultEvent)
-	if !ok {
-		return "", nil // TODO: handle non-event messages (ie. return from subscribe/unsubscribe)
-		// fmt.Errorf("Result is not type *ctypes.ResultEvent. Got %v", reflect.TypeOf(*result))
-	}
-	return event.Event, event.Data
-}
-
 func readResult(t *testing.T, bs []byte) ctypes.ErisDBResult {
 	var err error
 	result := new(ctypes.ErisDBResult)
diff --git a/rpc/v0/methods.go b/rpc/v0/methods.go
index b3aac0e9d5ea0a8a9d53dd18c283151d3e0900c8..8e888e6b3dd69d026c4c2c5e638e06e05c16220a 100644
--- a/rpc/v0/methods.go
+++ b/rpc/v0/methods.go
@@ -256,17 +256,11 @@ func (erisDbMethods *ErisDbMethods) Block(request *rpc.RPCRequest, requester int
 // *************************************** Consensus ************************************
 
 func (erisDbMethods *ErisDbMethods) ConsensusState(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) {
-	// TODO: [Silas] erisDbMethods has not implemented this since the refactor
-	// core_types.FromRoundState() will do it, but only if we have access to
-	// Tendermint's RonudState..
-	state := &core_types.ConsensusState{}
-	return state, 0, nil
+	return erisDbMethods.pipe.Consensus().ConsensusState(), 0, nil
 }
 
 func (erisDbMethods *ErisDbMethods) Validators(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) {
-	// TODO: [Silas] erisDbMethods has not implemented this since the refactor
-	validators := &core_types.ValidatorList{}
-	return validators, 0, nil
+	return erisDbMethods.pipe.Consensus().ListValidators(), 0, nil
 }
 
 // *************************************** Net ************************************
diff --git a/rpc/v0/restServer.go b/rpc/v0/restServer.go
index d6ad13bd29589c3ebbff44d86696446ace251dce..42c925a3634e349bcdbd81f855ecd3c51b0fd381 100644
--- a/rpc/v0/restServer.go
+++ b/rpc/v0/restServer.go
@@ -221,17 +221,13 @@ func (restServer *RestServer) handleBlock(c *gin.Context) {
 
 // ********************************* Consensus *********************************
 func (restServer *RestServer) handleConsensusState(c *gin.Context) {
-	// TODO: [Silas] erisDbMethods has not implemented this since the refactor
-	// core_types.FromRoundState() will do it, but only if we have access to
-	// Tendermint's RonudState..
-	cs := &core_types.ConsensusState{}
+	cs := restServer.pipe.Consensus().ConsensusState()
 	c.Writer.WriteHeader(200)
 	restServer.codec.Encode(cs, c.Writer)
 }
 
 func (restServer *RestServer) handleValidatorList(c *gin.Context) {
-	// TODO: [Silas] erisDbMethods has not implemented this since the refactor
-	vl := &core_types.ValidatorList{}
+	vl := restServer.pipe.Consensus().ListValidators()
 	c.Writer.WriteHeader(200)
 	restServer.codec.Encode(vl, c.Writer)
 }
diff --git a/test/mock/pipe.go b/test/mock/pipe.go
index 78ba9d38783445c94f85e70f6871ca71dffd91c6..b8394ad9ad9e73db7cd0aa46d04bf86f40456f40 100644
--- a/test/mock/pipe.go
+++ b/test/mock/pipe.go
@@ -208,6 +208,23 @@ func (cons *consensusEngine) Events() event.EventEmitter {
 	return nil
 }
 
+func (cons *consensusEngine) ListUnconfirmedTxs(maxTxs int) ([]txs.Tx, error) {
+	return nil, nil
+
+}
+
+func (cons *consensusEngine) ListValidators() []consensus_types.Validator {
+	return nil
+}
+
+func (cons *consensusEngine) ConsensusState() *consensus_types.ConsensusState {
+	return &consensus_types.ConsensusState{}
+}
+
+func (cons *consensusEngine) PeerConsensusStates() map[string]string {
+	return map[string]string{}
+}
+
 // Events
 type eventer struct {
 	testData *td.TestData
diff --git a/test/testdata/testdata/testdata.go b/test/testdata/testdata/testdata.go
index 56894ecb5a55601ba90f8d542e458dfce66f7442..f42cdccdcf595cc1133d647b247ddc0c00c54d25 100644
--- a/test/testdata/testdata/testdata.go
+++ b/test/testdata/testdata/testdata.go
@@ -2,16 +2,22 @@ package testdata
 
 import (
 	account "github.com/eris-ltd/eris-db/account"
+	consensus_types "github.com/eris-ltd/eris-db/consensus/types"
 	core_types "github.com/eris-ltd/eris-db/core/types"
 	event "github.com/eris-ltd/eris-db/event"
 	stypes "github.com/eris-ltd/eris-db/manager/eris-mint/state/types"
 	rpc_v0 "github.com/eris-ltd/eris-db/rpc/v0"
 	transaction "github.com/eris-ltd/eris-db/txs"
-
 	mintTypes "github.com/tendermint/tendermint/types"
 )
 
-var testDataJson = `{
+// TODO: [Silas] This would really be much better as a composite literal in go
+// where the compiler/type system/IDE would make it easier to maintain
+// not entirely straightforward to convert it, but shouldn't be that hard either
+// with recursive use of fmt.Printf("%#v", subStruct) on the decoded in-memory
+// object
+var testDataJson = `
+{
   "chain_data": {
     "priv_validator": {
       "address": "37236DF251AB70022B1DA351F08A20FB52443E37",
@@ -53,7 +59,10 @@ var testDataJson = `{
       ],
       "validators": [
         {
-          "pub_key": [1, "CB3688B7561D488A2A4834E1AEE9398BEF94844D8BDBBCA980C11E3654A45906"],
+          "pub_key": [
+            1,
+            "CB3688B7561D488A2A4834E1AEE9398BEF94844D8BDBBCA980C11E3654A45906"
+          ],
           "amount": 5000000000,
           "unbond_to": [
             {
@@ -92,20 +101,20 @@ var testDataJson = `{
     "output": {
       "accounts": [
         {
-	      "address": "0000000000000000000000000000000000000000",
-	      "pub_key": null,
-	      "sequence": 0,
-	      "balance": 1337,
-	      "code": "",
-	      "storage_root": "",
-	      "permissions": {
-	        "base": {
-	          "perms": 2302,
-	          "set": 16383
-	        },
-	        "roles": []
-	      }
-	    },
+          "address": "0000000000000000000000000000000000000000",
+          "pub_key": null,
+          "sequence": 0,
+          "balance": 1337,
+          "code": "",
+          "storage_root": "",
+          "permissions": {
+            "base": {
+              "perms": 2302,
+              "set": 16383
+            },
+            "roles": []
+          }
+        },
         {
           "address": "0000000000000000000000000000000000000002",
           "pub_key": null,
@@ -243,7 +252,9 @@ var testDataJson = `{
     "output": {}
   },
   "GetBlock": {
-    "input": {"height": 0},
+    "input": {
+      "height": 0
+    },
     "output": null
   },
   "GetBlocks": {
@@ -264,15 +275,23 @@ var testDataJson = `{
       "start_time": "",
       "commit_time": "0001-01-01 00:00:00 +0000 UTC",
       "validators": [
-        {
-          "address": "37236DF251AB70022B1DA351F08A20FB52443E37",
-          "pub_key": [1, "CB3688B7561D488A2A4834E1AEE9398BEF94844D8BDBBCA980C11E3654A45906"],
-          "bond_height": 0,
-          "unbond_height": 0,
-          "last_commit_height": 0,
-          "voting_power": 5000000000,
-          "accum": 0
-        }
+        [
+          1,
+          {
+            "validator": {
+              "address": "37236DF251AB70022B1DA351F08A20FB52443E37",
+              "pub_key": [
+                1,
+                "CB3688B7561D488A2A4834E1AEE9398BEF94844D8BDBBCA980C11E3654A45906"
+              ],
+              "bond_height": 0,
+              "unbond_height": 0,
+              "last_commit_height": 0,
+              "voting_power": 5000000000,
+              "accum": 0
+            }
+          }
+        ]
       ],
       "proposal": null
     }
@@ -283,7 +302,10 @@ var testDataJson = `{
       "bonded_validators": [
         {
           "address": "37236DF251AB70022B1DA351F08A20FB52443E37",
-          "pub_key": [1, "CB3688B7561D488A2A4834E1AEE9398BEF94844D8BDBBCA980C11E3654A45906"],
+          "pub_key": [
+            1,
+            "CB3688B7561D488A2A4834E1AEE9398BEF94844D8BDBBCA980C11E3654A45906"
+          ],
           "bond_height": 0,
           "unbond_height": 0,
           "last_commit_height": 0,
@@ -327,7 +349,9 @@ var testDataJson = `{
     "output": []
   },
   "GetPeer": {
-    "input": {"address": "127.0.0.1:30000"},
+    "input": {
+      "address": "127.0.0.1:30000"
+    },
     "output": {
       "is_outbound": false,
       "node_info": null
@@ -420,7 +444,11 @@ var testDataJson = `{
     }
   },
   "Call": {
-    "input": {"address": "9FC1ECFCAE2A554D4D1A000D0D80F748E66359E3", "from": "DEADBEEF", "data": ""},
+    "input": {
+      "address": "9FC1ECFCAE2A554D4D1A000D0D80F748E66359E3",
+      "from": "DEADBEEF",
+      "data": ""
+    },
     "output": {
       "return": "6000357c01000000000000000000000000000000000000000000000000000000009004806337f428411461004557806340c10f191461005a578063d0679d341461006e57005b610050600435610244565b8060005260206000f35b610068600435602435610082565b60006000f35b61007c600435602435610123565b60006000f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156100dd576100e2565b61011f565b80600160005060008473ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055505b5050565b80600160005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050541061015e57610163565b610240565b80600160005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282825054039250508190555080600160005060008473ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055507f93eb3c629eb575edaf0252e4f9fc0c5ccada50496f8c1d32f0f93a65a8257eb560003373ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020016000a15b5050565b6000600160005060008373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005054905061027d565b91905056",
       "gas_used": 0
@@ -484,7 +512,8 @@ var testDataJson = `{
       "name": "testKey",
       "owner": "37236DF251AB70022B1DA351F08A20FB52443E37",
       "data": "testData",
-      "expires": 250 }
+      "expires": 250
+    }
   },
   "GetNameRegEntries": {
     "input": {
@@ -492,15 +521,18 @@ var testDataJson = `{
     },
     "output": {
       "block_height": 1,
-      "names":[ {
-        "name": "testKey",
-        "owner": "37236DF251AB70022B1DA351F08A20FB52443E37",
-        "data": "testData",
-        "expires": 250
-      } ]
+      "names": [
+        {
+          "name": "testKey",
+          "owner": "37236DF251AB70022B1DA351F08A20FB52443E37",
+          "data": "testData",
+          "expires": 250
+        }
+      ]
     }
   }
-}`
+}
+`
 
 var serverDuration uint = 100
 
@@ -565,7 +597,7 @@ type (
 	}
 
 	GetConsensusStateData struct {
-		Output *core_types.ConsensusState `json:"output"`
+		Output *consensus_types.ConsensusState `json:"output"`
 	}
 
 	GetValidatorsData struct {
diff --git a/txs/tx.go b/txs/tx.go
index 9957d570060d6c37ae266e8fc3b75adcb63e7796..e0069c5b78af512b225075696bd5e089e2c2b71b 100644
--- a/txs/tx.go
+++ b/txs/tx.go
@@ -14,7 +14,7 @@ import (
 	"github.com/tendermint/go-wire"
 
 	"github.com/tendermint/go-crypto"
-	"github.com/tendermint/tendermint/types" // votes for dupeout ..
+	tendermint_types "github.com/tendermint/tendermint/types" // votes for dupeout ..
 )
 
 var (
@@ -341,8 +341,8 @@ func (tx *RebondTx) String() string {
 
 type DupeoutTx struct {
 	Address []byte     `json:"address"`
-	VoteA   types.Vote `json:"vote_a"`
-	VoteB   types.Vote `json:"vote_b"`
+	VoteA   tendermint_types.Vote `json:"vote_a"`
+	VoteB   tendermint_types.Vote `json:"vote_b"`
 }
 
 func (tx *DupeoutTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
@@ -378,12 +378,6 @@ func (tx *PermissionsTx) String() string {
 //-----------------------------------------------------------------------------
 
 func TxHash(chainID string, tx Tx) []byte {
-	signBytes := acm.SignBytes(chainID, tx)
-	return wire.BinaryRipemd160(signBytes)
-}
-
-// [Silas] Leaving this implementation here for when we transition
-func TxHashFuture(chainID string, tx Tx) []byte {
 	signBytes := acm.SignBytes(chainID, tx)
 	hasher := ripemd160.New()
 	hasher.Write(signBytes)
@@ -393,34 +387,28 @@ func TxHashFuture(chainID string, tx Tx) []byte {
 
 //-----------------------------------------------------------------------------
 
-func EncodeTx(tx Tx) []byte {
-	wrapTx := struct {
-		Tx Tx `json:"unwrap"`
-	}{tx}
-	return wire.BinaryBytes(wrapTx)
+func EncodeTx(tx Tx) ([]byte, error) {
+	var n int
+	var err error
+	buf := new(bytes.Buffer)
+	wire.WriteBinary(struct{ Tx }{tx}, buf, &n, &err)
+	if err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), nil
 }
 
-//func EncodeTx(tx txs.Tx) []byte {
-//	buf := new(bytes.Buffer)
-//	var n int
-//	var err error
-//	wire.WriteBinary(struct{ types.Tx }{tx}, buf, &n, &err)
-//	if err != nil {
-//		return err
-//	}
-//}
-
 // panic on err
-func DecodeTx(txBytes []byte) Tx {
+func DecodeTx(txBytes []byte) (Tx, error) {
 	var n int
 	var err error
 	tx := new(Tx)
 	buf := bytes.NewBuffer(txBytes)
 	wire.ReadBinaryPtr(tx, buf, len(txBytes), &n, &err)
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
-	return *tx
+	return *tx, nil
 }
 
 func GenerateReceipt(chainId string, tx Tx) Receipt {
diff --git a/txs/tx_test.go b/txs/tx_test.go
index 5a73d351cab29b7fefc51c425e6f385a05abf3aa..1fecefa56aa3cde6bfff8e45e6f10271de91b2f6 100644
--- a/txs/tx_test.go
+++ b/txs/tx_test.go
@@ -6,9 +6,9 @@ import (
 	acm "github.com/eris-ltd/eris-db/account"
 	ptypes "github.com/eris-ltd/eris-db/permission/types"
 
+	"github.com/stretchr/testify/assert"
 	. "github.com/tendermint/go-common"
 	"github.com/tendermint/go-crypto"
-	//"github.com/tendermint/tendermint/types"
 )
 
 var chainID = "myChainID"
@@ -177,6 +177,30 @@ func TestPermissionsTxSignable(t *testing.T) {
 	}
 }
 
+func TestEncodeTxDecodeTx(t *testing.T) {
+	inputAddress := []byte{1, 2, 3, 4, 5}
+	outputAddress := []byte{5, 4, 3, 2, 1}
+	amount := int64(2)
+	sequence := 1
+	tx := &SendTx{
+		Inputs: []*TxInput{{
+			Address:  inputAddress,
+			Amount:   amount,
+			Sequence: sequence,
+		}},
+		Outputs: []*TxOutput{{
+			Address: outputAddress,
+			Amount:  amount,
+		}},
+	}
+	txBytes, err := EncodeTx(tx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	txOut, err := DecodeTx(txBytes)
+	assert.Equal(t, tx, txOut)
+}
+
 /*
 func TestDupeoutTxSignable(t *testing.T) {
 	privAcc := acm.GenPrivAccount()