tendermint/types/types.go
2016-01-13 22:19:45 -05:00

140 lines
3.4 KiB
Go

package types
import (
"encoding/json"
"fmt"
"reflect"
"sync"
"github.com/tendermint/go-crypto"
"github.com/tendermint/go-event-meter"
"github.com/tendermint/go-events"
"github.com/tendermint/go-wire"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
//---------------------------------------------
// core types
// Known chain and validator set IDs (from which anything else can be found)
type ChainAndValidatorIDs struct {
ChainIDs []string `json:"chain_ids"`
ValidatorSetIDs []string `json:"validator_set_ids"`
}
// state of a chain
type ChainStatus struct {
Config *BlockchainConfig `json:"config"`
Status *BlockchainStatus `json:"status"`
}
// basic chain config
// threadsafe
type BlockchainConfig struct {
mtx sync.Mutex
ID string `json:"id"`
ValSetID string `json:"val_set_id"`
Validators []*ChainValidator `json:"validators"`
valIDMap map[string]int // map IDs to indices
}
func (bc *BlockchainConfig) PopulateValIDMap() {
bc.mtx.Lock()
defer bc.mtx.Unlock()
bc.valIDMap = make(map[string]int)
for i, v := range bc.Validators {
bc.valIDMap[v.ID] = i
}
}
func (bc *BlockchainConfig) GetValidatorByID(valID string) (*ChainValidator, error) {
bc.mtx.Lock()
defer bc.mtx.Unlock()
valIndex, ok := bc.valIDMap[valID]
if !ok {
return nil, fmt.Errorf("Unknown validator %s", valID)
}
return bc.Validators[valIndex], nil
}
// basic chain status/metrics
// threadsafe
type BlockchainStatus struct {
mtx sync.Mutex
Height int `json:"height"`
MeanBlockTime float64 `json:"mean_block_time" wire:"unsafe"`
TxThroughput float64 `json:"tx_throughput" wire:"unsafe"`
BlockchainSize int64 `json:"blockchain_size"` // how might we get StateSize ?
}
// validator on a chain
type ChainValidator struct {
*Validator `json:"validator"`
Addr string `json:"addr"` // do we want multiple addrs?
Index int `json:"index"`
em *eventmeter.EventMeter // holds a ws connection to the val
Latency float64 `json:"latency,omitempty" wire:"unsafe"`
}
func unmarshalEvent(b json.RawMessage) (string, events.EventData, error) {
var err error
result := new(ctypes.TMResult)
wire.ReadJSONPtr(result, b, &err)
if err != nil {
return "", nil, err
}
event, ok := (*result).(*ctypes.ResultEvent)
if !ok {
return "", nil, fmt.Errorf("Result is not type *ctypes.ResultEvent. Got %v", reflect.TypeOf(*result))
}
return event.Name, event.Data, nil
}
func (cv *ChainValidator) NewEventMeter() error {
em := eventmeter.NewEventMeter(fmt.Sprintf("ws://%s/websocket", cv.Addr), unmarshalEvent)
if err := em.Start(); err != nil {
return err
}
cv.em = em
return nil
}
func (cv *ChainValidator) EventMeter() *eventmeter.EventMeter {
return cv.em
}
// validator set (independent of chains)
type ValidatorSet struct {
Validators []*Validator `json:"validators"`
}
func (vs *ValidatorSet) Validator(valID string) (*Validator, error) {
for _, v := range vs.Validators {
if v.ID == valID {
return v, nil
}
}
return nil, fmt.Errorf("Unknwon validator %s", valID)
}
// validator (independent of chain)
type Validator struct {
ID string `json:"id"`
PubKey crypto.PubKey `json:"pub_key,omitempty"`
Chains []*ChainStatus `json:"chains,omitempty"`
}
func (v *Validator) Chain(chainID string) (*ChainStatus, error) {
for _, c := range v.Chains {
if c.Config.ID == chainID {
return c, nil
}
}
return nil, fmt.Errorf("Unknwon chain %s", chainID)
}