Skip to content

Commit fdd139a

Browse files
committed
fix parsing of Alonzo genesis.
1 parent ae1ae8b commit fdd139a

4 files changed

Lines changed: 99 additions & 14 deletions

File tree

clients/TypeScript/packages/client/src/Connection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export const Method = <
227227
try {
228228
const handler = res.handler || ((response, resolve, reject) => {
229229
if (response.method === req.method && response) {
230-
const success = response as unknown as { result: A | PromiseLike<A> };
230+
const success = response as unknown as { result: A | PromiseLike<A> }
231231
resolve(success.result)
232232
} else {
233233
reject(response)

clients/TypeScript/packages/client/test/LedgerStateQuery.test.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import {
66
DigestBlake2B256,
77
GenesisAlonzo,
88
GenesisByron,
9+
GenesisConway,
910
GenesisShelley,
1011
Point,
11-
QueryNetworkInvalidGenesis,
1212
RewardAccountSummary,
1313
Slot
1414
} from '@cardano-ogmios/schema'
@@ -84,14 +84,6 @@ describe('Local state queries', () => {
8484
expect(context.socket.readyState).toBe(context.socket.OPEN)
8585
})
8686

87-
it('rejects if the query is for another era', async () => {
88-
try {
89-
await client.genesisConfiguration('conway')
90-
} catch (e) {
91-
expect((e as QueryNetworkInvalidGenesis['error']).code).toBe(2004)
92-
}
93-
})
94-
9587
it('exposes the queries, uses a single context, and should be shutdowned when done', async () => {
9688
const epoch = await client.epoch()
9789
expect(epoch).toBeDefined()
@@ -119,6 +111,9 @@ describe('Local state queries', () => {
119111
const alonzoGenesis = await client.genesisConfiguration('alonzo')
120112
expect((alonzoGenesis as GenesisAlonzo).updatableParameters.minUtxoDepositCoefficient).toBeDefined()
121113

114+
const conwayGenesis = await client.genesisConfiguration('conway')
115+
expect((conwayGenesis as GenesisConway).constitution).toBeDefined()
116+
122117
const point = await client.ledgerTip() as { slot: Slot, id: DigestBlake2B256 }
123118
expect(point.slot).toBeDefined()
124119

@@ -224,13 +219,33 @@ describe('Local state queries', () => {
224219
expect(bound.epoch).toBeDefined()
225220
})
226221
})
227-
describe('genesisConfig', () => {
228-
it('fetches the config used to bootstrap the blockchain, excluding the genesis UTXO', async () => {
222+
describe('genesisConfig(byron)', () => {
223+
it('fetches the byron config used to bootstrap the blockchain, excluding the genesis UTXO', async () => {
224+
const config = await LedgerStateQuery.genesisConfiguration(context, 'byron')
225+
expect((config as GenesisByron).initialVouchers).toBeDefined()
226+
})
227+
})
228+
describe('genesisConfig(shelley)', () => {
229+
it('fetches the shelley config used to bootstrap the Shelley era', async () => {
229230
const config = await LedgerStateQuery.genesisConfiguration(context, 'shelley')
230231
expect((config as GenesisShelley).startTime).toBeDefined()
231232
expect((config as GenesisShelley).networkMagic).toBeDefined()
232233
})
233234
})
235+
describe('genesisConfig(alonzo)', () => {
236+
it('fetches the config used to bootstrap the Alonzo era', async () => {
237+
const config = await LedgerStateQuery.genesisConfiguration(context, 'alonzo')
238+
expect(config.updatableParameters.plutusCostModels['plutus:v1'])
239+
.toEqual([197209, 0, 1, 1, 396231, 621, 0, 1, 150000, 1000, 0, 1, 150000, 32, 2477736, 29175, 4, 29773, 100, 29773, 100, 29773, 100, 29773, 100, 29773, 100, 29773, 100, 100, 100, 29773, 100, 150000, 32, 150000, 32, 150000, 32, 150000, 1000, 0, 1, 150000, 32, 150000, 1000, 0, 8, 148000, 425507, 118, 0, 1, 1, 150000, 1000, 0, 8, 150000, 112536, 247, 1, 150000, 10000, 1, 136542, 1326, 1, 1000, 150000, 1000, 1, 150000, 32, 150000, 32, 150000, 32, 1, 1, 150000, 1, 150000, 4, 103599, 248, 1, 103599, 248, 1, 145276, 1366, 1, 179690, 497, 1, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 148000, 425507, 118, 0, 1, 1, 61516, 11218, 0, 1, 150000, 32, 148000, 425507, 118, 0, 1, 1, 148000, 425507, 118, 0, 1, 1, 2477736, 29175, 4, 0, 82363, 4, 150000, 5000, 0, 1, 150000, 32, 197209, 0, 1, 1, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 3345831, 1, 1])
240+
expect((config as GenesisAlonzo).updatableParameters.minUtxoDepositCoefficient).toBeDefined()
241+
})
242+
})
243+
describe('genesisConfig(conway)', () => {
244+
it('fetches the config used to bootstrap the Conway era', async () => {
245+
const config = await LedgerStateQuery.genesisConfiguration(context, 'conway')
246+
expect((config as GenesisConway).constitution).toBeDefined()
247+
})
248+
})
234249
describe('ledgerTip', () => {
235250
it('fetches the tip of the ledger', async () => {
236251
const point = await LedgerStateQuery.ledgerTip(context) as { slot: Slot, id: DigestBlake2B224 }

server/src/Ogmios/App/Configuration.hs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ import Data.Aeson
4848
, genericToEncoding
4949
)
5050
import Data.Aeson.Lens
51-
( _String
51+
( _JSON'
52+
, _String
53+
, _Value
5254
, key
5355
)
5456
import Data.Time.Clock.POSIX
@@ -78,7 +80,12 @@ import System.FilePath
7880
)
7981

8082
import qualified Cardano.Chain.Genesis as Byron
83+
import qualified Cardano.Ledger.Alonzo.Genesis as Ledger
84+
import qualified Cardano.Ledger.Api as Ledger
85+
import qualified Cardano.Ledger.Plutus as Ledger
8186
import qualified Data.Aeson as Json
87+
import qualified Data.Map as Map
88+
import qualified Data.Set as Set
8289
import qualified Data.Text as T
8390
import qualified Data.Yaml as Yaml
8491

@@ -137,7 +144,64 @@ readAlonzoGenesis configFile = do
137144
Nothing ->
138145
liftIO $ fail "Missing 'AlonzoGenesisFile' from node's configuration."
139146
Just (toString -> genesisFile) -> do
140-
Yaml.decodeFileThrow (replaceFileName configFile genesisFile)
147+
-- We have to decode Alonzo into an intermediate value first because
148+
-- the default JSON decoder from the cardano-ledge can no longer
149+
-- decode the genesis configuration.
150+
--
151+
-- The reason being that the decoder checks for the existence of
152+
-- various parameters in the cost model for Plutus V1. Yet, new
153+
-- parameters were added retro-actively to the cost model, so they
154+
-- aren't present in the genesis config. But the decoder doesn't
155+
-- care and fails.
156+
--
157+
-- So we have to manually add some placeholder key values to the
158+
-- base genesis, so that the decoder can succeed; only to drop them
159+
-- after from the map because they aren't actually part of the
160+
-- genesis configuration.
161+
value :: Yaml.Value <- Yaml.decodeFileThrow (replaceFileName configFile genesisFile)
162+
163+
let (costModelsWithFutureParams, sourceParamNames) = withFutureParameters (value ^. getter)
164+
where
165+
getter = key "costModels" . key "PlutusV1" . _JSON'
166+
167+
let valueWithPlaceholders = value & setter .~ Json.toJSON costModelsWithFutureParams
168+
where
169+
setter = key "costModels" . key "PlutusV1" . _Value
170+
171+
genesis <- liftIO $ Yaml.decodeThrow (Yaml.encode valueWithPlaceholders)
172+
173+
pure (withoutFutureParameters sourceParamNames genesis)
174+
where
175+
withFutureParameters :: Map Text Int64 -> (Map Text Int64, Set Text)
176+
withFutureParameters genesisParams = foldr
177+
(\paramName (params, sourceParamNames) ->
178+
case Map.lookup paramName params of
179+
Just{} -> (params, Set.insert paramName sourceParamNames)
180+
Nothing -> (Map.insert paramName 0 params, sourceParamNames)
181+
)
182+
(genesisParams, Set.empty)
183+
allV1ParamNames
184+
185+
allV1ParamNames :: [Text]
186+
allV1ParamNames = Ledger.costModelParamNames Ledger.PlutusV1
187+
188+
withoutFutureParameters :: Set Text -> GenesisConfig AlonzoEra -> GenesisConfig AlonzoEra
189+
withoutFutureParameters sourceParamNames config =
190+
let
191+
inner = Ledger.unAlonzoGenesisWrapper config
192+
costModels = Ledger.uappCostModels inner
193+
costModelsPruned = Map.adjust
194+
(either (error . show) identity
195+
. Ledger.mkCostModel Ledger.PlutusV1
196+
. Map.elems
197+
. (`Map.restrictKeys` sourceParamNames)
198+
. Ledger.costModelToMap
199+
)
200+
Ledger.PlutusV1
201+
(Ledger.costModelsValid costModels)
202+
in
203+
Ledger.AlonzoGenesisWrapper (inner { Ledger.uappCostModels = Ledger.mkCostModels costModelsPruned })
204+
141205

142206
readConwayGenesis :: MonadIO m => FilePath -> m (Either Text (GenesisConfig ConwayEra))
143207
readConwayGenesis configFile = do

server/src/Ogmios/Prelude.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module Ogmios.Prelude
2525
, typed
2626
, (^?)
2727
, (^.)
28+
, (.~)
2829

2930
-- * StrictMaybe
3031
, StrictMaybe
@@ -240,6 +241,11 @@ infixl 8 ^?
240241
s ^? l = getFirst (fmof l (First #. Just) s)
241242
where fmof l' f = getConst #. l' (Const #. f)
242243

244+
-- | Copied from https://hackage.haskell.org/package/generic-lens-2.2.2.0/docs/src/Data.Generics.Internal.VL.Lens.html#.~
245+
infixr 4 .~
246+
(.~) :: ((a -> Identity b) -> s -> Identity t) -> b -> s -> t
247+
(.~) f b = runIdentity . f (Identity . const b)
248+
243249
keepRedundantConstraint :: c => Proxy c -> ()
244250
keepRedundantConstraint _ = ()
245251

0 commit comments

Comments
 (0)