Before the multi-party submission feature it was obvious who are the controllers of a choice, in other words who can exercise that choice.
For example take a look the following code:
template Example
with
owner : Party
observers : Set Party
where
signatory owner
observer observers
nonconsuming choice GetAnswer : Int
with
actor : Party
controller actor
do pure 42
Without multi-party submission one could state that only the stakeholders can exercise GetAnswer
, id est the owner
or any of the observers
.
That reasoning could be made purely by looking at the Daml code.
With multi-party submission the following is possible:
example_test : Script ()
example_test = do
alice <- allocateParty "Alice"
bob <- allocateParty "Bob"
example <- alice `submit` createCmd Example with owner = alice, observers = Set.singleton alice
submitMustFail bob $ exerciseCmd example GetAnswer with actor = bob
answer <- submitMulti [bob] [alice] $ exerciseCmd example GetAnswer with actor = bob
42 === answer
So, although “Bob” does not have direct access to the contract (submitMustFail
succeeds), he can exercise the choice if is granted indirect visibility from “Alice”.
How should I think about this? Is it true that I cannot reason about the visibility of a Daml model any more just by looking at the code?
3 Likes
Interesting question!
This is not quite right. Even without multi-party submissions, a non-stakeholder can execute the choice. The prerequisite for that is that the actor has seen the contract. This is clearly the case if they are a stakeholder but it can also be achieved via divulgence. This does appear somewhere in the code but it can happen in a separate package and Daml generally operates in an open world assumption (meaning you don’t know what future code will be added).
So multi-party submissions don’t change anything fundamentally here. They just avoid the need to have to divulge the contract beforehand or add the other party as an observer beforehand.
Here’s a full example of achieving an exercise as a non-stakeholder via divulgence:
module Main where
import Daml.Script
import qualified DA.Set as Set
import DA.Set (Set)
template Example
with
owner : Party
observers : Set Party
where
signatory owner
observer observers
nonconsuming choice GetAnswer : Int
with
actor : Party
controller actor
do pure 42
template Divulger
with
sig : Party
obs : Party
where
signatory sig
observer obs
nonconsuming choice Divulge : Example
with
cid : ContractId Example
controller obs
do fetch cid
test = script do
alice <- allocateParty "Alice"
bob <- allocateParty "Bob"
cid <- submit alice $
createCmd (Example alice Set.empty)
submitMustFail bob $
exerciseCmd cid (GetAnswer bob)
divulger <- submit bob $
createCmd (Divulger bob alice)
submit alice $
exerciseCmd divulger (Divulge cid)
submit bob $
exerciseCmd cid (GetAnswer bob)
pure ()
3 Likes