`submitMustFailWith`

I was going to suggest the addition of a submitMustFailWith or equivalent to the SDK.

The use-case I have for this, is for example that I want to check that a transaction fails due to a failed precondition (e.g. asset quantity must be positive), rather than say, a missing controller - the current submitMustFail doesn’t discriminate between the two. This can be done with a trycatch_ clause.

I’ve factored this out into:

submitMustFailWith : forall e m cmds a . (Exception e, ActionCatch m, HasSubmit m cmds, HasCallStack) 
  => Party 
  -> cmds a 
  -> m ()
submitMustFailWith party cmds = 
  try do
    void $ submit party cmds
    throw $ AssertionFailed "Submit should have failed but passed"
  catch
    (_ : e) ->
      pure ()

testSplit = script do
  ...
  
  mint <- submitMulti [registrar, alice] [] $ createCmd Holding with
    instrument = usd
    quantity = 1000.0

  submitMustFailWith @PreconditionFailed alice $ exerciseCmd mint Split with splitQuantity = 2000.0

But the result is still

daml/Daml/Finance.daml|91 col 1| Script:Error:Scenario execution failed on commit at Daml.Finance:85:12: Unhandled exception:  DA.Exception.PreconditionFailed:PreconditionFailed@f20de1e4e37b92280264c08bf15eca0be0bc5babd7a7b5e574997f154c00cb78 with message = "Template precondition violated: Holding {regulators = Set [], registrars = Set ['registrar'], creditors = Set [], beneficiaries = Set ['alice'], subcustodians = ['registrar'], instrument = <contract-id>, quantity = -1000.0}" Ledger time: 1970-01-01T00:00:00Z Partial transaction: Failed exercise (unknown source): exercises Split on #1:0 (Daml.Finance:Holding) with splitQuantity = 2000.0000000000 Sub-transactions: 0 └─> 'alice' exercises Split on #1:0 (Daml.Finance:Holding) with splitQuantity = 2000.0000000000 children: 1 └─> create Daml.Finance:Holding with regulators = (DA.Set.Types:Set@97b883cd8a2b7f49f90d5d39c981cf6e110cf1f1c64427a28a6d58ec88c43657 with map = GenMap[]); registrars = (DA.Set.Types:Set@97b883cd8a2b7f49f90d5d39c981cf6e110cf1f1c6442

Am I writing the try/catch correctly?

Does this function seem like a sensible addition to the SDK?

1 Like

It’s definitely a sensible idea. We had a PR from @matt Give the reason for failure on `mustFail` nodes in scenarios by mjstewart · Pull Request #6517 · digital-asset/daml · GitHub which tried to add something like that but never got over the finish line.

There is an issue here in that we generally try very hard that everything that you can do in Daml Studio is also available over the ledger API. However, the ledger API does not expose the Daml exception that got thrown in your transaction so while we could expose this in Daml Studio, we cannot expose it in Daml script.

And there are also a number of non-exception failures from authorization failures to mistyped contract ids, … which will need a slightly different API.

I think it’s probably worth exposing something for this even if it just works in Daml Studio but it still needs some thought and a fair amount of implementation.

1 Like

So I’m a bit confused now.

I’ve just written a simple try/catch block, and it’s not working either:

  try do
    void $ submit alice $ exerciseCmd mint Split with splitQuantity = 2000.0
    -- error "Expected: PreconditoionFailed"
  catch
    PreconditionFailed{} -> pure ()

When you said

Do you essentially mean that try/catch is broken in daml Script? (But that it works inside an Update?)

It’s not broken in Daml script. If you throw in Script you can catch it. What doesn’t work is throwing an exception in a submission` and expecting to catch that exception on the client side. See How do I catch an inbuilt Exception in a Script? - #2 by cocreature for the same discussion.

1 Like

Duplicate of