Skip to content

Commit db16bde

Browse files
committed
Flip TxIx serialization to big endian
1 parent b433ed7 commit db16bde

File tree

16 files changed

+123
-34
lines changed

16 files changed

+123
-34
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!--
2+
A new scriv changelog fragment.
3+
4+
Uncomment the section that is right (remove the HTML comment wrapper).
5+
For top level release notes, leave all the headers commented out.
6+
-->
7+
8+
<!--
9+
### Patch
10+
11+
- A bullet item for the Patch category.
12+
13+
-->
14+
<!--
15+
### Non-Breaking
16+
17+
- A bullet item for the Non-Breaking category.
18+
19+
-->
20+
21+
### Breaking
22+
23+
- Change `TxIn (ShelleyBlock proto era)` to `BigEndianTxIn` which is a newtype wrapper over `TxIn` that *only* modifies the `MemPack` instance to ensure big-endian serialization.
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

ouroboros-consensus-cardano/src/ouroboros-consensus-cardano/Ouroboros/Consensus/Cardano/CanHardFork.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ translateLedgerStateShelleyToAllegraWrapper =
466466
LedgerTables
467467
. DiffMK
468468
. Diff.fromMapDeletes
469+
. coerceTxInMapKeys
469470
. Map.map SL.upgradeTxOut
470471
$ avvms
471472

@@ -478,6 +479,7 @@ translateLedgerStateShelleyToAllegraWrapper =
478479
. withLedgerTables ls
479480
. LedgerTables
480481
. ValuesMK
482+
. coerceTxInMapKeys
481483
$ avvms
482484

483485
resultingState =

ouroboros-consensus-cardano/src/ouroboros-consensus-cardano/Ouroboros/Consensus/Cardano/Ledger.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import Cardano.Ledger.Binary.Decoding hiding (Decoder)
2828
import Cardano.Ledger.Binary.Encoding hiding (Encoding)
2929
import qualified Cardano.Ledger.Conway.State as SL
3030
import Cardano.Ledger.Core (Era, eraDecoder, eraProtVerLow)
31-
import qualified Cardano.Ledger.Shelley.API as SL
3231
import Cardano.Ledger.Shelley.LedgerState as SL
3332
( esLStateL
3433
, lsCertStateL
@@ -57,7 +56,8 @@ import Ouroboros.Consensus.Ledger.Tables
5756
import Ouroboros.Consensus.Protocol.Praos (Praos)
5857
import Ouroboros.Consensus.Protocol.TPraos (TPraos)
5958
import Ouroboros.Consensus.Shelley.Ledger
60-
( IsShelleyBlock
59+
( BigEndianTxIn
60+
, IsShelleyBlock
6161
, ShelleyBlock
6262
, ShelleyCompatible
6363
, shelleyLedgerState
@@ -70,7 +70,7 @@ instance
7070
HasCanonicalTxIn (CardanoEras c)
7171
where
7272
newtype CanonicalTxIn (CardanoEras c) = CardanoTxIn
73-
{ getCardanoTxIn :: SL.TxIn
73+
{ getCardanoTxIn :: BigEndianTxIn
7474
}
7575
deriving stock (Show, Eq, Ord)
7676
deriving newtype NoThunks

ouroboros-consensus-cardano/src/ouroboros-consensus-cardano/Ouroboros/Consensus/Cardano/QueryHF.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
module Ouroboros.Consensus.Cardano.QueryHF () where
2121

22+
import Data.Coerce
2223
import Data.Functor.Product
2324
import Data.SOP.BasicFunctors
2425
import Data.SOP.Constraint
@@ -98,14 +99,14 @@ instance CardanoHardForkConstraints c => BlockSupportsHFLedgerQuery (CardanoEras
9899
answerShelleyLookupQueries
99100
(injectLedgerTables idx)
100101
(ejectHardForkTxOut idx)
101-
(ejectCanonicalTxIn idx)
102+
(coerce . ejectCanonicalTxIn idx)
102103
)
103104
answerBlockQueryHFTraverse =
104105
answerCardanoQueryHF
105106
( \idx ->
106107
answerShelleyTraversingQueries
107108
(ejectHardForkTxOut idx)
108-
(ejectCanonicalTxIn idx)
109+
(coerce . ejectCanonicalTxIn idx)
109110
(queryLedgerGetTraversingFilter idx)
110111
)
111112

ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Ledger.hs

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,13 @@ module Ouroboros.Consensus.Shelley.Ledger.Ledger
5454

5555
-- * Low-level UTxO manipulations
5656
, slUtxoL
57+
, BigEndianTxIn (..)
58+
, coerceTxInSet
59+
, coerceTxInMapKeys
5760
) where
5861

5962
import qualified Cardano.Ledger.BHeaderView as SL (BHeaderView)
60-
import qualified Cardano.Ledger.BaseTypes as SL (epochInfoPure)
63+
import qualified Cardano.Ledger.BaseTypes as SL (TxIx (..), epochInfoPure)
6164
import Cardano.Ledger.BaseTypes.NonZero (unNonZero)
6265
import Cardano.Ledger.Binary.Decoding
6366
( decShareCBOR
@@ -97,9 +100,11 @@ import Control.Arrow (left, second)
97100
import qualified Control.Exception as Exception
98101
import Control.Monad.Except
99102
import qualified Control.State.Transition.Extended as STS
100-
import Data.Coerce (coerce)
103+
import Data.Coerce
101104
import Data.Functor.Identity
105+
import Data.Map.Strict (Map)
102106
import Data.MemPack
107+
import Data.Set (Set)
103108
import qualified Data.Text as T
104109
import qualified Data.Text as Text
105110
import Data.Word
@@ -135,7 +140,9 @@ import Ouroboros.Consensus.Util.CBOR
135140
, encodeWithOrigin
136141
)
137142
import Ouroboros.Consensus.Util.IndexedMemPack
143+
import Ouroboros.Consensus.Util.RedundantConstraints (keepRedundantConstraint)
138144
import Ouroboros.Consensus.Util.Versioned
145+
import Unsafe.Coerce
139146

140147
{-------------------------------------------------------------------------------
141148
Config
@@ -317,7 +324,32 @@ shelleyLedgerTipPoint = shelleyTipToPoint . shelleyLedgerTip
317324

318325
instance ShelleyCompatible proto era => UpdateLedger (ShelleyBlock proto era)
319326

320-
type instance TxIn (LedgerState (ShelleyBlock proto era)) = SL.TxIn
327+
-- | The only purpose of this type is to modify the MemPack instance to use big
328+
-- endian serialization. This is necessary to ensure streaming functions of the
329+
-- UTxO set preserve the order of the entries, as otherwise we would get
330+
-- different sortings if sorting via the Serialized form and the Haskell Ord
331+
-- instance.
332+
newtype BigEndianTxIn = BigEndianTxIn {getOriginalTxIn :: SL.TxIn}
333+
deriving newtype (Eq, Show, Ord, NoThunks)
334+
335+
newtype BigEndianTxIx = BigEndianTxIx {getOriginalTxIx :: SL.TxIx}
336+
337+
instance MemPack BigEndianTxIx where
338+
typeName = "BigEndianTxIx"
339+
packedByteCount = packedByteCount . getOriginalTxIx
340+
packM (BigEndianTxIx (SL.TxIx w)) = packM (byteSwap16 w)
341+
unpackM = BigEndianTxIx . SL.TxIx . byteSwap16 <$> unpackM
342+
343+
instance MemPack BigEndianTxIn where
344+
typeName = "BigEndianTxIn"
345+
packedByteCount = packedByteCount . getOriginalTxIn
346+
packM (BigEndianTxIn (SL.TxIn txid txix)) = do
347+
packM txid
348+
packM (BigEndianTxIx txix)
349+
unpackM = do
350+
BigEndianTxIn <$> (SL.TxIn <$> unpackM <*> (getOriginalTxIx <$> unpackM))
351+
352+
type instance TxIn (LedgerState (ShelleyBlock proto era)) = BigEndianTxIn
321353
type instance TxOut (LedgerState (ShelleyBlock proto era)) = Core.TxOut era
322354

323355
instance
@@ -397,7 +429,7 @@ instance
397429
, shelleyLedgerTables = emptyLedgerTables
398430
}
399431
where
400-
(_, shelleyLedgerState') = shelleyLedgerState `slUtxoL` SL.UTxO m
432+
(_, shelleyLedgerState') = shelleyLedgerState `slUtxoL` SL.UTxO (coerceTxInMapKeys m)
401433
ShelleyLedgerState
402434
{ shelleyLedgerTip
403435
, shelleyLedgerState
@@ -409,7 +441,7 @@ instance
409441
{ shelleyLedgerTip = shelleyLedgerTip
410442
, shelleyLedgerState = shelleyLedgerState'
411443
, shelleyLedgerTransition = shelleyLedgerTransition
412-
, shelleyLedgerTables = LedgerTables (ValuesMK (SL.unUTxO tbs))
444+
, shelleyLedgerTables = LedgerTables (ValuesMK (coerceTxInMapKeys $ SL.unUTxO tbs))
413445
}
414446
where
415447
(tbs, shelleyLedgerState') = shelleyLedgerState `slUtxoL` mempty
@@ -419,6 +451,26 @@ instance
419451
, shelleyLedgerTransition
420452
} = st
421453

454+
-- | UNSAFE: use this function to coerce a @'Map' 'TxIn' ('TxOut' l)@ into and from
455+
-- a @'Map' 'BigEndianTxIn' ('TxOut' l)@.
456+
--
457+
-- This is only safe in such case because the keys are coercible and the 'Ord'
458+
-- instance is exactly the same.
459+
coerceTxInMapKeys :: forall k1 k2 v. Coercible k1 k2 => Map k1 v -> Map k2 v
460+
coerceTxInMapKeys = unsafeCoerce
461+
where
462+
_ = keepRedundantConstraint (Proxy @(Coercible k1 k2))
463+
464+
-- | UNSAFE: use this function to coerce a @'Set' 'TxIn'@ into and from
465+
-- a @'Set' 'BigEndianTxIn'@.
466+
--
467+
-- This is only safe in such case because the keys are coercible and the 'Ord'
468+
-- instance is exactly the same.
469+
coerceTxInSet :: forall k1 k2. Coercible k1 k2 => Set k1 -> Set k2
470+
coerceTxInSet = unsafeCoerce
471+
where
472+
_ = keepRedundantConstraint (Proxy @(Coercible k1 k2))
473+
422474
instance
423475
ShelleyBasedEra era =>
424476
CanStowLedgerTables (Ticked (LedgerState (ShelleyBlock proto era)))
@@ -432,7 +484,7 @@ instance
432484
}
433485
where
434486
(_, tickedShelleyLedgerState') =
435-
tickedShelleyLedgerState `slUtxoL` SL.UTxO tbs
487+
tickedShelleyLedgerState `slUtxoL` SL.UTxO (coerceTxInMapKeys tbs)
436488
TickedShelleyLedgerState
437489
{ untickedShelleyLedgerTip
438490
, tickedShelleyLedgerTransition
@@ -445,7 +497,7 @@ instance
445497
{ untickedShelleyLedgerTip = untickedShelleyLedgerTip
446498
, tickedShelleyLedgerTransition = tickedShelleyLedgerTransition
447499
, tickedShelleyLedgerState = tickedShelleyLedgerState'
448-
, tickedShelleyLedgerTables = LedgerTables (ValuesMK (SL.unUTxO tbs))
500+
, tickedShelleyLedgerTables = LedgerTables (ValuesMK (coerceTxInMapKeys (SL.unUTxO tbs)))
449501
}
450502
where
451503
(tbs, tickedShelleyLedgerState') = tickedShelleyLedgerState `slUtxoL` mempty
@@ -583,6 +635,7 @@ instance
583635
getBlockKeySets =
584636
LedgerTables
585637
. KeysMK
638+
. coerceTxInSet
586639
. Core.neededTxInsForBlock
587640
. shelleyBlockRaw
588641

ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Mempool.hs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,10 @@ import Ouroboros.Consensus.Ledger.Tables.Utils
9898
import Ouroboros.Consensus.Shelley.Eras
9999
import Ouroboros.Consensus.Shelley.Ledger.Block
100100
import Ouroboros.Consensus.Shelley.Ledger.Ledger
101-
( ShelleyLedgerConfig (shelleyLedgerGlobals)
101+
( BigEndianTxIn (..)
102+
, ShelleyLedgerConfig (shelleyLedgerGlobals)
102103
, Ticked (TickedShelleyLedgerState, tickedShelleyLedgerState)
104+
, coerceTxInSet
103105
, getPParams
104106
)
105107
import Ouroboros.Consensus.Shelley.Protocol.Abstract (ProtoCrypto)
@@ -177,8 +179,9 @@ instance
177179

178180
getTransactionKeySets (ShelleyTx _ tx) =
179181
LedgerTables $
180-
KeysMK
181-
(tx ^. bodyTxL . allInputsTxBodyF)
182+
KeysMK $
183+
coerceTxInSet
184+
(tx ^. bodyTxL . allInputsTxBodyF)
182185

183186
mkShelleyTx :: forall era proto. ShelleyBasedEra era => Tx era -> GenTx (ShelleyBlock proto era)
184187
mkShelleyTx tx = ShelleyTx (txIdTx tx) tx

0 commit comments

Comments
 (0)