Is there a way to test witnessing in a DAML Scenario?
Mod note: As of SDK 1.5.0 Scenarios have been superseded by the more powerful Daml Script. We now recommend using that for all purposes. For more information, and to learn how to use Script please check out @Andreas’ post on our blog.
I would like to test if a party is really unable to “see” a specific contract e.g. the party cannot fetch it and is neither a witness (in table view, it should have -). My understanding is that fetch is not enough for this task. I can manually check visibility in the “Table View” but would like to do it programmatically.
How can I do this preferably from a DAML Scenario?
I’m not aware of how you can do it using a scenario. You can be sure about this reading transaction trees on behalf of the user from the Ledger API and verifying you don’t see any event about the contract. This would mean you would have an integration test for it rather than a unit test.
You can do this using fetch. Let’s say you have
template Secret
with
p : Party
where
signatory p
and want to test whether Bob can see a contract signed by Alice. You can do so by just doing a fetch in a submit block:
d = scenario do
[alice, bob] <- mapA getParty ["Alice", "Bob"]
secret <- submit alice do
create Secret with p = alice
submit bob do
fetch secret
This will error with the expected message:
Attempt to fetch or exercise a contract not visible to the committer.
Contract: #0:0 (Main:Secret)
Committer: 'Bob'
Disclosed to: 'Alice'
You may now think that you can just change submit to submitMustFail and be done with it, but that’s not the case. Let’s divulge the contract to Bob to see what happens:
template SecretDivulger
with
bob : Party
alice : Party
where
signatory bob
controller alice can
Divulge : Secret
with
secret : ContractId Secret
do
fetch secret
d2 = scenario do
[alice, bob] <- mapA getParty ["Alice", "Bob"]
secret <- submit alice do
create Secret with ..
divulger <- submit bob do
create SecretDivulger with ..
submit alice do
exercise divulger Divulge with ..
submit bob do
fetch secret
The scenario still fails, but this time with a different error message:
0: fetch of Main:Secret at DA.Internal.Prelude:381:26
failed since none of the stakeholders 'Alice'
is in the authorizing set 'Bob'
The authorisation check didn’t pass. In other words, our original test would never succeed so changing the submit to submitMustFail doesn’t help at all.
But we can fix the authorization check by delegating the fetch:
template FetchDelegator
with
bob : Party
alice : Party
where
signatory alice
controller bob can
Fetch : Secret
with
secret : ContractId Secret
do
fetch secret
d3 = scenario do
[alice, bob] <- mapA getParty ["Alice", "Bob"]
secret <- submit alice do
create Secret with ..
divulger <- submit bob do
create SecretDivulger with ..
submit alice do
exercise divulger Divulge with ..
delegator <- submit alice do
create FetchDelegator with ..
submit bob do
exercise delegator Fetch with ..
You can now test that the final submit fails or succeeds exactly in line with whether Bob knows the contract or not.
This is rather a difficult way to test this, which is one of the many use-cases for returning error details on submitMustFail. @matt’s working on that.