package types import ( "encoding/json" "fmt" "io/ioutil" "sync" "github.com/rcrowley/go-metrics" tmtypes "github.com/tendermint/tendermint/types" ) //------------------------------------------------ // blockchain types // Known chain and validator set IDs (from which anything else can be found) type ChainAndValidatorSetIDs struct { ChainIDs []string `json:"chain_ids"` ValidatorSetIDs []string `json:"validator_set_ids"` } // Basic chain and network metrics type BlockchainStatus struct { // Blockchain Info Height int `json:"height"` BlockchainSize int64 `json:"blockchain_size"` // how might we get StateSize ? MeanBlockTime float64 `json:"mean_block_time" wire:"unsafe"` TxThroughput float64 `json:"tx_throughput" wire:"unsafe"` blockTimeMeter metrics.Meter txThroughputMeter metrics.Meter // Network Info NumValidators int `json:"num_validators"` ActiveValidators int `json:"active_validators"` ActiveNodes int `json:"active_nodes"` MeanLatency float64 `json:"mean_latency" wire:"unsafe"` Uptime float64 `json:"uptime" wire:"unsafe"` // TODO: charts for block time, latency (websockets/event-meter ?) } func NewBlockchainStatus() *BlockchainStatus { return &BlockchainStatus{ blockTimeMeter: metrics.NewMeter(), txThroughputMeter: metrics.NewMeter(), } } func (s *BlockchainStatus) NewBlock(block *tmtypes.Block) { s.Height = block.Header.Height s.blockTimeMeter.Mark(1) s.txThroughputMeter.Mark(int64(block.Header.NumTxs)) s.MeanBlockTime = 1 / s.blockTimeMeter.RateMean() s.TxThroughput = s.txThroughputMeter.RateMean() } // Main chain state // Returned over RPC but also used to manage state type ChainState struct { Config *BlockchainConfig `json:"config"` Status *BlockchainStatus `json:"status"` } // basic chain config // threadsafe type BlockchainConfig struct { ID string `json:"id"` ValSetID string `json:"val_set_id"` mtx sync.Mutex Validators []*ChainValidator `json:"validators"` valIDMap map[string]int // map IDs to indices } // So we can fetch validator by id 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.Validator.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 } func LoadChainFromFile(configFile string) (*BlockchainConfig, error) { b, err := ioutil.ReadFile(configFile) if err != nil { return nil, err } // for now we start with one blockchain loaded from file; // eventually more can be uploaded or created through endpoints chainConfig := new(BlockchainConfig) if err := json.Unmarshal(b, chainConfig); err != nil { return nil, err } return chainConfig, nil }