Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add session command data and enforce-session builtin #1171

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2dee0a2
Add enforceKeysetSession to Eval.hs
imalsogreg Mar 28, 2023
a74509f
Add enforce-session builtin
imalsogreg Mar 28, 2023
625a50a
add repl test
imalsogreg Mar 28, 2023
9d8e9b5
add sessionsigner to setupevalenv
imalsogreg Mar 28, 2023
31a425b
fixup
imalsogreg Mar 28, 2023
1e29182
export
imalsogreg Mar 28, 2023
05ae94e
Thread session-signer through payload and update tests
imalsogreg Mar 29, 2023
bfe2ad1
Add enforce-session to gas tests and gas golden
imalsogreg Mar 30, 2023
6fb10da
Update hashed payloads in continuation tests
imalsogreg Mar 30, 2023
6b228f6
Remove sessionSigner from the pact payload
imalsogreg Apr 3, 2023
bb25cd3
wip move sessionSigner into CommandEnv
imalsogreg Apr 4, 2023
452198e
Pass sessionPubkey into the environment through the Command
imalsogreg Apr 5, 2023
911298a
Remove sessionPubkey from ApiReq
imalsogreg Apr 5, 2023
6434715
tests fixup
imalsogreg Apr 5, 2023
024173e
Revert "Update hashed payloads in continuation tests"
imalsogreg Apr 5, 2023
a1926d2
Remove sessionPubkey from command too
imalsogreg Apr 5, 2023
3a5cc70
fix cap filtering in sessionPubKey check
imalsogreg Apr 5, 2023
1ee475e
cleanup
imalsogreg Apr 5, 2023
a810a2a
more cleanup
imalsogreg Apr 5, 2023
125ae0c
fixup
imalsogreg Apr 5, 2023
6184201
Update src/Pact/Native/Session.hs
imalsogreg Apr 10, 2023
a33ab26
Update src-ghc/Pact/GasModel/GasTests.hs
imalsogreg Apr 10, 2023
6173b6e
Update src/Pact/Native/Session.hs
imalsogreg Apr 10, 2023
b55bd9f
Update src-ghc/Pact/GasModel/GasTests.hs
imalsogreg Apr 10, 2023
35d7f4e
cleanup enforceKeysetSession
imalsogreg Apr 10, 2023
40d27ff
Update src/Pact/Native/Session.hs
imalsogreg Apr 10, 2023
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
22 changes: 22 additions & 0 deletions docs/en/pact-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1773,6 +1773,20 @@ pact> (scalar-mult 'g1 {'x: 1, 'y: 2} 2)
{"x": 1368015179489954701390400359078579693043519447331113978918064868415326638035,"y": 9918110051302171585080402603319702774565515993150576347155970296011118125764}
```

## Session {#Session}

### enforce-session {#enforce-session}

*keyset* `keyset` *→* `bool`

*keysetname* `string` *→* `bool`


Enforce that the current environment contains a session signer with a key that satisfies the keyset parameter. The execution environment is responsible for setting the session signer, usually in response to an authorization flow.
```lisp
(enforce-session keyset)
```

## REPL-only functions {#repl-lib}

The following functions are loaded automatically into the interactive REPL, or within script files with a `.repl` extension. They are not available for blockchain-based execution.
Expand Down Expand Up @@ -2028,6 +2042,14 @@ Install a managed namespace policy specifying ALLOW-ROOT and NS-POLICY-FUN.
```


### env-session {#env-session}

*public-key* `string` *caps* `[string]` *→* `string`





### env-sigs {#env-sigs}

*sigs* `[object:*]` *→* `string`
Expand Down
2 changes: 2 additions & 0 deletions golden/gas-model/golden
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,8 @@
(diff-time (time "2016-07-22T12:00:00Z")
(time "2018-07-22T12:00:00Z"))
- 12
- - (enforce-session 'some-loaded-keyset)
- 8
- - (make-list longNumber true)
- 1026
- - (make-list medNumber true)
Expand Down
1 change: 1 addition & 0 deletions pact.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ library
Pact.Native.Guards
Pact.Native.Db
Pact.Native.Internal
Pact.Native.Session
Pact.Native.SPV
Pact.Native.Time
Pact.Native.Ops
Expand Down
6 changes: 6 additions & 0 deletions src-ghc/Pact/ApiReq.hs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ import Pact.Types.Runtime
import Pact.Types.SigData
import Pact.Types.SPV

-- import Debug.Trace (trace)

-- | For fully-signed commands
data ApiKeyPair = ApiKeyPair {
_akpSecret :: PrivateKeyBS,
Expand Down Expand Up @@ -449,6 +451,7 @@ mkExec code mdata pubMeta kps nid ridm = do
pubMeta
rid
nid
Nothing
(Exec (ExecMsg code mdata))
return $ decodeUtf8 <$> cmd

Expand All @@ -475,6 +478,7 @@ mkUnsignedExec code mdata pubMeta kps nid ridm = do
pubMeta
rid
nid
Nothing
(Exec (ExecMsg code mdata))
return $ decodeUtf8 <$> cmd

Expand Down Expand Up @@ -538,6 +542,7 @@ mkCont txid step rollback mdata pubMeta kps ridm proof nid = do
pubMeta
rid
nid
Nothing
(Continuation (ContMsg txid step rollback mdata proof) :: (PactRPC ContMsg))
return $ decodeUtf8 <$> cmd

Expand Down Expand Up @@ -571,6 +576,7 @@ mkUnsignedCont txid step rollback mdata pubMeta kps ridm proof nid = do
pubMeta
(pack $ show rid)
nid
Nothing
(Continuation (ContMsg txid step rollback mdata proof) :: (PactRPC ContMsg))
return $ decodeUtf8 <$> cmd

Expand Down
10 changes: 5 additions & 5 deletions src-ghc/Pact/Bench.hs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ loadBenchModule db = do
pactInitialHash
[Signer Nothing pk Nothing []]
let ec = ExecutionConfig $ S.fromList [FlagDisablePact44]
e <- setupEvalEnv db entity Transactional md initRefStore
e <- setupEvalEnv db entity Transactional md Nothing initRefStore
freeGasEnv permissiveNamespacePolicy noSPVSupport def ec
(r :: Either SomeException EvalResult) <- try $ evalExec defaultInterpreter e pc
void $ eitherDie "loadBenchModule (load)" $ fmapL show r
Expand Down Expand Up @@ -185,8 +185,8 @@ runPactExec :: Advice -> String -> [Signer] -> Value -> Maybe (ModuleData Ref) -
runPactExec pt msg ss cdata benchMod dbEnv pc = do
let md = MsgData cdata Nothing pactInitialHash ss
ec = ExecutionConfig $ S.fromList [FlagDisablePact44]
e <- fmap (set eeAdvice pt) $ setupEvalEnv dbEnv entity Transactional md
initRefStore prodGasEnv permissiveNamespacePolicy noSPVSupport def ec
e <- fmap (set eeAdvice pt) $ setupEvalEnv dbEnv entity Transactional md Nothing
initRefStore prodGasEnv permissiveNamespacePolicy noSPVSupport def ec
let s = perfInterpreter pt $ defaultInterpreterState $
maybe id (const . initStateModules . HM.singleton (ModuleName "bench" Nothing)) benchMod
(r :: Either SomeException EvalResult) <- try $! evalExec s e pc
Expand All @@ -197,7 +197,7 @@ execPure :: Advice -> PactDbEnv e -> (String,[Term Name]) -> IO [Term Name]
execPure pt dbEnv (n,ts) = do
let md = MsgData Null Nothing pactInitialHash []
ec = ExecutionConfig $ S.fromList [FlagDisablePact44]
env <- fmap (set eeAdvice pt) $ setupEvalEnv dbEnv entity Local md
env <- fmap (set eeAdvice pt) $ setupEvalEnv dbEnv entity Local md Nothing
initRefStore prodGasEnv permissiveNamespacePolicy noSPVSupport def ec
o <- try $ runEval def env $ mapM eval ts
case o of
Expand Down Expand Up @@ -234,7 +234,7 @@ benchReadValue _ (TxTable _t) _k = rcp Nothing

mkBenchCmd :: [SomeKeyPairCaps] -> (String, Text) -> IO (String, Command ByteString)
mkBenchCmd kps (str, t) = do
cmd <- mkCommand' kps
cmd <- mkCommand' kps Nothing
$ toStrict . encode
$ Payload payload "nonce" () ss Nothing
return (str, cmd)
Expand Down
14 changes: 13 additions & 1 deletion src-ghc/Pact/GasModel/GasTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Data.Aeson (toJSON, ToJSON(..))
import Data.Bool (bool)
import Data.Default (def)
import Data.List (foldl')
import Data.Maybe (fromMaybe)
import Data.Maybe (fromMaybe, listToMaybe)
import NeatInterpolation (text)


Expand Down Expand Up @@ -171,6 +171,7 @@ allTests = HM.fromList
-- Keyset native functions
, ("define-keyset", defineKeysetTests)
, ("enforce-keyset", enforceKeysetTests)
, ("enforce-session", enforceSessionTests)
, ("keys-2", keys2Tests)
, ("keys-all", keysAllTests)
, ("keys-any", keysAnyTests)
Expand Down Expand Up @@ -546,6 +547,17 @@ enforceKeysetTests = tests
updateEnvMsgSig
[enforceKeysetExpr]

enforceSessionTests :: NativeDefName -> GasUnitTests
enforceSessionTests = tests
where
enforceSessionExpr = defPactExpression [text| (enforce-session '$sampleLoadedKeysetName) |]
updateEnvMsgSession = setEnv (set eeSessionSig (listToMaybe $ F.toList samplePubKeysWithCaps))

tests =
createGasUnitTests
updateEnvMsgSession
imalsogreg marked this conversation as resolved.
Show resolved Hide resolved
updateEnvMsgSession
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
updateEnvMsgSession
updateEnvMsgSession

[enforceSessionExpr]
imalsogreg marked this conversation as resolved.
Show resolved Hide resolved

readKeysetTests :: NativeDefName -> GasUnitTests
readKeysetTests = tests
Expand Down
2 changes: 1 addition & 1 deletion src-ghc/Pact/GasModel/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ getLoadedState code = do

defEvalEnv :: PactDbEnv e -> IO (EvalEnv e)
defEvalEnv db = do
setupEvalEnv db entity Transactional (initMsgData pactInitialHash)
setupEvalEnv db entity Transactional (initMsgData pactInitialHash) Nothing
initRefStore prodGasModel permissiveNamespacePolicy noSPVSupport def noPact44EC
where entity = Just $ EntityName "entity"
prodGasModel = GasEnv 10000000 0.01 $ tableGasModel defaultGasConfig
Expand Down
10 changes: 5 additions & 5 deletions src-ghc/Pact/Interpreter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -162,19 +162,21 @@ setupEvalEnv
-> Maybe EntityName
-> ExecutionMode
-> MsgData
-> Maybe PublicKeyText
-> RefStore
-> GasEnv
-> NamespacePolicy
-> SPVSupport
-> PublicData
-> ExecutionConfig
-> IO (EvalEnv e)
setupEvalEnv dbEnv ent mode msgData refStore gasEnv np spv pd ec = do
setupEvalEnv dbEnv ent mode msgData sessionPubkey refStore gasEnv np spv pd ec = do
gasRef <- newIORef 0
warnRef <- newIORef mempty
pure EvalEnv {
_eeRefStore = refStore
, _eeMsgSigs = mkMsgSigs $ mdSigners msgData
, _eeSessionSig = fmap (, S.empty) sessionPubkey
, _eeMsgBody = mdData msgData
, _eeMode = mode
, _eeEntity = ent
Expand All @@ -195,11 +197,9 @@ setupEvalEnv dbEnv ent mode msgData refStore gasEnv np spv pd ec = do
}
where
mkMsgSigs ss = M.fromList $ map toPair ss
toPair Signer{..} = (pk,S.fromList _siCapList)
where
toPair Signer{..} = (pk,S.fromList _siCapList)
where
pk = PublicKeyText $ fromMaybe _siPubKey _siAddress

pk = PublicKeyText $ fromMaybe _siPubKey _siAddress

initRefStore :: RefStore
initRefStore = RefStore nativeDefs
Expand Down
1 change: 1 addition & 0 deletions src-ghc/Pact/Server/History/Persistence.hs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ selectAllCommands e = do
let rowToCmd [SText (Utf8 hash'),SText (Utf8 cmd'),SText (Utf8 userSigs')] =
Command { _cmdPayload = cmd'
, _cmdSigs = userSigsFromField userSigs'
, _cmdSessionPubKey = Nothing
, _cmdHash = fromUntypedHash $ hashFromField hash'}
rowToCmd err = error $ "selectAllCommands: unexpected result schema: " ++ show err
fmap rowToCmd <$> qrys_ (_qrySelectAllCmds e) [RText,RText,RText]
2 changes: 1 addition & 1 deletion src-ghc/Pact/Server/History/Service.hs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ _testHistoryDB = do

_go :: HistoryService ()
_go = do
addNewKeys [Command "" [] initialHash]
addNewKeys [Command "" [] Nothing initialHash]
let rq = RequestKey pactInitialHash
res = PactResult $ Left $ PactError TxFailure def def . viaShow $ ("some error message" :: String)
updateExistingKeys (HashMap.fromList [(rq, CommandResult rq Nothing res (Gas 0) Nothing Nothing Nothing [])])
Expand Down
23 changes: 12 additions & 11 deletions src-ghc/Pact/Server/PactService.hs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ initPactService CommandConfig {..} loggers spv = do
blockHeight blockTime prevBlockHash
spv _ccExecutionConfig
eMode cmd (verifyCommand cmd)
, _ceiApplyPPCmd =
, _ceiApplyPPCmd = \eMode cmd ->
applyCmd logger _ccEntity p gasModel
blockHeight blockTime prevBlockHash
spv _ccExecutionConfig
spv _ccExecutionConfig eMode cmd
}
case _ccSqlite of
Nothing -> do
Expand Down Expand Up @@ -140,31 +140,32 @@ fullToHashLogCr full = (pactHash . BSL.toStrict . encode) full


runPayload :: Command (Payload PublicMeta ParsedCode) -> CommandM p (CommandResult Hash)
runPayload c@Command{..} = case (_pPayload _cmdPayload) of
Exec pm -> applyExec (cmdToRequestKey c) _cmdHash (_pSigners _cmdPayload) pm
Continuation ym -> applyContinuation (cmdToRequestKey c) _cmdHash (_pSigners _cmdPayload) ym
runPayload c@Command{..} = do
case (_pPayload _cmdPayload) of
Exec pm -> applyExec (cmdToRequestKey c) _cmdHash (_pSigners _cmdPayload) _cmdSessionPubKey pm
Continuation ym -> applyContinuation (cmdToRequestKey c) _cmdHash (_pSigners _cmdPayload) _cmdSessionPubKey ym


applyExec :: RequestKey -> PactHash -> [Signer] -> ExecMsg ParsedCode -> CommandM p (CommandResult Hash)
applyExec rk hsh signers (ExecMsg parsedCode edata) = do
applyExec :: RequestKey -> PactHash -> [Signer] -> Maybe PublicKeyText -> ExecMsg ParsedCode -> CommandM p (CommandResult Hash)
applyExec rk hsh signers sessionPubkey (ExecMsg parsedCode edata) = do
CommandEnv {..} <- ask
when (null (_pcExps parsedCode)) $ throwCmdEx "No expressions found"
evalEnv
<- liftIO $ setupEvalEnv _ceDbEnv _ceEntity _ceMode
(MsgData edata Nothing (toUntypedHash hsh) signers)
initRefStore _ceGasEnv permissiveNamespacePolicy
sessionPubkey initRefStore _ceGasEnv permissiveNamespacePolicy
_ceSPVSupport _cePublicData _ceExecutionConfig
EvalResult{..} <- liftIO $ evalExec defaultInterpreter evalEnv parsedCode
mapM_ (\p -> liftIO $ logLog _ceLogger "DEBUG" $ "applyExec: new pact added: " ++ show p) _erExec
return $ resultSuccess _erTxId rk _erGas (last _erOutput) _erExec _erLogs _erEvents


applyContinuation :: RequestKey -> PactHash -> [Signer] -> ContMsg -> CommandM p (CommandResult Hash)
applyContinuation rk hsh signers cm = do
applyContinuation :: RequestKey -> PactHash -> [Signer] -> Maybe PublicKeyText -> ContMsg -> CommandM p (CommandResult Hash)
applyContinuation rk hsh signers sessionSigner cm = do
CommandEnv{..} <- ask
-- Setup environment and get result
evalEnv <- liftIO $ setupEvalEnv _ceDbEnv _ceEntity _ceMode
(MsgData (_cmData cm) Nothing (toUntypedHash hsh) signers) initRefStore
(MsgData (_cmData cm) Nothing (toUntypedHash hsh) signers) sessionSigner initRefStore
_ceGasEnv permissiveNamespacePolicy _ceSPVSupport _cePublicData _ceExecutionConfig
EvalResult{..} <- liftIO $ evalContinuation defaultInterpreter evalEnv cm
return $ resultSuccess _erTxId rk _erGas (last _erOutput) _erExec _erLogs _erEvents
33 changes: 33 additions & 0 deletions src/Pact/Eval.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module Pact.Eval
,acquireModuleAdmin
,computeUserAppGas,prepareUserAppArgs,evalUserAppBody
,evalByName
,enforceKeySetSession
,resumePact
,enforcePactValue,enforcePactValue'
,toPersistDirect
Expand Down Expand Up @@ -146,6 +147,38 @@ enforceKeySet i ksn KeySet{..} = do
| otherwise = failed
{-# INLINE enforceKeySet #-}

-- | Enforce keyset against session key from the environment.
enforceKeySetSession :: PureSysOnly e => Info -> Maybe KeySetName -> KeySet -> Eval e ()
enforceKeySetSession i ksn KeySet{..} = do
sessionPubKey <- view eeSessionSig
case sessionPubKey of
Nothing -> evalError i "enforce-session called while there is no session pubkey in the environment"
Just (publicKeyText, caps) -> do
sigs' <- checkSigCaps (M.singleton publicKeyText caps)
runPred (M.size sigs')
where
failed = failTx i $ "Keyset failure " <> parens (pretty _ksPredFun) <> ": " <>
maybe (pretty $ map (elide . asString) $ toList _ksKeys) pretty ksn
atLeast t m = m >= t
elide pk | T.length pk < 8 = pk
| otherwise = T.take 8 pk <> "..."
count = length _ksKeys
runPred matched =
case M.lookup _ksPredFun keyPredBuiltins of
Just KeysAll -> runBuiltIn (\c m -> atLeast c m)
Just KeysAny -> runBuiltIn (\_ m -> atLeast 1 m)
Just Keys2 -> runBuiltIn (\_ m -> atLeast 2 m)
Nothing -> do
r <- evalByName _ksPredFun [toTerm count,toTerm matched] i
case r of
(TLiteral (LBool b) _) | b -> return ()
| otherwise -> failed
_ -> evalError i $ "Invalid response from keyset predicate: " <> pretty r
where
runBuiltIn p | p count matched = return ()
| otherwise = failed
{-# INLINE enforceKeySetSession #-}

enforceGuard :: HasInfo i => i -> Guard (Term Name) -> Eval e ()
enforceGuard i g = case g of
GKeySet k -> runSysOnly $ enforceKeySet (getInfo i) Nothing k
Expand Down
1 change: 1 addition & 0 deletions src/Pact/Gas/Table.hs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ defaultGasTable =
,("enforce", 1)
,("enforce-guard", 8)
,("enforce-keyset", 8)
,("enforce-session", 8)
,("enforce-one", 6)
,("enforce-pact-version", 1)
,("enumerate", 1)
Expand Down
2 changes: 2 additions & 0 deletions src/Pact/Native.hs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import Pact.Native.Internal
import Pact.Native.Keysets
import Pact.Native.Ops
import Pact.Native.SPV
import Pact.Native.Session (sessionDefs)
import Pact.Native.Time
import Pact.Native.Pairing(zkDefs)
import Pact.Parse
Expand All @@ -119,6 +120,7 @@ natives =
, decryptDefs
, guardDefs
, zkDefs
, sessionDefs
]


Expand Down
Loading