Skip to content
This repository was archived by the owner on Nov 26, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pact-lsp/Pact/Core/LanguageServer/Utils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ termAt p term
CWithCapability a b -> termAt p a <|> termAt p b
CTry a b -> termAt p a <|> termAt p b
CCreateUserGuard a -> termAt p a
CPure a -> termAt p a
<|> Just t
t@(ListLit tms _) -> getAlt (foldMap (Alt . termAt p) tms) <|> Just t
t@(Nullary tm _) -> termAt p tm <|> Just t
Expand Down
26 changes: 26 additions & 0 deletions pact-tests/pact-tests/read-only.repl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
(module read-only-test g
(defcap g () true)

(defschema sc a:integer b:string)
(deftable tbl:{sc})

(defcap ENFORCE_ME (a:integer) true)

(defun write-entry (k:string a:integer b:string)
(write tbl k {"a":a, "b":b})
)

(defun read-entry (k:string)
(read tbl k)
)

(defun write-then-read (k:string a:integer b:string)
(write-entry k a b)
(read-entry k)
))

(create-table tbl)

(expect "Writes and reads work" {"a":1, "b":"v"} (write-then-read "k" 1 "v") )
(expect-failure "Writes do not work in read-only mode" (pure (write-then-read "k" 1 "v")))
(expect "Only reads work in read-only mode" {"a":1, "b":"v"} (pure (read-entry "k")))
3 changes: 3 additions & 0 deletions pact/Pact/Core/Builtin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ data BuiltinForm o
| CWithCapability o o
| CCreateUserGuard o
| CEnforceOne o o
| CPure o
| CTry o o
deriving (Show, Eq, Functor, Foldable, Traversable, Generic)

Expand All @@ -75,6 +76,8 @@ instance Pretty o => Pretty (BuiltinForm o) where
parens ("create-user-guard" <+> pretty o)
CTry o o' ->
parens ("try" <+> pretty o <+> pretty o')
CPure o ->
parens ("pure" <+> pretty o)

-- | Our list of base-builtins to pact.
data CoreBuiltin
Expand Down
5 changes: 5 additions & 0 deletions pact/Pact/Core/IR/Desugar.hs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ data SpecialForm
| SFTry
| SFMap
| SFCond
| SFPure
| SFCreateUserGuard
deriving (Eq, Show, Enum, Bounded)

Expand All @@ -274,6 +275,7 @@ toSpecialForm = \case
"enforce-one" -> Just SFEnforceOne
"try" -> Just SFTry
"map" -> Just SFMap
"pure" -> Just SFPure
"do" -> Just SFDo
"cond" -> Just SFCond
"create-user-guard" -> Just SFCreateUserGuard
Expand Down Expand Up @@ -363,6 +365,9 @@ desugarSpecial (bn@(BareName t), varInfo) dsArgs appInfo = case toSpecialForm t
[e] -> BuiltinForm <$> (CCreateUserGuard <$> desugarLispTerm e) <*> pure appInfo
_ -> throwDesugarError (InvalidSyntax "create-user-guard must take one argument, which must be an application") appInfo
SFMap -> desugar1ArgHOF MapV args
SFPure -> case args of
[e] -> BuiltinForm <$> (CPure <$> desugarLispTerm e) <*> pure appInfo
_ -> throwDesugarError (InvalidSyntax "run-read-only must take one argument") appInfo
SFCond -> case reverse args of
defCase:xs -> do
defCase' <- desugarLispTerm defCase
Expand Down
5 changes: 4 additions & 1 deletion pact/Pact/Core/IR/Eval/CEK/Evaluator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ evaluateTerm cont handler env (BuiltinForm c info) = case c of
evalCEK cont' handler env x
_ -> throwExecutionError info $ NativeExecutionError (NativeName "create-user-guard") $
"create-user-guard: expected function application of a top-level function"
CPure term -> do
let env' = readOnlyEnv env
evalCEK cont handler env' term
-- | ------ From --------------- | ------ To ------------------------ |
-- <Try c body, E, K, H> <body, E, Mt, CEKHandler(E,c,K,_errState,H)>
-- _errState - callstack,granted caps,events,gas
Expand Down Expand Up @@ -314,7 +317,7 @@ mkDefPactClosure
-> FullyQualifiedName
-> DefPact Name Type b i
-> CEKEnv e b i
->CEKValue e b i
-> CEKValue e b i
mkDefPactClosure info fqn dpact env = case _dpArgs dpact of
[] ->
let dpc = DefPactClosure fqn NullaryClosure 0 env info
Expand Down
4 changes: 3 additions & 1 deletion pact/Pact/Core/IR/Eval/Direct/Evaluator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ module Pact.Core.IR.Eval.Direct.Evaluator
import Control.Lens hiding (op, from, to, parts)
import Control.Monad
import Control.Monad.Except
import Control.Monad.Reader
import Control.Monad.State.Strict
import Data.Text(Text)
import Data.Foldable
Expand Down Expand Up @@ -278,6 +277,9 @@ evaluate env = \case
else do
msg <- enforceString info =<< evaluate env str
throwUserRecoverableError info (UserEnforceError msg)
CPure e -> do
let env' = readOnlyEnv env
evaluate env' e
CWithCapability cap body -> do
enforceNotWithinDefcap info env "with-capability"
rawCap <- enforceCapToken info =<< evaluate env cap
Expand Down
3 changes: 3 additions & 0 deletions pact/Pact/Core/Serialise/CBOR_V1.hs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,8 @@ instance (Serialise (SerialiseV1 b), Serialise (SerialiseV1 i))
encodeListLen 3 <> encodeWord 6 <> encodeS t1 <> encodeS t2
CCreateUserGuard t1 ->
encodeListLen 2 <> encodeWord 7 <> encodeS t1
CPure t1 ->
encodeListLen 2 <> encodeWord 8 <> encodeS t1
{-# INLINE encode #-}

decode = do
Expand All @@ -385,6 +387,7 @@ instance (Serialise (SerialiseV1 b), Serialise (SerialiseV1 i))
5 -> CWithCapability <$> decodeS <*> decodeS
6 -> CTry <$> decodeS <*> decodeS
7 -> CCreateUserGuard <$> decodeS
8 -> CPure <$> decodeS
_ -> fail "unexpected decoding"
{-# INLINE decode #-}

Expand Down
1 change: 1 addition & 0 deletions test-utils/Pact/Core/Gen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ builtinFormGen b i = Gen.choice
, CWithCapability <$> termGen b i <*> termGen b i
, CTry <$> termGen b i <*> termGen b i
, CCreateUserGuard <$> termGen b i
, CPure <$> termGen b i
]

termGen :: Gen b -> Gen i -> Gen (Term Name Type b i)
Expand Down
Loading