Skip to content

Commit

Permalink
WIP: Propagate consensus protocol in block type
Browse files Browse the repository at this point in the history
  • Loading branch information
Jimbo4350 committed Apr 25, 2022
1 parent 4f5e13b commit c5099a5
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 96 deletions.
93 changes: 51 additions & 42 deletions cardano-api/src/Cardano/Api/Block.hs
Original file line number Diff line number Diff line change
Expand Up @@ -60,23 +60,27 @@ import Data.String (IsString)
import Cardano.Slotting.Block (BlockNo)
import Cardano.Slotting.Slot (EpochNo, SlotNo, WithOrigin (..))

import qualified Cardano.Crypto.Hash.Class
import qualified Cardano.Crypto.Hash.Class as Crypto
import qualified Cardano.Crypto.Hashing
import qualified Ouroboros.Consensus.Block as Consensus
import qualified Ouroboros.Consensus.Byron.Ledger as Consensus
import qualified Ouroboros.Consensus.Cardano.Block as Consensus
import qualified Ouroboros.Consensus.Cardano.ByronHFC as Consensus
import qualified Ouroboros.Consensus.HardFork.Combinator as Consensus
import qualified Ouroboros.Consensus.HardFork.Combinator.Degenerate as Consensus
-- import qualified Ouroboros.Consensus.Protocol.Praos as Praos
-- import qualified Ouroboros.Consensus.Protocol.Praos.Header as Praos
import qualified Ouroboros.Consensus.Protocol.TPraos as Consensus
import qualified Ouroboros.Consensus.Shelley.Ledger as Consensus
import qualified Ouroboros.Consensus.Shelley.Protocol.Abstract as Consensus
import qualified Ouroboros.Consensus.Shelley.ShelleyHFC as Consensus
import qualified Ouroboros.Network.Block as Consensus

import qualified Cardano.Chain.Block as Byron
import qualified Cardano.Chain.UTxO as Byron
import qualified Cardano.Ledger.Block as Ledger
import qualified Cardano.Ledger.Era as Ledger
import qualified Cardano.Protocol.TPraos.BHeader as TPraos
-- import qualified Cardano.Protocol.TPraos.BHeader as TPraos

import Cardano.Api.Eras
import Cardano.Api.HasTypeProxy
Expand All @@ -102,7 +106,7 @@ data Block era where
-> Block ByronEra

ShelleyBlock :: ShelleyBasedEra era
-> Consensus.ShelleyBlock (ShelleyLedgerEra era)
-> Consensus.ShelleyBlock (ConsensusProtocol era) (ShelleyLedgerEra era)
-> Block era

-- | A block consists of a header and a body containing transactions.
Expand Down Expand Up @@ -164,31 +168,32 @@ getBlockTxs (ByronBlock Consensus.ByronBlock { Consensus.byronBlockRaw }) =
}
} -> map ByronTx txs
getBlockTxs (ShelleyBlock era Consensus.ShelleyBlock{Consensus.shelleyBlockRaw}) =
obtainConsensusShelleyBasedEra era $
obtainConsensusShelleyCompatibleEra era $
getShelleyBlockTxs era shelleyBlockRaw

getShelleyBlockTxs :: forall era ledgerera.
ledgerera ~ ShelleyLedgerEra era
=> Consensus.ShelleyBasedEra ledgerera

getShelleyBlockTxs :: forall era ledgerera blockheader.
ShelleyLedgerEra era ~ ledgerera
=> Consensus.ShelleyCompatible (ConsensusProtocol era) ledgerera
=> Consensus.ShelleyProtocolHeader (ConsensusProtocol era) ~ blockheader
=> ShelleyBasedEra era
-> Ledger.Block (TPraos.BHeader (Ledger.Crypto ledgerera)) ledgerera
-> Ledger.Block blockheader ledgerera
-> [Tx era]
getShelleyBlockTxs era (Ledger.Block _header txs) =
[ ShelleyTx era txinblock
| txinblock <- toList (Ledger.fromTxSeq txs) ]

obtainConsensusShelleyBasedEra
obtainConsensusShelleyCompatibleEra
:: forall era ledgerera a.
ledgerera ~ ShelleyLedgerEra era
ShelleyLedgerEra era ~ ledgerera
=> ShelleyBasedEra era
-> (Consensus.ShelleyBasedEra ledgerera => a) -> a
obtainConsensusShelleyBasedEra ShelleyBasedEraShelley f = f
obtainConsensusShelleyBasedEra ShelleyBasedEraAllegra f = f
obtainConsensusShelleyBasedEra ShelleyBasedEraMary f = f
obtainConsensusShelleyBasedEra ShelleyBasedEraAlonzo f = f
obtainConsensusShelleyBasedEra ShelleyBasedEraBabbage _f =
error "TODO: Babbage era - depends on consensus exposing a babbage era"

-> (Consensus.ShelleyCompatible (ConsensusProtocol era) ledgerera => a)
-> a
obtainConsensusShelleyCompatibleEra ShelleyBasedEraShelley f = f
obtainConsensusShelleyCompatibleEra ShelleyBasedEraAllegra f = f
obtainConsensusShelleyCompatibleEra ShelleyBasedEraMary f = f
obtainConsensusShelleyCompatibleEra ShelleyBasedEraAlonzo f = f
obtainConsensusShelleyCompatibleEra ShelleyBasedEraBabbage f = f

-- ----------------------------------------------------------------------------
-- Block in a consensus mode
Expand All @@ -211,11 +216,11 @@ fromConsensusBlock ByronMode =
Consensus.DegenBlock b' ->
BlockInMode (ByronBlock b') ByronEraInByronMode

fromConsensusBlock ShelleyMode =
\b -> case b of
Consensus.DegenBlock b' ->
BlockInMode (ShelleyBlock ShelleyBasedEraShelley b')
ShelleyEraInShelleyMode
fromConsensusBlock ShelleyMode = error "TODO: Babbage"
-- \b -> case b of
-- Consensus.DegenBlock b' ->
-- BlockInMode (ShelleyBlock ShelleyBasedEraShelley b')
-- ShelleyEraInShelleyMode

fromConsensusBlock CardanoMode =
\b -> case b of
Expand All @@ -238,23 +243,26 @@ fromConsensusBlock CardanoMode =
BlockInMode (ShelleyBlock ShelleyBasedEraAlonzo b')
AlonzoEraInCardanoMode

Consensus.BlockBabbage b' ->
BlockInMode (ShelleyBlock ShelleyBasedEraBabbage b')
BabbageEraInCardanoMode

toConsensusBlock :: ConsensusBlockForMode mode ~ block => BlockInMode mode -> block
toConsensusBlock bInMode =
case bInMode of
-- Byron mode
BlockInMode (ByronBlock b') ByronEraInByronMode -> Consensus.DegenBlock b'

-- Shelley mode
BlockInMode (ShelleyBlock ShelleyBasedEraShelley b') ShelleyEraInShelleyMode -> Consensus.DegenBlock b'
BlockInMode (ShelleyBlock ShelleyBasedEraShelley _b') ShelleyEraInShelleyMode -> error "Consensus.DegenBlock b'"

-- Cardano mode
BlockInMode (ByronBlock b') ByronEraInCardanoMode -> Consensus.BlockByron b'
BlockInMode (ShelleyBlock ShelleyBasedEraShelley b') ShelleyEraInCardanoMode -> Consensus.BlockShelley b'
BlockInMode (ShelleyBlock ShelleyBasedEraAllegra b') AllegraEraInCardanoMode -> Consensus.BlockAllegra b'
BlockInMode (ShelleyBlock ShelleyBasedEraMary b') MaryEraInCardanoMode -> Consensus.BlockMary b'
BlockInMode (ShelleyBlock ShelleyBasedEraAlonzo b') AlonzoEraInCardanoMode -> Consensus.BlockAlonzo b'
BlockInMode (ShelleyBlock ShelleyBasedEraBabbage _b') BabbageEraInCardanoMode ->
error "TODO: Babbage era - depends on consensus exposing a babbage era"
BlockInMode (ShelleyBlock ShelleyBasedEraBabbage b') BabbageEraInCardanoMode -> Consensus.BlockBabbage b'

-- ----------------------------------------------------------------------------
-- Block headers
Expand Down Expand Up @@ -285,21 +293,22 @@ instance HasTypeProxy BlockHeader where
data AsType BlockHeader = AsBlockHeader
proxyToAsType _ = AsBlockHeader

getBlockHeader :: forall era . Block era -> BlockHeader
getBlockHeader
:: forall era . Block era -> BlockHeader
getBlockHeader (ShelleyBlock shelleyEra block) = case shelleyEra of
ShelleyBasedEraShelley -> go
ShelleyBasedEraAllegra -> go
ShelleyBasedEraMary -> go
ShelleyBasedEraAlonzo -> go
ShelleyBasedEraBabbage ->
error "TODO: Babbage era - depends on consensus exposing a babbage era"
ShelleyBasedEraBabbage -> go
where
go :: Consensus.ShelleyBasedEra (ShelleyLedgerEra era) => BlockHeader
go :: Consensus.ShelleyCompatible (ConsensusProtocol era) (ShelleyLedgerEra era)
=> BlockHeader
go = BlockHeader headerFieldSlot (HeaderHash hashSBS) headerFieldBlockNo
where
Consensus.HeaderFields {
Consensus.headerFieldHash
= Consensus.ShelleyHash (TPraos.HashHeader (Cardano.Crypto.Hash.Class.UnsafeHash hashSBS)),
= Consensus.ShelleyHash (Crypto.UnsafeHash hashSBS),
Consensus.headerFieldSlot,
Consensus.headerFieldBlockNo
} = Consensus.getHeaderFields block
Expand Down Expand Up @@ -361,28 +370,28 @@ fromConsensusPointHF (Consensus.BlockPoint slot (Consensus.OneEraHash h)) =

-- | Convert a 'Consensus.Point' for single Shelley-era block type
--
toConsensusPoint :: forall ledgerera.
Consensus.ShelleyBasedEra ledgerera
toConsensusPoint :: forall ledgerera protocol.
Consensus.ShelleyCompatible protocol ledgerera
=> ChainPoint
-> Consensus.Point (Consensus.ShelleyBlock ledgerera)
-> Consensus.Point (Consensus.ShelleyBlock protocol ledgerera)
toConsensusPoint ChainPointAtGenesis = Consensus.GenesisPoint
toConsensusPoint (ChainPoint slot (HeaderHash h)) =
Consensus.BlockPoint slot (Consensus.fromShortRawHash proxy h)
where
proxy :: Proxy (Consensus.ShelleyBlock ledgerera)
proxy :: Proxy (Consensus.ShelleyBlock protocol ledgerera)
proxy = Proxy

-- | Convert a 'Consensus.Point' for single Shelley-era block type
--
fromConsensusPoint :: forall ledgerera.
Consensus.ShelleyBasedEra ledgerera
=> Consensus.Point (Consensus.ShelleyBlock ledgerera)
fromConsensusPoint :: forall protocol ledgerera.
Consensus.ShelleyCompatible protocol ledgerera
=> Consensus.Point (Consensus.ShelleyBlock protocol ledgerera)
-> ChainPoint
fromConsensusPoint Consensus.GenesisPoint = ChainPointAtGenesis
fromConsensusPoint (Consensus.BlockPoint slot h) =
ChainPoint slot (HeaderHash (Consensus.toShortRawHash proxy h))
where
proxy :: Proxy (Consensus.ShelleyBlock ledgerera)
proxy :: Proxy (Consensus.ShelleyBlock protocol ledgerera)
proxy = Proxy

chainPointToSlotNo :: ChainPoint -> Maybe SlotNo
Expand Down Expand Up @@ -439,11 +448,11 @@ fromConsensusTip ByronMode = conv

fromConsensusTip ShelleyMode = conv
where
conv :: Consensus.Tip (Consensus.ShelleyBlockHFC Consensus.StandardShelley)
conv :: Consensus.Tip (Consensus.ShelleyBlockHFC (Consensus.TPraos Consensus.StandardCrypto) Consensus.StandardShelley)
-> ChainTip
conv Consensus.TipGenesis = ChainTipAtGenesis
conv (Consensus.Tip slot (Consensus.OneEraHash h) block) =
ChainTip slot (HeaderHash h) block
conv (Consensus.Tip slot (Consensus.OneEraHash hashSBS) block) =
ChainTip slot (HeaderHash hashSBS) block

fromConsensusTip CardanoMode = conv
where
Expand Down
36 changes: 21 additions & 15 deletions cardano-api/src/Cardano/Api/InMode.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ import qualified Ouroboros.Consensus.HardFork.Combinator as Consensus
import Ouroboros.Consensus.HardFork.Combinator.AcrossEras (EraMismatch)
import qualified Ouroboros.Consensus.HardFork.Combinator.Degenerate as Consensus
import qualified Ouroboros.Consensus.Ledger.SupportsMempool as Consensus
import qualified Ouroboros.Consensus.Shelley.HFEras as Consensus
import qualified Ouroboros.Consensus.Shelley.Ledger as Consensus
import qualified Ouroboros.Consensus.TypeFamilyWrappers as Consensus

import Cardano.Api.Eras
import Cardano.Api.Modes
import Cardano.Api.Tx
import Cardano.Api.TxBody
import Cardano.Api.TxBody (TxId, toByronTxId, toShelleyTxId)


-- ----------------------------------------------------------------------------
Expand Down Expand Up @@ -96,6 +97,10 @@ fromConsensusGenTx CardanoMode (Consensus.HardForkGenTx (Consensus.OneEraGenTx (
let Consensus.ShelleyTx _txid shelleyEraTx = tx'
in TxInMode (ShelleyTx ShelleyBasedEraAlonzo shelleyEraTx) AlonzoEraInCardanoMode

fromConsensusGenTx CardanoMode (Consensus.HardForkGenTx (Consensus.OneEraGenTx (S (S (S (S (S (Z tx')))))))) =
let Consensus.ShelleyTx _txid shelleyEraTx = tx'
in TxInMode (ShelleyTx ShelleyBasedEraBabbage shelleyEraTx) BabbageEraInCardanoMode

toConsensusGenTx :: ConsensusBlockForMode mode ~ block
=> TxInMode mode
-> Consensus.GenTx block
Expand Down Expand Up @@ -142,10 +147,10 @@ toConsensusGenTx (TxInMode (ShelleyTx _ tx) AlonzoEraInCardanoMode) =
where
tx' = Consensus.mkShelleyTx tx

toConsensusGenTx (TxInMode (ShelleyTx _ _tx) BabbageEraInCardanoMode) =
Consensus.HardForkGenTx (Consensus.OneEraGenTx (S (S (S (S (Z tx'))))))
toConsensusGenTx (TxInMode (ShelleyTx _ tx) BabbageEraInCardanoMode) =
Consensus.HardForkGenTx (Consensus.OneEraGenTx (S (S (S (S (S (Z tx')))))))
where
tx' = error "TODO: Babbage era - depends on consensus exposing a babbage era" -- Consensus.mkShelleyTx tx
tx' = Consensus.mkShelleyTx tx

-- ----------------------------------------------------------------------------
-- Transaction ids in the context of a consensus mode
Expand All @@ -171,9 +176,9 @@ toConsensusTxId (TxIdInMode txid ByronEraInByronMode) =
txid' = Consensus.ByronTxId $ toByronTxId txid

toConsensusTxId (TxIdInMode t ShelleyEraInShelleyMode) =
Consensus.HardForkGenTxId $ Consensus.OneEraGenTxId $ Z (Consensus.WrapGenTxId txid')
Consensus.HardForkGenTxId $ Consensus.OneEraGenTxId $ Z (Consensus.WrapGenTxId txid')
where
txid' :: Consensus.TxId (Consensus.GenTx (Consensus.ShelleyBlock Consensus.StandardShelley))
txid' :: Consensus.TxId (Consensus.GenTx Consensus.StandardShelleyBlock)
txid' = Consensus.ShelleyTxId $ toShelleyTxId t

toConsensusTxId (TxIdInMode txid ByronEraInCardanoMode) =
Expand All @@ -185,25 +190,25 @@ toConsensusTxId (TxIdInMode txid ByronEraInCardanoMode) =
toConsensusTxId (TxIdInMode txid ShelleyEraInCardanoMode) =
Consensus.HardForkGenTxId (Consensus.OneEraGenTxId (S (Z (Consensus.WrapGenTxId txid'))))
where
txid' :: Consensus.TxId (Consensus.GenTx (Consensus.ShelleyBlock Consensus.StandardShelley))
txid' :: Consensus.TxId (Consensus.GenTx Consensus.StandardShelleyBlock)
txid' = Consensus.ShelleyTxId $ toShelleyTxId txid

toConsensusTxId (TxIdInMode txid AllegraEraInCardanoMode) =
Consensus.HardForkGenTxId (Consensus.OneEraGenTxId (S (S (Z (Consensus.WrapGenTxId txid')))))
where
txid' :: Consensus.TxId (Consensus.GenTx (Consensus.ShelleyBlock Consensus.StandardAllegra))
txid' :: Consensus.TxId (Consensus.GenTx Consensus.StandardAllegraBlock)
txid' = Consensus.ShelleyTxId $ toShelleyTxId txid

toConsensusTxId (TxIdInMode txid MaryEraInCardanoMode) =
Consensus.HardForkGenTxId (Consensus.OneEraGenTxId (S (S (S (Z (Consensus.WrapGenTxId txid'))))))
where
txid' :: Consensus.TxId (Consensus.GenTx (Consensus.ShelleyBlock Consensus.StandardMary))
txid' :: Consensus.TxId (Consensus.GenTx Consensus.StandardMaryBlock)
txid' = Consensus.ShelleyTxId $ toShelleyTxId txid

toConsensusTxId (TxIdInMode txid AlonzoEraInCardanoMode) =
Consensus.HardForkGenTxId (Consensus.OneEraGenTxId (S (S (S (S (Z (Consensus.WrapGenTxId txid')))))))
where
txid' :: Consensus.TxId (Consensus.GenTx (Consensus.ShelleyBlock Consensus.StandardAlonzo))
txid' :: Consensus.TxId (Consensus.GenTx Consensus.StandardAlonzoBlock)
txid' = Consensus.ShelleyTxId $ toShelleyTxId txid

toConsensusTxId (TxIdInMode _txid BabbageEraInCardanoMode) =
Expand All @@ -224,7 +229,7 @@ data TxValidationError era where

ShelleyTxValidationError
:: ShelleyBasedEra era
-> Consensus.ApplyTxErr (Consensus.ShelleyBlock (ShelleyLedgerEra era))
-> Consensus.ApplyTxErr (Consensus.ShelleyBlock (ConsensusProtocol era) (ShelleyLedgerEra era))
-> TxValidationError era

-- The GADT in the ShelleyTxValidationError case requires a custom instance
Expand Down Expand Up @@ -290,10 +295,10 @@ fromConsensusApplyTxErr ByronMode (Consensus.DegenApplyTxErr err) =
(ByronTxValidationError err)
ByronEraInByronMode

fromConsensusApplyTxErr ShelleyMode (Consensus.DegenApplyTxErr err) =
TxValidationErrorInMode
(ShelleyTxValidationError ShelleyBasedEraShelley err)
ShelleyEraInShelleyMode
fromConsensusApplyTxErr ShelleyMode _ = error "TODO: Babbge (Consensus.DegenApplyTxErr err)"
--TxValidationErrorInMode
-- (ShelleyTxValidationError ShelleyBasedEraShelley err)
-- ShelleyEraInShelleyMode

fromConsensusApplyTxErr CardanoMode (Consensus.ApplyTxErrByron err) =
TxValidationErrorInMode
Expand Down Expand Up @@ -323,3 +328,4 @@ fromConsensusApplyTxErr CardanoMode (Consensus.ApplyTxErrAlonzo err) =
fromConsensusApplyTxErr CardanoMode (Consensus.ApplyTxErrWrongEra err) =
TxValidationEraMismatch err

fromConsensusApplyTxErr CardanoMode _ = error "TODO: Babbage"
16 changes: 8 additions & 8 deletions cardano-api/src/Cardano/Api/LedgerEvent.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,18 @@ import Cardano.Ledger.Shelley.Rewards
import Cardano.Ledger.Shelley.Rules.Epoch (EpochEvent (PoolReapEvent))
import Cardano.Ledger.Shelley.Rules.Mir (MirEvent (..))
import Cardano.Ledger.Shelley.Rules.NewEpoch
(NewEpochEvent (EpochEvent, MirEvent, DeltaRewardEvent, TotalRewardEvent))
(NewEpochEvent (DeltaRewardEvent, EpochEvent, MirEvent, TotalRewardEvent))
import Cardano.Ledger.Shelley.Rules.PoolReap (PoolreapEvent (RetiredPools))
import Cardano.Ledger.Shelley.Rules.Rupd (RupdEvent (RupdEvent))
import Cardano.Ledger.Shelley.Rules.Tick (TickEvent (NewEpochEvent))
import Control.State.Transition (Event)
import Data.Function (($), (.))
import Data.Functor (fmap)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Set (Set)
import Data.Maybe (Maybe (Just, Nothing))
import Data.SOP.Strict
import Data.Set (Set)
import Ouroboros.Consensus.Byron.Ledger.Block (ByronBlock)
import Ouroboros.Consensus.Cardano.Block (HardForkBlock)
import Ouroboros.Consensus.HardFork.Combinator.AcrossEras (getOneEraLedgerEvent)
Expand All @@ -51,7 +52,6 @@ import Ouroboros.Consensus.Ledger.Basics (AuxLedgerEvent)
import Ouroboros.Consensus.Shelley.Ledger (ShelleyBlock,
ShelleyLedgerEvent (ShelleyLedgerEventTICK))
import Ouroboros.Consensus.TypeFamilyWrappers
import Cardano.Ledger.Shelley.Rules.Rupd (RupdEvent(RupdEvent))

data LedgerEvent
= -- | The given pool is being registered for the first time on chain.
Expand Down Expand Up @@ -82,7 +82,7 @@ instance
Event (Ledger.Core.EraRule "MIR" ledgerera) ~ MirEvent ledgerera,
Event (Ledger.Core.EraRule "RUPD" ledgerera) ~ RupdEvent (Crypto ledgerera)
) =>
ConvertLedgerEvent (ShelleyBlock ledgerera)
ConvertLedgerEvent (ShelleyBlock protocol ledgerera)
where
toLedgerEvent evt = case unwrapLedgerEvent evt of
LEDeltaRewardEvent e m -> Just $ IncrementalRewardsDistribution e m
Expand Down Expand Up @@ -139,7 +139,7 @@ pattern LERewardEvent ::
) =>
EpochNo ->
Map StakeCredential (Set (Reward StandardCrypto)) ->
AuxLedgerEvent (LedgerState (ShelleyBlock ledgerera))
AuxLedgerEvent (LedgerState (ShelleyBlock protocol ledgerera))
pattern LERewardEvent e m <-
ShelleyLedgerEventTICK
(NewEpochEvent (TotalRewardEvent e (Map.mapKeys fromShelleyStakeCredential -> m)))
Expand All @@ -152,7 +152,7 @@ pattern LEDeltaRewardEvent ::
) =>
EpochNo ->
Map StakeCredential (Set (Reward StandardCrypto)) ->
AuxLedgerEvent (LedgerState (ShelleyBlock ledgerera))
AuxLedgerEvent (LedgerState (ShelleyBlock protocol ledgerera))
pattern LEDeltaRewardEvent e m <-
ShelleyLedgerEventTICK
(NewEpochEvent (DeltaRewardEvent (RupdEvent e (Map.mapKeys fromShelleyStakeCredential -> m))))
Expand All @@ -167,7 +167,7 @@ pattern LEMirTransfer ::
Map StakeCredential Lovelace ->
Lovelace ->
Lovelace ->
AuxLedgerEvent (LedgerState (ShelleyBlock ledgerera))
AuxLedgerEvent (LedgerState (ShelleyBlock protocol ledgerera))
pattern LEMirTransfer rp tp rtt ttr <-
ShelleyLedgerEventTICK
( NewEpochEvent
Expand All @@ -193,7 +193,7 @@ pattern LERetiredPools ::
Map StakeCredential (Map (Hash StakePoolKey) Lovelace) ->
Map StakeCredential (Map (Hash StakePoolKey) Lovelace) ->
EpochNo ->
AuxLedgerEvent (LedgerState (ShelleyBlock ledgerera))
AuxLedgerEvent (LedgerState (ShelleyBlock protocol ledgerera))
pattern LERetiredPools r u e <-
ShelleyLedgerEventTICK
( NewEpochEvent
Expand Down
Loading

0 comments on commit c5099a5

Please sign in to comment.