diff --git a/hapi/src/services/stats.service.js b/hapi/src/services/stats.service.js
index 63f1b2bb..7b45259e 100644
--- a/hapi/src/services/stats.service.js
+++ b/hapi/src/services/stats.service.js
@@ -6,49 +6,59 @@ const { hasuraUtil, sequelizeUtil, sleepFor, eosUtil } = require('../utils')
const STAT_ID = 'bceb5b75-6cb9-45af-9735-5389e0664847'
-const getTransactionsInTimeRage = async payload => {
- const query = `
- query($start: timestamptz!, $end: timestamptz!) {
- block: block_history_aggregate(
- where: { timestamp: { _gte: $start, _lte: $end } }
- ) {
- info: aggregate {
- sum {
- transactions_length
- }
- }
- }
- }
- `
- const data = await hasuraUtil.request(query, payload)
+const getTransactionsInTimeRage = async (start, end) => {
+ const [rows] = await sequelizeUtil.query(`
+ SELECT
+ sum(transactions_length)::integer as transactions_count
+ FROM
+ block_history
+ WHERE
+ timestamp between '${start.toISOString()}' and '${end.toISOString()}'
+ `)
- return data.block.info.sum.transactions_length || 0
+ return rows?.[0]?.transactions_count || 0
}
-const getNodesSummary = async payload => {
- const query = `
- query {
- producers: producer {
- bp_json
- }
- }
- `
- const data = await hasuraUtil.request(query, payload)
+const getNodesSummary = async () => {
let total = 0
- const totalByType = {}
-
- data.producers.forEach(producer => {
- producer.bp_json.nodes.forEach(node => {
- if (!totalByType[node.node_type]) {
- totalByType[node.node_type] = 0
- }
+ const payload = {}
+ const [rows] = await sequelizeUtil.query(`
+ SELECT
+ value->>'node_type' as node_type,
+ count(*)::integer as nodes_count
+ FROM
+ producer,
+ json_array_elements(to_json(bp_json->'nodes'))
+ GROUP BY
+ value->>'node_type'
+ `)
- totalByType[node.node_type]++
- total++
- })
+ rows.forEach(row => {
+ payload[row.node_type || 'unknown'] = row.nodes_count
+ total += row.nodes_count
})
- return { total, ...totalByType }
+ return { ...payload, total }
+}
+
+const getUniqueLocations = async () => {
+ const [rows] = await sequelizeUtil.query(`
+ SELECT
+ bp_json->'org'->'location'->>'country' as type,
+ count(*)::integer as producers_count,
+ STRING_AGG (owner, ',') as producers
+ FROM
+ producer
+ GROUP BY
+ bp_json->'org'->'location'->>'country'
+ ORDER BY
+ producers_count DESC
+ `)
+
+ return {
+ count: rows?.length || 0,
+ details: rows
+ }
}
const getBlockDistribution = async (range = '1 day') => {
@@ -101,6 +111,7 @@ const getStats = async () => {
transactions_in_last_hour
transactions_in_last_day
transactions_in_last_week
+ average_daily_transactions_in_last_week
last_round
last_block_at
tps_all_time_high
@@ -263,12 +274,6 @@ const syncTPSAllTimeHigh = async () => {
}
const newValue = rows[0]
- const blocks = newValue.blocks.split(',')
-
- for (let index = 0; index < blocks.length; index++) {
- const block = await getBlockUsage(blocks[index])
- blocks[index] = block
- }
if (parseInt(newValue.transactions_count) < lastValue.transactions_count) {
await udpateStats({
@@ -277,10 +282,18 @@ const syncTPSAllTimeHigh = async () => {
checked_at: end.toISOString()
}
})
+ syncTPSAllTimeHigh()
return
}
+ const blocks = newValue.blocks.split(',')
+
+ for (let index = 0; index < blocks.length; index++) {
+ const block = await getBlockUsage(blocks[index])
+ blocks[index] = block
+ }
+
await udpateStats({
tps_all_time_high: {
...newValue,
@@ -293,24 +306,26 @@ const syncTPSAllTimeHigh = async () => {
}
const sync = async () => {
- const transactionsInLastWeek = await getTransactionsInTimeRage({
- start: moment().subtract(1, 'week'),
- end: moment()
- })
+ const transactionsInLastWeek = await getTransactionsInTimeRage(
+ moment().subtract(1, 'week'),
+ moment()
+ )
const payload = {
- transactions_in_last_hour: await getTransactionsInTimeRage({
- start: moment().subtract(1, 'hour'),
- end: moment()
- }),
- transactions_in_last_day: await getTransactionsInTimeRage({
- start: moment().subtract(1, 'day'),
- end: moment()
- }),
+ transactions_in_last_hour: await getTransactionsInTimeRage(
+ moment().subtract(1, 'hour'),
+ moment()
+ ),
+ transactions_in_last_day: await getTransactionsInTimeRage(
+ moment().subtract(1, 'day'),
+ moment()
+ ),
transactions_in_last_week: transactionsInLastWeek,
average_daily_transactions_in_last_week: transactionsInLastWeek / 7,
- nodes_summary: await getNodesSummary()
+ nodes_summary: await getNodesSummary(),
+ unique_locations: await getUniqueLocations()
}
const stats = await getStats()
+
if (stats) {
await udpateStats(payload)
return
diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml
index 001aef13..a9877c6a 100644
--- a/hasura/metadata/tables.yaml
+++ b/hasura/metadata/tables.yaml
@@ -98,5 +98,6 @@
- transactions_in_last_day
- transactions_in_last_hour
- transactions_in_last_week
+ - unique_locations
- updated_at
filter: {}
diff --git a/hasura/migrations/1622180276502_alter_table_public_stat_add_column_unique_locations/down.sql b/hasura/migrations/1622180276502_alter_table_public_stat_add_column_unique_locations/down.sql
new file mode 100644
index 00000000..7005afc1
--- /dev/null
+++ b/hasura/migrations/1622180276502_alter_table_public_stat_add_column_unique_locations/down.sql
@@ -0,0 +1,4 @@
+-- Could not auto-generate a down migration.
+-- Please write an appropriate down migration for the SQL below:
+-- alter table "public"."stat" add column "unique_locations" jsonb
+ null default jsonb_build_object();
diff --git a/hasura/migrations/1622180276502_alter_table_public_stat_add_column_unique_locations/up.sql b/hasura/migrations/1622180276502_alter_table_public_stat_add_column_unique_locations/up.sql
new file mode 100644
index 00000000..c5b2cb09
--- /dev/null
+++ b/hasura/migrations/1622180276502_alter_table_public_stat_add_column_unique_locations/up.sql
@@ -0,0 +1,2 @@
+alter table "public"."stat" add column "unique_locations" jsonb
+ null default jsonb_build_object();
diff --git a/webapp/src/components/TransactionsHistory.js b/webapp/src/components/TransactionsHistory.js
index bc7f728a..8017eab4 100644
--- a/webapp/src/components/TransactionsHistory.js
+++ b/webapp/src/components/TransactionsHistory.js
@@ -69,7 +69,7 @@ const TransactionsHistory = ({ t, classes }) => {
>
{data?.stats?.[0]?.tps_all_time_high?.blocks?.map(
(block, index) => (
- <>
+
{
data?.stats?.[0]?.tps_all_time_high?.blocks.length - 1
? ', '
: ''}
- >
+
)
)}
@@ -126,6 +126,22 @@ const TransactionsHistory = ({ t, classes }) => {
+
+
+
+ {`${t('transactions')} ${t(
+ 'dailyAverage'
+ )}`}
+
+
+
+
+
@@ -139,6 +155,18 @@ const TransactionsHistory = ({ t, classes }) => {
+
+
+
+
+ {`${t('uniqueLocations')}`}
+
+
+
+
>
)
}
diff --git a/webapp/src/gql/producer.gql.js b/webapp/src/gql/producer.gql.js
index 841ab451..05181202 100644
--- a/webapp/src/gql/producer.gql.js
+++ b/webapp/src/gql/producer.gql.js
@@ -89,6 +89,7 @@ export const BLOCK_TRANSACTIONS_HISTORY = gql`
transactions_in_last_week
average_daily_transactions_in_last_week
tps_all_time_high
+ unique_locations
updated_at
}
}
diff --git a/webapp/src/language/en.json b/webapp/src/language/en.json
index 6362d498..33c0c195 100644
--- a/webapp/src/language/en.json
+++ b/webapp/src/language/en.json
@@ -24,6 +24,7 @@
"lastHour": "Last Hour",
"lastDay": "Last Day",
"lastWeek": "Last Week",
+ "dailyAverage":"Daily Average",
"lastYear": "Last Year",
"itemsPerPage": "Items per page",
"api": "API",
@@ -115,7 +116,8 @@
"query": " Query Nodes",
"producer": "Producer Nodes",
"query,seed": "Nodos Query, Seed",
- "undefined": "Undefined Nodes"
+ "undefined": "Undefined Nodes",
+ "uniqueLocations": "Unique Locations"
},
"blockProducersRoute": {},
"rewardsDistributionRoute": {
diff --git a/webapp/src/language/es.json b/webapp/src/language/es.json
index a06d8043..61c72ace 100644
--- a/webapp/src/language/es.json
+++ b/webapp/src/language/es.json
@@ -25,6 +25,7 @@
"lastDay": "Último día",
"lastWeek": "Última semana",
"lastYear": "Último año",
+ "dailyAverage":"Promedio diario",
"itemsPerPage": "Elementos por página",
"api": "API",
"ssl": "SSL",
@@ -123,7 +124,8 @@
"producer": "Nodos Tipo Producer",
"query,seed": "Nodos Query, Seed",
"undefined": "Nodos Indefinidos",
- "transactions": "Transacciones"
+ "transactions": "Transacciones",
+ "uniqueLocations": "Ubicaciones únicas"
},
"blockProducersRoute": {},
"rewardsDistributionRoute": {
diff --git a/webapp/src/models/eos.js b/webapp/src/models/eos.js
index ce884391..156a5ef0 100644
--- a/webapp/src/models/eos.js
+++ b/webapp/src/models/eos.js
@@ -17,8 +17,8 @@ export default {
producers: []
},
info: {},
- tps: [],
- tpb: [],
+ tps: new Array(30).fill({ blocks: [], transactions: 0 }),
+ tpb: new Array(60).fill({ blocks: [], transactions: 0 }),
tpsWaitingBlock: null
},
reducers: {
@@ -31,16 +31,16 @@ export default {
updateTransactionsStats(state, item) {
let tpb = state.tpb
- if (state.tpb.length >= 30) {
- tpb = state.tpb.splice(1, state.tpb.length)
+ if (state.tpb.length >= 60) {
+ tpb.pop()
}
tpb = [
- ...tpb,
{
blocks: [item.block],
transactions: item.transactions
- }
+ },
+ ...tpb
]
if (!state.tpsWaitingBlock) {
@@ -54,15 +54,15 @@ export default {
let tps = state.tps
if (state.tps.length >= 30) {
- tps = state.tps.splice(1, state.tps.length)
+ tps.pop()
}
tps = [
- ...tps,
{
blocks: [state.tpsWaitingBlock.block, item.block],
transactions: state.tpsWaitingBlock.transactions + item.transactions
- }
+ },
+ ...tps
]
return {
diff --git a/webapp/src/routes/Home/TransactionInfo.js b/webapp/src/routes/Home/TransactionInfo.js
index ccef09f8..3608eab6 100644
--- a/webapp/src/routes/Home/TransactionInfo.js
+++ b/webapp/src/routes/Home/TransactionInfo.js
@@ -14,6 +14,7 @@ import CardContent from '@material-ui/core/CardContent'
import Box from '@material-ui/core/Box'
import Typography from '@material-ui/core/Typography'
import PlayArrowIcon from '@material-ui/icons/PlayArrow'
+import LinearProgress from '@material-ui/core/LinearProgress'
import { TRANSACTION_QUERY } from '../../gql'
import { rangeOptions } from '../../utils'
@@ -28,14 +29,22 @@ const TransactionInfo = ({ t, classes }) => {
const theme = useTheme()
const tps = useSelector((state) => state.eos.tps)
const tpb = useSelector((state) => state.eos.tpb)
- const [graphicData, setGraphicData] = useState([])
+ const [graphicData, setGraphicData] = useState([
+ {
+ name: t('transactionsPerSecond'),
+ color: theme.palette.secondary.main
+ },
+ {
+ name: t('transactionsPerBlock'),
+ color: '#00C853'
+ }
+ ])
const [option, setOption] = useState(options[0])
const [pause, setPause] = useState(false)
- const [getTransactionHistory, { data: trxHistory }] =
+ const [getTransactionHistory, { data: trxHistory, loading }] =
useLazyQuery(TRANSACTION_QUERY)
useEffect(() => {
- const majorLength = tps.length > tpb.length ? tps.length : tpb.length
const trxPerSecond = []
const trxPerBlock = []
@@ -43,33 +52,32 @@ const TransactionInfo = ({ t, classes }) => {
return
}
- for (let index = 0; index < majorLength; index++) {
- const labelBlockPS = `Blocks:[${(tps[index]
- ? tps[index].blocks
- : ['']
- ).join()}]`
- const labelBlockPB = `Blocks:[${(tpb[index]
- ? tpb[index].blocks
- : []
- ).join()}]`
-
- trxPerSecond.push([
- labelBlockPS,
- tps[index] ? tps[index].transactions : 0
- ])
- trxPerBlock.push([labelBlockPB, tpb[index] ? tpb[index].transactions : 0])
+ for (let index = 0; index < tpb.length; index++) {
+ trxPerBlock.push({
+ name: `Block: ${tpb[index].blocks.join()}`,
+ y: tpb[index].transactions,
+ x: index > 0 ? index / 2 : index
+ })
+ }
+
+ for (let index = 0; index < tps.length; index++) {
+ trxPerSecond.push({
+ name: `Blocks: ${tps[index].blocks.join(', ')}`,
+ y: tps[index].transactions,
+ x: index
+ })
}
setGraphicData([
{
name: t('transactionsPerSecond'),
color: theme.palette.secondary.main,
- data: trxPerSecond.reverse()
+ data: trxPerSecond
},
{
name: t('transactionsPerBlock'),
color: '#00C853',
- data: trxPerBlock.reverse()
+ data: trxPerBlock
}
])
// eslint-disable-next-line
@@ -80,6 +88,7 @@ const TransactionInfo = ({ t, classes }) => {
return
}
+ setGraphicData([])
getTransactionHistory({
variables: { range: option }
})
@@ -94,7 +103,6 @@ const TransactionInfo = ({ t, classes }) => {
if (!trxHistory?.transactions?.length) {
setGraphicData([])
-
return
}
@@ -143,7 +151,7 @@ const TransactionInfo = ({ t, classes }) => {
)}
option === options[0].value && setPause(!pause)}
+ onClick={() => option === options[0] && setPause(!pause)}
className={clsx(classes.pauseButton, {
[classes.disableButton]: option !== options[0]
})}
@@ -155,7 +163,7 @@ const TransactionInfo = ({ t, classes }) => {
width={20}
height={20}
color={
- option !== options[0].value
+ option !== options[0]
? theme.palette.action.disabled
: theme.palette.common.black
}
@@ -165,7 +173,7 @@ const TransactionInfo = ({ t, classes }) => {
-
+ {loading && }