Display key used by exerciseByKey and fetchByKey in transaction log (#14035) (#14162)

* Show key in transaction log when exercising by key

* Only show key if key was actually used

* Show key if used by a fetch in transaction view

* Add test for key showing up in log on fetch/exercise

* CHANGELOG_BEGIN
Display key used by exerciseByKey and fetchByKey in transaction log
CHANGELOG_END

* Dummy commit for CHANGELOG

changelog_begin
changelog_end

* Use "by key" instead of "using key", to better match function names

* Test that key is only reported when ByKey is used
This commit is contained in:
dylant-da 2022-06-15 17:50:35 +01:00 committed by GitHub
parent b023bebfda
commit 90f0bf8ba0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 104 additions and 0 deletions

View File

@ -160,6 +160,79 @@ main =
]
expectScriptSuccess rs (vr "testExerciseByKey") $ \r ->
matchRegex r "Active contracts: \n\nReturn value: 42\n\n$",
testCase "fetch and exercising by key shows key in log" $ do
rs <-
runScripts
scriptService
[ "module Test where",
"import Daml.Script",
"",
"template T",
" with",
" owner : Party",
" where",
" signatory owner",
" key owner : Party",
" maintainer key",
" nonconsuming choice C : ()",
" controller owner",
" do",
" pure ()",
"",
"template Runner",
" with",
" owner : Party",
" where",
" signatory owner",
"",
" choice RunByKey : ()",
" with",
" party : Party",
" controller owner",
" do",
" cid <- create T with owner = party",
" exerciseByKey @T party C",
" fetchByKey @T party",
" pure ()",
"",
" choice Run : ()",
" with",
" party : Party",
" controller owner",
" do",
" cid <- create T with owner = party",
" exercise cid C",
" fetch cid",
" pure ()",
"",
"testReportsKey = do",
" p <- allocateParty \"p\"",
" submit p $ createAndExerciseCmd (Runner p) (RunByKey p)",
"",
"testDoesNotReportKey = do",
" p <- allocateParty \"p\"",
" submit p $ createAndExerciseCmd (Runner p) (Run p)"
]
expectScriptSuccess rs (vr "testReportsKey") $ \r ->
matchRegex r (T.unlines
[ ".*exercises.*"
, ".*by key.*"
]) &&
matchRegex r (T.unlines
[ ".*fetch.*"
, ".*by key.*"
])
expectScriptSuccess rs (vr "testDoesNotReportKey") $ \r ->
matchRegex r ".*exercises.*" &&
matchRegex r ".*fetch.*" &&
not (matchRegex r (T.unlines
[ ".*exercises.*"
, ".*by key.*"
])) &&
not (matchRegex r (T.unlines
[ ".*fetch.*"
, ".*by key.*"
])),
testCase "failing transactions" $ do
rs <-
runScripts

View File

@ -226,6 +226,7 @@ data ExerciseContext = ExerciseContext
, choiceId :: TL.Text
, exerciseLocation :: Maybe Location
, chosenValue :: Maybe Value
, exerciseKey :: Maybe KeyWithMaintainers
} deriving (Eq, Show)
ptxExerciseContext :: PartialTransaction -> Maybe ExerciseContext
@ -249,6 +250,7 @@ ptxExerciseContext PartialTransaction{..} = go Nothing partialTransactionRoots
, choiceId = node_ExerciseChoiceId
, exerciseLocation = Nothing
, chosenValue = node_ExerciseChosenValue
, exerciseKey = node_ExerciseExerciseByKey
}
in go (Just ctx) node_ExerciseChildren
| otherwise -> acc
@ -709,6 +711,13 @@ prettyNodeNode nn = do
<-> maybe mempty
(\tid -> parens (prettyDefName world tid))
node_FetchTemplateId
$$ foldMap
(\key ->
let prettyKey = prettyMay "<KEY?>" (prettyValue' False 0 world) $ keyWithMaintainersKey key
in
hsep [ keyword_ "by key", prettyKey ]
)
node_FetchFetchByKey
NodeNodeExercise Node_Exercise{..} -> do
ppChildren <- prettyChildren node_ExerciseChildren
@ -722,6 +731,13 @@ prettyNodeNode nn = do
, prettyContractId node_ExerciseTargetContractId
, parens (prettyMay "<missing TemplateId>" (prettyDefName world) node_ExerciseTemplateId)
]
$$ foldMap
(\key ->
let prettyKey = prettyMay "<KEY?>" (prettyValue' False 0 world) $ keyWithMaintainersKey key
in
hsep [ keyword_ "by key", prettyKey ]
)
node_ExerciseExerciseByKey
$$ if isUnitValue node_ExerciseChosenValue
then mempty
else keyword_ "with"

View File

@ -24,6 +24,7 @@ ctx choice = ExerciseContext
, choiceId = TL.pack choice
, exerciseLocation = Nothing
, chosenValue = Nothing
, exerciseKey = Nothing
}
ptxExerciseContextTests :: TestTree
@ -72,6 +73,7 @@ toPtx nodes = case runState (mapM go nodes) (0, []) of
, node_FetchTemplateId = Nothing
, node_FetchSignatories = V.empty
, node_FetchStakeholders = V.empty
, node_FetchFetchByKey = Nothing
}
Lookup -> pure $ S.NodeNodeLookupByKey S.Node_LookupByKey
{ node_LookupByKeyTemplateId = Nothing
@ -95,6 +97,7 @@ toPtx nodes = case runState (mapM go nodes) (0, []) of
, node_ExerciseChildren = V.fromList children'
, node_ExerciseExerciseResult = if complete then Just (S.Value (Just (S.ValueSumUnit S.Empty))) else Nothing
, node_ExerciseConsuming = False
, node_ExerciseExerciseByKey = Nothing
}
let node = S.Node
{ nodeNodeId = Just nid

View File

@ -582,6 +582,7 @@ message Node {
Identifier template_id = 2;
repeated Party signatories = 3;
repeated Party stakeholders = 4;
KeyWithMaintainers fetch_by_key = 13; // optional, if non-empty then fetched by key
}
message Exercise {
@ -596,6 +597,7 @@ message Node {
repeated Party stakeholders = 9;
repeated NodeId children = 11;
Value exercise_result = 12; // None for incomplete/aborted exercise nodes.
KeyWithMaintainers exercise_by_key = 13; // optional, if non-empty then exercised by key
}
message LookupByKey {

View File

@ -561,6 +561,11 @@ final class Conversions(
.setTemplateId(convertIdentifier(fetch.templateId))
.addAllSignatories(fetch.signatories.map(convertParty).asJava)
.addAllStakeholders(fetch.stakeholders.map(convertParty).asJava)
if (fetch.byKey) {
fetch.versionedKey.foreach { key =>
fetchBuilder.setFetchByKey(convertKeyWithMaintainers(key))
}
}
builder.setFetch(fetchBuilder.build)
case ex: Node.Exercise =>
nodeInfo.optLocation.map(loc => builder.setLocation(convertLocation(loc)))
@ -583,6 +588,11 @@ final class Conversions(
ex.exerciseResult.foreach { result =>
exerciseBuilder.setExerciseResult(convertValue(result))
}
if (ex.byKey) {
ex.versionedKey.foreach { key =>
exerciseBuilder.setExerciseByKey(convertKeyWithMaintainers(key))
}
}
builder.setExercise(exerciseBuilder.build)
case lbk: Node.LookupByKey =>