Skip to content

Commit

Permalink
Implement /emerald/stats/tx_volume
Browse files Browse the repository at this point in the history
  • Loading branch information
mitjat committed Jan 26, 2023
1 parent e0f008b commit ecd2101
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 20 deletions.
17 changes: 15 additions & 2 deletions api/spec/v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -804,13 +804,22 @@ paths:
$ref: '#/components/schemas/RuntimeTokenList'
<<: *common_error_responses

/consensus/stats/tx_volume:
/{layer}/stats/tx_volume:
get:
summary: Returns the consensus layer transaction volume at daily granularity
summary: |
Returns a timeline of the transaction volume at the chosen granularity,
for either consensus or one of the paratimes.
parameters:
- *limit
- *offset
- *bucket_size_seconds
- in: path
name: layer
required: true
schema:
$ref: '#/components/schemas/Layer'
description: |
The layer for which to return the transaction volume timeline.
responses:
'200':
description: |
Expand All @@ -823,6 +832,10 @@ paths:

components:
schemas:
Layer:
type: string
enum: [consensus, emerald]

Status:
type: object
required: [latest_chain_id, latest_block, latest_update]
Expand Down
11 changes: 8 additions & 3 deletions api/v1/strict_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,17 @@ func (srv *StrictServerImpl) GetConsensusProposalsProposalIdVotes(ctx context.Co
return apiTypes.GetConsensusProposalsProposalIdVotes200JSONResponse(*votes), nil
}

func (srv *StrictServerImpl) GetConsensusStatsTxVolume(ctx context.Context, request apiTypes.GetConsensusStatsTxVolumeRequestObject) (apiTypes.GetConsensusStatsTxVolumeResponseObject, error) {
volumeList, err := srv.dbClient.TxVolumes(ctx, request.Params)
func (srv *StrictServerImpl) GetLayerStatsTxVolume(ctx context.Context, request apiTypes.GetLayerStatsTxVolumeRequestObject) (apiTypes.GetLayerStatsTxVolumeResponseObject, error) {
// Additional param validation.
if !request.Layer.IsValid() {
return nil, &apiTypes.InvalidParamFormatError{ParamName: "layer", Err: fmt.Errorf("not a valid enum value: %s", request.Layer)}
}

volumeList, err := srv.dbClient.TxVolumes(ctx, request.Layer, request.Params)
if err != nil {
return nil, err
}
return apiTypes.GetConsensusStatsTxVolume200JSONResponse(*volumeList), nil
return apiTypes.GetLayerStatsTxVolume200JSONResponse(*volumeList), nil
}

func (srv *StrictServerImpl) GetConsensusTransactions(ctx context.Context, request apiTypes.GetConsensusTransactionsRequestObject) (apiTypes.GetConsensusTransactionsResponseObject, error) {
Expand Down
9 changes: 9 additions & 0 deletions api/v1/types/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,12 @@ func (c ConsensusEventType) IsValid() bool {
return false
}
}

func (c Layer) IsValid() bool {
switch c {
case LayerConsensus, LayerEmerald:
return true
default:
return false
}
}
9 changes: 3 additions & 6 deletions storage/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1455,12 +1455,8 @@ func (c *StorageClient) RuntimeTokens(ctx context.Context, p apiTypes.GetEmerald
}

// TxVolumes returns a list of transaction volumes per time bucket.
func (c *StorageClient) TxVolumes(ctx context.Context, p apiTypes.GetConsensusStatsTxVolumeParams) (*TxVolumeList, error) {
if p.BucketSizeSeconds == nil {
return nil, fmt.Errorf("bucket_size_seconds default was not applied") // double-check middleware's job
}

qf := NewQueryFactory(strcase.ToSnake(c.chainID), "")
func (c *StorageClient) TxVolumes(ctx context.Context, layer apiTypes.Layer, p apiTypes.GetLayerStatsTxVolumeParams) (*TxVolumeList, error) {
qf := NewQueryFactory(strcase.ToSnake(c.chainID), string(layer))
var query string
if *p.BucketSizeSeconds == 300 {
query = qf.FineTxVolumesQuery()
Expand All @@ -1473,6 +1469,7 @@ func (c *StorageClient) TxVolumes(ctx context.Context, p apiTypes.GetConsensusSt
rows, err := c.db.Query(
ctx,
query,
layer,
p.Limit,
p.Offset,
)
Expand Down
14 changes: 8 additions & 6 deletions storage/client/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,21 +357,23 @@ func (qf QueryFactory) RuntimeTokensQuery() string {
func (qf QueryFactory) FineTxVolumesQuery() string {
return `
SELECT window_start, tx_volume
FROM stats.min5_tx_volume
FROM stats.min5_tx_volume
WHERE layer = $1::text
ORDER BY
window_start DESC
LIMIT $1::bigint
OFFSET $2::bigint
LIMIT $2::bigint
OFFSET $3::bigint
`
}

func (qf QueryFactory) TxVolumesQuery() string {
return `
SELECT window_start, tx_volume
FROM stats.daily_tx_volume
FROM stats.daily_tx_volume
WHERE layer = $1::text
ORDER BY
window_start DESC
LIMIT $1::bigint
OFFSET $2::bigint
LIMIT $2::bigint
OFFSET $3::bigint
`
}
18 changes: 15 additions & 3 deletions storage/migrations/03_agg_stats.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,32 @@ GRANT EXECUTE ON FUNCTION floor_5min TO PUBLIC;
-- NOTE: This materialized view is NOT refreshed every 5 minutes due to computational cost.
CREATE MATERIALIZED VIEW stats.min5_tx_volume AS
SELECT
'consensus' AS layer,
floor_5min(b.time) AS window_start,
COUNT(*) AS tx_volume
FROM oasis_3.blocks AS b
INNER JOIN oasis_3.transactions AS t ON b.height = t.block
GROUP BY 1;
JOIN oasis_3.transactions AS t ON b.height = t.block
GROUP BY 2

UNION ALL

SELECT
'emerald' AS layer,
floor_5min(b.timestamp) AS window_start,
COUNT(*) AS tx_volume
FROM oasis_3.emerald_rounds AS b
JOIN oasis_3.emerald_transactions AS t ON b.round = t.round
GROUP BY 2;

-- daily_tx_volume stores the number of transactions per day
-- at the consensus layer.
CREATE MATERIALIZED VIEW stats.daily_tx_volume AS
SELECT
layer,
date_trunc ( 'day', sub.window_start ) AS window_start,
SUM(sub.tx_volume) AS tx_volume
FROM stats.min5_tx_volume AS sub
GROUP BY 1;
GROUP BY 1, 2;


-- Grant others read-only use. This does NOT apply to future tables in the schema.
Expand Down

0 comments on commit ecd2101

Please sign in to comment.