From 55a78fbd7231dec6a2e3474fec83fed438cf8a91 Mon Sep 17 00:00:00 2001 From: ToniRamirezM Date: Mon, 9 Nov 2020 15:38:41 +0100 Subject: [PATCH] API State Metrics --- api/state.go | 4 ++-- api/state_test.go | 19 +++++++++++++++++++ db/historydb/historydb.go | 34 ++++++++++++++++++++++++++++++++-- db/historydb/views.go | 13 +++++++++++-- 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/api/state.go b/api/state.go index 8ddd9b2..3232f9b 100644 --- a/api/state.go +++ b/api/state.go @@ -130,11 +130,11 @@ func (a *API) GetNextForgers(lastBlock common.Block, currentSlot, lastClosedSlot // UpdateMetrics update Status.Metrics information func (a *API) UpdateMetrics() error { - metrics, err := a.h.GetMetrics() + metrics, err := a.h.GetMetrics(a.status.Network.LastBatch.BatchNum) if err != nil { return err } - a.status.Metrics = metrics + a.status.Metrics = *metrics return nil } diff --git a/api/state_test.go b/api/state_test.go index c2b3443..de3e3cc 100644 --- a/api/state_test.go +++ b/api/state_test.go @@ -77,3 +77,22 @@ func TestUpdateNetworkInfo(t *testing.T) { assert.Equal(t, currentSlotNum, api.status.Network.CurrentSlot) assert.Equal(t, int(api.status.Auction.ClosedAuctionSlots)+1, len(api.status.Network.NextForgers)) } + +func TestUpdateMetrics(t *testing.T) { + // TODO: Improve checks when til is integrated + // Update Metrics needs api.status.Network.LastBatch.BatchNum to be updated + lastBlock := tc.blocks[3] + lastBatchNum := common.BatchNum(3) + currentSlotNum := int64(1) + err := api.UpdateNetworkInfo(lastBlock, lastBatchNum, currentSlotNum) + assert.NoError(t, err) + + err = api.UpdateMetrics() + assert.NoError(t, err) + assert.Greater(t, api.status.Metrics.TransactionsPerBatch, float64(0)) + assert.Greater(t, api.status.Metrics.BatchFrequency, float64(0)) + assert.Greater(t, api.status.Metrics.TransactionsPerBatch, float64(0)) + assert.Greater(t, api.status.Metrics.TotalAccounts, int64(0)) + assert.Greater(t, api.status.Metrics.TotalBJJs, int64(0)) + assert.Greater(t, api.status.Metrics.AvgTransactionFee, float64(0)) +} diff --git a/db/historydb/historydb.go b/db/historydb/historydb.go index 7e057a1..ed1cc6b 100644 --- a/db/historydb/historydb.go +++ b/db/historydb/historydb.go @@ -1484,7 +1484,37 @@ func (hdb *HistoryDB) GetAccountsAPI(tokenIDs []common.TokenID, ethAddr *ethComm } // GetMetrics returns metrics -func (hdb *HistoryDB) GetMetrics() (Metrics, error) { - metrics := Metrics{} +func (hdb *HistoryDB) GetMetrics(lastBatchNum common.BatchNum) (*Metrics, error) { + metricsTotals := &MetricsTotals{} + metrics := &Metrics{} + err := meddler.QueryRow( + hdb.db, metricsTotals, `SELECT COUNT(tx.*) as total_txs, MIN(tx.batch_num) as batch_num + FROM tx INNER JOIN block ON tx.eth_block_num = block.eth_block_num + WHERE block.timestamp >= NOW() - INTERVAL '24 HOURS';`) + if err != nil { + return nil, err + } + + metrics.TransactionsPerSecond = float64(metricsTotals.TotalTransactions / (24 * 60 * 60)) + metrics.TransactionsPerBatch = float64(int64(metricsTotals.TotalTransactions) / int64(lastBatchNum-metricsTotals.FirstBatchNum)) + + err = meddler.QueryRow( + hdb.db, metricsTotals, `SELECT COUNT(*) AS total_batches, + SUM(total_fees_usd) AS total_fees FROM batch + WHERE batch_num > $1;`, metricsTotals.FirstBatchNum) + if err != nil { + return nil, err + } + + metrics.BatchFrequency = float64((24 * 60 * 60) / metricsTotals.TotalBatches) + metrics.AvgTransactionFee = metricsTotals.TotalFeesUSD / float64(metricsTotals.TotalTransactions) + + err = meddler.QueryRow( + hdb.db, metrics, + `SELECT COUNT(*) AS total_bjjs, COUNT(DISTINCT(bjj)) AS total_accounts FROM account;`) + if err != nil { + return nil, err + } + return metrics, nil } diff --git a/db/historydb/views.go b/db/historydb/views.go index 7b89906..c9fc28e 100644 --- a/db/historydb/views.go +++ b/db/historydb/views.go @@ -303,11 +303,20 @@ type Metrics struct { TransactionsPerBatch float64 `json:"transactionsPerBatch"` BatchFrequency float64 `json:"batchFrequency"` TransactionsPerSecond float64 `json:"transactionsPerSecond"` - TotalAccounts int64 `json:"totalAccounts"` - TotalBJJs int64 `json:"totalBJJs"` + TotalAccounts int64 `json:"totalAccounts" meddler:"total_accounts"` + TotalBJJs int64 `json:"totalBJJs" meddler:"total_bjjs"` AvgTransactionFee float64 `json:"avgTransactionFee"` } +// MetricsTotals is used to get temporal information from HistoryDB +// to calculate data to be stored into the Metrics struct +type MetricsTotals struct { + TotalTransactions uint64 `meddler:"total_txs"` + FirstBatchNum common.BatchNum `meddler:"batch_num"` + TotalBatches int64 `meddler:"total_batches"` + TotalFeesUSD float64 `meddler:"total_fees"` +} + // BidAPI is a representation of a bid with additional information // required by the API type BidAPI struct {