Why isn't there an archive node in the transaction graph on a (consuming) choice

In the following code Transfer1 transaction graph doesn’t have an archive node, while Transfer2 transaction graph does. Why the difference?

module Main where

import Daml.Script

template Asset
  with
    owner : Party
  where
    signatory owner

    choice Transfer1 : ContractId Asset
      controller owner 
      do 
        create this

    nonconsuming choice Transfer2 : ContractId Asset
      controller owner 
      do 
        archive self
        create this


demo = script do
  alice <- allocateParty "Alice"

  asset1 <- submit alice do
    createCmd Asset with owner = alice

  asset2 <- submit alice do 
    exerciseCmd asset1 Transfer1

  asset3 <- submit alice do 
    exerciseCmd asset2 Transfer2

  return ()

Transaction graph:

Show table viewTransactions: 
  TX 0 1970-01-01T00:00:00Z (Main:26:13)
  #0:0
  │   consumed by: #1:0
  │   referenced by #1:0
  │   known to (since): 'Alice' (0)
  └─> create Main:Asset
      with
        owner = 'Alice'
  
  TX 1 1970-01-01T00:00:00Z (Main:29:13)
  #1:0
  │   known to (since): 'Alice' (1)
  └─> 'Alice' exercises Transfer1 on #0:0 (Main:Asset)
              with
      children:
      #1:1
      │   consumed by: #2:1
      │   referenced by #2:0, #2:1
      │   known to (since): 'Alice' (1)
      └─> create Main:Asset
          with
            owner = 'Alice'
  
  TX 2 1970-01-01T00:00:00Z (Main:32:13)
  #2:0
  │   known to (since): 'Alice' (2)
  └─> 'Alice' exercises Transfer2 on #1:1 (Main:Asset)
              with
      children:
      #2:1
      │   known to (since): 'Alice' (2)
      └─> 'Alice' exercises Archive on #1:1 (Main:Asset)
                  with
      
      #2:2
      │   known to (since): 'Alice' (2)
      └─> create Main:Asset
          with
            owner = 'Alice'

Active contracts:  #2:2

Return value: {}
2 Likes

Transaction trees in DAML (both in the transaction tree service as well as in the transaction graph in DAML Studio) only know about 4 types of nodes:

  1. Create
  2. Exercise (consuming and non-consuming)
  3. Fetch (not exposed in the transaction tree service atm)
  4. LookupByKey (not exposed in the transaction tree service atm)

There is no Archive node here. So how does archiveCmd cid or exerciseCmd cid Archive work? The DAML compiler automatically generates a consuming choice called Archive with the signatories as the controllers for every template.

So the only way to archive a contract is to call a consuming choice and that’s exactly what you are seeing here: In the first example you only see the exercise of the consuming Transfer1 choice. In the second example, you see the exercise of the nonconsuming Transfer2 choice which as a consequence exercises the consuming Archive choice injected by the compiler. In neither of those examples do you see a node representing the actual archive.

Now there are imho 2 issues here that we should address:

  1. In the short term, the transaction graph in DAML Studio should indicate which choices are consuming and which are nonconsuming.
  2. In the long term, we should imho try to change the primitives. Instead of having consuming and nonconsuming choices, only provide nonconsuming choices and a primitive for archiving. If needed, you can still have syntactic sugar in the compiler similar to how we have the preconsuming keyword atm. As a basis, archive + nonconsuming choices is much easier to grasp imho than consuming + nonconsuming.
4 Likes

One missing detail is that there are archive events in the Ledger API, but those are a simplified form of an consuming exercise event that is available through the methods that expose the “flat” transaction stream rather then full transaction trees.