Skip to content

Commit 2187c9c

Browse files
authored
Merge pull request #2044 from IntersectMBO/kderme/fix-epoch-stake
Fix epoch stake
2 parents b8748fb + 23fbbbe commit 2187c9c

File tree

5 files changed

+179
-3
lines changed

5 files changed

+179
-3
lines changed

cardano-db-sync/src/Cardano/DbSync/Default.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ insertBlock syncEnv cblk applyRes firstAfterRollback tookSnapshot = do
157157
let !details = apSlotDetails applyResult
158158
let !withinTwoMin = isWithinTwoMin details
159159
let !withinHalfHour = isWithinHalfHour details
160-
insertNewEpochLedgerEvents syncEnv (sdEpochNo details) (apEvents applyResult)
160+
insertNewEpochLedgerEvents syncEnv applyResult (sdEpochNo details) (apEvents applyResult)
161161

162162
let isNewEpochEvent = hasNewEpochEvent (apEvents applyResult)
163163
let isStartEventOrRollback = hasEpochStartEvent (apEvents applyResult) || firstAfterRollback

cardano-db-sync/src/Cardano/DbSync/Era/Shelley/Generic/StakeDist.hs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ module Cardano.DbSync.Era.Shelley.Generic.StakeDist (
1212
StakeSlice (..),
1313
getSecurityParameter,
1414
getStakeSlice,
15+
countEpochStake,
16+
fullEpochStake,
1517
getPoolDistr,
1618
) where
1719

@@ -175,6 +177,110 @@ genericStakeSlice pInfo epochBlockNo lstate isMigration
175177
VMap.mapMaybe id $
176178
VMap.mapWithKey (\a p -> (,p) <$> lookupStake a) delegationsSliced
177179

180+
countEpochStake ::
181+
ExtLedgerState CardanoBlock mk ->
182+
Maybe (Word64, EpochNo)
183+
countEpochStake els =
184+
case ledgerState els of
185+
LedgerStateByron _ -> Nothing
186+
LedgerStateShelley sls -> genericCountEpochStake sls
187+
LedgerStateAllegra als -> genericCountEpochStake als
188+
LedgerStateMary mls -> genericCountEpochStake mls
189+
LedgerStateAlonzo als -> genericCountEpochStake als
190+
LedgerStateBabbage bls -> genericCountEpochStake bls
191+
LedgerStateConway cls -> genericCountEpochStake cls
192+
LedgerStateDijkstra dls -> genericCountEpochStake dls
193+
194+
genericCountEpochStake ::
195+
LedgerState (ShelleyBlock p era) mk ->
196+
Maybe (Word64, EpochNo)
197+
genericCountEpochStake lstate =
198+
Just (delegationsLen, epoch)
199+
where
200+
epoch :: EpochNo
201+
epoch = EpochNo $ 1 + unEpochNo (Shelley.nesEL (Consensus.shelleyLedgerState lstate))
202+
203+
stakeSnapshot :: Ledger.SnapShot
204+
stakeSnapshot =
205+
Ledger.ssStakeMark . Shelley.esSnapshots . Shelley.nesEs $
206+
Consensus.shelleyLedgerState lstate
207+
208+
delegations :: VMap VB VB (Credential 'Staking) (KeyHash 'StakePool)
209+
delegations = Ledger.ssDelegations stakeSnapshot
210+
211+
delegationsLen :: Word64
212+
delegationsLen = fromIntegral $ VMap.size $ VMap.filter (\k _ -> hasStake k) delegations
213+
214+
stakes :: VMap VB VP (Credential 'Staking) (Ledger.CompactForm Coin)
215+
stakes = Ledger.unStake $ Ledger.ssStake stakeSnapshot
216+
217+
hasStake :: Credential 'Staking -> Bool
218+
hasStake cred = isJust (VMap.lookup cred stakes)
219+
220+
fullEpochStake ::
221+
ExtLedgerState CardanoBlock mk ->
222+
StakeSliceRes
223+
fullEpochStake els =
224+
case ledgerState els of
225+
LedgerStateByron _ -> NoSlices
226+
LedgerStateShelley sls -> genericFullStakeSlice sls
227+
LedgerStateAllegra als -> genericFullStakeSlice als
228+
LedgerStateMary mls -> genericFullStakeSlice mls
229+
LedgerStateAlonzo als -> genericFullStakeSlice als
230+
LedgerStateBabbage bls -> genericFullStakeSlice bls
231+
LedgerStateConway cls -> genericFullStakeSlice cls
232+
LedgerStateDijkstra dls -> genericFullStakeSlice dls
233+
234+
genericFullStakeSlice ::
235+
forall era p mk.
236+
LedgerState (ShelleyBlock p era) mk ->
237+
StakeSliceRes
238+
genericFullStakeSlice lstate =
239+
Slice stakeSlice True
240+
where
241+
epoch :: EpochNo
242+
epoch = EpochNo $ 1 + unEpochNo (Shelley.nesEL (Consensus.shelleyLedgerState lstate))
243+
244+
-- We use 'ssStakeMark' here. That means that when these values
245+
-- are added to the database, the epoch number where they become active is the current
246+
-- epoch plus one.
247+
stakeSnapshot :: Ledger.SnapShot
248+
stakeSnapshot =
249+
Ledger.ssStakeMark . Shelley.esSnapshots . Shelley.nesEs $
250+
Consensus.shelleyLedgerState lstate
251+
252+
delegations :: VMap.KVVector VB VB (Credential 'Staking, KeyHash 'StakePool)
253+
delegations = VMap.unVMap $ Ledger.ssDelegations stakeSnapshot
254+
255+
delegationsLen :: Word64
256+
delegationsLen = fromIntegral $ VG.length delegations
257+
258+
stakes :: VMap VB VP (Credential 'Staking) (Ledger.CompactForm Coin)
259+
stakes = Ledger.unStake $ Ledger.ssStake stakeSnapshot
260+
261+
lookupStake :: Credential 'Staking -> Maybe Coin
262+
lookupStake cred = Ledger.fromCompact <$> VMap.lookup cred stakes
263+
264+
-- The starting index of the data in the delegation vector.
265+
index :: Word64
266+
index = 0
267+
268+
stakeSlice :: StakeSlice
269+
stakeSlice =
270+
StakeSlice
271+
{ sliceEpochNo = epoch
272+
, sliceDistr = distribution
273+
}
274+
where
275+
delegationsSliced :: VMap VB VB (Credential 'Staking) (KeyHash 'StakePool)
276+
delegationsSliced = VMap $ VG.slice (fromIntegral index) (fromIntegral delegationsLen) delegations
277+
278+
distribution :: Map StakeCred (Coin, PoolKeyHash)
279+
distribution =
280+
VMap.toMap $
281+
VMap.mapMaybe id $
282+
VMap.mapWithKey (\a p -> (,p) <$> lookupStake a) delegationsSliced
283+
178284
getPoolDistr ::
179285
ExtLedgerState CardanoBlock mk ->
180286
Maybe (Map PoolKeyHash (Coin, Word64), Map PoolKeyHash Natural)

cardano-db-sync/src/Cardano/DbSync/Era/Universal/Insert/LedgerEvent.hs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ import qualified Cardano.DbSync.Era.Shelley.Generic as Generic
2525
import Cardano.DbSync.Era.Universal.Adjust (adjustEpochRewards)
2626
import Cardano.DbSync.Era.Universal.Epoch (insertPoolDepositRefunds, insertProposalRefunds, insertRewardRests, insertRewards)
2727
import Cardano.DbSync.Era.Universal.Insert.GovAction
28-
import Cardano.DbSync.Era.Universal.Validate (validateEpochRewards)
28+
import Cardano.DbSync.Era.Universal.Validate (validateEpochRewards, validateEpochStake)
2929
import Cardano.DbSync.Ledger.Event
3030
import Cardano.DbSync.Types
3131

3232
import Cardano.DbSync.Error (SyncNodeError)
33+
import Cardano.DbSync.Ledger.Types
3334
import Cardano.DbSync.Metrics (setDbEpochSyncDuration, setDbEpochSyncNumber)
3435
import Control.Concurrent.Class.MonadSTM.Strict (readTVarIO, writeTVar)
3536
import Control.Monad.Extra (whenJust)
@@ -44,10 +45,11 @@ import Text.Printf (printf)
4445
--------------------------------------------------------------------------------------------
4546
insertNewEpochLedgerEvents ::
4647
SyncEnv ->
48+
ApplyResult ->
4749
EpochNo ->
4850
[LedgerEvent] ->
4951
ExceptT SyncNodeError DB.DbM ()
50-
insertNewEpochLedgerEvents syncEnv currentEpochNo@(EpochNo curEpoch) =
52+
insertNewEpochLedgerEvents syncEnv applyRes currentEpochNo@(EpochNo curEpoch) =
5153
mapM_ handler
5254
where
5355
metricSetters = envMetricSetters syncEnv
@@ -72,6 +74,7 @@ insertNewEpochLedgerEvents syncEnv currentEpochNo@(EpochNo curEpoch) =
7274
handler ev =
7375
case ev of
7476
LedgerNewEpoch en ss -> do
77+
validateEpochStake syncEnv applyRes True
7578
databaseCacheSize <- lift DB.queryStatementCacheSize
7679
liftIO . logInfo tracer $ "Database Statement Cache size is " <> textShow databaseCacheSize
7780
currentTime <- liftIO getCurrentTime

cardano-db-sync/src/Cardano/DbSync/Era/Universal/Validate.hs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
{-# LANGUAGE NoImplicitPrelude #-}
66

77
module Cardano.DbSync.Era.Universal.Validate (
8+
validateEpochStake,
89
validateEpochRewards,
910
) where
1011

@@ -20,10 +21,53 @@ import qualified Data.Set as Set
2021
import GHC.Err (error)
2122

2223
import qualified Cardano.Db as DB
24+
import Cardano.DbSync.Api
25+
import Cardano.DbSync.Api.Types
2326
import qualified Cardano.DbSync.Era.Shelley.Generic as Generic
27+
import Cardano.DbSync.Era.Universal.Epoch
2428
import Cardano.DbSync.Error (SyncNodeError)
2529
import Cardano.DbSync.Ledger.Event
30+
import Cardano.DbSync.Ledger.Types
2631
import Cardano.DbSync.Types
32+
import Cardano.DbSync.Util.Constraint
33+
import qualified Data.Strict.Maybe as Strict
34+
35+
validateEpochStake ::
36+
SyncEnv ->
37+
ApplyResult ->
38+
Bool ->
39+
ExceptT SyncNodeError DB.DbM ()
40+
validateEpochStake syncEnv applyRes firstCall = case apOldLedger applyRes of
41+
Strict.Just lstate | Just (expectedCount, epoch) <- Generic.countEpochStake (clsState lstate) -> do
42+
actualCount <- lift $ DB.queryNormalEpochStakeCount (unEpochNo epoch)
43+
if actualCount /= expectedCount
44+
then do
45+
liftIO
46+
. logWarning tracer
47+
$ mconcat
48+
[ "validateEpochStake: epoch stake in epoch "
49+
, textShow (unEpochNo epoch)
50+
, " expected total of "
51+
, textShow expectedCount
52+
, " but got "
53+
, textShow actualCount
54+
]
55+
let slice = Generic.fullEpochStake (clsState lstate)
56+
addStakeConstraintsIfNotExist syncEnv tracer
57+
insertStakeSlice syncEnv slice
58+
when firstCall $ validateEpochStake syncEnv applyRes False
59+
else
60+
liftIO $
61+
logInfo tracer $
62+
mconcat
63+
[ "Validate Epoch Stake: total entries in epoch "
64+
, textShow (unEpochNo epoch)
65+
, " are "
66+
, textShow actualCount
67+
]
68+
_ -> pure ()
69+
where
70+
tracer = getTrace syncEnv
2771

2872
validateEpochRewards ::
2973
Trace IO Text ->

cardano-db/src/Cardano/Db/Statement/StakeDelegation.hs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,29 @@ queryNormalEpochRewardCount epochNum =
216216
runSession mkDbCallStack $
217217
HsqlSes.statement epochNum queryNormalEpochRewardCountStmt
218218

219+
-- | QUERY ---------------------------------------------------------------------
220+
queryNormalEpochStakeCountStmt :: HsqlStmt.Statement Word64 Word64
221+
queryNormalEpochStakeCountStmt =
222+
HsqlStmt.Statement sql encoder decoder True
223+
where
224+
sql =
225+
TextEnc.encodeUtf8 $
226+
Text.concat
227+
[ "SELECT COUNT(*)::bigint"
228+
, " FROM epoch_stake"
229+
, " WHERE epoch_no = $1"
230+
]
231+
232+
encoder = HsqlE.param (HsqlE.nonNullable $ fromIntegral >$< HsqlE.int8)
233+
decoder =
234+
HsqlD.singleRow $
235+
fromIntegral <$> HsqlD.column (HsqlD.nonNullable HsqlD.int8)
236+
237+
queryNormalEpochStakeCount :: Word64 -> DbM Word64
238+
queryNormalEpochStakeCount epochNum =
239+
runSession mkDbCallStack $
240+
HsqlSes.statement epochNum queryNormalEpochStakeCountStmt
241+
219242
--------------------------------------------------------------------------------
220243
queryRewardCount :: DbM Word64
221244
queryRewardCount =

0 commit comments

Comments
 (0)