@@ -30,19 +30,21 @@ module Cardano.Ledger.Dijkstra.BlockBody.Internal (
3030 alignedValidFlags ,
3131 mkBasicBlockBodyDijkstra ,
3232 DijkstraEraBlockBody (.. ),
33+ LeiosCert ,
3334) where
3435
3536import qualified Cardano.Crypto.Hash as Hash
3637import Cardano.Ledger.Alonzo.Tx (AlonzoEraTx (.. ), IsValid (.. ))
37- import Cardano.Ledger.BaseTypes (PerasCert )
38+ import Cardano.Ledger.BaseTypes (LeiosCert , PerasCert )
3839import Cardano.Ledger.Binary (
3940 Annotator (.. ),
4041 DecCBOR (.. ),
4142 EncCBORGroup (.. ),
42- decodeListLen ,
43+ decodeNullStrictMaybe ,
4344 encCBOR ,
4445 encodeFoldableEncoder ,
4546 encodeFoldableMapEncoder ,
47+ encodeNullStrictMaybe ,
4648 encodePreEncoded ,
4749 serialize ,
4850 withSlice ,
@@ -53,7 +55,6 @@ import Cardano.Ledger.Dijkstra.Tx ()
5355import Cardano.Ledger.Shelley.BlockBody (auxDataSeqDecoder )
5456import Control.DeepSeq (NFData )
5557import Control.Monad (unless )
56- import Data.Bifunctor (Bifunctor (.. ))
5758import Data.ByteString (ByteString )
5859import Data.ByteString.Builder (Builder , shortByteString , toLazyByteString )
5960import qualified Data.ByteString.Lazy as BSL
@@ -84,6 +85,9 @@ import NoThunks.Class (AllowThunksIn (..), NoThunks)
8485
8586data DijkstraBlockBody era = DijkstraBlockBodyInternal
8687 { dbbTxs :: ! (StrictSeq (Tx TopTx era ))
88+ , dbbLeiosCert :: ! (StrictMaybe LeiosCert )
89+ -- ^ Optional Leios certificate. When 'SJust', the EB closure carrying
90+ -- the actual transactions must be looked up via the LeiosDB.
8791 , dbbPerasCert :: ! (StrictMaybe PerasCert )
8892 -- ^ Optional Peras certificate
8993 , dbbHash :: Hash. Hash HASH EraIndependentBlockBody
@@ -98,81 +102,112 @@ data DijkstraBlockBody era = DijkstraBlockBodyInternal
98102 , dbbTxsIsValidBytes :: BSL. ByteString
99103 -- ^ Bytes representing a set of integers. These are the indices of
100104 -- transactions with 'isValid' == False.
105+ , dbbLeiosCertBytes :: Maybe BSL. ByteString
106+ -- ^ Bytes encoding the optional Leios certificate
101107 , dbbPerasCertBytes :: Maybe BSL. ByteString
102108 -- ^ Bytes encoding the optional Peras certificate
103109 }
104110 deriving (Generic )
105111
106- instance (NFData (Tx TopTx era ), NFData PerasCert ) => NFData (DijkstraBlockBody era )
112+ instance
113+ (NFData (Tx TopTx era ), NFData LeiosCert , NFData PerasCert ) =>
114+ NFData (DijkstraBlockBody era )
107115
108116instance EraBlockBody DijkstraEra where
109117 type BlockBody DijkstraEra = DijkstraBlockBody DijkstraEra
110118 mkBasicBlockBody = mkBasicBlockBodyDijkstra
111- txSeqBlockBodyL = lens dbbTxs (\ bb p -> bb {dbbTxs = p})
119+
120+ -- Rebuild via the bidirectional pattern so the cached body/wits/aux/isvalid
121+ -- bytes and the body hash are recomputed for the new tx sequence. Mirrors
122+ -- the Alonzo idiom 'lens abbTxs (\_ s -> AlonzoBlockBody s)'.
123+ txSeqBlockBodyL =
124+ lens dbbTxs (\ bb txs -> DijkstraBlockBody txs (dbbLeiosCert bb) (dbbPerasCert bb))
112125 hashBlockBody = dbbHash
113- numSegComponents = 5
126+ numSegComponents = 6
114127
115128mkBasicBlockBodyDijkstra ::
116129 ( SafeToHash (TxWits era )
117130 , BlockBody era ~ DijkstraBlockBody era
118131 , AlonzoEraTx era
119132 ) =>
120133 BlockBody era
121- mkBasicBlockBodyDijkstra = DijkstraBlockBody mempty SNothing
134+ mkBasicBlockBodyDijkstra = DijkstraBlockBody mempty SNothing SNothing
122135{-# INLINEABLE mkBasicBlockBodyDijkstra #-}
123136
124137-- | Dijkstra-specific extensions to 'EraBlockBody'
125138class EraBlockBody era => DijkstraEraBlockBody era where
139+ leiosCertBlockBodyL :: Lens' (BlockBody era ) (StrictMaybe LeiosCert )
140+ -- ^ Lens to access the optional Leios certificate in the block body
141+
126142 perasCertBlockBodyL :: Lens' (BlockBody era ) (StrictMaybe PerasCert )
127143 -- ^ Lens to access the optional Peras certificate in the block body
128144
129145instance DijkstraEraBlockBody DijkstraEra where
130- perasCertBlockBodyL = lens dbbPerasCert (\ bb c -> bb {dbbPerasCert = c})
146+ leiosCertBlockBodyL =
147+ lens dbbLeiosCert (\ bb c -> DijkstraBlockBody (dbbTxs bb) c (dbbPerasCert bb))
148+ perasCertBlockBodyL =
149+ lens dbbPerasCert (\ bb c -> DijkstraBlockBody (dbbTxs bb) (dbbLeiosCert bb) c)
131150
132151pattern DijkstraBlockBody ::
133152 forall era.
134153 ( AlonzoEraTx era
135154 , SafeToHash (TxWits era)
136155 ) =>
137156 StrictSeq (Tx TopTx era) ->
157+ StrictMaybe LeiosCert ->
138158 StrictMaybe PerasCert ->
139159 DijkstraBlockBody era
140- pattern DijkstraBlockBody xs mbPerasCert <-
141- DijkstraBlockBodyInternal xs mbPerasCert _ _ _ _ _ _
160+ pattern DijkstraBlockBody xs mbLeiosCert mbPerasCert <-
161+ DijkstraBlockBodyInternal xs mbLeiosCert mbPerasCert _ _ _ _ _ _ _
142162 where
143- DijkstraBlockBody txns mbPerasCert =
163+ DijkstraBlockBody txns mbLeiosCert mbPerasCert =
144164 let version = eraProtVerLow @ era
145165 serializeFoldablePreEncoded x =
146166 serialize version $
147167 encodeFoldableEncoder encodePreEncoded x
148168 metaChunk index m = encodeIndexed <$> strictMaybeToMaybe m
149169 where
150170 encodeIndexed metadata = encCBOR index <> encodePreEncoded metadata
151- txSeqBodies =
152- serializeFoldablePreEncoded $ originalBytes . view bodyTxL <$> txns
153- txSeqWits =
154- serializeFoldablePreEncoded $ originalBytes . view witsTxL <$> txns
155- txSeqAuxDatas =
156- serialize version . encodeFoldableMapEncoder metaChunk $
157- fmap originalBytes . view auxDataTxL <$> txns
158- txSeqIsValids =
159- serialize version $ encCBOR $ nonValidatingIndices txns
171+ -- NOTE: When the block contains a LeiosCert, any transactions must
172+ -- not be encoded or contribute to the block body hash.
173+ (txSeqBodies, txSeqWits, txSeqAuxDatas, txSeqIsValids) =
174+ case mbLeiosCert of
175+ SJust _ ->
176+ ( serializeFoldablePreEncoded (mempty :: StrictSeq ByteString )
177+ , serializeFoldablePreEncoded (mempty :: StrictSeq ByteString )
178+ , serialize
179+ version
180+ (encodeFoldableMapEncoder metaChunk (mempty :: StrictSeq (StrictMaybe ByteString )))
181+ , serialize version (encCBOR ([] :: [Int ]))
182+ )
183+ SNothing ->
184+ ( serializeFoldablePreEncoded $ originalBytes . view bodyTxL <$> txns
185+ , serializeFoldablePreEncoded $ originalBytes . view witsTxL <$> txns
186+ , serialize version . encodeFoldableMapEncoder metaChunk $
187+ fmap originalBytes . view auxDataTxL <$> txns
188+ , serialize version $ encCBOR $ nonValidatingIndices txns
189+ )
190+ mbLeiosCertBytes =
191+ Just (serialize version (encodeNullStrictMaybe encCBOR mbLeiosCert))
160192 mbPerasCertBytes =
161- fmap (serialize version) (strictMaybeToMaybe mbPerasCert)
193+ Just (serialize version (encodeNullStrictMaybe encCBOR mbPerasCert) )
162194 in DijkstraBlockBodyInternal
163195 { dbbTxs = txns
196+ , dbbLeiosCert = mbLeiosCert
164197 , dbbPerasCert = mbPerasCert
165198 , dbbHash =
166199 hashDijkstraSegWits
167200 txSeqBodies
168201 txSeqWits
169202 txSeqAuxDatas
170203 txSeqIsValids
204+ mbLeiosCertBytes
171205 mbPerasCertBytes
172206 , dbbTxsBodyBytes = txSeqBodies
173207 , dbbTxsWitsBytes = txSeqWits
174208 , dbbTxsAuxDataBytes = txSeqAuxDatas
175209 , dbbTxsIsValidBytes = txSeqIsValids
210+ , dbbLeiosCertBytes = mbLeiosCertBytes
176211 , dbbPerasCertBytes = mbPerasCertBytes
177212 }
178213
@@ -185,6 +220,7 @@ deriving via
185220 , " dbbTxsWitsBytes"
186221 , " dbbTxsAuxDataBytes"
187222 , " dbbTxsIsValidBytes"
223+ , " dbbLeiosCertBytes"
188224 , " dbbPerasCertBytes"
189225 ]
190226 (DijkstraBlockBody era)
@@ -207,8 +243,13 @@ instance Era era => EncCBORGroup (DijkstraBlockBody era) where
207243 <> dbbTxsWitsBytes blockBody
208244 <> dbbTxsAuxDataBytes blockBody
209245 <> dbbTxsIsValidBytes blockBody
246+ <> fromMaybe BSL. empty (dbbLeiosCertBytes blockBody)
210247 <> fromMaybe BSL. empty (dbbPerasCertBytes blockBody)
211- listLen _ = 5
248+
249+ -- The cert byte fields always encode something (a CBOR null when
250+ -- absent, the cert value when present), so the body always has 6
251+ -- elements.
252+ listLen _ = 6
212253
213254hashDijkstraSegWits ::
214255 BSL. ByteString ->
@@ -220,14 +261,17 @@ hashDijkstraSegWits ::
220261 BSL. ByteString ->
221262 -- | Bytes for transaction isValid flags
222263 Maybe BSL. ByteString ->
264+ -- | Bytes for optional Leios certificate
265+ Maybe BSL. ByteString ->
223266 -- | Bytes for optional Peras certificate
224267 Hash HASH EraIndependentBlockBody
225- hashDijkstraSegWits txSeqBodies txSeqWits txAuxData txSeqIsValids mbPerasCert =
268+ hashDijkstraSegWits txSeqBodies txSeqWits txAuxData txSeqIsValids mbLeiosCert mbPerasCert =
226269 coerce . hashLazy . toLazyByteString $
227270 hashPart txSeqBodies
228271 <> hashPart txSeqWits
229272 <> hashPart txAuxData
230273 <> hashPart txSeqIsValids
274+ <> maybe mempty hashPart mbLeiosCert
231275 <> maybe mempty hashPart mbPerasCert
232276 where
233277 hashLazy :: BSL. ByteString -> Hash HASH ByteString
@@ -246,9 +290,12 @@ instance
246290 ) =>
247291 DecCBOR (Annotator (DijkstraBlockBody era ))
248292 where
293+ -- The body is encoded as 6 group elements (via 'encCBORGroup'), so
294+ -- the outer 'decodeRecordNamed \"Block\" (const 7)' in
295+ -- 'Cardano.Ledger.Block' already consumed the list-length header.
296+ -- We just sequence the 6 items here (no inner 'decodeListLen'),
297+ -- matching the Alonzo/Conway-style body decoder.
249298 decCBOR = do
250- len <- decodeListLen
251-
252299 (bodies, bodiesAnn) <- withSlice decCBOR
253300 (wits, witsAnn) <- withSlice decCBOR
254301 let bodiesLength = length bodies
@@ -279,27 +326,35 @@ instance
279326 StrictSeq. forceToStrict $
280327 Seq. zipWith4 dijkstraSegwitTx bodies wits validFlags auxData
281328
282- (mbPerasCert, mbPerasCertAnn) <-
283- case len of
284- 4 -> return (pure SNothing , pure Nothing )
285- 5 -> bimap (pure . SJust ) (fmap Just ) <$> withSlice decCBOR
286- _ -> fail $ " unexpected body length: " <> show len
329+ -- Each cert slot is always present as 'encodeNullStrictMaybe'
330+ -- (CBOR null when absent, value when present).
331+ (leios, leiosSliceAnn) <-
332+ withSlice (decodeNullStrictMaybe (decCBOR @ LeiosCert ))
333+ (peras, perasSliceAnn) <-
334+ withSlice (decodeNullStrictMaybe (decCBOR @ PerasCert ))
335+ let mbLeiosCert = pure leios
336+ mbLeiosCertAnn = Just <$> leiosSliceAnn
337+ mbPerasCert = pure peras
338+ mbPerasCertAnn = Just <$> perasSliceAnn
287339
288340 pure $
289341 DijkstraBlockBodyInternal
290342 <$> txns
343+ <*> mbLeiosCert
291344 <*> mbPerasCert
292345 <*> ( hashDijkstraSegWits
293346 <$> bodiesAnn
294347 <*> witsAnn
295348 <*> auxDataAnn
296349 <*> isValAnn
350+ <*> mbLeiosCertAnn
297351 <*> mbPerasCertAnn
298352 )
299353 <*> bodiesAnn
300354 <*> witsAnn
301355 <*> auxDataAnn
302356 <*> isValAnn
357+ <*> mbLeiosCertAnn
303358 <*> mbPerasCertAnn
304359
305360--------------------------------------------------------------------------------
0 commit comments