diff --git a/acm/validator/validator.pb.go b/acm/validator/validator.pb.go
index 93c8b77d7b476877c6709de87971b03a0694bc96..b15639c0ed8a7b9be73832fa24e37d9f7180b06a 100644
--- a/acm/validator/validator.pb.go
+++ b/acm/validator/validator.pb.go
@@ -17,7 +17,6 @@ import golang_proto "github.com/golang/protobuf/proto"
 import fmt "fmt"
 import math "math"
 import _ "github.com/gogo/protobuf/gogoproto"
-import _ "github.com/hyperledger/burrow/permission"
 import crypto "github.com/hyperledger/burrow/crypto"
 
 import github_com_hyperledger_burrow_crypto "github.com/hyperledger/burrow/crypto"
@@ -385,21 +384,21 @@ func init() { proto.RegisterFile("validator.proto", fileDescriptorValidator) }
 func init() { golang_proto.RegisterFile("validator.proto", fileDescriptorValidator) }
 
 var fileDescriptorValidator = []byte{
-	// 255 bytes of a gzipped FileDescriptorProto
+	// 242 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2f, 0x4b, 0xcc, 0xc9,
 	0x4c, 0x49, 0x2c, 0xc9, 0x2f, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x84, 0x0b, 0x48,
 	0xe9, 0xa6, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xa7, 0xe7,
-	0xeb, 0x83, 0x55, 0x24, 0x95, 0xa6, 0x81, 0x79, 0x60, 0x0e, 0x98, 0x05, 0xd1, 0x29, 0x25, 0x50,
-	0x90, 0x5a, 0x94, 0x9b, 0x59, 0x5c, 0x9c, 0x99, 0x9f, 0x07, 0x15, 0xe1, 0x49, 0x2e, 0xaa, 0x2c,
-	0x28, 0x81, 0xca, 0x2b, 0xad, 0x62, 0xe4, 0xe2, 0x0c, 0x83, 0x19, 0x2e, 0xe4, 0xc5, 0xc5, 0xee,
-	0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x2c, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0xe3, 0x64, 0x70, 0xeb,
-	0x9e, 0xbc, 0x0e, 0x92, 0x8d, 0x19, 0x95, 0x05, 0xa9, 0x45, 0x39, 0xa9, 0x29, 0xe9, 0xa9, 0x45,
-	0xfa, 0x49, 0xa5, 0x45, 0x45, 0xf9, 0xe5, 0xfa, 0x50, 0xe3, 0xa0, 0xfa, 0x82, 0x60, 0x06, 0x08,
-	0x99, 0x72, 0x71, 0x06, 0x94, 0x26, 0xe5, 0x64, 0x26, 0x7b, 0xa7, 0x56, 0x4a, 0x30, 0x29, 0x30,
-	0x6a, 0x70, 0x1b, 0x09, 0xea, 0x41, 0x15, 0xc3, 0x25, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08,
-	0x42, 0xa8, 0x14, 0x12, 0xe1, 0x62, 0x0d, 0xc8, 0x2f, 0x4f, 0x2d, 0x92, 0x60, 0x56, 0x60, 0xd4,
-	0x60, 0x09, 0x82, 0x70, 0xac, 0x58, 0x66, 0x2c, 0x90, 0x67, 0x70, 0x72, 0x3c, 0xf1, 0x48, 0x8e,
-	0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x0f, 0x3c, 0x96, 0x63, 0x3c, 0xf1, 0x58,
-	0x8e, 0x31, 0x4a, 0x1b, 0xbf, 0xfb, 0x12, 0x93, 0x73, 0xf5, 0xe1, 0xc1, 0x97, 0xc4, 0x06, 0xf6,
-	0xb6, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x1c, 0xca, 0xd9, 0x6f, 0x63, 0x01, 0x00, 0x00,
+	0xeb, 0x83, 0x55, 0x24, 0x95, 0xa6, 0x81, 0x79, 0x60, 0x0e, 0x98, 0x05, 0xd1, 0x29, 0xc5, 0x93,
+	0x5c, 0x54, 0x59, 0x50, 0x02, 0xe5, 0x29, 0xad, 0x62, 0xe4, 0xe2, 0x0c, 0x83, 0x19, 0x25, 0xe4,
+	0xc5, 0xc5, 0xee, 0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x2c, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0xe3,
+	0x64, 0x70, 0xeb, 0x9e, 0xbc, 0x0e, 0x92, 0xf9, 0x19, 0x95, 0x05, 0xa9, 0x45, 0x39, 0xa9, 0x29,
+	0xe9, 0xa9, 0x45, 0xfa, 0x49, 0xa5, 0x45, 0x45, 0xf9, 0xe5, 0xfa, 0x50, 0xe3, 0xa0, 0xfa, 0x82,
+	0x60, 0x06, 0x08, 0x99, 0x72, 0x71, 0x06, 0x94, 0x26, 0xe5, 0x64, 0x26, 0x7b, 0xa7, 0x56, 0x4a,
+	0x30, 0x29, 0x30, 0x6a, 0x70, 0x1b, 0x09, 0xea, 0x41, 0x15, 0xc3, 0x25, 0x9c, 0x58, 0x4e, 0xdc,
+	0x93, 0x67, 0x08, 0x42, 0xa8, 0x14, 0x12, 0xe1, 0x62, 0x0d, 0xc8, 0x2f, 0x4f, 0x2d, 0x92, 0x60,
+	0x56, 0x60, 0xd4, 0x60, 0x09, 0x82, 0x70, 0xac, 0x58, 0x66, 0x2c, 0x90, 0x67, 0x70, 0x72, 0x3c,
+	0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x0f, 0x3c, 0x96, 0x63,
+	0x3c, 0xf1, 0x58, 0x8e, 0x31, 0x4a, 0x1b, 0xbf, 0xfb, 0x12, 0x93, 0x73, 0xf5, 0xe1, 0x81, 0x95,
+	0xc4, 0x06, 0xf6, 0xb6, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x5d, 0xe5, 0x4a, 0x65, 0x51, 0x01,
+	0x00, 0x00,
 }
diff --git a/consensus/tendermint/node_view.go b/consensus/tendermint/node_view.go
index 62a50085d82dd9d3b80eed78c5c0f90cb1c845c4..023533e141121bc049872d6529f6d4e38f8a3a22 100644
--- a/consensus/tendermint/node_view.go
+++ b/consensus/tendermint/node_view.go
@@ -7,32 +7,35 @@ import (
 	"github.com/hyperledger/burrow/txs"
 	"github.com/tendermint/tendermint/consensus"
 	ctypes "github.com/tendermint/tendermint/consensus/types"
-	tmCrypto "github.com/tendermint/tendermint/crypto"
 	"github.com/tendermint/tendermint/p2p"
 	"github.com/tendermint/tendermint/state"
 	"github.com/tendermint/tendermint/types"
 )
 
 type NodeView struct {
-	tmNode    *Node
-	txDecoder txs.Decoder
+	tmNode             *Node
+	validatorPublicKey crypto.PublicKey
+	txDecoder          txs.Decoder
 }
 
-func NewNodeView(tmNode *Node, txDecoder txs.Decoder) *NodeView {
-	return &NodeView{
-		tmNode:    tmNode,
-		txDecoder: txDecoder,
+func NewNodeView(tmNode *Node, txDecoder txs.Decoder) (*NodeView, error) {
+	publicKey, err := crypto.PublicKeyFromTendermintPubKey(tmNode.PrivValidator().GetPubKey())
+	if err != nil {
+		return nil, err
 	}
+	return &NodeView{
+		validatorPublicKey: publicKey,
+		tmNode:             tmNode,
+		txDecoder:          txDecoder,
+	}, nil
 }
 
-func (nv *NodeView) PrivValidatorPublicKey() (crypto.PublicKey, error) {
-	pub := nv.tmNode.PrivValidator().GetPubKey().(tmCrypto.PubKeyEd25519)
-
-	return crypto.PublicKeyFromBytes(pub[:], crypto.CurveTypeEd25519)
+func (nv *NodeView) ValidatorPublicKey() crypto.PublicKey {
+	return nv.validatorPublicKey
 }
 
-func (nv *NodeView) NodeInfo() p2p.NodeInfo {
-	return nv.tmNode.NodeInfo()
+func (nv *NodeView) NodeInfo() *NodeInfo {
+	return NewNodeInfo(nv.tmNode.NodeInfo())
 }
 
 func (nv *NodeView) IsListening() bool {
diff --git a/consensus/tendermint/tendermint.go b/consensus/tendermint/tendermint.go
index 0122f580eea7f9b3d70ab7c5f0cb355abcdcca08..573265ee6e48c2329f3f2ab516a9f6e051c52f76 100644
--- a/consensus/tendermint/tendermint.go
+++ b/consensus/tendermint/tendermint.go
@@ -4,7 +4,9 @@ import (
 	"os"
 	"path"
 
+	"github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/consensus/tendermint/abci"
+	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
@@ -12,6 +14,7 @@ import (
 	tmCrypto "github.com/tendermint/tendermint/crypto"
 	dbm "github.com/tendermint/tendermint/libs/db"
 	"github.com/tendermint/tendermint/node"
+	"github.com/tendermint/tendermint/p2p"
 	"github.com/tendermint/tendermint/proxy"
 	tmTypes "github.com/tendermint/tendermint/types"
 )
@@ -90,13 +93,15 @@ func DeriveGenesisDoc(burrowGenesisDoc *genesis.GenesisDoc) *tmTypes.GenesisDoc
 	}
 }
 
-func NewBlockEvent(message interface{}) *tmTypes.EventDataNewBlock {
-	tmEventData, ok := message.(tmTypes.TMEventData)
-	if ok {
-		eventDataNewBlock, ok := tmEventData.(tmTypes.EventDataNewBlock)
-		if ok {
-			return &eventDataNewBlock
-		}
+func NewNodeInfo(ni p2p.NodeInfo) *NodeInfo {
+	address, _ := crypto.AddressFromHexString(string(ni.ID))
+	return &NodeInfo{
+		ID:            address,
+		Moniker:       ni.Moniker,
+		ListenAddress: ni.ListenAddr,
+		Version:       ni.Version,
+		Channels:      binary.HexBytes(ni.Channels),
+		Network:       ni.Network,
+		Other:         ni.Other,
 	}
-	return nil
 }
diff --git a/consensus/tendermint/tendermint.pb.go b/consensus/tendermint/tendermint.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..6dd3e449aedb996afd63fed5b1ffcc96ed53fa12
--- /dev/null
+++ b/consensus/tendermint/tendermint.pb.go
@@ -0,0 +1,609 @@
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
+// source: tendermint.proto
+
+/*
+	Package tendermint is a generated protocol buffer package.
+
+	It is generated from these files:
+		tendermint.proto
+
+	It has these top-level messages:
+		NodeInfo
+*/
+package tendermint
+
+import proto "github.com/gogo/protobuf/proto"
+import golang_proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+import _ "github.com/gogo/protobuf/gogoproto"
+import _ "github.com/hyperledger/burrow/crypto"
+
+import github_com_hyperledger_burrow_crypto "github.com/hyperledger/burrow/crypto"
+import github_com_hyperledger_burrow_binary "github.com/hyperledger/burrow/binary"
+
+import io "io"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = golang_proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
+
+type NodeInfo struct {
+	ID            github_com_hyperledger_burrow_crypto.Address  `protobuf:"bytes,1,opt,name=ID,proto3,customtype=github.com/hyperledger/burrow/crypto.Address" json:"ID"`
+	ListenAddress string                                        `protobuf:"bytes,2,opt,name=ListenAddress,proto3" json:"ListenAddress,omitempty"`
+	Network       string                                        `protobuf:"bytes,3,opt,name=Network,proto3" json:"Network,omitempty"`
+	Version       string                                        `protobuf:"bytes,4,opt,name=Version,proto3" json:"Version,omitempty"`
+	Channels      github_com_hyperledger_burrow_binary.HexBytes `protobuf:"bytes,5,opt,name=Channels,proto3,customtype=github.com/hyperledger/burrow/binary.HexBytes" json:"Channels"`
+	Moniker       string                                        `protobuf:"bytes,6,opt,name=Moniker,proto3" json:"Moniker,omitempty"`
+	Other         []string                                      `protobuf:"bytes,7,rep,name=Other" json:"Other,omitempty"`
+}
+
+func (m *NodeInfo) Reset()                    { *m = NodeInfo{} }
+func (m *NodeInfo) String() string            { return proto.CompactTextString(m) }
+func (*NodeInfo) ProtoMessage()               {}
+func (*NodeInfo) Descriptor() ([]byte, []int) { return fileDescriptorTendermint, []int{0} }
+
+func (m *NodeInfo) GetListenAddress() string {
+	if m != nil {
+		return m.ListenAddress
+	}
+	return ""
+}
+
+func (m *NodeInfo) GetNetwork() string {
+	if m != nil {
+		return m.Network
+	}
+	return ""
+}
+
+func (m *NodeInfo) GetVersion() string {
+	if m != nil {
+		return m.Version
+	}
+	return ""
+}
+
+func (m *NodeInfo) GetMoniker() string {
+	if m != nil {
+		return m.Moniker
+	}
+	return ""
+}
+
+func (m *NodeInfo) GetOther() []string {
+	if m != nil {
+		return m.Other
+	}
+	return nil
+}
+
+func (*NodeInfo) XXX_MessageName() string {
+	return "tendermint.NodeInfo"
+}
+func init() {
+	proto.RegisterType((*NodeInfo)(nil), "tendermint.NodeInfo")
+	golang_proto.RegisterType((*NodeInfo)(nil), "tendermint.NodeInfo")
+}
+func (m *NodeInfo) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *NodeInfo) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	dAtA[i] = 0xa
+	i++
+	i = encodeVarintTendermint(dAtA, i, uint64(m.ID.Size()))
+	n1, err := m.ID.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n1
+	if len(m.ListenAddress) > 0 {
+		dAtA[i] = 0x12
+		i++
+		i = encodeVarintTendermint(dAtA, i, uint64(len(m.ListenAddress)))
+		i += copy(dAtA[i:], m.ListenAddress)
+	}
+	if len(m.Network) > 0 {
+		dAtA[i] = 0x1a
+		i++
+		i = encodeVarintTendermint(dAtA, i, uint64(len(m.Network)))
+		i += copy(dAtA[i:], m.Network)
+	}
+	if len(m.Version) > 0 {
+		dAtA[i] = 0x22
+		i++
+		i = encodeVarintTendermint(dAtA, i, uint64(len(m.Version)))
+		i += copy(dAtA[i:], m.Version)
+	}
+	dAtA[i] = 0x2a
+	i++
+	i = encodeVarintTendermint(dAtA, i, uint64(m.Channels.Size()))
+	n2, err := m.Channels.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n2
+	if len(m.Moniker) > 0 {
+		dAtA[i] = 0x32
+		i++
+		i = encodeVarintTendermint(dAtA, i, uint64(len(m.Moniker)))
+		i += copy(dAtA[i:], m.Moniker)
+	}
+	if len(m.Other) > 0 {
+		for _, s := range m.Other {
+			dAtA[i] = 0x3a
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			dAtA[i] = uint8(l)
+			i++
+			i += copy(dAtA[i:], s)
+		}
+	}
+	return i, nil
+}
+
+func encodeVarintTendermint(dAtA []byte, offset int, v uint64) int {
+	for v >= 1<<7 {
+		dAtA[offset] = uint8(v&0x7f | 0x80)
+		v >>= 7
+		offset++
+	}
+	dAtA[offset] = uint8(v)
+	return offset + 1
+}
+func (m *NodeInfo) Size() (n int) {
+	var l int
+	_ = l
+	l = m.ID.Size()
+	n += 1 + l + sovTendermint(uint64(l))
+	l = len(m.ListenAddress)
+	if l > 0 {
+		n += 1 + l + sovTendermint(uint64(l))
+	}
+	l = len(m.Network)
+	if l > 0 {
+		n += 1 + l + sovTendermint(uint64(l))
+	}
+	l = len(m.Version)
+	if l > 0 {
+		n += 1 + l + sovTendermint(uint64(l))
+	}
+	l = m.Channels.Size()
+	n += 1 + l + sovTendermint(uint64(l))
+	l = len(m.Moniker)
+	if l > 0 {
+		n += 1 + l + sovTendermint(uint64(l))
+	}
+	if len(m.Other) > 0 {
+		for _, s := range m.Other {
+			l = len(s)
+			n += 1 + l + sovTendermint(uint64(l))
+		}
+	}
+	return n
+}
+
+func sovTendermint(x uint64) (n int) {
+	for {
+		n++
+		x >>= 7
+		if x == 0 {
+			break
+		}
+	}
+	return n
+}
+func sozTendermint(x uint64) (n int) {
+	return sovTendermint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+func (m *NodeInfo) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowTendermint
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: NodeInfo: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: NodeInfo: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthTendermint
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.ID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ListenAddress", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthTendermint
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ListenAddress = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Network", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthTendermint
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Network = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthTendermint
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Version = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Channels", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthTendermint
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.Channels.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 6:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Moniker", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthTendermint
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Moniker = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 7:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Other", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthTendermint
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Other = append(m.Other, string(dAtA[iNdEx:postIndex]))
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipTendermint(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthTendermint
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func skipTendermint(dAtA []byte) (n int, err error) {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return 0, ErrIntOverflowTendermint
+			}
+			if iNdEx >= l {
+				return 0, io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		wireType := int(wire & 0x7)
+		switch wireType {
+		case 0:
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				iNdEx++
+				if dAtA[iNdEx-1] < 0x80 {
+					break
+				}
+			}
+			return iNdEx, nil
+		case 1:
+			iNdEx += 8
+			return iNdEx, nil
+		case 2:
+			var length int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowTendermint
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				length |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			iNdEx += length
+			if length < 0 {
+				return 0, ErrInvalidLengthTendermint
+			}
+			return iNdEx, nil
+		case 3:
+			for {
+				var innerWire uint64
+				var start int = iNdEx
+				for shift := uint(0); ; shift += 7 {
+					if shift >= 64 {
+						return 0, ErrIntOverflowTendermint
+					}
+					if iNdEx >= l {
+						return 0, io.ErrUnexpectedEOF
+					}
+					b := dAtA[iNdEx]
+					iNdEx++
+					innerWire |= (uint64(b) & 0x7F) << shift
+					if b < 0x80 {
+						break
+					}
+				}
+				innerWireType := int(innerWire & 0x7)
+				if innerWireType == 4 {
+					break
+				}
+				next, err := skipTendermint(dAtA[start:])
+				if err != nil {
+					return 0, err
+				}
+				iNdEx = start + next
+			}
+			return iNdEx, nil
+		case 4:
+			return iNdEx, nil
+		case 5:
+			iNdEx += 4
+			return iNdEx, nil
+		default:
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
+		}
+	}
+	panic("unreachable")
+}
+
+var (
+	ErrInvalidLengthTendermint = fmt.Errorf("proto: negative length found during unmarshaling")
+	ErrIntOverflowTendermint   = fmt.Errorf("proto: integer overflow")
+)
+
+func init() { proto.RegisterFile("tendermint.proto", fileDescriptorTendermint) }
+func init() { golang_proto.RegisterFile("tendermint.proto", fileDescriptorTendermint) }
+
+var fileDescriptorTendermint = []byte{
+	// 321 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0xbd, 0x4e, 0x3a, 0x41,
+	0x14, 0xc5, 0xff, 0xb3, 0xfc, 0xf9, 0x9a, 0x60, 0x62, 0x36, 0x16, 0x13, 0x8a, 0x85, 0x18, 0x0b,
+	0x0a, 0x61, 0x13, 0x3f, 0x1e, 0x40, 0xa4, 0x80, 0x44, 0x31, 0x6e, 0x61, 0x61, 0xc7, 0xb2, 0x97,
+	0xdd, 0x0d, 0x30, 0x97, 0xdc, 0x99, 0x0d, 0xee, 0x43, 0xf9, 0x0e, 0x96, 0x94, 0xd6, 0x16, 0xc4,
+	0xc0, 0x8b, 0x18, 0x66, 0x57, 0xd1, 0x46, 0xbb, 0xf9, 0x9d, 0x33, 0x73, 0xee, 0xc9, 0x5c, 0x7e,
+	0xa8, 0x41, 0x06, 0x40, 0xf3, 0x58, 0xea, 0xce, 0x82, 0x50, 0xa3, 0xcd, 0xf7, 0x4a, 0xbd, 0x1d,
+	0xc6, 0x3a, 0x4a, 0xfc, 0xce, 0x18, 0xe7, 0x6e, 0x88, 0x21, 0xba, 0xe6, 0x8a, 0x9f, 0x4c, 0x0c,
+	0x19, 0x30, 0xa7, 0xec, 0x69, 0xbd, 0x36, 0xa6, 0x74, 0xa1, 0x73, 0x3a, 0x7e, 0xb6, 0x78, 0x65,
+	0x88, 0x01, 0x0c, 0xe4, 0x04, 0xed, 0x1e, 0xb7, 0x06, 0x3d, 0xc1, 0x9a, 0xac, 0x55, 0xeb, 0x5e,
+	0xac, 0xd6, 0x8d, 0x7f, 0x6f, 0xeb, 0xc6, 0xe9, 0xb7, 0xf4, 0x28, 0x5d, 0x00, 0xcd, 0x20, 0x08,
+	0x81, 0x5c, 0x3f, 0x21, 0xc2, 0xa5, 0x9b, 0x87, 0x5d, 0x05, 0x01, 0x81, 0x52, 0x9e, 0x35, 0xe8,
+	0xd9, 0x27, 0xfc, 0xe0, 0x26, 0x56, 0x1a, 0x64, 0x2e, 0x0a, 0xab, 0xc9, 0x5a, 0x55, 0xef, 0xa7,
+	0x68, 0x0b, 0x5e, 0x1e, 0x82, 0x5e, 0x22, 0x4d, 0x45, 0xc1, 0xf8, 0x9f, 0xb8, 0x73, 0x1e, 0x80,
+	0x54, 0x8c, 0x52, 0xfc, 0xcf, 0x9c, 0x1c, 0xed, 0x7b, 0x5e, 0xb9, 0x8e, 0x46, 0x52, 0xc2, 0x4c,
+	0x89, 0xa2, 0x69, 0x79, 0x99, 0xb7, 0x6c, 0xff, 0xde, 0xd2, 0x8f, 0xe5, 0x88, 0xd2, 0x4e, 0x1f,
+	0x9e, 0xba, 0xa9, 0x06, 0xe5, 0x7d, 0xc5, 0xec, 0x86, 0xdd, 0xa2, 0x8c, 0xa7, 0x40, 0xa2, 0x94,
+	0x0d, 0xcb, 0xd1, 0x3e, 0xe2, 0xc5, 0x3b, 0x1d, 0x01, 0x89, 0x72, 0xb3, 0xd0, 0xaa, 0x7a, 0x19,
+	0x74, 0xfb, 0xab, 0x8d, 0xc3, 0x5e, 0x37, 0x0e, 0x7b, 0xdf, 0x38, 0xec, 0x65, 0xeb, 0xb0, 0xd5,
+	0xd6, 0x61, 0x8f, 0x67, 0x7f, 0x7c, 0x12, 0x4a, 0x05, 0x52, 0x25, 0xca, 0xdd, 0xaf, 0xcd, 0x2f,
+	0x99, 0x05, 0x9c, 0x7f, 0x04, 0x00, 0x00, 0xff, 0xff, 0x29, 0x50, 0xa8, 0x1b, 0xdd, 0x01, 0x00,
+	0x00,
+}
diff --git a/core/kernel.go b/core/kernel.go
index 46854844acfc90d1d9214deccb44c5cc8444abcb..28ff55a7271f663b3a6f4c5e145f8fb5ae41251f 100644
--- a/core/kernel.go
+++ b/core/kernel.go
@@ -126,7 +126,10 @@ func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tmTy
 
 	nameRegState := kern.State
 	accountState := kern.State
-	nodeView := tendermint.NewNodeView(kern.Node, txCodec)
+	nodeView, err := tendermint.NewNodeView(kern.Node, txCodec)
+	if err != nil {
+		return nil, err
+	}
 	kern.Service = rpc.NewService(accountState, nameRegState, kern.Blockchain, nodeView, kern.Logger)
 
 	kern.Launchers = []process.Launcher{
diff --git a/integration/rpcquery/query_server_test.go b/integration/rpcquery/query_server_test.go
index 05bb7e858e712a2868d6da4f24a89a3b3e4a620c..adef77c72001e4c67308c40bd31ae1afc08fa3f0 100644
--- a/integration/rpcquery/query_server_test.go
+++ b/integration/rpcquery/query_server_test.go
@@ -18,6 +18,25 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+func TestStatus(t *testing.T) {
+	cli := rpctest.NewQueryClient(t, testConfig.RPC.GRPC.ListenAddress)
+	stat, err := cli.Status(context.Background(), &rpcquery.StatusParam{})
+	require.NoError(t, err)
+	assert.Equal(t, rpctest.PrivateAccounts[0].PublicKey(), stat.PublicKey)
+	assert.Equal(t, rpctest.GenesisDoc.ChainID(), stat.ChainID)
+	for i := 0; i < 3; i++ {
+		// Unless we get lucky this is an error
+		_, err = cli.Status(context.Background(), &rpcquery.StatusParam{
+			BlockWithin: "1ns",
+		})
+		if err != nil {
+			break
+		}
+	}
+	require.Error(t, err)
+	assert.Contains(t, err.Error(), "no block committed within")
+}
+
 func TestGetAccount(t *testing.T) {
 	cli := rpctest.NewQueryClient(t, testConfig.RPC.GRPC.ListenAddress)
 	ca, err := cli.GetAccount(context.Background(), &rpcquery.GetAccountParam{
diff --git a/protobuf/rpc.proto b/protobuf/rpc.proto
new file mode 100644
index 0000000000000000000000000000000000000000..88f78933e3ddfda30a5facc8077fbe1f8dc09dc4
--- /dev/null
+++ b/protobuf/rpc.proto
@@ -0,0 +1,31 @@
+// Needed to proto2 rather than proto3 to get pointer field for PermArg
+syntax = 'proto3';
+
+option go_package = "github.com/hyperledger/burrow/rpc";
+
+import "github.com/gogo/protobuf/gogoproto/gogo.proto";
+import "crypto.proto";
+import "tendermint.proto";
+import "google/protobuf/timestamp.proto";
+
+package rpc;
+
+option (gogoproto.marshaler_all) = true;
+option (gogoproto.unmarshaler_all) = true;
+option (gogoproto.sizer_all) = true;
+option (gogoproto.goproto_registration) = true;
+option (gogoproto.messagename_all) = true;
+
+message ResultStatus {
+    string ChainID = 1;
+    bytes GenesisHash = 4 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.HexBytes", (gogoproto.nullable) = false];
+    tendermint.NodeInfo NodeInfo = 2;
+    string NodeVersion = 3;
+    crypto.PublicKey PublicKey = 5 [(gogoproto.nullable) = false];
+    bytes LatestBlockHash = 6 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.HexBytes", (gogoproto.nullable) = false];
+    uint64 LatestBlockHeight = 7;
+    // Unix
+
+    google.protobuf.Timestamp LatestBlockTime = 8 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
+}
+
diff --git a/protobuf/rpcquery.proto b/protobuf/rpcquery.proto
index fc8b66262e5fe309df5e52657782c93f87365473..8981b7b7fb11f3dddb344c7965c982cdd851ec19 100644
--- a/protobuf/rpcquery.proto
+++ b/protobuf/rpcquery.proto
@@ -9,6 +9,7 @@ import "github.com/gogo/protobuf/gogoproto/gogo.proto";
 import "names.proto";
 import "acm.proto";
 import "validator.proto";
+import "rpc.proto";
 
 option (gogoproto.marshaler_all) = true;
 option (gogoproto.unmarshaler_all) = true;
@@ -17,13 +18,20 @@ option (gogoproto.goproto_registration) = true;
 option (gogoproto.messagename_all) = true;
 
 service Query {
+    rpc Status (StatusParam) returns (rpc.ResultStatus);
     rpc GetAccount (GetAccountParam) returns (acm.ConcreteAccount);
     rpc ListAccounts (ListAccountsParam) returns (stream acm.ConcreteAccount);
+
     rpc GetName (GetNameParam) returns (names.Entry);
     rpc ListNames (ListNamesParam) returns (stream names.Entry);
+
     rpc GetValidatorSet (GetValidatorSetParam) returns (ValidatorSet);
 }
 
+message StatusParam {
+    string BlockWithin = 1;
+}
+
 message GetAccountParam {
     bytes Address = 1 [(gogoproto.customtype) = "github.com/hyperledger/burrow/crypto.Address", (gogoproto.nullable) = false];
 }
diff --git a/protobuf/tendermint.proto b/protobuf/tendermint.proto
new file mode 100644
index 0000000000000000000000000000000000000000..cef3f0c38dad42a922599910ff52db08a7f98e73
--- /dev/null
+++ b/protobuf/tendermint.proto
@@ -0,0 +1,25 @@
+// Needed to proto2 rather than proto3 to get pointer field for PermArg
+syntax = 'proto3';
+
+option go_package = "github.com/hyperledger/burrow/consensus/tendermint";
+
+import "github.com/gogo/protobuf/gogoproto/gogo.proto";
+import "crypto.proto";
+
+package tendermint;
+
+option (gogoproto.marshaler_all) = true;
+option (gogoproto.unmarshaler_all) = true;
+option (gogoproto.sizer_all) = true;
+option (gogoproto.goproto_registration) = true;
+option (gogoproto.messagename_all) = true;
+
+message NodeInfo {
+    bytes ID = 1 [(gogoproto.customtype) = "github.com/hyperledger/burrow/crypto.Address", (gogoproto.nullable) = false];
+    string ListenAddress = 2;
+    string Network = 3;
+    string Version = 4;
+    bytes Channels = 5 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.HexBytes", (gogoproto.nullable) = false];
+    string Moniker = 6;
+    repeated string Other = 7;
+}
diff --git a/rpc/metrics/export.go b/rpc/metrics/export.go
index 51e105c96c21f5f4090a3123ba2a9bf39d6aefce..d64a8577ee3ffd883c170de6e98b9c1aa04040a4 100644
--- a/rpc/metrics/export.go
+++ b/rpc/metrics/export.go
@@ -53,7 +53,7 @@ func (e *Exporter) gatherData() error {
 
 // Get status
 func (e *Exporter) getStatus() error {
-	res, err := e.service.Status()
+	res, err := e.service.Status("")
 	if err != nil {
 		return err
 	}
diff --git a/rpc/metrics/server.go b/rpc/metrics/server.go
index 5eab0754c58a243ebb9c6c1bda12515c3ebcc71f..273996dddc4e9240a562554b2fab6a71870e59a5 100644
--- a/rpc/metrics/server.go
+++ b/rpc/metrics/server.go
@@ -55,7 +55,7 @@ func StartServer(service *rpc.Service, pattern, listenAddress string, blockSampl
 	logger *logging.Logger) (*http.Server, error) {
 
 	// instantiate metrics and variables we do not expect to change during runtime
-	chainStatus, _ := service.Status()
+	chainStatus, _ := service.Status("")
 	exporter := Exporter{
 		burrowMetrics:    AddMetrics(),
 		datum:            &Datum{},
diff --git a/rpc/result.go b/rpc/result.go
index 35d21892f7d912c622a8cacc710a56ecdf66763e..a7ca72edb6408f5afbb3ef5cc2da5df2f844622b 100644
--- a/rpc/result.go
+++ b/rpc/result.go
@@ -15,18 +15,16 @@
 package rpc
 
 import (
-	"time"
-
 	"github.com/hyperledger/burrow/acm"
 	"github.com/hyperledger/burrow/acm/validator"
 	"github.com/hyperledger/burrow/binary"
+	"github.com/hyperledger/burrow/consensus/tendermint"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/txs"
 	"github.com/tendermint/go-amino"
 	consensusTypes "github.com/tendermint/tendermint/consensus/types"
-	"github.com/tendermint/tendermint/p2p"
 	"github.com/tendermint/tendermint/rpc/core/types"
 	tmTypes "github.com/tendermint/tendermint/types"
 )
@@ -94,22 +92,6 @@ func (b *Block) UnmarshalJSON(data []byte) (err error) {
 	return aminoCodec.UnmarshalJSON(data, &b.Block)
 }
 
-type ResultStatus struct {
-	NodeInfo          p2p.NodeInfo
-	GenesisHash       binary.HexBytes
-	PublicKey         crypto.PublicKey
-	LatestBlockHash   binary.HexBytes
-	LatestBlockHeight uint64
-	LatestBlockTime   int64
-	NodeVersion       string
-}
-
-type ResultLastBlockInfo struct {
-	LastBlockHeight uint64
-	LastBlockTime   time.Time
-	LastBlockHash   binary.HexBytes
-}
-
 type ResultChainId struct {
 	ChainName   string
 	ChainId     string
@@ -126,12 +108,12 @@ type ResultUnsubscribe struct {
 }
 
 type Peer struct {
-	NodeInfo   p2p.NodeInfo
+	NodeInfo   *tendermint.NodeInfo
 	IsOutbound bool
 }
 
 type ResultNetInfo struct {
-	ThisNode  p2p.NodeInfo
+	ThisNode  *tendermint.NodeInfo
 	Listening bool
 	Listeners []string
 	Peers     []*Peer
diff --git a/rpc/result_test.go b/rpc/result_test.go
index 9c66f47ad838dd8aaab94e017f7c7da4e23749e5..78af66633d1ed0cfbcab6dc14232e8b2dafe144f 100644
--- a/rpc/result_test.go
+++ b/rpc/result_test.go
@@ -18,12 +18,7 @@ import (
 	"encoding/json"
 	"testing"
 
-	"time"
-
-	"fmt"
-
 	"github.com/hyperledger/burrow/acm"
-	"github.com/hyperledger/burrow/binary"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/tendermint/tendermint/consensus/types"
@@ -87,15 +82,3 @@ func TestResultDumpConsensusState(t *testing.T) {
 	require.NoError(t, err)
 	assert.Equal(t, string(bs), string(bsOut))
 }
-
-func TestResultLastBlockInfo(t *testing.T) {
-	res := &ResultLastBlockInfo{
-		LastBlockTime:   time.Now(),
-		LastBlockHash:   binary.HexBytes{3, 4, 5, 6},
-		LastBlockHeight: 2343,
-	}
-	bs, err := json.Marshal(res)
-	require.NoError(t, err)
-	fmt.Println(string(bs))
-
-}
diff --git a/rpc/rpc.pb.go b/rpc/rpc.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..8836266a778e1caa5e0e61e063e67d8199b9579e
--- /dev/null
+++ b/rpc/rpc.pb.go
@@ -0,0 +1,652 @@
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
+// source: rpc.proto
+
+/*
+	Package rpc is a generated protocol buffer package.
+
+	It is generated from these files:
+		rpc.proto
+
+	It has these top-level messages:
+		ResultStatus
+*/
+package rpc
+
+import proto "github.com/gogo/protobuf/proto"
+import golang_proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+import _ "github.com/gogo/protobuf/gogoproto"
+import crypto "github.com/hyperledger/burrow/crypto"
+import tendermint "github.com/hyperledger/burrow/consensus/tendermint"
+import _ "github.com/golang/protobuf/ptypes/timestamp"
+
+import github_com_hyperledger_burrow_binary "github.com/hyperledger/burrow/binary"
+import time "time"
+
+import types "github.com/gogo/protobuf/types"
+
+import io "io"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = golang_proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+var _ = time.Kitchen
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
+
+type ResultStatus struct {
+	ChainID           string                                        `protobuf:"bytes,1,opt,name=ChainID,proto3" json:"ChainID,omitempty"`
+	GenesisHash       github_com_hyperledger_burrow_binary.HexBytes `protobuf:"bytes,4,opt,name=GenesisHash,proto3,customtype=github.com/hyperledger/burrow/binary.HexBytes" json:"GenesisHash"`
+	NodeInfo          *tendermint.NodeInfo                          `protobuf:"bytes,2,opt,name=NodeInfo" json:"NodeInfo,omitempty"`
+	NodeVersion       string                                        `protobuf:"bytes,3,opt,name=NodeVersion,proto3" json:"NodeVersion,omitempty"`
+	PublicKey         crypto.PublicKey                              `protobuf:"bytes,5,opt,name=PublicKey" json:"PublicKey"`
+	LatestBlockHash   github_com_hyperledger_burrow_binary.HexBytes `protobuf:"bytes,6,opt,name=LatestBlockHash,proto3,customtype=github.com/hyperledger/burrow/binary.HexBytes" json:"LatestBlockHash"`
+	LatestBlockHeight uint64                                        `protobuf:"varint,7,opt,name=LatestBlockHeight,proto3" json:"LatestBlockHeight,omitempty"`
+	LatestBlockTime   time.Time                                     `protobuf:"bytes,8,opt,name=LatestBlockTime,stdtime" json:"LatestBlockTime"`
+}
+
+func (m *ResultStatus) Reset()                    { *m = ResultStatus{} }
+func (m *ResultStatus) String() string            { return proto.CompactTextString(m) }
+func (*ResultStatus) ProtoMessage()               {}
+func (*ResultStatus) Descriptor() ([]byte, []int) { return fileDescriptorRpc, []int{0} }
+
+func (m *ResultStatus) GetChainID() string {
+	if m != nil {
+		return m.ChainID
+	}
+	return ""
+}
+
+func (m *ResultStatus) GetNodeInfo() *tendermint.NodeInfo {
+	if m != nil {
+		return m.NodeInfo
+	}
+	return nil
+}
+
+func (m *ResultStatus) GetNodeVersion() string {
+	if m != nil {
+		return m.NodeVersion
+	}
+	return ""
+}
+
+func (m *ResultStatus) GetPublicKey() crypto.PublicKey {
+	if m != nil {
+		return m.PublicKey
+	}
+	return crypto.PublicKey{}
+}
+
+func (m *ResultStatus) GetLatestBlockHeight() uint64 {
+	if m != nil {
+		return m.LatestBlockHeight
+	}
+	return 0
+}
+
+func (m *ResultStatus) GetLatestBlockTime() time.Time {
+	if m != nil {
+		return m.LatestBlockTime
+	}
+	return time.Time{}
+}
+
+func (*ResultStatus) XXX_MessageName() string {
+	return "rpc.ResultStatus"
+}
+func init() {
+	proto.RegisterType((*ResultStatus)(nil), "rpc.ResultStatus")
+	golang_proto.RegisterType((*ResultStatus)(nil), "rpc.ResultStatus")
+}
+func (m *ResultStatus) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *ResultStatus) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.ChainID) > 0 {
+		dAtA[i] = 0xa
+		i++
+		i = encodeVarintRpc(dAtA, i, uint64(len(m.ChainID)))
+		i += copy(dAtA[i:], m.ChainID)
+	}
+	if m.NodeInfo != nil {
+		dAtA[i] = 0x12
+		i++
+		i = encodeVarintRpc(dAtA, i, uint64(m.NodeInfo.Size()))
+		n1, err := m.NodeInfo.MarshalTo(dAtA[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n1
+	}
+	if len(m.NodeVersion) > 0 {
+		dAtA[i] = 0x1a
+		i++
+		i = encodeVarintRpc(dAtA, i, uint64(len(m.NodeVersion)))
+		i += copy(dAtA[i:], m.NodeVersion)
+	}
+	dAtA[i] = 0x22
+	i++
+	i = encodeVarintRpc(dAtA, i, uint64(m.GenesisHash.Size()))
+	n2, err := m.GenesisHash.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n2
+	dAtA[i] = 0x2a
+	i++
+	i = encodeVarintRpc(dAtA, i, uint64(m.PublicKey.Size()))
+	n3, err := m.PublicKey.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n3
+	dAtA[i] = 0x32
+	i++
+	i = encodeVarintRpc(dAtA, i, uint64(m.LatestBlockHash.Size()))
+	n4, err := m.LatestBlockHash.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n4
+	if m.LatestBlockHeight != 0 {
+		dAtA[i] = 0x38
+		i++
+		i = encodeVarintRpc(dAtA, i, uint64(m.LatestBlockHeight))
+	}
+	dAtA[i] = 0x42
+	i++
+	i = encodeVarintRpc(dAtA, i, uint64(types.SizeOfStdTime(m.LatestBlockTime)))
+	n5, err := types.StdTimeMarshalTo(m.LatestBlockTime, dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n5
+	return i, nil
+}
+
+func encodeVarintRpc(dAtA []byte, offset int, v uint64) int {
+	for v >= 1<<7 {
+		dAtA[offset] = uint8(v&0x7f | 0x80)
+		v >>= 7
+		offset++
+	}
+	dAtA[offset] = uint8(v)
+	return offset + 1
+}
+func (m *ResultStatus) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.ChainID)
+	if l > 0 {
+		n += 1 + l + sovRpc(uint64(l))
+	}
+	if m.NodeInfo != nil {
+		l = m.NodeInfo.Size()
+		n += 1 + l + sovRpc(uint64(l))
+	}
+	l = len(m.NodeVersion)
+	if l > 0 {
+		n += 1 + l + sovRpc(uint64(l))
+	}
+	l = m.GenesisHash.Size()
+	n += 1 + l + sovRpc(uint64(l))
+	l = m.PublicKey.Size()
+	n += 1 + l + sovRpc(uint64(l))
+	l = m.LatestBlockHash.Size()
+	n += 1 + l + sovRpc(uint64(l))
+	if m.LatestBlockHeight != 0 {
+		n += 1 + sovRpc(uint64(m.LatestBlockHeight))
+	}
+	l = types.SizeOfStdTime(m.LatestBlockTime)
+	n += 1 + l + sovRpc(uint64(l))
+	return n
+}
+
+func sovRpc(x uint64) (n int) {
+	for {
+		n++
+		x >>= 7
+		if x == 0 {
+			break
+		}
+	}
+	return n
+}
+func sozRpc(x uint64) (n int) {
+	return sovRpc(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+func (m *ResultStatus) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowRpc
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: ResultStatus: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: ResultStatus: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthRpc
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ChainID = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NodeInfo", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthRpc
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.NodeInfo == nil {
+				m.NodeInfo = &tendermint.NodeInfo{}
+			}
+			if err := m.NodeInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NodeVersion", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthRpc
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NodeVersion = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field GenesisHash", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthRpc
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.GenesisHash.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthRpc
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.PublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 6:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LatestBlockHash", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthRpc
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.LatestBlockHash.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 7:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LatestBlockHeight", wireType)
+			}
+			m.LatestBlockHeight = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.LatestBlockHeight |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 8:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LatestBlockTime", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthRpc
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := types.StdTimeUnmarshal(&m.LatestBlockTime, dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipRpc(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthRpc
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func skipRpc(dAtA []byte) (n int, err error) {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return 0, ErrIntOverflowRpc
+			}
+			if iNdEx >= l {
+				return 0, io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		wireType := int(wire & 0x7)
+		switch wireType {
+		case 0:
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				iNdEx++
+				if dAtA[iNdEx-1] < 0x80 {
+					break
+				}
+			}
+			return iNdEx, nil
+		case 1:
+			iNdEx += 8
+			return iNdEx, nil
+		case 2:
+			var length int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				length |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			iNdEx += length
+			if length < 0 {
+				return 0, ErrInvalidLengthRpc
+			}
+			return iNdEx, nil
+		case 3:
+			for {
+				var innerWire uint64
+				var start int = iNdEx
+				for shift := uint(0); ; shift += 7 {
+					if shift >= 64 {
+						return 0, ErrIntOverflowRpc
+					}
+					if iNdEx >= l {
+						return 0, io.ErrUnexpectedEOF
+					}
+					b := dAtA[iNdEx]
+					iNdEx++
+					innerWire |= (uint64(b) & 0x7F) << shift
+					if b < 0x80 {
+						break
+					}
+				}
+				innerWireType := int(innerWire & 0x7)
+				if innerWireType == 4 {
+					break
+				}
+				next, err := skipRpc(dAtA[start:])
+				if err != nil {
+					return 0, err
+				}
+				iNdEx = start + next
+			}
+			return iNdEx, nil
+		case 4:
+			return iNdEx, nil
+		case 5:
+			iNdEx += 4
+			return iNdEx, nil
+		default:
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
+		}
+	}
+	panic("unreachable")
+}
+
+var (
+	ErrInvalidLengthRpc = fmt.Errorf("proto: negative length found during unmarshaling")
+	ErrIntOverflowRpc   = fmt.Errorf("proto: integer overflow")
+)
+
+func init() { proto.RegisterFile("rpc.proto", fileDescriptorRpc) }
+func init() { golang_proto.RegisterFile("rpc.proto", fileDescriptorRpc) }
+
+var fileDescriptorRpc = []byte{
+	// 397 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x51, 0x41, 0xcf, 0xd2, 0x40,
+	0x10, 0x75, 0x05, 0xbf, 0x0f, 0x16, 0x12, 0x65, 0xe3, 0x61, 0xc3, 0xa1, 0xad, 0x9e, 0x7a, 0xd0,
+	0xad, 0xd1, 0x10, 0xef, 0xd5, 0x44, 0x88, 0x86, 0x98, 0x4a, 0x34, 0xf1, 0x62, 0xda, 0x32, 0xb4,
+	0x1b, 0xdb, 0x6e, 0xb3, 0xbb, 0x8d, 0xf6, 0x5f, 0xf8, 0x93, 0x3c, 0x72, 0xf4, 0xec, 0x01, 0x0d,
+	0x1c, 0xfd, 0x13, 0x86, 0x85, 0x42, 0xc5, 0xc4, 0x8b, 0xb7, 0x79, 0xf3, 0x66, 0xde, 0xbc, 0x99,
+	0xc1, 0x7d, 0x59, 0xc6, 0xac, 0x94, 0x42, 0x0b, 0xd2, 0x91, 0x65, 0x3c, 0x7e, 0x98, 0x70, 0x9d,
+	0x56, 0x11, 0x8b, 0x45, 0xee, 0x25, 0x22, 0x11, 0x9e, 0xe1, 0xa2, 0x6a, 0x65, 0x90, 0x01, 0x26,
+	0x3a, 0xf4, 0x8c, 0x87, 0xb1, 0xac, 0x4b, 0xdd, 0xa0, 0x3b, 0x1a, 0x8a, 0x25, 0xc8, 0x9c, 0x17,
+	0xfa, 0x98, 0xb1, 0x13, 0x21, 0x92, 0x0c, 0xce, 0x2a, 0x9a, 0xe7, 0xa0, 0x74, 0x98, 0x97, 0x87,
+	0x82, 0xfb, 0xbf, 0x3a, 0x78, 0x18, 0x80, 0xaa, 0x32, 0xfd, 0x46, 0x87, 0xba, 0x52, 0x84, 0xe2,
+	0xeb, 0x67, 0x69, 0xc8, 0x8b, 0xd9, 0x73, 0x8a, 0x1c, 0xe4, 0xf6, 0x83, 0x06, 0x92, 0x47, 0xb8,
+	0x37, 0x17, 0x4b, 0x98, 0x15, 0x2b, 0x41, 0x6f, 0x3a, 0xc8, 0x1d, 0x3c, 0xbe, 0xcb, 0x5a, 0x03,
+	0x1b, 0x2e, 0x38, 0x55, 0x11, 0x07, 0x0f, 0xf6, 0xf1, 0x5b, 0x90, 0x8a, 0x8b, 0x82, 0x76, 0x8c,
+	0x5e, 0x3b, 0x45, 0xde, 0xe1, 0xc1, 0x0b, 0x28, 0x40, 0x71, 0x35, 0x0d, 0x55, 0x4a, 0xbb, 0x0e,
+	0x72, 0x87, 0xfe, 0x64, 0xbd, 0xb1, 0x6f, 0x7c, 0xdf, 0xd8, 0xed, 0x5b, 0xa4, 0x75, 0x09, 0x32,
+	0x83, 0x65, 0x02, 0xd2, 0x8b, 0x2a, 0x29, 0xc5, 0x27, 0x2f, 0xe2, 0x45, 0x28, 0x6b, 0x36, 0x85,
+	0xcf, 0x7e, 0xad, 0x41, 0x05, 0x6d, 0x25, 0x32, 0xc1, 0xfd, 0xd7, 0x55, 0x94, 0xf1, 0xf8, 0x25,
+	0xd4, 0xf4, 0x96, 0x71, 0x3b, 0x62, 0xc7, 0x63, 0x9d, 0x08, 0xbf, 0xbb, 0x9f, 0x14, 0x9c, 0x2b,
+	0xc9, 0x07, 0x7c, 0xfb, 0x55, 0xa8, 0x41, 0x69, 0x3f, 0x13, 0xf1, 0x47, 0xe3, 0xe9, 0xea, 0x7f,
+	0x3c, 0x5d, 0xaa, 0x91, 0x07, 0x78, 0xd4, 0x4e, 0x01, 0x4f, 0x52, 0x4d, 0xaf, 0x1d, 0xe4, 0x76,
+	0x83, 0xbf, 0x09, 0x32, 0xff, 0xc3, 0xce, 0x82, 0xe7, 0x40, 0x7b, 0x66, 0x97, 0x31, 0x3b, 0x3c,
+	0x96, 0x35, 0x8f, 0x65, 0x8b, 0xe6, 0xb1, 0x7e, 0x6f, 0x6f, 0xf5, 0xcb, 0x0f, 0x1b, 0x05, 0x97,
+	0xcd, 0xfe, 0xd3, 0xf5, 0xd6, 0x42, 0xdf, 0xb6, 0x16, 0xfa, 0xb9, 0xb5, 0xd0, 0xd7, 0x9d, 0x85,
+	0xd6, 0x3b, 0x0b, 0xbd, 0xbf, 0xf7, 0xef, 0x9d, 0x64, 0x19, 0x47, 0x57, 0x66, 0xce, 0x93, 0xdf,
+	0x01, 0x00, 0x00, 0xff, 0xff, 0x84, 0x6f, 0xc9, 0xec, 0xaf, 0x02, 0x00, 0x00,
+}
diff --git a/rpc/rpcquery/query_server.go b/rpc/rpcquery/query_server.go
index debdc05b53f06473b252cff097b76e1512b56e62..45f2a54e2d5bbcee88f4e67be7b0eafa8db7b0eb 100644
--- a/rpc/rpcquery/query_server.go
+++ b/rpc/rpcquery/query_server.go
@@ -10,6 +10,7 @@ import (
 	"github.com/hyperledger/burrow/event/query"
 	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/logging"
+	"github.com/hyperledger/burrow/rpc"
 )
 
 type queryServer struct {
@@ -33,6 +34,10 @@ func NewQueryServer(state state.IterableReader, nameReg names.IterableReader, bl
 	}
 }
 
+func (qs *queryServer) Status(ctx context.Context, param *StatusParam) (*rpc.ResultStatus, error) {
+	return rpc.Status(qs.blockchain, qs.nodeView, param.BlockWithin)
+}
+
 // Account state
 
 func (qs *queryServer) GetAccount(ctx context.Context, param *GetAccountParam) (*acm.ConcreteAccount, error) {
diff --git a/rpc/rpcquery/rpcquery.pb.go b/rpc/rpcquery/rpcquery.pb.go
index ec9b81710c9f6a760e4d693965d95b4f70cbf1f0..120b2df0b75ecc09eea894cd791d286ae31814a4 100644
--- a/rpc/rpcquery/rpcquery.pb.go
+++ b/rpc/rpcquery/rpcquery.pb.go
@@ -8,6 +8,7 @@
 		rpcquery.proto
 
 	It has these top-level messages:
+		StatusParam
 		GetAccountParam
 		ListAccountsParam
 		GetNameParam
@@ -26,6 +27,7 @@ import _ "github.com/gogo/protobuf/gogoproto"
 import names "github.com/hyperledger/burrow/execution/names"
 import acm "github.com/hyperledger/burrow/acm"
 import validator "github.com/hyperledger/burrow/acm/validator"
+import rpc "github.com/hyperledger/burrow/rpc"
 
 import github_com_hyperledger_burrow_crypto "github.com/hyperledger/burrow/crypto"
 
@@ -46,6 +48,26 @@ var _ = math.Inf
 // proto package needs to be updated.
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 
+type StatusParam struct {
+	BlockWithin string `protobuf:"bytes,1,opt,name=BlockWithin,proto3" json:"BlockWithin,omitempty"`
+}
+
+func (m *StatusParam) Reset()                    { *m = StatusParam{} }
+func (m *StatusParam) String() string            { return proto.CompactTextString(m) }
+func (*StatusParam) ProtoMessage()               {}
+func (*StatusParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{0} }
+
+func (m *StatusParam) GetBlockWithin() string {
+	if m != nil {
+		return m.BlockWithin
+	}
+	return ""
+}
+
+func (*StatusParam) XXX_MessageName() string {
+	return "rpcquery.StatusParam"
+}
+
 type GetAccountParam struct {
 	Address github_com_hyperledger_burrow_crypto.Address `protobuf:"bytes,1,opt,name=Address,proto3,customtype=github.com/hyperledger/burrow/crypto.Address" json:"Address"`
 }
@@ -53,7 +75,7 @@ type GetAccountParam struct {
 func (m *GetAccountParam) Reset()                    { *m = GetAccountParam{} }
 func (m *GetAccountParam) String() string            { return proto.CompactTextString(m) }
 func (*GetAccountParam) ProtoMessage()               {}
-func (*GetAccountParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{0} }
+func (*GetAccountParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{1} }
 
 func (*GetAccountParam) XXX_MessageName() string {
 	return "rpcquery.GetAccountParam"
@@ -66,7 +88,7 @@ type ListAccountsParam struct {
 func (m *ListAccountsParam) Reset()                    { *m = ListAccountsParam{} }
 func (m *ListAccountsParam) String() string            { return proto.CompactTextString(m) }
 func (*ListAccountsParam) ProtoMessage()               {}
-func (*ListAccountsParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{1} }
+func (*ListAccountsParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{2} }
 
 func (m *ListAccountsParam) GetQuery() string {
 	if m != nil {
@@ -86,7 +108,7 @@ type GetNameParam struct {
 func (m *GetNameParam) Reset()                    { *m = GetNameParam{} }
 func (m *GetNameParam) String() string            { return proto.CompactTextString(m) }
 func (*GetNameParam) ProtoMessage()               {}
-func (*GetNameParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{2} }
+func (*GetNameParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{3} }
 
 func (m *GetNameParam) GetName() string {
 	if m != nil {
@@ -106,7 +128,7 @@ type ListNamesParam struct {
 func (m *ListNamesParam) Reset()                    { *m = ListNamesParam{} }
 func (m *ListNamesParam) String() string            { return proto.CompactTextString(m) }
 func (*ListNamesParam) ProtoMessage()               {}
-func (*ListNamesParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{3} }
+func (*ListNamesParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{4} }
 
 func (m *ListNamesParam) GetQuery() string {
 	if m != nil {
@@ -126,7 +148,7 @@ type GetValidatorSetParam struct {
 func (m *GetValidatorSetParam) Reset()                    { *m = GetValidatorSetParam{} }
 func (m *GetValidatorSetParam) String() string            { return proto.CompactTextString(m) }
 func (*GetValidatorSetParam) ProtoMessage()               {}
-func (*GetValidatorSetParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{4} }
+func (*GetValidatorSetParam) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{5} }
 
 func (m *GetValidatorSetParam) GetIncludeHistory() bool {
 	if m != nil {
@@ -148,7 +170,7 @@ type ValidatorSet struct {
 func (m *ValidatorSet) Reset()                    { *m = ValidatorSet{} }
 func (m *ValidatorSet) String() string            { return proto.CompactTextString(m) }
 func (*ValidatorSet) ProtoMessage()               {}
-func (*ValidatorSet) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{5} }
+func (*ValidatorSet) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{6} }
 
 func (m *ValidatorSet) GetHeight() uint64 {
 	if m != nil {
@@ -182,7 +204,7 @@ type ValidatorSetDeltas struct {
 func (m *ValidatorSetDeltas) Reset()                    { *m = ValidatorSetDeltas{} }
 func (m *ValidatorSetDeltas) String() string            { return proto.CompactTextString(m) }
 func (*ValidatorSetDeltas) ProtoMessage()               {}
-func (*ValidatorSetDeltas) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{6} }
+func (*ValidatorSetDeltas) Descriptor() ([]byte, []int) { return fileDescriptorRpcquery, []int{7} }
 
 func (m *ValidatorSetDeltas) GetValidators() []*validator.Validator {
 	if m != nil {
@@ -195,6 +217,8 @@ func (*ValidatorSetDeltas) XXX_MessageName() string {
 	return "rpcquery.ValidatorSetDeltas"
 }
 func init() {
+	proto.RegisterType((*StatusParam)(nil), "rpcquery.StatusParam")
+	golang_proto.RegisterType((*StatusParam)(nil), "rpcquery.StatusParam")
 	proto.RegisterType((*GetAccountParam)(nil), "rpcquery.GetAccountParam")
 	golang_proto.RegisterType((*GetAccountParam)(nil), "rpcquery.GetAccountParam")
 	proto.RegisterType((*ListAccountsParam)(nil), "rpcquery.ListAccountsParam")
@@ -222,6 +246,7 @@ const _ = grpc.SupportPackageIsVersion4
 // Client API for Query service
 
 type QueryClient interface {
+	Status(ctx context.Context, in *StatusParam, opts ...grpc.CallOption) (*rpc.ResultStatus, error)
 	GetAccount(ctx context.Context, in *GetAccountParam, opts ...grpc.CallOption) (*acm.ConcreteAccount, error)
 	ListAccounts(ctx context.Context, in *ListAccountsParam, opts ...grpc.CallOption) (Query_ListAccountsClient, error)
 	GetName(ctx context.Context, in *GetNameParam, opts ...grpc.CallOption) (*names.Entry, error)
@@ -237,6 +262,15 @@ func NewQueryClient(cc *grpc.ClientConn) QueryClient {
 	return &queryClient{cc}
 }
 
+func (c *queryClient) Status(ctx context.Context, in *StatusParam, opts ...grpc.CallOption) (*rpc.ResultStatus, error) {
+	out := new(rpc.ResultStatus)
+	err := grpc.Invoke(ctx, "/rpcquery.Query/Status", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *queryClient) GetAccount(ctx context.Context, in *GetAccountParam, opts ...grpc.CallOption) (*acm.ConcreteAccount, error) {
 	out := new(acm.ConcreteAccount)
 	err := grpc.Invoke(ctx, "/rpcquery.Query/GetAccount", in, out, c.cc, opts...)
@@ -331,6 +365,7 @@ func (c *queryClient) GetValidatorSet(ctx context.Context, in *GetValidatorSetPa
 // Server API for Query service
 
 type QueryServer interface {
+	Status(context.Context, *StatusParam) (*rpc.ResultStatus, error)
 	GetAccount(context.Context, *GetAccountParam) (*acm.ConcreteAccount, error)
 	ListAccounts(*ListAccountsParam, Query_ListAccountsServer) error
 	GetName(context.Context, *GetNameParam) (*names.Entry, error)
@@ -342,6 +377,24 @@ func RegisterQueryServer(s *grpc.Server, srv QueryServer) {
 	s.RegisterService(&_Query_serviceDesc, srv)
 }
 
+func _Query_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(StatusParam)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(QueryServer).Status(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/rpcquery.Query/Status",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(QueryServer).Status(ctx, req.(*StatusParam))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Query_GetAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(GetAccountParam)
 	if err := dec(in); err != nil {
@@ -442,6 +495,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{
 	ServiceName: "rpcquery.Query",
 	HandlerType: (*QueryServer)(nil),
 	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Status",
+			Handler:    _Query_Status_Handler,
+		},
 		{
 			MethodName: "GetAccount",
 			Handler:    _Query_GetAccount_Handler,
@@ -470,6 +527,30 @@ var _Query_serviceDesc = grpc.ServiceDesc{
 	Metadata: "rpcquery.proto",
 }
 
+func (m *StatusParam) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *StatusParam) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.BlockWithin) > 0 {
+		dAtA[i] = 0xa
+		i++
+		i = encodeVarintRpcquery(dAtA, i, uint64(len(m.BlockWithin)))
+		i += copy(dAtA[i:], m.BlockWithin)
+	}
+	return i, nil
+}
+
 func (m *GetAccountParam) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -682,6 +763,16 @@ func encodeVarintRpcquery(dAtA []byte, offset int, v uint64) int {
 	dAtA[offset] = uint8(v)
 	return offset + 1
 }
+func (m *StatusParam) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.BlockWithin)
+	if l > 0 {
+		n += 1 + l + sovRpcquery(uint64(l))
+	}
+	return n
+}
+
 func (m *GetAccountParam) Size() (n int) {
 	var l int
 	_ = l
@@ -775,6 +866,85 @@ func sovRpcquery(x uint64) (n int) {
 func sozRpcquery(x uint64) (n int) {
 	return sovRpcquery(uint64((x << 1) ^ uint64((int64(x) >> 63))))
 }
+func (m *StatusParam) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowRpcquery
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: StatusParam: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: StatusParam: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field BlockWithin", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpcquery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthRpcquery
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.BlockWithin = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipRpcquery(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthRpcquery
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func (m *GetAccountParam) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
@@ -1483,36 +1653,39 @@ func init() { proto.RegisterFile("rpcquery.proto", fileDescriptorRpcquery) }
 func init() { golang_proto.RegisterFile("rpcquery.proto", fileDescriptorRpcquery) }
 
 var fileDescriptorRpcquery = []byte{
-	// 487 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0x4f, 0x6f, 0xd3, 0x30,
-	0x1c, 0xc5, 0xeb, 0x58, 0xd7, 0xdf, 0xaa, 0x4e, 0x58, 0x55, 0x55, 0x02, 0xca, 0xa6, 0x1c, 0xaa,
-	0x81, 0x20, 0x99, 0xc6, 0xe0, 0x06, 0x62, 0x1b, 0xa8, 0x0c, 0xa1, 0x09, 0x32, 0x89, 0x03, 0x37,
-	0xd7, 0x31, 0x69, 0xa4, 0x26, 0x0e, 0x8e, 0x03, 0xea, 0x17, 0xe0, 0x63, 0x21, 0x8e, 0x3d, 0x72,
-	0xe6, 0x30, 0xa1, 0xee, 0x8b, 0xa0, 0x38, 0xce, 0xbf, 0x75, 0xea, 0xcd, 0xcf, 0x79, 0xef, 0xf7,
-	0xec, 0xbc, 0x67, 0xe8, 0x89, 0x98, 0x7e, 0x4b, 0x99, 0x98, 0xdb, 0xb1, 0xe0, 0x92, 0xe3, 0xed,
-	0x02, 0x1b, 0x4f, 0xfd, 0x40, 0x4e, 0xd3, 0x89, 0x4d, 0x79, 0xe8, 0xf8, 0xdc, 0xe7, 0x8e, 0x22,
-	0x4c, 0xd2, 0xaf, 0x0a, 0x29, 0xa0, 0x56, 0xb9, 0xd0, 0xd8, 0x89, 0x48, 0xc8, 0x12, 0x0d, 0x3a,
-	0x84, 0x86, 0x7a, 0xb9, 0xfb, 0x9d, 0xcc, 0x02, 0x8f, 0x48, 0x2e, 0xf2, 0x0d, 0x8b, 0xc0, 0xee,
-	0x98, 0xc9, 0x13, 0x4a, 0x79, 0x1a, 0xc9, 0x8f, 0x44, 0x90, 0x10, 0x5f, 0x40, 0xfb, 0xc4, 0xf3,
-	0x04, 0x4b, 0x92, 0x21, 0xda, 0x47, 0x07, 0xdd, 0xd3, 0xe3, 0xc5, 0xd5, 0xde, 0x9d, 0xbf, 0x57,
-	0x7b, 0x4f, 0x6a, 0x67, 0x98, 0xce, 0x63, 0x26, 0x66, 0xcc, 0xf3, 0x99, 0x70, 0x26, 0xa9, 0x10,
-	0xfc, 0x87, 0x43, 0xc5, 0x3c, 0x96, 0xdc, 0xd6, 0x5a, 0xb7, 0x18, 0x62, 0x3d, 0x82, 0x7b, 0x1f,
-	0x82, 0xa4, 0xf0, 0x48, 0x72, 0x93, 0x3e, 0xdc, 0xfd, 0x94, 0x5d, 0x4c, 0x59, 0x74, 0xdc, 0x1c,
-	0x58, 0x16, 0x74, 0xc7, 0x4c, 0x5e, 0x90, 0x90, 0xe5, 0x2c, 0x0c, 0x9b, 0x19, 0xd0, 0x24, 0xb5,
-	0xb6, 0x46, 0xd0, 0xcb, 0xc6, 0x65, 0xeb, 0xb5, 0xb3, 0x5e, 0x41, 0x7f, 0xcc, 0xe4, 0xe7, 0xe2,
-	0xbe, 0x97, 0x4c, 0x5f, 0x6f, 0x04, 0xbd, 0xf3, 0x88, 0xce, 0x52, 0x8f, 0xbd, 0x0b, 0x12, 0xc9,
-	0xb5, 0x6c, 0xdb, 0xbd, 0xb1, 0x6b, 0xfd, 0x44, 0xd0, 0xad, 0xab, 0xf1, 0x00, 0xb6, 0xa6, 0x2c,
-	0xf0, 0xa7, 0x52, 0x09, 0x36, 0x5d, 0x8d, 0xf0, 0x08, 0x5a, 0x97, 0x4c, 0x0e, 0x37, 0xf6, 0x5b,
-	0x07, 0x3b, 0x47, 0x7d, 0xbb, 0xfa, 0xc3, 0xa5, 0xda, 0xcd, 0x08, 0xf8, 0x05, 0xb4, 0x0b, 0xc7,
-	0x96, 0xe2, 0x3e, 0xb4, 0xcb, 0xb8, 0xeb, 0x46, 0x6f, 0xd8, 0x4c, 0x92, 0xc4, 0x2d, 0xc8, 0xd6,
-	0x7b, 0xc0, 0xab, 0x9f, 0xf1, 0x31, 0x40, 0xb9, 0x9b, 0xac, 0x35, 0xaf, 0xf1, 0x8e, 0x7e, 0x6d,
-	0xe8, 0x7f, 0x85, 0x5f, 0x02, 0x54, 0xc1, 0xe3, 0xfb, 0xd5, 0x51, 0x6e, 0xd4, 0xc1, 0xe8, 0xdb,
-	0x59, 0x7d, 0xce, 0x78, 0x44, 0x05, 0x93, 0xac, 0x10, 0x9c, 0x41, 0xb7, 0x1e, 0x2a, 0x7e, 0x50,
-	0x0d, 0x58, 0x09, 0xfb, 0xf6, 0x11, 0x87, 0x08, 0x3b, 0xd0, 0xd6, 0x71, 0xe3, 0x41, 0xe3, 0x00,
-	0x65, 0x03, 0x8c, 0xae, 0x9d, 0x37, 0xf9, 0x6d, 0x24, 0xc5, 0x1c, 0x3f, 0x87, 0x4e, 0x99, 0x3d,
-	0x1e, 0x36, 0x2d, 0xab, 0x42, 0x34, 0x45, 0x87, 0x08, 0x9f, 0xab, 0x92, 0x37, 0xc2, 0x34, 0x1b,
-	0x7e, 0x2b, 0x2d, 0x31, 0x06, 0xb7, 0x67, 0x73, 0xfa, 0x7a, 0xb1, 0x34, 0xd1, 0x9f, 0xa5, 0x89,
-	0xfe, 0x2d, 0x4d, 0xf4, 0xfb, 0xda, 0x44, 0x8b, 0x6b, 0x13, 0x7d, 0x79, 0xbc, 0xfe, 0x65, 0x88,
-	0x98, 0x3a, 0xc5, 0xb8, 0xc9, 0x96, 0x7a, 0x78, 0xcf, 0xfe, 0x07, 0x00, 0x00, 0xff, 0xff, 0xfd,
-	0xa4, 0xb6, 0xf9, 0xec, 0x03, 0x00, 0x00,
+	// 538 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0xc1, 0x6e, 0xd3, 0x40,
+	0x10, 0x86, 0xd9, 0xa6, 0x24, 0xcd, 0x24, 0x4a, 0xd5, 0x55, 0x88, 0x82, 0x41, 0x6e, 0xe4, 0x43,
+	0x54, 0x10, 0xd8, 0x55, 0x28, 0xdc, 0x40, 0x34, 0x05, 0x85, 0x22, 0x54, 0x81, 0x23, 0x81, 0xc4,
+	0x6d, 0xb3, 0x59, 0x12, 0x0b, 0xc7, 0x6b, 0xd6, 0x6b, 0x50, 0x5e, 0x80, 0xe7, 0xe2, 0x98, 0x23,
+	0x67, 0x0e, 0x15, 0x4a, 0xdf, 0x80, 0x27, 0x40, 0x5e, 0xaf, 0x63, 0xa7, 0xa9, 0x72, 0x9b, 0x59,
+	0xff, 0xff, 0xcc, 0x78, 0xf7, 0x1b, 0x68, 0x88, 0x90, 0x7e, 0x8b, 0x99, 0x98, 0xdb, 0xa1, 0xe0,
+	0x92, 0xe3, 0xbd, 0x2c, 0x37, 0x1e, 0x4f, 0x3c, 0x39, 0x8d, 0x47, 0x36, 0xe5, 0x33, 0x67, 0xc2,
+	0x27, 0xdc, 0x51, 0x82, 0x51, 0xfc, 0x45, 0x65, 0x2a, 0x51, 0x51, 0x6a, 0x34, 0x6a, 0x01, 0x99,
+	0xb1, 0x48, 0x27, 0x55, 0x42, 0x67, 0x3a, 0xdc, 0xff, 0x4e, 0x7c, 0x6f, 0x4c, 0x24, 0x17, 0xd9,
+	0x37, 0x11, 0xd2, 0x34, 0xb4, 0x1c, 0xa8, 0x0d, 0x25, 0x91, 0x71, 0xf4, 0x9e, 0x08, 0x32, 0xc3,
+	0x1d, 0xa8, 0xf5, 0x7d, 0x4e, 0xbf, 0x7e, 0xf2, 0xe4, 0xd4, 0x0b, 0xda, 0xa8, 0x83, 0x8e, 0xaa,
+	0x6e, 0xf1, 0xc8, 0x22, 0xb0, 0x3f, 0x60, 0xf2, 0x94, 0x52, 0x1e, 0x07, 0x32, 0x35, 0x5d, 0x40,
+	0xe5, 0x74, 0x3c, 0x16, 0x2c, 0x8a, 0x94, 0xa1, 0xde, 0x3f, 0x59, 0x5c, 0x1e, 0xde, 0xfa, 0x73,
+	0x79, 0xf8, 0xa8, 0x30, 0xff, 0x74, 0x1e, 0x32, 0xe1, 0xb3, 0xf1, 0x84, 0x09, 0x67, 0x14, 0x0b,
+	0xc1, 0x7f, 0x38, 0x54, 0xcc, 0x43, 0xc9, 0x6d, 0xed, 0x75, 0xb3, 0x22, 0xd6, 0x03, 0x38, 0x78,
+	0xe7, 0x45, 0x59, 0x0f, 0x3d, 0x59, 0x13, 0x6e, 0x7f, 0x48, 0x2e, 0x45, 0xcf, 0x94, 0x26, 0x96,
+	0x05, 0xf5, 0x01, 0x93, 0x17, 0x64, 0xc6, 0x52, 0x15, 0x86, 0xdd, 0x24, 0xd1, 0x22, 0x15, 0x5b,
+	0x5d, 0x68, 0x24, 0xe5, 0x92, 0x78, 0x6b, 0xad, 0x17, 0xd0, 0x1c, 0x30, 0xf9, 0x31, 0xbb, 0xab,
+	0x21, 0xd3, 0xbf, 0xd7, 0x85, 0xc6, 0x79, 0x40, 0xfd, 0x78, 0xcc, 0xde, 0x78, 0x91, 0xe4, 0xda,
+	0xb6, 0xe7, 0x5e, 0x3b, 0xb5, 0x7e, 0x22, 0xa8, 0x17, 0xdd, 0xb8, 0x05, 0xe5, 0x29, 0xf3, 0x26,
+	0x53, 0xa9, 0x0c, 0xbb, 0xae, 0xce, 0x70, 0x17, 0x4a, 0x43, 0x26, 0xdb, 0x3b, 0x9d, 0xd2, 0x51,
+	0xad, 0xd7, 0xb4, 0xf3, 0xd7, 0x59, 0xb9, 0xdd, 0x44, 0x80, 0x9f, 0x41, 0x25, 0xeb, 0x58, 0x52,
+	0xda, 0xfb, 0xf6, 0x0a, 0x95, 0x62, 0xa3, 0x57, 0xcc, 0x97, 0x24, 0x72, 0x33, 0xb1, 0xf5, 0x16,
+	0xf0, 0xe6, 0x67, 0x7c, 0x02, 0xb0, 0x3a, 0x8d, 0xb6, 0x36, 0x2f, 0xe8, 0x7a, 0xff, 0x76, 0xf4,
+	0x5d, 0xe1, 0x1e, 0x94, 0x53, 0x52, 0xf0, 0x9d, 0x7c, 0x8c, 0x02, 0x3b, 0xc6, 0x41, 0x72, 0x6c,
+	0xbb, 0x2c, 0x8a, 0x7d, 0xa9, 0x95, 0xcf, 0x01, 0x72, 0x58, 0xf0, 0xdd, 0xdc, 0x77, 0x0d, 0x21,
+	0xa3, 0x69, 0x27, 0xb8, 0x9e, 0xf1, 0x80, 0x0a, 0x26, 0x59, 0x66, 0x38, 0x83, 0x7a, 0x11, 0x04,
+	0x7c, 0x2f, 0x2f, 0xb0, 0x01, 0xc8, 0xcd, 0x25, 0x8e, 0x11, 0x76, 0xa0, 0xa2, 0x11, 0xc1, 0xad,
+	0xb5, 0x01, 0x56, 0xd4, 0x18, 0x75, 0x3b, 0xdd, 0x9c, 0xd7, 0x81, 0x14, 0x73, 0xfc, 0x14, 0xaa,
+	0x2b, 0x5e, 0x70, 0x7b, 0xbd, 0x65, 0x0e, 0xd1, 0xba, 0xe9, 0x18, 0xe1, 0x73, 0xb5, 0x18, 0x6b,
+	0x00, 0x98, 0x6b, 0xfd, 0x36, 0xc8, 0x32, 0x5a, 0x37, 0xbf, 0x67, 0xff, 0xe5, 0x62, 0x69, 0xa2,
+	0xdf, 0x4b, 0x13, 0xfd, 0x5d, 0x9a, 0xe8, 0xd7, 0x95, 0x89, 0x16, 0x57, 0x26, 0xfa, 0xfc, 0x70,
+	0xfb, 0x36, 0x89, 0x90, 0x3a, 0x59, 0xb9, 0x51, 0x59, 0x6d, 0xf7, 0x93, 0xff, 0x01, 0x00, 0x00,
+	0xff, 0xff, 0xb5, 0xb5, 0x70, 0xe2, 0x5c, 0x04, 0x00, 0x00,
 }
diff --git a/rpc/service.go b/rpc/service.go
index 3c266ad257c5576ff0136dfe80c673e2feec43c5..031a5f33ab076dfc31f543ca9b10d16995e75004 100644
--- a/rpc/service.go
+++ b/rpc/service.go
@@ -91,31 +91,8 @@ func (s *Service) ListUnconfirmedTxs(maxTxs int) (*ResultListUnconfirmedTxs, err
 	}, nil
 }
 
-func (s *Service) Status() (*ResultStatus, error) {
-	latestHeight := s.blockchain.LastBlockHeight()
-	var (
-		latestBlockMeta *tmTypes.BlockMeta
-		latestBlockHash []byte
-		latestBlockTime int64
-	)
-	if latestHeight != 0 {
-		latestBlockMeta = s.nodeView.BlockStore().LoadBlockMeta(int64(latestHeight))
-		latestBlockHash = latestBlockMeta.Header.Hash()
-		latestBlockTime = latestBlockMeta.Header.Time.UnixNano()
-	}
-	publicKey, err := s.nodeView.PrivValidatorPublicKey()
-	if err != nil {
-		return nil, err
-	}
-	return &ResultStatus{
-		NodeInfo:          s.nodeView.NodeInfo(),
-		GenesisHash:       s.blockchain.GenesisHash(),
-		PublicKey:         publicKey,
-		LatestBlockHash:   latestBlockHash,
-		LatestBlockHeight: latestHeight,
-		LatestBlockTime:   latestBlockTime,
-		NodeVersion:       project.History.CurrentVersion().String(),
-	}, nil
+func (s *Service) Status(blockWithin string) (*ResultStatus, error) {
+	return Status(s.BlockchainInfo(), s.nodeView, blockWithin)
 }
 
 func (s *Service) ChainIdentifiers() (*ResultChainId, error) {
@@ -130,7 +107,7 @@ func (s *Service) Peers() (*ResultPeers, error) {
 	peers := make([]*Peer, s.nodeView.Peers().Size())
 	for i, peer := range s.nodeView.Peers().List() {
 		peers[i] = &Peer{
-			NodeInfo:   peer.NodeInfo(),
+			NodeInfo:   tendermint.NewNodeInfo(peer.NodeInfo()),
 			IsOutbound: peer.IsOutbound(),
 		}
 	}
@@ -355,11 +332,16 @@ func (s *Service) GeneratePrivateAccount() (*ResultGeneratePrivateAccount, error
 	}, nil
 }
 
-func (s *Service) LastBlockInfo(blockWithin string) (*ResultLastBlockInfo, error) {
-	res := &ResultLastBlockInfo{
-		LastBlockHeight: s.blockchain.LastBlockHeight(),
-		LastBlockHash:   s.blockchain.LastBlockHash(),
-		LastBlockTime:   s.blockchain.LastBlockTime(),
+func Status(blockchain bcm.BlockchainInfo, nodeView *tendermint.NodeView, blockWithin string) (*ResultStatus, error) {
+	res := &ResultStatus{
+		ChainID:           blockchain.ChainID(),
+		NodeInfo:          nodeView.NodeInfo(),
+		NodeVersion:       project.History.CurrentVersion().String(),
+		GenesisHash:       blockchain.GenesisHash(),
+		PublicKey:         nodeView.ValidatorPublicKey(),
+		LatestBlockHash:   blockchain.LastBlockHash(),
+		LatestBlockHeight: blockchain.LastBlockHeight(),
+		LatestBlockTime:   blockchain.LastBlockTime(),
 	}
 	if blockWithin == "" {
 		return res, nil
@@ -368,12 +350,12 @@ func (s *Service) LastBlockInfo(blockWithin string) (*ResultLastBlockInfo, error
 	if err != nil {
 		return nil, fmt.Errorf("could not parse blockWithin duration to determine whether to throw error: %v", err)
 	}
-	// Take neg abs in case caller is counting backwards (not we add later)
+	// Take neg abs in case caller is counting backwards (note we later add the time since we normalise the duration to negative)
 	if duration > 0 {
 		duration = -duration
 	}
 	blockTimeThreshold := time.Now().Add(duration)
-	if res.LastBlockTime.After(blockTimeThreshold) {
+	if res.LatestBlockTime.After(blockTimeThreshold) {
 		// We've created blocks recently enough
 		return res, nil
 	}
@@ -381,6 +363,6 @@ func (s *Service) LastBlockInfo(blockWithin string) (*ResultLastBlockInfo, error
 	if err != nil {
 		resJSON = []byte("<error: could not marshal last block info>")
 	}
-	return nil, fmt.Errorf("no block committed within the last %s (cutoff: %s), last block info: %s",
+	return nil, fmt.Errorf("no block committed within the last %s (cutoff: %s), current status: %s",
 		blockWithin, blockTimeThreshold.Format(time.RFC3339), string(resJSON))
 }
diff --git a/rpc/tm/methods.go b/rpc/tm/methods.go
index e28e7d8626ad45c307e8fdd57fa3823eb857e2ad..6732aa66b4c15e7b8d1650dd231a0fb300970d8d 100644
--- a/rpc/tm/methods.go
+++ b/rpc/tm/methods.go
@@ -11,7 +11,7 @@ import (
 
 // Method names
 const (
-	// Status
+	// Status and healthcheck
 	Status  = "status"
 	NetInfo = "net_info"
 
@@ -44,16 +44,13 @@ const (
 	// Private keys and signing
 	GeneratePrivateAccount = "unsafe/gen_priv_account"
 	SignTx                 = "unsafe/sign_tx"
-
-	// Health check
-	LastBlockInfo = "last_block_info"
 )
 
 func GetRoutes(service *rpc.Service, logger *logging.Logger) map[string]*server.RPCFunc {
 	logger = logger.WithScope("GetRoutes")
 	return map[string]*server.RPCFunc{
 		// Status
-		Status:  server.NewRPCFunc(service.Status, ""),
+		Status:  server.NewRPCFunc(service.Status, "block_within"),
 		NetInfo: server.NewRPCFunc(service.NetInfo, ""),
 
 		// Accounts
@@ -85,7 +82,6 @@ func GetRoutes(service *rpc.Service, logger *logging.Logger) map[string]*server.
 
 		// Private account
 		GeneratePrivateAccount: server.NewRPCFunc(service.GeneratePrivateAccount, ""),
-		LastBlockInfo:          server.NewRPCFunc(service.LastBlockInfo, "block_within"),
 	}
 }