Structure¶
This section looks at the structure of a ledger and the associated ledger changes. The definitions presented here are all the ingredients required to record the interaction between parties in a Daml ledger. That is, they address the first question: “what do changes and ledgers look like?”. The basic building blocks of changes are actions, which get grouped into transactions, commits, and the Ledger.
Running workflow example¶
Most of the examples in this section look at the following Daml Script scenarios based on the templates from the running example. Two banks first each issue one asset to either Alice or Bob and then Alice proposes a DvP to Bob. Bob accepts the proposal and settles the DvP.
let eurAsset = SimpleAsset with
issuer = bank1
owner = alice
asset = "1 EUR"
eur <- submit bank1 do createCmd eurAsset
let usdAsset = SimpleAsset with
issuer = bank2
owner = bob
asset = "1 USD"
usd <- submit bank2 do createCmd usdAsset
proposeDvP <- submit alice $ do
createCmd ProposeSimpleDvP with
proposer = alice
counterparty = bob
allocated = eur
expected = usdAsset
disclosedEur <- fromSome <$> queryDisclosure alice eur
Acceptance and settlement can happen either in a single step via the AcceptAndSettle
choice.
(newUsd, newEur) <- submitWithDisclosures bob [disclosedEur] do
exerciseCmd proposeDvP $ AcceptAndSettle with toBeAllocated = usd
Or in two separate steps with Accept
followed by Settle
:
dvp <- submit bob $
do exerciseCmd proposeDvp $ Accept with toBeAllocated = usd
(newUsd, newEur) <- submitWithDisclosures bob [disclosedEur] do
exerciseCmd dvp $ Settle with actor = bob
Actions¶
Hierarchical structure¶
One of the main features of the Ledger Model is a hierarchical action structure.
This structure is illustrated using Bob settling the DvP by exercising the Settle
choice in the above scenario.
Alice and Bob have allocated their assets (contracts #1 and #2) on the ledger to a SimpleDvp
contract (#4).
These contracts appears as inputs (dashed boxes on the left) in the diagram below.
Exercising the Settle
choice yields an Exercise action,
which is the tree of nodes shown in blue.
The input contracts on the left are not part of the action.
The root node describes the parameters of the choice and references the SimpleDvp
input contract #4.
It has two subtrees, which perform the asset transfers automatically as part of the Settle
choice.
The left subtree represents Alice exercising the
Transfer
choice on herSimpleAsset
contract #1. It consists of two nodes: The root node describes the parameters of the choice and the input contract #1. The child node, which is a one-node subtree of its own, encodes the creation of Bob’s newSimpleAsset
contract #5.The right subtree is analogous: The root node of the subtree describes Bob exercising the
Transfer
choice on hisSimpleAsset
contract #2, and its child encodes the creation of Alice’s newSimpleAsset
contract #6.
Notably, the Exercise action is the whole tree even though the root node already describes all the relevant parameters. The Ledger Model focuses on actions rather than nodes because the root node cannot exist on its own, without its children, as the choice body in the Daml model must always execute when the choice is exercised. The integrity section goes into the details of this.
Nevertheless actions are not indivisible, but hierarchical:
The left and right subtrees are actions in their own right,
namely the Exercise actions for Alice and Bob exercising their Transfer
choice on their SimpleAsset
input contracts #1 and #2, respectively.
And each of the two subtrees contains another subtree,
namely the creation of Bob’s and Alice’s new SimpleAsset
contracts #5 and #6.
Each of these subtrees is an action in its own right.
This hierarchical structure induces a subaction relationship explained below
and forms the basis for the privacy model.
Definition¶
Overall, the settlement in the above example contains two types of actions:
Creating contracts
Exercising choices on contracts.
These are also the two main kinds of actions in the Ledger Model.
A node is one of the following:
A Create node records the creation of the contract. It contains the following pieces of information:
The contract ID is a unique identifier of the contract. It is equivalent to the transaction output (TxO) in ledgers based on unspent transaction outputs (UTxO).
The template ID identifies the Daml code associated with the contract, and its arguments define the contract instance, which is the immutable data associated with the contract ID.
The signatories are the non-empty set of parties that must authorize the creation and archival of the contract.
The contract observers, or just observers for short, are the set of parties that will be informed about the contract creation and archival, in addition to the signatories.
In Daml, the signatories and contract observers are determined by the
signatory
andobserver
clauses defined by the template.Create nodes are depicted as shown below. Diagrams often omit fields with empty values and observers that are also signatories.
An Exercise node records the parameters of a choice that one or more parties have exercised on a contract. It contains the following pieces of information:
An exercise kind, which is either consuming or non-consuming. Once consumed, a contract cannot be used again; for example, Alice must not be able to transfer her asset twice, as this would be double spending. In contrast, contracts exercised in a non-consuming fashion can be reused, for example for expressing a delegation from one party to another.
The contract ID on which the choice is exercised. This contract is called the input contract.
The interface ID if this choice was exercised through a Daml interface.
The template ID that defines the smart contract code for the choice with the given choice name; and the choice arguments that are passed to the smart contract code.
An associated set of parties called actors. These are the parties who perform the action. They are specified in the
controller
clause in the Daml template.An associated set of choice observers. These parties will be informed about the choice being exercised.
The exercise result as the Daml value returned by evaluating the choice body.
Exercise nodes are depicted as shown below, where the consequences are indicated by arrows ordered left-to-right. Diagrams omit the kind if it is consuming, empty field values, and choice observers that are also actors.
A Fetch node on a contract, which demonstrates that the contract exists and is active at the time of fetching. A Fetch behaves like a non-consuming Exercise with no consequences, and can be repeated. The fetch node contains the following pieces of information, analogous to Exercise nodes: contract ID, interface ID, template ID, and the actors, namely the parties who fetch the contract.
Fetch nodes are depicted as shown below.
An action consists of a root node and a list of consequences, which are themselves actions. This gives rise to the tree structure of an action: The root node of an action has as children the root nodes of its consequences.
An action inherits its kind from its root node:
A Create action has a Create node as the root. The consequences are empty.
An Exercise action has an Exercise node as the root and the consequences are the subactions. The Exercise action is the parent action of its consequences.
A Fetch action as a Fetch node as the root. The consequences are empty.
The terminology on nodes extends to actions via the root node. For example, the signatories of a Create action are the signatories of the Create node, and an Exercise action is (non)consuming if and only if its root node is. Moreover, an Exercise or a Fetch action on a contract is said to use the contract. Finally, a consuming Exercise is said to consume (or archive) its contract.
Examples¶
An example of a Fetch action appears in the Accept
choice on a DvP proposal contract from the template ProposeSimpleDvP
.
The choice body fetches the SimpleAsset
that Bob allocates to the DvP,
which checks that the asset contract is active and brings the contract instance into the computation,
so that the choice implementation can assert that this asset meets the expectation expressed in the proposal contract.
The next diagram shows this Exercise action with the Fetch action as its first consequence.
A non-consuming Exercise shows up in the combined AcceptAndSettle
choice on the ProposeSimpleDvP
contract:
This choice is non-consuming so that the Accept
choice exercised in the choice body can consume the proposal contract.
As the next diagram shows, non-consuming Exercises yield multiple references to the same input contract #3.
The diagram also shows that fetches have the same effect: input contract #2 is used twice.
Subactions¶
This example again highlights the hierarchical structure of actions:
The AcceptAndSettle
action contains the corresponding actions for Accept
and Settle
as its consequences.
More generally, for an action act, its proper subactions are all actions in the consequences of act, together with all of their proper subactions. Additionally, act is a (non-proper) subaction of itself.
The subaction relation is visualized below for Bob’s Settle
Exercise.
Each borderless box contains an action (via its tree of nodes) and the nesting of these boxes encodes the subaction relation.
In detail, both the blue and purple boxes are proper subactions of Bob’s Settle
action shown in grey.
The green box is a proper subaction of the blue and the grey boxes, and the yellow box is a proper subaction of the purple and the grey boxes.
Transactions¶
A transaction is a list of actions that are executed atomically.
Those actions are called the root actions of the transaction.
That is, for a transaction tx = act1, …, actn, every acti is a root action.
For example, if Alice and Charlie have made one DvP proposal each for Bob, then Bob may want to accept both simulataneously.
To that end, Bob exercises both Accept
choices in a single transaction with two root actions (blue and purple), as shown next.
Visually, transactions are delimited by the dashed lines on both sides, to distinguish them from actions.
Like for actions, the input contracts on the left are not part of the transaction.
For another example, consequences of an Exercise action form a transaction.
In the example of the Settle
action on Alice’s and Bob’s SimpleDvP
,
the consequences of the Settle
action form the following transaction,
where actions are ordered left-to-right as before.
The transaction consists of two root actions (blue and purple), namely the two Transfer
actions of the two legs of the DvP.
The hierarchical structure of actions extends to transactions and yields the notion of subtransactions. A proper subtransaction of a transaction is obtained by (repeatedly) replacing an action by its consequences; and a subtransaction of a transaction is either the transaction itself or a proper subtransaction thereof.
For example, given the transaction shown above consisting only of the two consequences of the Settle
action,
the next diagram shows all seven proper non-empty subtransactions, each with their dashed delimiters.
Inputs and outputs¶
The Ledger Model falls into the category of (extended) UTxO-style ledgers where the set of unspent transaction outputs (UTxOs) constitutes the current state of a ledger. Here, the transaction outputs are the contract IDs of the contracts created in a transaction. When a contract is consumed, its contract ID is spent and thus removed from the UTxO set. The data associated with each UTxO is immutable; modifications happen by consuming a contract ID and recreating a new contract with a different contract ID.
This Ledger Model extends the UTxO model in two aspects:
A transaction may use a contract without consuming it, for example by exercising a non-consuming choice or fetching it. In such a case, the contract ID remains in the set of UTxOs even though it appears as an input to a transaction.
Transactions are structured hierarchically and contract IDs created in the transaction may be consumed within the same transaction. For example, inside the
AcceptAndSettle
action, the createdSimpleDvP
in the first consequence is consumed by the second consequence. Such contracts are called transient.
These aspects are discussed in more detail in the remaining sections of the Ledger Model.
Ledger¶
The transaction structure records the contents of the changes, but not who requested them.
This information is added by the notion of a commit:
It consists of a single transaction and the one or more parties that requested it.
Those parties called the requesters of the commit.
In Daml Script, the requesters correspond to the actAs
parties given to the submit
commands.
- Definition Ledger:
A Ledger is a directed acyclic graph (DAG) of commits, where an edge (c1, c2) connects a commit c1 to another commit c2 if and only if the transaction of c1 uses a contract ID created by or used in the transaction in c2.
- Definition top-level action:
For a commit, the root actions of its transaction are called the top-level actions. A top-level action of any ledger commit is also a top-level action of the ledger.
A Canton Ledger thus represents the full history of all actions taken by parties. The graph structure of the Ledger induces an order on the commits in the ledger. Visually, a ledger can be represented as a sequence growing from left to right as time progresses. Below, dashed vertical lines in purple mark the boundaries of commits, and each commit is annotated with its requester(s). Blue arrows link each Exercise and Fetch action to the Create action of the input contract. These arrows highlight that the ledger forms a transaction graph.
For example, the following Daml Script encodes the whole workflow of the running DvP example.
let eurAsset = SimpleAsset with
issuer = bank1
owner = alice
asset = "1 EUR"
eur <- submit bank1 do createCmd eurAsset
let usdAsset = SimpleAsset with
issuer = bank2
owner = bob
asset = "1 USD"
usd <- submit bank2 do createCmd usdAsset
proposeDvP <- submit alice $ do
createCmd ProposeSimpleDvP with
proposer = alice
counterparty = bob
allocated = eur
expected = usdAsset
disclosedEur <- fromSome <$> queryDisclosure alice eur
This workflow gives rise to the ledger shown below with four commits:
In the first commit, Bank 1 requests the creation of the
SimpleAsset
of1 EUR
issued to Alice (contract #1).In the second commit, Bank 2 requests the creation of the
SimpleAsset
of1 USD
issued to Bob (contract #2).In the thrid commit, Alice requests the creation of the
SimpleDvpPoposal
(contract #3).In the forth commit, Bob requests to exercise the
AcceptAndSettle
choice on the DvP proposal.
Note
The Ledger does not impose an order between independent commits. In this example, there are no edges among the first three commits, so they could be presented in any order.
As the Ledger is a DAG, one can always extend the order into a linear sequence via a topological sort. For the next sections, we pretend that the Ledger is totally ordered (unless otherwise specified). We discuss the more general partial orders in the causality section.