missed

package module
v0.0.0-...-f997f5a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 31, 2021 License: MIT Imports: 25 Imported by: 0

README

cosmissed

Simple webservice/dashboard for tracking network info and missed blocks on Tendermint/Cosmos chains.

Unfortunately running this service requires a commercial subscription to Maxmind's API service. I would have liked to just use their free databases, but hosting it publicly violates their license terms.

Summary page:

summary screenshot

Missed block monitor:

missed screenshot

Network Graph:

network screenshot

  • The reports sent lag by 2 blocks and will not be sent if the server is syncing, this is to avoid false positives which can occur if the server is slow or behind (this affects the tendermint prometheus exporter too.
  • This requires access to both the tendermint and cosmos rpc APIs (normally port 26657 and 1317, or can use unix domain sockets.)
  • It may be traffic intensive (especially when building the cache,) and should be run against a local, private server.
  • The error not a valid HistValidatorsResp structure at startup likely means that the state has been pruned for that block height on your API server and there is not enough history to build the full cache. Try a lower -n value (normally the upper limit is 9,000).
  • All assets are bundled using go:embed, so a simple go install github.com/blockpane/cosmissed should get everything needed to run.

Usage:

Usage of cosmissedd
  -c string
        cosmos http API endpoint (default "http://127.0.0.1:1317")
  -cache string
        filename for caching previous blocks (default "cosmissed.dat")
  -extra-rpc string
        extra tendermint RPC endpoints to poll for peer info, comma seperated list of URLs
  -key string
        Required: Key for GeoIP2 Precision Web Service
  -l int
        webserver port to listen on (default 8080)
  -n int
        most recent blocks to track (default 3000)
  -p string
        address prefix, ex- cosmos = cosmosvaloper, cosmosvalcons ... (default "cosmos")
  -socket string
        filename for unix socket to listen on, if set will disable TCP listener
  -t string
        tendermint http API endpoint (default "http://127.0.0.1:26657")
  -user string
        Required: Username for GeoIP2 Precision Web Service
  -v    log new records to stdout (error logs already on stderr)

This project uses eCharts for the visualizations and Bootswatch for themes.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	CClient   *http.Client
	TClient   *http.Client
	NetworkId string
	CUrl      string
	TUrl      string
)
View Source
var IndexHtml []byte
View Source
var MMCache = &GeoCache{
	Nodes: make(map[string]*GeoNode),
}
View Source
var MissedHtml []byte
View Source
var NetHtml []byte
View Source
var Precision int
View Source
var Prefix = "cosmos"
View Source
var StaticContent embed.FS
View Source
var UnconfirmedCache = []byte(`[]`)

Functions

func CurrentHeight

func CurrentHeight() (curHeight int, networkName string, err error)

func IsPrivate

func IsPrivate(ip net.IP) bool

func PubToCons

func PubToCons(prefix, pub string) (string, error)

func SummariesToChart

func SummariesToChart(s []*Summary) ([]byte, error)

func SummaryToUpdate

func SummaryToUpdate(s *Summary) []byte

func WatchUnconfirmed

func WatchUnconfirmed(ctx context.Context, updates chan []byte, client *http.Client, baseUrl, origApi string, started chan interface{})

Types

type BlockChart

type BlockChart struct {
	Blocks  []int     `json:"blocks"`          // block number
	Time    []string  `json:"time"`            // time as a string
	Missed  []int     `json:"missed"`          // number of missing validators
	MissPct []float64 `json:"missing_percent"` // vote power missing (shows actual risk of losing consensus.)
	Took    []float64 `json:"took"`            // time since last block in seconds
}

BlockChart is just another way of presenting the same data that is easier to use with some charting libraries, where each series is presented as an array

type ChartUpdate

type ChartUpdate struct {
	Block   int     `json:"block"`
	Time    string  `json:"time"`
	Missed  int     `json:"missed"`
	MissPct float64 `json:"missing_percent"`
	Took    float64 `json:"took"`
}

type CommisionRates

type CommisionRates struct {
	Rate          float32 `json:"rate"`
	MaxRate       float32 `json:"max_rate"`
	MaxChangeRate float32 `json:"max_change_rate"`
}

type Commission

type Commission struct {
	CommisionRates CommisionRates `json:"commision_rates"`
	UpdateTime     time.Time      `json:"update_time"`
}

type ConsensusPubkey

type ConsensusPubkey struct {
	Type string `json:"@type"`
	Key  string `json:"key"`
}

type Description

type Description struct {
	Moniker         string `json:"moniker"`
	Identity        string `json:"identity"`
	Website         string `json:"website"`
	SecurityContact string `json:"security_contact"`
	Details         string `json:"details"`
}

type Discovered

type Discovered struct {
	Nodes map[string]*DiscoveredNode
	// contains filtered or unexported fields
}

func NewDiscovered

func NewDiscovered() *Discovered

func (*Discovered) Add

func (d *Discovered) Add(ip net.IP, port int) error

func (*Discovered) Skip

func (d *Discovered) Skip(s string) bool

func (*Discovered) Trim

func (d *Discovered) Trim()

type DiscoveredNode

type DiscoveredNode struct {
	Ip         string
	Port       int
	Skip       bool
	ValidUntil time.Time
}

type GeoCache

type GeoCache struct {
	Nodes map[string]*GeoNode
	// contains filtered or unexported fields
}

func (*GeoCache) Fetch

func (g *GeoCache) Fetch(ip net.IP) (*GeoNode, error)

func (*GeoCache) Get

func (g *GeoCache) Get(s string) *GeoNode

func (*GeoCache) SetAuth

func (g *GeoCache) SetAuth(u, k string) bool

type GeoNode

type GeoNode struct {
	City     string `json:"city"`
	Country  string `json:"country"`
	Provider string `json:"provider"`
	LatLong  point  `json:"lat_long"`
}

type HistValidatorsResp

type HistValidatorsResp struct {
	Hist struct {
		Validators []Validator `json:"valset"`
	} `json:"hist"`
	Validators []Validator `json:"validators"`
}

type MinNeighbor

type MinNeighbor struct {
	RemoteIp string `json:"remote_ip"`
	NodeInfo struct {
		IsOutbound bool   `json:"is_outbound"`
		Moniker    string `json:"moniker"`
		Other      struct {
			// tendermint RPC API we will try to connect and get more peers (future feature)
			// if not listening on 127.0.0.1 or unix://
			RpcAddress string `json:"rpc_address"`
		} `json:"other"`
	} `json:"node_info"`
}

MinNeighbor is a stripped down response from the API with only a moniker and IP

type NetworkStats

type NetworkStats struct {
	PeersDiscovered int        `json:"peers_discovered"`
	RpcDiscovered   int        `json:"rpc_discovered"`
	CityLabels      []string   `json:"city_labels"`
	CityCounts      []int      `json:"city_counts"`
	CountryLabels   []string   `json:"country_labels"`
	CountryCounts   []int      `json:"country_counts"`
	LastUpdated     time.Time  `json:"last_updated"`
	Sunburst        []Sunburst `json:"sunburst"`
	Providers       []Sunburst `json:"providers"`
}

func NetworkSummary

func NetworkSummary(d *Discovered, p PeerMap) NetworkStats

type NoGeoKeyError

type NoGeoKeyError struct{}

func (NoGeoKeyError) Error

func (n NoGeoKeyError) Error() string

type NodeLocation

type NodeLocation struct {
	Region     string `json:"region"`
	Country    string `json:"country"`
	Coordinate point  `json:"coordinate"`
	Isp        string `json:"isp"`
}

type Pagination

type Pagination struct {
	NextKey string `json:"next_key"`
	Total   uint32 `json:"total"`
}

type Params

type Params struct {
	Depth int    `json:"depth"`
	Power uint64 `json:"power"`
	Chain string `json:"chain"`
}

type Peer

type Peer struct {
	Host        string `json:"host"`
	RpcPort     int    `json:"rpc_port"`
	Coordinates point  `json:"coordinates"`
	Outbound    bool   `json:"incoming"`
}

type PeerMap

type PeerMap []PeerSet

func FetchPeers

func FetchPeers(xtra []string) (peers PeerMap)

func (PeerMap) ToLinesJson

func (pm PeerMap) ToLinesJson() (int, []byte, error)

type PeerSet

type PeerSet struct {
	Host        string `json:"host"`
	Coordinates point  `json:"coordinates"`
	Peers       []Peer `json:"peers"`
}

func GetNeighbors

func GetNeighbors(node string) (source string, peers PeerSet, e error)

GetNeighbors calls the RCP endpoint asking for neighbors.

type Summary

type Summary struct {
	BlockNum          int               `json:"block_num"`
	Timestamp         int64             `json:"timestamp"`
	DeltaSec          float64           `json:"delta_sec,omitempty"`
	Missed            int               `json:"missed"`
	MissingValidators map[string]string `json:"missing"`
	PresentValidators map[string]string `json:"-"`
	Proposer          string            `json:"proposer"`
	VotePower         uint64            `json:"vote_power"`
	VoteMissing       uint64            `json:"vote_missing"`
	JailedUnbonding   map[string]string `json:"jailed_unbonding"`
}

func FetchSummary

func FetchSummary(height int, catchingUp bool) (*Summary, error)

type Sunburst

type Sunburst struct {
	Name     string     `json:"name"`
	Value    int        `json:"value"`
	Children []Sunburst `json:"children,omitempty"`
}

type Top

type Top struct {
	Moniker   string  `json:"moniker"`
	Missed    int     `json:"missed"`
	MissedPct float32 `json:"missed_pct"`
	Votes     int64   `json:"votes"`
}

Top holds info about who missed rounds, and is used for building a polar area chart, where weight increases with votes

func TopMissed

func TopMissed(summaries []*Summary, blocks int, prefix string) ([]*Top, error)

type Validator

type Validator struct {
	OperatorAddress   string          `json:"operator_address"`
	ConsensusPubkey   ConsensusPubkey `json:"consensus_pubkey"`
	Valcons           string          `json:"valcons,omitempty"`           // this is not part of the struct provided by Cosmos
	ValidatorAddress  string          `json:"validator-address,omitempty"` // this is not part of the struct provided by Cosmos
	Jailed            bool            `json:"jailed"`
	Status            string          `json:"status"`
	Tokens            uint64          `json:"tokens"`
	DelegatorShares   float64         `json:"delegator_shares"`
	Description       Description     `json:"description"`
	UnbondingHeight   uint64          `json:"unbonding_height"`
	UnbondingTime     time.Time       `json:"unbonding_time"`
	Commission        Commission      `json:"commission"`
	MinSelfDelegation float64         `json:"min_self_delegation"`
}

func ParseValidatorsResp

func ParseValidatorsResp(body []byte, history bool) ([]Validator, error)

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL