Finish uptime
This commit is contained in:
parent
58d8cd034a
commit
be8ca28c56
32
src/components/UptimeBar.vue
Normal file
32
src/components/UptimeBar.vue
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<script lang=ts setup>
|
||||||
|
import type { Commit } from "@/types";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
blocks: { type: Array as PropType<Commit[]>},
|
||||||
|
validator: { type: String },
|
||||||
|
})
|
||||||
|
|
||||||
|
const bars = computed(() => {
|
||||||
|
const uptime = Array(50).fill({height:0, color: 'bg-secondary'})
|
||||||
|
props.blocks.forEach(element => {
|
||||||
|
const has = element.signatures?.findIndex(sig => sig.validator_address === props.validator )
|
||||||
|
// console.log(has, props.validato, element)
|
||||||
|
uptime.push({
|
||||||
|
height: element.height,
|
||||||
|
color: has > -1 ? 'bg-success' : 'bg-error'
|
||||||
|
})
|
||||||
|
uptime.shift()
|
||||||
|
});
|
||||||
|
return uptime
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="d-flex justify-evenly">
|
||||||
|
<span v-for="(b,i) in bars"
|
||||||
|
:key="i"
|
||||||
|
:class="b.color"
|
||||||
|
style="width:1.5%">
|
||||||
|
<v-tooltip v-if="Number(b.height) > 0" activator="parent" location="top">{{ b.height }}</v-tooltip>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -50,6 +50,11 @@ export function consensusPubkeyToHexAddress(consensusPubkey?: {"@type": string,
|
|||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function valconsToBase64(address: string) {
|
||||||
|
if(address) return toHex(fromBech32(address).data).toUpperCase()
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
export function toETHAddress(cosmosAddress: string) {
|
export function toETHAddress(cosmosAddress: string) {
|
||||||
return `0x${toHex(fromBech32(cosmosAddress).data)}`
|
return `0x${toHex(fromBech32(cosmosAddress).data)}`
|
||||||
|
@ -63,7 +63,8 @@ export class CosmosRestClient {
|
|||||||
return this.request(this.registry.slashing_params, {})
|
return this.request(this.registry.slashing_params, {})
|
||||||
}
|
}
|
||||||
async getSlashingSigningInfos() {
|
async getSlashingSigningInfos() {
|
||||||
return this.request(this.registry.slashing_signing_info, {})
|
const query = "?pagination.limit=300"
|
||||||
|
return this.request(this.registry.slashing_signing_info, {}, query)
|
||||||
}
|
}
|
||||||
// Gov
|
// Gov
|
||||||
async getGovParamsVoting() {
|
async getGovParamsVoting() {
|
||||||
|
@ -1,41 +1,72 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
import {fromBase64, fromBech32, fromHex, toBase64, toBech32, toHex} from '@cosmjs/encoding'
|
||||||
|
import { useFormatter, useStakingStore, useBaseStore, useBlockchain } from '@/stores';
|
||||||
|
import UptimeBar from '@/components/UptimeBar.vue';
|
||||||
|
import type { Commit } from '@/types'
|
||||||
|
import { consensusPubkeyToHexAddress, valconsToBase64 } from "@/libs";
|
||||||
|
|
||||||
interface TabItem{
|
const stakingStore = useStakingStore();
|
||||||
tabName: string
|
const baseStore = useBaseStore();
|
||||||
id: number
|
const chainStore = useBlockchain()
|
||||||
value: string
|
const format = useFormatter();
|
||||||
}
|
const latest = ref({})
|
||||||
|
const commits = ref([] as Commit[]);
|
||||||
|
const keyword = ref("")
|
||||||
|
|
||||||
const tab = ref('');
|
const signingInfo = ref({})
|
||||||
const tabList: Array<TabItem> = [
|
|
||||||
{ tabName: 'Group By Validator', id: 1, value: 'validator' },
|
const validators = computed(()=> {
|
||||||
{ tabName: 'Group By Proposer', id: 2, value: 'proposer' },
|
if(keyword) return stakingStore.validators.filter(x => x.description.moniker.indexOf(keyword.value) > -1)
|
||||||
]
|
return stakingStore.validators
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
baseStore.fetchLatest().then(block => {
|
||||||
|
latest.value = block
|
||||||
|
commits.value.unshift(block.block.last_commit)
|
||||||
|
const height = Number(block.block.header?.height|| 0)
|
||||||
|
if(height > 0) {
|
||||||
|
// constructs sequence for loading blocks
|
||||||
|
let promise = Promise.resolve()
|
||||||
|
for (let i = height - 1; i > height - 50; i -= 1) {
|
||||||
|
if (i > height - 48 && i > 0) {
|
||||||
|
promise = promise.then(() => new Promise(resolve => {
|
||||||
|
baseStore.fetchBlock(i).then((x) => {
|
||||||
|
commits.value.unshift(x.block.last_commit)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
chainStore.rpc.getSlashingSigningInfos().then((x)=> {
|
||||||
|
x.info?.forEach(i => {
|
||||||
|
signingInfo.value[valconsToBase64(i.address)] = i
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
function clickTab(item: TabItem) {
|
|
||||||
// toggle tab and stop another tab fetch
|
|
||||||
console.log(tab, 'tab')
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="">
|
<div>
|
||||||
<VTabs v-model="tab" class="v-tabs-pill">
|
<VRow>
|
||||||
<VTab
|
<VCol cols="12" md="4">Current Height: {{latest.block?.header?.height}} </VCol>
|
||||||
v-for="(item, index) in tabList"
|
<VCol cols="12" md="8"><VTextField v-model="keyword" label="Keywords to filter validators" /></VCol>
|
||||||
:key="index"
|
</VRow>
|
||||||
:value="item.value"
|
<VRow>
|
||||||
@click="clickTab(item)"
|
<VCol v-for="(v, i) in validators" cols="12" md="3" xl="2">
|
||||||
>{{ item.tabName }}</VTab>
|
<div class="d-flex justify-between">
|
||||||
</VTabs>
|
<span class="text-truncate">{{i + 1}}. {{v.description.moniker}}</span>
|
||||||
<VWindow v-model="tab" class="mt-5">
|
<VChip v-if="Number(signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter || 0) > 0" size="small" class="mb-1" label color="error">{{ signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter }}</VChip>
|
||||||
<VWindowItem v-for="(item, index) in tabList" :key="index" :value="item.value">
|
<VChip v-else size="small" class="mb-1" label color="success">{{ signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter }}</VChip>
|
||||||
<!-- <ProposalListItem :proposals="store?.proposals['2']" /> -->
|
</div>
|
||||||
|
<UptimeBar :blocks="commits" :validator="toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))" />
|
||||||
<VCard> {{item.tabName}}</VCard>
|
</VCol>
|
||||||
</VWindowItem>
|
</VRow>
|
||||||
</VWindow>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<route>
|
<route>
|
||||||
|
@ -80,15 +80,17 @@ export interface Block {
|
|||||||
"evidence": {
|
"evidence": {
|
||||||
"evidence": any[]
|
"evidence": any[]
|
||||||
},
|
},
|
||||||
"last_commit": {
|
"last_commit": Commit
|
||||||
"height": string,
|
|
||||||
"round": number,
|
|
||||||
"block_id": BlockId,
|
|
||||||
"signatures": Signature[]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Commit {
|
||||||
|
"height": string,
|
||||||
|
"round": number,
|
||||||
|
"block_id": BlockId,
|
||||||
|
"signatures": Signature[]
|
||||||
|
}
|
||||||
|
|
||||||
export interface TendermintValidator {
|
export interface TendermintValidator {
|
||||||
"address": string,
|
"address": string,
|
||||||
"pub_key": Key,
|
"pub_key": Key,
|
||||||
|
@ -29,4 +29,10 @@ export class Response<T> {
|
|||||||
export interface Coin {
|
export interface Coin {
|
||||||
amount: string;
|
amount: string;
|
||||||
denom: string;
|
denom: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UptimeStatus {
|
||||||
|
height: number;
|
||||||
|
filled: boolean;
|
||||||
|
signed: boolean;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user