Finish uptime

This commit is contained in:
liangping 2023-04-29 18:21:42 +08:00
parent 58d8cd034a
commit be8ca28c56
6 changed files with 114 additions and 37 deletions

View 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%">&nbsp;
<v-tooltip v-if="Number(b.height) > 0" activator="parent" location="top">{{ b.height }}</v-tooltip>
</span>
</div>
</template>

View File

@ -51,6 +51,11 @@ export function consensusPubkeyToHexAddress(consensusPubkey?: {"@type": string,
return ''
}
export function valconsToBase64(address: string) {
if(address) return toHex(fromBech32(address).data).toUpperCase()
return ''
}
export function toETHAddress(cosmosAddress: string) {
return `0x${toHex(fromBech32(cosmosAddress).data)}`
}

View File

@ -63,7 +63,8 @@ export class CosmosRestClient {
return this.request(this.registry.slashing_params, {})
}
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
async getGovParamsVoting() {

View File

@ -1,41 +1,72 @@
<script lang="ts" setup>
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{
tabName: string
id: number
value: string
const stakingStore = useStakingStore();
const baseStore = useBaseStore();
const chainStore = useBlockchain()
const format = useFormatter();
const latest = ref({})
const commits = ref([] as Commit[]);
const keyword = ref("")
const signingInfo = ref({})
const validators = computed(()=> {
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()
})
}))
}
const tab = ref('');
const tabList: Array<TabItem> = [
{ tabName: 'Group By Validator', id: 1, value: 'validator' },
{ tabName: 'Group By Proposer', id: 2, value: 'proposer' },
]
function clickTab(item: TabItem) {
// toggle tab and stop another tab fetch
console.log(tab, 'tab')
}
}
});
chainStore.rpc.getSlashingSigningInfos().then((x)=> {
x.info?.forEach(i => {
signingInfo.value[valconsToBase64(i.address)] = i
})
})
})
</script>
<template>
<div class="">
<VTabs v-model="tab" class="v-tabs-pill">
<VTab
v-for="(item, index) in tabList"
:key="index"
:value="item.value"
@click="clickTab(item)"
>{{ item.tabName }}</VTab>
</VTabs>
<VWindow v-model="tab" class="mt-5">
<VWindowItem v-for="(item, index) in tabList" :key="index" :value="item.value">
<!-- <ProposalListItem :proposals="store?.proposals['2']" /> -->
<VCard> {{item.tabName}}</VCard>
</VWindowItem>
</VWindow>
<div>
<VRow>
<VCol cols="12" md="4">Current Height: {{latest.block?.header?.height}} </VCol>
<VCol cols="12" md="8"><VTextField v-model="keyword" label="Keywords to filter validators" /></VCol>
</VRow>
<VRow>
<VCol v-for="(v, i) in validators" cols="12" md="3" xl="2">
<div class="d-flex justify-between">
<span class="text-truncate">{{i + 1}}. {{v.description.moniker}}</span>
<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>
<VChip v-else size="small" class="mb-1" label color="success">{{ signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]?.missed_blocks_counter }}</VChip>
</div>
<UptimeBar :blocks="commits" :validator="toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))" />
</VCol>
</VRow>
</div>
</template>
<route>

View File

@ -80,14 +80,16 @@ export interface Block {
"evidence": {
"evidence": any[]
},
"last_commit": {
"last_commit": Commit
}
}
export interface Commit {
"height": string,
"round": number,
"block_id": BlockId,
"signatures": Signature[]
}
}
}
export interface TendermintValidator {
"address": string,

View File

@ -30,3 +30,9 @@ export interface Coin {
amount: string;
denom: string;
}
export interface UptimeStatus {
height: number;
filled: boolean;
signed: boolean;
}