Skip to content
This repository was archived by the owner on Aug 18, 2020. It is now read-only.

Commit 8a84111

Browse files
Merge pull request #3495 from input-output-hk/adinapoli/feature/cbr-246-hook-sync-progress-to-info-api
[CBR-246] Implement getInfo with the new data layer
2 parents eaaf5c6 + 2156a9a commit 8a84111

File tree

3 files changed

+71
-15
lines changed

3 files changed

+71
-15
lines changed

wallet-new/src/Cardano/Wallet/Kernel/NodeStateAdaptor.hs

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module Cardano.Wallet.Kernel.NodeStateAdaptor (
2323
, getSlotCount
2424
, getSlotStart
2525
, getNextEpochSlotDuration
26+
, getNodeSyncProgress
2627
, curSoftwareVersion
2728
, compileInfo
2829
, getNtpDrift
@@ -42,10 +43,10 @@ module Cardano.Wallet.Kernel.NodeStateAdaptor (
4243

4344
import Universum
4445

45-
import Control.Lens (lens)
46+
import Control.Lens (lens, to)
4647
import Control.Monad.IO.Unlift (MonadUnliftIO, UnliftIO (UnliftIO),
4748
askUnliftIO, unliftIO, withUnliftIO)
48-
import Control.Monad.STM (retry)
49+
import Control.Monad.STM (orElse, retry)
4950
import Data.Conduit (mapOutputMaybe, runConduitRes, (.|))
5051
import qualified Data.Conduit.List as Conduit
5152
import Data.SafeCopy (base, deriveSafeCopy)
@@ -57,14 +58,16 @@ import Ntp.Packet (NtpOffset)
5758
import Serokell.Data.Memory.Units (Byte)
5859

5960
import qualified Cardano.Wallet.API.V1.Types as V1
60-
import Pos.Chain.Block (Block, HeaderHash, MainBlock, blockHeader,
61-
headerHash, mainBlockSlot, prevBlockL)
61+
import Pos.Chain.Block (Block, HeaderHash, LastKnownHeader,
62+
LastKnownHeaderTag, MainBlock, blockHeader, headerHash,
63+
mainBlockSlot, prevBlockL)
6264
import Pos.Chain.Update (ConfirmedProposalState,
6365
HasUpdateConfiguration, SoftwareVersion, bvdMaxTxSize)
6466
import qualified Pos.Chain.Update as Upd
6567
import Pos.Context (NodeContext (..))
66-
import Pos.Core (ProtocolConstants (pcK), SlotCount, Timestamp,
67-
genesisBlockVersionData, pcEpochSlots)
68+
import Pos.Core (BlockCount, ProtocolConstants (pcK), SlotCount,
69+
Timestamp, difficultyL, genesisBlockVersionData,
70+
getChainDifficulty, pcEpochSlots)
6871
import Pos.Core.Configuration (HasConfiguration, genesisHash,
6972
protocolConstants)
7073
import Pos.Core.Slotting (EpochIndex (..), HasSlottingVar (..),
@@ -257,6 +260,18 @@ data NodeStateAdaptor m = Adaptor {
257260
-- | Get last known slot duration.
258261
, getNextEpochSlotDuration :: m Millisecond
259262

263+
-- | Get the "sync progress". This term is desperately overloaded but
264+
-- in this context we need something very simple: a tuple containing the
265+
-- "global blockchain height" and the "node blockchain height". The
266+
-- former is the maximum between the biggest height we observed from an
267+
-- unsolicited block we received and the current local tip:
268+
--
269+
-- global_height = max (last_known_header, node_local_tip)
270+
--
271+
-- The latter is simply the node local tip, i.e. "how far we went into
272+
-- chasing the global blockchain height during syncing".
273+
, getNodeSyncProgress :: LockContext -> m (Maybe BlockCount, BlockCount)
274+
260275
-- | Version of application (code running)
261276
, curSoftwareVersion :: m SoftwareVersion
262277

@@ -265,6 +280,7 @@ data NodeStateAdaptor m = Adaptor {
265280

266281
-- | Ask the NTP client for the status
267282
, getNtpDrift :: V1.ForceNtpCheck -> m V1.TimeInfo
283+
268284
}
269285

270286
{-------------------------------------------------------------------------------
@@ -298,6 +314,9 @@ instance HasLens S.SimpleSlottingStateVar Res S.SimpleSlottingStateVar where
298314
instance HasLens UpdateContext Res UpdateContext where
299315
lensOf = mkResLens (nrContextLens . lensOf')
300316

317+
instance HasLens LastKnownHeaderTag Res LastKnownHeader where
318+
lensOf = mkResLens (nrContextLens . lensOf @LastKnownHeaderTag)
319+
301320
instance HasSlottingVar Res where
302321
slottingTimestamp = mkResLens (nrContextLens . slottingTimestamp)
303322
slottingVar = mkResLens (nrContextLens . slottingVar)
@@ -346,11 +365,12 @@ newNodeStateAdaptor :: forall m ext. (NodeConstraints, MonadIO m, MonadMask m)
346365
-> TVar NtpStatus
347366
-> NodeStateAdaptor m
348367
newNodeStateAdaptor nr ntpStatus = Adaptor {
349-
withNodeState = run
350-
, getTipSlotId = run $ \_lock -> defaultGetTipSlotId
351-
, getMaxTxSize = run $ \_lock -> defaultGetMaxTxSize
352-
, getSlotStart = \slotId -> run $ \_lock -> defaultGetSlotStart slotId
353-
, getNextEpochSlotDuration = run $ \_lock -> defaultGetNextEpochSlotDuration
368+
withNodeState = run
369+
, getTipSlotId = run $ \_lock -> defaultGetTipSlotId
370+
, getMaxTxSize = run $ \_lock -> defaultGetMaxTxSize
371+
, getSlotStart = \slotId -> run $ \_lock -> defaultGetSlotStart slotId
372+
, getNextEpochSlotDuration = run $ \_lock -> defaultGetNextEpochSlotDuration
373+
, getNodeSyncProgress = \lockCtx -> run $ defaultSyncProgress lockCtx
354374
, getSecurityParameter = return $ pcK' protocolConstants
355375
, getSlotCount = return $ pcEpochSlots protocolConstants
356376
, curSoftwareVersion = return $ Upd.curSoftwareVersion
@@ -405,6 +425,23 @@ defaultGetSlotStart slotId =
405425
defaultGetNextEpochSlotDuration :: MonadIO m => WithNodeState m Millisecond
406426
defaultGetNextEpochSlotDuration = Slotting.getNextEpochSlotDuration
407427

428+
defaultSyncProgress :: (MonadIO m, MonadMask m, NodeConstraints)
429+
=> LockContext
430+
-> Lock (WithNodeState m)
431+
-> WithNodeState m (Maybe BlockCount, BlockCount)
432+
defaultSyncProgress lockContext lock = do
433+
(globalHeight, localHeight) <- lock lockContext $ \_localTipHash -> do
434+
-- We need to grab the localTip again as '_localTip' has type
435+
-- 'HeaderHash' but we cannot grab the difficulty out of it.
436+
headerRef <- view (lensOf @LastKnownHeaderTag)
437+
localTip <- getTipHeader
438+
mbHeader <- atomically $ readTVar headerRef `orElse` pure Nothing
439+
pure (view (difficultyL . to getChainDifficulty) <$> mbHeader
440+
,view (difficultyL . to getChainDifficulty) localTip
441+
)
442+
return (max localHeight <$> globalHeight, localHeight)
443+
444+
408445
{-------------------------------------------------------------------------------
409446
Non-mockable functions
410447
-------------------------------------------------------------------------------}
@@ -511,6 +548,7 @@ mockNodeState MockNodeStateParams{..} =
511548
, getTipSlotId = return mockNodeStateTipSlotId
512549
, getSecurityParameter = return mockNodeStateSecurityParameter
513550
, getNextEpochSlotDuration = return mockNodeStateNextEpochSlotDuration
551+
, getNodeSyncProgress = \_ -> return mockNodeStateSyncProgress
514552
, getSlotStart = return . mockNodeStateSlotStart
515553
, getMaxTxSize = return $ bvdMaxTxSize genesisBlockVersionData
516554
, getSlotCount = return $ pcEpochSlots protocolConstants
@@ -540,6 +578,9 @@ data MockNodeStateParams = NodeConstraints => MockNodeStateParams {
540578
-- | Value for 'getNextEpochSlotDuration'
541579
, mockNodeStateNextEpochSlotDuration :: Millisecond
542580

581+
-- | Value for 'getNodeSyncProgress'
582+
, mockNodeStateSyncProgress :: (Maybe BlockCount, BlockCount)
583+
543584
-- | Value for 'getNtpDrift'
544585
, mockNodeStateNtpDrift :: V1.ForceNtpCheck -> V1.TimeInfo
545586
}
@@ -563,6 +604,7 @@ defMockNodeStateParams =
563604
mockNodeStateTipSlotId = notDefined "mockNodeStateTipSlotId"
564605
, mockNodeStateSlotStart = notDefined "mockNodeStateSlotStart"
565606
, mockNodeStateNextEpochSlotDuration = notDefined "mockNodeStateNextEpochSlotDuration"
607+
, mockNodeStateSyncProgress = notDefined "mockNodeStateSyncProgress"
566608
, mockNodeStateSecurityParameter = SecurityParameter 2160
567609
, mockNodeStateNtpDrift = const (V1.TimeInfo Nothing)
568610
}

wallet-new/src/Cardano/Wallet/WalletLayer/Kernel/Info.hs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,21 @@ module Cardano.Wallet.WalletLayer.Kernel.Info (
44

55
import Universum
66

7+
import qualified Pos.Core as Core
8+
79
import qualified Cardano.Wallet.API.V1.Types as V1
810
import Cardano.Wallet.Kernel.Diffusion (walletGetSubscriptionStatus)
911
import qualified Cardano.Wallet.Kernel.Internal as Kernel
1012
import Cardano.Wallet.Kernel.NodeStateAdaptor (NodeStateAdaptor)
1113
import qualified Cardano.Wallet.Kernel.NodeStateAdaptor as Node
1214

1315
getNodeInfo :: MonadIO m => Kernel.ActiveWallet -> V1.ForceNtpCheck -> m V1.NodeInfo
14-
getNodeInfo aw ntpCheckBehavior = liftIO $
16+
getNodeInfo aw ntpCheckBehavior = liftIO $ do
17+
(mbNodeHeight, localHeight) <- Node.getNodeSyncProgress node Node.NotYetLocked
1518
V1.NodeInfo
16-
<$> (pure $ V1.mkSyncPercentage 100) -- TODO (Restoration [CBR-243])
17-
<*> (pure $ Nothing) -- TODO (Restoration [CBR-243])
18-
<*> (pure $ V1.mkBlockchainHeight 0) -- TODO (Restoration [CBR-243])
19+
<$> (pure $ v1SyncPercentage mbNodeHeight localHeight)
20+
<*> (pure $ V1.mkBlockchainHeight <$> mbNodeHeight)
21+
<*> (pure $ V1.mkBlockchainHeight localHeight)
1922
<*> (Node.getNtpDrift node ntpCheckBehavior)
2023
<*> (walletGetSubscriptionStatus (Kernel.walletDiffusion aw))
2124
where
@@ -24,3 +27,12 @@ getNodeInfo aw ntpCheckBehavior = liftIO $
2427

2528
pw :: Kernel.PassiveWallet
2629
pw = Kernel.walletPassive aw
30+
31+
-- | Computes the V1 'SyncPercentage' out of the global & local blockchain heights.
32+
v1SyncPercentage :: Maybe Core.BlockCount -> Core.BlockCount -> V1.SyncPercentage
33+
v1SyncPercentage nodeHeight walletHeight =
34+
let percentage = case nodeHeight of
35+
Nothing -> 0
36+
Just nd | walletHeight >= nd -> 100 :: Int
37+
Just nd -> floor @Double $ (fromIntegral walletHeight / max 1.0 (fromIntegral nd)) * 100.0
38+
in V1.mkSyncPercentage (fromIntegral percentage)

wallet-new/test/unit/Test/Spec/TxMetaScenarios.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ nodeStParams1 =
393393
, mockNodeStateSecurityParameter = SecurityParameter 2160
394394
, mockNodeStateNextEpochSlotDuration = fromMicroseconds 200
395395
, mockNodeStateNtpDrift = const (V1.TimeInfo Nothing)
396+
, mockNodeStateSyncProgress = (Just 100, 100)
396397
}
397398

398399
nodeStParams2 :: MockNodeStateParams
@@ -406,6 +407,7 @@ nodeStParams2 =
406407
, mockNodeStateSecurityParameter = SecurityParameter 2160
407408
, mockNodeStateNextEpochSlotDuration = fromMicroseconds 200
408409
, mockNodeStateNtpDrift = const (V1.TimeInfo Nothing)
410+
, mockNodeStateSyncProgress = (Just 100, 100)
409411
}
410412

411413
-- | Initialize active wallet in a manner suitable for generator-based testing.

0 commit comments

Comments
 (0)