From b11d892e6d2e763de457b88b6a0943968c68487c Mon Sep 17 00:00:00 2001 From: KadenaFriend <241389759+kdafriend@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:56:27 +0000 Subject: [PATCH 1/7] Use base64 package instead of the old base64-bytestring-kadena --- cabal.project | 9 +---- chainweb.cabal | 4 +-- src/Chainweb/Mempool/Mempool.hs | 5 +-- src/Chainweb/Pact4/SPV.hs | 13 +++---- src/Chainweb/Utils.hs | 36 ++++++++++--------- src/Data/LogMessage.hs | 6 ++-- .../unit/Chainweb/Test/BlockHeader/Genesis.hs | 3 +- .../Chainweb/Test/Pact4/PactMultiChainTest.hs | 3 +- test/unit/Chainweb/Test/Pact4/SPV.hs | 3 +- .../Chainweb/Test/Pact5/PactServiceTest.hs | 3 +- 10 files changed, 40 insertions(+), 45 deletions(-) diff --git a/cabal.project b/cabal.project index f5a73a451d..74939a60f7 100644 --- a/cabal.project +++ b/cabal.project @@ -100,7 +100,7 @@ source-repository-package source-repository-package type: git location: https://github.com/kda-community/pact-5 - tag: 72f427605406df61be8284091922f1fe1af7541b + tag: 57aa03024a88f3206a31d3d8e7876a5f0983ba4a source-repository-package type: git @@ -140,13 +140,6 @@ source-repository-package tag: c234b19732a0576067305b001c02e783e19e0f2b --sha256: 16x2awn8v7dhdbz66a170xbmdj0pyxn1xwinqmsxhlq3qs35ncfj --- Required for non-canonical decode in base64-bytestring (remove after 2.20 fork) -source-repository-package - type: git - location: https://github.com/kda-community/base64-bytestring-kadena - tag: 90247042ab3b8662809210af2a78e6dee0f9b4ac - --sha256: 0dqsrjxm0cm35xcihm49dhwdvmz79vsv4sd5qs2izc4sbnd0d8n6 - -- -------------------------------------------------------------------------- -- -- Relaxed Bounds diff --git a/chainweb.cabal b/chainweb.cabal index d552800538..b3a1d9ba29 100644 --- a/chainweb.cabal +++ b/chainweb.cabal @@ -380,7 +380,7 @@ library , attoparsec >= 0.13 , base >= 4.12 && < 5 , base16-bytestring >= 0.1 - , base64-bytestring-kadena == 0.1 + , base64 >= 2.0 , binary >= 0.8 , bytestring >= 0.10.12 , case-insensitive >= 1.2 @@ -697,7 +697,7 @@ test-suite chainweb-tests , async >= 2.2 , base >= 4.12 && < 5 , base16-bytestring >= 0.1 - , base64-bytestring-kadena == 0.1 + , base64 >= 2.0 , byteslice >= 0.2.12 , bytesmith >= 0.3.10 , bytestring >= 0.10.12 diff --git a/src/Chainweb/Mempool/Mempool.hs b/src/Chainweb/Mempool/Mempool.hs index a6f8ce4319..8cdfe61cfa 100644 --- a/src/Chainweb/Mempool/Mempool.hs +++ b/src/Chainweb/Mempool/Mempool.hs @@ -108,6 +108,7 @@ import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Short as SB import Data.Decimal (Decimal, DecimalRaw(..)) import Data.Foldable (traverse_) +import Data.Bifunctor (first) import Data.Hashable (Hashable(hashWithSalt)) import Data.HashSet (HashSet) import qualified Data.HashSet as HashSet @@ -750,7 +751,7 @@ mockCodec = Codec mockEncode mockDecode mockEncode :: MockTx -> ByteString mockEncode (MockTx nonce (GasPrice (ParsedDecimal price)) limit meta) = - B64.encode $ + encodeB64UrlNoPadding $ runPutS $ do putWord64le $ fromIntegral nonce putDecimal price @@ -793,7 +794,7 @@ getDecimal = do mockDecode :: ByteString -> Either String MockTx mockDecode s = do - s' <- B64.decode s + s' <- first T.unpack $ B64.decodeBase64UnpaddedUntyped s runGetEitherS (MockTx <$> getI64 <*> getPrice <*> getGL <*> getMeta) s' where getPrice = GasPrice . ParsedDecimal <$> getDecimal diff --git a/src/Chainweb/Pact4/SPV.hs b/src/Chainweb/Pact4/SPV.hs index 84bf0b5709..b1dcc704a5 100644 --- a/src/Chainweb/Pact4/SPV.hs +++ b/src/Chainweb/Pact4/SPV.hs @@ -196,33 +196,34 @@ decodeB64UrlNoPaddingTextWithFixedErrorMessage errorMessageType msg = fromEitherM . first (\e -> Base64DecodeException $ base64ErrorMessage e) . (if errorMessageType == Legacy then patchNonCanonical else id) - . B64U.decode + . B64U.decodeBase64Untyped . Text.encodeUtf8 . (if errorMessageType == Legacy then pad else id) $ msg where pad t = let s = Text.length t `mod` 4 in t <> Text.replicate ((4 - s) `mod` 4) "=" base64ErrorMessage m = case errorMessageType of - Legacy -> base64DowngradeErrorMessage (Text.pack m) + Legacy -> base64DowngradeErrorMessage m Simplified -> "could not base64-decode message" patchNonCanonical decodeResult = case decodeResult of Right bs -> Right bs - Left e | "non-canonical" `Text.isInfixOf` Text.pack e -> - (B64U.decodeNonCanonical (Text.encodeUtf8 msg)) + Left e | "non-canonical" `Text.isInfixOf` e -> + Right $ B64U.decodeBase64Lenient $ Text.encodeUtf8 msg Left e -> Left e {-# INLINE decodeB64UrlNoPaddingTextWithFixedErrorMessage #-} --- | Converts the error message format of base64-bytestring-1.2 +-- | Converts the error message format of base64-bytestring-1.2 or base64 2.0 -- into that of base64-bytestring-0.1, for the error messages -- that have made it onto the chain. --- This allows us to upgrade to base64-bytestring-1.2 without +-- This allows us to upgrade to base64 without -- breaking compatibility. base64DowngradeErrorMessage :: Text -> Text base64DowngradeErrorMessage msg = case msg of "Base64-encoded bytestring has invalid size" -> "invalid base64 encoding near offset 0" +-- Note : two be confirmed, but the two next shims shouldn't be necessary with base64 2.0 (Text.stripPrefix "invalid character at offset: " -> Just suffix) -> Text.pack $ "invalid base64 encoding near offset " ++ show (adjustedOffset suffix) (Text.stripPrefix "invalid padding at offset: " -> Just suffix) -> diff --git a/src/Chainweb/Utils.hs b/src/Chainweb/Utils.hs index b33a2409e5..28180ca2e9 100644 --- a/src/Chainweb/Utils.hs +++ b/src/Chainweb/Utils.hs @@ -109,6 +109,7 @@ module Chainweb.Utils -- ** Base64 , encodeB64Text , decodeB64Text +, encodeB64Url , encodeB64UrlText , decodeB64UrlText , encodeB64UrlNoPadding @@ -266,10 +267,10 @@ import Data.Bifunctor import Data.Bool (bool) import Data.ByteString (ByteString) import Data.ByteString qualified as B +import Data.Base64.Types qualified as B64 import Data.ByteString.Base64 qualified as B64 import Data.ByteString.Base64.URL qualified as B64U import Data.ByteString.Builder qualified as BB -import Data.ByteString.Char8 qualified as B8 import Data.ByteString.Lazy qualified as BL import Data.Csv qualified as CSV import Data.Decimal @@ -662,15 +663,15 @@ strip0x t = case T.stripPrefix "0x" t of -- decodeB64Text :: MonadThrow m => T.Text -> m B.ByteString decodeB64Text = fromEitherM - . first (Base64DecodeException . T.pack) - . B64.decode + . first Base64DecodeException + . B64.decodeBase64Untyped . T.encodeUtf8 {-# INLINE decodeB64Text #-} -- | Encode a binary value to a textual base64 representation. -- encodeB64Text :: B.ByteString -> T.Text -encodeB64Text = T.decodeUtf8 . B64.encode +encodeB64Text = B64.extractBase64 . B64.encodeBase64 {-# INLINE encodeB64Text #-} -- | Decode a binary value from a textual base64-url representation. A @@ -679,16 +680,22 @@ encodeB64Text = T.decodeUtf8 . B64.encode -- decodeB64UrlText :: MonadThrow m => T.Text -> m B.ByteString decodeB64UrlText = fromEitherM - . first (Base64DecodeException . T.pack) - . B64U.decode + . first Base64DecodeException + . B64U.decodeBase64Untyped . T.encodeUtf8 {-# INLINE decodeB64UrlText #-} + +-- | Encode a binary value to a textual base64-url witg Padding +encodeB64Url :: B.ByteString -> B.ByteString +encodeB64Url = B64.extractBase64 . B64U.encodeBase64' +{-# INLINE encodeB64UrlText #-} + -- | Encode a binary value to a textual base64-url representation. -- encodeB64UrlText :: B.ByteString -> T.Text -encodeB64UrlText = T.decodeUtf8 . B64U.encode -{-# INLINE encodeB64UrlText #-} +encodeB64UrlText = B64.extractBase64 . B64U.encodeBase64 +{-# INLINE encodeB64Url #-} -- | Decode a binary value from a textual base64-url without padding -- representation. A 'Base64DecodeException' is thrown if the input is not a @@ -696,33 +703,30 @@ encodeB64UrlText = T.decodeUtf8 . B64U.encode -- decodeB64UrlNoPaddingText :: MonadThrow m => T.Text -> m B.ByteString decodeB64UrlNoPaddingText = fromEitherM - . first (Base64DecodeException . T.pack) - . B64U.decode + . first Base64DecodeException + . B64U.decodeBase64UnpaddedUntyped . T.encodeUtf8 - . pad - where - pad t = let s = T.length t `mod` 4 in t <> T.replicate ((4 - s) `mod` 4) "=" {-# INLINE decodeB64UrlNoPaddingText #-} -- | Encode a binary value to a textual base64-url without padding -- representation. -- encodeB64UrlNoPaddingText :: B.ByteString -> T.Text -encodeB64UrlNoPaddingText = T.dropWhileEnd (== '=') . T.decodeUtf8 . B64U.encode +encodeB64UrlNoPaddingText = B64.extractBase64 . B64U.encodeBase64Unpadded {-# INLINE encodeB64UrlNoPaddingText #-} -- | Encode a binary value to a textual base64-url without padding -- representation. -- encodeB64UrlNoPadding :: B.ByteString -> B.ByteString -encodeB64UrlNoPadding = B8.dropWhileEnd (== '=') . B64U.encode +encodeB64UrlNoPadding = B64.extractBase64 . B64U.encodeBase64Unpadded' {-# INLINE encodeB64UrlNoPadding #-} -- | Encode a binary value to a base64-url (without padding) JSON encoding. -- b64UrlNoPaddingTextEncoding :: B.ByteString -> Encoding b64UrlNoPaddingTextEncoding t = - Aeson.unsafeToEncoding $ BB.char8 '\"' <> BB.byteString (B8.dropWhileEnd (== '=') $ B64U.encode t) <> BB.char8 '\"' + Aeson.unsafeToEncoding $ BB.char8 '\"' <> (BB.byteString . encodeB64UrlNoPadding) t <> BB.char8 '\"' -- -------------------------------------------------------------------------- -- -- ** JSON diff --git a/src/Data/LogMessage.hs b/src/Data/LogMessage.hs index 6848322971..4335dd211f 100644 --- a/src/Data/LogMessage.hs +++ b/src/Data/LogMessage.hs @@ -59,6 +59,7 @@ import Control.DeepSeq import Data.Aeson import qualified Data.ByteString as B +import qualified Data.Base64.Types as B64 import qualified Data.ByteString.Base64.URL as B64 import qualified Data.ByteString.Lazy as BL import Data.Proxy @@ -202,8 +203,8 @@ data BinaryLog deriving anyclass (NFData) instance LogMessage BinaryLog where - logText (BinaryLog a) = T.decodeUtf8 $ B64.encode a - logText (BinaryLogLazy a) = T.decodeUtf8 . B64.encode $ BL.toStrict a + logText (BinaryLog a) = B64.extractBase64 $ B64.encodeBase64 a + logText (BinaryLogLazy a) = B64.extractBase64 . B64.encodeBase64 $ BL.toStrict a {-# INLINE logText #-} -- | Static textual log messages using 'Symbol' literals from 'GHC.TypeLits'. @@ -216,4 +217,3 @@ instance NFData SomeSymbolLog where instance LogMessage SomeSymbolLog where logText (SomeSymbolLog (_ :: Proxy a)) = T.pack $ symbolVal (Proxy @a) {-# INLINE logText #-} - diff --git a/test/unit/Chainweb/Test/BlockHeader/Genesis.hs b/test/unit/Chainweb/Test/BlockHeader/Genesis.hs index affc622b61..a41f09411f 100644 --- a/test/unit/Chainweb/Test/BlockHeader/Genesis.hs +++ b/test/unit/Chainweb/Test/BlockHeader/Genesis.hs @@ -14,7 +14,6 @@ module Chainweb.Test.BlockHeader.Genesis ( tests ) where import Control.Lens -import qualified Data.ByteString.Base64.URL as B64U import qualified Data.ByteString.Builder as BB import qualified Data.ByteString.Lazy as BL import Data.Function (on) @@ -57,7 +56,7 @@ blockHashes = BB.toLazyByteString . foldMap (hash . snd) . sortBy (compare `on` fst) . HM.toList where hash :: BlockHeader -> BB.Builder - hash = BB.byteString . B64U.encode . runPutS . encodeBlockHash . view blockHash + hash = BB.byteString . encodeB64Url . runPutS . encodeBlockHash . view blockHash blockHashTest :: ChainwebVersion -> TestTree blockHashTest v = golden (sshow v <> "-block-hashes") $ diff --git a/test/unit/Chainweb/Test/Pact4/PactMultiChainTest.hs b/test/unit/Chainweb/Test/Pact4/PactMultiChainTest.hs index b5eff22709..db5ecf8fed 100644 --- a/test/unit/Chainweb/Test/Pact4/PactMultiChainTest.hs +++ b/test/unit/Chainweb/Test/Pact4/PactMultiChainTest.hs @@ -19,7 +19,6 @@ import Control.Monad import Control.Monad.Catch import Control.Monad.Reader import Data.Aeson (Value, object, (.=)) -import qualified Data.ByteString.Base64.URL as B64U import qualified Data.HashMap.Strict as HM import Data.IORef import Data.List(isPrefixOf) @@ -1706,7 +1705,7 @@ buildXProof -> PactTestM (ContProof, PactId) buildXProof scid bh i sendTx = do bdb <- view menvBdb - proof <- liftIO $ ContProof . B64U.encode . encodeToByteString <$> + proof <- liftIO $ ContProof . encodeB64UrlNoPadding . encodeToByteString <$> createTransactionOutputProof_ (_bdbWebBlockHeaderDb bdb) (_bdbPayloadDb bdb) chain0 scid bh i pid <- getPactId sendTx return (proof,pid) diff --git a/test/unit/Chainweb/Test/Pact4/SPV.hs b/test/unit/Chainweb/Test/Pact4/SPV.hs index 0ce12c4e62..d9a574ed35 100644 --- a/test/unit/Chainweb/Test/Pact4/SPV.hs +++ b/test/unit/Chainweb/Test/Pact4/SPV.hs @@ -33,7 +33,6 @@ import Control.Monad import Control.Lens hiding ((.=)) import Data.Aeson as Aeson -import qualified Data.ByteString.Base64.URL as B64U import qualified Data.ByteString.Char8 as B8 import Data.ByteString.Lazy (toStrict) @@ -529,7 +528,7 @@ createSuccess v time (TestBlockDb wdb pdb _c) pidv sid tid bhe = do True -> return mempty False -> do q <- toJSON <$> createTransactionOutputProof_ wdb pdb tid sid bhe 0 - let proof = Just . ContProof . B64U.encode . toStrict . Aeson.encode $ q + let proof = Just . ContProof . encodeB64UrlNoPadding . toStrict . Aeson.encode $ q createCont v tid pidv proof time `finally` writeIORef ref True diff --git a/test/unit/Chainweb/Test/Pact5/PactServiceTest.hs b/test/unit/Chainweb/Test/Pact5/PactServiceTest.hs index c348e5998f..538087fd13 100644 --- a/test/unit/Chainweb/Test/Pact5/PactServiceTest.hs +++ b/test/unit/Chainweb/Test/Pact5/PactServiceTest.hs @@ -51,7 +51,6 @@ import Chainweb.Test.TestVersions import Chainweb.Test.Utils import Chainweb.Time import Chainweb.Utils -import qualified Data.ByteString.Base64.URL as B64U import Chainweb.SPV.CreateProof import Chainweb.Version import Chainweb.WebBlockHeaderDB (getWebBlockHeaderDb) @@ -590,7 +589,7 @@ assertCutHeight fixt bh = do view cutMaxHeight cut @?= bh makeProof :: Fixture -> ChainId -> ChainId -> BlockHeight -> Int -> IO ContProof -makeProof Fixture{..} cidT cidS bh i = (ContProof . B64U.encode . encodeToByteString) <$> +makeProof Fixture{..} cidT cidS bh i = (ContProof . encodeB64UrlNoPadding . encodeToByteString) <$> createTransactionOutputProof_ (_bdbWebBlockHeaderDb _fixtureBlockDb) ( _bdbPayloadDb _fixtureBlockDb) cidT cidS bh i From d8d6e3c3c09870d453770f409af971eae82ee61a Mon Sep 17 00:00:00 2001 From: KadenaFriend <241389759+kdafriend@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:56:46 +0000 Subject: [PATCH 2/7] Update freeze file --- cabal.project.freeze | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cabal.project.freeze b/cabal.project.freeze index d75da4415f..4971bb5326 100644 --- a/cabal.project.freeze +++ b/cabal.project.freeze @@ -53,7 +53,6 @@ constraints: any.Cabal ==3.12.1.0 || ==3.14.2.0, any.base64 ==2.0, base64 -simd, any.base64-bytestring ==1.2.1.0, - any.base64-bytestring-kadena ==0.1, any.basement ==0.0.16, any.bifunctors ==5.6.3, bifunctors +tagged, @@ -534,4 +533,4 @@ constraints: any.Cabal ==3.12.1.0 || ==3.14.2.0, zip-archive -executable, any.zlib ==0.7.1.1, zlib -bundled-c-zlib +non-blocking-ffi +pkg-config -index-state: hackage.haskell.org 2026-10-18T08:35:38Z +index-state: hackage.haskell.org 2026-10-18T17:06:51Z From c02a4ec805cf0c3336d4931548851783ac95c833 Mon Sep 17 00:00:00 2001 From: KadenaFriend <241389759+kdafriend@users.noreply.github.com> Date: Sun, 18 Oct 2026 21:25:20 +0000 Subject: [PATCH 3/7] FIx unused package --- chainweb.cabal | 1 - 1 file changed, 1 deletion(-) diff --git a/chainweb.cabal b/chainweb.cabal index b3a1d9ba29..7d5fbe1f16 100644 --- a/chainweb.cabal +++ b/chainweb.cabal @@ -697,7 +697,6 @@ test-suite chainweb-tests , async >= 2.2 , base >= 4.12 && < 5 , base16-bytestring >= 0.1 - , base64 >= 2.0 , byteslice >= 0.2.12 , bytesmith >= 0.3.10 , bytestring >= 0.10.12 From 5483898a2be49bfb5b2a5c28f69330d06b88c0aa Mon Sep 17 00:00:00 2001 From: KadenaFriend <241389759+kdafriend@users.noreply.github.com> Date: Mon, 19 Oct 2026 04:58:46 +0000 Subject: [PATCH 4/7] Fix comment --- src/Chainweb/Pact4/SPV.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chainweb/Pact4/SPV.hs b/src/Chainweb/Pact4/SPV.hs index b1dcc704a5..0b64092bd4 100644 --- a/src/Chainweb/Pact4/SPV.hs +++ b/src/Chainweb/Pact4/SPV.hs @@ -223,7 +223,7 @@ base64DowngradeErrorMessage :: Text -> Text base64DowngradeErrorMessage msg = case msg of "Base64-encoded bytestring has invalid size" -> "invalid base64 encoding near offset 0" --- Note : two be confirmed, but the two next shims shouldn't be necessary with base64 2.0 +-- Note : to be confirmed, but the two next shims shouldn't be necessary with base64 2.0 (Text.stripPrefix "invalid character at offset: " -> Just suffix) -> Text.pack $ "invalid base64 encoding near offset " ++ show (adjustedOffset suffix) (Text.stripPrefix "invalid padding at offset: " -> Just suffix) -> From 25207a9e39f2c748639ad8f2f16450476d1fae81 Mon Sep 17 00:00:00 2001 From: KadenaFriend <241389759+kdafriend@users.noreply.github.com> Date: Mon, 19 Oct 2026 04:59:24 +0000 Subject: [PATCH 5/7] Make sure we use the SIMD version of the base64 package --- cabal.project | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cabal.project b/cabal.project index 74939a60f7..5dbc72ff76 100644 --- a/cabal.project +++ b/cabal.project @@ -141,6 +141,11 @@ source-repository-package --sha256: 16x2awn8v7dhdbz66a170xbmdj0pyxn1xwinqmsxhlq3qs35ncfj -- -------------------------------------------------------------------------- -- +-- Make sure we are using the SIMD enabled version of Base64 +constraints: + base64 +simd + +---------------------------------------------------------------------------------- -- Relaxed Bounds -- GHC-9: From 64a9eeadc77ce478466f63003f8c90483cbd0693 Mon Sep 17 00:00:00 2001 From: KadenaFriend <241389759+kdafriend@users.noreply.github.com> Date: Mon, 19 Oct 2026 05:09:56 +0000 Subject: [PATCH 6/7] Freeze file update --- cabal.project.freeze | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal.project.freeze b/cabal.project.freeze index 4971bb5326..2e28e22447 100644 --- a/cabal.project.freeze +++ b/cabal.project.freeze @@ -51,7 +51,7 @@ constraints: any.Cabal ==3.12.1.0 || ==3.14.2.0, any.base16 ==1.0, any.base16-bytestring ==1.0.2.0, any.base64 ==2.0, - base64 -simd, + base64 +simd, any.base64-bytestring ==1.2.1.0, any.basement ==0.0.16, any.bifunctors ==5.6.3, From beadf074e2283538ec065cd173e789133b0890e8 Mon Sep 17 00:00:00 2001 From: KadenaFriend <241389759+kdafriend@users.noreply.github.com> Date: Wed, 21 Oct 2026 09:58:24 +0000 Subject: [PATCH 7/7] Use the modern version of Base16 --- cabal.project | 6 ++++-- cabal.project.freeze | 13 +++++++------ chainweb.cabal | 8 ++++---- src/Chainweb/BlockHeaderDB/RestAPI/Server.hs | 4 ++-- .../Pact/Backend/PactState/EmbeddedSnapshot.hs | 7 +++---- .../Pact/Backend/PactState/GrandHash/Algorithm.hs | 6 ++++-- .../Pact/Backend/PactState/GrandHash/Utils.hs | 6 +++--- src/Chainweb/SPV/EventProof.hs | 3 ++- src/Chainweb/VerifierPlugin/Hyperlane/Utils.hs | 3 ++- src/Chainweb/VerifierPlugin/SignedList.hs | 4 ++-- test/lib/Chainweb/Test/MultiNode.hs | 5 +++-- test/unit/Chainweb/Test/Pact4/GrandHash.hs | 6 ++---- test/unit/Chainweb/Test/Pact5/RemotePactTest.hs | 5 +++-- test/unit/Chainweb/Test/Pact5/SPVTest.hs | 1 - 14 files changed, 41 insertions(+), 36 deletions(-) diff --git a/cabal.project b/cabal.project index 5dbc72ff76..07216a77d3 100644 --- a/cabal.project +++ b/cabal.project @@ -100,6 +100,8 @@ source-repository-package source-repository-package type: git location: https://github.com/kda-community/pact-5 + -- For now, we still use an outdated pin, that still compiles with GHC 9.10 + -- TO be changed soon tag: 57aa03024a88f3206a31d3d8e7876a5f0983ba4a source-repository-package @@ -141,10 +143,10 @@ source-repository-package --sha256: 16x2awn8v7dhdbz66a170xbmdj0pyxn1xwinqmsxhlq3qs35ncfj -- -------------------------------------------------------------------------- -- --- Make sure we are using the SIMD enabled version of Base64 +-- Make sure we are using the SIMD enabled version of Base16 / Base64 constraints: base64 +simd - + ,base16 +simd ---------------------------------------------------------------------------------- -- Relaxed Bounds diff --git a/cabal.project.freeze b/cabal.project.freeze index 2e28e22447..bbabea5c6a 100644 --- a/cabal.project.freeze +++ b/cabal.project.freeze @@ -48,9 +48,10 @@ constraints: any.Cabal ==3.12.1.0 || ==3.14.2.0, any.base-orphans ==0.9.4, any.base-unicode-symbols ==0.2.4.2, base-unicode-symbols +base-4-8 -old-base, - any.base16 ==1.0, + any.base16 ==2.0, + base16 +simd, any.base16-bytestring ==1.0.2.0, - any.base64 ==2.0, + any.base64 ==2.1, base64 +simd, any.base64-bytestring ==1.2.1.0, any.basement ==0.0.16, @@ -348,7 +349,7 @@ constraints: any.Cabal ==3.12.1.0 || ==3.14.2.0, any.regex ==1.1.0.2, any.regex-base ==0.94.0.3, any.regex-pcre-builtin ==0.95.2.3.8.44, - any.regex-tdfa ==1.3.2.6, + any.regex-tdfa ==1.3.2.7, regex-tdfa +doctest -force-o2, any.resource-pool ==0.5.1.0, any.resourcet ==1.3.0, @@ -415,8 +416,8 @@ constraints: any.Cabal ==3.12.1.0 || ==3.14.2.0, any.tagged ==0.8.11, tagged +deepseq +template-haskell, any.tagsoup ==0.14.8, - any.tasty ==1.5.4, - tasty +unix, + any.tasty ==1.5.5, + tasty +terminal-size +unix, any.tasty-golden ==2.3.6, tasty-golden -build-example, any.tasty-hedgehog ==1.4.0.2, @@ -533,4 +534,4 @@ constraints: any.Cabal ==3.12.1.0 || ==3.14.2.0, zip-archive -executable, any.zlib ==0.7.1.1, zlib -bundled-c-zlib +non-blocking-ffi +pkg-config -index-state: hackage.haskell.org 2026-10-18T17:06:51Z +index-state: hackage.haskell.org 2026-10-21T06:37:23Z diff --git a/chainweb.cabal b/chainweb.cabal index 7d5fbe1f16..43f997f39e 100644 --- a/chainweb.cabal +++ b/chainweb.cabal @@ -379,8 +379,8 @@ library , async >= 2.2 , attoparsec >= 0.13 , base >= 4.12 && < 5 - , base16-bytestring >= 0.1 - , base64 >= 2.0 + , base16 >= 2.0 + , base64 >= 2.1 , binary >= 0.8 , bytestring >= 0.10.12 , case-insensitive >= 1.2 @@ -538,7 +538,7 @@ library chainweb-test-utils , aeson >= 2.2 , async >= 2.2 , base >= 4.12 && < 5 - , base16-bytestring >= 0.1 + , base16 >= 2.0 , bytestring >= 0.10.12 , case-insensitive >= 1.2 , chainweb-storage >= 0.1 @@ -696,7 +696,7 @@ test-suite chainweb-tests , aeson >= 2.2 , async >= 2.2 , base >= 4.12 && < 5 - , base16-bytestring >= 0.1 + , base16 >= 2.0 , byteslice >= 0.2.12 , bytesmith >= 0.3.10 , bytestring >= 0.10.12 diff --git a/src/Chainweb/BlockHeaderDB/RestAPI/Server.hs b/src/Chainweb/BlockHeaderDB/RestAPI/Server.hs index 7bda07fa04..7362f2407b 100644 --- a/src/Chainweb/BlockHeaderDB/RestAPI/Server.hs +++ b/src/Chainweb/BlockHeaderDB/RestAPI/Server.hs @@ -39,6 +39,7 @@ import Control.Monad.IO.Class import Data.Aeson import Data.Binary.Builder (fromByteString, fromLazyByteString) import qualified Data.ByteString as BS +import qualified Data.Base16.Types as B16 import qualified Data.ByteString.Base16 as B16 import Data.ByteString.Short (fromShort) import Data.Foldable @@ -47,7 +48,6 @@ import Data.Functor.Of import Data.IORef import qualified Data.Map.Strict as Map import Data.Proxy -import Data.Text.Encoding (decodeUtf8) import Numeric.Natural(Natural) import Network.Wai.EventSource (ServerEvent(..), eventSourceAppIO) @@ -423,7 +423,7 @@ blockStreamHandler db withPayloads = Tagged $ \req resp -> do , _huPayloadWithOutputs = x <$ guard withPayloads , _huTxCount = length $ _payloadWithOutputsTransactions x - , _huPowHash = decodeUtf8 . B16.encode . BS.reverse . fromShort . powHashBytes $ view blockPow bh + , _huPowHash = B16.extractBase16 . B16.encodeBase16 . BS.reverse . fromShort . powHashBytes $ view blockPow bh , _huTarget = showTargetHex $ view blockTarget bh } diff --git a/src/Chainweb/Pact/Backend/PactState/EmbeddedSnapshot.hs b/src/Chainweb/Pact/Backend/PactState/EmbeddedSnapshot.hs index 8ecb320113..5f00d2d40b 100644 --- a/src/Chainweb/Pact/Backend/PactState/EmbeddedSnapshot.hs +++ b/src/Chainweb/Pact/Backend/PactState/EmbeddedSnapshot.hs @@ -12,7 +12,8 @@ import Chainweb.BlockHeader (BlockHeader) import Chainweb.Pact.Backend.PactState.GrandHash.Algorithm (ChainGrandHash) import Data.Aeson qualified as A import Data.ByteString (ByteString) -import Data.ByteString.Base16 qualified as Base16 +import Data.Base16.Types qualified as B16 +import Data.ByteString.Base16 qualified as B16 import Data.Text (Text) import Data.Text.Encoding qualified as Text @@ -28,6 +29,4 @@ unsafeDecodeBlockHeader t = case A.decodeStrict (Text.encodeUtf8 t) of Nothing -> error "unsafeDecodeBlockHeader: invalid BlockHeader JSON" unsafeBase16Decode :: Text -> ByteString -unsafeBase16Decode t = case Base16.decode (Text.encodeUtf8 t) of - Right a -> a - Left err -> error ("unsafeBase16Decode failed: " ++ show err) +unsafeBase16Decode = B16.decodeBase16' . B16.assertBase16 diff --git a/src/Chainweb/Pact/Backend/PactState/GrandHash/Algorithm.hs b/src/Chainweb/Pact/Backend/PactState/GrandHash/Algorithm.hs index 19bca1d7ea..362783189f 100644 --- a/src/Chainweb/Pact/Backend/PactState/GrandHash/Algorithm.hs +++ b/src/Chainweb/Pact/Backend/PactState/GrandHash/Algorithm.hs @@ -28,7 +28,9 @@ import Data.Bifunctor (first) import Data.ByteArray qualified as Memory import Data.ByteString (ByteString) import Data.ByteString qualified as BS -import Data.ByteString.Base16 qualified as Base16 +import Data.Coerce (coerce) +import Data.Base16.Types qualified as B16 +import Data.ByteString.Base16 qualified as B16 import Data.ByteString.Builder qualified as BB import Data.ByteString.Lazy qualified as BL import Data.Int (Int64) @@ -58,7 +60,7 @@ newtype TableHash = TableHash { getTableHash :: ByteString } newtype HexBytes = HexBytes ByteString instance Show HexBytes where - show (HexBytes b) = Text.unpack (Text.decodeUtf8 (Base16.encode b)) + show = Text.unpack . B16.extractBase16 . B16.encodeBase16 . coerce computeGrandHash :: forall m r. (Monad m) => Stream (Of (Text, Map ByteString PactRowContents)) m r diff --git a/src/Chainweb/Pact/Backend/PactState/GrandHash/Utils.hs b/src/Chainweb/Pact/Backend/PactState/GrandHash/Utils.hs index a0188d4f37..1f02edf8f8 100644 --- a/src/Chainweb/Pact/Backend/PactState/GrandHash/Utils.hs +++ b/src/Chainweb/Pact/Backend/PactState/GrandHash/Utils.hs @@ -46,13 +46,13 @@ import Control.Exception (bracket) import Control.Lens ((^?!), ix, view) import Control.Monad (forM, when) import Data.ByteString (ByteString) -import Data.ByteString.Base16 qualified as Base16 +import Data.Base16.Types qualified as B16 +import Data.ByteString.Base16 qualified as B16 import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict qualified as HM import Data.Maybe (fromMaybe) import Data.Text (Text) import Data.Text qualified as Text -import Data.Text.Encoding qualified as Text import Options.Applicative qualified as O import System.Directory (doesFileExist) import System.Exit (exitFailure) @@ -216,7 +216,7 @@ withConnections logger pactDir cids f = do closeConnections = mapM_ stopSqliteDb hex :: ByteString -> Text -hex = Text.decodeUtf8 . Base16.encode +hex = B16.extractBase16 . B16.encodeBase16 cwvParser :: O.Parser ChainwebVersion cwvParser = fmap (lookupVersionByName . fromMaybe (error "ChainwebVersion parse failed") . fromText) diff --git a/src/Chainweb/SPV/EventProof.hs b/src/Chainweb/SPV/EventProof.hs index a8320b7d66..8c0f1b9548 100644 --- a/src/Chainweb/SPV/EventProof.hs +++ b/src/Chainweb/SPV/EventProof.hs @@ -109,6 +109,7 @@ import Crypto.Hash.Algorithms import Data.Aeson import qualified Data.ByteArray as BA import qualified Data.ByteString as B +import qualified Data.Base16.Types as B16 import qualified Data.ByteString.Base16 as B16 import qualified Data.ByteString.Short as BS import Data.Decimal @@ -260,7 +261,7 @@ getInt256Be = do int256Hex :: Int256 -> B.ByteString int256Hex x@(Int256 i) - | i >= 0 = "0x" <> B16.encode (runPutS $ putInt256Be x) + | i >= 0 = "0x" <> (B16.extractBase16 $ B16.encodeBase16' $ runPutS $ putInt256Be x) | otherwise = "-" <> int256Hex (Int256 (-i)) -- -------------------------------------------------------------------------- -- diff --git a/src/Chainweb/VerifierPlugin/Hyperlane/Utils.hs b/src/Chainweb/VerifierPlugin/Hyperlane/Utils.hs index bb12aa68ce..97d354e5a4 100644 --- a/src/Chainweb/VerifierPlugin/Hyperlane/Utils.hs +++ b/src/Chainweb/VerifierPlugin/Hyperlane/Utils.hs @@ -24,6 +24,7 @@ module Chainweb.VerifierPlugin.Hyperlane.Utils import Control.Lens hiding (index) import Control.Monad.Catch +import Data.Bifunctor (first) import qualified Data.ByteString as B import qualified Data.ByteString.Base16 as B16 import qualified Data.ByteString.Short as BS @@ -78,7 +79,7 @@ encodeHex = ((<>) "0x") . Text.decodeUtf8 . B.toStrict . Builder.toLazyByteStrin decodeHex :: Text -> Either String B.ByteString decodeHex s - | Just h <- Text.stripPrefix "0x" s = B16.decode $ Text.encodeUtf8 h + | Just h <- Text.stripPrefix "0x" s = first (const "Base16 Decoding Error") $ B16.decodeBase16Untyped $ Text.encodeUtf8 h | otherwise = Left "decodeHex: does not start with 0x" decodeHexUnsafe :: Text -> B.ByteString diff --git a/src/Chainweb/VerifierPlugin/SignedList.hs b/src/Chainweb/VerifierPlugin/SignedList.hs index 168e8f5d50..60b9e4b961 100644 --- a/src/Chainweb/VerifierPlugin/SignedList.hs +++ b/src/Chainweb/VerifierPlugin/SignedList.hs @@ -115,7 +115,7 @@ foldHashList -> ExceptT VerifierError (ST s) (BS.ByteString, PactValue) foldHashList gp gasRef = \case -- Top-level precomputed digest provided as hex. - + HLHashHex hexTxt -> do bs <- decodeHex hexTxt pure (bs, PList V.empty) @@ -235,4 +235,4 @@ decompressPublicKey cKey = & either (const Nothing) (Just . SBS.fromShort . ecdsaPublicKeyBytes) hexToBS :: BS.ByteString -> Maybe BS.ByteString -hexToBS = either (const Nothing) Just . B16.decode +hexToBS = either (const Nothing) Just . B16.decodeBase16Untyped diff --git a/test/lib/Chainweb/Test/MultiNode.hs b/test/lib/Chainweb/Test/MultiNode.hs index 5c77e78034..435fe8722a 100644 --- a/test/lib/Chainweb/Test/MultiNode.hs +++ b/test/lib/Chainweb/Test/MultiNode.hs @@ -59,7 +59,8 @@ import Control.Monad import Chronos qualified import Patience.Map qualified as Patience -import Data.ByteString.Base16 qualified as Base16 +import Data.Base16.Types as B16 +import Data.ByteString.Base16 qualified as B16 import Chainweb.Pact.Backend.PactState.EmbeddedSnapshot (Snapshot(..)) import Data.Aeson (ToJSON) import Data.Foldable @@ -476,7 +477,7 @@ pactImportTest logLevel v n rocksDb pactDir step = do logFunctionText logger' Info "Verifying state" snapshot@(snapshotBlockHeight, snapshotHashes) <- GrandHash.Import.pactVerify logger' v pactConns rdb grands logFunctionText logger' Debug $ "SNAPSHOT BLOCKHEIGHT = " <> sshow (fst snapshot) - logFunctionText logger' Debug $ "SNAPSHOT HASHES = " <> sshow (HM.map (\s -> (T.decodeUtf8 (Base16.encode (getChainGrandHash s.pactHash)), view blockHeight s.blockHeader)) (snd snapshot)) + logFunctionText logger' Debug $ "SNAPSHOT HASHES = " <> sshow (HM.map (\s -> (B16.extractBase16 (B16.encodeBase16 (getChainGrandHash s.pactHash)), view blockHeight s.blockHeader)) (snd snapshot)) logFunctionText logger' Info "Making a copy of the pact state, and dropping the post-verified content" withSystemTempDirectory "pact-copy" $ \copyPactDir -> do diff --git a/test/unit/Chainweb/Test/Pact4/GrandHash.hs b/test/unit/Chainweb/Test/Pact4/GrandHash.hs index c57a23f807..daea347f71 100644 --- a/test/unit/Chainweb/Test/Pact4/GrandHash.hs +++ b/test/unit/Chainweb/Test/Pact4/GrandHash.hs @@ -13,12 +13,12 @@ module Chainweb.Test.Pact4.GrandHash import Data.ByteArray qualified as Memory import Data.Functor.Identity (Identity(..)) -import Data.ByteString.Base16 qualified as Base16 import Data.Maybe (mapMaybe) import Crypto.Hash (hashWith) import Data.List qualified as List import Chainweb.Pact.Backend.PactState (PactRow(..), Table(..)) import Chainweb.Pact.Backend.PactState.GrandHash.Algorithm (TableHash(..), rowToHashInput, hashTable, tableNameToHashInput, hashStream, hashAlgorithm) +import Chainweb.Pact.Backend.PactState.GrandHash.Utils import Control.Monad (replicateM) import Data.ByteString (ByteString) import Data.ByteString.Builder qualified as BB @@ -41,6 +41,7 @@ import Test.Tasty (TestTree) import Test.Tasty.HUnit (Assertion, testCase, (@?=)) import Test.Tasty.QuickCheck (testProperty) + import Chainweb.Test.Utils tests :: TestTree @@ -185,6 +186,3 @@ parseTableHashInput b = Smith.parseBytesEither parser (Bytes.fromByteString b) len <- SmithLE.word64 "tablename len" tablename <- Smith.take "tablename" (fromIntegral @Word64 @Int len) pure (len, Bytes.toByteString tablename) - -hex :: ByteString -> Text -hex = Text.decodeUtf8 . Base16.encode diff --git a/test/unit/Chainweb/Test/Pact5/RemotePactTest.hs b/test/unit/Chainweb/Test/Pact5/RemotePactTest.hs index 7c4f2c7cf3..93367152ac 100644 --- a/test/unit/Chainweb/Test/Pact5/RemotePactTest.hs +++ b/test/unit/Chainweb/Test/Pact5/RemotePactTest.hs @@ -53,6 +53,7 @@ import Control.Monad.Trans.Resource (ResourceT, allocate, runResourceT) import Data.Aeson qualified as A import Data.Aeson.Lens qualified as A import Data.Aeson.KeyMap qualified as A.KeyMap +import Data.Base16.Types qualified as B16 import Data.ByteString.Base16 qualified as B16 import Data.Foldable (forM_, traverse_) import Data.HashMap.Strict qualified as HashMap @@ -1101,8 +1102,8 @@ localTests baseRdb = let & cbSigners .~ [mkEd25519Signer' sender00 []] goodCmdHash <- _cmdHash <$> buildTextCmd v buildSender00Cmd sender01KeyPair <- either error return $ importEd25519KeyPair Nothing - (PrivBS $ either error id $ B16.decode $ T.encodeUtf8 $ snd sender01) - let sender01Sig = ED25519Sig $ T.decodeUtf8 $ B16.encode $ exportEd25519Signature $ + (PrivBS $ either (error . T.unpack) id $ B16.decodeBase16Untyped $ T.encodeUtf8 $ snd sender01) + let sender01Sig = ED25519Sig $ B16.extractBase16 $ B16.encodeBase16 $ exportEd25519Signature $ signEd25519 (fst sender01KeyPair) (snd sender01KeyPair) goodCmdHash buildTextCmd v buildSender00Cmd diff --git a/test/unit/Chainweb/Test/Pact5/SPVTest.hs b/test/unit/Chainweb/Test/Pact5/SPVTest.hs index 778ab74061..e0a9aa0ce8 100644 --- a/test/unit/Chainweb/Test/Pact5/SPVTest.hs +++ b/test/unit/Chainweb/Test/Pact5/SPVTest.hs @@ -23,7 +23,6 @@ module Chainweb.Test.Pact5.SPVTest ( tests ) where -import Data.ByteString.Base16 qualified as Base16 import Chainweb.Block (Block (_blockPayloadWithOutputs)) import System.Environment (lookupEnv, setEnv) import Control.Applicative ((<|>))