add consensus state monitor tool
This commit is contained in:
parent
8a2de4fd8a
commit
139b42416a
@ -347,6 +347,14 @@ const router = new VueRouter({
|
||||
},
|
||||
},
|
||||
// common modules
|
||||
{
|
||||
path: '/tools/consensus-states',
|
||||
name: 'consensus',
|
||||
component: () => import('@/views/ConsensusStates.vue'),
|
||||
meta: {
|
||||
layout: 'full',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/error/error-404',
|
||||
name: 'error-404',
|
||||
|
186
src/views/ConsensusStates.vue
Normal file
186
src/views/ConsensusStates.vue
Normal file
@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<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-input-group>
|
||||
<b-input-group-prepend>
|
||||
<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 }}</span>
|
||||
</template>
|
||||
</v-select>
|
||||
</b-input-group-prepend>
|
||||
<b-form-input
|
||||
v-model="rpc"
|
||||
placeholder="Button on both side"
|
||||
/>
|
||||
<b-input-group-append>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click="update()"
|
||||
>
|
||||
Moniter
|
||||
</b-button>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
<div
|
||||
v-if="httpstatus !== 200"
|
||||
class="text-danger"
|
||||
>
|
||||
{{ httpstatus }}: {{ httpStatusText }}
|
||||
</div>
|
||||
</b-card>
|
||||
<b-card
|
||||
v-if="roundState['height/round/step']"
|
||||
:title="`Height/Round/Step: ${roundState['height/round/step']}`"
|
||||
>
|
||||
<div
|
||||
v-for="item in roundState.height_vote_set"
|
||||
:key="item.round"
|
||||
>
|
||||
Round: {{ item.round }} {{ item.precommits_bit_array }}
|
||||
<b-card-body nobody>
|
||||
<b-button
|
||||
v-for="(pre, i) in item.precommits"
|
||||
:key="i"
|
||||
size="sm"
|
||||
style="margin: 2px;"
|
||||
:variant="color(i, pre)"
|
||||
>
|
||||
<small>{{ showName(i, pre) }}</small>
|
||||
</b-button>
|
||||
</b-card-body>
|
||||
</div>
|
||||
</b-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
BAvatar,
|
||||
BBreadcrumb, BCard, BCardBody, BInputGroup, BFormInput, BInputGroupAppend, BInputGroupPrepend, BButton,
|
||||
} from 'bootstrap-vue'
|
||||
import fetch from 'node-fetch'
|
||||
import { consensusPubkeyToHexAddress, getLocalChains } from '@/libs/utils'
|
||||
import vSelect from 'vue-select'
|
||||
import FullHeader from './components/FullHeader.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FullHeader,
|
||||
BBreadcrumb,
|
||||
BCard,
|
||||
BCardBody,
|
||||
BInputGroup,
|
||||
BFormInput,
|
||||
BInputGroupAppend,
|
||||
BInputGroupPrepend,
|
||||
BButton,
|
||||
BAvatar,
|
||||
vSelect,
|
||||
},
|
||||
|
||||
data() {
|
||||
const chains = getLocalChains()
|
||||
const selected = 'cosmos'
|
||||
return {
|
||||
navs: [
|
||||
{
|
||||
text: 'Tools',
|
||||
},
|
||||
{
|
||||
text: 'Consensus Monitor',
|
||||
},
|
||||
],
|
||||
showPrevote: false,
|
||||
rpc: chains[selected].rpc[0],
|
||||
httpstatus: 200,
|
||||
httpStatusText: '',
|
||||
roundState: {},
|
||||
selected,
|
||||
chains,
|
||||
vals: [],
|
||||
positions: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.validators()
|
||||
},
|
||||
methods: {
|
||||
color(i, txt) {
|
||||
if (i === this.roundState.proposer.index) {
|
||||
return txt === 'nil-Vote' ? 'outline-primary' : 'primary'
|
||||
}
|
||||
return txt === 'nil-Vote' ? 'outline-secondary' : 'success'
|
||||
},
|
||||
update() {
|
||||
fetch(this.rpc).then(data => {
|
||||
this.httpstatus = data.status
|
||||
this.httpStatusText = data.httpStatusText
|
||||
return data.json()
|
||||
}).then(res => {
|
||||
this.roundState = res.result.round_state
|
||||
})
|
||||
},
|
||||
validators() {
|
||||
const conf = this.chains[this.selected]
|
||||
this.$http.getValidatorList(conf).then(data => {
|
||||
this.vals = data.map(x => {
|
||||
const x2 = x
|
||||
x2.hex = consensusPubkeyToHexAddress(x.consensus_pubkey)
|
||||
return x2
|
||||
})
|
||||
})
|
||||
},
|
||||
onchange(v) {
|
||||
this.roundState = {}
|
||||
this.selected = v.chain_name
|
||||
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)
|
||||
})
|
||||
}
|
||||
})
|
||||
this.validators()
|
||||
},
|
||||
showName(i, text) {
|
||||
if (text === 'nil-Vote') {
|
||||
if (this.positions[i]) {
|
||||
const val = this.vals.find(x => x.hex === this.positions[i].address)
|
||||
return val?.description?.moniker || i
|
||||
}
|
||||
return i
|
||||
}
|
||||
const txt = text.substring(text.indexOf(':') + 1, text.indexOf(' '))
|
||||
const val = this.vals.find(x => x.hex.startsWith(txt))
|
||||
return val?.description?.moniker || txt
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import '@core/scss/vue/libs/vue-select.scss';
|
||||
</style>
|
@ -1,22 +1,6 @@
|
||||
<template>
|
||||
<div class="text-center container-lg">
|
||||
<b-nav
|
||||
align="right"
|
||||
style="width:100%"
|
||||
class="nav text-right text-nowrap ml-auto"
|
||||
>
|
||||
<b-nav-item><dark-toggler /></b-nav-item>
|
||||
<b-nav-item><locale /></b-nav-item>
|
||||
<b-button
|
||||
v-ripple.400="'rgba(255, 255, 255, 0.15)'"
|
||||
variant="primary"
|
||||
class="btn-icon mt-25"
|
||||
:to="{ name: 'accounts' }"
|
||||
>
|
||||
<feather-icon icon="KeyIcon" />
|
||||
<span class="align-middle ml-25">Wallet</span>
|
||||
</b-button>
|
||||
</b-nav>
|
||||
<full-header />
|
||||
<b-link>
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<vuexy-logo />
|
||||
@ -135,16 +119,14 @@
|
||||
<script>
|
||||
/* eslint-disable global-require */
|
||||
import {
|
||||
BLink, BAvatar, BRow, BCol, BCard, BCardText, BCardTitle, BNav, BNavItem, BButton,
|
||||
BDropdown, BDropdownItem,
|
||||
BLink, BAvatar, BRow, BCol, BCard, BCardText, BCardTitle, BDropdown, BDropdownItem,
|
||||
} from 'bootstrap-vue'
|
||||
import Ripple from 'vue-ripple-directive'
|
||||
import VuexyLogo from '@core/layouts/components/Logo.vue'
|
||||
import store from '@/store/index'
|
||||
import { timeIn, toDay } from '@/libs/utils'
|
||||
import DarkToggler from '@/@core/layouts/components/app-navbar/components/DarkToggler.vue'
|
||||
import Locale from '@/@core/layouts/components/app-navbar/components/Locale.vue'
|
||||
import AppFooter from '@/@core/layouts/components/AppFooter.vue'
|
||||
import FullHeader from './components/FullHeader.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -157,14 +139,9 @@ export default {
|
||||
BCardTitle,
|
||||
BDropdown,
|
||||
BDropdownItem,
|
||||
BNav,
|
||||
BNavItem,
|
||||
BButton,
|
||||
|
||||
VuexyLogo,
|
||||
DarkToggler,
|
||||
Locale,
|
||||
AppFooter,
|
||||
FullHeader,
|
||||
},
|
||||
directives: {
|
||||
Ripple,
|
||||
|
41
src/views/components/FullHeader.vue
Normal file
41
src/views/components/FullHeader.vue
Normal file
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<b-nav
|
||||
align="right"
|
||||
style="width:100%"
|
||||
class="nav text-right text-nowrap ml-auto"
|
||||
>
|
||||
<b-nav-item><dark-toggler /></b-nav-item>
|
||||
<b-nav-item><locale /></b-nav-item>
|
||||
<b-button
|
||||
v-ripple.400="'rgba(255, 255, 255, 0.15)'"
|
||||
variant="primary"
|
||||
class="btn-icon mt-25"
|
||||
:to="{ name: 'accounts' }"
|
||||
>
|
||||
<feather-icon icon="KeyIcon" />
|
||||
<span class="align-middle ml-25">Wallet</span>
|
||||
</b-button>
|
||||
</b-nav>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
BNav, BNavItem, BButton,
|
||||
} from 'bootstrap-vue'
|
||||
import Ripple from 'vue-ripple-directive'
|
||||
import DarkToggler from '@/@core/layouts/components/app-navbar/components/DarkToggler.vue'
|
||||
import Locale from '@/@core/layouts/components/app-navbar/components/Locale.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BNav,
|
||||
BNavItem,
|
||||
BButton,
|
||||
DarkToggler,
|
||||
Locale,
|
||||
},
|
||||
directives: {
|
||||
Ripple,
|
||||
},
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user