Skip to content

Commit 445e59e

Browse files
authored
include latest round in dashboard for DA finance (#2496)
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
1 parent 3b1aa30 commit 445e59e

File tree

2 files changed

+107
-49
lines changed

2 files changed

+107
-49
lines changed

apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/ScanTotalSupplyBigQueryIntegrationTest.scala

Lines changed: 83 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import com.digitalasset.canton.resource.DbStorage
1010
import com.digitalasset.canton.topology.PartyId
1111
import com.digitalasset.daml.lf.data.Time.Timestamp as LfTimestamp
1212
import com.google.cloud.bigquery as bq
13-
import bq.{Field, JobInfo, Schema, TableId}
13+
import bq.{Field, FieldValueList, JobInfo, Schema, TableId, TableResult}
1414
import bq.storage.v1.{JsonStreamWriter, TableSchema}
1515
import slick.jdbc.canton.ActionBasedSQLInterpolation.Implicits.*
1616
import slick.jdbc.GetResult
@@ -83,6 +83,7 @@ class ScanTotalSupplyBigQueryIntegrationTest
8383
// The peak is 17 transactions in a (simulated) minute, or 0.28333 tps over a minute,
8484
// so we assert 15-20 transactions, or 0.25-0.34 tps
8585
private val peakTps = (0.25, 0.34)
86+
private val totalRounds = 4
8687

8788
override def beforeAll() = {
8889
super.beforeAll()
@@ -152,12 +153,14 @@ class ScanTotalSupplyBigQueryIntegrationTest
152153
createBigQueryFunctions()
153154
}
154155

155-
val results = withClue("running total supply queries in BigQuery") {
156-
runTotalSupplyQueries()
156+
withClue("testing total supply queries in BigQuery") {
157+
val results = runDashboardQueries()
158+
verifyDashboardResults(results)
157159
}
158160

159-
withClue(s"verify total supply results") {
160-
verifyResults(results)
161+
withClue("testing finance queries") {
162+
val results = runFinanceQueries()
163+
verifyFinanceResults(results)
161164
}
162165
}
163166

@@ -523,16 +526,31 @@ class ScanTotalSupplyBigQueryIntegrationTest
523526
job.waitFor()
524527
}
525528

526-
/** Runs the total supply queries from the SQL file
529+
private def runFinanceQueries()(implicit env: FixtureParam): FinanceMetrics = {
530+
val project = bigquery.getOptions.getProjectId
531+
// The TPS query assumes staleness of up to 4 hours, so we query for stats 5 hours after the current ledger time.
532+
val timestamp = getLedgerTime.toInstant.plus(5, ChronoUnit.HOURS).toString
533+
logger.info(s"Querying all dashboard stats as of $timestamp")
534+
val sql =
535+
s"SELECT * FROM `$project.$functionsDatasetName.all_finance_stats`('$timestamp', 0);"
536+
537+
parseFinanceResults(runTableSqlQuery(sql))
538+
}
539+
540+
/** Runs the dashboard queries from the SQL file
527541
*/
528-
private def runTotalSupplyQueries()(implicit env: FixtureParam): ExpectedMetrics = {
542+
private def runDashboardQueries()(implicit env: FixtureParam): DashboardMetrics = {
529543
val project = bigquery.getOptions.getProjectId
530544
// The TPS query assumes staleness of up to 4 hours, so we query for stats 5 hours after the current ledger time.
531545
val timestamp = getLedgerTime.toInstant.plus(5, ChronoUnit.HOURS).toString
546+
logger.info(s"Querying all dashboard stats as of $timestamp")
532547
val sql =
533548
s"SELECT * FROM `$project.$functionsDatasetName.all_dashboard_stats`('$timestamp', 0);"
534549

535-
logger.info(s"Querying all stats as of $timestamp")
550+
parseDashboardResults(runTableSqlQuery(sql))
551+
}
552+
553+
private def runTableSqlQuery(sql: String): TableResult = {
536554

537555
// Execute the query
538556
val queryConfig = bq.QueryJobConfiguration
@@ -549,11 +567,15 @@ class ScanTotalSupplyBigQueryIntegrationTest
549567
job.waitFor()
550568

551569
// results should be available now
552-
val result = job.getQueryResults()
553-
parseQueryResults(result)
570+
job.getQueryResults()
554571
}
555572

556-
private case class ExpectedMetrics(
573+
private case class FinanceMetrics(
574+
// Most metrics reuse the same code as the dasboard computation, so we don't bother validating them again
575+
latestRound: Long
576+
)
577+
578+
private case class DashboardMetrics(
557579
locked: BigDecimal,
558580
unlocked: BigDecimal,
559581
currentSupplyTotal: BigDecimal,
@@ -572,51 +594,64 @@ class ScanTotalSupplyBigQueryIntegrationTest
572594
avgCoinPrice: BigDecimal,
573595
)
574596

575-
private def parseQueryResults(result: bq.TableResult) = {
576-
// We expect the final query to return a single row with all metrics
577-
val row = result.iterateAll().iterator().next()
578-
logger.debug(s"Query row: $row; schema ${result.getSchema}")
597+
private def required(row: FieldValueList, column: String) = {
598+
val field = row get column
599+
if (field.isNull)
600+
fail(s"Column '$column' in all-stats results is null")
601+
field
602+
}
579603

580-
def required(column: String) = {
581-
val field = row get column
582-
if (field.isNull)
583-
fail(s"Column '$column' in all-stats results is null")
584-
field
585-
}
604+
def bd(row: FieldValueList, column: String) = {
605+
BigDecimal(required(row, column).getStringValue)
606+
}
586607

587-
def bd(column: String) = {
588-
BigDecimal(required(column).getStringValue)
589-
}
608+
def int(row: FieldValueList, column: String) = {
609+
required(row, column).getLongValue
610+
}
590611

591-
def int(column: String) = {
592-
required(column).getLongValue
593-
}
612+
def float(row: FieldValueList, column: String) = {
613+
required(row, column).getDoubleValue
614+
}
594615

595-
def float(column: String) = {
596-
required(column).getDoubleValue
597-
}
616+
private def parseFinanceResults(result: bq.TableResult) = {
617+
val row = result.iterateAll().iterator().next()
618+
logger.debug(s"Query row: $row; schema ${result.getSchema}")
619+
620+
FinanceMetrics(
621+
latestRound = int(row, "latest_round")
622+
)
623+
}
624+
625+
private def parseDashboardResults(result: bq.TableResult) = {
626+
// We expect the final query to return a single row with all metrics
627+
val row = result.iterateAll().iterator().next()
628+
logger.debug(s"Query row: $row; schema ${result.getSchema}")
598629

599-
ExpectedMetrics(
600-
locked = bd("locked"),
601-
unlocked = bd("unlocked"),
602-
currentSupplyTotal = bd("current_supply_total"),
603-
unminted = bd("unminted"),
604-
mintedAppRewards = bd("daily_mint_app_rewards"),
605-
mintedValidatorRewards = bd("daily_mint_validator_rewards"),
606-
mintedSvRewards = bd("daily_mint_sv_rewards"),
607-
mintedUnclaimed = bd("daily_mint_unclaimed_activity_records"),
608-
burned = bd("daily_burn"),
609-
numAmuletHolders = int("num_amulet_holders"),
610-
numActiveValidators = int("num_active_validators"),
611-
avgTps = float("average_tps"),
612-
peakTps = float("peak_tps"),
613-
minCoinPrice = bd("daily_min_coin_price"),
614-
maxCoinPrice = bd("daily_max_coin_price"),
615-
avgCoinPrice = bd("daily_avg_coin_price"),
630+
DashboardMetrics(
631+
locked = bd(row, "locked"),
632+
unlocked = bd(row, "unlocked"),
633+
currentSupplyTotal = bd(row, "current_supply_total"),
634+
unminted = bd(row, "unminted"),
635+
mintedAppRewards = bd(row, "daily_mint_app_rewards"),
636+
mintedValidatorRewards = bd(row, "daily_mint_validator_rewards"),
637+
mintedSvRewards = bd(row, "daily_mint_sv_rewards"),
638+
mintedUnclaimed = bd(row, "daily_mint_unclaimed_activity_records"),
639+
burned = bd(row, "daily_burn"),
640+
numAmuletHolders = int(row, "num_amulet_holders"),
641+
numActiveValidators = int(row, "num_active_validators"),
642+
avgTps = float(row, "average_tps"),
643+
peakTps = float(row, "peak_tps"),
644+
minCoinPrice = bd(row, "daily_min_coin_price"),
645+
maxCoinPrice = bd(row, "daily_max_coin_price"),
646+
avgCoinPrice = bd(row, "daily_avg_coin_price"),
616647
)
617648
}
618649

619-
private def verifyResults(results: ExpectedMetrics): Unit = {
650+
private def verifyFinanceResults(results: FinanceMetrics): Unit = {
651+
results.latestRound shouldBe totalRounds withClue "total_rounds"
652+
}
653+
654+
private def verifyDashboardResults(results: DashboardMetrics): Unit = {
620655
// Verify individual metrics
621656
forEvery(
622657
Seq(

cluster/pulumi/canton-network/src/bigQuery_functions.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ const daml_prim_path = new BQScalarFunction(
6969
WHEN 'contractId' THEN '.contractId'
7070
WHEN 'list' THEN '.list.elements'
7171
WHEN 'party' THEN '.party'
72+
WHEN 'int64' THEN '.int64'
7273
-- we treat records just like outer layer;
7374
-- see how paths start with '$.record'
7475
WHEN 'record' THEN ''
@@ -586,6 +587,24 @@ const coin_price = new BQScalarFunction(
586587
`
587588
);
588589

590+
const latest_round = new BQScalarFunction(
591+
'latest_round',
592+
as_of_args,
593+
INT64,
594+
`
595+
(SELECT
596+
CAST(JSON_VALUE(c.create_arguments, \`$$FUNCTIONS_DATASET$$.daml_record_path\`([1,0], 'int64')) AS INT64)
597+
FROM \`$$SCAN_DATASET$$.scan_sv_1_update_history_creates\` c
598+
WHERE template_id_entity_name = 'SummarizingMiningRound'
599+
AND c.template_id_module_name = 'Splice.Round'
600+
AND package_name = 'splice-amulet'
601+
AND \`$$FUNCTIONS_DATASET$$.up_to_time\`(
602+
as_of_record_time, migration_id,
603+
c.record_time, c.migration_id)
604+
ORDER BY c.record_time DESC LIMIT 1)
605+
`
606+
);
607+
589608
const all_dashboard_stats = new BQTableFunction(
590609
'all_dashboard_stats',
591610
as_of_args,
@@ -689,6 +708,7 @@ const all_finance_stats = new BQTableFunction(
689708
new BQColumn('total_burn', BIGNUMERIC),
690709
new BQColumn('num_amulet_holders', INT64),
691710
new BQColumn('num_active_validators', INT64),
711+
new BQColumn('latest_round', INT64),
692712
],
693713
`
694714
SELECT
@@ -729,7 +749,9 @@ const all_finance_stats = new BQTableFunction(
729749
migration_id),
730750
0) AS total_burn,
731751
\`$$FUNCTIONS_DATASET$$.num_amulet_holders\`(as_of_record_time, migration_id) as num_amulet_holders,
732-
\`$$FUNCTIONS_DATASET$$.num_active_validators\`(as_of_record_time, migration_id) as num_active_validators
752+
\`$$FUNCTIONS_DATASET$$.num_active_validators\`(as_of_record_time, migration_id) as num_active_validators,
753+
\`$$FUNCTIONS_DATASET$$.latest_round\`(as_of_record_time, migration_id) as latest_round
754+
733755
`
734756
);
735757

@@ -878,6 +900,7 @@ export const allScanFunctions = [
878900
average_tps,
879901
peak_tps,
880902
coin_price,
903+
latest_round,
881904
all_dashboard_stats,
882905
all_finance_stats,
883906
];

0 commit comments

Comments
 (0)