diff --git a/account/state/state_cache.go b/account/state/state_cache.go
index 75dd70b1cf33be132d2685990a2ade2d302fb466..869842431bc3213eda869d65103ddf384d13738f 100644
--- a/account/state/state_cache.go
+++ b/account/state/state_cache.go
@@ -193,7 +193,7 @@ func (cache *stateCache) Sync(state Writer) error {
 		addresses = append(addresses, address)
 	}
 
-	sort.Stable(addresses)
+	sort.Sort(addresses)
 	for _, address := range addresses {
 		accInfo := cache.accounts[address]
 		accInfo.RLock()
@@ -208,7 +208,7 @@ func (cache *stateCache) Sync(state Writer) error {
 				keys = append(keys, key)
 			}
 			// First update keys
-			sort.Stable(keys)
+			sort.Sort(keys)
 			for _, key := range keys {
 				value := accInfo.storage[key]
 				err := state.SetStorage(address, key, value)
diff --git a/account/validator.go b/account/validator.go
index 017b1eb2a180036f22665aaac2b8ff5fd6750ba6..121b76fd234a4b27303e47bbef4f1b1f83b80f13 100644
--- a/account/validator.go
+++ b/account/validator.go
@@ -10,9 +10,6 @@ type Validator interface {
 	Addressable
 	// The validator's voting power
 	Power() uint64
-	// Alter the validator's voting power by amount that can be negative or positive.
-	// A power of 0 effectively unbonds the validator
-	WithNewPower(uint64) Validator
 }
 
 // Neither abci_types or tm_types has quite the representation we want
diff --git a/account/validator_test.go b/account/validator_test.go
index ff660300316d650d7e3ab64ff89ae4b88effecd4..0bc76357b7691133223a361dd82e5f7dde55f285 100644
--- a/account/validator_test.go
+++ b/account/validator_test.go
@@ -1,14 +1 @@
 package account
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestAlterPower(t *testing.T) {
-	val := AsValidator(NewConcreteAccountFromSecret("seeeeecret").Account())
-	valInc := val.WithNewPower(2442132)
-	assert.Equal(t, uint64(0), val.Power())
-	assert.Equal(t, uint64(2442132), valInc.Power())
-}
diff --git a/binary/integer.go b/binary/integer.go
index cd57bf3a1b8ccf9536a31318b6c52d0f8a8cc624..5824a4a9a9efbdb0a596765dbbf004ede7ef02d4 100644
--- a/binary/integer.go
+++ b/binary/integer.go
@@ -81,8 +81,6 @@ func IsUint64SumOverflow(a, b uint64) bool {
 	return math.MaxUint64-a < b
 }
 
-//
-
 // Converts a possibly negative big int x into a positive big int encoding a twos complement representation of x
 // truncated to 32 bytes
 func U256(x *big.Int) *big.Int {
diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go
index 74cbe338568a2bcf7ab16b3ece5065aa18f47129..daafb1ac10e88fb069502b29e574a06f4aad6bc0 100644
--- a/blockchain/blockchain.go
+++ b/blockchain/blockchain.go
@@ -18,81 +18,44 @@ import (
 	"bytes"
 	"encoding/json"
 	"fmt"
-	"sync"
 	"time"
 
+	"sync"
+
 	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/logging"
 	dbm "github.com/tendermint/tmlibs/db"
 )
 
-var stateKey = []byte("BlockchainState")
-
-// Immutable Root of blockchain
-type Root interface {
-	// GenesisHash precomputed from GenesisDoc
-	GenesisHash() []byte
-	GenesisDoc() genesis.GenesisDoc
-}
-
-// 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
-	LastBlockHash() []byte
-	// Note this is the hash of the application state after the most recently committed block's transactions executed
-	// and so lastBlock.Header.AppHash will be one block older than our AppHashAfterLastBlock (i.e. Tendermint closes
-	// the AppHash we return from ABCI Commit into the _next_ block)
-	AppHashAfterLastBlock() []byte
-}
+// Blocks to average validator power over
+const DefaultValidatorsWindowSize = 10
 
-// Burrow's portion of the Blockchain state
-type Blockchain interface {
-	// Read locker
-	sync.Locker
-	Root
-	Tip
-	// Returns an immutable copy of the tip
-	Tip() Tip
-	// Returns a copy of the current validator set
-	Validators() []acm.Validator
-}
-
-type MutableBlockchain interface {
-	Blockchain
-	CommitBlock(blockTime time.Time, blockHash, appHash []byte) error
-}
+var stateKey = []byte("BlockchainState")
 
-type root struct {
+type Root struct {
 	genesisHash []byte
 	genesisDoc  genesis.GenesisDoc
 }
 
-type tip struct {
+type Tip struct {
 	chainID               string
 	lastBlockHeight       uint64
 	lastBlockTime         time.Time
 	lastBlockHash         []byte
 	appHashAfterLastBlock []byte
+	validators            Validators
+	validatorsWindow      ValidatorsWindow
 }
 
-type blockchain struct {
+type Blockchain struct {
+	Root
+	Tip
 	sync.RWMutex
 	db dbm.DB
-	*root
-	*tip
-	validators []acm.Validator
 }
 
-var _ Root = &blockchain{}
-var _ Tip = &blockchain{}
-var _ Blockchain = &blockchain{}
-var _ MutableBlockchain = &blockchain{}
-
 type PersistedState struct {
 	AppHashAfterLastBlock []byte
 	LastBlockHeight       uint64
@@ -100,23 +63,23 @@ type PersistedState struct {
 }
 
 func LoadOrNewBlockchain(db dbm.DB, genesisDoc *genesis.GenesisDoc,
-	logger *logging.Logger) (*blockchain, error) {
+	logger *logging.Logger) (*Blockchain, error) {
 
 	logger = logger.WithScope("LoadOrNewBlockchain")
 	logger.InfoMsg("Trying to load blockchain state from database",
 		"database_key", stateKey)
-	blockchain, err := loadBlockchain(db)
+	bc, err := loadBlockchain(db)
 	if err != nil {
 		return nil, fmt.Errorf("error loading blockchain state from database: %v", err)
 	}
-	if blockchain != nil {
-		dbHash := blockchain.genesisDoc.Hash()
+	if bc != nil {
+		dbHash := bc.genesisDoc.Hash()
 		argHash := genesisDoc.Hash()
 		if !bytes.Equal(dbHash, argHash) {
 			return nil, fmt.Errorf("GenesisDoc passed to LoadOrNewBlockchain has hash: 0x%X, which does not "+
 				"match the one found in database: 0x%X", argHash, dbHash)
 		}
-		return blockchain, nil
+		return bc, nil
 	}
 
 	logger.InfoMsg("No existing blockchain state found in database, making new blockchain")
@@ -124,7 +87,7 @@ func LoadOrNewBlockchain(db dbm.DB, genesisDoc *genesis.GenesisDoc,
 }
 
 // Pointer to blockchain state initialised from genesis
-func newBlockchain(db dbm.DB, genesisDoc *genesis.GenesisDoc) *blockchain {
+func newBlockchain(db dbm.DB, genesisDoc *genesis.GenesisDoc) *Blockchain {
 	var validators []acm.Validator
 	for _, gv := range genesisDoc.Validators {
 		validators = append(validators, acm.ConcreteValidator{
@@ -132,16 +95,15 @@ func newBlockchain(db dbm.DB, genesisDoc *genesis.GenesisDoc) *blockchain {
 			Power:     uint64(gv.Amount),
 		}.Validator())
 	}
-	root := NewRoot(genesisDoc)
-	return &blockchain{
-		db:         db,
-		root:       root,
-		tip:        NewTip(genesisDoc.ChainID(), root.genesisDoc.GenesisTime, root.genesisHash),
-		validators: validators,
+	rt := NewRoot(genesisDoc)
+	return &Blockchain{
+		db:   db,
+		Root: rt,
+		Tip:  NewTip(genesisDoc.ChainID(), rt.genesisDoc.GenesisTime, rt.genesisHash),
 	}
 }
 
-func loadBlockchain(db dbm.DB) (*blockchain, error) {
+func loadBlockchain(db dbm.DB) (*Blockchain, error) {
 	buf := db.Get(stateKey)
 	if len(buf) == 0 {
 		return nil, nil
@@ -150,29 +112,31 @@ func loadBlockchain(db dbm.DB) (*blockchain, error) {
 	if err != nil {
 		return nil, err
 	}
-	blockchain := newBlockchain(db, &persistedState.GenesisDoc)
-	blockchain.lastBlockHeight = persistedState.LastBlockHeight
-	blockchain.appHashAfterLastBlock = persistedState.AppHashAfterLastBlock
-	return blockchain, nil
+	bc := newBlockchain(db, &persistedState.GenesisDoc)
+	bc.lastBlockHeight = persistedState.LastBlockHeight
+	bc.appHashAfterLastBlock = persistedState.AppHashAfterLastBlock
+	return bc, nil
 }
 
-func NewRoot(genesisDoc *genesis.GenesisDoc) *root {
-	return &root{
+func NewRoot(genesisDoc *genesis.GenesisDoc) Root {
+	return Root{
 		genesisHash: genesisDoc.Hash(),
 		genesisDoc:  *genesisDoc,
 	}
 }
 
 // Create genesis Tip
-func NewTip(chainID string, genesisTime time.Time, genesisHash []byte) *tip {
-	return &tip{
+func NewTip(chainID string, genesisTime time.Time, genesisHash []byte) Tip {
+	return Tip{
 		chainID:               chainID,
 		lastBlockTime:         genesisTime,
 		appHashAfterLastBlock: genesisHash,
+		validators:            NewValidators(),
+		validatorsWindow:      NewValidatorsWindow(DefaultValidatorsWindowSize),
 	}
 }
 
-func (bc *blockchain) CommitBlock(blockTime time.Time, blockHash, appHash []byte) error {
+func (bc *Blockchain) CommitBlock(blockTime time.Time, blockHash, appHash []byte) error {
 	bc.Lock()
 	defer bc.Unlock()
 	bc.lastBlockHeight += 1
@@ -182,7 +146,7 @@ func (bc *blockchain) CommitBlock(blockTime time.Time, blockHash, appHash []byte
 	return bc.save()
 }
 
-func (bc *blockchain) save() error {
+func (bc *Blockchain) save() error {
 	if bc.db != nil {
 		encodedState, err := bc.Encode()
 		if err != nil {
@@ -193,28 +157,7 @@ func (bc *blockchain) save() error {
 	return nil
 }
 
-func (bc *blockchain) Root() Root {
-	return bc.root
-}
-
-func (bc *blockchain) Tip() Tip {
-	bc.RLock()
-	defer bc.RUnlock()
-	t := *bc.tip
-	return &t
-}
-
-func (bc *blockchain) Validators() []acm.Validator {
-	bc.RLock()
-	defer bc.RUnlock()
-	vs := make([]acm.Validator, len(bc.validators))
-	for i, v := range bc.validators {
-		vs[i] = v
-	}
-	return vs
-}
-
-func (bc *blockchain) Encode() ([]byte, error) {
+func (bc *Blockchain) Encode() ([]byte, error) {
 	persistedState := &PersistedState{
 		GenesisDoc:            bc.genesisDoc,
 		AppHashAfterLastBlock: bc.appHashAfterLastBlock,
@@ -236,30 +179,38 @@ func Decode(encodedState []byte) (*PersistedState, error) {
 	return persistedState, nil
 }
 
-func (r *root) GenesisHash() []byte {
+func (r *Root) GenesisHash() []byte {
 	return r.genesisHash
 }
 
-func (r *root) GenesisDoc() genesis.GenesisDoc {
+func (r *Root) GenesisDoc() genesis.GenesisDoc {
 	return r.genesisDoc
 }
 
-func (t *tip) ChainID() string {
+func (t *Tip) ChainID() string {
 	return t.chainID
 }
 
-func (t *tip) LastBlockHeight() uint64 {
+func (t *Tip) LastBlockHeight() uint64 {
 	return t.lastBlockHeight
 }
 
-func (t *tip) LastBlockTime() time.Time {
+func (t *Tip) LastBlockTime() time.Time {
 	return t.lastBlockTime
 }
 
-func (t *tip) LastBlockHash() []byte {
+func (t *Tip) LastBlockHash() []byte {
 	return t.lastBlockHash
 }
 
-func (t *tip) AppHashAfterLastBlock() []byte {
+func (t *Tip) AppHashAfterLastBlock() []byte {
 	return t.appHashAfterLastBlock
 }
+
+func (t *Tip) IterateValidators(iter func(publicKey crypto.PublicKey, power uint64) (stop bool)) (stopped bool) {
+	return t.validators.Iterate(iter)
+}
+
+func (t *Tip) NumValidators() int {
+	return t.validators.Length()
+}
diff --git a/blockchain/validators.go b/blockchain/validators.go
new file mode 100644
index 0000000000000000000000000000000000000000..0ba398af0cd0d2103664d84158223865134978bd
--- /dev/null
+++ b/blockchain/validators.go
@@ -0,0 +1,122 @@
+package blockchain
+
+import (
+	"fmt"
+
+	"sort"
+
+	"bytes"
+	"encoding/binary"
+
+	burrowBinary "github.com/hyperledger/burrow/binary"
+	"github.com/hyperledger/burrow/crypto"
+)
+
+// A Validator multiset
+type Validators struct {
+	power      map[crypto.Address]uint64
+	publicKey  map[crypto.Address]crypto.PublicKey
+	totalPower uint64
+}
+
+func NewValidators() Validators {
+	return Validators{
+		power:     make(map[crypto.Address]uint64),
+		publicKey: make(map[crypto.Address]crypto.PublicKey),
+	}
+}
+
+// Add the power of a validator
+func (vs *Validators) AlterPower(publicKey crypto.PublicKey, power uint64) error {
+	address := publicKey.Address()
+	// Remove existing power (possibly 0) from total
+	vs.totalPower -= vs.power[address]
+	if burrowBinary.IsUint64SumOverflow(vs.totalPower, power) {
+		// Undo removing existing power
+		vs.totalPower += vs.power[address]
+		return fmt.Errorf("could not increase total validator power by %v from %v since that would overflow "+
+			"uint64", power, vs.totalPower)
+	}
+	vs.publicKey[address] = publicKey
+	vs.power[address] = power
+	// Note we are adjusting by the difference in power (+/-) since we subtracted the previous amount above
+	vs.totalPower += power
+	return nil
+}
+
+func (vs *Validators) AddPower(publicKey crypto.PublicKey, power uint64) error {
+	currentPower := vs.power[publicKey.Address()]
+	if burrowBinary.IsUint64SumOverflow(currentPower, power) {
+		return fmt.Errorf("could add power %v to validator %v with power %v because that would overflow uint64",
+			power, publicKey.Address(), currentPower)
+	}
+	return vs.AlterPower(publicKey, vs.power[publicKey.Address()]+power)
+}
+
+func (vs *Validators) SubtractPower(publicKey crypto.PublicKey, power uint64) error {
+	currentPower := vs.power[publicKey.Address()]
+	if currentPower < power {
+		return fmt.Errorf("could subtract power %v from validator %v with power %v because that would "+
+			"underflow uint64", power, publicKey.Address(), currentPower)
+	}
+	return vs.AlterPower(publicKey, vs.power[publicKey.Address()]-power)
+}
+
+// Iterates over validators sorted by address
+func (vs *Validators) Iterate(iter func(publicKey crypto.PublicKey, power uint64) (stop bool)) (stopped bool) {
+	addresses := make(crypto.Addresses, 0, len(vs.power))
+	for address := range vs.power {
+		addresses = append(addresses, address)
+	}
+	sort.Sort(addresses)
+	for _, address := range addresses {
+		if iter(vs.publicKey[address], vs.power[address]) {
+			return true
+		}
+	}
+	return false
+}
+
+func (vs *Validators) Length() int {
+	return len(vs.power)
+}
+
+func (vs *Validators) TotalPower() uint64 {
+	return vs.totalPower
+}
+
+// Uses the fixed width public key encoding to
+func (vs *Validators) Encode() []byte {
+	buffer := new(bytes.Buffer)
+	// varint buffer
+	buf := make([]byte, 8)
+	vs.Iterate(func(publicKey crypto.PublicKey, power uint64) (stop bool) {
+		buffer.Write(publicKey.Encode())
+		buffer.Write(buf[:binary.PutUvarint(buf, power)])
+		return
+	})
+	return buffer.Bytes()
+}
+
+// Decodes validators encoded with Encode - expects the exact encoded size with no trailing bytes
+func DecodeValidators(encoded []byte, validators *Validators) error {
+	publicKey := new(crypto.PublicKey)
+	i := 0
+	for i < len(encoded) {
+		n, err := crypto.DecodePublicKeyFixedWidth(encoded[i:], publicKey)
+		if err != nil {
+			return err
+		}
+		i += n
+		power, n := binary.Uvarint(encoded[i:])
+		if n <= 0 {
+			return fmt.Errorf("error decoding uint64 from validators binary encoding")
+		}
+		i += n
+		err = validators.AlterPower(*publicKey, power)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/blockchain/validators_test.go b/blockchain/validators_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..35513d43af9c052f3c31a494ec6d5ea4ee7c149b
--- /dev/null
+++ b/blockchain/validators_test.go
@@ -0,0 +1,50 @@
+package blockchain
+
+import (
+	"testing"
+
+	"fmt"
+
+	"math/rand"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/crypto"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestValidators_AlterPower(t *testing.T) {
+	vs := NewValidators()
+	pow1 := uint64(2312312321)
+	assert.NoError(t, vs.AlterPower(pubKey(1), pow1))
+	assert.Equal(t, pow1, vs.TotalPower())
+}
+
+func TestValidators_Encode(t *testing.T) {
+	vs := NewValidators()
+	rnd := rand.New(rand.NewSource(43534543))
+	for i := 0; i < 100; i++ {
+		power := uint64(rnd.Intn(10))
+		require.NoError(t, vs.AlterPower(pubKey(rnd.Int63()), power))
+	}
+	encoded := vs.Encode()
+	vsOut := NewValidators()
+	require.NoError(t, DecodeValidators(encoded, &vsOut))
+	// Check decoded matches encoded
+	var publicKeyPower []interface{}
+	vs.Iterate(func(publicKey crypto.PublicKey, power uint64) (stop bool) {
+		publicKeyPower = append(publicKeyPower, publicKey, power)
+		return
+	})
+	vsOut.Iterate(func(publicKey crypto.PublicKey, power uint64) (stop bool) {
+		assert.Equal(t, publicKeyPower[0], publicKey)
+		assert.Equal(t, publicKeyPower[1], power)
+		publicKeyPower = publicKeyPower[2:]
+		return
+	})
+	assert.Len(t, publicKeyPower, 0, "should exhaust all validators in decoded multiset")
+}
+
+func pubKey(secret interface{}) crypto.PublicKey {
+	return acm.NewConcreteAccountFromSecret(fmt.Sprintf("%v", secret)).PublicKey
+}
diff --git a/blockchain/validators_window.go b/blockchain/validators_window.go
new file mode 100644
index 0000000000000000000000000000000000000000..11ebf209b36e441b3826785725abdd7975e485fa
--- /dev/null
+++ b/blockchain/validators_window.go
@@ -0,0 +1,64 @@
+package blockchain
+
+import (
+	"github.com/hyperledger/burrow/crypto"
+)
+
+type ValidatorsWindow struct {
+	Buckets []Validators
+	Total   Validators
+	head    int
+}
+
+// Provides a sliding window over the last size buckets of validator power changes
+func NewValidatorsWindow(size int) ValidatorsWindow {
+	if size < 1 {
+		size = 1
+	}
+	vw := ValidatorsWindow{
+		Buckets: make([]Validators, size),
+		Total:   NewValidators(),
+	}
+	vw.Buckets[vw.head] = NewValidators()
+	return vw
+}
+
+// Updates the current head bucket (accumulator)
+func (vw *ValidatorsWindow) AlterPower(publicKey crypto.PublicKey, power uint64) error {
+	return vw.Buckets[vw.head].AlterPower(publicKey, power)
+}
+
+func (vw *ValidatorsWindow) CommitInto(validatorsToUpdate *Validators) error {
+	var err error
+	if vw.Buckets[vw.head].Iterate(func(publicKey crypto.PublicKey, power uint64) (stop bool) {
+		// Update the sink validators
+		err = validatorsToUpdate.AlterPower(publicKey, power)
+		if err != nil {
+			return true
+		}
+		// Add to total power
+		err = vw.Total.AddPower(publicKey, power)
+		if err != nil {
+			return true
+		}
+		return false
+	}) {
+		// If iteration stopped there was an error
+		return err
+	}
+	// move the ring buffer on
+	vw.head = (vw.head + 1) % len(vw.Buckets)
+	// Subtract the tail bucket (if any) from the total
+	if vw.Buckets[vw.head].Iterate(func(publicKey crypto.PublicKey, power uint64) (stop bool) {
+		err = vw.Total.SubtractPower(publicKey, power)
+		if err != nil {
+			return false
+		}
+		return true
+	}) {
+		return err
+	}
+	// Clear new head bucket (and possibly previous tail)
+	vw.Buckets[vw.head] = NewValidators()
+	return nil
+}
diff --git a/consensus/tendermint/abci/app.go b/consensus/tendermint/abci/app.go
index 6ad441166a96d5dcaa9b572927fbace51314cbab..31306fca8a1ea388c65e745ec36e495dbb9dd8e0 100644
--- a/consensus/tendermint/abci/app.go
+++ b/consensus/tendermint/abci/app.go
@@ -7,13 +7,14 @@ import (
 
 	bcm "github.com/hyperledger/burrow/blockchain"
 	"github.com/hyperledger/burrow/consensus/tendermint/codes"
+	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/execution"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
 	"github.com/hyperledger/burrow/project"
 	"github.com/hyperledger/burrow/txs"
 	"github.com/pkg/errors"
-	abci_types "github.com/tendermint/abci/types"
+	abciTypes "github.com/tendermint/abci/types"
 	"github.com/tendermint/go-wire"
 )
 
@@ -21,21 +22,21 @@ const responseInfoName = "Burrow"
 
 type App struct {
 	// State
-	blockchain    bcm.MutableBlockchain
+	blockchain    *bcm.Blockchain
 	checker       execution.BatchExecutor
 	committer     execution.BatchCommitter
 	mempoolLocker sync.Locker
 	// We need to cache these from BeginBlock for when we need actually need it in Commit
-	block *abci_types.RequestBeginBlock
+	block *abciTypes.RequestBeginBlock
 	// Utility
 	txDecoder txs.Decoder
 	// Logging
 	logger *logging.Logger
 }
 
-var _ abci_types.Application = &App{}
+var _ abciTypes.Application = &App{}
 
-func NewApp(blockchain bcm.MutableBlockchain,
+func NewApp(blockchain *bcm.Blockchain,
 	checker execution.BatchExecutor,
 	committer execution.BatchCommitter,
 	logger *logging.Logger) *App {
@@ -55,9 +56,9 @@ func (app *App) SetMempoolLocker(mempoolLocker sync.Locker) {
 	app.mempoolLocker = mempoolLocker
 }
 
-func (app *App) Info(info abci_types.RequestInfo) abci_types.ResponseInfo {
-	tip := app.blockchain.Tip()
-	return abci_types.ResponseInfo{
+func (app *App) Info(info abciTypes.RequestInfo) abciTypes.ResponseInfo {
+	tip := app.blockchain.Tip
+	return abciTypes.ResponseInfo{
 		Data:             responseInfoName,
 		Version:          project.History.CurrentVersion().String(),
 		LastBlockHeight:  int64(tip.LastBlockHeight()),
@@ -65,25 +66,25 @@ func (app *App) Info(info abci_types.RequestInfo) abci_types.ResponseInfo {
 	}
 }
 
-func (app *App) SetOption(option abci_types.RequestSetOption) (respSetOption abci_types.ResponseSetOption) {
+func (app *App) SetOption(option abciTypes.RequestSetOption) (respSetOption abciTypes.ResponseSetOption) {
 	respSetOption.Log = "SetOption not supported"
 	respSetOption.Code = codes.UnsupportedRequestCode
 	return
 }
 
-func (app *App) Query(reqQuery abci_types.RequestQuery) (respQuery abci_types.ResponseQuery) {
+func (app *App) Query(reqQuery abciTypes.RequestQuery) (respQuery abciTypes.ResponseQuery) {
 	respQuery.Log = "Query not supported"
 	respQuery.Code = codes.UnsupportedRequestCode
 	return
 }
 
-func (app *App) CheckTx(txBytes []byte) abci_types.ResponseCheckTx {
+func (app *App) CheckTx(txBytes []byte) abciTypes.ResponseCheckTx {
 	tx, err := app.txDecoder.DecodeTx(txBytes)
 	if err != nil {
 		app.logger.TraceMsg("CheckTx decoding error",
 			"tag", "CheckTx",
 			structure.ErrorKey, err)
-		return abci_types.ResponseCheckTx{
+		return abciTypes.ResponseCheckTx{
 			Code: codes.EncodingErrorCode,
 			Log:  fmt.Sprintf("Encoding error: %s", err),
 		}
@@ -97,7 +98,7 @@ func (app *App) CheckTx(txBytes []byte) abci_types.ResponseCheckTx {
 			"tag", "CheckTx",
 			"tx_hash", receipt.TxHash,
 			"creates_contract", receipt.CreatesContract)
-		return abci_types.ResponseCheckTx{
+		return abciTypes.ResponseCheckTx{
 			Code: codes.EncodingErrorCode,
 			Log:  fmt.Sprintf("CheckTx could not execute transaction: %s, error: %v", tx, err),
 		}
@@ -108,30 +109,30 @@ func (app *App) CheckTx(txBytes []byte) abci_types.ResponseCheckTx {
 		"tag", "CheckTx",
 		"tx_hash", receipt.TxHash,
 		"creates_contract", receipt.CreatesContract)
-	return abci_types.ResponseCheckTx{
+	return abciTypes.ResponseCheckTx{
 		Code: codes.TxExecutionSuccessCode,
 		Log:  "CheckTx success - receipt in data",
 		Data: receiptBytes,
 	}
 }
 
-func (app *App) InitChain(chain abci_types.RequestInitChain) (respInitChain abci_types.ResponseInitChain) {
+func (app *App) InitChain(chain abciTypes.RequestInitChain) (respInitChain abciTypes.ResponseInitChain) {
 	// Could verify agreement on initial validator set here
 	return
 }
 
-func (app *App) BeginBlock(block abci_types.RequestBeginBlock) (respBeginBlock abci_types.ResponseBeginBlock) {
+func (app *App) BeginBlock(block abciTypes.RequestBeginBlock) (respBeginBlock abciTypes.ResponseBeginBlock) {
 	app.block = &block
 	return
 }
 
-func (app *App) DeliverTx(txBytes []byte) abci_types.ResponseDeliverTx {
+func (app *App) DeliverTx(txBytes []byte) abciTypes.ResponseDeliverTx {
 	tx, err := app.txDecoder.DecodeTx(txBytes)
 	if err != nil {
 		app.logger.TraceMsg("DeliverTx decoding error",
 			"tag", "DeliverTx",
 			structure.ErrorKey, err)
-		return abci_types.ResponseDeliverTx{
+		return abciTypes.ResponseDeliverTx{
 			Code: codes.EncodingErrorCode,
 			Log:  fmt.Sprintf("Encoding error: %s", err),
 		}
@@ -145,7 +146,7 @@ func (app *App) DeliverTx(txBytes []byte) abci_types.ResponseDeliverTx {
 			"tag", "DeliverTx",
 			"tx_hash", receipt.TxHash,
 			"creates_contract", receipt.CreatesContract)
-		return abci_types.ResponseDeliverTx{
+		return abciTypes.ResponseDeliverTx{
 			Code: codes.TxExecutionErrorCode,
 			Log:  fmt.Sprintf("DeliverTx could not execute transaction: %s, error: %s", tx, err),
 		}
@@ -156,20 +157,30 @@ func (app *App) DeliverTx(txBytes []byte) abci_types.ResponseDeliverTx {
 		"tx_hash", receipt.TxHash,
 		"creates_contract", receipt.CreatesContract)
 	receiptBytes := wire.BinaryBytes(receipt)
-	return abci_types.ResponseDeliverTx{
+	return abciTypes.ResponseDeliverTx{
 		Code: codes.TxExecutionSuccessCode,
 		Log:  "DeliverTx success - receipt in data",
 		Data: receiptBytes,
 	}
 }
 
-func (app *App) EndBlock(reqEndBlock abci_types.RequestEndBlock) (respEndBlock abci_types.ResponseEndBlock) {
+func (app *App) EndBlock(reqEndBlock abciTypes.RequestEndBlock) abciTypes.ResponseEndBlock {
 	// Validator mutation goes here
-	return
+	var validatorUpdates abciTypes.Validators
+	app.blockchain.IterateValidators(func(publicKey crypto.PublicKey, power uint64) (stop bool) {
+		validatorUpdates = append(validatorUpdates, abciTypes.Validator{
+			Address: publicKey.Address().Bytes(),
+			PubKey:  publicKey.ABCIPubKey(),
+			Power:   int64(power),
+		})
+		return
+	})
+	return abciTypes.ResponseEndBlock{
+		ValidatorUpdates: validatorUpdates,
+	}
 }
 
-func (app *App) Commit() abci_types.ResponseCommit {
-	tip := app.blockchain.Tip()
+func (app *App) Commit() abciTypes.ResponseCommit {
 	app.logger.InfoMsg("Committing block",
 		"tag", "Commit",
 		structure.ScopeKey, "Commit()",
@@ -177,8 +188,8 @@ func (app *App) Commit() abci_types.ResponseCommit {
 		"hash", app.block.Hash,
 		"txs", app.block.Header.NumTxs,
 		"block_time", app.block.Header.Time, // [CSK] this sends a fairly non-sensical number; should be human readable
-		"last_block_time", tip.LastBlockTime(),
-		"last_block_hash", tip.LastBlockHash())
+		"last_block_time", app.blockchain.Tip.LastBlockTime(),
+		"last_block_hash", app.blockchain.Tip.LastBlockHash())
 
 	// Lock the checker while we reset it and possibly while recheckTxs replays transactions
 	app.checker.Lock()
@@ -233,7 +244,7 @@ func (app *App) Commit() abci_types.ResponseCommit {
 			"but Tendermint reports a block height of %v, and the two should agree",
 			app.blockchain.LastBlockHeight(), app.block.Header.Height))
 	}
-	return abci_types.ResponseCommit{
+	return abciTypes.ResponseCommit{
 		Data: appHash,
 	}
 }
diff --git a/crypto/crypto.go b/crypto/crypto.go
index da0e85dd0af80b0c12d026c551fd0b6ae8ed0389..fc8ebf9e16e89ec5393aed337d9fd4367c0c37a9 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -2,17 +2,8 @@ package crypto
 
 import (
 	"bytes"
-	crand "crypto/rand"
-	"crypto/sha256"
-	"encoding/json"
 	"fmt"
 	"io"
-
-	"github.com/btcsuite/btcd/btcec"
-	tm_crypto "github.com/tendermint/go-crypto"
-	"github.com/tmthrgd/go-hex"
-	"golang.org/x/crypto/ed25519"
-	"golang.org/x/crypto/ripemd160"
 )
 
 type CurveType int8
@@ -33,6 +24,11 @@ func (k CurveType) String() string {
 	}
 }
 
+// Get this CurveType's 8 bit identifier as a byte
+func (k CurveType) Byte() byte {
+	return byte(k)
+}
+
 func CurveTypeFromString(s string) (CurveType, error) {
 	switch s {
 	case "secp256k1":
@@ -45,17 +41,6 @@ func CurveTypeFromString(s string) (CurveType, error) {
 	}
 }
 
-func (p PublicKey) AddressHashType() string {
-	switch p.CurveType {
-	case CurveTypeEd25519:
-		return "go-crypto-0.5.0"
-	case CurveTypeSecp256k1:
-		return "btc"
-	default:
-		return ""
-	}
-}
-
 type ErrInvalidCurve string
 
 func (err ErrInvalidCurve) Error() string {
@@ -69,117 +54,6 @@ type Signer interface {
 	Sign(msg []byte) (Signature, error)
 }
 
-// PublicKey
-type PublicKey struct {
-	CurveType CurveType
-	PublicKey []byte
-}
-
-type PrivateKey struct {
-	CurveType  CurveType
-	PublicKey  []byte
-	PrivateKey []byte
-}
-
-type PublicKeyJSON struct {
-	CurveType string
-	PublicKey string
-}
-
-func (p PublicKey) MarshalJSON() ([]byte, error) {
-	jStruct := PublicKeyJSON{
-		CurveType: p.CurveType.String(),
-		PublicKey: hex.EncodeUpperToString(p.PublicKey),
-	}
-	txt, err := json.Marshal(jStruct)
-	return txt, err
-}
-
-func (p PublicKey) MarshalText() ([]byte, error) {
-	return p.MarshalJSON()
-}
-
-func (p *PublicKey) UnmarshalJSON(text []byte) error {
-	var jStruct PublicKeyJSON
-	err := json.Unmarshal(text, &jStruct)
-	if err != nil {
-		return err
-	}
-	CurveType, err := CurveTypeFromString(jStruct.CurveType)
-	if err != nil {
-		return err
-	}
-	bs, err := hex.DecodeString(jStruct.PublicKey)
-	if err != nil {
-		return err
-	}
-	p.CurveType = CurveType
-	p.PublicKey = bs
-	return nil
-}
-
-func (p *PublicKey) UnmarshalText(text []byte) error {
-	return p.UnmarshalJSON(text)
-}
-
-func (p PublicKey) IsValid() bool {
-	switch p.CurveType {
-	case CurveTypeEd25519:
-		return len(p.PublicKey) == ed25519.PublicKeySize
-	case CurveTypeSecp256k1:
-		return len(p.PublicKey) == btcec.PubKeyBytesLenCompressed
-	default:
-		return false
-	}
-}
-func (p PublicKey) Verify(msg []byte, signature Signature) bool {
-	switch p.CurveType {
-	case CurveTypeEd25519:
-		return ed25519.Verify(p.PublicKey, msg, signature.Signature[:])
-	case CurveTypeSecp256k1:
-		pub, err := btcec.ParsePubKey(p.PublicKey, btcec.S256())
-		if err != nil {
-			return false
-		}
-		sig, err := btcec.ParseDERSignature(signature.Signature, btcec.S256())
-		if err != nil {
-			return false
-		}
-		return sig.Verify(msg, pub)
-	default:
-		panic(fmt.Sprintf("invalid curve type"))
-	}
-}
-
-func (p PublicKey) Address() Address {
-	switch p.CurveType {
-	case CurveTypeEd25519:
-		// FIMXE: tendermint go-crypto-0.5.0 uses weird scheme, this is fixed in 0.6.0
-		tmPubKey := new(tm_crypto.PubKeyEd25519)
-		copy(tmPubKey[:], p.PublicKey)
-		addr, _ := AddressFromBytes(tmPubKey.Address())
-		return addr
-	case CurveTypeSecp256k1:
-		sha := sha256.New()
-		sha.Write(p.PublicKey[:])
-
-		hash := ripemd160.New()
-		hash.Write(sha.Sum(nil))
-		addr, _ := AddressFromBytes(hash.Sum(nil))
-		return addr
-	default:
-		panic(fmt.Sprintf("unknown CurveType %d", p.CurveType))
-	}
-}
-
-func (p PublicKey) RawBytes() []byte {
-	return p.PublicKey[:]
-}
-
-func (p PublicKey) String() string {
-	return hex.EncodeUpperToString(p.PublicKey)
-}
-
 // Signable is an interface for all signable things.
 // It typically removes signatures before serializing.
 type Signable interface {
@@ -195,167 +69,3 @@ func SignBytes(chainID string, o Signable) []byte {
 	}
 	return buf.Bytes()
 }
-
-// Currently this is a stub that reads the raw bytes returned by key_client and returns
-// an ed25519 public key.
-func PublicKeyFromBytes(bs []byte, curveType CurveType) (PublicKey, error) {
-	switch curveType {
-	case CurveTypeEd25519:
-		if len(bs) != ed25519.PublicKeySize {
-			return PublicKey{}, fmt.Errorf("bytes passed have length %v but ed25519 public keys have %v bytes",
-				len(bs), ed25519.PublicKeySize)
-		}
-	case CurveTypeSecp256k1:
-		if len(bs) != btcec.PubKeyBytesLenCompressed {
-			return PublicKey{}, fmt.Errorf("bytes passed have length %v but secp256k1 public keys have %v bytes",
-				len(bs), btcec.PubKeyBytesLenCompressed)
-		}
-	default:
-		return PublicKey{}, ErrInvalidCurve(curveType)
-	}
-
-	return PublicKey{PublicKey: bs, CurveType: curveType}, nil
-}
-
-func (p PrivateKey) RawBytes() []byte {
-	return p.PrivateKey
-}
-
-func (p PrivateKey) Sign(msg []byte) (Signature, error) {
-	switch p.CurveType {
-	case CurveTypeEd25519:
-		if len(p.PrivateKey) != ed25519.PrivateKeySize {
-			return Signature{}, fmt.Errorf("bytes passed have length %v but ed25519 private keys have %v bytes",
-				len(p.PrivateKey), ed25519.PrivateKeySize)
-		}
-		privKey := ed25519.PrivateKey(p.PrivateKey)
-		return Signature{ed25519.Sign(privKey, msg)}, nil
-	case CurveTypeSecp256k1:
-		if len(p.PrivateKey) != btcec.PrivKeyBytesLen {
-			return Signature{}, fmt.Errorf("bytes passed have length %v but secp256k1 private keys have %v bytes",
-				len(p.PrivateKey), btcec.PrivKeyBytesLen)
-		}
-		privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), p.PrivateKey)
-
-		sig, err := privKey.Sign(msg)
-		if err != nil {
-			return Signature{}, err
-		}
-		return Signature{Signature: sig.Serialize()}, nil
-	default:
-		return Signature{}, ErrInvalidCurve(p.CurveType)
-	}
-}
-
-func (p PrivateKey) GetPublicKey() PublicKey {
-	return PublicKey{CurveType: p.CurveType, PublicKey: p.PublicKey}
-}
-
-func PrivateKeyFromRawBytes(privKeyBytes []byte, curveType CurveType) (PrivateKey, error) {
-	switch curveType {
-	case CurveTypeEd25519:
-		if len(privKeyBytes) != ed25519.PrivateKeySize {
-			return PrivateKey{}, fmt.Errorf("bytes passed have length %v but ed25519 private keys have %v bytes",
-				len(privKeyBytes), ed25519.PrivateKeySize)
-		}
-		return PrivateKey{PrivateKey: privKeyBytes, PublicKey: privKeyBytes[32:], CurveType: CurveTypeEd25519}, nil
-	case CurveTypeSecp256k1:
-		if len(privKeyBytes) != btcec.PrivKeyBytesLen {
-			return PrivateKey{}, fmt.Errorf("bytes passed have length %v but secp256k1 private keys have %v bytes",
-				len(privKeyBytes), btcec.PrivKeyBytesLen)
-		}
-		privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
-		return PrivateKey{PrivateKey: privKey.Serialize(), PublicKey: pubKey.SerializeCompressed(), CurveType: CurveTypeSecp256k1}, nil
-	default:
-		return PrivateKey{}, ErrInvalidCurve(curveType)
-	}
-}
-
-func GeneratePrivateKey(random io.Reader, curveType CurveType) (PrivateKey, error) {
-	if random == nil {
-		random = crand.Reader
-	}
-	switch curveType {
-	case CurveTypeEd25519:
-		_, priv, err := ed25519.GenerateKey(random)
-		if err != nil {
-			return PrivateKey{}, err
-		}
-		return PrivateKeyFromRawBytes(priv, CurveTypeEd25519)
-	case CurveTypeSecp256k1:
-		privKeyBytes := make([]byte, 32)
-		_, err := random.Read(privKeyBytes)
-		if err != nil {
-			return PrivateKey{}, err
-		}
-		return PrivateKeyFromRawBytes(privKeyBytes, CurveTypeSecp256k1)
-	default:
-		return PrivateKey{}, ErrInvalidCurve(curveType)
-	}
-}
-
-func PrivateKeyFromSecret(secret string, curveType CurveType) PrivateKey {
-	hasher := sha256.New()
-	hasher.Write(([]byte)(secret))
-	// No error from a buffer
-	privateKey, _ := GeneratePrivateKey(bytes.NewBuffer(hasher.Sum(nil)), curveType)
-	return privateKey
-}
-
-// Ensures the last 32 bytes of the ed25519 private key is the public key derived from the first 32 private bytes
-func EnsureEd25519PrivateKeyCorrect(candidatePrivateKey ed25519.PrivateKey) error {
-	if len(candidatePrivateKey) != ed25519.PrivateKeySize {
-		return fmt.Errorf("ed25519 key has size %v but %v bytes passed as key", ed25519.PrivateKeySize,
-			len(candidatePrivateKey))
-	}
-	_, derivedPrivateKey, err := ed25519.GenerateKey(bytes.NewBuffer(candidatePrivateKey))
-	if err != nil {
-		return err
-	}
-	if !bytes.Equal(derivedPrivateKey, candidatePrivateKey) {
-		return fmt.Errorf("ed25519 key generated from prefix of %X should equal %X, but is %X",
-			candidatePrivateKey, candidatePrivateKey, derivedPrivateKey)
-	}
-	return nil
-}
-
-func ChainSign(signer Signer, chainID string, o Signable) (Signature, error) {
-	sig, err := signer.Sign(SignBytes(chainID, o))
-	if err != nil {
-		return Signature{}, err
-	}
-	return sig, nil
-}
-
-// Signature
-
-type Signature struct {
-	Signature []byte
-}
-
-// Currently this is a stub that reads the raw bytes returned by key_client and returns
-// an ed25519 signature.
-func SignatureFromBytes(bs []byte, curveType CurveType) (Signature, error) {
-	switch curveType {
-	case CurveTypeEd25519:
-		signatureEd25519 := Signature{}
-		if len(bs) != ed25519.SignatureSize {
-			return Signature{}, fmt.Errorf("bytes passed have length %v by ed25519 signatures have %v bytes",
-				len(bs), ed25519.SignatureSize)
-		}
-		copy(signatureEd25519.Signature[:], bs)
-		return Signature{
-			Signature: bs,
-		}, nil
-	case CurveTypeSecp256k1:
-		return Signature{
-			Signature: bs,
-		}, nil
-	default:
-		return Signature{}, nil
-	}
-}
-
-func (sig Signature) RawBytes() []byte {
-	return sig.Signature
-}
diff --git a/crypto/private_key.go b/crypto/private_key.go
new file mode 100644
index 0000000000000000000000000000000000000000..f1bad18969e89de0d4882a293e6f2b0117a19709
--- /dev/null
+++ b/crypto/private_key.go
@@ -0,0 +1,141 @@
+package crypto
+
+import (
+	"bytes"
+	cryptoRand "crypto/rand"
+	"crypto/sha256"
+	"fmt"
+	"io"
+
+	"github.com/btcsuite/btcd/btcec"
+	"golang.org/x/crypto/ed25519"
+)
+
+type PrivateKey struct {
+	CurveType  CurveType
+	PublicKey  []byte
+	PrivateKey []byte
+}
+
+// Currently this is a stub that reads the raw bytes returned by key_client and returns
+// an ed25519 public key.
+func PublicKeyFromBytes(bs []byte, curveType CurveType) (PublicKey, error) {
+	switch curveType {
+	case CurveTypeEd25519:
+		if len(bs) != ed25519.PublicKeySize {
+			return PublicKey{}, fmt.Errorf("bytes passed have length %v but ed25519 public keys have %v bytes",
+				len(bs), ed25519.PublicKeySize)
+		}
+	case CurveTypeSecp256k1:
+		if len(bs) != btcec.PubKeyBytesLenCompressed {
+			return PublicKey{}, fmt.Errorf("bytes passed have length %v but secp256k1 public keys have %v bytes",
+				len(bs), btcec.PubKeyBytesLenCompressed)
+		}
+	default:
+		return PublicKey{}, ErrInvalidCurve(curveType)
+	}
+
+	return PublicKey{PublicKey: bs, CurveType: curveType}, nil
+}
+
+func (p PrivateKey) RawBytes() []byte {
+	return p.PrivateKey
+}
+
+func (p PrivateKey) Sign(msg []byte) (Signature, error) {
+	switch p.CurveType {
+	case CurveTypeEd25519:
+		if len(p.PrivateKey) != ed25519.PrivateKeySize {
+			return Signature{}, fmt.Errorf("bytes passed have length %v but ed25519 private keys have %v bytes",
+				len(p.PrivateKey), ed25519.PrivateKeySize)
+		}
+		privKey := ed25519.PrivateKey(p.PrivateKey)
+		return Signature{ed25519.Sign(privKey, msg)}, nil
+	case CurveTypeSecp256k1:
+		if len(p.PrivateKey) != btcec.PrivKeyBytesLen {
+			return Signature{}, fmt.Errorf("bytes passed have length %v but secp256k1 private keys have %v bytes",
+				len(p.PrivateKey), btcec.PrivKeyBytesLen)
+		}
+		privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), p.PrivateKey)
+
+		sig, err := privKey.Sign(msg)
+		if err != nil {
+			return Signature{}, err
+		}
+		return Signature{Signature: sig.Serialize()}, nil
+	default:
+		return Signature{}, ErrInvalidCurve(p.CurveType)
+	}
+}
+
+func (p PrivateKey) GetPublicKey() PublicKey {
+	return PublicKey{CurveType: p.CurveType, PublicKey: p.PublicKey}
+}
+
+func PrivateKeyFromRawBytes(privKeyBytes []byte, curveType CurveType) (PrivateKey, error) {
+	switch curveType {
+	case CurveTypeEd25519:
+		if len(privKeyBytes) != ed25519.PrivateKeySize {
+			return PrivateKey{}, fmt.Errorf("bytes passed have length %v but ed25519 private keys have %v bytes",
+				len(privKeyBytes), ed25519.PrivateKeySize)
+		}
+		return PrivateKey{PrivateKey: privKeyBytes, PublicKey: privKeyBytes[32:], CurveType: CurveTypeEd25519}, nil
+	case CurveTypeSecp256k1:
+		if len(privKeyBytes) != btcec.PrivKeyBytesLen {
+			return PrivateKey{}, fmt.Errorf("bytes passed have length %v but secp256k1 private keys have %v bytes",
+				len(privKeyBytes), btcec.PrivKeyBytesLen)
+		}
+		privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
+		return PrivateKey{PrivateKey: privKey.Serialize(), PublicKey: pubKey.SerializeCompressed(), CurveType: CurveTypeSecp256k1}, nil
+	default:
+		return PrivateKey{}, ErrInvalidCurve(curveType)
+	}
+}
+
+func GeneratePrivateKey(random io.Reader, curveType CurveType) (PrivateKey, error) {
+	if random == nil {
+		random = cryptoRand.Reader
+	}
+	switch curveType {
+	case CurveTypeEd25519:
+		_, priv, err := ed25519.GenerateKey(random)
+		if err != nil {
+			return PrivateKey{}, err
+		}
+		return PrivateKeyFromRawBytes(priv, CurveTypeEd25519)
+	case CurveTypeSecp256k1:
+		privKeyBytes := make([]byte, 32)
+		_, err := random.Read(privKeyBytes)
+		if err != nil {
+			return PrivateKey{}, err
+		}
+		return PrivateKeyFromRawBytes(privKeyBytes, CurveTypeSecp256k1)
+	default:
+		return PrivateKey{}, ErrInvalidCurve(curveType)
+	}
+}
+
+func PrivateKeyFromSecret(secret string, curveType CurveType) PrivateKey {
+	hasher := sha256.New()
+	hasher.Write(([]byte)(secret))
+	// No error from a buffer
+	privateKey, _ := GeneratePrivateKey(bytes.NewBuffer(hasher.Sum(nil)), curveType)
+	return privateKey
+}
+
+// Ensures the last 32 bytes of the ed25519 private key is the public key derived from the first 32 private bytes
+func EnsureEd25519PrivateKeyCorrect(candidatePrivateKey ed25519.PrivateKey) error {
+	if len(candidatePrivateKey) != ed25519.PrivateKeySize {
+		return fmt.Errorf("ed25519 key has size %v but %v bytes passed as key", ed25519.PrivateKeySize,
+			len(candidatePrivateKey))
+	}
+	_, derivedPrivateKey, err := ed25519.GenerateKey(bytes.NewBuffer(candidatePrivateKey))
+	if err != nil {
+		return err
+	}
+	if !bytes.Equal(derivedPrivateKey, candidatePrivateKey) {
+		return fmt.Errorf("ed25519 key generated from prefix of %X should equal %X, but is %X",
+			candidatePrivateKey, candidatePrivateKey, derivedPrivateKey)
+	}
+	return nil
+}
diff --git a/crypto/public_key.go b/crypto/public_key.go
new file mode 100644
index 0000000000000000000000000000000000000000..a3d6564c51a355bf8190e217a97d1bfbc8f79505
--- /dev/null
+++ b/crypto/public_key.go
@@ -0,0 +1,197 @@
+package crypto
+
+import (
+	"crypto/sha256"
+	"encoding/json"
+	"fmt"
+
+	"github.com/btcsuite/btcd/btcec"
+	abci "github.com/tendermint/abci/types"
+	tmCrypto "github.com/tendermint/go-crypto"
+	"github.com/tmthrgd/go-hex"
+	"golang.org/x/crypto/ed25519"
+	"golang.org/x/crypto/ripemd160"
+)
+
+// PublicKey
+type PublicKey struct {
+	CurveType CurveType
+	PublicKey []byte
+	// memoised address
+	address *Address
+}
+
+type PublicKeyJSON struct {
+	CurveType string
+	PublicKey string
+}
+
+// Returns the length in bytes of the public key
+func PublicKeyLength(curveType CurveType) int {
+	switch curveType {
+	case CurveTypeEd25519:
+		return ed25519.PublicKeySize
+	case CurveTypeSecp256k1:
+		return btcec.PubKeyBytesLenCompressed
+	default:
+		// Other functions rely on this
+		return 0
+	}
+}
+
+func (p PublicKey) MarshalJSON() ([]byte, error) {
+	jStruct := PublicKeyJSON{
+		CurveType: p.CurveType.String(),
+		PublicKey: hex.EncodeUpperToString(p.PublicKey),
+	}
+	txt, err := json.Marshal(jStruct)
+	return txt, err
+}
+
+func (p PublicKey) MarshalText() ([]byte, error) {
+	return p.MarshalJSON()
+}
+
+func (p *PublicKey) UnmarshalJSON(text []byte) error {
+	var jStruct PublicKeyJSON
+	err := json.Unmarshal(text, &jStruct)
+	if err != nil {
+		return err
+	}
+	CurveType, err := CurveTypeFromString(jStruct.CurveType)
+	if err != nil {
+		return err
+	}
+	bs, err := hex.DecodeString(jStruct.PublicKey)
+	if err != nil {
+		return err
+	}
+	p.CurveType = CurveType
+	p.PublicKey = bs
+	return nil
+}
+
+func (p *PublicKey) UnmarshalText(text []byte) error {
+	return p.UnmarshalJSON(text)
+}
+
+func (p PublicKey) IsValid() bool {
+	return PublicKeyLength(p.CurveType) == len(p.PublicKey)
+}
+
+func (p PublicKey) Verify(msg []byte, signature Signature) bool {
+	switch p.CurveType {
+	case CurveTypeEd25519:
+		return ed25519.Verify(p.PublicKey, msg, signature.Signature[:])
+	case CurveTypeSecp256k1:
+		pub, err := btcec.ParsePubKey(p.PublicKey, btcec.S256())
+		if err != nil {
+			return false
+		}
+		sig, err := btcec.ParseDERSignature(signature.Signature, btcec.S256())
+		if err != nil {
+			return false
+		}
+		return sig.Verify(msg, pub)
+	default:
+		panic(fmt.Sprintf("invalid curve type"))
+	}
+}
+
+func (p PublicKey) Address() Address {
+	if p.address == nil {
+		address := p.computeAddress()
+		p.address = &address
+	}
+	return *p.address
+}
+
+func (p PublicKey) computeAddress() Address {
+	switch p.CurveType {
+	case CurveTypeEd25519:
+		// FIMXE: tendermint go-crypto-0.5.0 uses weird scheme, this is fixed in 0.6.0
+		tmPubKey := new(tmCrypto.PubKeyEd25519)
+		copy(tmPubKey[:], p.PublicKey)
+		addr, _ := AddressFromBytes(tmPubKey.Address())
+		return addr
+	case CurveTypeSecp256k1:
+		sha := sha256.New()
+		sha.Write(p.PublicKey[:])
+
+		hash := ripemd160.New()
+		hash.Write(sha.Sum(nil))
+		addr, _ := AddressFromBytes(hash.Sum(nil))
+		return addr
+	default:
+		panic(fmt.Sprintf("unknown CurveType %d", p.CurveType))
+	}
+}
+
+func (p PublicKey) AddressHashType() string {
+	switch p.CurveType {
+	case CurveTypeEd25519:
+		return "go-crypto-0.5.0"
+	case CurveTypeSecp256k1:
+		return "btc"
+	default:
+		return ""
+	}
+}
+
+func (p PublicKey) RawBytes() []byte {
+	return p.PublicKey[:]
+}
+
+// Return the ABCI PubKey. See Tendermint protobuf.go for the go-crypto conversion this is based on
+func (p PublicKey) ABCIPubKey() abci.PubKey {
+	switch p.CurveType {
+	case CurveTypeEd25519:
+		return abci.PubKey{
+			Type: "ed25519",
+			Data: p.RawBytes(),
+		}
+	case CurveTypeSecp256k1:
+		return abci.PubKey{
+			Type: "secp256k1",
+			Data: p.RawBytes(),
+		}
+	default:
+		return abci.PubKey{}
+	}
+}
+
+func (p PublicKey) String() string {
+	return hex.EncodeUpperToString(p.PublicKey)
+}
+
+// Produces a binary encoding of the CurveType byte plus
+// the public key for padded to a fixed width on the right
+func (p PublicKey) Encode() []byte {
+	encoded := make([]byte, PublicKeyLength(p.CurveType)+1)
+	encoded[0] = p.CurveType.Byte()
+	copy(encoded[1:], p.PublicKey)
+	return encoded
+}
+
+// Decodes an encoded public key returning the number of bytes consumed
+func DecodePublicKeyFixedWidth(buf []byte, publicKey *PublicKey) (int, error) {
+	if len(buf) < 1 {
+		return 0, fmt.Errorf("encoded bytes buffer must not be empty")
+	}
+	curveType := CurveType(buf[0])
+	publicKeyEnd := PublicKeyLength(curveType) + 1
+	if publicKeyEnd <= 0 {
+		return 0, fmt.Errorf("CurveType with identifier %v is unknown", curveType.Byte())
+	}
+	if len(buf) < publicKeyEnd {
+		return 0, fmt.Errorf("encoded bytes buffer has length %v but public key encoding for %v needs %v bytes",
+			len(buf), curveType, publicKeyEnd)
+	}
+
+	publicKey.CurveType = curveType
+	publicKey.PublicKey = buf[1:publicKeyEnd]
+	if !publicKey.IsValid() {
+		return publicKeyEnd, fmt.Errorf("decoded public key %v is not valid", publicKey)
+	}
+	return publicKeyEnd, nil
+}
diff --git a/crypto/signature.go b/crypto/signature.go
new file mode 100644
index 0000000000000000000000000000000000000000..fcbff9de8615a56443a0279bfbab4d04b9a9ac3c
--- /dev/null
+++ b/crypto/signature.go
@@ -0,0 +1,46 @@
+package crypto
+
+import (
+	"fmt"
+
+	"golang.org/x/crypto/ed25519"
+)
+
+type Signature struct {
+	Signature []byte
+}
+
+// Currently this is a stub that reads the raw bytes returned by key_client and returns
+// an ed25519 signature.
+func SignatureFromBytes(bs []byte, curveType CurveType) (Signature, error) {
+	switch curveType {
+	case CurveTypeEd25519:
+		signatureEd25519 := Signature{}
+		if len(bs) != ed25519.SignatureSize {
+			return Signature{}, fmt.Errorf("bytes passed have length %v by ed25519 signatures have %v bytes",
+				len(bs), ed25519.SignatureSize)
+		}
+		copy(signatureEd25519.Signature[:], bs)
+		return Signature{
+			Signature: bs,
+		}, nil
+	case CurveTypeSecp256k1:
+		return Signature{
+			Signature: bs,
+		}, nil
+	default:
+		return Signature{}, nil
+	}
+}
+
+func (sig Signature) RawBytes() []byte {
+	return sig.Signature
+}
+
+func ChainSign(signer Signer, chainID string, o Signable) (Signature, error) {
+	sig, err := signer.Sign(SignBytes(chainID, o))
+	if err != nil {
+		return Signature{}, err
+	}
+	return sig, nil
+}
diff --git a/genesis/spec/template_account.go b/genesis/spec/template_account.go
new file mode 100644
index 0000000000000000000000000000000000000000..f09cd57a1b53b27895263ba3d8d0836b4310056d
--- /dev/null
+++ b/genesis/spec/template_account.go
@@ -0,0 +1 @@
+package spec
diff --git a/governance/governance.go b/governance/governance.go
new file mode 100644
index 0000000000000000000000000000000000000000..b3e56f5b8307a645379c05d533e2eb64361700b7
--- /dev/null
+++ b/governance/governance.go
@@ -0,0 +1,17 @@
+// The governance package contains functionality for altering permissions, token distribution, consensus parameters,
+// validators, and network forks.
+package governance
+
+// TODO:
+// - Set validator power
+// - Set account amount(s)
+// - Set account permissions
+// - Set global permissions
+// - Set ConsensusParams
+// Future considerations:
+// - Handle network forks/termination/merging/replacement ?
+// - Provide transaction in stasis/sudo (voting?)
+// - Handle bonding by other means (e.g. pre-shared key permitting n bondings)
+// - Network administered proxies (i.e. instead of keys have password authentication for identities - allow calls to originate as if from address without key?)
+// Subject to:
+// - Less than 1/3 validator power change per block
diff --git a/rpc/service.go b/rpc/service.go
index 3a40c9cbdf4ce1a7c5c1fb5f6057ea81d920fede..0a360749541a9c542a2ed405914ae6431fe861c6 100644
--- a/rpc/service.go
+++ b/rpc/service.go
@@ -48,14 +48,14 @@ type Service struct {
 	nameReg         execution.NameRegIterable
 	mempoolAccounts *execution.Accounts
 	subscribable    event.Subscribable
-	blockchain      bcm.Blockchain
+	blockchain      *bcm.Blockchain
 	transactor      *execution.Transactor
 	nodeView        *query.NodeView
 	logger          *logging.Logger
 }
 
 func NewService(ctx context.Context, state state.Iterable, nameReg execution.NameRegIterable,
-	checker state.Reader, subscribable event.Subscribable, blockchain bcm.Blockchain, keyClient keys.KeyClient,
+	checker state.Reader, subscribable event.Subscribable, blockchain *bcm.Blockchain, keyClient keys.KeyClient,
 	transactor *execution.Transactor, nodeView *query.NodeView, logger *logging.Logger) *Service {
 
 	return &Service{
@@ -151,7 +151,7 @@ func (s *Service) Unsubscribe(ctx context.Context, subscriptionID string) error
 }
 
 func (s *Service) Status() (*ResultStatus, error) {
-	tip := s.blockchain.Tip()
+	tip := s.blockchain.Tip
 	latestHeight := tip.LastBlockHeight()
 	var (
 		latestBlockMeta *tm_types.BlockMeta
@@ -241,7 +241,7 @@ func (s *Service) ListAccounts(predicate func(acm.Account) bool) (*ResultListAcc
 	})
 
 	return &ResultListAccounts{
-		BlockHeight: s.blockchain.Tip().LastBlockHeight(),
+		BlockHeight: s.blockchain.Tip.LastBlockHeight(),
 		Accounts:    accounts,
 	}, nil
 }
@@ -353,7 +353,7 @@ func (s *Service) GetBlock(height uint64) (*ResultGetBlock, error) {
 // Passing 0 for maxHeight sets the upper height of the range to the current
 // blockchain height.
 func (s *Service) ListBlocks(minHeight, maxHeight uint64) (*ResultListBlocks, error) {
-	latestHeight := s.blockchain.Tip().LastBlockHeight()
+	latestHeight := s.blockchain.Tip.LastBlockHeight()
 
 	if minHeight == 0 {
 		minHeight = 1
@@ -378,15 +378,17 @@ func (s *Service) ListBlocks(minHeight, maxHeight uint64) (*ResultListBlocks, er
 }
 
 func (s *Service) ListValidators() (*ResultListValidators, error) {
-	// TODO: when we reintroduce support for bonding and unbonding update this
-	// to reflect the mutable bonding state
-	validators := s.blockchain.Validators()
-	concreteValidators := make([]*acm.ConcreteValidator, len(validators))
-	for i, validator := range validators {
-		concreteValidators[i] = acm.AsConcreteValidator(validator)
-	}
+	concreteValidators := make([]*acm.ConcreteValidator, 0, s.blockchain.NumValidators())
+	s.blockchain.IterateValidators(func(publicKey crypto.PublicKey, power uint64) (stop bool) {
+		concreteValidators = append(concreteValidators, &acm.ConcreteValidator{
+			Address:   publicKey.Address(),
+			PublicKey: publicKey,
+			Power:     power,
+		})
+		return
+	})
 	return &ResultListValidators{
-		BlockHeight:         s.blockchain.Tip().LastBlockHeight(),
+		BlockHeight:         s.blockchain.Tip.LastBlockHeight(),
 		BondedValidators:    concreteValidators,
 		UnbondingValidators: nil,
 	}, nil
diff --git a/txs/gov_tx.go b/txs/gov_tx.go
new file mode 100644
index 0000000000000000000000000000000000000000..ebfdb6f49f05444c23e56278f9e087af2b788b61
--- /dev/null
+++ b/txs/gov_tx.go
@@ -0,0 +1,91 @@
+package txs
+
+import (
+	"fmt"
+	"io"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/crypto"
+	"github.com/tendermint/go-wire"
+)
+
+type CallTx struct {
+	Input *TxInput
+	// Pointer since CallTx defines unset 'to' address as inducing account creation
+	Address  *crypto.Address
+	GasLimit uint64
+	Fee      uint64
+	Data     []byte
+	txHashMemoizer
+}
+
+var _ Tx = &CallTx{}
+
+func NewCallTx(st state.AccountGetter, from crypto.PublicKey, to *crypto.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 crypto.PublicKey, to *crypto.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 = crypto.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)
+}