optimized block loading
This commit is contained in:
parent
727a53177e
commit
4a375f58d0
@ -5,10 +5,10 @@ import {
|
||||
useStakingStore,
|
||||
useBaseStore,
|
||||
useBlockchain,
|
||||
useFormatter,
|
||||
useFormatter,
|
||||
} from '@/stores';
|
||||
import UptimeBar from '@/components/UptimeBar.vue';
|
||||
import type { SlashingParam, SigningInfo } from '@/types';
|
||||
import type { SlashingParam, SigningInfo, Block } from '@/types';
|
||||
import { consensusPubkeyToHexAddress, valconsToBase64 } from '@/libs';
|
||||
|
||||
const props = defineProps(['chain']);
|
||||
@ -53,24 +53,24 @@ const validatorSet = computed(() => {
|
||||
});
|
||||
});
|
||||
|
||||
const blocks = ref({} as Record<string, BlockColor[]>);
|
||||
const blockColors = ref({} as Record<string, BlockColor[]>);
|
||||
|
||||
const grid = computed(() => {
|
||||
const grid = computed(() => {
|
||||
|
||||
const validators = keyword.value.length === 0 ? validatorSet.value :
|
||||
validatorSet.value.filter((v) => v.moniker.toLowerCase().includes(keyword.value.toLowerCase()));
|
||||
const validators = keyword.value.length === 0 ? validatorSet.value :
|
||||
validatorSet.value.filter((v) => v.moniker.toLowerCase().includes(keyword.value.toLowerCase()));
|
||||
|
||||
const window = Number(slashingParam.value.signed_blocks_window || 0);
|
||||
return validators.map((v) => {
|
||||
const signing = signingInfo.value[v.hex];
|
||||
const uptime = signing && window > 0
|
||||
? (window - Number(signing.missed_blocks_counter)) / window
|
||||
: undefined
|
||||
? (window - Number(signing.missed_blocks_counter)) / window
|
||||
: undefined
|
||||
return {
|
||||
moniker: v.moniker,
|
||||
hex: v.hex,
|
||||
base64: v.base64,
|
||||
blocks: padding(blocks.value[v.base64] || []) ,
|
||||
blocks: padding(blockColors.value[v.base64] || []),
|
||||
uptime,
|
||||
missed_blocks_counter: signing?.missed_blocks_counter || 0,
|
||||
signing
|
||||
@ -78,77 +78,29 @@ const grid = computed(() => {
|
||||
})
|
||||
});
|
||||
|
||||
const preload = ref(false);
|
||||
baseStore.$subscribe((_, state) => {
|
||||
const newHeight = Number(state.latest?.block?.header?.height || 0)
|
||||
if (newHeight > latest.value) {
|
||||
latest.value = newHeight;
|
||||
if(Number(state.latest.block.header.height) % 7 === 0 ) updateTotalSigningInfo();
|
||||
validatorSet.value.forEach((v) => {
|
||||
const sig = state.latest.block.last_commit?.signatures.find((s) => s.validator_address === v.base64)
|
||||
const block = blocks.value[v.base64] || [];
|
||||
if (sig){
|
||||
block.push({
|
||||
height: state.latest.block.header.height,
|
||||
color: sig.block_id_flag === 'BLOCK_ID_FLAG_COMMIT' ? 'bg-green-500' : 'bg-yellow-500'
|
||||
});
|
||||
} else {
|
||||
block.push({
|
||||
height: state.latest.block.header.height,
|
||||
color: 'bg-red-500'
|
||||
});
|
||||
}
|
||||
if (block.length > 50) block.shift();
|
||||
blocks.value[v.base64] = block;
|
||||
});
|
||||
// initialize if it's the first time
|
||||
if(!preload.value) {
|
||||
preFill();
|
||||
preload.value = true;
|
||||
}
|
||||
|
||||
if (Number(state.latest.block.header.height) % 7 === 0) updateTotalSigningInfo();
|
||||
fillblock(state.latest);
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
live.value = true;
|
||||
|
||||
baseStore.fetchLatest().then((l) => {
|
||||
let b = l;
|
||||
if (
|
||||
baseStore.recents?.findIndex((x) => x.block_id.hash === l.block_id.hash) >
|
||||
-1
|
||||
) {
|
||||
b = baseStore.recents?.at(0) || l;
|
||||
}
|
||||
latest.value = Number(b.block.header.height);
|
||||
const height = Number(b.block.header?.height || 0);
|
||||
if (height > 50) {
|
||||
// constructs sequence for loading blocks
|
||||
let promise = Promise.resolve();
|
||||
for (let i = height - 1; i > height - 50; i -= 1) {
|
||||
promise = promise.then(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
if (live.value) {
|
||||
// continue only if the page is living
|
||||
baseStore.fetchBlock(i).then((x) => {
|
||||
validatorSet.value.forEach((v) => {
|
||||
const sig = x.block.last_commit?.signatures.find((s) => s.validator_address === v.base64)
|
||||
const block = blocks.value[v.base64] || [];
|
||||
if (sig){
|
||||
block.unshift({
|
||||
height: x.block.header.height,
|
||||
color: sig.block_id_flag === 'BLOCK_ID_FLAG_COMMIT' ? 'bg-green-500' : 'bg-yellow-500'
|
||||
});
|
||||
} else {
|
||||
block.unshift({
|
||||
height: x.block.header.height,
|
||||
color: 'bg-red-500'
|
||||
});
|
||||
}
|
||||
blocks.value[v.base64] = block;
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// fill the recent blocks
|
||||
baseStore.recents?.forEach((b) => {
|
||||
fillblock(b, 'start');
|
||||
});
|
||||
|
||||
updateTotalSigningInfo();
|
||||
@ -158,6 +110,50 @@ onMounted(() => {
|
||||
});
|
||||
});
|
||||
|
||||
function preFill() {
|
||||
|
||||
if(latest.value > 50 && baseStore.recents.length >= 49 ) return
|
||||
// preload 50 blocks if recent blocks are not enough
|
||||
let promise = Promise.resolve();
|
||||
for (let i = latest.value - baseStore.recents.length; i > latest.value - 50 && i > 1; i -= 1) {
|
||||
promise = promise.then(() =>
|
||||
new Promise((resolve) => {
|
||||
if (live.value) {
|
||||
// continue only if the page is living
|
||||
if (i > latest.value - 50)
|
||||
baseStore.fetchBlock(i).then((x) => {
|
||||
fillblock(x, 'start');
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
function fillblock(b: Block, direction: string = 'end') {
|
||||
validatorSet.value.forEach((v) => {
|
||||
const sig = b.block.last_commit?.signatures.find((s) => s.validator_address === v.base64)
|
||||
const block = blockColors.value[v.base64] || [];
|
||||
let color = {
|
||||
height: b.block.header.height,
|
||||
color: 'bg-red-500'
|
||||
}
|
||||
if (sig) {
|
||||
color = {
|
||||
height: b.block.header.height,
|
||||
color: sig.block_id_flag === 'BLOCK_ID_FLAG_COMMIT' ? 'bg-green-500' : 'bg-yellow-500'
|
||||
}
|
||||
}
|
||||
if (direction === 'end') {
|
||||
block.push(color);
|
||||
} else {
|
||||
block.unshift(color);
|
||||
}
|
||||
if (block.length > 50) block.shift();
|
||||
blockColors.value[v.base64] = block;
|
||||
});
|
||||
}
|
||||
|
||||
function updateTotalSigningInfo() {
|
||||
chainStore.rpc.getSlashingSigningInfos().then((x) => {
|
||||
x.info?.forEach((i) => {
|
||||
@ -184,36 +180,24 @@ function fetchAllKeyRotation() {
|
||||
<template>
|
||||
<div>
|
||||
<div class="tabs tabs-boxed bg-transparent mb-4">
|
||||
<a
|
||||
class="tab text-gray-400 capitalize"
|
||||
:class="{ 'tab-active': tab === '3' }"
|
||||
@click="changeTab('3')"
|
||||
>{{ $t('uptime.overall') }}</a
|
||||
>
|
||||
<a
|
||||
class="tab text-gray-400 capitalize"
|
||||
:class="{ 'tab-active': tab === '2' }"
|
||||
@click="changeTab('2')"
|
||||
>{{ $t('module.blocks') }}</a
|
||||
>
|
||||
<a class="tab text-gray-400 capitalize" :class="{ 'tab-active': tab === '3' }" @click="changeTab('3')">{{
|
||||
$t('uptime.overall') }}</a>
|
||||
<a class="tab text-gray-400 capitalize" :class="{ 'tab-active': tab === '2' }" @click="changeTab('2')">{{
|
||||
$t('module.blocks') }}</a>
|
||||
<RouterLink :to="`/${chain}/uptime/customize`">
|
||||
<a class="tab text-gray-400 capitalize">{{ $t('uptime.customize') }}</a>
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="bg-base-100 px-5 pt-5">
|
||||
<div class="flex items-center gap-x-4">
|
||||
<input
|
||||
type="text"
|
||||
v-model="keyword"
|
||||
placeholder="Keywords to filter validators"
|
||||
class="input input-sm w-full flex-1 border border-gray-200 dark:border-gray-600"
|
||||
/>
|
||||
<button v-if="chainStore.isConsumerChain" class="btn btn-sm btn-primary" @click="fetchAllKeyRotation">Load Rotated Keys</button>
|
||||
<input type="text" v-model="keyword" placeholder="Keywords to filter validators"
|
||||
class="input input-sm w-full flex-1 border border-gray-200 dark:border-gray-600" />
|
||||
<button v-if="chainStore.isConsumerChain" class="btn btn-sm btn-primary" @click="fetchAllKeyRotation">Load
|
||||
Rotated Keys</button>
|
||||
</div>
|
||||
|
||||
<div v-if="chainStore.isConsumerChain && Object.keys(stakingStore.keyRotation).length === 0"
|
||||
class="alert alert-warning my-4"
|
||||
>
|
||||
class="alert alert-warning my-4">
|
||||
Note: Please load rotated keys to see the correct uptime
|
||||
</div>
|
||||
<!-- grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-x-4 mt-4 -->
|
||||
@ -222,20 +206,13 @@ function fetchAllKeyRotation() {
|
||||
<div v-for="(unit, i) in grid" :key="i">
|
||||
<div class="flex justify-between py-0 w-[248px]">
|
||||
<label class="truncate text-sm">
|
||||
<span class="ml-1 text-black dark:text-white"
|
||||
>{{ i + 1 }}.{{ unit.moniker }}</span
|
||||
>
|
||||
<span class="ml-1 text-black dark:text-white">{{ i + 1 }}.{{ unit.moniker }}</span>
|
||||
</label>
|
||||
<div
|
||||
v-if="Number(unit?.missed_blocks_counter || 0) > 10"
|
||||
class="badge badge-sm bg-transparent border-0 text-red-500 font-bold"
|
||||
>
|
||||
<div v-if="Number(unit?.missed_blocks_counter || 0) > 10"
|
||||
class="badge badge-sm bg-transparent border-0 text-red-500 font-bold">
|
||||
{{ unit?.missed_blocks_counter }}
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="badge badge-sm bg-transparent text-green-600 border-0 font-bold"
|
||||
>
|
||||
<div v-else class="badge badge-sm bg-transparent text-green-600 border-0 font-bold">
|
||||
{{ unit?.missed_blocks_counter }}
|
||||
</div>
|
||||
</div>
|
||||
@ -244,9 +221,9 @@ function fetchAllKeyRotation() {
|
||||
</div>
|
||||
<div class="mt-5 text-xs flex justify-center gap-2">
|
||||
<span class=" font-bold">{{ $t('uptime.legend') }}: </span>
|
||||
<span class="bg-green-500"> </span> {{ $t('uptime.committed')}}
|
||||
<span class="bg-yellow-500"> </span> {{ $t('uptime.precommitted')}}
|
||||
<span class="bg-red-500"> </span> {{ $t('uptime.missed')}}
|
||||
<span class="bg-green-500"> </span> {{ $t('uptime.committed') }}
|
||||
<span class="bg-yellow-500"> </span> {{ $t('uptime.precommitted') }}
|
||||
<span class="bg-red-500"> </span> {{ $t('uptime.missed') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -269,40 +246,27 @@ function fetchAllKeyRotation() {
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span
|
||||
:class="
|
||||
v.uptime && v.uptime > 0.95 ? 'text-green-500' : 'text-red-500'
|
||||
"
|
||||
>
|
||||
<div
|
||||
class="tooltip"
|
||||
:data-tip="`${v.missed_blocks_counter} missing blocks`"
|
||||
>
|
||||
<span :class="v.uptime && v.uptime > 0.95 ? 'text-green-500' : 'text-red-500'
|
||||
">
|
||||
<div class="tooltip" :data-tip="`${v.missed_blocks_counter} missing blocks`">
|
||||
{{ format.percent(v.uptime) }}
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="v.signing && !v.signing.jailed_until.startsWith('1970')">
|
||||
<div
|
||||
class="tooltip"
|
||||
:data-tip="format.toDay(v.signing.jailed_until, 'long')"
|
||||
>
|
||||
<div class="tooltip" :data-tip="format.toDay(v.signing.jailed_until, 'long')">
|
||||
<span>{{ format.toDay(v.signing.jailed_until, 'from') }}</span>
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-xs text-right">
|
||||
<span
|
||||
v-if="v.signing && v.signing.jailed_until.startsWith('1970')"
|
||||
class="text-right"
|
||||
>{{
|
||||
format.percent(
|
||||
Number(v.signing.index_offset) /
|
||||
(latest - Number(v.signing.start_height))
|
||||
)
|
||||
}}</span
|
||||
>
|
||||
<span v-if="v.signing && v.signing.jailed_until.startsWith('1970')" class="text-right">{{
|
||||
format.percent(
|
||||
Number(v.signing.index_offset) /
|
||||
(latest - Number(v.signing.start_height))
|
||||
)
|
||||
}}</span>
|
||||
{{ v.signing?.index_offset }}
|
||||
</td>
|
||||
<td class="text-right">{{ v.signing?.start_height }}</td>
|
||||
@ -312,12 +276,10 @@ function fetchAllKeyRotation() {
|
||||
<tr>
|
||||
<td colspan="2" class="text-right">
|
||||
{{ $t('uptime.minimum_uptime') }}:
|
||||
<span
|
||||
class="lowercase tooltip"
|
||||
:data-tip="`Window size: ${slashingParam.signed_blocks_window}`"
|
||||
><span class="ml-2 btn btn-error btn-xs">{{
|
||||
format.percent(slashingParam.min_signed_per_window)
|
||||
}}</span>
|
||||
<span class="lowercase tooltip" :data-tip="`Window size: ${slashingParam.signed_blocks_window}`"><span
|
||||
class="ml-2 btn btn-error btn-xs">{{
|
||||
format.percent(slashingParam.min_signed_per_window)
|
||||
}}</span>
|
||||
</span>
|
||||
</td>
|
||||
<td colspan="8"></td>
|
||||
|
Loading…
Reference in New Issue
Block a user