add consensus view

This commit is contained in:
liangping 2022-08-26 14:56:49 +08:00
parent b6dd542cb3
commit e2f041a19f
6 changed files with 83 additions and 101 deletions

View File

@ -25,6 +25,11 @@ export default () => ([
title: 'uptime', title: 'uptime',
route: 'uptime', route: 'uptime',
}, },
{
scope: 'normal',
title: 'parameters',
route: 'parameters',
},
{ {
scope: 'normal', scope: 'normal',
title: 'statesync', title: 'statesync',
@ -32,8 +37,8 @@ export default () => ([
}, },
{ {
scope: 'normal', scope: 'normal',
title: 'parameters', title: 'consensus',
route: 'parameters', route: 'consensus',
}, },
{ {
scope: 'cos-mos', scope: 'cos-mos',

View File

@ -1 +0,0 @@
// unimplement

View File

@ -36,6 +36,11 @@ function processMenu() {
icon: 'LifeBuoyIcon', icon: 'LifeBuoyIcon',
}) })
} }
chainMenus.push({
title: 'Github',
href: 'https://github.com/ping-pub/explorer',
icon: 'GithubIcon',
})
chainMenus.push({ chainMenus.push({
title: 'Discord', title: 'Discord',
href: 'https://discord.gg/CmjYVSr6GW', href: 'https://discord.gg/CmjYVSr6GW',
@ -47,9 +52,9 @@ function processMenu() {
icon: 'TwitterIcon', icon: 'TwitterIcon',
}) })
chainMenus.push({ chainMenus.push({
title: 'Github', title: 'Telegram',
href: 'https://github.com/ping-pub/explorer', href: 'https://t.me/pingpub',
icon: 'GithubIcon', icon: 'SendIcon',
}) })
return chainMenus return chainMenus

View File

@ -362,11 +362,17 @@ const router = new VueRouter({
}, },
// common modules // common modules
{ {
path: '/tools/consensus-states', path: '/:chain/consensus',
name: 'consensus', name: 'consensus',
component: () => import('@/views/ConsensusStates.vue'), component: () => import('@/views/ConsensusStates.vue'),
meta: { meta: {
layout: 'full', pageTitle: 'Consensus State',
breadcrumb: [
{
text: 'Consensus State',
active: true,
},
],
}, },
}, },
{ {

View File

@ -1,36 +1,7 @@
<template> <template>
<div class="container-md"> <div class="container-md">
<full-header />
<b-card class="d-flex justify-content-start my-1">
<b-breadcrumb :items="navs" />
</b-card>
<b-card> <b-card>
<b-row> <b-row>
<b-col
sm="12"
md="4"
>
<v-select
v-model="selected"
:options="Object.values(chains)"
label="chain_name"
@input="onchange"
>
<template #no-options="">
Please select a chain.
</template>
<template #option="{ chain_name, logo }">
<b-avatar
:src="logo"
size="16"
variant="light-primary"
class="align-middle mr-50"
/>
<span> {{ chain_name.toUpperCase() }}</span>
</template>
</v-select>
</b-col>
<b-col> <b-col>
<b-input-group> <b-input-group>
<b-form-input <b-form-input
@ -40,7 +11,7 @@
<b-input-group-append> <b-input-group-append>
<b-button <b-button
variant="outline-primary" variant="outline-primary"
@click="update()" @click="onchange()"
> >
Moniter Moniter
</b-button> </b-button>
@ -55,10 +26,11 @@
{{ httpstatus }}: {{ httpStatusText }} {{ httpstatus }}: {{ httpStatusText }}
</div> </div>
</b-card> </b-card>
<b-card <b-card v-if="roundState['height/round/step']">
v-if="roundState['height/round/step']" <b-card-title class="d-flex justify-content-between">
:title="`Height/Round/Step: ${roundState['height/round/step']}`" <span>Height/Round/Step: {{ roundState['height/round/step'] }}</span>
> <small class="text-danger">Updated at {{ format(updatetime) }}</small>
</b-card-title>
<div <div
v-for="item in roundState.height_vote_set" v-for="item in roundState.height_vote_set"
:key="item.round" :key="item.round"
@ -95,25 +67,35 @@
/> Not Signed /> Not Signed
</b-card-footer> </b-card-footer>
</b-card> </b-card>
<app-footer class="mb-1" />
<b-alert
variant="info"
show
>
<h4 class="alert-heading">
Tips
</h4>
<div class="alert-body">
<span>If you want to change the default rpc endpoint. make sure that "https" and "CORS" are enabled on your server.</span>
</div>
</b-alert>
</div> </div>
</template> </template>
<script> <script>
import { import {
BAvatar, BCardFooter, BRow, BCol, BAvatar, BCardFooter, BRow, BCol, BCardTitle, BAlert,
BBreadcrumb, BCard, BCardBody, BInputGroup, BFormInput, BInputGroupAppend, BButton, BCard, BCardBody, BInputGroup, BFormInput, BInputGroupAppend, BButton,
} from 'bootstrap-vue' } from 'bootstrap-vue'
import fetch from 'node-fetch' import fetch from 'node-fetch'
import { consensusPubkeyToHexAddress, getLocalChains } from '@/libs/utils' import {
consensusPubkeyToHexAddress, getLocalChains, getCachedValidators, toDay,
} from '@/libs/utils'
import vSelect from 'vue-select' import vSelect from 'vue-select'
import AppFooter from '@/@core/layouts/components/AppFooter.vue'
import FullHeader from './components/FullHeader.vue'
export default { export default {
components: { components: {
FullHeader, BAlert,
BBreadcrumb,
BRow, BRow,
BCol, BCol,
BCard, BCard,
@ -124,21 +106,13 @@ export default {
BInputGroupAppend, BInputGroupAppend,
BButton, BButton,
BAvatar, BAvatar,
BCardTitle,
vSelect, vSelect,
AppFooter,
}, },
data() { data() {
const chains = getLocalChains() const chains = getLocalChains()
return { return {
navs: [
{
text: 'Tools',
},
{
text: 'Consensus Monitor',
},
],
showPrevote: false, showPrevote: false,
httpstatus: 200, httpstatus: 200,
httpStatusText: '', httpStatusText: '',
@ -146,20 +120,25 @@ export default {
chains, chains,
vals: [], vals: [],
positions: [], positions: [],
updatetime: new Date(),
rpc: '',
} }
}, },
computed: { computed: {
selected() { selected() {
return this.$route.query.chain || this.chains[Object.keys(this.chains)[0]].chain_name return this.$store.state.chains.selected.chain_name
},
rpc() {
return `${this.chains[this.selected].rpc[0]}/consensus_state`
}, },
}, },
created() { created() {
this.validators() this.validators()
this.rpc = `${this.chains[this.selected].rpc[0]}/consensus_state`
this.timer = setInterval(this.update, 6000)
},
beforeDestroy() {
clearInterval(this.timer)
}, },
methods: { methods: {
format: v => toDay(v, 'time'),
color(i, txt) { color(i, txt) {
if (i === this.roundState.proposer.index) { if (i === this.roundState.proposer.index) {
return txt === 'nil-Vote' ? 'outline-primary' : 'primary' return txt === 'nil-Vote' ? 'outline-primary' : 'primary'
@ -167,6 +146,8 @@ export default {
return txt === 'nil-Vote' ? 'outline-secondary' : 'success' return txt === 'nil-Vote' ? 'outline-secondary' : 'success'
}, },
update() { update() {
this.updatetime = new Date()
if (this.httpstatus === 200) {
fetch(this.rpc).then(data => { fetch(this.rpc).then(data => {
this.httpstatus = data.status this.httpstatus = data.status
this.httpStatusText = data.httpStatusText this.httpStatusText = data.httpStatusText
@ -177,36 +158,28 @@ export default {
this.httpstatus = 500 this.httpstatus = 500
this.httpStatusText = err this.httpStatusText = err
}) })
}
}, },
validators() { validators() {
const conf = this.chains[this.selected] const conf = this.chains[this.selected]
let vals = []
this.$http.getValidatorList(conf).then(data => { this.$http.getValidatorList(conf).then(data => {
this.vals = data.map(x => { vals = data
}).catch(() => {
vals = getCachedValidators(this.selected.chain_name) || []
}).finally(() => {
this.vals = vals.map(x => {
const x2 = x const x2 = x
x2.hex = consensusPubkeyToHexAddress(x.consensus_pubkey) x2.hex = consensusPubkeyToHexAddress(x.consensus_pubkey)
return x2 return x2
}) })
}) })
}, },
onchange(v) { onchange() {
this.httpstatus = 200 this.httpstatus = 200
this.httpStatusText = '' this.httpStatusText = ''
this.roundState = {} this.roundState = {}
this.selected = v.chain_name // this.validators()
this.rpc = `${v.rpc[0]}/consensus_state`
// used for mapping nil-vote validators
fetch(`${v.rpc[0]}/validators?per_page=100`).then(data => data.json()).then(res2 => {
this.positions = res2.result.validators
if (res2.result.total > 100) {
fetch(`${v.rpc[0]}/validators?page=2&per_page=100`).then(data => data.json()).then(res => {
this.positions = this.positions.concat(res.result.validators)
})
}
}).catch(err => {
this.httpstatus = 500
this.httpStatusText = err
})
this.validators()
}, },
showName(i, text) { showName(i, text) {
if (text === 'nil-Vote') { if (text === 'nil-Vote') {

View File

@ -10,18 +10,12 @@
<b-card> <b-card>
<b-card-title> <b-card-title>
Starting New Node From State Sync Starting New Node From State Sync
<b-badge
v-if="snapshot_provider?false:true"
variant="danger"
>
WIP
</b-badge>
</b-card-title> </b-card-title>
<b class="mt-1">1. Install Binary ({{ version }})</b><br> <b class="mt-1">1. Install Binary (Version: {{ version }})</b><br>
We need to install the binary first and make sure that the version is the one currently in use on mainnet. We need to install the binary first and make sure that the version is the one currently in use on mainnet.
<br><br> <br><br>
<b class="mt-1">2. Enable State Sync</b><br> <b class="mt-1">2. Enable State Sync</b><br>
We can configure Tendermint to use state sync in <code>$DAEMON_HOME/config/config.toml</code>, then start daemon. We can configure Tendermint to use state sync in <code>$DAEMON_HOME/config/config.toml</code>.
<ul class="mt-1"> <ul class="mt-1">
<li <li
v-for="e in error" v-for="e in error"
@ -41,6 +35,8 @@
class="my-1" class="my-1"
@change="check()" @change="check()"
/> />
<b class="mt-1">3. Start the daemon</b><br>
If you are resetting node, run <code>unsafe-reset-all</code> before you start the daemon.
</b-card> </b-card>
<b-card> <b-card>
@ -48,7 +44,6 @@
Enable Snapshot For State Sync Enable Snapshot For State Sync
</b-card-title> </b-card-title>
To make state sync works, we can enable snapshot in <code>$DAEMON_HOME/config/app.toml</code> To make state sync works, we can enable snapshot in <code>$DAEMON_HOME/config/app.toml</code>
and don't forget to share your snapshot server <a href="https://github.com/ping-pub/explorer/discussions">Here</a>
<b-form-textarea <b-form-textarea
id="snapshot" id="snapshot"
v-model="snapshot" v-model="snapshot"
@ -62,12 +57,11 @@
<script> <script>
import { import {
BCard, BCardTitle, BFormTextarea, BBadge, BCard, BCardTitle, BFormTextarea,
} from 'bootstrap-vue' } from 'bootstrap-vue'
export default { export default {
components: { components: {
BBadge,
BCard, BCard,
BCardTitle, BCardTitle,
BFormTextarea, BFormTextarea,