Skip to content

Commit

Permalink
Unify stats across relevant pages (#2561)
Browse files Browse the repository at this point in the history
* Unify stats across relevant pages

* add op stats to tx page and change stats titles

* demo config

* aboba or cat fix

* chart tooltip fix

* tests

* revert config
  • Loading branch information
isstuev authored Feb 13, 2025
1 parent 06e5313 commit 67a0d0e
Show file tree
Hide file tree
Showing 32 changed files with 746 additions and 343 deletions.
26 changes: 24 additions & 2 deletions deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -726,12 +726,34 @@ const schema = yup
.array()
.transform(replaceQuotes)
.json()
.of(yup.string<ChainIndicatorId>().oneOf(CHAIN_INDICATOR_IDS)),
.of(yup.string<ChainIndicatorId>().oneOf(CHAIN_INDICATOR_IDS))
.test(
'stats-api-required',
'NEXT_PUBLIC_STATS_API_HOST is required when daily_operational_txs is enabled in NEXT_PUBLIC_HOMEPAGE_CHARTS',
function(value) {
// daily_operational_txs is presented only in stats microservice
if (value?.includes('daily_operational_txs')) {
return Boolean(this.parent.NEXT_PUBLIC_STATS_API_HOST);
}
return true;
}
),
NEXT_PUBLIC_HOMEPAGE_STATS: yup
.array()
.transform(replaceQuotes)
.json()
.of(yup.string<HomeStatsWidgetId>().oneOf(HOME_STATS_WIDGET_IDS)),
.of(yup.string<HomeStatsWidgetId>().oneOf(HOME_STATS_WIDGET_IDS))
.test(
'stats-api-required',
'NEXT_PUBLIC_STATS_API_HOST is required when total_operational_txs is enabled in NEXT_PUBLIC_HOMEPAGE_STATS',
function(value) {
// total_operational_txs is presented only in stats microservice
if (value?.includes('total_operational_txs')) {
return Boolean(this.parent.NEXT_PUBLIC_STATS_API_HOST);
}
return true;
}
),
NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR: yup.string(),
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND: yup.string(),
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG: yup
Expand Down
4 changes: 2 additions & 2 deletions docs/ENVS.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will

| Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_HOMEPAGE_CHARTS | `Array<'daily_txs' \| 'coin_price' \| 'secondary_coin_price' \| 'market_cap' \| 'tvl'>` | List of charts displayed on the home page | - | - | `['daily_txs','coin_price','market_cap']` | v1.0.x+ |
| NEXT_PUBLIC_HOMEPAGE_STATS | `Array<'latest_batch' \| 'total_blocks' \| 'average_block_time' \| 'total_txs' \| 'latest_l1_state_batch' \| 'wallet_addresses' \| 'gas_tracker' \| 'btc_locked' \| 'current_epoch'>` | List of stats widgets displayed on the home page | - | For zkSync, zkEvm and Arbitrum rollups: `['latest_batch','average_block_time','total_txs','wallet_addresses','gas_tracker']`, for other cases: `['total_blocks','average_block_time','total_txs','wallet_addresses','gas_tracker']` | `['total_blocks','total_txs','wallet_addresses']` | v1.35.x+ |
| NEXT_PUBLIC_HOMEPAGE_CHARTS | `Array<'daily_txs' \| 'daily_operational_txs' \| 'coin_price' \| 'secondary_coin_price' \| 'market_cap' \| 'tvl'>` | List of charts displayed on the home page | - | - | `['daily_txs','coin_price','market_cap']` | v1.0.x+ |
| NEXT_PUBLIC_HOMEPAGE_STATS | `Array<'latest_batch' \| 'total_blocks' \| 'average_block_time' \| 'total_txs' \| 'total_operational_txs' \| 'latest_l1_state_batch' \| 'wallet_addresses' \| 'gas_tracker' \| 'btc_locked' \| 'current_epoch'>` | List of stats widgets displayed on the home page | - | For zkSync, zkEvm and Arbitrum rollups: `['latest_batch','average_block_time','total_txs','wallet_addresses','gas_tracker']`, for other cases: `['total_blocks','average_block_time','total_txs','wallet_addresses','gas_tracker']` | `['total_blocks','total_txs','wallet_addresses']` | v1.35.x+ |
| NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR | `string` | Text color of the hero plate on the homepage (escape "#" symbol if you use HEX color codes or use rgba-value instead). **DEPRECATED** _Use `NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG` instead_ | - | `white` | `\#DCFE76` | v1.0.x+ |
| NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND | `string` | Background css value for hero plate on the homepage (escape "#" symbol if you use HEX color codes or use rgba-value instead). **DEPRECATED** _Use `NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG` instead_ | - | `radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%), var(--chakra-colors-blue-400)` | `radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%)` \| `no-repeat bottom 20% right 0px/100% url(https://placekitten/1400/200)` | v1.1.0+ |
| NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG | `HeroBannerConfig`, see details [below](#hero-banner-configuration-properties) | Configuration of hero banner appearance. | - | - | See [below](#hero-banner-configuration-properties) | v1.35.0+ |
Expand Down
18 changes: 18 additions & 0 deletions lib/api/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,21 @@ export const RESOURCES = {
endpoint: getFeaturePayload(config.features.stats)?.api.endpoint,
basePath: getFeaturePayload(config.features.stats)?.api.basePath,
},
stats_main: {
path: '/api/v1/pages/main',
endpoint: getFeaturePayload(config.features.stats)?.api.endpoint,
basePath: getFeaturePayload(config.features.stats)?.api.basePath,
},
stats_transactions: {
path: '/api/v1/pages/transactions',
endpoint: getFeaturePayload(config.features.stats)?.api.endpoint,
basePath: getFeaturePayload(config.features.stats)?.api.basePath,
},
stats_contracts: {
path: '/api/v1/pages/contracts',
endpoint: getFeaturePayload(config.features.stats)?.api.endpoint,
basePath: getFeaturePayload(config.features.stats)?.api.basePath,
},

// NAME SERVICE
addresses_lookup: {
Expand Down Expand Up @@ -1481,6 +1496,9 @@ Q extends 'advanced_filter' ? AdvancedFilterResponse :
Q extends 'advanced_filter_methods' ? AdvancedFilterMethodsResponse :
Q extends 'pools' ? PoolsResponse :
Q extends 'pool' ? Pool :
Q extends 'stats_main' ? stats.MainPageStats :
Q extends 'stats_transactions' ? stats.TransactionsPageStats :
Q extends 'stats_contracts' ? stats.ContractsPageStats :
never;
/* eslint-enable @stylistic/indent */

Expand Down
71 changes: 71 additions & 0 deletions mocks/stats/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type * as stats from '@blockscout/stats-types';

import { averageGasPrice } from './line';

export const base: stats.MainPageStats = {
average_block_time: {
id: 'averageBlockTime',
value: '14.909090909090908',
title: 'Average block time',
units: 's',
description: 'Average time taken in seconds for a block to be included in the blockchain',
},
total_addresses: {
id: 'totalAddresses',
value: '113606435',
title: 'Total addresses',
description: 'Number of addresses that participated in the blockchain',
},
total_blocks: {
id: 'totalBlocks',
value: '7660515',
title: 'Total blocks',
description: 'Number of blocks over all time',
},
total_transactions: {
id: 'totalTxns',
value: '411264599',
title: 'Total txns',
description: 'All transactions including pending, dropped, replaced, failed transactions',
},
yesterday_transactions: {
id: 'yesterdayTxns',
value: '213019',
title: 'Yesterday txns',
description: 'Number of transactions yesterday (0:00 - 23:59 UTC)',
},
total_operational_transactions: {
id: 'totalOperationalTxns',
value: '403598877',
title: 'Total operational txns',
description: '\'Total txns\' without block creation transactions',
},
yesterday_operational_transactions: {
id: 'yesterdayOperationalTxns',
value: '210852',
title: 'Yesterday operational txns',
description: 'Number of transactions yesterday (0:00 - 23:59 UTC) without block creation transactions',
},
daily_new_transactions: {
chart: averageGasPrice.chart,
info: {
id: 'newTxnsWindow',
title: 'Daily transactions',
description: 'The chart displays daily transactions for the past 30 days',
resolutions: [
'DAY',
],
},
},
daily_new_operational_transactions: {
chart: averageGasPrice.chart,
info: {
id: 'newOperationalTxnsWindow',
title: 'Daily operational transactions',
description: 'The chart displays daily transactions for the past 30 days (without block creation transactions)',
resolutions: [
'DAY',
],
},
},
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
},
"dependencies": {
"@blockscout/bens-types": "1.4.1",
"@blockscout/stats-types": "2.0.0",
"@blockscout/stats-types": "2.5.0-alpha",
"@blockscout/visualizer-types": "0.2.0",
"@chakra-ui/react": "2.7.1",
"@chakra-ui/theme-tools": "^2.0.18",
Expand Down
9 changes: 9 additions & 0 deletions stubs/contract.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type * as stats from '@blockscout/stats-types';
import type { SmartContract, SmartContractMudSystemsResponse } from 'types/api/contract';
import type { VerifiedContract, VerifiedContractsCounters } from 'types/api/contracts';

import type { SolidityScanReport } from 'lib/solidityScan/schema';

import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams';
import { STATS_COUNTER } from './stats';

export const CONTRACT_CODE_UNVERIFIED = {
creation_bytecode: '0x60806040526e',
Expand Down Expand Up @@ -81,6 +83,13 @@ export const VERIFIED_CONTRACTS_COUNTERS: VerifiedContractsCounters = {
new_verified_smart_contracts_24h: '1234',
};

export const VERIFIED_CONTRACTS_COUNTERS_MICROSERVICE: stats.ContractsPageStats = {
total_contracts: STATS_COUNTER,
new_contracts_24h: STATS_COUNTER,
total_verified_contracts: STATS_COUNTER,
new_verified_contracts_24h: STATS_COUNTER,
};

export const SOLIDITY_SCAN_REPORT: SolidityScanReport = {
scan_report: {
contractname: 'BullRunners',
Expand Down
34 changes: 27 additions & 7 deletions stubs/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,19 @@ export const HOMEPAGE_STATS: HomeStats = {
tvl: '1767425.102766552',
};

const STATS_CHART_INFO: stats.LineChartInfo = {
id: 'chart_0',
title: 'Average transaction fee',
description: 'The average amount in ETH spent per transaction',
units: 'ETH',
resolutions: [ 'DAY', 'MONTH' ],
};

export const STATS_CHARTS_SECTION: stats.LineChartSection = {
id: 'placeholder',
title: 'Placeholder',
charts: [
{
id: 'chart_0',
title: 'Average transaction fee',
description: 'The average amount in ETH spent per transaction',
units: 'ETH',
resolutions: [ 'DAY', 'MONTH' ],
},
STATS_CHART_INFO,
{
id: 'chart_1',
title: 'Transactions fees',
Expand Down Expand Up @@ -88,3 +90,21 @@ export const STATS_COUNTER: stats.Counter = {
description: 'Placeholder description',
units: '',
};

export const HOMEPAGE_STATS_MICROSERVICE: stats.MainPageStats = {
average_block_time: STATS_COUNTER,
total_addresses: STATS_COUNTER,
total_blocks: STATS_COUNTER,
total_transactions: STATS_COUNTER,
yesterday_transactions: STATS_COUNTER,
total_operational_transactions: STATS_COUNTER,
yesterday_operational_transactions: STATS_COUNTER,
daily_new_transactions: {
chart: [],
info: STATS_CHART_INFO,
},
daily_new_operational_transactions: {
chart: [],
info: STATS_CHART_INFO,
},
};
10 changes: 10 additions & 0 deletions stubs/tx.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type * as stats from '@blockscout/stats-types';
import type { RawTracesResponse } from 'types/api/rawTrace';
import type { Transaction, TransactionsStats } from 'types/api/transaction';

import { ADDRESS_PARAMS } from './addressParams';
import { STATS_COUNTER } from './stats';

export const TX_HASH = '0x3ed9d81e7c1001bdda1caa1dc62c0acbbe3d2c671cdc20dc1e65efdaa4186967';

Expand Down Expand Up @@ -66,3 +68,11 @@ export const TXS_STATS: TransactionsStats = {
transaction_fees_sum_24h: '22184012506492688277',
transactions_count_24h: '992890',
};

export const TXS_STATS_MICROSERVICE: stats.TransactionsPageStats = {
pending_transactions_30m: STATS_COUNTER,
transactions_24h: STATS_COUNTER,
operational_transactions_24h: STATS_COUNTER,
transactions_fee_24h: STATS_COUNTER,
average_transactions_fee_24h: STATS_COUNTER,
};
3 changes: 2 additions & 1 deletion types/homepage.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
export const CHAIN_INDICATOR_IDS = [ 'daily_txs', 'coin_price', 'secondary_coin_price', 'market_cap', 'tvl' ] as const;
export const CHAIN_INDICATOR_IDS = [ 'daily_txs', 'daily_operational_txs', 'coin_price', 'secondary_coin_price', 'market_cap', 'tvl' ] as const;
export type ChainIndicatorId = typeof CHAIN_INDICATOR_IDS[number];

export const HOME_STATS_WIDGET_IDS = [
'latest_batch',
'total_blocks',
'average_block_time',
'total_txs',
'total_operational_txs',
'latest_l1_state_batch',
'wallet_addresses',
'gas_tracker',
Expand Down
8 changes: 7 additions & 1 deletion ui/home/Stats.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ test.describe('all items', () => {
test.beforeEach(async({ render, mockApiResponse, mockEnvs }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_HOMEPAGE_STATS', '["total_blocks","average_block_time","total_txs","wallet_addresses","gas_tracker","btc_locked"]' ],
[ 'NEXT_PUBLIC_STATS_API_HOST', '' ],
]);
await mockApiResponse('stats', statsMock.withBtcLocked);
component = await render(<Stats/>);
Expand All @@ -22,7 +23,10 @@ test.describe('all items', () => {
});
});

test('no gas info', async({ render, mockApiResponse }) => {
test('no gas info', async({ render, mockApiResponse, mockEnvs }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_STATS_API_HOST', '' ],
]);
await mockApiResponse('stats', statsMock.withoutGasInfo);
const component = await render(<Stats/>);

Expand All @@ -32,6 +36,7 @@ test('no gas info', async({ render, mockApiResponse }) => {
test('4 items default view +@mobile -@default', async({ render, mockApiResponse, mockEnvs }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_HOMEPAGE_STATS', '["total_txs","gas_tracker","wallet_addresses","total_blocks"]' ],
[ 'NEXT_PUBLIC_STATS_API_HOST', '' ],
]);
await mockApiResponse('stats', statsMock.base);
const component = await render(<Stats/>);
Expand All @@ -41,6 +46,7 @@ test('4 items default view +@mobile -@default', async({ render, mockApiResponse,
test('3 items default view +@mobile -@default', async({ render, mockApiResponse, mockEnvs }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_HOMEPAGE_STATS', '["total_txs","wallet_addresses","total_blocks"]' ],
[ 'NEXT_PUBLIC_STATS_API_HOST', '' ],
]);
await mockApiResponse('stats', statsMock.base);
const component = await render(<Stats/>);
Expand Down
Loading

0 comments on commit 67a0d0e

Please sign in to comment.