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