Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add batch daml example as a code snippet #770

Merged
merged 20 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 57 additions & 61 deletions docs/2.10.0/docs/canton/usermanual/performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -506,74 +506,70 @@ If you submit a ledger API command (which can have multiple Daml commands), then

Just putting all Daml commands into a single batch command does not help, as you might still create lots of views.

In the protocol up to version 5, Canton creates a view for every action node in the transaction tree if the informees change
between the node and its parent. Therefore, in order to minimize the number of views, you should try to minimize the number of
changes of informees. Informees are roughly the signatories, observers of the contract and of the choice, and the controllers of the choice.

Instead of sending a batch with 20 exercise commands `Foo`, group your contracts by stakeholder and send one exercise
command on a generator contract with the list of contracts that in turn exercises the `Foo` choice per stakeholder group.

If you write batch commands, group the operations on the ledger based on the informees and create a single choice and
batch operation per informee group. You can use choice observers to align informees if necessary.

For example, if the below `doUpdate` is only visible to the `owner` party, then whether the `efficient` flag is set or not
will have a huge impact on the number of views created.

.. code:: daml

doUpdate : Bool -> Party -> Party -> [ContractId Example] -> Update ()
doUpdate efficient owner obs batch = do
if efficient then do
-- Would be even more efficient if we can reuse the BatchFoo contract
batcher <- create BatchFoo with owner
batcher `exercise` Run with batch = batch; obs = obs
else do
-- Canton will create one view per exercise
forA_ batch (`exercise` Foo)
pure ()

template Example
with
owner : Party
obs: Party
where
signatory owner
observer obs

choice Foo : ()
controller owner
do
return ()

template BatchFoo
with
owner : Party
where
signatory owner

choice Run : ()
with
batch : [ContractId Example]
obs : Party
-- The observer here is a choice observer. Therefore, Canton will
-- ship a single view with the top node of this choice if the observer of the
-- choice aligns with the observer of the contract.
observer obs
controller owner
do
forA_ batch (`exercise` Foo)


As a rule, the number of views should depend on the number of stakeholder groups you have in your batch choice,
not the number of "batches" you process in parallel within one command.
Strategy for Protocol Version 6
+++++++++++++++++++++++++++++++

Starting from protocol version 6, Canton creates a view for every action node in the transaction tree if the
**participants that host their informees are not a subset of their parent view's informee participants**.
A view's informee participants are all the participants that must be informed about the view.
Therefore, to reduce the number of views, you should try to reduce either the number of times the set of informees grows
or make sure most of your actions share the same pool of participants that must be informed. Alternatively, you can
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
add informees to the action nodes close to the root (e.g., by including choice observers) so that their children nodes
are aggregated in the initial view, since these children nodes will only target a subset of those participants.

JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
One concrete way to reduce the number of views being generated by a Daml model is to write batch commands and group the
operations on the ledger based on their informees' participants and create a single choice and batch operations per
informee's participants group.
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved

You can also reduce the number of views being generated for the children of a node (i.e., parent-child views) when
creating your Daml model.
With the below example as reference, instead of sending a batch with 20 exercise commands `Foo`,
you can group your contracts by a set of stakeholders that cover the exercise's informee participants and send
one exercise command on a generator contract with the list of contracts that in turn exercises the Foo choice
per stakeholder group. This way you can perform these operations in a single view, instead of having them spawn multiple
different views.

For example, if the `doUpdate` bellow is called from a choice visible to the `owner` party alone, then whether the `efficient`
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
flag is set or not will have a huge impact on the number of views created.
In the choice `Foo` of the `Example` contract even though the participants to be informed are a subset of the
contract's informee participants they don't get merged into a single view if this choice is called independently each time,
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
since they produce multiple root actions each belonging to their own view. Finally, aligning the choice observer of `Run`
to its template contract means that either they are the same or the new observer is hosted by any of the contract's informee
participants.
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved

.. literalinclude:: code-snippets/troubleshooting/Batching.daml
:language: daml

As a rule, the number of views should depend on the number of groups of informee participants
you have in your batch choice, not the number of "batches" you process in parallel within one command.
A informee's participants group is formed by aggregating the participants that host each stakeholder, or, in other
words, the set participants that need to see a particular view.
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved

The informees for the different type of transaction tree nodes are (also see :ref:`da-model-projections`):
* create: signatories, observers
* create: signatories, observers
* consuming exercise: signatories, observers, stakeholders of the choice (controller, choice observers)
* nonconsuming exercise: signatories, stakeholders of the choice (controller, choice observers), but not the observers of the contract
* fetch: signatories + actors of the fetch, which are all stakholders which are in the authorization context that the fetch executed in
* lookupByKey: only key maintainers


Strategy for Protocol Versions 5 and Lower
++++++++++++++++++++++++++++++++++++++++++

For protocol versions 5 and lower, Canton creates a view for every action node in the transaction tree if the informees
or confirming parties change between the node and its parent. Therefore, in order to minimize the number of views,
you should try to minimize the number of changes of informees and confirming parties.
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved

When compared with the decomposition strategy for protocol version 6, this view decomposition is more granular,
with more views created, and thus less performant, since the condition to merge an action node in a view
is more restricted. In this case, we only consider the lists of informees and confirming parties and any change
to these lists will spawn a new view.
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved

To batch, the rule here is to group the operations on the ledger based solely on the lists of informees and confirming
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
parties. You can use choice observers to align informees if necessary. With the previous model as reference, the batch
function will only be able to reduce the total number of views if the observer of the aggregating choice is the
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
same as the `Example` contract observer.

.. _model_tuning_events:

Reduce Ledger Events
Expand Down
56 changes: 9 additions & 47 deletions docs/2.8.9/docs/canton/usermanual/performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ If you submit a ledger API command (which can have multiple Daml commands), then

Just putting all Daml commands into a single batch command does not help, as you might still create lots of views.

In the protocol up to version 5, Canton creates a view for every action node in the transaction tree if the informees change
Currently, Canton creates a view for every action node in the transaction tree if the informees change
between the node and its parent. Therefore, in order to minimize the number of views, you should try to minimize the number of
changes of informees. Informees are roughly the signatories, observers of the contract and of the choice, and the controllers of the choice.

Expand All @@ -516,53 +516,15 @@ command on a generator contract with the list of contracts that in turn exercise
If you write batch commands, group the operations on the ledger based on the informees and create a single choice and
batch operation per informee group. You can use choice observers to align informees if necessary.

For example, if the below `doUpdate` is only visible to the `owner` party, then whether the `efficient` flag is set or not
will have a huge impact on the number of views created.

.. code:: daml

doUpdate : Bool -> Party -> Party -> [ContractId Example] -> Update ()
doUpdate efficient owner obs batch = do
if efficient then do
-- Would be even more efficient if we can reuse the BatchFoo contract
batcher <- create BatchFoo with owner
batcher `exercise` Run with batch = batch; obs = obs
else do
-- Canton will create one view per exercise
forA_ batch (`exercise` Foo)
pure ()

template Example
with
owner : Party
obs: Party
where
signatory owner
observer obs

choice Foo : ()
controller owner
do
return ()

template BatchFoo
with
owner : Party
where
signatory owner

choice Run : ()
with
batch : [ContractId Example]
obs : Party
-- The observer here is a choice observer. Therefore, Canton will
-- ship a single view with the top node of this choice if the observer of the
-- choice aligns with the observer of the contract.
observer obs
controller owner
do
forA_ batch (`exercise` Foo)
For example, if the `doUpdate` bellow is called from a choice visible to the `owner` party alone, then whether the `efficient`
flag is set or not will have a huge impact on the number of views created.
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
In the choice `Foo` of the `Example` contract even though the participants to be informed are a subset of the
contract's informee participants they don't get merged into a single view if this choice is called independently each time,
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
since they produce multiple root actions each belonging to their own view. Finally, aligning the choice observer of `Run`
to its template contract means that they must be the same.

.. literalinclude:: code-snippets/troubleshooting/Batching.daml
:language: daml

As a rule, the number of views should depend on the number of stakeholder groups you have in your batch choice,
not the number of "batches" you process in parallel within one command.
Expand Down
57 changes: 9 additions & 48 deletions docs/2.9.1/docs/canton/usermanual/performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -529,55 +529,16 @@ one exercise command on a generator contract with the list of contracts that in
per stakeholder group. This way you can perform these operations in a single view, instead of having them spawn multiple
different views.

For example, if the `doUpdate` is called from a choice visible to the `owner` party alone, then whether the `efficient`
For example, if the `doUpdate` bellow is called from a choice visible to the `owner` party alone, then whether the `efficient`
flag is set or not will have a huge impact on the number of views created.

.. code:: daml

doUpdate : Bool -> Party -> Party -> [ContractId Example] -> Update ()
doUpdate efficient owner obs batch = do
if efficient then do
batcher <- create BatchFoo with owner
-- This only works out if obs is the same observer on all the exercised Example contracts
batcher `exercise` Run with batch = batch; obs = obs
else do
-- Canton will create one view per exercise
forA_ batch (`exercise` Foo)
pure ()

template Example
with
owner : Party
obs: Party
where
signatory owner
observer obs

-- even though the participants to be informed are a subset of the contract's informee participants
-- they don't get merged into a single view if this choice is called independently each time (multiple root actions)
choice Foo : ()
controller owner
do
return ()

template BatchFoo
with
owner : Party
where
signatory owner

choice Run : ()
with
batch : [ContractId Example]
obs : Party
-- The observer here is a choice observer. Therefore, Canton will
-- ship a single view with the top node of this choice if the observer of the
-- choice aligns with the observer of the contract. In other words, either they are the same or the new observer
-- is hosted by any of the contract's informee participants.
observer obs
controller owner
do
forA_ batch (`exercise` Foo)
In the choice `Foo` of the `Example` contract even though the participants to be informed are a subset of the
contract's informee participants they don't get merged into a single view if this choice is called independently each time,
since they produce multiple root actions each belonging to their own view. Finally, aligning the choice observer of `Run`
to its template contract means that either they are the same or the new observer is hosted by any of the contract's informee
participants.

.. literalinclude:: code-snippets/troubleshooting/Batching.daml
:language: daml

As a rule, the number of views should depend on the number of groups of informee participants
you have in your batch choice, not the number of "batches" you process in parallel within one command.
Expand Down
97 changes: 36 additions & 61 deletions docs/3.1/docs/canton/usermanual/performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -506,69 +506,44 @@ If you submit a ledger API command (which can have multiple Daml commands), then

Just putting all Daml commands into a single batch command does not help, as you might still create lots of views.

In the protocol up to version 5, Canton creates a view for every action node in the transaction tree if the informees change
between the node and its parent. Therefore, in order to minimize the number of views, you should try to minimize the number of
changes of informees. Informees are roughly the signatories, observers of the contract and of the choice, and the controllers of the choice.

Instead of sending a batch with 20 exercise commands `Foo`, group your contracts by stakeholder and send one exercise
command on a generator contract with the list of contracts that in turn exercises the `Foo` choice per stakeholder group.

If you write batch commands, group the operations on the ledger based on the informees and create a single choice and
batch operation per informee group. You can use choice observers to align informees if necessary.

For example, if the below `doUpdate` is only visible to the `owner` party, then whether the `efficient` flag is set or not
will have a huge impact on the number of views created.

.. code:: daml

doUpdate : Bool -> Party -> Party -> [ContractId Example] -> Update ()
doUpdate efficient owner obs batch = do
if efficient then do
-- Would be even more efficient if we can reuse the BatchFoo contract
batcher <- create BatchFoo with owner
batcher `exercise` Run with batch = batch; obs = obs
else do
-- Canton will create one view per exercise
forA_ batch (`exercise` Foo)
pure ()

template Example
with
owner : Party
obs: Party
where
signatory owner
observer obs

choice Foo : ()
controller owner
do
return ()

template BatchFoo
with
owner : Party
where
signatory owner

choice Run : ()
with
batch : [ContractId Example]
obs : Party
-- The observer here is a choice observer. Therefore, Canton will
-- ship a single view with the top node of this choice if the observer of the
-- choice aligns with the observer of the contract.
observer obs
controller owner
do
forA_ batch (`exercise` Foo)


As a rule, the number of views should depend on the number of stakeholder groups you have in your batch choice,
not the number of "batches" you process in parallel within one command.
Currently, Canton creates a view for every action node in the transaction tree if the
**participants that host their informees are not a subset of their parent view's informee participants**.
A view's informee participants are all the participants that must be informed about the view.
Therefore, to reduce the number of views, you should try to reduce either the number of times the set of informees grows
or make sure most of your actions share the same pool of participants that must be informed. Alternatively, you can
add informees to the action nodes close to the root (e.g., by including choice observers) so that their children nodes
are aggregated in the initial view, since these children nodes will only target a subset of those participants.
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved

One concrete way to reduce the number of views being generated by a Daml model is to write batch commands and group the
operations on the ledger based on their informees' participants and create a single choice and batch operations per
informee's participants group.

You can also reduce the number of views being generated for the children of a node (i.e., parent-child views) when
creating your Daml model.
With the below example as reference, instead of sending a batch with 20 exercise commands `Foo`,
you can group your contracts by a set of stakeholders that cover the exercise's informee participants and send
one exercise command on a generator contract with the list of contracts that in turn exercises the Foo choice
per stakeholder group. This way you can perform these operations in a single view, instead of having them spawn multiple
different views.

For example, if the `doUpdate` bellow is called from a choice visible to the `owner` party alone, then whether the `efficient`
flag is set or not will have a huge impact on the number of views created.
In the choice `Foo` of the `Example` contract even though the participants to be informed are a subset of the
contract's informee participants they don't get merged into a single view if this choice is called independently each time,
since they produce multiple root actions each belonging to their own view. Finally, aligning the choice observer of `Run`
JoaoSa-da marked this conversation as resolved.
Show resolved Hide resolved
to its template contract means that either they are the same or the new observer is hosted by any of the contract's informee
participants.

.. literalinclude:: code-snippets/troubleshooting/Batching.daml
:language: daml

As a rule, the number of views should depend on the number of groups of informee participants
you have in your batch choice, not the number of "batches" you process in parallel within one command.
A informee's participants group is formed by aggregating the participants that host each stakeholder, or, in other
words, the set participants that need to see a particular view.

The informees for the different type of transaction tree nodes are (also see :ref:`da-model-projections`):
* create: signatories, observers
* create: signatories, observers
* consuming exercise: signatories, observers, stakeholders of the choice (controller, choice observers)
* nonconsuming exercise: signatories, stakeholders of the choice (controller, choice observers), but not the observers of the contract
* fetch: signatories + actors of the fetch, which are all stakholders which are in the authorization context that the fetch executed in
Expand Down