Scenario results not appearing

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 have multiple contracts that I have setup, one of them is Agent.daml for which the scenario results appear just fine, however, my Investor contract for which an agent is the signatory is not displaying scenario results, so i’m assuming, I have either setup the contract incorrectly or my scenario code is incorrect?

Here’s a screenshot

1 Like

Hey @krmmalik can you copy and paste your code as text? It’ll help with addressing your issue and providing examples of how to do this. Also please include the code for the Agent and Guarantor templates.

You can have it nicely formatted by putting a line of 3 back-ticks (```) above and below the code such that:

```
template Investor with
-- The rest of the code
```

Becomes:

template Investor with
-- The rest of the code

The problem is the fragment with ...; agent.agentname = alice; .... You can see that the = is underlined in red. Same problem for guarantor. You can’t just set agent.agentname in isolation there, but need to set the agent field to a value of type Agent. You haven’t shared your Agent type, but it’ll look something like this:

submit hakan do
  create Investor with
    investorname = hakan
    agent = Agent with
      agentname = alice
      ...
    guarantor = Guarantor with
      guarantorname = [fadhim, jahan]
      ...
2 Likes

It appears that the scenario does not appear because your code does not compile.

Notice the squiggly line under the = sign in agent.agentname = alice.

What does the compiler tell you there?

1 Like

This advice will make it much easier for the forum contributors to help you. :wink:

3 Likes

Investor template

module Investor where

import Agent
import Proposal
import Guarantor

-- MAIN_TEMPLATE_BEGIN
template Investor with
    agent: Agent
    proposal: Proposal
    guarantor: Guarantor
    investorname: Party

  where
    signatory investorname
    observer agent.agentname, guarantor.guarantorname
-- MAIN_TEMPLATE_END

    key agent.agentname: Party
    maintainer key

-- RUN_SCENARIO --

exampleinvestor =
  scenario do
    -- Creates each party
    hakan <- getParty "Hakan"
    alice <- getParty "Alice"
    fadhim <- getParty "Fadhim"
    jahan <- getParty "Jahan"
    -- Creates an instance of the Investor contract, authorized by "Hakan"
    submit hakan do
      create Investor
        -- 
        with investorname = hakan; agent.agentname = alice; guarantor.guarantorname = [Fadhim, Jahan]
      
      


  -- END_SCENARIO --

Agent.daml

module Agent where


-- MAIN_TEMPLATE_BEGIN
template Agent with
    agentname: Party
    guarantors: [Party]
  where
    signatory agentname
    observer guarantors
-- MAIN_TEMPLATE_END

    key agentname: Party
    maintainer key

    -- VOUCH_BEGIN
    nonconsuming choice Choose: ContractId Agent with
        selectPeopleThatVouch: Party
      controller agentname
      do
        assertMsg "You cannot vouch for yourself" (selectPeopleThatVouch /= agentname)
        assertMsg "You cannot follow the same user twice" (notElem selectPeopleThatVouch guarantors)
        archive self
        create this with guarantors = selectPeopleThatVouch :: guarantors
    -- VOUCH_END

-- RUN_SCENARIO --

example =
  scenario do
    -- Creates each party
    alice <- getParty "Alice"
    fadhim <- getParty "Fadhim"
    jahan <- getParty "Jahan"
    -- Creates an instance of the Agent contract, authorized by "Alice"
    submit alice do
      create Agent
        -- 
        with agentname = alice; guarantors = [fadhim, jahan]
      
      


  -- END_SCENARIO --

Guarantor.daml

module Guarantor where

-- MAIN_TEMPLATE_BEGIN
template Guarantor with
    guarantorname: Party
    
  where
    signatory guarantorname


-- RUN_SCENARIO --

gexample =
  scenario do
    -- Creates each party
    fadhim <- getParty "Fadhim"
    -- Creates an instance of the Guarntor contract, authorized by "Fadhim"
    submit fadhim do
      create Guarantor
        -- 
        with guarantorname = fadhim
      
      

-- END_SCENARIO --

Thank you.

1 Like

It tells me parser error

/Users/khurammalik/DevTree/Qirad Agent Network/app/daml/Investor.daml:38:52: error:
    parse error on input ‘=’
    Perhaps you need a 'let' in a 'do' block?
    e.g. 'let x = 5' instead of 'x = 5'
1 Like

Oh I see what you mean. Ok, let me try this and report back

2 Likes

@krmmalik I believe @bernhard’s answer might help you.

1 Like

I’m still getting a parser error.

This is the code i put together

-- RUN_SCENARIO --

exampleinvestor =
  scenario do
    -- Creates each party
    hakan <- getParty "Hakan"
    alice <- getParty "Alice"
    fadhim <- getParty "Fadhim"
    jahan <- getParty "Jahan"
    -- Creates an instance of the Investor contract, authorized by "Hakan"
    submit hakan do
    create Investor with
     investorname = hakan
     agent = Agent with
    agentname = alice
    guarantor = Guarantor with
    guarantorname = [fadhim, jahan]
      
      


  -- END_SCENARIO --

1 Like

Changing the indentation in places fixes some errors but not all so I’m wondering if this is an indentation issue?

1 Like

Indentation is very important in Daml, but it’s not just the indentation here. Your definition of Agent requires a list of Partys called guarantors which is missing in your snippet. The Investor also requires a Guarantor, which has a single Party field, not a list. So here’s a version with correct indentation (I’ve set all the code in a single file and removed the choices for simplicity):

module Main where

template Investor with
  agent: Agent
  guarantor: Guarantor
  investorname: Party
    where
    signatory investorname
    observer agent.agentname, guarantor.guarantorname
    key agent.agentname: Party
    maintainer key

template Agent with
    agentname: Party
    guarantors: [Party]
  where
    signatory agentname
    observer guarantors

    key agentname: Party
    maintainer key
      
template Guarantor with
    guarantorname: Party    
  where
    signatory guarantorname

exampleinvestor =
  scenario do
    hakan <- getParty "Hakan"
    alice <- getParty "Alice"
    fadhim <- getParty "Fadhim"
    jahan <- getParty "Jahan"
    submit hakan do
    create Investor with
      investorname = hakan
      guarantor = Guarantor with guarantorname = jahan
      agent = Agent with agentname = alice; guarantors = [fadhim]
    return ()

Now, the indentation is correct, and I have added a return () at the end to get the right type for the scenario, but you’ll see this s still failing. The remaining error is that the Investor template is declaring a non-signatory maintainer for its key. Key maintainers have to be signatories. The error message read:

Scenario execution failed on commit at Main:34:5:
  0: create of Main:Investor at DA.Internal.Prelude:373:26
     failed due to that some parties are maintainers but not signatories:  'Alice'

and a solution here would be to make the agent.agentname party the signatory (and also therefore submit as Alice):

module Main where

template Investor with
  agent: Agent
  guarantor: Guarantor
  investorname: Party
    where
    signatory agent.agentname
    observer agent.agentname, guarantor.guarantorname
    key agent.agentname: Party
    maintainer key

template Agent with
    agentname: Party
    guarantors: [Party]
  where
    signatory agentname
    observer guarantors

    key agentname: Party
    maintainer key
      
template Guarantor with
    guarantorname: Party    
  where
    signatory guarantorname

exampleinvestor =
  scenario do
    hakan <- getParty "Hakan"
    alice <- getParty "Alice"
    fadhim <- getParty "Fadhim"
    jahan <- getParty "Jahan"
    submit alice do
      create Investor with
        investorname = hakan
        guarantor = Guarantor with guarantorname = jahan
        agent = Agent with agentname = alice; guarantors = [fadhim]
    return ()

As a final note, I would point you to my previous explanation of the differences between contracts, contract IDs and contract payloads. It’s obviously a bit of a preliminary code snippet here, but it seems like at least some of your templates should really just be data declarations.

3 Likes

Thank you so much @Gary_Verhaegen . I will try this hopefully tomorrow and get back to you.
The thing about the data declarations was going to be my next question a little later down the line. For now, I set up individual templates just to get the hang of putting templates together in DAML but I did wonder if I needed to modularise things so much so I’m glad you’ve brought it up already. I’m doing a presentation on Qirad today so won’t get a chance to work on this code today but will definitely come back and take a look at the snippet as well as the explanations you have linked. That will be very handy.

Thank you once again.

2 Likes

OK, I see my original mistake now as you say, the fact that I was supplying a list when it requires a single argument and also using a key other than a signatory, so now i have fixed those (although I changed the signatory to investorname because in reality only the investor should be able to issue that contract).

The scenario still isn’t running I am afraid(?)

 submit hakan do
    create Investor with
       investorname = hakan
       agent = Agent with
         agentname = alice; guarantors = [fadhim]
         guarantor = Guarantor with
         guarantorname = jahan
      return()

Still getting a parser error. It is a copy of your code in the sense that i typed it out line by line (to make sure I am able to understand the code being produced) apart from the fact that i used the investorname as signatory and therefore left Hakan to submit the contract.

2 Likes

I slightly changed the indentation to put guarantor and guarantorname on the same indentation level as agent (because they are parameters to the Investor template). Also notice that return is slightly mis-indented (not sure whether that’s just an error copying the code).

    submit hakan do
      create Investor with
        investorname = hakan
        agent = Agent with
          agentname = alice; guarantors = [fadhim]
        guarantor = Guarantor with
          guarantorname = jahan
      return()

If I apply this to the code I copied from above I now see an authorization error (that you can explore more thoroughly by clicking on Scenario results and having a look at the error).

Does this help you?

2 Likes

I’m afraid that gave me a whole whirlwind of errors

/Users/khurammalik/DevTree/Qirad Agent Network/app/daml/Investor.daml:35:14: error:
    • Constructor ‘Investor’ does not have the required strict field(s): proposal
    • In the first argument of ‘create’, namely
        ‘Investor
           {investorname = hakan,
            agent = Agent {agentname = alice, guarantors = [fadhim]},
            guarantor = Guarantor {guarantorname = jahan}}’
      In a stmt of a 'do' block:
        create
          Investor
            {investorname = hakan,
             agent = Agent {agentname = alice, guarantors = [fadhim]},
             guarantor = Guarantor {guarantorname = jahan}}
      In the second argument of ‘submit’, namely
        ‘do create
              Investor
                {investorname = hakan,
                 agent = Agent {agentname = alice, guarantors = [...]},
                 guarantor = Guarantor {guarantorname = jahan}}
            return ()’

Can you double check? It works for me (modulo the authorization error).

Here is the full code for your convenience.

module Main where

template Investor with
  agent: Agent
  guarantor: Guarantor
  investorname: Party
    where
    signatory agent.agentname
    observer agent.agentname, guarantor.guarantorname
    key agent.agentname: Party
    maintainer key

template Agent with
    agentname: Party
    guarantors: [Party]
  where
    signatory agentname
    observer guarantors

    key agentname: Party
    maintainer key
      
template Guarantor with
    guarantorname: Party    
  where
    signatory guarantorname

exampleinvestor =
  scenario do
    hakan <- getParty "Hakan"
    alice <- getParty "Alice"
    fadhim <- getParty "Fadhim"
    jahan <- getParty "Jahan"
    submit hakan do
      create Investor with
        investorname = hakan
        agent = Agent with
          agentname = alice; guarantors = [fadhim]
        guarantor = Guarantor with
          guarantorname = jahan
      return()
2 Likes

Hi @krmmalik,

The Proposal template was not part of the code you shared, so in my code snippet I simply removed the proposal field from Investor. Apologies for forgetting to mention that.

In order for your code to work without removing that field, you will have to add a Proposal payload to the create Investor call. Without seeing the Proposal template I cannot give you much more guidance here.

2 Likes

ok, I have it working!

Thank you everyone in this thread especially @Gary_Verhaegen, I really appreciate your patience and the time you’ve spent in helping me walk through this. This trial and error has been much more valuable to me than the documentation alone – even the interactive tutorials and examples.

OK, so now for my next question since it was touched upon in this thread already.

In reality, the actual part of the contract in Qirad is really only the Proposal. The rest are in fact just entities/parties. There is a contract between the agents and the guarantors (that is actually supposed to be a group of agents that vouch for each other so their job as agents and guarantors are interchangeable), so my question is now regards the data declaration part you pointed out and the fact that I could do this all in one file, or at least most of it.

The way I see it, I have an agent contract and then a proposal contract and the rest are just data declarations. Would this be the right way to look at it?

And potentially I should still put both templates into one file as well anyway?

I am coming from a non-coding background so the data declarations explanation was a little hard for me to grasp so I’m going to try to revisit it and re-understand but conceptually I think I understand what you’re saying.

1 Like

Hi @krmmalik,

Struggling through building your own application is always going to be much more enlightening than reading documentation or following in predetermined footsteps. That said, if you do have any suggestion for improving either the documentation or the tutorials, we’re always happy to receive those.

Regarding data modelling, there are a few key concepts at play.

A data declaration is the primary way to define a composite data structure in Daml. That is, any time you think two (or more) pieces of information should be consider “together”, the go-to solution for that is data. You want to store information about a person?

data Person = Person with age: Int, name: Text

A template is a representation of a contract. When you define a template, Daml will automatically create for you an equivalent data declaration, which I will refer to in the following as a contract payload. The template defines what kind of contracts you can store on the ledger; contracts are always on the ledger and never in your code. However, you can read data from the ledger and store a copy in your code in the form of a contract payload.

The issue is that the existence of a piece of data in your code that happens to have the right shape to be the payload of a contract in no way indicates the existence of a contract with corresponding data on the ledger.

There is also, in the general case, no guarantee that, for a given contract that exists on the ledger, there is no other contract with the exact same payload. (Contract keys are an exception to that.) If you want to refer to a specific contract (on the ledger) from your code, you need to use a reference to that contract, which we call a contract ID. There is no way, in Daml code, to create a contract ID from nothing, so when you have a contract ID there is a good chance there was, at some point, a contract with that ID on the ledger. You can, from your Daml code, verify the existence of that contract and get the corresponding payload (fetch).

The issue I was pointing out in your code is that you seem to be using template declarations to define, say, Agent, but then you only use the Agent data type, with no relation to the ledger.

Specifically, in:

template Agent with
    agentname: Party
  where
    signatory agentname

template Investor with
    agent: Agent
    investorname: Party
  where
    signatory investorname

the field agent in Investor is of the data type that corresponds to the payload that a contract of type Agent could have, but does not necessarily correspond to any Agent contract on the ledger, so you may believe you have a lot more consistency guarantees than you actually do.

Is this any clearer? I guess the main point of confusion I can see here is that there are multiple “namespaces” at play, i.e. the data type Agent is only tangentially related to the template type Agent. This ambiguity is very useful in practice once you understand how all the pieces fit together, but I can see how it could be an obstacle to getting to that understanding in the first place.

3 Likes