Skip to content

Commit edb2ee4

Browse files
authored
Merge pull request #4904 from IntersectMBO/td/improve-txseq-decoders
Improve `TxSeq` decoders
2 parents 1dc13a2 + 5fedd3a commit edb2ee4

File tree

6 files changed

+84
-61
lines changed

6 files changed

+84
-61
lines changed

eras/alonzo/impl/src/Cardano/Ledger/Alonzo/TxSeq/Internal.hs

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,13 @@ import Cardano.Ledger.Binary (
4646
withSlice,
4747
)
4848
import Cardano.Ledger.Core
49-
import Cardano.Ledger.Shelley.BlockChain (constructMetadata, indexLookupSeq)
49+
import Cardano.Ledger.Shelley.BlockChain (auxDataSeqDecoder)
5050
import Control.Monad (unless)
5151
import Data.ByteString (ByteString)
5252
import Data.ByteString.Builder (shortByteString, toLazyByteString)
5353
import qualified Data.ByteString.Lazy as BSL
5454
import Data.Coerce (coerce)
55-
import qualified Data.Map.Strict as Map
5655
import Data.Maybe.Strict (maybeToStrictMaybe, strictMaybeToMaybe)
57-
import Data.Monoid (All (..))
5856
import Data.Proxy (Proxy (..))
5957
import qualified Data.Sequence as Seq
6058
import Data.Sequence.Strict (StrictSeq)
@@ -189,17 +187,10 @@ instance AlonzoEraTx era => DecCBOR (Annotator (AlonzoTxSeq era)) where
189187
let bodiesLength = length bodies
190188
inRange x = (0 <= x) && (x <= (bodiesLength - 1))
191189
witsLength = length wits
192-
(auxData, auxDataAnn) <- withSlice $
193-
do
194-
auxDataMap <- decCBOR
195-
unless
196-
(getAll (Map.foldMapWithKey (\k _ -> All (inRange k)) auxDataMap))
197-
( fail
198-
( "Some Auxiliarydata index is not in the range: 0 .. "
199-
++ show (bodiesLength - 1)
200-
)
201-
)
202-
pure (constructMetadata bodiesLength auxDataMap)
190+
(auxData, auxDataAnn) <- withSlice $ do
191+
auxDataMap <- decCBOR
192+
auxDataSeqDecoder bodiesLength auxDataMap False
193+
203194
(isValIdxs, isValAnn) <- withSlice decCBOR
204195
let validFlags = alignedValidFlags bodiesLength isValIdxs
205196
unless
@@ -248,14 +239,7 @@ instance
248239
let bodiesLength = length bodies
249240
inRange x = (0 <= x) && (x <= (bodiesLength - 1))
250241
witsLength = length wits
251-
unless
252-
(getAll (Map.foldMapWithKey (\k _ -> All (inRange k)) auxDataMap))
253-
( fail
254-
( "Some Auxiliarydata index is not in the range: 0 .. "
255-
++ show (bodiesLength - 1)
256-
)
257-
)
258-
let auxData = indexLookupSeq bodiesLength auxDataMap
242+
auxData <- auxDataSeqDecoder @(TxAuxData era) bodiesLength auxDataMap False
259243
Annotated isValidIdxs isValidBytes <- decodeAnnotated decCBOR
260244
let validFlags = alignedValidFlags bodiesLength isValidIdxs
261245
unless

eras/shelley/impl/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## 1.16.0.0
44

5+
* Add `auxDataSeqDecoder`
6+
* Remove `constructMetadata`
57
* Remove `getProposedPPUpdates` as no longer relevant
68
* Remove `proposalsL` and `futureProposalsL` as unused
79
* Remove redundant supercalss constraints for `ApplyBlock`
@@ -16,7 +18,6 @@
1618
* `ShelleyTxBody`
1719
* `ShelleyTx`
1820
* `ShelleyTxSeq`
19-
* Add `indexLookupSeq`
2021
* Add `segWitTx`
2122
* Rename `segwitTx` to `segWitAnnTx`
2223
* Converted `CertState` to a type family

eras/shelley/impl/src/Cardano/Ledger/Shelley/BlockChain.hs

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818

1919
module Cardano.Ledger.Shelley.BlockChain (
2020
ShelleyTxSeq (ShelleyTxSeq, txSeqTxns', TxSeq'),
21-
constructMetadata,
22-
indexLookupSeq,
21+
auxDataSeqDecoder,
2322
txSeqTxns,
2423
bbHash,
2524
bBodySize,
@@ -61,7 +60,9 @@ import Control.Monad (unless)
6160
import Data.ByteString (ByteString)
6261
import qualified Data.ByteString.Lazy as BSL
6362
import Data.Coerce (coerce)
64-
import Data.Map.Strict (Map)
63+
import Data.Functor.Identity (Identity (..))
64+
import Data.IntMap (IntMap)
65+
import qualified Data.IntMap as IntMap
6566
import qualified Data.Map.Strict as Map
6667
import Data.Monoid (All (..))
6768
import Data.Sequence (Seq)
@@ -191,18 +192,6 @@ bbHash (TxSeq' _ bodies wits md) =
191192
hashStrict = Hash.hashWith id
192193
hashPart = Hash.hashToBytes . hashStrict . BSL.toStrict
193194

194-
-- | Given a size and a mapping from indices to maybe metadata,
195-
-- return a sequence whose size is the size parameter and
196-
-- whose non-Nothing values correspond to the values in the mapping.
197-
constructMetadata ::
198-
Int ->
199-
Map Int (Annotator (TxAuxData era)) ->
200-
Seq (Maybe (Annotator (TxAuxData era)))
201-
constructMetadata = indexLookupSeq
202-
203-
indexLookupSeq :: Int -> Map Int a -> Seq (Maybe a)
204-
indexLookupSeq n md = fmap (`Map.lookup` md) (Seq.fromList [0 .. n - 1])
205-
206195
-- | The parts of the Tx in Blocks that have to have DecCBOR(Annotator x) instances.
207196
-- These are exactly the parts that are SafeToHash.
208197
-- | Decode a TxSeq, used in decoding a Block.
@@ -215,24 +204,19 @@ txSeqDecoder ::
215204
txSeqDecoder lax = do
216205
(bodies, bodiesAnn) <- withSlice decCBOR
217206
(wits, witsAnn) <- withSlice decCBOR
218-
let b = length bodies
219-
inRange x = (0 <= x) && (x <= (b - 1))
220-
w = length wits
221-
(metadata, metadataAnn) <- withSlice $
222-
do
223-
m <- decCBOR
224-
unless -- TODO this PR introduces this new test, That didn't used to run in the Shelley
225-
(lax || all inRange (Map.keysSet m)) -- Era, Is it possible there might be some blocks, that should have been caught on the chain?
226-
(fail ("Some Auxiliarydata index is not in the range: 0 .. " ++ show (b - 1)))
227-
pure (constructMetadata @era b m)
207+
let bodiesLength = length bodies
208+
witsLength = length wits
209+
(metadata, metadataAnn) <- withSlice $ do
210+
auxDataMap <- decCBOR
211+
auxDataSeqDecoder bodiesLength auxDataMap lax
228212

229213
unless
230-
(lax || b == w)
214+
(lax || bodiesLength == witsLength)
231215
( fail $
232216
"different number of transaction bodies ("
233-
<> show b
217+
<> show bodiesLength
234218
<> ") and witness sets ("
235-
<> show w
219+
<> show witsLength
236220
<> ")"
237221
)
238222

@@ -242,6 +226,21 @@ txSeqDecoder lax = do
242226
Seq.zipWith3 segWitAnnTx bodies wits metadata
243227
pure $ TxSeq' <$> txns <*> bodiesAnn <*> witsAnn <*> metadataAnn
244228

229+
auxDataSeqDecoder ::
230+
Int -> IntMap a -> Bool -> Decoder s (Seq (Maybe a))
231+
auxDataSeqDecoder bodiesLength auxDataMap lax = do
232+
unless
233+
(lax || getAll (IntMap.foldMapWithKey (\k _ -> All (inRange k)) auxDataMap))
234+
(fail ("Some Auxiliarydata index is not in the range: 0 .. " ++ show (bodiesLength - 1)))
235+
pure (indexLookupSeq bodiesLength auxDataMap)
236+
where
237+
inRange x = (0 <= x) && (x <= (bodiesLength - 1))
238+
-- Given a size and a mapping from indices to maybe values,
239+
-- return a sequence whose size is the size parameter and
240+
-- whose non-Nothing values correspond to the values in the mapping.
241+
indexLookupSeq :: Int -> IntMap a -> Seq (Maybe a)
242+
indexLookupSeq n ixMap = Seq.fromList [IntMap.lookup ix ixMap | ix <- [0 .. n - 1]]
243+
245244
instance EraTx era => DecCBOR (Annotator (ShelleyTxSeq era)) where
246245
decCBOR = txSeqDecoder False
247246

@@ -256,13 +255,12 @@ instance
256255
decCBOR = do
257256
Annotated bodies bodiesBytes <- decodeAnnotated decCBOR
258257
Annotated wits witsBytes <- decodeAnnotated decCBOR
259-
Annotated auxDataMap auxDataBytes <- decodeAnnotated decCBOR
258+
Annotated (auxDataMap :: IntMap (TxAuxData era)) auxDataBytes <- decodeAnnotated decCBOR
260259
let bodiesLength = length bodies
261-
let inRange x = (0 <= x) && (x <= (bodiesLength - 1))
262-
unless
263-
(getAll (Map.foldMapWithKey (\k _ -> All (inRange k)) auxDataMap))
264-
(fail ("Some Auxiliarydata index is not in the range: 0 .. " ++ show (bodiesLength - 1)))
265-
let auxData = indexLookupSeq bodiesLength auxDataMap
260+
auxData <-
261+
fmap (fmap runIdentity)
262+
<$> auxDataSeqDecoder bodiesLength (fmap pure auxDataMap) False
263+
266264
let witsLength = length wits
267265
unless
268266
(bodiesLength == witsLength)

libs/cardano-ledger-binary/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## 1.6.0.0
44

5+
* Add `DecCBOR` instance for `Data.IntMap`
6+
* Add `decodeIntMap`
57
* Add `ToCBOR` instance for `PV1.Data`
68
* Add `DecCBOR` instance for `Annotated a ByteString`
79
* Add `originalBytesExpectedFailureMessage` needed for testing

libs/cardano-ledger-binary/src/Cardano/Ledger/Binary/Decoding/DecCBOR.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import Data.ByteString.Short.Internal (ShortByteString(SBS))
6666
import Data.Fixed (Fixed (..))
6767
import Data.IP (IPv4, IPv6)
6868
import Data.Int (Int16, Int32, Int64, Int8)
69+
import qualified Data.IntMap as IntMap
6970
import Data.List.NonEmpty (NonEmpty)
7071
import qualified Data.Map.Strict as Map
7172
import qualified Data.Maybe.Strict as SMaybe
@@ -406,6 +407,10 @@ instance (Ord k, DecCBOR k, DecCBOR v) => DecCBOR (Map.Map k v) where
406407
decCBOR = decodeMap decCBOR decCBOR
407408
{-# INLINE decCBOR #-}
408409

410+
instance DecCBOR v => DecCBOR (IntMap.IntMap v) where
411+
decCBOR = decodeIntMap decCBOR
412+
{-# INLINE decCBOR #-}
413+
409414
instance
410415
( Ord k
411416
, DecCBOR k

libs/cardano-ledger-binary/src/Cardano/Ledger/Binary/Decoding/Decoder.hs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ module Cardano.Ledger.Binary.Decoding.Decoder (
6767
decodeVector,
6868
decodeSet,
6969
setTag,
70+
decodeIntMap,
7071
decodeMap,
7172
decodeMapByKey,
7273
decodeMapLikeEnforceNoDuplicates,
@@ -259,6 +260,7 @@ import qualified Data.ByteString.Lazy as BSL
259260
import Data.Functor.Compose (Compose (..))
260261
import Data.IP (IPv4, IPv6, fromHostAddress, fromHostAddress6)
261262
import Data.Int (Int16, Int32, Int64, Int8)
263+
import qualified Data.IntMap as IntMap
262264
import qualified Data.List.NonEmpty as NE (NonEmpty, nonEmpty)
263265
import qualified Data.Map.Strict as Map
264266
import Data.Maybe.Strict (StrictMaybe (..), maybeToStrictMaybe)
@@ -794,15 +796,46 @@ decodeMapLikeEnforceNoDuplicates ::
794796
Decoder s (Maybe Int) ->
795797
Decoder s (k, v) ->
796798
Decoder s (Map.Map k v)
797-
decodeMapLikeEnforceNoDuplicates decodeLenOrIndef =
799+
decodeMapLikeEnforceNoDuplicates =
800+
decodeMapLikeEnforceNoDuplicatesInternal Map.fromList Map.size
801+
{-# INLINE decodeMapLikeEnforceNoDuplicates #-}
802+
803+
decodeMapLikeEnforceNoDuplicatesInternal ::
804+
([(k, v)] -> m) ->
805+
(m -> Int) ->
806+
Decoder s (Maybe Int) ->
807+
Decoder s (k, v) ->
808+
Decoder s m
809+
decodeMapLikeEnforceNoDuplicatesInternal fromPairs size decodeLenOrIndef =
798810
-- We first decode into a list because most of the time the encoded Map will be in sorted
799811
-- order and there is a nice optimization on the `Map.fromList` that can take advantage of
800812
-- that fact. In case when encoded data is not sorted the penalty of going through a list
801813
-- is insignificant.
802814
decodeListLikeEnforceNoDuplicates decodeLenOrIndef (:) $ \xs ->
803-
let result = Map.fromList (reverse xs)
804-
in (Map.size result, result)
805-
{-# INLINE decodeMapLikeEnforceNoDuplicates #-}
815+
let result = fromPairs (reverse xs)
816+
in (size result, result)
817+
818+
decodeIntMap :: Decoder s v -> Decoder s (IntMap.IntMap v)
819+
decodeIntMap decodeValue =
820+
ifDecoderVersionAtLeast
821+
(natVersion @2)
822+
( ifDecoderVersionAtLeast
823+
(natVersion @9)
824+
( decodeMapLikeEnforceNoDuplicatesInternal
825+
IntMap.fromList
826+
IntMap.size
827+
decodeMapLenOrIndef
828+
decodeKeyValue
829+
)
830+
(IntMap.fromList <$> decodeCollection decodeMapLenOrIndef decodeKeyValue)
831+
)
832+
( decodeMapSkel
833+
(IntMap.fromDistinctAscList . reverse)
834+
decodeKeyValue
835+
)
836+
where
837+
decodeKeyValue = (,) <$> decodeInt <*> decodeValue
838+
{-# INLINE decodeIntMap #-}
806839

807840
-- | Decode `VMap`. Unlike `decodeMap` it does not behavee differently for
808841
-- version prior to 2.

0 commit comments

Comments
 (0)