improve consumer uptime

This commit is contained in:
liangping 2024-09-01 23:27:43 +08:00
parent 1243306c69
commit fac4c1a543
8 changed files with 89 additions and 28 deletions

View File

@ -11,7 +11,7 @@
{"provider": "Allnodes", "address": "https://neutron-rpc.publicnode.com:443"}
],
"provider_chain": {
"api": ["https://api-cosmoshub-ia.cosmosia.notional.ventures"]
"api": ["https://rest.cosmos.directory/cosmoshub"]
},
"features": ["dashboard", "blocks", "ibc", "cosmwasm", "uptime", "parameters", "state-sync", "consensus", "supply", "widget"],
"sdk_version": "0.45.1",

View File

@ -1,6 +1,7 @@
import {
fromBase64,
fromBech32,
toBase64,
toBech32,
toHex,
} from '@cosmjs/encoding';
@ -42,6 +43,23 @@ export function consensusPubkeyToHexAddress(consensusPubkey?: {
return raw;
}
// not work as expected, will fix later or remove
export function consumerKeyToBase64Address(consumerKey?: Record<string, string>) {
if (!consumerKey) return '';
let raw = '';
if (consumerKey.ed25519) {
const pubkey = fromBase64(consumerKey.ed25519);
if (pubkey) return toBase64(sha256(pubkey)).slice(0, 40);
}
if (consumerKey.secp256k1) {
const pubkey = fromBase64(consumerKey.secp256k1);
if (pubkey) return toBase64(new Ripemd160().update(sha256(pubkey)).digest());
}
return raw;
}
export function pubKeyToValcons(
consensusPubkey: { '@type': string; key: string },
prefix: string
@ -57,7 +75,7 @@ export function pubKeyToValcons(
}
export function valconsToBase64(address: string) {
if (address) return toHex(fromBech32(address).data).toUpperCase();
if (address) return toBase64(fromBech32(address).data);
return '';
}

View File

@ -199,4 +199,8 @@ export const DEFAULT: RequestRegistry = {
url: '/interchain_security/ccv/provider/opted_in_validators/{chain_id}',
adapter,
},
interchain_security_consumer_validators: {
url: '/interchain_security/ccv/provider/consumer_validators/{chain_id}',
adapter,
},
};

View File

@ -153,6 +153,7 @@ export interface RequestRegistry extends AbstractRegistry {
ibc_core_connection_connections_connection_id_client_state: Request<ClientStateWithProof>;
interchain_security_ccv_provider_validator_consumer_addr: Request<{consumer_address: string}>
interchain_security_provider_opted_in_validators: Request<{validators_provider_addresses: string[]}>
interchain_security_consumer_validators: Request<{validators: {provider_address: string, consumer_key: {ed25519: string}, power: string}[]}>
}
export function adapter<T>(source: any): Promise<T> {

View File

@ -365,4 +365,7 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
async getInterchainSecurityProviderOptedInValidators(chain_id: string) {
return this.request(this.registry.interchain_security_provider_opted_in_validators, {chain_id});
}
async getInterchainSecurityConsumerValidators(chain_id: string) {
return this.request(this.registry.interchain_security_consumer_validators, {chain_id});
}
}

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { ref, onMounted, computed, onUnmounted } from 'vue';
import { fromHex, toBase64 } from '@cosmjs/encoding';
import { fromHex, toBase64, fromBase64, toHex } from '@cosmjs/encoding';
import {
useStakingStore,
useBaseStore,
@ -22,6 +22,7 @@ const keyword = ref('');
const live = ref(true);
const slashingParam = ref({} as SlashingParam);
const signingInfo = ref({} as Record<string, SigningInfo>);
const consumerValidators = ref([] as {moniker: string, base64: string}[]);
interface BlockColor {
height: string;
@ -43,11 +44,20 @@ function padding(blocks: BlockColor[] = []) {
}
const validatorSet = computed(() => {
if (chainStore.isConsumerChain) {
return consumerValidators.value.map((v) => {
const b64 = valconsToBase64(v.moniker)
const moniker = stakingStore.validators.find((x) => toBase64(fromHex(consensusPubkeyToHexAddress(x.consensus_pubkey))) === b64)?.description.moniker;
return {
moniker: moniker || v.moniker,
base64: v.base64
};
});
};
return stakingStore.validators.map((v) => {
const hex = consensusPubkeyToHexAddress(v.consensus_pubkey)
return {
moniker: v.description.moniker,
hex,
base64: toBase64(fromHex(hex))
};
});
@ -62,13 +72,12 @@ const grid = computed(() => {
const window = Number(slashingParam.value.signed_blocks_window || 0);
return validators.map((v) => {
const signing = signingInfo.value[v.hex];
const signing = signingInfo.value[v.base64];
const uptime = signing && window > 0
? (window - Number(signing.missed_blocks_counter)) / window
: undefined
return {
moniker: v.moniker,
hex: v.hex,
base64: v.base64,
blocks: padding(blockColors.value[v.base64] || []),
uptime,
@ -88,6 +97,21 @@ baseStore.$subscribe((_, state) => {
preFill();
preload.value = true;
}
// reset the consumer validators
if (newHeight > 0 && consumerValidators.value.length === 0) {
const chain_id = state.latest.block.header.chain_id;
Promise.resolve().then(async () =>{
await stakingStore.getConsumerValidators(chain_id).then((x) => {
x.validators.forEach(v => {
const base64 = toBase64(fromHex(consensusPubkeyToHexAddress({"@type": "/cosmos.crypto.ed25519.PubKey", key: v.consumer_key.ed25519 })));
const moniker = v.provider_address;
consumerValidators.value.push({ moniker, base64});
});
});
})
}
if (Number(state.latest.block.header.height) % 7 === 0) updateTotalSigningInfo();
fillblock(state.latest);
@ -97,7 +121,6 @@ baseStore.$subscribe((_, state) => {
onMounted(() => {
live.value = true;
// fill the recent blocks
baseStore.recents?.forEach((b) => {
fillblock(b, 'start');
@ -172,9 +195,6 @@ function changeTab(v: string) {
tab.value = v;
}
function fetchAllKeyRotation() {
stakingStore.fetchAllKeyRotation(baseStore.latest?.block?.header?.chain_id)
}
</script>
<template>
@ -192,14 +212,8 @@ function fetchAllKeyRotation() {
<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>
</div>
<div v-if="chainStore.isConsumerChain && Object.keys(stakingStore.keyRotation).length === 0"
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 -->
<div :class="tab === '2' ? '' : 'hidden'">
<div class="flex flex-row flex-wrap gap-x-4 mt-4 justify-center">

View File

@ -146,7 +146,9 @@ export const useBlockchain = defineStore('blockchain', {
// global.current
// }
useWalletStore().$reset();
await useStakingStore().init();
if (!this.isConsumerChain) {
await useStakingStore().init();
}
useBankStore().initial();
useBaseStore().initial();
useGovStore().initial();

View File

@ -130,11 +130,21 @@ export const useStakingStore = defineStore('stakingStore', {
return consensusPubkeyToHexAddress(key)
},
async getConsumerValidators(chain_id: string) {
if(this.blockchain.current?.providerChain?.api && this.blockchain.current.providerChain.api.length > 0) {
const client = CosmosRestClient.newDefault(this.blockchain.current.providerChain.api[0].address)
await client.getStakingValidators('BOND_STATUS_BONDED', 500).then((res) => { this.validators = res.validators });
return client.getInterchainSecurityConsumerValidators(chain_id)
} else {
return { validators: [] }
}
},
async fetchAllKeyRotation(chain_id: string) {
let vs = []
for(const val of this.validators) {
const { prefix } = fromBech32(val.operator_address)
console.log(val, prefix)
await this.fetchKeyRotation(chain_id, pubKeyToValcons(val.consensus_pubkey, prefix.replace('valoper','valcons')))
const cons = pubKeyToValcons(val.consensus_pubkey, prefix.replace('valoper','valcons'))
vs.push(cons)
}
},
async fetchValidators(status: string, limit = 300) {
@ -142,15 +152,24 @@ export const useStakingStore = defineStore('stakingStore', {
if(this.blockchain.current?.providerChain.api && this.blockchain.current.providerChain.api.length > 0) {
const client = CosmosRestClient.newDefault(this.blockchain.current.providerChain.api[0].address)
// provider validators
const res = await client.getStakingValidators(status, limit)
const proVals = res.validators.sort(
(a, b) => Number(b.delegator_shares) - Number(a.delegator_shares)
)
if (status === 'BOND_STATUS_BONDED') {
this.validators = proVals;
}
return proVals
// const baseStore = useBaseStore();
// let chain_id = baseStore.latest?.block?.header?.chain_id
// // fetch chain id if not available
// if (chain_id === undefined) {
// await baseStore.fetchLatest();
// chain_id = baseStore.latest?.block?.header?.chain_id || "unknown";
// }
// const res = await client.getInterchainSecurityConsumerValidators(chain_id)
// const consumerValidators = res.validators.sort(
// (a, b) => Number(b.power) - Number(a.power)
// )
const providerValidators = await client.getStakingValidators(status, limit);
// return consumerValidators.map((val) => {
// providerValidators.validators.find((v) => v.consensus_pubkey === val.provider_address)
// })
return providerValidators;
} else {
console.error("Please provide provider chain api in your chain configuration")
}
}
return this.blockchain.rpc?.getStakingValidators(status, limit).then((res) => {