From 9b57e250818b7ebc67a7719523be18ef529b4b00 Mon Sep 17 00:00:00 2001
From: Benjamin Bollen <ben@erisindustries.com>
Date: Tue, 31 May 2016 16:52:05 +0200
Subject: [PATCH] First phase to separate out core types; move Pipe interface
 to /core

Signed-off-by: Benjamin Bollen <ben@erisindustries.com>
---
 core/pipe.go               | 107 ++++++++++++++++++++
 core/types/account.go      | 112 +++++++++++++++++++++
 core/types/events.go       |  47 +++++++++
 core/types/filters.go      | 192 ++++++++++++++++++++++++++++++++++++
 core/types/priv_account.go | 105 ++++++++++++++++++++
 core/types/types.go        | 196 +++++++++++++++++++++++++++++++++++++
 6 files changed, 759 insertions(+)
 create mode 100644 core/pipe.go
 create mode 100644 core/types/account.go
 create mode 100644 core/types/events.go
 create mode 100644 core/types/filters.go
 create mode 100644 core/types/priv_account.go
 create mode 100644 core/types/types.go

diff --git a/core/pipe.go b/core/pipe.go
new file mode 100644
index 00000000..4414c9e3
--- /dev/null
+++ b/core/pipe.go
@@ -0,0 +1,107 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+package core
+
+import (
+  types "github.com/eris-ltd/eris-db/core/types"
+)
+
+// TODO: [ben] This respects the old Pipe interface from Eris-DB.
+// This made sense as a wrapper around the old Tendermint, but now
+// it strongly reflects the internal details of old Tendermint outwards
+// and provides little value as an abstraction.
+// The refactor needed here for eris-db-0.12.1 is to expose a language
+// of transactions, block verification and accounts, grouping
+// these interfaces into an Engine, Communicator, NameReg, Permissions (suggestion)
+
+import (
+  events           "github.com/tendermint/go-events"
+  tendermint_types "github.com/tendermint/tendermint/types"
+
+  transactions "github.com/eris-ltd/eris-db/txs"
+)
+
+type Pipe interface {
+  Accounts() Accounts
+  Blockchain() Blockchain
+  Consensus() Consensus
+  Events() EventEmitter
+  NameReg() NameReg
+  Net() Net
+  Transactor() Transactor
+}
+
+type Accounts interface {
+  GenPrivAccount() (*types.PrivAccount, error)
+  GenPrivAccountFromKey(privKey []byte) (*types.PrivAccount, error)
+  Accounts([]*types.FilterData) (*types.AccountList, error)
+  Account(address []byte) (*types.Account, error)
+  Storage(address []byte) (*types.Storage, error)
+  StorageAt(address, key []byte) (*types.StorageItem, error)
+}
+
+type Blockchain interface {
+  Info() (*types.BlockchainInfo, error)
+  GenesisHash() ([]byte, error)
+  ChainId() (string, error)
+  LatestBlockHeight() (int, error)
+  LatestBlock() (*tendermint_types.Block, error)
+  Blocks([]*types.FilterData) (*types.Blocks, error)
+  Block(height int) (*tendermint_types.Block, error)
+}
+
+type Consensus interface {
+  State() (*types.ConsensusState, error)
+  Validators() (*types.ValidatorList, error)
+}
+
+type EventEmitter interface {
+  Subscribe(subId, event string, callback func(events.EventData)) (bool, error)
+  Unsubscribe(subId string) (bool, error)
+}
+
+type NameReg interface {
+  Entry(key string) (*transactions.NameRegEntry, error)
+  Entries([]*types.FilterData) (*types.ResultListNames, error)
+}
+
+type Net interface {
+  Info() (*types.NetworkInfo, error)
+  ClientVersion() (string, error)
+  Moniker() (string, error)
+  Listening() (bool, error)
+  Listeners() ([]string, error)
+  Peers() ([]*types.Peer, error)
+  Peer(string) (*types.Peer, error)
+}
+
+type Transactor interface {
+  Call(fromAddress, toAddress, data []byte) (*types.Call, error)
+  CallCode(fromAddress, code, data []byte) (*types.Call, error)
+  // Send(privKey, toAddress []byte, amount int64) (*types.Receipt, error)
+  // SendAndHold(privKey, toAddress []byte, amount int64) (*types.Receipt, error)
+  BroadcastTx(tx transactions.Tx) (*types.Receipt, error)
+  Transact(privKey, address, data []byte, gasLimit,
+    fee int64) (*types.Receipt, error)
+  TransactAndHold(privKey, address, data []byte, gasLimit,
+    fee int64) (*transactions.EventDataCall, error)
+  TransactNameReg(privKey []byte, name, data string, amount,
+    fee int64) (*types.Receipt, error)
+  UnconfirmedTxs() (*types.UnconfirmedTxs, error)
+  SignTx(tx transactions.Tx,
+    privAccounts []*types.PrivAccount) (transactions.Tx, error)
+}
diff --git a/core/types/account.go b/core/types/account.go
new file mode 100644
index 00000000..7e836559
--- /dev/null
+++ b/core/types/account.go
@@ -0,0 +1,112 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// TODO: [ben] Account and PrivateAccount need to become a pure interface
+// and then move the implementation to the manager types.
+// Eg, Geth has its accounts, different from ErisMint
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+
+	ptypes "github.com/eris-ltd/eris-db/permission/types"
+	. "github.com/tendermint/go-common"
+	"github.com/tendermint/go-crypto"
+	"github.com/tendermint/go-merkle"
+	"github.com/tendermint/go-wire"
+)
+
+// Signable is an interface for all signable things.
+// It typically removes signatures before serializing.
+type Signable interface {
+	WriteSignBytes(chainID string, w io.Writer, n *int, err *error)
+	// SignBytes is a convenience method for getting the bytes to sign of a Signable.
+	SignBytes(chainID string, o Signable) []byte
+}
+
+// SignBytes is a convenience method for getting the bytes to sign of a Signable.
+func SignBytes(chainID string, o Signable) []byte {
+	buf, n, err := new(bytes.Buffer), new(int), new(error)
+	o.WriteSignBytes(chainID, buf, n, err)
+	if *err != nil {
+		PanicCrisis(err)
+	}
+	return buf.Bytes()
+}
+
+// HashSignBytes is a convenience method for getting the hash of the bytes of a signable
+func HashSignBytes(chainID string, o Signable) []byte {
+	return merkle.SimpleHashFromBinary(SignBytes(chainID, o))
+}
+
+//-----------------------------------------------------------------------------
+
+// Account resides in the application state, and is mutated by transactions
+// on the blockchain.
+// Serialized by wire.[read|write]Reflect
+type Account struct {
+	Address     []byte        `json:"address"`
+	PubKey      crypto.PubKey `json:"pub_key"`
+	Sequence    int           `json:"sequence"`
+	Balance     int64         `json:"balance"`
+	Code        []byte        `json:"code"`         // VM code
+	StorageRoot []byte        `json:"storage_root"` // VM storage merkle root.
+
+	Permissions ptypes.AccountPermissions `json:"permissions"`
+}
+
+func (acc *Account) Copy() *Account {
+	accCopy := *acc
+	return &accCopy
+}
+
+func (acc *Account) String() string {
+	if acc == nil {
+		return "nil-Account"
+	}
+	return fmt.Sprintf("Account{%X:%v B:%v C:%v S:%X P:%s}", acc.Address, acc.PubKey, acc.Balance, len(acc.Code), acc.StorageRoot, acc.Permissions)
+}
+
+func AccountEncoder(o interface{}, w io.Writer, n *int, err *error) {
+	wire.WriteBinary(o.(*Account), w, n, err)
+}
+
+func AccountDecoder(r io.Reader, n *int, err *error) interface{} {
+	return wire.ReadBinary(&Account{}, r, 0, n, err)
+}
+
+var AccountCodec = wire.Codec{
+	Encode: AccountEncoder,
+	Decode: AccountDecoder,
+}
+
+func EncodeAccount(acc *Account) []byte {
+	w := new(bytes.Buffer)
+	var n int
+	var err error
+	AccountEncoder(acc, w, &n, &err)
+	return w.Bytes()
+}
+
+func DecodeAccount(accBytes []byte) *Account {
+	var n int
+	var err error
+	acc := AccountDecoder(bytes.NewBuffer(accBytes), &n, &err)
+	return acc.(*Account)
+}
diff --git a/core/types/events.go b/core/types/events.go
new file mode 100644
index 00000000..c96f7dfa
--- /dev/null
+++ b/core/types/events.go
@@ -0,0 +1,47 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+package types
+
+import (
+	evts "github.com/tendermint/go-events"
+)
+
+// TODO improve
+// TODO: [ben] yes please ^^^
+// [ben] To improve this we will switch out go-events with eris-db/event so
+// that there is no need anymore for this poor wrapper.
+
+// The events struct has methods for working with events.
+type events struct {
+	eventSwitch *evts.EventSwitch
+}
+
+func newEvents(eventSwitch *evts.EventSwitch) *events {
+	return &events{eventSwitch}
+}
+
+// Subscribe to an event.
+func (this *events) Subscribe(subId, event string, callback func(evts.EventData)) (bool, error) {
+	this.eventSwitch.AddListenerForEvent(subId, event, callback)
+	return true, nil
+}
+
+// Un-subscribe from an event.
+func (this *events) Unsubscribe(subId string) (bool, error) {
+	this.eventSwitch.RemoveListener(subId)
+	return true, nil
+}
diff --git a/core/types/filters.go b/core/types/filters.go
new file mode 100644
index 00000000..9cb86241
--- /dev/null
+++ b/core/types/filters.go
@@ -0,0 +1,192 @@
+package types
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+// TODO add generic filters for various different kinds of matching.
+
+// Used to filter.
+// Op can be any of the following:
+// The usual relative operators: <, >, <=, >=, ==, != (where applicable)
+// A range parameter (see: https://help.github.com/articles/search-syntax/)
+type FilterData struct {
+	Field string `json:"field"`
+	Op    string `json:"op"`
+	Value string `json:"value"`
+}
+
+// Filters based on fields.
+type Filter interface {
+	Match(v interface{}) bool
+}
+
+// A filter that can be configured with in-data.
+type ConfigurableFilter interface {
+	Filter
+	Configure(*FilterData) error
+}
+
+// Filter made up of many filters.
+type CompositeFilter struct {
+	filters []Filter
+}
+
+func (this *CompositeFilter) SetData(filters []Filter) {
+	this.filters = filters
+}
+
+func (this *CompositeFilter) Match(v interface{}) bool {
+	for _, f := range this.filters {
+		if !f.Match(v) {
+			return false
+		}
+	}
+	return true
+}
+
+// Rubberstamps everything.
+type MatchAllFilter struct{}
+
+func (this *MatchAllFilter) Match(v interface{}) bool { return true }
+
+// Used to generate filters based on filter data.
+// Keeping separate pools for "edge cases" (Composite and MatchAll)
+type FilterFactory struct {
+	filterPools         map[string]*sync.Pool
+	compositeFilterPool *sync.Pool
+	matchAllFilterPool  *sync.Pool
+}
+
+func NewFilterFactory() *FilterFactory {
+	aff := &FilterFactory{}
+	// Match all.
+	aff.matchAllFilterPool = &sync.Pool{
+		New: func() interface{} {
+			return &MatchAllFilter{}
+		},
+	}
+	// Composite.
+	aff.compositeFilterPool = &sync.Pool{
+		New: func() interface{} {
+			return &CompositeFilter{}
+		},
+	}
+	// Regular.
+	aff.filterPools = make(map[string]*sync.Pool)
+
+	return aff
+}
+
+func (this *FilterFactory) RegisterFilterPool(fieldName string, pool *sync.Pool) {
+	this.filterPools[strings.ToLower(fieldName)] = pool
+}
+
+// Creates a new filter given the input data array. If the array is zero length or nil, an empty
+// filter will be returned that returns true on all matches. If the array is of size 1, a regular
+// filter is returned, otherwise a CompositeFieldFilter is returned, which is a special filter that
+// contains a number of other filters. It implements AccountFieldFilter, and will match an account
+// only if all the sub-filters matches.
+func (this *FilterFactory) NewFilter(fdArr []*FilterData) (Filter, error) {
+
+	if fdArr == nil || len(fdArr) == 0 {
+		return &MatchAllFilter{}, nil
+	}
+	if len(fdArr) == 1 {
+		return this.newSingleFilter(fdArr[0])
+	}
+	filters := []Filter{}
+	for _, fd := range fdArr {
+		f, err := this.newSingleFilter(fd)
+		if err != nil {
+			return nil, err
+		}
+		filters = append(filters, f)
+	}
+	cf := this.compositeFilterPool.Get().(*CompositeFilter)
+	cf.filters = filters
+	return cf, nil
+}
+
+func (this *FilterFactory) newSingleFilter(fd *FilterData) (ConfigurableFilter, error) {
+	fp, ok := this.filterPools[strings.ToLower(fd.Field)]
+	if !ok {
+		return nil, fmt.Errorf("Field is not supported: " + fd.Field)
+	}
+	f := fp.Get().(ConfigurableFilter)
+	err := f.Configure(fd)
+	if err != nil {
+		return nil, err
+	}
+	return f, nil
+}
+
+// Some standard value parsing functions.
+
+func ParseNumberValue(value string) (int64, error) {
+	var val int64
+	// Check for wildcards.
+	if value == "min" {
+		val = math.MinInt64
+	} else if value == "max" {
+		val = math.MaxInt64
+	} else {
+		tv, err := strconv.ParseInt(value, 10, 64)
+
+		if err != nil {
+			return 0, fmt.Errorf("Wrong value type.")
+		}
+		val = tv
+	}
+	return val, nil
+}
+
+// Some standard filtering functions.
+
+func GetRangeFilter(op, fName string) (func(a, b int64) bool, error) {
+	if op == "==" {
+		return func(a, b int64) bool {
+			return a == b
+		}, nil
+	} else if op == "!=" {
+		return func(a, b int64) bool {
+			return a != b
+		}, nil
+	} else if op == "<=" {
+		return func(a, b int64) bool {
+			return a <= b
+		}, nil
+	} else if op == ">=" {
+		return func(a, b int64) bool {
+			return a >= b
+		}, nil
+	} else if op == "<" {
+		return func(a, b int64) bool {
+			return a < b
+		}, nil
+	} else if op == ">" {
+		return func(a, b int64) bool {
+			return a > b
+		}, nil
+	} else {
+		return nil, fmt.Errorf("Op: " + op + " is not supported for '" + fName + "' filtering")
+	}
+}
+
+func GetStringFilter(op, fName string) (func(s0, s1 string) bool, error) {
+	if op == "==" {
+		return func(s0, s1 string) bool {
+			return strings.EqualFold(s0, s1)
+		}, nil
+	} else if op == "!=" {
+		return func(s0, s1 string) bool {
+			return !strings.EqualFold(s0, s1)
+		}, nil
+	} else {
+		return nil, fmt.Errorf("Op: " + op + " is not supported for '" + fName + "' filtering.")
+	}
+}
diff --git a/core/types/priv_account.go b/core/types/priv_account.go
new file mode 100644
index 00000000..77c40215
--- /dev/null
+++ b/core/types/priv_account.go
@@ -0,0 +1,105 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// TODO: [ben] Account and PrivateAccount need to become a pure interface
+// and then move the implementation to the manager types.
+// Eg, Geth has its accounts, different from ErisMint
+
+package types
+
+import (
+	"github.com/tendermint/ed25519"
+	. "github.com/tendermint/go-common"
+	"github.com/tendermint/go-crypto"
+	"github.com/tendermint/go-wire"
+)
+
+type PrivAccount struct {
+	Address []byte         `json:"address"`
+	PubKey  crypto.PubKey  `json:"pub_key"`
+	PrivKey crypto.PrivKey `json:"priv_key"`
+}
+
+func (pA *PrivAccount) Generate(index int) *PrivAccount {
+	newPrivKey := pA.PrivKey.(crypto.PrivKeyEd25519).Generate(index)
+	newPubKey := newPrivKey.PubKey()
+	newAddress := newPubKey.Address()
+	return &PrivAccount{
+		Address: newAddress,
+		PubKey:  newPubKey,
+		PrivKey: newPrivKey,
+	}
+}
+
+func (pA *PrivAccount) Sign(chainID string, o Signable) crypto.Signature {
+	return pA.PrivKey.Sign(SignBytes(chainID, o))
+}
+
+func (pA *PrivAccount) String() string {
+	return Fmt("PrivAccount{%X}", pA.Address)
+}
+
+//----------------------------------------
+
+// Generates a new account with private key.
+func GenPrivAccount() *PrivAccount {
+	privKeyBytes := new([64]byte)
+	copy(privKeyBytes[:32], crypto.CRandBytes(32))
+	pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
+	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
+	privKey := crypto.PrivKeyEd25519(*privKeyBytes)
+	return &PrivAccount{
+		Address: pubKey.Address(),
+		PubKey:  pubKey,
+		PrivKey: privKey,
+	}
+}
+
+// Generates 32 priv key bytes from secret
+func GenPrivKeyBytesFromSecret(secret string) []byte {
+	return wire.BinarySha256(secret) // Not Ripemd160 because we want 32 bytes.
+}
+
+// Generates a new account with private key from SHA256 hash of a secret
+func GenPrivAccountFromSecret(secret string) *PrivAccount {
+	privKey32 := GenPrivKeyBytesFromSecret(secret)
+	privKeyBytes := new([64]byte)
+	copy(privKeyBytes[:32], privKey32)
+	pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
+	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
+	privKey := crypto.PrivKeyEd25519(*privKeyBytes)
+	return &PrivAccount{
+		Address: pubKey.Address(),
+		PubKey:  pubKey,
+		PrivKey: privKey,
+	}
+}
+
+func GenPrivAccountFromPrivKeyBytes(privKeyBytes []byte) *PrivAccount {
+	if len(privKeyBytes) != 64 {
+		PanicSanity(Fmt("Expected 64 bytes but got %v", len(privKeyBytes)))
+	}
+	var privKeyArray [64]byte
+	copy(privKeyArray[:], privKeyBytes)
+	pubKeyBytes := ed25519.MakePublicKey(&privKeyArray)
+	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
+	privKey := crypto.PrivKeyEd25519(privKeyArray)
+	return &PrivAccount{
+		Address: pubKey.Address(),
+		PubKey:  pubKey,
+		PrivKey: privKey,
+	}
+}
diff --git a/core/types/types.go b/core/types/types.go
new file mode 100644
index 00000000..1a36fd0e
--- /dev/null
+++ b/core/types/types.go
@@ -0,0 +1,196 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// TODO: [ben] this is poorly constructed but copied over
+// from eris-db/erisdb/pipe/types to make incremental changes and allow
+// for a discussion around the proper defintion of the needed types.
+package types
+
+import (
+	transactions "github.com/eris-ltd/eris-db/txs"
+
+	"github.com/tendermint/go-p2p" // NodeInfo (drop this!)
+	csus "github.com/tendermint/tendermint/consensus"
+	"github.com/tendermint/tendermint/types"
+)
+
+type (
+
+	// *********************************** Address ***********************************
+
+	// Accounts
+	AccountList struct {
+		Accounts []*Account `json:"accounts"`
+	}
+
+	// A contract account storage item.
+	StorageItem struct {
+		Key   []byte `json:"key"`
+		Value []byte `json:"value"`
+	}
+
+	// Account storage
+	Storage struct {
+		StorageRoot  []byte        `json:"storage_root"`
+		StorageItems []StorageItem `json:"storage_items"`
+	}
+
+	// *********************************** Blockchain ***********************************
+
+	// BlockchainInfo
+	BlockchainInfo struct {
+		ChainId           string           `json:"chain_id"`
+		GenesisHash       []byte           `json:"genesis_hash"`
+		LatestBlockHeight int              `json:"latest_block_height"`
+		LatestBlock       *types.BlockMeta `json:"latest_block"`
+	}
+
+	// Genesis hash
+	GenesisHash struct {
+		Hash []byte `json:"hash"`
+	}
+
+	// Get the latest
+	LatestBlockHeight struct {
+		Height int `json:"height"`
+	}
+
+	ChainId struct {
+		ChainId string `json:"chain_id"`
+	}
+
+	// GetBlocks
+	Blocks struct {
+		MinHeight  int                `json:"min_height"`
+		MaxHeight  int                `json:"max_height"`
+		BlockMetas []*types.BlockMeta `json:"block_metas"`
+	}
+
+	// *********************************** Consensus ***********************************
+
+	// ConsensusState
+	ConsensusState struct {
+		Height     int                `json:"height"`
+		Round      int                `json:"round"`
+		Step       uint8              `json:"step"`
+		StartTime  string             `json:"start_time"`
+		CommitTime string             `json:"commit_time"`
+		Validators []*types.Validator `json:"validators"`
+		Proposal   *types.Proposal    `json:"proposal"`
+	}
+
+	// Validators
+	ValidatorList struct {
+		BlockHeight         int                `json:"block_height"`
+		BondedValidators    []*types.Validator `json:"bonded_validators"`
+		UnbondingValidators []*types.Validator `json:"unbonding_validators"`
+	}
+
+	// *********************************** Events ***********************************
+
+	// EventSubscribe
+	EventSub struct {
+		SubId string `json:"sub_id"`
+	}
+
+	// EventUnsubscribe
+	EventUnsub struct {
+		Result bool `json:"result"`
+	}
+
+	// EventPoll
+	PollResponse struct {
+		Events []interface{} `json:"events"`
+	}
+
+	// *********************************** Network ***********************************
+
+	// NetworkInfo
+	NetworkInfo struct {
+		ClientVersion string   `json:"client_version"`
+		Moniker       string   `json:"moniker"`
+		Listening     bool     `json:"listening"`
+		Listeners     []string `json:"listeners"`
+		Peers         []*Peer  `json:"peers"`
+	}
+
+	ClientVersion struct {
+		ClientVersion string `json:"client_version"`
+	}
+
+	Moniker struct {
+		Moniker string `json:"moniker"`
+	}
+
+	Listening struct {
+		Listening bool `json:"listening"`
+	}
+
+	Listeners struct {
+		Listeners []string `json:"listeners"`
+	}
+
+	// used in Peers and BlockchainInfo
+	Peer struct {
+		nodeInfo   *p2p.NodeInfo `json:"node_info"`
+		IsOutbound bool          `json:"is_outbound"`
+	}
+
+	// *********************************** Transactions ***********************************
+
+	// Call or CallCode
+	Call struct {
+		Return  string `json:"return"`
+		GasUsed int64  `json:"gas_used"`
+		// TODO ...
+	}
+
+	// UnconfirmedTxs
+	UnconfirmedTxs struct {
+		Txs []transactions.Tx `json:"txs"`
+	}
+
+	// BroadcastTx or Transact
+	Receipt struct {
+		TxHash          []byte `json:"tx_hash"`
+		CreatesContract uint8  `json:"creates_contract"`
+		ContractAddr    []byte `json:"contract_addr"`
+	}
+
+	TransactionResult struct {
+	}
+)
+
+func FromRoundState(rs *csus.RoundState) *ConsensusState {
+	cs := &ConsensusState{
+		CommitTime: rs.CommitTime.String(),
+		Height:     rs.Height,
+		Proposal:   rs.Proposal,
+		Round:      rs.Round,
+		StartTime:  rs.StartTime.String(),
+		Step:       uint8(rs.Step),
+		Validators: rs.Validators.Validators,
+	}
+	return cs
+}
+
+//------------------------------------------------------------------------------
+// copied in from NameReg
+
+type ResultListNames struct {
+	BlockHeight int                 `json:"block_height"`
+	Names       []*transactions.NameRegEntry `json:"names"`
+}
-- 
GitLab