Ensure & Assert Constraints - finding details of what failed?

If we have a complex clause in ensure or assert checks, anyway to notifiy thecaller what condition or subcondition really failed?

2 Likes

For ensure conditions you cannot get more information atm. For asserts you have two options:

  1. Instead of having a single call to assert, make multiple calls to assertMsg with different strings. The string will appear in the error so you can use that to figure out which one failed.
  2. Using assertMsg works well if you want the error for debugging. If you actually need to consume it from code, parsing the string in the error is a rather fragile approach and you probably want a structured error instead of a simple string. In that case assert or assertMsg isn’t going to help. However, you have another option: The choice result. Let’s make a simple example:
choice C : () 
  controller p
  do assert conditionA
        assert conditionB
        pure ()

The only thing that choice will do if it succeeds is to archive the contract (it is a consuming choice).

Now we can modify that as follows:

nonconsuming choice C : Either Error () 
  controller p
  do if conditionA
          then if conditionB
                     then do archive self
                             pure (Right ())
                     else pure (Left ErrorB)
          else pure (Left ErrorA)

data Error = ErrorA | ErrorB

You’ll notice a few things:

  1. I’ve made the choice nonconsuming. This is because if the assertions fail we still need to return a value from the choice but do not want to archive the contract.
  2. I’ve changed the return type to Either Error () and introduced a new Error type.
  3. I’ve replaced the assertions by if statements. There are various ways to make this nicer than the nested ifs here but I’ve deliberately kept things as simple as possible.

There is one important difference here: The nonconsuming choice will always be recorded on the ledger even if the assertions fail. This is not necessarily an issue and in some applications this is even desirable but it is something you have to keep in mind.

Overall, if you do not need to consume the error programmatically and you do not need to record the error on the ledger, assertMsg is much simpler and preferable.

4 Likes