From 92d904b0d648059445a3127207a1c11e0ca7ba8a Mon Sep 17 00:00:00 2001 From: chessai Date: Thu, 10 Oct 2024 15:26:53 -0500 Subject: [PATCH] wip Change-Id: I4d858686e3d92c956385cbdf5e8d865f835b498a --- src/Chainweb/Chainweb/Configuration.hs | 7 -- src/Chainweb/Pact/PactService.hs | 65 +++++++++++++++++-- .../Pact/PactService/Pact4/ExecBlock.hs | 11 +--- src/Chainweb/Pact/ReflectingDb.hs | 11 ++-- 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/Chainweb/Chainweb/Configuration.hs b/src/Chainweb/Chainweb/Configuration.hs index c9eaac038..2cdb1a2fe 100644 --- a/src/Chainweb/Chainweb/Configuration.hs +++ b/src/Chainweb/Chainweb/Configuration.hs @@ -465,13 +465,6 @@ validateChainwebVersion v = do , "set to recap-development or development, but version is set to" , sshow (_versionName v) ] - -- FIXME Pact5: disable - when (v == mainnet || v == testnet04) $ - throwError $ T.unwords - [ "This node version is a technical preview of Pact 5, and" - , "cannot be used with Pact 4 chainweb versions (testnet04, mainnet)" - , "just yet." - ] where isDevelopment = _versionCode v `elem` [_versionCode dv | dv <- [recapDevnet, devnet]] diff --git a/src/Chainweb/Pact/PactService.hs b/src/Chainweb/Pact/PactService.hs index b85348663..489db6d25 100644 --- a/src/Chainweb/Pact/PactService.hs +++ b/src/Chainweb/Pact/PactService.hs @@ -125,6 +125,7 @@ import Data.Time.Format.ISO8601 import qualified Chainweb.Pact.PactService.Pact4.ExecBlock as Pact4 import qualified Chainweb.Pact4.Types as Pact4 import qualified Chainweb.Pact5.Backend.ChainwebPactDb as Pact5 +import qualified Pact.Core.Command.RPC as Pact5 import qualified Pact.Core.Command.Types as Pact5 import qualified Pact.Core.Hash as Pact5 import qualified Data.ByteString.Short as SB @@ -727,16 +728,58 @@ execReadOnlyReplay lowerBound maybeUpperBound = pactLabel "execReadOnlyReplay" $ Left () -> do return () Right (pwo, pact5Db) -> do +{- + when (V.length (_payloadWithOutputsTransactions pwo) == 1) $ do + let Transaction txBytes = fst $ V.head (_payloadWithOutputsTransactions pwo) + cmd <- do + -- TODO: Make this transformation not so convoluted... + + -- 1. Decode input bytes as a Pact4 Command + let cmd4 :: Pact4.Command Text + cmd4 = fromJuste $ decodeStrictOrThrow' txBytes + + -- 2. Parse the pact4 payload bytes + cmdPayload4 <- case Pact4.decodePayload (pact4ParserVersion v cid (view blockHeight bh)) (Text.encodeUtf8 $ Pact4._cmdPayload cmd4) of + Left err -> internalError $ "execReadOnlyReplay parity: failed to decode pact4 command: " <> sshow err + Right cmdPayload -> return $ fmap Pact4._pcCode cmdPayload + + -- 3. Convert the entire Pact-4 command into a Pact-5 one + let cmd5 = Pact5.fromPact4Command (cmdPayload4 <$ cmd4) + + -- 4. Re-parse the payload. 'fromPact4Command' unfortunately strips the 'Parsed Code' bit. + -- This is ugly as hell. Oh well. + return $ cmd5 <&> \payloadWithText -> payloadWithText <&> \text -> case Pact5.parsePact text of + Left err -> error $ "execReadOnlyReplay parity: failed to parse pact5 command: " <> sshow err + Right cmdPayload -> cmdPayload + + let code = case Pact5._pPayload (Pact5._cmdPayload cmd ^. Pact5.payloadObj) of + Pact5.Exec (Pact5.ExecMsg c _data) -> Pact5._pcCode c + Pact5.Continuation _contMsg -> "" + when ("coin.transfer " `Text.isInfixOf` code) $ do + !_ <- error $ "first block with only 1 tx: " <> sshow (cid, view blockHeight bh, code) + return () +-} forM_ (_payloadWithOutputsTransactions pwo) $ \(Transaction txBytes, TransactionOutput txOutBytes) -> do cmd <- do - let cmdText :: Pact4.Command Text - cmdText = fromJuste $ decodeStrictOrThrow' txBytes + -- TODO: Make this transformation not so convoluted... + + -- 1. Decode input bytes as a Pact4 Command + let cmd4 :: Pact4.Command Text + cmd4 = fromJuste $ decodeStrictOrThrow' txBytes - cmdPayload <- case Pact4.decodePayload (pact4ParserVersion v cid (view blockHeight bh)) (Text.encodeUtf8 $ Pact4._cmdPayload cmdText) of + -- 2. Parse the pact4 payload bytes + cmdPayload4 <- case Pact4.decodePayload (pact4ParserVersion v cid (view blockHeight bh)) (Text.encodeUtf8 $ Pact4._cmdPayload cmd4) of Left err -> internalError $ "execReadOnlyReplay parity: failed to decode pact4 command: " <> sshow err Right cmdPayload -> return $ fmap Pact4._pcCode cmdPayload - return $ Pact5.fromPact4Command (cmdPayload <$ cmdText) + -- 3. Convert the entire Pact-4 command into a Pact-5 one + let cmd5 = Pact5.fromPact4Command (cmdPayload4 <$ cmd4) + + -- 4. Re-parse the payload. 'fromPact4Command' unfortunately strips the 'Parsed Code' bit. + -- This is ugly as hell. Oh well. + return $ cmd5 <&> \payloadWithText -> payloadWithText <&> \text -> case Pact5.parsePact text of + Left err -> error $ "execReadOnlyReplay parity: failed to parse pact5 command: " <> sshow err + Right cmdPayload -> cmdPayload -- TODO: Converting to and from JSON here is bad for perf. cmdResult :: Pact5.CommandResult Pact5.Hash (Pact5.PactErrorCompat (Pact5.LocatedErrorInfo Pact5.Info)) <- do @@ -744,6 +787,20 @@ execReadOnlyReplay lowerBound maybeUpperBound = pactLabel "execReadOnlyReplay" $ cmdResult4 = fromJuste $ decodeStrictOrThrow' txOutBytes decodeStrictOrThrow' (BS.toStrict $ J.encode cmdResult4) + miner <- fromMinerData (_payloadWithOutputsMiner pwo) + let txContext = Pact5.TxContext + { _tcParentHeader = ParentHeader bhParent + , _tcMiner = miner + } + let spvSupport = Pact5.pactSPV bhdb bh + let initialGas = Pact5.initialGasOf (Pact5._cmdPayload cmd) + + Pact5.applyCmd logger Nothing pact5Db txContext spvSupport initialGas (fmap (^. Pact5.payloadObj) cmd) >>= \case + Left e -> do + print e + Right _ -> do + !_ <- error "it's all good" + return () return () return () diff --git a/src/Chainweb/Pact/PactService/Pact4/ExecBlock.hs b/src/Chainweb/Pact/PactService/Pact4/ExecBlock.hs index 1f705b46f..587128bf2 100644 --- a/src/Chainweb/Pact/PactService/Pact4/ExecBlock.hs +++ b/src/Chainweb/Pact/PactService/Pact4/ExecBlock.hs @@ -114,13 +114,7 @@ import qualified Data.List.NonEmpty as NE import Pact.Core.Persistence.Types qualified as Pact5 import Pact.Core.Builtin qualified as Pact5 import Pact.Core.Evaluate qualified as Pact5 - - --let originalPact4Db = Pact4._cpPactDbEnv blockDbEnv - --(reflecting4Db, reflected5Db) <- liftIO $ mkReflectingPactDb (pdPactDb originalPact4Db) - --let pactDb = originalPact4Db { pdPactDb = reflecting4Db } - -mkReflectingPactDb :: Pact4.PactDb e -> IO (Pact4.PactDb e, Pact5.PactDb Pact5.CoreBuiltin Pact5.Info) -mkReflectingPactDb = undefined +import Chainweb.Pact.ReflectingDb (mkReflectingDb) execBlockReflecting :: (CanReadablePayloadCas tbl, Logger logger) @@ -128,9 +122,10 @@ execBlockReflecting -> CheckablePayload -> PactBlockM logger tbl (Pact4.Gas, PayloadWithOutputs, Pact5.PactDb Pact5.CoreBuiltin Pact5.Info) execBlockReflecting currHeader payload = do + liftIO $ putStrLn "peeopeeop" let plData = checkablePayloadToPayloadData payload dbEnv' <- view psBlockDbEnv - (reflecting4Db, reflected5Db) <- liftIO $ mkReflectingPactDb (pdPactDb (_cpPactDbEnv dbEnv')) + (reflecting4Db, reflected5Db) <- liftIO $ mkReflectingDb (pdPactDb (_cpPactDbEnv dbEnv')) let dbEnv = dbEnv' { _cpPactDbEnv = (_cpPactDbEnv dbEnv') { pdPactDb = reflecting4Db } } miner <- decodeStrictOrThrow' (_minerData $ view payloadDataMiner plData) diff --git a/src/Chainweb/Pact/ReflectingDb.hs b/src/Chainweb/Pact/ReflectingDb.hs index 697f3d1f1..e9414284e 100644 --- a/src/Chainweb/Pact/ReflectingDb.hs +++ b/src/Chainweb/Pact/ReflectingDb.hs @@ -1,4 +1,5 @@ {-# LANGUAGE GADTs #-} +{-# LANGUAGE ImportQualifiedPost #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE OverloadedStrings #-} @@ -7,7 +8,8 @@ module Chainweb.Pact.ReflectingDb where -import Data.Text(Text) +import Data.Text (Text) +import Data.Text qualified as T import qualified Pact.Types.Persistence as Pact4 import qualified Pact.Types.Util as Pact4 @@ -118,17 +120,18 @@ pact4ReflectingDb PactTables{..} pact4Db = do pure ks _ -> pure ks - - read' :: forall k v . (IsString k,FromJSON v) => IORef WriteSet -> Pact4.Domain k v -> k -> Pact4.Method e (Maybe v) read' wsRef dom k meth = do + putStrLn "peepeepoopoo" let domainStr = Pact4.asString dom let keyString = Pact4.asString keyString writeSet <- readIORef wsRef Pact4._readRow pact4Db dom k meth >>= \case Nothing -> pure Nothing Just v -> do - unless (isInWriteSet domainStr keyString writeSet) $ writeToPactTables dom k v + unless (isInWriteSet domainStr keyString writeSet) $ do + putStrLn $ "Writing { domain = " <> T.unpack domainStr <> ", key = " <> T.unpack keyString <> " }" + writeToPactTables dom k v pure (Just v) writeToPactTables :: Pact4.Domain k v -> k -> v -> IO ()