From ce0c9901d260567a6f6b73221ac71d6aa2caf4fc Mon Sep 17 00:00:00 2001 From: maximilien-hyle Date: Mon, 23 Jun 2025 18:40:09 +0200 Subject: [PATCH 1/3] Add stats for dp --- src/explorer/NetworkStats.vue | 54 +++- src/explorer/ValidatorDetail.vue | 444 +++++++++++++++++++++++++++++++ src/main.ts | 6 + 3 files changed, 499 insertions(+), 5 deletions(-) create mode 100644 src/explorer/ValidatorDetail.vue diff --git a/src/explorer/NetworkStats.vue b/src/explorer/NetworkStats.vue index b3145e1..543a7c2 100644 --- a/src/explorer/NetworkStats.vue +++ b/src/explorer/NetworkStats.vue @@ -351,7 +351,7 @@ const handleValidatorLeave = () => {
@@ -383,17 +383,20 @@ const handleValidatorLeave = () => {
Validator Balances & Data Dissemination
-
+ + +

{{ cluster.name }}

-
@@ -427,10 +430,51 @@ const handleValidatorLeave = () => { }}
-
+
+ + +
+
+ +
+
+ {{ validator.slice(0, 10) }}...{{ validator.slice(-6) }} +
+
+ Disseminated: {{ formatBytes(stakingState?.fees.balances[validator]?.cumul_size || 0) }} +
+
+
+
+
+
+
+ Balance: + {{ formatNumber(stakingState?.fees.balances[validator]?.balance || 0) }} HYL +
+
+ Stake: + {{ formatNumber(stakingState.stakes[validator] || 0) }} +
+
+
+
+
Loading staking data...
diff --git a/src/explorer/ValidatorDetail.vue b/src/explorer/ValidatorDetail.vue new file mode 100644 index 0000000..a390964 --- /dev/null +++ b/src/explorer/ValidatorDetail.vue @@ -0,0 +1,444 @@ + + + + + diff --git a/src/main.ts b/src/main.ts index 98ac870..89a4211 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,6 +12,7 @@ import Proofs from "./explorer/Proofs.vue"; import NetworkStats from "./explorer/NetworkStats.vue"; import Dashboard from "./explorer/Dashboard.vue"; import Address from "./explorer/Address.vue"; +import ValidatorDetail from "./explorer/ValidatorDetail.vue"; const routes = [ { path: "/", component: Home, name: "Home" }, @@ -60,6 +61,11 @@ const routes = [ component: Address, name: "Address", }, + { + path: "/validator/:validator_id", + component: ValidatorDetail, + name: "ValidatorDetail", + }, ]; const router = createRouter({ From cef0abec7f2ad61c45cfa1169fbe03a5b4e0070c Mon Sep 17 00:00:00 2001 From: maximilien-hyle Date: Wed, 25 Jun 2025 16:17:42 +0200 Subject: [PATCH 2/3] validator to lane manager --- src/explorer/ValidatorDetail.vue | 46 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/explorer/ValidatorDetail.vue b/src/explorer/ValidatorDetail.vue index a390964..7b712a3 100644 --- a/src/explorer/ValidatorDetail.vue +++ b/src/explorer/ValidatorDetail.vue @@ -21,9 +21,9 @@ interface DataProposal { const route = useRoute(); const router = useRouter(); -const validatorId = computed(() => route.params.validator_id as string); +const laneManagerId = computed(() => route.params.validator_id as string); -const validatorInfo = ref<{ +const laneManagerInfo = ref<{ id: string; balance: number; cumul_size: number; @@ -53,34 +53,34 @@ const formatBytes = (bytes: number): string => { return (bytes / Math.pow(k, i)).toFixed(2) + " " + sizes[i]; }; -const fetchValidatorInfo = async () => { +const fetchLaneManagerInfo = async () => { try { const response = await fetch(getNetworkNodeApiUrl(network.value) + `/v1/consensus/staking_state?no_cache=${Date.now()}`); const stakingState = await response.json(); - if (stakingState?.fees?.balances[validatorId.value]) { - validatorInfo.value = { - id: validatorId.value, - balance: stakingState.fees.balances[validatorId.value].balance, - cumul_size: stakingState.fees.balances[validatorId.value].cumul_size, + if (stakingState?.fees?.balances[laneManagerId.value]) { + laneManagerInfo.value = { + id: laneManagerId.value, + balance: stakingState.fees.balances[laneManagerId.value].balance, + cumul_size: stakingState.fees.balances[laneManagerId.value].cumul_size, delegated: 0, // TODO: Calculate delegated amount }; } } catch (err) { - console.error("Error fetching validator info:", err); - error.value = "Failed to fetch validator information"; + console.error("Error fetching lane manager info:", err); + error.value = "Failed to fetch lane manager information"; } }; const fetchDataProposals = async () => { try { const response = await fetch( - getNetworkIndexerApiUrl(network.value) + `/v1/indexer/data_proposals/lane/${validatorId.value}?no_cache=${Date.now()}`, + getNetworkIndexerApiUrl(network.value) + `/v1/indexer/data_proposals/lane/${laneManagerId.value}?no_cache=${Date.now()}`, ); if (response.ok) { dataProposals.value = await response.json(); } else { - console.warn("No data proposals found for this validator"); + console.warn("No data proposals found for this lane manager"); } } catch (err) { console.error("Error fetching data proposals:", err); @@ -125,7 +125,7 @@ const toggleProposal = async (proposalHash: string) => { onMounted(async () => { loading.value = true; try { - await Promise.all([fetchValidatorInfo(), fetchDataProposals()]); + await Promise.all([fetchLaneManagerInfo(), fetchDataProposals()]); } finally { loading.value = false; } @@ -152,12 +152,12 @@ const totalTransactions = computed(() => dataProposals.value.reduce((sum, p) =>
-

Validator Details

-

Comprehensive information about validator activity

+

Lane Manager Details

+

Comprehensive information about lane manager activity

- +
@@ -168,11 +168,11 @@ const totalTransactions = computed(() => dataProposals.value.reduce((sum, p) => d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /> -

Validator ID

+

Lane Manager ID

- {{ validatorId }} - + {{ laneManagerId }} +
@@ -190,7 +190,7 @@ const totalTransactions = computed(() => dataProposals.value.reduce((sum, p) =>
- +
@@ -205,7 +205,7 @@ const totalTransactions = computed(() => dataProposals.value.reduce((sum, p) =>

Balance

- {{ validatorInfo ? formatNumber(validatorInfo.balance) : "0" }} HYL + {{ laneManagerInfo ? formatNumber(laneManagerInfo.balance) : "0" }} HYL

@@ -222,7 +222,7 @@ const totalTransactions = computed(() => dataProposals.value.reduce((sum, p) =>

Data Disseminated

- {{ validatorInfo ? formatBytes(validatorInfo.cumul_size) : "0 B" }} + {{ laneManagerInfo ? formatBytes(laneManagerInfo.cumul_size) : "0 B" }}

@@ -270,7 +270,7 @@ const totalTransactions = computed(() => dataProposals.value.reduce((sum, p) =>
- No data proposals found for this validator + No data proposals found for this lane manager
From e12f776e0bd5b45ecb4e3014196636170d2d8214 Mon Sep 17 00:00:00 2001 From: maximilien-hyle Date: Wed, 25 Jun 2025 18:58:06 +0200 Subject: [PATCH 3/3] rename + random fix --- ...idatorDetail.vue => LaneManagerDetail.vue} | 99 ++++++++++++++----- src/explorer/NetworkStats.vue | 4 +- src/main.ts | 8 +- 3 files changed, 81 insertions(+), 30 deletions(-) rename src/explorer/{ValidatorDetail.vue => LaneManagerDetail.vue} (85%) diff --git a/src/explorer/ValidatorDetail.vue b/src/explorer/LaneManagerDetail.vue similarity index 85% rename from src/explorer/ValidatorDetail.vue rename to src/explorer/LaneManagerDetail.vue index 7b712a3..8570021 100644 --- a/src/explorer/ValidatorDetail.vue +++ b/src/explorer/LaneManagerDetail.vue @@ -21,7 +21,7 @@ interface DataProposal { const route = useRoute(); const router = useRouter(); -const laneManagerId = computed(() => route.params.validator_id as string); +const laneManagerId = computed(() => route.params.lane_manager_id as string); const laneManagerInfo = ref<{ id: string; @@ -34,6 +34,7 @@ const dataProposals = ref([]); const loading = ref(false); const error = ref(""); const expandedProposals = ref>(new Set()); +const loadingTransactions = ref>(new Set()); // Format number to human readable format const formatNumber = (num: number): string => { @@ -79,6 +80,8 @@ const fetchDataProposals = async () => { ); if (response.ok) { dataProposals.value = await response.json(); + // Charger automatiquement les transactions pour chaque data proposal + await fetchAllProposalTransactions(); } else { console.warn("No data proposals found for this lane manager"); } @@ -87,7 +90,20 @@ const fetchDataProposals = async () => { } }; +const fetchAllProposalTransactions = async () => { + // Charger les transactions pour tous les data proposals en parallèle + const promises = dataProposals.value.map((proposal) => fetchProposalTransactions(proposal.hash)); + await Promise.all(promises); +}; + const fetchProposalTransactions = async (proposalHash: string) => { + // Éviter les appels multiples pour le même proposal + if (loadingTransactions.value.has(proposalHash)) { + return; + } + + loadingTransactions.value.add(proposalHash); + try { const response = await fetch( getNetworkIndexerApiUrl(network.value) + `/v1/indexer/data_proposal/hash/${proposalHash}/transactions?no_cache=${Date.now()}`, @@ -103,22 +119,31 @@ const fetchProposalTransactions = async (proposalHash: string) => { transactionStore.value.data[tx.tx_hash] = tx; }); } + } else { + console.warn(`No transactions found for proposal ${proposalHash}`); + // Marquer comme tableau vide pour éviter de refaire l'appel + const proposal = dataProposals.value.find((p) => p.hash === proposalHash); + if (proposal) { + proposal.transactions = []; + } } } catch (err) { console.error("Error fetching proposal transactions:", err); + // Marquer comme tableau vide en cas d'erreur pour éviter de refaire l'appel + const proposal = dataProposals.value.find((p) => p.hash === proposalHash); + if (proposal) { + proposal.transactions = []; + } + } finally { + loadingTransactions.value.delete(proposalHash); } }; -const toggleProposal = async (proposalHash: string) => { +const toggleProposal = (proposalHash: string) => { if (expandedProposals.value.has(proposalHash)) { expandedProposals.value.delete(proposalHash); } else { expandedProposals.value.add(proposalHash); - // Fetch transactions for this proposal if not already loaded - const proposal = dataProposals.value.find((p) => p.hash === proposalHash); - if (proposal && !proposal.transactions) { - await fetchProposalTransactions(proposalHash); - } } }; @@ -131,9 +156,10 @@ onMounted(async () => { } }); -// Computed properties for statistics -const totalProposals = computed(() => dataProposals.value.length); -const totalTransactions = computed(() => dataProposals.value.reduce((sum, p) => sum + p.tx_count, 0)); +// Computed properties for filtering and statistics +const filteredDataProposals = computed(() => dataProposals.value.filter((proposal) => proposal.block_height !== 0)); +const totalProposals = computed(() => filteredDataProposals.value.length); +const totalTransactions = computed(() => filteredDataProposals.value.reduce((sum, p) => sum + p.tx_count, 0));