Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse decimals and output for rational fields in protocol parameters and genesis #2992

Merged
merged 2 commits into from
Jul 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cardano-api/cardano-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ library
Cardano.Api.HasTypeProxy
Cardano.Api.IPC
Cardano.Api.IPC.Monad
Cardano.Api.Json
Cardano.Api.Key
Cardano.Api.KeysByron
Cardano.Api.KeysPraos
Expand Down
21 changes: 21 additions & 0 deletions cardano-api/src/Cardano/Api/Json.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Cardano.Api.Json
( toRationalJSON
) where

import Data.Aeson
import Data.Either
import Data.Maybe
import Data.Scientific
import GHC.Real

-- Rationals and JSON are an awkward mix. We cannot convert rationals
-- like @1/3@ to JSON numbers. But _most_ of the numbers we want to use
-- in practice have simple decimal representations. Our solution here is
-- to use simple decimal representations where we can and representation
-- in a @{"numerator": 1, "denominator": 3}@ style otherwise.
--
toRationalJSON :: Rational -> Value
toRationalJSON r =
case fromRationalRepetendLimited 20 r of
Right (s, Nothing) -> toJSON s
_ -> toJSON r
11 changes: 6 additions & 5 deletions cardano-api/src/Cardano/Api/Orphans.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@ module Cardano.Api.Orphans () where

import Prelude

import Data.Aeson (FromJSON (..), ToJSON (..), object, (.=), (.!=), (.:), (.:?))
import qualified Data.Aeson as Aeson
import Data.Aeson.Types (FromJSONKey (..), ToJSONKey (..), toJSONKeyText)
import qualified Data.ByteString.Base16 as B16
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Data.Map.Strict as Map
import Data.Aeson (FromJSON (..), ToJSON (..), object, (.=), (.!=), (.:), (.:?))
import qualified Data.Aeson as Aeson
import Data.Aeson.Types (FromJSONKey (..), ToJSONKey (..), toJSONKeyText)

import Control.Applicative
import Control.Iterate.SetAlgebra (BiMap (..), Bimap)

import Cardano.Api.Json
import qualified Cardano.Ledger.BaseTypes as Ledger
import Cardano.Ledger.BaseTypes (StrictMaybe (..), strictMaybeToMaybe)
import Cardano.Ledger.Crypto (StandardCrypto)
Expand Down Expand Up @@ -302,8 +303,8 @@ deriving instance FromJSON Alonzo.ExUnits
instance ToJSON Alonzo.Prices where
toJSON Alonzo.Prices { Alonzo.prSteps, Alonzo.prMem } =
-- We cannot round-trip via NonNegativeInterval, so we go via Rational
object [ "prSteps" .= Ledger.unboundRational prSteps
, "prMem" .= Ledger.unboundRational prMem
object [ "prSteps" .= toRationalJSON (Ledger.unboundRational prSteps)
, "prMem" .= toRationalJSON (Ledger.unboundRational prMem)
]

instance FromJSON Alonzo.Prices where
Expand Down
31 changes: 9 additions & 22 deletions cardano-api/src/Cardano/Api/ProtocolParameters.hs
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,20 @@ module Cardano.Api.ProtocolParameters (

import Prelude

import Control.Monad
import Data.Aeson (FromJSON (..), ToJSON (..), object, withObject,
(.!=), (.:), (.:?), (.=))
import Data.Bifunctor (bimap)
import Data.ByteString (ByteString)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.String (IsString)
import qualified Data.Scientific as Scientific
import Data.Text (Text)
import Data.Maybe (fromMaybe)
import GHC.Generics
import Numeric.Natural

import Control.Monad

import Data.Aeson (FromJSON (..), ToJSON (..), object, withObject,
(.!=), (.:), (.:?), (.=))
import qualified Data.Aeson as Aeson
import Data.Bifunctor (bimap)

import Cardano.Api.Json
import qualified Cardano.Binary as CBOR
import qualified Cardano.Crypto.Hash.Class as Crypto
import Cardano.Slotting.Slot (EpochNo)
Expand Down Expand Up @@ -343,18 +340,6 @@ instance ToJSON ProtocolParameters where
, "collateralPercentage" .= protocolParamCollateralPercent
, "maxCollateralInputs" .= protocolParamMaxCollateralInputs
]
where
-- Rationals and JSON are an awkward mix. We cannot convert rationals
-- like @1/3@ to JSON numbers. But _most_ of the numbers we want to use
-- in practice have simple decimal representations. Our solution here is
-- to use simple decimal representations where we can and representation
-- in a @{"numerator": 1, "denominator": 3}@ style otherwise.
--
toRationalJSON :: Rational -> Aeson.Value
toRationalJSON r =
case Scientific.fromRationalRepetend (Just 5) r of
Right (s, Nothing) -> toJSON s
_ -> toJSON r


-- ----------------------------------------------------------------------------
Expand Down Expand Up @@ -475,6 +460,7 @@ data ProtocolParametersUpdate =
-- This is the \"tau\" incentives parameter from the design document.
--
protocolUpdateTreasuryCut :: Maybe Rational,

-- Introduced in Alonzo

-- | Cost in ada per word of UTxO storage.
Expand Down Expand Up @@ -714,8 +700,9 @@ instance FromCBOR ExecutionUnitPrices where

instance ToJSON ExecutionUnitPrices where
toJSON ExecutionUnitPrices{priceExecutionSteps, priceExecutionMemory} =
object [ "priceSteps" .= priceExecutionSteps
, "priceMemory" .= priceExecutionMemory ]
object [ "priceSteps" .= toRationalJSON priceExecutionSteps
, "priceMemory" .= toRationalJSON priceExecutionMemory
]

instance FromJSON ExecutionUnitPrices where
parseJSON =
Expand Down