In a different thread, @cocreature stated
That doesn’t actually allow you to catch authorization errors though which was part of the original question.
That got me thinking why not?!
In a different thread, @cocreature stated
That doesn’t actually allow you to catch authorization errors though which was part of the original question.
That got me thinking why not?!
Pro tip: if you put your answer to your own question as a second message, you can actually mark it as the answer and then the question looks like it’s answered.
I’m going to answer my own question here, because I’ve been pondering this for the last half hour.
First, I figured you can already write a model isomorphic to any other model in which authorization errors are handleable. First, just make every choice a public choice with a field controllers : Set Party
and an initial assert (controllers == expectedControllers)
. So instead of
controller expectedControllers can
Foo : Bar
with
...
do
write
choice Foo : Bar
with
controllers : Set Party
...
controller controllers
do
assert (controllers == expectedControllers)
...
Secondly, wrap every create
in the function
catchableCreate c = do assert (signatory c `subset` (signatory this `union` controllers)) create c
Now every authorization check has become an assertion, which the new exception handling feature can catch.
But then I was reminded why authorization errors are not catchable. Imagine there was a contract c
on the ledger at some point with Alice as a signatory. Eve learned of this contract somehow and wants to know whether it’s still active, even through by the Daml privacy model she has no right to get that information. Let’s suppose she could submit this transaction:
try do
fetch c
catch
AuthorizationError m -> return ()
One of two things can happen:
c
does not exist.Fetch
.Whether she gets 1 or 2 must not depend on the activeness of c
, otherwise we have an information leak. But 1 has to be possible since the contract may be genuinely unknown to the validators - Alice in this case. So we always have to go with 1 and therefore the authorization error cannot be handled.
So given I said you can build an isomorphic model where we can catch authorization errors, did we introduce a privacy leak with Daml Exceptions?
I believe not. Can you spot where I want wrong with my “isomorphic model”?
By changing a choice to a public choice with an assertion to check controllers, I have decoupled the authorization for the activeness check from the authorization for the execution of the exercise body. Anyone is now authorized to check activeness by calling the public choice. The two models are not isomorphic after all.
Imagine this choice:
choice CheckActive : ()
with
fetcher : Party
controller fetcher
do
abort "Abort! Abort!"
This is saying anyone can call this choice and as part of that check the activeness of the surrounding contract. But no exercise of the choice will ever succeed.
Anyone can now legitimately check the activeness of c
using
try do
exercise c CheckActive
catch
GeneralError m -> return ()
This is one of many subtleties in Exception handling we had to explore in-depth as part of the design of this feature, and I hope to cover this and more in a blog post soon.
What do you think, does the above argument hold up? Do you think authorization errors could be handled without privacy leaks? Let me know
While I’m certain @bernhard is aware of that I do want to point out for others that this only applies to catching authorization failures within a transaction. @Brian_Weir’s request of catching this on a call to submit
is perfectly reasonable and there is nothing fundamental that prevents this.