From 638a0cb976bc2e9f08303d3580f1e3ec44fdb1ed Mon Sep 17 00:00:00 2001 From: Nate Date: Sat, 14 Dec 2024 09:17:06 -0800 Subject: [PATCH] fix(sqlite): Recalculate contract metrics --- go.mod | 2 +- persist/sqlite/migrations.go | 7 ++++ persist/sqlite/recalc.go | 73 ++++++++++++++++++++++++++---------- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 84e9492a..68a34a07 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( go.sia.tech/core v0.7.1 go.sia.tech/coreutils v0.7.1-0.20241203172514-7bf95dd18f31 go.sia.tech/jape v0.12.1 + go.sia.tech/mux v1.3.0 go.sia.tech/web/hostd v0.52.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 @@ -33,7 +34,6 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect go.etcd.io/bbolt v1.3.11 // indirect - go.sia.tech/mux v1.3.0 // indirect go.sia.tech/web v0.0.0-20240610131903-5611d44a533e // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.29.0 // indirect diff --git a/persist/sqlite/migrations.go b/persist/sqlite/migrations.go index b5cbb83e..f0aadeb1 100644 --- a/persist/sqlite/migrations.go +++ b/persist/sqlite/migrations.go @@ -12,6 +12,12 @@ import ( "go.uber.org/zap" ) +// migrateVersion36 recalculates the contract metrics to remove the pending contract +// values from the metrics. +func migrateVersion36(tx *txn, log *zap.Logger) error { + return recalcContractMetrics(tx, log) +} + // migrateVersion35 trims the port from the net_address in the host settings // table. func migrateVersion35(tx *txn, _ *zap.Logger) error { @@ -1009,4 +1015,5 @@ var migrations = []func(tx *txn, log *zap.Logger) error{ migrateVersion33, migrateVersion34, migrateVersion35, + migrateVersion36, } diff --git a/persist/sqlite/recalc.go b/persist/sqlite/recalc.go index 42a5d797..e224332e 100644 --- a/persist/sqlite/recalc.go +++ b/persist/sqlite/recalc.go @@ -135,33 +135,68 @@ GROUP BY volume_id` } func recalcContractMetrics(tx *txn, log *zap.Logger) error { - rows, err := tx.Query(`SELECT contract_status, locked_collateral, risked_collateral, rpc_revenue, storage_revenue, ingress_revenue, egress_revenue, account_funding, registry_read, registry_write FROM contracts WHERE contract_status IN (?, ?);`, contracts.ContractStatusActive, contracts.ContractStatusSuccessful) - if err != nil { - return fmt.Errorf("failed to query contracts: %w", err) - } - defer rows.Close() - var totalLocked types.Currency var totalPending, totalEarned contracts.Usage - for rows.Next() { - var status contracts.ContractStatus - var lockedCollateral types.Currency - var usage contracts.Usage - if err := rows.Scan(&status, decode(&lockedCollateral), decode(&usage.RiskedCollateral), decode(&usage.RPCRevenue), decode(&usage.StorageRevenue), decode(&usage.IngressRevenue), decode(&usage.EgressRevenue), decode(&usage.AccountFunding), decode(&usage.RegistryRead), decode(&usage.RegistryWrite)); err != nil { - return fmt.Errorf("failed to scan contract: %w", err) + err := func() error { + rows, err := tx.Query(`SELECT contract_status, locked_collateral, risked_collateral, rpc_revenue, storage_revenue, ingress_revenue, egress_revenue, account_funding, registry_read, registry_write FROM contracts WHERE contract_status IN (?, ?);`, contracts.ContractStatusActive, contracts.ContractStatusSuccessful) + if err != nil { + return fmt.Errorf("failed to query contracts: %w", err) } + defer rows.Close() + for rows.Next() { + var status contracts.ContractStatus + var lockedCollateral types.Currency + var usage contracts.Usage + + if err := rows.Scan(&status, decode(&lockedCollateral), decode(&usage.RiskedCollateral), decode(&usage.RPCRevenue), decode(&usage.StorageRevenue), decode(&usage.IngressRevenue), decode(&usage.EgressRevenue), decode(&usage.AccountFunding), decode(&usage.RegistryRead), decode(&usage.RegistryWrite)); err != nil { + return fmt.Errorf("failed to scan contract: %w", err) + } + + switch status { + case contracts.ContractStatusActive: + totalLocked = totalLocked.Add(lockedCollateral) + totalPending = totalPending.Add(usage) + case contracts.ContractStatusSuccessful: + totalEarned = totalEarned.Add(usage) + } + } + return rows.Err() + }() + if err != nil { + return fmt.Errorf("failed to calculate v1 metrics: %w", err) + } - switch status { - case contracts.ContractStatusActive: - totalLocked = totalLocked.Add(lockedCollateral) - totalPending = totalPending.Add(usage) - case contracts.ContractStatusSuccessful: - totalEarned = totalEarned.Add(usage) + err = func() error { + rows, err := tx.Query(`SELECT contract_status, locked_collateral, risked_collateral, rpc_revenue, storage_revenue, ingress_revenue, egress_revenue, account_funding FROM contracts_v2 WHERE contract_status IN (?, ?, ?);`, contracts.V2ContractStatusActive, contracts.V2ContractStatusSuccessful, contracts.V2ContractStatusRenewed) + if err != nil { + return fmt.Errorf("failed to query contracts: %w", err) + } + defer rows.Close() + for rows.Next() { + var status contracts.V2ContractStatus + var lockedCollateral types.Currency + var usage contracts.Usage + + if err := rows.Scan(&status, decode(&lockedCollateral), decode(&usage.RiskedCollateral), decode(&usage.RPCRevenue), decode(&usage.StorageRevenue), decode(&usage.IngressRevenue), decode(&usage.EgressRevenue), decode(&usage.AccountFunding), decode(&usage.RegistryRead), decode(&usage.RegistryWrite)); err != nil { + return fmt.Errorf("failed to scan contract: %w", err) + } + + switch status { + case contracts.V2ContractStatusActive: + totalLocked = totalLocked.Add(lockedCollateral) + totalPending = totalPending.Add(usage) + case contracts.V2ContractStatusSuccessful, contracts.V2ContractStatusRenewed: + totalEarned = totalEarned.Add(usage) + } } + return rows.Err() + }() + if err != nil { + return fmt.Errorf("failed to calculate v2 metrics: %w", err) } - log.Debug("resetting metrics", zap.Stringer("lockedCollateral", totalLocked), zap.Stringer("riskedCollateral", totalPending.RiskedCollateral)) + log.Debug("resetting contract metrics", zap.Stringer("lockedCollateral", totalLocked), zap.Stringer("riskedCollateral", totalPending.RiskedCollateral)) if err := setCurrencyStat(tx, metricLockedCollateral, totalLocked, time.Now()); err != nil { return fmt.Errorf("failed to increment locked collateral: %w", err)